diff --git a/.gitignore b/.gitignore index ce0460f432..a45279fb21 100644 --- a/.gitignore +++ b/.gitignore @@ -25,16 +25,6 @@ local.properties # PDT-specific .buildpath -########### -## Symlinks -########### - -*-sym.* -*-symdir/ -[Ee]xternal[Ff]iles/ -/src/Plugins/*-sym -/src/Presentation/SmartStore.Web/Themes/*-sym - ########################################################### ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. @@ -43,23 +33,48 @@ local.properties # User-specific files *.suo *.user +*.userosscache *.sln.docstates -# Build results +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs +# Build results [Dd]ebug/ +[Dd]ebugPublic/ [Rr]elease/ +[Rr]eleases/ x64/ -# build/ +x86/ +bld/ [Bb]in/ [Oo]bj/ +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + *_i.c *_p.c +*_i.h *.ilk *.meta *.obj @@ -79,6 +94,7 @@ x64/ *.vssscc .builds *.pidb +*.svclog *.scc # Visual C++ cache files @@ -93,6 +109,7 @@ ipch/ *.psess *.vsp *.vspx +*.sap # Guidance Automation Toolkit *.gpState @@ -108,8 +125,16 @@ _TeamCity* *.dotCover # NCrunch -*.ncrunch* +_NCrunch_* .*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ # Installshield output folder [Ee]xpress/ @@ -128,31 +153,58 @@ DocProject/Help/html publish/ # Publish Web Output -*.Publish.xml +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted *.pubxml - -# NuGet Packages Directory -## TODO: If you have NuGet Package Restore enabled, uncomment the next line -/src/packages +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets # Windows Azure Build Output csx *.build.csdef +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + # Windows Store app package directory AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ # Others # sql/ -*.Cache ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl -*.[Pp]ublish.xml +*.dbproj.schemaview *.pfx *.publishsettings +node_modules/ +orleans.codegen.cs # RIA/Silverlight projects Generated_Code/ @@ -165,12 +217,42 @@ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files -App_Data/*.mdf -App_Data/*.ldf +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ -################### -## Windows detritus -################### +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ # Windows image file caches Thumbs.db @@ -185,6 +267,21 @@ $RECYCLE.BIN/ # Mac crap .DS_Store + +########### +## Symlinks +########### + +*-sym.* +*-symdir/ +[Ee]xternal[Ff]iles/ +/src/Plugins/*-sym +/src/Presentation/SmartStore.Web/Themes/*-sym + + +########### +## Specific +########### # Backups [Bb]ackup/ [Bb]ackups/ @@ -194,21 +291,27 @@ _[Bb]ackups/ *.orig Kopie von* -########### -## Specific -########### /build /src/Presentation/SmartStore.Web/Plugins /src/Presentation/SmartStore.Web/App_Data/_temp/ +/src/Presentation/SmartStore.Web/App_Data/ExportProfiles/ +/src/Presentation/SmartStore.Web/App_Data/ImportProfiles/ /src/Presentation/SmartStore.Web/App_Data/Settings.txt /src/Presentation/SmartStore.Web/App_Data/InstalledPlugins.txt +/src/Presentation/SmartStore.Web/App_Data/Licenses.lic /src/Presentation/SmartStore.Web/Media # Import/Export /src/Presentation/SmartStore.Web/Content/files/[Ee]xport[Ii]mport/*.* +/src/Presentation/SmartStore.Web/[Ee]xchange/* # Media /src/Presentation/SmartStore.Web/Media/[Tt]humbs /src/Presentation/SmartStore.Web/Media/[Uu]ploaded +# Tools +/src/Tools/SmartStore.WebApi.Client/packages +/src/Tools/SmartStore.WebApi.Client/SmartStore.WebApi.Client.sln + src/SmartStoreNET.Packager.sln +Log.txt diff --git a/CREDITS.txt b/CREDITS.txt index ed9967dca3..88b2d0a6be 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1,9 +1,9 @@ SmartStore.NET Copyright 1999-2014 SmartStore AG -http://www.smartstore.com | http://smartstore.codeplex.com +http://www.smartstore.com | https://github.com/smartstoreag/SmartStoreNET -SmartStore.NET is a derivation of the ASP.NET open source e-commerce solution +SmartStore.NET is a fork of the ASP.NET open source e-commerce solution nopCommerce (http://www.nopcommerce.com). SmartStore.NET includes works distributed under the licenses listed below. @@ -12,14 +12,14 @@ copyright notices, and licenses. 51Degrees ------ -WebSite: http://http://51degrees.mobi/ +--------------------------------------------- +WebSite: http://51degrees.mobi/ Copyright: Copyright 2010 - 2013 51Degrees.mobi Limited License: Mozilla Public License 2.0 (MPL-2.0) ANTLR ------ +--------------------------------------------- Website: http://www.antlr.org Copyright: Copyright ANTLR / Terence Parr 2014 License: BSD License @@ -27,7 +27,7 @@ License: BSD License ASP.NET MVC ------ +--------------------------------------------- Website: http://aspnet.codeplex.com/wikipage?title=MVC&referringTitle=Home Copyright: Copyright (c) 2008-2011 Microsoft Corporation License: MICROSOFT ASP.NET MODEL VIEW CONTROLLER 3 EULA @@ -35,7 +35,7 @@ License: MICROSOFT ASP.NET MODEL VIEW CONTROLLER 3 EULA Autofac ------ +--------------------------------------------- Website: http://code.google.com/p/autofac/ Copyright: Copyright (c) 2007-2014 Autofac Contributors http://code.google.com/p/autofac/wiki/Contributing @@ -43,148 +43,143 @@ License: MIT AutoMapper ------ -WebSite: http://http://www.automapper.org +--------------------------------------------- +WebSite: http://www.automapper.org Copyright: Copyright 2008-2013 Jimmy Bogard and other contributors License: MIT Bundle Transformer ------ +--------------------------------------------- Website: https://bundletransformer.codeplex.com Copyright: Copyright Andrey Taritsyn 2014 License: Apache License 2.0 (Apache) DotNetOpenAuth ------ -Website: http://http://dotnetopenauth.net/ +--------------------------------------------- +Website: http://dotnetopenauth.net/ Copyright: Copyright (c) 2011, Outercurve Foundation License: MS-PL DotNetZip ------ +--------------------------------------------- Website: http://dotnetzip.codeplex.com/ Copyright: License: MS-PL Entity Framework ------ +--------------------------------------------- Website: https://entityframework.codeplex.com Copyright: Copyright (c) 2012-2014 Microsoft Corporation License: Apache License 2.0 (Apache) EPPlus ------ +--------------------------------------------- Website: https://epplus.codeplex.com/ Copyright: Copyright (C) 2011 Jan Kllman License: GNU Library General Public License (LGPL) Fasterflect ------ +--------------------------------------------- Website: https://fasterflect.codeplex.com/ License: Apache License 2.0 (Apache) Fluent Validation ------ +--------------------------------------------- Website: https://fluentvalidation.codeplex.com/ License: Apache License 2.0 (Apache) Glimpse ------ +--------------------------------------------- Website: https://github.com/Glimpse/Glimpse Copyright: Copyright (C) 2014 Glimpse contributors (http://getglimpse.com/Community) License: Apache License 2.0 (Apache) ImageResizer.NET ------ +--------------------------------------------- Website: https://imageresizing.net/ Copyright: Copyright (c) 2012 Imazen License: Freedom License -iTextSharp ------ -Website: http://itextpdf.com/ -License: Affero General Public License - - JavaScriptEngineSwitcher ------ +--------------------------------------------- Website: https://github.com/Taritsyn/JavaScriptEngineSwitcher Copyright: Copyright Andrey Taritsyn 2014 License: Apache License 2.0 (Apache) jQuery ------ +--------------------------------------------- Website: http://jquery.com Copyright: Copyright (c) 2010 John Resig, http://jquery.com License: MIT jQuery ScrollTo ------ +--------------------------------------------- Website: http://flesler.blogspot.com Copyright: Copyright (c) 2007-2009 Ariel Flesler License: MIT jQuery UI (Core, Widget, Datepicker) ------ +--------------------------------------------- Website: http://docs.jquery.com/UI Copyright: Copyright (c) 2010 lib/jquery.ui/AUTHORS.txt (http://jqueryui.com/about) License: MIT JSON.NET ------ -Website: http://http://james.newtonking.com/ +--------------------------------------------- +Website: http://james.newtonking.com/ Copyright: Copyright (c) 2007 James Newton-King License: MIT -LESS CSS for .NET ------ -Website: http://www.dotlesscss.org/ -License: Apache License v2.0 +GeoLite Free by MaxMind +--------------------------------------------- +Website: http://www.maxmind.com +Copyright: Copyright (c) 2014 Maxmind +License: Creative Commons Attribution-ShareAlike 3.0 Unported License Microsoft SQL Server Compact 4.0 ------ +--------------------------------------------- Website: http://www.microsoft.com Copyright: Copyright (c) 2011 Microsoft Corporation License: Custom EULA - http://www.microsoft.com/web/webpi/eula/SQLCE_EULA_ENU.rtf MiniProfiler ------ +--------------------------------------------- Website: http://miniprofiler.com/ License: Apache License, Version 2.0 Modernizr ------ +--------------------------------------------- Website: http://modernizr.com/ License: MIT NuGet ------ +--------------------------------------------- Website: http://nuget.codeplex.com Copyright: Copyright 2010-2011 Outercurve Foundation License: Apache Software Foundation License 2.0 nUnit ------ +--------------------------------------------- Website: http://www.nunit.org/index.php Copyright: Copyright (c) 2002-2007 NUnit.org Portions Copyright (c) 2002-2008 Charlie Poole or Copyright (c) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov or Copyright (c) 2000-2002 Philip A. Craig @@ -192,26 +187,32 @@ License: Derived from zlib: http://nunit.org/index.php?p=license&r=2.4 Telerik MVC Extensions ------ +--------------------------------------------- Website: http://www.telerik.com/ License: GPL v3.0 TinyMCE ------ +--------------------------------------------- WebSite: http://tinymce.moxiecode.com/ Copyright: Copyright (c) 2003-2009 Moxiecode Systems AB License: LGPL 2.1 Twitter Bootstrap ------ +--------------------------------------------- Website: http://twitter.github.io/bootstrap/ License: Apache License v2.0 underscore.js ------ +--------------------------------------------- Website: http://underscorejs.org Copyright: Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors License: MIT + + +wkhtmltopdf +--------------------------------------------- +Website: http://wkhtmltopdf.org/ +License: LGPL diff --git a/LICENSE.txt b/LICENSE.txt index f166cc57b2..70566f2d0e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,502 +1,674 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - Preamble - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - This library is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + You should have received a copy of the GNU General Public License + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! \ No newline at end of file + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/README.md b/README.md index b2b4bbecc6..a7a83aee3a 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,32 @@ -# [SmartStore.NET](http://www.smartstore.com/net/en) +## Overview -SmartStore.NET is a free, open source, full-featured e-commerce solution for companies of any size. It is web standards compliant and incorporates the newest Microsoft web technology stack. +

+ SmartStore.NET Demoshop +

-**SmartStore.NET includes all essential features to create multilingual and multi-currency stores** targeting desktop or mobile devices and enabling SEO optimized rich product catalogs with support for an unlimited number of products and categories, variants, datasheets, ESD, discounts, coupons and many more. +SmartStore.NET is a free, open source, full-featured e-commerce solution for companies of any size. It is web standards compliant and incorporates the newest Microsoft web technology stack. -A comprehensive set of tools for CRM & CMS, sales, marketing, payment & shipping handling among others makes SmartStore.NET a powerful all-in-one solution fulfilling all your needs... totally FREE! +**SmartStore.NET includes all essential features to create multilingual and multi-currency stores** targeting desktop or mobile devices and enabling SEO optimized rich product catalogs with support for an unlimited number of products and categories, variants, bundles, datasheets, ESD, discounts, coupons and many more. -**SmartStore.NET delivers a beautiful and configurable shop frontend out-of-the-box** built with a design approach on the highest level, including components like Twitter Bootstrap, Less Css and others. The innovative ShopBar, a powerful layered navigation, reviews & ratings, an optimized (one-page) checkout process... they all provide a perfect shopping experience to your buyers. +A comprehensive set of tools for CRM & CMS, sales, marketing, payment & shipping handling, etc. makes SmartStore.NET a powerful all-in-one solution fulfilling all your needs... totally FREE! -The state-of-the-art architecture of SmartStore.NET - with ASP.NET 4.5 + MVC 5, Entity Framework 6 and Domain Driven Design approach - makes it easy to extend, extremely flexible and essentially fun to work with ;-) +**SmartStore.NET delivers a beautiful and configurable shop front-end out-of-the-box**, built with a design approach on the highest level, including components like `Twitter Bootstrap`, `Less CSS` and others. The innovative ShopBar, a powerful layered navigation, reviews & ratings, an optimized checkout process... they all provide a perfect shopping experience for your buyers. -* **Website:** [http://www.smartstore.com/net](http://www.smartstore.com/net) -* **Community:** [http://community.smartstore.com](http://community.smartstore.com) +The state-of-the-art architecture of SmartStore.NET - with `ASP.NET 4.5` + `MVC 5`, `Entity Framework 6` and Domain Driven Design approach - makes it easy to extend, extremely flexible and essentially fun to work with ;-) +* **Website:** [http://www.smartstore.com/en/net](http://www.smartstore.com/en/net) +* **Forum:** [http://community.smartstore.com](http://community.smartstore.com) +* **Marketplace:** [http://community.smartstore.com/marketplace](http://community.smartstore.com/marketplace) +* **Documentation:** [SmartStore.NET Documentation in English](http://docs.smartstore.com/display/SMNET/SmartStore.NET+Documentation+Home) ## Highlights ### Technology & Design -* State of the art architecture thanks to ASP.NET 4.5, ASP.NET MVC 5, Entity Framework 6 and Domain Driven Design +* State of the art architecture thanks to `ASP.NET 4.5`, `ASP.NET MVC 5`, `Entity Framework 6` and Domain Driven Design * Easy to extend and extremely flexible thanks to modular design -* Consistent and sophisticated use of modern components such as jQuery, Twitter Bootstrap, LESS & more in the frontend and backend. +* (NEW) A powerful theming engine lets you create themes & skins with minimum effort thanks to theme inheritance +* Consistent and sophisticated use of modern components such as `jQuery`, `Twitter Bootstrap`, `LESS` & more in the front and back end. * Easy shop management thanks to modern and clean UI * Out of the box shop design on the highest level * Revolutionary Shopbar for the best shopping experience @@ -30,8 +36,8 @@ The state-of-the-art architecture of SmartStore.NET - with ASP.NET 4.5 + MVC 5, * Multi-Store support * Unlimited number of products and categories -* (NEW) Product Bundles -* (NEW) RESTful WebApi +* Product Bundles +* RESTful WebApi * Multi-language support * 100% Mobile optimized * Perfectly optimized for search engines @@ -48,16 +54,19 @@ The state-of-the-art architecture of SmartStore.NET - with ASP.NET 4.5 + MVC 5, * and many more... ## Project Status -SmartStore.NET V2 has been released on April 04. 2014. The highlights are: +SmartStore.NET V2.5.0 has been released on March 03, 2016. The highlights are: + + * New import/export framework (profiles, filters, mapping, projections, scheduling, deployment... just everything!) + * TaskScheduler: Rewritten from scratch to be suitable for Web Farms (including support for cron expressions) + * Payment and shipping methods by customer roles + * Restrict payment methods to countries + * Restrict payment methods to shipping methods + * Email attachment support for message templates + * Attach order invoice PDF automatically to order notification emails + * Overall performance increase + * Lots of bug fixes + -* RESTful **WebApi** -* Highly optimized and **simplified product management** -* Product **Bundles** -* Considerably **faster app startup** and page processing -* New variant attribute type: **Linked Product** -* **Package upload** for plugins and themes -* Lightning **fast asynchronous Excel import** with progress indicators and detailed reports -* For developers: Code-based Entity Framework **database migrations** ##Try it online @@ -80,3 +89,8 @@ We have set up a live online demo for you so you are able to test SmartStore.NET * ASP.NET MVC 5 * MS SQL Server 2008 Express (or higher) OR MS SQL Server Compact 4 * Full Trust + + +## License + +SmartStore.NET is released under the [GPLv3 license](http://www.gnu.org/licenses/gpl-3.0.txt). diff --git a/SmartStoreNET.Tasks.Targets b/SmartStoreNET.Tasks.Targets index 317cce21ad..f184eaa7eb 100644 --- a/SmartStoreNET.Tasks.Targets +++ b/SmartStoreNET.Tasks.Targets @@ -2,7 +2,7 @@ - + @@ -44,7 +44,7 @@ x86 $(BUILD_NUMBER) - 2.0.2 + 2.6.0 $(StageFolder) .$(Version) @@ -114,7 +114,6 @@ - @@ -125,6 +124,9 @@ + + + diff --git a/assets/SmartStoreNET.png b/assets/SmartStoreNET.png new file mode 100644 index 0000000000..1fc5ca5409 Binary files /dev/null and b/assets/SmartStoreNET.png differ diff --git a/build.bat b/build.bat index e017b455af..b58175809a 100644 --- a/build.bat +++ b/build.bat @@ -1,21 +1,24 @@ -set MSBuildPath=%windir%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe +FOR %%b in ( + "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" + "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" + "%ProgramFiles%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" -@IF NOT EXIST %MSBuildPath% @ECHO COULDN'T FIND MSBUILD: %MSBuildPath% (Is .NET 4 installed?) -ELSE GOTO END + "%VS120COMNTOOLS%..\..\VC\vcvarsall.bat" + "%ProgramFiles(x86)%\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" + "%ProgramFiles%\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" + + "%VS110COMNTOOLS%..\..\VC\vcvarsall.bat" + "%ProgramFiles(x86)%\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" + "%ProgramFiles%\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" + ) do ( + if exist %%b ( + call %%b x86 + goto build + ) +) + +echo "Unable to detect suitable environment. Build may not succeed." -:CheckOS -IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT) +:build -:64BIT -echo 64-bit... -set MSBuildPath="%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild.exe" -GOTO END - -:32BIT -echo 32-bit... -set MSBuildPath="%ProgramFiles%\MSBuild\12.0\Bin\MSBuild.exe" -GOTO END - -:END - -%MSBuildPath% SmartStoreNET.proj /p:DebugSymbols=false /p:DebugType=None /P:SlnName=SmartStoreNET /maxcpucount %* \ No newline at end of file +msbuild SmartStoreNET.proj /p:DebugSymbols=false /p:DebugType=None /P:SlnName=SmartStoreNET /maxcpucount %* \ No newline at end of file diff --git a/changelog.md b/changelog.md index 7a64d0d8fd..0dac88a9fd 100644 --- a/changelog.md +++ b/changelog.md @@ -1,17 +1,407 @@ -#Release Notes# - -##SmartStore.NET 2.1# - -###New Features### -* (Developer) Overhauled plugin architecture: +# Release Notes + +## SmartStore.NET 2.6 + +### Highlights +* Major improvements in Importer & Exporter: better field mapping, higher performance, bug fixes etc. +* 'PayPal PLUS' payment plugin +* 'paydirekt' payment plugin +* 'Viveum' payment plugin +* 'BeezUP' export provider +* (Dev) Publishing SmartStore.Web from within Visual Studio now deploys the project correctly. No need to execute ClickToBuild.cmd anymore. Just publish directly to any target, including Azure. + +### New Features +* #961 Fix "Open Redirection Vulnerability" +* #571 Option to display another checkbox on confirm page to let the customer accept that his email address can be handed over to a third party +* #870 Implement address import for customers (both billing & shipping address) +* #886 Add setting to hide manufacturer images on product detail page and to hide default image for manufacturers +* Import localized SEO names for product and categories +* #477 Implement option to specify the number of exported and imported pictures +* #859 Make checkout attributes suitable for multi-stores +* Product details: Select attribute and gift card values by query string parameters +* #950 make contact form comply with current German law + +### Improvements +* Major improvements in Importer: better field mapping, higher performance, bug fixes etc. +* (Dev) Publishing SmartStore.Web from within Visual Studio now deploys the project correctly. No need to execute ClickToBuild.cmd anymore. Just publish directly to any target, including Azure. +* Localization & SEO: language switcher now takes language specific SEO slugs into account when building links +* Smarter import of plugin resource files with graceful fallbacks (de-DE > de > de-* > en-US > en > en-* > *) +* (Perf) Faster language resource file import +* Exports the product detail link including the attribute query string when exporting attribute combinations +* #918 Compare products: Display base price information +* Export email attachments needs to be stored in database because the temp file may not exist anymore when sending the email +* #913 Use HTML5 Input types (tel, email) +* Added paging to frontend order list +* Added paging to backend checkout attribute list +* #977 Show PAngV base/delivery amount also +* Updated LiveEngage LiveChat plugin + +### Bugfixes +* TaskScheduler could fail polling when primary store url is an external IP address +* Fixed ajax cache issue when saving payment or shipping restrictions. Internet Explorer showed the old data state (before storage). +* "The provider failed at the Execute method: Member 'CurrentValues' cannot be called for the entity of type 'Product'" when exporting product attribute combinations +* Bundles without selected attributes could throw an exception on product detail page +* GMC feed did not export the product type and Billiger did not export shop_cat (category path) +* The error message of a payment provider when capturing a payment was not displayed +* Adding new shipping method threw an exception +* Attribute Values: Assigning IsPreselected to more than one value causes an error +* BizImporter: fixed redirection bug when default file extension in .biz wasn't .html +* Fixed: Export deployment emails were always send manually +* Manually notifying gift card recipient threw an exception +* Loading shipping by weight grid failed under SQL CE +* #949 Import: ProcessSlugs does not process explicitly specified "SeName", if product name did not change in an update scenario +* Customer import: Creates customer role duplicates for inserted customers +* GMC feed does not generate the sale price if the sale price is set for a future date +* Mobile devices: Fixed "Uncaught Error: Syntax error, unrecognized expression: :nth-child" +* Download nor sample download were removable when editing product +* Copied product must not share sample download of source product. Could produce "The DELETE statement conflicted with the REFERENCE constraint 'FK_dbo.Product_dbo.Download_SampleDownloadId'". +* #921 Specification attribute options with single quotation marks are causing a Javascript error +* #971 Product is added to cart automatically if it has a non-required file upload attribute +* #973 Bundle item upload is nowhere linked +* Base price in product list ignored PriceDisplayType (catalog settings) and possibly displayed the wrong base price info +* Private messages: Fixes "No route in the route table matches the supplied values" +* Payone: Hash string incorrect for frontend API payments where the order has more than 9 products +* Export mail notification: Download link not working if SSL is enabled +* Discount rule has spent amount including sub total option can cause wrong discount calculation if the cart contains a product several times +* #986 File uploads possible through /content/filemanager/index.html + + +## SmartStore.NET 2.5 + +### Highlights + * New import/export framework (profiles, filters, mapping, projections, scheduling, deployment... just everything!) + * TaskScheduler: Rewritten from scratch to be suitable for Web Farms (including support for cron expressions) + * Payment and shipping methods by customer roles + * Restrict payment methods to countries + * Restrict payment methods to shipping methods + * Email attachment support for message templates + * Attach order invoice PDF automatically to order notification emails + * Overall performance increase + * Lots of bug fixes + +### New Features +* New export and import framework +* Import of customer and category data +* #141 Payment and shipping methods by customer roles +* #67 Restrict payment methods to countries +* #94 Restrict payment methods to shipping methods +* #747 Restrict payment methods by old versus new customer (plugin) +* #584 Email attachment support for message templates +* Attach order invoice PDF automatically to order notification emails +* #526 Min/Max amount option for which the payment method should be offered during checkout +* (Dev) New _SyncMapping_ service: enables easier entity synchronization with external systems +* (Dev) #792 ViewEngine: Enable vbhtml views per configuration +* (Dev) Plugin developers can now render child actions into a dynamically created special tab called 'Plugins' +* #718 ShopConnector: Import option for "Published" and "Disable buy\wishlist button" +* #702 Facebook and Twitter external authentication suitable for multi-stores +* New scheduled task: Clear e-mail queue +* New scheduled task: Clear uploadeded transient media files +* #704 Make primary store currency suitable for multi-stores +* #727 Web-API: Option to deactivate TimestampOlderThanLastRequest validation +* #731 Web-API: Allow deletion and inserting of product category and manufacturer assignments +* #733 Option to set a display order for homepage products +* #607 HTML capable full description for payment methods displayed in checkout +* #732 Product list: Option to display the pre-selected price instead of the lowest price +* New payment provider for Offline Payment Plugin: Purchase Order Number +* #202 Implement option for product list 'default sort order' +* #360 Import & export product variant combinations +* #722 System > SEO Names: Implement editing of an UrlRecord +* Admin > System > System Info shows used application memory (RAM) +* Added option to make VATIN mandatory during customer registration +* #840 Activity log: Have option to exclude search engine activity +* #841 Activity log for deleting an order +* More settings to control creation of SEO names +* GMC feed: Supporting fields multipack, bundle, adult, energy efficiency class and custom label (0 to 4) +* #760 Setting to set a customer role for new registered users +* #800 Multi-store: Option to display all orders of all stores for customer in frontend +* #457 Added option to hide the default image for categories and products +* #451 Add message token for product shipping surcharge +* #436 Make %Order.Product(s)% token to link the product detail page and a add product thumbnail +* #339 Meta robots setting for page indexing of search engines +* PayPal: Option for API security protocol +* Product filter: Option to sort filter results by their display order rather than by number of matches +* Elmar Shopinfo: Option to export delivery time as availability +* #654 Place user agreement for downloadable files in checkout process +* #398 EU law: add 'revocation' form and revocation waiver for ESD +* #738 Implement download of pictures via URLs in product import +* Web-API: Bridge to import framework: uploading import files to import profile directory +* Setting to round down calculated reward points +* #695 Implement checkbox in checkout to let customers subscribe to newsletters +* #495 Implement option to search product detail description by default + +### Improvements +* (Perf) Implemented static caches for URL aliases and localized properties. Increases app startup and request speed by up to 30%. +* (Perf) Significantly reduced number of database reads during product list rendering. Increases request speed by up to 10%. +* (Perf) Implemented 2nd level cache for infrequently changed entities. Increases request speed by up to 10%. +* TaskScheduler: Rewritten from scratch to be suitable for Web Farms +* TaskScheduler: Supports cron expressions to define task execution frequency +* TaskScheduler: Editing tasks does not require app restart anymore +* TaskScheduler: Enhanced UI +* #721 Message Queue: implemented "Delete all" +* #725 Prevent LowestProductPrice being 0 +* #709 News feed produced invalid RSS feed. Added content:encoded. Added maximum news age setting for feed export. +* #735 Include SKUs of attribute combinations when filtering the backend product list +* Filter for homepage and published\unpublished products in backend product list +* Reduce database round trips initiated by price calculation +* Google Analytics: added support for mobile devices +* (Dev) TaskScheduler: Tasks can propagate progress info (percentage & message) +* (Dev) TaskScheduler: Cancellation request is sent to tasks on app shutdown +* ShippingByWeight & ShippingByTotal: Support for multiple zip ranges (comma separated) +* Two more options to handle customer numbers: display customer number in frontend & let customers enter their customer number if it's still empty +* #62 free shipping info on product detail page +* Display base price in CompactProductBox +* Automatically redirect to referrer after login +* #826 Image gallery: the viewport height was fixed to 300 px, but now respects MediaSettings > ImageSize. +* #249 Make UI editor for 'SeoSettings.ExtraRobotsDisallows' +* Debitoor: Customer VAT number not transmitted anymore because it appears on the Debitoor invoice. +* #778 Web-API: Increase MaxExpansionDepth for using expand pathes +* #767 Remove assignments to a grouped product if the grouped product is deleted +* #773 Reduce number of guest records created by search engine requests +* #791 Preselected attributes or attribute combinations should always be appended as querystring to product page links +* Simplified handling of SEO names +* URLs are not converted to lower case anymore +* Product grid sortable by name, price and created on +* #26 Display company or name in order list +* Added inline editing of country grid +* #790 Improved language editing +* #843 Implement a product picker +* #850 Use new product picker for selecting required products +* Trusted Shops: badge will be displayed in mobile themes, payment info link replaced compare list link in footer +* Product filter: Specification attributes are sorted by display order rather than alphabetically by name +* #856 Don't route topics which are excluded from sitemap +* #851 Replace reCAPTCHA with "I'm not a robot" CAPTCHA +* #713 Display gift card remaining amount in frontend order details and order messages +* #736 Render PayPal Express Button in minibasket +* PayPal: Support for partial refunds +* Offline credit card payment: Option to exclude credit card types + +### Bugfixes +* #523 Redirecting to payment provider performed by core instead of plugin +* Preselected price was wrong for product attributes with multiple preselected values (same on product detail page) +* #749 Visual Studio 2015 compilation error: CS0009: Metadata file. SmartStore.Licensing.dll could not be opened -- Illegal tables in compressed metadata stream +* PayPal Express: fixed capture method +* #770 Resizing browser with product details page causes product image to disappear +* GMC feed: Availability value "available for order" deprecated +* Mobile: Shopping cart warnings weren't displayed to customers +* Tax provider and payment method were automatically activated when there were no active provider\method +* #784 Biz-Importer: Name of delivery time must not be imported empty +* #776 Preview: Manufacturer and Product in Multi Store +* #755 Some methods still loading all products in one go +* #796 Selected specification in product filter mask is displayed with default language (not localized) +* #805 Product filter is reset if 'product sorting' or 'view mode' or 'amount of displayed products per page' is changed +* Hide link to a topic page if it is limited to stores +* #829 Activity log: Searching by customer email out of function +* Product import: Store mappings were not applied when inserting new records +* Faulty permission handling in ajax grid actions (no message, infinite loading icon) +* Grouped products: Display order was not correct +* Deletion of a customer could delete all newsletter subscriptions +* PayPal: Fixed "The request was aborted: Could not create SSL/TLS secure channel." +* PayPal Express: Void and refund out of function ("The transaction id is not valid") +* Customer could not delete his avatar +* Facebook authentication: Email missing in verification +* Attribute with a product linkage throws exception if added to cart +* Number of products per product tag could be incorrect in a multi-store + + +## SmartStore.NET 2.2.2 + +### New Features +* SmartStore.NET User Guide +* #210 Implement multi-store support for import/export +* Added zip code to shipping by weight computation method +* Skrill payment plugin (distributed via Marketplace) +* (Dev) DevTool plugin: added option to display all widget zones in public store +* New options for manufacturer display on the homepage +* Added optional customer number field + +### Improvements +* (Perf) several minor optimizations for faster app startup and page rendering +* UI: optimized image gallery widget (white background & nicer animations) + enhanced modal dialog fade animations +* (Soft) deletion of SEO slug supporting entities now also deletes the corresponding url records +* License checker now supports IDN mapping for domain names +* #716 Supporting of paged google-product data query for SQL-Server Compact Edition +* #648 Add hint for * at mandatory form fields at address creation +* Added link to imprint and disclaimer to footer in mobile theme +* #521 Display bonus points in order export +* Updated GMC taxonomy files +* MsieJsEngine now is the default LESS script engine + +### Bugfixes +* #694 Product variant attribute in product page should not be preselected implicitly +* Fixed: If currencies are limited to one for a multi-store, this currency should dominate the setting for the primary store currency +* #563 Scheduled Tasks: ensure that 'LastEndUtc' is ALWAYS set +* Topics grid: fixed 'maxJsonLength exceeded' error +* Debitoor: Fixed "The property named 'lines.0.productOrService' should be defined" +* Send currency code of primary store currency (not of working currency) to payment gateway +* #691 Product quantity not added to cart on mobile theme +* #186 Mobile: variant images do not refresh +* #671 Bundle products: display base price according to applied discount +* #619 Display base price according to applied tier price +* #726 PAngV: basket displays wrong base price when attribute price adjustment has been set +* Weight adjustment of attributes weren't applied in shopping cart overview +* Shipping by weight calculates wrong surcharge if attribute combination prices are set +* Don't let database hooks call other hooks. +* There was no payment redirect if only one payment method is available in checkout + + +## SmartStore.NET 2.2.1 + +### New Features +* #582 GMC feed: Option to include\exclude a product +* #652 Web API: Support for file upload and multipart mime +* New option to display product thumbnails in instant search (NOTE: the feature can be enabled via _Configuration > Settings > Catalog Settings > Search_) +* #594 Option to prevent a message from being automatically sent +* Category filtering by store for backend category tree and list +* #554 Flag to indicate that a new payment notification (IPN) arrived for an order since last opening\editing of the order +* Setting whether and how to display sub-categories on a category page (hide, above products, bottom of page) +* Debitoor: Extend option "Book invoice if paid" to also (optionally) mail the invoice as a PDF +* #508 Limit country settings to stores +* #205 Add multistore support for forums + +### Improvements +* PDF converter: first init is much faster now +* Localized properties for forums and forum groups + +### Bugfixes +* PDF converter: fixed _QFont::setPixelSize_ bug +* Fixed System.NullReferenceException at admin/order/pdfpackagingslips +* #660 Don't show shipping cost hint in product detail page if product has free shipping + +## SmartStore.NET 2.2.0 + +### New Features +* New mobile theme: _MobileLight_ (a light variant of the default mobile theme) +* Localization: in a multi-language environment missing language resources fall back to default language's resources (instead of returning the ugly resource key) +* Quantity unit management +* #428 New option to override global category list view type +* #672 New option to automatically create mutual associations for cross sell and related products +* #485 Enable shop admin to change creation date of a blog entry +* #258 Implement email validation in checkout +* New option to specify the maximum number of displayed filter items +* New option to specify whether all filter groups should be displayed expanded +* #459 New field to specify html tag for page titles on widget level +* Added _shrink database_ to backend UI +* #588 Alternative localized category name used as title for category pages +* #592 Add a second category description displayed beyond products on category page +* Promotion feeds now export the preselected price (including price adjustments and overrides) +* Implement 'free shipping threshold' for feed creation +* _Billiger_ feed: Implement new field for shipping costs to austria +* (Developer) Added `BeginTransaction()` and `UseTransaction()` methods to `IDbContext` + +### Improvements +* (Perf) product list rendering up to 10x (!) faster now (depends on page size and view mode) +* The data grid in the backend now preserves client state between requests (page, pageSize, sorting, filtering etc.) +* Excel Import & Export: much lower memory consumption and increased performance +* Moving pictures from DB to FS or vice versa is lightning fast now, consumes much lower memory and is encapsulated in a transaction which ensures reliable rollback after failure. Plus the database gets automatically shrinked after moving to FS. +* Feed plugins: product query now paged to reduce memory payload +* #589 Backend product list: add filter for products with "no category mapping" and "no manufacturer mapping" +* Minor UI tweaks in checkout process +* Payone: CC-Check via client API, not via Server API (requires PCI certification) +* #189 Allow deletion of multiple reviews +* #622 UI: Redesign table in Sales > Orders > Order > Tab Products +* #625 Bundles can be ordered if an attribute combination of a bundle item is not available +* #666 Export addresses in customer export +* New shopping cart setting ShowItemsFromWishlistToCartButton +* XML product export now is paged and more data gets exported +* #560 Return requests: Add fields for last update, last update of requested action and general notes +* #626 Add `IsActive` flag for checkout attributes + +### Bugfixes +* Instant search box did not display all results when SQL Fulltext Search was enabled +* Print order as PDF redirected to login although the admin already was logged in +* #621 PDF Order: does not take overridden attribute combination price into account (in order line) +* _Amazon payments_: Declined authorization IPN did not void the payment status +* Fixed „Payment method couldn't be loaded“ when order amount is zero +* #598 Wrong input parameter name for ReturnRequestSubmit +* #557 Localize MVC validation strings +* Fixed rare bug "The length of the string exceeds the value set on the maxJsonLength property" (Controller: Order, Action: OrderNotesSelect) +* _Debitoor_: Adding order notes can result in infinite order update event loop with thousands of order notes +* Tax rates persisted on order item level to avoid rounding issues (required for Debitoor, Accarda and Payone) +* Hide additional shipping surcharge when display prices permission is not granted +* Fixed "Adding a relationship with an entity which is in the Deleted state is not allowed" when adding bundles to cart +* Fixed price calculation of multiple bundles issue +* Fixed auto add required products for bundle items +* Fixes #641: Protocol in sitemap should be HTTPS when `ForceSslForAllPages` is true +* #640 Do not display shipping infos for grouped products in product lists +* #634 Bundle price in list should not differ from price in details if there is only one bundle item with one attribute +* Do not copy associated product when copying a bundle product +* Null DeliveryTimeId when deleting products. Otherwise deleted products can prevent deletion of delivery times. +* Fixed: Product with inactive attribute combination could be moved to wishlist, copied to cart and be purchased +* Mobile Theme: Show prices according to selected variant value, display of deliverytime +* Bundles: Display base price according to Catalog Setting > Product Detail > Display Base Price + +## SmartStore.NET 2.1.1 + +### New Features +* Html to PDF converter: PDF documents are created from regular HTML templates now, therefore radically simplifying PDF output customization. +* Html widgets: added option to create a wrapper around widget content +* SEO: added new settings `Canonical host name rule`. Enforces permanent redirection to a single domain name for a better page rank (e.g. myshop.com > www.myshop.com or vice versa) +* SEO: added support for `` in multi-language stores. The tags are automatically rendered along with the language switcher. +* (Developer) Implemented new HtmlHelper extension `AddLinkPart`: registers `` tags which should be rendered in page's head section +* (Developer) Implemented new HtmlHelper extension `AddCustomHeadParts`: registers whatever head (meta) tag you wish +* (Developer) Added `SmartUrlRoutingModule`, which can pass static files to `UrlRoutingModule` if desired (e.g. used by MiniProfiler). This way static files can be handled by regular actions or filters, without polluting web.config. +* New payment plugin "Payone" +* Option to set a delivery time for products available for order with stock quantity < 1 +* Option to disable product reviews on product detail page +* Option to supress display of sub category picture links + +### Improvements +* (Perf) Faster application warmup +* (Perf) Faster product list rendering +* Reworked routing: removed static file security barrier again (caused too much problems) +* #545 Made all (applicable) settings multi-store-enabled +* #579 Make all relative urls absolute prior sending email +* The display order of attribute values are considered in the sorting of backend's attribute combination grid +* Optimized error handling and redesigned error pages +* Removed `PageNotFound` topic. Text is a simple locale resource now. +* PayPal settings are multi-store-enabled +* #555 Product edit: Improve category select box. Add history (last x selected items) above all others. +* #510 Payment plugins: Qualify configuration(s) for multistores +* #556 A negative value should be possible for additional payment fees +* Dashboard: Order items linked with order list +* Security: Missing http-only flag for some cookies set + +### Bugfixes +* PayPal Express: corrected basket transmission by eliminating tax transmission +* Fixed password recovery redirection +* #552 Left navbar should stay expanded on product detail pages +* #538 Specification attribute labels in product filter mask are not displayed localized +* #540 Amazon payments: Multistore configuration might be lost if "All stores" are left empty +* #532 Amazon payments: Reflect refunds made at amazon seller central when using data polling +* #577 Exception thrown because of missing TaxRate table when opening tax by region provider configuration +* Added IIS rewrite rule for `/productreviews/{id}` > `/product/reviews/{id}` +* Email a friend redirects to "not found" +* #567 Products marked as 'Featured' should also be included in regular lists +* Fixed some missing company information in order to PDF export +* #583 Fixed "The property rate with the value x is malformed" when creating products +* Fixed ignored discount and tier price when product has attribute combination price +* PayPal Standard provider now using shipping rather than billing address if shipping is required +* Amazon payments: Order wasn't found if the capturing\refunding took place at Amazon Seller Central and the notification came through IPN + + +## SmartStore.NET 2.1.0 + +### New Features +* (Developer) *Overhauled plugin architecture*: - Plugins are regular MVC areas now - No embedded views anymore. Views get copied to the deployment folder - No cumbersome return View("Very.Long.View.Identifier") anymore - Views in plugin source folders can be edited during debug. The changes are reflected without plugin recompilation. -* Added _CDN_ setting to store configuration. Allows static files to be served through a content delivery network, e.g. cloudfront. (contributed by 'normalc') +* (Developer) *Theme inheritance*: create derived child themes with minimum effort by overriding only small parts (static files and even variables). +* *Preview Mode*: virtually test themes and stores more easily +* New payment plugin *Pay with Amazon* +* Support for *hierarchical SEO slugs*, e.g.: samsung/galaxy/s5/16gb/white +* (Developer) Model binding for plugin tab views: models from plugin tabs get automatically materialized and bound to TabbableModel.CustomProperties[MyKey]. Extended the SmartModelBinder for this. +* (Developer) New event _ModelBoundEvent_. Consume this in plugins to persist plugin specific models. +* (Admin) Added _GMC_ tab to product edit view. This is more a coding example for the above stuff rather than a new feature. +* (Developer) Implemented _AdminThemedAttribute_: instructs the view engine to additionally search in the admin area for views. Very useful in larger plugin projects. +* (Developer) Enhanced _IMenuProvider_: menu items can now be injected to the public catalog menu * (Developer) Implemented _IWidgetProvider_. Allows request scoped registration of action routes to be injectable into widget zones. Perfect for custom action filters. * (Developer) Simple widgets: the model of the parent action view context now gets passed to a widget. * (Developer) New IoC method ContainerManager.InjectProperties() +* Implemented support for EU VAT regulation for digital goods (2008/8/EG directive) +* Implemented Media Manager for HTML editor (including file upload) +* Added _CDN_ setting to store configuration. Allows static files to be served through a content delivery network, e.g. cloudfront. (contributed by 'normalc') * #393 Web API: Implement OData actions for simpler working with product attributes * #431 Web API: Add support for localized properties * ShippingByWeight: new settings to configure a small quantity surcharge @@ -21,33 +411,60 @@ * #69 Award reward points for product reviews * #164 Add multistore support for polls * #170 Multistore support for Newsletters - -###Improvements### +* #266 Update Pending Order in Admin Panel +* #331 Show CommentBox in checkout (optional) +* Option to turn off the filter for products in categories +* Export/Import was enabeled to work with localized values for name, short description and long description +* Added two new themes 'Alpha Blue' and 'Alpha Black' + +### Improvements +* New backend design and cleaner frontend theme +* Replaced TinyMCE HTML editor with CKeditor +* Simplified checkout process by combining payment method and info pages +* (Perf) Lower memory consumption +* (Perf) (Developer) Client Dependency updates + - jQuery 1.8.3 > 2.1.1 (although the backend is still using v1.8.3 because of the Telerik components) + - FontAwesome 3 > 4.1 + - Modernizr 2.5 > 2.7.2 + - jQuery UI to 1.11 + - SearchBox uses Typeahead now instead of jQuery UI AutoComplete + - Got rid of obsolete jQuery UI files (will remove this later completely) +* (UI) AJAXified product edit tab: all tabs other than the first one load on demand per AJAX +* (Developer) Plugins can provide custom tabs more easily (now with on demand AJAX loading) * Task Scheduler: - Can run tasks manually now (async) - Better UI - Shows last error - (Developer) Breaking change: New parameter _TaskExecutionContext_ for _ITask.Execute()_ * UI: TabStrips remember their last selected tab across page requests in an unobtrusive way (removed old selection code) -* TinyMCE 4: activated spell checking, added FontSelect and FontSizeSelect tools to the toolbar * Price formatting: the DisplayLocale's FormatProvider was not applied when _CustomFormatting_ was specified for Currency * Admin: Specification attributes are now sorted by DisplayOrder, THEN BY Name -* Perf: significantly increased excel import performance... again ;-) -* Perf: significantly increased excel export performance +* Admin: Replaced DatePicker with DateTimePicker control +* (Perf) significantly increased excel import performance... again ;-) +* (Perf) significantly increased excel export performance and optimized memory usage +* (Perf) SEO sitemap is being cached now, resulting in fast reponse times with larger catalogs +* (UI) optimized and reorganized product edit view a bit * (Developer) MVC filter attributes are now Autofac injectable * (Developer) Implemented _RunSync_ extension methods for _Func_ and _Func>_. A reliable way to execute async operations synchronously. * (Developer) Refactored model creation for category navigation: it now incorporates _TreeNode_, which enables plugin developers to alter the main menu with the event hook _NavigationModelBuilt_. * (Developer) Added _user.less_ to Alpha theme for user defined css overrides and tweaks * (Developer) Moved _PublicControllerBase_ to SmartStore.Web.Framework * (Developer) Moved 'AdminControllerBase' to SmartStore.Web.Framework +* (Developer) Optimized Bundle handling + - Html.Add[Script|CssFile]Parts() now can handle already bundled resources correctly (no attempt is made to bundle them, the bundle's virtual url is returned instead) + - Made extra bundles for frequently used resources (like sequence js, fileupload, image gallery etc.). This way they always come compressed. * #384 Web API: Inserting sluged recources like products require an URL record * #382 Promotion feed plugins: Asynchronous feed creation, more options and improvements * #433 GMC feed: Option to filter config records that have not been edited * #362 Display 'from {0}' for products with variant attributes * #239 Categories: Ask merchant if he want a cascading or a non cascading deletion * HTML text collapser: Make it usable for all long texts +* #375 Implement SKU search for 'related products picker' +* #391 Admin: allow searching/filtering for specification attributes +* Removed _OpenID_ plugin from core +* Specification attribute values that are assigned to a product can be edited -###Bugfixes### +### Bugfixes * Twitter Auth: fixed _SecurityTransparent_ error * Facebook Auth: fixed _SecurityTransparent_ error * OpenID Auth: fixed _SecurityTransparent_ error @@ -67,11 +484,22 @@ * Paging of return request grid did not work * #428 Multiline checkout attributes aren't rendered correctly * #434 Shipping.ByTotal: Make grid pageable - - -##SmartStore.NET 2.0.2# - -###Bugfixes### +* #419 email account password hidden +* #424 Localize return reasons & return actions +* #479 Product filter: Wrong count of manufacturers if products of sub-categories are included +* #492 Ipayment credit card: Order notes are only created when the order exists +* #493 Postfinance plugin does not work if shopname includes a "umlaut" +* #237 Mobile theme: inactive attribute combinations should not be added to cart +* #178 Mobile theme doesn't display base price +* Ipayment: Capturing did not work because the security was not transmitted +* #405 "Reset Password" Link in Emails is wrong with SSL secured sites +* #471 Checkout: Redirecting to external payment page could take a while. Clicking "Buy" button again might cancel the redirecting. +* Pricing not considered attribute combination prices for bundles with per item pricing + + +## SmartStore.NET 2.0.2 + +### Bugfixes * IMPORTANT FIX: Memory leak leads to _OutOfMemoryException_ in application after a while * Installation fix: some varchar(MAX) columns get created as varchar(4000). Added a migration to fix the column specs. * Installation fix: Setup fails with exception _Value cannot be null. Parameter name: stream_ @@ -86,18 +514,18 @@ * Fixed "Controller does not implement IController" (concerning plugin controllers) * #361 Wrong delivery time in order confirmation -###Improvements### +### Improvements * #250 Implemented validation to theme configuration editing -##SmartStore.NET 2.0.1## +## SmartStore.NET 2.0.1 -###New Features### +### New Features * #292 Allow specific price for attribute combinations * Added image upload support to Summernote editor * (Developer) Added WebApi client test tools to the solution (C# and JavaScript) -###Improvements### +### Improvements * Content slider slides can be filtered by store * TinyMCE now shows advanced tab for images * Updated BundleTransformer to the latest version 1.8.25 @@ -105,14 +533,14 @@ * Updated some 3rd party libraries to their latest versions * #320 Unavailable attribute combinations: better UI indication -###Bugfixes### +### Bugfixes * UI notifications get displayed repeatedly * (Developer) Fixed Razor intellisense for plugin projects (NOTE: switch to 'PluginDev' configuration while editing plugin views, switch back when finished) -##SmartStore.NET 2.0.0# +## SmartStore.NET 2.0.0 -###Highlights### +### Highlights * RESTFul **WebApi** * Highly optimized and **simplified product management** * Product **Bundles** @@ -122,7 +550,7 @@ * Lightning **fast asynchronous Excel import** with progress indicators and detailed reports * (Developer) Code-based Entity Framework database **migrations** -###New Features### +### New Features * [RESTFul WebApi](https://smartstore.codeplex.com/wikipage?title=Web%20API) * Product Bundles: create configurable product kits by combining products * Package upload for plugins and themes @@ -143,7 +571,7 @@ * (Developer) New interface _IWidget_ for simplified widget development and multi-widgets per plugin * (Developer) Outsourced notifications from MVC controller and implemented _INotifier_ for more centralized approach -###Improvements### +### Improvements * Highly optimized and simplified product management * Considerably faster app startup and page processing * Lightning fast asynchronous Excel import with progress indicators and detailed reports @@ -178,7 +606,7 @@ * * Updated all dependant libraries to their latest versions * (Developer) Implemented _PaymentMethodBase_ abstract class to simplify payment plugin development -###Bugfixes### +### Bugfixes * #150 GTB & disclaimer aren't readable when they become to long * #151 NewsletterSubscriptionDeactivationUrl-Token doesn't get repleaced * #153 Admin->Contentslider throws an error when asigned languages aren't available anymore @@ -201,9 +629,9 @@ -##SmartStore.NET 1.2.1.0# +## SmartStore.NET 1.2.1.0 -###New Features### +### New Features * Added option *Limit to current basket subtotal* to _HadSpentAmount_ discount rule * Items in product lists can be labelled as _NEW_ for a configurable period of time * Product templates can optionally display a _discount sign_ when discounts were applied @@ -212,7 +640,7 @@ * Added a field for the HTML body id to store entity * (Developer) New property 'ExtraData' for DiscountRequirement entity -###Bugfixes### +### Bugfixes * #110: PictureService.GetThumbLocalPath doesn't add picture to cache if it doesn't exist (this broke PDFService among others) * #114: Runtime error occurs after new customer registration in the storefront * #115: XML exports could fail because of invalid characters @@ -223,7 +651,7 @@ * #134: Fix mobile checkout * #111: Send wishlist via e-mail doesn't work -###Improvements### +### Improvements * #97: Product numbers of attribute combinations could not be searched * #120: Excel product import: The same product pictures were imported repeatedly which led to duplicate pictures. * Updated _FontAwesome_ to version 3.2.1 @@ -232,16 +660,16 @@ * Better display and handling when choosing a flag for languages -##SmartStore.NET 1.2.0.0# +## SmartStore.NET 1.2.0.0 -###Highlights### +### Highlights - Multi-store support - "Trusted Shops" plugins - Highly improved _SmartStore.biz Importer_ plugin - Add custom HTML content to pages - Performance optimization -###New Features### +### New Features - **Multi-store-support:** now multiple stores can be managed within a single application instance (e.g. for building different catalogs, brands, landing pages etc.) - Added 3 new **Trusted Shops** plugins: Seal, Buyer Protection, Store Reviews - Added **Display as HTML Widget** to CMS Topics (store owner now can add arbitrary HTML content to any page region without modifying view files) @@ -258,7 +686,7 @@ - (Developer) **Localizable views:** the view engine now is able to resolve localized (physical) view files (by appending the language seo code to a view file name in the same folder, e.g. 'en' or 'de'). The engine first tries to detect a view file with the matching language suffix, then falls back to the default one. - (Developer) Added new interface __IPreApplicationStart__ allowing plugins to register HttpModules very early in the app bootstrap stage -###Improvements### +### Improvements - Minor improvements for _SOFORT Überweisung_ plugin - ContentSlider: updated 'sequence js' to most recent version and optimized html & css code - Content slider: the background slide behaviour is configurable now (NoSlide, Slide, SlideOpposite) @@ -276,7 +704,7 @@ - (Developer) Added 'bodyOnly' parameter to TopicBlock ChildAction - (Developer) HtmlHelper __SmartLabelFor__ now renders the model property name by default (instead of the _SmartResourceDisplayName_ resource key) -###Bugfixes### +### Bugfixes - bunch of fixes and improvements for the _SmartStore.biz Importer_ plugin - The feed for "Leguide.com" plugin did not work in Germany - Fixed minor issues in _shipping-by-weight_ plugin @@ -291,9 +719,9 @@ -##SmartStore.NET 1.0.1.0## +## SmartStore.NET 1.0.1.0 -###Bug### +### Bug * [SMNET-1] - Die Anzahl der eingetragenen Mengen bei Varianten wird nicht richtig im Warenkorb übernommen. * [SMNET-5] - Fehler beim Hochladen von Bildern im IE @@ -321,7 +749,7 @@ * [SMNET-199] - CategoryNavigationModel: Children von inaktiven Warengruppen müssen in Navigationsleisten ignoriert werden * [SMNET-202] - SmartTabSelection mit verschachtelten Tabs fehlerhaft nach Reload einer Seite -###Improvement### +### Improvement * [SMNET-13] - Attributwerte: der Text "Aufpreis" muss um "Minderpreis" erweitert werden. * [SMNET-15] - Umgestaltung der Darstellung der Staffelpreise (Popover ab dem fünften Element) @@ -346,7 +774,7 @@ * [SMNET-180] - Leichten Border und Verlauf in Lieferzeit-Indikator eingebaut * [SMNET-188] - Lokalisierung: IsDirty-Flag und Option "Nur neue anfügen" -###New Feature### +### New Feature * [SMNET-14] - Brutto/Netto Preisanzeige über Kundengruppen steuerbar diff --git a/how-to-build.txt b/how-to-build.txt index 102f51f3d9..7d0456ae8a 100644 --- a/how-to-build.txt +++ b/how-to-build.txt @@ -1,15 +1,14 @@ -Manually: -1. SmartStore.Web and SmartStore.Admin are two web applications. They both need to be published to the same directory. - SmartStore.Web to Published\Web\. SmartStore.Admin to Published\Web\Administration\. Make sure the .dlls - from SmartStore.Admin (Published\Web\Administration\bin\) are moved and exist in (Published\Web\bin\). -2. Ensure that plugins (\Presentation\SmartStore.Web\Plugins) are copied into \Published\Web\Plugins\ directory -3. Select all the files in Published\Web\ directory and upload them to your web server. +HOW TO BUILD: +============= +SmartStore.NET package with source code contains the "ClickToBuild.cmd" batch file, which will deploy everything correctly for you +to a "Stage" folder. The build process will build the project in release mode and move all +compiled and deployable files to the correct directory: "build/Web" -Automatic: -1. SmartStore.NET package with source code contains the "ClickToBuild.cmd" batch file, which will deploy everything correctly for you - to a "Stage" folder. The build process will build the project in release mode and move all - compiled and deployable files to the correct directory. - Note: Before running the file make sure you built the project in Visual Studio. -2. Select all the files in "build\Web" directory and upload them to your web server. - Note: If you're getting an error, try to compile the solution in Visual Studio before running the .bat file \ No newline at end of file +SmartStore.NET source code distribution does NOT contain the NuGet packages required to succesfully build the solution. +Instead these packages are downloaded during the very first compilation. Thus, when your initial build attempt fails, +this could indicate that the packages could not be downloaded completely yet. In this case, just build again! +If you're still getting errors, try to compile the solution in Visual Studio 2013 before running the .bat file, but +before make sure that 'SmartStore.Web' is set as your startup project. + +After a successful build, select all the files in the "build\Web" directory and upload them to your web server. \ No newline at end of file diff --git a/lib/SmartStore.Licensing/SmartStore.Licensing.dll b/lib/SmartStore.Licensing/SmartStore.Licensing.dll new file mode 100644 index 0000000000..8acdf39c24 Binary files /dev/null and b/lib/SmartStore.Licensing/SmartStore.Licensing.dll differ diff --git a/lib/Telerik/Telerik.Web.Mvc.dll b/lib/Telerik/Telerik.Web.Mvc.dll new file mode 100644 index 0000000000..2d2710051c Binary files /dev/null and b/lib/Telerik/Telerik.Web.Mvc.dll differ diff --git a/src/.nuget/NuGet.exe b/src/.nuget/NuGet.exe index 8f61340295..c41a0d0deb 100644 Binary files a/src/.nuget/NuGet.exe and b/src/.nuget/NuGet.exe differ diff --git a/src/AssemblySharedInfo.cs b/src/AssemblySharedInfo.cs index 8fd027386d..79225de4c7 100644 --- a/src/AssemblySharedInfo.cs +++ b/src/AssemblySharedInfo.cs @@ -1,6 +1,4 @@ using System.Reflection; -using System.Runtime.InteropServices; -using System.Security; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -9,6 +7,6 @@ [assembly: AssemblyDescription("SmartStore.NET")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("SmartStore AG")] -[assembly: AssemblyCopyright("Copyright © SmartStore AG 2014")] +[assembly: AssemblyCopyright("Copyright © SmartStore AG 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/src/AssemblyVersionInfo.cs b/src/AssemblyVersionInfo.cs index 3b7ecad06e..f74f0edf78 100644 --- a/src/AssemblyVersionInfo.cs +++ b/src/AssemblyVersionInfo.cs @@ -9,7 +9,7 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.0.0")] +[assembly: AssemblyVersion("2.6.0.0")] -[assembly: AssemblyFileVersion("2.0.0.0")] -[assembly: AssemblyInformationalVersion("2.0.2.0")] +[assembly: AssemblyFileVersion("2.6.0.0")] +[assembly: AssemblyInformationalVersion("2.6.0.0")] diff --git a/src/Libraries/SmartStore.Core/Async/AsyncExtensions.cs b/src/Libraries/SmartStore.Core/Async/AsyncExtensions.cs deleted file mode 100644 index 22aa775edb..0000000000 --- a/src/Libraries/SmartStore.Core/Async/AsyncExtensions.cs +++ /dev/null @@ -1,143 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace SmartStore.Core.Async -{ - - public static class AsyncExtensions - { - - /// - /// Execute's an async Task{T} method which has a void return value synchronously - /// - /// Task{T} method to execute - public static void RunSync(this Func task) - { - Guard.ArgumentNotNull(() => task); - - var oldContext = SynchronizationContext.Current; - var synch = new ExclusiveSynchronizationContext(); - SynchronizationContext.SetSynchronizationContext(synch); - synch.Post(async _ => - { - try - { - await task(); - } - catch (Exception e) - { - synch.InnerException = e; - throw; - } - finally - { - synch.EndMessageLoop(); - } - }, null); - synch.BeginMessageLoop(); - - SynchronizationContext.SetSynchronizationContext(oldContext); - } - - /// - /// Execute's an async Task{T} method which has a T return type synchronously - /// - /// Return Type - /// Task{T} method to execute - /// - public static T RunSync(this Func> task) - { - Guard.ArgumentNotNull(() => task); - - var oldContext = SynchronizationContext.Current; - var synch = new ExclusiveSynchronizationContext(); - SynchronizationContext.SetSynchronizationContext(synch); - T ret = default(T); - synch.Post(async _ => - { - try - { - ret = await task(); - } - catch (Exception e) - { - synch.InnerException = e; - throw; - } - finally - { - synch.EndMessageLoop(); - } - }, null); - synch.BeginMessageLoop(); - - SynchronizationContext.SetSynchronizationContext(oldContext); - return ret; - } - - private class ExclusiveSynchronizationContext : SynchronizationContext - { - private bool done; - public Exception InnerException { get; set; } - readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); - readonly Queue> items = - new Queue>(); - - public override void Send(SendOrPostCallback d, object state) - { - throw new NotSupportedException("We cannot send to our same thread"); - } - - public override void Post(SendOrPostCallback d, object state) - { - lock (items) - { - items.Enqueue(Tuple.Create(d, state)); - } - workItemsWaiting.Set(); - } - - public void EndMessageLoop() - { - Post(_ => done = true, null); - } - - public void BeginMessageLoop() - { - while (!done) - { - Tuple task = null; - lock (items) - { - if (items.Count > 0) - { - task = items.Dequeue(); - } - } - if (task != null) - { - task.Item1(task.Item2); - if (InnerException != null) // the method threw an exeption - { - throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); - } - } - else - { - workItemsWaiting.WaitOne(); - } - } - } - - public override SynchronizationContext CreateCopy() - { - return this; - } - } - } - -} diff --git a/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs b/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs index d1c84eebeb..b02ea8dd58 100644 --- a/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs +++ b/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs @@ -1,73 +1,372 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using System.Web.Hosting; using Autofac; using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; namespace SmartStore.Core.Async { public static class AsyncRunner { + private static readonly BackgroundWorkHost _host = new BackgroundWorkHost(); - public static Task Run(Action action) + /// + /// Gets the global cancellation token which signals the application shutdown + /// + public static CancellationToken AppShutdownCancellationToken + { + get { return _host.ShutdownCancellationTokenSource.Token; } + } + + /// + /// Executes an async Task method which has a void return value synchronously + /// + /// Task method to execute + public static void RunSync(Func func) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + synch.Post(async _ => + { + try + { + await func(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + + SynchronizationContext.SetSynchronizationContext(oldContext); + } + + /// + /// Executes an async Task method which has a TResult return type synchronously + /// + /// Return Type + /// Task method to execute + /// + public static TResult RunSync(Func> func) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + TResult ret = default(TResult); + synch.Post(async _ => + { + try + { + ret = await func(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + SynchronizationContext.SetSynchronizationContext(oldContext); + return ret; + } + + public static Task Run(Action action) { return Run(action, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); } - public static Task Run(Action action, CancellationToken cancellationToken) + public static Task Run(Action action, CancellationToken cancellationToken) { return Run(action, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); } - public static Task Run(Action action, TaskCreationOptions options) + public static Task Run(Action action, TaskCreationOptions options) { return Run(action, CancellationToken.None, options, TaskScheduler.Default); } - public static Task Run(Action action, CancellationToken cancellationToken, TaskCreationOptions options) + public static Task Run(Action action, CancellationToken cancellationToken, TaskCreationOptions options) { return Run(action, cancellationToken, options, TaskScheduler.Default); } - public static Task Run(Action action, TaskScheduler scheduler) + public static Task Run(Action action, TaskScheduler scheduler) { return Run(action, CancellationToken.None, TaskCreationOptions.None, scheduler); } - - public static Task Run(Action action, CancellationToken cancellationToken, TaskCreationOptions options, TaskScheduler scheduler) + + public static Task Run(Action action, CancellationToken cancellationToken, TaskCreationOptions options, TaskScheduler scheduler) { Guard.ArgumentNotNull(() => action); Guard.ArgumentNotNull(() => scheduler); + var ct = _host.CreateCompositeCancellationTokenSource(cancellationToken).Token; + options |= TaskCreationOptions.LongRunning; // enforce an exclusive thread (not from pool) + var t = Task.Factory.StartNew(() => { - using (var container = EngineContext.Current.ContainerManager.Container.BeginLifetimeScope(AutofacLifetimeScopeProvider.HttpRequestTag)) + var accessor = EngineContext.Current.ContainerManager.ScopeAccessor; + using (accessor.BeginContextAwareScope()) { - action(container); + action(accessor.GetLifetimeScope(null), ct); } - }, cancellationToken, options, scheduler); + }, ct, options, scheduler); + + _host.Register(t, ct); return t; } - public static Task Run(Action action, object state, CancellationToken cancellationToken, TaskCreationOptions options, TaskScheduler scheduler) + public static Task Run(Action action, object state, CancellationToken cancellationToken, TaskCreationOptions options, TaskScheduler scheduler) { Guard.ArgumentNotNull(() => state); Guard.ArgumentNotNull(() => action); Guard.ArgumentNotNull(() => scheduler); + var ct = _host.CreateCompositeCancellationTokenSource(cancellationToken).Token; + options |= TaskCreationOptions.LongRunning; // enforce an exclusive thread (not from pool) + var t = Task.Factory.StartNew((o) => { - using (var container = EngineContext.Current.ContainerManager.Container.BeginLifetimeScope(AutofacLifetimeScopeProvider.HttpRequestTag)) + var accessor = EngineContext.Current.ContainerManager.ScopeAccessor; + using (accessor.BeginContextAwareScope()) { - action(container, o); + action(accessor.GetLifetimeScope(null), ct, o); } - }, state, cancellationToken, options, scheduler); + }, state, ct, options, scheduler); + + _host.Register(t, ct); return t; } + + + public static Task Run(Func function) + { + return Run(function, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + public static Task Run(Func function, CancellationToken cancellationToken) + { + return Run(function, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); + } + + public static Task Run(Func function, TaskCreationOptions options) + { + return Run(function, CancellationToken.None, options, TaskScheduler.Default); + } + + public static Task Run(Func function, CancellationToken cancellationToken, TaskCreationOptions options) + { + return Run(function, cancellationToken, options, TaskScheduler.Default); + } + + public static Task Run(Func function, TaskScheduler scheduler) + { + return Run(function, CancellationToken.None, TaskCreationOptions.None, scheduler); + } + + public static Task Run(Func function, CancellationToken cancellationToken, TaskCreationOptions options, TaskScheduler scheduler) + { + Guard.ArgumentNotNull(() => function); + Guard.ArgumentNotNull(() => scheduler); + + var ct = _host.CreateCompositeCancellationTokenSource(cancellationToken).Token; + options |= TaskCreationOptions.LongRunning; // enforce an exclusive thread (not from pool) + + var t = Task.Factory.StartNew(() => + { + var accessor = EngineContext.Current.ContainerManager.ScopeAccessor; + using (accessor.BeginContextAwareScope()) + { + return function(accessor.GetLifetimeScope(null), ct); + } + }, ct, options, scheduler); + + _host.Register(t, ct); + + return t; + } + + public static Task Run(Func function, object state, CancellationToken cancellationToken, TaskCreationOptions options, TaskScheduler scheduler) + { + Guard.ArgumentNotNull(() => state); + Guard.ArgumentNotNull(() => function); + Guard.ArgumentNotNull(() => scheduler); + + var ct = _host.CreateCompositeCancellationTokenSource(cancellationToken).Token; + options |= TaskCreationOptions.LongRunning; // enforce an exclusive thread (not from pool) + + var t = Task.Factory.StartNew((o) => + { + var accessor = EngineContext.Current.ContainerManager.ScopeAccessor; + using (accessor.BeginContextAwareScope()) + { + return function(accessor.GetLifetimeScope(null), ct, o); + } + }, state, ct, options, scheduler); + + _host.Register(t, ct); + + return t; + } + + + private class ExclusiveSynchronizationContext : SynchronizationContext + { + private bool _done; + readonly AutoResetEvent _workItemsWaiting = new AutoResetEvent(false); + readonly Queue> _items = new Queue>(); + + public Exception InnerException { get; set; } + + public override void Send(SendOrPostCallback d, object state) + { + throw new NotSupportedException("We cannot send to the same thread"); + } + + public override void Post(SendOrPostCallback d, object state) + { + lock (_items) + { + _items.Enqueue(Tuple.Create(d, state)); + } + _workItemsWaiting.Set(); + } + + public void EndMessageLoop() + { + Post(_ => _done = true, null); + } + + public void BeginMessageLoop() + { + while (!_done) + { + Tuple task = null; + lock (_items) + { + if (_items.Count > 0) + { + task = _items.Dequeue(); + } + } + if (task != null) + { + task.Item1(task.Item2); + if (InnerException != null) // the method threw an exeption + { + throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); + } + } + else + { + _workItemsWaiting.WaitOne(); + } + } + } + + public override SynchronizationContext CreateCopy() + { + return this; + } + } + + } + + internal class BackgroundWorkHost : IRegisteredObject + { + private readonly CancellationTokenSource _shutdownCancellationTokenSource = new CancellationTokenSource(); + private int _numRunningWorkItems; + + public BackgroundWorkHost() + { + HostingEnvironment.RegisterObject(this); + } + + public CancellationTokenSource ShutdownCancellationTokenSource + { + get { return _shutdownCancellationTokenSource; } + } + + public void Stop(bool immediate) + { + int num; + lock (this) + { + _shutdownCancellationTokenSource.Cancel(); + num = _numRunningWorkItems; + } + if (num == 0) + { + FinalShutdown(); + } + } + + public CancellationTokenSource CreateCompositeCancellationTokenSource(CancellationToken userCancellationToken) + { + if (userCancellationToken == CancellationToken.None) + { + return _shutdownCancellationTokenSource; + } + return CancellationTokenSource.CreateLinkedTokenSource(_shutdownCancellationTokenSource.Token, userCancellationToken); + } + + public void Register(Task work, CancellationToken cancellationToken) + { + if (!cancellationToken.IsCancellationRequested) + { + lock (this) + { + if (cancellationToken.IsCancellationRequested) + { + return; + } + _numRunningWorkItems++; + } + + work.ContinueWith( + WorkItemComplete, + CancellationToken.None, + TaskContinuationOptions.ExecuteSynchronously, + TaskScheduler.Default); + } + } + + private void WorkItemComplete(Task work) + { + int num; + bool isCancellationRequested; + lock (this) + { + num = --_numRunningWorkItems; + isCancellationRequested = _shutdownCancellationTokenSource.IsCancellationRequested; + } + if (num == 0 && isCancellationRequested) + { + FinalShutdown(); + } + } + + private void FinalShutdown() + { + HostingEnvironment.UnregisterObject(this); + } + } } diff --git a/src/Libraries/SmartStore.Core/Async/AsyncState.cs b/src/Libraries/SmartStore.Core/Async/AsyncState.cs index 2a4fb4a1d9..ce99542612 100644 --- a/src/Libraries/SmartStore.Core/Async/AsyncState.cs +++ b/src/Libraries/SmartStore.Core/Async/AsyncState.cs @@ -1,9 +1,6 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Runtime.Caching; -using System.Text; using System.Threading; namespace SmartStore.Core.Async @@ -11,8 +8,8 @@ namespace SmartStore.Core.Async public class AsyncState { - private readonly static AsyncState s_instance = new AsyncState(); - private readonly MemoryCache _cache = MemoryCache.Default; + private static readonly AsyncState s_instance = new AsyncState(); + private readonly MemoryCache _cache = new MemoryCache("SmartStore.AsyncState"); private AsyncState() { @@ -35,6 +32,22 @@ public T Get(string name = null) return Get(out cancelTokenSource, name); } + public IEnumerable GetAll() + { + var keyPrefix = BuildKey(null); + foreach (var kvp in _cache) + { + if (kvp.Key.StartsWith(keyPrefix)) + { + var value = kvp.Value as StateInfo; + if (value != null && value.Progress != null) + { + yield return (T)value.Progress; + } + } + } + } + public CancellationTokenSource GetCancelTokenSource(string name = null) { CancellationTokenSource cancelTokenSource; @@ -46,13 +59,13 @@ private T Get(out CancellationTokenSource cancelTokenSource, string name = nu { cancelTokenSource = null; var key = BuildKey(name); - + var value = _cache.Get(key) as StateInfo; if (value != null) { cancelTokenSource = value.CancellationTokenSource; - return (T)(value.Progress); + return (T)value.Progress; } return default(T); @@ -60,14 +73,32 @@ private T Get(out CancellationTokenSource cancelTokenSource, string name = nu public void Set(T state, string name = null, bool neverExpires = false) { - this.Set(state, null, name, neverExpires); + Guard.ArgumentNotNull(() => state); + Set(state, null, name, neverExpires); + } + + public void Update(Action update, string name = null) + { + Guard.ArgumentNotNull(() => update); + + var key = BuildKey(typeof(T), name); + + var value = _cache.Get(key) as StateInfo; + if (value != null) + { + var state = (T)value.Progress; + if (state != null) + { + update(state); + } + } } public void SetCancelTokenSource(CancellationTokenSource cancelTokenSource, string name = null) { Guard.ArgumentNotNull(() => cancelTokenSource); - this.Set(default(T), cancelTokenSource, name); + Set(default(T), cancelTokenSource, name); } private void Set(T state, CancellationTokenSource cancelTokenSource, string name = null, bool neverExpires = false) @@ -79,7 +110,10 @@ private void Set(T state, CancellationTokenSource cancelTokenSource, string n if (value != null) { // exists already, so update - value.Progress = state; + if (state != null) + { + value.Progress = state; + } if (cancelTokenSource != null && value.CancellationTokenSource == null) { value.CancellationTokenSource = cancelTokenSource; @@ -88,7 +122,10 @@ private void Set(T state, CancellationTokenSource cancelTokenSource, string n var policy = new CacheItemPolicy { SlidingExpiration = neverExpires ? TimeSpan.Zero : TimeSpan.FromMinutes(15) }; - _cache.Set(key, value ?? new StateInfo { Progress = state, CancellationTokenSource = cancelTokenSource }, policy); + _cache.Set( + key, + value ?? new StateInfo { Progress = state, CancellationTokenSource = cancelTokenSource }, + policy); } public bool Remove(string name = null) diff --git a/src/Libraries/SmartStore.Core/BaseEntity.cs b/src/Libraries/SmartStore.Core/BaseEntity.cs index f41a4f97c1..0c90dc9a9a 100644 --- a/src/Libraries/SmartStore.Core/BaseEntity.cs +++ b/src/Libraries/SmartStore.Core/BaseEntity.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.Serialization; @@ -12,24 +13,16 @@ namespace SmartStore.Core /// [DataContract] public abstract partial class BaseEntity - { - /// + { + /// /// Gets or sets the entity identifier /// - [DataMember, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [DataMember] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } - public override bool Equals(object obj) - { - return Equals(obj as BaseEntity); - } - - private static bool IsTransient(BaseEntity obj) - { - return obj != null && Equals(obj.Id, default(int)); - } - - public Type GetUnproxiedType() + [SuppressMessage("ReSharper", "PossibleNullReferenceException")] + public Type GetUnproxiedType() { var t = GetType(); if (t.AssemblyQualifiedName.StartsWith("System.Data.Entity.")) @@ -40,7 +33,21 @@ public Type GetUnproxiedType() return t; } - public virtual bool Equals(BaseEntity other) + /// + /// Transient objects are not associated with an item already in storage. For instance, + /// a Product entity is transient if its Id is 0. + /// + public virtual bool IsTransientRecord() + { + return Id == 0; + } + + public override bool Equals(object obj) + { + return Equals(obj as BaseEntity); + } + + protected virtual bool Equals(BaseEntity other) { if (other == null) return false; @@ -48,24 +55,34 @@ public virtual bool Equals(BaseEntity other) if (ReferenceEquals(this, other)) return true; - if (!IsTransient(this) && - !IsTransient(other) && - Equals(Id, other.Id)) + if (HasSameNonDefaultIds(other)) { var otherType = other.GetUnproxiedType(); var thisType = GetUnproxiedType(); - return thisType.IsAssignableFrom(otherType) || - otherType.IsAssignableFrom(thisType); + return thisType.Equals(otherType); } return false; } - public override int GetHashCode() + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] + public override int GetHashCode() { - if (Equals(Id, default(int))) - return base.GetHashCode(); - return Id.GetHashCode(); + if (IsTransientRecord()) + { + return base.GetHashCode(); + } + else + { + unchecked + { + // It's possible for two objects to return the same hash code based on + // identically valued properties, even if they're of two different types, + // so we include the object's type in the hash calculation + var hashCode = GetUnproxiedType().GetHashCode(); + return (hashCode * 31) ^ Id.GetHashCode(); + } + } } public static bool operator ==(BaseEntity x, BaseEntity y) @@ -77,5 +94,10 @@ public override int GetHashCode() { return !(x == y); } + + private bool HasSameNonDefaultIds(BaseEntity other) + { + return !this.IsTransientRecord() && !other.IsTransientRecord() && this.Id == other.Id; + } } } diff --git a/src/Libraries/SmartStore.Core/Caching/AspNetCache.cs b/src/Libraries/SmartStore.Core/Caching/AspNetCache.cs index 0c3bb4d9a2..4af855729a 100644 --- a/src/Libraries/SmartStore.Core/Caching/AspNetCache.cs +++ b/src/Libraries/SmartStore.Core/Caching/AspNetCache.cs @@ -4,81 +4,80 @@ using System.Linq; using System.Web; using System.Web.Caching; -using SmartStore.Core.Fakes; namespace SmartStore.Core.Caching { public partial class AspNetCache : ICache { - private const string REGION_NAME = "$$SmartStoreNET$$"; - private readonly HttpContextBase _context; - - public AspNetCache(HttpContextBase context) - { - this._context = context; - } + private const string RegionName = "$$SmartStoreNET$$"; public IEnumerable> Entries { get { - if (_context is FakeHttpContext) + if (HttpRuntime.Cache == null) return Enumerable.Empty>(); - return from entry in _context.Cache.Cast() + return from entry in HttpRuntime.Cache.Cast() let key = entry.Key.ToString() - where key.StartsWith(REGION_NAME) + where key.StartsWith(RegionName) select new KeyValuePair( - key.Substring(REGION_NAME.Length), + key.Substring(RegionName.Length), entry.Value); } } public object Get(string key) { - if (_context is FakeHttpContext) + if (HttpRuntime.Cache == null) return null; - - return _context.Cache.Get(BuildKey(key)); + + return HttpRuntime.Cache.Get(BuildKey(key)); } public void Set(string key, object value, int? cacheTime) { + if (HttpRuntime.Cache == null) + return; + key = BuildKey(key); var absoluteExpiration = Cache.NoAbsoluteExpiration; - if (cacheTime.GetValueOrDefault() > 0) + if (cacheTime.HasValue) { + var span = cacheTime.Value == 0 ? TimeSpan.FromMilliseconds(10) : TimeSpan.FromMinutes(cacheTime.Value); absoluteExpiration = DateTime.UtcNow + TimeSpan.FromMinutes(cacheTime.Value); } - _context.Cache.Insert(key, value, null, absoluteExpiration, Cache.NoSlidingExpiration); + HttpRuntime.Cache.Insert(key, value, null, absoluteExpiration, Cache.NoSlidingExpiration); } public bool Contains(string key) { - if (_context is FakeHttpContext) + if (HttpRuntime.Cache == null) return false; - - return _context.Cache.Get(BuildKey(key)) != null; + + return HttpRuntime.Cache.Get(BuildKey(key)) != null; } public void Remove(string key) { - if (_context is FakeHttpContext) + if (HttpRuntime.Cache == null) return; - - _context.Cache.Remove(BuildKey(key)); + + HttpRuntime.Cache.Remove(BuildKey(key)); } public static string BuildKey(string key) { - return key.HasValue() ? REGION_NAME + key : null; + return key.HasValue() ? RegionName + key : null; } public bool IsSingleton { + // because Asp.NET Cache is thread-safe by itself, + // no need to mess up with locks. get { return false; } } diff --git a/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs b/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs index bdf35da722..6949aec542 100644 --- a/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs +++ b/src/Libraries/SmartStore.Core/Caching/DefaultCacheManager.cs @@ -12,7 +12,7 @@ public static class ICacheManagerExtensions { public static T Get(this ICacheManager cacheManager, string key) { - return cacheManager.Get(key, () => { return default(T); }); + return cacheManager.Get(key, () => default(T)); } } @@ -21,7 +21,12 @@ public partial class CacheManager : ICacheManager where TCache : ICache private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); private readonly ICache _cache; - public CacheManager(Func fn) + // Wwe put a special string into cache if value is null, + // otherwise our 'Contains()' would always return false, + // which is bad if we intentionally wanted to save NULL values. + private const string FakeNull = "__[NULL]__"; + + public CacheManager(Func fn) { this._cache = fn(typeof(TCache)); } @@ -32,35 +37,40 @@ public T Get(string key, Func acquirer, int? cacheTime = null) if (_cache.Contains(key)) { - return (T)_cache.Get(key); + return GetExisting(key); } - else + + using (EnterReadLock()) { - using (EnterReadLock()) + if (!_cache.Contains(key)) { - if (!_cache.Contains(key)) - { - var value = acquirer(); - this.Set(key, value, cacheTime); + var value = acquirer(); + this.Set(key, value, cacheTime); - return value; - } + return value; } - - return (T)_cache.Get(key); } - } + + return GetExisting(key); + } + + private T GetExisting(string key) + { + var value = _cache.Get(key); + + if (value.Equals(FakeNull)) + return default(T); + + return (T)_cache.Get(key); + } public void Set(string key, object value, int? cacheTime = null) { Guard.ArgumentNotEmpty(() => key); - - if (value == null) - return; using (EnterWriteLock()) { - _cache.Set(key, value, cacheTime); + _cache.Set(key, value ?? FakeNull, cacheTime); } } diff --git a/src/Libraries/SmartStore.Core/Caching/ICache.cs b/src/Libraries/SmartStore.Core/Caching/ICache.cs index a250d20bc0..b9fc134a8d 100644 --- a/src/Libraries/SmartStore.Core/Caching/ICache.cs +++ b/src/Libraries/SmartStore.Core/Caching/ICache.cs @@ -26,7 +26,7 @@ public interface ICache /// Adds the cache item with the specified key /// /// Key - /// Data + /// Data /// Cache time in minutes void Set(string key, object value, int? cacheTime); diff --git a/src/Libraries/SmartStore.Core/Caching/NullCache.cs b/src/Libraries/SmartStore.Core/Caching/NullCache.cs index ea96b38717..f02414d682 100644 --- a/src/Libraries/SmartStore.Core/Caching/NullCache.cs +++ b/src/Libraries/SmartStore.Core/Caching/NullCache.cs @@ -7,8 +7,7 @@ namespace SmartStore.Core.Caching /// public partial class NullCache : ICacheManager { - - private readonly static ICacheManager s_instance = new NullCache(); + private static readonly ICacheManager s_instance = new NullCache(); public static ICacheManager Instance { diff --git a/src/Libraries/SmartStore.Core/Caching/RequestCache.cs b/src/Libraries/SmartStore.Core/Caching/RequestCache.cs index a293c6cd4f..7ab183061f 100644 --- a/src/Libraries/SmartStore.Core/Caching/RequestCache.cs +++ b/src/Libraries/SmartStore.Core/Caching/RequestCache.cs @@ -9,7 +9,7 @@ namespace SmartStore.Core.Caching public partial class RequestCache : ICache { - private const string REGION_NAME = "$$SmartStoreNET$$"; + private const string RegionName = "$$SmartStoreNET$$"; private readonly HttpContextBase _context; public RequestCache(HttpContextBase context) @@ -39,9 +39,9 @@ public IEnumerable> Entries string key = enumerator.Key as string; if (key == null) continue; - if (key.StartsWith(REGION_NAME)) + if (key.StartsWith(RegionName)) { - yield return new KeyValuePair(key.Substring(REGION_NAME.Length), enumerator.Value); + yield return new KeyValuePair(key.Substring(RegionName.Length), enumerator.Value); } } } @@ -64,13 +64,10 @@ public void Set(string key, object value, int? cacheTime) key = BuildKey(key); - if (value != null) - { - if (items.Contains(key)) - items[key] = value; - else - items.Add(key, value); - } + if (items.Contains(key)) + items[key] = value; + else + items.Add(key, value); } public bool Contains(string key) @@ -93,7 +90,7 @@ public void Remove(string key) private string BuildKey(string key) { - return key.HasValue() ? REGION_NAME + key : null; + return key.HasValue() ? RegionName + key : null; } public bool IsSingleton diff --git a/src/Libraries/SmartStore.Core/Caching/StaticCache.cs b/src/Libraries/SmartStore.Core/Caching/StaticCache.cs index 3e68892de3..c4fc216e76 100644 --- a/src/Libraries/SmartStore.Core/Caching/StaticCache.cs +++ b/src/Libraries/SmartStore.Core/Caching/StaticCache.cs @@ -42,9 +42,10 @@ public void Set(string key, object value, int? cacheTime) { var cacheItem = new CacheItem(key, value); CacheItemPolicy policy = null; - if (cacheTime.GetValueOrDefault() > 0) + if (cacheTime.HasValue) { - policy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime.Value) }; + var span = cacheTime.Value == 0 ? TimeSpan.FromMilliseconds(10) : TimeSpan.FromMinutes(cacheTime.Value); + policy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now + span }; } Cache.Add(cacheItem, policy); diff --git a/src/Libraries/SmartStore.Core/Collections/IPersistentCollection.cs b/src/Libraries/SmartStore.Core/Collections/IPersistentCollection.cs deleted file mode 100644 index c536842b73..0000000000 --- a/src/Libraries/SmartStore.Core/Collections/IPersistentCollection.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; - -namespace SmartStore.Collections -{ - public interface IPersistentCollection : ICollection, ICollection - where T : class - { - Action> AfterAdd { get; set; } - Action> AfterRemove { get; set; } - Func, T, bool> BeforeAdd { get; set; } - Func, T, bool> BeforeRemove { get; set; } - } -} diff --git a/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs b/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs new file mode 100644 index 0000000000..789c363da0 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Collections/LazyMultimap.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace SmartStore.Collections +{ + /// + /// Manages data keys and offers a combination of eager and lazy data loading + /// + public class LazyMultimap : Multimap + { + private readonly Func> _load; + private readonly List _loaded; // to avoid database round trips with empty results + private List _collect; + //private int _roundTripCount; + + /// + /// Constructor + /// + /// int[] keys like Entity.Id, Multimap{int, T}> delegate to load data + /// Keys of eager loaded data + public LazyMultimap(Func> load, IEnumerable collect = null) + { + _load = load; + _loaded = new List(); + + _collect = collect == null ? new List() : new List(collect); + } + + protected virtual void Load(IEnumerable keys) + { + if (keys != null) + { + var loadKeys = (_collect.Count == 0 ? keys : _collect.Concat(keys)) + .Distinct() + .Except(_loaded) + .ToArray(); + + _collect.Clear(); // invalidate, do not load again + + if (loadKeys.Any()) + { + //++_roundTripCount; + //Debug.WriteLine("Round trip {0} of {1}: {2}", _roundTripCount, typeof(T).Name, string.Join(",", loadKeys.OrderBy(x => x))); + + var items = _load(loadKeys); + + _loaded.AddRange(loadKeys); + + if (items != null) + { + foreach (var range in items) + { + base.AddRange(range.Key, range.Value); + } + } + } + } + } + + /// + /// Get data. Load it if not already loaded yet. + /// + /// Data key + /// Collection of data + public virtual ICollection Load(int key) + { + if (key == 0) + { + return new List(); + } + + if (!_loaded.Contains(key)) + { + Load(new int[] { key }); + } + + // better not override indexer cause of stack overflow risk + var result = base[key]; + + Debug.Assert(_loaded.Contains(key), "Possible missing multimap result for key {0} and type {1}.".FormatInvariant(key, typeof(T).Name), ""); + + return result; + } + + /// + /// Collect keys for combined loading + /// + /// Data keys + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + public virtual void Collect(IEnumerable keys) + { + if (keys != null && keys.Any()) + { + _collect = _collect.Union(keys).ToList(); + } + } + + /// + /// Collect single key for combined loading + /// + /// Data key + public virtual void Collect(int key) + { + if (key != 0 && !_collect.Contains(key)) + { + _collect.Add(key); + } + } + + public override void Clear() + { + _loaded.Clear(); + _collect.Clear(); + //_roundTripCount = 0; + + base.Clear(); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Collections/MostRecentlyUsedList.cs b/src/Libraries/SmartStore.Core/Collections/MostRecentlyUsedList.cs new file mode 100644 index 0000000000..6d81d0bc3a --- /dev/null +++ b/src/Libraries/SmartStore.Core/Collections/MostRecentlyUsedList.cs @@ -0,0 +1,101 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace SmartStore.Collections +{ + public class MostRecentlyUsedList : IEnumerable + { + private readonly int _maxSize; + private readonly List _mru; + + public MostRecentlyUsedList(int maxSize) + { + _maxSize = maxSize; + _mru = new List(); + } + + public MostRecentlyUsedList(IEnumerable collection, int maxSize) + { + _maxSize = maxSize; + _mru = collection.ToList(); + + Normalize(); + } + + public MostRecentlyUsedList(string collection, int maxSize) + { + _maxSize = maxSize; + _mru = collection.SplitSafe(Delimiter).Cast().ToList(); + + Normalize(); + } + + public MostRecentlyUsedList(IEnumerable collection, T newItem, int maxSize) + { + _maxSize = maxSize; + _mru = collection.ToList(); + + Add(newItem); + } + + public MostRecentlyUsedList(string collection, T newItem, int maxSize) + { + _maxSize = maxSize; + _mru = collection.SplitSafe(Delimiter).Cast().ToList(); + + Add(newItem); + } + + public static string Delimiter { get { return ";"; } } + + private void Normalize() + { + if (_maxSize >= 0) + { + while (_mru.Count > _maxSize) + _mru.RemoveAt(_mru.Count - 1); + } + } + + public IEnumerator GetEnumerator() + { + return _mru.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _mru.GetEnumerator(); + } + + public override string ToString() + { + return string.Join(Delimiter, _mru); + } + + public T this[int key] + { + get + { + return _mru[key]; + } + set + { + _mru[key] = value; + } + } + + public int Count { get { return _mru.Count; } } + + public void Add(T item) + { + int i = _mru.IndexOf(item); + if (i > -1) + _mru.RemoveAt(i); + + _mru.Insert(0, item); + + Normalize(); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Collections/MultiMap.cs b/src/Libraries/SmartStore.Core/Collections/MultiMap.cs index 3e20b70a5d..1ae76884f8 100644 --- a/src/Libraries/SmartStore.Core/Collections/MultiMap.cs +++ b/src/Libraries/SmartStore.Core/Collections/MultiMap.cs @@ -16,10 +16,10 @@ namespace SmartStore.Collections /// /// The type of key. /// The type of value. - public class Multimap : IEnumerable>> + public class Multimap : IEnumerable>> { - private readonly IDictionary> _items; - private readonly Func> _listCreator; + private readonly IDictionary> _items; + private readonly Func> _listCreator; private readonly bool _isReadonly = false; public Multimap() @@ -31,29 +31,29 @@ internal Multimap(bool threadSafe) { if (threadSafe) { - _items = new ConcurrentDictionary>(); - _listCreator = () => new ThreadSafeList(); + _items = new ConcurrentDictionary>(); + _listCreator = () => new SynchronizedCollection(); } else { - _items = new Dictionary>(); + _items = new Dictionary>(); _listCreator = () => new List(); } } - public Multimap(Func> listCreator) - : this(new Dictionary>(), listCreator) + public Multimap(Func> listCreator) + : this(new Dictionary>(), listCreator) { } - internal Multimap(IDictionary> dictionary, Func> listCreator) + internal Multimap(IDictionary> dictionary, Func> listCreator) { _items = dictionary; _listCreator = listCreator; } - protected Multimap(IDictionary> dictionary, bool isReadonly) + protected Multimap(IDictionary> dictionary, bool isReadonly) { Guard.ArgumentNotNull(() => dictionary); @@ -96,7 +96,7 @@ public int TotalValueCount /// Gets the collection of values stored under the specified key. /// /// The key. - public virtual IList this[TKey key] + public virtual ICollection this[TKey key] { get { @@ -123,7 +123,7 @@ public virtual ICollection Keys /// /// Gets the collection of collections of values. /// - public virtual ICollection> Values + public virtual ICollection> Values { get { return _items.Values; } } @@ -239,9 +239,9 @@ IEnumerator IEnumerable.GetEnumerator() /// Returns an enumerator that iterates through the multimap. /// /// An object that can be used to iterate through the multimap. - public virtual IEnumerator>> GetEnumerator() + public virtual IEnumerator>> GetEnumerator() { - foreach (KeyValuePair> pair in _items) + foreach (KeyValuePair> pair in _items) yield return pair; } @@ -273,63 +273,5 @@ public static Multimap CreateFromLookup(ILookup sour } #endregion - - #region Nested ThreadSafeMultimap - - //private class ThreadSafeMultimap : Multimap - //{ - // private readonly ReaderWriterLockSlim _rwLock; - - // public ThreadSafeMultimap(ReaderWriterLockSlim rwLock) - // { - // _rwLock = rwLock; - // } - - // public override void Add(TKey key, TValue value) - // { - // using (_rwLock.GetUpgradeableReadLock()) - // { - // base.Add(key, value); - // } - // } - - // public override void AddRange(TKey key, IEnumerable values) - // { - // using (_rwLock.GetUpgradeableReadLock()) - // { - // base.AddRange(key, values); - // } - // } - - // public override bool ContainsValue(TKey key, TValue value) - // { - // using (_rwLock.GetUpgradeableReadLock()) - // { - // return base.ContainsValue(key, value); - // } - // } - - // public override bool Remove(TKey key, TValue value) - // { - // using (_rwLock.GetUpgradeableReadLock()) - // { - // return base.Remove(key, value); - // } - // } - - // public override IList this[TKey key] - // { - // get - // { - // using (_rwLock.GetUpgradeableReadLock()) - // { - // return base[key]; - // } - // } - // } - - //} - - #endregion } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Collections/PersistentCollection.cs b/src/Libraries/SmartStore.Core/Collections/PersistentCollection.cs deleted file mode 100644 index 6322bd0b1f..0000000000 --- a/src/Libraries/SmartStore.Core/Collections/PersistentCollection.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace SmartStore.Collections -{ - public class PersistentCollection : IPersistentCollection - where T : class - { - private readonly ICollection _actual; - private Action> _afterAdd; - private Action> _afterRemove; - private Func, T, bool> _beforeAdd; - private Func, T, bool> _beforeRemove; - - public PersistentCollection(ICollection actual) - { - _actual = actual; - } - - /// - /// perform actions on one or more list items after an item is - /// added. - /// - public Action> AfterAdd - { - get { return _afterAdd ?? (_afterAdd = l => { }); } - set { _afterAdd = value; } - } - - /// - /// perform actions on one or more list items after an item is - /// removed. - /// - public Action> AfterRemove - { - get { return _afterRemove ?? (_afterRemove = l => { }); } - set { _afterRemove = value; } - } - - /// - /// perform a check on the item being added before adding it. - /// Return true if it should be added, false if it should not be - /// added. - /// - public Func, T, bool> BeforeAdd - { - get { return _beforeAdd ?? (_beforeAdd = (l, x) => true); } - set { _beforeAdd = value; } - } - - /// - /// perform a check on the item being removed before removing - /// it. Return true if it should be removed, false if it should not - /// be removed. - /// - public Func, T, bool> BeforeRemove - { - get { return _beforeRemove ?? (_beforeRemove = (l, x) => true); } - set { _beforeRemove = value; } - } - - public IEnumerator GetEnumerator() - { - return _actual.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - - public int Count - { - get { return _actual.Count; } - } - public bool IsReadOnly - { - get { return _actual.IsReadOnly; } - } - - public void Add(T item) - { - if (BeforeAdd(this, item)) - { - _actual.Add(item); - AfterAdd(this); - } - } - - public void Clear() - { - while (_actual.Any()) - { - Remove(_actual.First()); - } - } - - public bool Contains(T item) - { - return _actual.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _actual.CopyTo(array, arrayIndex); - } - - public bool Remove(T item) - { - if (BeforeRemove(this, item)) - { - bool toReturn = _actual.Remove(item); - AfterRemove(this); - return toReturn; - } - return true; - } - - void ICollection.CopyTo(Array array, int index) - { - var copy = new T[_actual.Count]; - _actual.CopyTo(copy, 0); - Array.Copy(copy, 0, array, index, _actual.Count); - } - - int ICollection.Count - { - get { return _actual.Count; } - } - - bool ICollection.IsSynchronized - { - get { throw new NotImplementedException(); } - } - - object ICollection.SyncRoot - { - get { throw new NotImplementedException(); } - } - } -} diff --git a/src/Libraries/SmartStore.Core/Collections/Querystring.cs b/src/Libraries/SmartStore.Core/Collections/Querystring.cs new file mode 100644 index 0000000000..9df23fc868 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Collections/Querystring.cs @@ -0,0 +1,198 @@ +using System.Text; +using System.Web; +using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; + +namespace SmartStore.Collections +{ + /// + /// http://weblogs.asp.net/bradvincent/archive/2008/10/27/helper-class-querystring-builder-chainable.aspx + /// + public class QueryString : NameValueCollection + { + public QueryString() + { + } + + public QueryString(string queryString) + { + FillFromString(queryString); + } + + public static QueryString Current + { + get { return new QueryString().FromCurrent(); } + } + + /// + /// extracts a querystring from a full URL + /// + /// the string to extract the querystring from + /// a string representing only the querystring + [SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")] + public static string ExtractQuerystring(string s) + { + if (!string.IsNullOrEmpty(s)) + { + if (s.Contains("?")) + { + return s.Substring(s.IndexOf("?") + 1); + } + } + return s; + } + + /// + /// returns a querystring object based on a string + /// + /// the string to parse + /// the QueryString object + public QueryString FillFromString(string s, bool urlDecode = false) + { + base.Clear(); + if (string.IsNullOrEmpty(s)) + { + return this; + } + + foreach (string keyValuePair in ExtractQuerystring(s).Split('&')) + { + if (string.IsNullOrEmpty(keyValuePair)) + { + continue; + } + + string[] split = keyValuePair.Split('='); + base.Add(split[0], split.Length == 2 ? (urlDecode ? HttpUtility.UrlDecode(split[1]) : split[1]) : ""); + } + return this; + } + + /// + /// returns a QueryString object based on the current querystring of the request + /// + /// the QueryString object + public QueryString FromCurrent() + { + if (HttpContext.Current != null) + { + return FillFromString(HttpContext.Current.Request.QueryString.ToString(), true); + } + base.Clear(); + return this; + } + + /// + /// add a name value pair to the collection + /// + /// the name + /// the value associated to the name + /// the QueryString object + public new QueryString Add(string name, string value) + { + return Add(name, value, false); + } + + /// + /// adds a name value pair to the collection + /// + /// the name + /// the value associated to the name + /// true if the name is unique within the querystring. This allows us to override existing values + /// the QueryString object + public QueryString Add(string name, string value, bool isUnique) + { + string existingValue = base[name]; + if (string.IsNullOrEmpty(existingValue)) + { + base.Add(name, HttpUtility.UrlEncode(value)); + } + else if (isUnique) + { + base[name] = HttpUtility.UrlEncode(value); + } + else + { + base[name] += "," + HttpUtility.UrlEncode(value); + } + return this; + } + + /// + /// removes a name value pair from the querystring collection + /// + /// name of the querystring value to remove + /// the QueryString object + public new QueryString Remove(string name) + { + string existingValue = base[name]; + if (!string.IsNullOrEmpty(existingValue)) + { + base.Remove(name); + } + return this; + } + + /// + /// clears the collection + /// + /// the QueryString object + public QueryString Reset() + { + base.Clear(); + return this; + } + + /// + /// overrides the default + /// + /// + /// the associated decoded value for the specified name + public new string this[string name] + { + get { return HttpUtility.UrlDecode(base[name]); } + } + + /// + /// overrides the default indexer + /// + /// + /// the associated decoded value for the specified index + public new string this[int index] + { + get { return HttpUtility.UrlDecode(base[index]); } + } + + /// + /// checks if a name already exists within the query string collection + /// + /// the name to check + /// a boolean if the name exists + public bool Contains(string name) + { + string existingValue = base[name]; + return !string.IsNullOrEmpty(existingValue); + } + + /// + /// outputs the querystring object to a string + /// + /// the encoded querystring as it would appear in a browser + public override string ToString() + { + var builder = new StringBuilder(); + for (var i = 0; i < base.Keys.Count; i++) + { + if (!string.IsNullOrEmpty(base.Keys[i])) + { + foreach (string val in base[base.Keys[i]].EmptyNull().Split(',')) + { + builder.Append((builder.Length == 0) ? "?" : "&").Append( + HttpUtility.UrlEncode(base.Keys[i])).Append("=").Append(val); + } + } + } + return builder.ToString(); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Collections/QuerystringBuilder.cs b/src/Libraries/SmartStore.Core/Collections/QuerystringBuilder.cs deleted file mode 100644 index 739f54d67e..0000000000 --- a/src/Libraries/SmartStore.Core/Collections/QuerystringBuilder.cs +++ /dev/null @@ -1,195 +0,0 @@ -using System.Text; -using System.Web; -using System.Collections.Specialized; - -namespace SmartStore.Collections -{ - /// - /// http://weblogs.asp.net/bradvincent/archive/2008/10/27/helper-class-querystring-builder-chainable.aspx - /// - public class QueryString : NameValueCollection - { - public QueryString() - { - } - - public QueryString(string queryString) - { - FillFromString(queryString); - } - - public static QueryString Current - { - get { return new QueryString().FromCurrent(); } - } - - /// - /// extracts a querystring from a full URL - /// - /// the string to extract the querystring from - /// a string representing only the querystring - public string ExtractQuerystring(string s) - { - if (!string.IsNullOrEmpty(s)) - { - if (s.Contains("?")) - { - return s.Substring(s.IndexOf("?") + 1); - } - } - return s; - } - - /// - /// returns a querystring object based on a string - /// - /// the string to parse - /// the QueryString object - public QueryString FillFromString(string s) - { - base.Clear(); - if (string.IsNullOrEmpty(s)) - { - return this; - } - foreach (string keyValuePair in ExtractQuerystring(s).Split('&')) - { - if (string.IsNullOrEmpty(keyValuePair)) - { - continue; - } - string[] split = keyValuePair.Split('='); - base.Add(split[0], - split.Length == 2 ? split[1] : ""); - } - return this; - } - - /// - /// returns a QueryString object based on the current querystring of the request - /// - /// the QueryString object - public QueryString FromCurrent() - { - if (HttpContext.Current != null) - { - return FillFromString(HttpContext.Current.Request.QueryString.ToString()); - } - base.Clear(); - return this; - } - - /// - /// add a name value pair to the collection - /// - /// the name - /// the value associated to the name - /// the QueryString object - public new QueryString Add(string name, string value) - { - return Add(name, value, false); - } - - /// - /// adds a name value pair to the collection - /// - /// the name - /// the value associated to the name - /// true if the name is unique within the querystring. This allows us to override existing values - /// the QueryString object - public QueryString Add(string name, string value, bool isUnique) - { - string existingValue = base[name]; - if (string.IsNullOrEmpty(existingValue)) - { - base.Add(name, HttpUtility.UrlEncode(value)); - } - else if (isUnique) - { - base[name] = HttpUtility.UrlEncode(value); - } - else - { - base[name] += "," + HttpUtility.UrlEncode(value); - } - return this; - } - - /// - /// removes a name value pair from the querystring collection - /// - /// name of the querystring value to remove - /// the QueryString object - public new QueryString Remove(string name) - { - string existingValue = base[name]; - if (!string.IsNullOrEmpty(existingValue)) - { - base.Remove(name); - } - return this; - } - - /// - /// clears the collection - /// - /// the QueryString object - public QueryString Reset() - { - base.Clear(); - return this; - } - - /// - /// overrides the default - /// - /// - /// the associated decoded value for the specified name - public new string this[string name] - { - get { return HttpUtility.UrlDecode(base[name]); } - } - - /// - /// overrides the default indexer - /// - /// - /// the associated decoded value for the specified index - public new string this[int index] - { - get { return HttpUtility.UrlDecode(base[index]); } - } - - /// - /// checks if a name already exists within the query string collection - /// - /// the name to check - /// a boolean if the name exists - public bool Contains(string name) - { - string existingValue = base[name]; - return !string.IsNullOrEmpty(existingValue); - } - - /// - /// outputs the querystring object to a string - /// - /// the encoded querystring as it would appear in a browser - public override string ToString() - { - var builder = new StringBuilder(); - for (var i = 0; i < base.Keys.Count; i++) - { - if (!string.IsNullOrEmpty(base.Keys[i])) - { - foreach (string val in base[base.Keys[i]].Split(',')) - { - builder.Append((builder.Length == 0) ? "?" : "&").Append( - HttpUtility.UrlEncode(base.Keys[i])).Append("=").Append(val); - } - } - } - return builder.ToString(); - } - } -} diff --git a/src/Libraries/SmartStore.Core/Collections/ThreadSafeList.cs b/src/Libraries/SmartStore.Core/Collections/ThreadSafeList.cs deleted file mode 100644 index 04737fad68..0000000000 --- a/src/Libraries/SmartStore.Core/Collections/ThreadSafeList.cs +++ /dev/null @@ -1,291 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -using SmartStore.Utilities.Threading; - -namespace SmartStore.Collections -{ - - [Serializable] - public class ThreadSafeList : IList, IList - { - #region Fields - - private List _list; - - [NonSerialized] - private readonly ReaderWriterLockSlim _rwLock; - - #endregion - - #region Ctor - - public ThreadSafeList() - : this(new ReaderWriterLockSlim()) - { - } - - public ThreadSafeList(ReaderWriterLockSlim rwLock) - { - _list = new List(); - _rwLock = rwLock ?? new ReaderWriterLockSlim(); - } - - public ThreadSafeList(int capacity) - : this(capacity, null) - { - } - - public ThreadSafeList(int capacity, ReaderWriterLockSlim rwLock) - { - _list = new List(capacity); - _rwLock = rwLock ?? new ReaderWriterLockSlim(); - } - - public ThreadSafeList(IEnumerable collection) - : this(collection, null) - { - } - - public ThreadSafeList(IEnumerable collection, ReaderWriterLockSlim rwLock) - { - _list = new List(collection); - _rwLock = rwLock ?? new ReaderWriterLockSlim(); - } - - #endregion - - #region Properties - - public int Count - { - get - { - using (_rwLock.GetReadLock()) - { - return _list.Count; - } - } - } - - public bool IsReadOnly - { - get - { - return false; - } - } - - public T this[int index] - { - get - { - using (_rwLock.GetReadLock()) - { - return _list[index]; - } - } - set - { - using (_rwLock.GetWriteLock()) - { - _list[index] = value; - } - } - } - - public ReaderWriterLockSlim Lock - { - get - { - return _rwLock; - } - } - - #endregion - - #region Methods - - public void Add(T item) - { - using (_rwLock.GetWriteLock()) - { - _list.Add(item); - } - } - - public void Clear() - { - using (_rwLock.GetWriteLock()) - { - _list.Clear(); - } - } - - public bool Contains(T item) - { - using (_rwLock.GetReadLock()) - { - return _list.Contains(item); - } - } - - public void CopyTo(T[] array, int arrayIndex) - { - using (_rwLock.GetWriteLock()) - { - _list.CopyTo(array, arrayIndex); - } - } - - public IEnumerator GetEnumerator() - { - using (_rwLock.GetReadLock()) - { - return _list.AsReadOnly().GetEnumerator(); - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return this.GetEnumerator(); - } - - public int IndexOf(T item) - { - using (_rwLock.GetReadLock()) - { - return _list.IndexOf(item); - } - } - - public void Insert(int index, T item) - { - using (_rwLock.GetWriteLock()) - { - _list.Insert(index, item); - } - } - - public bool Remove(T item) - { - using (_rwLock.GetWriteLock()) - { - return _list.Remove(item); - } - } - - public void RemoveAt(int index) - { - using (_rwLock.GetWriteLock()) - { - _list.RemoveAt(index); - } - } - - private static void VerifyValueType(object value) - { - if (!IsCompatibleObject(value)) - { - throw Error.Argument("value", "Argument '{0}' is of wrong type. It must be '{1}'.", "value", typeof(T)); - } - } - - private static bool IsCompatibleObject(object value) - { - if (!(value is T) && ((value != null) || typeof(T).IsValueType)) - { - return false; - } - return true; - } - - #endregion - - #region IList Members - - int IList.Add(object value) - { - VerifyValueType(value); - this.Add((T)value); - return this.Count - 1; - } - - bool IList.Contains(object value) - { - return (IsCompatibleObject(value) && this.Contains((T)value)); - } - - int IList.IndexOf(object value) - { - if (IsCompatibleObject(value)) - { - return this.IndexOf((T)value); - } - return -1; - } - - void IList.Insert(int index, object value) - { - VerifyValueType(value); - this.Insert(index, (T)value); - } - - bool IList.IsFixedSize - { - get { return false; } - } - - void IList.Remove(object value) - { - if (IsCompatibleObject(value)) - { - this.Remove((T)value); - } - } - - object IList.this[int index] - { - get - { - return this[index]; - } - set - { - VerifyValueType(value); - this[index] = (T)value; - } - } - - #endregion - - #region ICollection Members - - void ICollection.CopyTo(Array array, int index) - { - using (_rwLock.GetWriteLock()) - { - ((ICollection)_list).CopyTo(array, index); - } - } - - bool ICollection.IsSynchronized - { - get { return true; } - } - - public object SyncRoot - { - get - { - return ((ICollection)_list).SyncRoot; - } - } - - #endregion - } - -} diff --git a/src/Libraries/SmartStore.Core/Collections/TopologicalSorter.cs b/src/Libraries/SmartStore.Core/Collections/TopologicalSorter.cs new file mode 100644 index 0000000000..5fc2b6818a --- /dev/null +++ b/src/Libraries/SmartStore.Core/Collections/TopologicalSorter.cs @@ -0,0 +1,220 @@ +// CREDITS to Tawani Anyangwe: http://tawani.blogspot.de/2009/02/topological-sorting-and-cyclic.html +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SmartStore.Collections +{ + + public interface ITopologicSortable + { + TKey Key { get; } + TKey[] DependsOn { get; } + } + + public static class TopologicalSortExtensions + { + + public static ITopologicSortable[] SortTopological(this ITopologicSortable[] items) + { + return SortTopological(items, null); + } + + public static ITopologicSortable[] SortTopological(this ITopologicSortable[] items, IEqualityComparer comparer) + { + Guard.ArgumentNotNull(() => items); + + var sortedIndexes = SortIndexesTopological(items, comparer); + var sortedList = new List>(sortedIndexes.Length); + + for (var i = 0; i < sortedIndexes.Length; i++) + { + //sortedList[i] = items[sortedIndexes[i]]; + sortedList.Add(items[sortedIndexes[i]]); + } + + return sortedList.ToArray(); + } + + public static int[] SortIndexesTopological(this ITopologicSortable[] items) + { + return SortIndexesTopological(items, null); + } + + public static int[] SortIndexesTopological(this ITopologicSortable[] items, IEqualityComparer comparer) + { + Guard.ArgumentNotNull(() => items); + + if (items.Length == 0) + { + return new int[] { }; + } + + if (comparer == null) + { + comparer = EqualityComparer.Default; + } + + var sorter = new TopologicalSorter(items.Length); + var indexes = new Dictionary(comparer); + + // add vertices + for (int i = 0; i < items.Length; i++) + { + indexes[items[i].Key] = sorter.AddVertex(i); + } + + // add edges + for (int i = 0; i < items.Length; i++) + { + if (items[i].DependsOn != null) + { + for (int j = 0; j < items[i].DependsOn.Length; j++) + { + if (indexes.ContainsKey(items[i].DependsOn[j])) + { + sorter.AddEdge(i, indexes[items[i].DependsOn[j]]); + } + } + } + } + + int[] result = sorter.Sort().Reverse().ToArray(); + return result; + } + } + + public class CyclicDependencyException : Exception + { + public CyclicDependencyException() + : base("Cyclic dependency detected") + { + } + + public CyclicDependencyException(string message) + : base(message) + { + } + } + + internal class TopologicalSorter + { + #region Private Members + + private readonly int[] _vertices; // list of vertices + private readonly int[,] _matrix; // adjacency matrix + private int _numVerts; // current number of vertices + private readonly int[] _sortedArray; + + #endregion + + #region Ctor + + public TopologicalSorter(int size) + { + _vertices = new int[size]; + _matrix = new int[size, size]; + _numVerts = 0; + for (int i = 0; i < size; i++) + { + for (int j = 0; j < size; j++) + { + _matrix[i, j] = 0; + } + } + _sortedArray = new int[size]; // sorted vert labels + } + + #endregion + + #region Public Methods + + public int AddVertex(int vertex) + { + _vertices[_numVerts++] = vertex; + return _numVerts - 1; + } + + public void AddEdge(int start, int end) + { + _matrix[start, end] = 1; + } + + public int[] Sort() // topological sort + { + while (_numVerts > 0) // while vertices remain, + { + // get a vertex with no successors, or -1 + int currentVertex = NoSuccessors(); + if (currentVertex == -1) + { + // must be a cycle + throw new CyclicDependencyException(); + } + + // insert vertex label in sorted array (start at end) + _sortedArray[_numVerts - 1] = _vertices[currentVertex]; + + DeleteVertex(currentVertex); // delete vertex + } + + // vertices all gone; return sortedArray + return _sortedArray; + } + + #endregion + + #region Private Helper Methods + + // returns vert with no successors (or -1 if no such verts) + private int NoSuccessors() + { + for (int row = 0; row < _numVerts; row++) + { + bool isEdge = false; // edge from row to column in adjMat + for (int col = 0; col < _numVerts; col++) + { + if (_matrix[row, col] > 0) // if edge to another, + { + isEdge = true; + break; // this vertex has a successor try another + } + } + if (!isEdge) // if no edges, has no successors + return row; + } + return -1; // no + } + + private void DeleteVertex(int delVert) + { + // if not last vertex, delete from vertexList + if (delVert != _numVerts - 1) + { + for (int j = delVert; j < _numVerts - 1; j++) + _vertices[j] = _vertices[j + 1]; + + for (int row = delVert; row < _numVerts - 1; row++) + MoveRowUp(row, _numVerts); + + for (int col = delVert; col < _numVerts - 1; col++) + MoveColLeft(col, _numVerts - 1); + } + _numVerts--; // one less vertex + } + + private void MoveRowUp(int row, int length) + { + for (int col = 0; col < length; col++) + _matrix[row, col] = _matrix[row + 1, col]; + } + + private void MoveColLeft(int col, int length) + { + for (int row = 0; row < length; row++) + _matrix[row, col] = _matrix[row, col + 1]; + } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs b/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs deleted file mode 100644 index 81c2ecb4f7..0000000000 --- a/src/Libraries/SmartStore.Core/ComponentModel/Expando.cs +++ /dev/null @@ -1,416 +0,0 @@ -#region License -/* - ************************************************************** - * Author: Rick Strahl - * © West Wind Technologies, 2012 - * http://www.west-wind.com/ - * - * Created: Feb 2, 2012 - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - ************************************************************** -*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Dynamic; -using System.Reflection; -using Fasterflect; - -namespace SmartStore.ComponentModel -{ - /// - /// Class that provides extensible properties and methods to an - /// existing object when cast to dynamic. This - /// dynamic object stores 'extra' properties in a dictionary or - /// checks the actual properties of the instance passed via - /// constructor. - /// - /// This class can be subclassed to extend an existing type or - /// you can pass in an instance to extend. Properties (both - /// dynamic and strongly typed) can be accessed through an - /// indexer. - /// - /// This type allows you three ways to access its properties: - /// - /// Directly: any explicitly declared properties are accessible - /// Dynamic: dynamic cast allows access to dictionary and native properties/methods - /// Dictionary: Any of the extended properties are accessible via IDictionary interface - /// - [Serializable] - public class Expando : DynamicObject, IDynamicMetaObjectProvider - { - /// - /// Instance of object passed in - /// - private object _instance; - - /// - /// Cached type of the instance - /// - private Type _instanceType; - - private IList _instancePropertyInfo; - - /// - /// String Dictionary that contains the extra dynamic values - /// stored on this object/instance - /// - /// Using PropertyBag to support XML Serialization of the dictionary - public PropertyBag Properties = new PropertyBag(); - - /// - /// This constructor just works off the internal dictionary and any - /// public properties of this object. - /// - /// Note you can subclass Expando. - /// - public Expando() - { - Initialize(this); - } - - /// - /// Allows passing in an existing instance variable to 'extend'. - /// - /// - /// You can pass in null here if you don't want to - /// check native properties and only check the Dictionary! - /// - /// - public Expando(object instance) - { - Initialize(instance); - } - - - protected virtual void Initialize(object instance) - { - _instance = instance; - if (instance != null) - _instanceType = instance.GetType(); - } - - IList InstancePropertyInfo - { - get - { - if (_instancePropertyInfo == null && _instance != null) - _instancePropertyInfo = _instance.GetType().Properties(Flags.InstancePublicDeclaredOnly); - return _instancePropertyInfo; - } - } - - public override IEnumerable GetDynamicMemberNames() - { - foreach (var prop in this.GetProperties(false)) - yield return prop.Key; - } - - - /// - /// Try to retrieve a member by name first from instance properties - /// followed by the collection entries. - /// - /// - /// - /// - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - result = null; - - // first check the Properties collection for member - if (Properties.Keys.Contains(binder.Name)) - { - result = Properties[binder.Name]; - return true; - } - - - // Next check for Public properties via Reflection - if (_instance != null) - { - try - { - return GetProperty(_instance, binder.Name, out result); - } - catch { } - } - - // failed to retrieve a property - result = null; - return false; - } - - - /// - /// Property setter implementation tries to retrieve value from instance - /// first then into this object - /// - /// - /// - /// - public override bool TrySetMember(SetMemberBinder binder, object value) - { - - // first check to see if there's a native property to set - if (_instance != null) - { - try - { - bool result = SetProperty(_instance, binder.Name, value); - if (result) - return true; - } - catch { } - } - - // no match - set or add to dictionary - Properties[binder.Name] = value; - return true; - } - - /// - /// Dynamic invocation method. Currently allows only for Reflection based - /// operation (no ability to add methods dynamically). - /// - /// - /// - /// - /// - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - if (_instance != null) - { - try - { - // check instance passed in for methods to invoke - if (InvokeMethod(_instance, binder.Name, args, out result)) - return true; - } - catch { } - } - - result = null; - return false; - } - - - /// - /// Reflection Helper method to retrieve a property - /// - /// - /// - /// - /// - protected bool GetProperty(object instance, string name, out object result) - { - if (instance == null) - instance = this; - - var pi = _instanceType.Property(name, Flags.InstancePublic); - if (pi != null) - { - result = instance.GetPropertyValue(pi.Name); - return true; - } - - result = null; - return false; - } - - /// - /// Reflection helper method to set a property value - /// - /// - /// - /// - /// - protected bool SetProperty(object instance, string name, object value) - { - if (instance == null) - instance = this; - - var pi = _instanceType.Property(name, Flags.InstancePublic); - if (pi != null) - { - instance.SetPropertyValue(pi.Name, value); - return true; - } - return false; - } - - /// - /// Reflection helper method to invoke a method - /// - /// - /// - /// - /// - /// - protected bool InvokeMethod(object instance, string name, object[] args, out object result) - { - if (instance == null) - instance = this; - - // Look at the instanceType - var mi = _instanceType.Method(name, Flags.InstancePublic); - - if (mi != null) - { - result = _instance.CallMethod(mi.Name, args); - return true; - } - - result = null; - return false; - } - - - /// - /// Convenience method that provides a string Indexer - /// to the Properties collection AND the strongly typed - /// properties of the object by name. - /// - /// // dynamic - /// exp["Address"] = "112 nowhere lane"; - /// // strong - /// var name = exp["StronglyTypedProperty"] as string; - /// - /// - /// The getter checks the Properties dictionary first - /// then looks in PropertyInfo for properties. - /// The setter checks the instance properties before - /// checking the Properties dictionary. - /// - /// - /// - /// - public object this[string key] - { - get - { - try - { - // try to get from properties collection first - return Properties[key]; - } - catch (KeyNotFoundException) - { - // try reflection on instanceType - object result = null; - if (GetProperty(_instance, key, out result)) - return result; - - // no doesn't exist - throw; - } - } - set - { - if (Properties.ContainsKey(key)) - { - Properties[key] = value; - return; - } - - // check instance for existance of type first - var pi = _instanceType.Property(key, Flags.Public); - if (pi != null) - SetProperty(_instance, key, value); - else - Properties[key] = value; - } - } - - - /// - /// Returns and the properties of - /// - /// - /// - public IEnumerable> GetProperties(bool includeInstanceProperties = false) - { - if (includeInstanceProperties && _instance != null) - { - foreach (var prop in this.InstancePropertyInfo) - yield return new KeyValuePair(prop.Name, prop.GetValue(_instance, null)); - } - - foreach (var key in this.Properties.Keys) - yield return new KeyValuePair(key, this.Properties[key]); - - } - - /// - /// Checks whether a property exists in the Property collection - /// or as a property on the instance - /// - /// - /// - public bool Contains(KeyValuePair item, bool includeInstanceProperties = false) - { - return this.Contains(item.Key, includeInstanceProperties); - } - - /// - /// Checks whether a property exists in the Property collection - /// or as a property on the instance - /// - /// - /// - /// - public bool Contains(string propertyName, bool includeInstanceProperties = false) - { - bool res = Properties.ContainsKey(propertyName); - if (res) - return true; - - if (includeInstanceProperties && _instance != null) - { - foreach (var prop in this.InstancePropertyInfo) - { - if (prop.Name == propertyName) - return true; - } - } - - return false; - } - - public bool TryGetValue(string propertyName, out object value) - { - value = null; - - if (this.Contains(propertyName, true)) - { - value = this[propertyName]; - return true; - } - - return false; - } - - } -} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs b/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs new file mode 100644 index 0000000000..79a4362f30 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Linq.Expressions; +using System.Collections.Concurrent; + +namespace SmartStore.ComponentModel +{ + public class FastActivator + { + private static readonly ConcurrentDictionary _activatorsCache = new ConcurrentDictionary(); + + public FastActivator(ConstructorInfo constructorInfo) + { + Guard.ArgumentNotNull(() => constructorInfo); + + Constructor = constructorInfo; + Invoker = MakeFastInvoker(constructorInfo); + ParameterTypes = constructorInfo.GetParameters().Select(p => p.ParameterType).ToArray(); + } + + /// + /// Gets the backing . + /// + public ConstructorInfo Constructor { get; private set; } + + /// + /// Gets the parameter types from the backing + /// + public Type[] ParameterTypes { get; private set; } + + /// + /// Gets the constructor invoker. + /// + public Func Invoker { get; private set; } + + /// + /// Creates an instance of the type using the specified parameters. + /// + /// A reference to the newly created object. + public object Activate(params object[] parameters) + { + return Invoker(parameters); + } + + /// + /// Creates a single fast constructor invoker. The result is not cached. + /// + /// constructorInfo to create invoker for. + /// a fast invoker. + public static Func MakeFastInvoker(ConstructorInfo constructorInfo) + { + var paramsInfo = constructorInfo.GetParameters(); + + var parametersExpression = Expression.Parameter(typeof(object[]), "args"); + var argumentsExpression = new Expression[paramsInfo.Length]; + + for (int paramIndex = 0; paramIndex < paramsInfo.Length; paramIndex++) + { + var indexExpression = Expression.Constant(paramIndex); + var parameterType = paramsInfo[paramIndex].ParameterType; + + var parameterIndexExpression = Expression.ArrayIndex(parametersExpression, indexExpression); + var convertExpression = Expression.Convert(parameterIndexExpression, parameterType); + argumentsExpression[paramIndex] = convertExpression; + + if (!parameterType.GetTypeInfo().IsValueType) + continue; + + var nullConditionExpression = Expression.Equal(parameterIndexExpression, Expression.Constant(null)); + argumentsExpression[paramIndex] = Expression.Condition(nullConditionExpression, Expression.Default(parameterType), convertExpression); + } + + var newExpression = Expression.New(constructorInfo, argumentsExpression); + var lambda = Expression.Lambda>(newExpression, parametersExpression); + + return lambda.Compile(); + } + + #region Static + + /// + /// Creates and caches fast constructor invokers + /// + /// The type to extract fast constructor invokers for + /// A cached array of all public instance constructors from the given type. + /// The parameterless default constructor is always excluded from the list of activators + public static FastActivator[] GetActivators(Type type) + { + return GetActivatorsCore(type); + } + + private static FastActivator[] GetActivatorsCore(Type type) + { + FastActivator[] activators; + if (!_activatorsCache.TryGetValue(type, out activators)) + { + var candidates = GetCandidateConstructors(type); + activators = candidates.Select(c => new FastActivator(c)).ToArray(); + _activatorsCache.TryAdd(type, activators); + } + + return activators; + } + + /// + /// Creates an instance of the specified type using the constructor that best matches the specified parameters. + /// + /// The type of object to create. + /// + /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. + /// If args is an empty array or null, the constructor that takes no parameters (the default constructor) is invoked. + /// + /// A reference to the newly created object. + public static T CreateInstance(params object[] args) + { + return (T)CreateInstance(typeof(T), args); + } + + /// + /// Creates an instance of the specified type using the constructor that best matches the specified parameters. + /// + /// The type of object to create. + /// + /// An array of arguments that match in number, order, and type the parameters of the constructor to invoke. + /// If args is an empty array or null, the constructor that takes no parameters (the default constructor) is invoked. + /// + /// A reference to the newly created object. + public static object CreateInstance(Type type, params object[] args) + { + Guard.ArgumentNotNull(type, "type"); + + if (args == null || args.Length == 0) + { + // don't struggle with FastActivator: native reflection is really fast with default constructor! + return Activator.CreateInstance(type); + } + + var activators = GetActivatorsCore(type); + var matchingActivator = FindMatchingActivatorCore(activators, type, args); + + if (matchingActivator == null) + { + throw new ArgumentException("No matching contructor was found for the given arguments.", "args"); + } + + return matchingActivator.Activate(args); + } + + public static FastActivator FindMatchingActivator(Type type, params object[] args) + { + var activators = GetActivatorsCore(type); + var matchingActivator = FindMatchingActivatorCore(activators, type, args); + + return matchingActivator; + } + + private static FastActivator FindMatchingActivatorCore(FastActivator[] activators, Type type, object[] args) + { + if (activators.Length == 0) + { + return null; + } + + if (activators.Length == 1) + { + // this seems to be bad design, but it's on purpose for performance reasons. + // In nearly ALL cases there is only one constructor. + return activators[0]; + } + + var argTypes = args.Select(x => x.GetType()).ToArray(); + var constructor = type.GetConstructor( + BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, + null, + argTypes, + null); + + if (constructor != null) + { + var matchingActivator = activators.FirstOrDefault(a => a.Constructor == constructor); + return matchingActivator; + } + + return null; + } + + private static IEnumerable GetCandidateConstructors(Type type) + { + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + return constructors.Where(c => c.GetParameters().Length > 0); + } + + private static void CheckIsValidType(Type type) + { + if (type.IsAbstract || type.IsInterface) + { + throw new ArgumentException("The type to create activators for must be concrete. Type: {0}".FormatInvariant(type.ToString()), "type"); + } + } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/FastProperty.cs b/src/Libraries/SmartStore.Core/ComponentModel/FastProperty.cs new file mode 100644 index 0000000000..068b84f008 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/FastProperty.cs @@ -0,0 +1,671 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace SmartStore.ComponentModel +{ + public enum PropertyCachingStrategy + { + /// + /// Don't cache FastProperty instances + /// + Uncached = 0, + /// + /// Always cache FastProperty instances + /// + Cached = 1, + /// + /// Always cache FastProperty instances. PLUS cache all other properties of the declaring type. + /// + EagerCached = 2 + } + + public class FastProperty + { + // Delegate type for a by-ref property getter + private delegate TValue ByRefFunc(ref TDeclaringType arg); + + private static readonly MethodInfo CallPropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallPropertyGetter"); + private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallPropertyGetterByReference"); + private static readonly MethodInfo CallNullSafePropertyGetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallNullSafePropertyGetter"); + private static readonly MethodInfo CallNullSafePropertyGetterByReferenceOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallNullSafePropertyGetterByReference"); + private static readonly MethodInfo CallPropertySetterOpenGenericMethod = typeof(FastProperty).GetTypeInfo().GetDeclaredMethod("CallPropertySetter"); + + private static readonly ConcurrentDictionary _singlePropertiesCache = new ConcurrentDictionary(); + + // Using an array rather than IEnumerable, as target will be called on the hot path numerous times. + private static readonly ConcurrentDictionary> _propertiesCache = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> _visiblePropertiesCache = new ConcurrentDictionary>(); + + private Action _valueSetter; + private bool? _isPublicSettable; + private bool? _isSequenceType; + + /// + /// Initializes a . + /// This constructor does not cache the helper. For caching, use . + /// + [SuppressMessage("ReSharper", "VirtualMemberCallInContructor")] + public FastProperty(PropertyInfo property) + { + Guard.ArgumentNotNull(() => property); + + Property = property; + Name = property.Name; + ValueGetter = MakeFastPropertyGetter(property); + } + + /// + /// Gets the backing . + /// + public PropertyInfo Property { get; private set; } + + /// + /// Gets (or sets in derived types) the property name. + /// + public virtual string Name { get; protected set; } + + /// + /// Gets the property value getter. + /// + public Func ValueGetter { get; private set; } + + public bool IsPublicSettable + { + get + { + if (!_isPublicSettable.HasValue) + { + _isPublicSettable = Property.CanWrite && Property.GetSetMethod(false) != null; + } + return _isPublicSettable.Value; + } + } + + public bool IsSequenceType + { + get + { + if (!_isSequenceType.HasValue) + { + _isSequenceType = Property.PropertyType != typeof(string) && Property.PropertyType.IsSubClass(typeof(IEnumerable<>)); + } + return _isSequenceType.Value; + } + } + + /// + /// Gets the property value setter. + /// + public Action ValueSetter + { + get + { + if (_valueSetter == null) + { + // We'll allow safe races here. + _valueSetter = MakeFastPropertySetter(Property); + } + + return _valueSetter; + } + } + + /// + /// Returns the property value for the specified . + /// + /// The object whose property value will be returned. + /// The property value. + public object GetValue(object instance) + { + return ValueGetter(instance); + } + + /// + /// Sets the property value for the specified . + /// + /// The object whose property value will be set. + /// The property value. + public void SetValue(object instance, object value) + { + ValueSetter(instance, value); + } + + /// + /// Creates and caches fast property helpers that expose getters for every public get property on the + /// underlying type. + /// + /// the instance to extract property accessors for. + /// A cached array of all public property getters from the underlying type of target instance. + /// + public static IReadOnlyDictionary GetProperties(object instance, PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) + { + return GetProperties(instance.GetType()); + } + + /// + /// Creates and caches fast property helpers that expose getters for every public get property on the + /// specified type. + /// + /// The type to extract property accessors for. + /// A cached array of all public property getters from the type of target instance. + /// + public static IReadOnlyDictionary GetProperties(Type type, PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) + { + var propertiesCache = cachingStrategy > PropertyCachingStrategy.Uncached ? _propertiesCache : CreateVolatileCache(); + + return (IReadOnlyDictionary)GetProperties(type, CreateInstance, propertiesCache); + } + + /// + /// + /// Creates and caches fast property helpers that expose getters for every non-hidden get property + /// on the specified type. + /// + /// + /// excludes properties defined on base types that have been + /// hidden by definitions using the new keyword. + /// + /// + /// The instance to extract property accessors for. + /// + /// A cached array of all public property getters from the instance's type. + /// + public static IReadOnlyDictionary GetVisibleProperties(object instance, PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) + { + var propertiesCache = cachingStrategy > PropertyCachingStrategy.Uncached ? _propertiesCache : CreateVolatileCache(); + var visiblePropertiesCache = cachingStrategy > PropertyCachingStrategy.Uncached ? _visiblePropertiesCache : CreateVolatileCache(); + + return (IReadOnlyDictionary)GetVisibleProperties(instance.GetType(), CreateInstance, propertiesCache, visiblePropertiesCache); + } + + /// + /// + /// Creates and caches fast property helpers that expose getters for every non-hidden get property + /// on the specified type. + /// + /// + /// excludes properties defined on base types that have been + /// hidden by definitions using the new keyword. + /// + /// + /// The type to extract property accessors for. + /// + /// A cached array of all public property getters from the type. + /// + public static IReadOnlyDictionary GetVisibleProperties(Type type, PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) + { + var propertiesCache = cachingStrategy > PropertyCachingStrategy.Uncached ? _propertiesCache : CreateVolatileCache(); + var visiblePropertiesCache = cachingStrategy > PropertyCachingStrategy.Uncached ? _visiblePropertiesCache : CreateVolatileCache(); + + return (IReadOnlyDictionary)GetVisibleProperties(type, CreateInstance, propertiesCache, visiblePropertiesCache); + } + + public static FastProperty GetProperty( + Expression> property, + PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) + { + return GetProperty(property.ExtractPropertyInfo(), cachingStrategy); + } + + public static FastProperty GetProperty( + Type type, + string propertyName, + PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) + { + Guard.ArgumentNotNull(() => type); + Guard.ArgumentNotEmpty(() => propertyName); + + FastProperty fastProperty = null; + + if (TryGetCachedProperty(type, propertyName, cachingStrategy == PropertyCachingStrategy.EagerCached, out fastProperty)) + { + return fastProperty; + } + + var key = new PropertyKey(type, propertyName); + if (!_singlePropertiesCache.TryGetValue(key, out fastProperty)) + { + var pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase); + if (pi != null) + { + fastProperty = CreateInstance(pi); + if (cachingStrategy > PropertyCachingStrategy.Uncached) + { + _singlePropertiesCache.TryAdd(key, fastProperty); + } + } + } + + return fastProperty; + } + + public static FastProperty GetProperty( + PropertyInfo propertyInfo, + PropertyCachingStrategy cachingStrategy = PropertyCachingStrategy.Cached) + { + Guard.ArgumentNotNull(() => propertyInfo); + + FastProperty fastProperty = null; + + if (TryGetCachedProperty(propertyInfo.ReflectedType, propertyInfo.Name, cachingStrategy == PropertyCachingStrategy.EagerCached, out fastProperty)) + { + return fastProperty; + } + + var key = new PropertyKey(propertyInfo.ReflectedType, propertyInfo.Name); + if (!_singlePropertiesCache.TryGetValue(key, out fastProperty)) + { + fastProperty = CreateInstance(propertyInfo); + if (cachingStrategy > PropertyCachingStrategy.Uncached) + { + _singlePropertiesCache.TryAdd(key, fastProperty); + } + } + + return fastProperty; + } + + private static bool TryGetCachedProperty( + Type type, + string propertyName, + bool eagerCached, + out FastProperty fastProperty) + { + fastProperty = null; + IDictionary allProperties; + + if (eagerCached) + { + allProperties = (IDictionary)GetProperties(type); + allProperties.TryGetValue(propertyName, out fastProperty); + } + + if (fastProperty == null && _propertiesCache.TryGetValue(type, out allProperties)) + { + allProperties.TryGetValue(propertyName, out fastProperty); + } + + return fastProperty != null; + } + + /// + /// Creates a single fast property getter. The result is not cached. + /// + /// propertyInfo to extract the getter for. + /// a fast getter. + /// + /// This method is more memory efficient than a dynamically compiled lambda, and about the + /// same speed. + /// + public static Func MakeFastPropertyGetter(PropertyInfo propertyInfo) + { + Debug.Assert(propertyInfo != null); + + return MakeFastPropertyGetter( + propertyInfo, + CallPropertyGetterOpenGenericMethod, + CallPropertyGetterByReferenceOpenGenericMethod); + } + + /// + /// Creates a single fast property getter which is safe for a null input object. The result is not cached. + /// + /// propertyInfo to extract the getter for. + /// a fast getter. + /// + /// This method is more memory efficient than a dynamically compiled lambda, and about the + /// same speed. + /// + public static Func MakeNullSafeFastPropertyGetter(PropertyInfo propertyInfo) + { + Debug.Assert(propertyInfo != null); + + return MakeFastPropertyGetter( + propertyInfo, + CallNullSafePropertyGetterOpenGenericMethod, + CallNullSafePropertyGetterByReferenceOpenGenericMethod); + } + + private static Func MakeFastPropertyGetter( + PropertyInfo propertyInfo, + MethodInfo propertyGetterWrapperMethod, + MethodInfo propertyGetterByRefWrapperMethod) + { + Debug.Assert(propertyInfo != null); + + // Must be a generic method with a Func<,> parameter + Debug.Assert(propertyGetterWrapperMethod != null); + Debug.Assert(propertyGetterWrapperMethod.IsGenericMethodDefinition); + Debug.Assert(propertyGetterWrapperMethod.GetParameters().Length == 2); + + // Must be a generic method with a ByRefFunc<,> parameter + Debug.Assert(propertyGetterByRefWrapperMethod != null); + Debug.Assert(propertyGetterByRefWrapperMethod.IsGenericMethodDefinition); + Debug.Assert(propertyGetterByRefWrapperMethod.GetParameters().Length == 2); + + var getMethod = propertyInfo.GetMethod; + Debug.Assert(getMethod != null); + Debug.Assert(!getMethod.IsStatic); + Debug.Assert(getMethod.GetParameters().Length == 0); + + // Instance methods in the CLR can be turned into static methods where the first parameter + // is open over "target". This parameter is always passed by reference, so we have a code + // path for value types and a code path for reference types. + if (getMethod.DeclaringType.GetTypeInfo().IsValueType) + { + // Create a delegate (ref TDeclaringType) -> TValue + return MakeFastPropertyGetter( + typeof(ByRefFunc<,>), + getMethod, + propertyGetterByRefWrapperMethod); + } + else + { + // Create a delegate TDeclaringType -> TValue + return MakeFastPropertyGetter( + typeof(Func<,>), + getMethod, + propertyGetterWrapperMethod); + } + } + + private static Func MakeFastPropertyGetter( + Type openGenericDelegateType, + MethodInfo propertyGetMethod, + MethodInfo openGenericWrapperMethod) + { + var typeInput = propertyGetMethod.DeclaringType; + var typeOutput = propertyGetMethod.ReturnType; + + var delegateType = openGenericDelegateType.MakeGenericType(typeInput, typeOutput); + var propertyGetterDelegate = propertyGetMethod.CreateDelegate(delegateType); + + var wrapperDelegateMethod = openGenericWrapperMethod.MakeGenericMethod(typeInput, typeOutput); + var accessorDelegate = wrapperDelegateMethod.CreateDelegate( + typeof(Func), + propertyGetterDelegate); + + return (Func)accessorDelegate; + } + + /// + /// Creates a single fast property setter for reference types. The result is not cached. + /// + /// propertyInfo to extract the setter for. + /// a fast getter. + /// + /// This method is more memory efficient than a dynamically compiled lambda, and about the + /// same speed. This only works for reference types. + /// + public static Action MakeFastPropertySetter(PropertyInfo propertyInfo) + { + Debug.Assert(propertyInfo != null); + Debug.Assert(!propertyInfo.DeclaringType.GetTypeInfo().IsValueType); + + var setMethod = propertyInfo.SetMethod; + Debug.Assert(setMethod != null); + Debug.Assert(!setMethod.IsStatic); + Debug.Assert(setMethod.ReturnType == typeof(void)); + var parameters = setMethod.GetParameters(); + Debug.Assert(parameters.Length == 1); + + // Instance methods in the CLR can be turned into static methods where the first parameter + // is open over "target". This parameter is always passed by reference, so we have a code + // path for value types and a code path for reference types. + var typeInput = setMethod.DeclaringType; + var parameterType = parameters[0].ParameterType; + + // Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; } + var propertySetterAsAction = + setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, parameterType)); + var callPropertySetterClosedGenericMethod = + CallPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, parameterType); + var callPropertySetterDelegate = + callPropertySetterClosedGenericMethod.CreateDelegate( + typeof(Action), propertySetterAsAction); + + return (Action)callPropertySetterDelegate; + } + + /// + /// Given an object, adds each instance property with a public get method as a key and its + /// associated value to a dictionary. + /// + /// If the object is already an + /// IDictionary{string, object} + /// + /// instance, then a copy + /// is returned. + /// + /// + /// The implementation of FastProperty will cache the property accessors per-type. This is + /// faster when the the same type is used multiple times with ObjectToDictionary. + /// + public static IDictionary ObjectToDictionary(object value, Func keySelector = null) + { + var dictionary = value as IDictionary; + if (dictionary != null) + { + return new Dictionary(dictionary, StringComparer.OrdinalIgnoreCase); + } + + keySelector = keySelector ?? new Func(key => key); + + dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + + if (value != null) + { + foreach (var prop in GetProperties(value).Values) + { + dictionary[keySelector(prop.Name)] = prop.GetValue(value); + } + } + + return dictionary; + } + + private static FastProperty CreateInstance(PropertyInfo property) + { + return new FastProperty(property); + } + + // Called via reflection + private static object CallPropertyGetter( + Func getter, + object target) + { + return getter((TDeclaringType)target); + } + + // Called via reflection + private static object CallPropertyGetterByReference( + ByRefFunc getter, + object target) + { + var unboxed = (TDeclaringType)target; + return getter(ref unboxed); + } + + // Called via reflection + private static object CallNullSafePropertyGetter( + Func getter, + object target) + { + if (target == null) + { + return null; + } + + return getter((TDeclaringType)target); + } + + // Called via reflection + private static object CallNullSafePropertyGetterByReference( + ByRefFunc getter, + object target) + { + if (target == null) + { + return null; + } + + var unboxed = (TDeclaringType)target; + return getter(ref unboxed); + } + + private static void CallPropertySetter( + Action setter, + object target, + object value) + { + setter((TDeclaringType)target, (TValue)value); + } + + protected static IDictionary GetVisibleProperties( + Type type, + Func createPropertyHelper, + ConcurrentDictionary> allPropertiesCache, + ConcurrentDictionary> visiblePropertiesCache) + { + IDictionary result; + if (visiblePropertiesCache.TryGetValue(type, out result)) + { + return result; + } + + // The simple and common case, this is normal POCO object - no need to allocate. + var allPropertiesDefinedOnType = true; + var allProperties = GetProperties(type, createPropertyHelper, allPropertiesCache); + foreach (var propertyHelper in allProperties.Values) + { + if (propertyHelper.Property.DeclaringType != type) + { + allPropertiesDefinedOnType = false; + break; + } + } + + if (allPropertiesDefinedOnType) + { + result = allProperties; + visiblePropertiesCache.TryAdd(type, result); + return result; + } + + // There's some inherited properties here, so we need to check for hiding via 'new'. + var filteredProperties = new List(allProperties.Count); + foreach (var propertyHelper in allProperties.Values) + { + var declaringType = propertyHelper.Property.DeclaringType; + if (declaringType == type) + { + filteredProperties.Add(propertyHelper); + continue; + } + + // If this property was declared on a base type then look for the definition closest to the + // the type to see if we should include it. + var ignoreProperty = false; + + // Walk up the hierarchy until we find the type that actally declares this + // PropertyInfo. + var currentTypeInfo = type.GetTypeInfo(); + var declaringTypeInfo = declaringType.GetTypeInfo(); + while (currentTypeInfo != null && currentTypeInfo != declaringTypeInfo) + { + // We've found a 'more proximal' public definition + var declaredProperty = currentTypeInfo.GetDeclaredProperty(propertyHelper.Name); + if (declaredProperty != null) + { + ignoreProperty = true; + break; + } + + if (currentTypeInfo.BaseType != null) + { + currentTypeInfo = currentTypeInfo.BaseType.GetTypeInfo(); + } + + } + + if (!ignoreProperty) + { + filteredProperties.Add(propertyHelper); + } + } + + result = filteredProperties.ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); + visiblePropertiesCache.TryAdd(type, result); + return result; + } + + protected static IDictionary GetProperties( + Type type, + Func createPropertyHelper, + ConcurrentDictionary> cache) + { + // Unwrap nullable types. This means Nullable.Value and Nullable.HasValue will not be + // part of the sequence of properties returned by this method. + type = Nullable.GetUnderlyingType(type) ?? type; + + IDictionary fastProperties; + if (!cache.TryGetValue(type, out fastProperties)) + { + var candidates = GetCandidateProperties(type); + fastProperties = candidates.Select(p => createPropertyHelper(p)).ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase); + cache.TryAdd(type, fastProperties); + } + + return fastProperties; + } + + private static IEnumerable GetCandidateProperties(Type type) + { + // We avoid loading indexed properties using the Where statement. + var properties = type.GetRuntimeProperties().Where(IsCandidateProperty); + + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsInterface) + { + // Reflection does not return information about inherited properties on the interface itself. + properties = properties.Concat(typeInfo.ImplementedInterfaces.SelectMany( + interfaceType => interfaceType.GetRuntimeProperties().Where(IsCandidateProperty))); + } + + return properties; + } + + // Indexed properties are not useful (or valid) for grabbing properties off an object. + private static bool IsCandidateProperty(PropertyInfo property) + { + return property.GetIndexParameters().Length == 0 && + property.GetMethod != null && + property.GetMethod.IsPublic && + !property.GetMethod.IsStatic; + } + + private static ConcurrentDictionary> CreateVolatileCache() + { + return new ConcurrentDictionary>(); + } + + class PropertyKey : Tuple + { + public PropertyKey(Type type, string propertyName) + : base(type, propertyName) + { + } + public Type Type { get { return base.Item1; } } + public string PropertyName { get { return base.Item2; } } + } + } +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/ComponentModel/GenericListTypeConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/GenericListTypeConverter.cs deleted file mode 100644 index f5253dd01b..0000000000 --- a/src/Libraries/SmartStore.Core/ComponentModel/GenericListTypeConverter.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; -using System.Linq; - -namespace SmartStore.Core.ComponentModel -{ - public class GenericListTypeConverter : TypeConverter - { - protected readonly TypeConverter _typeConverter; - - public GenericListTypeConverter() - { - _typeConverter = TypeDescriptor.GetConverter(typeof(T)); - if (_typeConverter == null) - throw new InvalidOperationException("No type converter exists for type " + typeof(T).FullName); - } - - protected virtual string[] GetStringArray(string input) - { - if (!String.IsNullOrEmpty(input)) - { - string[] result = input.Split(','); - Array.ForEach(result, s => s.Trim()); - return result; - } - else - return new string[0]; - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - - if (sourceType == typeof(string)) - { - string[] items = GetStringArray(sourceType.ToString()); - return (items.Count() > 0); - } - - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string) - { - string[] items = GetStringArray((string)value); - var result = new List(); - Array.ForEach(items, s => - { - object item = _typeConverter.ConvertFromInvariantString(s); - if (item != null) - { - result.Add((T)item); - } - }); - - return result; - } - return base.ConvertFrom(context, culture, value); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string)) - { - string result = string.Empty; - if (((IList)value) != null) - { - //we don't use string.Join() because it doesn't support invariant culture - for (int i = 0; i < ((IList)value).Count; i++) - { - var str1 = Convert.ToString(((IList)value)[i], CultureInfo.InvariantCulture); - result += str1; - //don't add comma after the last element - if (i != ((IList)value).Count - 1) - result += ","; - } - } - return result; - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } -} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs new file mode 100644 index 0000000000..1049481e35 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/HybridExpando.cs @@ -0,0 +1,496 @@ +#region License +/* + ************************************************************** + * Author: Rick Strahl + * © West Wind Technologies, 2012 + * http://www.west-wind.com/ + * + * Created: Feb 2, 2012 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + ************************************************************** +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Dynamic; +using System.Reflection; +using System.Collections; + +namespace SmartStore.ComponentModel +{ + /// + /// Class that provides extensible properties and methods to an + /// existing object when cast to dynamic. This + /// dynamic object stores 'extra' properties in a dictionary or + /// checks the actual properties of the instance passed via + /// constructor. + /// + /// This class can be subclassed to extend an existing type or + /// you can pass in an instance to extend. Properties (both + /// dynamic and strongly typed) can be accessed through an + /// indexer. + /// + /// This type allows you three ways to access its properties: + /// + /// Directly: any explicitly declared properties are accessible + /// Dynamic: dynamic cast allows access to dictionary and native properties/methods + /// Dictionary: Any of the extended properties are accessible via IDictionary interface + /// + [Serializable] + public class HybridExpando : DynamicObject, IDictionary + { + /// + /// Instance of object passed in + /// + private object _instance; + + /// + /// Cached type of the instance + /// + private Type _instanceType; + + /// + /// String Dictionary that contains the extra dynamic values + /// stored on this object/instance + /// + /// Using PropertyBag to support XML Serialization of the dictionary + public PropertyBag Properties = new PropertyBag(); + + /// + /// This constructor just works off the internal dictionary and any + /// public properties of this object. + /// + /// Note you can subclass Expando. + /// + public HybridExpando() + { + Initialize(this); + } + + /// + /// Allows passing in an existing instance variable to 'extend'. + /// + /// + /// You can pass in null here if you don't want to + /// check native properties and only check the Dictionary! + /// + /// + public HybridExpando(object instance) + { + Initialize(instance); + } + + protected void Initialize(object instance) + { + _instance = instance; + if (instance != null) + _instanceType = instance.GetType(); + } + + protected object WrappedObject + { + get { return _instance; } + } + + public override IEnumerable GetDynamicMemberNames() + { + foreach (var prop in this.GetProperties(false)) + yield return prop.Key; + } + + + /// + /// Try to retrieve a member by name first from instance properties + /// followed by the collection entries. + /// + /// + /// + /// + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + return TryGetMemberCore(binder.Name, out result); + } + + protected virtual bool TryGetMemberCore(string name, out object result) + { + result = null; + + // first check the Properties collection for member + if (Properties.Keys.Contains(name)) + { + result = Properties[name]; + return true; + } + + // Next check for public properties via Reflection + if (_instance != null) + { + try + { + return GetProperty(_instance, name, out result); + } + catch { } + } + + // failed to retrieve a property + result = null; + return false; + } + + + /// + /// Property setter implementation tries to retrieve value from instance + /// first then into this object + /// + /// + /// + /// + public override bool TrySetMember(SetMemberBinder binder, object value) + { + return TrySetMemberCore(binder.Name, value); + } + + protected virtual bool TrySetMemberCore(string name, object value) + { + // first check to see if there's a native property to set + if (_instance != null) + { + try + { + bool result = SetProperty(_instance, name, value); + if (result) + return true; + } + catch { } + } + + // no match - set or add to dictionary + Properties[name] = value; + return true; + } + + /// + /// Dynamic invocation method. Currently allows only for Reflection based + /// operation (no ability to add methods dynamically). + /// + /// + /// + /// + /// + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + if (_instance != null) + { + try + { + // check instance passed in for methods to invoke + if (InvokeMethod(_instance, binder.Name, args, out result)) + return true; + } + catch { } + } + + result = null; + return false; + } + + + /// + /// Reflection Helper method to retrieve a property + /// + /// + /// + /// + /// + protected bool GetProperty(object instance, string name, out object result) + { + var fastProp = _instanceType != null ? FastProperty.GetProperty(_instanceType, name, PropertyCachingStrategy.EagerCached) : null; + if (fastProp != null) + { + result = fastProp.GetValue(instance ?? this); + return true; + } + + result = null; + return false; + } + + /// + /// Reflection helper method to set a property value + /// + /// + /// + /// + /// + protected bool SetProperty(object instance, string name, object value) + { + var fastProp = _instanceType != null ? FastProperty.GetProperty(_instanceType, name, PropertyCachingStrategy.EagerCached) : null; + if (fastProp != null) + { + fastProp.SetValue(instance ?? this, value); + return true; + } + + return false; + } + + /// + /// Reflection helper method to invoke a method + /// + /// + /// + /// + /// + /// + protected bool InvokeMethod(object instance, string name, object[] args, out object result) + { + // Look at the instanceType + var mi = _instanceType != null ? _instanceType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public) : null; + if (mi != null) + { + result = mi.Invoke(instance ?? this, args); + return true; + } + + result = null; + return false; + } + + + /// + /// Convenience method that provides a string Indexer + /// to the Properties collection AND the strongly typed + /// properties of the object by name. + /// + /// // dynamic + /// exp["Address"] = "112 nowhere lane"; + /// // strong + /// var name = exp["StronglyTypedProperty"] as string; + /// + /// + /// The getter checks the Properties dictionary first + /// then looks in PropertyInfo for properties. + /// The setter checks the instance properties before + /// checking the Properties dictionary. + /// + /// + /// + /// + public object this[string key] + { + get + { + object result = null; + if (!TryGetMemberCore(key, out result)) + { + throw new KeyNotFoundException(); + } + + return result; + } + set + { + TrySetMemberCore(key, value); + } + } + + + /// + /// Returns all properties + /// + /// + /// + public IEnumerable> GetProperties(bool includeInstanceProperties = false) + { + foreach (var key in this.Properties.Keys) + { + yield return new KeyValuePair(key, this.Properties[key]); + } + + if (includeInstanceProperties && _instance != null) + { + foreach (var prop in FastProperty.GetProperties(_instance).Values) + { + if (!this.Properties.ContainsKey(prop.Name)) + { + yield return new KeyValuePair(prop.Name, prop.GetValue(_instance)); + } + } + } + + } + + /// + /// Checks whether a property exists in the Property collection + /// or as a property on the instance + /// + /// + /// + public bool Contains(KeyValuePair item, bool includeInstanceProperties = false) + { + return this.Contains(item.Key, includeInstanceProperties); + } + + /// + /// Checks whether a property exists in the Property collection + /// or as a property on the instance + /// + /// + /// + /// + public bool Contains(string propertyName, bool includeInstanceProperties = false) + { + if (Properties.ContainsKey(propertyName)) + { + return true; + } + + if (includeInstanceProperties && _instance != null) + { + return FastProperty.GetProperties(_instance).ContainsKey(propertyName); + } + + return false; + } + + #region IDictionary + + ICollection IDictionary.Keys + { + get + { + return GetProperties(true).Select(x => x.Key).AsReadOnly(); + } + } + + ICollection IDictionary.Values + { + get + { + return GetProperties(true).Select(x => x.Value).AsReadOnly(); + } + } + + int ICollection>.Count + { + get + { + var count = Properties.Count; + if (_instanceType != null) + { + count += FastProperty.GetProperties(_instanceType).Count; + } + + return count; + } + } + + bool ICollection>.IsReadOnly + { + get + { + return false; + } + } + + object IDictionary.this[string key] + { + get + { + return this[key]; + } + + set + { + this[key] = value; + } + } + + bool IDictionary.ContainsKey(string key) + { + return Contains(key, true); + } + + void IDictionary.Add(string key, object value) + { + throw new NotImplementedException(); + } + + bool IDictionary.Remove(string key) + { + throw new NotImplementedException(); + } + + public bool TryGetValue(string key, out object value) + { + value = null; + + if (this.Contains(key, true)) + { + value = this[key]; + return true; + } + + return false; + } + + void ICollection>.Add(KeyValuePair item) + { + throw new NotImplementedException(); + } + + void ICollection>.Clear() + { + throw new NotImplementedException(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return Contains(item.Key, true); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + bool ICollection>.Remove(KeyValuePair item) + { + throw new NotImplementedException(); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return GetProperties(true).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetProperties(true).GetEnumerator(); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs b/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs index fb2ab77767..bec72dcea5 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/PropertyBag.cs @@ -181,7 +181,7 @@ public void WriteXml(System.Xml.XmlWriter writer) writer.WriteStartElement("item"); writer.WriteStartElement("key"); - writer.WriteString(key as string); + writer.WriteString(key); writer.WriteEndElement(); writer.WriteStartElement("value"); @@ -306,8 +306,7 @@ public bool FromXml(string xml) if (string.IsNullOrEmpty(xml)) return true; - var result = SerializationUtils.DeSerializeObject(xml, - this.GetType()) as PropertyBag; + var result = SerializationUtils.DeSerializeObject(xml, this.GetType()) as PropertyBag; if (result != null) { foreach (var item in result) diff --git a/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs b/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs index 263e516ef5..e36995facd 100644 --- a/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs +++ b/src/Libraries/SmartStore.Core/ComponentModel/SerializationUtils.cs @@ -34,20 +34,13 @@ using System; using System.IO; using System.Text; -//using System.Reflection; -using Fasterflect; - using System.Xml; using System.Xml.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Diagnostics; -using System.Runtime.Serialization; namespace SmartStore.ComponentModel { - - // Serialization specific code - internal static class SerializationUtils { /// @@ -194,25 +187,25 @@ public static bool SerializeObject(object instance, out string xmlResultString, return true; } - - /// - /// Serializes an object instance to a file. - /// - /// the object instance to serialize - /// - /// determines whether XML serialization or binary serialization is used - /// - public static bool SerializeObject(object instance, out byte[] resultBuffer, bool throwExceptions = false) + /// + /// Serializes an object instance to a file. + /// + /// the object instance to serialize + /// + /// + /// + public static bool SerializeObject(object instance, out byte[] resultBuffer, bool throwExceptions = false) { bool retVal = true; + resultBuffer = null; - MemoryStream ms = null; + var ms = new MemoryStream(); try { - BinaryFormatter serializer = new BinaryFormatter(); - ms = new MemoryStream(); + var serializer = new BinaryFormatter(); serializer.Serialize(ms, instance); - } + resultBuffer = ms.ToArray(); + } catch (Exception ex) { Debug.Write("SerializeObject failed with : " + ex.GetBaseException().Message, "West Wind"); @@ -223,12 +216,9 @@ public static bool SerializeObject(object instance, out byte[] resultBuffer, boo } finally { - if (ms != null) - ms.Close(); + ms.Close(); } - resultBuffer = ms.ToArray(); - return retVal; } @@ -419,17 +409,17 @@ public static object DeSerializeObject(byte[] buffer, Type objectType, bool thro /// public static string ObjectToString(object instance, string separator, ObjectToStringTypes type) { - var fi = instance.GetType().Fields(); + var fi = instance.GetType().GetFields(); string output = string.Empty; if (type == ObjectToStringTypes.Properties || type == ObjectToStringTypes.PropertiesAndFields) { - foreach (var property in instance.GetType().Properties()) + foreach (var property in instance.GetType().GetProperties()) { try { - output += property.Name + ":" + instance.GetPropertyValue(property.Name).ToString() + separator; + output += property.Name + ":" + property.GetValue(instance, null).ToString() + separator; } catch { @@ -444,7 +434,7 @@ public static string ObjectToString(object instance, string separator, ObjectToS { try { - output = output + field.Name + ": " + instance.GetFieldValue(field.Name).ToString() + separator; + output = output + field.Name + ": " + field.GetValue(instance).ToString() + separator; } catch { diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/BooleanConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/BooleanConverter.cs new file mode 100644 index 0000000000..11e6c6c941 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/BooleanConverter.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.ComponentModel +{ + [SuppressMessage("ReSharper", "CanBeReplacedWithTryCastAndCheckForNull")] + public class BooleanConverter : TypeConverterBase + { + private readonly HashSet _trueValues; + private readonly HashSet _falseValues; + + public BooleanConverter(string[] trueValues, string[] falseValues) + : base(typeof(bool)) + { + _trueValues = new HashSet(trueValues, StringComparer.OrdinalIgnoreCase); + _falseValues = new HashSet(falseValues, StringComparer.OrdinalIgnoreCase); + } + + public ICollection TrueValues + { + get { return _trueValues; } + } + + public ICollection FalseValues + { + get { return _falseValues; } + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value is short) + { + if ((short)value == 0) + { + return false; + } + if ((short)value == 1) + { + return true; + } + } + + if (value is string) + { + var str = (string)value; + + bool b; + if (bool.TryParse(str, out b)) + { + return b; + } + + short sh; + if (short.TryParse(str, out sh)) + { + if (sh == 0) + { + return false; + } + if (sh == 1) + { + return true; + } + } + + str = (str.NullEmpty() ?? string.Empty).Trim(); + if (_trueValues.Contains(str)) + { + return true; + } + + if (_falseValues.Contains(str)) + { + return false; + } + } + + return base.ConvertFrom(culture, value); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/DateTimeConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/DateTimeConverter.cs new file mode 100644 index 0000000000..b357dcddb8 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/DateTimeConverter.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.ComponentModel +{ + [SuppressMessage("ReSharper", "CanBeReplacedWithTryCastAndCheckForNull")] + public class DateTimeConverter : TypeConverterBase + { + public DateTimeConverter() + : base(typeof(DateTime)) + { + } + + public override bool CanConvertFrom(Type type) + { + return type == typeof(string) + || type == typeof(long) + || type == typeof(double) + || type == typeof(TimeSpan) + || base.CanConvertFrom(type); + } + + public override bool CanConvertTo(Type type) + { + return type == typeof(string) + || type == typeof(long) + || type == typeof(double) + || type == typeof(DateTimeOffset) + || type == typeof(TimeSpan) + || base.CanConvertTo(type); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value is TimeSpan) + { + var span = (TimeSpan)value; + return new DateTime(span.Ticks); + } + + if (value is string) + { + var str = (string)value; + + DateTime time; + if (DateTime.TryParse(str, culture, DateTimeStyles.None, out time)) + { + return time; + } + + long lng; + if (long.TryParse(str, NumberStyles.None, culture, out lng)) + { + return lng.FromUnixTime(); + } + + double dbl; + if (double.TryParse(str, NumberStyles.AllowDecimalPoint, culture, out dbl)) + { + return DateTime.FromOADate(dbl); + } + } + + if (value is long) + { + return ((long)value).FromUnixTime(); + } + + if (value is double) + { + return DateTime.FromOADate((double)value); + } + + return base.ConvertFrom(culture, value); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + var time = (DateTime)value; + + if (to == typeof(DateTimeOffset)) + { + return new DateTimeOffset(time); + } + + if (to == typeof(TimeSpan)) + { + return new TimeSpan(time.Ticks); + } + + if (to == typeof(double)) + { + return time.ToOADate(); + } + + if (to == typeof(long)) + { + return time.ToUnixTime(); + } + + return base.ConvertTo(culture, format, value, to); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs new file mode 100644 index 0000000000..1980693205 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/EnumerableConverter.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; + +namespace SmartStore.ComponentModel +{ + [SuppressMessage("ReSharper", "CanBeReplacedWithTryCastAndCheckForNull")] + public class EnumerableConverter : TypeConverterBase + { + private readonly Func, object> _activator; + private readonly ITypeConverter _elementTypeConverter; + + public EnumerableConverter(Type sequenceType) + : base(typeof(object)) + { + _elementTypeConverter = TypeConverterFactory.GetConverter(); + if (_elementTypeConverter == null) + throw new InvalidOperationException("No type converter exists for type " + typeof(T).FullName); + + _activator = CreateSequenceActivator(sequenceType); + } + + [SuppressMessage("ReSharper", "RedundantLambdaSignatureParentheses")] + private static Func, object> CreateSequenceActivator(Type sequenceType) + { + // Default is IEnumerable + Func, object> activator = null; + + var t = sequenceType; + + if (t == typeof(IEnumerable)) + { + activator = (x) => x; + } + else if (t == (typeof(IReadOnlyCollection)) || t == (typeof(IReadOnlyList))) + { + activator = (x) => x.AsReadOnly(); + } + else if (t.IsAssignableFrom(typeof(List))) + { + activator = (x) => x.ToList(); + } + else if (t.IsAssignableFrom(typeof(HashSet))) + { + activator = (x) => new HashSet(x); + } + else if (t.IsAssignableFrom(typeof(Queue))) + { + activator = (x) => new Queue(x); + } + else if (t.IsAssignableFrom(typeof(Stack))) + { + activator = (x) => new Stack(x); + } + else if (t.IsAssignableFrom(typeof(LinkedList))) + { + activator = (x) => new LinkedList(x); + } + else if (t.IsAssignableFrom(typeof(ConcurrentBag))) + { + activator = (x) => new ConcurrentBag(x); + } + else if (t.IsAssignableFrom(typeof(ArraySegment))) + { + activator = (x) => new ArraySegment(x.ToArray()); + } + + if (activator == null) + { + throw new InvalidOperationException("'{0}' is not a valid type for enumerable conversion.".FormatInvariant(sequenceType.FullName)); + } + + return activator; + } + + public override bool CanConvertFrom(Type type) + { + return type == typeof(string) || typeof(IConvertible).IsAssignableFrom(type); + } + + public override bool CanConvertTo(Type type) + { + return type == typeof(string); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value == null) + { + return _activator(Enumerable.Empty()); + } + + if (value is string) + { + var items = GetStringArray((string)value); + + var result = items + .Select(x => _elementTypeConverter.ConvertFrom(culture, x)) + .Where(x => x != null) + .Cast(); + + return _activator(result); + } + + if (value is IConvertible) + { + var result2 = (new object[] { value }) + .Select(x => Convert.ChangeType(value, typeof(T))) + .Cast(); + + return _activator(result2); + } + + return base.ConvertFrom(culture, value); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + if (to == typeof(string)) + { + string result = string.Empty; + var enumerable = value as IEnumerable; + + if (enumerable != null) + { + // we don't use string.Join() because it doesn't support invariant culture + foreach (var token in enumerable) + { + var str = _elementTypeConverter.ConvertTo(culture, format, token, typeof(string)); + result += str + ","; + } + + result = result.TrimEnd(','); + } + + return result; + } + + return base.ConvertTo(culture, format, value, to); + } + + protected virtual string[] GetStringArray(string input) + { + if (!String.IsNullOrEmpty(input)) + { + var splitChar = '|'; + + if (input.IndexOf(splitChar) < 0) + { + if (input.IndexOf(';') > -1) + { + splitChar = ';'; + } + else if (input.IndexOf(',') > -1) + { + splitChar = ','; + } + } + + var result = input.Split(new char[] { splitChar }, StringSplitOptions.RemoveEmptyEntries); + // ReSharper disable once ReturnValueOfPureMethodIsNotUsed + Array.ForEach(result, s => s.Trim()); + return result; + } + + return new string[0]; + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ITypeConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ITypeConverter.cs new file mode 100644 index 0000000000..c76ecba218 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ITypeConverter.cs @@ -0,0 +1,83 @@ +using System; +using System.Globalization; + +namespace SmartStore.ComponentModel +{ + /// + /// Converts objects. + /// + public interface ITypeConverter + { + /// + /// Returns whether this converter can convert an object of the given type to the type of this converter. + /// + /// A Type that represents the type you want to convert from. + /// true if this converter can perform the conversion; otherwise, false. + bool CanConvertFrom(Type type); + + /// + /// Returns whether this converter can convert the object to the specified type. + /// + /// A Type that represents the type you want to convert to. + /// true if this converter can perform the conversion; otherwise, false. + bool CanConvertTo(Type type); + + /// + /// Converts the given value to the type of this converter. + /// + /// The to use as the current culture. If null is passed, the invariant culture is assumed. + /// The object to convert. + /// An object that represents the converted value. + object ConvertFrom(CultureInfo culture, object value); + + /// + /// Converts the given value object to the specified type, using the arguments. + /// + /// The to use as the current culture. If null is passed, the invariant culture is assumed. + /// A standard or custom format expression. + /// The object to convert. + /// The type to convert the value parameter to. + /// An Object that represents the converted value. + object ConvertTo(CultureInfo culture, string format, object value, Type to); + } + + public static class ITypeConverterExtensions + { + public static object ConvertFrom(this ITypeConverter converter, object value) + { + return converter.ConvertFrom(CultureInfo.InvariantCulture, value); + } + + public static object ConvertTo(this ITypeConverter converter, object value, Type to) + { + return converter.ConvertTo(CultureInfo.InvariantCulture, null, value, to); + } + + public static object SafeConvert(this ITypeConverter converter, string value) + { + try + { + if (converter != null && value.HasValue() && converter.CanConvertFrom(typeof(string))) + { + return converter.ConvertFrom(value); + } + } + catch (Exception exc) + { + exc.Dump(); + } + + return null; + } + + public static bool IsEqual(this ITypeConverter converter, string value, object compareWith) + { + object convertedObject = converter.SafeConvert(value); + + if (convertedObject != null && compareWith != null) + return convertedObject.Equals(compareWith); + + return false; + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/NullableConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/NullableConverter.cs new file mode 100644 index 0000000000..d11c53409f --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/NullableConverter.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.ComponentModel +{ + [SuppressMessage("ReSharper", "TryCastAlwaysSucceeds")] + public class NullableConverter : TypeConverterBase + { + private readonly bool _underlyingTypeIsConvertible; + + public NullableConverter(Type type) + : base(type) + { + NullableType = type; + UnderlyingType = Nullable.GetUnderlyingType(type); + + if (UnderlyingType == null) + { + throw Error.Argument("type", "Type is not a nullable type."); + } + + _underlyingTypeIsConvertible = typeof(IConvertible).IsAssignableFrom(UnderlyingType) && !UnderlyingType.IsEnum; + UnderlyingTypeConverter = TypeConverterFactory.GetConverter(UnderlyingType); + } + + public Type NullableType + { + get; + private set; + } + + public Type UnderlyingType + { + get; + private set; + } + + public ITypeConverter UnderlyingTypeConverter + { + get; + private set; + } + + public override bool CanConvertFrom(Type type) + { + if (type == this.UnderlyingType) + { + return true; + } + + if (UnderlyingTypeConverter.CanConvertFrom(type)) + { + return true; + } + + if (_underlyingTypeIsConvertible && type != typeof(string) && typeof(IConvertible).IsAssignableFrom(type)) + { + return true; + } + + return false; + } + + public override bool CanConvertTo(Type type) + { + Console.WriteLine("NullableConverter can convert to {0}: {1}".FormatInvariant(type.Name, UnderlyingTypeConverter.CanConvertTo(type))); + + if (type == this.UnderlyingType) + { + return true; + } + + return UnderlyingTypeConverter.CanConvertTo(type); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if ((value == null) || (value.GetType() == this.UnderlyingType)) + { + return value; + } + + if ((value is string) && string.IsNullOrEmpty(value as string)) + { + return null; + } + + if (_underlyingTypeIsConvertible && !(value is string) && value is IConvertible) + { + // num > num? + return Convert.ChangeType(value, UnderlyingType, culture); + } + + return UnderlyingTypeConverter.ConvertFrom(culture, value); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + if ((to == this.UnderlyingType) && this.NullableType.IsInstanceOfType(value)) + { + return value; + } + + if (value == null) + { + if (to == typeof(string)) + { + return string.Empty; + } + } + + return UnderlyingTypeConverter.ConvertTo(culture, format, value, to); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ProductBundleDataConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ProductBundleDataConverter.cs new file mode 100644 index 0000000000..599431116f --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ProductBundleDataConverter.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml.Serialization; +using SmartStore.Core.Domain.Catalog; + +namespace SmartStore.ComponentModel +{ + [SuppressMessage("ReSharper", "TryCastAlwaysSucceeds")] + public class ProductBundleDataConverter : TypeConverterBase + { + private readonly bool _forList; + + public ProductBundleDataConverter(bool forList) + : base(typeof(object)) + { + _forList = forList; + } + + public override bool CanConvertFrom(Type type) + { + return type == typeof(string); + } + + public override bool CanConvertTo(Type type) + { + return type == typeof(string); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value is string) + { + object result = null; + string str = value as string; + if (!string.IsNullOrEmpty(str)) + { + try + { + using (var tr = new StringReader(str)) + { + var serializer = new XmlSerializer(_forList ? typeof(List) : typeof(ProductBundleItemOrderData)); + result = serializer.Deserialize(tr); + } + } + catch + { + // xml error + } + } + + return result; + } + + return base.ConvertFrom(culture, value); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + if (to == typeof(string)) + { + if (value != null && (value is ProductBundleItemOrderData || value is IList)) + { + var sb = new StringBuilder(); + using (var tw = new StringWriter(sb)) + { + var serializer = new XmlSerializer(_forList ? typeof(List) : typeof(ProductBundleItemOrderData)); + serializer.Serialize(tw, value); + return sb.ToString(); + } + } + else + { + return string.Empty; + } + } + + return base.ConvertTo(culture, format, value, to); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ShippingOptionConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ShippingOptionConverter.cs new file mode 100644 index 0000000000..b79c9a5f2f --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/ShippingOptionConverter.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Text; +using System.Xml.Serialization; +using SmartStore.Core.Domain.Shipping; + +namespace SmartStore.ComponentModel +{ + [SuppressMessage("ReSharper", "TryCastAlwaysSucceeds")] + public class ShippingOptionConverter : TypeConverterBase + { + private readonly bool _forList; + + public ShippingOptionConverter(bool forList) + : base(typeof(object)) + { + _forList = forList; + } + + public override bool CanConvertFrom(Type type) + { + return type == typeof(string); + } + + public override bool CanConvertTo(Type type) + { + return type == typeof(string); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value is string) + { + object result = null; + string str = value as string; + if (!String.IsNullOrEmpty(str)) + { + try + { + using (var tr = new StringReader(str)) + { + var serializer = new XmlSerializer(_forList ? typeof(List) : typeof(ShippingOption)); + result = serializer.Deserialize(tr); + } + } + catch + { + // xml error + } + } + + return result; + } + + return base.ConvertFrom(culture, value); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + if (to == typeof(string)) + { + if (value != null && (value is ShippingOption || value is IList)) + { + var sb = new StringBuilder(); + using (var tw = new StringWriter(sb)) + { + var serializer = new XmlSerializer(_forList ? typeof(List) : typeof(ShippingOption)); + serializer.Serialize(tw, value); + return sb.ToString(); + } + } + else + { + return string.Empty; + } + } + + return base.ConvertTo(culture, format, value, to); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TimeSpanConverter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TimeSpanConverter.cs new file mode 100644 index 0000000000..656355d8e8 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TimeSpanConverter.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.ComponentModel +{ + [SuppressMessage("ReSharper", "CanBeReplacedWithTryCastAndCheckForNull")] + public class TimeSpanConverter : TypeConverterBase + { + public TimeSpanConverter() + : base(typeof(TimeSpan)) + { + } + + public override bool CanConvertFrom(Type type) + { + return type == typeof(string) + || type == typeof(DateTime) + || base.CanConvertFrom(type); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value is DateTime) + { + var time = (DateTime)value; + return new TimeSpan(time.Ticks); + } + + if (value is string) + { + var str = (string)value; + + TimeSpan span; + if (TimeSpan.TryParse(str, culture, out span)) + { + return span; + } + + long lng; + if (long.TryParse(str, NumberStyles.None, culture, out lng)) + { + return new TimeSpan(lng.FromUnixTime().Ticks); + } + + double dbl; + if (double.TryParse(str, NumberStyles.None, culture, out dbl)) + { + return new TimeSpan(DateTime.FromOADate(dbl).Ticks); + } + } + + try + { + return (TimeSpan)System.Convert.ChangeType(value, typeof(TimeSpan), culture); + } + catch { } + + return base.ConvertFrom(culture, value); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterAdapter.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterAdapter.cs new file mode 100644 index 0000000000..b7ed897169 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterAdapter.cs @@ -0,0 +1,37 @@ +using System; +using System.ComponentModel; +using System.Globalization; + +namespace SmartStore.ComponentModel +{ + internal class TypeConverterAdapter : TypeConverterBase + { + private readonly TypeConverter _converter; + + public TypeConverterAdapter(TypeConverter converter) + : base(typeof(object)) + { + _converter = converter; + } + + public override bool CanConvertFrom(Type type) + { + return _converter != null && _converter.CanConvertFrom(type); + } + + public override bool CanConvertTo(Type type) + { + return _converter != null && _converter.CanConvertTo(type); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + return _converter.ConvertFrom(null, culture, value); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + return _converter.ConvertTo(null, culture, value, to); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterBase.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterBase.cs new file mode 100644 index 0000000000..958cd9274c --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterBase.cs @@ -0,0 +1,68 @@ +using System; +using System.ComponentModel; +using System.Globalization; + +namespace SmartStore.ComponentModel +{ + public abstract class TypeConverterBase : ITypeConverter + { + private readonly Lazy _systemConverter; + private readonly Type _type; + + protected TypeConverterBase(Type type) + { + Guard.ArgumentNotNull(() => type); + + _type = type; + _systemConverter = new Lazy(() => TypeDescriptor.GetConverter(type), true); + } + + public TypeConverter SystemConverter + { + get + { + if (_type == typeof(object)) + { + return null; + } + + return _systemConverter.Value; + } + } + + public virtual bool CanConvertFrom(Type type) + { + return SystemConverter != null && SystemConverter.CanConvertFrom(type); + } + + public virtual bool CanConvertTo(Type type) + { + return type == typeof(string) || (SystemConverter != null && SystemConverter.CanConvertTo(type)); + } + + public virtual object ConvertFrom(CultureInfo culture, object value) + { + if (SystemConverter != null) + { + return SystemConverter.ConvertFrom(null, culture, value); + } + + throw Error.InvalidCast(value.GetType(), _type); + } + + public virtual object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + if (SystemConverter != null) + { + return SystemConverter.ConvertTo(null, culture, value, to); + } + + if (value == null) + { + return string.Empty; + } + + return value.ToString(); + } + } +} diff --git a/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterFactory.cs b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterFactory.cs new file mode 100644 index 0000000000..4f25272dd8 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ComponentModel/TypeConversion/TypeConverterFactory.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.ComponentModel; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Shipping; + +namespace SmartStore.ComponentModel +{ + public static class TypeConverterFactory + { + private static readonly ConcurrentDictionary _typeConverters = new ConcurrentDictionary(); + + static TypeConverterFactory() + { + CreateDefaultConverters(); + } + + private static void CreateDefaultConverters() + { + _typeConverters.TryAdd(typeof(DateTime), new DateTimeConverter()); + _typeConverters.TryAdd(typeof(TimeSpan), new TimeSpanConverter()); + _typeConverters.TryAdd(typeof(bool), new BooleanConverter( + new [] { "yes", "y", "on", "wahr" }, + new [] { "no", "n", "off", "falsch" })); + + ITypeConverter converter = new ShippingOptionConverter(true); + _typeConverters.TryAdd(typeof(IList), converter); + _typeConverters.TryAdd(typeof(List), converter); + _typeConverters.TryAdd(typeof(ShippingOption), new ShippingOptionConverter(false)); + + converter = new ProductBundleDataConverter(true); + _typeConverters.TryAdd(typeof(IList), converter); + _typeConverters.TryAdd(typeof(List), converter); + _typeConverters.TryAdd(typeof(ProductBundleItemOrderData), new ProductBundleDataConverter(false)); + } + + public static void RegisterConverter(ITypeConverter typeConverter) + { + RegisterConverter(typeof(T), typeConverter); + } + + public static void RegisterConverter(Type type, ITypeConverter typeConverter) + { + Guard.ArgumentNotNull(() => type); + Guard.ArgumentNotNull(() => typeConverter); + + _typeConverters.TryAdd(type, typeConverter); + } + + public static ITypeConverter RemoveConverter(ITypeConverter typeConverter) + { + return RemoveConverter(typeof(T)); + } + + public static ITypeConverter RemoveConverter(Type type) + { + Guard.ArgumentNotNull(() => type); + + ITypeConverter converter = null; + _typeConverters.TryRemove(type, out converter); + return converter; + } + + public static ITypeConverter GetConverter() + { + return GetConverter(typeof(T)); + } + + public static ITypeConverter GetConverter(object component) + { + Guard.ArgumentNotNull(() => component); + + return GetConverter(component.GetType()); + } + + public static ITypeConverter GetConverter(Type type) + { + Guard.ArgumentNotNull(() => type); + + ITypeConverter converter; + if (_typeConverters.TryGetValue(type, out converter)) + { + return converter; + } + + var isGenericType = type.IsGenericType; + if (isGenericType) + { + var definition = type.GetGenericTypeDefinition(); + + // Nullables + if (definition == typeof(Nullable<>)) + { + converter = new NullableConverter(type); + RegisterConverter(type, converter); + return converter; + } + + // Sequence types + var genericArgs = type.GetGenericArguments(); + var isEnumerable = genericArgs.Length == 1 && type.IsSubClass(typeof(IEnumerable<>)); + if (isEnumerable) + { + converter = (ITypeConverter)Activator.CreateInstance(typeof(EnumerableConverter<>).MakeGenericType(genericArgs[0]), type); + RegisterConverter(type, converter); + return converter; + } + } + + // default fallback + converter = new TypeConverterAdapter(TypeDescriptor.GetConverter(type)); + RegisterConverter(type, converter); + return converter; + } + } +} diff --git a/src/Libraries/SmartStore.Core/Data/DataSettings.cs b/src/Libraries/SmartStore.Core/Data/DataSettings.cs index e428ea55dd..8743fce97f 100644 --- a/src/Libraries/SmartStore.Core/Data/DataSettings.cs +++ b/src/Libraries/SmartStore.Core/Data/DataSettings.cs @@ -104,6 +104,12 @@ public static void Delete() #region Instance members + public Version AppVersion + { + get; + set; + } + public string DataProvider { get; @@ -174,6 +180,10 @@ public virtual bool Load() if (settings.Any()) { this.RawDataSettings.AddRange(settings); + if (settings.ContainsKey("AppVersion")) + { + this.AppVersion = new Version(settings["AppVersion"]); + } if (settings.ContainsKey("DataProvider")) { this.DataProvider = settings["DataProvider"]; @@ -196,6 +206,7 @@ public void Reset() using (s_rwLock.GetWriteLock()) { this.RawDataSettings.Clear(); + this.AppVersion = null; this.DataProvider = null; this.DataConnectionString = null; s_installed = null; @@ -265,11 +276,11 @@ protected virtual IDictionary ParseSettings(string text) protected virtual string SerializeSettings() { - return string.Format("DataProvider: {0}{2}DataConnectionString: {1}{2}", - this.DataProvider, - this.DataConnectionString, - Environment.NewLine - ); + return string.Format("AppVersion: {0}{3}DataProvider: {1}{3}DataConnectionString: {2}{3}", + this.AppVersion.ToString(), + this.DataProvider, + this.DataConnectionString, + Environment.NewLine); } #endregion diff --git a/src/Libraries/SmartStore.Core/Data/DbContextScope.cs b/src/Libraries/SmartStore.Core/Data/DbContextScope.cs index 0bb34142df..93a7552c50 100644 --- a/src/Libraries/SmartStore.Core/Data/DbContextScope.cs +++ b/src/Libraries/SmartStore.Core/Data/DbContextScope.cs @@ -1,21 +1,40 @@ using System; using SmartStore.Core.Infrastructure; +using System.Linq.Expressions; +using System.Collections.Generic; +using System.Linq; namespace SmartStore.Core.Data { public class DbContextScope : IDisposable { - private readonly bool _autoDetectChangesEnabled; + private readonly IDbContext _ctx; + private readonly bool _autoDetectChangesEnabled; private readonly bool _proxyCreationEnabled; private readonly bool _validateOnSaveEnabled; - private readonly IDbContext _ctx; + private readonly bool _forceNoTracking; + private readonly bool _hooksEnabled; + private readonly bool _autoCommit; + private readonly bool _lazyLoading; + - public DbContextScope(IDbContext ctx = null, bool? autoDetectChanges = null, bool? proxyCreation = null, bool? validateOnSave = null) + public DbContextScope(IDbContext ctx = null, + bool? autoDetectChanges = null, + bool? proxyCreation = null, + bool? validateOnSave = null, + bool? forceNoTracking = null, + bool? hooksEnabled = null, + bool? autoCommit = null, + bool? lazyLoading = null) { _ctx = ctx ?? EngineContext.Current.Resolve(); _autoDetectChangesEnabled = _ctx.AutoDetectChangesEnabled; _proxyCreationEnabled = _ctx.ProxyCreationEnabled; _validateOnSaveEnabled = _ctx.ValidateOnSaveEnabled; + _forceNoTracking = _ctx.ForceNoTracking; + _hooksEnabled = _ctx.HooksEnabled; + _autoCommit = _ctx.AutoCommitEnabled; + _lazyLoading = _ctx.LazyLoadingEnabled; if (autoDetectChanges.HasValue) _ctx.AutoDetectChangesEnabled = autoDetectChanges.Value; @@ -25,7 +44,45 @@ public DbContextScope(IDbContext ctx = null, bool? autoDetectChanges = null, boo if (validateOnSave.HasValue) _ctx.ValidateOnSaveEnabled = validateOnSave.Value; - } + + if (forceNoTracking.HasValue) + _ctx.ForceNoTracking = forceNoTracking.Value; + + if (hooksEnabled.HasValue) + _ctx.HooksEnabled = hooksEnabled.Value; + + if (autoCommit.HasValue) + _ctx.AutoCommitEnabled = autoCommit.Value; + + if (lazyLoading.HasValue) + _ctx.LazyLoadingEnabled = lazyLoading.Value; + } + + public IDbContext DbContext + { + get { return _ctx; } + } + + public void LoadCollection( + TEntity entity, + Expression>> navigationProperty, + bool force = false, + Func, IQueryable> queryAction = null) + where TEntity : BaseEntity + where TCollection : BaseEntity + { + _ctx.LoadCollection(entity, navigationProperty, force, queryAction); + } + + public void LoadReference( + TEntity entity, + Expression> navigationProperty, + bool force = false) + where TEntity : BaseEntity + where TProperty : BaseEntity + { + _ctx.LoadReference(entity, navigationProperty, force); + } public int Commit() { @@ -37,6 +94,10 @@ public void Dispose() _ctx.AutoDetectChangesEnabled = _autoDetectChangesEnabled; _ctx.ProxyCreationEnabled = _proxyCreationEnabled; _ctx.ValidateOnSaveEnabled = _validateOnSaveEnabled; + _ctx.ForceNoTracking = _forceNoTracking; + _ctx.HooksEnabled = _hooksEnabled; + _ctx.AutoCommitEnabled = _autoCommit; + _ctx.LazyLoadingEnabled = _lazyLoading; } } diff --git a/src/Libraries/SmartStore.Core/Data/Hooks/HooksEventConsumer.cs b/src/Libraries/SmartStore.Core/Data/Hooks/HooksEventConsumer.cs index def515b630..2372dbba00 100644 --- a/src/Libraries/SmartStore.Core/Data/Hooks/HooksEventConsumer.cs +++ b/src/Libraries/SmartStore.Core/Data/Hooks/HooksEventConsumer.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using Autofac.Features.Metadata; @@ -50,9 +51,9 @@ public HooksEventConsumer( public void HandleEvent(PreActionHookEvent eventMessage) { - var entries = eventMessage.ModifiedEntries; + var entries = eventMessage.ModifiedEntries.ToArray(); - if (!entries.Any() || !_preHooks.Any()) + if (entries.Length == 0 || !_preHooks.Any()) return; foreach (var entry in entries) @@ -64,7 +65,11 @@ public void HandleEvent(PreActionHookEvent eventMessage) if (hook.HookStates == e.PreSaveState && hook.RequiresValidation == eventMessage.RequiresValidation) { var metadata = new HookEntityMetadata(e.PreSaveState); - hook.HookObject(e.Entity, metadata); + using (var scope = new DbContextScope(hooksEnabled: false)) + { + // dead end: don't let hooks call hooks again + hook.HookObject(e.Entity, metadata); + } if (metadata.HasStateChanged) { @@ -75,6 +80,7 @@ public void HandleEvent(PreActionHookEvent eventMessage) } } + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] private IEnumerable GetPreHookInstancesFor(Type hookedType) { if (_preHooksCache.ContainsKey(hookedType)) @@ -89,9 +95,9 @@ private IEnumerable GetPreHookInstancesFor(Type hookedType) public void HandleEvent(PostActionHookEvent eventMessage) { - var entries = eventMessage.ModifiedEntries; + var entries = eventMessage.ModifiedEntries.ToArray(); - if (!entries.Any() || !_postHooks.Any()) + if (entries.Length == 0 || !_postHooks.Any()) return; foreach (var entry in entries) @@ -103,7 +109,11 @@ public void HandleEvent(PostActionHookEvent eventMessage) if (hook.HookStates == e.PreSaveState) { var metadata = new HookEntityMetadata(e.PreSaveState); - hook.HookObject(e.Entity, metadata); + using (var scope = new DbContextScope(hooksEnabled: false)) + { + // dead end: don't let hooks call hooks again + hook.HookObject(e.Entity, metadata); + } } } } diff --git a/src/Libraries/SmartStore.Core/Data/IDbContext.cs b/src/Libraries/SmartStore.Core/Data/IDbContext.cs index b44aa4398b..cb276a03ac 100644 --- a/src/Libraries/SmartStore.Core/Data/IDbContext.cs +++ b/src/Libraries/SmartStore.Core/Data/IDbContext.cs @@ -1,7 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; using System.Data.Entity; +using System.Linq; +using System.Linq.Expressions; using System.Threading.Tasks; -using SmartStore.Core; namespace SmartStore.Core.Data { @@ -37,16 +41,32 @@ IList ExecuteStoredProcedureList(string commandText, params ob /// Executes sql by using SQL-Server Management Objects which supports GO statements. int ExecuteSqlThroughSmo(string sql); - // codehint: sm-add (required for UoW implementation) string Alias { get; } - // codehint: sm-add (increasing performance on bulk inserts) + // increasing performance on bulk operations bool ProxyCreationEnabled { get; set; } - bool AutoDetectChangesEnabled { get; set; } + bool LazyLoadingEnabled { get; set; } + bool AutoDetectChangesEnabled { get; set; } bool ValidateOnSaveEnabled { get; set; } bool HooksEnabled { get; set; } bool HasChanges { get; } + /// + /// Gets or sets a value indicating whether entities returned from queries + /// or created from stored procedures + /// should automatically be attached to the DbContext. + /// + /// + /// Set this to true only during long running processes (like export) + /// + bool ForceNoTracking { get; set; } + + /// + /// Gets or sets a value indicating whether database write operations + /// originating from repositories should be committed immediately. + /// + bool AutoCommitEnabled { get; set; } + /// /// Gets a list of modified properties for the specified entity /// @@ -65,26 +85,29 @@ IList ExecuteStoredProcedureList(string commandText, params ob /// Type of entity /// The entity instance to attach /// true when the entity is attched already, false otherwise - bool IsAttached(TEntity entity) where TEntity : BaseEntity, new(); + bool IsAttached(TEntity entity) where TEntity : BaseEntity; - /// - /// Detaches an entity from the current object context if it's attached - /// - /// Type of entity - /// The entity instance to detach - void DetachEntity(TEntity entity) where TEntity : BaseEntity, new(); + /// + /// Attaches an entity to the context or returns an already attached entity (if it was already attached) + /// + /// Type of entity + /// Entity + /// Attached entity + TEntity Attach(TEntity entity) where TEntity : BaseEntity; /// - /// Detaches an entity from the current object context + /// Detaches an entity from the current object context if it's attached /// + /// Type of entity /// The entity instance to detach - void Detach(object entity); + void DetachEntity(TEntity entity) where TEntity : BaseEntity; /// - /// Detaches all entities from the current object context + /// Detaches all entities of type TEntity from the current object context /// + /// When true, only entities in unchanged state get detached. /// The count of detached entities - int DetachAll(); + int DetachEntities(bool unchangedEntitiesOnly = true) where TEntity : class; /// /// Change the state of an entity object @@ -92,14 +115,28 @@ IList ExecuteStoredProcedureList(string commandText, params ob /// Type of entity /// The entity instance /// The new state - void ChangeState(TEntity entity, System.Data.Entity.EntityState newState); + void ChangeState(TEntity entity, System.Data.Entity.EntityState newState) where TEntity : BaseEntity; /// - /// Changes the object state to unchanged + /// Reloads the entity from the database overwriting any property values with values from the database. + /// The entity will be in the Unchanged state after calling this method. /// /// Type of entity /// The entity instance - /// true on success, false on failure - bool SetToUnchanged(TEntity entity); + void ReloadEntity(TEntity entity) where TEntity : BaseEntity; + + /// + /// Begins a transaction on the underlying store connection using the specified isolation level + /// + /// The database isolation level with which the underlying store transaction will be created + /// A transaction object wrapping access to the underlying store's transaction object + ITransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified); + + /// + /// Enables the user to pass in a database transaction created outside of the Database object if you want the Entity Framework to execute commands within that external transaction. Alternatively, pass in null to clear the framework's knowledge of that transaction. + /// + /// the external transaction + void UseTransaction(DbTransaction transaction); } + } diff --git a/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs b/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs new file mode 100644 index 0000000000..f3afa01d07 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Data/IDbContextExtensions.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using SmartStore.Core; +using SmartStore.Core.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Data.Entity; + +namespace SmartStore +{ + public static class IDbContextExtensions + { + + /// + /// Detaches all entities from the current object context + /// + /// When true, only entities in unchanged state get detached. + /// The count of detached entities + public static int DetachAll(this IDbContext ctx, bool unchangedEntitiesOnly = true) + { + return ctx.DetachEntities(unchangedEntitiesOnly); + } + + public static void DetachEntities(this IDbContext ctx, IEnumerable entities) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => ctx); + + entities.Each(x => ctx.DetachEntity(x)); + } + + /// + /// Changes the object state to unchanged + /// + /// Type of entity + /// + /// The entity instance + /// true on success, false on failure + public static bool SetToUnchanged(this IDbContext ctx, TEntity entity) where TEntity : BaseEntity + { + try + { + ctx.ChangeState(entity, System.Data.Entity.EntityState.Unchanged); + return true; + } + catch (Exception ex) + { + ex.Dump(); + return false; + } + } + + public static IQueryable QueryForCollection( + this IDbContext ctx, + TEntity entity, + Expression>> navigationProperty) + where TEntity : BaseEntity + where TCollection : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => navigationProperty); + + var dbContext = ctx as DbContext; + if (dbContext == null) + { + throw new NotSupportedException("The IDbContext instance does not inherit from DbContext (EF)"); + } + + return dbContext.Entry(entity).Collection(navigationProperty).Query(); + } + + public static IQueryable QueryForReference( + this IDbContext ctx, + TEntity entity, + Expression> navigationProperty) + where TEntity : BaseEntity + where TProperty : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => navigationProperty); + + var dbContext = ctx as DbContext; + if (dbContext == null) + { + throw new NotSupportedException("The IDbContext instance does not inherit from DbContext (EF)"); + } + + return dbContext.Entry(entity).Reference(navigationProperty).Query(); + } + + public static void LoadCollection( + this IDbContext ctx, + TEntity entity, + Expression>> navigationProperty, + bool force = false, + Func, IQueryable> queryAction = null) + where TEntity : BaseEntity + where TCollection : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => navigationProperty); + + var dbContext = ctx as DbContext; + if (dbContext == null) + { + throw new NotSupportedException("The IDbContext instance does not inherit from DbContext (EF)"); + } + + var entry = dbContext.Entry(entity); + var collection = entry.Collection(navigationProperty); + + if (force) + { + collection.IsLoaded = false; + } + + if (!collection.IsLoaded) + { + if (queryAction != null || ctx.ForceNoTracking) + { + var query = !ctx.ForceNoTracking + ? collection.Query() + : collection.Query().AsNoTracking(); + + var myQuery = queryAction != null + ? queryAction(query) + : query; + + collection.CurrentValue = myQuery.ToList(); + } + else + { + collection.Load(); + } + + collection.IsLoaded = true; + } + } + + public static void LoadReference( + this IDbContext ctx, + TEntity entity, + Expression> navigationProperty, + bool force = false) + where TEntity : BaseEntity + where TProperty : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => navigationProperty); + + var dbContext = ctx as DbContext; + if (dbContext == null) + { + throw new NotSupportedException("The IDbContext instance does not inherit from DbContext (EF)"); + } + + var entry = dbContext.Entry(entity); + var reference = entry.Reference(navigationProperty); + + if (force) + { + reference.IsLoaded = false; + } + + if (!reference.IsLoaded) + { + reference.Load(); + reference.IsLoaded = true; + } + } + + public static void AttachRange(this IDbContext ctx, IEnumerable entities) where TEntity : BaseEntity + { + entities.Each(x => ctx.Attach(x)); + } + + } +} diff --git a/src/Libraries/SmartStore.Core/Data/IQueryableExtensions.cs b/src/Libraries/SmartStore.Core/Data/IQueryableExtensions.cs new file mode 100644 index 0000000000..2289488b95 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Data/IQueryableExtensions.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Data.Entity; +using System.Linq.Expressions; +using SmartStore.Core; + +namespace SmartStore +{ + public static class IQueryableExtensions + { + + /// + /// Instructs the repository to eager load entities that may be in the type's association path. + /// + /// A previously created query object which the expansion should be applied to. + /// + /// The path of the child entities to eager load. + /// Deeper paths can be specified by separating the path with dots. + /// + /// A new query object to which the expansion was applied. + public static IQueryable Expand(this IQueryable query, string path) where T : BaseEntity + { + Guard.ArgumentNotNull(query, "query"); + Guard.ArgumentNotEmpty(path, "path"); + + return query.Include(path); + } + + /// + /// Instructs the repository to eager load entities that may be in the type's association path. + /// + /// A previously created query object which the expansion should be applied to. + /// The path of the child entities to eager load. + /// A new query object to which the expansion was applied. + public static IQueryable Expand(this IQueryable query, Expression> path) where T : BaseEntity + { + Guard.ArgumentNotNull(query, "query"); + Guard.ArgumentNotNull(path, "path"); + + return query.Include(path); + } + + } +} diff --git a/src/Libraries/SmartStore.Core/Data/IRepository.cs b/src/Libraries/SmartStore.Core/Data/IRepository.cs index a2d29f0779..cae856f654 100644 --- a/src/Libraries/SmartStore.Core/Data/IRepository.cs +++ b/src/Libraries/SmartStore.Core/Data/IRepository.cs @@ -21,6 +21,11 @@ public partial interface IRepository where T : BaseEntity /// IQueryable TableUntracked { get; } + /// + /// Provides access to the entities currently being tracked by the context and have not been marked as deleted + /// + ICollection Local { get; } + /// /// Creates a new instance of an entity of type {T} /// @@ -34,6 +39,13 @@ public partial interface IRepository where T : BaseEntity /// The resolved entity T GetById(object id); + /// + /// Attaches an entity to the context + /// + /// The entity to attach + /// The entity + T Attach(T entity); + /// /// Marks the entity instance to be saved to the store. /// @@ -55,6 +67,13 @@ public partial interface IRepository where T : BaseEntity /// Implementors should delegate this to the current void Update(T entity); + /// + /// Marks the changes of existing entities to be saved to the store. + /// + /// A list of entity instances that should be updated in the database. + /// Implementors should delegate this to the current + void UpdateRange(IEnumerable entities); + /// /// Marks an existing entity to be deleted from the store. /// @@ -62,23 +81,17 @@ public partial interface IRepository where T : BaseEntity /// Implementors should delegate this to the current void Delete(T entity); - /// - /// Instructs the repository to eager load entities that may be in the type's association path. - /// - /// A previously created query object which the expansion should be applied to. - /// - /// The path of the child entities to eager load. - /// Deeper paths can be specified by separating the path with dots. - /// - /// A new query object to which the expansion was applied. + /// + /// Marks existing entities to be deleted from the store. + /// + /// A list of entity instances that should be deleted from the database. + /// Implementors should delegate this to the current + void DeleteRange(IEnumerable entities); + + [Obsolete("Use the extension method from 'SmartStore.Core, SmartStore.Core.Data' instead")] IQueryable Expand(IQueryable query, string path); - /// - /// Instructs the repository to eager load entities that may be in the type's association path. - /// - /// A previously created query object which the expansion should be applied to. - /// The path of the child entities to eager load. - /// A new query object to which the expansion was applied. + [Obsolete("Use the extension method from 'SmartStore.Core, SmartStore.Core.Data' instead")] IQueryable Expand(IQueryable query, Expression> path); /// @@ -113,6 +126,10 @@ public partial interface IRepository where T : BaseEntity /// Gets or sets a value indicating whether database write operations /// such as insert, delete or update should be committed immediately. /// - bool AutoCommitEnabled { get; set; } + /// + /// Set this to true or false to supersede the global AutoCommitEnabled + /// on level for this repository instance only. + /// + bool? AutoCommitEnabled { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Data/ITransaction.cs b/src/Libraries/SmartStore.Core/Data/ITransaction.cs new file mode 100644 index 0000000000..e20bb41d17 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Data/ITransaction.cs @@ -0,0 +1,10 @@ +using System; + +namespace SmartStore.Core.Data +{ + public interface ITransaction : IDisposable + { + void Commit(); + void Rollback(); + } +} diff --git a/src/Libraries/SmartStore.Core/Data/Impex/ImportMessage.cs b/src/Libraries/SmartStore.Core/Data/Impex/ImportMessage.cs deleted file mode 100644 index e1658cd057..0000000000 --- a/src/Libraries/SmartStore.Core/Data/Impex/ImportMessage.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace SmartStore.Core.Data -{ - - public class ImportMessage - { - public ImportMessage(string message, ImportMessageType messageType = ImportMessageType.Info) - { - Guard.ArgumentNotEmpty(() => message); - - this.Message = message; - this.MessageType = messageType; - } - - public ImportRowInfo AffectedItem - { - get; - set; - } - - public string AffectedField - { - get; - set; - } - - public ImportMessageType MessageType - { - get; - set; - } - - public string Message - { - get; - set; - } - - public override string ToString() - { - return "{0} - {1}".FormatCurrent(MessageType.ToString().ToUpper(), Message.EmptyNull()); - } - } - - public class ImportRowInfo : Tuple - { - public ImportRowInfo(int position, string entityName) - : base(position, entityName) - { - } - - public int Position - { - get { return base.Item1; } - } - - public string EntityName - { - get { return base.Item2; } - } - } - - public enum ImportMessageType - { - Info = 0, - Warning = 5, - Error = 10 - } - -} diff --git a/src/Libraries/SmartStore.Core/Data/Impex/ImportModeFlags.cs b/src/Libraries/SmartStore.Core/Data/Impex/ImportModeFlags.cs deleted file mode 100644 index f7c40437d9..0000000000 --- a/src/Libraries/SmartStore.Core/Data/Impex/ImportModeFlags.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace SmartStore.Core.Data -{ - - [Flags] - public enum ImportModeFlags - { - Insert = 1, - Update = 2 - } - -} diff --git a/src/Libraries/SmartStore.Core/Data/Impex/ImportProgressInfo.cs b/src/Libraries/SmartStore.Core/Data/Impex/ImportProgressInfo.cs deleted file mode 100644 index 9ddf010991..0000000000 --- a/src/Libraries/SmartStore.Core/Data/Impex/ImportProgressInfo.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SmartStore.Core.Data -{ - - public class ImportProgressInfo - { - - public int TotalRecords - { - get; - set; - } - - public int TotalProcessed - { - get; - set; - } - - public double ProcessedPercent - { - get - { - if (TotalRecords == 0) - return 0; - - return ((double)TotalProcessed / (double)TotalRecords) * 100; - } - } - - public int NewRecords - { - get; - set; - } - - public int ModifiedRecords - { - get; - set; - } - - public TimeSpan ElapsedTime - { - get; - set; - } - - public int TotalWarnings - { - get; - set; - } - - public int TotalErrors - { - get; - set; - } - } - -} diff --git a/src/Libraries/SmartStore.Core/Data/Impex/ImportResult.cs b/src/Libraries/SmartStore.Core/Data/Impex/ImportResult.cs deleted file mode 100644 index 1856607135..0000000000 --- a/src/Libraries/SmartStore.Core/Data/Impex/ImportResult.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SmartStore.Core.Data -{ - - public class ImportResult - { - - public ImportResult() - { - this.Messages = new List(); - this.StartDateUtc = DateTime.UtcNow; - } - - public DateTime StartDateUtc - { - get; - set; - } - - public DateTime EndDateUtc - { - get; - set; - } - - public int TotalRecords - { - get; - set; - } - - public int NewRecords - { - get; - set; - } - - public int ModifiedRecords - { - get; - set; - } - - public int AffectedRecords - { - get { return NewRecords + ModifiedRecords; } - } - - public bool Cancelled - { - get; - set; - } - - public ImportMessage AddInfo(string message, ImportRowInfo affectedRow = null, string affectedField = null) - { - return this.AddMessage(message, ImportMessageType.Info, affectedRow, affectedField); - } - - public ImportMessage AddWarning(string message, ImportRowInfo affectedRow = null, string affectedField = null) - { - return this.AddMessage(message, ImportMessageType.Warning, affectedRow, affectedField); - } - - public ImportMessage AddError(string message, ImportRowInfo affectedRow = null, string affectedField = null) - { - return this.AddMessage(message, ImportMessageType.Error, affectedRow, affectedField); - } - - public ImportMessage AddError(Exception exception, int? affectedBatch = null, string stage = null) - { - var ex = exception; - while (true) - { - if (ex.InnerException == null) - break; - ex = ex.InnerException; - } - - var prefix = new List(); - if (affectedBatch.HasValue) - { - prefix.Add("Batch: " + affectedBatch.Value); - } - if (stage.HasValue()) - { - prefix.Add("Stage: " + stage); - } - - string msg = string.Empty; - if (prefix.Any()) - { - msg = "[{0}] ".FormatCurrent(String.Join(", ", prefix)); - } - - msg += ex.Message; - - return this.AddMessage(msg, ImportMessageType.Error); - } - - public ImportMessage AddMessage(string message, ImportMessageType severity, ImportRowInfo affectedRow = null, string affectedField = null) - { - var msg = new ImportMessage(message, severity); - msg.AffectedItem = affectedRow; - msg.AffectedField = affectedField; - this.Messages.Add(msg); - return msg; - } - - public IList Messages - { - get; - private set; - } - - public bool HasWarnings - { - get { return this.Messages.Any(x => x.MessageType == ImportMessageType.Warning); } - } - - public bool HasErrors - { - get { return this.Messages.Any(x => x.MessageType == ImportMessageType.Error); } - } - - } - -} diff --git a/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs b/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs index 43c1308998..ed034c1730 100644 --- a/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs +++ b/src/Libraries/SmartStore.Core/Data/RepositoryExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Text; @@ -9,22 +10,6 @@ namespace SmartStore.Core.Data public static class RepositoryExtensions { - - public static IEnumerable LoadAll(this IRepository rs) where T : BaseEntity - { - return rs.Table.AsEnumerable(); - } - - public static IEnumerable Where(this IRepository rs, Func predicate) where T : BaseEntity - { - return rs.Table.Where(predicate); - } - - public static T GetSingle(this IRepository rs, Func predicate) where T : BaseEntity - { - return rs.Table.SingleOrDefault(predicate); - } - public static T GetFirst(this IRepository rs, Func predicate) where T : BaseEntity { return rs.Table.FirstOrDefault(predicate); @@ -42,15 +27,77 @@ public static IEnumerable GetMany(this IRepository rs, IEnumerable } } - public static void Delete(this IRepository rs, object id) where T : BaseEntity + public static void Delete(this IRepository rs, int id) where T : BaseEntity { - T entityToDelete = rs.GetById(id); - if (entityToDelete != null) - { - rs.Delete(entityToDelete); - } + Guard.ArgumentNotZero(id, "id"); + + // Perf: work with stub entity + var entity = rs.Create(); + entity.Id = id; + + rs.Attach(entity); + + // must downcast 'cause of Rhino mocks stub + rs.Context.ChangeState((BaseEntity)entity, System.Data.Entity.EntityState.Deleted); } + public static void DeleteRange(this IRepository rs, IEnumerable ids) where T : BaseEntity + { + Guard.ArgumentNotNull(() => ids); + + ids.Each(id => rs.Delete(id)); + } + + /// + /// Truncates the table + /// + /// Entity type + /// The repository + /// An optional filter + /// + /// false: does not make any attempts to determine dependant entities, just deletes ONLY them (faster). + /// true: loads all entities into the context first and deletes them, along with their dependencies (slower). + /// + /// The total number of affected entities + /// + /// This method turns off auto detection, validation and hooking. + /// + [SuppressMessage("ReSharper", "UnusedVariable")] + public static int DeleteAll(this IRepository rs, Expression> predicate = null, bool cascade = false) where T : BaseEntity + { + var count = 0; + + using (var scope = new DbContextScope(ctx: rs.Context, autoDetectChanges: false, validateOnSave: false, hooksEnabled: false, autoCommit: false)) + { + var query = rs.Table; + if (predicate != null) + { + query = query.Where(predicate); + } + + if (cascade) + { + var records = query.ToList(); + foreach (var chunk in records.Chunk(500)) + { + rs.DeleteRange(chunk.ToList()); + count += rs.Context.SaveChanges(); + } + } + else + { + var ids = query.Select(x => new { Id = x.Id }).ToList(); + foreach (var chunk in ids.Chunk(500)) + { + rs.DeleteRange(chunk.Select(x => x.Id)); + count += rs.Context.SaveChanges(); + } + } + } + + return count; + } + public static IQueryable Get( this IRepository rs, Expression> predicate = null, @@ -64,10 +111,9 @@ public static IQueryable Get( query = query.Where(predicate); } - foreach (var includeProperty in includeProperties.Split - (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { - query = rs.Expand(query, includeProperty.Trim()); + query = query.Expand(includeProperty.Trim()); } if (orderBy != null) diff --git a/src/Libraries/SmartStore.Core/Data/SqlFileTokenizer.cs b/src/Libraries/SmartStore.Core/Data/SqlFileTokenizer.cs index 343dad1287..e85c9bac4c 100644 --- a/src/Libraries/SmartStore.Core/Data/SqlFileTokenizer.cs +++ b/src/Libraries/SmartStore.Core/Data/SqlFileTokenizer.cs @@ -49,10 +49,10 @@ public IEnumerable Tokenize() using (var reader = ReadSqlFile()) { - var statement = string.Empty; + string statement; while ((statement = ReadNextSqlStatement(reader)) != null) { - yield return statement; + yield return statement.EmptyNull(); } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogExtensions.cs b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogExtensions.cs index d28f41b9c9..e5cbfc2f5c 100644 --- a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogExtensions.cs +++ b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogExtensions.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace SmartStore.Core.Domain.Blogs { public static class BlogExtensions { - public static string[] ParseTags(this BlogPost blogPost) + [SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] + public static string[] ParseTags(this BlogPost blogPost) { if (blogPost == null) throw new ArgumentNullException("blogPost"); @@ -13,8 +15,8 @@ public static string[] ParseTags(this BlogPost blogPost) var parsedTags = new List(); if (!String.IsNullOrEmpty(blogPost.Tags)) { - string[] tags2 = blogPost.Tags.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string tag2 in tags2) + var tags2 = blogPost.Tags.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var tag2 in tags2) { var tmp = tag2.Trim(); if (!String.IsNullOrEmpty(tmp)) diff --git a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogPost.cs b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogPost.cs index 2dde3ede67..da8ad66682 100644 --- a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogPost.cs +++ b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogPost.cs @@ -93,7 +93,7 @@ public partial class BlogPost : BaseEntity, ISlugSupported, IStoreMappingSupport /// public virtual ICollection BlogComments { - get { return _blogComments ?? (_blogComments = new List()); } + get { return _blogComments ?? (_blogComments = new HashSet()); } protected set { _blogComments = value; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs index 8a1b5ca08e..e0c7492934 100644 --- a/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Blogs/BlogSettings.cs @@ -11,6 +11,7 @@ public BlogSettings() PostsPageSize = 10; AllowNotRegisteredUsersToLeaveComments = true; NumberOfTags = 15; + MaxAgeInDays = 180; } /// @@ -38,6 +39,11 @@ public BlogSettings() /// public int NumberOfTags { get; set; } + /// + /// The maximum age of blog items (in days) for RSS feed + /// + public int MaxAgeInDays { get; set; } + /// /// Enable the blog RSS feed link in customers browser address bar /// diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs index 0ca1537365..12f9fa8587 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/CatalogSettings.cs @@ -3,6 +3,12 @@ namespace SmartStore.Core.Domain.Catalog { + public enum SubCategoryDisplayType + { + Hide = 0, + AboveProductList = 5, + Bottom = 10 + } public class CatalogSettings : ISettings { @@ -10,6 +16,7 @@ public CatalogSettings() { FileUploadAllowedExtensions = new List(); AllowProductSorting = true; + DefaultSortOrder = ProductSortingEnum.Position; AllowProductViewModeChanging = true; DefaultViewMode = "grid"; CategoryBreadcrumbEnabled = true; @@ -24,10 +31,18 @@ public CatalogSettings() RecentlyAddedProductsNumber = 10; RecentlyAddedProductsEnabled = true; CompareProductsEnabled = true; + FilterEnabled = true; + MaxFilterItemsToDisplay = 4; + SortFilterResultsByMatches = true; + SubCategoryDisplayType = SubCategoryDisplayType.AboveProductList; ProductSearchAutoCompleteEnabled = true; + ShowProductImagesInSearchAutoComplete = true; ProductSearchAutoCompleteNumberOfProducts = 10; ProductSearchTermMinimumLength = 3; NumberOfBestsellersOnHomepage = 6; + ShowManufacturersOnHomepage = true; + ShowManufacturerPictures = false; + ShowManufacturerPicturesInProductDetail = true; SearchPageProductsPerPage = 6; ProductsAlsoPurchasedEnabled = true; ProductsAlsoPurchasedNumber = 6; @@ -41,13 +56,16 @@ public CatalogSettings() MaximumBackInStockSubscriptions = 200; FileUploadMaximumSizeBytes = 1024 * 200; //200KB ManufacturersBlockItemsToDisplay = 5; - DisplayAllImagesNumber = 6; // codehint: sm-add + DisplayAllImagesNumber = 6; ShowColorSquaresInLists = true; ShowDiscountSign = true; ShowVariantCombinationPriceAdjustment = true; ShowLinkedAttributeValueImage = true; EnableDynamicPriceUpdate = true; + ShowProductReviewsInProductDetail = true; HtmlTextCollapsedHeight = 260; + MostRecentlyUsedCategoriesMaxSize = 6; + MostRecentlyUsedManufacturersMaxSize = 4; } /// @@ -110,13 +128,18 @@ public CatalogSettings() /// public bool AllowProductSorting { get; set; } + /// + /// Gets or sets the default sort order in product lists + /// + public ProductSortingEnum DefaultSortOrder { get; set; } + /// /// Gets or sets a value indicating whether customers are allowed to change product view mode /// public bool AllowProductViewModeChanging { get; set; } /// - /// Gets or sets a value indicating whether customers are allowed to change product view mode + /// Gets or sets the default view mode for product lists /// public string DefaultViewMode { get; set; } @@ -139,6 +162,31 @@ public CatalogSettings() /// Gets or sets a value indicating whether category breadcrumb is enabled /// public bool CategoryBreadcrumbEnabled { get; set; } + + /// + /// Gets or sets a value indicating whether filter is enabled + /// + public bool FilterEnabled { get; set; } + + /// + /// Gets or sets a value which determines the maximum number of displayed filter items + /// + public int MaxFilterItemsToDisplay { get; set; } + + /// + /// Gets or sets a value indicating whether all filter criterias should be expanded + /// + public bool ExpandAllFilterCriteria { get; set; } + + /// + /// Gets or sets a value indicating whether filter results should be sorted by matches + /// + public bool SortFilterResultsByMatches { get; set; } + + /// + /// Gets or sets a value indicating whether and where to display a list of subcategories + /// + public SubCategoryDisplayType SubCategoryDisplayType { get; set; } /// /// Gets or sets a value indicating whether a 'Share button' is enabled @@ -150,12 +198,16 @@ public CatalogSettings() /// public string PageShareCode { get; set; } - /// codehint: sm-add /// /// Gets or sets a value indicating whether to display reviews in product lists /// public bool ShowProductReviewsInProductLists { get; set; } + /// + /// Gets or sets a value indicating whether to display reviews in product detail + /// + public bool ShowProductReviewsInProductDetail { get; set; } + /// /// Gets or sets a value indicating product reviews must be approved /// @@ -247,9 +299,39 @@ public CatalogSettings() public int NumberOfBestsellersOnHomepage { get; set; } /// - /// Gets or sets a number of products per page on search products page + /// Gets or sets a value indicating whether to show manufacturers on home page /// - public int SearchPageProductsPerPage { get; set; } + public bool ShowManufacturersOnHomepage { get; set; } + + /// + /// Gets or sets a value indicating whether to show manufacturer pictures or names on home page + /// + public bool ShowManufacturerPictures { get; set; } + + /// + /// Gets or sets a value indicating whether to hide manufacturer pictures in product detail + /// + public bool ShowManufacturerPicturesInProductDetail { get; set; } + + /// + /// Gets or sets a value indicating whether to hide maufacturer default pictures + /// + public bool HideManufacturerDefaultPictures { get; set; } + + /// + /// Gets or sets a value indicating whether to hide category default pictures + /// + public bool HideCategoryDefaultPictures { get; set; } + + /// + /// Gets or sets a value indicating whether to hide product default pictures + /// + public bool HideProductDefaultPictures { get; set; } + + /// + /// Gets or sets a number of products per page on search products page + /// + public int SearchPageProductsPerPage { get; set; } /// /// Gets or sets "List of products purchased by other customers who purchased the above" option is enable @@ -291,18 +373,11 @@ public CatalogSettings() /// public string ProductsByTagPageSizeOptions { get; set; } - //codehint: sm-add begin public int ProductSearchPageSize { get; set; } public bool ProductSearchAllowCustomersToSelectPageSize { get; set; } public string ProductSearchPageSizeOptions { get; set; } - - public int RecentlyAddedProductsPageSize { get; set; } - - public bool RecentlyAddedProductsAllowCustomersToSelectPageSize { get; set; } - - public string RecentlyAddedProductsPageSizeOptions { get; set; } public int DisplayAllImagesNumber { get; set; } @@ -312,16 +387,26 @@ public CatalogSettings() public int? LabelAsNewForMaxDays { get; set; } + public bool ShowDefaultQuantityUnit { get; set; } + public bool ShowDiscountSign { get; set; } public bool SuppressSkuSearch { get; set; } - //codehint: sm-add end + /// + /// Gets or sets a value indicating whether to search long description + /// + public bool SearchDescriptions { get; set; } - /// - /// Gets or sets the available customer selectable default page size options - /// - public string DefaultPageSizeOptions { get; set; } + /// + /// Gets or sets the available customer selectable default page size options + /// + public string DefaultPageSizeOptions { get; set; } + + /// + /// Gets or sets the price display type for prices in product lists + /// + public PriceDisplayType PriceDisplayType { get; set; } /// /// Gets or sets a value indicating whether to include "Short description" in compare products @@ -399,5 +484,20 @@ public CatalogSettings() /// Gets or sets the height of collapsed text /// public int HtmlTextCollapsedHeight { get; set; } + + /// + /// Gets or sets an identifier for a delivery time dislayed when stock is empty + /// + public int? DeliveryTimeIdForEmptyStock { get; set; } + + /// + /// Gets or sets how many items to display maximally in the most recently used category list + /// + public int MostRecentlyUsedCategoriesMaxSize { get; set; } + + /// + /// Gets or sets how many items to display maximally in the most recently used manufacturer list + /// + public int MostRecentlyUsedManufacturersMaxSize { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/Category.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/Category.cs index 3a82ddd86e..83c5ef53c6 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/Category.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/Category.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; using System.Runtime.Serialization; using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Localization; @@ -14,6 +16,7 @@ namespace SmartStore.Core.Domain.Catalog /// Represents a category /// [DataContract] + [DebuggerDisplay("{Id}: {Name} (Parent: {ParentCategoryId})")] public partial class Category : BaseEntity, ISoftDeletable, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported { private ICollection _appliedDiscounts; @@ -24,17 +27,28 @@ public partial class Category : BaseEntity, ISoftDeletable, ILocalizedEntity, IS [DataMember] public string Name { get; set; } + /// + /// Gets or sets the full name (category page title) + /// + [DataMember] + public string FullName { get; set; } + /// /// Gets or sets the description /// [DataMember] public string Description { get; set; } + /// + /// Gets or sets a description displayed at the bottom of the category page + /// + [DataMember] + public string BottomDescription { get; set; } + /// /// Gets or sets the category alias /// (an optional key for advanced customization) /// - /// codehint: sm-add [DataMember] public string Alias { get; set; } @@ -141,6 +155,7 @@ public partial class Category : BaseEntity, ISoftDeletable, ILocalizedEntity, IS /// /// Gets or sets a value indicating whether the entity has been deleted /// + [Index] public bool Deleted { get; set; } /// @@ -161,19 +176,20 @@ public partial class Category : BaseEntity, ISoftDeletable, ILocalizedEntity, IS [DataMember] public DateTime UpdatedOnUtc { get; set; } + /// + /// Gets or sets the date and time of instance update + /// + [DataMember] + public string DefaultViewMode { get; set; } + /// /// Gets or sets the collection of applied discounts /// [DataMember] public virtual ICollection AppliedDiscounts { - get { return _appliedDiscounts ?? (_appliedDiscounts = new List()); } + get { return _appliedDiscounts ?? (_appliedDiscounts = new HashSet()); } protected set { _appliedDiscounts = value; } } - - public override string ToString() - { - return string.Format( "{0}: {1} (Parent: {2})", this.Id, this.Name, this.ParentCategoryId); - } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/Manufacturer.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/Manufacturer.cs index 7aa0222761..88b366c773 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/Manufacturer.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/Manufacturer.cs @@ -4,6 +4,7 @@ using SmartStore.Core.Domain.Stores; using System.Runtime.Serialization; using SmartStore.Core.Domain.Media; +using System.ComponentModel.DataAnnotations.Schema; namespace SmartStore.Core.Domain.Catalog { @@ -100,6 +101,7 @@ public partial class Manufacturer : BaseEntity, ISoftDeletable, ILocalizedEntity /// /// Gets or sets a value indicating whether the entity has been deleted /// + [Index] public bool Deleted { get; set; } /// diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/PriceDisplayType.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/PriceDisplayType.cs new file mode 100644 index 0000000000..aeb4c24250 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/PriceDisplayType.cs @@ -0,0 +1,29 @@ + +namespace SmartStore.Core.Domain.Catalog +{ + /// + /// Represents types of product prices to display + /// + public enum PriceDisplayType + { + /// + /// The lowest possible price of a product (default) + /// + LowestPrice = 0, + + /// + /// The product price initially displayed on the product detail page + /// + PreSelectedPrice = 10, + + /// + /// The product price without associated data like discounts, tier prices, attributes or attribute combinations + /// + PriceWithoutDiscountsAndAttributes = 20, + + /// + /// Do not display a product price + /// + Hide = 30 + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs index 8afa527e0c..999f66bad3 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/Product.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; using System.Diagnostics; using System.Runtime.Serialization; using SmartStore.Core.Domain.Directory; @@ -17,7 +18,7 @@ namespace SmartStore.Core.Domain.Catalog /// [DataContract] public partial class Product : BaseEntity, ISoftDeletable, ILocalizedEntity, ISlugSupported, IAclSupported, IStoreMappingSupported, IMergedData - { + { private ICollection _productCategories; private ICollection _productManufacturers; private ICollection _productPictures; @@ -37,6 +38,7 @@ public partial class Product : BaseEntity, ISoftDeletable, ILocalizedEntity, ISl private string _manufacturerPartNumber; private decimal _price; private int? _deliveryTimeId; + private int? _quantityUnitId; private decimal _length; private decimal _width; private decimal _height; @@ -102,6 +104,12 @@ public partial class Product : BaseEntity, ISoftDeletable, ILocalizedEntity, ISl [DataMember] public bool ShowOnHomePage { get; set; } + /// + /// Gets or sets the display order for homepage products + /// + [DataMember] + public int HomePageDisplayOrder { get; set; } + /// /// Gets or sets the meta keywords /// @@ -183,6 +191,7 @@ public string Sku /// Gets or sets the manufacturer part number /// [DataMember] + [Index] public string ManufacturerPartNumber { [DebuggerStepThrough] @@ -200,6 +209,7 @@ public string ManufacturerPartNumber /// Gets or sets the Global Trade Item Number (GTIN). These identifiers include UPC (in North America), EAN (in Europe), JAN (in Japan), and ISBN (for books). /// [DataMember] + [Index] public string Gtin { [DebuggerStepThrough] @@ -244,7 +254,7 @@ public string Gtin public bool AutomaticallyAddRequiredProducts { get; set; } /// - /// Gets or sets a value indicating whether the product is download + /// Gets or sets a value indicating whether the product is a download /// [DataMember] public bool IsDownload { get; set; } @@ -357,6 +367,13 @@ public string Gtin [DataMember] public bool IsTaxExempt { get; set; } + /// + /// Gets or sets a value indicating whether the product is an electronic service + /// bound to EU VAT regulations for digital goods. + /// + [DataMember] + public bool IsEsd { get; set; } + /// /// Gets or sets the tax category identifier /// @@ -378,7 +395,7 @@ public int StockQuantity [DebuggerStepThrough] get { - return this.GetMergedDataValue("StockQuantity", _stockQuantity); + return this.GetMergedDataValue("StockQuantity", _stockQuantity); } set { @@ -550,7 +567,7 @@ public decimal Price /// Gets or sets a value indicating whether this product has tier prices configured /// The same as if we run this.TierPrices.Count > 0 /// We use this property for performance optimization: - /// if this property is set to false, then we do not need to load tier prices navifation property + /// if this property is set to false, then we do not need to load tier prices navigation property /// /// [DataMember] @@ -656,6 +673,7 @@ public decimal Height /// /// Gets or sets a value indicating whether the entity has been deleted /// + [Index] public bool Deleted { get; set; } /// @@ -690,6 +708,27 @@ public int? DeliveryTimeId [DataMember] public virtual DeliveryTime DeliveryTime { get; set; } + /// + /// Gets or sets the quantity unit identifier + /// + [DataMember] + public int? QuantityUnitId + { + [DebuggerStepThrough] + get + { + return this.GetMergedDataValue("QuantityUnitId", _quantityUnitId); + } + set + { + _quantityUnitId = value; + } + } + + [DataMember] + public virtual QuantityUnit QuantityUnit { get; set; } + + /// /// Gets or sets if base price quotation (PAnGV) is enabled /// @@ -704,7 +743,7 @@ public int? DeliveryTimeId /// /// Amount of product per packing unit in the given measure unit - /// (e.g. 250 ml shower gel: "0.25" if MeasureUnit = "liter" and BaseAmount = 1) + /// (e.g. 250 ml shower gel: "0.25" if MeasureUnit = "liter" and BaseAmount = 1) /// [DataMember] public decimal? BasePriceAmount @@ -907,7 +946,7 @@ public RecurringProductCyclePeriod RecurringCyclePeriod [DataMember] public virtual ICollection ProductCategories { - get { return _productCategories ?? (_productCategories = new List()); } + get { return _productCategories ?? (_productCategories = new HashSet()); } protected set { _productCategories = value; } } @@ -917,7 +956,7 @@ public virtual ICollection ProductCategories [DataMember] public virtual ICollection ProductManufacturers { - get { return _productManufacturers ?? (_productManufacturers = new List()); } + get { return _productManufacturers ?? (_productManufacturers = new HashSet()); } protected set { _productManufacturers = value; } } @@ -936,7 +975,7 @@ public virtual ICollection ProductPictures /// public virtual ICollection ProductReviews { - get { return _productReviews ?? (_productReviews = new List()); } + get { return _productReviews ?? (_productReviews = new HashSet()); } protected set { _productReviews = value; } } @@ -946,7 +985,7 @@ public virtual ICollection ProductReviews [DataMember] public virtual ICollection ProductSpecificationAttributes { - get { return _productSpecificationAttributes ?? (_productSpecificationAttributes = new List()); } + get { return _productSpecificationAttributes ?? (_productSpecificationAttributes = new HashSet()); } protected set { _productSpecificationAttributes = value; } } @@ -956,7 +995,7 @@ public virtual ICollection ProductSpecificationAt [DataMember] public virtual ICollection ProductTags { - get { return _productTags ?? (_productTags = new List()); } + get { return _productTags ?? (_productTags = new HashSet()); } protected set { _productTags = value; } } @@ -966,7 +1005,7 @@ public virtual ICollection ProductTags [DataMember] public virtual ICollection ProductVariantAttributes { - get { return _productVariantAttributes ?? (_productVariantAttributes = new List()); } + get { return _productVariantAttributes ?? (_productVariantAttributes = new HashSet()); } protected set { _productVariantAttributes = value; } } @@ -986,7 +1025,7 @@ public virtual ICollection ProductVariantAtt [DataMember] public virtual ICollection TierPrices { - get { return _tierPrices ?? (_tierPrices = new List()); } + get { return _tierPrices ?? (_tierPrices = new HashSet()); } protected set { _tierPrices = value; } } @@ -996,7 +1035,7 @@ public virtual ICollection TierPrices [DataMember] public virtual ICollection AppliedDiscounts { - get { return _appliedDiscounts ?? (_appliedDiscounts = new List()); } + get { return _appliedDiscounts ?? (_appliedDiscounts = new HashSet()); } protected set { _appliedDiscounts = value; } } @@ -1006,8 +1045,8 @@ public virtual ICollection AppliedDiscounts [DataMember] public virtual ICollection ProductBundleItems { - get { return _productBundleItems ?? (_productBundleItems = new List()); } + get { return _productBundleItems ?? (_productBundleItems = new HashSet()); } protected set { _productBundleItems = value; } } - } + } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleData.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleData.cs index 9001a046dc..354720c7ea 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleData.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleData.cs @@ -34,57 +34,4 @@ public partial class ProductBundleItemOrderData public string AttributesInfo { get; set; } public bool PerItemShoppingCart { get; set; } } - - public class ProductBundleDataListTypeConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - return true; - - return base.CanConvertFrom(context, sourceType); - } - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string) - { - List bundleData = null; - string rawValue = value as string; - - if (rawValue.HasValue()) - { - try - { - using (var reader = new StringReader(rawValue)) - { - var xml = new XmlSerializer(typeof(List)); - bundleData = (List)xml.Deserialize(reader); - } - } - catch { } - } - return bundleData; - } - return base.ConvertFrom(context, culture, value); - } - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string)) - { - var bundleData = value as List; - - if (bundleData == null) - return ""; - - var sb = new StringBuilder(); - using (var writer = new StringWriter(sb)) - { - var xml = new XmlSerializer(typeof(List)); - xml.Serialize(writer, value); - return sb.ToString(); - } - } - return base.ConvertTo(context, culture, value, destinationType); - } - } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleItem.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleItem.cs index 89a0b4ebb0..ea28857ec8 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleItem.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductBundleItem.cs @@ -111,7 +111,7 @@ public partial class ProductBundleItem : BaseEntity, ILocalizedEntity, ICloneabl /// public virtual ICollection AttributeFilters { - get { return _attributeFilters ?? (_attributeFilters = new List()); } + get { return _attributeFilters ?? (_attributeFilters = new HashSet()); } protected set { _attributeFilters = value; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductReview.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductReview.cs index 8ff18c78cf..eb52702201 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductReview.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductReview.cs @@ -50,7 +50,7 @@ public partial class ProductReview : CustomerContent /// public virtual ICollection ProductReviewHelpfulnessEntries { - get { return _productReviewHelpfulnessEntries ?? (_productReviewHelpfulnessEntries = new List()); } + get { return _productReviewHelpfulnessEntries ?? (_productReviewHelpfulnessEntries = new HashSet()); } protected set { _productReviewHelpfulnessEntries = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductSortingEnum.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductSortingEnum.cs index 17a29dbab3..8db56d81b4 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductSortingEnum.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductSortingEnum.cs @@ -5,10 +5,14 @@ /// public enum ProductSortingEnum { + /// + /// Initial state + /// + Initial = 0, /// /// Position (display order) /// - Position = 0, + Position = 1, /// /// Name: A to Z /// @@ -32,6 +36,6 @@ public enum ProductSortingEnum /// /// Product creation date /// - CreatedOnAsc = 16 // codehint: sm-add + CreatedOnAsc = 16 } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductTag.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductTag.cs index 18786c6c49..153d570195 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductTag.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductTag.cs @@ -23,7 +23,7 @@ public partial class ProductTag : BaseEntity, ILocalizedEntity /// public virtual ICollection Products { - get { return _products ?? (_products = new List()); } + get { return _products ?? (_products = new HashSet()); } protected set { _products = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttribute.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttribute.cs index 09b677320c..c6ca76e9d2 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttribute.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttribute.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.Serialization; using SmartStore.Core.Domain.Localization; @@ -16,6 +17,7 @@ public partial class ProductVariantAttribute : BaseEntity, ILocalizedEntity /// Gets or sets the product identifier /// [DataMember] + [Index("IX_Product_ProductAttribute_Mapping_ProductId_DisplayOrder", 1)] public int ProductId { get; set; } /// @@ -46,6 +48,7 @@ public partial class ProductVariantAttribute : BaseEntity, ILocalizedEntity /// Gets or sets the display order /// [DataMember] + [Index("IX_Product_ProductAttribute_Mapping_ProductId_DisplayOrder", 2)] public int DisplayOrder { get; set; } /// @@ -81,7 +84,7 @@ public AttributeControlType AttributeControlType [DataMember] public virtual ICollection ProductVariantAttributeValues { - get { return _productVariantAttributeValues ?? (_productVariantAttributeValues = new List()); } + get { return _productVariantAttributeValues ?? (_productVariantAttributeValues = new HashSet()); } protected set { _productVariantAttributeValues = value; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttributeValue.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttributeValue.cs index 518b856f17..dabf57aadf 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttributeValue.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/ProductVariantAttributeValue.cs @@ -1,3 +1,4 @@ +using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.Serialization; using SmartStore.Core.Domain.Localization; @@ -13,6 +14,7 @@ public partial class ProductVariantAttributeValue : BaseEntity, ILocalizedEntity /// Gets or sets the product variant attribute mapping identifier /// [DataMember] + [Index("IX_ProductVariantAttributeValue_ProductVariantAttributeId_DisplayOrder", 1)] public int ProductVariantAttributeId { get; set; } /// @@ -56,6 +58,7 @@ public partial class ProductVariantAttributeValue : BaseEntity, ILocalizedEntity /// Gets or sets the display order /// [DataMember] + [Index("IX_ProductVariantAttributeValue_ProductVariantAttributeId_DisplayOrder", 2)] public int DisplayOrder { get; set; } /// diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/SmartStoreProductVariantAttributeCombination.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/SmartStoreProductVariantAttributeCombination.cs index c1177e990b..e7caa492b1 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/SmartStoreProductVariantAttributeCombination.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/SmartStoreProductVariantAttributeCombination.cs @@ -51,6 +51,12 @@ public ProductVariantAttributeCombination() [DataMember] public virtual DeliveryTime DeliveryTime { get; set; } + [DataMember] + public int? QuantityUnitId { get; set; } + + [DataMember] + public virtual QuantityUnit QuantityUnit { get; set; } + [DataMember] public bool IsActive { get; set; } //public bool IsDefaultCombination { get; set; } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttribute.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttribute.cs index 9fe5d84bbf..d8a42e6ccf 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttribute.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttribute.cs @@ -30,7 +30,7 @@ public partial class SpecificationAttribute : BaseEntity, ILocalizedEntity [DataMember] public virtual ICollection SpecificationAttributeOptions { - get { return _specificationAttributeOptions ?? (_specificationAttributeOptions = new List()); } + get { return _specificationAttributeOptions ?? (_specificationAttributeOptions = new HashSet()); } protected set { _specificationAttributeOptions = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttributeOption.cs b/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttributeOption.cs index c087ac510f..e3019778e6 100644 --- a/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttributeOption.cs +++ b/src/Libraries/SmartStore.Core/Domain/Catalog/SpecificationAttributeOption.cs @@ -42,7 +42,7 @@ public partial class SpecificationAttributeOption : BaseEntity, ILocalizedEntity [DataMember] public virtual ICollection ProductSpecificationAttributes { - get { return _productSpecificationAttributes ?? (_productSpecificationAttributes = new List()); } + get { return _productSpecificationAttributes ?? (_productSpecificationAttributes = new HashSet()); } protected set { _productSpecificationAttributes = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Common/AddressSettings.cs b/src/Libraries/SmartStore.Core/Domain/Common/AddressSettings.cs index 8f7cf26f3c..dab1a90658 100644 --- a/src/Libraries/SmartStore.Core/Domain/Common/AddressSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Common/AddressSettings.cs @@ -7,6 +7,7 @@ public class AddressSettings : ISettings { public AddressSettings() { + ValidateEmailAddress = false; CompanyEnabled = true; StreetAddressEnabled = true; StreetAddressRequired = true; @@ -21,7 +22,12 @@ public AddressSettings() PhoneRequired = true; FaxEnabled = true; } - + + /// + /// Gets or sets a value indicating whether email address should be validated + /// + public bool ValidateEmailAddress { get; set; } + /// /// Gets or sets a value indicating whether 'Company' is enabled /// diff --git a/src/Libraries/SmartStore.Core/Domain/Common/AdminAreaSettings.cs b/src/Libraries/SmartStore.Core/Domain/Common/AdminAreaSettings.cs index 77835ab16a..2458d9faa7 100644 --- a/src/Libraries/SmartStore.Core/Domain/Common/AdminAreaSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Common/AdminAreaSettings.cs @@ -7,7 +7,7 @@ public class AdminAreaSettings : ISettings { public AdminAreaSettings() { - GridPageSize = 15; + GridPageSize = 25; DisplayProductPictures = true; RichEditorFlavor = "RichEditor"; } diff --git a/src/Libraries/SmartStore.Core/Domain/Common/CommonSettings.cs b/src/Libraries/SmartStore.Core/Domain/Common/CommonSettings.cs index d6af1d213a..84ceca5428 100644 --- a/src/Libraries/SmartStore.Core/Domain/Common/CommonSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Common/CommonSettings.cs @@ -1,5 +1,4 @@ - -using SmartStore.Core.Configuration; +using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.Common { @@ -13,6 +12,8 @@ public CommonSettings() SitemapIncludeManufacturers = true; SitemapIncludeTopics = true; FullTextMode = FulltextSearchMode.ExactMatch; + AutoUpdateEnabled = true; + EntityPickerPageSize = 48; } public bool UseSystemEmailForContactUsForm { get; set; } @@ -28,19 +29,25 @@ public CommonSettings() public bool SitemapIncludeTopics { get; set; } /// - /// Gets a sets a value indicating whether to display a warning if java-script is disabled + /// Gets or sets a value indicating whether to display a warning if java-script is disabled /// public bool DisplayJavaScriptDisabledWarning { get; set; } /// - /// Gets a sets a value indicating whether to full-text search is supported + /// Gets or sets a value indicating whether to full-text search is supported /// public bool UseFullTextSearch { get; set; } /// - /// Gets a sets a Full-Text search mode + /// Gets or sets a Full-Text search mode /// public FulltextSearchMode FullTextMode { get; set; } - } + public bool AutoUpdateEnabled { get; set; } + + /// + /// Gets or sets the page size for the entity picker + /// + public int EntityPickerPageSize { get; set; } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs b/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs index 1b69923429..bddfb93963 100644 --- a/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Common/PdfSettings.cs @@ -9,7 +9,6 @@ public PdfSettings() { Enabled = true; RenderOrderNotes = true; - FontFileName = "OpenSans-Regular.ttf"; } /// @@ -32,9 +31,14 @@ public PdfSettings() /// public bool RenderOrderNotes { get; set; } - /// - /// Gets or sets the font file name that will be used - /// - public string FontFileName { get; set; } + /// + /// Gets or sets a value indicating whether to attach the order PDF to 'Order Placed (customer)' email + /// + public bool AttachOrderPdfToOrderPlacedEmail { get; set; } + + /// + /// Gets or sets a value indicating whether to attach the order PDF to 'Order Completed (customer)' email + /// + public bool AttachOrderPdfToOrderCompletedEmail { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Configuration/Setting.cs b/src/Libraries/SmartStore.Core/Domain/Configuration/Setting.cs index d6b4793e8f..0c981c906a 100644 --- a/src/Libraries/SmartStore.Core/Domain/Configuration/Setting.cs +++ b/src/Libraries/SmartStore.Core/Domain/Configuration/Setting.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Runtime.Serialization; namespace SmartStore.Core.Domain.Configuration { @@ -5,6 +6,7 @@ namespace SmartStore.Core.Domain.Configuration /// Represents a setting /// [DataContract] + [DebuggerDisplay("{Name}: {Value}")] public partial class Setting : BaseEntity { public Setting() { } @@ -33,10 +35,5 @@ public Setting(string name, string value, int storeId = 0) /// [DataMember] public int StoreId { get; set; } - - public override string ToString() - { - return Name; - } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/Customer.cs b/src/Libraries/SmartStore.Core/Domain/Customers/Customer.cs index c230b888df..e55f57bd4f 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/Customer.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/Customer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Runtime.Serialization; using SmartStore.Core.Domain.Common; @@ -103,6 +104,7 @@ public PasswordFormat PasswordFormat /// /// Gets or sets a value indicating whether the customer has been deleted /// + [Index] public bool Deleted { get; set; } /// @@ -115,6 +117,7 @@ public PasswordFormat PasswordFormat /// Gets or sets the customer system name /// [DataMember] + [Index] public string SystemName { get; set; } /// @@ -148,7 +151,7 @@ public PasswordFormat PasswordFormat /// public virtual ICollection ExternalAuthenticationRecords { - get { return _externalAuthenticationRecords ?? (_externalAuthenticationRecords = new List()); } + get { return _externalAuthenticationRecords ?? (_externalAuthenticationRecords = new HashSet()); } protected set { _externalAuthenticationRecords = value; } } @@ -157,7 +160,7 @@ public virtual ICollection ExternalAuthenticationR /// public virtual ICollection CustomerContent { - get { return _customerContent ?? (_customerContent = new List()); } + get { return _customerContent ?? (_customerContent = new HashSet()); } protected set { _customerContent = value; } } @@ -166,7 +169,7 @@ public virtual ICollection CustomerContent /// public virtual ICollection CustomerRoles { - get { return _customerRoles ?? (_customerRoles = new List()); } + get { return _customerRoles ?? (_customerRoles = new HashSet()); } protected set { _customerRoles = value; } } @@ -175,7 +178,7 @@ public virtual ICollection CustomerRoles /// public virtual ICollection ShoppingCartItems { - get { return _shoppingCartItems ?? (_shoppingCartItems = new List()); } + get { return _shoppingCartItems ?? (_shoppingCartItems = new HashSet()); } protected set { _shoppingCartItems = value; } } @@ -185,7 +188,7 @@ public virtual ICollection ShoppingCartItems [DataMember] public virtual ICollection Orders { - get { return _orders ?? (_orders = new List()); } + get { return _orders ?? (_orders = new HashSet()); } protected set { _orders = value; } } @@ -194,7 +197,7 @@ public virtual ICollection Orders /// public virtual ICollection RewardPointsHistory { - get { return _rewardPointsHistory ?? (_rewardPointsHistory = new List()); } + get { return _rewardPointsHistory ?? (_rewardPointsHistory = new HashSet()); } protected set { _rewardPointsHistory = value; } } @@ -204,7 +207,7 @@ public virtual ICollection RewardPointsHistory [DataMember] public virtual ICollection ReturnRequests { - get { return _returnRequests ?? (_returnRequests = new List()); } + get { return _returnRequests ?? (_returnRequests = new HashSet()); } protected set { _returnRequests = value; } } @@ -226,7 +229,7 @@ public virtual ICollection ReturnRequests [DataMember] public virtual ICollection
Addresses { - get { return _addresses ?? (_addresses = new List
()); } + get { return _addresses ?? (_addresses = new HashSet
()); } protected set { _addresses = value; } } @@ -235,7 +238,7 @@ public virtual ICollection
Addresses /// public virtual ICollection ForumTopics { - get { return _forumTopics ?? (_forumTopics = new List()); } + get { return _forumTopics ?? (_forumTopics = new HashSet()); } protected set { _forumTopics = value; } } @@ -244,7 +247,7 @@ public virtual ICollection ForumTopics /// public virtual ICollection ForumPosts { - get { return _forumPosts ?? (_forumPosts = new List()); } + get { return _forumPosts ?? (_forumPosts = new HashSet()); } protected set { _forumPosts = value; } } @@ -254,7 +257,7 @@ public virtual ICollection ForumPosts public virtual void RemoveAddress(Address address) { - if (this.Addresses.Contains(address)) + if (this.Addresses.Contains(address)) { if (this.BillingAddress == address) this.BillingAddress = null; if (this.ShippingAddress == address) this.ShippingAddress = null; diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNameFormat.cs b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNameFormat.cs index 37ed8c79cb..c10aa440f4 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNameFormat.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNameFormat.cs @@ -3,7 +3,7 @@ namespace SmartStore.Core.Domain.Customers /// /// Represents the customer name fortatting enumeration /// - public enum CustomerNameFormat : int + public enum CustomerNameFormat { /// /// Show emails @@ -16,6 +16,14 @@ public enum CustomerNameFormat : int /// /// Show full names /// - ShowFullNames = 3 + ShowFullNames = 3, + /// + /// Show first name + /// + ShowFirstName = 4, + /// + /// Show shorted name and city + /// + ShowNameAndCity = 5 } } diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNumberMethod.cs b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNumberMethod.cs new file mode 100644 index 0000000000..f333486399 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNumberMethod.cs @@ -0,0 +1,24 @@ +namespace SmartStore.Core.Domain.Customers +{ + /// + /// Represents the customer number method + /// + public enum CustomerNumberMethod + { + /// + /// no customer number will be saved + /// + Disabled = 10, + + /// + /// customer numbers can be saved + /// + Enabled = 20, + + /// + /// customer numbers will automatically be set when new customers are created + /// + AutomaticallySet = 30, + + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNumberVisibility.cs b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNumberVisibility.cs new file mode 100644 index 0000000000..d05e588e97 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerNumberVisibility.cs @@ -0,0 +1,28 @@ +namespace SmartStore.Core.Domain.Customers +{ + /// + /// Represents the customer visibility in the frontend + /// + public enum CustomerNumberVisibility + { + /// + /// Customer number won't be displayed in the frontend + /// + None = 10, + + /// + /// Customer number will be displayed in the frontend + /// + Display = 20, + + /// + /// A customer can enter his own number if customer number wasn't saved yet + /// + EditableIfEmpty = 30, + + /// + /// A customer can enter his own number and alter it + /// + Editable = 40, + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerRole.cs b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerRole.cs index 63a4005407..6d3b2003e8 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerRole.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerRole.cs @@ -26,7 +26,6 @@ public partial class CustomerRole : BaseEntity /// public bool TaxExempt { get; set; } - /// codehint: sm-add /// /// Gets or sets the tax display type /// @@ -53,7 +52,7 @@ public partial class CustomerRole : BaseEntity /// public virtual ICollection PermissionRecords { - get { return _permissionRecords ?? (_permissionRecords = new List()); } + get { return _permissionRecords ?? (_permissionRecords = new HashSet()); } protected set { _permissionRecords = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs index 89875a5f3d..e6d7f56f56 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/CustomerSettings.cs @@ -8,19 +8,23 @@ public class CustomerSettings : ISettings public CustomerSettings() { UsernamesEnabled = true; + CustomerNumberMethod = Customers.CustomerNumberMethod.Disabled; + CustomerNumberVisibility = Customers.CustomerNumberVisibility.None; DefaultPasswordFormat = PasswordFormat.Hashed; HashedPasswordFormat = "SHA1"; PasswordMinLength = 6; UserRegistrationType = UserRegistrationType.Standard; AvatarMaximumSizeBytes = 20000; DefaultAvatarEnabled = true; - CustomerNameFormat = CustomerNameFormat.ShowUsernames; + CustomerNameFormat = CustomerNameFormat.ShowFirstName; + CustomerNameFormatMaxLength = 64; GenderEnabled = true; DateOfBirthEnabled = true; CompanyEnabled = true; NewsletterEnabled = true; OnlineCustomerMinutes = 20; StoreLastVisitedPage = true; + DisplayPrivacyAgreementOnContactUs = false; } /// @@ -28,6 +32,16 @@ public CustomerSettings() /// public bool UsernamesEnabled { get; set; } + /// + /// Gets or sets the customer number method + /// + public CustomerNumberMethod CustomerNumberMethod { get; set; } + + /// + /// Gets or sets the customer number visibility + /// + public CustomerNumberVisibility CustomerNumberVisibility { get; set; } + /// /// Gets or sets a value indicating whether users can check the availability of usernames (when registering or changing in 'My Account') /// @@ -113,6 +127,11 @@ public CustomerSettings() /// public CustomerNameFormat CustomerNameFormat { get; set; } + /// + /// Gets or sets a value indicating the maximum length of a formatted customer name + /// + public int CustomerNameFormatMaxLength { get; set; } + /// /// Gets or sets a value indicating whether 'Newsletter' form field is enabled /// @@ -133,7 +152,11 @@ public CustomerSettings() /// public bool StoreLastVisitedPage { get; set; } - + /// + /// Gets or sets a value indicating whether to display a checkbox to the customer where he can agree to privacy terms + /// + public bool DisplayPrivacyAgreementOnContactUs { get; set; } + #region Form fields /// @@ -228,8 +251,12 @@ public CustomerSettings() #endregion - // codehint: sm-add (no ui, only db edit) public string PrefillLoginUsername { get; set; } public string PrefillLoginPwd { get; set; } - } + + /// + /// Identifier of a customer role that new registered customers will be assigned to + /// + public int RegisterCustomerRoleId { get; set; } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/PasswordFormat.cs b/src/Libraries/SmartStore.Core/Domain/Customers/PasswordFormat.cs index b84ab3a661..4b35797ec7 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/PasswordFormat.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/PasswordFormat.cs @@ -1,7 +1,7 @@  namespace SmartStore.Core.Domain.Customers { - public enum PasswordFormat : int + public enum PasswordFormat { Clear = 0, Hashed = 1, diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/RewardPointsSettings.cs b/src/Libraries/SmartStore.Core/Domain/Customers/RewardPointsSettings.cs index 1d6ec48df5..f0e99e9502 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/RewardPointsSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/RewardPointsSettings.cs @@ -24,10 +24,15 @@ public RewardPointsSettings() /// public decimal ExchangeRate { get; set; } - /// - /// Gets or sets a number of points awarded for registration - /// - public int PointsForRegistration { get; set; } + /// + /// Gets or sets a value whether to round down reward points + /// + public bool RoundDownRewardPoints { get; set; } + + /// + /// Gets or sets a number of points awarded for registration + /// + public int PointsForRegistration { get; set; } /// /// Gets or sets a number of points awarded for a product review diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs index 0be2d6cb24..33569b4855 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerAttributeNames.cs @@ -20,6 +20,7 @@ public static partial class SystemCustomerAttributeNames public static string VatNumber { get { return "VatNumber"; } } public static string VatNumberStatusId { get { return "VatNumberStatusId"; } } public static string TimeZoneId { get { return "TimeZoneId"; } } + public static string CustomerNumber { get { return "CustomerNumber"; } } //Other attributes public static string DiscountCouponCode { get { return "DiscountCouponCode"; } } @@ -31,8 +32,11 @@ public static partial class SystemCustomerAttributeNames public static string PasswordRecoveryToken { get { return "PasswordRecoveryToken"; } } public static string AccountActivationToken { get { return "AccountActivationToken"; } } public static string LastVisitedPage { get { return "LastVisitedPage"; } } - public static string ImpersonatedCustomerId { get { return "ImpersonatedCustomerId"; } } + public static string LastUserAgent { get { return "LastUserAgent"; } } + public static string ImpersonatedCustomerId { get { return "ImpersonatedCustomerId"; } } public static string AdminAreaStoreScopeConfiguration { get { return "AdminAreaStoreScopeConfiguration"; } } + public static string MostRecentlyUsedCategories { get { return "MostRecentlyUsedCategories"; } } + public static string MostRecentlyUsedManufacturers { get { return "MostRecentlyUsedManufacturers"; } } //depends on store public static string CurrencyId { get { return "CurrencyId"; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerNames.cs b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerNames.cs index 6922b88f2b..48ed1b0dfd 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerNames.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerNames.cs @@ -5,5 +5,6 @@ public static partial class SystemCustomerNames { public static string SearchEngine { get { return "SearchEngine"; } } public static string BackgroundTask { get { return "BackgroundTask"; } } + public static string PdfConverter { get { return "PdfConverter"; } } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs index 760d14d9be..214fd18191 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/SystemCustomerRoleNames.cs @@ -3,7 +3,6 @@ namespace SmartStore.Core.Domain.Customers { public static partial class SystemCustomerRoleNames { - /// codehint: sm-add public static string SuperAdministrators { get { return "SuperAdmins"; } } public static string Administrators { get { return "Administrators"; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Customers/UserRegistrationType.cs b/src/Libraries/SmartStore.Core/Domain/Customers/UserRegistrationType.cs index dc89589020..1f950092db 100644 --- a/src/Libraries/SmartStore.Core/Domain/Customers/UserRegistrationType.cs +++ b/src/Libraries/SmartStore.Core/Domain/Customers/UserRegistrationType.cs @@ -3,7 +3,7 @@ namespace SmartStore.Core.Domain.Customers /// /// Represents the customer registration type fortatting enumeration /// - public enum UserRegistrationType : int + public enum UserRegistrationType { /// /// Standard account creation diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/DataExchangeEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/DataExchangeEnums.cs new file mode 100644 index 0000000000..7a3ab1f8ae --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/DataExchangeEnums.cs @@ -0,0 +1,26 @@ +namespace SmartStore.Core.Domain.DataExchange +{ + public delegate void ProgressValueSetter(int value, int maximum, string message); + + + /// + /// Data exchange abortion types + /// + public enum DataExchangeAbortion + { + /// + /// No abortion. Go on with processing. + /// + None = 0, + + /// + /// Break item processing but not the rest of the execution. Typically used for demo limitations. + /// + Soft, + + /// + /// Break processing immediately + /// + Hard + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/DataExchangeSettings.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/DataExchangeSettings.cs new file mode 100644 index 0000000000..4b0bc6d497 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/DataExchangeSettings.cs @@ -0,0 +1,28 @@ +using SmartStore.Core.Configuration; + +namespace SmartStore.Core.Domain.DataExchange +{ + public class DataExchangeSettings : ISettings + { + public DataExchangeSettings() + { + MaxFileNameLength = 50; + ImageDownloadTimeout = 10; + } + + /// + /// The maximum length of file names (in characters) of files created by the export framework + /// + public int MaxFileNameLength { get; set; } + + /// + /// Relative path to a folder with images to be imported + /// + public string ImageImportFolder { get; set; } + + /// + /// The timeout for image download per entity in minutes + /// + public int ImageDownloadTimeout { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportDeployment.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportDeployment.cs new file mode 100644 index 0000000000..b9e323c670 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportDeployment.cs @@ -0,0 +1,141 @@ +using System; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Core.Domain +{ + public class ExportDeployment : BaseEntity, ICloneable + { + /// + /// The profile identifier + /// + public int ProfileId { get; set; } + + /// + /// Name of the deployment + /// + public string Name { get; set; } + + /// + /// Whether the deployment is enabled + /// + public bool Enabled { get; set; } + + /// + /// XML with information about the last deployment result + /// + public string ResultInfo { get; set; } + + /// + /// The deployment type identifier + /// + public int DeploymentTypeId { get; set; } + + /// + /// The deployment type + /// + public ExportDeploymentType DeploymentType + { + get + { + return (ExportDeploymentType)DeploymentTypeId; + } + set + { + DeploymentTypeId = (int)value; + } + } + + public string Username { get; set; } + + public string Password { get; set; } + + /// + /// Deployment URL + /// + public string Url { get; set; } + + /// + /// The type identifier of how to transmit via HTTP + /// + public int HttpTransmissionTypeId { get; set; } + + /// + /// The type of how to transmit via HTTP + /// + public ExportHttpTransmissionType HttpTransmissionType + { + get + { + return (ExportHttpTransmissionType)HttpTransmissionTypeId; + } + set + { + HttpTransmissionTypeId = (int)value; + } + } + + /// + /// The file system path + /// + public string FileSystemPath { get; set; } + + /// + /// Path of a subfolder + /// + public string SubFolder { get; set; } + + /// + /// Multiple email addresses can be separated by commas + /// + public string EmailAddresses { get; set; } + + /// + /// Subject of the email + /// + public string EmailSubject { get; set; } + + /// + /// Identifier of the email account + /// + public int EmailAccountId { get; set; } + + /// + /// Whether to use FTP active or passive mode + /// + public bool PassiveMode { get; set; } + + /// + /// Whether to use SSL + /// + public bool UseSsl { get; set; } + + public virtual ExportProfile Profile { get; set; } + + public ExportDeployment Clone() + { + var deployment = new ExportDeployment + { + Name = this.Name, + Enabled = this.Enabled, + DeploymentTypeId = this.DeploymentTypeId, + Username = this.Username, + Password = this.Password, + Url = this.Url, + HttpTransmissionTypeId = this.HttpTransmissionTypeId, + FileSystemPath = this.FileSystemPath, + SubFolder = this.SubFolder, + EmailAddresses = this.EmailAddresses, + EmailSubject = this.EmailSubject, + EmailAccountId = this.EmailAccountId, + PassiveMode = this.PassiveMode, + UseSsl = this.UseSsl + }; + return deployment; + } + + object ICloneable.Clone() + { + return this.Clone(); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs new file mode 100644 index 0000000000..6ea68ec73c --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportEnums.cs @@ -0,0 +1,146 @@ +using System; + +namespace SmartStore.Core.Domain.DataExchange +{ + /// + /// Supported entity types + /// + public enum ExportEntityType + { + Product = 0, + Category, + Manufacturer, + Customer, + Order, + NewsLetterSubscription + } + + /// + /// Supported deployment types + /// + public enum ExportDeploymentType + { + FileSystem = 0, + Email, + Http, + Ftp, + PublicFolder + } + + /// + /// Supported HTTP transmission types + /// + public enum ExportHttpTransmissionType + { + SimplePost = 0, + MultipartFormDataPost + } + + /// + /// Controls the merging of various data as product description + /// + public enum ExportDescriptionMerging + { + None = 0, + ShortDescriptionOrNameIfEmpty, + ShortDescription, + Description, + NameAndShortDescription, + NameAndDescription, + ManufacturerAndNameAndShortDescription, + ManufacturerAndNameAndDescription + } + + /// + /// Controls the merging of various data while exporting attribute combinations as products + /// + public enum ExportAttributeValueMerging + { + None = 0, + AppendAllValuesToName + } + + /// + /// Controls data processing and projection items supported by an export provider + /// + [Flags] + public enum ExportFeatures + { + None = 0, + + /// + /// Whether to automatically create a file based public deployment when an export profile is created + /// + CreatesInitialPublicDeployment = 1, + + /// + /// Whether to offer option to include\exclude grouped products + /// + CanOmitGroupedProducts = 1 << 2, + + /// + /// Whether to offer option to export attribute combinations as products + /// + CanProjectAttributeCombinations = 1 << 3, + + /// + /// Whether to offer further options to manipulate the product description + /// + CanProjectDescription = 1 << 4, + + /// + /// Whether to offer option to enter a brand fallback + /// + OffersBrandFallback = 1 << 5, + + /// + /// Whether to offer option to set a picture size and to get the URL of the main image + /// + CanIncludeMainPicture = 1 << 6, + + /// + /// Whether to use SKU as manufacturer part number if MPN is empty + /// + UsesSkuAsMpnFallback = 1 << 7, + + /// + /// Whether to offer option to enter a shipping time fallback + /// + OffersShippingTimeFallback = 1 << 8, + + /// + /// Whether to offer option to enter a shipping costs fallback and a free shipping threshold + /// + OffersShippingCostsFallback = 1 << 9, + + /// + /// Whether to get the calculated old product price + /// + UsesOldPrice = 1 << 10, + + /// + /// Whether to get the calculated special and regular price (ignoring special offers) + /// + UsesSpecialPrice = 1 << 11, + + /// + /// Whether to not automatically send a completion email + /// + CanOmitCompletionMail = 1 << 12, + + /// + /// Whether to provide additional data of attribute combinations + /// + UsesAttributeCombination = 1 << 13 + } + + /// + /// Possible order status change after order exporting + /// + public enum ExportOrderStatusChange + { + None = 0, + Processing, + Complete + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs new file mode 100644 index 0000000000..23d08fd03c --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportFilter.cs @@ -0,0 +1,175 @@ +using System; +using SmartStore.Core.Domain.Catalog; + +namespace SmartStore.Core.Domain.DataExchange +{ + [Serializable] + public class ExportFilter + { + /// + /// Store identifier; 0 to load all records + /// + public int StoreId { get; set; } + + /// + /// Entity created from + /// + public DateTime? CreatedFrom { get; set; } + + /// + /// Entity created to + /// + public DateTime? CreatedTo { get; set; } + + #region Product + + /// + /// Minimum product identifier + /// + public int? IdMinimum { get; set; } + + /// + /// Maximum product identifier + /// + public int? IdMaximum { get; set; } + + /// + /// Minimum price + /// + public decimal? PriceMinimum { get; set; } + + /// + /// Maximum price + /// + public decimal? PriceMaximum { get; set; } + + /// + /// Minimum product availability + /// + public int? AvailabilityMinimum { get; set; } + + /// + /// Maximum product availability + /// + public int? AvailabilityMaximum { get; set; } + + /// + /// A value indicating whether to load only published or non published products + /// + public bool? IsPublished { get; set; } + + /// + /// Category identifiers + /// + public int[] CategoryIds { get; set; } + + /// + /// A value indicating whether to load products without any catgory mapping + /// + public bool? WithoutCategories { get; set; } + + /// + /// Manufacturer identifier + /// + public int? ManufacturerId { get; set; } + + /// + /// A value indicating whether to load products without any manufacturer mapping + /// + public bool? WithoutManufacturers { get; set; } + + /// + /// Identifiers of product tag + /// + public int? ProductTagId { get; set; } + + /// + /// A value indicating whether to load products that are marked as featured (relates only to categories and manufacturers) + /// + public bool? FeaturedProducts { get; set; } + + /// + /// Filter by product type + /// + public ProductType? ProductType { get; set; } + + #endregion + + #region Order + + /// + /// Filter by order status + /// + public int[] OrderStatusIds { get; set; } + + /// + /// Filter by payment status + /// + public int[] PaymentStatusIds { get; set; } + + /// + /// Filter by shipping status + /// + public int[] ShippingStatusIds { get; set; } + + #endregion + + #region Customer + + /// + /// Filter by active or inactive customers + /// + public bool? IsActiveCustomer { get; set; } + + /// + /// Filter by tax exempt customers + /// + public bool? IsTaxExempt { get; set; } + + /// + /// Identifiers of customer roles + /// + public int[] CustomerRoleIds { get; set; } + + /// + /// Filter by billing country identifiers + /// + public int[] BillingCountryIds { get; set; } + + /// + /// Filter by shipping country identifiers + /// + public int[] ShippingCountryIds { get; set; } + + /// + /// Filter by last activity date from + /// + public DateTime? LastActivityFrom { get; set; } + + /// + /// Filter by last activity date to + /// + public DateTime? LastActivityTo { get; set; } + + /// + /// Filter by at least spent amount + /// + public decimal? HasSpentAtLeastAmount { get; set; } + + /// + /// Filter by at least placed orders + /// + public int? HasPlacedAtLeastOrders { get; set; } + + #endregion + + #region Newsletter Subscription + + /// + /// Filter by active or inactive subscriber + /// + public bool? IsActiveSubscriber { get; set; } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs new file mode 100644 index 0000000000..3161d1ea94 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProfile.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Tasks; + +namespace SmartStore.Core.Domain +{ + public class ExportProfile : BaseEntity, ICloneable + { + private ICollection _deployments; + + public ExportProfile() + { + Enabled = true; + PerStore = true; + Cleanup = true; + EmailAccountId = 0; + } + + /// + /// The name of the profile + /// + public string Name { get; set; } + + /// + /// The root path of the export folder + /// + public string FolderName { get; set; } + + /// + /// The pattern for file names + /// + public string FileNamePattern { get; set; } + + /// + /// The system name of the profile + /// + public string SystemName { get; set; } + + /// + /// The system name of the export provider + /// + public string ProviderSystemName { get; set; } + + /// + /// Whether the profile is an unremovable system profile + /// + public bool IsSystemProfile { get; set; } + + /// + /// Whether the export profile is enabled + /// + public bool Enabled { get; set; } + + /// + /// The scheduling task identifier + /// + public int SchedulingTaskId { get; set; } + + /// + /// XML with filtering information + /// + public string Filtering { get; set; } + + /// + /// XML with projection information + /// + public string Projection { get; set; } + + /// + /// XML with provider specific configuration data + /// + public string ProviderConfigData { get; set; } + + /// + /// XML with information about the last export + /// + public string ResultInfo { get; set; } + + /// + /// The number of records to be skipped + /// + public int Offset { get; set; } + + /// + /// How many records to be loaded per database round-trip + /// + public int Limit { get; set; } + + /// + /// The maximum number of records of one processed batch + /// + public int BatchSize { get; set; } + + /// + /// Whether to start a separate run-through for each store + /// + public bool PerStore { get; set; } + + /// + /// Email Account identifier used to send a notification message an export completes + /// + public int EmailAccountId { get; set; } + + /// + /// Email addresses where to send the notification message + /// + public string CompletedEmailAddresses { get; set; } + + /// + /// Whether to combine and compress the export files in a ZIP archive + /// + public bool CreateZipArchive { get; set; } + + /// + /// Whether to delete unneeded files after deployment + /// + public bool Cleanup { get; set; } + + + /// + /// The scheduling task + /// + public virtual ScheduleTask ScheduleTask { get; set; } + + /// + /// Gets or sets export deployments + /// + public virtual ICollection Deployments + { + get { return _deployments ?? (_deployments = new HashSet()); } + set { _deployments = value; } + } + + public ExportProfile Clone() + { + var profile = new ExportProfile + { + Name = this.Name, + FolderName = null, + FileNamePattern = this.FileNamePattern, + ProviderSystemName = this.ProviderSystemName, + Enabled = this.Enabled, + SchedulingTaskId = 0, + Filtering = this.Filtering, + Projection = this.Projection, + ProviderConfigData = this.ProviderConfigData, + ResultInfo = null, + Offset = this.Offset, + Limit = this.Limit, + BatchSize = this.BatchSize, + PerStore = this.PerStore, + EmailAccountId = this.EmailAccountId, + CompletedEmailAddresses = this.CompletedEmailAddresses, + CreateZipArchive = this.CreateZipArchive, + Cleanup = this.Cleanup + }; + return profile; + } + + object ICloneable.Clone() + { + return this.Clone(); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs new file mode 100644 index 0000000000..493acda473 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ExportProjection.cs @@ -0,0 +1,181 @@ +using System; +using System.Xml.Serialization; +using SmartStore.Core.Domain.Catalog; + +namespace SmartStore.Core.Domain.DataExchange +{ + /// + /// Settings projected onto an export + /// + /// + /// Note possible projection controlling: a) developer controls, b) merchant controls, c) developer controls what the merchant can control + /// + [Serializable] + public class ExportProjection + { + #region All entity types + + /// + /// Store identifier + /// + public int? StoreId { get; set; } + + /// + /// The language to be applied to the export + /// + public int? LanguageId { get; set; } + + /// + /// The currency to be applied to the export + /// + public int? CurrencyId { get; set; } + + /// + /// Customer identifier + /// + public int? CustomerId { get; set; } + + #endregion + + #region Product + + /// + /// Description merging identifier + /// + public int DescriptionMergingId { get; set; } + + /// + /// Decription merging + /// + [XmlIgnore] + public ExportDescriptionMerging DescriptionMerging + { + get + { + return (ExportDescriptionMerging)DescriptionMergingId; + } + set + { + DescriptionMergingId = (int)value; + } + } + + /// + /// Convert HTML decription to plain text + /// + public bool DescriptionToPlainText { get; set; } + + /// + /// Comma separated text to append to the decription + /// + public string AppendDescriptionText { get; set; } + + /// + /// Remove critical characters from the description + /// + public bool RemoveCriticalCharacters { get; set; } + + /// + /// Comma separated list of critical characters + /// + public string CriticalCharacters { get; set; } + + /// + /// The price type for calculating the product price + /// + public PriceDisplayType? PriceType { get; set; } + + /// + /// Convert net to gross prices + /// + public bool ConvertNetToGrossPrices { get; set; } + + /// + /// Fallback for product brand + /// + public string Brand { get; set; } + + /// + /// Number of images per object to be exported + /// + public int? NumberOfPictures { get; set; } + + /// + /// Picture size + /// + public int PictureSize { get; set; } + + /// + /// Fallback for shipping time + /// + public string ShippingTime { get; set; } + + /// + /// Fallback for shipping costs + /// + public decimal? ShippingCosts { get; set; } + + /// + /// Free shipping threshold + /// + public decimal? FreeShippingThreshold { get; set; } + + /// + /// Whether to export attribute combinations as products + /// + public bool AttributeCombinationAsProduct { get; set; } + + /// + /// Identifier for merging attribute values of attribute combinations + /// + public int AttributeCombinationValueMergingId { get; set; } + + /// + /// Merging attribute values of attribute combinations + /// + [XmlIgnore] + public ExportAttributeValueMerging AttributeCombinationValueMerging + { + get + { + return (ExportAttributeValueMerging)AttributeCombinationValueMergingId; + } + set + { + AttributeCombinationValueMergingId = (int)value; + } + } + + /// + /// Whether to export grouped products + /// + public bool NoGroupedProducts { get; set; } + + #endregion + + #region Order + + /// + /// Identifier of the new state for orders + /// + public int OrderStatusChangeId { get; set; } + + /// + /// New state for orders + /// + [XmlIgnore] + public ExportOrderStatusChange OrderStatusChange + { + get + { + return (ExportOrderStatusChange)OrderStatusChangeId; + } + set + { + OrderStatusChangeId = (int)value; + } + } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs new file mode 100644 index 0000000000..94bbd69246 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportEnums.cs @@ -0,0 +1,28 @@ +using System; + +namespace SmartStore.Core.Domain.DataExchange +{ + /// + /// Supported entity types + /// + public enum ImportEntityType + { + Product = 0, + Category, + Customer, + NewsLetterSubscription + } + + public enum ImportFileType + { + CSV = 0, + XLSX + } + + [Flags] + public enum ImportModeFlags + { + Insert = 1, + Update = 2 + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs new file mode 100644 index 0000000000..1139496b4a --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/ImportProfile.cs @@ -0,0 +1,113 @@ +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Tasks; + +namespace SmartStore.Core.Domain +{ + public class ImportProfile : BaseEntity + { + /// + /// The name of the profile + /// + public string Name { get; set; } + + /// + /// The name of the folder (file system) + /// + public string FolderName { get; set; } + + /// + /// The identifier of the file type + /// + public int FileTypeId { get; set; } + + /// + /// The file type + /// + public ImportFileType FileType + { + get + { + return (ImportFileType)FileTypeId; + } + set + { + FileTypeId = (int)value; + } + } + + /// + /// The identifier of the entity type + /// + public int EntityTypeId { get; set; } + + /// + /// The entity type + /// + public ImportEntityType EntityType + { + get + { + return (ImportEntityType)EntityTypeId; + } + set + { + EntityTypeId = (int)value; + } + } + + /// + /// Whether the profile is enabled + /// + public bool Enabled { get; set; } + + /// + /// Number of records to bypass + /// + public int Skip { get; set; } + + /// + /// Maximum number of records to return + /// + public int Take { get; set; } + + /// + /// Whether to only update existing data + /// + public bool UpdateOnly { get; set; } + + /// + /// Name of key fields to identify existing records during import + /// + public string KeyFieldNames { get; set; } + + /// + /// File type specific configuration + /// + public string FileTypeConfiguration { get; set; } + + /// + /// XML with extra data + /// + public string ExtraData { get; set; } + + /// + /// Mapping of import columns + /// + public string ColumnMapping { get; set; } + + /// + /// XML with information about the last import + /// + public string ResultInfo { get; set; } + + /// + /// The scheduling task identifier + /// + public int SchedulingTaskId { get; set; } + + /// + /// The scheduling task + /// + public virtual ScheduleTask ScheduleTask { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/DataExchange/SyncMapping.cs b/src/Libraries/SmartStore.Core/Domain/DataExchange/SyncMapping.cs new file mode 100644 index 0000000000..a297bc8f85 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/DataExchange/SyncMapping.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.Core.Domain.DataExchange +{ + /// + /// Holds info about a synchronization operation with an external system + /// + [DataContract] + public partial class SyncMapping : BaseEntity + { + public SyncMapping() + { + this.SyncedOnUtc = DateTime.UtcNow; + } + + /// + /// Gets or sets the entity identifier in SmartStore + /// + [Index("IX_SyncMapping_ByEntity", 0, IsUnique = true)] + [DataMember] + public int EntityId { get; set; } + + /// + /// Gets or sets the entity's key in the external application + /// + [Index("IX_SyncMapping_BySource", 0, IsUnique = true)] + [DataMember] + public string SourceKey { get; set; } + + /// + /// Gets or sets a name representing the entity type + /// + [Index("IX_SyncMapping_ByEntity", 1, IsUnique = true)] + [Index("IX_SyncMapping_BySource", 1, IsUnique = true)] + [DataMember] + public string EntityName { get; set; } + + /// + /// Gets or sets a name for the external application + /// + [Index("IX_SyncMapping_ByEntity", 2, IsUnique = true)] + [Index("IX_SyncMapping_BySource", 2, IsUnique = true)] + [DataMember] + public string ContextName { get; set; } + + /// + /// Gets or sets an optional content hash reflecting the source model at the time of last sync + /// + [DataMember] + public string SourceHash { get; set; } + + /// + /// Gets or sets a custom integer value + /// + [DataMember] + public int? CustomInt { get; set; } + + /// + /// Gets or sets a custom string value + /// + [DataMember] + public string CustomString { get; set; } + + /// + /// Gets or sets a custom bool value + /// + [DataMember] + public bool? CustomBool { get; set; } + + /// + /// Gets or sets the date of the last sync operation + /// + [DataMember] + public DateTime SyncedOnUtc { get; set; } + + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Directory/Country.cs b/src/Libraries/SmartStore.Core/Domain/Directory/Country.cs index d324292c0f..117a487a07 100644 --- a/src/Libraries/SmartStore.Core/Domain/Directory/Country.cs +++ b/src/Libraries/SmartStore.Core/Domain/Directory/Country.cs @@ -1,7 +1,8 @@ using System.Collections.Generic; +using System.Runtime.Serialization; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Shipping; -using System.Runtime.Serialization; +using SmartStore.Core.Domain.Stores; namespace SmartStore.Core.Domain.Directory { @@ -9,7 +10,7 @@ namespace SmartStore.Core.Domain.Directory /// Represents a country /// [DataContract] - public partial class Country : BaseEntity, ILocalizedEntity + public partial class Country : BaseEntity, ILocalizedEntity, IStoreMappingSupported { private ICollection _stateProvinces; private ICollection _restrictedShippingMethods; @@ -68,13 +69,19 @@ public partial class Country : BaseEntity, ILocalizedEntity /// [DataMember] public int DisplayOrder { get; set; } + + /// + /// Gets or sets a value indicating whether the entity is limited/restricted to certain stores + /// + [DataMember] + public bool LimitedToStores { get; set; } /// /// Gets or sets the state/provinces /// public virtual ICollection StateProvinces { - get { return _stateProvinces ?? (_stateProvinces = new List()); } + get { return _stateProvinces ?? (_stateProvinces = new HashSet()); } protected set { _stateProvinces = value; } } @@ -83,7 +90,7 @@ public virtual ICollection StateProvinces /// public virtual ICollection RestrictedShippingMethods { - get { return _restrictedShippingMethods ?? (_restrictedShippingMethods = new List()); } + get { return _restrictedShippingMethods ?? (_restrictedShippingMethods = new HashSet()); } protected set { _restrictedShippingMethods = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs b/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs index d1c807b4a6..371d202799 100644 --- a/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Directory/CurrencySettings.cs @@ -1,12 +1,9 @@ - -using SmartStore.Core.Configuration; +using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.Directory { public class CurrencySettings : ISettings { - public int PrimaryStoreCurrencyId { get; set; } - public int PrimaryExchangeRateCurrencyId { get; set; } public string ActiveExchangeRateProviderSystemName { get; set; } public bool AutoUpdateEnabled { get; set; } public long LastUpdateTime { get; set; } diff --git a/src/Libraries/SmartStore.Core/Domain/Directory/DeliveryTime.cs b/src/Libraries/SmartStore.Core/Domain/Directory/DeliveryTime.cs index 01f8171a9f..8918b39b4f 100644 --- a/src/Libraries/SmartStore.Core/Domain/Directory/DeliveryTime.cs +++ b/src/Libraries/SmartStore.Core/Domain/Directory/DeliveryTime.cs @@ -28,11 +28,6 @@ public partial class DeliveryTime : BaseEntity, ILocalizedEntity [DataMember] public string DisplayLocale { get; set; } - /// - /// Gets or sets a value indicating whether the entity is published - /// - //public virtual bool Published { get; set; } - /// /// Gets or sets the display order /// diff --git a/src/Libraries/SmartStore.Core/Domain/Directory/ExchangeRate.cs b/src/Libraries/SmartStore.Core/Domain/Directory/ExchangeRate.cs index be7e47e2ec..b8d1c9f989 100644 --- a/src/Libraries/SmartStore.Core/Domain/Directory/ExchangeRate.cs +++ b/src/Libraries/SmartStore.Core/Domain/Directory/ExchangeRate.cs @@ -1,10 +1,12 @@ using System; +using System.Diagnostics; namespace SmartStore.Core.Domain.Directory { /// /// Represents an exchange rate /// + [DebuggerDisplay("{CurrencyCode} {Rate}")] public partial class ExchangeRate { /// @@ -31,15 +33,6 @@ public ExchangeRate() /// public DateTime UpdatedOn { get; set; } - - /// - /// Format the rate into a string with the currency code, e.g. "USD 0.72543" - /// - /// - public override string ToString() - { - return string.Format("{0} {1}", this.CurrencyCode, this.Rate); - } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Directory/QuantityUnit.cs b/src/Libraries/SmartStore.Core/Domain/Directory/QuantityUnit.cs new file mode 100644 index 0000000000..f10f0543c3 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Directory/QuantityUnit.cs @@ -0,0 +1,44 @@ +using System; +using SmartStore.Core.Domain.Localization; +using System.Runtime.Serialization; + +namespace SmartStore.Core.Domain.Directory +{ + /// + /// Represents a quantity unit + /// + [DataContract] + public partial class QuantityUnit : BaseEntity, ILocalizedEntity + { + /// + /// Gets or sets the name + /// + [DataMember] + public string Name { get; set; } + + /// + /// Gets or sets the description + /// + [DataMember] + public string Description { get; set; } + + /// + /// Gets or sets the display locale + /// + [DataMember] + public string DisplayLocale { get; set; } + + /// + /// Gets or sets the display order + /// + [DataMember] + public int DisplayOrder { get; set; } + + /// + /// Gets or sets the default quantity unit + /// + [DataMember] + public bool IsDefault { get; set; } + + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Discounts/Discount.cs b/src/Libraries/SmartStore.Core/Domain/Discounts/Discount.cs index ee4e7e5bcb..a803bc898f 100644 --- a/src/Libraries/SmartStore.Core/Domain/Discounts/Discount.cs +++ b/src/Libraries/SmartStore.Core/Domain/Discounts/Discount.cs @@ -118,7 +118,7 @@ public DiscountLimitationType DiscountLimitation /// public virtual ICollection DiscountRequirements { - get { return _discountRequirements ?? (_discountRequirements = new List()); } + get { return _discountRequirements ?? (_discountRequirements = new HashSet()); } protected set { _discountRequirements = value; } } @@ -128,7 +128,7 @@ public virtual ICollection DiscountRequirements [DataMember] public virtual ICollection AppliedToCategories { - get { return _appliedToCategories ?? (_appliedToCategories = new List()); } + get { return _appliedToCategories ?? (_appliedToCategories = new HashSet()); } protected set { _appliedToCategories = value; } } @@ -137,7 +137,7 @@ public virtual ICollection AppliedToCategories /// public virtual ICollection AppliedToProducts { - get { return _appliedToProducts ?? (_appliedToProducts = new List()); } + get { return _appliedToProducts ?? (_appliedToProducts = new HashSet()); } protected set { _appliedToProducts = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Forums/Forum.cs b/src/Libraries/SmartStore.Core/Domain/Forums/Forum.cs index 4823f78825..1af950f759 100644 --- a/src/Libraries/SmartStore.Core/Domain/Forums/Forum.cs +++ b/src/Libraries/SmartStore.Core/Domain/Forums/Forum.cs @@ -1,11 +1,13 @@ using System; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Seo; namespace SmartStore.Core.Domain.Forums { /// /// Represents a forum /// - public partial class Forum : BaseEntity + public partial class Forum : BaseEntity, ILocalizedEntity, ISlugSupported { /// /// Gets or sets the forum group identifier diff --git a/src/Libraries/SmartStore.Core/Domain/Forums/ForumGroup.cs b/src/Libraries/SmartStore.Core/Domain/Forums/ForumGroup.cs index 5a78652dc6..fc84ae983e 100644 --- a/src/Libraries/SmartStore.Core/Domain/Forums/ForumGroup.cs +++ b/src/Libraries/SmartStore.Core/Domain/Forums/ForumGroup.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Seo; +using SmartStore.Core.Domain.Stores; namespace SmartStore.Core.Domain.Forums { /// /// Represents a forum group /// - public partial class ForumGroup : BaseEntity + public partial class ForumGroup : BaseEntity, IStoreMappingSupported, ILocalizedEntity, ISlugSupported { private ICollection _forums; @@ -35,12 +38,17 @@ public partial class ForumGroup : BaseEntity /// public DateTime UpdatedOnUtc { get; set; } + /// + /// Gets or sets a value indicating whether the entity is limited/restricted to certain stores + /// + public bool LimitedToStores { get; set; } + /// /// Gets or sets the collection of Forums /// public virtual ICollection Forums { - get { return _forums ?? (_forums = new List()); } + get { return _forums ?? (_forums = new HashSet()); } protected set { _forums = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Localization/Language.cs b/src/Libraries/SmartStore.Core/Domain/Localization/Language.cs index 9d898a2c75..ae4864b0c8 100644 --- a/src/Libraries/SmartStore.Core/Domain/Localization/Language.cs +++ b/src/Libraries/SmartStore.Core/Domain/Localization/Language.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Stores; using System.Runtime.Serialization; +using System.Diagnostics; namespace SmartStore.Core.Domain.Localization { @@ -8,6 +9,7 @@ namespace SmartStore.Core.Domain.Localization /// Represents a language /// [DataContract] + [DebuggerDisplay("{LanguageCulture}")] public partial class Language : BaseEntity, IStoreMappingSupported { private ICollection _localeStringResources; @@ -65,14 +67,9 @@ public partial class Language : BaseEntity, IStoreMappingSupported /// public virtual ICollection LocaleStringResources { - get { return _localeStringResources ?? (_localeStringResources = new List()); } + get { return _localeStringResources ?? (_localeStringResources = new HashSet()); } protected set { _localeStringResources = value; } } - // codehint: sm-add - public override string ToString() - { - return this.LanguageCulture; - } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Localization/LocaleStringResource.cs b/src/Libraries/SmartStore.Core/Domain/Localization/LocaleStringResource.cs index e15a379905..5beec257d7 100644 --- a/src/Libraries/SmartStore.Core/Domain/Localization/LocaleStringResource.cs +++ b/src/Libraries/SmartStore.Core/Domain/Localization/LocaleStringResource.cs @@ -1,8 +1,10 @@ +using System.Diagnostics; namespace SmartStore.Core.Domain.Localization { /// /// Represents a locale string resource /// + [DebuggerDisplay("{ResourceName} - {ResourceValue}")] public partial class LocaleStringResource : BaseEntity { /// @@ -35,10 +37,6 @@ public partial class LocaleStringResource : BaseEntity /// public virtual Language Language { get; set; } - public override string ToString() - { - return string.Format("{0} - {1}", ResourceName, ResourceValue); - } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs b/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs index 4cd7889fee..b02a4ad2a2 100644 --- a/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Localization/LocalizationSettings.cs @@ -9,6 +9,7 @@ public LocalizationSettings() UseImagesForLanguageSelection = true; DefaultLanguageRedirectBehaviour = DefaultLanguageRedirectBehaviour.StripSeoCode; InvalidLanguageRedirectBehaviour = InvalidLanguageRedirectBehaviour.ReturnHttp404; + LoadAllLocalizedPropertiesOnStartup = true; } /// @@ -26,6 +27,11 @@ public LocalizationSettings() /// public bool LoadAllLocaleRecordsOnStartup { get; set; } + /// + /// A value indicating whether to load all localized entity properties on application startup + /// + public bool LoadAllLocalizedPropertiesOnStartup { get; set; } + /// /// A value indicating whether the browser user lannguage should be detected /// diff --git a/src/Libraries/SmartStore.Core/Domain/Localization/LocalizedProperty.cs b/src/Libraries/SmartStore.Core/Domain/Localization/LocalizedProperty.cs index f00010b5e7..f0d0406fb4 100644 --- a/src/Libraries/SmartStore.Core/Domain/Localization/LocalizedProperty.cs +++ b/src/Libraries/SmartStore.Core/Domain/Localization/LocalizedProperty.cs @@ -1,3 +1,4 @@ +using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.Serialization; namespace SmartStore.Core.Domain.Localization @@ -12,24 +13,28 @@ public partial class LocalizedProperty : BaseEntity /// Gets or sets the entity identifier /// [DataMember] + [Index("IX_LocalizedProperty_Compound", Order = 1)] public int EntityId { get; set; } /// /// Gets or sets the language identifier /// [DataMember] + [Index("IX_LocalizedProperty_Compound", Order = 4)] public int LanguageId { get; set; } /// /// Gets or sets the locale key group /// [DataMember] + [Index("IX_LocalizedProperty_Compound", Order = 3)] public string LocaleKeyGroup { get; set; } /// /// Gets or sets the locale key /// [DataMember] + [Index("IX_LocalizedProperty_Compound", Order = 2)] public string LocaleKey { get; set; } /// diff --git a/src/Libraries/SmartStore.Core/Domain/Media/Download.cs b/src/Libraries/SmartStore.Core/Domain/Media/Download.cs index 92ebeba670..0082cbfc67 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/Download.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/Download.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.Serialization; namespace SmartStore.Core.Domain.Media @@ -7,22 +8,28 @@ namespace SmartStore.Core.Domain.Media /// Represents a download /// [DataContract] - public partial class Download : BaseEntity + public partial class Download : BaseEntity, ITransient { - /// - /// Gets a sets a GUID + public Download() + { + this.UpdatedOnUtc = DateTime.UtcNow; + } + + /// + /// Gets or sets a GUID /// [DataMember] + [Index] public Guid DownloadGuid { get; set; } /// - /// Gets a sets a value indicating whether DownloadUrl property should be used + /// Gets or sets a value indicating whether DownloadUrl property should be used /// [DataMember] public bool UseDownloadUrl { get; set; } /// - /// Gets a sets a download URL + /// Gets or sets a download URL /// [DataMember] public string DownloadUrl { get; set; } @@ -55,5 +62,19 @@ public partial class Download : BaseEntity /// [DataMember] public bool IsNew { get; set; } + + /// + /// Gets or sets a value indicating whether the entity transient/preliminary + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 1)] + public bool IsTransient { get; set; } + + /// + /// Gets or sets the date and time of instance update + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 0)] + public DateTime UpdatedOnUtc { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Media/MediaSettings.cs b/src/Libraries/SmartStore.Core/Domain/Media/MediaSettings.cs index 6d1deff20f..b3072c0912 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/MediaSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/MediaSettings.cs @@ -1,5 +1,4 @@ - -using SmartStore.Core.Configuration; +using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.Media { @@ -11,6 +10,7 @@ public MediaSettings() ProductThumbPictureSize = 100; ProductDetailsPictureSize = 300; ProductThumbPictureSizeOnProductDetailsPage = 70; + MessageProductThumbPictureSize = 70; AssociatedProductPictureSize = 125; BundledProductPictureSize = 70; CategoryThumbPictureSize = 125; @@ -18,7 +18,7 @@ public MediaSettings() CartThumbPictureSize = 80; CartThumbBundleItemPictureSize = 32; MiniCartThumbPictureSize = 32; - AutoCompleteSearchThumbPictureSize = 20; + VariantValueThumbPictureSize = 20; MaximumImageSize = 1280; DefaultPictureZoomEnabled = true; PictureZoomType = "window"; @@ -30,16 +30,17 @@ public MediaSettings() public int ProductThumbPictureSize { get; set; } public int ProductDetailsPictureSize { get; set; } public int ProductThumbPictureSizeOnProductDetailsPage { get; set; } - public int AssociatedProductPictureSize { get; set; } + public int MessageProductThumbPictureSize { get; set; } + public int AssociatedProductPictureSize { get; set; } public int BundledProductPictureSize { get; set; } - public int CategoryThumbPictureSize { get; set; } + public int CategoryThumbPictureSize { get; set; } public int ManufacturerThumbPictureSize { get; set; } public int CartThumbPictureSize { get; set; } public int CartThumbBundleItemPictureSize { get; set; } public int MiniCartThumbPictureSize { get; set; } - public int AutoCompleteSearchThumbPictureSize { get; set; } + public int VariantValueThumbPictureSize { get; set; } - public bool DefaultPictureZoomEnabled { get; set; } + public bool DefaultPictureZoomEnabled { get; set; } public string PictureZoomType { get; set; } public int MaximumImageSize { get; set; } diff --git a/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs b/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs index 58293af411..f527b7d693 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/Picture.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Catalog; using System.Runtime.Serialization; +using System; +using System.ComponentModel.DataAnnotations.Schema; namespace SmartStore.Core.Domain.Media { @@ -8,9 +10,14 @@ namespace SmartStore.Core.Domain.Media /// Represents a picture /// [DataContract] - public partial class Picture : BaseEntity + public partial class Picture : BaseEntity, ITransient { - private ICollection _productPictures; + public Picture() + { + this.UpdatedOnUtc = DateTime.UtcNow; + } + + private ICollection _productPictures; /// /// Gets or sets the picture binary /// @@ -34,13 +41,27 @@ public partial class Picture : BaseEntity [DataMember] public bool IsNew { get; set; } + /// + /// Gets or sets a value indicating whether the entity transient/preliminary + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 1)] + public bool IsTransient { get; set; } + + /// + /// Gets or sets the date and time of instance update + /// + [DataMember] + [Index("IX_UpdatedOn_IsTransient", 0)] + public DateTime UpdatedOnUtc { get; set; } + /// /// Gets or sets the product pictures /// [DataMember] public virtual ICollection ProductPictures { - get { return _productPictures ?? (_productPictures = new List()); } + get { return _productPictures ?? (_productPictures = new HashSet()); } protected set { _productPictures = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Media/PictureType.cs b/src/Libraries/SmartStore.Core/Domain/Media/PictureType.cs index 618b4f5052..3da89ff17a 100644 --- a/src/Libraries/SmartStore.Core/Domain/Media/PictureType.cs +++ b/src/Libraries/SmartStore.Core/Domain/Media/PictureType.cs @@ -3,7 +3,7 @@ namespace SmartStore.Core.Domain.Media /// /// Represents a picture item type /// - public enum PictureType : int + public enum PictureType { /// /// Entities (products, categories, manufacturers) @@ -15,7 +15,6 @@ public enum PictureType : int Avatar = 10, } - // codehint: sm-add public enum ThumbnailScaleMode { Auto, diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs index decde80336..859a7bd74f 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAccount.cs @@ -54,9 +54,10 @@ public string FriendlyName { get { - if (!String.IsNullOrWhiteSpace(this.DisplayName)) - return this.Email + " (" + this.DisplayName + ")"; - return this.Email; + if (DisplayName.IsEmpty()) + return Email; + + return "{0} ({1})".FormatInvariant(DisplayName, Email); } } diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs new file mode 100644 index 0000000000..3dada46a59 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Messages/EmailAttachmentStorageLocation.cs @@ -0,0 +1,22 @@ +using SmartStore.Core.Domain.Media; + +namespace SmartStore.Core.Domain.Messages +{ + public enum EmailAttachmentStorageLocation + { + /// + /// Attachment is embedded as Blob + /// + Blob, + + /// + /// Attachment is a reference to + /// + FileReference, + + /// + /// Attachment is located on disk (physical or virtual path) + /// + Path + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs b/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs index 79ca39edc1..75f66564ae 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/MessageTemplate.cs @@ -1,4 +1,5 @@ using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Stores; namespace SmartStore.Core.Domain.Messages @@ -42,5 +43,25 @@ public partial class MessageTemplate : BaseEntity, ILocalizedEntity, IStoreMappi /// Gets or sets a value indicating whether the entity is limited/restricted to certain stores /// public bool LimitedToStores { get; set; } + + /// + /// Gets or sets a value indicating whether emails derived from the template are only send manually + /// + public bool SendManually { get; set; } + + /// + /// Gets or sets the attachment 1 file identifier + /// + public int? Attachment1FileId { get; set; } + + /// + /// Gets or sets the attachment 2 file identifier + /// + public int? Attachment2FileId { get; set; } + + /// + /// Gets or sets the attachment 3 file identifier + /// + public int? Attachment3FileId { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/NewsLetterSubscription.cs b/src/Libraries/SmartStore.Core/Domain/Messages/NewsLetterSubscription.cs index 694975fe82..6339d91d32 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/NewsLetterSubscription.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/NewsLetterSubscription.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations.Schema; namespace SmartStore.Core.Domain.Messages { @@ -15,6 +16,7 @@ public partial class NewsLetterSubscription : BaseEntity /// /// Gets or sets the subcriber email /// + [Index("IX_NewsletterSubscription_Email_StoreId", 1)] public string Email { get; set; } /// @@ -30,6 +32,7 @@ public partial class NewsLetterSubscription : BaseEntity /// /// Gets or sets the store identifier /// + [Index("IX_NewsletterSubscription_Email_StoreId", 2)] public int StoreId { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs index d0d88d8db4..d3f7e63b93 100644 --- a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmail.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace SmartStore.Core.Domain.Messages { @@ -7,6 +8,8 @@ namespace SmartStore.Core.Domain.Messages /// public partial class QueuedEmail : BaseEntity { + private ICollection _attachments; + /// /// Gets or sets the priority /// @@ -82,9 +85,23 @@ public partial class QueuedEmail : BaseEntity /// public int EmailAccountId { get; set; } + /// + /// Gets or sets a value indicating whether emails are only send manually + /// + public bool SendManually { get; set; } + /// /// Gets the email account /// public virtual EmailAccount EmailAccount { get; set; } + + /// + /// Gets or sets the collection of attachments + /// + public virtual ICollection Attachments + { + get { return _attachments ?? (_attachments = new HashSet()); } + protected set { _attachments = value; } + } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs new file mode 100644 index 0000000000..cd6d436139 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Messages/QueuedEmailAttachment.cs @@ -0,0 +1,61 @@ +using SmartStore.Core.Domain.Media; + +namespace SmartStore.Core.Domain.Messages +{ + /// + /// Reperesents an e-mail attachment + /// + public partial class QueuedEmailAttachment : BaseEntity + { + + /// + /// Gets or sets the queued email identifier + /// + public int QueuedEmailId { get; set; } + + /// + /// Gets or sets the queued email entity instance + /// + public virtual QueuedEmail QueuedEmail { get; set; } + + /// + /// Gets or sets the storage location + /// + public EmailAttachmentStorageLocation StorageLocation { get; set; } + + /// + /// A physical or virtual path to the file (only applicable if location is Path) + /// + public string Path { get; set; } + + /// + /// The id of a record (only applicable if location is FileReference) + /// + public int? FileId { get; set; } + + /// + /// Gets the file object + /// + /// + /// This property is not named Download on purpose, because we're going to rename Download to File in a future release. + /// + public virtual Download File { get; set; } + + /// + /// The attachment's binary data (only applicable if location is Blob) + /// + public byte[] Data { get; set; } + + /// + /// The attachment file name (without path) + /// + public string Name { get; set; } + + /// + /// The attachment file's mime type, e.g. application/pdf + /// + public string MimeType { get; set; } + + } + +} diff --git a/src/Libraries/SmartStore.Core/Domain/News/NewsItem.cs b/src/Libraries/SmartStore.Core/Domain/News/NewsItem.cs index 5b12c93244..cbcf775f72 100644 --- a/src/Libraries/SmartStore.Core/Domain/News/NewsItem.cs +++ b/src/Libraries/SmartStore.Core/Domain/News/NewsItem.cs @@ -98,7 +98,7 @@ public partial class NewsItem : BaseEntity, ISlugSupported, IStoreMappingSupport /// public virtual ICollection NewsComments { - get { return _newsComments ?? (_newsComments = new List()); } + get { return _newsComments ?? (_newsComments = new HashSet()); } protected set { _newsComments = value; } } diff --git a/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs b/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs index 479b3c5c9b..ffceb3edab 100644 --- a/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/News/NewsSettings.cs @@ -1,5 +1,4 @@ - -using SmartStore.Core.Configuration; +using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.News { @@ -12,6 +11,7 @@ public NewsSettings() ShowNewsOnMainPage = true; MainPageNewsCount = 3; NewsArchivePageSize = 10; + MaxAgeInDays = 180; } /// @@ -44,6 +44,11 @@ public NewsSettings() /// public int NewsArchivePageSize { get; set; } + /// + /// The maximum age of news (in days) for RSS feed + /// + public int MaxAgeInDays { get; set; } + /// /// Enable the news RSS feed link in customers browser address bar /// diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/CheckoutAttribute.cs b/src/Libraries/SmartStore.Core/Domain/Orders/CheckoutAttribute.cs index c00cf19194..63cbf58ea8 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/CheckoutAttribute.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/CheckoutAttribute.cs @@ -1,16 +1,22 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Stores; namespace SmartStore.Core.Domain.Orders { - /// - /// Represents a checkout attribute - /// - public partial class CheckoutAttribute : BaseEntity, ILocalizedEntity - { + /// + /// Represents a checkout attribute + /// + public partial class CheckoutAttribute : BaseEntity, ILocalizedEntity, IStoreMappingSupported + { private ICollection _checkoutAttributeValues; + public CheckoutAttribute() + { + this.IsActive = true; + } + /// /// Gets or sets the name /// @@ -50,11 +56,21 @@ public partial class CheckoutAttribute : BaseEntity, ILocalizedEntity /// Gets or sets the display order /// public int DisplayOrder { get; set; } - - /// - /// Gets the attribute control type - /// - public AttributeControlType AttributeControlType + + /// + /// Gets or sets whether the checkout attribute is active + /// + public bool IsActive { get; set; } + + /// + /// Gets or sets a value indicating whether the entity is limited/restricted to certain stores + /// + public bool LimitedToStores { get; set; } + + /// + /// Gets the attribute control type + /// + public AttributeControlType AttributeControlType { get { @@ -65,12 +81,13 @@ public AttributeControlType AttributeControlType this.AttributeControlTypeId = (int)value; } } + /// /// Gets the checkout attribute values /// public virtual ICollection CheckoutAttributeValues { - get { return _checkoutAttributeValues ?? (_checkoutAttributeValues = new List()); } + get { return _checkoutAttributeValues ?? (_checkoutAttributeValues = new HashSet()); } protected set { _checkoutAttributeValues = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/CheckoutEnums.cs b/src/Libraries/SmartStore.Core/Domain/Orders/CheckoutEnums.cs new file mode 100644 index 0000000000..4ce792b336 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Orders/CheckoutEnums.cs @@ -0,0 +1,45 @@ +namespace SmartStore.Core.Domain.Orders +{ + /// + /// Setting for newsletter subscription in checkout + /// + public enum CheckoutNewsLetterSubscription + { + /// + /// No newsletter subscription checkbox + /// + None = 0, + + /// + /// Deactivated newsletter subscription checkbox + /// + Deactivated, + + /// + /// Activated newsletter subscription checkbox + /// + Activated + } + + + /// + /// Setting to hand over customer email to third party + /// + public enum CheckoutThirdPartyEmailHandOver + { + /// + /// No third party email hand over checkbox + /// + None = 0, + + /// + /// Deactivated third party email hand over checkbox + /// + Deactivated, + + /// + /// Activated third party email hand over checkbox + /// + Activated + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/GiftCard.cs b/src/Libraries/SmartStore.Core/Domain/Orders/GiftCard.cs index 7a6a05608b..0ec44d2923 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/GiftCard.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/GiftCard.cs @@ -76,7 +76,7 @@ public partial class GiftCard : BaseEntity /// public virtual ICollection GiftCardUsageHistory { - get { return _giftCardUsageHistory ?? (_giftCardUsageHistory = new List()); } + get { return _giftCardUsageHistory ?? (_giftCardUsageHistory = new HashSet()); } protected set { _giftCardUsageHistory = value; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/Order.cs b/src/Libraries/SmartStore.Core/Domain/Orders/Order.cs index 462633fce6..9db5f14733 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/Order.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/Order.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; using System.Diagnostics; using System.Globalization; using System.Runtime.Serialization; @@ -187,6 +188,12 @@ protected virtual SortedDictionary ParseTaxRates(string taxRat [DataMember] public decimal OrderShippingExclTax { get; set; } + /// + /// Gets or sets the tax rate for order shipping + /// + [DataMember] + public decimal OrderShippingTaxRate { get; set; } + /// /// Gets or sets the payment method additional fee (incl tax) /// @@ -199,6 +206,12 @@ protected virtual SortedDictionary ParseTaxRates(string taxRat [DataMember] public decimal PaymentMethodAdditionalFeeExclTax { get; set; } + /// + /// Gets or sets the tax rate for payment method additional fee + /// + [DataMember] + public decimal PaymentMethodAdditionalFeeTaxRate { get; set; } + /// /// Gets or sets the tax rates /// @@ -307,7 +320,6 @@ protected virtual SortedDictionary ParseTaxRates(string taxRat /// public string CardExpirationYear { get; set; } - /// codehint:sm-add begin /// /// Gets or sets a value indicating whether storing of credit card number is allowed /// @@ -348,8 +360,12 @@ protected virtual SortedDictionary ParseTaxRates(string taxRat /// public string DirectDebitIban { get; set; } - /// codehint:sm-add end - + /// + /// Gets or sets the customer order comment + /// + [DataMember] + public string CustomerOrderComment { get; set; } + /// /// Gets or sets the authorization transaction identifier /// @@ -413,6 +429,7 @@ protected virtual SortedDictionary ParseTaxRates(string taxRat /// /// Gets or sets a value indicating whether the entity has been deleted /// + [Index] public bool Deleted { get; set; } /// @@ -433,14 +450,26 @@ protected virtual SortedDictionary ParseTaxRates(string taxRat [DataMember] public int? RewardPointsRemaining { get; set; } - #endregion + /// + /// Gets or sets a value indicating whether a new payment notification arrived (IPN, webhook, callback etc.) + /// + [DataMember] + public bool HasNewPaymentNotification { get; set; } - #region Navigation properties + /// + /// Gets or sets a value indicating whether the customer accepted to hand over email address to third party + /// + [DataMember] + public bool AcceptThirdPartyEmailHandOver { get; set; } - /// - /// Gets or sets the customer - /// - [DataMember] + #endregion + + #region Navigation properties + + /// + /// Gets or sets the customer + /// + [DataMember] public virtual Customer Customer { get; set; } /// @@ -465,7 +494,7 @@ protected virtual SortedDictionary ParseTaxRates(string taxRat /// public virtual ICollection DiscountUsageHistory { - get { return _discountUsageHistory ?? (_discountUsageHistory = new List()); } + get { return _discountUsageHistory ?? (_discountUsageHistory = new HashSet()); } protected set { _discountUsageHistory = value; } } @@ -474,7 +503,7 @@ public virtual ICollection DiscountUsageHistory /// public virtual ICollection GiftCardUsageHistory { - get { return _giftCardUsageHistory ?? (_giftCardUsageHistory = new List()); } + get { return _giftCardUsageHistory ?? (_giftCardUsageHistory = new HashSet()); } protected set { _giftCardUsageHistory = value; } } @@ -484,7 +513,7 @@ public virtual ICollection GiftCardUsageHistory [DataMember] public virtual ICollection OrderNotes { - get { return _orderNotes ?? (_orderNotes = new List()); } + get { return _orderNotes ?? (_orderNotes = new HashSet()); } protected set { _orderNotes = value; } } @@ -494,7 +523,7 @@ public virtual ICollection OrderNotes [DataMember] public virtual ICollection OrderItems { - get { return _orderItems ?? (_orderItems = new List()); } + get { return _orderItems ?? (_orderItems = new HashSet()); } protected set { _orderItems = value; } } @@ -504,7 +533,7 @@ public virtual ICollection OrderItems [DataMember] public virtual ICollection Shipments { - get { return _shipments ?? (_shipments = new List()); } + get { return _shipments ?? (_shipments = new HashSet()); } protected set { _shipments = value; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/OrderItem.cs b/src/Libraries/SmartStore.Core/Domain/Orders/OrderItem.cs index 0d7e5c3d17..f3f2fc6416 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/OrderItem.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/OrderItem.cs @@ -61,6 +61,12 @@ public partial class OrderItem : BaseEntity [DataMember] public decimal PriceExclTax { get; set; } + /// + /// Gets or sets the tax rate + /// + [DataMember] + public decimal TaxRate { get; set; } + /// /// Gets or sets the discount amount (incl tax) /// @@ -139,7 +145,7 @@ public partial class OrderItem : BaseEntity /// public virtual ICollection AssociatedGiftCards { - get { return _associatedGiftCards ?? (_associatedGiftCards = new List()); } + get { return _associatedGiftCards ?? (_associatedGiftCards = new HashSet()); } protected set { _associatedGiftCards = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs b/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs index 8e6cf0fde1..05e9a49fd4 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/OrderSettings.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; -using SmartStore.Core.Configuration; +using SmartStore.Core.Configuration; +using SmartStore.Core.Domain.Localization; namespace SmartStore.Core.Domain.Orders { - public class OrderSettings : ISettings + public class OrderSettings : BaseEntity, ISettings, ILocalizedEntity { public OrderSettings() { @@ -11,10 +11,11 @@ public OrderSettings() AnonymousCheckoutAllowed = true; TermsOfServiceEnabled = true; ReturnRequestsEnabled = true; - ReturnRequestActions = new List() { "Repair", "Replacement", "Store Credit" }; - ReturnRequestReasons = new List() { "Received Wrong Product", "Wrong Product Ordered", "There Was A Problem With The Product" }; + ReturnRequestActions = "Repair,Replacement,Store Credit"; + ReturnRequestReasons = "Received Wrong Product,Wrong Product Ordered,There Was A Problem With The Product"; NumberOfDaysReturnRequestAvailable = 365; MinimumOrderPlacementInterval = 30; + OrderListPageSize = 10; } /// @@ -42,16 +43,6 @@ public OrderSettings() /// public bool TermsOfServiceEnabled { get; set; } - /// - /// Gets or sets a value indicating whether 'One-page checkout' is enabled - /// - public bool OnePageCheckoutEnabled { get; set; } - - /// - /// Gets or sets a value indicating whether order totals should be displayed on 'Payment info' tab of 'One-page checkout' page - /// - public bool OnePageCheckoutDisplayOrderTotalsOnPaymentInfoTab { get; set; } - /// /// Gets or sets a value indicating whether "Order completed" page should be skipped /// @@ -65,12 +56,12 @@ public OrderSettings() /// /// Gets or sets a list of return request reasons /// - public List ReturnRequestReasons { get; set; } + public string ReturnRequestReasons { get; set; } /// /// Gets or sets a list of return request actions /// - public List ReturnRequestActions { get; set; } + public string ReturnRequestActions { get; set; } /// /// Gets or sets a number of days that the Return Request Link will be available for customers after order placing. @@ -92,5 +83,14 @@ public OrderSettings() /// public int MinimumOrderPlacementInterval { get; set; } - } + /// + /// Gets or sets a value indicating whether to display all orders of all stores to a customer + /// + public bool DisplayOrdersOfAllStores { get; set; } + + /// + /// Page size of the order list + /// + public int OrderListPageSize { get; set; } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/OrderStatus.cs b/src/Libraries/SmartStore.Core/Domain/Orders/OrderStatus.cs index cbff14a755..bf41213405 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/OrderStatus.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/OrderStatus.cs @@ -3,7 +3,7 @@ namespace SmartStore.Core.Domain.Orders /// /// Represents an order status enumeration /// - public enum OrderStatus : int + public enum OrderStatus { /// /// Pending diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/RecurringPayment.cs b/src/Libraries/SmartStore.Core/Domain/Orders/RecurringPayment.cs index dd4896bb5b..9861dc9302 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/RecurringPayment.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/RecurringPayment.cs @@ -62,12 +62,12 @@ public DateTime? NextPaymentDate DateTime? result = null; if (!this.IsActive) - return result; + return null; var historyCollection = this.RecurringPaymentHistory; if (historyCollection.Count >= this.TotalCycles) { - return result; + return null; } //set another value to change calculation method diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequest.cs b/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequest.cs index 4135b6b042..ba269bdf4c 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequest.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequest.cs @@ -46,6 +46,12 @@ public partial class ReturnRequest : BaseEntity [DataMember] public string RequestedAction { get; set; } + /// + /// Gets or sets the date and time when requested action was last updated + /// + [DataMember] + public DateTime? RequestedActionUpdatedOnUtc { get; set; } + /// /// Gets or sets the customer comments /// @@ -58,6 +64,12 @@ public partial class ReturnRequest : BaseEntity [DataMember] public string StaffNotes { get; set; } + /// + /// Gets or sets the admin comment + /// + [DataMember] + public string AdminComment { get; set; } + /// /// Gets or sets the return status identifier /// diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequestStatus.cs b/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequestStatus.cs index 8cbb36ee80..02fea117d8 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequestStatus.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/ReturnRequestStatus.cs @@ -4,7 +4,7 @@ namespace SmartStore.Core.Domain.Orders /// /// Represents a return status /// - public enum ReturnRequestStatus : int + public enum ReturnRequestStatus { /// /// Pending diff --git a/src/Libraries/SmartStore.Core/Domain/Orders/ShoppingCartSettings.cs b/src/Libraries/SmartStore.Core/Domain/Orders/ShoppingCartSettings.cs index 5cf047fdbc..e403d7cdb1 100644 --- a/src/Libraries/SmartStore.Core/Domain/Orders/ShoppingCartSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Orders/ShoppingCartSettings.cs @@ -1,20 +1,24 @@ using SmartStore.Core.Configuration; +using SmartStore.Core.Domain.Localization; namespace SmartStore.Core.Domain.Orders { - public class ShoppingCartSettings : ISettings - { + public class ShoppingCartSettings : BaseEntity, ISettings, ILocalizedEntity + { public ShoppingCartSettings() { MaximumShoppingCartItems = 1000; MaximumWishlistItems = 1000; MoveItemsFromWishlistToCart = true; + ShowItemsFromWishlistToCartButton = true; ShowProductImagesOnShoppingCart = true; ShowProductBundleImagesOnShoppingCart = true; ShowProductImagesOnWishList = true; ShowProductBundleImagesOnWishList = true; ShowDiscountBox = true; ShowGiftCardBox = true; + ShowCommentBox = true; + ShowEsdRevocationWaiverBox = true; CrossSellsNumber = 8; EmailWishlistEnabled = true; MiniShoppingCartEnabled = true; @@ -56,6 +60,11 @@ public ShoppingCartSettings() /// public bool MoveItemsFromWishlistToCart { get; set; } + /// + /// Gets or sets a value indicating whether to show the items from wishlist to ahopping cart button. + /// + public bool ShowItemsFromWishlistToCartButton { get; set; } + /// /// Gets or sets a value indicating whether to show product image on shopping cart page /// @@ -87,9 +96,34 @@ public ShoppingCartSettings() public bool ShowGiftCardBox { get; set; } /// - /// Gets or sets a number of "Cross-sells" on shopping cart page + /// Gets or sets a value indicating whether to show a comment box on shopping cart page /// - public int CrossSellsNumber { get; set; } + public bool ShowCommentBox { get; set; } + + /// + /// Gets or sets a value indicating whether to show a revocation waiver checkbox box for ESD products + /// + public bool ShowEsdRevocationWaiverBox { get; set; } + + /// + /// Gets or sets a value indicating whether to show a checkbox to subscribe to newsletters + /// + public CheckoutNewsLetterSubscription NewsLetterSubscription { get; set; } + + /// + /// Gets or sets a value indicating whether to show a checkbox to let the customer accept to hand over email address to third party + /// + public CheckoutThirdPartyEmailHandOver ThirdPartyEmailHandOver { get; set; } + + /// + /// Gets or sets the label to accept to hand over the email to third party + /// + public string ThirdPartyEmailHandOverLabel { get; set; } + + /// + /// Gets or sets a number of "Cross-sells" on shopping cart page + /// + public int CrossSellsNumber { get; set; } /// /// Gets or sets a value indicating whether "email a wishlist" feature is enabled @@ -120,7 +154,6 @@ public ShoppingCartSettings() /// public bool RoundPricesDuringCalculation { get; set; } - // codehint: sm-add /// /// Gets or sets a value indicating whether to show a legal hint in the order summary /// @@ -136,6 +169,11 @@ public ShoppingCartSettings() /// public bool ShowShortDesc { get; set; } + /// + /// Gets or sets a value indicating whether to show the product weight in the order summary + /// + public bool ShowWeight { get; set; } + /// /// Gets or sets a value indicating whether to show the product short description in the order summary /// diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs new file mode 100644 index 0000000000..e078434cc6 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentMethod.cs @@ -0,0 +1,24 @@ +using System.Runtime.Serialization; +using SmartStore.Core.Domain.Localization; + +namespace SmartStore.Core.Domain.Payments +{ + /// + /// Represents a payment method + /// + [DataContract] + public partial class PaymentMethod : BaseEntity, ILocalizedEntity + { + /// + /// Gets or sets the payment method system name + /// + [DataMember] + public string PaymentMethodSystemName { get; set; } + + /// + /// Gets or sets the full description + /// + [DataMember] + public string FullDescription { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentStatus.cs b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentStatus.cs index ddd4e0bcaa..44f3dc262e 100644 --- a/src/Libraries/SmartStore.Core/Domain/Payments/PaymentStatus.cs +++ b/src/Libraries/SmartStore.Core/Domain/Payments/PaymentStatus.cs @@ -4,7 +4,7 @@ namespace SmartStore.Core.Domain.Payments /// /// Represents a payment status enumeration /// - public enum PaymentStatus : int + public enum PaymentStatus { /// /// Pending diff --git a/src/Libraries/SmartStore.Core/Domain/Polls/Poll.cs b/src/Libraries/SmartStore.Core/Domain/Polls/Poll.cs index 3b3f6e5395..73c2d2481f 100644 --- a/src/Libraries/SmartStore.Core/Domain/Polls/Poll.cs +++ b/src/Libraries/SmartStore.Core/Domain/Polls/Poll.cs @@ -67,7 +67,7 @@ public partial class Poll : BaseEntity, IStoreMappingSupported /// public virtual ICollection PollAnswers { - get { return _pollAnswers ?? (_pollAnswers = new List()); } + get { return _pollAnswers ?? (_pollAnswers = new HashSet()); } protected set { _pollAnswers = value; } } diff --git a/src/Libraries/SmartStore.Core/Domain/Polls/PollAnswer.cs b/src/Libraries/SmartStore.Core/Domain/Polls/PollAnswer.cs index b44812d8d0..86fb99cb53 100644 --- a/src/Libraries/SmartStore.Core/Domain/Polls/PollAnswer.cs +++ b/src/Libraries/SmartStore.Core/Domain/Polls/PollAnswer.cs @@ -39,7 +39,7 @@ public partial class PollAnswer : BaseEntity /// public virtual ICollection PollVotingRecords { - get { return _pollVotingRecords ?? (_pollVotingRecords = new List()); } + get { return _pollVotingRecords ?? (_pollVotingRecords = new HashSet()); } protected set { _pollVotingRecords = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Security/AclRecord.cs b/src/Libraries/SmartStore.Core/Domain/Security/AclRecord.cs index cd0349e586..7bd0cf40e3 100644 --- a/src/Libraries/SmartStore.Core/Domain/Security/AclRecord.cs +++ b/src/Libraries/SmartStore.Core/Domain/Security/AclRecord.cs @@ -1,3 +1,4 @@ +using SmartStore.Core.Domain.Customers; namespace SmartStore.Core.Domain.Security { /// @@ -20,6 +21,11 @@ public partial class AclRecord : BaseEntity /// public int CustomerRoleId { get; set; } + /// + /// Gets or sets the customer role + /// + public virtual CustomerRole CustomerRole { get; set; } + /// /// Gets or sets a value indicating whether the entry is idle /// diff --git a/src/Libraries/SmartStore.Core/Domain/Security/PermissionRecord.cs b/src/Libraries/SmartStore.Core/Domain/Security/PermissionRecord.cs index fd4d3d0f96..067a942459 100644 --- a/src/Libraries/SmartStore.Core/Domain/Security/PermissionRecord.cs +++ b/src/Libraries/SmartStore.Core/Domain/Security/PermissionRecord.cs @@ -30,7 +30,7 @@ public class PermissionRecord : BaseEntity /// public virtual ICollection CustomerRoles { - get { return _customerRoles ?? (_customerRoles = new List()); } + get { return _customerRoles ?? (_customerRoles = new HashSet()); } protected set { _customerRoles = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Seo/CanonicalHostNameRule.cs b/src/Libraries/SmartStore.Core/Domain/Seo/CanonicalHostNameRule.cs new file mode 100644 index 0000000000..7e64e097aa --- /dev/null +++ b/src/Libraries/SmartStore.Core/Domain/Seo/CanonicalHostNameRule.cs @@ -0,0 +1,20 @@ +namespace SmartStore.Core.Domain.Seo +{ + + public enum CanonicalHostNameRule + { + /// + /// Doesn't matter (as requested) + /// + NoRule, + /// + /// The www prefix is required (www.myshop.com is default host) + /// + RequireWww, + /// + /// The www prefix should be omitted (myshop.com is default host) + /// + OmitWww + } + +} diff --git a/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs b/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs index d7055dee10..1f06b5aba6 100644 --- a/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Seo/SeoSettings.cs @@ -1,33 +1,81 @@ - +using System; using System.Collections.Generic; using SmartStore.Core.Configuration; namespace SmartStore.Core.Domain.Seo { - public class SeoSettings : ISettings + public class SeoSettings : ISettings { public SeoSettings() { PageTitleSeparator = ". "; PageTitleSeoAdjustment = PageTitleSeoAdjustment.PagenameAfterStorename; - DefaultTitle = "Your store"; + DefaultTitle = "Shop"; DefaultMetaKeywords = ""; DefaultMetaDescription = ""; - AllowUnicodeCharsInUrls = true; - ReservedUrlRecordSlugs = new List() { "admin", "install", "recentlyviewedproducts", "newproducts", "compareproducts", "clearcomparelist", "setproductreviewhelpfulness", "login", "register", "logout", "cart", "wishlist", "emailwishlist", "checkout", "onepagecheckout", "contactus", "passwordrecovery", "subscribenewsletter", "blog", "boards", "inboxupdate", "sentupdate", "news", "sitemap", "sitemapseo", "search", "config", "api", "odata" }; - ExtraRobotsDisallows = new List(); + AllowUnicodeCharsInUrls = false; + CanonicalHostNameRule = CanonicalHostNameRule.NoRule; + LoadAllUrlAliasesOnStartup = true; + + ExtraRobotsDisallows = new List { "/blog/tag/", "/blog/month/", "/producttags/" }; + + ReservedUrlRecordSlugs = new List + { + "admin", + "install", + "recentlyviewedproducts", + "newproducts", + "compareproducts", + "clearcomparelist", + "setproductreviewhelpfulness", + "login", + "register", + "logout", + "cart", + "wishlist", + "emailwishlist", + "checkout", + "contactus", + "passwordrecovery", + "subscribenewsletter", + "blog", + "boards", + "inboxupdate", + "sentupdate", + "news", + "sitemap", + "sitemapseo", + "search", + "config", + "api", + "odata" + }; + + SeoNameCharConversion = string.Join(Environment.NewLine, new List + { + "ä;ae", + "ö;oe", + "ü;ue", + "Ä;Ae", + "Ö;Oe", + "Ü;Ue", + "ß;ss" + }); } - + public string PageTitleSeparator { get; set; } public PageTitleSeoAdjustment PageTitleSeoAdjustment { get; set; } public string DefaultTitle { get; set; } public string DefaultMetaKeywords { get; set; } public string DefaultMetaDescription { get; set; } + public string MetaRobotsContent { get; set; } - public bool ConvertNonWesternChars { get; set; } + public bool ConvertNonWesternChars { get; set; } public bool AllowUnicodeCharsInUrls { get; set; } + public string SeoNameCharConversion { get; set; } - public bool CanonicalUrlsEnabled { get; set; } + public bool CanonicalUrlsEnabled { get; set; } + public CanonicalHostNameRule CanonicalHostNameRule { get; set; } /// /// Slugs (sename) reserved for some other needs @@ -35,5 +83,10 @@ public SeoSettings() public List ReservedUrlRecordSlugs { get; set; } public List ExtraRobotsDisallows { get; set; } + + /// + /// A value indicating whether to load all URL records and active slugs on application startup + /// + public bool LoadAllUrlAliasesOnStartup { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs index 2dad16128f..e189e22b12 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/Shipment.cs @@ -59,9 +59,10 @@ public partial class Shipment : BaseEntity /// /// Gets or sets the shipment items /// + [DataMember] public virtual ICollection ShipmentItems { - get { return _shipmentItems ?? (_shipmentItems = new List()); } + get { return _shipmentItems ?? (_shipmentItems = new HashSet()); } protected set { _shipmentItems = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs index 48db08b9e1..fc77fb18b2 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShipmentItem.cs @@ -1,29 +1,35 @@ +using System.Runtime.Serialization; namespace SmartStore.Core.Domain.Shipping { /// /// Represents a shipment order product variant /// + [DataContract] public partial class ShipmentItem : BaseEntity { /// /// Gets or sets the shipment identifier /// + [DataMember] public int ShipmentId { get; set; } /// /// Gets or sets the order item identifier /// + [DataMember] public int OrderItemId { get; set; } /// /// Gets or sets the quantity /// + [DataMember] public int Quantity { get; set; } /// /// Gets the shipment /// + [DataMember] public virtual Shipment Shipment { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs index 2685392c3c..078b12a20c 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingMethod.cs @@ -5,10 +5,10 @@ namespace SmartStore.Core.Domain.Shipping { - /// - /// Represents a shipping method (used for offline shipping rate computation methods) - /// - [DataContract] + /// + /// Represents a shipping method (used for offline shipping rate computation methods) + /// + [DataContract] public partial class ShippingMethod : BaseEntity, ILocalizedEntity { private ICollection _restrictedCountries; @@ -40,7 +40,7 @@ public partial class ShippingMethod : BaseEntity, ILocalizedEntity [DataMember] public virtual ICollection RestrictedCountries { - get { return _restrictedCountries ?? (_restrictedCountries = new List()); } + get { return _restrictedCountries ?? (_restrictedCountries = new HashSet()); } protected set { _restrictedCountries = value; } } } diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs index d059f630b7..5edb06f415 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingOption.cs @@ -13,6 +13,11 @@ namespace SmartStore.Core.Domain.Shipping /// public partial class ShippingOption { + /// + /// Shipping method identifier + /// + public int ShippingMethodId { get; set; } + /// /// Gets or sets the system name of shipping rate computation method /// @@ -33,134 +38,4 @@ public partial class ShippingOption /// public string Description { get; set; } } - - - public class ShippingOptionTypeConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - { - return true; - } - - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string) - { - ShippingOption shippingOption = null; - string valueStr = value as string; - if (!String.IsNullOrEmpty(valueStr)) - { - try - { - using (var tr = new StringReader(valueStr)) - { - var xmlS = new XmlSerializer(typeof(ShippingOption)); - shippingOption = (ShippingOption)xmlS.Deserialize(tr); - } - } - catch - { - //xml error - } - } - return shippingOption; - } - return base.ConvertFrom(context, culture, value); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string)) - { - var shippingOption = value as ShippingOption; - if (shippingOption != null) - { - var sb = new StringBuilder(); - using (var tw = new StringWriter(sb)) - { - var xmlS = new XmlSerializer(typeof(ShippingOption)); - xmlS.Serialize(tw, value); - string serialized = sb.ToString(); - return serialized; - } - } - else - { - return ""; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - - public class ShippingOptionListTypeConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - { - return true; - } - - return base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string) - { - List shippingOptions = null; - string valueStr = value as string; - if (!String.IsNullOrEmpty(valueStr)) - { - try - { - using (var tr = new StringReader(valueStr)) - { - var xmlS = new XmlSerializer(typeof(List)); - shippingOptions = (List)xmlS.Deserialize(tr); - } - } - catch - { - //xml error - } - } - return shippingOptions; - } - return base.ConvertFrom(context, culture, value); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (destinationType == typeof(string)) - { - var shippingOptions = value as List; - if (shippingOptions != null) - { - var sb = new StringBuilder(); - using (var tw = new StringWriter(sb)) - { - var xmlS = new XmlSerializer(typeof(List)); - xmlS.Serialize(tw, value); - string serialized = sb.ToString(); - return serialized; - } - } - else - { - return ""; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } } diff --git a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingStatus.cs b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingStatus.cs index 64c1cde1e2..18bf8246d6 100644 --- a/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingStatus.cs +++ b/src/Libraries/SmartStore.Core/Domain/Shipping/ShippingStatus.cs @@ -3,7 +3,7 @@ namespace SmartStore.Core.Domain.Shipping /// /// Represents the shipping status enumeration /// - public enum ShippingStatus : int + public enum ShippingStatus { /// /// Shipping not required diff --git a/src/Libraries/SmartStore.Core/Domain/StoreInformationSettings.cs b/src/Libraries/SmartStore.Core/Domain/StoreInformationSettings.cs index 079e3831a1..b486b2acc3 100644 --- a/src/Libraries/SmartStore.Core/Domain/StoreInformationSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/StoreInformationSettings.cs @@ -19,8 +19,6 @@ public StoreInformationSettings() /// public bool StoreClosedAllowForAdmins { get; set; } - // codehint: sm-delete - /// /// Gets or sets a value indicating whether mini profiler should be displayed in public store (used for debugging) /// diff --git a/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs b/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs index 0b5c7e30b2..0d9fe6be96 100644 --- a/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs +++ b/src/Libraries/SmartStore.Core/Domain/Stores/Store.cs @@ -1,4 +1,5 @@ using System.Runtime.Serialization; +using SmartStore.Core.Domain.Directory; namespace SmartStore.Core.Domain.Stores { @@ -59,8 +60,34 @@ public partial class Store : BaseEntity /// /// Gets or sets the CDN host name, if static media content should be served through a CDN. /// + [DataMember] public string ContentDeliveryNetwork { get; set; } + /// + /// Gets or sets the primary store currency identifier + /// + [DataMember] + public int PrimaryStoreCurrencyId { get; set; } + + /// + /// Gets or sets the primary exchange rate currency identifier + /// + [DataMember] + public int PrimaryExchangeRateCurrencyId { get; set; } + + /// + /// Gets or sets the primary store currency + /// + [DataMember] + public virtual Currency PrimaryStoreCurrency { get; set; } + + /// + /// Gets or sets the primary exchange rate currency + /// + [DataMember] + public virtual Currency PrimaryExchangeRateCurrency { get; set; } + + /// /// Gets the security mode for the store /// diff --git a/src/Libraries/SmartStore.Core/Domain/Stores/StoreExtensions.cs b/src/Libraries/SmartStore.Core/Domain/Stores/StoreExtensions.cs index fe7812464c..3273ab21da 100644 --- a/src/Libraries/SmartStore.Core/Domain/Stores/StoreExtensions.cs +++ b/src/Libraries/SmartStore.Core/Domain/Stores/StoreExtensions.cs @@ -17,16 +17,12 @@ public static string[] ParseHostValues(this Store store) throw new ArgumentNullException("store"); var parsedValues = new List(); - if (!String.IsNullOrEmpty(store.Hosts)) + if (!string.IsNullOrEmpty(store.Hosts)) { - string[] hosts = store.Hosts.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string host in hosts) - { - var tmp = host.Trim(); - if (!String.IsNullOrEmpty(tmp)) - parsedValues.Add(tmp); - } + var hosts = store.Hosts.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + parsedValues.AddRange(hosts.Select(host => host.Trim()).Where(tmp => !string.IsNullOrEmpty(tmp))); } + return parsedValues.ToArray(); } diff --git a/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs b/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs index c04458e8de..5806d83c4f 100644 --- a/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs +++ b/src/Libraries/SmartStore.Core/Domain/Tasks/ScheduleTask.cs @@ -1,9 +1,13 @@  using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics; namespace SmartStore.Core.Domain.Tasks { - public class ScheduleTask : BaseEntity + [DebuggerDisplay("{Name} (Type: {Type})")] + public class ScheduleTask : BaseEntity, ICloneable { /// /// Gets or sets the name @@ -11,18 +15,25 @@ public class ScheduleTask : BaseEntity public string Name { get; set; } /// - /// Gets or sets the run period (in seconds) + /// Gets or sets the task alias (an optional key for advanced customization) /// - public int Seconds { get; set; } + public string Alias { get; set; } + + /// + /// Gets or sets the CRON expression used to calculate future schedules + /// + public string CronExpression { get; set; } /// /// Gets or sets the type of appropriate ITask class /// + [Index("IX_Type")] public string Type { get; set; } /// /// Gets or sets the value indicating whether a task is enabled /// + [Index("IX_NextRun_Enabled", 1)] public bool Enabled { get; set; } /// @@ -30,25 +41,69 @@ public class ScheduleTask : BaseEntity /// public bool StopOnError { get; set; } + [Index("IX_NextRun_Enabled", 0)] + public DateTime? NextRunUtc { get; set; } + + [Index("IX_LastStart_LastEnd", 0)] public DateTime? LastStartUtc { get; set; } + [Index("IX_LastStart_LastEnd", 1)] public DateTime? LastEndUtc { get; set; } public DateTime? LastSuccessUtc { get; set; } public string LastError { get; set; } + public bool IsHidden { get; set; } + + /// + /// Gets or sets a value indicating the current percentual progress for a running task + /// + public int? ProgressPercent { get; set; } + + /// + /// Gets or sets the current progress message for a running task + /// + public string ProgressMessage { get; set; } + + /// + /// Concurrency Token + /// + [Timestamp] + public byte[] RowVersion { get; set; } + /// - /// Gets the value indicating whether a task is running + /// Gets a value indicating whether a task is running /// public bool IsRunning { get { - var result = (LastStartUtc.HasValue && LastStartUtc.Value > LastEndUtc.GetValueOrDefault()); + var result = LastStartUtc.HasValue && LastStartUtc.Value > LastEndUtc.GetValueOrDefault(); + return result; + } + } + /// + /// Gets a value indicating whether a task is scheduled for execution (Enabled = true and NextRunUtc <= UtcNow ) + /// + public bool IsPending + { + get + { + var result = Enabled && NextRunUtc.HasValue && NextRunUtc <= DateTime.UtcNow; return result; } } - } + + public ScheduleTask Clone() + { + return (ScheduleTask)this.MemberwiseClone(); + } + + object ICloneable.Clone() + { + return this.MemberwiseClone(); + } + } } diff --git a/src/Libraries/SmartStore.Core/Domain/Tax/TaxSettings.cs b/src/Libraries/SmartStore.Core/Domain/Tax/TaxSettings.cs index e857b65054..5a69937cac 100644 --- a/src/Libraries/SmartStore.Core/Domain/Tax/TaxSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Tax/TaxSettings.cs @@ -68,19 +68,16 @@ public TaxSettings() /// public bool HideTaxInOrderSummary { get; set; } - /// codehint: sm-add /// /// Gets or sets a value indicating whether to show legal info in product list /// public bool ShowLegalHintsInProductList { get; set; } - /// codehint: sm-add /// /// Gets or sets a value indicating whether to show legal info in product detail /// public bool ShowLegalHintsInProductDetails { get; set; } - /// codehint: sm-add /// /// Gets or sets a value indicating whether to show legal info in footer /// @@ -140,5 +137,10 @@ public TaxSettings() /// Gets or sets a value indicating whether we should notify a store owner when a new VAT number is submitted /// public bool EuVatEmailAdminWhenNewVatSubmitted { get; set; } + + /// + /// Gets or sets a value indicating whether a VAT-ID is required + /// + public bool VatRequired { get; set; } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Domain/Themes/ThemeSettings.cs b/src/Libraries/SmartStore.Core/Domain/Themes/ThemeSettings.cs index 83fd09bf3b..43517c8410 100644 --- a/src/Libraries/SmartStore.Core/Domain/Themes/ThemeSettings.cs +++ b/src/Libraries/SmartStore.Core/Domain/Themes/ThemeSettings.cs @@ -38,6 +38,15 @@ public ThemeSettings() /// public bool AllowCustomerToSelectTheme { get; set; } + /// + /// Gets or sets a value indicating whether user's theme choice should be saved in a cookie + /// + /// + /// If false, user's theme choice is associated to the account, + /// which may be undesirable when, for example, multiple users share a guest account. + /// + public bool SaveThemeChoiceInCookie { get; set; } + /// /// Gets or sets a value indicating whether mobile devices supported /// diff --git a/src/Libraries/SmartStore.Core/Domain/Themes/ThemeVariable.cs b/src/Libraries/SmartStore.Core/Domain/Themes/ThemeVariable.cs index d4efbf4656..12dad624d9 100644 --- a/src/Libraries/SmartStore.Core/Domain/Themes/ThemeVariable.cs +++ b/src/Libraries/SmartStore.Core/Domain/Themes/ThemeVariable.cs @@ -31,7 +31,7 @@ public class ThemeVariable : BaseEntity /// public int StoreId { get; set; } - public override bool Equals(BaseEntity other) + protected override bool Equals(BaseEntity other) { var equals = base.Equals(other); if (!equals) diff --git a/src/Libraries/SmartStore.Core/Domain/Topics/Topic.cs b/src/Libraries/SmartStore.Core/Domain/Topics/Topic.cs index d8fe4c8408..8181a60047 100644 --- a/src/Libraries/SmartStore.Core/Domain/Topics/Topic.cs +++ b/src/Libraries/SmartStore.Core/Domain/Topics/Topic.cs @@ -71,6 +71,11 @@ public partial class Topic : BaseEntity, ILocalizedEntity, IStoreMappingSupporte /// public string WidgetZone { get; set; } + /// + /// Gets or sets a value indicating whether the content should be surrounded by a topic block wrapper + /// + public bool? WidgetWrapContent { get; set; } + /// /// Gets or sets a value indicating whether the title should be displayed in the widget block /// @@ -86,6 +91,11 @@ public partial class Topic : BaseEntity, ILocalizedEntity, IStoreMappingSupporte /// public int Priority { get; set; } + /// + /// Gets or sets the title tag + /// + public string TitleTag { get; set; } + /// /// Helper function which gets the comma-separated WidgetZone property as list of strings /// diff --git a/src/Libraries/SmartStore.Core/Email/Attachment.cs b/src/Libraries/SmartStore.Core/Email/Attachment.cs deleted file mode 100644 index 437848f0ac..0000000000 --- a/src/Libraries/SmartStore.Core/Email/Attachment.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Text; -using System.IO; -using System.Net.Mime; -using net = System.Net.Mail; - -namespace SmartStore.Core.Email -{ - /// - /// attachment-multipart - /// - public class Attachment - { - //private readonly net.Attachment _attachment; - private net.Attachment _attachment; - - public Attachment() - { - MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes("")); - this.Stream = stream; - - _attachment = new net.Attachment(this.Stream, ""); - } - - public Attachment(string filePath) - { - _attachment = new net.Attachment(filePath); - this.GetContentFromFile(filePath); - } - - public Attachment(string filePath, string mediaType) - { - _attachment = new net.Attachment(filePath, mediaType); - } - - public ContentType ContentType - { - get - { - return _attachment.ContentType; - } - set - { - _attachment.ContentType = value; - } - } - public string Name - { - get - { - return _attachment.Name; - } - set - { - _attachment.Name = value; - } - } - public string MediaType - { - get - { - return _attachment.ContentType.MediaType; - } - set - { - _attachment.ContentType.MediaType = value; - } - } - public ContentDisposition ContentDisposition - { - get - { - return _attachment.ContentDisposition; - } - } - public TransferEncoding ContentTransferEncoding - { - get - { - return _attachment.TransferEncoding; - } - set - { - _attachment.TransferEncoding = value; - } - } - public string ContentDescription { get; set; } - public Stream Stream { get; set; } - //public string FileName { get; set; } - - public void GetContentFromFile(string location) - { - byte[] buffer; - FileStream fileStream = new FileStream(location, FileMode.Open, FileAccess.Read); - - int length = (int)fileStream.Length; - buffer = new byte[length]; - int count; - int sum = 0; - - while ((count = fileStream.Read(buffer, sum, length - sum)) > 0) - sum += count; - - this.Stream = new MemoryStream(buffer); - - string extension = Path.GetExtension(location); - string filename = Path.GetFileName(location); - - switch(extension) - { - case ".txt": - this.MediaType = "text/plain"; - break; - case ".jpg": - this.MediaType = "image/jpeg"; - break; - default: - this.MediaType = "application/octet-stream"; - break; - } - - this.Name = filename; - this.ContentTransferEncoding = TransferEncoding.Base64; - this.ContentDisposition.FileName = filename; - this.ContentDisposition.DispositionType = "attachment"; - } - - public void GetContentFromString(string content) - { - this.Stream = new MemoryStream(Encoding.UTF8.GetBytes(content)); - //this.Stream = new MemoryStream(Convert.FromBase64String(content)); - } - - public void GetContentFromBase64String(string content) - { - this.Stream = new MemoryStream(Convert.FromBase64String(content)); - } - - //NEW METHODS TO WRAP ATTACHMENT - //TODO: Testen - public net.Attachment Instance - { - get - { - return _attachment; - } - set - { - _attachment = value; - } - } - - public Attachment CreateAttachmentFromString(string content, ContentType contentType) - { - this.Instance = net.Attachment.CreateAttachmentFromString(content, contentType); - return InitAttachment(_attachment); - } - - public Attachment CreateAttachmentFromString(string content, string name) - { - this.Instance = net.Attachment.CreateAttachmentFromString(content, name); - return InitAttachment(_attachment); - } - - public Attachment CreateAttachmentFromString(string content, string name, Encoding contentEncoding, string mediaType) - { - this.Instance = net.Attachment.CreateAttachmentFromString(content, name, contentEncoding, mediaType); - return InitAttachment(_attachment); - } - - public Attachment InitAttachment(net.Attachment tempAttachment) - { - this.Stream = tempAttachment.ContentStream; - this.Name = tempAttachment.Name; - this.ContentTransferEncoding = tempAttachment.TransferEncoding; - this.ContentType = tempAttachment.ContentType; - this.MediaType = tempAttachment.ContentType.MediaType; - - return this; - } - - } -} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs b/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs index 9e5ebd2543..b9862e0c52 100644 --- a/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs +++ b/src/Libraries/SmartStore.Core/Email/DefaultEmailSender.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using net = System.Net.Mail; +using System.Net.Mail; using System.Net.Mime; using System.Net; using System.IO; @@ -14,18 +14,14 @@ namespace SmartStore.Core.Email public class DefaultEmailSender : IEmailSender { - public DefaultEmailSender() - { - } - /// /// Builds System.Net.Mail.Message /// /// SmartStore.Email.Message /// System.Net.Mail.Message - protected virtual net.MailMessage BuildMailMessage(EmailMessage original) + protected virtual MailMessage BuildMailMessage(EmailMessage original) { - net.MailMessage msg = new net.MailMessage(); + MailMessage msg = new MailMessage(); if (String.IsNullOrEmpty(original.Subject)) { @@ -37,15 +33,15 @@ protected virtual net.MailMessage BuildMailMessage(EmailMessage original) if (original.AltText.HasValue()) { - msg.AlternateViews.Add(net.AlternateView.CreateAlternateViewFromString(original.AltText, new ContentType("text/html"))); - msg.AlternateViews.Add(net.AlternateView.CreateAlternateViewFromString(original.Body, new ContentType("text/plain"))); + msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(original.AltText, new ContentType("text/html"))); + msg.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(original.Body, new ContentType("text/plain"))); } else { msg.Body = original.Body; } - msg.DeliveryNotificationOptions = net.DeliveryNotificationOptions.None; + msg.DeliveryNotificationOptions = DeliveryNotificationOptions.None; msg.From = original.From.ToMailAddress(); @@ -54,31 +50,7 @@ protected virtual net.MailMessage BuildMailMessage(EmailMessage original) msg.Bcc.AddRange(original.Bcc.Where(x => x.Address.HasValue()).Select(x => x.ToMailAddress())); msg.ReplyToList.AddRange(original.ReplyTo.Where(x => x.Address.HasValue()).Select(x => x.ToMailAddress())); - foreach (Attachment attachment in original.Attachments) - { - byte[] byteData; - - if (attachment.ContentTransferEncoding == TransferEncoding.Base64) - { - using (var sr = new StreamReader(attachment.Stream)) - { - byteData = Convert.FromBase64String(sr.ReadToEnd()); - } - } - else - { - byteData = attachment.Stream.ToByteArray(); - } - - MemoryStream s = new MemoryStream(byteData); - net.Attachment att = new net.Attachment(s, attachment.Name, attachment.ContentType.MediaType); - - att.ContentType.MediaType = attachment.MediaType; - att.TransferEncoding = attachment.ContentTransferEncoding; - att.ContentDisposition.DispositionType = attachment.ContentDisposition.DispositionType; - - msg.Attachments.Add(att); - } + msg.Attachments.AddRange(original.Attachments); if (original.Headers != null) msg.Headers.AddRange(original.Headers); @@ -96,11 +68,12 @@ public void SendEmail(SmtpContext context, EmailMessage message) Guard.ArgumentNotNull(() => context); Guard.ArgumentNotNull(() => message); - var msg = this.BuildMailMessage(message); - - using (var client = context.ToSmtpClient()) + using (var msg = this.BuildMailMessage(message)) { - client.Send(msg); + using (var client = context.ToSmtpClient()) + { + client.Send(msg); + } } } @@ -109,12 +82,14 @@ public Task SendEmailAsync(SmtpContext context, EmailMessage message) Guard.ArgumentNotNull(() => context); Guard.ArgumentNotNull(() => message); + var client = context.ToSmtpClient(); var msg = this.BuildMailMessage(message); - using (var client = context.ToSmtpClient()) + return client.SendMailAsync(msg).ContinueWith(t => { - return client.SendMailAsync(msg); - } + client.Dispose(); + msg.Dispose(); + }); } #endregion diff --git a/src/Libraries/SmartStore.Core/Email/EmailMessage.cs b/src/Libraries/SmartStore.Core/Email/EmailMessage.cs index 58a8508c07..683071e498 100644 --- a/src/Libraries/SmartStore.Core/Email/EmailMessage.cs +++ b/src/Libraries/SmartStore.Core/Email/EmailMessage.cs @@ -2,15 +2,9 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Net.Mail; -using System.Net.Mime; -using System.Xml.Serialization; -using System.Linq; using System.IO; using System.Text; -using System.Xml; -using System.Web; using System.Net; -using System.Threading.Tasks; namespace SmartStore.Core.Email { @@ -78,18 +72,13 @@ public EmailMessage(EmailAddress to, string subject, string body, EmailAddress f public NameValueCollection Headers { get; private set; } - public void AddAttachment(Attachment attachment) - { - this.Attachments.Add(attachment); - } - public async void BodyFromFile(string filePathOrUrl) { - StreamReader sr = null; + StreamReader sr; if (filePathOrUrl.ToLower().StartsWith("http")) { - WebClient wc = new WebClient(); + var wc = new WebClient(); sr = new StreamReader(await wc.OpenReadTaskAsync(filePathOrUrl)); } else diff --git a/src/Libraries/SmartStore.Core/Email/SmtpContext.cs b/src/Libraries/SmartStore.Core/Email/SmtpContext.cs index 796e642109..054487610f 100644 --- a/src/Libraries/SmartStore.Core/Email/SmtpContext.cs +++ b/src/Libraries/SmartStore.Core/Email/SmtpContext.cs @@ -73,6 +73,8 @@ public SmtpClient ToSmtpClient() smtpClient.UseDefaultCredentials = this.UseDefaultCredentials; smtpClient.EnableSsl = this.EnableSsl; + smtpClient.Timeout = 10000; + if (this.UseDefaultCredentials) { smtpClient.Credentials = CredentialCache.DefaultNetworkCredentials; diff --git a/src/Libraries/SmartStore.Core/Events/CommonMessages/AppInitScheduledTasksEvent.cs b/src/Libraries/SmartStore.Core/Events/CommonMessages/AppInitScheduledTasksEvent.cs index 9f10cd94dc..348b5fac89 100644 --- a/src/Libraries/SmartStore.Core/Events/CommonMessages/AppInitScheduledTasksEvent.cs +++ b/src/Libraries/SmartStore.Core/Events/CommonMessages/AppInitScheduledTasksEvent.cs @@ -9,9 +9,8 @@ namespace SmartStore.Core.Events /// /// to initialize scheduled tasks in Application_Start /// - /// codehint: sm-add public class AppInitScheduledTasksEvent { - public List ScheduledTasks { get; set; } + public IList ScheduledTasks { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Events/CommonMessages/AppRegisterGlobalFiltersEvent.cs b/src/Libraries/SmartStore.Core/Events/CommonMessages/AppRegisterGlobalFiltersEvent.cs index f7c0c63e4e..d825cc079d 100644 --- a/src/Libraries/SmartStore.Core/Events/CommonMessages/AppRegisterGlobalFiltersEvent.cs +++ b/src/Libraries/SmartStore.Core/Events/CommonMessages/AppRegisterGlobalFiltersEvent.cs @@ -7,7 +7,6 @@ namespace SmartStore.Core.Events /// /// to register global filters in Application_Start /// - /// codehint: sm-add public class AppRegisterGlobalFiltersEvent { public GlobalFilterCollection Filters { get; set; } diff --git a/src/Libraries/SmartStore.Core/Events/EventConsumerMetadata.cs b/src/Libraries/SmartStore.Core/Events/EventConsumerMetadata.cs index dcc676e784..1ae4f063fb 100644 --- a/src/Libraries/SmartStore.Core/Events/EventConsumerMetadata.cs +++ b/src/Libraries/SmartStore.Core/Events/EventConsumerMetadata.cs @@ -1,4 +1,5 @@ using System; +using SmartStore.Core.Plugins; namespace SmartStore.Core.Events { @@ -6,5 +7,6 @@ public class EventConsumerMetadata { public bool ExecuteAsync { get; set; } public bool IsActive { get; set; } + public PluginDescriptor PluginDescriptor { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs index 0c044d1996..b6fec3780a 100644 --- a/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/CollectionExtensions.cs @@ -7,10 +7,8 @@ namespace SmartStore { - public static class CollectionExtensions { - public static void AddRange(this ICollection initial, IEnumerable other) { if (other == null) @@ -27,35 +25,9 @@ public static void AddRange(this ICollection initial, IEnumerable other other.Each(x => initial.Add(x)); } - //public static bool IsNullOrEmpty(this ICollection source) - //{ - // return (source == null || source.Count == 0); - //} - public static bool IsNullOrEmpty(this ICollection source) { return (source == null || source.Count == 0); } - - public static bool EqualsAll(this IList a, IList b) - { - if (a == null || b == null) - return (a == null && b == null); - - if (a.Count != b.Count) - return false; - - EqualityComparer comparer = EqualityComparer.Default; - - for (int i = 0; i < a.Count; i++) - { - if (!comparer.Equals(a[i], b[i])) - return false; - } - - return true; - } - } - } diff --git a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs index 2ee0fe32fc..a97d4862bf 100644 --- a/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/ConversionExtensions.cs @@ -1,209 +1,83 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Drawing; -using System.ComponentModel; -using System.Drawing.Imaging; +using System.Diagnostics; using System.Globalization; -using System.Collections; -using System.Reflection; +using System.IO; using System.Runtime.Serialization.Formatters.Binary; -using SmartStore.Utilities; -using System.Diagnostics; using System.Security.Cryptography; -using SmartStore.Core.ComponentModel; -using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Domain.Catalog; +using System.Text; +using System.Text.RegularExpressions; +using SmartStore.ComponentModel; +using SmartStore.Utilities; namespace SmartStore { - - public static class ConversionExtensions + public static class ConversionExtensions { - private readonly static IDictionary s_customTypeConverters; - - static ConversionExtensions() - { - var intConverter = new GenericListTypeConverter(); - var decConverter = new GenericListTypeConverter(); - var stringConverter = new GenericListTypeConverter(); - var soListConverter = new ShippingOptionListTypeConverter(); - var bundleDataListConverter = new ProductBundleDataListTypeConverter(); - - s_customTypeConverters = new Dictionary(); - s_customTypeConverters.Add(typeof(List), intConverter); - s_customTypeConverters.Add(typeof(IList), intConverter); - s_customTypeConverters.Add(typeof(List), decConverter); - s_customTypeConverters.Add(typeof(IList), decConverter); - s_customTypeConverters.Add(typeof(List), stringConverter); - s_customTypeConverters.Add(typeof(IList), stringConverter); - s_customTypeConverters.Add(typeof(ShippingOption), new ShippingOptionTypeConverter()); - s_customTypeConverters.Add(typeof(List), soListConverter); - s_customTypeConverters.Add(typeof(IList), soListConverter); - s_customTypeConverters.Add(typeof(List), bundleDataListConverter); - s_customTypeConverters.Add(typeof(IList), bundleDataListConverter); - } - #region Object public static T Convert(this object value) { - return (T)Convert(value, typeof(T)); - } - - public static T Convert(this object value, CultureInfo culture) - { - return (T)Convert(value, typeof(T), culture); - } + return (T)(Convert(value, typeof(T)) ?? default(T)); + } - public static object Convert(this object value, Type to) - { - return value.Convert(to, CultureInfo.InvariantCulture); - } + public static T Convert(this object value, T defaultValue) + { + return (T)(Convert(value, typeof(T)) ?? defaultValue); + } - public static object Convert(this object value, Type to, CultureInfo culture) + public static T Convert(this object value, CultureInfo culture) { - Guard.ArgumentNotNull(to, "to"); - - if (value == null || to.IsInstanceOfType(value)) - { - return value; - } - - // array conversion results in four cases, as below - Array valueAsArray = value as Array; - if (to.IsArray) - { - Type destinationElementType = to.GetElementType(); - if (valueAsArray != null) - { - // case 1: both destination + source type are arrays, so convert each element - IList valueAsList = (IList)valueAsArray; - IList converted = Array.CreateInstance(destinationElementType, valueAsList.Count); - for (int i = 0; i < valueAsList.Count; i++) - { - converted[i] = valueAsList[i].Convert(destinationElementType, culture); - } - return converted; - } - else - { - // case 2: destination type is array but source is single element, so wrap element in array + convert - object element = value.Convert(destinationElementType, culture); - IList converted = Array.CreateInstance(destinationElementType, 1); - converted[0] = element; - return converted; - } - } - else if (valueAsArray != null) - { - // case 3: destination type is single element but source is array, so extract first element + convert - IList valueAsList = (IList)valueAsArray; - if (valueAsList.Count > 0) - { - value = valueAsList[0]; - } - // .. fallthrough to case 4 - } - // case 4: both destination + source type are single elements, so convert - - Type fromType = value.GetType(); - - //if (to.IsInterface || to.IsGenericTypeDefinition || to.IsAbstract) - // throw Error.Argument("to", "Target type '{0}' is not a value type or a non-abstract class.", to.FullName); - - // use Convert.ChangeType if both types are IConvertible - if (value is IConvertible && typeof(IConvertible).IsAssignableFrom(to)) - { - if (to.IsEnum) - { - if (value is string) - return Enum.Parse(to, value.ToString(), true); - else if (fromType.IsInteger()) - return Enum.ToObject(to, value); - } + return (T)(Convert(value, typeof(T), culture) ?? default(T)); + } - return System.Convert.ChangeType(value, to, culture); - } + public static T Convert(this object value, T defaultValue, CultureInfo culture) + { + return (T)(Convert(value, typeof(T), culture) ?? defaultValue); + } - if (value is DateTime && to == typeof(DateTimeOffset)) - return new DateTimeOffset((DateTime)value); + public static object Convert(this object value, Type to) + { + return value.Convert(to, CultureInfo.InvariantCulture); + } - if (value is string && to == typeof(Guid)) - return new Guid((string)value); + public static object Convert(this object value, Type to, CultureInfo culture) + { + Guard.ArgumentNotNull(to, "to"); - // see if source or target types have a TypeConverter that converts between the two - TypeConverter toConverter = GetTypeConverter(fromType); + if (value == null || value == DBNull.Value || to.IsInstanceOfType(value)) + { + return value == DBNull.Value ? null : value; + } - Type nonNullableTo = to.GetNonNullableType(); - bool isNullableTo = to != nonNullableTo; + Type from = value.GetType(); - if (toConverter != null && toConverter.CanConvertTo(nonNullableTo)) - { - object result = toConverter.ConvertTo(null, culture, value, nonNullableTo); - return isNullableTo ? Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(nonNullableTo), result) : result; + if (culture == null) + { + culture = CultureInfo.InvariantCulture; } - TypeConverter fromConverter = GetTypeConverter(nonNullableTo); - - if (fromConverter != null && fromConverter.CanConvertFrom(fromType)) - { - object result = fromConverter.ConvertFrom(null, culture, value); - return isNullableTo ? Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(nonNullableTo), result) : result; - } - - // TypeConverter doesn't like Double to Decimal - if (fromType == typeof(double) && nonNullableTo == typeof(decimal)) + // get a converter for 'to' (value -> to) + var converter = TypeConverterFactory.GetConverter(to); + if (converter != null && converter.CanConvertFrom(from)) { - decimal result = new Decimal((double)value); - return isNullableTo ? Activator.CreateInstance(typeof(Nullable<>).MakeGenericType(nonNullableTo), result) : result; + return converter.ConvertFrom(culture, value); } - throw Error.InvalidCast(fromType, to); - - #region OBSOLETE - // TypeConverter converter = TypeDescriptor.GetConverter(to); - // bool canConvertFrom = converter.CanConvertFrom(value.GetType()); - // if (!canConvertFrom) - // { - // converter = TypeDescriptor.GetConverter(value.GetType()); - // } - // if (!(canConvertFrom || converter.CanConvertTo(to))) - // { - // throw Error.InvalidOperation(@"The parameter conversion from type '{0}' to type '{1}' failed - // because no TypeConverter can convert between these types.", - // value.GetType().FullName, - // to.FullName); - // } - - // try - // { - // CultureInfo cultureToUse = culture ?? CultureInfo.CurrentCulture; - // object convertedValue = (canConvertFrom) ? - // converter.ConvertFrom(null /* context */, cultureToUse, value) : - // converter.ConvertTo(null /* context */, cultureToUse, value, to); - // return convertedValue; - // } - // catch (Exception ex) - // { - // throw Error.InvalidOperation(@"The parameter conversion from type '{0}' to type '{1}' failed. - // See the inner exception for more information.", ex, - // value.GetType().FullName, - // to.FullName); - // } - #endregion - } + // try the other way round with a 'from' converter (to <- from) + converter = TypeConverterFactory.GetConverter(from); + if (converter != null && converter.CanConvertTo(to)) + { + return converter.ConvertTo(culture, null, value, to); + } - internal static TypeConverter GetTypeConverter(Type type) - { - TypeConverter converter; - if (s_customTypeConverters.TryGetValue(type, out converter)) + // use Convert.ChangeType if both types are IConvertible + if (value is IConvertible && typeof(IConvertible).IsAssignableFrom(to)) { - return converter; + return System.Convert.ChangeType(value, to, culture); } - return TypeDescriptor.GetConverter(type); + + throw Error.InvalidCast(from, to); } #endregion @@ -219,187 +93,64 @@ public static char ToHex(this int value) return (char)((value - 10) + 97); } - /// - /// Returns kilobytes - /// - /// - /// - public static int ToKb(this int value) - { - return value * 1024; - } - - /// - /// Returns megabytes - /// - /// - /// - public static int ToMb(this int value) - { - return value * 1024 * 1024; - } - - /// Returns a that represents a specified number of minutes. - /// number of minutes - /// A that represents a value. - /// 3.Minutes() - public static TimeSpan ToMinutes(this int minutes) - { - return TimeSpan.FromMinutes(minutes); - } - - /// - /// Returns a that represents a specified number of seconds. - /// - /// number of seconds - /// A that represents a value. - /// 2.Seconds() - public static TimeSpan ToSeconds(this int seconds) - { - return TimeSpan.FromSeconds(seconds); - } - - /// - /// Returns a that represents a specified number of milliseconds. - /// - /// milliseconds for this timespan - /// A that represents a value. - public static TimeSpan ToMilliseconds(this int milliseconds) - { - return TimeSpan.FromMilliseconds(milliseconds); - } - - /// - /// Returns a that represents a specified number of days. - /// - /// Number of days. - /// A that represents a value. - public static TimeSpan ToDays(this int days) - { - return TimeSpan.FromDays(days); - } - - - /// - /// Returns a that represents a specified number of hours. - /// - /// Number of hours. - /// A that represents a value. - public static TimeSpan ToHours(this int hours) - { - return TimeSpan.FromHours(hours); - } - - #endregion - - #region double - - /// Returns a that represents a specified number of minutes. - /// number of minutes - /// A that represents a value. - /// 3D.Minutes() - public static TimeSpan ToMinutes(this double minutes) - { - return TimeSpan.FromMinutes(minutes); - } - - - /// Returns a that represents a specified number of hours. - /// number of hours - /// A that represents a value. - /// 3D.Hours() - public static TimeSpan ToHours(this double hours) - { - return TimeSpan.FromHours(hours); - } - - /// Returns a that represents a specified number of seconds. - /// number of seconds - /// A that represents a value. - /// 2D.Seconds() - public static TimeSpan ToSeconds(this double seconds) - { - return TimeSpan.FromSeconds(seconds); - } - - /// Returns a that represents a specified number of milliseconds. - /// milliseconds for this timespan - /// A that represents a value. - public static TimeSpan ToMilliseconds(this double milliseconds) - { - return TimeSpan.FromMilliseconds(milliseconds); - } - - /// - /// Returns a that represents a specified number of days. - /// - /// Number of days, accurate to the milliseconds. - /// A that represents a value. - public static TimeSpan ToDays(this double days) - { - return TimeSpan.FromDays(days); - } - #endregion #region String public static T ToEnum(this string value, T defaultValue) where T : IComparable, IFormattable { - T convertedValue = defaultValue; + Guard.ArgumentIsEnumType(typeof(T), "T"); - if (!string.IsNullOrEmpty(value)) - { - try - { - convertedValue = (T)Enum.Parse(typeof(T), value.Trim(), true); - } - catch (ArgumentException) - { - } - } - - return convertedValue; - } - - public static string[] ToArray(this string value) - { - return value.ToArray(new char[] { ',' }); - } + T result; + if (CommonHelper.TryConvert(value, out result)) + { + return result; + } - public static string[] ToArray(this string value, params char[] separator) - { - return value.Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries); + return defaultValue; } public static int ToInt(this string value, int defaultValue = 0) { int result; - if (int.TryParse(value, out result)) - { - return result; - } - return defaultValue; + if (CommonHelper.TryConvert(value, out result)) + { + return result; + } + + return defaultValue; } - public static float ToFloat(this string value, float defaultValue = 0) + public static char ToChar(this string value, bool unescape = false, char defaultValue = '\0') + { + char result; + if (value.HasValue() && char.TryParse(unescape ? Regex.Unescape(value) : value, out result)) + { + return result; + } + return defaultValue; + } + + public static float ToFloat(this string value, float defaultValue = 0) { float result; - if (float.TryParse(value, out result)) - { - return result; - } - return defaultValue; + if (CommonHelper.TryConvert(value, out result)) + { + return result; + } + + return defaultValue; } public static bool ToBool(this string value, bool defaultValue = false) { bool result; - if (bool.TryParse(value, out result)) - { - return result; - } - return defaultValue; + if (CommonHelper.TryConvert(value, out result)) + { + return result; + } + + return defaultValue; } public static DateTime? ToDateTime(this string value, DateTime? defaultValue) @@ -432,24 +183,25 @@ public static bool ToBool(this string value, bool defaultValue = false) return defaultValue; } - public static Guid ToGuid(this string value) - { - if ((!String.IsNullOrEmpty(value)) && (value.Trim().Length == 22)) - { - string encoded = string.Concat(value.Trim().Replace("-", "+").Replace("_", "/"), "=="); - - byte[] base64 = System.Convert.FromBase64String(encoded); - - return new Guid(base64); - } - - return Guid.Empty; - } + /// + /// Parse ISO-8601 UTC timestamp including milliseconds. + /// + /// + /// Dublicate can be found in HmacAuthentication class. + /// + public static DateTime? ToDateTimeIso8601(this string value) + { + if (value.HasValue()) + { + DateTime dt; + if (DateTime.TryParseExact(value, "o", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out dt)) + return dt; - public static byte[] ToByteArray(this string value) - { - return Encoding.Default.GetBytes(value); - } + if (DateTime.TryParseExact(value, "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out dt)) + return dt; + } + return null; + } [DebuggerStepThrough] public static Version ToVersion(this string value, Version defaultVersion = null) @@ -466,67 +218,49 @@ public static Version ToVersion(this string value, Version defaultVersion = null #endregion - #region DateTime - - // [...] - - #endregion - #region Stream public static byte[] ToByteArray(this Stream stream) { Guard.ArgumentNotNull(stream, "stream"); - byte[] buffer; - - if (stream is MemoryStream && stream.CanRead && stream.CanSeek) - { - int len = System.Convert.ToInt32(stream.Length); - buffer = new byte[len]; - stream.Read(buffer, 0, len); - return buffer; - } - - MemoryStream memStream = null; - try - { - buffer = new byte[1024]; - memStream = new MemoryStream(); - int bytesRead = stream.Read(buffer, 0, buffer.Length); - if (bytesRead > 0) - { - memStream.Write(buffer, 0, bytesRead); - bytesRead = stream.Read(buffer, 0, buffer.Length); - } - } - finally - { - if (memStream != null) - memStream.Close(); - } - - if (memStream != null) - { - return memStream.ToArray(); - } - - return null; + if (stream is MemoryStream) + { + return ((MemoryStream)stream).ToArray(); + } + else + { + using (var ms = new MemoryStream()) + { + stream.CopyTo(ms); + return ms.ToArray(); + } + } } - public static string AsString(this Stream stream) + public static string AsString(this Stream stream) + { + return stream.AsString(Encoding.UTF8); + } + + public static string AsString(this Stream stream, Encoding encoding) { - // convert memory stream to string + Guard.ArgumentNotNull(() => encoding); + + // convert stream to string string result; - stream.Position = 0; - using (StreamReader sr = new StreamReader(stream)) + if (stream.CanSeek) + { + stream.Position = 0; + } + + using (StreamReader sr = new StreamReader(stream, encoding)) { result = sr.ReadToEnd(); } return result; - } #endregion @@ -549,32 +283,18 @@ public static object ToObject(this byte[] bytes) } } - public static Image ToImage(this byte[] bytes) - { - using (var stream = new MemoryStream(bytes)) - { - return Image.FromStream(stream); - } - } - public static Stream ToStream(this byte[] bytes) { return new MemoryStream(bytes); } - public static string AsString(this byte[] bytes) - { - return Encoding.Default.GetString(bytes); - } - - - /// - /// Computes the MD5 hash of a byte array - /// - /// The byte array to compute the hash for - /// The hash value - //[DebuggerStepThrough] - public static string Hash(this byte[] value, bool toBase64 = false) + /// + /// Computes the MD5 hash of a byte array + /// + /// The byte array to compute the hash for + /// The hash value + [DebuggerStepThrough] + public static string Hash(this byte[] value, bool toBase64 = false) { Guard.ArgumentNotNull(value, "value"); @@ -603,45 +323,6 @@ public static string Hash(this byte[] value, bool toBase64 = false) #endregion - #region Image/Bitmap - - public static byte[] ToByteArray(this Image image) - { - Guard.ArgumentNotNull(() => image); - - byte[] bytes; - - ImageConverter converter = new ImageConverter(); - bytes = (byte[])converter.ConvertTo(image, typeof(byte[])); - return bytes; - } - - internal static byte[] ToByteArray(this Image image, ImageFormat format) - { - Guard.ArgumentNotNull(() => image); - Guard.ArgumentNotNull(() => format); - - using (var stream = new MemoryStream()) - { - image.Save(stream, format); - return stream.ToByteArray(); - } - } - - internal static Image ConvertTo(this Image image, ImageFormat format) - { - Guard.ArgumentNotNull(() => image); - Guard.ArgumentNotNull(() => format); - - using (var stream = new MemoryStream()) - { - image.Save(stream, format); - return Image.FromStream(stream); - } - } - - #endregion - #region Enumerable: Collections/List/Dictionary... public static T ToObject(this IDictionary values) where T : class diff --git a/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs index abb4fbc944..3070172cdc 100644 --- a/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/DateTimeExtensions.cs @@ -5,23 +5,9 @@ namespace SmartStore { - public static class DateTimeExtensions { - private static readonly DateTime MinDate = new DateTime(1900, 1, 1); - private static readonly DateTime MaxDate = new DateTime(9999, 12, 31, 23, 59, 59, 999); - public static long InitialJavaScriptDateTicks = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Ticks; - - public static bool IsValid(this DateTime value) - { - return (value >= MinDate) && (value <= MaxDate); - } - - public static string GetLocalOffset(this DateTime value) - { - TimeSpan utcOffset = TimeZoneInfo.Local.GetUtcOffset(value); - return utcOffset.Hours.ToString("+00;-00", CultureInfo.InvariantCulture) + ":" + utcOffset.Minutes.ToString("00;00", CultureInfo.InvariantCulture); - } + public static readonly DateTime BeginOfEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); /// /// Converts a nullable date/time value to UTC. @@ -33,38 +19,6 @@ public static string GetLocalOffset(this DateTime value) return dateTime.HasValue ? dateTime.Value.ToUniversalTime() : (DateTime?)null; } - /// - /// Returns a copy of a date/time value with its kind - /// set to but does not perform - /// any time-zone adjustment. - /// - /// - /// This method is useful when obtaining date/time values from sources - /// that might not correctly set the UTC flag. - /// - /// The date/time - /// The same date/time with the UTC flag set - public static DateTime AssumeUniversalTime(this DateTime dateTime) - { - return new DateTime(dateTime.Ticks, DateTimeKind.Utc); - } - - /// - /// Returns a copy of a nullable date/time value with its kind - /// set to but does not perform - /// any time-zone adjustment. - /// - /// - /// This method is useful when obtaining date/time values from sources - /// that might not correctly set the UTC flag. - /// - /// The nullable date/time - /// The same nullable date/time with the UTC flag set - public static DateTime? AssumeUniversalTime(this DateTime? dateTime) - { - return dateTime.HasValue ? AssumeUniversalTime(dateTime.Value) : (DateTime?)null; - } - /// /// Converts a nullable UTC date/time value to local time. /// @@ -143,289 +97,13 @@ public static DateTime GetEvenMinuteDateBefore(this DateTime? dateTime) return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, 0); } - /// - /// Returns a date that is rounded to the next even second above the given - /// date. - /// - /// the Date to round, if the current time will - /// be used - /// the new rounded date - public static DateTime GetEvenSecondDate(this DateTime? dateTime) - { - if (!dateTime.HasValue) - { - dateTime = DateTime.UtcNow; - } - DateTime d = dateTime.Value; - d = d.AddSeconds(1); - return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second); - } - - /// - /// Returns a date that is rounded to the previous even second below the - /// given date. - ///

- /// For example an input date with a time of 08:13:54.341 would result in a - /// date with the time of 08:13:00.000. - ///

- ///
- /// the Date to round, if the current time will - /// be used - /// the new rounded date - public static DateTime GetEvenSecondDateBefore(this DateTime? dateTime) - { - if (!dateTime.HasValue) - { - dateTime = DateTime.UtcNow; - } - DateTime d = dateTime.Value; - return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second); - } - - /// - /// Returns a date that is rounded to the next even multiple of the given - /// minute. - ///

- /// For example an input date with a time of 08:13:54, and an input - /// minute-base of 5 would result in a date with the time of 08:15:00. The - /// same input date with an input minute-base of 10 would result in a date - /// with the time of 08:20:00. But a date with the time 08:53:31 and an - /// input minute-base of 45 would result in 09:00:00, because the even-hour - /// is the next 'base' for 45-minute intervals. - ///

- /// - ///

- /// More examples: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
Input TimeMinute-BaseResult Time
11:16:412011:20:00
11:36:412011:40:00
11:46:412012:00:00
11:26:413011:30:00
11:36:413012:00:00
11:16:411711:17:00
11:17:411711:34:00
11:52:411712:00:00
11:52:41511:55:00
11:57:41512:00:00
11:17:41012:00:00
11:17:41111:08:00
- ///

- /// - ///
- /// the Date to round, if the current time willbe used - /// the base-minute to set the time on - /// The new rounded date - public static DateTime GetNextGivenMinuteDate(this DateTime? dateTime, int minuteBase) - { - if (minuteBase < 0 || minuteBase > 59) - { - throw new ArgumentException("minuteBase must be >=0 and <= 59"); - } - - if (!dateTime.HasValue) - { - dateTime = DateTime.UtcNow; - } - DateTime d = dateTime.Value; - - if (minuteBase == 0) - { - d = d.AddHours(1); - return new DateTime(d.Year, d.Month, d.Day, d.Hour, 0, 0); - } - - int minute = d.Minute; - int arItr = minute / minuteBase; - int nextMinuteOccurance = minuteBase * (arItr + 1); - - if (nextMinuteOccurance < 60) - { - return new DateTime(d.Year, d.Month, d.Day, d.Hour, nextMinuteOccurance, 0); - } - else - { - d = d.AddHours(1); - return new DateTime(d.Year, d.Month, d.Day, d.Hour, 0, 0); - } - } - - /// - /// Returns a date that is rounded to the next even multiple of the given - /// minute. - ///

- /// The rules for calculating the second are the same as those for - /// calculating the minute in the method - /// . - ///

- ///
- /// The date. - /// The second base. - /// - public static DateTime GetNextGivenSecondDate(this DateTime? dateTime, int secondBase) - { - if (secondBase < 0 || secondBase > 59) - { - throw new ArgumentException("secondBase must be >=0 and <= 59"); - } - - if (!dateTime.HasValue) - { - dateTime = DateTime.UtcNow; - } - - DateTime d = dateTime.Value; - - if (secondBase == 0) - { - d = d.AddMinutes(1); - return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, 0); - } - - int second = d.Second; - int arItr = second / secondBase; - int nextSecondOccurance = secondBase * (arItr + 1); - - if (nextSecondOccurance < 60) - { - return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, nextSecondOccurance); - } - else - { - d = d.AddMinutes(1); - return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, 0); - } - } - - - /// - /// Translate a date and time from a users timezone to the another - /// (probably server) timezone to assist in creating a simple trigger with - /// the right date and time. - /// - /// the date to translate - /// the original time-zone - /// the destination time-zone - /// the translated UTC date - public static DateTime TranslateTime(this DateTime date, TimeZone src, TimeZone dest) - { - DateTime newDate = DateTime.UtcNow; - double offset = (GetOffset(date, dest) - GetOffset(date, src)); - - newDate = newDate.AddMilliseconds(-1 * offset); - - return newDate; - } - - /// - /// Gets the offset from UT for the given date in the given timezone, - /// taking into account daylight savings. - /// - /// the date that is the base for the offset - /// the time-zone to calculate to offset to - /// the offset - public static double GetOffset(this DateTime date, TimeZone tz) - { - if (tz.IsDaylightSavingTime(date)) - { - // TODO - return tz.BaseUtcOffset.TotalMilliseconds + 0; - } - - return tz.BaseUtcOffset.TotalMilliseconds; - } - - /// - /// This functions determines if the TimeZone uses daylight saving time - /// - /// TimeZone instance to validate - /// True or false depending if daylight savings time is used - public static bool UseDaylightTime(this TimeZone timezone) - { - return timezone.SupportsDaylightSavingTime; - } - public static long ToJavaScriptTicks(this DateTime dateTime) { DateTimeOffset utcDateTime = dateTime.ToUniversalTime(); - long javaScriptTicks = (utcDateTime.Ticks - InitialJavaScriptDateTicks) / (long)10000; + long javaScriptTicks = (utcDateTime.Ticks - BeginOfEpoch.Ticks) / (long)10000; return javaScriptTicks; } - //public static long ToJavaScriptTicks(this DateTimeOffset offset) - //{ - // DateTimeOffset utcDateTime = offset.ToUniversalTime(); - // long javaScriptTicks = (utcDateTime.Ticks - InitialJavaScriptDateTicks) / (long)10000; - // return javaScriptTicks; - //} - - public static XmlDateTimeSerializationMode ToSerializationMode(DateTimeKind kind) - { - switch (kind) - { - case DateTimeKind.Local: - return XmlDateTimeSerializationMode.Local; - case DateTimeKind.Unspecified: - return XmlDateTimeSerializationMode.Unspecified; - case DateTimeKind.Utc: - return XmlDateTimeSerializationMode.Utc; - default: - throw new ArgumentOutOfRangeException("kind", kind, "Unexpected DateTimeKind value."); - } - } - /// /// Get the first day of the month for /// any full date submitted @@ -464,6 +142,18 @@ public static DateTime ToEndOfTheDay(this DateTime dt) { return (dt.HasValue ? dt.Value.ToEndOfTheDay() : dt); } + + /// Epoch time. Number of seconds since midnight (UTC) on 1st January 1970. + public static long ToUnixTime(this DateTime date) + { + return Convert.ToInt64((date.ToUniversalTime() - BeginOfEpoch).TotalSeconds); + } + + /// UTC date based on number of seconds since midnight (UTC) on 1st January 1970. + public static DateTime FromUnixTime(this long unixTime) + { + return BeginOfEpoch.AddSeconds(unixTime); + } } } diff --git a/src/Libraries/SmartStore.Core/Extensions/DecimalExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/DecimalExtensions.cs new file mode 100644 index 0000000000..aa6dd811e3 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Extensions/DecimalExtensions.cs @@ -0,0 +1,46 @@ +using System; +using System.Globalization; + +namespace SmartStore +{ + public static class DecimalExtensions + { + /// + /// Rounds and formats a decimal culture invariant + /// + /// The decimal + /// Rounding decimal number + /// Formated value + public static string FormatInvariant(this decimal value, int decimals = 2) + { + return Math.Round(value, decimals).ToString("0.00", CultureInfo.InvariantCulture); + } + + /// + /// Calculates the tax (percentage) from a gross and a net value. + /// + /// Gross value + /// Net value + /// Rounding decimal number + /// Tax percentage + public static decimal ToTaxPercentage(this decimal inclTax, decimal exclTax, int? decimals = null) + { + if (exclTax == decimal.Zero) + return decimal.Zero; + + var result = ((inclTax / exclTax) - 1.0M) * 100.0M; + + return (decimals.HasValue ? Math.Round(result, decimals.Value) : result); + } + + /// + /// Converts to smallest currency uint, e.g. cents + /// + /// Smallest currency unit + public static int ToSmallestCurrencyUnit(this decimal value, MidpointRounding rounding = MidpointRounding.AwayFromZero) + { + var result = Math.Round(value * 100, 0, MidpointRounding.AwayFromZero); + return Convert.ToInt32(result); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs index 6b91605920..6e4c8976e8 100644 --- a/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/DictionaryExtensions.cs @@ -5,14 +5,13 @@ using System.Web.Routing; using System.Globalization; using System.Dynamic; +using SmartStore.Utilities; namespace SmartStore { - public static class DictionaryExtensions { - - public static void AddRange(this IDictionary values, IEnumerable> other) + public static void AddRange(this IDictionary values, IEnumerable> other) { foreach (var kvp in other) { @@ -34,16 +33,16 @@ public static void Merge(this IDictionary instance, string key, public static void Merge(this IDictionary instance, object values, bool replaceExisting = true) { - instance.Merge(new RouteValueDictionary(values), replaceExisting); + instance.Merge(CommonHelper.ObjectToDictionary(values), replaceExisting); } - public static void Merge(this IDictionary instance, IDictionary from, bool replaceExisting = true) + public static void Merge(this IDictionary instance, IDictionary from, bool replaceExisting = true) { - foreach (KeyValuePair keyValuePair in from) + foreach (var kvp in from) { - if (replaceExisting || !instance.ContainsKey(keyValuePair.Key)) + if (replaceExisting || !instance.ContainsKey(kvp.Key)) { - instance[keyValuePair.Key] = keyValuePair.Value; + instance[kvp.Key] = kvp.Value; } } } @@ -58,30 +57,22 @@ public static void PrependInValue(this IDictionary instance, str instance[key] = !instance.ContainsKey(key) ? value.ToString() : (value + separator + instance[key]); } - public static string ToAttributeString(this IDictionary instance) - { - StringBuilder builder = new StringBuilder(); - foreach (KeyValuePair pair in instance) - { - object[] args = new object[] { HttpUtility.HtmlAttributeEncode(pair.Key), HttpUtility.HtmlAttributeEncode(pair.Value.ToString()) }; - builder.Append(" {0}=\"{1}\"".FormatWith(args)); - } - return builder.ToString(); - } - - public static T GetValue(this IDictionary instance, K key) + public static TValue GetValue(this IDictionary instance, TKey key) { try { object val; if (instance != null && instance.TryGetValue(key, out val) && val != null) - return (T)Convert.ChangeType(val, typeof(T), CultureInfo.InvariantCulture); + { + return (TValue)Convert.ChangeType(val, typeof(TValue), CultureInfo.InvariantCulture); + } } - catch (Exception exc) + catch (Exception ex) { - exc.Dump(); + ex.Dump(); } - return default(T); + + return default(TValue); } public static ExpandoObject ToExpandoObject(this IDictionary source, bool castIfPossible = false) diff --git a/src/Libraries/SmartStore.Core/Extensions/EnumExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/EnumExtensions.cs deleted file mode 100644 index 6097509595..0000000000 --- a/src/Libraries/SmartStore.Core/Extensions/EnumExtensions.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; - -namespace SmartStore -{ - - public static class EnumExtensions - { - - /// - /// Gets the of an - /// type value. - /// - /// The type value. - /// A string containing the text of the - /// . - public static string GetFriendlyName(this Enum value) - { - Guard.ArgumentNotNull(value, "value"); - - string friendlyName = value.ToString(); - FieldInfo fieldInfo = value.GetType().GetField(friendlyName); - - var attributes = (EnumFriendlyNameAttribute[])fieldInfo.GetCustomAttributes(typeof(EnumFriendlyNameAttribute), false); - - if (attributes != null && attributes.Length == 1) - { - friendlyName = attributes[0].FriendlyName; - } - return friendlyName; - } - - /// - /// Gets the of an - /// type value. - /// - /// The type value. - /// A string containing the text of the - /// . - public static string GetDescription(this Enum value) - { - Guard.ArgumentNotNull(value, "value"); - - string description = value.ToString(); - FieldInfo fieldInfo = value.GetType().GetField(description); - - EnumDescriptionAttribute[] attributes = - (EnumDescriptionAttribute[]) - fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false); - - if (attributes != null && attributes.Length == 1) - { - description = attributes[0].Description; - } - return description; - } - - /// - /// Checks if the specified enum flag is set on a flagged enumeration type. - /// - /// - /// - /// - /// - public static bool IsSet(this T value, T flags) where T : struct - { - Type type = typeof(T); - - // only works with enums - if (!type.IsEnum) - throw Error.Argument("T", "The type parameter T must be an enum type."); - - // handle each underlying type - Type numberType = Enum.GetUnderlyingType(type); - - if (numberType.Equals(typeof(int))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(sbyte))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(byte))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(short))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(ushort))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(uint))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(long))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(ulong))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else if (numberType.Equals(typeof(char))) - { - return BoxUnbox(value, flags, (a, b) => (a & b) == b); - } - else - { - throw new ArgumentException("Unknown enum underlying type " + - numberType.Name + "."); - } - } - - /// - /// Helper function for handling the value types. Boxes the params to - /// object so that the cast can be called on them. - /// - private static bool BoxUnbox(object value, object flags, Func op) - { - return op((T)value, (T)flags); - } - - } - -} diff --git a/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs index 88dbb9a27d..948cfddc6a 100644 --- a/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/EnumerableExtensions.cs @@ -1,21 +1,44 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Collections; -using System.Linq; -using System.Linq.Expressions; using System.Collections.Specialized; +using System.Linq; +using System.Text; +using System.Web; using SmartStore.Collections; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace SmartStore { - - public static class EnumerableExtensions - { - - #region IEnumerable - - private class Status + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + public static class EnumerableExtensions + { + #region Nested classes + + private static class DefaultReadOnlyCollection + { + private static ReadOnlyCollection defaultCollection; + + [SuppressMessage("ReSharper", "ConvertIfStatementToNullCoalescingExpression")] + internal static ReadOnlyCollection Empty + { + get + { + if (defaultCollection == null) + { + defaultCollection = new ReadOnlyCollection(new T[0]); + } + return defaultCollection; + } + } + } + + #endregion + + #region IEnumerable + + private class Status { public bool EndOfSequence; } @@ -53,15 +76,15 @@ public static IEnumerable> Chunk(this IEnumerable items, in } - /// - /// Performs an action on each item while iterating through a list. - /// This is a handy shortcut for foreach(item in list) { ... } - /// - /// The type of the items. - /// The list, which holds the objects. - /// The action delegate which is called on each item while iterating. - //[DebuggerStepThrough] - public static void Each(this IEnumerable source, Action action) + /// + /// Performs an action on each item while iterating through a list. + /// This is a handy shortcut for foreach(item in list) { ... } + /// + /// The type of the items. + /// The list, which holds the objects. + /// The action delegate which is called on each item while iterating. + [DebuggerStepThrough] + public static void Each(this IEnumerable source, Action action) { foreach (T t in source) { @@ -69,107 +92,113 @@ public static void Each(this IEnumerable source, Action action) } } - ///// - ///// Performs an action on each item while iterating through a list. - ///// This is a handy shortcut for foreach(item in list) { ... } - ///// - ///// The type of the items. - ///// The enumerator instance that this extension operates on. - ///// The action delegate which is called on each item while iterating. - //public static void Each(this IEnumerator source, Action action) - //{ - // while (source.MoveNext()) - // action(source.Current); - //} - - /// - /// Casts the objects within a list into another type. - /// - /// The type of the source objects. - /// The target type of the objects. - /// The list, which holds the objects. - /// The delegate function which is responsible for converting each object. - public static IEnumerable Transform(this IEnumerable source, Converter converter) - { - foreach (TSource s in source) - yield return converter(s); - } - - /// - /// Shorthand extension method for converting enumerables into the arrays - /// - /// The type of the source array. - /// The type of the target array. - /// The collection to convert. - /// The converter. - /// target array instance - public static TTarget[] ToArray(this IEnumerable source, Func converter) - { - Guard.ArgumentNotNull(() => source); - Guard.ArgumentNotNull(() => converter); - - return source.Select(converter).ToArray(); - } - - public static bool Exists(this IEnumerable source, Func func) - { - return source.Count(func) > 0; - } - - public static IEnumerable CastValid(this IEnumerable source) - { - return source.Cast().Where(o => o is T).Cast(); - } - - public static bool HasItems(this IEnumerable source) - { - return source != null && source.GetEnumerator().MoveNext(); - } - - public static int GetCount(this IEnumerable source) - { - return source.AsQueryable().GetCount(); - } - - public static bool IsNullOrEmpty(this IEnumerable source) - { - return (source == null || !source.HasItems()); - } + /// + /// Performs an action on each item while iterating through a list. + /// This is a handy shortcut for foreach(item in list) { ... } + /// + /// The type of the items. + /// The list, which holds the objects. + /// The action delegate which is called on each item while iterating. + [DebuggerStepThrough] + public static void Each(this IEnumerable source, Action action) + { + int i = 0; + foreach (T t in source) + { + action(t, i++); + } + } public static ReadOnlyCollection AsReadOnly(this IEnumerable source) { - return new ReadOnlyCollection(source.ToList()); - } - - public static IEnumerable OrderByOrdinal(this IEnumerable source) - where T : IOrdered - { - return source.OrderByOrdinal(false); - } - - public static IEnumerable OrderByOrdinal(this IEnumerable source, bool descending) - where T : IOrdered - { - if (!descending) - return source.OrderBy(x => x.Ordinal); - else - return source.OrderByDescending(x => x.Ordinal); + if (source == null || !source.Any()) + return DefaultReadOnlyCollection.Empty; + + var readOnly = source as ReadOnlyCollection; + if (readOnly != null) + { + return readOnly; + } + + var list = source as List; + if (list != null) + { + return list.AsReadOnly(); + } + + return new ReadOnlyCollection(source.ToArray()); } - public static bool TryGetItem(this IEnumerable source, Expression> predicate, out T item) - { - item = default(T); - - try - { - item = source.AsQueryable().First(predicate); - return true; - } - catch - { - return false; - } - } + /// + /// Converts an enumerable to a dictionary while tolerating duplicate entries (last wins) + /// + /// source + /// keySelector + /// Result as dictionary + public static Dictionary ToDictionarySafe( + this IEnumerable source, + Func keySelector) + { + return source.ToDictionarySafe(keySelector, new Func(src => src), null); + } + + /// + /// Converts an enumerable to a dictionary while tolerating duplicate entries (last wins) + /// + /// source + /// keySelector + /// comparer + /// Result as dictionary + public static Dictionary ToDictionarySafe( + this IEnumerable source, + Func keySelector, + IEqualityComparer comparer) + { + return source.ToDictionarySafe(keySelector, new Func(src => src), comparer); + } + + /// + /// Converts an enumerable to a dictionary while tolerating duplicate entries (last wins) + /// + /// source + /// keySelector + /// elementSelector + /// Result as dictionary + public static Dictionary ToDictionarySafe( + this IEnumerable source, + Func keySelector, + Func elementSelector) + { + return source.ToDictionarySafe(keySelector, elementSelector, null); + } + + /// + /// Converts an enumerable to a dictionary while tolerating duplicate entries (last wins) + /// + /// source + /// keySelector + /// elementSelector + /// comparer + /// Result as dictionary + public static Dictionary ToDictionarySafe( + this IEnumerable source, + Func keySelector, + Func elementSelector, + IEqualityComparer comparer) + { + Guard.ArgumentNotNull(() => source); + Guard.ArgumentNotNull(() => keySelector); + Guard.ArgumentNotNull(() => elementSelector); + + var dictionary = new Dictionary(comparer); + + foreach (var local in source) + { + dictionary[keySelector(local)] = elementSelector(local); + } + + return dictionary; + } #endregion @@ -201,6 +230,7 @@ public static Multimap ToMultimap( public static void AddRange(this NameValueCollection initial, NameValueCollection other) { Guard.ArgumentNotNull(initial, "initial"); + if (other == null) return; @@ -210,63 +240,45 @@ public static void AddRange(this NameValueCollection initial, NameValueCollectio } } - #endregion - - #region AsSerializable - - /// - /// Convenience API to allow an IEnumerable[T] (such as returned by Linq2Sql, NHibernate, EF etc.) - /// to be serialized by DataContractSerializer. - /// - /// The type of item. - /// The original collection. - /// A serializable enumerable wrapper. - public static IEnumerable AsSerializable(this IEnumerable source) where T : class - { - return new IEnumerableWrapper(source); - } - - /// - /// This wrapper allows IEnumerable to be serialized by DataContractSerializer. - /// It implements the minimal amount of surface needed for serialization. - /// - /// Type of item. - class IEnumerableWrapper : IEnumerable - where T : class - { - IEnumerable _collection; - - // The DataContractSerilizer needs a default constructor to ensure the object can be - // deserialized. We have a dummy one since we don't actually need deserialization. - public IEnumerableWrapper() - { - throw new NotImplementedException(); - } - - internal IEnumerableWrapper(IEnumerable collection) - { - this._collection = collection; - } - - // The DataContractSerilizer needs an Add method to ensure the object can be - // deserialized. We have a dummy one since we don't actually need deserialization. - public void Add(T item) - { - throw new NotImplementedException(); - } - - public IEnumerator GetEnumerator() - { - return this._collection.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return ((IEnumerable)this._collection).GetEnumerator(); - } - } + /// + /// Builds an URL query string + /// + /// Name value collection + /// Encoding type. Can be null. + /// Whether to encode keys and values + /// The query string without leading a question mark + public static string BuildQueryString(this NameValueCollection nvc, Encoding encoding, bool encode = true) + { + var sb = new StringBuilder(); + + if (nvc != null) + { + foreach (string str in nvc) + { + if (sb.Length > 0) + sb.Append('&'); + + if (!encode) + sb.Append(str); + else if (encoding == null) + sb.Append(HttpUtility.UrlEncode(str)); + else + sb.Append(HttpUtility.UrlEncode(str, encoding)); + + sb.Append('='); + + if (!encode) + sb.Append(nvc[str]); + else if (encoding == null) + sb.Append(HttpUtility.UrlEncode(nvc[str])); + else + sb.Append(HttpUtility.UrlEncode(nvc[str], encoding)); + } + } + + return sb.ToString(); + } #endregion } - } diff --git a/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs index 26edc0d0e3..acd2f75109 100644 --- a/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/HtmlTextWriterExtensions.cs @@ -4,14 +4,12 @@ using System.Web.UI; namespace SmartStore -{ - +{ public static class HtmlTextWriterExtensions { - public static void AddAttributes(this HtmlTextWriter writer, IDictionary attributes) { - if (attributes.Any>()) + if (attributes.Any()) { foreach (var pair in attributes) { @@ -20,8 +18,5 @@ public static void AddAttributes(this HtmlTextWriter writer, IDictionary webRequest); + Guard.ArgumentNotNull(() => httpRequest); + + var authCookie = httpRequest.Cookies[FormsAuthentication.FormsCookieName]; + if (authCookie == null) + return; + + var sendCookie = new Cookie(authCookie.Name, authCookie.Value, authCookie.Path, httpRequest.Url.Host); + + if (webRequest.CookieContainer == null) + { + webRequest.CookieContainer = new CookieContainer(); + } + + webRequest.CookieContainer.Add(sendCookie); + } } } diff --git a/src/Libraries/SmartStore.Core/Extensions/IOExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/IOExtensions.cs new file mode 100644 index 0000000000..d176d04adb --- /dev/null +++ b/src/Libraries/SmartStore.Core/Extensions/IOExtensions.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore +{ + public static class IOExtensions + { + + public static bool IsFileLocked(this FileInfo file) + { + if (file == null) + return false; + + FileStream stream = null; + + try + { + stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); + } + catch (IOException) + { + //the file is unavailable because it is: + //still being written to + //or being processed by another thread + //or does not exist (has already been processed) + return true; + } + finally + { + if (stream != null) + stream.Close(); + } + + //file is not locked + return false; + } + } + +} diff --git a/src/Libraries/SmartStore.Core/Extensions/JsonExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/JsonExtensions.cs deleted file mode 100644 index 4c192adc74..0000000000 --- a/src/Libraries/SmartStore.Core/Extensions/JsonExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using Newtonsoft.Json; - - -/////////////////////////////////////////////////////////////////////// -// Needs JSon.Net (Newtonsoft.Json.dll) from http://json.codeplex.com/ -////////////////////////////////////////////////////////////////////// - -namespace SmartStore -{ - public static class JsonExtensions - { - public static async Task GetDynamicJsonObject(this Uri uri) - { - using (WebClient wc = new WebClient()) - { - wc.Encoding = System.Text.Encoding.UTF8; - wc.Headers["User-Agent"] = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET4.0C; .NET4.0E)"; - var response = await wc.DownloadStringTaskAsync(uri); - return JsonConvert.DeserializeObject(response); - } - } - } -} - - - diff --git a/src/Libraries/SmartStore.Core/Extensions/LinqExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/LinqExtensions.cs index 06a3b2dc6d..c0731e7538 100644 --- a/src/Libraries/SmartStore.Core/Extensions/LinqExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/LinqExtensions.cs @@ -1,15 +1,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace SmartStore { - public static class LinqExtensions { - public static PropertyInfo ExtractPropertyInfo(this LambdaExpression propertyAccessor) { return propertyAccessor.ExtractMemberInfo() as PropertyInfo; @@ -20,7 +19,8 @@ public static FieldInfo ExtractFieldInfo(this LambdaExpression propertyAccessor) return propertyAccessor.ExtractMemberInfo() as FieldInfo; } - public static MemberInfo ExtractMemberInfo(this LambdaExpression propertyAccessor) + [SuppressMessage("ReSharper", "CanBeReplacedWithTryCastAndCheckForNull")] + public static MemberInfo ExtractMemberInfo(this LambdaExpression propertyAccessor) { Guard.ArgumentNotNull(() => propertyAccessor); diff --git a/src/Libraries/SmartStore.Core/Extensions/ListExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/ListExtensions.cs deleted file mode 100644 index f966ee5456..0000000000 --- a/src/Libraries/SmartStore.Core/Extensions/ListExtensions.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace SmartStore -{ - - public static class ListExtensions - { - - public static string ToSeparatedString(this IList value) - { - return ToSeparatedString(value, ","); - } - - public static string ToSeparatedString(this IList value, string separator) - { - if (value.Count == 0) - { - return String.Empty; - } - if (value.Count == 1) - { - if (value[0] != null) - { - return value[0].ToString(); - } - return string.Empty; - } - - StringBuilder builder = new StringBuilder(); - bool flag = true; - bool flag2 = false; - foreach (object obj2 in value) - { - if (!flag) - { - builder.Append(separator); - } - if (obj2 != null) - { - builder.Append(obj2.ToString().TrimEnd(new char[0])); - flag2 = true; - } - flag = false; - } - if (!flag2) - { - return string.Empty; - } - return builder.ToString(); - } - - /// - /// Makes a slice of the specified list in between the start and end indexes. - /// - /// The list. - /// The start index. - /// The end index. - /// A slice of the list. - public static IList Slice(this IList list, int? start, int? end) - { - return list.Slice(start, end, null); - } - - /// - /// Makes a slice of the specified list in between the start and end indexes, - /// getting every so many items based upon the step. - /// - /// The list. - /// The start index. - /// The end index. - /// The step. - /// A slice of the list. - public static IList Slice(this IList list, int? start, int? end, int? step) - { - if (list == null) - throw new ArgumentNullException("list"); - - if (step == 0) - throw Error.Argument("step", "Step cannot be zero."); - - List slicedList = new List(); - - // nothing to slice - if (list.Count == 0) - return slicedList; - - // set defaults for null arguments - int s = step ?? 1; - int startIndex = start ?? 0; - int endIndex = end ?? list.Count; - - // start from the end of the list if start is negative - startIndex = (startIndex < 0) ? list.Count + startIndex : startIndex; - - // end from the start of the list if end is negative - endIndex = (endIndex < 0) ? list.Count + endIndex : endIndex; - - // ensure indexes keep within collection bounds - startIndex = Math.Max(startIndex, 0); - endIndex = Math.Min(endIndex, list.Count - 1); - - // loop between start and end indexes, incrementing by the step - for (int i = startIndex; i < endIndex; i += s) - { - slicedList.Add(list[i]); - } - - return slicedList; - } - - } - -} diff --git a/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs index a7489dce55..033c5d4230 100644 --- a/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/MiscExtensions.cs @@ -1,78 +1,51 @@ using System; -using System.Text; +using System.ComponentModel; using System.Data; using System.Data.OleDb; using System.Diagnostics; -using System.ComponentModel; +using System.Text; using System.Web.Routing; using SmartStore.Core; -using System.Globalization; namespace SmartStore { public static class MiscExtensions { - public static void Dump(this Exception exc) { - try { - exc.StackTrace.Dump(); - exc.Message.Dump(); + public static void Dump(this Exception exception) + { + try + { + exception.StackTrace.Dump(); + exception.Message.Dump(); } - catch (Exception) { + catch { } + } + + public static string ToAllMessages(this Exception exception) + { + var sb = new StringBuilder(); + + while (exception != null) + { + if (!sb.ToString().EmptyNull().Contains(exception.Message)) + { + sb.Grow(exception.Message, " * "); + } + exception = exception.InnerException; } + return sb.ToString(); } + public static string ToElapsedMinutes(this Stopwatch watch) { return "{0:0.0}".FormatWith(TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds).TotalMinutes); } + public static string ToElapsedSeconds(this Stopwatch watch) { return "{0:0.0}".FormatWith(TimeSpan.FromMilliseconds(watch.ElapsedMilliseconds).TotalSeconds); } - public static bool HasColumn(this DataView dv, string columnName) - { - dv.RowFilter = "ColumnName='" + columnName + "'"; - return dv.Count > 0; - } - public static string GetDataType(this DataTable dt, string columnName) - { - dt.DefaultView.RowFilter = "ColumnName='" + columnName + "'"; - return dt.Rows[0]["DataType"].ToString(); - } - - public static int CountExecute(this OleDbConnection conn, string sqlCount) - { - using (OleDbCommand cmd = new OleDbCommand(sqlCount, conn)) - { - return (int)cmd.ExecuteScalar(); - } - } - - public static object SafeConvert(this TypeConverter converter, string value) - { - try - { - if (converter != null && value.HasValue() && converter.CanConvertFrom(typeof(string))) - { - return converter.ConvertFromString(value); - } - } - catch (Exception exc) - { - exc.Dump(); - } - return null; - } - public static bool IsEqual(this TypeConverter converter, string value, object compareWith) - { - object convertedObject = converter.SafeConvert(value); - - if (convertedObject != null && compareWith != null) - return convertedObject.Equals(compareWith); - - return false; - } - public static bool IsNullOrDefault(this T? value) where T : struct { return default(T).Equals(value.GetValueOrDefault()); @@ -98,29 +71,17 @@ public static string ToHexString(this byte[] bytes, int length = 0) public static T GetMergedDataValue(this IMergedData mergedData, string key, T defaultValue) { - try + if (mergedData.MergedDataValues != null && !mergedData.MergedDataIgnore) { - if (mergedData.MergedDataValues != null && !mergedData.MergedDataIgnore) - { - object value; + object value; - if (mergedData.MergedDataValues.TryGetValue(key, out value)) - return (T)value; - } + if (mergedData.MergedDataValues.TryGetValue(key, out value)) + return (T)value; } - catch (Exception) { } return defaultValue; } - public static bool IsRouteEqual(this RouteData routeData, string controller, string action) - { - if (routeData == null) - return false; - - return routeData.GetRequiredString("controller").IsCaseInsensitiveEqual(controller) && routeData.GetRequiredString("action").IsCaseInsensitiveEqual(action); - } - /// /// Append grow if string builder is empty. Append delimiter and grow otherwise. /// @@ -140,17 +101,6 @@ public static void Grow(this StringBuilder sb, string grow, string delimiter) } } - /// - /// Rounds and formats a decimal culture invariant - /// - /// The decimal - /// Rounding decimal number - /// Formated value - public static string FormatInvariant(this decimal value, int decimals = 2) - { - return Math.Round(value, decimals).ToString("0.00", CultureInfo.InvariantCulture); - } - public static string SafeGet(this string[] arr, int index) { return (arr != null && index < arr.Length ? arr[index] : ""); diff --git a/src/Libraries/SmartStore.Core/Extensions/StreamExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/StreamExtensions.cs index 31bddf144d..f958bdaf73 100644 --- a/src/Libraries/SmartStore.Core/Extensions/StreamExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/StreamExtensions.cs @@ -10,26 +10,35 @@ namespace SmartStore { public static class StreamExtensions { - - public static bool ToFile(this Stream srcStream, string path) + public static StreamReader ToStreamReader(this Stream stream, bool leaveOpen) + { + return new StreamReader(stream, Encoding.UTF8, true, 0x400, leaveOpen); + } + + public static StreamReader ToStreamReader(this Stream stream, Encoding encoding, bool detectEncoding, int bufferSize, bool leaveOpen) + { + return new StreamReader(stream, encoding, detectEncoding, bufferSize, leaveOpen); + } + + public static bool ToFile(this Stream srcStream, string path) { if (srcStream == null) return false; const int BuffSize = 32768; bool result = true; - int len = 0; Stream dstStream = null; byte[] buffer = new Byte[BuffSize]; try { - using (dstStream = File.OpenWrite(path)) - { + using (dstStream = File.OpenWrite(path)) + { + int len; while ((len = srcStream.Read(buffer, 0, BuffSize)) > 0) dstStream.Write(buffer, 0, len); } - } + } catch { result = false; diff --git a/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs index f70a9ac1c4..9131705215 100644 --- a/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/StringExtensions.cs @@ -7,11 +7,11 @@ using System.Text.RegularExpressions; using System.IO; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; namespace SmartStore { - public static class StringExtensions { public const string CarriageReturnLineFeed = "\r\n"; @@ -112,37 +112,37 @@ public static string NullEmpty(this string value) return (string.IsNullOrEmpty(value)) ? null : value; } - /// - /// Formats a string to an invariant culture - /// - /// The format string. - /// The objects. - /// - [DebuggerStepThrough] + /// + /// Formats a string to an invariant culture + /// + /// The format string. + /// The objects. + /// + [DebuggerStepThrough] public static string FormatInvariant(this string format, params object[] objects) { return string.Format(CultureInfo.InvariantCulture, format, objects); } - /// - /// Formats a string to the current culture. - /// - /// The format string. - /// The objects. - /// - [DebuggerStepThrough] + /// + /// Formats a string to the current culture. + /// + /// The format string. + /// The objects. + /// + [DebuggerStepThrough] public static string FormatCurrent(this string format, params object[] objects) { return string.Format(CultureInfo.CurrentCulture, format, objects); } - /// - /// Formats a string to the current UI culture. - /// - /// The format string. - /// The objects. - /// - [DebuggerStepThrough] + /// + /// Formats a string to the current UI culture. + /// + /// The format string. + /// The objects. + /// + [DebuggerStepThrough] public static string FormatCurrentUI(this string format, params object[] objects) { return string.Format(CultureInfo.CurrentUICulture, format, objects); @@ -160,29 +160,29 @@ public static string FormatWith(this string format, IFormatProvider provider, pa return string.Format(provider, format, args); } - /// - /// Determines whether this instance and another specified System.String object have the same value. - /// - /// The string to check equality. - /// The comparing with string. - /// - /// true if the value of the comparing parameter is the same as this string; otherwise, false. - /// - [DebuggerStepThrough] + /// + /// Determines whether this instance and another specified System.String object have the same value. + /// + /// The string to check equality. + /// The comparing with string. + /// + /// true if the value of the comparing parameter is the same as this string; otherwise, false. + /// + [DebuggerStepThrough] public static bool IsCaseSensitiveEqual(this string value, string comparing) { return string.CompareOrdinal(value, comparing) == 0; } - /// - /// Determines whether this instance and another specified System.String object have the same value. - /// - /// The string to check equality. - /// The comparing with string. - /// - /// true if the value of the comparing parameter is the same as this string; otherwise, false. - /// - [DebuggerStepThrough] + /// + /// Determines whether this instance and another specified System.String object have the same value. + /// + /// The string to check equality. + /// The comparing with string. + /// + /// true if the value of the comparing parameter is the same as this string; otherwise, false. + /// + [DebuggerStepThrough] public static bool IsCaseInsensitiveEqual(this string value, string comparing) { return string.Compare(value, comparing, StringComparison.OrdinalIgnoreCase) == 0; @@ -194,27 +194,17 @@ public static bool IsCaseInsensitiveEqual(this string value, string comparing) [DebuggerStepThrough] public static bool IsEmpty(this string value) { - - if (value == null || value.Length == 0) - return true; - - for (int i = 0; i < value.Length; i++) - { - if (!char.IsWhiteSpace(value[i])) - return false; - } - - return true; + return string.IsNullOrWhiteSpace(value); } - /// - /// Determines whether the string is all white space. Empty string will return false. - /// - /// The string to test whether it is all white space. - /// - /// true if the string is all white space; otherwise, false. - /// - [DebuggerStepThrough] + /// + /// Determines whether the string is all white space. Empty string will return false. + /// + /// The string to test whether it is all white space. + /// + /// true if the string is all white space; otherwise, false. + /// + [DebuggerStepThrough] public static bool IsWhiteSpace(this string value) { Guard.ArgumentNotNull(value, "value"); @@ -234,23 +224,19 @@ public static bool IsWhiteSpace(this string value) [DebuggerStepThrough] public static bool HasValue(this string value) { - return !string.IsNullOrEmpty(value); + return !string.IsNullOrWhiteSpace(value); } - /// codehint: sm-edit - /// to get equivalent result to PHPs md5 function call Hash("my value", false, false). + /// to get equivalent result to PHPs md5 function call Hash("my value", Encoding.ASCII, false). [DebuggerStepThrough] - public static string Hash(this string value, bool toBase64 = false, bool unicode = false) + public static string Hash(this string value, Encoding encoding, bool toBase64 = false) { - Guard.ArgumentNotEmpty(value, "value"); + if (value.IsEmpty()) + return value; - using (MD5 md5 = MD5.Create()) + using (var md5 = MD5.Create()) { - byte[] data = null; - if (unicode) - data = Encoding.Unicode.GetBytes(value); - else - data = Encoding.ASCII.GetBytes(value); + byte[] data = encoding.GetBytes(value); if (toBase64) { @@ -264,6 +250,20 @@ public static string Hash(this string value, bool toBase64 = false, bool unicode } } + /// + /// Mask by replacing characters with asterisks. + /// + /// The string + /// Number of characters to leave untouched. + /// The mask string + [DebuggerStepThrough] + public static string Mask(this string value, int length) + { + if (value.HasValue()) + return value.Substring(0, length) + new String('*', value.Length - length); + return value; + } + [DebuggerStepThrough] public static bool IsWebUrl(this string value) { @@ -340,26 +340,6 @@ public static string Truncate(this string value, int maxLength, string suffix = } } - /// - /// Determines whether the string contains white space. - /// - /// The string to test for white space. - /// - /// true if the string contains white space; otherwise, false. - /// - [DebuggerStepThrough] - public static bool ContainsWhiteSpace(this string value) - { - Guard.ArgumentNotNull(value, "value"); - - for (int i = 0; i < value.Length; i++) - { - if (char.IsWhiteSpace(value[i])) - return true; - } - return false; - } - /// /// Ensure that a string starts with a string. /// @@ -375,13 +355,13 @@ public static string EnsureStartsWith(this string value, string startsWith) return value.StartsWith(startsWith) ? value : (startsWith + value); } - /// - /// Ensures the target string ends with the specified string. - /// - /// The target. - /// The value. - /// The target string with the value string at the end. - [DebuggerStepThrough] + /// + /// Ensures the target string ends with the specified string. + /// + /// The target. + /// The value. + /// The target string with the value string at the end. + [DebuggerStepThrough] public static string EnsureEndsWith(this string value, string endWith) { Guard.ArgumentNotNull(value, "value"); @@ -401,15 +381,6 @@ public static string EnsureEndsWith(this string value, string endWith) return value + endWith; } - [DebuggerStepThrough] - public static int? GetLength(this string value) - { - if (value == null) - return null; - else - return value.Length; - } - [DebuggerStepThrough] public static string UrlEncode(this string value) { @@ -477,13 +448,13 @@ private static string RemoveHtmlInternal(string s, ICollection removeTag }); } - /// - /// Replaces pascal casing with spaces. For example "CustomerId" would become "Customer Id". - /// Strings that already contain spaces are ignored. - /// - /// String to split - /// The string after being split - [DebuggerStepThrough] + /// + /// Replaces pascal casing with spaces. For example "CustomerId" would become "Customer Id". + /// Strings that already contain spaces are ignored. + /// + /// String to split + /// The string after being split + [DebuggerStepThrough] public static string SplitPascalCase(this string value) { //return Regex.Replace(input, "([A-Z][a-z])", " $1", RegexOptions.Compiled).Trim(); @@ -506,7 +477,7 @@ public static string SplitPascalCase(this string value) return sb.ToString(); } - /// codehint: sm-add + [DebuggerStepThrough] public static string[] SplitSafe(this string value, string separator) { @@ -514,114 +485,27 @@ public static string[] SplitSafe(this string value, string separator) return new string[0]; return value.Split(new string[] { separator }, StringSplitOptions.RemoveEmptyEntries); } + /// Splits a string into two strings - /// codehint: sm-add /// true: success, false: failure [DebuggerStepThrough] - public static bool SplitToPair(this string value, out string strLeft, out string strRight, string delimiter) { + [SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")] + public static bool SplitToPair(this string value, out string strLeft, out string strRight, string delimiter) + { int idx = -1; - if (value.IsNullOrEmpty() || delimiter.IsNullOrEmpty() || (idx = value.IndexOf(delimiter)) == -1) { + if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(delimiter) || (idx = value.IndexOf(delimiter)) == -1) + { strLeft = value; strRight = ""; return false; } + strLeft = value.Substring(0, idx); strRight = value.Substring(idx + delimiter.Length); + return true; } - [DebuggerStepThrough] - public static string ToCamelCase(this string instance) - { - char ch = instance[0]; - return (ch.ToString().ToLowerInvariant() + instance.Substring(1)); - } - - [DebuggerStepThrough] - public static string ReplaceNewLines(this string value, string replacement) - { - StringReader sr = new StringReader(value); - StringBuilder sb = new StringBuilder(); - - bool first = true; - - string line; - while ((line = sr.ReadLine()) != null) - { - if (first) - first = false; - else - sb.Append(replacement); - - sb.Append(line); - } - - return sb.ToString(); - } - - /// - /// Indents the specified string. - /// - /// The string to indent. - /// The number of characters to indent by. - /// - [DebuggerStepThrough] - public static string Indent(this string value, int indentation) - { - return Indent(value, indentation, ' '); - } - - /// - /// Indents the specified string. - /// - /// The string to indent. - /// The number of characters to indent by. - /// The indent character. - /// - [DebuggerStepThrough] - public static string Indent(this string value, int indentation, char indentChar) - { - Guard.ArgumentNotNull(value, "value"); - Guard.ArgumentIsPositive(indentation, "indentation"); - - StringReader sr = new StringReader(value); - StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); - - ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line) - { - tw.Write(new string(indentChar, indentation)); - tw.Write(line); - }); - - return sw.ToString(); - } - - /// - /// Numbers the lines. - /// - /// The string to number. - /// - public static string NumberLines(this string value) - { - Guard.ArgumentNotNull(value, "value"); - - StringReader sr = new StringReader(value); - StringWriter sw = new StringWriter(CultureInfo.InvariantCulture); - - int lineNumber = 1; - - ActionTextReaderLine(sr, sw, delegate(TextWriter tw, string line) - { - tw.Write(lineNumber.ToString(CultureInfo.InvariantCulture).PadLeft(4)); - tw.Write(". "); - tw.Write(line); - - lineNumber++; - }); - - return sw.ToString(); - } - [DebuggerStepThrough] public static string EncodeJsString(this string value) { @@ -631,7 +515,7 @@ public static string EncodeJsString(this string value) [DebuggerStepThrough] public static string EncodeJsString(this string value, char delimiter, bool appendDelimiters) { - StringBuilder sb = new StringBuilder(value.GetLength() ?? 16); + StringBuilder sb = new StringBuilder(value != null ? value.Length : 16); using (StringWriter w = new StringWriter(sb, CultureInfo.InvariantCulture)) { EncodeJsString(w, value, delimiter, appendDelimiters); @@ -713,19 +597,21 @@ public static string RemoveEncloser(this string value, string start, string end, } /// Debug.WriteLine - /// codehint: sm-add [DebuggerStepThrough] - public static void Dump(this string value) + public static void Dump(this string value, bool appendMarks = false) { Debug.WriteLine(value); + Debug.WriteLineIf(appendMarks, "------------------------------------------------"); } - - /// Smart way to create a HTML attribute with a leading space. - /// codehint: sm-add - /// Name of the attribute. + + /// Smart way to create a HTML attribute with a leading space. + /// Name of the attribute. + /// + /// + [SuppressMessage("ReSharper", "StringCompareIsCultureSpecific.3")] public static string ToAttribute(this string value, string name, bool htmlEncode = true) { - if (value == null || name.IsNullOrEmpty()) + if (name.IsEmpty()) return ""; if (value == "" && name != "value" && !name.StartsWith("data")) @@ -778,7 +664,31 @@ public static string Replace(this string value, int x1, int x2, string replaceBy return value; } - [DebuggerStepThrough] + [DebuggerStepThrough] + public static string Replace(this string value, string oldValue, string newValue, StringComparison comparisonType) + { + try + { + int startIndex = 0; + while (true) + { + startIndex = value.IndexOf(oldValue, startIndex, comparisonType); + if (startIndex == -1) + break; + + value = value.Substring(0, startIndex) + newValue + value.Substring(startIndex + oldValue.Length); + + startIndex += newValue.Length; + } + } + catch (Exception exc) + { + exc.Dump(); + } + return value; + } + + [DebuggerStepThrough] public static string TrimSafe(this string value) { return (value.HasValue() ? value.Trim() : value); @@ -868,55 +778,16 @@ public static string Prettify(this string value, bool allowSpace = false, char[] public static string SanitizeHtmlId(this string value) { - if (string.IsNullOrWhiteSpace(value)) - { - return null; - } - StringBuilder builder = new StringBuilder(value.Length); - int index = value.IndexOf("#"); - int num2 = value.LastIndexOf("#"); - if (num2 > index) - { - ReplaceInvalidHtmlIdCharacters(value.Substring(0, index), builder); - builder.Append(value.Substring(index, (num2 - index) + 1)); - ReplaceInvalidHtmlIdCharacters(value.Substring(num2 + 1), builder); - } - else - { - ReplaceInvalidHtmlIdCharacters(value, builder); - } - return builder.ToString(); - } - - private static bool IsValidHtmlIdCharacter(char c) - { - bool invalid = (c == '?' || c == '!' || c == '#' || c == '.' || c == ' ' || c == ';' || c == ':'); - return !invalid; - } - - private static void ReplaceInvalidHtmlIdCharacters(string part, StringBuilder builder) - { - for (int i = 0; i < part.Length; i++) - { - char c = part[i]; - if (IsValidHtmlIdCharacter(c)) - { - builder.Append(c); - } - else - { - builder.Append('_'); - } - } + return System.Web.Mvc.TagBuilder.CreateSanitizedId(value); } - public static string Sha(this string value) + public static string Sha(this string value, Encoding encoding) { - if (value.HasValue()) + if (value.HasValue()) { - using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider()) + using (var sha1 = new SHA1CryptoServiceProvider()) { - byte[] data = Encoding.ASCII.GetBytes(value); + byte[] data = encoding.GetBytes(value); return sha1.ComputeHash(data).ToHexString(); } @@ -976,12 +847,14 @@ private static string ToValidPathInternal(this string input, bool isPath, string [DebuggerStepThrough] public static int[] ToIntArray(this string s) { - return Array.ConvertAll(s.SplitSafe(","), v => int.Parse(v)); + return Array.ConvertAll(s.SplitSafe(","), v => int.Parse(v.Trim())); } [DebuggerStepThrough] public static bool ToIntArrayContains(this string s, int value, bool defaultValue) { + if (s == null) + return defaultValue; var arr = s.ToIntArray(); if (arr == null || arr.Count() <= 0) return defaultValue; @@ -991,7 +864,7 @@ public static bool ToIntArrayContains(this string s, int value, bool defaultValu [DebuggerStepThrough] public static string RemoveInvalidXmlChars(this string s) { - if (s.IsNullOrEmpty()) + if (s.IsEmpty()) return s; return Regex.Replace(s, @"[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFFFD]", "", RegexOptions.Compiled); @@ -1000,14 +873,15 @@ public static string RemoveInvalidXmlChars(this string s) [DebuggerStepThrough] public static string ReplaceCsvChars(this string s) { - if (s.HasValue()) + if (s.IsEmpty()) { - s = s.Replace(';', ','); - s = s.Replace('\r', ' '); - s = s.Replace('\n', ' '); - return s.Replace("'", ""); + return ""; } - return ""; + + s = s.Replace(';', ','); + s = s.Replace('\r', ' '); + s = s.Replace('\n', ' '); + return s.Replace("'", ""); } #endregion @@ -1077,22 +951,6 @@ private static void EncodeJsString(TextWriter writer, string value, char delimit writer.Write(delimiter); } - - private static void ActionTextReaderLine(TextReader textReader, TextWriter textWriter, ActionLine lineAction) - { - string line; - bool firstLine = true; - while ((line = textReader.ReadLine()) != null) - { - if (!firstLine) - textWriter.WriteLine(); - else - firstLine = false; - - lineAction(textWriter, line); - } - } - #endregion } diff --git a/src/Libraries/SmartStore.Core/Extensions/TypeDescriptorExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/TypeDescriptorExtensions.cs deleted file mode 100644 index f9467d851a..0000000000 --- a/src/Libraries/SmartStore.Core/Extensions/TypeDescriptorExtensions.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.ComponentModel; - -using SmartStore.Linq; - -namespace SmartStore -{ - - public static class TypeDescriptorExtensions - { - - public static IEnumerable GetAttributes(this ICustomTypeDescriptor td) where TAttribute : Attribute - { - var attributes = td.GetAttributes().OfType(); - return TypeExtensions.SortAttributesIfPossible(attributes); - } - - public static IEnumerable GetAttributes(this PropertyDescriptor pd) where TAttribute : Attribute - { - var attributes = pd.Attributes.OfType(); - return TypeExtensions.SortAttributesIfPossible(attributes); - } - - public static IEnumerable GetAttributes(this PropertyDescriptor pd, - Func predicate) - where TAttribute : Attribute - { - Guard.ArgumentNotNull(predicate, "predicate"); - - var attributes = pd.Attributes.OfType().Where(predicate); - return TypeExtensions.SortAttributesIfPossible(attributes); - } - - public static PropertyDescriptor GetProperty(this ICustomTypeDescriptor td, string name) - { - Guard.ArgumentNotEmpty(name, "name"); - return td.GetProperties().Find(name, true); - //.Cast() - //.FirstOrDefault(p => p.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)); - } - - public static IEnumerable GetPropertiesWith(this ICustomTypeDescriptor td) - where TAttribute : Attribute - { - return td.GetPropertiesWith(x => true); - } - - public static IEnumerable GetPropertiesWith( - this ICustomTypeDescriptor td, - Func predicate) - where TAttribute : Attribute - { - Guard.ArgumentNotNull(predicate, "predicate"); - - return td.GetProperties() - .Cast() - .Where(p => p.GetAttributes().Any(predicate)); - - //Expression> expression = (TAttribute a) => typeof(TAttribute).IsAssignableFrom(a.GetType()); - - //return td.GetProperties() - // .Cast() - // .Where(p => p.Attributes.Cast() - // .Any(expression.And(predicate).Compile())); - - //var query = from p in this.EntityTypeDescriptor.GetProperties().Cast() - // let attributes = p.Attributes.Cast() - // where attributes.Any(a => typeof(TAttribute).IsAssignableFrom(a.GetType())) - // //where attributes.Any(a => typeof(TAttribute).IsAssignableFrom(a.GetType())) - // select p; - - //return query - // .Select(p => new EntityProperty(p, this)) - // .AsReadOnly(); - } - - } - -} diff --git a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs index e3a57c0c0e..baf9195b18 100644 --- a/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/TypeExtensions.cs @@ -4,26 +4,26 @@ using System.Reflection; using System.Collections; using System.Diagnostics; -using Fasterflect; +using System.Diagnostics.CodeAnalysis; namespace SmartStore { - public static class TypeExtensions { - private static Type[] s_predefinedTypes; - private static Type[] s_predefinedGenericTypes; - - static TypeExtensions() - { - s_predefinedTypes = new Type[] { typeof(string), typeof(decimal), typeof(DateTime), typeof(TimeSpan), typeof(Guid) }; - s_predefinedGenericTypes = new Type[] { typeof(Nullable<>) }; - } + private static readonly Type[] s_predefinedTypes = new Type[] { typeof(string), typeof(decimal), typeof(DateTime), typeof(TimeSpan), typeof(Guid) }; + private static readonly Type[] s_predefinedGenericTypes = new Type[] { typeof(Nullable<>) }; public static string AssemblyQualifiedNameWithoutVersion(this Type type) { - string[] strArray = type.AssemblyQualifiedName.Split(new char[] { ',' }); - return string.Format("{0},{1}", strArray[0], strArray[1]); + Guard.ArgumentNotNull(() => type); + + if (type.AssemblyQualifiedName != null) + { + var strArray = type.AssemblyQualifiedName.Split(new char[] { ',' }); + return string.Format("{0}, {1}", strArray[0], strArray[1]); + } + + return null; } public static bool IsSequenceType(this Type seqType) @@ -45,15 +45,8 @@ public static bool IsPredefinedSimpleType(this Type type) { return true; } + return s_predefinedTypes.Any(t => t == type); - //foreach (Type type2 in s_predefinedTypes) - //{ - // if (type2 == type) - // { - // return true; - // } - //} - //return false; } public static bool IsStruct(this Type type) @@ -75,15 +68,8 @@ public static bool IsPredefinedGenericType(this Type type) { return false; } + return s_predefinedGenericTypes.Any(t => t == type); - //foreach (Type type2 in s_predefinedGenericTypes) - //{ - // if (type2 == type) - // { - // return true; - // } - //} - //return false; } public static bool IsPredefinedType(this Type type) @@ -97,7 +83,6 @@ public static bool IsPredefinedType(this Type type) public static bool IsInteger(this Type type) { - switch (Type.GetTypeCode(type)) { case TypeCode.SByte: @@ -119,11 +104,6 @@ public static bool IsNullable(this Type type) return type != null && type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); } - public static bool IsNullAssignable(this Type type) - { - return !type.IsValueType || type.IsNullable(); - } - public static bool IsConstructable(this Type type) { Guard.ArgumentNotNull(type, "type"); @@ -224,244 +204,6 @@ private static bool IsSubClassInternal(Type initialType, Type currentType, Type return IsSubClassInternal(initialType, currentType.BaseType, check, out implementingType); } - public static bool IsIndexed(this PropertyInfo property) - { - Guard.ArgumentNotNull(property, "property"); - return !property.GetIndexParameters().IsNullOrEmpty(); - } - - /// - /// Determines whether the member is an indexed property. - /// - /// The member. - /// - /// true if the member is an indexed property; otherwise, false. - /// - public static bool IsIndexed(this MemberInfo member) - { - Guard.ArgumentNotNull(member, "member"); - - PropertyInfo propertyInfo = member as PropertyInfo; - - if (propertyInfo != null) - return propertyInfo.IsIndexed(); - else - return false; - } - - /// - /// Checks to see if the specified type is assignable. - /// - /// - /// - public static bool IsType(this Type type) - { - return typeof(TType).IsAssignableFrom(type); - } - - - - public static MemberInfo GetSingleMember(this Type type, string name, MemberTypes memberTypes) - { - return type.GetSingleMember( - name, - memberTypes, - BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); - } - - public static MemberInfo GetSingleMember(this Type type, string name, MemberTypes memberTypes, BindingFlags bindingAttr) - { - return type.GetMember( - name, - memberTypes, - bindingAttr).SingleOrDefault(); - } - - public static string GetNameAndAssemblyName(this Type type) - { - Guard.ArgumentNotNull(type, "type"); - return type.FullName + ", " + type.Assembly.GetName().Name; - } - - public static IEnumerable GetFieldsAndProperties(this Type type, BindingFlags bindingAttr) - { - foreach (var fi in type.GetFields(bindingAttr)) - { - yield return fi; - } - - foreach (var pi in type.GetProperties(bindingAttr)) - { - yield return pi; - } - } - - public static MemberInfo GetFieldOrProperty(this Type type, string name, bool ignoreCase) - { - BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; - if (ignoreCase) - flags |= BindingFlags.IgnoreCase; - - return type.GetSingleMember( - name, - MemberTypes.Field | MemberTypes.Property, - flags); - } - - public static List FindMembers(this Type targetType, MemberTypes memberType, BindingFlags bindingAttr, MemberFilter filter, object filterCriteria) - { - Guard.ArgumentNotNull(targetType, "targetType"); - - List memberInfos = new List(targetType.FindMembers(memberType, bindingAttr, filter, filterCriteria)); - - // fix weirdness with FieldInfos only being returned for the current Type - // find base type fields and add them to result - if ((memberType & MemberTypes.Field) != 0 - && (bindingAttr & BindingFlags.NonPublic) != 0) - { - // modify flags to not search for public fields - BindingFlags nonPublicBindingAttr = bindingAttr ^ BindingFlags.Public; - - while ((targetType = targetType.BaseType) != null) - { - memberInfos.AddRange(targetType.FindMembers(MemberTypes.Field, nonPublicBindingAttr, filter, filterCriteria)); - } - } - - return memberInfos; - } - - //public static Type MakeGenericType(this Type genericTypeDefinition, params Type[] innerTypes) - //{ - // Guard.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition"); - // Guard.ArgumentNotEmpty(innerTypes, "innerTypes"); - // Guard.Argument.IsTrue(genericTypeDefinition.IsGenericTypeDefinition, "genericTypeDefinition", "Type '{0}' must be a generic type definition.".FormatInvariant(genericTypeDefinition)); - - // return genericTypeDefinition.MakeGenericType(innerTypes); - //} - - public static object CreateGeneric(this Type genericTypeDefinition, Type innerType, params object[] args) - { - return CreateGeneric(genericTypeDefinition, new Type[] { innerType }, args); - } - - public static object CreateGeneric(this Type genericTypeDefinition, Type[] innerTypes, params object[] args) - { - return CreateGeneric(genericTypeDefinition, innerTypes, (t, a) => Activator.CreateInstance(t, args)); - } - - public static object CreateGeneric(this Type genericTypeDefinition, Type[] innerTypes, Func instanceCreator, params object[] args) - { - Guard.ArgumentNotNull(() => genericTypeDefinition); - Guard.ArgumentNotEmpty(() => innerTypes); - Guard.ArgumentNotNull(() => instanceCreator); - - Type specificType = genericTypeDefinition.MakeGenericType(innerTypes); - - return instanceCreator(specificType, args); - } - - public static IList CreateGenericList(this Type listType) - { - Guard.ArgumentNotNull(listType, "listType"); - return (IList)typeof(List<>).CreateGeneric(listType); - } - - //public static Type RemoveNullable(this Type type) - //{ - // if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>))) - // { - // return type.GetGenericArguments()[0]; - // } - // return type; - //} - - public static bool IsEnumerable(this Type type) - { - Guard.ArgumentNotNull(type, "type"); - return type.IsAssignableFrom(typeof(IEnumerable)); - } - - public static bool IsGenericDictionary(this Type type) - { - if (type.IsInterface && type.IsGenericType) - { - return typeof(IDictionary<,>).Equals(type.GetGenericTypeDefinition()); - } - return (type.GetInterface(typeof(IDictionary<,>).Name) != null); - } - - //public static bool IsListType(this Type type) - //{ - // Guard.ArgumentNotNull(type, "type"); - - // if (type.IsArray) - // return true; - // else if (typeof(IList).IsAssignableFrom(type)) - // return true; - // else if (type.IsSubClass(typeof(IList<>))) - // return true; - // else - // return false; - //} - - /// - /// Gets the member's value on the object. - /// - /// The member. - /// The target object. - /// The member's value on the object. - public static object GetValue(this MemberInfo member, object target) - { - Guard.ArgumentNotNull(member, "member"); - Guard.ArgumentNotNull(target, "target"); - - var type = target.GetType(); - - switch (member.MemberType) - { - case MemberTypes.Field: - return target.GetFieldValue(member.Name); - //return ((FieldInfo)member).GetValue(target); - case MemberTypes.Property: - return target.GetPropertyValue(member.Name); - default: - throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatInvariant(member.Name), "member"); - } - } - - /// - /// Sets the member's value on the target object. - /// - /// The member. - /// The target. - /// The value. - public static void SetValue(this MemberInfo member, object target, object value) - { - Guard.ArgumentNotNull(member, "member"); - Guard.ArgumentNotNull(target, "target"); - - switch (member.MemberType) - { - case MemberTypes.Field: - target.SetFieldValue(member.Name, value); - break; - //return ((FieldInfo)member).GetValue(target); - case MemberTypes.Property: - try - { - target.SetPropertyValue(member.Name, value); - } - catch (TargetParameterCountException e) - { - throw new ArgumentException("PropertyInfo '{0}' has index parameters".FormatInvariant(member.Name), "member", e); - } - break; - default: - throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatInvariant(member.Name), "member"); - } - } - /// /// Gets the underlying type of a type. /// @@ -474,62 +216,15 @@ public static Type GetNonNullableType(this Type type) return type.GetGenericArguments()[0]; } - /// - /// Determines whether the specified MemberInfo can be read. - /// - /// The MemberInfo to determine whether can be read. - /// - /// true if the specified MemberInfo can be read; otherwise, false. - /// - /// - /// For methods this will return true if the return type - /// is not void and the method is parameterless. - /// - public static bool CanReadValue(this MemberInfo member) - { - switch (member.MemberType) - { - case MemberTypes.Field: - return true; - case MemberTypes.Property: - return ((PropertyInfo)member).CanRead; - case MemberTypes.Method: - MethodInfo mi = (MethodInfo)member; - return mi.ReturnType != typeof(void) && mi.GetParameters().Length == 0; - default: - return false; - } - } - - /// - /// Determines whether the specified MemberInfo can be set. - /// - /// The MemberInfo to determine whether can be set. - /// - /// true if the specified MemberInfo can be set; otherwise, false. - /// - public static bool CanSetValue(this MemberInfo member) - { - switch (member.MemberType) - { - case MemberTypes.Field: - return true; - case MemberTypes.Property: - return ((PropertyInfo)member).CanWrite; - default: - return false; - } - } - - /// - /// Returns single attribute from the type - /// - /// Attribute to use - /// Attribute provider - /// - /// Null if the attribute is not found - /// If there are 2 or more attributes - public static TAttribute GetAttribute(this ICustomAttributeProvider target, bool inherits) where TAttribute : Attribute + /// + /// Returns single attribute from the type + /// + /// Attribute to use + /// Attribute provider + /// + /// Null if the attribute is not found + /// If there are 2 or more attributes + public static TAttribute GetAttribute(this ICustomAttributeProvider target, bool inherits) where TAttribute : Attribute { if (target.IsDefined(typeof(TAttribute), inherits)) { @@ -542,7 +237,6 @@ public static TAttribute GetAttribute(this ICustomAttributeProvider } return null; - } public static bool HasAttribute(this ICustomAttributeProvider target, bool inherits) where TAttribute : Attribute @@ -550,15 +244,15 @@ public static bool HasAttribute(this ICustomAttributeProvider target return target.IsDefined(typeof(TAttribute), inherits); } - /// - /// Given a particular MemberInfo, return the custom attributes of the - /// given type on that member. - /// - /// Type of attribute to retrieve. - /// The member to look at. - /// True to include attributes inherited from base classes. - /// Array of found attributes. - public static TAttribute[] GetAttributes(this ICustomAttributeProvider target, bool inherits) where TAttribute : Attribute + /// + /// Given a particular MemberInfo, return the custom attributes of the + /// given type on that member. + /// + /// Type of attribute to retrieve. + /// The member to look at. + /// True to include attributes inherited from base classes. + /// Array of found attributes. + public static TAttribute[] GetAttributes(this ICustomAttributeProvider target, bool inherits) where TAttribute : Attribute { if (target.IsDefined(typeof(TAttribute), inherits)) { @@ -567,30 +261,9 @@ public static TAttribute[] GetAttributes(this ICustomAttributeProvid .Cast(); return SortAttributesIfPossible(attributes).ToArray(); - - #region Obsolete - //return target - // .GetCustomAttributes(typeof(TAttribute), inherits) - // .ToArray(a => (TAttribute)a); - #endregion } - return new TAttribute[0]; - #region Obsolete - //// OBSOLETE 1 - //return target.GetCustomAttributes(typeof(TAttribute), inherits).Cast().ToArray(); - - //// OBSOLETE 2 - //object[] attributesAsObjects = member.GetCustomAttributes(typeof(TAttribute), inherits); - //TAttribute[] attributes = new TAttribute[attributesAsObjects.Length]; - //int index = 0; - //Array.ForEach(attributesAsObjects, - // delegate(object o) - // { - // attributes[index++] = (TAttribute)o; - // }); - //return attributes; - #endregion + return new TAttribute[0]; } /// @@ -625,7 +298,8 @@ public static TAttribute[] GetAllAttributes(this MemberInfo member, return attributes.ToArray(); } - internal static IEnumerable SortAttributesIfPossible(IEnumerable attributes) + [SuppressMessage("ReSharper", "SuspiciousTypeConversion.Global")] + internal static IEnumerable SortAttributesIfPossible(IEnumerable attributes) where TAttribute : Attribute { if (typeof(IOrdered).IsAssignableFrom(typeof(TAttribute))) @@ -671,15 +345,16 @@ internal static Type FindIEnumerable(this Type seqType) return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType()); if (seqType.IsGenericType) { - foreach (Type arg in seqType.GetGenericArguments()) + var args = seqType.GetGenericArguments(); + foreach (var arg in args) { - Type ienum = typeof(IEnumerable<>).MakeGenericType(arg); + var ienum = typeof(IEnumerable<>).MakeGenericType(arg); if (ienum.IsAssignableFrom(seqType)) return ienum; } } Type[] ifaces = seqType.GetInterfaces(); - if (ifaces != null && ifaces.Length > 0) + if (ifaces.Length > 0) { foreach (Type iface in ifaces) { diff --git a/src/Libraries/SmartStore.Core/Extensions/XPathExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/XPathExtensions.cs new file mode 100644 index 0000000000..d44109c7f2 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Extensions/XPathExtensions.cs @@ -0,0 +1,98 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Xml.XPath; +using SmartStore.Core.Domain.Localization; + +namespace SmartStore +{ + public static class XPathExtensions + { + /// + /// Safe way to get the value of a xpath navigator item + /// + /// Type + /// The node + /// Optional xpath + /// Optional default value + /// For localized values. Xpath scheme: Localized/xpath[@culture = 'language.LanguageCulture'] + /// If null is passed, CultureInfo.InvariantCulture is used. + /// The value + public static T GetValue(this XPathNavigator node, string xpath = null, T defaultValue = default(T), Language language = null, CultureInfo culture = null) + { + try + { + if (node != null) + { + if (xpath.IsEmpty()) + { + if (node.Value.HasValue()) + return node.Value.Convert(culture); + + return defaultValue; + } + + if (language != null) + xpath = "Localized/{0}[@culture = '{1}']".FormatWith(xpath, language.LanguageCulture.EmptyNull().ToLower()); + + var n = node.SelectSingleNode(xpath); + + if (n != null && n.Value.HasValue()) + return n.Value.Convert(culture); + } + } + catch (Exception exc) + { + exc.Dump(); + } + + return defaultValue; + } + + /// + /// Safe way to get a string value of a xpath navigator item + /// + /// The node + /// Optional xpath + /// Optional default value + /// The value + public static string GetString(this XPathNavigator node, string xpath = null, string defaultValue = null) + { + // note: better not merge GetString(...) and GetValue(...) + try + { + if (node != null) + { + if (xpath.IsEmpty()) + return node.Value; + + var n = node.SelectSingleNode(xpath); + + if (n != null) + return n.Value; + } + } + catch (Exception exc) + { + exc.Dump(); + } + + return defaultValue; + } + + /// + /// Safe way to get a localized string value of a xpath navigator item + /// + /// The node + /// For localized values. Xpath scheme: Localized/xpath[@culture = 'language.LanguageCulture'] + /// Optional xpath + /// Optional default value + /// The value + public static string GetString(this XPathNavigator node, Language language, string xpath, string defaultValue = null) + { + return node.GetString( + "Localized/{0}[@culture = '{1}']".FormatWith(xpath.EmptyNull(), language.LanguageCulture.EmptyNull().ToLower()), + defaultValue); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Extensions/XmlNodeExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/XmlNodeExtensions.cs index 0633efa3ef..601c4cef6d 100644 --- a/src/Libraries/SmartStore.Core/Extensions/XmlNodeExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/XmlNodeExtensions.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.Globalization; using System.Xml; namespace SmartStore @@ -16,7 +17,7 @@ public static class XmlNodeExtensions XmlAttribute attr = node.Attributes[attributeName]; if (attr != null) { - return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(attr.InnerText); + return attr.InnerText.Convert(); } } } @@ -27,6 +28,7 @@ public static class XmlNodeExtensions return defaultValue; } + /// Safe way to get inner text of an attribute. public static string GetAttributeText(this XmlNode node, string attributeName) { @@ -34,19 +36,20 @@ public static string GetAttributeText(this XmlNode node, string attributeName) } /// Safe way to get inner text of a node. - public static T GetText(this XmlNode node, string xpath = null, T defaultValue = default(T)) + public static T GetText(this XmlNode node, string xpath = null, T defaultValue = default(T), CultureInfo culture = null) { try { if (node != null) { - if (xpath.IsNullOrEmpty()) - return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(node.InnerText); + if (xpath.IsEmpty()) + return node.InnerText.Convert(); - XmlNode n = node.SelectSingleNode(xpath); - if (n != null) - return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(n.InnerText); - } + var n = node.SelectSingleNode(xpath); + + if (n != null && n.InnerText.HasValue()) + return n.InnerText.Convert(culture); + } } catch (Exception exc) { @@ -55,11 +58,11 @@ public static string GetAttributeText(this XmlNode node, string attributeName) return defaultValue; } + /// Safe way to get inner text of a node. public static string GetText(this XmlNode node, string xpath = null, string defaultValue = default(string)) { return node.GetText(xpath, defaultValue); } - - } // class + } } diff --git a/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs b/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs index 000994fb77..ca4e1c2c71 100644 --- a/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs +++ b/src/Libraries/SmartStore.Core/Extensions/XmlWriterExtensions.cs @@ -1,10 +1,9 @@ using System; -using System.ComponentModel; using System.Xml; +using SmartStore.Core.Domain.Localization; namespace SmartStore { - /// codehint: sm-add public static class XmlWriterExtensions { public static void WriteCData(this XmlWriter writer, string name, string value, string prefix = null, string ns = null) @@ -15,19 +14,40 @@ public static void WriteCData(this XmlWriter writer, string name, string value, writer.WriteStartElement(name); else writer.WriteStartElement(prefix, name, ns); + writer.WriteCData(value.RemoveInvalidXmlChars()); + writer.WriteEndElement(); } } - public static void WriteNode(this XmlWriter writer, string name, Action content) - { - if (name.HasValue() && content != null) - { + + /// + /// Created a simple or CData node element + /// + /// The writer + /// Node name + /// Node value + /// The language. Its culture is always converted to lowercase! + /// Whether to create simple or CData node + public static void Write(this XmlWriter writer, string name, string value, Language language = null, bool asCData = false) + { + if (name.HasValue() && value != null) + { + if (language != null && value.IsEmpty()) + return; // do not create too many empty nodes for empty localized values + writer.WriteStartElement(name); - content(); + + if (language != null) + writer.WriteAttributeString("culture", language.LanguageCulture.EmptyNull().ToLower()); + + if (asCData) + writer.WriteCData(value.RemoveInvalidXmlChars()); + else + writer.WriteString(value.RemoveInvalidXmlChars()); + writer.WriteEndElement(); } } - - } // class + } } diff --git a/src/Libraries/SmartStore.Core/Fakes/FakeController.cs b/src/Libraries/SmartStore.Core/Fakes/FakeController.cs new file mode 100644 index 0000000000..1ff087bb77 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Fakes/FakeController.cs @@ -0,0 +1,8 @@ +using System.Web.Mvc; + +namespace SmartStore.Core.Fakes +{ + public class FakeController : Controller + { + } +} diff --git a/src/Libraries/SmartStore.Core/Financial/Currency.cs b/src/Libraries/SmartStore.Core/Financial/Currency.cs deleted file mode 100644 index a30be2bf3f..0000000000 --- a/src/Libraries/SmartStore.Core/Financial/Currency.cs +++ /dev/null @@ -1,307 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Globalization; - -namespace SmartStore.Financial -{ - - [Serializable] - public struct Currency : IEquatable - { - #region Fields - - internal readonly RegionInfo Region; - public static readonly Currency Empty = new Currency(); - - #endregion - - #region Ctor - - public Currency(RegionInfo region) - : this() - { - Guard.ArgumentNotNull(() => region); - - Region = region; - - this.ThreeLetterISOCode = region.ISOCurrencySymbol; - this.Symbol = region.CurrencySymbol; - this.NativeName = region.CurrencyNativeName; - this.EnglishName = region.CurrencyEnglishName; - } - - public Currency(Currency currency) - : this() - { - this.ThreeLetterISOCode = currency.ThreeLetterISOCode; - this.Symbol = currency.Symbol; - this.NativeName = currency.NativeName; - this.EnglishName = currency.EnglishName; - this.Region = currency.Region; - } - - #endregion - - #region Properties - - /// - /// Gets the ISO standard three-letter name. - /// - public string ThreeLetterISOCode { get; private set; } - - ///// - ///// Gets the integer-based ISO code. - ///// - //public int NumericISOCode { get; private set; } - - /// - /// Gets the prefixing symbol of the currency. - /// - public string Symbol { get; private set; } - - /// - /// Gets the native name of the currency. - /// - public string NativeName { get; private set; } - - /// - /// Gets the english name of the currency. - /// - public string EnglishName { get; private set; } - - // TODO: (?) DecimalDigits, Separator, GroupSeparator, GroupSizes, NegativePatterm, PositivePattern - - #endregion - - #region Methods - - public static Currency Default - { - get - { - return new Currency(RegionInfo.CurrentRegion); - } - } - - public static Currency GetCurrency(string threeLetterISOCode) - { - Guard.ArgumentNotEmpty(threeLetterISOCode, "threeLetterISOCode"); - - if (threeLetterISOCode.Length != 3) - throw new ArgumentException("The currency ISO code must be 3 letters in length.", "threeLetterISOCode"); - - var query = - from r in GetValidRegions() - where r.ISOCurrencySymbol.Equals(threeLetterISOCode, StringComparison.InvariantCultureIgnoreCase) - select r; - var region = query.First(); - - return new Currency(region); - } - - public static Currency GetCurrency(RegionInfo region) - { - return new Currency(region); - } - - public static bool TryGetCurrency(string threeLetterISOCode, out Currency currency) - { - currency = Currency.Empty; - - try - { - currency = Currency.GetCurrency(threeLetterISOCode); - return (currency.ThreeLetterISOCode != null); - } - catch - { - return false; - } - } - - public static IEnumerable AllCurrencies - { - get - { - return from r in GetValidRegions() - select new Currency(r); - } - } - - internal static IEnumerable GetValidRegions() - { - return - from c in - (from c in CultureInfo.GetCultures(CultureTypes.InstalledWin32Cultures) - where !c.IsNeutralCulture && c.LCID != 0x7f - select c) - select new RegionInfo(c.Name); - } - - #endregion - - #region Comparison - - public override int GetHashCode() - { - return this.ThreeLetterISOCode.ToUpperInvariant().GetHashCode(); - } - - public override bool Equals(object obj) - { - if (obj == null) - return false; - - if (obj.GetType() != typeof(Currency)) - return false; - - return this.Equals((Currency)obj); - } - - public bool Equals(Currency other) - { - return (this.ThreeLetterISOCode.Equals(other.ThreeLetterISOCode, StringComparison.InvariantCultureIgnoreCase)); - } - - public override string ToString() - { - return "{0} ({1})".FormatCurrent( - this.Symbol ?? this.ThreeLetterISOCode, - this.NativeName ?? this.EnglishName ?? this.ThreeLetterISOCode); - } - - #endregion - - #region Implicit operators - - public static implicit operator Currency(string threeLetterISOCode) - { - return Currency.GetCurrency(threeLetterISOCode); - } - - public static implicit operator Currency(Money value) - { - return new Currency(value.Currency); - } - - #endregion - - #region Operator overloads - - public static bool operator ==(Currency left, Currency right) - { - return left.Equals(right); - } - - public static bool operator !=(Currency left, Currency right) - { - return !left.Equals(right); - } - - #endregion - - #region Temp/Cargo - - // ISOCode, NumericISOCode, Symbol, EnglishName, DecimalDigits - - //new CurrencyInfo("ARS", 32, "", "Argentine peso", 2, false), - //new CurrencyInfo("AUD", 36, "", "Australian dollar", 2, false), - //new CurrencyInfo("ATS", 40, "", "Austrian schilling", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("BSD", 44, "", "Bahamian dollar", 2, false), - //new CurrencyInfo("BHD", 48, "", "Bahraini dinar", 2, false), - //new CurrencyInfo("BDT", 50, "", "Bangladesh taka", 2, false), - //new CurrencyInfo("BEF", 56, "", "Belgian franc", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("BWP", 72, "", "Botswanan pula", 2, false), - //new CurrencyInfo("BRL", 986, "", "Brazilian real", 2, false), - //new CurrencyInfo("GBP", 826, "£", "British pound", 2, true), - //new CurrencyInfo("BND", 96, "", "Brunei dollar", 2, false), - //new CurrencyInfo("BGN", 975, "", "Bulgarian lev", 2, false), - //new CurrencyInfo("CAD", 124, "", "Canadian dollar", 2, false), - //new CurrencyInfo("CLP", 152, "", "Chilean peso", 2, false), - //new CurrencyInfo("CNY", 156, "", "Chinese yuan renminbi", 2, false), - //new CurrencyInfo("COP", 170, "", "Colombian peso", 2, false), - //new CurrencyInfo("HRK", 191, "", "Croatian kuna", 2, false), - //new CurrencyInfo("CYP", 196, "", "Cyprus pound", 2, false), - //new CurrencyInfo("CZK", 203, "", "Czech koruna", 2, false), - //new CurrencyInfo("DKK", 208, "DK", "Danische Krone", 2, true), - //new CurrencyInfo("DEM", 276, "DM", "Deutsche Mark", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("EGP", 818, "", "Egyptian pound", 2, false), - //new CurrencyInfo("EEK", 233, "", "Estonian kroon", 2, false), - //new CurrencyInfo("EUR", 978, "", "Euro", 2, true), - //new CurrencyInfo("XEU", 954, "", "European Currency Unit", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("FJD", 242, "", "Fiji dollar", 2, false), - //new CurrencyInfo("FIM", 246, "", "Finnish markka", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("FRF", 250, "", "French franc", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("GHC", 288, "", "Ghana cedi", 2, false), - //new CurrencyInfo("GRD", 300, "", "Greek drachma", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("HNL", 340, "", "Honduras lempira", 2, false), - //new CurrencyInfo("HKD", 344, "", "Hong Kong dollar", 2, false), - //new CurrencyInfo("HUF", 348, "", "Hungarian forint", 2, false), - //new CurrencyInfo("ISK", 352, "", "Iceland krona", 2, false), - //new CurrencyInfo("INR", 356, "", "Indian rupee", 2, false), - //new CurrencyInfo("IDR", 360, "", "Indonesian rupiah", 2, false), - //new CurrencyInfo("IRR", 364, "", "Iranian rial", 2, false), - //new CurrencyInfo("IQD", 368, "", "Iraqi dinar", 2, false), - //new CurrencyInfo("IEP", 372, "", "Irish pound", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("ILS", 376, "Shekel", "Israeli shekel", 2, false), - //new CurrencyInfo("ITL", 380, "", "Italian lira", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("JMD", 388, "", "Jamaican dollar", 2, false), - //new CurrencyInfo("JPY", 392, "¥", "Japanese yen", 2, true), - //new CurrencyInfo("KWD", 414, "", "Kuwaiti dinar", 2, false), - //new CurrencyInfo("LVL", 428, "", "Latvian lats", 2, false), - //new CurrencyInfo("LYD", 434, "", "Libyan dinar", 2, false), - //new CurrencyInfo("LTL", 440, "", "Lithuanian litas", 2, false), - //new CurrencyInfo("LUF", 442, "", "Luxembourg franc", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("MYR", 458, "", "Malaysian ringgit", 2, false), - //new CurrencyInfo("MTL", 470, "", "Maltese lira", 2, false), - //new CurrencyInfo("MUR", 480, "", "Mauritius rupee", 2, false), - //new CurrencyInfo("MXP", 484, "", "Mexican peso", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("MXN", 484, "", "Mexican peso", 2, false), - //new CurrencyInfo("MAD", 504, "", "Moroccan dirham", 2, false), - //new CurrencyInfo("MMK", 104, "", "Myanmar kyat", 2, false), - //new CurrencyInfo("NPR", 524, "", "Nepalese rupee", 2, false), - //new CurrencyInfo("ANG", 532, "", "Netherlands Antillian guilder", 2, false), - //new CurrencyInfo("NLG", 528, "", "Netherlands guilder", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("NZD", 554, "", "New Zealand dollar", 2, false), - //new CurrencyInfo("NOK", 578, "NK", "Norwegische Krone", 2, true), - //new CurrencyInfo("OMR", 512, "", "Omani rial", 2, false), - //new CurrencyInfo("PKR", 586, "", "Pakistan rupee", 2, false), - //new CurrencyInfo("PAB", 590, "", "Panamanian balboa", 2, false), - //new CurrencyInfo("PEN", 604, "", "Peruvian sol nuevo", 2, false), - //new CurrencyInfo("PHP", 608, "", "Philippine peso", 2, false), - //new CurrencyInfo("PLN", 985, "Zloty", "Polish zloty", 2, true), - //new CurrencyInfo("PTE", 620, "", "Portuguese escudo", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("QAR", 634, "", "Qatari riyal", 2, false), - //new CurrencyInfo("ROL", 642, "", "Romanian leu", 2, false), - //new CurrencyInfo("RON", 0, "", "Romanian new leu", 2, false), - //new CurrencyInfo("RUB", 643, "Rubel", "Russian ruble", 2, true), - //new CurrencyInfo("SAR", 682, "", "Saudi riyal", 2, false), - //new CurrencyInfo("SGD", 702, "", "Singapore dollar", 2, false), - //new CurrencyInfo("SKK", 703, "", "Slovak koruna", 2, false), - //new CurrencyInfo("SIT", 705, "", "Slovenia tolar", 2, false), - //new CurrencyInfo("ZAR", 710, "Rand", "South African rand", 2, true), - //new CurrencyInfo("ZAL", 991, "", "South African rand (financial)", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("KRW", 410, "", "South Korean won", 2, false), - //new CurrencyInfo("ESP", 724, "", "Spanish peseta", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("XDR", 960, "", "Special Drawing Right", 2, false), - //new CurrencyInfo("LKR", 144, "", "Sri Lankan rupee", 2, false), - //new CurrencyInfo("SEK", 752, "SK", "Schwedische Krone", 2, true), - //new CurrencyInfo("CHF", 756, "Franken", "Swiss franc", 2, true), - //new CurrencyInfo("TWD", 901, "", "Taiwan new dollar", 2, false), - //new CurrencyInfo("THB", 764, "", "Thai baht", 2, false), - //new CurrencyInfo("TTD", 780, "", "Trinidad and Tobago dollar", 2, false), - //new CurrencyInfo("TND", 788, "", "Tunisian dinar", 2, false), - //new CurrencyInfo("TRL", 792, "", "Turkish lira", 2, false), // Gibt es nicht mehr - //new CurrencyInfo("TRY", 949, "", "Turkish new lira", 2, true), - //new CurrencyInfo("AED", 784, "", "U.A.E. dirham", 2, false), - //new CurrencyInfo("USD", 840, "$", "US Dollar", 2, true), - //new CurrencyInfo("VEB", 862, "", "Venezuelan bolivar", 2, false) - - - #endregion - - } - -} diff --git a/src/Libraries/SmartStore.Core/Financial/Money.cs b/src/Libraries/SmartStore.Core/Financial/Money.cs deleted file mode 100644 index 9166aaa4c1..0000000000 --- a/src/Libraries/SmartStore.Core/Financial/Money.cs +++ /dev/null @@ -1,652 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Globalization; - -namespace SmartStore.Financial -{ - - [Serializable] - public struct Money : IComparable, IComparable, IFormattable, IConvertible - { - #region Fields - - public static readonly Money Zero = new Money(0, Currency.Empty); - - #endregion - - #region Ctor - - public Money(decimal amount) - : this(amount, Currency.Default) - { - } - - public Money(decimal amount, string currencyISOCode) - : this(amount, Currency.GetCurrency(currencyISOCode)) - { - } - - //public Money(decimal amount, int currencyCode) - //{ - // // TODO - //} - - public Money(decimal amount, Currency currency) - : this() - { - this.Value = amount; - this.Currency = currency; - } - - public Money(Money money) - : this() - { - this.Value = money.Value; - this.Currency = money.Currency; - } - - #endregion - - #region Properties - - public decimal Value { get; private set; } - - public Currency Currency { get; private set; } - - #endregion - - #region Methods - - public override int GetHashCode() - { - if (this.Value == 0) - return 0; - - return this.Value.GetHashCode() | this.Currency.GetHashCode(); - } - - public override bool Equals(object obj) - { - if (obj == null) - return false; - - if (obj.GetType() != typeof(Money)) - return false; - - Money other = (Money)obj; - - if (other.Value == 0 && this.Value == 0) - return true; - - return other.Value == this.Value && other.Currency == this.Currency; - } - - public int CompareTo(Money other) - { - return ((IComparable)this).CompareTo(other); - } - - int IComparable.CompareTo(object obj) - { - if (obj == null || !(obj is Money)) - return 1; - - Money other = (Money)obj; - - if (this.Value == other.Value) - return 0; - if (this.Value < other.Value) - return -1; - return 1; - } - - private static void GuardCurrenciesAreEqual(Money a, Money b) - { - if (a.Currency != b.Currency) - throw new InvalidOperationException("Cannot operate on money values with different currencies."); - } - - #endregion - - #region ToString - - /// - /// Returns a string-representation of the money value. - /// - /// The string value of the money. - public override string ToString() - { - return this.ToString("C", null, false); - } - - public string ToString(bool useISOCodeAsSymbol) - { - return this.ToString("C", null, useISOCodeAsSymbol); - } - - public string ToString(string format) - { - return this.ToString(format, null, false); - } - - public string ToString(string format, bool useISOCodeAsSymbol) - { - return this.ToString(format, null, useISOCodeAsSymbol); - } - - public string ToString(IFormatProvider provider) - { - return this.ToString("C", provider, false); - } - - public string ToString(IFormatProvider provider, bool useISOCodeAsSymbol) - { - return this.ToString("C", provider, useISOCodeAsSymbol); - } - - public string ToString(string format, IFormatProvider provider) - { - return this.ToString(format, provider, false); - } - - public string ToString(string format, IFormatProvider provider, bool useISOCodeAsSymbol) - { - // REVIEW: was ist mit Digits, Groups, Decimal usw. Müssen wir die nicht von DB oder sonstwo beziehen? - - Guard.ArgumentNotEmpty(format, "format"); - - NumberFormatInfo info = null; - - CultureInfo ci; - - if (provider == null) - provider = CultureInfo.GetCultureInfo(this.Currency.Region.Name).NumberFormat; - - info = provider as NumberFormatInfo; - if (info == null) - { - ci = provider as CultureInfo; - if (ci != null) - info = ci.NumberFormat; - } - - if (info != null) - { - info = (NumberFormatInfo)info.Clone(); - - if (Currency != Currency.Empty) - { - info.CurrencySymbol = useISOCodeAsSymbol ? - Currency.ThreeLetterISOCode : - Currency.Symbol.NullEmpty() ?? Currency.ThreeLetterISOCode; - } - else - { - info.CurrencySymbol = "?"; - } - } - - return Value.ToString(format, info); - } - - #endregion - - #region Implicit/explicit operator overloads - - public static implicit operator Money(byte value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(int value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(long value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(sbyte value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(short value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(uint value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(ulong value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(ushort value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(decimal value) - { - return new Money(value); - } - - public static implicit operator Money(double value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static implicit operator Money(float value) - { - return new Money(System.Convert.ToDecimal(value)); - } - - public static explicit operator byte(Money money) - { - return System.Convert.ToByte(money.Value); - } - - public static explicit operator decimal(Money money) - { - return money.Value; - } - - public static explicit operator double(Money money) - { - return System.Convert.ToDouble(money.Value); - } - - public static explicit operator float(Money money) - { - return System.Convert.ToSingle(money.Value); - } - - public static explicit operator int(Money money) - { - return System.Convert.ToInt32(money.Value); - } - - public static explicit operator long(Money money) - { - return System.Convert.ToInt64(money.Value); - } - - public static explicit operator sbyte(Money money) - { - return System.Convert.ToSByte(money.Value); - } - - public static explicit operator short(Money money) - { - return System.Convert.ToInt16(money.Value); - } - - public static explicit operator ushort(Money money) - { - return System.Convert.ToUInt16(money.Value); - } - - public static explicit operator uint(Money money) - { - return System.Convert.ToUInt32(money.Value); - } - - public static explicit operator ulong(Money money) - { - return System.Convert.ToUInt64(money.Value); - } - - #endregion - - #region Equality/Comparison - - public static bool operator ==(Money a, Money b) - { - return a.Equals(b); - } - - public static bool operator !=(Money a, Money b) - { - return !a.Equals(b); - } - - public static bool operator >(Money a, Money b) - { - if (b.Value == 0 && a.Value > 0) - return true; - - if (b.Value < 0 && a.Value >= 0) - return true; - - if (a == Money.Zero) - return b.Value < 0; - - if (b == Money.Zero) - return a.Value > 0; - - GuardCurrenciesAreEqual(a, b); - - return a.Value > b.Value; - - } - - public static bool operator <(Money a, Money b) - { - if (a.Value == 0 && b.Value > 0) - return true; - - if (a.Value < 0 && b.Value >= 0) - return true; - - if (b == Money.Zero) - return a.Value < 0; - - if (a == Money.Zero) - return b.Value > 0; - - GuardCurrenciesAreEqual(a, b); - - return a.Value < b.Value; - } - - public static bool operator <=(Money a, Money b) - { - if (a.Value < 0 && b.Value >= 0) - return true; - - if (a.Value == 0 && b.Value >= 0) - return true; - - GuardCurrenciesAreEqual(a, b); - - return a.Value < b.Value || a.Equals(b); - - } - - public static bool operator >=(Money a, Money b) - { - if (b.Value < 0 && a.Value >= 0) - return true; - - if (b.Value == 0 && a.Value >= 0) - return true; - - GuardCurrenciesAreEqual(a, b); - - return a.Value > b.Value || a.Equals(b); - - } - - #endregion - - #region Addition - - public static Money operator ++(Money a) - { - a.Value++; - - return a; - } - - public static Money operator +(Money a, Money b) - { - if (a == Money.Zero) - return b; - - if (b == Money.Zero) - return a; - - GuardCurrenciesAreEqual(a, b); - - return new Money(a.Value + b.Value, a.Currency); - } - - #endregion - - #region Subtraction - - public static Money operator --(Money a) - { - a.Value--; - - return a; - } - - public static Money operator -(Money a, Money b) - { - if (a == Money.Zero) - return new Money(0 - b.Value, a.Currency); - - if (b == Money.Zero) - return a; - - GuardCurrenciesAreEqual(a, b); - - return new Money(a.Value - b.Value, a.Currency); - } - - #endregion - - #region Multiplication - - public static Money operator *(Money a, Money b) - { - GuardCurrenciesAreEqual(a, b); - return new Money(a.Value * b.Value, a.Currency); - } - - public static Money operator *(Money a, decimal b) - { - return new Money(a.Value * b, a.Currency); - } - - public static Money operator *(decimal a, Money b) - { - return new Money(b.Value * a, b.Currency); - } - - public static Money operator *(Money a, int b) - { - return new Money(a.Value * b, a.Currency); - } - - public static Money operator *(int a, Money b) - { - return new Money(b.Value * a, b.Currency); - } - - #endregion - - #region Division - - public static Money operator /(Money a, Money b) - { - GuardCurrenciesAreEqual(a, b); - return new Money(a.Value / b.Value, a.Currency); - } - - public static Money operator /(Money a, decimal b) - { - return new Money(a.Value / b, a.Currency); - } - - public static Money operator /(decimal a, Money b) - { - return new Money(a / b.Value, b.Currency); - } - - public static Money operator /(Money a, int b) - { - return new Money(a.Value / b, a.Currency); - } - - public static Money operator /(int a, Money b) - { - return new Money(a / b.Value, b.Currency); - } - - #endregion - - #region Parse - - // [...] TODO - - #endregion - - #region Exchange & Math - - /// - /// Gets the ratio of one money to another. - /// - /// The numerator of the operation. - /// The denominator of the operation. - /// A decimal from 0.0 to 1.0 of the ratio between the two money values. - public static decimal GetRatio(Money numerator, Money denominator) - { - if (numerator == Money.Zero) - return 0; - - if (denominator == Money.Zero) - throw new DivideByZeroException("Attempted to divide by zero!"); - - GuardCurrenciesAreEqual(numerator, denominator); - - return numerator.Value / denominator.Value; - } - - /// - /// Gets the smallest money, given the two values. - /// - /// The first money to compare. - /// The second money to compare. - /// The smallest money value of the arguments. - public static Money Min(Money m1, Money m2) - { - if (m1 == m2) // This will check currency. - return m1; - - return new Money(Math.Min(m1.Value, m2.Value), m1.Currency); - } - - /// - /// Gets the largest money, given the two values. - /// - /// The first money to compare. - /// The second money to compare. - /// The largest money value of the arguments. - public static Money Max(Money m1, Money m2) - { - if (m1 == m2) // This will check currency. - return m1; - - return new Money(Math.Max(m1.Value, m2.Value), m1.Currency); - } - - /// - /// Gets the absolute value of the . - /// - /// The value of money to convert. - /// The money value as an absolute value. - public static Money Abs(Money value) - { - return new Money(Math.Abs(value.Value), value.Currency); - } - - #endregion - - #region IConvertible Members - - public TypeCode GetTypeCode() - { - return TypeCode.Decimal; - } - - public bool ToBoolean(IFormatProvider provider) - { - throw Error.InvalidCast(typeof(Money), typeof(bool)); - } - - public byte ToByte(IFormatProvider provider) - { - return (byte)this.Value; - } - - public char ToChar(IFormatProvider provider) - { - throw Error.InvalidCast(typeof(Money), typeof(bool)); - } - - public DateTime ToDateTime(IFormatProvider provider) - { - throw Error.InvalidCast(typeof(Money), typeof(bool)); - } - - public decimal ToDecimal(IFormatProvider provider) - { - return this.Value; - } - - public double ToDouble(IFormatProvider provider) - { - return (double)this.Value; - } - - public short ToInt16(IFormatProvider provider) - { - return (short)this.Value; - } - - public int ToInt32(IFormatProvider provider) - { - return (int)this.Value; - } - - public long ToInt64(IFormatProvider provider) - { - return (long)this.Value; - } - - public sbyte ToSByte(IFormatProvider provider) - { - return (sbyte)this.Value; - } - - public float ToSingle(IFormatProvider provider) - { - return (float)this.Value; - } - - public object ToType(Type conversionType, IFormatProvider provider) - { - return System.Convert.ChangeType(this.Value, conversionType, provider); - } - - public ushort ToUInt16(IFormatProvider provider) - { - return (ushort)this.Value; - } - - public uint ToUInt32(IFormatProvider provider) - { - return (uint)this.Value; - } - - public ulong ToUInt64(IFormatProvider provider) - { - return (ulong)this.Value; - } - - #endregion - - } - -} diff --git a/src/Libraries/SmartStore.Core/Html/BBCodeHelper.cs b/src/Libraries/SmartStore.Core/Html/BBCodeHelper.cs index ab38aa46fe..dea33ad5f2 100644 --- a/src/Libraries/SmartStore.Core/Html/BBCodeHelper.cs +++ b/src/Libraries/SmartStore.Core/Html/BBCodeHelper.cs @@ -15,7 +15,7 @@ public partial class BBCodeHelper private static readonly Regex regexUnderLine = new Regex(@"\[u\](.+?)\[/u\]", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex regexUrl1 = new Regex(@"\[url\=([^\]]+)\]([^\]]+)\[/url\]", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex regexUrl2 = new Regex(@"\[url\](.+?)\[/url\]", RegexOptions.Compiled | RegexOptions.IgnoreCase); - private static readonly Regex regexQuote = new Regex(@"\[quote\](.+?)\[/quote\]", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private static readonly Regex regexQuote = new Regex(@"\[quote(=.+?)?\](.+?)\[/quote\]", RegexOptions.Compiled | RegexOptions.IgnoreCase); #endregion #region Methods @@ -70,7 +70,30 @@ public static string FormatText(string text, bool replaceBold, bool replaceItali if (replaceQuote) { - text = regexQuote.Replace(text, "
$1
"); + while (regexQuote.IsMatch(text)) + { + text = regexQuote.Replace(text, (m) => + { + var from = m.Groups[1].Value; + var quote = m.Groups[2].Value; + + if (quote.IsEmpty()) + { + return ""; + } + + string result = ""; + if (from.HasValue()) + { + result += "{0}:".FormatCurrent(from.Substring(1)); + } + + result += "
{0}
".FormatCurrent(quote); + + return result; + }); + } + } if (replaceCode) diff --git a/src/Libraries/SmartStore.Core/Html/CodeFormatter/CodeFormatHelper.cs b/src/Libraries/SmartStore.Core/Html/CodeFormatter/CodeFormatHelper.cs index d2de15007c..a840a6ed53 100644 --- a/src/Libraries/SmartStore.Core/Html/CodeFormatter/CodeFormatHelper.cs +++ b/src/Libraries/SmartStore.Core/Html/CodeFormatter/CodeFormatHelper.cs @@ -17,31 +17,6 @@ public partial class CodeFormatHelper #region Utilities - /// - /// Code evaluator method - /// - /// Match - /// Formatted text - private static string CodeEvaluator(Match match) - { - if (!match.Success) - return match.Value; - - var options = new HighlightOptions(); - - options.Language = match.Groups["lang"].Value; - options.Code = match.Groups["code"].Value; - options.DisplayLineNumbers = match.Groups["linenumbers"].Value == "on" ? true : false; - options.Title = match.Groups["title"].Value; - options.AlternateLineNumbers = match.Groups["altlinenumbers"].Value == "on" ? true : false; - - string result = match.Value.Replace(match.Groups["begin"].Value, ""); - result = result.Replace(match.Groups["end"].Value, ""); - result = Highlight(options, result); - return result; - - } - /// /// Code evaluator method /// diff --git a/src/Libraries/SmartStore.Core/Html/HtmlUtils.cs b/src/Libraries/SmartStore.Core/Html/HtmlUtils.cs index 51d36bfc7c..f5f5527993 100644 --- a/src/Libraries/SmartStore.Core/Html/HtmlUtils.cs +++ b/src/Libraries/SmartStore.Core/Html/HtmlUtils.cs @@ -44,9 +44,9 @@ private static string EnsureOnlyAllowedHtml(string text) private static bool IsValidTag(string tag, string tags) { string[] allowedTags = tags.Split(','); - if (tag.IndexOf("javascript") >= 0) return false; - if (tag.IndexOf("vbscript") >= 0) return false; - if (tag.IndexOf("onclick") >= 0) return false; + if (tag.IndexOf("javascript", StringComparison.OrdinalIgnoreCase) >= 0) return false; + if (tag.IndexOf("vbscript", StringComparison.OrdinalIgnoreCase) >= 0) return false; + if (tag.IndexOf("onclick", StringComparison.OrdinalIgnoreCase) >= 0) return false; var endchars = new char[] { ' ', '>', '/', '\t' }; @@ -54,12 +54,7 @@ private static bool IsValidTag(string tag, string tags) if (pos > 0) tag = tag.Substring(0, pos); if (tag[0] == '/') tag = tag.Substring(1); - foreach (string aTag in allowedTags) - { - if (tag == aTag) return true; - } - - return false; + return allowedTags.Any(aTag => tag == aTag); } #endregion @@ -87,12 +82,12 @@ public static string FormatText(string text, bool stripTags, { if (stripTags) { - text = HtmlUtils.StripTags(text); + text = StripTags(text); } if (allowHtml) { - text = HtmlUtils.EnsureOnlyAllowedHtml(text); + text = EnsureOnlyAllowedHtml(text); } else { @@ -101,7 +96,7 @@ public static string FormatText(string text, bool stripTags, if (convertPlainTextToHtml) { - text = HtmlUtils.ConvertPlainTextToHtml(text); + text = ConvertPlainTextToHtml(text); } if (allowBBCode) @@ -208,7 +203,6 @@ public static string ConvertHtmlToPlainText(string text, /// Converts an attribute string spec to a html table putting each new line in a TR and each attr name/value in a TD. ///
/// The text to convert - /// A value indicating whether to encode (HTML) values /// The formatted (html) string public static string ConvertPlainTextToTable(string text, string tableCssClass = null) { diff --git a/src/Libraries/SmartStore.Core/Html/ResolveLinksHelper.cs b/src/Libraries/SmartStore.Core/Html/ResolveLinksHelper.cs index d0e72938fe..c58f9540ba 100644 --- a/src/Libraries/SmartStore.Core/Html/ResolveLinksHelper.cs +++ b/src/Libraries/SmartStore.Core/Html/ResolveLinksHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.RegularExpressions; @@ -23,6 +24,8 @@ public partial class ResolveLinksHelper /// /// Shortens any absolute URL to a specified maximum length /// + [SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")] + [SuppressMessage("ReSharper", "StringLastIndexOfIsCultureSpecific.1")] private static string ShortenUrl(string url, int max) { if (url.Length <= max) diff --git a/src/Libraries/SmartStore.Core/IActivatable.cs b/src/Libraries/SmartStore.Core/IActivatable.cs new file mode 100644 index 0000000000..b42cb554fc --- /dev/null +++ b/src/Libraries/SmartStore.Core/IActivatable.cs @@ -0,0 +1,9 @@ +using System; + +namespace SmartStore.Core +{ + public interface IActivatable + { + bool IsActive { get; } + } +} diff --git a/src/Libraries/SmartStore.Core/IHideObjectMembers.cs b/src/Libraries/SmartStore.Core/IHideObjectMembers.cs index 7228c572b6..97947ea881 100644 --- a/src/Libraries/SmartStore.Core/IHideObjectMembers.cs +++ b/src/Libraries/SmartStore.Core/IHideObjectMembers.cs @@ -1,13 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; namespace SmartStore { - [EditorBrowsable(EditorBrowsableState.Never)] public interface IHideObjectMembers { diff --git a/src/Libraries/SmartStore.Core/IO/Media/FileSystemStorageProvider.cs b/src/Libraries/SmartStore.Core/IO/Media/FileSystemStorageProvider.cs index 8a047c9110..636c7fbee5 100644 --- a/src/Libraries/SmartStore.Core/IO/Media/FileSystemStorageProvider.cs +++ b/src/Libraries/SmartStore.Core/IO/Media/FileSystemStorageProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Web.Hosting; @@ -12,9 +13,10 @@ public class FileSystemStorageProvider : IStorageProvider private readonly string _storagePath; private readonly string _publicPath; - public FileSystemStorageProvider(FileSystemSettings settings) + [SuppressMessage("ReSharper", "PossibleNullReferenceException")] + public FileSystemStorageProvider(FileSystemSettings settings) { - string mediaPath = CommonHelper.MapPath("~/Media/", false); + var mediaPath = CommonHelper.MapPath("~/Media/", false); _storagePath = Path.Combine(mediaPath, settings.DirectoryName); var appPath = ""; @@ -29,11 +31,13 @@ public FileSystemStorageProvider(FileSystemSettings settings) _publicPath = appPath + "Media/" + settings.DirectoryName + "/"; } - string Map(string path) { + private string Map(string path) + { return string.IsNullOrEmpty(path) ? _storagePath : Path.Combine(_storagePath, path); } - static string Fix(string path) { + static string Fix(string path) + { return string.IsNullOrEmpty(path) ? "" : Path.DirectorySeparatorChar != '/' diff --git a/src/Libraries/SmartStore.Core/IO/Media/IStorageProvider.cs b/src/Libraries/SmartStore.Core/IO/Media/IStorageProvider.cs index a43de9e8d6..38a8958457 100644 --- a/src/Libraries/SmartStore.Core/IO/Media/IStorageProvider.cs +++ b/src/Libraries/SmartStore.Core/IO/Media/IStorageProvider.cs @@ -1,4 +1,4 @@ - +using System; using System.Collections.Generic; namespace SmartStore.Core.IO.Media @@ -48,12 +48,12 @@ public interface IStorageProvider /// If the folder doesn't exist. void DeleteFolder(string path); - /// - /// Renames a folder in the storage provider. - /// - /// The relative path to the folder to be renamed. - /// The relative path to the new folder. - void RenameFolder(string path, string newPath); + /// + /// Renames a folder in the storage provider. + /// + /// The relative path to the folder to be renamed. + /// The relative path to the new folder. + void RenameFolder(string path, string newPath); /// /// Deletes a file in the storage provider. @@ -62,12 +62,12 @@ public interface IStorageProvider /// If the file doesn't exist. void DeleteFile(string path); - /// - /// Renames a file in the storage provider. - /// - /// The relative path to the file to be renamed. - /// The relative path to the new file. - void RenameFile(string path, string newPath); + /// + /// Renames a file in the storage provider. + /// + /// The relative path to the file to be renamed. + /// The relative path to the new file. + void RenameFile(string path, string newPath); /// /// Creates a file in the storage provider. diff --git a/src/Libraries/SmartStore.Core/IO/MimeTypes.cs b/src/Libraries/SmartStore.Core/IO/MimeTypes.cs index bb2aee7deb..e44c81b0a2 100644 --- a/src/Libraries/SmartStore.Core/IO/MimeTypes.cs +++ b/src/Libraries/SmartStore.Core/IO/MimeTypes.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Security; using System.Text; @@ -11,6 +13,7 @@ namespace SmartStore.Core.IO public static class MimeTypes { + private static readonly ConcurrentDictionary _mimeMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); public static string MapNameToMimeType(string fileNameOrExtension) { @@ -18,44 +21,47 @@ public static string MapNameToMimeType(string fileNameOrExtension) } /// - /// Returns the (dotless) extensions for a mime type + /// Returns the (dotless) extension for a mime type /// /// The mime type /// The corresponding file extension (without dot) + [SuppressMessage("ReSharper", "RedundantAssignment")] public static string MapMimeTypeToExtension(string mimeType) { if (mimeType.IsEmpty()) return null; - string result = null; + return _mimeMap.GetOrAdd(mimeType, k => { + string result; - try - { - using (var key = Registry.ClassesRoot.OpenSubKey(@"MIME\Database\Content Type\" + mimeType, false)) + try { - object value = key != null ? key.GetValue("Extension", null) : null; - result = value != null ? value.ToString().Trim('.') : null; + using (var key = Registry.ClassesRoot.OpenSubKey(@"MIME\Database\Content Type\" + mimeType, false)) + { + object value = key != null ? key.GetValue("Extension", null) : null; + result = value != null ? value.ToString().Trim('.') : null; + } } - } - catch (SecurityException) - { - string[] parts = mimeType.Split('/'); - result = parts[parts.Length - 1]; - switch (result) - { - case "pjpeg": - result = "jpg"; - break; - case "x-png": - result = "png"; - break; - case "x-icon": - result = "ico"; - break; - } - } - - return result; + catch + { + string[] parts = mimeType.Split('/'); + result = parts[parts.Length - 1]; + switch (result) + { + case "pjpeg": + result = "jpg"; + break; + case "x-png": + result = "png"; + break; + case "x-icon": + result = "ico"; + break; + } + } + + return result; + }); } } diff --git a/src/Libraries/SmartStore.Core/IO/VirtualPath/DefaultVirtualPathProvider.cs b/src/Libraries/SmartStore.Core/IO/VirtualPath/DefaultVirtualPathProvider.cs index 5e2164b149..102649e1b2 100644 --- a/src/Libraries/SmartStore.Core/IO/VirtualPath/DefaultVirtualPathProvider.cs +++ b/src/Libraries/SmartStore.Core/IO/VirtualPath/DefaultVirtualPathProvider.cs @@ -92,7 +92,7 @@ public bool IsMalformedVirtualPath(string virtualPath) if (string.IsNullOrEmpty(virtualPath)) return true; - if (virtualPath.IndexOf("..") >= 0) + if (virtualPath.IndexOf("..", StringComparison.OrdinalIgnoreCase) >= 0) { virtualPath = virtualPath.Replace(Path.DirectorySeparatorChar, '/'); string rootPrefix = virtualPath.StartsWith("~/") ? "~/" : virtualPath.StartsWith("/") ? "/" : ""; diff --git a/src/Libraries/SmartStore.Core/IPageable.cs b/src/Libraries/SmartStore.Core/IPageable.cs index 4751bc51c0..60d6b3f63f 100644 --- a/src/Libraries/SmartStore.Core/IPageable.cs +++ b/src/Libraries/SmartStore.Core/IPageable.cs @@ -3,8 +3,6 @@ using System.Collections; using System.Collections.Generic; -// codehint: sm-add (new file) - namespace SmartStore.Core { diff --git a/src/Libraries/SmartStore.Core/IStoreContext.cs b/src/Libraries/SmartStore.Core/IStoreContext.cs index e4429b6686..2ab8bfede9 100644 --- a/src/Libraries/SmartStore.Core/IStoreContext.cs +++ b/src/Libraries/SmartStore.Core/IStoreContext.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Domain.Stores; namespace SmartStore.Core { @@ -12,6 +7,30 @@ namespace SmartStore.Core /// public interface IStoreContext { + /// + /// Sets a store override to be used for the current request + /// + /// The store override or null to remove the override + void SetRequestStore(int? storeId); + + /// + /// Sets a store override to be used for the current user's session (e.g. for preview mode) + /// + /// The store override or null to remove the override + void SetPreviewStore(int? storeId); + + /// + /// Gets the store override for the current request + /// + /// The store override or null + int? GetRequestStore(); + + /// + /// Gets the store override for the current session + /// + /// The store override or null + int? GetPreviewStore(); + /// /// Gets or sets the current store /// @@ -20,7 +39,6 @@ public interface IStoreContext /// /// IsSingleStoreMode ? 0 : CurrentStore.Id /// - /// codehint: sm-add int CurrentStoreIdIfMultiStoreMode { get; } } } diff --git a/src/Libraries/SmartStore.Core/ITransient.cs b/src/Libraries/SmartStore.Core/ITransient.cs new file mode 100644 index 0000000000..761dcee833 --- /dev/null +++ b/src/Libraries/SmartStore.Core/ITransient.cs @@ -0,0 +1,9 @@ +using System; + +namespace SmartStore +{ + public interface ITransient + { + bool IsTransient { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/IWebHelper.cs b/src/Libraries/SmartStore.Core/IWebHelper.cs index d5b4e22a4a..2d089bd64d 100644 --- a/src/Libraries/SmartStore.Core/IWebHelper.cs +++ b/src/Libraries/SmartStore.Core/IWebHelper.cs @@ -13,11 +13,21 @@ public partial interface IWebHelper /// URL referrer string GetUrlReferrer(); - /// - /// Get context IP address - /// - /// URL referrer - string GetCurrentIpAddress(); + /// + /// Gets a unique client identifier + /// + /// A unique identifier + /// + /// The client identifier is a hashed combination of client ip address and user agent. + /// This method returns null if IP or user agent (or both) cannot be determined. + /// + string GetClientIdent(); + + /// + /// Get context IP address + /// + /// URL referrer + string GetCurrentIpAddress(); /// /// Gets this page name @@ -116,24 +126,7 @@ public partial interface IWebHelper /// /// A value indicating whether /// Redirect URL; empty string if you want to redirect to the current page URL - void RestartAppDomain(bool makeRedirect = false, string redirectUrl = ""); - - /// - /// Get a value indicating whether the request is made by search engine (web crawler) - /// - /// HTTP context - /// Result - bool IsSearchEngine(HttpContextBase context); - - /// - /// Gets a value that indicates whether the client is being redirected to a new location - /// - bool IsRequestBeingRedirected { get; } - - /// - /// Gets or sets a value that indicates whether the client is being redirected to a new location using POST - /// - bool IsPostBeingDone { get; set; } - + /// Usually true after a new plugin was installed (nukes the MVC cache) + void RestartAppDomain(bool makeRedirect = false, string redirectUrl = "", bool aggressive = false); } } diff --git a/src/Libraries/SmartStore.Core/IWorkContext.cs b/src/Libraries/SmartStore.Core/IWorkContext.cs index 942e983e0c..e137ac98bd 100644 --- a/src/Libraries/SmartStore.Core/IWorkContext.cs +++ b/src/Libraries/SmartStore.Core/IWorkContext.cs @@ -56,13 +56,8 @@ public interface IWorkContext TaxDisplayType GetTaxDisplayTypeFor(Customer customer, int storeId); /// - /// Get or set value indicating whether we're in admin area + /// Gets or sets a value indicating whether we're in admin area /// - bool IsAdmin { get; set; } - - ///// - ///// Get or set a value indicating whether we're in the public shop - ///// - //bool IsPublic { get; set; } - } + bool IsAdmin { get; set; } + } } diff --git a/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs b/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs index d22729f32e..79a7a41f22 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/AppDomainTypeFinder.cs @@ -19,24 +19,21 @@ public class AppDomainTypeFinder : ITypeFinder { #region Private Fields - private string _assemblySkipLoadingPattern = @"^System|^mscorlib|^Microsoft|^CppCodeProvider|^VJSharpCodeProvider|^WebDev|^Nuget|^Castle|^Iesi|^log4net|^Autofac|^AutoMapper|^dotless|^EntityFramework|^EPPlus|^Fasterflect|^FiftyOne|^nunit|^TestDriven|^MbUnit|^Rhino|^QuickGraph|^TestFu|^Telerik|^Antlr3|^Recaptcha|^FluentValidation|^ImageResizer|^itextsharp|^MiniProfiler|^Newtonsoft|^Pandora|^WebGrease|^Noesis|^DotNetOpenAuth|^Facebook|^LinqToTwitter|^PerceptiveMCAPI|^CookComputing|^GCheckout|^Mono\.Math|^Org\.Mentalis|^App_Web|^BundleTransformer|^ClearScript|^JavaScriptEngineSwitcher|^Glimpse|^Ionic|^App_GlobalResources|^AjaxMin"; + private static object s_lock = new object(); + + private string _assemblySkipLoadingPattern = @"^System|^mscorlib|^Microsoft|^CppCodeProvider|^VJSharpCodeProvider|^WebDev|^Nuget|^Castle|^Iesi|^log4net|^Autofac|^AutoMapper|^EntityFramework|^EPPlus|^nunit|^TestDriven|^MbUnit|^Rhino|^QuickGraph|^TestFu|^Telerik|^Antlr3|^Recaptcha|^FluentValidation|^ImageResizer|^itextsharp|^MiniProfiler|^Newtonsoft|^Pandora|^WebGrease|^Noesis|^DotNetOpenAuth|^Facebook|^LinqToTwitter|^PerceptiveMCAPI|^CookComputing|^GCheckout|^Mono\.Math|^Org\.Mentalis|^App_Web|^BundleTransformer|^ClearScript|^JavaScriptEngineSwitcher|^MsieJavaScriptEngine|^Glimpse|^Ionic|^App_GlobalResources|^AjaxMin|^MaxMind|^NReco|^OffAmazonPayments|^UAParser"; + private string _assemblyRestrictToLoadingPattern = ".*"; + private readonly IDictionary _assemblyMatchTable = new Dictionary(); + + private Regex _assemblySkipLoadingRegex; + private Regex _assemblyRestrictToLoadingRegex; private bool _ignoreReflectionErrors = true; private bool _loadAppDomainAssemblies = true; - private string _assemblyRestrictToLoadingPattern = ".*"; private IList _customAssemblyNames = new List(); #endregion - #region Constructors - - /// Creates a new instance of the AppDomainTypeFinder. - public AppDomainTypeFinder() - { - } - - #endregion - #region Properties /// The app domain to look for types in. @@ -45,43 +42,53 @@ public virtual AppDomain App get { return AppDomain.CurrentDomain; } } - /// Gets or sets wether SmartStore should iterate assemblies in the app domain when loading SmartStore types. Loading patterns are applied when loading these assemblies. + /// + /// Gets or sets wether SmartStore should iterate assemblies in the app domain when loading SmartStore types. Loading patterns are applied when loading these assemblies. + /// public bool LoadAppDomainAssemblies { get { return _loadAppDomainAssemblies; } set { _loadAppDomainAssemblies = value; } } - /// Gets or sets assemblies loaded at startup in addition to those loaded in the AppDomain. + /// + /// Gets or sets assemblies loaded at startup in addition to those loaded in the AppDomain. + /// public IList CustomAssemblyNames { get { return _customAssemblyNames; } set { _customAssemblyNames = value; } } - /// Gets the pattern for dlls that we know don't need to be investigated. + /// + /// Gets the pattern for dlls that we know don't need to be investigated. + /// public string AssemblySkipLoadingPattern { get { return _assemblySkipLoadingPattern; } - set { _assemblySkipLoadingPattern = value; } + set + { + _assemblySkipLoadingPattern = value; + _assemblySkipLoadingRegex = null; + _assemblyMatchTable.Clear(); + } } - /// Gets or sets the pattern for dll that will be investigated. For ease of use this defaults to match all but to increase performance you might want to configure a pattern that includes assemblies and your own. - /// If you change this so that SmartStore assemblies arn't investigated (e.g. by not including something like "^SmartStore|..." you may break core functionality. + /// + /// Gets or sets the pattern for dll that will be investigated. For ease of use this defaults to match all but to increase performance you might want to configure a pattern that includes assemblies and your own. + /// + /// + /// If you change this so that SmartStore assemblies aren't investigated (e.g. by not including something like "^SmartStore|..." you may break core functionality. + /// public string AssemblyRestrictToLoadingPattern { get { return _assemblyRestrictToLoadingPattern; } - set { _assemblyRestrictToLoadingPattern = value; } - } - - #endregion - - #region Internal Attributed Assembly class - - private class AttributedAssembly - { - internal Assembly Assembly { get; set; } - internal Type PluginAttributeType { get; set; } + set + { + _assemblyRestrictToLoadingPattern = value; + _assemblyRestrictToLoadingRegex = null; + _assemblyMatchTable.Clear(); + } } #endregion @@ -103,7 +110,7 @@ public IEnumerable FindClassesOfType(Type assignTypeFrom, IEnumerable FindClassesOfType(Type assignTypeFrom, IEnumerable - /// Caches attributed assembly information so they don't have to be re-read - /// - private readonly List _attributedAssemblies = new List(); - - /// - /// Caches the assembly attributes that have been searched for - /// - private readonly List _assemblyAttributesSearched = new List(); - - /// Gets the assemblies related to the current implementation. + /// Gets the assemblies related to the current implementation. + /// /// Indicates whether uninstalled plugin's assemblies should be filtered out /// A list of assemblies that should be loaded by the SmartStore factory. public virtual IList GetAssemblies(bool ignoreInactivePlugins = false) { - var addedAssemblyNames = new List(); + var addedAssemblyNames = new HashSet(); var assemblies = new List(); if (LoadAppDomainAssemblies) @@ -184,12 +183,15 @@ public virtual IList GetAssemblies(bool ignoreInactivePlugins = false) #endregion - /// Iterates all assemblies in the AppDomain and if it's name matches the configured patterns add it to our list. + /// + /// Iterates all assemblies in the AppDomain and if it's name matches the configured patterns add it to our list. + /// /// /// - private void AddAssembliesInAppDomain(List addedAssemblyNames, List assemblies) + private void AddAssembliesInAppDomain(HashSet addedAssemblyNames, List assemblies) { - foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) + var curDomainAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in curDomainAssemblies) { if (Matches(assembly.FullName)) { @@ -202,8 +204,10 @@ private void AddAssembliesInAppDomain(List addedAssemblyNames, ListAdds specificly configured assemblies. - protected virtual void AddCustomAssemblies(List addedAssemblyNames, List assemblies) + /// + /// Adds specificly configured assemblies. + /// + protected virtual void AddCustomAssemblies(HashSet addedAssemblyNames, List assemblies) { foreach (string assemblyName in CustomAssemblyNames) { @@ -216,25 +220,68 @@ protected virtual void AddCustomAssemblies(List addedAssemblyNames, List } } - /// Check if a dll is one of the shipped dlls that we know don't need to be investigated. + /// + /// Check if a dll is one of the shipped dlls that we know don't need to be investigated. + /// /// The name of the assembly to check. /// True if the assembly should be loaded into SmartStore. public virtual bool Matches(string assemblyFullName) { - return !Matches(assemblyFullName, AssemblySkipLoadingPattern) - && Matches(assemblyFullName, AssemblyRestrictToLoadingPattern); - } + if (_assemblyMatchTable.ContainsKey(assemblyFullName)) + { + return _assemblyMatchTable[assemblyFullName]; + } + + if (_assemblySkipLoadingRegex == null) + { + lock (s_lock) + { + if (_assemblySkipLoadingRegex == null) + { + _assemblySkipLoadingRegex = new Regex(_assemblySkipLoadingPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline); + } + } + } - /// Check if a dll is one of the shipped dlls that we know don't need to be investigated. - /// The assembly name to match. - /// The regular expression pattern to match against the assembly name. - /// True if the pattern matches the assembly name. - protected virtual bool Matches(string assemblyFullName, string pattern) - { - return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); + if (_assemblySkipLoadingRegex.IsMatch(assemblyFullName)) + { + _assemblyMatchTable[assemblyFullName] = false; + return false; + } + + if (_assemblyRestrictToLoadingRegex == null) + { + lock (s_lock) + { + if (_assemblyRestrictToLoadingRegex == null) + { + _assemblyRestrictToLoadingRegex = new Regex(_assemblyRestrictToLoadingPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline); + } + } + } + + var matches = _assemblyRestrictToLoadingRegex.IsMatch(assemblyFullName); + _assemblyMatchTable[assemblyFullName] = matches; + + return matches; + + //return !Matches(assemblyFullName, AssemblySkipLoadingPattern) && Matches(assemblyFullName, AssemblyRestrictToLoadingPattern); } - /// Makes sure matching assemblies in the supplied folder are loaded in the app domain. + ///// + ///// Check if a dll is one of the shipped dlls that we know don't need to be investigated. + ///// + ///// The assembly name to match. + ///// The regular expression pattern to match against the assembly name. + ///// True if the pattern matches the assembly name. + //protected virtual bool Matches(string assemblyFullName, string pattern) + //{ + // return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline); + //} + + /// + /// Makes sure matching assemblies in the supplied folder are loaded in the app domain. + /// /// The physical path to a directory containing dlls to load in the app domain. protected virtual void LoadMatchingAssemblies(string directoryPath) { diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs index 8073e0afdc..a53cc21140 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/ComparableObject.cs @@ -3,38 +3,22 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.ComponentModel; -using Fasterflect; +using SmartStore.Utilities; +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using SmartStore.ComponentModel; namespace SmartStore { - /// /// Provides a standard base class for facilitating sophisticated comparison of objects. /// [Serializable] public abstract class ComparableObject { - /// - /// To help ensure hashcode uniqueness, a carefully selected random number multiplier - /// is used within the calculation. Goodrich and Tamassia's Data Structures and - /// Algorithms in Java asserts that 31, 33, 37, 39 and 41 will produce the fewest number - /// of collissions. See http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ - /// for more information. - /// - protected const int HashMultiplier = 31; + private readonly HashSet _extraSignatureProperties = new HashSet(StringComparer.OrdinalIgnoreCase); - private readonly List _extraSignatureProperties = new List(); - - /// - /// This static member caches the domain signature properties to avoid looking them up for - /// each instance of the same type. - /// - /// A description of the ThreadStatic attribute may be found at - /// http://www.dotnetjunkies.com/WebLog/chris.taylor/archive/2005/08/18/132026.aspx - /// - [ThreadStatic] - private static IDictionary> s_signatureProperties; + private static readonly ConcurrentDictionary _signaturePropertyNames = new ConcurrentDictionary(); public override bool Equals(object obj) { @@ -53,28 +37,32 @@ public override bool Equals(object obj) /// if at all, in an object's lifetime; it's important that properties are carefully /// selected which truly represent the signature of an object. /// + [SuppressMessage("ReSharper", "BaseObjectGetHashCodeCallInGetHashCode")] + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] public override int GetHashCode() { unchecked { - var signatureProperties = GetSignatureProperties(); + var signatureProperties = GetSignatureProperties().ToArray(); Type t = this.GetType(); - // It's possible for two objects to return the same hash code based on - // identically valued properties, even if they're of two different types, - // so we include the object's type in the hash calculation - int hashCode = t.GetHashCode(); + var combiner = HashCodeCombiner.Start(); - foreach (var pi in signatureProperties) + // It's possible for two objects to return the same hash code based on + // identically valued properties, even if they're of two different types, + // so we include the object's type in the hash calculation + combiner.Add(t.GetHashCode()); + + foreach (var prop in signatureProperties) { - object value = this.GetPropertyValue(pi.Name); // pi.GetValue(this); + var value = prop.GetValue(this); if (value != null) - hashCode = (hashCode * HashMultiplier) ^ value.GetHashCode(); + combiner.Add(value.GetHashCode()); } - if (signatureProperties.Any()) - return hashCode; + if (signatureProperties.Length > 0) + return combiner.CombinedHash; // If no properties were flagged as being part of the signature of the object, // then simply return the hashcode of the base object as the hashcode. @@ -102,8 +90,8 @@ protected virtual bool HasSameSignatureAs(ComparableObject compareTo) foreach (var pi in signatureProperties) { - object thisValue = this.GetPropertyValue(pi.Name); - object thatValue = compareTo.GetPropertyValue(pi.Name); + object thisValue = pi.GetValue(this); + object thatValue = pi.GetValue(compareTo); if (thisValue == null && thatValue == null) continue; @@ -123,56 +111,46 @@ protected virtual bool HasSameSignatureAs(ComparableObject compareTo) /// /// - public IEnumerable GetSignatureProperties() + public IEnumerable GetSignatureProperties() { - IEnumerable properties; - - // Init the signaturePropertiesDictionary here due to reasons described at - // http://blogs.msdn.com/jfoscoding/archive/2006/07/18/670497.aspx - if (s_signatureProperties == null) - s_signatureProperties = new Dictionary>(); - - var t = GetType(); - - if (s_signatureProperties.TryGetValue(t, out properties)) - return properties; - - return (s_signatureProperties[t] = GetSignaturePropertiesCore()); + var type = GetType(); + var propertyNames = GetSignaturePropertyNamesCore(); + + foreach (var name in propertyNames) + { + var fastProperty = FastProperty.GetProperty(type, name); + if (fastProperty != null) + { + yield return fastProperty; + } + } } /// /// Enforces the template method pattern to have child objects determine which specific /// properties should and should not be included in the object signature comparison. /// - protected virtual IEnumerable GetSignaturePropertiesCore() + protected virtual string[] GetSignaturePropertyNamesCore() { - Type t = this.GetType(); - //var properties = TypeDescriptor.GetProvider(t).GetTypeDescriptor(t) - // .GetPropertiesWith(); + Type type = this.GetType(); + string[] names; - //if (_extraSignatureProperties.Count > 0) - //{ - // properties = properties.Union(_extraSignatureProperties); - //} + if (!_signaturePropertyNames.TryGetValue(type, out names)) + { + names = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => Attribute.IsDefined(p, typeof(ObjectSignatureAttribute), true)) + .Select(p => p.Name) + .ToArray(); - //return new PropertyDescriptorCollection(properties.ToArray(), true); + _signaturePropertyNames.TryAdd(type, names); + } - var properties = t.GetProperties() - .Where(p => Attribute.IsDefined(p, typeof(ObjectSignatureAttribute), true)); + if (_extraSignatureProperties.Count == 0) + { + return names; + } - return properties.Union(_extraSignatureProperties).ToList(); - } - - /// - /// Adds an extra property to the type specific signature properties list. - /// - /// The property to add. - /// Both lists are unioned, so - /// that no duplicates can occur within the global descriptor collection. - protected void RegisterSignatureProperty(PropertyInfo propertyInfo) - { - Guard.ArgumentNotNull(() => propertyInfo); - _extraSignatureProperties.Add(propertyInfo); + return names.Union(_extraSignatureProperties).ToArray(); } /// @@ -185,13 +163,7 @@ protected void RegisterSignatureProperty(string propertyName) { Guard.ArgumentNotEmpty(() => propertyName); - Type t = GetType(); - - var pi = t.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); - if (pi == null) - throw Error.Argument("propertyName", "Could not find property '{0}' on type '{1}'.", propertyName, t); - - RegisterSignatureProperty(pi); + _extraSignatureProperties.Add(propertyName); } } @@ -200,6 +172,7 @@ protected void RegisterSignatureProperty(string propertyName) /// /// Generic version of . /// + [Serializable] public abstract class ComparableObject : ComparableObject, IEquatable { @@ -213,7 +186,7 @@ protected void RegisterSignatureProperty(Expression> expression) { Guard.ArgumentNotNull(() => expression); - base.RegisterSignatureProperty(expression.ExtractPropertyInfo()); + base.RegisterSignatureProperty(expression.ExtractPropertyInfo().Name); } public virtual bool Equals(T other) diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ContextState.cs b/src/Libraries/SmartStore.Core/Infrastructure/ContextState.cs new file mode 100644 index 0000000000..996493f80d --- /dev/null +++ b/src/Libraries/SmartStore.Core/Infrastructure/ContextState.cs @@ -0,0 +1,81 @@ +using System; +using System.Runtime.Remoting.Messaging; +using System.Threading; +using System.Web; + +namespace SmartStore.Core.Infrastructure +{ + /// + /// Holds some state for the current HttpContext or thread + /// + /// The type of data to store + public class ContextState where T : class + { + private readonly string _name; + private readonly Func _defaultValue; + + public ContextState(string name) + { + _name = name; + } + + public ContextState(string name, Func defaultValue) + { + _name = name; + _defaultValue = defaultValue; + } + + public T GetState() + { + if (HttpContext.Current == null) + { + var data = CallContext.GetData(_name); + + if (data == null) + { + if (_defaultValue != null) + { + CallContext.SetData(_name, data = _defaultValue()); + return data as T; + } + } + + return data as T; + } + + if (HttpContext.Current.Items[_name] == null) + { + HttpContext.Current.Items[_name] = _defaultValue == null ? null : _defaultValue(); + } + + return HttpContext.Current.Items[_name] as T; + } + + public void SetState(T state) + { + if (HttpContext.Current == null) + { + CallContext.SetData(_name, state); + } + else + { + HttpContext.Current.Items[_name] = state; + } + } + + public void RemoveState() + { + if (HttpContext.Current == null) + { + CallContext.FreeNamedDataSlot(_name); + } + else + { + if (HttpContext.Current.Items.Contains(_name)) + { + HttpContext.Current.Items.Remove(_name); + } + } + } + } +} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DateRange.cs b/src/Libraries/SmartStore.Core/Infrastructure/DateRange.cs deleted file mode 100644 index bb331223be..0000000000 --- a/src/Libraries/SmartStore.Core/Infrastructure/DateRange.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace SmartStore -{ - - public class DateRange : ValueObject, ICloneable - { - - public DateRange() - { - } - - public DateRange(DateTime to) - : this(default(DateTime), to) - { - } - - public DateRange(DateTime from, DateTime to) - { - DateFrom = from; - DateTo = to; - } - - [ObjectSignature] - public DateTime? DateFrom { get; set; } - - [ObjectSignature] - public DateTime? DateTo { get; set; } - - public bool IsDefined - { - get { return DateFrom.HasValue || DateTo.HasValue; } - } - - //public override int GetHashCode() - //{ - // return SystemUtil.GetHashCode(this.DateFrom, this.DateTo); - //} - - //public override bool Equals(object obj) - //{ - // if (ReferenceEquals(null, obj)) return false; - // if (ReferenceEquals(this, obj)) return true; - - // DateRange other = (DateRange)obj; - // return this.DateFrom.Equals(other.DateFrom) && this.DateTo.Equals(other.DateTo); - //} - - #region ICloneable Members - - public DateRange Clone() - { - return new DateRange() - { - DateFrom = this.DateFrom, - DateTo = this.DateTo - }; - } - - object ICloneable.Clone() - { - return this.Clone(); - } - - #endregion - - } - -} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/AutofacLifetimeScopeProvider.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/AutofacLifetimeScopeProvider.cs deleted file mode 100644 index b307f82e78..0000000000 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/AutofacLifetimeScopeProvider.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Web; -using Autofac; -using Autofac.Integration.Mvc; - -namespace SmartStore.Core.Infrastructure.DependencyManagement -{ - public class AutofacLifetimeScopeProvider : ILifetimeScopeProvider - { - private readonly ILifetimeScope _container; - internal static readonly object HttpRequestTag = "AutofacWebRequest"; - - public AutofacLifetimeScopeProvider(ILifetimeScope container) - { - Guard.ArgumentNotNull(() => container); - - this._container = container; - AutofacRequestLifetimeHttpModule.SetLifetimeScopeProvider(this); - - } - - public ILifetimeScope ApplicationContainer - { - get { return _container; } - } - - public void EndLifetimeScope() - { - try - { - ILifetimeScope lifetimeScope = LifetimeScope; - if (lifetimeScope != null) - { - lifetimeScope.Dispose(); - HttpContext.Current.Items.Remove(typeof(ILifetimeScope)); - } - } - catch { } - } - - public ILifetimeScope GetLifetimeScope(Action configurationAction) - { - //little hack here to get dependencies when HttpContext is not available - if (HttpContext.Current != null) - { - return LifetimeScope ?? (LifetimeScope = GetLifetimeScopeCore(configurationAction)); - } - else - { - return GetLifetimeScopeCore(configurationAction); - } - } - - protected virtual ILifetimeScope GetLifetimeScopeCore(Action configurationAction) - { - return (configurationAction == null) - ? _container.BeginLifetimeScope(HttpRequestTag) - : _container.BeginLifetimeScope(HttpRequestTag, configurationAction); - } - - private static ILifetimeScope LifetimeScope - { - get - { - return (ILifetimeScope)HttpContext.Current.Items[typeof(ILifetimeScope)]; - } - set - { - HttpContext.Current.Items[typeof(ILifetimeScope)] = value; - } - } - - - } -} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/AutofacRequestLifetimeHttpModule.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/AutofacRequestLifetimeHttpModule.cs index 9f84b3d57b..a3fa432497 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/AutofacRequestLifetimeHttpModule.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/AutofacRequestLifetimeHttpModule.cs @@ -1,7 +1,5 @@ using System; -using System.Threading; using System.Web; -using Autofac; using Autofac.Integration.Mvc; namespace SmartStore.Core.Infrastructure.DependencyManagement @@ -12,7 +10,6 @@ namespace SmartStore.Core.Infrastructure.DependencyManagement /// public class AutofacRequestLifetimeHttpModule : IHttpModule { - #region New public void Init(HttpApplication context) { @@ -42,13 +39,12 @@ public static void SetLifetimeScopeProvider(ILifetimeScopeProvider lifetimeScope internal static ILifetimeScopeProvider LifetimeScopeProvider { get; - set; + private set; } public void Dispose() { } - #endregion } } diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs index 3811eae586..f39bbeedeb 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ContainerManager.cs @@ -1,12 +1,11 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; -using System.Web; -using System.Threading; +using System.Reflection; using Autofac; using Autofac.Builder; -using Autofac.Integration.Mvc; -using SmartStore.Utilities; +using SmartStore.ComponentModel; using SmartStore.Core.Caching; namespace SmartStore.Core.Infrastructure.DependencyManagement @@ -14,6 +13,7 @@ namespace SmartStore.Core.Infrastructure.DependencyManagement public class ContainerManager { private readonly IContainer _container; + private readonly ConcurrentDictionary _cachedActivators = new ConcurrentDictionary(); public ContainerManager(IContainer container) { @@ -25,9 +25,9 @@ public IContainer Container get { return _container; } } - public T Resolve(string key = "", ILifetimeScope scope = null) where T : class + public T Resolve(object key = null, ILifetimeScope scope = null) where T : class { - if (string.IsNullOrEmpty(key)) + if (key == null) { return (scope ?? Scope()).Resolve(); } @@ -49,9 +49,9 @@ public object ResolveNamed(string name, Type type, ILifetimeScope scope = null) return (scope ?? Scope()).ResolveNamed(name, type); } - public T[] ResolveAll(string key = "", ILifetimeScope scope = null) + public T[] ResolveAll(object key = null, ILifetimeScope scope = null) { - if (string.IsNullOrEmpty(key)) + if (key == null) { return (scope ?? Scope()).Resolve>().ToArray(); } @@ -65,30 +65,67 @@ public T ResolveUnregistered(ILifetimeScope scope = null) where T : class public object ResolveUnregistered(Type type, ILifetimeScope scope = null) { - var constructors = type.GetConstructors(); - foreach (var constructor in constructors) - { - try - { - var parameters = constructor.GetParameters(); - var parameterInstances = new List(); - foreach (var parameter in parameters) - { - var service = Resolve(parameter.ParameterType, scope); - if (service == null) - throw new SmartException("Unkown dependency"); - parameterInstances.Add(service); - } - return Activator.CreateInstance(type, parameterInstances.ToArray()); - } - catch (SmartException) - { + FastActivator activator; + object[] parameterInstances = null; + + if (!_cachedActivators.TryGetValue(type, out activator)) + { + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + foreach (var constructor in constructors) + { + var parameterTypes = constructor.GetParameters().Select(p => p.ParameterType).ToArray(); + if (TryResolveAll(parameterTypes, out parameterInstances, scope)) + { + activator = new FastActivator(constructor); + _cachedActivators.TryAdd(type, activator); + break; + } + } + } + if (activator != null) + { + if (parameterInstances == null) + { + TryResolveAll(activator.ParameterTypes, out parameterInstances, scope); } - } - throw new SmartException("No contructor was found that had all the dependencies satisfied."); + if (parameterInstances != null) + { + return activator.Activate(parameterInstances); + } + } + + throw new SmartException("No constructor for {0} was found that had all the dependencies satisfied.".FormatInvariant(type.Name.NaIfEmpty())); } + private bool TryResolveAll(Type[] types, out object[] instances, ILifetimeScope scope = null) + { + instances = null; + + try + { + var instances2 = new object[types.Length]; + + for (int i = 0; i < types.Length; i++) + { + var service = Resolve(types[i], scope); + if (service == null) + { + return false; + } + + instances2[i] = service; + } + + instances = instances2; + return true; + } + catch + { + return false; + } + } + public bool TryResolve(Type serviceType, ILifetimeScope scope, out object instance) { return (scope ?? Scope()).TryResolve(serviceType, out instance); @@ -121,21 +158,17 @@ public T InjectUnsetProperties(T instance, ILifetimeScope scope = null) public ILifetimeScope Scope() { - ILifetimeScope scope = null; - try - { - scope = AutofacDependencyResolver.Current.RequestLifetimeScope; - } - catch { } + var scope = _container.Resolve().GetLifetimeScope(null); + return scope ?? _container; + } - if (scope == null) + public ILifetimeScopeAccessor ScopeAccessor + { + get { - // really hackisch. But strange things are going on ?? :-) - scope = _container.BeginLifetimeScope("AutofacWebRequest"); + return _container.Resolve(); } - - return scope ?? _container; - } + } } @@ -146,9 +179,14 @@ public static IRegistrationBuilder Wit return registration.WithParameter(Autofac.Core.ResolvedParameter.ForNamed("static")); } - public static IRegistrationBuilder WithRequestCache(this IRegistrationBuilder registration) where TReflectionActivatorData : ReflectionActivatorData + public static IRegistrationBuilder WithAspNetCache(this IRegistrationBuilder registration) where TReflectionActivatorData : ReflectionActivatorData + { + return registration.WithParameter(Autofac.Core.ResolvedParameter.ForNamed("aspnet")); + } + + public static IRegistrationBuilder WithNullCache(this IRegistrationBuilder registration) where TReflectionActivatorData : ReflectionActivatorData { - return registration.WithParameter(Autofac.Core.ResolvedParameter.ForNamed("request")); + return registration.WithParameter(Autofac.Core.ResolvedParameter.ForNamed("null")); } } diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeAccessor.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeAccessor.cs new file mode 100644 index 0000000000..03e0fbbba7 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeAccessor.cs @@ -0,0 +1,94 @@ +using System; +using System.Diagnostics; +using System.Web; +using Autofac; +using Autofac.Core.Lifetime; +using SmartStore.Core.Data; +using SmartStore.Core.Logging; +using SmartStore.Utilities; + +namespace SmartStore.Core.Infrastructure.DependencyManagement +{ + public class DefaultLifetimeScopeAccessor : ILifetimeScopeAccessor + { + private ContextState _state; + private readonly ILifetimeScope _rootContainer; + internal static readonly object ScopeTag = "AutofacWebRequest"; + + public DefaultLifetimeScopeAccessor(ILifetimeScope rootContainer) + { + Guard.ArgumentNotNull(() => rootContainer); + + //rootContainer.ChildLifetimeScopeBeginning += OnScopeBeginning; + + this._rootContainer = rootContainer; + this._state = new ContextState("CustomLifetimeScopeProvider.WorkScope"); + } + + public ILifetimeScope ApplicationContainer + { + get { return _rootContainer; } + } + + public IDisposable BeginContextAwareScope() + { + var disposer = HttpContext.Current != null + ? ActionDisposable.Empty + : new ActionDisposable(() => this.EndLifetimeScope()); + + return disposer; + } + + public void EndLifetimeScope() + { + try + { + var scope = _state.GetState(); + if (scope != null) + { + try + { + if (DataSettings.DatabaseIsInstalled()) + scope.Resolve().Flush(); + } + catch { } + + scope.Dispose(); + _state.RemoveState(); + } + } + catch { } + } + + public ILifetimeScope GetLifetimeScope(Action configurationAction) + { + var scope = _state.GetState(); + if (scope == null) + { + _state.SetState((scope = BeginLifetimeScope(configurationAction))); + //scope.CurrentScopeEnding += OnScopeEnding; + } + return scope; + } + + //private void OnScopeBeginning(object sender, LifetimeScopeBeginningEventArgs args) + //{ + // bool isWeb = System.Web.HttpContext.Current != null; + // Debug.WriteLine("Scope Begin, Web: " + isWeb); + //} + + //private void OnScopeEnding(object sender, LifetimeScopeEndingEventArgs args) + //{ + // bool isWeb = System.Web.HttpContext.Current != null; + // Debug.WriteLine("Scope END, Web: " + isWeb); + //} + + private ILifetimeScope BeginLifetimeScope(Action configurationAction) + { + return (configurationAction == null) + ? _rootContainer.BeginLifetimeScope(ScopeTag) + : _rootContainer.BeginLifetimeScope(ScopeTag, configurationAction); + } + + } +} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeProvider.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeProvider.cs new file mode 100644 index 0000000000..9f01c73248 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/DefaultLifetimeScopeProvider.cs @@ -0,0 +1,35 @@ +using System; +using Autofac; +using Autofac.Integration.Mvc; + +namespace SmartStore.Core.Infrastructure.DependencyManagement +{ + public class DefaultLifetimeScopeProvider : ILifetimeScopeProvider + { + private readonly ILifetimeScopeAccessor _accessor; + + public DefaultLifetimeScopeProvider(ILifetimeScopeAccessor accessor) + { + Guard.ArgumentNotNull(() => accessor); + + this._accessor = accessor; + AutofacRequestLifetimeHttpModule.SetLifetimeScopeProvider(this); + } + + public ILifetimeScope ApplicationContainer + { + get { return _accessor.ApplicationContainer; } + } + + public void EndLifetimeScope() + { + _accessor.EndLifetimeScope(); + } + + public ILifetimeScope GetLifetimeScope(Action configurationAction) + { + return _accessor.GetLifetimeScope(configurationAction); + } + + } +} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ILifetimeScopeAccessor.cs b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ILifetimeScopeAccessor.cs new file mode 100644 index 0000000000..03beda80b8 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Infrastructure/DependencyManagement/ILifetimeScopeAccessor.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Autofac; + +namespace SmartStore.Core.Infrastructure.DependencyManagement +{ + public interface ILifetimeScopeAccessor + { + /// + /// Gets the global, application-wide container. + /// + ILifetimeScope ApplicationContainer { get; } + + /// + /// Ends the current lifetime scope. + /// + void EndLifetimeScope(); + + /// + /// Gets a nested lifetime scope that services can be resolved from + /// + /// A configuration action that will execute during lifetime scope creation. + /// + /// A new or existing nested lifetime scope. + /// + ILifetimeScope GetLifetimeScope(Action configurationAction); + + /// + /// Either creates a new lifetime scope when HttpContext.Current is null, + /// OR returns the current http context scoped lifetime. + /// + /// + /// A disposable object which does nothing when internal lifetime scope is bound to the http context, + /// OR ends the lifetime scope otherwise. + /// + /// + /// This method is intended for usage in background threads or tasks. There may be situations where HttpContext is present, + /// especially when a task was started with TaskScheduler.FromCurrentSynchronizationContext(). In this case it may not be + /// desirable to create a new scope, but use the existing, http context bound scope instead. + /// + IDisposable BeginContextAwareScope(); + } +} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/DisposableObject.cs b/src/Libraries/SmartStore.Core/Infrastructure/DisposableObject.cs index 9a942eaf09..e3b01f2e42 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/DisposableObject.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/DisposableObject.cs @@ -8,18 +8,18 @@ namespace SmartStore public abstract class DisposableObject : IDisposable { - private bool _disposed = false; + private bool _isDisposed; public virtual bool IsDisposed { [DebuggerStepThrough] - get { return _disposed; } + get { return _isDisposed; } } [DebuggerStepThrough] protected void CheckDisposed() { - if (IsDisposed) + if (_isDisposed) { throw Error.ObjectDisposed(GetType().FullName); } @@ -28,7 +28,7 @@ protected void CheckDisposed() [DebuggerStepThrough] protected void CheckDisposed(string errorMessage) { - if (IsDisposed) + if (_isDisposed) { throw Error.ObjectDisposed(GetType().FullName, errorMessage); } @@ -37,24 +37,27 @@ protected void CheckDisposed(string errorMessage) [DebuggerStepThrough] public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); + if (!_isDisposed) + { + Dispose(true); + GC.SuppressFinalize(this); + } } protected void Dispose(bool disposing) { - if (!_disposed) + if (!_isDisposed) { OnDispose(disposing); } - _disposed = true; + _isDisposed = true; } protected abstract void OnDispose(bool disposing); protected static void DisposeEnumerable(IEnumerable enumerable) { - if (!enumerable.IsNullOrEmpty()) + if (enumerable != null) { foreach (object obj2 in enumerable) { diff --git a/src/Libraries/SmartStore.Core/Infrastructure/EngineContext.cs b/src/Libraries/SmartStore.Core/Infrastructure/EngineContext.cs index e8abc8ee61..aa7c8497ee 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/EngineContext.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/EngineContext.cs @@ -13,14 +13,16 @@ namespace SmartStore.Core.Infrastructure public class EngineContext { #region Initialization Methods + /// Initializes a static instance of the SmartStore factory. /// Creates a new factory instance even though the factory has been previously initialized. + /// A custom implementation of to use instead of the built-in engine [MethodImpl(MethodImplOptions.Synchronized)] - public static IEngine Initialize(bool forceRecreate) + public static IEngine Initialize(bool forceRecreate, IEngine engine = null) { if (Singleton.Instance == null || forceRecreate) { - Singleton.Instance = CreateEngineInstance(); + Singleton.Instance = engine ?? CreateEngineInstance(); Singleton.Instance.Initialize(); } return Singleton.Instance; diff --git a/src/Libraries/SmartStore.Core/Infrastructure/EnumFriendlyNameAttribute.cs b/src/Libraries/SmartStore.Core/Infrastructure/EnumFriendlyNameAttribute.cs deleted file mode 100644 index 1be47733be..0000000000 --- a/src/Libraries/SmartStore.Core/Infrastructure/EnumFriendlyNameAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SmartStore -{ - - /// - /// Provides a friendly display name for an enumerated type value. - /// - [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] - public sealed class EnumFriendlyNameAttribute : Attribute - { - public EnumFriendlyNameAttribute(string friendlyName) - { - FriendlyName = friendlyName; - } - - public string FriendlyName { get; private set; } - } - - /// - /// Provides a description for an enumerated type. - /// - [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field, AllowMultiple = false)] - public sealed class EnumDescriptionAttribute : Attribute - { - - /// - /// Initializes a new instance of the - /// class. - /// - /// The description to store in this attribute. - /// - public EnumDescriptionAttribute(string description) - { - Description = description; - } - - /// - /// Gets the description stored in this attribute. - /// - /// The description stored in the attribute. - public string Description { get; private set; } - } - -} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/Error.cs b/src/Libraries/SmartStore.Core/Infrastructure/Error.cs index d8752d8169..47f03f6f2e 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/Error.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/Error.cs @@ -2,8 +2,6 @@ using System.Globalization; using System.Diagnostics; -using Fasterflect; - namespace SmartStore { public static class Error @@ -77,7 +75,7 @@ public static Exception Argument(Func arg, string message, params object[] [DebuggerStepThrough] public static Exception InvalidOperation(string message, params object[] args) { - return Error.InvalidOperation(message, null, args); + return InvalidOperation(message, null, args); } [DebuggerStepThrough] diff --git a/src/Libraries/SmartStore.Core/Infrastructure/Guard.cs b/src/Libraries/SmartStore.Core/Infrastructure/Guard.cs index 05c2d0bd75..5a15aba9f3 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/Guard.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/Guard.cs @@ -2,6 +2,8 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Linq.Expressions; namespace SmartStore @@ -110,8 +112,11 @@ public static void Arguments(Func arg1, Func arg2, F [DebuggerStepThrough] public static void ArgumentNotEmpty(Func arg) { - if (arg().IsEmpty()) - throw Error.ArgumentNullOrEmpty(arg); + if (arg().IsEmpty()) + { + var argName = GetParamName(arg); + throw Error.Argument(argName, "String parameter '{0}' cannot be null or all whitespace.", argName); + } } [DebuggerStepThrough] @@ -124,16 +129,6 @@ public static void ArgumentNotEmpty(Func arg) } } - [DebuggerStepThrough] - public static void ArgumentNotEmpty(Func arg) - { - if (!arg().HasItems()) - { - string argName = GetParamName(arg); - throw Error.Argument(argName, "List cannot be null and must have at least one item."); - } - } - [DebuggerStepThrough] public static void ArgumentNotEmpty(string arg, string argName) { @@ -142,10 +137,10 @@ public static void ArgumentNotEmpty(string arg, string argName) } [DebuggerStepThrough] - public static void ArgumentNotEmpty(IEnumerable arg, string argName) + public static void ArgumentNotEmpty(ICollection arg, string argName) { - if (!arg.HasItems()) - throw Error.Argument(argName, "List cannot be null and must have at least one item."); + if (arg != null && !arg.Any()) + throw Error.Argument(argName, "Collection cannot be null and must have at least one item."); } [DebuggerStepThrough] @@ -309,7 +304,7 @@ public static void ArgumentNotDisposed(DisposableObject arg, string argName) [DebuggerStepThrough] public static void PagingArgsValid(int indexArg, int sizeArg, string indexArgName, string sizeArgName) { - ArgumentNotNegative(indexArg, indexArgName, "PageIndex cannot be below 0"); + ArgumentNotNegative(indexArg, indexArgName, "PageIndex cannot be below 0"); if (indexArg > 0) { // if pageIndex is specified (> 0), PageSize CANNOT be 0 @@ -323,9 +318,10 @@ public static void PagingArgsValid(int indexArg, int sizeArg, string indexArgNam } [DebuggerStepThrough] + [SuppressMessage("ReSharper", "UnusedMember.Local")] private static string GetParamName(Expression> expression) { - string name = string.Empty; + var name = string.Empty; MemberExpression body = expression.Body as MemberExpression; if (body != null) diff --git a/src/Libraries/SmartStore.Core/Infrastructure/IEngine.cs b/src/Libraries/SmartStore.Core/Infrastructure/IEngine.cs index 7053d65252..43d05ecce3 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/IEngine.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/IEngine.cs @@ -18,7 +18,6 @@ public interface IEngine /// /// Initialize components and plugins in the SmartStore environment. /// - /// Config void Initialize(); T Resolve(string name = null) where T : class; diff --git a/src/Libraries/SmartStore.Core/Infrastructure/Misc.cs b/src/Libraries/SmartStore.Core/Infrastructure/Misc.cs deleted file mode 100644 index c09656ec4b..0000000000 --- a/src/Libraries/SmartStore.Core/Infrastructure/Misc.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Reflection; -using System.Text; -using System.Globalization; -using System.IO; - -namespace SmartStore -{ - - //internal delegate T Creator(); - - internal static class Misc - { - - public static bool TryAction(Func func, out T output) - { - Guard.ArgumentNotNull(() => func); - - try - { - output = func(); - return true; - } - catch - { - output = default(T); - return false; - } - } - - /// - /// Perform an action if the string is not null or empty. - /// - /// The value. - /// The action to perform. - public static void IfNotNullOrEmpty(string value, Action action) - { - IfNotNullOrEmpty(value, action, null); - } - - private static void IfNotNullOrEmpty(string value, Action trueAction, Action falseAction) - { - if (!string.IsNullOrEmpty(value)) - { - if (trueAction != null) - trueAction(value); - } - else - { - if (falseAction != null) - falseAction(value); - } - } - - } -} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ObjectSignatureAttribute.cs b/src/Libraries/SmartStore.Core/Infrastructure/ObjectSignatureAttribute.cs index 3095534f82..42b53f80c4 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/ObjectSignatureAttribute.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/ObjectSignatureAttribute.cs @@ -1,12 +1,9 @@ using System; - namespace SmartStore -{ - +{ [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class ObjectSignatureAttribute : Attribute { } - } diff --git a/src/Libraries/SmartStore.Core/Infrastructure/RegularExpressions.cs b/src/Libraries/SmartStore.Core/Infrastructure/RegularExpressions.cs index bb4fae16b0..a9143bed56 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/RegularExpressions.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/RegularExpressions.cs @@ -4,7 +4,6 @@ namespace SmartStore { - public static class RegularExpressions { @@ -19,10 +18,10 @@ public static class RegularExpressions public static readonly Regex IsNotNumber = new Regex("[^0-9.-]", RegexOptions.Compiled); public static readonly Regex IsPositiveInteger = new Regex(@"\d{1,10}", RegexOptions.Compiled); public static readonly Regex IsNumeric = new Regex("(" + ValidRealPattern + ")|(" + ValidIntegerPattern + ")", RegexOptions.Compiled); - public static readonly Regex IsWebUrl = new Regex(@"(http|https)://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", RegexOptions.Singleline | RegexOptions.Compiled); - // insufficient, fails on valid email first+second-test01@domain.com - //public static readonly Regex IsEmail = new Regex(@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", RegexOptions.Singleline | RegexOptions.Compiled); + //public static readonly Regex IsWebUrl = new Regex(@"(http|https)://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", RegexOptions.Singleline | RegexOptions.Compiled); + /// see https://msdn.microsoft.com/en-us/library/ms998267.aspx + public static readonly Regex IsWebUrl = new Regex(@"^(ht|f)tp(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_\=~]*)?$", RegexOptions.Singleline | RegexOptions.Compiled); public static readonly Regex IsEmail = new Regex("^(?:[\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~]+\\.)*[\\w\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-](?!\\.)){0,61}[a-zA-Z0-9]?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\\[(?:(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\.){3}(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\]))$", RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -31,10 +30,12 @@ public static class RegularExpressions public static readonly Regex IsGuid = new Regex(@"\{?[a-fA-F0-9]{8}(?:-(?:[a-fA-F0-9]){4}){3}-[a-fA-F0-9]{12}\}?", RegexOptions.Compiled); public static readonly Regex IsBase64Guid = new Regex(@"[a-zA-Z0-9+/=]{22,24}", RegexOptions.Compiled); - public static readonly Regex IsCultureCode = new Regex(@"^([a-z]{2})|([a-z]{2}-[A-Z]{2})$", RegexOptions.Singleline | RegexOptions.Compiled); + public static readonly Regex IsCultureCode = new Regex(@"^[a-z]{2}(-[A-Z]{2})?$", RegexOptions.Singleline | RegexOptions.Compiled); public static readonly Regex IsYearRange = new Regex(@"^(\d{4})-(\d{4})$", RegexOptions.Compiled); + public static readonly Regex IsIban = new Regex(@"[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}", RegexOptions.Singleline | RegexOptions.Compiled); + public static readonly Regex IsBic = new Regex(@"([a-zA-Z]{4}[a-zA-Z]{2}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?)", RegexOptions.Singleline | RegexOptions.Compiled); } } diff --git a/src/Libraries/SmartStore.Core/Infrastructure/SmartStoreEngine.cs b/src/Libraries/SmartStore.Core/Infrastructure/SmartStoreEngine.cs index dccbbcb958..accd095b46 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/SmartStoreEngine.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/SmartStoreEngine.cs @@ -1,13 +1,10 @@ using System; using System.Collections.Generic; -using System.Configuration; using System.Linq; -using System.Reflection; using System.Threading.Tasks; using System.Web.Mvc; using Autofac; using Autofac.Integration.Mvc; -using SmartStore.Core.Configuration; using SmartStore.Core.Data; using SmartStore.Core.Infrastructure.DependencyManagement; using SmartStore.Core.Plugins; @@ -39,19 +36,42 @@ protected virtual void RunStartupTasks() } } - protected virtual void RegisterDependencies() + protected virtual ITypeFinder CreateTypeFinder() + { + return new WebAppTypeFinder(); + } + + protected virtual object CreateDependencyResolver(IContainer container) + { + var scopeProvider = container.Resolve(); + var dependencyResolver = new AutofacDependencyResolver(container, scopeProvider); + return dependencyResolver; + } + + protected virtual ContainerManager RegisterDependencies() { var builder = new ContainerBuilder(); var container = builder.Build(); + var typeFinder = CreateTypeFinder(); // core dependencies builder = new ContainerBuilder(); - builder.RegisterInstance(this).As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); + builder.RegisterInstance(this).As(); + builder.RegisterInstance(typeFinder).As(); + + // Autofac + var lifetimeScopeAccessor = new DefaultLifetimeScopeAccessor(container); + var lifetimeScopeProvider = new DefaultLifetimeScopeProvider(lifetimeScopeAccessor); + builder.RegisterInstance(lifetimeScopeAccessor).As(); + builder.RegisterInstance(lifetimeScopeProvider).As(); + + var dependencyResolver = new AutofacDependencyResolver(container, lifetimeScopeProvider); + builder.RegisterInstance(dependencyResolver); + DependencyResolver.SetResolver(dependencyResolver); + builder.Update(container); // register dependencies provided by other assemblies - var typeFinder = container.Resolve(); builder = new ContainerBuilder(); var registrarTypes = typeFinder.FindClassesOfType(); var registrarInstances = new List(); @@ -67,12 +87,7 @@ protected virtual void RegisterDependencies() } builder.Update(container); - // AutofacDependencyResolver - var scopeProvider = new AutofacLifetimeScopeProvider(container); - var dependencyResolver = new AutofacDependencyResolver(container, scopeProvider); - DependencyResolver.SetResolver(dependencyResolver); - - _containerManager = new ContainerManager(container); + return new ContainerManager(container); } #endregion @@ -84,7 +99,7 @@ protected virtual void RegisterDependencies() /// public void Initialize() { - RegisterDependencies(); + _containerManager = RegisterDependencies(); if (DataSettings.DatabaseIsInstalled()) { RunStartupTasks(); diff --git a/src/Libraries/SmartStore.Core/Infrastructure/ValueObject.cs b/src/Libraries/SmartStore.Core/Infrastructure/ValueObject.cs deleted file mode 100644 index 066c47f810..0000000000 --- a/src/Libraries/SmartStore.Core/Infrastructure/ValueObject.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using Fasterflect; - -namespace SmartStore -{ - - /// - /// Base class for complex value objects, which do not have - /// identifiers. - /// - /// Type of the entity, which is the value obect. - public abstract class ValueObject : ComparableObject> - where T : ValueObject - { - - /// - /// Registers all properties of the subclass as signature properties. - /// - protected void RegisterProperties() - { - RegisterProperties((pd) => true); - } - - /// - /// Registers any properties of the subclass matching - /// the given as signature properties. - /// - protected void RegisterProperties(Func filter) - { - foreach (var pi in this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) - { - if (filter(pi)) - RegisterSignatureProperty(pi); - } - } - - public override bool Equals(object obj) - { - return base.Equals(obj); - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - - public override string ToString() - { - var sb = new StringBuilder(); - var properties = GetSignatureProperties(); - int propsCount = properties.Count(); - - int i = 1; - - foreach (var pi in properties) - { - object value = this.GetPropertyValue(pi.Name); - if (value == null) - continue; - - sb.Append(pi.Name + ": " + value.ToString()); - if (i < propsCount) - sb.Append(", "); - - i++; - } - - return sb.ToString(); - } - - public static bool operator ==(ValueObject x, ValueObject y) - { - if ((object)x == null) - return (object)y == null; - - return x.Equals(y); - } - - public static bool operator !=(ValueObject x, ValueObject y) - { - return !(x == y); - } - - } - -} diff --git a/src/Libraries/SmartStore.Core/Infrastructure/WebAppTypeFinder.cs b/src/Libraries/SmartStore.Core/Infrastructure/WebAppTypeFinder.cs index c57861d90a..90dc70012f 100644 --- a/src/Libraries/SmartStore.Core/Infrastructure/WebAppTypeFinder.cs +++ b/src/Libraries/SmartStore.Core/Infrastructure/WebAppTypeFinder.cs @@ -15,8 +15,8 @@ public class WebAppTypeFinder : AppDomainTypeFinder { #region Fields - private bool _ensureBinFolderAssembliesLoaded = true; - private bool _binFolderAssembliesLoaded = false; + private bool _ensureBinFolderAssembliesLoaded; + private bool _binFolderAssembliesLoaded; #endregion @@ -63,14 +63,12 @@ public virtual string GetBinDirectory() } } - public override IList GetAssemblies(bool ignoreInactivePlugins = false) { if (this.EnsureBinFolderAssembliesLoaded && !_binFolderAssembliesLoaded) { _binFolderAssembliesLoaded = true; string binPath = GetBinDirectory(); - //binPath = _webHelper.MapPath("~/bin"); LoadMatchingAssemblies(binPath); } diff --git a/src/Libraries/SmartStore.Core/Linq/Expanders/LambdaPathExpander.cs b/src/Libraries/SmartStore.Core/Linq/Expanders/LambdaPathExpander.cs index 185b8a946e..4c7c1ec45d 100644 --- a/src/Libraries/SmartStore.Core/Linq/Expanders/LambdaPathExpander.cs +++ b/src/Libraries/SmartStore.Core/Linq/Expanders/LambdaPathExpander.cs @@ -57,16 +57,14 @@ public virtual void Expand(Type type, string path) var tokenizer = new StringTokenizer(path, ".", false); foreach (string member in tokenizer) { - // Property oder Field des Members ermitteln - MemberInfo prop = t.GetFieldOrProperty(member, true); - //MemberInfo prop = t.GetProperty(member); + // Property ermitteln + //MemberInfo prop = t.GetFieldOrProperty(member, true); + var prop = t.GetProperty(member, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance); if (prop == null) throw new ArgumentException("The property or member '{0}' does not exist in type '{1}'.".FormatInvariant(member, t.FullName)); - Type memberType = (prop.MemberType == MemberTypes.Property) - ? ((PropertyInfo)prop).PropertyType - : ((FieldInfo)prop).FieldType; + Type memberType = prop.PropertyType; DoExpand(t, member); diff --git a/src/Libraries/SmartStore.Core/Linq/Expressions/ExpressionVisitor.cs b/src/Libraries/SmartStore.Core/Linq/Expressions/ExpressionVisitor.cs index b1a66d8885..63cf7761fd 100644 --- a/src/Libraries/SmartStore.Core/Linq/Expressions/ExpressionVisitor.cs +++ b/src/Libraries/SmartStore.Core/Linq/Expressions/ExpressionVisitor.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; @@ -21,6 +22,7 @@ namespace SmartStore.Linq.Expressions /// for anyone outside of Microsoft to be using... /// [DebuggerStepThrough, DebuggerNonUserCode] + [SuppressMessage("ReSharper", "PossibleUnintendedReferenceComparison")] public abstract class ExpressionVisitor { /// diff --git a/src/Libraries/SmartStore.Core/Localization/LocalizationHelper.cs b/src/Libraries/SmartStore.Core/Localization/LocalizationHelper.cs new file mode 100644 index 0000000000..ed9beed2ad --- /dev/null +++ b/src/Libraries/SmartStore.Core/Localization/LocalizationHelper.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace SmartStore.Core.Localization +{ + public static class LocalizationHelper + { + private readonly static HashSet _cultureCodes = + new HashSet( + CultureInfo.GetCultures(CultureTypes.NeutralCultures | CultureTypes.SpecificCultures | CultureTypes.UserCustomCulture) + .Select(x => x.IetfLanguageTag) + .Where(x => !string.IsNullOrWhiteSpace(x))); + + public static bool IsValidCultureCode(string cultureCode) + { + return _cultureCodes.Contains(cultureCode); + } + + public static string GetLanguageNativeName(string locale) + { + try + { + if (locale.HasValue()) + { + var info = CultureInfo.GetCultureInfoByIetfLanguageTag(locale); + if (info != null) + return info.NativeName; + } + } + catch { } + + return null; + } + + public static string GetCurrencySymbol(string locale) + { + try + { + if (locale.HasValue()) + { + var info = new RegionInfo(locale); + if (info != null) + return info.CurrencySymbol; + } + } + catch { } + + return null; + } + } +} diff --git a/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs b/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs index 0c32d85236..3ff8526a96 100644 --- a/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs +++ b/src/Libraries/SmartStore.Core/Logging/ICustomerActivityService.cs @@ -1,15 +1,14 @@ using System; using System.Collections.Generic; -using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Logging; namespace SmartStore.Core.Logging { - /// - /// Customer activity service interface - /// - public partial interface ICustomerActivityService + /// + /// Customer activity service interface + /// + public partial interface ICustomerActivityService { /// /// Inserts an activity log type item @@ -75,19 +74,27 @@ ActivityLog InsertActivity(string systemKeyword, /// Activity log void DeleteActivity(ActivityLog activityLog); - /// - /// Gets all activity log items - /// - /// Log item creation from; null to load all customers - /// Log item creation to; null to load all customers - /// Customer identifier; null to load all customers - /// Activity log type identifier - /// Page index - /// Page size - /// Activity log collection - IPagedList GetAllActivities(DateTime? createdOnFrom, - DateTime? createdOnTo, int? customerId, - int activityLogTypeId, int pageIndex, int pageSize); + /// + /// Gets all activity log items + /// + /// Log item creation from; null to load all customers + /// Log item creation to; null to load all customers + /// Customer identifier; null to load all customers + /// Activity log type identifier + /// Page index + /// Page size + /// Customer email + /// Customer system name + /// Activity log collection + IPagedList GetAllActivities( + DateTime? createdOnFrom, + DateTime? createdOnTo, + int? customerId, + int activityLogTypeId, + int pageIndex, + int pageSize, + string email = null, + bool? customerSystemAccount = null); /// /// Gets an activity log item @@ -96,9 +103,16 @@ IPagedList GetAllActivities(DateTime? createdOnFrom, /// Activity log item ActivityLog GetActivityById(int activityLogId); - /// - /// Clears activity log - /// - void ClearAllActivities(); + /// + /// Gets activity logs be identifier + /// + /// Activity log identifiers + /// List of activity logs + IList GetActivityByIds(int[] activityLogIds); + + /// + /// Clears activity log + /// + void ClearAllActivities(); } } diff --git a/src/Libraries/SmartStore.Core/Logging/ILogger.cs b/src/Libraries/SmartStore.Core/Logging/ILogger.cs index c4e2409204..098d77c6ed 100644 --- a/src/Libraries/SmartStore.Core/Logging/ILogger.cs +++ b/src/Libraries/SmartStore.Core/Logging/ILogger.cs @@ -40,8 +40,7 @@ public partial interface ILogger /// Page index /// Page size /// Log item collection - IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, - string message, LogLevel? logLevel, int pageIndex, int pageSize, int minFrequency); + IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, string message, LogLevel? logLevel, int pageIndex, int pageSize, int minFrequency); /// /// Gets a log item @@ -61,8 +60,8 @@ IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, /// Inserts a log item /// /// The log context - /// A log item - Log InsertLog(LogContext context); + /// Always return null + void InsertLog(LogContext context); /// /// Inserts a log item @@ -71,7 +70,12 @@ IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, /// The short message /// The full message /// The customer to associate log record with - /// A log item - Log InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null); + /// Always return null + void InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null); + + /// + /// Commits log entries to the data store + /// + void Flush(); } } diff --git a/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs b/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs index 86c8f4400e..fb8a10be35 100644 --- a/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs +++ b/src/Libraries/SmartStore.Core/Logging/LoggingExtensions.cs @@ -9,38 +9,61 @@ public static class LoggingExtensions public static void Debug(this ILogger logger, string message, Exception exception = null, Customer customer = null) { - FilteredLog(logger, LogLevel.Debug, message, exception, customer); + FilteredLog(logger, LogLevel.Debug, message, null, exception, customer); } public static void Information(this ILogger logger, string message, Exception exception = null, Customer customer = null) { - FilteredLog(logger, LogLevel.Information, message, exception, customer); + FilteredLog(logger, LogLevel.Information, message, null, exception, customer); } public static void Warning(this ILogger logger, string message, Exception exception = null, Customer customer = null) { - FilteredLog(logger, LogLevel.Warning, message, exception, customer); + FilteredLog(logger, LogLevel.Warning, message, null, exception, customer); } public static void Error(this ILogger logger, string message, Exception exception = null, Customer customer = null) { - FilteredLog(logger, LogLevel.Error, message, exception, customer); + FilteredLog(logger, LogLevel.Error, message, null, exception, customer); } - public static void Fatal(this ILogger logger, string message, Exception exception = null, Customer customer = null) + public static void Error(this ILogger logger, string message, string fullMessage, Exception exception = null, Customer customer = null) + { + FilteredLog(logger, LogLevel.Error, message, fullMessage, exception, customer); + } + + public static void Fatal(this ILogger logger, string message, Exception exception = null, Customer customer = null) { - FilteredLog(logger, LogLevel.Fatal, message, exception, customer); + FilteredLog(logger, LogLevel.Fatal, message, null, exception, customer); } - private static void FilteredLog(ILogger logger, LogLevel level, string message, Exception exception = null, Customer customer = null) + public static void Error(this ILogger logger, Exception exception, Customer customer = null) + { + FilteredLog(logger, LogLevel.Error, exception.ToAllMessages(), null, exception, customer); + } + + public static void ErrorsAll(this ILogger logger, Exception exception, Customer customer = null) + { + while (exception != null) + { + FilteredLog(logger, LogLevel.Error, exception.Message, exception.StackTrace, exception, customer); + exception = exception.InnerException; + } + } + + private static void FilteredLog(ILogger logger, LogLevel level, string message, string fullMessage, Exception exception = null, Customer customer = null) { - //don't log thread abort exception + // don't log thread abort exception if ((exception != null) && (exception is System.Threading.ThreadAbortException)) return; if (logger.IsEnabled(level)) { - string fullMessage = exception == null ? string.Empty : exception.ToString(); + if (exception != null && fullMessage.IsEmpty()) + { + fullMessage = "{0}\n{1}\n{2}".FormatCurrent(exception.Message, new String('-', 20), exception.StackTrace); + } + logger.InsertLog(level, message, fullMessage, customer); } } diff --git a/src/Libraries/SmartStore.Core/Logging/NullLogger.cs b/src/Libraries/SmartStore.Core/Logging/NullLogger.cs index ef05a608b1..e2cb89133a 100644 --- a/src/Libraries/SmartStore.Core/Logging/NullLogger.cs +++ b/src/Libraries/SmartStore.Core/Logging/NullLogger.cs @@ -86,9 +86,8 @@ public virtual IList GetLogByIds(int[] logIds) return new List(); } - public Log InsertLog(LogContext context) + public void InsertLog(LogContext context) { - return null; } /// @@ -99,9 +98,12 @@ public Log InsertLog(LogContext context) /// The full message /// The customer to associate log record with /// A log item - public Log InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null) + public void InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null) { - return null; } - } + + public void Flush() + { + } + } } diff --git a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs index 296ee8e931..593a39ddb0 100644 --- a/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs +++ b/src/Libraries/SmartStore.Core/Logging/TraceLogger.cs @@ -1,18 +1,20 @@ using System; using System.Collections.Generic; -using System.Linq; +using System.Diagnostics; +using System.IO; using System.Text; -using SmartStore.Core.Domain.Logging; using SmartStore.Core.Domain.Customers; -using System.Diagnostics; +using SmartStore.Core.Domain.Logging; +using SmartStore.Utilities; namespace SmartStore.Core.Logging { public class TraceLogger : DisposableObject, ILogger { private readonly TraceSource _traceSource; + private readonly StreamWriter _streamWriter; - public TraceLogger() : this("SmartStore.log") + public TraceLogger() : this(CommonHelper.MapPath("~/App_Data/SmartStore.log")) { } @@ -23,23 +25,37 @@ public TraceLogger(string fileName) _traceSource = new TraceSource("SmartStore"); _traceSource.Switch = new SourceSwitch("LogSwitch", "Error"); _traceSource.Listeners.Remove("Default"); - + var console = new ConsoleTraceListener(false); console.Filter = new EventTypeFilter(SourceLevels.All); console.Name = "console"; + _traceSource.Listeners.Add(console); + var textListener = new TextWriterTraceListener(fileName); textListener.Filter = new EventTypeFilter(SourceLevels.All); textListener.TraceOutputOptions = TraceOptions.DateTime; - _traceSource.Listeners.Add(console); - _traceSource.Listeners.Add(textListener); - - // Allow the trace source to send messages to - // listeners for all event types. Currently only + try + { + // force UTF-8 encoding (even if the text just contains ANSI characters) + var append = File.Exists(fileName); + _streamWriter = new StreamWriter(fileName, append, Encoding.UTF8); + + textListener.Writer = _streamWriter; + + _traceSource.Listeners.Add(textListener); + } + catch (IOException) + { + // file is locked by another process + } + + // Allow the trace source to send messages to + // listeners for all event types. Currently only // error messages or higher go to the listeners. - // Messages must get past the source switch to - // get to the listeners, regardless of the settings + // Messages must get past the source switch to + // get to the listeners, regardless of the settings // for the listeners. _traceSource.Switch.Level = SourceLevels.All; } @@ -82,16 +98,20 @@ public IList GetLogByIds(int[] logIds) return null; } - public Log InsertLog(LogContext context) + public void InsertLog(LogContext context) { var type = LogLevelToEventType(context.LogLevel); - _traceSource.TraceEvent(type, (int)type, "{0}: {1}".FormatCurrent(type.ToString().ToUpper(), context.ShortMessage)); - return null; + var msg = context.ShortMessage.Grow(context.FullMessage, Environment.NewLine); + + if (msg.HasValue()) + { + _traceSource.TraceEvent(type, (int)type, "{0}: {1}".FormatCurrent(type.ToString().ToUpper(), msg)); + } } - public Log InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null) + public void InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null) { - var context = new LogContext() + var context = new LogContext { LogLevel = logLevel, ShortMessage = shortMessage, @@ -99,7 +119,7 @@ public Log InsertLog(LogLevel logLevel, string shortMessage, string fullMessage Customer = customer }; - return InsertLog(context); + InsertLog(context); } private TraceEventType LogLevelToEventType(LogLevel level) @@ -119,10 +139,21 @@ private TraceEventType LogLevelToEventType(LogLevel level) } } + public void Flush() + { + _traceSource.Flush(); + } + protected override void OnDispose(bool disposing) { _traceSource.Flush(); _traceSource.Close(); + + if (_streamWriter != null) + { + _streamWriter.Close(); + _streamWriter.Dispose(); + } } } } diff --git a/src/Libraries/SmartStore.Core/Packaging/ExtensionDescriptor.cs b/src/Libraries/SmartStore.Core/Packaging/ExtensionDescriptor.cs index 23a18e096f..2d014ace46 100644 --- a/src/Libraries/SmartStore.Core/Packaging/ExtensionDescriptor.cs +++ b/src/Libraries/SmartStore.Core/Packaging/ExtensionDescriptor.cs @@ -5,7 +5,7 @@ namespace SmartStore.Core.Packaging { - internal class ExtensionDescriptor + public class ExtensionDescriptor { /// /// Virtual path base, "~/Themes" or "~/Plugins" diff --git a/src/Libraries/SmartStore.Core/Packaging/FolderUpdater.cs b/src/Libraries/SmartStore.Core/Packaging/FolderUpdater.cs index 314eb5d61c..d02cc71cce 100644 --- a/src/Libraries/SmartStore.Core/Packaging/FolderUpdater.cs +++ b/src/Libraries/SmartStore.Core/Packaging/FolderUpdater.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.IO; using SmartStore.Core.Logging; @@ -14,6 +15,7 @@ public interface IFolderUpdater void Restore(DirectoryInfo backupfolder, DirectoryInfo existingFolder); } + [SuppressMessage("ReSharper", "NotAccessedField.Local")] public class FolderUpdater : IFolderUpdater { public class FolderContent @@ -83,6 +85,7 @@ private FolderContent GetFolderContent(DirectoryInfo folder, IEnumerable files, IEnumerable ignores) { if (!folder.Exists) diff --git a/src/Libraries/SmartStore.Core/Packaging/NuGet/ExtensionReferenceRepository.cs b/src/Libraries/SmartStore.Core/Packaging/NuGet/ExtensionReferenceRepository.cs index 16223cc543..f5ca4be0fe 100644 --- a/src/Libraries/SmartStore.Core/Packaging/NuGet/ExtensionReferenceRepository.cs +++ b/src/Libraries/SmartStore.Core/Packaging/NuGet/ExtensionReferenceRepository.cs @@ -53,14 +53,12 @@ public override bool SupportsPrereleasePackages /// internal class PluginReferenceRepository : ExtensionReferenceRepository { - private readonly IPluginFinder _pluginFinder; private readonly IList _descriptors; public PluginReferenceRepository(IProjectSystem project, IPackageRepository sourceRepository, IPluginFinder pluginFinder) : base(project, sourceRepository) { - _pluginFinder = pluginFinder; - _descriptors = _pluginFinder.GetPluginDescriptors().ToList(); + _descriptors = pluginFinder.GetPluginDescriptors().ToList(); } public override IQueryable GetPackages() @@ -83,14 +81,12 @@ public override IQueryable GetPackages() /// internal class ThemeReferenceRepository : ExtensionReferenceRepository { - private readonly IThemeRegistry _themeRegistry; private readonly ICollection _themeManifests; public ThemeReferenceRepository(IProjectSystem project, IPackageRepository sourceRepository, IThemeRegistry themeRegistry) : base(project, sourceRepository) { - _themeRegistry = themeRegistry; - _themeManifests = _themeRegistry.GetThemeManifests(); + _themeManifests = themeRegistry.GetThemeManifests(true); } public override IQueryable GetPackages() diff --git a/src/Libraries/SmartStore.Core/Packaging/NuGet/FileBasedProjectSystem.cs b/src/Libraries/SmartStore.Core/Packaging/NuGet/FileBasedProjectSystem.cs index f6294a4e68..a32cae4e91 100644 --- a/src/Libraries/SmartStore.Core/Packaging/NuGet/FileBasedProjectSystem.cs +++ b/src/Libraries/SmartStore.Core/Packaging/NuGet/FileBasedProjectSystem.cs @@ -8,7 +8,7 @@ namespace SmartStore.Core.Packaging { - internal class FileBasedProjectSystem : PhysicalFileSystem, IProjectSystem, IFileSystem + internal class FileBasedProjectSystem : PhysicalFileSystem, IProjectSystem { public FileBasedProjectSystem(string root) diff --git a/src/Libraries/SmartStore.Core/Packaging/NuGet/NullSourceRepository.cs b/src/Libraries/SmartStore.Core/Packaging/NuGet/NullSourceRepository.cs index 95cd8ca76b..5d98420378 100644 --- a/src/Libraries/SmartStore.Core/Packaging/NuGet/NullSourceRepository.cs +++ b/src/Libraries/SmartStore.Core/Packaging/NuGet/NullSourceRepository.cs @@ -12,10 +12,6 @@ namespace SmartStore.Core.Packaging /// internal class NullSourceRepository : PackageRepositoryBase { - public NullSourceRepository() - { - } - public override IQueryable GetPackages() { return Enumerable.Empty().AsQueryable(); diff --git a/src/Libraries/SmartStore.Core/Packaging/PackageBuilder.cs b/src/Libraries/SmartStore.Core/Packaging/PackageBuilder.cs index 53e322fe59..ee78bbc8fd 100644 --- a/src/Libraries/SmartStore.Core/Packaging/PackageBuilder.cs +++ b/src/Libraries/SmartStore.Core/Packaging/PackageBuilder.cs @@ -18,12 +18,10 @@ namespace SmartStore.Core.Packaging public class PackageBuilder : IPackageBuilder { private readonly IWebSiteFolder _webSiteFolder; - private readonly IVirtualPathProvider _virtualPathProvider; - public PackageBuilder(IWebSiteFolder webSiteFolder, IVirtualPathProvider virtualPathProvider) + public PackageBuilder(IWebSiteFolder webSiteFolder) { this._webSiteFolder = webSiteFolder; - this._virtualPathProvider = virtualPathProvider; } private static readonly string[] _ignoredThemeExtensions = new[] { @@ -38,18 +36,18 @@ private static bool IgnoreFile(string filePath) { return String.IsNullOrEmpty(filePath) || _ignoredThemePaths.Any(filePath.Contains) || - _ignoredThemeExtensions.Contains(Path.GetExtension(filePath) ?? ""); + _ignoredThemeExtensions.Contains(Path.GetExtension(filePath).NullEmpty() ?? ""); } public Stream BuildPackage(PluginDescriptor pluginDescriptor) { - return BuildPackage(PackagingUtils.ConvertToExtensionDescriptor(pluginDescriptor)); + return BuildPackage(pluginDescriptor.ConvertToExtensionDescriptor()); } public Stream BuildPackage(ThemeManifest themeManifest) { - return BuildPackage(PackagingUtils.ConvertToExtensionDescriptor(themeManifest)); + return BuildPackage(themeManifest.ConvertToExtensionDescriptor()); } private Stream BuildPackage(ExtensionDescriptor extensionDescriptor) @@ -58,7 +56,7 @@ private Stream BuildPackage(ExtensionDescriptor extensionDescriptor) BeginPackage(context); try { - EstablishPaths(context, _webSiteFolder, extensionDescriptor.Location, extensionDescriptor.Id, extensionDescriptor.ExtensionType); + EstablishPaths(context, _webSiteFolder, extensionDescriptor.Id, extensionDescriptor.ExtensionType); SetCoreProperties(context, extensionDescriptor); EmbedFiles(context); } @@ -100,7 +98,7 @@ private static void SetCoreProperties(BuildContext context, ExtensionDescriptor } } - private static void EstablishPaths(BuildContext context, IWebSiteFolder webSiteFolder, string locationPath, string extensionName, string extensionType = "Plugin") + private static void EstablishPaths(BuildContext context, IWebSiteFolder webSiteFolder, string extensionName, string extensionType = "Plugin") { context.SourceFolder = webSiteFolder; if (extensionType.IsCaseInsensitiveEqual("theme")) @@ -129,11 +127,11 @@ private static void EmbedFiles(BuildContext context) // the package that way (the package itself is the logical base path). // Get it by stripping the basePath off including the slash. var relativePath = virtualPath.Replace(basePath, ""); - EmbedVirtualFile(context, relativePath, MediaTypeNames.Application.Octet); + EmbedVirtualFile(context, relativePath); } } - private static void EmbedVirtualFile(BuildContext context, string relativePath, string contentType) + private static void EmbedVirtualFile(BuildContext context, string relativePath) { var file = new VirtualPackageFile( context.SourceFolder, @@ -153,8 +151,6 @@ private class BuildContext public IWebSiteFolder SourceFolder { get; set; } public string SourcePath { get; set; } public string TargetPath { get; set; } - - public XDocument Project { get; set; } } #endregion diff --git a/src/Libraries/SmartStore.Core/Packaging/PackageInfo.cs b/src/Libraries/SmartStore.Core/Packaging/PackageInfo.cs index 53f4eddefb..2de699d27a 100644 --- a/src/Libraries/SmartStore.Core/Packaging/PackageInfo.cs +++ b/src/Libraries/SmartStore.Core/Packaging/PackageInfo.cs @@ -12,5 +12,6 @@ public class PackageInfo public string Version { get; set; } public string Type { get; set; } public string Path { get; set; } + public ExtensionDescriptor ExtensionDescriptor { get; set; } } } diff --git a/src/Libraries/SmartStore.Core/Packaging/PackageInstaller.cs b/src/Libraries/SmartStore.Core/Packaging/PackageInstaller.cs index b97e4e1423..5a0664ef51 100644 --- a/src/Libraries/SmartStore.Core/Packaging/PackageInstaller.cs +++ b/src/Libraries/SmartStore.Core/Packaging/PackageInstaller.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using NuGet; @@ -62,7 +63,7 @@ public PackageInfo Install(Stream packageStream, string location, string applica { Guard.ArgumentNotNull(() => packageStream); - IPackage package = null; + IPackage package; try { package = new ZipPackage(packageStream); @@ -118,9 +119,11 @@ protected PackageInfo InstallPackage(IPackage package, IPackageRepository packag // check if the new package is compatible with current SmartStore version var descriptor = package.GetExtensionDescriptor(packageInfo.Type); - + if (descriptor != null) { + packageInfo.ExtensionDescriptor = descriptor; + if (!PluginManager.IsAssumedCompatible(descriptor.MinAppVersion)) { if (previousInstalled) @@ -213,6 +216,7 @@ public void Uninstall(string packageId, string applicationFolder) } } + [SuppressMessage("ReSharper", "UnusedMethodReturnValue.Local")] private bool RestoreExtensionFolder(string extensionFolder, string extensionId) { var virtualSource = _virtualPathProvider.Combine("~", extensionFolder, extensionId); diff --git a/src/Libraries/SmartStore.Core/Packaging/PackagingUtils.cs b/src/Libraries/SmartStore.Core/Packaging/PackagingUtils.cs index 52e982f315..91657a7900 100644 --- a/src/Libraries/SmartStore.Core/Packaging/PackagingUtils.cs +++ b/src/Libraries/SmartStore.Core/Packaging/PackagingUtils.cs @@ -74,14 +74,15 @@ internal static ExtensionDescriptor ConvertToExtensionDescriptor(this PluginDesc { ExtensionType = "Plugin", Location = "~/Plugins", + Path = pluginDescriptor.PhysicalPath, Id = pluginDescriptor.FolderName, Author = pluginDescriptor.Author, MinAppVersion = pluginDescriptor.MinAppVersion, Version = pluginDescriptor.Version, Name = pluginDescriptor.FriendlyName, Description = pluginDescriptor.Description, - WebSite = string.Empty, // TODO: (pkg) Add author url to plugin manifests, - Tags = string.Empty // TODO: (pkg) Add tags to plugin manifests + WebSite = pluginDescriptor.Url, // TODO: (pkg) Add author url to plugin manifests, + Tags = string.Empty // TODO: (pkg) Add tags to plugin manifests, }; return descriptor; @@ -93,14 +94,15 @@ internal static ExtensionDescriptor ConvertToExtensionDescriptor(this ThemeManif { ExtensionType = "Theme", Location = "~/Themes", + Path = themeManifest.Path, Id = themeManifest.ThemeName, Author = themeManifest.Author.HasValue() ? themeManifest.Author : "[Unknown]", - MinAppVersion = SmartStoreVersion.FullVersion, // TODO: (pkg) Add SupportedVersion to theme manifests + MinAppVersion = SmartStoreVersion.Version, // TODO: (pkg) Add SupportedVersion to theme manifests Version = new Version(themeManifest.Version), Name = themeManifest.ThemeTitle, Description = string.Empty, // TODO: (pkg) Add description to theme manifests - WebSite = string.Empty, // TODO: (pkg) Add author url to theme manifests, - Tags = string.Empty // TODO: (pkg) Add tags to theme manifests + WebSite = themeManifest.Url, + Tags = string.Empty // TODO: (pkg) Add tags to theme manifests, }; return descriptor; diff --git a/src/Libraries/SmartStore.Core/Packaging/Updater/AppUpdater.cs b/src/Libraries/SmartStore.Core/Packaging/Updater/AppUpdater.cs index f5d906c1c8..f54398153e 100644 --- a/src/Libraries/SmartStore.Core/Packaging/Updater/AppUpdater.cs +++ b/src/Libraries/SmartStore.Core/Packaging/Updater/AppUpdater.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading; @@ -12,18 +13,39 @@ using NuGet; using NuGetPackageManager = NuGet.PackageManager; using SmartStore.Core.Data; +using SmartStore.Core.Plugins; namespace SmartStore.Core.Packaging { - internal sealed class AppUpdater : DisposableObject + public sealed class AppUpdater : DisposableObject { - private const string UpdatePackagePath = "~/App_Data/Update"; + public const string UpdatePackagePath = "~/App_Data/Update"; private static readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); private TraceLogger _logger; - public bool TryUpdate() + #region Package update + + [SuppressMessage("ReSharper", "RedundantAssignment")] + public bool InstallablePackageExists() + { + string packagePath = null; + var package = FindPackage(false, out packagePath); + + if (package == null) + return false; + + if (!ValidatePackage(package)) + return false; + + if (!CheckEnvironment()) + return false; + + return true; + } + + internal bool TryUpdateFromPackage() { // NEVER EVER (!!!) make an attempt to auto-update in a dev environment!!!!!!! if (CommonHelper.IsDevEnvironment) @@ -34,7 +56,7 @@ public bool TryUpdate() try { string packagePath = null; - var package = FindPackage(out packagePath); + var package = FindPackage(true, out packagePath); if (package == null) return false; @@ -81,7 +103,7 @@ private TraceLogger CreateLogger(IPackage package) return new TraceLogger(logFile); } - private IPackage FindPackage(out string path) + private IPackage FindPackage(bool createLogger, out string path) { path = null; var dir = CommonHelper.MapPath(UpdatePackagePath, false); @@ -92,17 +114,18 @@ private IPackage FindPackage(out string path) var files = Directory.GetFiles(dir, "SmartStore.*.nupkg", SearchOption.TopDirectoryOnly); // TODO: allow more than one package in folder and return newest - if (files == null || files.Length == 0 || files.Length > 1) + if (files.Length == 0 || files.Length > 1) return null; - IPackage package = null; - try { path = files[0]; - package = new ZipPackage(files[0]); - _logger = CreateLogger(package); - _logger.Information("Found update package '{0}'".FormatInvariant(package.GetFullName())); + IPackage package = new ZipPackage(files[0]); + if (createLogger) + { + _logger = CreateLogger(package); + _logger.Information("Found update package '{0}'".FormatInvariant(package.GetFullName())); + } return package; } catch { } @@ -115,7 +138,7 @@ private bool ValidatePackage(IPackage package) if (package.Id != "SmartStore") return false; - var currentVersion = new SemanticVersion(SmartStoreVersion.FullVersion); + var currentVersion = new SemanticVersion(SmartStoreVersion.Version); return package.Version > currentVersion; } @@ -190,6 +213,130 @@ private PackageInfo ExecuteUpdate(IPackage package) return info; } + #endregion + + + #region Migrations + + internal void ExecuteMigrations() + { + if (!DataSettings.DatabaseIsInstalled()) + return; + + var currentVersion = SmartStoreVersion.Version; + var prevVersion = DataSettings.Current.AppVersion ?? new Version(1, 0); + + if (prevVersion >= currentVersion) + return; + + if (prevVersion < new Version(2, 1)) + { + // we introduced app migrations in V2.1. So any version prior 2.1 + // has to perform the initial migration + MigrateInitial(); + } + + DataSettings.Current.AppVersion = currentVersion; + DataSettings.Current.Save(); + } + + private void MigrateInitial() + { + var installedPlugins = PluginFileParser.ParseInstalledPluginsFile(); + if (installedPlugins.Count == 0) + return; + + var renamedPlugins = new List(); + + var pluginRenameMap = new Dictionary + { + { "CurrencyExchange.ECB", null /* null means: remove it */ }, + { "CurrencyExchange.MoneyConverter", null }, + { "ExternalAuth.OpenId", null }, + { "Tax.Free", null }, + { "Api.WebApi", "SmartStore.WebApi" }, + { "DiscountRequirement.MustBeAssignedToCustomerRole", "SmartStore.DiscountRules" }, + { "DiscountRequirement.HadSpentAmount", "SmartStore.DiscountRules" }, + { "DiscountRequirement.HasAllProducts", "SmartStore.DiscountRules" }, + { "DiscountRequirement.HasOneProduct", "SmartStore.DiscountRules" }, + { "DiscountRequirement.Store", "SmartStore.DiscountRules" }, + { "DiscountRequirement.BillingCountryIs", "SmartStore.DiscountRules" }, + { "DiscountRequirement.ShippingCountryIs", "SmartStore.DiscountRules" }, + { "DiscountRequirement.HasPaymentMethod", "SmartStore.DiscountRules.HasPaymentMethod" }, + { "DiscountRequirement.HasShippingOption", "SmartStore.DiscountRules.HasShippingOption" }, + { "DiscountRequirement.PurchasedAllProducts", "SmartStore.DiscountRules.PurchasedProducts" }, + { "DiscountRequirement.PurchasedOneProduct", "SmartStore.DiscountRules.PurchasedProducts" }, + { "PromotionFeed.Froogle", "SmartStore.GoogleMerchantCenter" }, + { "PromotionFeed.Billiger", "SmartStore.Billiger" }, + { "PromotionFeed.ElmarShopinfo", "SmartStore.ElmarShopinfo" }, + { "PromotionFeed.Guenstiger", "SmartStore.Guenstiger" }, + { "Payments.AccardaKar", "SmartStore.AccardaKar" }, + { "Payments.AmazonPay", "SmartStore.AmazonPay" }, + { "Developer.DevTools", "SmartStore.DevTools" }, + { "ExternalAuth.Facebook", "SmartStore.FacebookAuth" }, + { "ExternalAuth.Twitter", "SmartStore.TwitterAuth" }, + { "SMS.Clickatell", "SmartStore.Clickatell" }, + { "Widgets.GoogleAnalytics", "SmartStore.GoogleAnalytics" }, + { "Misc.DemoShop", "SmartStore.DemoShopControlling" }, + { "Admin.OrderNumberFormatter", "SmartStore.OrderNumberFormatter" }, + { "Admin.Debitoor", "SmartStore.Debitoor" }, + { "Widgets.ETracker", "SmartStore.ETracker" }, + { "Payments.PayPalDirect", "SmartStore.PayPal" }, + { "Payments.PayPalStandard", "SmartStore.PayPal" }, + { "Payments.PayPalExpress", "SmartStore.PayPal" }, + { "Developer.Glimpse", "SmartStore.Glimpse" }, + { "Import.Biz", "SmartStore.BizImporter" }, + { "Payments.Sofortueberweisung", "SmartStore.Sofortueberweisung" }, + { "Payments.PostFinanceECommerce", "SmartStore.PostFinanceECommerce" }, + { "Misc.MailChimp", "SmartStore.MailChimp" }, + { "Mobile.SMS.Verizon", "SmartStore.Verizon" }, + { "Widgets.LivePersonChat", "SmartStore.LivePersonChat" }, + { "Payments.CashOnDelivery", "SmartStore.OfflinePayment" }, + { "Payments.Invoice", "SmartStore.OfflinePayment" }, + { "Payments.PayInStore", "SmartStore.OfflinePayment" }, + { "Payments.Prepayment", "SmartStore.OfflinePayment" }, + { "Payments.IPaymentCreditCard", "SmartStore.IPayment" }, + { "Payments.IPaymentDirectDebit", "SmartStore.IPayment" }, + { "Payments.AuthorizeNet", "SmartStore.AuthorizeNet" }, + { "Shipping.AustraliaPost", "SmartStore.AustraliaPost" }, + { "Shipping.CanadaPost", "SmartStore.CanadaPost" }, + { "Shipping.Fedex", "SmartStore.Fedex" }, + { "Shipping.UPS", "SmartStore.UPS" }, + { "Payments.Manual", "SmartStore.OfflinePayment" }, + { "Shipping.USPS", "SmartStore.USPS" }, + { "Widgets.TrustedShopsSeal", "SmartStore.TrustedShops" }, + { "Widgets.TrustedShopsCustomerReviews", "SmartStore.TrustedShops" }, + { "Widgets.TrustedShopsCustomerProtection", "SmartStore.TrustedShops" }, + { "Shipping.ByWeight", "SmartStore.ShippingByWeight" }, + { "Payments.DirectDebit", "SmartStore.OfflinePayment" }, + { "Tax.FixedRate", "SmartStore.Tax" }, + { "Tax.CountryStateZip", "SmartStore.Tax" }, + { "Shipping.ByTotal", "SmartStore.Shipping" }, + { "Shipping.FixedRate", "SmartStore.Shipping" } + }; + + foreach (var name in installedPlugins) + { + if (pluginRenameMap.ContainsKey(name)) + { + string newName = pluginRenameMap[name]; + if (newName != null && !renamedPlugins.Contains(newName)) + { + renamedPlugins.Add(newName); + } + } + else + { + renamedPlugins.Add(name); + } + } + + PluginFileParser.SaveInstalledPluginsFile(renamedPlugins); + } + + #endregion + + protected override void OnDispose(bool disposing) { if (disposing) diff --git a/src/Libraries/SmartStore.Core/PagedList.cs b/src/Libraries/SmartStore.Core/PagedList.cs index d3fe3802a0..4f4689496e 100644 --- a/src/Libraries/SmartStore.Core/PagedList.cs +++ b/src/Libraries/SmartStore.Core/PagedList.cs @@ -4,8 +4,6 @@ namespace SmartStore.Core { - - // codehint: sm-add (whole file) public abstract class PagedListBase : IPageable { @@ -21,16 +19,6 @@ protected PagedListBase(IPageable pageable) this.Init(pageable); } - protected PagedListBase(IEnumerable source, int pageIndex, int pageSize) - { - Guard.ArgumentNotNull(source, "source"); - Guard.PagingArgsValid(pageIndex, pageSize, "pageIndex", "pageSize"); - - this.PageIndex = pageIndex; - this.PageSize = pageSize; - this.TotalCount = source.GetCount(); - } - protected PagedListBase(int pageIndex, int pageSize, int totalItemsCount) { Guard.PagingArgsValid(pageIndex, pageSize, "pageIndex", "pageSize"); @@ -43,10 +31,10 @@ protected PagedListBase(int pageIndex, int pageSize, int totalItemsCount) // only here for compat reasons with nc public void LoadPagedList(IPagedList pagedList) { - this.Init(pagedList as IPageable); + this.Init(pagedList); } - public virtual void Init(IPageable pageable) + public void Init(IPageable pageable) { Guard.ArgumentNotNull(pageable, "pageable"); @@ -89,7 +77,10 @@ public int TotalPages { get { - var total = this.TotalCount / this.PageSize; + if (this.PageSize == 0) + return 0; + + var total = this.TotalCount / this.PageSize; if (this.TotalCount % this.PageSize > 0) total++; @@ -155,7 +146,8 @@ public virtual IEnumerator GetEnumerator() public class PagedList : PagedListBase { - public PagedList(int pageIndex, int pageSize, int totalItemsCount) : base(pageIndex, pageSize, totalItemsCount) + public PagedList(int pageIndex, int pageSize, int totalItemsCount) + : base(pageIndex, pageSize, totalItemsCount) { } } diff --git a/src/Libraries/SmartStore.Core/PagedList`T.cs b/src/Libraries/SmartStore.Core/PagedList`T.cs index b80ea3751c..af5039d810 100644 --- a/src/Libraries/SmartStore.Core/PagedList`T.cs +++ b/src/Libraries/SmartStore.Core/PagedList`T.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Data.Entity; +using System.Data.Entity.Infrastructure; namespace SmartStore.Core { @@ -18,9 +20,26 @@ public class PagedList : List, IPagedList /// Page size public PagedList(IQueryable source, int pageIndex, int pageSize) { - // codehint: sm-edit Guard.ArgumentNotNull(source, "source"); - Init(source.Skip(pageIndex * pageSize).Take(pageSize), pageIndex, pageSize, source.Count()); + + if (pageIndex == 0 && pageSize == int.MaxValue) + { + // avoid unnecessary SQL + Init(source, pageIndex, pageSize, source.Count()); + } + else + { + if (source.Provider is IDbAsyncQueryProvider) + { + // the Lambda overloads for Skip() and Take() let EF use cached query plans, thus slightly increasing performance. + var skip = pageIndex * pageSize; + Init(source.Skip(() => skip).Take(() => pageSize), pageIndex, pageSize, source.Count()); + } + else + { + Init(source.Skip(pageIndex * pageSize).Take(pageSize), pageIndex, pageSize, source.Count()); + } + } } /// @@ -31,8 +50,8 @@ public PagedList(IQueryable source, int pageIndex, int pageSize) /// Page size public PagedList(IList source, int pageIndex, int pageSize) { - // codehint: sm-edit Guard.ArgumentNotNull(source, "source"); + Init(source.Skip(pageIndex * pageSize).Take(pageSize), pageIndex, pageSize, source.Count); } @@ -45,12 +64,10 @@ public PagedList(IList source, int pageIndex, int pageSize) /// Total count public PagedList(IEnumerable source, int pageIndex, int pageSize, int totalCount) { - // codehint: sm-edit Guard.ArgumentNotNull(source, "source"); Init(source, pageIndex, pageSize, totalCount); } - // codehint: sm-add private void Init(IEnumerable source, int pageIndex, int pageSize, int totalCount) { Guard.PagingArgsValid(pageIndex, pageSize,"pageIndex", "pageSize"); diff --git a/src/Libraries/SmartStore.Core/Plugins/BasePlugin.cs b/src/Libraries/SmartStore.Core/Plugins/BasePlugin.cs index 16c8e45a85..80ae85fd5a 100644 --- a/src/Libraries/SmartStore.Core/Plugins/BasePlugin.cs +++ b/src/Libraries/SmartStore.Core/Plugins/BasePlugin.cs @@ -2,10 +2,6 @@ { public abstract class BasePlugin : IPlugin { - protected BasePlugin() - { - } - /// /// Gets or sets the plugin descriptor /// diff --git a/src/Libraries/SmartStore.Core/Plugins/IConfigurable.cs b/src/Libraries/SmartStore.Core/Plugins/IConfigurable.cs new file mode 100644 index 0000000000..5a0308eb79 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/IConfigurable.cs @@ -0,0 +1,19 @@ +using System; +using System.Web.Routing; + +namespace SmartStore.Core.Plugins +{ + /// + /// Marks a concrete provider or plugin implementation as configurable through the backend + /// + public interface IConfigurable + { + /// + /// Gets a route for provider or plugin configuration + /// + /// Action name + /// Controller name + /// Route values + void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/IPluginFinder.cs b/src/Libraries/SmartStore.Core/Plugins/IPluginFinder.cs index 9061cfaab5..51afd082ee 100644 --- a/src/Libraries/SmartStore.Core/Plugins/IPluginFinder.cs +++ b/src/Libraries/SmartStore.Core/Plugins/IPluginFinder.cs @@ -31,7 +31,6 @@ public interface IPluginFinder /// Plugin descriptors IEnumerable GetPluginDescriptors(bool installedOnly = true) where T : class, IPlugin; - // codehint: sm-add PluginDescriptor GetPluginDescriptorByAssembly(Assembly assembly, bool installedOnly = true); /// @@ -50,10 +49,5 @@ public interface IPluginFinder /// A value indicating whether to load only installed plugins /// >Plugin descriptor PluginDescriptor GetPluginDescriptorBySystemName(string systemName, bool installedOnly = true) where T : class, IPlugin; - - /// - /// Reload plugins - /// - void ReloadPlugins(); } } diff --git a/src/Libraries/SmartStore.Core/Plugins/PluginDescriptor.cs b/src/Libraries/SmartStore.Core/Plugins/PluginDescriptor.cs index 36d95826e2..0409454f60 100644 --- a/src/Libraries/SmartStore.Core/Plugins/PluginDescriptor.cs +++ b/src/Libraries/SmartStore.Core/Plugins/PluginDescriptor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; using System.Xml; @@ -19,16 +20,17 @@ public class PluginDescriptor : IComparable public PluginDescriptor() { this.Version = new Version("1.0"); - this.MinAppVersion = SmartStoreVersion.FullVersion; + this.MinAppVersion = SmartStoreVersion.Version; } - public PluginDescriptor(Assembly referencedAssembly, FileInfo originalAssemblyFile, Type pluginType) - : this() - { - this.ReferencedAssembly = referencedAssembly; - this.OriginalAssemblyFile = originalAssemblyFile; - this.PluginType = pluginType; - } + // Unit tests + public PluginDescriptor(Assembly referencedAssembly, FileInfo originalAssemblyFile, Type pluginType) + : this() + { + this.ReferencedAssembly = referencedAssembly; + this.OriginalAssemblyFile = originalAssemblyFile; + this.PluginType = pluginType; + } /// /// Plugin file name @@ -38,15 +40,8 @@ public PluginDescriptor(Assembly referencedAssembly, FileInfo originalAssemblyFi /// /// The physical path of the runtime plugin /// - public string PhysicalPath - { - get - { - return OriginalAssemblyFile.Directory.FullName; - } - } + public string PhysicalPath { get; set; } - // codehint: sm-add /// /// Gets the file name of the brand image (without path) /// or an empty string if no image is specified @@ -58,11 +53,11 @@ public string BrandImageFileName if (_brandImageFileName == null) { // "null" means we haven't checked yet! - var filesToCheck = new string[] { "branding.png", "branding.gif", "branding.jpg", "branding.jpeg" }; + var filesToCheck = new [] { "branding.png", "branding.gif", "branding.jpg", "branding.jpeg" }; var dir = this.PhysicalPath; foreach (var file in filesToCheck) { - if (File.Exists(Path.Combine(dir, file))) + if (File.Exists(Path.Combine(dir, "Content", file))) { _brandImageFileName = file; break; @@ -149,6 +144,12 @@ public bool IsInKnownGroup [DataMember] public string Author { get; set; } + /// + /// Gets or sets the project/marketplace url + /// + [DataMember] + public string Url { get; set; } + /// /// Gets or sets the display order /// @@ -161,27 +162,41 @@ public bool IsInKnownGroup [DataMember] public bool Installed { get; set; } + /// + /// Gets or sets the value indicating whether the plugin is configurable + /// + /// + /// A plugin is configurable when it implements the interface + /// + [DataMember] + public bool IsConfigurable { get; set; } + /// /// Gets or sets the root key of string resources. /// /// Tries to get it from first entry of resource XML file if not specified. In that case the first resource name should not contain a dot if it's not part of the root key. /// Otherwise you get the wrong root key. - public string ResourceRootKey { + public string ResourceRootKey + { get { - if (_resourceRootKey == null) { + if (_resourceRootKey == null) + { _resourceRootKey = ""; - - try { + try + { // try to get root-key from first entry of XML file - string localizationDir = Path.Combine(OriginalAssemblyFile.Directory.FullName, "Localization"); + string localizationDir = Path.Combine(PhysicalPath, "Localization"); - if (System.IO.Directory.Exists(localizationDir)) { + if (System.IO.Directory.Exists(localizationDir)) + { string filePath = System.IO.Directory.EnumerateFiles(localizationDir, "*.xml").FirstOrDefault(); - if (filePath.HasValue()) { + if (filePath.HasValue()) + { XmlDocument doc = new XmlDocument(); doc.Load(filePath); var node = doc.SelectSingleNode(@"//Language/LocaleResource"); - if (node != null) { + if (node != null) + { string key = node.Attributes["Name"].InnerText; if (key.HasValue() && key.Contains('.')) _resourceRootKey = key.Substring(0, key.LastIndexOf('.')); @@ -189,7 +204,8 @@ public string ResourceRootKey { } } } - catch (Exception exc) { + catch (Exception exc) + { exc.Dump(); } } @@ -219,15 +235,16 @@ public IPlugin Instance() return Instance(); } - public int CompareTo(PluginDescriptor other) + [SuppressMessage("ReSharper", "StringCompareToIsCultureSpecific")] + public int CompareTo(PluginDescriptor other) { - if (DisplayOrder != other.DisplayOrder) - return DisplayOrder.CompareTo(other.DisplayOrder); - else - return FriendlyName.CompareTo(other.FriendlyName); + if (DisplayOrder != other.DisplayOrder) + return DisplayOrder.CompareTo(other.DisplayOrder); + else if (FriendlyName != null) + return FriendlyName.CompareTo(other.FriendlyName); + return 0; } - /// codehint: sm-add public string GetSettingKey(string name) { return "PluginSetting.{0}.{1}".FormatWith(SystemName, name); diff --git a/src/Libraries/SmartStore.Core/Plugins/PluginFileParser.cs b/src/Libraries/SmartStore.Core/Plugins/PluginFileParser.cs index fed5d61056..c12ea913e3 100644 --- a/src/Libraries/SmartStore.Core/Plugins/PluginFileParser.cs +++ b/src/Libraries/SmartStore.Core/Plugins/PluginFileParser.cs @@ -20,48 +20,49 @@ public override int Compare(string x, string y) } } - // codehint: sm-add internal readonly static string[] KnownGroups = new string[] { - "Admin", // NEW - "Marketing", // NEW + "Admin", + "Marketing", "Payment", "Shipping", "Tax", - "Analytics", // NEW - "CMS", // NEW - "SEO", // NEW - "PromotionFeed", - "DiscountRequirement", - "Import", - "CurrencyExchange", - "ExternalAuth", - "Api", // NEW - "Mobile", - "Social", // NEW - "Security", // NEW - "Widget", - "Developer", // NEW + "Analytics", + "CMS", + "Media", + "SEO", + "Data", + "Globalization", + "Api", + "Mobile", + "Social", + "Security", + "Developer", "Sales", + "Design", "Misc" }; public readonly static IComparer KnownGroupComparer = new GroupComparer(); + public readonly static string InstalledPluginsFilePath = CommonHelper.MapPath("~/App_Data/InstalledPlugins.txt"); - public static IList ParseInstalledPluginsFile(string filePath) + public static HashSet ParseInstalledPluginsFile(string filePath = null) { - //read and parse the file + filePath = filePath ?? InstalledPluginsFilePath; + + var lines = new HashSet(StringComparer.OrdinalIgnoreCase); + + // read and parse the file if (!File.Exists(filePath)) - return new List(); + return lines; var text = File.ReadAllText(filePath); if (String.IsNullOrEmpty(text)) - return new List(); + return lines; //Old way of file reading. This leads to unexpected behavior when a user's FTP program transfers these files as ASCII (\r\n becomes \n). //var lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); - var lines = new List(); using (var reader = new StringReader(text)) { string str; @@ -75,11 +76,13 @@ public static IList ParseInstalledPluginsFile(string filePath) return lines; } - public static void SaveInstalledPluginsFile(IList pluginSystemNames, string filePath) + public static void SaveInstalledPluginsFile(ICollection pluginSystemNames, string filePath = null) { if (pluginSystemNames == null || pluginSystemNames.Count == 0) return; + filePath = filePath ?? InstalledPluginsFilePath; + string result = ""; foreach (var sn in pluginSystemNames) result += string.Format("{0}{1}", sn, Environment.NewLine); @@ -95,7 +98,9 @@ public static PluginDescriptor ParsePluginDescriptionFile(string filePath) if (String.IsNullOrEmpty(text)) return descriptor; - descriptor.FolderName = new DirectoryInfo(Path.GetDirectoryName(filePath)).Name; + string dirName = Path.GetDirectoryName(filePath); + descriptor.PhysicalPath = dirName; + descriptor.FolderName = new DirectoryInfo(dirName).Name; var settings = new List(); using (var reader = new StringReader(text)) @@ -124,12 +129,12 @@ public static PluginDescriptor ParsePluginDescriptionFile(string filePath) string key = setting.Substring(0, separatorIndex).Trim(); string value = setting.Substring(separatorIndex + 1).Trim(); - group = null; + //group = null; switch (key) { case "Group": - group = value; // descriptor.Group = value; + group = value; break; case "FriendlyName": descriptor.FriendlyName = value; @@ -156,6 +161,9 @@ public static PluginDescriptor ParsePluginDescriptionFile(string filePath) case "Author": descriptor.Author = value; break; + case "Url": + descriptor.Url = value; + break; case "DisplayOrder": { int displayOrder; @@ -167,42 +175,29 @@ public static PluginDescriptor ParsePluginDescriptionFile(string filePath) descriptor.PluginFileName = value; break; case "ResourceRootKey": - descriptor.ResourceRootKey = value; // codehint: sm-add + descriptor.ResourceRootKey = value; break; } } - // codehint: sm-add - descriptor.Group = GetKnownGroupName(descriptor.SystemName); - if (descriptor.Group == "Misc" && group.HasValue()) - { - descriptor.Group = group; - } + if (IsKnownGroup(group)) + { + descriptor.Group = group; + } + else + { + descriptor.Group = "Misc"; + } return descriptor; } - - // codehint: sm-add - private static string GetKnownGroupName(string systemName) - { - if (systemName.IsEmpty()) - { - return "Misc"; - } - - string token = systemName.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries)[0]; - - int idx = Array.FindIndex( - KnownGroups, - x => x.Equals(token, StringComparison.OrdinalIgnoreCase) || x.Equals(Inflector.Singularize(token), StringComparison.OrdinalIgnoreCase)); - if (idx >= 0) - { - return KnownGroups[idx]; - } - - return "Misc"; - } + private static bool IsKnownGroup(string group) + { + if (group.IsEmpty()) + return false; + return KnownGroups.Contains(group, StringComparer.OrdinalIgnoreCase); + } public static void SavePluginDescriptionFile(PluginDescriptor plugin) { @@ -210,9 +205,9 @@ public static void SavePluginDescriptionFile(PluginDescriptor plugin) throw new ArgumentException("plugin"); //get the Description.txt file path - if (plugin.OriginalAssemblyFile == null) + if (plugin.PhysicalPath.IsEmpty()) throw new Exception(string.Format("Cannot load original assembly path for {0} plugin.", plugin.SystemName)); - var filePath = Path.Combine(plugin.OriginalAssemblyFile.Directory.FullName, "Description.txt"); + var filePath = Path.Combine(plugin.PhysicalPath, "Description.txt"); if (!File.Exists(filePath)) throw new Exception(string.Format("Description file for {0} plugin does not exist. {1}", plugin.SystemName, filePath)); @@ -227,6 +222,7 @@ public static void SavePluginDescriptionFile(PluginDescriptor plugin) keyValues.Add(new KeyValuePair("Version", plugin.Version.ToString())); keyValues.Add(new KeyValuePair("MinAppVersion", string.Join(",", plugin.MinAppVersion))); keyValues.Add(new KeyValuePair("Author", plugin.Author)); + keyValues.Add(new KeyValuePair("Url", plugin.Url)); keyValues.Add(new KeyValuePair("DisplayOrder", plugin.DisplayOrder.ToString())); keyValues.Add(new KeyValuePair("FileName", plugin.PluginFileName)); keyValues.Add(new KeyValuePair("ResourceRootKey", plugin.ResourceRootKey)); diff --git a/src/Libraries/SmartStore.Core/Plugins/PluginFinder.cs b/src/Libraries/SmartStore.Core/Plugins/PluginFinder.cs index 09c9a5ace4..d911e202e6 100644 --- a/src/Libraries/SmartStore.Core/Plugins/PluginFinder.cs +++ b/src/Libraries/SmartStore.Core/Plugins/PluginFinder.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -10,18 +11,31 @@ namespace SmartStore.Core.Plugins /// public class PluginFinder : IPluginFinder { - private IList _plugins; - private bool _arePluginsLoaded = false; - protected virtual void EnsurePluginsAreLoaded() + private IList _plugins; + private readonly IDictionary _nameMap = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + private readonly IDictionary _assemblyMap = new Dictionary(); + + private static readonly object s_lock = new object(); + + public PluginFinder() { - if (!_arePluginsLoaded) + lock (s_lock) { - var foundPlugins = PluginManager.ReferencedPlugins.ToList(); - foundPlugins.Sort(); //sort - _plugins = foundPlugins.ToList(); + LoadPlugins(); + } + } + + private void LoadPlugins() + { + var plugins = PluginManager.ReferencedPlugins.ToList(); + plugins.Sort(); //sort + _plugins = plugins; - _arePluginsLoaded = true; + foreach (var plugin in plugins) + { + _nameMap[plugin.SystemName] = plugin; + _assemblyMap[plugin.ReferencedAssembly] = plugin; } } @@ -33,8 +47,6 @@ protected virtual void EnsurePluginsAreLoaded() /// Plugins public virtual IEnumerable GetPlugins(bool installedOnly = true) where T : class, IPlugin { - EnsurePluginsAreLoaded(); - foreach (var plugin in _plugins) if (typeof(T).IsAssignableFrom(plugin.PluginType)) if (!installedOnly || plugin.Installed) @@ -48,8 +60,6 @@ public virtual IEnumerable GetPlugins(bool installedOnly = true) where T : /// Plugin descriptors public virtual IEnumerable GetPluginDescriptors(bool installedOnly = true) { - EnsurePluginsAreLoaded(); - foreach (var plugin in _plugins) if (!installedOnly || plugin.Installed) yield return plugin; @@ -64,8 +74,6 @@ public virtual IEnumerable GetPluginDescriptors(bool installed public virtual IEnumerable GetPluginDescriptors(bool installedOnly = true) where T : class, IPlugin { - EnsurePluginsAreLoaded(); - foreach (var plugin in _plugins) if (typeof(T).IsAssignableFrom(plugin.PluginType)) if (!installedOnly || plugin.Installed) @@ -74,8 +82,14 @@ public virtual IEnumerable GetPluginDescriptors(bool instal public virtual PluginDescriptor GetPluginDescriptorByAssembly(Assembly assembly, bool installedOnly = true) { - Guard.ArgumentNotNull(() => assembly); - return GetPluginDescriptors(installedOnly).FirstOrDefault(p => p.ReferencedAssembly == assembly); + PluginDescriptor descriptor; + if (assembly != null && _assemblyMap.TryGetValue(assembly, out descriptor)) + { + if (!installedOnly || descriptor.Installed) + return descriptor; + } + + return null; } /// @@ -86,8 +100,14 @@ public virtual PluginDescriptor GetPluginDescriptorByAssembly(Assembly assembly, /// >Plugin descriptor public virtual PluginDescriptor GetPluginDescriptorBySystemName(string systemName, bool installedOnly = true) { - return GetPluginDescriptors(installedOnly) - .SingleOrDefault(p => p.SystemName.Equals(systemName, StringComparison.InvariantCultureIgnoreCase)); + PluginDescriptor descriptor; + if (systemName.HasValue() && _nameMap.TryGetValue(systemName, out descriptor)) + { + if (!installedOnly || descriptor.Installed) + return descriptor; + } + + return null; } /// @@ -99,17 +119,18 @@ public virtual PluginDescriptor GetPluginDescriptorBySystemName(string systemNam /// >Plugin descriptor public virtual PluginDescriptor GetPluginDescriptorBySystemName(string systemName, bool installedOnly = true) where T : class, IPlugin { - return GetPluginDescriptors(installedOnly) - .SingleOrDefault(p => p.SystemName.Equals(systemName, StringComparison.InvariantCultureIgnoreCase)); + PluginDescriptor descriptor; + if (systemName.HasValue() && _nameMap.TryGetValue(systemName, out descriptor)) + { + if (!installedOnly || descriptor.Installed) + { + if (typeof(T).IsAssignableFrom(descriptor.PluginType)) + return descriptor; + } + } + + return null; } - /// - /// Reload plugins - /// - public virtual void ReloadPlugins() - { - _arePluginsLoaded = false; - EnsurePluginsAreLoaded(); - } } } diff --git a/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs b/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs index cbad6354fb..7fd04123aa 100644 --- a/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs +++ b/src/Libraries/SmartStore.Core/Plugins/PluginManager.cs @@ -13,7 +13,7 @@ using System.Web.Hosting; using Microsoft.Web.Infrastructure; using Microsoft.Web.Infrastructure.DynamicModuleHelper; -using SmartStore.Core.ComponentModel; +using SmartStore.ComponentModel; using SmartStore.Core.Infrastructure.DependencyManagement; using SmartStore.Core.Plugins; using SmartStore.Core.Packaging; @@ -37,7 +37,7 @@ public class PluginManager private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); private static DirectoryInfo _shadowCopyFolder; - private static readonly string _installedPluginsFilePath = CommonHelper.MapPath("~/App_Data/InstalledPlugins.txt"); + //private static readonly string _installedPluginsFilePath = CommonHelper.MapPath("~/App_Data/InstalledPlugins.txt"); private static readonly string _pluginsPath = "~/Plugins"; private static readonly string _shadowCopyPath = "~/Plugins/bin"; private static bool _clearShadowDirectoryOnStartup; @@ -85,12 +85,17 @@ public static IEnumerable IncompatiblePlugins /// public static void Initialize() { - var updater = new AppUpdater(); - if (updater.TryUpdate()) + using (var updater = new AppUpdater()) { - // [...] + // update from NuGet package, if it exists and is valid + if (updater.TryUpdateFromPackage()) + { + // [...] + } + + // execute migrations + updater.ExecuteMigrations(); } - updater.Dispose(); // adding a process-specific environment path (either bin/x86 or bin/amd64) // ensures that unmanaged native dependencies can be resolved successfully. @@ -108,9 +113,7 @@ public static void Initialize() var incompatiblePlugins = new List(); _clearShadowDirectoryOnStartup = CommonHelper.GetAppSetting("sm:ClearPluginsShadowDirectoryOnStartup", true); try - { - var installedPluginSystemNames = PluginFileParser.ParseInstalledPluginsFile(_installedPluginsFilePath); - + { Debug.WriteLine("Creating shadow copy folder and querying for dlls"); //ensure folders are created Directory.CreateDirectory(pluginFolderPath); @@ -140,10 +143,12 @@ public static void Initialize() where !x.IsMatch("bin") && !x.IsMatch("_Backup") select Path.Combine(pluginFolderPath, x); + var installedPluginSystemNames = PluginFileParser.ParseInstalledPluginsFile(); + // now activate all plugins foreach (var pluginPath in pluginPaths) { - var result = LoadPluginFromFolder(pluginPath); + var result = LoadPluginFromFolder(pluginPath, installedPluginSystemNames); if (result != null) { if (result.IsIncompatible) @@ -173,19 +178,10 @@ public static void Initialize() } IncompatiblePlugins = incompatiblePlugins.AsReadOnly(); - } } - public static LoadPluginResult LoadPluginFromFolder(string pluginFolderPath) - { - using (Locker.GetWriteLock()) - { - return LoadPluginFromFolder(pluginFolderPath, null); - } - } - - private static LoadPluginResult LoadPluginFromFolder(string pluginFolderPath, IList installedPluginSystemNames) + private static LoadPluginResult LoadPluginFromFolder(string pluginFolderPath, ICollection installedPluginSystemNames) { Guard.ArgumentNotEmpty(() => pluginFolderPath); @@ -234,11 +230,11 @@ private static LoadPluginResult LoadPluginFromFolder(string pluginFolderPath, IL if (installedPluginSystemNames == null) { - installedPluginSystemNames = PluginFileParser.ParseInstalledPluginsFile(_installedPluginsFilePath); + installedPluginSystemNames = PluginFileParser.ParseInstalledPluginsFile(); } // set 'Installed' property - descriptor.Installed = installedPluginSystemNames.Any(x => x.Equals(descriptor.SystemName, StringComparison.InvariantCultureIgnoreCase)); + descriptor.Installed = installedPluginSystemNames.Contains(descriptor.SystemName); try { @@ -282,6 +278,7 @@ private static LoadPluginResult LoadPluginFromFolder(string pluginFolderPath, IL if (typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface && t.IsClass && !t.IsAbstract) { descriptor.PluginType = t; + descriptor.IsConfigurable = typeof(IConfigurable).IsAssignableFrom(t); pluginFound = true; } else if (descriptor.Installed && typeof(IPreApplicationStart).IsAssignableFrom(t) && !t.IsInterface && t.IsClass && !t.IsAbstract && t.HasDefaultConstructor()) @@ -329,12 +326,12 @@ public static void MarkPluginAsInstalled(string systemName) throw new ArgumentNullException("systemName"); var installedPluginSystemNames = GetInstalledPluginNames(); - bool alreadyMarkedAsInstalled = installedPluginSystemNames.Any(x => x.IsCaseInsensitiveEqual(systemName)); + bool alreadyMarkedAsInstalled = installedPluginSystemNames.Contains(systemName); if (!alreadyMarkedAsInstalled) { installedPluginSystemNames.Add(systemName); } - PluginFileParser.SaveInstalledPluginsFile(installedPluginSystemNames, _installedPluginsFilePath); + PluginFileParser.SaveInstalledPluginsFile(installedPluginSystemNames); } /// @@ -346,12 +343,12 @@ public static void MarkPluginAsUninstalled(string systemName) Guard.ArgumentNotEmpty(() => systemName); var installedPluginSystemNames = GetInstalledPluginNames(); - bool alreadyMarkedAsInstalled = installedPluginSystemNames.Any(x => x.IsCaseInsensitiveEqual(systemName)); + bool alreadyMarkedAsInstalled = installedPluginSystemNames.Contains(systemName); if (alreadyMarkedAsInstalled) { installedPluginSystemNames.Remove(systemName); } - PluginFileParser.SaveInstalledPluginsFile(installedPluginSystemNames, _installedPluginsFilePath); + PluginFileParser.SaveInstalledPluginsFile(installedPluginSystemNames); } /// @@ -359,14 +356,14 @@ public static void MarkPluginAsUninstalled(string systemName) /// public static void MarkAllPluginsAsUninstalled() { - var filePath = _installedPluginsFilePath; + var filePath = PluginFileParser.InstalledPluginsFilePath; if (File.Exists(filePath)) File.Delete(filePath); } - private static IList GetInstalledPluginNames() + private static ICollection GetInstalledPluginNames() { - var filePath = _installedPluginsFilePath; + var filePath = PluginFileParser.InstalledPluginsFilePath; if (!File.Exists(filePath)) { using (File.Create(filePath)) @@ -375,7 +372,7 @@ private static IList GetInstalledPluginNames() } } - var installedPluginSystemNames = PluginFileParser.ParseInstalledPluginsFile(_installedPluginsFilePath); + var installedPluginSystemNames = PluginFileParser.ParseInstalledPluginsFile(); return installedPluginSystemNames; } @@ -412,12 +409,12 @@ public static bool IsAssumedCompatible(Version minAppVersion) { Guard.ArgumentNotNull(() => minAppVersion); - if (SmartStoreVersion.FullVersion == minAppVersion) + if (SmartStoreVersion.Version == minAppVersion) { return true; } - if (SmartStoreVersion.FullVersion < minAppVersion) + if (SmartStoreVersion.Version < minAppVersion) { return false; } diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/DependentWidgetsAttribute.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/DependentWidgetsAttribute.cs new file mode 100644 index 0000000000..384b6a7627 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/DependentWidgetsAttribute.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.Core.Plugins +{ + /// + /// Enables provider developers to specify one or many widgets, which + /// should automatically get (de)activated when the provider gets (de)activated. + /// Useful in scenarios where separate widgets are responsible for the displaying of provider data. + /// + /// + /// A widget should definitely NOT depend on multiple providers as the activation + /// only occurs on a single item base. + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class DependentWidgetsAttribute : Attribute + { + public DependentWidgetsAttribute(params string[] widgetSystemNames) + { + WidgetSystemNames = widgetSystemNames; + } + + public string[] WidgetSystemNames { get; private set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/DisplayOrderAttribute.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/DisplayOrderAttribute.cs new file mode 100644 index 0000000000..33a8b3b13e --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/DisplayOrderAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace SmartStore.Core.Plugins +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)] + public sealed class DisplayOrderAttribute : Attribute + { + public DisplayOrderAttribute(int displayOrder) + { + DisplayOrder = displayOrder; + } + + public int DisplayOrder { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/FriendlyNameAttribute.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/FriendlyNameAttribute.cs new file mode 100644 index 0000000000..e2be7dc7ce --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/FriendlyNameAttribute.cs @@ -0,0 +1,19 @@ +using System; + +namespace SmartStore.Core.Plugins +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)] + public sealed class FriendlyNameAttribute : Attribute + { + public FriendlyNameAttribute(string name) + { + Guard.ArgumentNotNull(() => name); + + Name = name; + } + + public string Name { get; set; } + + public string Description { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/IProvider.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/IProvider.cs new file mode 100644 index 0000000000..f0dc56eb1a --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/IProvider.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Routing; + +namespace SmartStore.Core.Plugins +{ + public interface IProvider + { + } + + public sealed class Provider where TProvider : IProvider + { + private readonly Lazy _lazy; + + public Provider(Lazy lazy) + { + this._lazy = lazy; + } + + public TProvider Value + { + get { return _lazy.Value; } + } + + public ProviderMetadata Metadata + { + get { return _lazy.Metadata; } + } + + public bool IsValueCreated + { + get { return _lazy.IsValueCreated; } + } + + public Lazy ToLazy() + { + return _lazy; + } + + public override string ToString() + { + return _lazy.Metadata.SystemName; + } + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/IProviderManager.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/IProviderManager.cs new file mode 100644 index 0000000000..c2a10fe5b8 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/IProviderManager.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace SmartStore.Core.Plugins +{ + public interface IProviderManager + { + Provider GetProvider(string systemName, int storeId = 0) where TProvider : IProvider; + + Provider GetProvider(string systemName, int storeId = 0); + + IEnumerable> GetAllProviders(int storeId = 0) where TProvider : IProvider; + + IEnumerable> GetAllProviders(int storeId = 0); + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/IUserEditable.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/IUserEditable.cs new file mode 100644 index 0000000000..8544372396 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/IUserEditable.cs @@ -0,0 +1,8 @@ +using System; + +namespace SmartStore.Core.Plugins +{ + public interface IUserEditable + { + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/IsHiddenAttribute.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/IsHiddenAttribute.cs new file mode 100644 index 0000000000..6ba32b9d5a --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/IsHiddenAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace SmartStore.Core.Plugins +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public sealed class IsHiddenAttribute : Attribute + { + public IsHiddenAttribute(bool isHidden) + { + IsHidden = isHidden; + } + + public bool IsHidden { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs new file mode 100644 index 0000000000..d07a628170 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/ProviderMetadata.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Core.Plugins +{ + public class ProviderMetadata + { + /// + /// Gets or sets the provider type + /// + public Type ProviderType { get; set; } + + /// + /// Gets or sets the provider's group name + /// + public string GroupName { get; set; } + + /// + /// Gets or sets the provider system name + /// + public string SystemName { get; set; } + + /// + /// Gets or sets the resource key pattern for user data (e.g. FriendlyName) + /// + /// + /// Plugins.{1}.{0} > 0 = provider system name, 1 = propertyname + /// + public string ResourceKeyPattern { get; set; } + + /// + /// Gets or sets the setting key pattern for user data (e.g. DisplayOrder) + /// + /// + /// Plugins.{0}.{1} > 0 = provider system name, 1 = propertyname + /// + public string SettingKeyPattern { get; set; } + + /// + /// Gets or sets the provider friendly name + /// + public string FriendlyName { get; set; } + + /// + /// Gets or sets the provider description + /// + public string Description { get; set; } + + /// + /// Gets or sets the display order + /// + public int DisplayOrder { get; set; } + + /// + /// Gets or sets a value indicating whether the provider is configurable (by implementing ) + /// + public bool IsConfigurable { get; set; } + + /// + /// Gets or sets a value indicating whether the provider is editable by the user (by implementing ) + /// + /// + /// A provider is editable if the user is allowed to change display order and/or localize display name + /// + public bool IsEditable { get; set; } + + /// + /// Gets or sets a value indicating whether the provider is hidden (by decorating with ) + /// + public bool IsHidden { get; set; } + + /// + /// Gets or sets flags that reflects what features of export data processing is supported by a provider + /// + public ExportFeatures ExportFeatures { get; set; } + + /// + /// Gets or sets an array of widget system names, which depend on the current provider + /// + /// + /// Dependent widgets get automatically (de)activated when their parent providers get (de)activated + /// + public string[] DependentWidgets { get; set; } + + /// + /// Gets or sets the instance in which the provider is implemented + /// + /// The value is null, if the provider is part of the application core + public PluginDescriptor PluginDescriptor { get; set; } + + public string GetSettingKey(string name) + { + return SettingKeyPattern.FormatWith(SystemName, name); + } + + public override string ToString() + { + return "Provider '{0}' - {1}".FormatCurrent(SystemName, FriendlyName); + } + + public override bool Equals(object obj) + { + var other = obj as ProviderMetadata; + return other != null && + SystemName != null && + SystemName.Equals(other.SystemName); + } + + public override int GetHashCode() + { + return SystemName.GetHashCode(); + } + } +} diff --git a/src/Libraries/SmartStore.Core/Plugins/Providers/SystemNameAttribute.cs b/src/Libraries/SmartStore.Core/Plugins/Providers/SystemNameAttribute.cs new file mode 100644 index 0000000000..60e290daa1 --- /dev/null +++ b/src/Libraries/SmartStore.Core/Plugins/Providers/SystemNameAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace SmartStore.Core.Plugins +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)] + public sealed class SystemNameAttribute : Attribute + { + public SystemNameAttribute(string name) + { + Guard.ArgumentNotEmpty(() => name); + Name = name; + } + + public string Name { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Core/RouteInfo.cs b/src/Libraries/SmartStore.Core/RouteInfo.cs index abe3cec0a0..b6856d1a0f 100644 --- a/src/Libraries/SmartStore.Core/RouteInfo.cs +++ b/src/Libraries/SmartStore.Core/RouteInfo.cs @@ -5,26 +5,43 @@ namespace SmartStore { - public class RouteInfo { + public RouteInfo(RouteInfo cloneFrom) + : this(cloneFrom.Action, cloneFrom.Controller, new RouteValueDictionary(cloneFrom.RouteValues)) + { + Guard.ArgumentNotNull(() => cloneFrom); + } - public RouteInfo(string action, string controller, object routeValues) + public RouteInfo(string action, object routeValues) + : this(action, null, routeValues) + { + } + + public RouteInfo(string action, string controller, object routeValues) : this(action, controller, new RouteValueDictionary(routeValues)) { - Guard.ArgumentNotNull(() => routeValues); } - public RouteInfo(string action, string controller, IDictionary routeValues) + public RouteInfo(string action, IDictionary routeValues) + : this(action, null, routeValues) + { + } + + public RouteInfo(string action, string controller, IDictionary routeValues) : this(action, controller, new RouteValueDictionary(routeValues)) { Guard.ArgumentNotNull(() => routeValues); } - public RouteInfo(string action, string controller, RouteValueDictionary routeValues) + public RouteInfo(string action, RouteValueDictionary routeValues) + : this(action, null, routeValues) + { + } + + public RouteInfo(string action, string controller, RouteValueDictionary routeValues) { Guard.ArgumentNotEmpty(() => action); - Guard.ArgumentNotEmpty(() => controller); Guard.ArgumentNotNull(() => routeValues); this.Action = action; @@ -51,5 +68,4 @@ public RouteValueDictionary RouteValues } } - } diff --git a/src/Libraries/SmartStore.Core/Security/SmartStorePrincipal.cs b/src/Libraries/SmartStore.Core/Security/SmartStorePrincipal.cs new file mode 100644 index 0000000000..991551ca7c --- /dev/null +++ b/src/Libraries/SmartStore.Core/Security/SmartStorePrincipal.cs @@ -0,0 +1,39 @@ +using System.Security; +using System.Security.Claims; +using System.Security.Principal; +using System.Web.Security; +using SmartStore.Core.Domain.Customers; + +namespace SmartStore.Core +{ + + public class SmartStoreIdentity : ClaimsIdentity + { + [SecuritySafeCritical] + public SmartStoreIdentity(int customerId, string name, string type) + : base(new GenericIdentity(name, type)) + { + CustomerId = customerId; + } + + public int CustomerId { get; private set; } + + public override bool IsAuthenticated { get { return CustomerId != 0; } } + } + + + public class SmartStorePrincipal : IPrincipal + { + public SmartStorePrincipal(Customer customer, string type) + { + this.Identity = new SmartStoreIdentity(customer.Id, customer.Username, type); + } + + public bool IsInRole(string role) + { + return (Identity != null && Identity.IsAuthenticated && role.HasValue() && Roles.IsUserInRole(Identity.Name, role)); + } + + public IIdentity Identity { get; private set; } + } +} diff --git a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj index f83369af32..a14afb2ba4 100644 --- a/src/Libraries/SmartStore.Core/SmartStore.Core.csproj +++ b/src/Libraries/SmartStore.Core/SmartStore.Core.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,7 +10,7 @@ Properties SmartStore.Core SmartStore.Core - v4.5 + v4.5.1 512 @@ -62,23 +62,21 @@ MinimumRecommendedRules.ruleset - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + True False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - - - False - ..\..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll True @@ -87,9 +85,9 @@ ..\..\packages\Microsoft.Web.Xdt.1.0.0\lib\net40\Microsoft.Web.XmlTransform.dll - - False - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True False @@ -100,36 +98,37 @@ - ..\..\packages\System.Linq.Dynamic.1.0.0\lib\net40\System.Linq.Dynamic.dll + + False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - + False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll @@ -144,14 +143,70 @@ Properties\AssemblyVersionInfo.cs - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -172,10 +227,6 @@ - - - - @@ -197,7 +248,6 @@ - @@ -215,7 +265,6 @@ - @@ -261,9 +310,8 @@ - - + @@ -307,15 +355,12 @@ - - - @@ -329,8 +374,11 @@ + + + + - @@ -392,24 +440,17 @@ - - - - - - - @@ -474,7 +515,6 @@ - @@ -521,19 +561,23 @@ - + - - + + + - + + + + @@ -554,6 +598,7 @@ + @@ -562,6 +607,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201407191010096_BetterReturnRequest.cs b/src/Libraries/SmartStore.Data/Migrations/201407191010096_BetterReturnRequest.cs index d1ccc55ff1..66824ec8ed 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201407191010096_BetterReturnRequest.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201407191010096_BetterReturnRequest.cs @@ -8,17 +8,8 @@ public partial class BetterReturnRequest : DbMigration, ILocaleResourcesProvider { public override void Up() { - AddColumn("dbo.Order", "UpdatedOnUtc", c => c.DateTime(nullable: false)); + AddColumn("dbo.Order", "UpdatedOnUtc", c => c.DateTime(nullable: false, defaultValue: DateTime.UtcNow)); AddColumn("dbo.Order", "RewardPointsRemaining", c => c.Int()); - - try - { - Sql("Update [dbo].[Order] Set UpdatedOnUtc = CreatedOnUtc"); - } - catch (Exception exc) - { - exc.Dump(); - } } public override void Down() @@ -35,11 +26,14 @@ public bool RollbackOnFailure public void Seed(SmartObjectContext context) { context.MigrateLocaleResources(MigrateLocaleResources); + + context.Execute("Update [dbo].[Order] Set UpdatedOnUtc = CreatedOnUtc"); } public void MigrateLocaleResources(LocaleResourcesBuilder builder) { - builder.Delete("Admin.Orders.Products.ReturnRequests"); + builder.Delete("Admin.Orders.Products.ReturnRequests", "Admin.Orders.Fields.CancelOrderTotals", "Admin.Orders.Products.AddNew.Note2", + "Admin.Catalog.Products.List.DownloadPDF"); builder.AddOrUpdate("Admin.Orders.Products.ReturnRequest", "Return request", @@ -58,26 +52,28 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) "Rcksendung akzeptieren"); - builder.AddOrUpdate("Admin.Orders.OrderItem.Cancel.Info", + builder.AddOrUpdate("Admin.Orders.OrderItem.Update.Info", "Stock quantity old {0}, new {1}.
Reward points old {2}, new {3}.", "Lagerbestand alt {0}, neu {1}.
Bonuspunkte alt {2}, neu {3}."); - builder.AddOrUpdate("Admin.Orders.OrderItem.Cancel.Caption", - "Remove product", - "Produkt entfernen"); - - builder.AddOrUpdate("Admin.Orders.OrderItem.Cancel.Fields.AdjustInventory", + builder.AddOrUpdate("Admin.Orders.OrderItem.AutoUpdate.AdjustInventory", "Adjust inventory", "Lagerbestand anpassen", - "Determines whether to increase the stock quantity.", - "Legt fest, ob der Lagerbestand wieder erhht werden soll."); + "Determines whether to adjust the stock quantity proportionately.", + "Legt fest, ob der Lagerbestand anteilig angepasst werden soll."); - builder.AddOrUpdate("Admin.Orders.OrderItem.Cancel.Fields.ReduceRewardPoints", - "Adjust reward points", - "Bonuspunkte anpassen", + builder.AddOrUpdate("Admin.Orders.OrderItem.AutoUpdate.UpdateRewardPoints", + "Reduce reward points", + "Bonuspunkte abziehen", "Determines whether granted reward points should be deducted again proportionately.", "Legt fest, ob gewhrte Bonuspunkte wieder anteilig abgezogen werden sollen."); + builder.AddOrUpdate("Admin.Orders.OrderItem.AutoUpdate.UpdateTotals", + "Update totals", + "Summen anpassen", + "Determines whether to update the order totals.", + "Legt fest, ob die Auftragssummen angepasst werden sollen."); + builder.AddOrUpdate("Admin.Common.ExportToPdf.All", "Export to PDF (all)", diff --git a/src/Libraries/SmartStore.Data/Migrations/201408071158147_MultistorePoll.cs b/src/Libraries/SmartStore.Data/Migrations/201408071158147_MultistorePoll.cs index d21802284e..7b37bbfd6f 100644 --- a/src/Libraries/SmartStore.Data/Migrations/201408071158147_MultistorePoll.cs +++ b/src/Libraries/SmartStore.Data/Migrations/201408071158147_MultistorePoll.cs @@ -55,7 +55,7 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder) builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.EnableHtmlTextCollapser", "Truncate long texts", "Langtexte krzen", - "Option to truncate long texts and to only shown on click in full length.", + "Option to truncate long texts and to only show on click in full length.", "Option, bei der Langtexte gekrzt und erst auf Klick in voller Lnge angezeigt werden."); builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.HtmlTextCollapsedHeight", diff --git a/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.Designer.cs new file mode 100644 index 0000000000..50e366aa26 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class CheckoutCommmentBox : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(CheckoutCommmentBox)); + + string IMigrationMetadata.Id + { + get { return "201408291450443_CheckoutCommmentBox"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.cs b/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.cs new file mode 100644 index 0000000000..90e7a135e2 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.cs @@ -0,0 +1,49 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class CheckoutCommmentBox : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public override void Up() + { + AddColumn("dbo.Order", "CustomerOrderComment", c => c.String()); + } + + public override void Down() + { + DropColumn("dbo.Order", "CustomerOrderComment"); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + // add or update resources + builder.AddOrUpdate("ShoppingCart.CommentBox") + .Value("Do you want to tell us something regarding this order?") + .Value("de", "Mchten Sie uns etwas Wichtiges zu Ihrer Bestellung mitteilen?"); + + builder.AddOrUpdate("Admin.Order.CustomerComment.Heading") + .Value("The customer has added the following comment to his order") + .Value("de", "Der Kunde hat folgenden Kommentar fr diese Bestellung hinterlassen"); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ShowCommentBox") + .Value("Show comment box on confirm order page") + .Value("de", "Zeige Kommentarbox auf Bestellabschlussseite"); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ShowCommentBox.Hint") + .Value("Determines whether comment box is displayed on confirm order page") + .Value("de", "Legt fest ob der Kunde auf der Bestellabschlussseite einen Kommentar zu seiner Bestellung hinterlegen kann."); + } + + public bool RollbackOnFailure + { + get { return false; } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.resx b/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.resx new file mode 100644 index 0000000000..080c5fef34 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201408291450443_CheckoutCommmentBox.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.Designer.cs new file mode 100644 index 0000000000..a4de110fc2 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class CustomerNameFormat : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(CustomerNameFormat)); + + string IMigrationMetadata.Id + { + get { return "201409150936394_CustomerNameFormat"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.cs b/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.cs new file mode 100644 index 0000000000..efb1c46e73 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.cs @@ -0,0 +1,48 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class CustomerNameFormat : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNameFormat.ShowFirstName", + "Show first name", + "Vornamen anzeigen"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNameFormat.ShowNameAndCity", + "Show shorted name and city", + "Gekrzten Namen und Ort anzeigen"); + + builder.AddOrUpdate("Common.ComingFrom", + "from", + "aus"); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNameFormatMaxLength", + "Maximum length of the customer name", + "Maximale Lnge des Benutzernamens", + "Determines the maximum length of the displayed customer name.", + "Legt die maximale Lnge des angezeigten Benutzernamens fest."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.resx b/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.resx new file mode 100644 index 0000000000..28776adb34 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201409150936394_CustomerNameFormat.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.Designer.cs new file mode 100644 index 0000000000..0e36edcc1e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class NewRes : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(NewRes)); + + string IMigrationMetadata.Id + { + get { return "201410091620122_NewRes"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.cs b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.cs new file mode 100644 index 0000000000..4c637b9c9d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.cs @@ -0,0 +1,115 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Linq; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Tasks; + using SmartStore.Data.Setup; + using SmartStore.Core.Domain.Localization; + + public partial class NewRes : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + // update scheduled task types + var table = context.Set(); + + ScheduleTask task; + + task = table.FirstOrDefault(x => x.Name.StartsWith("PromotionFeed.Froogle")); + if (task != null) + { + task.Name = "SmartStore.GoogleMerchantCenter feed file generation"; + task.Type = "SmartStore.GoogleMerchantCenter.StaticFileGenerationTask, SmartStore.GoogleMerchantCenter"; + } + + task = table.FirstOrDefault(x => x.Name.StartsWith("PromotionFeed.Billiger")); + if (task != null) + { + task.Name = "SmartStore.Billiger feed file generation"; + task.Type = "SmartStore.Billiger.StaticFileGenerationTask, SmartStore.Billiger"; + } + + task = table.FirstOrDefault(x => x.Name.StartsWith("PromotionFeed.Guenstiger")); + if (task != null) + { + task.Name = "SmartStore.Guenstiger feed file generation"; + task.Type = "SmartStore.Guenstiger.StaticFileGenerationTask, SmartStore.Guenstiger"; + } + + task = table.FirstOrDefault(x => x.Name.StartsWith("PromotionFeed.ElmarShopinfo")); + if (task != null) + { + task.Name = "SmartStore.ElmarShopinfo feed file generation"; + task.Type = "SmartStore.ElmarShopinfo.StaticFileGenerationTask, SmartStore.ElmarShopinfo"; + } + + task = table.FirstOrDefault(x => x.Name.StartsWith("PromotionFeed.Shopwahl")); + if (task != null) + { + task.Name = "SmartStore.Shopwahl feed file generation"; + task.Type = "SmartStore.Shopwahl.StaticFileGenerationTask, SmartStore.Shopwahl"; + } + + task = table.FirstOrDefault(x => x.Name.StartsWith("MailChimp")); + if (task != null) + { + task.Type = "SmartStore.MailChimp.MailChimpSynchronizationTask, SmartStore.MailChimp"; + } + + context.SaveChanges(); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Promotions").Value("de", "Marketing"); + builder.AddOrUpdate("Admin.Plugins.Manage", + "Manage plugins", + "Plugins verwalten"); + + builder.AddOrUpdate("admin.help.nopcommercenote", + "SmartStore.NET is a fork of the ASP.NET open source e-commerce solution {0}.", + "SmartStore.NET ist ein Fork der ASP.NET Open-Source E-Commerce-Lsung {0}."); + + builder.AddOrUpdate("Payment.ExpirationDate", + "Valid until", + "Gltig bis"); + + builder.Update("Plugins.Payment.CashOnDelivery.PaymentInfoDescription") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") + .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); + + builder.Update("Plugins.Payment.Invoice.PaymentInfoDescription") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") + .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); + + builder.Update("Plugins.Payment.DirectDebit.PaymentInfoDescription") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") + .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); + + builder.Update("Plugins.Payment.PayInStore.PaymentInfoDescription") + .Value("en", "Reserve items at your local store, and pay in store when you pick up your order.") + .Value("de", "Reservieren Sie Produkte und zahlen Sie an der Kasse in unserem Ladenlokal."); + + builder.Update("Plugins.Payment.Prepayment.PaymentInfoDescription") + .Value("en", "Once your order is placed, you will be contacted by our staff to confirm the order.") + .Value("de", "Sobald Ihre Bestellung abgeschloen ist, werden Sie persnlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu besttigen."); + + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.resx b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.resx new file mode 100644 index 0000000000..f00f34bf07 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201410091620122_NewRes.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy96XIcObIu+H/M5h1k+nXvtXOlUnW3WZ+2qrlGUqREO1rYTEo6ff7QgpEgiWZkRFYsXPraPNn8mEeaVxgAsWEPbLFkKq3MVMkA8AFwOBwOh8Px//0//+9v/+t5k7x6BHkBs/T31+/e/PL6FUjjbA3Tu99fV+Xt//zr6//1f/2f/8dvp+vN86vvbb4/4XyoZFr8/vq+LLd/e/u2iO/BJirebGCcZ0V2W76Js83baJ29/fWXX/797bt3bwGCeI2wXr367bJKS7gB5A/050mWxmBbVlHyOVuDpGi+o5QVQX31JdqAYhvF4PfXq02Ul6syy8Gb91EZvX51lMAINWMFktvXr6I0zcqoRI3827cCrMo8S+9WW/QhSq5etgDlu42SAjSN/1uf3bQfv/yK+/G2L9hCxVVRZhtLwHd/agjzli/uRN7XHeEQ6U4RicsX3GtCvt9fX+TZuorL4ypdJ+C8BJujsszhTVWCM5iUIH/9im/E306SHAMwVD8hpEfZYPrmBI1Akt29GYL+t1ccwL91vPTrm1/wf//26qRKyioHv6egKvMo+bdXF9VNAuP/AC9X2QNIf0+rJKE7iLqI0pgP6BNqyRbk5csluG26fb5+/eotW+4tX7ArRpWpO36eln/69fWrL6jy6CYBHf9QRCK9+gBSkEclWF9EJepwijEAGQGhdq6unmjDteqROqIHA/oeJZU32nlxkQM0PUGMyNNCHWdZAqJ0GOxL9AjvCKGVdHv96hIkJEtxD7e1KBhkyWu6/FmebS6zxGCSUMWuV1mVx6jFV5l92asovwMl29vf3vZz1m4mh5y6h7mqrqshlu+MqIkdCOzvVdS03QflPSziDK3KLcp7EMNNlLx+heZuDBvt4K+vX63iCGP+2RTvAqApkpbRHbCe+Rwi/rfFQAs7UlBev/ocPX8C6V15j1r0C1JJzuAzWLdfGtRvKUT6DCpU5tVgJav7LC/fgyLO4bZehpUVop8BKqwlQycoCl8qfYRrcHVfbW7SCCa+YN/RwKPcvjBEOBT3DsJfZKptEr18zddYW/Fh95McYAHwNf1Wxh3Loy9XEDOZJdi37doDTLnAcatHMdcy1y5VLstcu0TaLepNDWYdvubKaDrJZh1ev7n8sjVb1xm7bhh1wLzpukbbKhr+6sVBqdCIx5pEuDpfXeAiylGdH/Ks2qKGhNEvmkXgPF3DR7hGe/TkZSFLuWWt06/tqH1T1ne03sD0JNtsQK/HjVZZy7Vgg5Zk/y0nGpynr+nHbAMuAuiKn0EZoSn+lOXrYnSdEVc25TDj+q5gmYSYQgMMlSTZ0wkR/SC/BI8QPHkrqEfbbZ49gvUlkp3p3ara+PHNl6wMjNjCXSHxnnCd9m5jONBVdfNPgOZfdhR76/mf4AaWuHFkJfMe4tVDNf6ki9LqNoqxwpCjVa/8grY8/aZgtGo/IBYbvZLz4gO8LU+i3HvD1OKE0C0uwR8VzMHX8h5RvBb+3pzSYPaqik5av/sljFCrsCZbwhhrMkfrNdcG7z6dF++zpzTJIv/tboPjO3Lf0qSe4C2gdx/RqNQT7uutgOlof2pgTp+3MCdq9fvohcc0gziKS/hIIEKw/ceoWEVIxwGhRpVFE5o32JpvBciP7nIAaDXPtTEM2BV4Hl9vPC8uQVzlNbqv9GiATl7iBNSN8pVxNOIFyGHmPfs6TLL2E2DPuXJerO7h9jTFRbzZ8bw4Q8OPAbcBhgTJU4hnXpS0iCf32ABhbla2bv5V9Hz6jHYh3nMBAZ2gncxdlr/4jjnSTtAu5jx9RLMKwSGN/d6fkZByFj8Es/ZjQypBPHqMICoLEwrV00ArbanzWgPTgD3/lD3VvcaLBELzHRSk28PbF7LzPsvyto3HAG2cPM+Iovghw4Zu7BLhfaCLN3IY8bymJdo8dPtVb2WAmOPRKMFNtQkzSDVi9BwOkRAArBswCCbQM9FcwA08rl6Oq7Ls7QIecwvn/gGL+wQWZRjQZvInADEvEsnMyYor5glSrAkcjP2PjmiQ4IvH12Q9bgXNnuIkKywOVm2XhS3CiRLLjphjrkq0vW6Ps6QnXOZYp+naA6m1RJ2m+DgsCH81YotBBiMzRSPYJq0T7RuuIKjnpLfAR2soKMru1O8k29zAtDkAC8iEqM2tF0FxtN0m0F/Z/QHg3f14U5HdggSH/wHXI6J/HJc23UrjK086ID9hEs6XIJx7A0iAi4vccn0bxA7CR5C/4MKWho/jqADNEhJk29vhfQZRUeUAqXY628dfQmiEXZ1Hm5CuVh0s/sFCm5GWOA2QE6UBC1AY83bjVAFy7KcQyvDAgGJqhMZc3We1PQNJr3BOrM261q1zUl+RNvW6yX2V9bbq3llEnUvw4NFktXXYoae0ztHlms0o+Lgw6Sr3FjaToztO7yNj6FHl7mA06DmlcEiy7FFjtSK7WnWHWtuWxtGIz6LqgJDPseH0IZ627XRGTftl2VR9kOZ17McFJDjaLjR5NK3ncqgazmdzbHN3CK1ucp1F02I2g6rBXC7H9pJt5C2MSRbaX1bdfnkRTX/0BVT9Gyjl2N+r6E7buWsmnyhPqWSlOKXzOErT71EOo1S6GdQ2X1NOM0AGpVSjZFLUcah4aKuOW/TWtovO/eIPPDVcyGcVGZHNoeRFLpstO9LWDUlzu2QZuYVEgcBiDhlJjd1q+8sW1n61nabY/Tq41qrrGnA0/XUcR9N2ZEK4H3wr8AYk0BUa9aWc4Oaetirbra71mWhjTHKwADX2I4eSjctQcZJV2yw9QZzibbMRkOQHU2HOpcjIEKc/Mst8ebRHwsSzdW4Y2htfZQP7G3E3SxfQbZD7fMKypM1suzhJ9u1jbPOH+yBYBIy3+Q1Uw/nYW2igE/ISkn7IMqq7Is3tdcel3cx6XHJpIQ5Lsbquee58THr9AgeiGF18t7wW6uLF4apEkJ7VN69C+Y81Nh7LMxJ8c2YF/wX86mYufRRXWR25gcd2duhocL6yvkceyrmBA8lllN5pXX6CXR4PeIdphOPvBd8ZWdoh6k921dztGMpBzx4+ipIo5cb2uFpsSlvfn1m0mfoW82mC+ilk8LtV3bbAWuH8DNYwetOUP2ibGnFSk+gYplHeeyA3f5moGUNuYxuAMbVLyih3mEF2BhOQ6pXpPwW6hvYFPFnL0aBnZeJUlecYPCvj5rXbtGUw/WMiHKbxVPGWVOr0dDqB05LlPBsUZyyqSWM5g8Oecg+1NUQYE4nRKMjRC4V3mMXaeUPIFWD+8WS/rBKweilKsBmwL4WxJ6y2YPQjjWOYJNjPDFfib0noruGFgbsEBaJtTDZ+XWAING8tLRU9TCfhddvzMINHVRq9YOapr+VNWXE7GsPWj9A1N/t0y3E6fUaCqg6zG7qlg0cNYx4vKHeh2sMIt7WH8Xt0WHSQWMF3SN/QQIfVRl3XwEJg6MltfX6bZPlH8EwC5k5ee6OYfsrwmjO2F7urFmy7zwpwLschHWaNuq5AO61QByDnxRmI8EC0CsKM9lzlStVzqIHXdZ9Z7Xbd/VBsisSMI2zhXPzEh9obZBd3ITpu+8sGGu0gH0aXDzS5fwoZwXKr4Q0HtpD+mgPzh2IeqguMID987mqYtD+ILAkkRA7S4+D8IzLUwTVnWa45B2eaHXSmOfiX7JF/ie6Ui13cxTMuWbqgKEgzhdht1JcX/fcZNU4wHeEVvuvf1E+8WxoRc5KlJT7dmkKXH5LeoUzYmHCThKasA0j7EeUjSLa3VfIPUJBwj0HAvmQuWD46vO3NX4Xerrgf7HRTuaFFCooCzdWhy+5CmWtuPit6pCyhv9ysLuZ1dtDOahfx0+oc3a/D/kRdV0ujDxXsaq1/O8TTHXDOChRe8HRDPfA0XjUXUVHgDcjowret6CzLN5G/x0+DtoqS8deNSd/dCBjw9uj2FiYwwEaVBFP13s0E0qzPi9oh5ChmHrRz9pmfzrvkU1SU59uj9Rrtd8b3DQi6b8BN/5TdwdTxRi0u34bkVUK4u7fXJFWoDK3wv6ayUb7hQqroHS5msVV1Gqefbux1zeTzStrKZlE3mMtn22p+16FrdpPnutdpxHbzeQSlS5nR9qYA7bs0QG4uq4TaTA41sdlstrQ+fcYqTZQcVeU9VmrqcDOXIK6tg5Ie6EpIh8GogDAmZqVsBwipAdXmIisUd1G6ZGlHxFSh1ZIsTk28yrYw1rSRpKsbySbLW8nlsW0mMTHJW0iSpI1jU4R2ccm2TboEaJeRYh8roBpgJou0ifIcQlMV2eyb/BTl64sMpmXxERal6thfkk/RenU+SR80ma2D+zQ+iEZrjZBZIv64PGoByGe0FYF0CEZ1/D4+l5T8ykwC7dU5vbb2HUHtd/Zoo5GlbxqAw65eXdcZzItyMs19koqGdv2BtgbZZhulLxPUI3dKH9iRIe7AITMfYRrbnuqdUC9JjGgPIFPz3VQV/Tp6Rf8Ft1hXipKBCEWBTEH3WQoGH/QL9EZr+5LZwvfb6p1MPYekS2G70HZ5+gWQSxIWbT7deq2mJ6m2cVxOsYlMBmVD2Vx+EYFacnl46zcYh+VZXdfAgmkaLsfFI6NoDB/eFlQCFiqG+dVT9glgIp4X2YCg/TWAQLq6zwEwrfBPASpEghbkMOYq83z+9nvkbeIN5xsyggOpeHmsu7Ym3fzQea77wrU84iJ1DOeWbIcGi1hvSGnJregWI9wly5k0g9h4aS6vfRxLD4clowXghu6wcGjkyN57k4bzDju/SxGt60c47Z3oDKQSJVimkEe8+mchwtzmN6udemiEDNJheqvrCnRVfSb18uYmB48wGhATYWJBLlpx0W1MHddzYfJrV30vl6vuSDOA51WDdZjzmjnfkMr7TpiB+0QYX/hzHJQRsd5evdc2eF4e/ohfdVqk9AVwmtbHSXbXeWhZT2lcunhDYSzDj7tpzCS+0bjz2ARsPUHVLi8NopSlKFpf9xl7dpKlC6wkzeTNRnVTPHgIAxzWAnVdn6L0roruvL0SQ91PsI3flK1DHDE5XTSrmd37slS7sjV4J5InJW2V8awMD1o/fTWy4JvnhZHD1c8lXiIc6QiPWqfkVhSn1ZA3fmqXTNOmtrJZ2UyC2udi28gkSpdrNofXWt03wnqtJoGU4L9I5jctzmHJVtc1j62lHZmG6tot3xj1o9J/VGAFpjisO0uiu/MN6iwO/zxA7iBhvi7L/X0iYARrVx17rR6MS1AQ0SYX5rKcUompzSiId31urzMuGbS3VJVgHiTssKwLEMCV0HpAhIz0MmJb+1CYxJE2SecFnl0XSXUHU0GIDF67y6pYJnyCqE6BhAKvUpmJECehcKG4/xwqVAIFuQxrG9M632n4IyqaDoY7k71gb7hPeTlee/9/+E69EwN+AU+Fu0kXl35DQSyDx1qL7iSRNaY0H2NK49sT4czHLaKU0amBve4z9mwtSxeYWJrJm2XrprjzKy5/UJTUde249Xh1n+UhpqNltWdEdE1da7Ad3TxG2p/R5r4oi+rBaB6kZ25blm5JlG1ThETp6srmsL1iQq3PckuLkxbA21W0qoLbzilLku9ZSbZkMQmtY60NYIjiDQ+0DB0Wt+ooLZ4cnHnUW5sOU76v4QhxTeenNjPqbOIORpPXb99MNc1j3GuIgyKo58ORfUhHUovqC4lfbxH/9Svsgp6sy7CIUEzDZorUedipRyVJpxudbh0qkJuuiuCA/nJCCANoIFOc5YSXhDjIBnVdoTaJ88iHOiRZo+mOfxs72CYt6PPoZPP1gQSQucqwpJzxVHARu1HfnZnbLoBIa9kOgEmQynt3zb+XsWo5b7gQyeS5bKHyukyAoYPcJMBAB7murmvoVPMvfxnFeJYDEOwOeKjgngiokWgYhxuCAdEaJJxnG4ezZn7PpcMkCKfp6BpLGZBvYFEMRNnjc6njBepzipJIn91PueSwXe4tg7jKEapAgIN8cpZPo+qL88jG/tm70Wv2CPYZbBILeo7ZnHeaxLrAm17ahg74MLs1vB7oEuM0Qd7aUa57dwsnCIHVVtkoJhPW/BXzMuG+aao6imNQFNNUeIEvQKNN65iRyt0uho4UgZgXsnZxi51kbRcu2EGwkrJFH7L4IELVdZFYx96PEAeSw4E8o2z3TRfDV9jDhI/Y+Yvn1lHAecmhCRRu2sA+RPdAE+mMskZSsb7VzaQy+cuzpjFeAo1gHCSaui5CpcVINDxaGMAXqAm/p/NFMbyFZH822rwK4NP87xA8eULgkM9OAREUOKGGuMWr5a7dEcJ+LAh2Ty5IZa3iWQarNWGogU0maevIT13T6gz+S4Cn9D8IfnVdhEAf8qzajnzKPNJdrSmdG7/0D6l4ESrI4oAlaJB9yD4uET/Xu8X9HFZL82s6EyfNqTS5NKcz+EvzphFeIp1gHOS6RsjsvTT+Cee45gUv0/ktfbtLJgCc5nczGNZTu379q/7fYVar6yIEmuglEFKX91PDpMNLMSywD0l6WxfYh8Is3/gh5MWhYatgDQmDdhG94GskQcHquNcTPlLb3QWp8hyk8cskLwK1lV1GvZ/nexDDTZS8fnWRo19Eir1+99fXr1Y45MHvr//qPBdYzynfcfoelVOKlVV1UyKRmJyncXKFYY2I9WfrbjGVnT5PU9kVrgyNDXnYeaoeMpVO09NG6kzTw6aysXvGyCsk2CFetaPkDICxu6mueew+I2wsscYPUklGcnRWaSfBuLWQ+TZaFUgjrdI1WB9tRu0J/WLrD5ADxHYBAoXfg/ghq8qjEvHRTVWCKTeFQuXFf24meImyWZNDXdg5ur2FCURzMpjivB2dBuSmC9b28Su0OUDy6wTxFqtUOLMUQqL9w8cbSNzkSfRTgTbjXcmPigewVg3JqD08eXwc/9VPXNHp8xbmZIf9OUvL+4nr/AeIxqcnPb/q53regxvofQGDgjqKybr5MUvWE/CHWPFEjElVfBylD5PsDLk6JxExdJ3nJ1NW172UM12V5zfRBMpFs5oSBbAL6jb2vK/QhiBvApJe5VFaRDH+2asGk1c9yZRRVX4JiioZn+wn0RZbmKcluFjpRL1dVTedjj5tly+qPL6PCjClZfsigq7Xl/mHNMcel6Y6vD/Hz91X9THC5ObU9yAB5V69IaXZCV8CfCZF3ZKV2/PVDyUwpwzSIzvC7dd8xv7YTpYuHM1LM9k6gWkd1eoaZD5qbIqiac6eaa0J51uBNtMfYVFmihf6ZBmvm0PIvrHqXMJxqCar7SMUH+At2W8NdkKW8fpbAdY/YHkvdGY4t9ApgyK2nSOlcJAxDX+TGGRC+7kkobF8ulPLvtQxiVQtw8mKlvVJ8pZR6bYtuwRrADZgTcuaU+Xjk3SuQaYYzCx0ZriE9QPZqO3qKHdtqkh2NkX6lDeV7NKqrZE0FnLy0o7LoBB6fC4vfym5IHR43reGKaQC8+Bwoa6rO8bzNMTWUs3XmjvOw079gYnpCtuXGFhk24/CXNHnttUXGpkyhoJg1HBWcjnNdLm24OpIJUM7THN1XS29fGcos4KGAGOeIAl+/jeSQGmpaa7t9iUGFN32ozAv9bltBQqnaE2htBt1SK7TeQkcfyFzECzqulrzFiUVZO9LmEmnEI5eI3sUnBdtY0l4riiA0agFPMmq7US250tEjC1EIzyJca2rbZqIKiuQ4n3sFD2rq5qmW5/RZosK2DlaPedFzx0ZiQszs1l0JAOU/ZJsZHYSFnDT3sglqbY/16oyYo8UWZWrsiq/15JMtdDrBsXh8R2TzTgikvfthiB6/kX92pgvzN+rqOm916YjheVFDuPR/V27ikZ36Z2iN5P0pLU91Drc2F1iaxu7b7N4i07rJfo+e0qTLFoHeN/ovGjBgqnZnxADpwVocS23KFia/gDw7t5iazFwV6tK1wlAalA0vj9ALYBPSOC0UPytVGSOiiKLsXPvulUm5KcSAbUYlWY2pPX4218tDgKlxymSg0JjhbEe1YFmdblkDWsSNU1rc/jrfV/I4wBeeh+GOOh96rqCaGtfqEccpgu31171y3pnjEXuOQckgdnBu3S6SQ7mnSab5ODbKwyxBO8wBzV8F+gqd03wEBjHURKlMfDcNhWjX9aaysA1kmTQOprJvFFkbme6fILY0GYOfyIU2GHHpDcBj4NaNxuXNxYaj5fOx+cg/9R1BdFBrvIofkAUn8hfmtx1Dbu7IzwDXL2w34MEPoL8xbH45LqPsfMbP+kVvnG2LnlqR006x3UvA8QGMhmUTnpsLq9QQjRkCKF0MIoPz0hCpyCebrJD7mns2YOTIeQ8UM1X+Wxx3K8gdkwvwR/4EUF3AwEDc5gHmnkQImBVsEkQarsU5nDoEkRFlp5lec1N05tBGv4FxOwd5IDAcTz6F93HdqEoo9vbL9kU4VkYEREm/NeCLny5bkwpmii2pLIcku2bNJvnni0jOs4JkuV+bgM80mGB0M3IAAvERZQ3aoLlQVt9LOZQkB7iEI6EwQx5Ybwf5gn4g6YkyBEP4dP/0Qx/YdbuXRDFPXMrlHRWSl3T+WlVXZlNorCr8wa9SitUJFtLlJmG2+1s2NQdkwq1SE5LVXmGmxzk7LQBWW3RXLtt3lTrZIHLwU5URkl290aLe1geR5fncsJ/3bJhKRzXChxK6QwmqGMB3sJGfP30NW26fUGd0LiHZHIObO40y7WsLpvyRgXER2aNSlmbODV84tBbPZwpCXQolnTRQvntHrRddRacOtiD3LQVeCM/yjOut8oYEkxOJsV72XNPdf6YJIDU8JOLci1PW68Ch1IA7YuLuqEDxgjCL7jYOwi8n0E06bhXcew6/ZQTjmw9pq3PTu0quvPfliGQw9Rynlp/DvT409BarV2Vr/uhLCTLLZ2sWkeZPCF483uUwyjtg4efZJsbmEaeGvEw+IGX1XWtHqoArDxwxbyEurPEMJV8jtLqNorxIOYXaLQHnbfCVGtpmx64JEQaEgrtB1yHA/sY9vZRVABCOVunXkNY/IOFNjrEOSoKeJeiWQQJH52vdafC734JwkCtsx227dveCivI9TRvi9hOnhEhuRc/hDm7IQbLr1X59ZaA1oe21kRVBwCjRli3ZGtWsGsWQ1jOTYuqrGPG5UMefxjUrbaOGpRy6WzIQxO+nvA6zkGxGV2oNTDBLIZX4LlEnzbb8aOO41Aqf1Qw97+8TE2VtMyzJISDw0zHMPwUshAxtnLF+dCF5zmX/kgNG6ZlbHuotxoadJUHJnH5tPtbaYlrpeQdpIG2vGqHbAcSYgsdcDE5rCIGq8hRAqOBTUAAST2TrXa0UCC+mlITljO0ukRgD9yurktBN3+HkB2aRANuflmS5as/qigHxeXdzeidqo0k63+imUA/hxTcCbK+fjhBRecFQkILOYgDBNXx0CE5JCIaQqi1n2D6gD1W54w5ZqttLUfPMtQ7zZQ1pxWpDdDksPp8BmsYvWkBDuuMZt42NPIOEPitj6j1LU+8xYkINXq0smOYRv1bfu1fJtUNLVRpiQYDw47elzOYgHSK1ff0GfWpCK+vypapL+DJjp+MRcwVBHlzbOSs4XYYBzGjrivQKhzkRlJ7gQCva5bHPGEOOQJfohm8poE7KlUsOta9ZrP2qoM8h6AcKLKFPKLoq5CYCYVETQuDnCsQRnQJ1oC/FPX/DvJCXddEfj28DqPVNkaqdFUkpynO770HW4EY8UqYTgy4IGSF9kZ4oAP5T9ld1jkAzHbGwfe93CTH2fplildya82xPfb9AsqnLH8IPLp2Mu9zRK62eYq+BuUgAdV11eT3ZfsaZR5p6qCsmSvu92ADiLnhJnFZh0n54g0Dc+BGdV2EUKMvK4H41MC+qKnl1zBr15jcfxzFD+cp8ZCi3zP32MQqEA9TIugAj7YvDhWiYo6IqArWk4YNGMorbPsGC4Tcoqoqk2xYB7Ia9yPIZpb2174CG6Qnezk1yOAOgkRd1zza2XcInlBT76ev2XUrZszPiBHBXZa/BOBlHurAxwc+noyPG+EegI05pAMXH7h4Mi4mQwFjL3fJbLPJ0jc80oGN1XWFMR+hHn3Is2o7PVuimmeYhQOmgZG8P8c0FRzFySWIM6fXr8l5AoJ704EcZtzYM25Og632YNzaufB8nXR9COy28S33YersTVf+wM/7zM+rpLqbvtZQV4E/ReldFd2NtTCs4nuwrhJwFRUPLgcoqFjxhgY5zCV1XfPcKkHrd5auPZ8OC+S2aC02wnhElNn2a3qa55n3M4KfIhIqPi8dnuHBZU/TtWPJVRXHoChc66U7H8pVw1z9vL2FCXQzXnRli/7nQcio6zpar3PEJ96eMiABAS6EOC6C6seE695JD1469rjucvVHLUKicLgi5vA7TgFRgfivfUbMmu/fwxzE+NW7NwzSgfXVdQ2sr6YXwGxXl5eiBBtEhyeyFZm6+ktMOkM34r8uzy7YMPd7tI41Fwn8Z0oHdpgsh8myT5PlpMpzkMYuDzj3k6QFOUwO58nxl5EMb/XAnCAIXeUjTQww9rz4lGEAf7KamC/PsnyDBp167mCs+j7BDUQsdpXVns2+CjOZYMX9kq5iL+glHb6PRLahPTUa2eAXEYylMuK1auPpgUkwijcC1EFIq+ui6eR9cTmU7yQZQe+YZNkWxrvoxSnwr9R/U51L2JRrsnpGBISPiBaf0TafvGDjOmFZnMNs1czWEI7SmIdCzdSrLBQS4s9/glgXP/DP42iMOHbh9FZ5HMYw8tZPzovGxHj8clSV9/6meQrwEumtW0hFzXHFHEmG0mysiPVCi5VrNj8d0kWZTRK5RZ3X1v29nzomradzK9veZxpqOZXTawkgpmn06VPmco8RlbpD8+0NhXKQ/uq6KDLhKhdz06V+1np6GTqSYOHILD8m6fNcC/mpAxN1NvHoRJM36KuidEUyoSJL17Y2uCipyRhCnOD8B5GirmtmU/KAifDXcWp18oiwuDKz2UbwzsWA0azOxZsW48C6zrwzliPQ4DZlpIpxnIxdW2JDWnmN598pmkrJURzX76S4z0Ea5zAP1XUROumE+F9GOWxpTPNDK4hh5fq6cIye6Xt4keX8Qz+25wQFGskwBLJte1QUAyrFSDXXi/uq8I6biaNwgtsIzWokBMlcQKVGklmN0PG4ntiJLQ7qILnUdc2jfR7Hcb201A5yQHfmZtoEX50lUJCxQDrKNJcC6PXdPz72FJrNF/BUfAKYyT0PSjthIUc8yAyNzJBSzPvkdCYlKsxMCrpJGPMG598rUIF1Q2v3WUPBHKaKuq6LHGa5d4RfbJfUuh+NskjjWgf910IsmVfZ9J27yibp2iXYJi9B+mdUzyR9OjkZvQqkH45ex35phGHXH/y+QA6B510/DKNo0IhqqfJAiDWKSQ6FqDXtms3cHwyp8giHQ8qMXgdEJ/cgfsgqr9fi6ldw3whQh3VcXdeAYB3p7vdOPim6QhNqi/Nf1FGiQuGeF1fR8+kzoKjhCoWA2khswZ7GXvgDqsJs1zzEKc97LZE9vVw0LSM8uGlc0OuRTXktAYXn4QXCIQWFp5jvLJlHJB+e7Ztdck0vs3jdzlrYOcmsSxwvC/P1RfSCWeAjLPC9O3ehpQA8SC11XTzJfIUWGYmFXsjg+yqdZwoeuhYL9/PMtIwwz4wLBp1n4SbYYWZpmPglTkC9NHvOBgx0AXKYrf1vcpRRQvB8LR84sg+ekiGsMaEO+wJFYjlPIXYDWLIko5toJMWu2RJq0cVkHJRXbG5bB2bl+j+1WOa3bNby3Eksk1ve8F/kyWVCFidvaIJBMr8RAA/iWV1XmHCNbkEHJTjkxv984YO7+ueqeqpQwkph1I6kVPoIM+u6z97LG3UuQZBqsnqqegmZDe0LKs4R8FmggyBR13XRPkn0zk8EdDi/zmNcNTc15llRoGmR+HMZD3Xgs6XymYVW43NJ9HA5dGCtvPsEHkHifQ//PsvLLqTD1PdNzlD2cJUPbOa2XYjLkR1wlTdth5zo7waeIA5DCMTkIM9BPkVdE8ZBGvLwAn9UdRw4r118/a7wx6jQPzjjQjq3672qa73a67zhrvGuQBMxzOFpmvQW3lV5vWNtcA4iX13XPPcX9vBlF8onwil+//MbCuHAsc4cu6vvcpFQYy6cg8sV9f8ObKOZ+yRKwQDzBFIK0zip1uA8XUFUZdTZ29w9t9qrkCihDOJoYHC3MgwtrmCpDTUappZJXIQ/gzJqolzo1P1wlb0H1AWtCeqbZqwCx2m9BCkSyUfFD7iuD1m80GqU/8rS8elQV4W2yk8M3f1afpzhBSqAfHC4d6Na6o6KIoshEeKsjegCklepr5v/c6vOabp+1cYdk2Xv9x/1ONUBz+icaNDQYge3aHlDzfr99f8Qej1YR3d0R9UhB3/3ml8jv6b1ifErfPyM/cxOoiKO1iLtEd3W7Beym66vi6MdTYEWapiW4hoM0xhuo8SoC1xpwzUct66rh095D7Z48qWl0TiZNKApIm9HVx1HvSFi/faW4kA7xmws0KZMw78WPwZjci/Mi3UsnzHZLszAmOw4GTFma9WeiTHbjeGgrOQzypix36eas6GAay4Zf3nz5p2A7MRIqkZMwEIquu6CVEN71/rq1NEWDQpWvZre4BtqqgHXFZIxVZvfhqm0dUgYzJBxvUjTzHQbwrRFxiNLV4O52A9Ak/ZHcwMJuyQZkEVWyoYyQdcr0/ZJ6CrJNzyITmLNiHQTyDgjEpm0oy0/tx53jfgGPoL8hRzmDGhYTGaNDuegvLHQMl6j2zna8qlrzXRamJTORlxFlZubszp1oFuSBlhAKKDhMBf9TFmNxTK6mJ2CshfTcalyvEyaQF+OXQSXGm5k+fwj8+gO72VVfZiBQXdwN/s5SqvbiGyK8sEdrSyzjDHpfDZcKcWfY3era8gEfKWj8y7schumZrrB8MSAWFIW1EhBV54brFLCf7q6FiMXB3s0nYAcHE+TptDlFsXZhiu6rMxE/LzDq7uuHzMx8A6u8iSQDUzvPoPyPltfXwKEBrHzwgm2DWiNj8NFZUzMlrLhX4P6ZPsokhjQGrkqkVKHhu0RMQq4buGVjZblltKFzmhFFmkN5pSYf0JrezDBVNaOkdFWsi4y2yRu3NsHmZHLJ2PDzlPenAF5VHPWC6eWK9owAfMoaLpLbMOKnqFhZmdLWBZisSWMpJWS4dlJ2p4JmUpKa5P6mYLzHYi3Fw36EPgqDhCzSg/Fu+sOFofiIrKEscyY1qXvxzBJkNbSVjDYTDZ/cCpw8OakEGeXAzWaWzT9vZWh9vIFdPRo8rqQRahGtogpyD6/AjXUiwkk1tB4Ga2H1O25WeRVHYagdiZF2wvS8v6Wv4qHtKVk/CorYMO0+golnNsHKlga5xp1ZQL2NRpDk3bQwUBm4eHjJLu7yIpymG+FnDJebTPZ8KcIvFM8qWz+BHyoHJOd4b3mkeDrjnF0XMJnVnFg9/KwHRMK8BI+VDH4MvhQ1YOJWFE1PibVt2XmtshfgkcInj6CZHtbJSnWeZmEIeP8QHGNnV4o6WCsH6pdbbdverc4rrbr2HSGfMNxtrDp1wVnY3/8gNV5CTbDioCQU8bUbSYbJhaBd0oRUDZ/Aq5UjslOKAK49e3a0TGOjkv4zCoOdFAEpPASPlQx+DL4UNWDiVhRNT4m1bdl5lMEsiQZloJMLumyjjJYLeEM4E5JPmnTp1iLZWOwExIPt/woLZ6wF0AmBGdgmYLKp+KzOostt9HAMs1QwsDL4DVJwyfiNslYGKl4KP+svPY9K4mpKs7y9TXFMTr2UJRR8SCd3ZYTVVUpuFLO7svgzYGuTMSnA2NnyrN1qfk4F+QbWOBYN01PWpM/7qj6bExfTMq/XAkr/tXXpjkZwhlGOEE0I5I8e/Dzw5mIcfqMIwlFyVFV3mNejEkiN0BK2hiVlpFKV9CGfGYN2KlDR6suTSAlrcbYpD2zH0eeZXm1IWbXQQYXs8q4uctlw7oSaCs+DeKQo27EBJylJu7usBEJPWfIR2xeJSM1wfAsOYkDn4mV5K2YipfkBN4dZrom/9bPVGgHm8qoZCNrDqJBJexDtW1xa6aq/VMxnmQ8TKruSy1BiNVcYyBk6i6PIb5qZBXzLZTvJE2fVuAx42HMdwtQvyh+GdaSqA6HV8EocBX3Sfl6ISyo6MOkOpw4PibVkwKzsWL9tpqhJ7Ess4wVmzDJ5mwoBTZ3IA6kv+laMQEj6ahrUj1bcmaOGtwPsNkCctFu2jzkbZ+M63Zyx9DGmfqG33ppX1Hs4oqpuERbShepjC7gEs9NXqEm9NjyuNSoKxMwrdEYmrRj9lBl0p7Uks+Kn7gXVUfmXvZF1iGZvVC+ZToxF9My42bSiO7h4PkWd+Kmo+dRLp9yebf1++Nxd4cFFS2faoUXx2KXmG0o3ImQcwSG28WAJsrWT8p2Oxi85AO8LU8i7BCBmnwfFWD9A5b3PQep2GWgnIwt2yI2XDlUjUosyrg/3N12w1ZNwHuGw2DEiVKE2RmTUSI6FhriF2kpHVO6ao36CiXsqZoF88tQo65MyNPaMTRpR1tmWTz8jZ5idozMFJ2Mm9lad0cRNe/MXEwtHU+TxjAF51Vbv2QlMNkj9fmUKivOYq2yUri7w5qKlk+lrIpjsfw90iV4QtPnIkMARTt/Bm3vukIyNpTkt2FIbXU7ZaU36ckE3GoyfjthwZd1xEwRGCxpLPak+x+bitwmjFfQIxywktya0xOJzaaKmWl77ZFD3Z3lRd7wCearfByWv7i07a73zC2rDPEFk1vHdLa2OHkFslh+Cq5eDgtKuzAhJ0rHyKT+DmBe94I2Yq+ZxwqXO6CzAY/sE/TOS2tWtWQq3VlFY1Oe2i7Ac+USlFWe4levgMnNCHl2uTpA5bTTnKVV7JjOrOvDJNqybpx2Qk/uG20o91QFgl/aCykArTSTjFR7EuX1WnZcpesEaM9mNGXkWgqb3U5TUVelPj+k+jDaYmHQsknUkMGhMGlFX2pGFZnryeCyoSwxOhPu5vox2I05+HUnVxGhF0NuFaoCo3PqLvpaDHViDjbdQc8LNjbeEIdKcw9GTnQOl7iTjKntwQRcqR2jHWLJ1RbE8La5/X9Uljm8qUpgyqL60hqWlRd0YOGBFuwgS5v1aDoWNxvjXWB5eU++bvGf1wqOVK7u9lhSBUMDY6VsODRHZmM2mpbzTxWP7k6hsbjzhpFlUYqw0IVEy+Busl1P3tmWHG2zjOeafOrPP+P8+z77imXCN+7zr8aZexa2y/JVdKeJDyfm1cwbhxnCIKtVMJQcLuJZg/k9ymGUlt2wnGSbG5iSjNdoxsBHkL9cwY0mrq0djoZwGggHmho3SHb3ku74aFZYx4ZOJxdsx9SkZXS5uSe/rn+GGzoDiEVw/A7v7yy6tYypsYM7PUWvXGeBA+sH4Pd9YvLlcPYesvOwtcIUYB4G15okhD7uGsvPYYGwHW+LSbAYgwPfue9RUnU9FLjVkjW1YBazhOAEmCr69qinzdCsXezsMerwfDPJiD8sZhUPMffkul5Fm20C3mdPaZJF6ju48uyBrQkcuGyD27Zz7M2toi3TMaKC0kZ2K6bkbBx2BUGOeh0DJja+ksPk2WUc1uW04TEFvGWgfsJnc0tSfVcmYFH9UJk0gC63AAYd2i4KOUdgy13cBCpbPykT7u5Gj3IcrX8a2i1U5TTrsdo912BlVta3S8xq2JfplvihUTRpCVNwQexsz8jTsbAL84bULdVNmYX39kF8dvupM5iUOA7x8IUKCwwjnuSKe7GopikuFzAWKHuHezjHXBhmAXOZPOvFjuMofjhPV2UWP6yqmyLOYe39MHi/Y6igbCooytjMgMFqd+rSh2lvJmBx0/G02bQtjquHlI2BchPz9C7qzoZ9mZGhd1CLObq9hQn6Aq6HLsQKOWUs22WyYVIRefKHK5RNmICblIQ1qXvuG//kxRa75V1dRPkoj6v401Q10+N2c6/Fw8TfiVUY9fcRzZjPiPXxa/RnebYZ5DtNGfnmis5ut5VSVzQ92xm0ZpJtziDxTVpBl1sK811ltqzXlxiV8ahqZmc7sS3TM51IdpM29KXmU9KQgv2IBudTdndN/caDqVbX1GWkilufxUp109QiU+K4xi9uj2HQnyk0wuGxM9IN2aKLYN9BUSnLPBLD7qZhR9eDiXlzJ1XHv1egAuvTTQSTa/LvUax/7kxVQMaVVF4brlRWIeFMps2L486hnkzAoUPjZdIEutx8McvuQfyQVbwjoPBZHcPMEEAa00xa1irCmWntMvEr9HFxnG7bvQk433a8jeQ1X3jG4JJxlSNS3F1ELyTo6nkKMe5QmGtNKXmoSbaAXbRJXWXmcZ6D7MCMGjMBVxqNgFE7qHKL4cI2ornANqY8ogIw4U2npwQMq5dw69DUmF8o2/ZuBvYfGm+TJvFlZ5sNn7I4SuC/wLpt4/WnKL2rsN1KxYDqIjKOF3Lb8LqmKgl3dy1fHFcP92MCPh4eN5NGtGVm5FgDI8SQ8cHS6OBqbFiEp/9MdoYdsS+cojLlCypTohIgb2+/bKK8/HrzTxCXOAk8o/GOScOiNM1KgvK3bwU4SXLMBsXvr8u8EkUmhl6B0tDhsHj9qi5i5SEoMO1ApUa1mMJqwAYh2segZRj9++8DICdRCe6yHAIZSpP4MtwbGJdVLsVokkwJokNichiTB0dthznAWoKOUlS2YWgqDIkUk4kAY9Zx7UCweQzGo87/OUqr24iQSzc56GyD0EOYVmCtrJIyX7cmDIA0HiBSwnVOM0MNwSygmgUkbZjobRz7z6C8z9YyJDbHMCCSk/hWwSNaMaQtYzIYE5sIZPlk4LIMQh4n2d1FVkix2rRBkFYjkoH0KukQCFbOwKrEe4JLUJDlUgooyTcI/gU8FSrR36YNz8ksSY7S4kkxFbtUIyAVhDETYB1DxwH1vcuhloB8A4sCreVoP5blUp7n8wyCnj6jZTmNkqOqvMcKSR35TV2BLv9gZcQbSMXBXaIZzFW2hbESh6SaAEUqBLNWfMizaqtsBUkdBCIGJhlGY60zXHmpF1nlklWScVjMSt57laPLn+w1RNcBmtFPJTCoV9RNYPCLokqY+l3XARjxJUE5vaQvDhqseSrNqn9CzRBERTH2sbfB3lJP9ci7ybykNNg2Nh6+vH38uwVm6pk8tKVGUVMFVR3qgyaEprQ/2lipTpWZV2NKPBJzU0kpEuzSDEgTjE1TgTb4nlvFFrWZVmGCbQ0qjc5i0fjmHHVoEWkiZ0jXjS4AyQBIdz1dhkKFChhUxDP5lpQkmBX/HBEZoURp0oe7dI/2qISkN3INjskwrMHLb3JIFXrVbRyLHeMV2GyTSM6Psnym9osXHTCfx1jEaDC5LMN6BUgB4jXthOTzDO9840StF3eJgzDfcg1MlzjM5vE9WFcJuIqKBymbU+nDXWvvhEi71l+yGeI9EBWIn34AeHcv1QaYDKZw7yFSRwrFNOHzGGzJ8hykscL4UCcOa2LCvQblHsBq8rIexPKZwHprD/Js5z4n51rKq9EcihiR9XC1v+2gONlsI3gnJV6bNryDpXynpDtWxoFtkOUIXbWCk81iZM74BEq0bR7iF3nOwQooBzQZKuMjODQgvPeNdGREZylbWKUSo3IDG9yGyA69VRsvhVODZR0m2GaGNOqUU95kyan0YGMxb6415x5sjuEhzLOiQAUTDSSfx6D3UqlkIo3Qr1Kl4NVJw7pd9Kw9BujTh+mttEbJDVHU6Z7qTOa6O3mhMkvPZrqc/PGjEG2DK9AdNXe9kRwMCYeag6jtiTONqoBjzjlRTgcqtaw2TCXZjXltf7ir8oGoxF2FF1FDUKllXB0XCXnUfeCzymhCzyUNOQSocdmlNXpeH223CQTrq4xup0gUbX51r3TFZMSiTpM1tNKiSuimHoIglOv504RuXW6b/rWFQtKswxx3ynUVy4/CNSSTFjDooaxcAMJJYSW0k/czlIBnX7RRi3fNyzcyMSx/4MaAI4bBZCRiXRdC0aaTob1+oqSPmHewW0IRDZ0Mpb4SeWwpxlc8rC8IWc17NawxOJJrGqWBNgnqFAdpPnVnZNllJOJ8XTTkkSJOonYyNbPON0qGUpcZZABlUQ2LmZNxsBIJSbXogeg6PEel2e06OjxX/Qg5zZRlfZyuL0FR5ojpwZpysRKpaFBK3dnhwjKaCu5aGnIa1CBbNvoe+5OVdvW67lzSJJSUZtR0TZZfSi/OG01HLinmyBRqY0dpaMNnUfeAyymjB+V2qCEFDzQRETjPQDUp2IzD/WCH1pssLJyEOHquc7FDtC71VEMllggxl8aAIGSWWiN6X1edMULEklBFSWQfghzDJEEyrnOZ1VCFy2rQHbZEAPpwgBMRqXGM7S/QaKgk5B3uFV9ER6fejdeAXAKwTA6pBsCBXjI32/5mnIRo+gLqDmrLycincBTW0FBfhYSQlEOzNyFbL2ot8cRM6t4IeWVEovy6NYQRoSYgxkm2IZdFe/dyOT2EfPp+8Nm9Z54UVEIfJandty6X4BGCp48g2d5WSYqlI5Og2cUMlRzccAwAeFPVsBqNdFNV40Du1vVfOzfFTOreCXll9KIuI2gIJUKNPDdxhS2/93ci5PQQ8un7wWf35iIpqIQ+SlK7zM0sSbSMwmbQTAE6n9RYUN8P0c0iBmJkxuhvtlzXN1TkXaez6FtO5VR1v7tnM0AEGkpmFpFR0pEE37OS6A/Yle6avu0jJ4cqu74/ilL+YleDraCbYghcqMfdILrm7jBJCKgvoemntqCU28QrUDo66vE1y1bT13C7vUEiKnIabM0GiWa51ZucSLorZdqtn1lBdZeNyssoOnBpTkNlsypH3i52N+201JXkUvdLzCyjG33/T0MkCdgUFCGuWsMk4bINdIPNrSRK6z82RBUObgqyXNNXGRU0ofMM9IDKqqBGNEwGGkRCA+ZqZkjmaG6GajmjzmM0jnVfwvBEjSUnhkBRL6FBX7DViQ0qn8lcp/oSQnRQcCoOkRPYgTZ1aLlhi640n7ozsuwy2rQXiDV0kUKNbMWt69TJUy7HUPN1UtSYBlPJTtlt6+s+UIzaHUxeQN0tbTmdOxh/pdvAN0xeh8Y3bDRKNnfjDckoidk53D82ZOcIBGTDdA4ys+sUJPYWJb34LAPzp8+pnIXD5jIeaRoSaNxKxEwmjde4kFgTYhp3kTamwvUFavF9VID1D1jeUzESRNIMFVF3bqCkjGxUPAgN1YaAVewUyrgoC3Vx3YerUNNQXmC4o9JyOvpZSCZ9HRJSKscoFCW/0QNqTE62lGV/mcJjEpataHS5hyOWDIh+KsuAnOpzKiVeEz5lSOJRSGOSQBJiRauOavOru6QrJqOUIkKMhmjaGkbWY2V1D87Q4UJ2nXWcNpa4rmPl6LdJDsSUJORyqPvFZlT5XkpvZ+hwxpyYdIih6z5wkZoIbMbhPjD5dSQZVtHkkDLfORWVnbfOrR/soEWBzzi0B+bye+2neayRjQpMPKkBaS7NqRMQsgJyqcBGvdJKHSnoyEK7b/wwCynzGpwVGTCS5enTxOzEBxO7poMKy+SROrtOhChLyWWTEARNK5/U4OrNJBNgOTwVdfNSndmik7rZ6Um/qeaoULHGPqHMa9EvjbXCk2LT2C5Yn7PhO0JcRo2bgCx/WN+5aUkkD/VnQLKBgoOd1ZfXXLVShjEcJvBAnSNfv9LEbrxWRVyUTG8HGM38tEeTCgV9HEudgHBogEyhNmOK4PNEH5DTdvJo0Vy5W0/hCaeZtiHGY6pgKo/gAUzYUuWQMdkGSUDn9o4cQGOpZVTd/lBU0URRNY22YAwxSAFTJA2l9bFkhwfBuAnTRXbQNWl4/TYp7UWV4ZV8zDGZVIniG+JAfneaOxDaibrLIKlWNzIu69x5rRY0BrW1Wg+fZ0T618+1KhItxkKPY00mLZzFGLVBJu0HSt8C9aANcomHRrOKNtsE9LG41UoNl3NYF2ELeKs2HJxs8eyjjXvTp4srzjiuy+ijyKnukLyAjD505HMNhRSAE/jY9zVrljExk0lXNEuVNVkmXY4oQ2n9c3iFVxYZnBWqkprZprHRWtUwNTGtyOhCwDFJNxPRuHcSB44hbIpbdF6NYkRq8X1IG8prKp/qGEPx5IL2NGOwjJoEQ0WloQKUD0joLscPVTTySYeqfo2gGCpi31mN0AhK1GkESPcmw7XmZFfMpO6OkFcabYh6JkIXbkjAGvkUV3hoYfgWl+1kVRdS3lYx5yUN+MhTk31O4voszzY60umy62S9spR8YeEewdAuI2roaUl3lVkQjsps3Le+TGCiUcAjk4x6H+RaeCtEIr802TXSR11KKtOYF1J0Uk2DK5NvwnMpQcmnYzZpPrOO6VjMiVJTsRb1ysk1++KLSB9lXnWXVEVkdGLfY9HQSQkqoRX3yo2/h5j0oZVrydsuEo8x07Iafy9DCKkbhuo1GZ1/mWl9MjaVPIoTwI+RfSnm+jyFJYwSjUu1roDOAVFTTu7cKLxzo/Vv1MGP690vfcfnWnyDZ5iYyrLmHVdBmJDY9BaAYY0Sqg8OqmvUQfpVouGQg/Lc6i6rCymDDfKPKWkIqkEfOUrT0ApuuHIPrdiDK/UYK/Rvb2sA7CUXwRTkXdpvb/GjhJuo+fDbW5QlBtuyipLP2RokRZvQvt7Zl2y+vFptoxiL8/+5ev3qeZOkxe+v78ty+7e3bwsCXbzZwDjPiuy2fBNnm7fROnv76y+//Pvbd+/ebmqMtzGzD/6Na21XE5pbaLS5VBw/eA3OYF6U76MyuokKRPGT9UbIttpEefn15p8gLom74DMnS37rqNxWaGYZlO3hMRDWMVsk/LvxT8OtwD0Bb3BzBw2HPHhP+TNEDCw4CF2AhRlQhESgKzTxoryddk3Xz9eIlFlSbdL+b5531aX7BvA4bIo5YtcRHpBJcMAjuocStEs1Rz4vLnKABAfAQdI5IrJJIuZvb7kR5vnrrcBgnCTgOdmNzwMzdghOnop1m4p5EOqz7TRQIAqJ5rh/ryJCKRaw/2qO1MfAoJH6r/ZIFwAtfEjyYsVDhkmnm6Pjf1m8+os5wuo+y8v3gHrJk0YTU82Ra9FKb0hoZDHVHPkjXIOr+2pzk5L3QmlYLskc8zssIHkdm0brPlrMk+omgcU9L+Koz1a8s02il2a7xXENlWKOeJID/KDm1/RbGbOIbIo54rftWoHIpixNqAcR5e4CfGKxjXuiEN1tkgVmlKOekdBl3dusArgij/WEPE/X8BGukfqdvEgnJ5thT0RnlSRKYCHRQrtbb2DahDnmNDsmxZ6/moemVTxGJVvR9+lr+hHt7S6EZZNPM0f9DMroP8DLUx0Gk8ZkU+wQlaMlJNrhXsGSX5SozxYjnyTZU+ewRe57cb2X57CoYbvNs0ewvoxwUOAVDkHIwIvJFnM1Kwfg5TnsW3+VlVEip480h1Mf1JUoM1nMmops6K+yo5jTjdgUc8RPcANL3CCylnEtFhItWvpQcQ3EHyzmB/WUGVpvyi9I7eMVJVUe81o+IG5iMesvNjvfPu4Su+3tv1u0pykjW9L5NHPU5n3Ur+U9dnNsXUBobHkO6xp6ZUCOz6RbzN8Kya0IxypGasDRes2h8XN5MLfN6Pb+zuzo9t8tVP6mDD+y9HcL5TxN6ulJOTMzKrok3Wb+PdfT6eutAl+ew54ap89bmBMz7vvopZBThs9jXws5EiYIsrmlzmWxcY0K3kWe2byKyRbSlCnJt15MtWr1twLt1e9yAETNUUy14E+64BW2P7PsKSbbzMvuPImfmFSCjfxqCp28xAn4BNK78p6XYLIcrjVcgBxmwjiq8jjUQhQMAiNIYlkOG8rjACmnaYR2Z4JQZJJsMM8QH7SBV3hQNs1mP7SGeCZHSVv65B4fMPF7I1Uum/ZfRc+nz2gfVPKNpxLM8VCh9uFlnkW4JCt9Cu2lztNHNNtQ4fplUx5dmclCUmF/VLmtlkuyNpWR8kePEUyiG5gI8OpcbjXJOyHPYTEOMNWgi6kWmnz2VPe9cX7iB1eWbrXDgbcvxJJwluVt+44B2lcKuxx1RotjhCh+yLAFFB/MCscIfKLlXlntby1sms1ds9V1EksuGlq4qTbycZfnsK0heh6qgc9hSTewbopCflmRJFvNOrxmHFcvx1VZ8kYWMdUa+Qcs7hNYlBp4PosFZWpZkwDE7hdoDyUa9OU5LAz7aCdDisKYW73YFBvLngBljfE1WUtg+q/WdsYT8ryjxMJYJ1isQTjGR5RIWsemuCGuyijHvhcAR14QDkb0Od1qPE3XRvXx+Sw4rDENnqbYw0PGaLIMVqseFjwMCpCxjzaj1e7VsD5dRqtdFH3VlNtC6W6hqjHReg0KaRwKST8GM1v1pXs84Wi7TSCv50szmOP/APDunpvo7TcL6kj2aPa7sh9wzYM0nyzoJenPR+v+dGuEXrxosjnUpRMsykxzHnEHPYAHCRC8lbqPu3nsrulrFyxIsH1xaTY6egGahUdiDhBTHZA/g6iocvAthaUCncnhUMPRRvQFEhIdcPEPLTadwda9ihwRijY1IdHabat+o0JuilFkcawD00BfRZfDuRd9mFBtT+hsi3Fl6R8w8vFlUT3fZODMoi46jjcL/tfPZ6NtsdTCz6VZ2bFV/n1c0lIcB9vSMvHDp9lY9hqNQ9yDMCnmiI1mIeDR363PIIuTrNpmKfaSl55BMukWq7wC1Q2tHQVywE7UdBW/sjksz/Xrk6w6QKBwrk8nLkbqNcZtKH152FzstTZyB7GnLrpYsadyT3J1JEtgJJj3yCcbk1VNRZXvmCz94Oalx6rdLlUnQ2KqBTIkTjQCZP/ZppV3YAX/xVsXu6+Obm3FVVZfIpHjD+W1b/9X2ZGAkGhpcr2M0jteGDMJcztQjm382R0HtiWaGg53Bsa4M1BLOc87AzWIy50BVclx1I2mumOYRvmLVNy3STbW/Q2oQ6iwpvz2q4V4ANkZTEAq6ERMgo1nxhfAnU83n5bDfvUZVxguZLDcL7BMzZMBrx+GVGXcxe3MNqNmq1vHWQhhPqIAPSxJWpRxWKutWrW9dkOjOnJZJWD1UpRgI27kDLJbHQjLLTpMgoWpFCYJtnricuJuQky10UwbRzo5tCTZxshTlEhfJjodHaJYdKVU53Op7ULp2C7L4VRDHRel9rlT18LlcqmpHQDpDkeTzW2UiDDQDU+XwcJw+FzmERZQnN2w/7wckcw80+ElizWvm5gIYW3xpdq2UNks/wieSUwK3vLKJFkv6yT4jiix6aQ9VhVa16ow9lYWzcXsOoiwfNVTZZlzs8mdF2doA171F5cEv3g+ef+5lb7wF4RhaUB3ptWjLJ9x6fZLrgQwaQcGdmLgcJzrybJz8Kq/GhD6iIumguqISpXncEylxzocJu3eYdLhEOVwiMKm2/pt8C9TB1DO6vgY7mqZqvzyFTKJKLYWw3XvRR9R+rsFGom7wiE132xc5ZPtbZX8AxTk9jHvM88lWuN+ydSwXVr4KTPA3ecF/v319r8JTkrsnPnvLs5KLMRUvN5WK+x0qe8WG4Vt94QM06T+s82mow2xw+82+u8/p2C3lMHHSXbXhgyz50tt6ZF4sq5OFHhMgsX5COrCRVaIIUyp77OPErPSNZIulbyzZLtoaqFGXT/r+hWraJ9occUrKprecPe8qO+zj+MX8FS4zzZt6XFnm6iosCnzzV9MFFkwbvr77ON+kSXJ9wyrUZcgznLhrVyTeTsIMdJ8RfUepcWTqAWwKYvbonh6liseRbBQ1qbW0j5UUKGn1SlWV2HyVDDm9V8tTnA3QnTn5pONcaUosAWNt6q0X+2RzrJ8E0nC3fKp9sirKOFjGzApFoas4GFeQ4cv6l5fFF4YoBMs8HDAGt5E13yb3nx0XtT+O93zXizFuEQLrxmFE5Gbt9CnCGmo8n0VlzTnbgg35VN2B1PpNTAx1Q65DXSkBBcyLGat6t8m9VmrFI+uGixVypLjrFTkORuR9anPdiMvQvVfp12jkDjeRumLoNHWH62uH8p86dz880rE7+jbI0xjQUYLiRZtFIJOndgGmarZ7h2/rrVfrZF+lSL9aoP0X3CLt/tRIt795JIstIL7LAWyiMZMgsX8aUOxcvOn/zyFlJ9LrydzwPvGaD2TXNR6VcmlHqaT482i8fCVnHz2SbaY8rgRfJrFOchT9gmUJdpIFpk4/cRUC+T7HAAdtiTdYowqtLmCsRSZT3O4O/c94l3AmZSZjmd3zSWnZcjWl9pHerBYDkJkCGCpsiS0Y074w/nzuxSRug7qy58wsUnL4UxaB/NkTBrKhS/15ccyLodTdgMslzc3OXisHxrlFjYm5SB2jZi7PT/z4+sWxfFsUl50HG5un+0V4jFT36d1DTnO1txGrf5i601XmxqlTw11SRaYzQF9U/ZEtK7Jc1jIgv4BHnUlykwWYxTdcUSpv1ht0Rcda+nn9Gwdy0ty57bc/UvkPjJc9fy6gQxXF12qoty2+KRKyNV66VLQJVocyaXwjwqsgGSnySVZmJOS6O58g9qDQy5IzLJisoUjYcmZVMmH+efgT62T1fcdV2VOvAiKrMp99x0yRJd5bgSzC3pb23pxOrEp9oiSq7FcktWdrTzbXCTVHf8uHptidbicVbEwr6jPi5kFrWeQH+e3KI5+XFM++768nQl5V5dTeOtPFqtXlXBLTP1lnrVg6Zr8YSenq2d5Gv/PuSOb69p558noeaGpw3F08FQVHmddwDXKnDqn3jO1z4t+z0p+7nFJe6ybY8L7c58j3+2mJuLPebXTXSM1Zf54XdJMWsUowV/Jgv+hAkWJtHM8syT6AJs858He0jUrX91hZjd5HC0tjKs8RvJwl5cXX6qdT/2Sres7tgrnbNeXZZvpJsZr5dOmdtBufafJeEu9quuUsV2q51rnQb6BRYGU6foej+eaz6G5rP+DEEudg2Fd6buQZOw+rfu6GA46fS7xRZzkqCrvUaUwJo4JIbhJh+zAWXZw43BZ2CvsIVzFW6qcrzFNbiGvJ8nS7dEbET9UiSSbeV1f8cBeZQ+AMxrQ3y3RjuIYFIUKk0m10MixXxPSOlXyQpa+mNl+luXVxt+RpoNxmMeasuNM2qtsC2Meovs41+QXryzb3lU+v5BHwLhYxC2tnQtGRPiSsEWAuUFwXCeHovA4s4PUyEN0H2ebHZgEshf5mARrL3ipA7ylcbGWnrxdsflqjvQdgicOpvlkYwArSlm0Efq7PZpqJGXp9ugkkrQUt045yCw7mRX5CytXOTWpiPqQZ9VWKqe6lF2+wvClW3t4ydJ+nkNI4akpVZ+YhIPAMuSZQwzJkdQ2IgICqG0Ex1UcKgov1d61/EtYB+5+TWjmx9g12e15WlFuHHYmlcluozMJlnhiCCPqs82RoeQtGof3Z8LukJrr1s1eX4g3KKTaHBPXx00KaEmy5bjg64GVgMsl2bdXDiumWpj66neT5MBCojVufW1XaUdUZbLnuJMqz0Eav0geIpfmsKmhLncZ8ef+bIp9m9mDRdWcEXNZ7MCjUiZxqM+2fF3dlDhc8HkaJ6hhMvbmczjWcPo8VEOXw74GEvK4e+pO1xd5Ts8atX2T57StsREJmr7xORxr0PSFz+EoPZAUhlhTi5IzAKQdMsgeom5pVw2yW7khYGEiXJJsv1qOkXxcXEa75UcJXJ9k2zoxJjn93ebCx22VrsFa9ggkn2aD+hTl64sMpmXxA+QAjS3voqbIYrES3IP4IavKo7LM4U1VAuWORZ/To8biPzfJQFV1Fvv1TeW8KEu3cKoJHEWx0023Cp11a+0qiDVnJPjQFg6JgxPEIrJFWJ/Txg0jX4tOS/1XOyRRSeu/WiJJ+uzWw89R8QDWemqq8ti1+eTx8VexxfVXO6TT5y3MifvG5ywt70VQIYMr/j9AJKEyn+7Gwe9hDuLyPbiB/D0VVSYbY0pXrIkK+jFLJIYVVS6fmmQcpM7lVNNxlD6ImxFpBmd8cbJKM7jhn5+ooXGaE2obE06F3KU7oZ/fRLyhj0+0XxeITiKNKyzPYTHTKqQz5vBfZJpe5VFaRDH+KSxsmnz+tYlMqs/pX+MlKCo+6vNQXhvpuMWxAjT0lOfwqUHWI3UuqzP9TsvTdEiTzeYaRh7fRwVQ2imlGWz2VVB+i4BJsLeJNZHhpBaxNs0eFW+4cDjaqqzXaK0dy7iQzdFFmKjcSzpgMNlpXYJNBFPhjoAiy2IOMdpN8LcC7Wc+wqL0fzpaAukShdUMZpwjj85uxvMx9d3SaCA1qVuK712LKvQB3pI9TUDmkkC6MJcZzDjM1dbNo9DfLaRaAdY/YHkvZTIh0Q5XEoiE+vwTMG4YXvXgz8kuiDcqEsUtkpeW1LnsuV92csSnWWjsEguqveX0vGhbQC67RYIeI81g33e0WdzK9i+ydBttJIZbiLhJ1PO4JAdMyX0YPs1CVwUp1sRFdZT6bosmaSCTYGG1A0Uh3MHuPtpwU0/2jNy5EbhJkmGPpWonMQI4zTgGZNKUHdF5BleocHjpk6bXJy8CPnD89yoiVGah+q8WikcKS/LoufTEVEx1QJaeh4qpNpRUtde1rep2urax3bvUy6K0sYosrnVIm6/IYrHUDx45+h41ao4YnY8W32dPaZJFa0lUKy7JZoFpiyrVFUkGCy9rxGhpAVoMwYVbTLZoO5J7PwC8u+ffW6O+WzjcVek6AXh14FztqO/WcvEE34OUScY6YVnL6hcSNsl7WcUwrsuqvOyYy6r/EvhFiInzxS0MzlXWPQYq86+mk/dYw6OtnWHsPSKii7nHCGUcTg3rWVx3gZNKzTdblGOUgt8AkYB1SXb2ItkunP4+/R5s52YQPpGpw3P6zJoWxfHdoinfHQ8lya/yKH5AHZMdAPJpFqjYpU+mpzAJlqd0QH6cyKdZnbnBR5DL30UVEn+C2eNvZKCRPGbRlKaGrk7JmXL73cFwIZ+b1nZfewPBbDpMWeXpJfiDxEX0VF4oKCe1RVt+JDYKdKUqNAOFVaTC2asuQVRk6VmW16PF28i5RBtcMuyA7N15E4eQ6HDxSBoiXEy14Zzo9vaLGNqX/m7Tf4r55de8FFl208lktiUzI3+eINEVYtlk0ZyWziGIZcu9iyhvFn7xViKdYmvdkiGyKTaqQk9j2UGsLH22LW/AU4oxLLttrxALgxysiXle3m82xxxr1UHetXyz2oIY3jaBKvux9wvRqoN2iddqhzeSZ0jA6Sfvydet1DV4IK/lvZAzmKDJJ7hn8mlWIvTpa9qQQRWznUm2tinvzpMGusHyVCg0yC7KhRXcSIqGtA1m/D95IJr94MQxeDAY9+1QWKJd44ZG/pLHegOs7AjHfRmXFp57pOcdl+9RDpES282Ek2xzA9PIf9UYxncfRyvQkVaQh4pbLPAHCz/Ukn8Msv5icT4XpdVtFON7Yjna1krvparyWDpBSbyfrJxYQHrHX2Nuv5mj/IBrHqT5ZI7xUXKM9NHe1SUqACGC7LBVSHTAxT+02HQGCy28KOBdina/kHDEOf+onSzd/gQMh30ULu1waTYOVrKHUPqv+2PEQLIufpDbGbgky33X16r8eksgmnB54vZLzLL0dWqUxSncirSLpoGmkHI7JEu3OMYHzyX6JD65RH23c+z/o4K5zJ+//e4wnU+ytMyzRGaPVeXZf9U97JwLMNkmn2VHCYwEsUk+Tbr1c4xIuyzBTW4ujiK96zuRwUS4Am5UOc63QSGCZdl2jZtR2Sxf/VFFOSgu7264oxA+0XLDcrT+Z1WUYtQVIdFi+0G2CSpgMdVmLbvIwQokIJbcHmCSplhrVIhkOsgWRibB5mZD+oAP4qT6i5C4h05O7aUNz0gPDYpLdAdl0XFkXFufeA2PTbFyeG6Lfsu5fRifZt9OAdIT7ximkRC+ikuzkZ9piUZVEr2PTjDHO4MJSAWp3n81R8LP3aWFoKVQn21k4xfwxMtE8mkx8/gKgpysK34TuYNxmMmassvfdoaOH48ftFW5vbRpczh+2FhS5zq5q9/N9jqowz9dzuXk5eY+nFGuPMJyY7cmrIrkNI1uEl7ho79boIG4yoHQJuqzhYlcfBrpo/W7SNld1hmROc2OTZpTo/1YbpLjbP3CN5H+br0et5buL6B8yvIH6dIs5FmWAGg+BZADTTZXcaAsPo5UqKvnMfqvtkiilKG/j7dAzqUH3YMNIJYJJL48dSEaykUf0pcfh31IpZxtu/405cIkiRdmHStsRxjuOIofzlNyakUHMfVjPQWoAxMaI43koBDKlz6gqh/WK33nrkbS3hhXYIOUFt8zFRmiA6uawSxVF8fvAl9EvG9I/3WPT+hO0EDdZflLGG7i0Rw4aRjiwEWL46LWOzIIE3FgHs6aBxbaHRb6AFKQwziQqwCP5hK9dRBi6ZvI/wAv9ZO5DFL/1QpJADnsKaR8fBQnlyDOfMMOdzAOnKspu3SWDWv3GMegf16crxPBnbT+thg2/JYHYcMOxoENNWV/LjZcJRV3Y7H+MocPs+pVPP1reHMZk+N7sK4ScBUVD57GZArJxZisLb5UbXKFZl/Ku+h3Hy3skoKHgK1rgPSkyuWYqsy2X9PTPM9yQQ/oE2xmAwk5kpeCAYhNsUM8TddSvPa7ZfuqOAZFIW8hlWbZRpGG1OfFSIDuVU1PbaqFcdGm1GXHmfiKZ+GdnoMP9ZCTbPlRLz5zWUdBVFQ5qD0pPc2iNJSLPVRffrErBnktDG3unrDaxkpYNskc8xLfqmSxmk97bM1oxv893NQea0G4sUNzZ0gNxIEn95wnT6o8B2nsG8y5gXGJ4KwuulTma1ssPvPDplixHv+uT+QUrPxThhKFB3iZJFtLyVmWb6KyhHyAHTHVxkt/A5GycZU1roGclz6XaHGqXN0ksLjndRvq85yeYUuK0aXsdYZfskSbEuKqxTmVM0mLEWGIBatNOFcNAc5BphlgjCPc6DrFCxFi6lxOFoRAPFT30cIKkW1hzON0H/fY6eMiJ6++NIHzfc9WaSyno1U9wEi8HsgV6SzPNiru5tNsOFOFyaZYze1/grgUpnT90aJl4FlyWd7O8nwJIskV+cjyyKSxORy/1E+t84BCshN29xKfEp7KsccSg1hmUMKnzNMHmwJyOofUlB7JdtZXKQ3BICbP5ntYx+bm3fs3tnd/d5k5MXIwBiVnEl5MKkcYaUUbwarhv921PaeZzWlxs43gnaf236I4OSmqii7VkBFKo8DXmliQ+sucW2NfE8NMXEzeND6KyUOafpxMIzlws774OBwteenZ+o3nxjgjTg4mwe7ionhv0cooleV8vBDyxcLMU4A8FTrUf7VoS1QU4uLSf7VdFVYFP179Z6v+vQe3UZWUaLavETfCKCmEzsqyLGbeNnvfQPcvWDCnk50BhKUuScdxXEue+mCbF9yS5F1c7sK5btFiWnBy49L2fvH8Ap6KT6AsQR7OHCzHdJiSpkAjzUxp7aKJWJdv2oXczrtkOsVyR1zO/16BCqwJ1f0mAAXkwPXa0uOw+kUOsxzysVX6r3aWYdEebIsgLor9Vxt7Mm9FtisttqL9ZnFMDbbJC9+Q7qM1jtgkJsFikp9wU/vEUuUQlIzdVCtGEHZoTl+Rp745f+Husx2WpGnU56nUnrksVPcgfsiqUJFvBTgXm9UwxlJ3CkuO/EwefMYb4Yv60qkcW53Lpt1X0fPpMxDIwCRYUDV6bi9bC+eWbJKFJneIg20kDgLEMJZjhhAMk8YtFmoXjtdkGaaUPod4wDs55y5x7Dr8IOBF9IJr/QgLxPi+3q9yVBdnWGOkceYdXz2PJks3R6+fB+cgu497fLrNky0stwVgs8nk+kucANm7TUyCJd4FQFv7tbBCsEk2W+UySkhpbtPDJNjYi9DwoYED4s6HSZnDehzqJth5CvGBjHSC82l7PM+Jiz38Fwkxjzviu67weC4rigHGSIe5wS7eu11PV6KRexDyMCh8mgOqAtAeSxIehUlYDNdfAnzE2D6r4Lu20VhOK5seYCyTcxO28B2/Eei/O6D9qkD7da919JM8Kwq0G0mCcBSP5rIXHoTYX66abSX1dFJ2c06e0CkZVfUJPIJEWNSo7zYGxywv2/sXnJGRTrE4uaqSRArIJFioiNvGZ4MjWv95LqfrC9QTIch999Fm83wL8hzkAhaTsF/XBc9y8EdFbu9yB5zdZxvndxLG/mNU8JtDOmExIgp9KKF3PPsaxCX6kKrkUs9rfqJwf/1Jie8OkDpzcQlYryu9VD7ZOX2VXDf1HGYM4TLA8nLjDG19BUUcYPq7jckoTqo1OE9XEJWOuI24mGp10NH4M6OEUn7cIWaYw4f6CpZ8sIbm05ReI59BGTUXizjljE2xQ1Q+Kysk2uFKaEZ9ns7FVa0Fpkg8HRU/4PoOlLwiyKZZHAuSEv+VpVzX6e+2aGhn8CShppBoi3ucYQHNTzo+bUx/vrEXgqOiyGKIYwOl4vubsCCeR9dH220CMQ9RqoDuxU1tOV7wt7lVyztafdbiuqqs4HqVVbn0jUCjdaSDli0omJhdWzybeRXleOI4NrMllmUzf3srHW8flugsW1YM0ZdSsYPCQGVE5hZ90bzQNdKPExqYqRmBOHyhP9GCdZ+try9BUeYQqx8nuJdDEsKktLBLZMrUGU2ExXBdnmzCVRCAWQya7Ck+aupNzTStUeuauvOkC8Qm5hYjrtV5WsvbMG1FVM/h7wADDLykcX4D3eDMNtDHMEnQ584wajDafBHVkNuMNYvpSVMOLOSwc9B+jGndsJMsXUM8nq/Oiy9Vkvz++jZKCmDZe2/muQD5BhY4iGcdXv+afspAy0NDJYVgT1x+OrsBe+mr8xw9ATwAnw002HNNobBmkzfGrKIqoZI2lqwhh1/iSrMvLHAJnqJ8fZHBtCwaV9PrbwVY/4DlfWNm1flqDBYWvTOEIgZ8MViR5wiwWAH4ZLjBS1ykhsgQTuC0qrqNhiOUCaHicKCefMSjhZQ4PPYSGWi4//5qTrNxb/5/Fd3pdRtZdjF6JUns85hoMSKwr+riZJIwblwQewlCCr5CtbZWfMgfwRTkfJbOmNt86f4u2g94QKM78Dlbg6Toy+H3eTYR6VGxjWKyg1+DM5gX2Ok6uokKUGd5/Qq1/REiqdceZjUGlz+Sk6SOC9lm+Byl8BYU5VX2ANLfX//6y7tfX786SmBU4BP55Pb1q+dNkhZ/i8m8jdI0K0nXf399X5bbv719W5AaizcbGOdZkd2Wb+Js8zZaZ28R1p/evnv3Fqw3b/niDawRyi//3qIUxZq5dE8dSbKcclyl6wSco45396nOYFLysvS3/wAC97WjfgluX6lky29v+YK/SfgNN+v31xBTm8xQ8tQi8eWMcDiKFOcCpAOvX2ERhC9OdmLorRa+7x9XEU/nv52na/D8++v/TQr+7dX5f17TZf/tFVkb//bql1f/t3UjmKtqVBtcYYjzhB8Wd++rBrqBQ0D08Ykde+0JP130r5TbMVNX0IuTano6N4Ir7tWUv1dRQ0J3Lmyt/C3GGsRwEyVY6KJfBZGe7/6KRhE7v//++s90BWUuOhCp8NFGPkYDTvwWTVldRMP/tuXTxyiP7yO00fkcPde3l1D7fvnFtoXER5M5E2fx/9smev7vtqC1BKdiDXh0+iNa+67uq81NSoL4uAN9R+N5k3gNAPWYgzsI60rkzrusJ2bDv+hLCTGXWIKxTphWYLYieb8EcRsswH0cL6IcNYHc+ukuj/ghNpyOxC9EmmMVJcnLlGLHCHQcuYNyh8Y8Wm9g2sXBDgDYMk4TH9FvqLGvzNf0I9qnX3guLqzDVdhFRvC7CkBGyvMqbGOPkiR76iyj4BGCJ68F7Gi7RTs4sMYPeqV3q2rjM95fsjIoXgtGLhhznfVsXyjIJpzVVXYUe63/gmOdO9TqoQo+RaK0uo3isspBjlaE8gvSeHr9IFQtHxDLhMY8Lz7A2/Ikyr20ohbDfz1tQhl9Le9BfsE4O7m1rA2N1C3NevH47hcHkVPhjVMJY7xUH63XXJVezT8v3mdPaZJFfkprg+E3NN/SpJ6ELZxXzxDR61ny9VbAc9oMNiCnz1uYkx3s++hFhWi0+2sASXAEAujP3R+jYhUhzQGEGFUWyX47z5dX7edNiIU6hqOKH93lANC6lku/GKD6haEAGgeOx9bELvGTJw0IE3jER97ReBdd2JEAiEzYER9bHz6e6Z7t8JFlZ2hQ27MeL6VsXZ8pRUmLdnKPjylcDEGGTadi4rm3mwuE5z4mSN/A4SvSRzRDEFjtuei5Fymz+CGQVQ5bSAje0WMEUVmYUJgeVhdpG50WH5gG6++n7Knua/P0j98wIBUc3r6QbetZlrftOwZoV+MDexzFD+QGBT7r8jxHwDssjHde05CNmO4xKGT1QSMDN9UmxMDUeNFzKDzScbBuoCAIr0kiNseZj6uX46os+62245TBuX/A4j6BRekP2MzlBCC+RHKVsYC64J0gdZlAwdjPrEsDBJf8X5P1uBU0u4QT8jbMSHWstggnSpw7YnQUQdXRxSe7ghswYJO2xT5N1wGRW0vRaVqCvPDmxUZ6MahgZAZqJNykdSJ1/wqCeu56yXy0eIKipGL4bm5gSjYsozIran97uFc0V4R8elFHVx2N2uwuIzj8D7geEf3juLTpVqXQMqcDDitwQp0fhjnMbAM2eqziCznHlHYOPoL8BQ+cvXGELe1jGjmOCtCsXN5b6A7rM4iKKgffUihYRxgt9C/WOmhXxdFmTN+Krhr8g63KwVZXe6aQAyWZwcjXSN44voAcuyKFMGAwgJgMIfFW91ltE4lyC2uFsSNA53WzH54Ag+fjvzqcj7c08rcYfytAGPcjtTNT8DW5rcpdghharOgoyH7LcrPIB0BqTn+Kk6zaZil2HPZaXgUUlbHB1bmNHKySVdCPUXscvGRaWJyNBY88ZMX+Ch4Xx5zg/jPYQz0067UDGcaJ5uD6wriihTlguIDEmcHBUbkt6KMyY2+oFfwX8OkB4whUXGW1tzqP7GRwbDC+siZvE+XBzMMMacWXUXo3YGB2cxcO5G8W2ICyQC+hpWywf16H41qS7Mlq3/TmGKZR3p1CoWl9Qz64LSSI2BhnQErYT0aQncEEpEP6yZ9cvM2+gCfz2WDrnL5nLDPvZaHxVIAR5Z61FaPZrolvGe0s27Q9c7B5diV9R44n7WWVADraawA1erUFo1sYmug7TfwuX1//xlMpBFgfo+wqo8OAKFHNLBct6IXSWdZpqCjg+tWw2l8pNHhLYYVe7one6JReFD59LvMI3xB3aJu5ZKNOLvZEpA2aSv5ir+WcZEmWfwTPTSj5sODN4lU/uxT4gGbkhbH1R9kvY9vMupTCKGNQf1/SqwHnxRna/lX9rYTpt6S2HEjfqTlwYQgupClq3wa29E/DjXvIhjtx8kDT/XBQEPag4GDcH2zd7hn3D7ZvJc7O2b67OKj1A2Z7su7Qr+xZasFdST+9Y8sEjgw3rc+L9t78PvhSWrPpnvHnhwp2FVUp/KMCkEDeQiyG7B248sGjFJfLQqcbKqRSMNT+NaoAGkwLdpblm8gzLE6LtYqSMBeCg4eGCXRJ9Oj2FibQW9sl1xG9VKEAC/h5UVv9j2ImUJuTi0DY44NPUVEqlwMnxKDSGzfvU3YH00BeiRivvaBqAGlzOkIH7bVb1QUAn22FLIawXXNEBPP2GC+Z0qdTdnbFJDFxg87JYGDS5dFtYmebbZS+BMKSnf6ZaMBtQa85guBx/M5HmMYO23+uuE9LTqi72J6rOJlP70KC/RoE7L/g9iIrcAgOife2mzp1n6VAHlrKLeBeG4Jn7vXPfMMhe4dsZ6XnoB32nYMdlpjGimZp9dJDCVCI205XT9kngIl1XmSDVxl+teW7q/scAHP8P9nioykCchhz2F6x8L5HXqrwjIFsjWcq+6jezzJhl3BwEspoen6XIurVgZUsrMnmHEJrE3vCIOOpdzMuKDc3OXiEkYxBfW8C7YIkO06yO6zI7QmLforSuwoHD7Pm0b6kF5NKjzQFSWdmgSAP1odAqg8Ua2NgkHjBDdaJ5mK72ZTuQ/KGguzfPvJ1wV3kBdzDMX/4A+Ep9nateNkTOTvKWtzS6KRKyEUX/TGm/VkVOexagRF2aWdJdHe+QU3HV4sGaWPvFXtZ7tfFwXF1mtoxeVXiMLGXoJC8P7ez8252/aal5yCTuwQWacGlXutuqg8Oy5ttLpLqDqriQxqefmZVrGZ7jzOTL+Cp2KNHwGbn0IAaOHkIJgwUfv4lDFIQCbxM5fZn2qcsQ389bDBaWOP7G1mSHKXF0974heEOOThLk1LB7XluIrF9auN7Vvq9BjD23R9EtD3hmtmX+XDcU/teNTIvzFF2kCU6WDgbsqx+qEBRIi0Wz5EleK0vUwNxXpWtvYrxhfY9kQXDe8G//MVeYQ70mkqop00avscYCrY30nC9/VZbp1PCP6N4nOqGzkdxAvkGFjhuxSWIsaTdX+b3WYdGmUzdfXc/YOOxPn3GVI2So6q8x3SNiTKwV+M++3WfcC6g7WidU/dAAsI2kjMw+lfMW1fZAwizjSRwR3EMiiIcKPH/QAPs5d1vPOnOsrza7NFZ/lW2hbH99GqK+UW0mHtyGz0MaKYvXJjcCnSJc7tr9/nI/CDcsScThHTInkWbYjs+QfA44po945bVTqt626FDiKQvtST2MkZ9932dGt84wa3wDH3eoCiG3BGNxO/y3KzvpgTaJ+HzIc+qraMEasqO6xLq9LxF4BOKL82q4/d4fQCBgueeTKk6iJVRLJy7KZ7ItNwTGbUT4uGnZbe6x/vBaaQvAa8bErygkTr08V13Q+lnr9T7Xsn3bAx3od77Rr7flWNSEl86qviWOHYrBFYTEDkgVH3hLnC0jC4eVZXnII1fgl1pbgEvo/7MdSCM91+dZyV7RuVH7e9RGVqYoZ12ieZCcp7GCWqqITn+7CaJ28pOn6ep7ApX1gWYn6iHTKXT9LSRDdP0sKls7J4xkgXJYojFdZScATB2N9U1j91nhI1lUpiLUmS0RmeH7mHOUWshc2q0KpAKWyE1YD3yww6X4CnK1xcZkvzFD5ADxFqeofvuQfyQVf1L5qH3QEIFxX9uAoW3aVZHhb+arSdVmOhlnTq8DdJH4t+F9Xv8AEcOkBw5QePPLuBOw45QaH8Xv4HATQqmsQn984zGXDyAtYp03i09eXwME3QHg50+b2FOthSfs7R/2T4g7j9AFKbvNF++h0i4le/BTf+kt5v3YQfTRN37mCXrQGMlggdkBAr8OEofgu0xONxgU4zGPT8JDdmGOgoMe34TBVqQGglNlIKQYTSxmwmaEP+q3xLOo7SIYvZ54lHgg7GbqoJLUFSBQpeeRFt8/Tc8cUTggK1GG7JOJwrf9IsKly1AaDvjRQRDuU5zMZGC0LSBxHsVHKewqm1poxiBAsSDXYoFXr8juASbCKaUV/WgG7P1s4PfCqRpf4RIhO5NNLvZ3x0kRe1rb4r5OftMEB/jA7wlqvcesk7bNfvB60t6jd+3Aqx/wPLekYW44t5NYW73Bzd+TMmse8KgrXJBjTJaWR3uhCpwfM61WlL7n2mMbHQ7L9qmkjs+kacu0YKhjdI2oPp+iTq7hYhPgulNHWK4+wgrkGItN1QLa7hwzfsMioK6ken5qkI/Ihk52Z9LA7Vz29ijgCVdf4K6W8yorl3M+w7j36uoGQh3Wf0thSV5TGzsI7iuotFPGafozSQ9afcz9Xo6dpfY2sbu22gHXOEPtt5nT2mSRWvvQDTnRQsVRHH5hFgwLUCL6fWiOJbKPwC8u3dS20xqOK7SdQIcHy1Xit4TfAkvDI/aLctfcHCHfVqWZ1lAv1AhMvwu37UOWVn3ltzClTvaULhfVpjZnVdronr5QBKE4yiJcEx5H/WqGN0HJeQmKaxdnbZPOLyjxZcf4RUtfOyx2Z+HUWeU5Fd5FD/A9C7giRnxEBtXKSHHXiDUudx7kMBHkJs8jLeUh5DaCbBHVoauS07XBOqSAc6PRLvu6Lt7C92jrPL0EvyBI5Xty7D737oJNHCz6z8h7EKXICqy9CzLa14Jo6Q3HAfI/tdgv29Fbj6are+TFLe3X7JQjtvMhAtxSWcpDhAWC01GHExOonyvFht/qXMR5c0C7GXBqe0rbseJdFm/t3P7QfY/Rpxdjs5s3h/PRR/NTpAj9sdG7NH2pSFWoZ0Tc83Ir7aIhrdNML5uHPdE5s08LeS0/bplfUCNdX4tmt/8xU75ZzBB5PaMrFoHKG7I5xujeOwHOzUE3ZMJIO9iKN5bTLTuWRhlT1hkZ0ahESpX0d0eU97ybV1b4n2Pcoh0nY6H0U70BqbRPkm8h8qGpkbuhiXUPwPr8upJlFa3UYyvnuRoW6W4VOZbi7PabBQWn7RrLPQfcD0e+Mdx/QeiAhDKux+nWVWDf7BVuQShLwp4l6IZCAlTng889PPuF3tubA8dcDw2hysTTGmfvf954R9xf+823EgOxw8hNsJkL/G1Kr/eEkjSyTHezFCsaHuyjM3MXw2Kx45BRPCOfY0+UU92eLtY/1HB3M+tjVKj0jLPEn9D4jQq9L5NlqMERsFDmQfcF3n5jfoKxPpm1X4MtKKLztJJBPI0o83Fh0Ym9SzJ8tUfVZSD4vLuJnQ7a413/U9EfDowQnBjfe1mM0FF5wVCWoEExJ7ez6GCuZKZ7L/GfILpAz5RkSkYy3H8aH3F90Rytd0Jep/oW+9S/y33egxeAhPkIsIxTKM+ogtCvCEfHOVXWiJSYaggbTyDCUhDCVf8rlFahLoZcl58AU8j7JmuEJfVNqH9mFVzn++FC5+MX+5z9x6oS/vYRELs/EMe0pufzeAx2BN2DnAgIFkkRJHujbkqktMU5/fSi1YgrnJg2T4j8y79KEYw8+Wn7C7rrKPTb/Il3Sw3yXG2fgkVCateX1s76xdQPmX5g9/Y2E3jz1H9sut+zOa6j36sUmOMIhesFy9zLeMebADZWt/szXPGpE+h5ZTtuJpgMoF0VO+bWKOOxyzHUfxwnpKjAjpa3p6wTQin23l13NldW6e4W0Sfxl+BDVqd98Y2PsragV8hRE0TAg17A498/tE+eX0Y4/0d49ZN7DDEezvEhK4w3rdjzBAbBtSF+rG+0EOKgMPzn0xXdTtjHU9BPYqTSxBnexPYceHbUo1B1Pr87nydWDh5GXPEt/zAEVMaKpLqLjhoCB9Al+djzA1i8T1YVwm4ioqHPeGzcB41KzT90rVX3ByjY0RD1ve3hJfZ9mt6mueZVzAo/ODxqozyMkBID4x1mq4DIa2qOAZFEapdNKEc7fvm63/7vNOezELnp0nDvJAa4EkFW8ltbgYCUVHloAnksx/DPbgkv3NZkskzG6hnT1gLCo1+iTnQ8BzZ/mnUkfemDQ+9R6Kt9gc5sNGBjRwslc0rwT8L+/zFZaeofpmZxXZhHVNHFmfO+ZRhAAuimIfNOMvyDRoy6ip/IPhPcAMRP1xlhD8sbvVIjrWqmwQW98vwrF1K8A5JDzP8MBNSxNFg+rq0GAsfxD/VZh9PY6kuBXXEnf2QlIyYnwXnKtvCeLZQXxbHOyQceRtKdk8Y099N4CzPNu5syJb2u6mXuTeDLuvnmVvd/BPEwl1B1mzooHPga4hhrEb4BmLktfidF81e+vilfoAzEFj3+IwP3hSigNgB0KdP2b64DFI9wrU42Gh4gB33/TF8ZHeJLEkMzPvBluPu0wf3hr86gFob5S18iDbbCN7ti04c8FBGvua6gWG/9tmnfcANsDF7kSfpmpfm94TFpK/ssTP8L/Y2mmbvPyw9WGzT+yPB23uR5ar4PKaXPfPUsrNmDYuKYlCwuwDXMnhVeN1MxXdcwW1UJSWayIQDUalRzn7IhvJncxt0WVuP47iWUvWBoBh4XFeD0W0Dg92byw0uo0VlqghStKD3vdA/9qL0BTwVnwBmxj20Cso7F9Q+OM4K6M+DQXWj8Vww/16BCqxrIu4Hz13kMMs9r1tjm93A+Y69bMegBod11qL3Kgve1KtsjIZegm3yYtdaC9gxWnxyEhoRLfChIRe/pIcVhThOSQ6Bl4ciBhlsjlFsErWmYWDKY0tbmPPMLSr3IH7Iqr0LSzc42V0clxcZCJE8TofzX9SXr0JgnhdX0fPpM6B66gKDQNpbf35a9s4FexSm1T5FAhQ653BGIUIEf87Ae7ofourNNHsucXAa/BrKRfSCCbJfDx/zvbOfPSJCgJcoF+99wvd6T9jh5CVOABvP32kEMMwFQHvbta8vUhklBM1Pg8Z3YQyeuJ3sxliAyw/nKcQmcMf3k9nSi4/LQXxk4b9ItFJS957MtxA3LhW3Dw2YoC/pxQC1A/NoF847+JGQnS+fWywWCWGXek+0J6x70UYVeufDvB3Kr0veQOVZUSBVNTmMYJgRtJD7++LRh3ryCTyCxE/Wr+6zvGxdnoN4xZyh7KaARnakbXMaHPoseEwfRKOw9ohCoaJiI04FeQ7yUHizXFsxCq2d4/fD8fU1n91EHY/0Y1QMBSgKdO1lBeo7U/sheUZx/diJiD2UyfdnGcsFBuki94n2hP61A7RsFNwWyzROqjU4T1cQwUbd3sntmKT130MJpbdVVeUM6NTPK1iKN1ydkIId834GZdQ4sguqijOg3wNPcsxwtAt4afcSIC0rPyp+wPUd8DqWqxH+K0vD9LGGw4+PM3Rzb9lxhsWi51yydvIxfx0HFuRA3medazGuRYErzd/WJck/LKCZyuz0eKqon8GSbr/lVqIvOoYDRNtDDzuD7WA2Ve3qWNLNt2tBX3KMkSSOEGgPgST4fbY+wV11m5wskPEUrSt0GlVJjXaUFQA8r/71XbGcrF3JUZyVGqtCa+5wGNsWwnRUm6qcRpWpy81+4juSdPPtWtCXHGMkL0C+gQV2aaijedKRR12GlccznrRUvU5jLK3YUiqKEEFuDnd9cmO9pviY89h31G0ns/doL2BGL390m1W++d9V5GTUU+tIuuyoMrdZPK1Ko2xA236nNtSFRxzRS/AIwdNHkGxvqyR1XIADWJhMfC2CDEfdYecBaYt7NeVHVDQUH+Fu2XGS3bVxHvZ1LJv+GUWPMTKHIZpdZIWD215fcoxJiq/S/SxjGcw+F5o58CCcl4APB2ZAmb7kKBI8S5LvGT5hmzV6/gSSG3X0KC2eXA6t6bKjL6P7OwLzvpkWTjbU4xRMNOCQuH1QUKc3R2s94B+gID66AaC+ZJZIKl4/KooshmRkuV1A/WjrdfN/jutP0/UrvBNB2Zv0piUrkNy+6b59rpISbhMYo5p/f/3uNT9Tvqa1c+8r7CWMb0mcREUcrUUqoNavlS1gGsw2hEti2/M/hGqIr0kdLuMkS4syjxBlxekN0xhuo4SjAJfPUBDgznWIfMp7sMWHR2kp76pJjdTju2LFHT5H7SE6/PaW4hs7dpJa64XBlI3iz8JOMgoth536RWIWduoOlQLKpV/evHknjF2P1B0X0lD9x12XKfLTUNXwzyxNuqOwoy0iOT6fb5oPQXG9yqo8VnNEW5YZx/7jJMJFOIKWtWVk3uq6PAFz6Y/cFXXqj2VnZ7OrKMd+HEHExR6zmdWQz8FmGteM2disWV53SpbJVDYhbW8kmY16tkRB1nHYgBibXxGfn78mVMVd2Et71DYpd7U/mhAm2DLLnzEtU3ZRDZY2h0nfGxlG98pGjs1tRLhGIw8fQf5yha/XKMeWzsQMKpNgtQe0kIah+ELZ1XF4w2pdo9o2N090WpzCq3dZijnXaBk/7ZFazvfIRitfDF/tjMVyRqaa3mZpZ7Wa2Wj5OUqr24hYzvIJDZd0tQwcm7DrBkymN7tgxGzYkeEKdSd8B3RcoaNskjR9FFazHv8wEsi6WrrAonhvZ1a4BTDb9CudvXibebXjrrRcAoQG8RXb+o6JwUkNi8CMNJ80CfvJLyipm9XlGIUFORJMwIkGF7QUFZvcyFoITw4d60hGXTHOPwUX2nDBbOynvto3Fd+VaJ+C2vWIugqupU1fFo/R7WV5i03ZeZ5iumPBS7OxUnuvLyATDewfueBUBKn7tusMIL2KuvCh1zCt/xxeHDPYT9EJWYJp3HzecO3dxO5VsSHVui3Biofu4ySLDH8bXNaUkeVM2+EJuEp7911Rpf5+7EycNaAgWwiIveUrmzGega3UMRGm5qpjmCRIo5fHg3DiqSEnXhu5t7vcYFQXS/z5uaGJWXkt78RCF6+m0dKmdGl7s3i1PbJZvGbjqzpU+arMya3JgihEXfx2JXN1GegR7T9OwlyylrPtkWYYhc3kBBuHzaTdMqmXjuc/C6+1V8N3g7/a1jJt6D/uPB91XdkJ3mlvju8G77StZdrQf9x53um6shO8g6+87wbf4Jayh7Xkw87zC+nGzvBKHR7hWmy07UiNyCV1G4UWtJ/HOc83HcUA3NJ0xKQ2nH0+fuHj2tGxxwYtjHxpdjyFxGm4Sxe1UNc+NuM4HMiTZApuNI7iqOJPo7CNC2DWoVN9FSPoBv4nZFJrBpmbQQciRk5t77SSoIsycw1NkAmZb1KDlyvDLY7ZdkgCLpHpppJ43ow3r6Q7fcavxUTJUVXeY8SYJHJL8qIlnq4HTLv0GXdeAmq7Z8OQs/HiWZZXG2KUDc146vPFrk4Gifq683zR92V3mIA8pzU1F9RveAls0HzeDz6QvFO2aEa4Jv/Wby5rB495lrkfvObzJAsRqVBswkisoyLMiMxjVFHfriWIEEm77UdsTH6ZQeiYj+W0EodkX4DyoWq2z9CNyUKTay+W4zqp/kKaNRsTkTDKIzjJ6XQX5klTAtJ82XXfuLobJhWxBJ959Hdi0zwt00yp5ppzzewabhue6Rt+mP4jRK3JX67lcaUWGoaLbrm0PWyGvQnExXTLpN7ZI3FJeU0yV+xlxE/AYuYyZS7+Ii2cd+EjHnFL5qiulWILRnSFm4x3+o7sEsMsP4bJPGwzYbwSO8aZO0rJB3hbnkT5+vqiwk/DFGD9A5b3ij64D+PAtaS2FQxY/3E8SWI8Tp5M0fXFiCekQzE7izC6jrxDrkM6kqyRtVzangmUHisOCMRt1npPW3BZvPaNngoL1YaWxGqT6UjOfMaM6Lxq05esBMvXs3ErxRbUX3ebh/qOLF/PvgRPiNsvMgRQtMJpJ+yTkoYzzZGm77ztUtarnbBkyvgs6CI4oI4vh10mE0OuvMIMy7yB/fA7BoteydpGCsH6RnxXYjIG6vqx/GWsbSqxGMnb7TpqI3OOYHBgE0aLM2o8sIGYyNgs0RWY95C2DU05XSCbwzH9a47oM2orZZWn+DEdMIKv8Uj6MNVkTrVhUvZAB6b7sxPab3eBZ3qpcgiPpRQvc+q2GWnISZTXKstxla4ToD2eaI5VqJySEy861YpN+BZxKgmfOOaJlooW4zCQ0DeTOvsmLoeFdmKVWgKbTblWOXHX7MuVwFvLP4NfAmNNeCLvxFdzH8w39a+2IIa3/397V9YbN46E/8pi/kAw794FPPFkNkAyycbO7KMgdzNtIeqWIamTyf761S0edUlNSmrPvARx8yPrYPFUsap7fXhblnnyeC7VFdgYyT/EF4a8duujxbsGU4RZ//Bc/xlJ5NKnHt4eZIYQamokZBVw2QPD3ETNN6FLZ1BKWNFhAmxgo5OrXNrQhvOXnJsvNrbVJ2xKgrVtvt86PMQHPobZVnYRI88QL3rpC9ktaCJN2CGsGH4MMC4m4g7dp0Bn/hVMTNrha1pZBV/d0P6I8yQ+lcPc+jo7PianBhjhKeP19zA6yHgHYxRMuhbkeYNMi4SHeeKFKiiotVGCSrjQ2d6y/V3N2Xzzhrr8unupja59VEfEuF6blBjii7W+l2By/JWQAwS6fOlroM1a46LXPh7McjN3PbYQf8TpeTBSWsIwdrGs5TbiStjsgCFteJY9hTHlVtoJ9mw3sLZZR/fx8TlVd9n3U5rF+HO8AWCcdYYf55xzJJsFXycWULygliK76DOUv5otPCQqr+SrU2ujYXMvjXXc2ESQGWvg3uBF+/VFBDYe5ZEQ07nbgFlt//iwjhEteESYZj8bORSMrl+d0972Dcn1q5vkOXh9huWKJCFqdOeGzMyrgbFboL+thCa6OfsY9u1vkrSsY0sGdyVeapqyJKOZdMAvx0WZlVU+u63qsvxLvPv69nRfZruv9+fHYpcnrb/VVXguI8yb+VYxzNX7MWOSTdn4b87utr9z257RLbg+X2Jza6/St1++JGn1i4oWivE8EDQbGn+99odeoygSYms/IG1Ckgdd5HBTcGi7od9f2OrkynQV61Il37fKoN9XhhofVPQmz47LWYlJ3FrjzKKrtw9LIAlFvTO2YiAP2d/msRHzGLtivS1Gta/8Vqn8XXaItP/XHYVvNiycsVewyxbZ4WpUMW5C7V0onYUxNF0o0S7GZHETpnYVh/X1rGrJeWuqOa0+Zf3nrM5q/+sxTtKo+fd2R2eyMEBGpk6jYBGb0pg3WDF+D2JTuKrC2JUukYSczt96IVae1O5rdra9oZyf8XnLQRoTmFu6TOJkUCyatZD+Tow+wxgkIqFozrOrrhhTanfOK4kPH+MfTVzDt6ekbtdTeEN8K28TtoJD2YXXHbPQkUdEU+uJzdhHHyWVlshXPweLSgYKRbIWNvzqPAPxa5RTorHadVezz3fZLk6T/6l9z2P0Lj4dzs6JWev9AaB39/jjIhbosG0y45YGsTpYVWGszZVJQrTncEX78n24DOffaZ8rX8Z58mrOkd3XvU/qW6K+/1ulz1/O6akO6Fd3ydh4c6M+2FT1e1lvux6yCKvPml3XBmh9Q9lklyuXD+CLMwASeLhfZHO9RItcwUp6ZBLtNe3QKPgZNSsDhnf6aibl12egE2br1mRUXs9nJc0Or7Njc1AUzmpalaUnMp204Zui//6CpitU1ZPILWxG9f/rLOn4fNQjnD6EUsWHcnmabkqepqlB0A0aUM/baob0u/peTJyPtCpLz0c6ab1J4/cXNB+hqp5EbmEzqv9f+yPj81GPcPpwQa/0GabkaT4aBN2gAfW8rbf1ztL0j6xMTodPapfle/HRz6q3+JHPpm/sy53CFzRH0ZqfRHMN+6p/uD0V31VOnOcGjNOt/c/LvKS5xMh8HfpGobdqXCOL27hBmHV9teqdlfzO4rqnLk8XGIsbVPcXewO1/uPkqfZ0fc9ZphvRso9Yfq3qlD/qUVXVUHl/15/t1ZskL8q7uIwf48L92FfXulel8HnqT/9oa0x6ynm/e1LH+J8/7R+zykLiR9lrUWcKYziVsCbkRUocJ0kSYpu/S4rONc5pfyyCCIylDIXXcakOzVd6h8JYBFEYSzkVJbvynCtIRX0JqKK+UNYDBBULQPRH1IGi93GTlUPcP3USsyRX7SES7SoDRfWaAeRYMILCurSNYpCogZBpm7AaB0Hpu0eJFd5VfB+fzl/ipq+ImchEUXzoSDEvDBM8dRPBDVR7q+eOVxsBDlsbJCRL0KMJsRSGR5IOgaEEan8o5ASoBxQ8v/UlIPt9IdN8n4ruvSqfsj1AxQZAxGwMR7Oshk1lut+qHQs05q1ykKIJYQiOnw4cWmMRRGYsZSiMzkQOhbEIojCWchRqbxp1X+bN2bJoswsA1EAYSBlEMlyMl54O5bEIolaX8rOjdkHhTopaITgXauUCOggFvG3xVNOGeEOnm7aYmnJaBCeDyo9JUVSb5/76xJXHgYCyOSiG8q9/VtvaU5zensuneoPf5uJAuaDhEEd0DYa75g0uMti1MohuU1xEogHfYB+y52SH0ekKCUIdQkIJI0K23yEk7f+WZ+dnjEhXSFDqEAylzmPcIdL9DrXfFQm3sZ/rd5OD2y66jzVh1EbWRDJc/JZ8qbaN+Z7hAoZBXMBIIRcEZZqarBuRRUArQ7tTdDBtkL9nJTSTamUokbaYIfJJfa8E/pglp7LAOwxEQYRBoGD/hRy7xiJszyU6YBmJ73EqeKeZCFalRpJvQJlGOaxGA8KKZ+fUBES0IbCYNkp2lsMSeGGnOgxPne+QbGrSkx6dF83VFwkHdUfWmMWdmK8pHEn7tElGhHVgU0j0VlMuo0Pm/cDok5UIvsh68/iVM8ncW1kR7afepwgYknEy2VKQGO9StXTwCb3W1eB2REP4cXcXNBSBO5+hlKGgxf91SGhlEA2tmL0pyMA70e53+GYgE9y6NqjByOD2h2KUjNRKH6r6qunIR/BoaJWDOjMh3IUHFovNvf/AkOB1CAaecNP4oI7PaQyOVBjG3TyOSOGnAoIDF0J9OhBT7hcGnLCDoNYXKdnf1ElVw4yaHF0IeDRwUNyd6C5F7wO0MvBedCxmiHzOcSJaGUREK+Ymiqr2/pyqh7j4Ck0URjE4URgITm9jnDxXb2MZqLexmBuNKi6qgfNflRyeoC26VQ6OPxMiI3iXVKeIAp6GXAhBVkOxV3J5rk478PZ8KIKv4vpSye0JM8cCGOIuZdLMasfAAiYWE0Dde1lQdoxrMWyAUa6VwuNcA8hJtSGhKHItgiHZgtgF4/gcJweoS8cieIHoS7mrVCN8jHt1ahSDV6UGgh2HTc9SK7CNgEehBRJ8M3inylLlzDjBgNj3BAjL8GIEyXEYMEohqgaAsx43UotrRi4GtCcXNpU4di7BgCI2ZGcRNK4CcDmEIOFrIgQ8kR0BHzIGZJ/wzEf+DmkAg368M2Gs2PVg3eMOPzYAFtnEcFaYZ0VRNZ7iVF0IaHkOilU1tCihi5FkEar+VyKnxb4E3P/1hdwZMf6T8EoxSsHzoQ7gSCGfrYgvVrJPVf1nE0IQF0J9f4lun5/TRO0fsg6fKP4rcl8ZNzoHIeOhg/McmP4QuAcHguNdLD6popqCG29XgQdJ91kZd1RxENTX6Q4k6Aj7yzLzgZyGSz5dRzVUfHc4uBLJvtvLv98bqeKmXmVKbqCFF9HRiJvKBfAkH2MGgBI8AWiB887wwM29v9JLMReeASDYqeKkjFJsTyol5b5+cfXrQDDXFBM1pYe5bhX0pUNQ8+vG3FyjwZtVA4P+rgPSdjzXPPdN19mKJup9C3n8g9WtIvsdgSniDPH7hYcXH34YAD2dcPnfjPiDnyzR7w7Gf4/b+5KmIrptmi4mtW2J7jsPO1dySTVcKNvHvhEK858Ha4JqcQvDquchzg8KHBGSap76fGPq6Teck2zHrhTScqC5xykLqZgpVmNX8j+lrqQW4NlFQaoErBDSToD3JUYj1IOR2YttZL4MQZdaE0cIA7xUaaUgXqDMtav5Yg/r6Dg1oaK72BATKfLoRhff4zRqi8bvtRxosM3WQiowngMRWy4Q53/bBT00aiqTD4hm97z1GEongZoAXsezWJBVoA2B5UHUxA8SEB5soCysEvN2Leqv11R3J0dv3+WVcbHhZ1iNxPTjKqIV694RaAx7JBZEgfhWTV6ZWJ0AYRHxtqIy/QlbNLQLqAcEBlAF9CyvVQH52m666N0VMiW0DfEvrnUd3tTDHmXOF9FSHS6oCfTeSwuKPlyDD18KiMkTBxM9br3pbbscea8L1oQU4JSFUAQ+CeJgL/24BTX8kqRpNZEOLRNKsKDhVCCyoQuE7sMljU3jUjvYkEPAeodvNIA9rp+uBuiR8ZivAdAFXQEXy36A3ciDPa42axIPq9tWJA+lp6umf1tOqsMFhVCB/T6+qYm+fZ8uav80nBTVBYUQ1X7A3tQcf7z8cJWlKSmmCQghov66vT0zQa/X54nWPrCP2hZh4XTIhUw6NczgAEM95Nn/DBFthwL9Sz61jZFVJIRDXvO3IjIv9MmWIO8GsFUy+oB3VeIbIVlFfoFzBKYE3KQKQX8S0WZ6ovV52E1wSl9GNYLt9eLWtJaKqCga5HZUVjGENUkiizStTYoQMl11Q5wQUk8AKoRSnIAmTVXtVz/iNh6evLwWLJjAho/qKDHshzpT5EiPboLIq2MYlo0YKiPLYGwUt7Zb0W/Pdk2S3dpiLmZ0nd5sRqLeLDViNZxH1hcet02gE8GtCojzf6VihPdpasHRe+YKSs1NFiLEtBROPCjaUDT6V+COHHAFwoPhYkcOKLaR0QoZq8iTajq9C/UCpvyd3q+bUMcQPwnXgQ3xK7gT+2ms5+kCZeSf+Cbtgvx/iQ4vah9xK/pYnc+e4kLt/5uUTxoFV3CuijdxjLp2TLGmKhovbL4ijHE7to+rAa7gSRCwJjriRcHaPKnms97vYv2YtfzOC2upZ4j1xkyIGiTAhKjHqRvrgSHoposIRJUjt0IkPsTGiIii1zQiCYvnRy3suOAr+bWOdVTTB+zDx4SF8Cu0HdLwvvei8eTeq8cjjMZ2cSlNoCfGwZrO+krGTpx7EOo9ktgjnw28pjOfEQWSmfBAZJipDohu2Y1kKmjlBRfcgs5Gsf77O7TbhB2EM9JzmUAjHIezJwI344p+NsCTqFgjHw4/2o1+JqSoBwVRIwMHhxgcq6uCODCiWP/nxqXVQIaVFTh2MxX9K0gUN1dvTRjLdYYFEWFrkZi7oHHNaIawH14vMoUIWjVDABNtI6F8fVsrTXyqCZOtLayqjY4AN1IE6eWCo4NNE248DL0FvTSIMgg/FRzNCoVIA4ixDZUQoaOlryzFTRC37r4eYArCbusanRI4O4iK+UVcUjvYEL0Gdc7Q4fKKk2grvIrIvY64Lis8KbVsU7NJNTZBESOUrFildDuLKEXSrhFYkmocDhY5f5W+j4/PqRrj1eMrtIUkFhgran67uCAR8edOBDNEHgLmG96LkMgIkj/uz/dvdBIBNNXxGP+XiE9M4i7I/7QdXlTn8qm70eJXL7RKsNVr7v2ZF7VMUsiLVoWVb5q5MZ1SfZkbVI4jumku2/aMd1lwkgvyopWtE+K+lUny0TQkzdjhT03EwOSq+B+e66poSMkQER9vXJD/rzZOWom2JpoxYqYHrni4EOgQAwXN0XA/eOR67nkzlUL0Js+OlD4oeAiFwFkjulFFJoG4WBUP2QRFaOBrV4OWeyJy8lAAswIBJ8Y5nCejHe108gusHawNzyqhjALEhbCHZcTWckhEZvoOV3QUiwsBpRRppKBShRgtADkymgao5BczHBzAZBIRkOoCcHiQ1iWsBMvO0ZoLl3CDbsu9ExGmzpjjJmMmoYjenpIyiVPCBY6qcLGnj+UuA6fa6DxmmPQZlyujd/FzSfF6QesGEpdsCfYdlOU/mRm0Q08uwkfsgNG4gBeG64CSqNwPsTrIvChz1EGvT8HXJXs98rMOdecnJyB/VG8PXmenoszjpJof6t3oIF8fouYhi7D6xK2Df1q8umfEuYGOnmhCBP0syic38NhNRsHPk7RuVRUKj0u8aQVqCSCk5mbkjADuMS5rMbzNAikz2qsOIhfGZYrtgwWBdggDafbF4YhWEFzL8yHtfyM1iKuhC1sMb1FAZpSmDSrlyWWK7WMygRYFA2n2xVGfVhDcTuIiXhed5C/AKuCr7QXWWiQpTrtEcIluPKh9DCYFL6gUnhZrUuSqdZWiL8WzNmjsXmReqwvv9eTbnYuV3P3Fb+JGZLBPmR6Fv3nVNlKrvupnlQ9lN6/atFLdD9Wf1dG1Ovm9z/YqLZpfb159Ole1j6r9604VyWFs4qZq86SaBHhjoz3m7elL1p//LI56SF88ZMYt431cxrd5mdRhxaviXbX7bBKmNTc19fXZo9q/PX04l8/nshJZHR9T43R584qmf/PK4fmm9RUufIhQsZlUIqgPp1/OSbof+H4Tp4V1osaaeF1pv0n13vZlNThLdfgxtPR7dhI21KnvTj2r074adH2q4OLD6T7+pubw9rlQ79Qh3v34WAc4bi6esEb4jjDVfnOXxIc8PhZdG2P96s/KhvfHP//1fxuJQblsxwcA + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.Designer.cs new file mode 100644 index 0000000000..8be4a5ab81 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class EuEsd : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(EuEsd)); + + string IMigrationMetadata.Id + { + get { return "201411182201537_EuEsd"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.cs b/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.cs new file mode 100644 index 0000000000..103035c04a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.cs @@ -0,0 +1,18 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class EuEsd : DbMigration + { + public override void Up() + { + AddColumn("dbo.Product", "IsEsd", c => c.Boolean(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.Product", "IsEsd"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.resx b/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.resx new file mode 100644 index 0000000000..3f005e104b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201411182201537_EuEsd.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.Designer.cs new file mode 100644 index 0000000000..85879d8f1d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class V21Final : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(V21Final)); + + string IMigrationMetadata.Id + { + get { return "201411182202431_V21Final"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.cs b/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.cs new file mode 100644 index 0000000000..8776a3c7d0 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.cs @@ -0,0 +1,153 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class V21Final : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + // New stuff from MH + builder.AddOrUpdate("Products.CallForPrice.GoToForm", + "Ask for price", + "Preis anfragen"); + builder.AddOrUpdate("ThemeVar.Alpha.DisplayNavbar", + "Display Megamenu", + "Zeige Megamenu"); + + // Tax & VAT stuff + builder.Delete("ShoppingCart.Totals.TaxRateLine"); + builder.AddOrUpdate("ShoppingCart.Totals.SubTotal", + "Subtotal", + "Zwischensumme"); + builder.AddOrUpdate("ShoppingCart.Totals.Tax", + "Tax", + "MwSt"); + builder.AddOrUpdate("ShoppingCart.Totals.TaxRateLineIncl", + "Incl. {0} % Tax", + "inkl. {0} % MwSt"); + builder.AddOrUpdate("ShoppingCart.Totals.TaxRateLineExcl", + "Plus {0} % Tax", + "zzgl. {0} % MwSt"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.IsEsd", + "Is Electronic Service", + "Ist elektronische Leistung", + "Specifies whether the product is an electronic service bound to EU VAT regulations for digital goods (2008/8/EG directive)", + "Legt fest, ob das Produkt elektronisch vertrieben wird und daher gem EU Richtlinie 2008/8/EG versteuert werden muss."); + + // Some german fixes + builder.AddOrUpdate("Products.ProductHasBeenAddedToTheWishlist").Value("de", "Das Produkt wurde Ihrer Wunschliste hinzugefgt"); + builder.AddOrUpdate("Products.ProductHasBeenAddedToTheWishlist.Link").Value("de", "Das Produkt wurde Ihrer Wunschliste hinzugefgt"); + builder.AddOrUpdate("Products.ProductHasBeenAddedToTheCart").Value("de", "Das Produkt wurde Ihrem Warenkorb hinzugefgt"); + builder.AddOrUpdate("Products.ProductHasBeenAddedToTheCart.Link").Value("de", "Das Produkt wurde Ihrem Warenkorb hinzugefgt"); + builder.AddOrUpdate("Products.ProductNotAddedToTheCart.Link").Value("de", "Produkt konnte Ihrem Warenkorb nicht hinzugefgt werden."); + builder.AddOrUpdate("Products.RecentlyViewedProducts").Value("de", "Zuletzt angesehen"); + + builder.AddOrUpdate("Admin.Catalog.Attributes.CheckoutAttributes.Deleted").Value("de", "Das Attribut wurde erfolgreich gelscht."); + + // Theme inheritance + builder.AddOrUpdate("Admin.Configuration.Themes.IsBasedOn", + "Based on", + "Basiert auf"); + builder.AddOrUpdate("Admin.Configuration.Themes.MissingBaseTheme", + "Error: Base theme '{0}' not found", + "Fehler: Basis-Theme '{0}' nicht gefunden"); + builder.AddOrUpdate("Admin.Configuration.Themes.Reload", + "Reload themes", + "Themes aktualisieren"); + + // Theme Preview + builder.AddOrUpdate("Admin.Configuration.Themes.Preview", + "Preview", + "Vorschau"); + builder.AddOrUpdate("Admin.Configuration.Themes.Theme", + "Theme", + "Theme"); + builder.AddOrUpdate("Admin.Configuration.Themes.PreviewMode", + "Preview Mode", + "Vorschaumodus"); + builder.AddOrUpdate("Admin.Configuration.Themes.ExitPreviewMode", + "Exit preview mode", + "Vorschau beenden"); + + builder.AddOrUpdate("Common.Apply", "Apply", "bernehmen"); + + builder.AddOrUpdate("Common.Reload", "Reload", "Neu laden"); + builder.AddOrUpdate("Common.Refresh", "Refresh", "Aktualisieren"); + + builder.AddOrUpdate("Admin.Orders.PdfInvoice", "Order as PDF", "Auftrag als PDF"); + builder.AddOrUpdate("Order.GetPDFInvoice", "Order as PDF", "Auftrag als PDF"); + + builder.AddOrUpdate("Admin.Orders.Fields.Affiliate", "Affiliate", "Partner"); + builder.AddOrUpdate("Admin.Customers.Customers.Fields.Affiliate", "Affiliate", "Partner"); + + builder.AddOrUpdate("Admin.Configuration.DeliveryTime.BackToList", "Back to delivery times list", "Zurck zur Lieferzeitenliste"); + + builder.AddOrUpdate("Admin.Configuration.Measures.Weights.Description", + "NOTE: if you change your primary weight, then do not forget to update the appropriate ratios of the units.", + "Achtung: Wenn die Standardgewichtseinheit gendert wird, mssen auch die zugehrigen Umrechnungseinheiten (Verhltnis) angepasst werden."); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.Seconds.Positive", + "Seconds should be positive.", + "Sekunden mssen grer als 0 sein."); + + builder.Delete("Admin.Affiliates.Customers.Name"); + + // Avatars + builder.AddOrUpdate("Account.Avatar.MaximumUploadedFileSize", + "Maximum avatar size is {0}", + "Die maximale Gre des Avatars betrgt {0}"); + builder.AddOrUpdate("Account.Avatar.UploadRules", + "Avatar must be in GIF, PNG or JPG format with the maximum size of {0}", + "Ein Avatar muss im GIF-, PNG- oder JPG-Format vorliegen und darf {0} nicht berschreiten."); + + // Misc + builder.AddOrUpdate("Admin.Catalog.Attributes.AttributeControlType", + "Control type", + "Typ"); + builder.AddOrUpdate("Admin.Catalog.Attributes.AttributeControlType.Hint", + "Choose how to display your attribute values.", + "Bestimmt den Steuerelement-Typen fr die Erfassung der Attribut-Werte"); + builder.AddOrUpdate("Admin.Catalog.Products.ProductVariantAttributes.AttributeCombinations.Fields.Sku").Value("#"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.SeName").Value("en", "URL Alias"); + builder.AddOrUpdate("Admin.Catalog.Manufacturers.Fields.SeName").Value("en", "URL alias"); + builder.AddOrUpdate("Admin.Catalog.Categories.Fields.SeName").Value("en", "URL alias"); + + + // Marketplace + builder.AddOrUpdate("Admin.Marketplace", + "Marketplace", + "Marketplace"); + builder.AddOrUpdate("Admin.Marketplace.News", + "Marketplace News", + "Marketplace News"); + builder.AddOrUpdate("Admin.Marketplace.ComingSoon", + "In the SmartStore.NET Marketplace we offer modules, themes & language packages, which will make your shop better and more successful. Once we are ready to go, you'll be informed about the latest extensions here. Stay tuned...", + "Im SmartStore.NET Marketplace werden Module, Themes & Sprachpakete angeboten, die Ihren Onlineshop besser, flexibler und erfolgreicher machen sollen. Sobald wir die Arbeiten am Marketplace abgeschlossen haben, werden Sie hier ber die neuesten Erweiterungen informiert."); + builder.AddOrUpdate("Admin.Marketplace.Visit", + "Visit Marketplace", + "Zum Marketplace"); + } + + + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.resx b/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.resx new file mode 100644 index 0000000000..3f005e104b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201411182202431_V21Final.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.Designer.cs new file mode 100644 index 0000000000..2a0242351c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class V211 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(V211)); + + string IMigrationMetadata.Id + { + get { return "201412081934318_V211"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.cs b/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.cs new file mode 100644 index 0000000000..11b4d61f22 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.cs @@ -0,0 +1,256 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Topics; + using SmartStore.Data.Setup; + using System.Linq; + + public partial class V211 : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var topic = context.Set().FirstOrDefault(x => x.SystemName == "PageNotFound"); + if (topic != null) + { + context.Set().Remove(topic); + } + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.CanonicalHostNameRule", + "Canonical host name rule", + "Regel fr kanonischen Domnennamen"); + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.CanonicalHostNameRule.Hint", + "Enforces permanent redirection to a single domain name for a better page rank (e.g. mystore.com > www.mystore.com or vice versa)", + "Erzwingt die permanente Umleitung zu einem einzelnen Domnnennamen fr ein besseres Seitenranking (z.B. meinshop.de > www.meinshop.de oder umgekehrt)"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Seo.CanonicalHostNameRule.NoRule", + "Don't apply", + "Nicht anwenden"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Seo.CanonicalHostNameRule.RequireWww", + "Require www prefix", + "www-Prfix erzwingen"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Seo.CanonicalHostNameRule.OmitWww", + "Omit www prefix", + "www-Prfix weglassen"); + + // order payment row + builder.AddOrUpdate("Admin.Orders.Fields.PartialRefundOffline", + "Partial refund (Offline)", + "Teilerstattung (Offline)"); + builder.AddOrUpdate("Admin.Orders.Fields.Void", + "Cancel", + "Stornieren"); + builder.AddOrUpdate("Admin.Orders.Fields.VoidOffline", + "Cancel (Offline)", + "Stornieren (Offline)"); + + builder.AddOrUpdate("Admin.Orders.Fields.MarkAsPaid.Hint", + "Sets the payment status to 'paid' without contacting the payment provider.", + "Setzt den Zahlungsstatus auf 'Bezahlt' ohne dabei den Zahlungsanbieter zu kontaktieren."); + builder.AddOrUpdate("Admin.Orders.Fields.Capture.Hint", + "Books a previously authorised payment through the payment provider.", + "Zieht eine zuvor reservierte Zahlung ber den Zahlungsanbieter ein."); + builder.AddOrUpdate("Admin.Orders.Fields.Refund.Hint", + "Initiates a refund of the total order value at the payment provider.", + "Leitet eine Rckerstattung des gesamten Auftragswertes beim Zahlungsanbieter ein."); + builder.AddOrUpdate("Admin.Orders.Fields.RefundOffline.Hint", + "Setzt the payment status to 'refunded' without contacting the payment provider.", + "Setzt den Zahlungsstatus auf 'Erstattet', ohne dabei den Zahlungsanbieter zu kontaktieren."); + builder.AddOrUpdate("Admin.Orders.Fields.PartialRefund.Hint", + "Initiates the refund of a partial amount of the total order value at the payment provider.", + "Leitet die Rckerstattung eines Teilbetrages des Auftragswertes beim Zahlungsanbieter ein."); + builder.AddOrUpdate("Admin.Orders.Fields.PartialRefundOffline.Hint", + "Setzt the payment status to 'partially refunded' including the refunded amount without contacting the payment provider.", + "Setzt den Zahlungsstatus auf 'Teilweise erstattet' samt Erstattungsbetrag, ohne dabei den Zahlungsanbieter zu kontaktieren."); + builder.AddOrUpdate("Admin.Orders.Fields.Void.Hint", + "Initiates the cancellation of the payment transaction at the payment provider.", + "Leitet die Stornierung der Zahlungstransaktion beim Zahlungsanbieter ein."); + builder.AddOrUpdate("Admin.Orders.Fields.VoidOffline.Hint", + "Setzt the payment status to 'canceled' without contacting the payment provider.", + "Setzt den Zahlungsstatus auf 'Storniert', ohne dabei den Zahlungsanbieter zu kontaktieren."); + + // Error Handling (404/500) + builder.Delete("PageTitle.PageNotFound"); + builder.AddOrUpdate("ErrorPage.Title", + "Oops!", + "Oops!"); + builder.AddOrUpdate("ErrorPage.Body", + @"We apologize, a server error ocurred while handling your request, this is not a problem with your computer or internet connection. + The details have been sent to our support team and we will investigate the issue very soon.

+ In the meantime, please retry your request as it may have been temporary.", + @"Leider ist ein Serverfehler aufgetreten, und das hat nichts mit Ihrem Computer oder Ihrem Internetanschluss zu tun. + Unser Support Team wurde bereits benachrichtigt und wird sich sehr bald um die Behebung kmmern."); + builder.AddOrUpdate("NotFoundPage.Title", + "404", + "404"); + builder.AddOrUpdate("NotFoundPage.Body", + "Sorry! The page you were looking for could not be found.", + "Tut uns leid! Diese Adresse gibt es auf unserer Website nicht."); + + // amazon payment review + builder.AddOrUpdate("Checkout.ConfirmYourOrder", + "Please confirm your order.", + "Bitte besttigen Sie Ihren Auftrag."); + + builder.AddOrUpdate("Checkout.ConfirmHint", + "Please verify the order total and the specifics regarding the billing address and, if required, the shipping address. You can make corrections to your entry anytime by clicking on back. If everything is as it should be, deliver your order to us by clicking confirm.", + "Bitte prfen Sie die Gesamtsumme und die Rechnungsadresse. Bei abweichender Lieferanschrift prfen Sie bitte auch diese. nderungen knnen Sie jederzeit mit einem Klick auf zurck vornehmen. Sind alle Daten richtig, besttigen Sie bitte mit einem Klick auf kaufen Ihre Bestellung."); + + // new setting + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.DeliveryTimeIdForEmptyStock", + "Delivery time dislayed when stock is empty", + "Lieferzeit, die bei einem leerem Lagerbestand angezeigt wird", + "Delivery time to be dislayed when the stock quantity of a product is equal or less 0.", + "Lieferzeit, die angezeigt wird, wenn der Warenbestand des Produktes kleiner gleich 0 ist."); + + // old setting now with ui + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.IncludeFeaturedProductsInNormalLists", + "Show featured products in lists", + "Top-Produkte in Listen anzeigen", + "Specifies whether to display featured products in product and filter lists. Otherwise they only appear in the top featured product list.", + "Legt fest, ob Top-Produkte sowohl in den Produkt- als auch in den Filterlisten angezeigt werden sollen. Ansonsten erscheinen sie nur oberhalb in der Top-Produktliste."); + + // new notification + builder.AddOrUpdate("Admin.Order.NotFound", + "An order with this number was not found.", + "Ein Auftrag mit dieser Nummer wurde nicht gefunden."); + + // PDF + builder.AddOrUpdate("Common.Date", + "Date", + "Datum"); + + builder.Delete( + "PDFInvoice.Address", + "PDFInvoice.Address2", + "PDFInvoice.BillingInformation", + "PDFInvoice.Company", + "PDFInvoice.CreatedOn", + "PDFInvoice.Discount", + "PDFInvoice.Fax", + "PDFInvoice.GiftCardInfo", + "PDFInvoice.Name", + "PDFInvoice.Note", + "PDFInvoice.OrderDate", + "PDFInvoice.OrderTotal", + "PDFInvoice.PaymentMethod", + "PDFInvoice.PaymentMethodAdditionalFee", + "PDFInvoice.Phone", + "PDFInvoice.PurchaseOrderNumber", + "PDFInvoice.RewardPoints", + "PDFInvoice.ShippingInformation", + "PDFInvoice.ShippingMethod", + "PDFInvoice.Sub-Total", + "PDFInvoice.Shipping", + "PDFInvoice.Tax", + "PDFInvoice.TaxRate", + "PDFInvoice.VATNumber"); + + builder.AddOrUpdate("PDFInvoice.Footer.Bankcode").Value("de", "BLZ: {0}"); + builder.AddOrUpdate("PDFInvoice.TaxNumber").Value("en", "Tax Number: {0}"); + builder.AddOrUpdate("PDFInvoice.Order#", + "Order#", + "Auftrag#"); + builder.AddOrUpdate("PDFInvoice.SKU", + "SKU", + "Artikelnr."); + + builder.AddOrUpdate("PDFPackagingSlip.DeliveryDate", + "Delivery date", + "Lieferdatum"); + builder.AddOrUpdate("PDFPackagingSlip.Weight", + "Weight", + "Gewicht"); + builder.AddOrUpdate("PDFPackagingSlip.DeliveryDate", + "Delivery date", + "Lieferdatum"); + builder.AddOrUpdate("PDFPackagingSlip.TrackingNumber", + "Tracking number", + "Trackingnummer"); + builder.AddOrUpdate("PDFPackagingSlip.ShippingMethod", + "Shipping method", + "Versandart"); + builder.AddOrUpdate("PDFPackagingSlip.ProductListHeadline", + "Shipped products", + "Gelieferte Produkte"); + + builder.AddOrUpdate("Admin.Common.ExportToPdf.TooManyItems", + "Too many items! The PDF conversion is limited to 500 items. Please reduce the amount of selected records.", + "Zu viele Objekte! Mehr als 500 Objekte knnen nicht konvertiert werden. Bitte reduzieren Sie die Anzahl ausgewhlter Datenstze."); + builder.AddOrUpdate("Admin.Common.ExportToPdf.TocTitle", + "Table of contents", + "Inhaltsverzeichnis"); + + builder.AddOrUpdate("PDFProductCatalog.Manufacturer", + "Manufacturer", + "Hersteller"); + builder.AddOrUpdate("PDFProductCatalog.Length", + "Legth", + "Lnge"); + builder.AddOrUpdate("PDFProductCatalog.Width", + "Width", + "Breite"); + builder.AddOrUpdate("PDFProductCatalog.Height", + "Height", + "Hhe"); + + builder.AddOrUpdate("PDFProductCatalog.SpecificationAttributes", + "Specification attributes", + "Spezifikation"); + builder.AddOrUpdate("PDFProductCatalog.BundledItems", + "Bundled items", + "Produktset besteht aus"); + builder.AddOrUpdate("PDFProductCatalog.AssociatedProducts", + "Associated products", + "Gruppierte Produkte"); + + + builder.AddOrUpdate("PDFProductCatalog.CompanyEmailAddress", + "Mail", + "E-Mail"); + builder.AddOrUpdate("PDFProductCatalog.CompanyTelephoneNumber", + "Phone", + "Telefon"); + builder.AddOrUpdate("PDFProductCatalog.CompanyFaxNumber", + "Fax", + "Fax"); + builder.AddOrUpdate("PDFProductCatalog.Cover.Address", + "Address", + "Anschrift"); + builder.AddOrUpdate("PDFProductCatalog.Cover.ContactData", + "Contact data", + "Kontaktdaten"); + + builder.AddOrUpdate("Admin.Configuration.Settings.Order.MinOrderSubtotalAmount").Value("de", "Mindestbestellwert Zwischensumme"); + builder.AddOrUpdate("Admin.Configuration.Settings.Order.MinOrderSubtotalAmount.Hint").Value("de", "Legt den Mindestbestellwert der Zwischensumme fest."); + builder.AddOrUpdate("Admin.Configuration.Settings.Order.MinOrderTotalAmount").Value("de", "Mindestbestellwert Gesamtsumme"); + builder.AddOrUpdate("Admin.Configuration.Settings.Order.MinOrderTotalAmount.Hint").Value("de", "Legt den Mindestbestellwert der Gesamtsumme fest."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowProductReviewsInProductDetail", + "Show product reviews in product detail view", + "Zeige Produktbewertungen in der Produktdetailansicht"); + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowProductReviewsInProductDetail.Hint", + "Determines whether product reviews are shown in product detail view.", + "Legt fest, ob Produktbewertungen in der Produktdetailansicht angezeigt werden."); + + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.resx b/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.resx new file mode 100644 index 0000000000..3f005e104b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201412081934318_V211.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.Designer.cs new file mode 100644 index 0000000000..2588652294 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class WidgetWrapContent : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(WidgetWrapContent)); + + string IMigrationMetadata.Id + { + get { return "201501191849483_WidgetWrapContent"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.cs b/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.cs new file mode 100644 index 0000000000..67db7d913b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.cs @@ -0,0 +1,38 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class WidgetWrapContent : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Topic", "WidgetWrapContent", c => c.Boolean()); + } + + public override void Down() + { + DropColumn("dbo.Topic", "WidgetWrapContent"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.ContentManagement.Topics.Fields.WidgetWrapContent", + "Add wrapper around content", + "Inhalt mit Container umhllen", + "Adds an HTML wrapper around widget content", + "Umhllt den Widget Inhalt mit einem HTML-Container"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.resx b/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.resx new file mode 100644 index 0000000000..e64cc40d76 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201501191849483_WidgetWrapContent.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.Designer.cs new file mode 100644 index 0000000000..775e8ffd3d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class DefaultViewModeForCategories : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(DefaultViewModeForCategories)); + + string IMigrationMetadata.Id + { + get { return "201501221417371_DefaultViewModeForCategories"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.cs b/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.cs new file mode 100644 index 0000000000..0ab1511472 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.cs @@ -0,0 +1,56 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Topics; + using SmartStore.Data.Setup; + using System.Linq; + + public partial class DefaultViewModeForCategories : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Category", "DefaultViewMode", c => c.String()); + } + + public override void Down() + { + DropColumn("dbo.Category", "DefaultViewMode"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.Checkout", + "Checkout", + "Checkout"); + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.ValidateEmailAddress", + "Validate customer email address", + "Prfung der Kunden-Email-Adresse"); + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.ValidateEmailAddress.Hint", + "Determines whether the customers email address is validated during the checkout process", + "Bestimmt ob die Email-Adresse des Kunden im Checkout validiert wird."); + builder.AddOrUpdate("Admin.Address.Fields.EmailMatch", + "Reenter email address", + "Besttigung der E-Mail"); + builder.AddOrUpdate("Address.Fields.EmailMatch", + "Reenter email address", + "Besttigung der E-Mail"); + builder.AddOrUpdate("Admin.Address.Fields.EmailMatch.Required", + "Please reenter your email address", + "Bitte wiederholen Sie die Eingabe Ihrer E-Mail-Adresse"); + builder.AddOrUpdate("Admin.Address.Fields.EmailMatch.MustMatchEmail", + "The email address has to match the email address entered before", + "Die E-Mail-Adresse muss mit der zuvor eingegebenen E-Mail-Adresse bereinstimmen"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.resx b/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.resx new file mode 100644 index 0000000000..0910187fe6 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201501221417371_DefaultViewModeForCategories.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.Designer.cs new file mode 100644 index 0000000000..ee292d9cbb --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class Licensing : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(Licensing)); + + string IMigrationMetadata.Id + { + get { return "201502120858030_Licensing"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.cs b/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.cs new file mode 100644 index 0000000000..618732eb72 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.cs @@ -0,0 +1,81 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class Licensing : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.License", + "License", + "Lizenzieren"); + + builder.AddOrUpdate("Admin.Common.Licensed", + "Licensed", + "Lizenziert"); + + builder.AddOrUpdate("Admin.Common.ResourceNotFound", + "The resource was not found.", + "Die gewnschte Ressource wurde nicht gefunden."); + + builder.AddOrUpdate("Admin.Configuration.Plugins.LicenseActivated", + "The plugin has been successfully licensed.", + "Das Plugin wurde erfolgreich lizenziert."); + + builder.AddOrUpdate("Admin.Configuration.Plugins.LicenseKey", + "License key", + "Lizenzschlssel", + "Please enter the license key for the plugin.", + "Bitte den Lizenzschlssel fr das Plugin eingeben."); + + builder.AddOrUpdate("Admin.Plugins.AddOnLicensing", + "Add-on licensing", + "Add-on Lizenzierung"); + + builder.AddOrUpdate("Admin.Plugins.LicensingDemoRemainingDays", + "Demo {0} day(s) remaining", + "Demo {0} Tag(e) verbleibend"); + + builder.AddOrUpdate("Admin.Plugins.LicensingDemoNotStarted", + "Demo", + "Demo"); + + builder.AddOrUpdate("Admin.Plugins.LicensingDemoExpired", + "Demo expired", + "Demo abgelaufen"); + + builder.AddOrUpdate("Admin.Plugins.LicensingResetStatusCheck", + "Renew check", + "Prfung erneuern"); + + + builder.AddOrUpdate("Admin.Configuration.Payment.CannotActivatePaymentMethod", + "Activating this payment method is forbidden by the plugin.", + "Das Plugin erlaubt keine Aktivierung dieser Zahlungsmethode."); + + builder.AddOrUpdate("Admin.Configuration.Shipping.CannotActivateShippingRateComputationMethod", + "Activating this shipping rate computation method is forbidden by the plugin.", + "Das Plugin erlaubt keine Aktivierung dieser Berechnungsmethode fr Versandkosten."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.resx b/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.resx new file mode 100644 index 0000000000..ee1843014a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502120858030_Licensing.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.Designer.cs new file mode 100644 index 0000000000..b3c53d818d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class QtyUnitsAndOrderItemTaxRate : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(QtyUnitsAndOrderItemTaxRate)); + + string IMigrationMetadata.Id + { + get { return "201502191643156_QtyUnitsAndOrderItemTaxRate"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.cs b/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.cs new file mode 100644 index 0000000000..48ccd918a5 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.cs @@ -0,0 +1,134 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class QtyUnitsAndOrderItemTaxRate : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.QuantityUnit", + c => new + { + Id = c.Int(nullable: false, identity: true), + Name = c.String(nullable: false, maxLength: 50), + Description = c.String(maxLength: 50), + DisplayLocale = c.String(maxLength: 50), + DisplayOrder = c.Int(nullable: false), + IsDefault = c.Boolean(nullable: false), + }) + .PrimaryKey(t => t.Id); + + AddColumn("dbo.Product", "QuantityUnitId", c => c.Int()); + AddColumn("dbo.Order", "OrderShippingTaxRate", c => c.Decimal(nullable: false, precision: 18, scale: 4)); + AddColumn("dbo.Order", "PaymentMethodAdditionalFeeTaxRate", c => c.Decimal(nullable: false, precision: 18, scale: 4)); + AddColumn("dbo.OrderItem", "TaxRate", c => c.Decimal(nullable: false, precision: 18, scale: 4)); + AddColumn("dbo.ProductVariantAttributeCombination", "QuantityUnitId", c => c.Int()); + AddColumn("dbo.Topic", "TitleTag", c => c.String()); + CreateIndex("dbo.Product", "QuantityUnitId"); + CreateIndex("dbo.ProductVariantAttributeCombination", "QuantityUnitId"); + AddForeignKey("dbo.ProductVariantAttributeCombination", "QuantityUnitId", "dbo.QuantityUnit", "Id"); + AddForeignKey("dbo.Product", "QuantityUnitId", "dbo.QuantityUnit", "Id"); + } + + public override void Down() + { + DropForeignKey("dbo.Product", "QuantityUnitId", "dbo.QuantityUnit"); + DropForeignKey("dbo.ProductVariantAttributeCombination", "QuantityUnitId", "dbo.QuantityUnit"); + DropIndex("dbo.ProductVariantAttributeCombination", new[] { "QuantityUnitId" }); + DropIndex("dbo.Product", new[] { "QuantityUnitId" }); + DropColumn("dbo.Topic", "TitleTag"); + DropColumn("dbo.ProductVariantAttributeCombination", "QuantityUnitId"); + DropColumn("dbo.OrderItem", "TaxRate"); + DropColumn("dbo.Order", "PaymentMethodAdditionalFeeTaxRate"); + DropColumn("dbo.Order", "OrderShippingTaxRate"); + DropColumn("dbo.Product", "QuantityUnitId"); + DropTable("dbo.QuantityUnit"); + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + // QtyUnits + builder.AddOrUpdate("Admin.Configuration.QuantityUnit.AddNew", + "Add new quantity unit", + "Verpackungseinheit hinzufgen"); + builder.AddOrUpdate("Admin.Configuration.QuantityUnit.EditQuantityUnitDetails", + "Edit quantity unit", + "Verpackungseinheit bearbeiten"); + builder.AddOrUpdate("Admin.Configuration.QuantityUnit", + "Quantity units", + "Verpackungseinheiten"); + + builder.AddOrUpdate("Admin.Configuration.QuantityUnit.Fields.Name", + "Name", + "Name"); + builder.AddOrUpdate("Admin.Configuration.QuantityUnit.Fields.Name.Hint", + "Set the name of quantity unit", + "Legt den Namen der Verpackungseinheit fest"); + builder.AddOrUpdate("Admin.Configuration.QuantityUnit.Fields.IsDefault", + "Default quantity unit", + "Standard-Verpackungseinheit"); + builder.AddOrUpdate("Admin.Configuration.QuantityUnit.Fields.IsDefault.Hint", + "Sets the default quantity unit", + "Legt die Standard-Verpackungseinheit fest"); + + + builder.AddOrUpdate("Admin.Configuration.QuantityUnit.Added", + "Quantity unit successfully added", + "Verpackungseinheit wurde erfolgreich zugefgt"); + builder.AddOrUpdate("Admin.Configuration.Quantityunits.Updated", + "Quantity unit successfully updated", + "Verpackungseinheit wurde erfolgreich aktualisiert"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.QuantityUnit", + "Quantity unit", + "Verpackungseinheit"); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowDefaultQuantityUnit", + "Show default quantity unit", + "Zeige die Standard-Verpackungseinheit", + "Show default quantity unit if the product has no quantity unit set.", + "Zeige die Standard-Verpackungseinheit, falls fr das Produkt keine Verpackungseinheit festgelegt ist."); + + + // OrderItemTaxRate + builder.AddOrUpdate("Admin.Orders.Products.AddNew.TaxRate", + "Tax rate", + "Steuersatz", + "The tax rate for the product", + "Die Steuerrate des Produktes"); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.MaxFilterItemsToDisplay", + "Maximum filter items", + "Maximale Anzahl Filtereintrge", + "Determines the maximum amount of filter items to display", + "Bestimmt die maximale Anzahl angezeigter Filtereintrge"); + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ExpandAllFilterCriteria", + "Expand all filter groups", + "Alle Filtergruppen aufklappen", + "Determines whether all filter groups should be displayed expanded", + "Legt fest, ob alle Filtergruppen aufgeklappt angezeigt werden sollen"); + + builder.AddOrUpdate("Admin.Common.Export.Wait", + "Please wait while the export is being executed", + "Bitte haben Sie einen Augenblick Geduld, whrend der Export durchgefhrt wird"); + + builder.AddOrUpdate("Admin.ContentManagement.Topics.Fields.TitleTag", + "Title tag", + "Titel-Tag", + "Determines the title tag of the topic", + "Legt das Tag fest, welches fr die berschrift des Topics ausgegeben wird"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.resx b/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.resx new file mode 100644 index 0000000000..299cfbcddd --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502191643156_QtyUnitsAndOrderItemTaxRate.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.Designer.cs new file mode 100644 index 0000000000..00b899bd87 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class NewIndexesV22 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(NewIndexesV22)); + + string IMigrationMetadata.Id + { + get { return "201502202248081_NewIndexesV22"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.cs b/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.cs new file mode 100644 index 0000000000..3a5409115b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.cs @@ -0,0 +1,26 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class NewIndexesV22 : DbMigration + { + public override void Up() + { + DropIndex("dbo.Product_ProductAttribute_Mapping", new[] { "ProductId" }); + DropIndex("dbo.ProductVariantAttributeValue", new[] { "ProductVariantAttributeId" }); + CreateIndex("dbo.Product_ProductAttribute_Mapping", new[] { "ProductId", "DisplayOrder" }, name: "IX_Product_ProductAttribute_Mapping_ProductId_DisplayOrder"); + CreateIndex("dbo.ProductVariantAttributeValue", new[] { "ProductVariantAttributeId", "DisplayOrder" }, name: "IX_ProductVariantAttributeValue_ProductVariantAttributeId_DisplayOrder"); + CreateIndex("dbo.NewsLetterSubscription", new[] { "Email", "StoreId" }, name: "IX_NewsletterSubscription_Email_StoreId"); + } + + public override void Down() + { + DropIndex("dbo.NewsLetterSubscription", "IX_NewsletterSubscription_Email_StoreId"); + DropIndex("dbo.ProductVariantAttributeValue", "IX_ProductVariantAttributeValue_ProductVariantAttributeId_DisplayOrder"); + DropIndex("dbo.Product_ProductAttribute_Mapping", "IX_Product_ProductAttribute_Mapping_ProductId_DisplayOrder"); + CreateIndex("dbo.ProductVariantAttributeValue", "ProductVariantAttributeId"); + CreateIndex("dbo.Product_ProductAttribute_Mapping", "ProductId"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.resx b/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.resx new file mode 100644 index 0000000000..f920141203 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502202248081_NewIndexesV22.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.Designer.cs new file mode 100644 index 0000000000..cbae839811 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class LocalizedPropertyIndex : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(LocalizedPropertyIndex)); + + string IMigrationMetadata.Id + { + get { return "201502280342294_LocalizedPropertyIndex"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.cs b/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.cs new file mode 100644 index 0000000000..40d882b9e4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.cs @@ -0,0 +1,20 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class LocalizedPropertyIndex : DbMigration + { + public override void Up() + { + DropIndex("dbo.LocalizedProperty", new[] { "LanguageId" }); + CreateIndex("dbo.LocalizedProperty", new[] { "EntityId", "LocaleKey", "LocaleKeyGroup", "LanguageId" }, name: "IX_LocalizedProperty_Compound"); + } + + public override void Down() + { + DropIndex("dbo.LocalizedProperty", "IX_LocalizedProperty_Compound"); + CreateIndex("dbo.LocalizedProperty", "LanguageId"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.resx b/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.resx new file mode 100644 index 0000000000..6e085155b0 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201502280342294_LocalizedPropertyIndex.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.Designer.cs new file mode 100644 index 0000000000..cba99355c6 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class V22Res : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(V22Res)); + + string IMigrationMetadata.Id + { + get { return "201503032227054_V22Res"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.cs b/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.cs new file mode 100644 index 0000000000..b66b0d7113 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.cs @@ -0,0 +1,112 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + using System.Linq; + + public partial class V22Res : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + // Checkout + builder.Delete("Checkout.YourOrderHasBeenSuccessfullyProcessed"); + builder.AddOrUpdate("Checkout.OrderHasBeenReceived", + "Your order has been received", + "Ihre Bestellung ist angekommen"); + builder.AddOrUpdate("Checkout.ThankYou", + "Thank you for your purchase!", + "Vielen Dank fr Ihren Einkauf!"); + builder.AddOrUpdate("Checkout.OrderNumber", + "Your order number", + "Ihre Bestellnummer"); + builder.AddOrUpdate("Checkout.PlacedOrderDetails", + "Order details", + "Bestelldetails"); + builder.AddOrUpdate("Checkout.Continue", + "Continue shopping", + "Weiter einkaufen"); + + // Move pictures + builder.Delete("Admin.Configuration.Settings.Media.PicturesStoredIntoDatabase.Hint"); + builder.AddOrUpdate("Common.Shrink", + "Shrink", + "Verkleinern"); + builder.AddOrUpdate("Common.ShrinkDatabaseSuccessful", + "The database has been successfully shrinked", + "Die Datenbank wurde erfolgreich verkleinert"); + builder.AddOrUpdate("Admin.Configuration.Settings.Media.MovePicturesNote", + "Do not forget to backup your database before changing this option. Please bear in mind that this operation can take several minutes depending on the amount of images.", + "Bitte sichern Sie Ihre Datenbank, ehe Sie Mediendateien verschieben. Dieser Vorgang kann je nach Menge der Bilddaten mehrere Minuten in Anspruch nehmen."); + builder.AddOrUpdate("Admin.Configuration.Settings.Media.MoveToDb", + "Move to database", + "In Datenbank verschieben"); + builder.AddOrUpdate("Admin.Configuration.Settings.Media.MoveToFs", + "Move to file system", + "Ins Dateisystem verschieben"); + + // Misc + builder.AddOrUpdate("Mobile.ViewFullSite", + "Desktop version", + "Desktop Version"); + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.FilterEnabled", + "Display filter sidebar widget", + "Filter Sidebar Widget anzeigen"); + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.FilterEnabled.Hint", + "Displays the filter sidebar widget for products within categories", + "Aktiviert das Filter Sidebar Widget zum Filtern von Produkten in Warengruppen"); + builder.AddOrUpdate("Admin.Catalog.Products.SpecificationAttributes.Fields.ShowOnProductPage.Hint") + .Value("en", "Check to display the attribute in the public product detail page"); + builder.AddOrUpdate("Admin.Catalog.Products.SpecificationAttributes.AddNew", + "Assign a specification attribute", + "Spezifikationsattribut zuordnen"); + builder.AddOrUpdate("Admin.Catalog.Attributes.SpecificationAttributes.Bundled.ShowNotOnProductPage") + .Value("en", "Don't show on product page"); + + builder.AddOrUpdate("Admin.Configuration.Themes.Option.SaveThemeChoiceInCookie", + "Save theme choice in cookie", + "Benutzer Theme in Cookie speichern"); + builder.AddOrUpdate("Admin.Configuration.Themes.Option.SaveThemeChoiceInCookie.Hint", + "If unchecked, user's theme choice is associated to the account, which may be undesirable when, for example, multiple users share a guest account.", + "Wenn nicht gewhlt, wird das Benutzer Theme mit dem Kundenkonto verknpft, was u.U. unerwnscht sein kann, wenn sich bspw. mehrere User einen Gastzugang teilen."); + + builder.AddOrUpdate("ShoppingCart.SelectAttribute", + "Please select '{0}'.", + "Bitte '{0}' auswhlen."); + + builder.AddOrUpdate("ShoppingCart.AttributeError", + "An unknown error has occurred in the examination of the selected product variant.", + "Ein unbekannter Fehler ist bei der Prfung der ausgewhlten Produktvariante aufgetreten."); + + builder.AddOrUpdate("Common.Execution", + "Execution", + "Ausfhrung"); + + builder.AddOrUpdate("Admin.Catalog.Attributes.SpecificationAttributes.OptionsCount", + "Number options", + "Anzahl Optionen"); + + builder.AddOrUpdate("Admin.Common.DeleteSelected", + "Delete selected", + "Ausgewhlte lschen"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.resx b/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.resx new file mode 100644 index 0000000000..6e085155b0 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201503032227054_V22Res.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.Designer.cs new file mode 100644 index 0000000000..93180e898a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class PdfConverterUser : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PdfConverterUser)); + + string IMigrationMetadata.Id + { + get { return "201503101851123_PdfConverterUser"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.cs b/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.cs new file mode 100644 index 0000000000..d0a855570c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.cs @@ -0,0 +1,41 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Customers; + using SmartStore.Data.Setup; + + public partial class PdfConverterUser : DbMigration, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.Set().AddOrUpdate(x => x.SystemName, + new Customer + { + Email = "builtin@pdf-converter-record.com", + CustomerGuid = Guid.NewGuid(), + PasswordFormat = PasswordFormat.Clear, + AdminComment = "Built-in system record used for the PDF converter.", + Active = true, + IsSystemAccount = true, + SystemName = SystemCustomerNames.PdfConverter, + CreatedOnUtc = DateTime.UtcNow, + LastActivityDateUtc = DateTime.UtcNow, + } + ); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.resx b/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.resx new file mode 100644 index 0000000000..6e085155b0 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201503101851123_PdfConverterUser.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.Designer.cs new file mode 100644 index 0000000000..cf72dff95e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class NewCategoryProperties : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(NewCategoryProperties)); + + string IMigrationMetadata.Id + { + get { return "201504131412183_NewCategoryProperties"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.cs b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.cs new file mode 100644 index 0000000000..0ae7100ae6 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.cs @@ -0,0 +1,109 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using System.Web.Hosting; + using SmartStore.Core.Data; + using SmartStore.Data.Setup; + + public partial class NewCategoryProperties : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Category", "FullName", c => c.String(maxLength: 400)); + AddColumn("dbo.Category", "BottomDescription", c => c.String()); + AddColumn("dbo.ReturnRequest", "RequestedActionUpdatedOnUtc", c => c.DateTime()); + AddColumn("dbo.ReturnRequest", "AdminComment", c => c.String(maxLength: 4000)); + AddColumn("dbo.CheckoutAttribute", "IsActive", c => c.Boolean(nullable: false)); + + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) + { + this.SqlFileOrResource("LatestProductLoadAllPaged.sql"); + } + } + + public override void Down() + { + // inverse of LatestProductLoadAllPaged.sql does not make sense to me + + DropColumn("dbo.CheckoutAttribute", "IsActive"); + DropColumn("dbo.ReturnRequest", "AdminComment"); + DropColumn("dbo.ReturnRequest", "RequestedActionUpdatedOnUtc"); + DropColumn("dbo.Category", "BottomDescription"); + DropColumn("dbo.Category", "FullName"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Catalog.Categories.Fields.FullName", + "Complete name", + "Vollstndiger Name", + "Complete name displayed as title on the category page.", + "Vollstndiger Name, der als Titel auf der Warengruppenseite angezeigt wird."); + + builder.AddOrUpdate("Admin.Catalog.Categories.Fields.BottomDescription", + "Bottom description", + "Untere Beschreibung", + "Optional second description displayed below products on the category page.", + "Optionale zweite Beschreibung, die auf der Warengruppenseite unterhalb der Produkte angezeigt wird."); + + builder.AddOrUpdate("Admin.Catalog.Products.List.SearchWithoutCategories", + "Without category mapping", + "Ohne Warengruppenzuordnung", + "Filters for products without category mapping.", + "Filtert nach Produkten ohne Warengruppenzuordnung."); + + builder.AddOrUpdate("Admin.Catalog.Products.List.SearchWithoutManufacturers", + "Without manufacturer mapping", + "Ohne Herstellerzuordnung", + "Filters for products without manufacturer mapping.", + "Filtert nach Produkten ohne Herstellerzuordnung."); + + builder.AddOrUpdate("Admin.Common.AdminComment", + "Admin comment", + "Admin-Kommentar", + "Admin comment for internal use. Won't be published.", + "Kommentar fr internen Gebrauch. Wird nicht verffentlicht."); + + builder.AddOrUpdate("Admin.ReturnRequests.Fields.RequestedActionUpdatedOnUtc", + "Last update of requested action", + "Letzte Aktualisierung der angeforderten Aktion", + "Date when the requested action was updated the last time.", + "Datum, an dem die angeforderte Aktion zuletzt gendert wurde."); + + builder.AddOrUpdate("Admin.Common.CreateMutuallyAssociations", + "Create all mutual associations", + "Alle gegenseitigen Zuordnungen erstellen"); + + builder.AddOrUpdate("Admin.Common.AskCreateMutuallyAssociations", + "Do you want to create all mutual associations?", + "Mchten Sie alle gegenseitigen Zuordnungen erstellen?"); + + builder.AddOrUpdate("Admin.Common.CreateMutuallyAssociationsResult", + "There were {0} mutual association(s) created.", + "Es wurden {0} gegenseitige Zuordnung(en) erstellt."); + + builder.AddOrUpdate("Admin.Configuration.Plugins.LicensingInvalidStoreUrl", + "The license key cannot be activated for the entered store URL. Please enter the right store URL in your store details before activating the key.", + "Der Lizenzschlssel kann fr die hinterlegte Shop-URL nicht aktiviert werden. Bitte tragen Sie vor der Aktivierung in den Shop-Details die korrekte Shop-URL ein."); + + builder.AddOrUpdate("Admin.Configuration.Plugins.ConfirmLicensing", + "Please check whether the licensing is done for the right store URL! Proceed with the licensing?", + "Bitte berprfen Sie, ob die Lizenzierung fr die richtige Shop-URL erfolgt! Mit der Lizenzierung fortfahren?"); + + builder.AddOrUpdate("Admin.Common.Unlicensed", + "Unlicensed", + "Unlizenziert"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.resx b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.resx new file mode 100644 index 0000000000..8ebb7814c7 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504131412183_NewCategoryProperties.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.Designer.cs new file mode 100644 index 0000000000..ddaae8eeae --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class V22Final : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(V22Final)); + + string IMigrationMetadata.Id + { + get { return "201504171629262_V22Final"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.cs b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.cs new file mode 100644 index 0000000000..23b0f56a14 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.cs @@ -0,0 +1,101 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + using System.Linq; + + public partial class V22Final : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Date", + "Date", + "Datum"); + builder.AddOrUpdate("Common.MoreInfo", + "More info", + "Mehr Info"); + builder.AddOrUpdate("Common.Download", + "Download", + "Download"); + + builder.Delete( + "Reviews.Date", + "RewardPoints.Fields.Date", + "Admin.Customers.Customers.RewardPoints.Fields.Date", + "DownloadableProducts.Fields.Date", + "Order.ShipmentStatusEvents.Date", + "PrivateMessages.Inbox.DateColumn", + "PrivateMessages.Sent.DateColumn"); + + builder.AddOrUpdate("Admin.CheckUpdate", + "Check for update", + "Auf Aktualisierung prfen"); + builder.AddOrUpdate("Admin.CheckUpdate.UpdateAvailable", + "Update available", + "Update verfgbar"); + builder.AddOrUpdate("Admin.CheckUpdate.IsUpToDate", + "SmartStore.NET is up to date", + "SmartStore.NET ist auf dem neuesten Stand"); + builder.AddOrUpdate("Admin.CheckUpdate.YourVersion", + "Your version", + "Ihre Version"); + builder.AddOrUpdate("Admin.CheckUpdate.CurrentVersion", + "Current version", + "Aktuelle Version"); + builder.AddOrUpdate("Admin.CheckUpdate.ReleaseNotes", + "Release Notes", + "Release Notes"); + builder.AddOrUpdate("Admin.CheckUpdate.DontNotifyAnymore", + "Don't notify anymore", + "Nicht mehr benachrichtigen"); + + builder.AddOrUpdate("Common.Next", + "Next", + "Weiter"); + + builder.AddOrUpdate("Admin.Common.BackToConfiguration", + "Back to configuration", + "Zurck zur Konfiguration"); + builder.AddOrUpdate("Admin.Common.UploadFileSucceeded", + "The file has been successfully uploaded.", + "Die Datei wurde erfolgreich hochgeladen."); + builder.AddOrUpdate("Admin.Common.UploadFileFailed", + "The upload has failed.", + "Der Upload ist leider fehlgeschlagen."); + builder.AddOrUpdate("Admin.Common.ImportAll", + "Import all", + "Alle importieren"); + builder.AddOrUpdate("Admin.Common.ImportSelected", + "Import selected", + "Ausgewhlte importieren"); + builder.AddOrUpdate("Admin.Common.UnknownError", + "An unknown error has occurred.", + "Es ist ein unbekannter Fehler aufgetreten."); + + builder.AddOrUpdate("Plugins.Feed.FreeShippingThreshold", + "Free shipping threshold", + "Kostenloser Versand ab", + "Amount as from shipping is free.", + "Betrag, ab dem keine Versandkosten anfallen."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.resx b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.resx new file mode 100644 index 0000000000..8ebb7814c7 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504171629262_V22Final.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.Designer.cs new file mode 100644 index 0000000000..a94627f448 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class AutoUpdateRes : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(AutoUpdateRes)); + + string IMigrationMetadata.Id + { + get { return "201504232202590_AutoUpdateRes"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.cs b/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.cs new file mode 100644 index 0000000000..84dd3e8dbd --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.cs @@ -0,0 +1,60 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class AutoUpdateRes : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.CheckUpdate.UpdateNow", + "Update now", + "Jetzt aktualisieren"); + builder.AddOrUpdate("Admin.CheckUpdate.AutoUpdatePossible", + "AutoUpdate possible", + "AutoUpdate mglich"); + builder.AddOrUpdate("Admin.CheckUpdate.AutoUpdateFailure", + "Unknown error during package download. Please try again later.", + "Unbekannter Fehler beim Paket-Download. Bitte versuchen Sie es spter erneut."); + + builder.AddOrUpdate("Admin.CheckUpdate.AutoUpdatePossibleInfo", + @"

This update can be installed automatically. For this SmartStore.NET downloads an installation package + to your webserver, executes it and restarts the application. Before the installation + your shop directory is backed up, except the folders App_Data and Media, as well as the + SQL Server database file. +

+

+ Click the Update now button to download and install the package. As an alternative to this, you can + download the package to your local PC further below and perform the installation at a later time manually. +

", + @"

Dieses Update kann automatisch installiert werden. Hierfr ldt SmartStore.NET ein Installationspaket + auf Ihren Webserver herunter, fhrt die Installation durch und startet die Anwendung neu. Vor der Installation wird der + Verzeichnisinhalt Ihres Shops gesichert, mit Ausnahme der Ordner App_Data und Media sowie der + SQL Server Datenbank. +

+

+ Klicken Sie die Schaltflche Jetzt aktualisieren, um das Paket downzuloaden und zu installieren. Alternativ hierzu knnen + Sie weiter unten das Paket auf Ihren lokalen PC downloaden und die Installation zu einem spteren Zeitpunkt manuell durchfhren. +

"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.resx b/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.resx new file mode 100644 index 0000000000..cc80a45d18 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504232202590_AutoUpdateRes.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.Designer.cs new file mode 100644 index 0000000000..faa97538ed --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class TempFileCleanupTask : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(TempFileCleanupTask)); + + string IMigrationMetadata.Id + { + get { return "201504270946381_TempFileCleanupTask"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.cs b/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.cs new file mode 100644 index 0000000000..adcf8c1589 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.cs @@ -0,0 +1,39 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Tasks; + using SmartStore.Data.Setup; + + public partial class TempFileCleanupTask : DbMigration, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.Set().AddOrUpdate(x => x.Type, + new ScheduleTask + { + Name = "Cleanup temporary files", + CronExpression = "30 3 * * *", + Type = "SmartStore.Services.Common.TempFileCleanupTask, SmartStore.Services", + Enabled = true, + StopOnError = false + } + ); + + context.SaveChanges(); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.resx b/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.resx new file mode 100644 index 0000000000..cc80a45d18 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504270946381_TempFileCleanupTask.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.Designer.cs new file mode 100644 index 0000000000..1a16386517 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class SendEmailsManually : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(SendEmailsManually)); + + string IMigrationMetadata.Id + { + get { return "201504290937512_SendEmailsManually"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.cs b/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.cs new file mode 100644 index 0000000000..d06f7cea83 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.cs @@ -0,0 +1,100 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class SendEmailsManually : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Order", "HasNewPaymentNotification", c => c.Boolean(nullable: false)); + AddColumn("dbo.MessageTemplate", "SendManually", c => c.Boolean(nullable: false)); + AddColumn("dbo.QueuedEmail", "SendManually", c => c.Boolean(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.QueuedEmail", "SendManually"); + DropColumn("dbo.MessageTemplate", "SendManually"); + DropColumn("dbo.Order", "HasNewPaymentNotification"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.ErrorSendingEmail", + "Error sending an email", + "Fehler beim Senden einer E-Mail"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.Fields.SendManually", + "Only send manually", + "Nur manuell senden", + "Indicates whether the email should only be send manually.", + "Legt fest, ob die E-Mail ausschlielich manuell gesendet werden soll."); + + builder.AddOrUpdate("Admin.System.QueuedEmails.List.SendManually", + "Load emails manually send only", + "Lade nur manuell zu sendende E-Mails", + "Load emails manually send only.", + "Lade nur manuell zu sendende E-Mails."); + + builder.AddOrUpdate("Admin.System.QueuedEmails.List.LoadNotSent", + "Load not sent emails only", + "Lade nur noch nicht gesendete E-Mails", + "Load not sent emails only.", + "Lade nur noch nicht gesendete E-Mails."); + + builder.AddOrUpdate("Admin.System.QueuedEmails.Requeued", + "The queued email has been requeued successfully.", + "Die Nachricht wurde erfolgreich neu eingereiht."); + + builder.AddOrUpdate("Admin.Common.SendNow", + "Send now", + "Jetzt senden"); + + builder.AddOrUpdate("Admin.ContentManagement.MessageTemplates.Fields.SendManually", + "Only send manually", + "Nur manuell senden", + "Indicates whether emails derived from this message template should only be send manually.", + "Legt fest, ob E-Mails, die von dieser Nachrichtenvorlage abgeleitet sind, ausschlielich manuell gesendet werden sollen."); + + + builder.AddOrUpdate("Admin.Orders.Payments.NewIpn", + "New IPN", + "Neue IPN"); + + builder.AddOrUpdate("Admin.Orders.Payments.NewIpn.Hint", + "A new notification from the payment provider has arrived in the order notes.", + "In den Auftragsnotizen ist eine neue Benachrichtigung vom Zahlungsanbieter eingetroffen."); + + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.SubCategoryDisplayType", + "Show subcategories", + "Unterwarengruppen anzeigen", + "Indicates whether and where to show subcategories on a category page.", + "Legt fest, ob und wo Unterwarengruppen auf einer Warengruppenseite angezeigt werden sollen."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.SubCategoryDisplayType.Hide", + "Do not display", + "Nicht anzeigen"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.SubCategoryDisplayType.AboveProductList", + "Above product list", + "ber der Produktliste"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.SubCategoryDisplayType.Bottom", + "At bottom of page", + "Am Seitenende"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.resx b/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.resx new file mode 100644 index 0000000000..22e46cf0d4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201504290937512_SendEmailsManually.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.Designer.cs new file mode 100644 index 0000000000..c10a58454d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class PdfConverterRoleFix : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PdfConverterRoleFix)); + + string IMigrationMetadata.Id + { + get { return "201505052021483_PdfConverterRoleFix"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.cs b/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.cs new file mode 100644 index 0000000000..1bd58e0760 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.cs @@ -0,0 +1,47 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Linq; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Customers; + using SmartStore.Data.Setup; + + public partial class PdfConverterRoleFix : DbMigration, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + var pdfUser = context.Set().Include(x => x.CustomerRoles).FirstOrDefault(x => x.SystemName == SystemCustomerNames.PdfConverter); + + if (pdfUser == null) + return; + + if (!pdfUser.CustomerRoles.Any()) + { + var guestRole = pdfUser.CustomerRoles.FirstOrDefault(x => x.SystemName == SystemCustomerRoleNames.Guests); + if (guestRole == null) + { + guestRole = context.Set().FirstOrDefault(x => x.SystemName == SystemCustomerRoleNames.Guests); + if (guestRole != null) + { + pdfUser.CustomerRoles.Add(guestRole); + context.SaveChanges(); + } + } + } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.resx b/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.resx new file mode 100644 index 0000000000..22e46cf0d4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505052021483_PdfConverterRoleFix.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.Designer.cs new file mode 100644 index 0000000000..a39bd3bf2f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class CountryMultistore : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(CountryMultistore)); + + string IMigrationMetadata.Id + { + get { return "201505061813010_CountryMultistore"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.cs b/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.cs new file mode 100644 index 0000000000..9ba99664ba --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.cs @@ -0,0 +1,46 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class CountryMultistore : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Country", "LimitedToStores", c => c.Boolean(nullable: false)); + AddColumn("dbo.Forums_Group", "LimitedToStores", c => c.Boolean(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.Forums_Group", "LimitedToStores"); + DropColumn("dbo.Country", "LimitedToStores"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.ContentManagement.Forums.ForumGroup.Fields.SeName", + "URL-Alias", + "URL-Alias", + "Set a search engine friendly page name e.g. 'the-best-forumgroup' to make your page URL 'http://www.yourStore.com/the-best-forumgroup'. Leave empty to generate it automatically based on the name of the forum group.", + "Legt einen Suchmaschinen-freundlichen Seitennamen fr die Forengruppe fest. 'Tolle Forengruppe' resultiert bspw. in '~/tolle-forengruppe'. Standard ist der Name der Forengruppe."); + + builder.AddOrUpdate("Admin.ContentManagement.Forums.Forum.Fields.SeName", + "URL-Alias", + "URL-Alias", + "Set a search engine friendly page name e.g. 'the-best-forum' to make your page URL 'http://www.yourStore.com/the-best-forum'. Leave empty to generate it automatically based on the name of the forum.", + "Legt einen Suchmaschinen-freundlichen Seitennamen fr das Forum fest. 'Tolles Forum' resultiert bspw. in '~/tolles-forum'. Standard ist der Name des Forums."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.resx b/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.resx new file mode 100644 index 0000000000..8a4e44f84b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505061813010_CountryMultistore.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy9WXMcO7Im+D5m8x9keupuuy0dqarM6padM21kipRol6JYzJR0677QgpFgEsXIiDyxcKm2+WXzMD9p/sIAiA2BLbDFknnyRUoGgA+Aw+FwOByO/+//+X9//V8v2+jNE0gzmMS/vf3w7pe3b0AcJmsYb357W+T3//Ovb//X//V//h+/nq23L29+1Pn+hPOhknH229uHPN/97f37LHwA2yB7t4VhmmTJff4uTLbvg3Xy/uMvv/z7+w8f3gME8RZhvXnz600R53ALyB/oz0USh2CXF0H0NVmDKKu+o5QlQX1zFWxBtgtC8Nvb5TZI82WepODdpyAP3r45iWCAmrEE0f3bN0EcJ3mQo0b+7XsGlnmaxJvlDn0IotXrDqB890GUgarxf2uz6/bjl4+4H+/bgjVUWGR5sjUE/PCnijDv2eJW5H3bEA6R7gyROH/FvSbk++3t34uAfPoew/ztG7bCvy2iFGfuUHhByIyywfjdJ5iCEH19fUcD/dsbJvu/NVzy8d3Hd7+8++Xf3iyKKC9S8FsMijwNon97c13cRTD8D/C6Sh5B/FtcRBHddNR4lNb5gD5dp8kOpPnrDbivOnSxfvvmfbfce7ZgU4wqU3bzIs7/9PHtmytUeXAXgYYzKJKQXn0GMUiDHKyvgzwHaYwxAOk/VztTF/63rg2xIppSb998DV4uQbzJH357+xc0h87hC1jXH6oGILKiCYjK5GkBBA1UV/oJZGEKdyUPudbdUxXMdlHwepmEQeSho1qVfUvXIO0bQjXSRfYJ3AeIJ2uY0ySJQBD3AP36vp1RynmGqlsXYX5axOsIXORge5IjmtwVOTiHUY5bbzz3FkjSRcnmXR/0cTbK62qJ1l+rGqkhujegH0FUOKNdZNcpQMsgktJgbcbbCOwqeIIbQmgp3d6+uQERyZI9wF255Pay5C1d/jxNtjdJpDFJqGK3y6RIQyxgEvOyqyDdgNzXTPY5dY9zVV5XRSzXGVES2xNYrfW4oaBlLEyQ9lujfAIh3AbR2zdo7oaw0sL/+vbNEq+pv739sy7eNUBTJM6DDTCe+WZay59/8bGaLx+SNNdTVdBPDxWWkqERFJkrlb7ANVg9FNu7OICRK9gPNPB3kfPIEeGQPVgI/8F0rUUKsAD4Fn/Pw4bl0ZcV3Jqrtt93awcw6QLHrB7ZVMtcvVTZLHP1Emm2qFc16HX4limj6GQ3a//6zeQXrdmqzph1Q6sD+k1XNdpU0XBXL45KhUI8liTC1bnqAtdBiur8nCbFDjXEj35RLQIX8Ro+wXURRNHrTJZyw1rHX9tR+8as72S9hfEi2W5Bq8cNVlnNtWCLlmT3LScanOdv8ZdkC6496IpfQR6gKf6cpOtscJ0RVzbmMOP6VjBXmrb89OwkipLnBRH9IL0BTxA8OyuoJ7tdmjyB9Q2SnfFmWWzd+OYqyT0j1nArJN4jptPObfQHuizu/gnQ/EtOQmc9/xJuYY4bR1Yy5yFePhbDT7ogLu6DECsMKVr18iu05Wk3BYNV+xmx2OCVXGSf4X2+CFLnDVON40O3uAG/FzAF3/IHRPFS+DtzSoXZqioqaf3hFz9CrcCabA5DrMmcrNdMG5z7dJF9Sp7jKAnct7sVjuvIfY+jcoLXgM59RKNSTrhv9xympf2pgjl72cGUqNWfglcWUw/iJMzhE4HwwfZfgmwZIB0H+BrVLhrXvN7WfM9AerJJAaDVPNvGdMBW4GV4vfEiuwFhkZbortKjAlq8hhEoG+Uq42jEa5DCxHn2NZhk7SfAjnPlIls+wN1ZjIs4s+NFdo6GHwPuPAwJkqcQz7wgqhEXD9gAoW9WNm7+Kng5e0G7EOe5cJGdZc7kRK1ZoO3QJklfXRkHqThoK3QRP6GpieCQ2v/gzo1IwwsfvR0ZYGssQTx5CiAqCyMK1dHKK2yp9YIFY489v0yey17jlQahuQ4K2iDA+1eyfT9P0rqNpwDtvhwPmoLwMcHWcuy/5HwqjHeDGPGipCXagTSbXmeNgtj00SjBbbH1M0glYvDiD5EQAKwrMAhGUFbRXMANPC1eT4s8b40LDnML5/4Js4cIZrkf0GryRwAxL5LrneMZW8wF0s4JHAzdz59oEO8r0LdoPWwF1cZkkWQGp7Omy8IO4QSRYUf0MZc52qPXZ2LCYzJ9rLN47YBUm7POYnym5oW/KrHVQQYDM0Ul2EatE20+VhCUc9JZ4KM1FGR5c3S4SLZ3MK5O0TwyIWpz7YqQnex2EXTXmH8CuHkYbip29zHe4X/C9YDoX4alTbPSuMqTBshNmPhzSPDnIwEiYONnN18HCb6D8Amkr7iwofWEdhA3LHoaZKBafbxsuxu8ryDIihSUzu/Duio3dZ5sfbp6NbD4Rxdaj7TEaYGcaPVYoPyY1yunDpBiPwlfho8OKKaGb8zlQ1LaU5Dg8+dEWy2JzRIp9FWpU2+r3KuktZW3ziryXJwHkSKrqcMQLQ1Ujja33Yycj00nXeZe081k6Q7U+uhoenTZOzj1em5JHKIMe1QZvMiGWN6h2iymcHRis8g6wOWzbDh9iKhsO51R0X5RNlkfhHkt+3ENCY6yC1UeReuZHLKGs9ks29wcgsubXGZRtLibQdZgJpdle8kO9B6GJAvtrytvv7iIoj/qArL+9ZSy7O8q2Cg7d9vJx8tTKlkqTuk8ltL0R5BCpNSJ9pHK5ivKKQZIo5RslHSKWg4VC23UcYPemnbRul/dG6EKHuxm5JmQTpdyYSeTKRuyZ8OKxrJZ+eZ2c0gbzGQzbTJtwxE0t0kWcQaXyPECn0M0+toeyO29FIuLwZVS2/w6eiHL6+rxyf04jE9uPTI+PDW+Z3iv5Om2kfz+knejVl2V6a7c+OS3MplZ2LkqK5lFycq7KlskxS6JF4hTnC1THJL4+M3P6RsZGeIfSWaZK4+2SJh4pn4gfdv4VdKzFeM33nQB1V6+zcctS8rMpouTwMQwhEWivw+c8ULbIlFBVZyPHat6OiEuIeiHKKO8K8LcTteB6n23w32gGuK4FMvr6lmKB7oeg2+reKq5z4A/3l2J0yRHfDrqJRwc9mfwlameRr6u3xwvzHjpWXn/zpcDYGVpMzypwvenlvBfwK3uztWfbJWU8TtYbGuPnArnW9d5zGHfoeEBdBPEG6XPlrcQAh5vsg3gvzDjm0NzOwU/yIADHKlI0KkfEDx/VW+qLKWx78NHiy1L/wGkYH+jbYUtxbSw9e1JVZ2pbTGbxmnyXAa3u/x1C4x1969gDYN3Vfmj4q4QXyWJTmEcpK3LevWXzkTq8zPcAoypXMIGuTkPknMYgVi9O/iTp8uPV+DZWG57PSHlp6o4R+8JKTOv7aZtB9M9EsdxGo8V5Uumvo+ng1gtWdazQXJcJZs0hjPYr29DX1t9BM8R2N+8nGJReMdZrJw3hFwe5h9L9psiAsvXLAfbHoOZH/vFcgcGPx06hVGEvQtxJe6Wi+bypx+4G5Ah2oZko9mEI0Hz1tAy0sI0El5lDvAzeFSlwStmnvIe55gV16PRb23xXXNlFzAcp7MXJKjKIOqj7UVbP4PhTmqku1DluY7d2tPxdnWIqU4DHVcbeV09C8EwMdUXSZSkX8ALCdM8eu17EWbddJ/l4YiTQTrOGnldnnZavg5cLrJzEOCBqBWECe3H0pWq5VANX/s2s9zZvvkh2RTxGQfYwtncDuhrr5dd3DXvru8uG2i0o3wYXD7Q5P5DyIgut2rea+kWUl9u6fwhmYfyAgPID5cbOjrt9yJLPAmRo/SYsx/VqJ4tFCccXYHm5Qp0dN7ZQ+edoz/L/vmzWJ1ydRd3/oxLlM4pCsJMPnYb5ZVV931GieNNR3iDIzxU9RPvlkrELJI4x6dbY+jyfdLblwkbE26UgKhl2HI3onwB0e6+iP4BMhJk1AvYVWKD5aLDm973lujtklvhhg0tUSpaxCDL0FztC3HAlbll5rOkR9IS6ivt8mJOZwf1rLYRP7XO0fw67k/kddU0+lzAptbyt0UU5x7nLE/xKM+21LNiw1VzHWQZ3oAMLnzris6TdBu4e/xUaMsgGn7dGPW1F49hlk/u72EEPWxUSfRd592MJ836IisdQk7CzjOK1j7643mXXAZZfrE7Wa/Rfmd43wCv+wbc9MtkA2PLy8m4fB3DWQphfym3JKlEZaiF/y2VjfIN51J573A+i6mqUzn9NGOvaiabV9DWbhZ5g5l8pq1mdx2qZld5bludhm83m4dTuqQZTW8K0L5LPeRmsgqo3ckhJ3Y3mymtz16wShNEJ0X+gJWaMsjQDQhL66CgB6oSwmHQKsCNiV4p0wFCakCxvU4yyV2UJlnYET6Va7Ugi1UTV8kOhoo2knR5I7vJ4lYyeUybSUxM4haSJGHjuilcu5hk0ybdALTLiLGPFZANcCeLsIniHFxTJdnMm/wcpOvrBMZ59gVmuezYX5BP0np5PkEfFJlNe1L7IGqtNVxmgfhj8sgFIJvROMITFXhTHrWRzSUkvzQTR3t5TqetfUNQ85092mgk8bsK4Lirl9d1DtMsH01zH6Wivl2/p61Bst0F8esI9Yid0nt2ZIg7cKDUJxiHpqd6C+rpkQHtAWRqfhiroo+DV/RfcId1pSDqCfbkyRT0kMSg9xlJTy8D1+/nzXy/Ld/JlHNIuBTWC22Tp10AmSRu0WbTjddqepIqG8fk5JvYySBtaDeXW3ClmlwO3voVxnF5ltfVs2Dqhuex8cjIKsOHswWVgPmKXL96Ti4BJuJFlvQI2o8eBNLqIQVAt8I/eagQCVqQwpCpzPHR5R+Bs4nXn2+IN6cOV+8XxT6WvYvW3IIT7qXoPLdt4VK8MYE/+nMLdle9RYz3t/RCIOlWZ60QrI7CDHzjhbmctoVdelisQDUAM3THdUghlg7eOdWfXLrYxIjW5Uuyg0glSrCMIY9YbdJAhNnN766y66BgdpCO01tel6eb7xNpq3d3KXiCQY+Y8BPKcg56kNU+13I95ya/ctV38uBqTkg9OHJVWMc5r5jzFamcr5hpeGP4ca2/wDElEesd1HuBvcfv/j0GZIdPUtcCq2l9GiWbxuHLeErj0tk7CmMebuFVY0ZxtcadxxZl4wkq96CpEIUsRdH6ts3YspMonWMlYSZnNiqb4sBDGOC4FsjrugziTRFsnJ0cfV13MA0Hlax9nFhZ3Vsrmd357lW9slV4C8G7pKbKeJL7By3fTxtY8E3z9svxJukc7yQOdCJIrVNiK4rVasgaP5VLpm5Ta9ksbSZBbXN129hJFC7X3RxOa3XbCOO1msRlgv8imd/VOMclW17XNLaWemQqqiu3fEPUj0r/XoAlGOPs7zwKNhdb1FkcTbqH3F6iht3kh/vCwQDWrjKUWzkYNyAjok0szEU5hRJTmZET7+rcTmdcImhnqSrAPErYflnnIR4soXWPCBnozcq69r6oiwNtki4yPLuuo2IDY06I9N7iS4pQJHy8qE6ehAKrUumJECuhcC25Tu0r8gIFOQ9rW6d1rtPwZ5BVHfR3JnvdvTA/5l17ZTiB/iv6Vgx4BZ4ze5MuLv2OgpgHj9UW3VECdYxpPsaUxpcx/JmPa0Qho1MDe9tmbNlalM4xsTCTM8uWTbHnV1z+qCjJ69pz6/HyIUl9TEfDas+J6Bq7Vm87ummMtH9Em/usLKpHo7mXntltWZolUbRN4RKFq2s3h+mNFWp9FltarLQA1q6iVBXsdk5JFP1IcrIlC0mkHmNtAENk71igeeiwuFUncfZs4cwj39o0mOJ9DUOIWzo/tZmRZ+N3MIq8bvtmqmkO415CHBVBNR8O7EM6kFpU3m/8do/4r11hZ/QCXoJFhGQaVlOkzNOdelSScLrR6caRB5npKok16C4nuKiCGjLFWk44SYijbJDX5WuTOI18KCOcVZru8Je7vW3SvL7uTjZfn0k8mlWCJeV87gJOsxsd7AaichdApLVoB9BJEMp7e82/lbFyOa+5EInkuWihcrpMgKG93CTAQEe5Lq+r71TzL38ZxHiWAuDtSrmvWKEIqJJoGIcZgh7R6iU6aB3Ws2R+x6VDJ6an7uhqSxmQbmGW9QTtY3PJww+qc/KSSJ3dTblksG3uLYOwSBEqR4CjfLKWT4Pqi9PIxvYVvcFrdogd6m0Sc3qO3py3msSqOJ5O2oYK+Di7Fbzu6RLjODHj6lEue3cPR4ioVVdZKSYj1vwN8zLhvnGqOglDkGXjVHiNL0CjTeuQgc/tLoYOFNCYFbJmYZCtZG0TfdhCsJKyWRsB+ShC5XWR0MnObxp7ksOePKNM903X/VfY/YSP2PuL58ZBxVnJoYg7rtvANuJ3TxPpjKJGUqHD5c2kMrnLs6oxTgKNYBwlmrwuQqXZSDQ8WhjAFaiK5qfyRdG8hWR+Nlo9MuDS/B8QPDtC4AjSVgERJDi+hrjGK+Wu2RHCYSwIZi84CGWt5JUHozWhr4FVJmHryE9V08oM7kuAo/Q/Cn55XYRAn9Ok2A18yjzQXa0xnRuv2ndZnAjlZXHAEtTLPuQQl4g/1jPI7RyWS/NbOhMjzak0sTSnM7hL86oRTiKdYBzlukLIHLw0Psg5Ppa3TDmX3MWF8GUxkTyxEhfV2BpLivJtsvK/o5CQ10UINNI7JaQu54eQSYfnYqfoPnPpbKzoPmNm+AIRIS+ONFt4a4gftOvgFd9K8QpWhtEe8Qnd5mpJkaYgDl9Hea+oruwmaN1GP4EQboPo7ZvrFP0iUuzth7++fbPEERR+e/tX67nQdcRyHacfQT6mWFkWdzkSidFFHEYrDKtFrD8bd6tT2dnLOJWtcGVobMiz02P1sFPpOD2tpM44PawqG7VnqCKDqWxeWUc4olUEYhUhiM4BGJqm8pqHJrC85qGpXeEPH9qT8NDgTFrP9WFrIWJlsCqQ4l3Ea7A+2Q7aE/rZ3J8gBYjtPIRXfwDhY1LkJznio7siB2NupbnKs//cjvAcaKV6+LrmdHJ/DyOI5qS3/cFucBqQ+0F4U4OfAk4Bkl8LxFtd3cmapRAS7VU/3EDiJo+ihnO0GS6QQZA9grVsSAbt4eLpafinV3FFZy87mBJDwtckzh9GrvMfIBienvT8Kh85+gTuoPO1FQrqJCTr5pckWo/AH3zFIzEmVfFpED+OsgFm6hxFxNB1XizGrK55X2i8Ki/ughGUi2o1JQpgEwpv6HlfoA1BWoVxXaVBnAUh/tmqBqNXPcqUkVV+A7IiGp7si2CHDenjEpyvdKTeLou7Rkcft8vXRRo+BBkY04B/HUDbS9/s86NDj0tVHd6fI4GzK8rTktGtxp9ABPKDenlLsRO+AfjojbpbrHVs8SXIrsBzZcW5SvA9m7DzKqH7UWf3lEZ45Emm0S2bsT32FKVznhLCTKY+eUq/wbIGkctgN0XSNGtHwdo29D1Du/QvMMsTyYOJooy31SFu21h5Lu44WZHV9E2Qz/CebOR6OyHKePs9A+ufMH/gOtOfm+uURhHTzpFSOOabgr9JSDiu/UwS11g23aplV2WIKFnLcLKkZW2SuGVUumnLbsAagC1Y00LsTPoWKJ2rlyl6M3Od6S9h/F45ars86GCdypO9myJ8WZ1KtmnVTksaczlZacdkkAg9NpeT+5pYEFq8tlzCZEKBeXRYkdfVHIM6WnhLqeZqJh7mna32JEZ3hW1L9Cyy9Udurqhzm+oLlUwZQkHQanhXclnNdLG2YOuIJkI7TnN5XTW9XGdoZwX1AdZ5Ecb7weJAAqWmpr6225boUXTrj9y8VOc2FSiMojWG0q7VIbFO5yRw3IXMUbDI66rtZpRUED33oSedfDjKDeyqcJHVjSXR0gIP1qgacJEUu5GM2jeIGDuIDURjWO2a2sYJcLMEMd7HjtGzsqpxuvUVbbao+KmD1XORtdxBzIdT21sHMkCZL8laZiduAdftjViSKvtzKyvD90iSVboqy/I7LclUC51uoBzfQtLZjCMiOd8O8aLnX5ePv7nC/L0Iqt47bTpimF+nMBzchbepaHCP3TF6M0pPhvYwrm0bpY44NMm6tQ1Nu0ncXMd1b/2UPMdREqw9PGd1kdVg3tT4SzRB4gzUuIZbICytfwK4eTDYuvTcpSvidQSQmhUM78hQCvgFiZPni7+litJJliUh9kpe18qK+NTDo5Yk0/z6tCp3+67BQaPwuEZwEKmtkJaj2tOsJpeoYVWioml1Dne98oq8BeGkV2KIo14pr8uLNnhFvdkxXnTF+ipm0jp7zHJP2yMJ9A72hdNNcPBvNdkEB+tOUacFeMc5qOA7T1ftS4L7wDgNoiAOgeO2LBv8ltlYBrSBJIPSkU3k7SJya1Pl48SGMrP/EyfPDkE6vfF43FS78dg8qVF51DQ+REf5J6/Liw6ySoPwEVF8JEdvcknX7+6O8AywdR//BCL4BNJXy+Kj6z7aznXspJf43pm6/MkdQekct60M4BvYySB1Auzmcgr1REP6EEpHo3v/jCR08uJJJzpEH8de3jsZfM4D2XwVzxbL/Qpix/gG/I7fjLQ3EHRgjvNAMQ98BBTzNgl8bZf8HD7dgCBL4vMkLblpfDNIxb+AmL29HBC4NUB9eUpvaKsbsMPHjVnmwf39VTJGiJqT9RbG/Vd7//yLlwdBOrLNT1y5GV2xs91RUzSR7KVFOQT7TmE2x81mQpSzBVqE3PwpWKTjyqaa/x5WtusgrfQbwxPC8jzPoiA9xD48LL1ZIP24hUwTYglNSZAiHsJuEYNZLP0oHfsgilvmluwuulLqls5P7zGk2QQ7DXler3eMuYpEa4k0U3+7rS2yqvNdrhbBMa8sT3+TvRz6ViDLHZpr9R33RhbYnEgFeRAlm3dK3OPyOLg8FxP+264bCMRyrcDBq85hhDrm4c12xNfP3+Kq29fU0ZJ9ECzrAPxWs1zJ6qIpr1WAfwxZq5SxbVbBJxa9VcPpkkCFYkgXJZTb7kHZVWvBqYI9yk1TgTfw41HDutkMIcHEZJK86z71VGfPdzxIDTe5KNbylPVKcCgF0Lw4rxtaYAwg/LyLvaPA+yOIJhX3Ss6Lx59y3Fmzw7R12amtgo37tgyBHKeW9dT6s6dHyvrWauWqfNsOZSZYbulk2TrayeODN38EKQziNlz7ItnewThw1Ij7wY+8LK9r+Vh4YOWeu/c5VB2C+qnkaxAX90GIBzG9RqPd63Xmp1pD23TP7SbSEF9oP+HaH9gXv9emggwQypl6I2vC4h9daK1DnJMsg5sYzSJI+OhirTqD/uDnWLj2EsS2fcMzp/rkAl+CNb0Jl5Erec7GtL08XkIiM3z0c+xDbJ3fivzbPQEtz3uNiSoPqkYxh2q1Vyx+t10MThPQLSozrGmX93lyolG33LCqUcqms7YmVnoW23a2i2HUY7qoTbc75X2cNbGV+VcNj/rg4AK9gvFmaF2Blxx92u6GD4+PQ/P8XsDU/bI6NV/iPE0iH34hE51esVPIQLyaylRrQcrynE1/hPYg3TKmPVQbWzW6ygKTOI9Ks4CwxK1U8vbSQFleZlgwA/FhefC4mBxXEY1V5CSCQc/eyYOknsjEPVjoF1dNqQrz6ltdIrBHbpfXJaGbux/NHk2iHu/IJErS5e9FkILsZnM3eKdK29L6n2gm0M793n1Hy+umI1R0kSEktJCD0EMQJQcdkkEiosGHWnsJ40fs6DtlDDtTbWs+epam3qmnrFmtSHVALovV5ytYw+BdDXBcZxTztqKRc8DJ720Ete9p5CxOeKjBo9OdwjhoH52s/9Kprm+hinM0GBh28L6cwwjEY6y+Zy+oT5l/fVW0TF2BZzN+0hYxKwjS6rTNWsNtMI5iRl6Xp1XYy0Wu+t4FXtcsT8dcDZle7x713m7BHRUqFg3r3naztqqDOAenHEiy+TyeaasQmAm5REULVaZAfWdEzIg2wTnwl6z87ygv5HWN5A7F6jBKbWOgSpdZdBbj/M57sCUIEa/46USP50aSKa/te/JjuEw2SeM3MdkZB9v3fBudJuvXMZ5zLjXH+sj7CuTPSfroeXTNZN7XgNwIdBR9FcpRAsrrKsnvyvYlyjTS1EJZ01fcH8AWEHPDXWSzDpPy2bsOzJEb5XURQg2+rHjiUw37oqKWj37WriG5/zQIHy9i4h22LO6ooyPrTawE8TglvA7wYPtiX5E9poiAK2E9YbSFvrzctq+3gM8tqqwywYa1J6t2P7xsZmk39xXYIj3ZyalBBHcUJPK6ptHOfkDwjJr6MH7NtlsxbX5GjAg2SfrqgZdZqCMfH/l4ND6uhLsHNmaQjlx85OLRuJgMBQyd3CWT7TaJ37FIRzaW1+XHfIR69DlNit34bIlqnmAW9pgGBvL+HNJUcBJGNyBMrF5TJ+cJCO5dA3KccUPPuCkNtsqDcWPnwot11PTBs9vG99SFqZN3TfkjPx8yPy+jYjN+rb6uQV8G8aYINkMtDMvwAayLCKyC7NHmAAUVy97RIMe5JK9rmlslaP1O4rXjU3Ge3BaNxYYfj4g82X2Lz9I0cX428jIgEfbT3OLBA1z2LF5bllwWYQiyzLZeuvO+XDX01c/7exhBO+NFUzZrfx6FjLyuk/U6RXzi7CkDIuDhQojlIih/PLrsnfDgpWGP2yZXe9TCJXKHK3wOt+MUEGSI/+pn44z5/hNMQYhfOXzXQTqyvryunvVV9wKY6erymuVgi+jwTLYiY1d/g0mn6Ub81/nZBSvm/oTWseoigftMacCOk+U4WQ5psiyKNAVxaPNgdztJapDj5LCeHH8ZyPBWDswCQagqH2higKHnxWWCAdzJqmO+PE/SLRp06pWIoeq7hFuIWGyVlJ7NrgozmWDZw5yuYs/oASK2j0S2oT01GlnvFxG0pTLitWLr6IFJMLJ3HNRRSMvrounkfHHZl+8kGUHnmGTJDob76MXJ8a/Qf1Oei9uUK7I6RgSET4gWX9E2nzz8YzthuzjH2aqYrT4cpTEP+Zqpq8QXEuLPf4JQ+dDrMBojjl04vlUehzEMnPWTi6wyMZ6+nhT5g7tpngK8QXrrDlJRc2wxB5KhNBtLYr3QYuW2m58O6SLNJojcIs9r6v7eTh2d1tO5pW1vM/W1nMrptAQQ0zT6dJnY3GNEpTZovr2jUI7SX14XRSZc5WxuuvQ+0T2QDB1IsDBkFh+TtHluufzUgYk8G390osjr9TFWuiKRUBGlK1vrXZSUZPQhTnD+o0iR1zWxKbnHRPhxmFqtPCIMrsxsdwHc2BgwqtU5e1djHFnXmneGcgTq3aYMVDGOk7FvS6xPK6/2/DtDUyk6CcPyeRn7OUjjHOehvC5CJ5UQ/8sghy2Vab5vBdGsXF0XjtEzfg+vk5R9H8n0nCBDI+mHQKZtD7KsR6UYqOZycV9mznEzcRROcB+gWY2EIJkLqNRAMqsSOg7XExuxxUAdJZe8rmm0z9MwLJeW0kEOqM7cdJvgqrN4CjLmSUcZ51IAvb67x8f2en69BPEah34Iouh1IIlzBZ6zS4AnjOOhayN4xIhH+aOQP0KKOZ/CTqSQ+ZmVXjccQ94G/XsBCrCuaG0/ayiY41SR13WdwiR1jhaMbZxKV6ZBFnxca68vnI/ld5WM37lVMkrXbsAuevXSP616RunTYjF4FUjXHLyOw9Iu/a4/+K2CFALHe4MYRtKg8VRce51UdVDVNdYJDquo9fG2m7k9sJLl4Q6tpBmdDq4WDyB8TAqnV+zKl4nfcVBHnUBeV4+QHuhO+l4+dbpEE2qH81+X0at84V5kq+Dl7AVQ1LCFQkB1hDhvz5XP42FXX/YL+Wk/KzUUD42K894KZFgrX3XLcA+Kahd0ekRUXItHIXx8YbFPaWIp5jrbphHtx2cJB5KA+pJrfJnF6ojGws5KZt3geGCYr6+DV8wCX2CG7xXaCy0J4FFqyetiSeYqtMhIzPTCCdtX4TyT8NAtX7idZ7pluHmmXdDrPPM3wY4zS8HEr2EEyqXZcTZgoGuQwmTtflMlDyKC52qNwZGL8JT0YSHydZjpKdLMRQyxm8OcJRndRC0pdtstIRddnYy98qqb29RBW7r+jy2W2S2bsTy3EsvkFjv8F3lSmpDFytubYJDM7zjAo3iW1+UnHKVdUEUBDoloMF145Kb+qaoeK1SyVBjVIymUPtzMum2zt/JGnosTpIqsjqpeRGZD/UKMdYT/LtBRkMjruq6fXPrgJgIanI/TGGn1TY1pkmVoWkTuXMZCHflsrnxmoNW4XII9Xn7tWSs3l+AJRM7n2A9JmjchK8a+T3OOsvurvGczt2tCeA7sYCy9Sdx3SWDT88SyH0IgJgdpCtIx6hoxzlOf1xn4vSjj3Dnt4st3k78EmfpBHRvS2V1fll1bVl5X9ndNeQmqiGgWT+/E93BTpOWOtcI5inx5XdPczzjAl2so3wqr9wle3lEIR4615th9fXeMhFKz4RxcLiv/O7KNYu6TKAw9zONJKYzDqFiDi3gJUZVBY2+z9wCrr3qihNyLo4HG3VE/tFjBXBlK1U8to7gtfwV5UEXxUKn7/ir7BKhLYyPUN85Yeb7HdwNiJJJPsp9wXR6yOKGVKP+VxMPToazqZxrsKv2fa7tOebTVfu6Mm1vPTxO8wHmQL17uEpGOrQJVaGSbsZCtySdZloSQrDZdY9Y1JM+D31b/M8vjWbx+UweAE2VvN0plJ8rIc3RO1CO0KsMdWodRs357+z84wvTW0ZwxUnWIwT+8ZRfzb3F5tP0Gn5Njh7hFkIXBmh8eRLd19wvZ9pf39hEXZ0ijgHHOKwswDuEuiLS6wJTWVDZw65p62JRPYIelRJxrjZNOA6oi4nY01THU6yPWr+8pDjRjzMpUrss05Z/DMmZVh4gxa8P+3Bmz24UJGLM7TlqMWZvfJ2LMegfbKyvZjCJmbDfU+mzI4epLxl/evfvAIVsxkqwRI7CQjK77INXQJru8K3ayQ4OCdcSqN/h6n2zAVYVETFXnN2EqZR0CBtNkXCfSVDPdhDB1keHI0tSgL/Y90KT+UV25wr5TGmQRlTKhjNf1Srd9AroK8vUPopVY0yLdCDJOi0Q67ajLT63H3SK+gU8gfSWnTj0aViezQoezUN660CJeo9s52PKpas14WpiQzlpcRZWbmrMadaBZknpYgCug4DAb/UxajcEyOpudgrQX43GpdLx0mkDfBp4Fl2puZNn8A/PoHu9lZX2YgEH3cDeLg3HcB2RTlPbuaEWZRYxJ5zPhSiH+FLtbVUNG4CsVnfdhl1sxdacbHZ7oEUvSggopaMtzvVUK+E9V12zkYm+PxhOQveOp0xS63Kw4W3NFF5UZiZ/3eHVX9WMiBt7DVZ5E7oHx5ivIH5L17Q1AaBB7WSywbUBpfOwvKmLibikT/tWoT7SPIokerZHLHCl1aNieEKOA2xpe2mhRbiFd6IxGZBHWoE+J6Se0sgcjTGXlGGltJcsik03iyg+/lxmZfCI2bFz69RmQRdVnPX9quaQNIzCPhKb7xDZd0dM3zN3Z4peFutgCRlJKSf/sJGzPiEwlpLVO/Z2C0x2I1zci2rcIZBzAZxUeijf3MgwOxXlkAWPpMa1N309hFCGtpa6gt5nd/N6pwMDrk4KfXRbUqNz92gs2fe1lC6jo0fgSmpOFq0a0iEnIPr0C1deLESRW33hprYfUNb9J5FUZL6H0tETbC9LyNhyBjIeUpUT8KipgwrTqCgWc20ZUmBvnanVlBPbVGkOddtBRSybh4dMo2VwnWd7Pt1xOEa/WmUz4kwfeK56UNn8EPpSOyd7wXvVa823DOCouYTPLOLB5AtqMCTl4AR/KGHwefCjrwUisKBsfnerrMlNb5G/AEwTPX0C0uy+iGOu8nYQ+43xPcYWdnitpYazvq11ut696NzuuNuvYeIZ8zXE2sOmXBSdjf/z610UOtv2KAJdTxNR1JhMm5oH3ShGQNn8ErpSOyV4oArj19drRMI6KS9jMMg60UASE8AI+lDH4PPhQ1oORWFE2PjrV12WmUwSSKOqXgp1cwmUdZTBawjuAeyX5hE0fYy0WjcFeSDzc8pM4e8ZeAAkXRaLLFFQ+GZ+VWUy5jQYWaYYCBp4HrwkaPhK3CcZCS8VD+SfltR9JTkxVYZKubymOUbGHpIyMB+nsppwoq0rClWJ2nwdv9nRlJD7tGTtdni1LTce5IN3CDAflqXpSm/xxR+VnY+piQv5lShjxr7o2xckQzjDACaIekcTZvZ8fTkSMsxcc8iiITor8AfNiSBKZAZLSRqu0iFSqgibk02vAXh06GnVpBClpNMY67Zn8OPI8SYstMbv2MjifVcTNTS4T1hVAG/GpF4cceSNG4Cw5cfeHjUiMPE0+6uaVMlIVtc+QkxjwiVhJ3IqxeElM4P1hplvyb/mehnKwqYxSNjLmIBpUwD5U22a3ZsraPxbjCcZDp+q21ByEWMk1GkKm7PIQ4qtEljHfTPlO0PRxBV5nPLT5bgbqF8Uv/VoS1WH/KhgFLuM+IV/PhAUlfRhVh+PHR6d6UmAyViwfgdP0JBZlFrFiFc9Znw2FwPoOxJ70N1UrRmAkFXV1qu+WnJijevcD3WweuWg/bR7ito/GdXu5Y6jjTH3Hj9LUzz02ccVkXKIspYpURhewiecmrlARemx+XKrVlRGYVmsMddoxeagyYU9KyWfET8zTrwNzb/fp2D6ZPVO+7XRiKqbtjJtOI5oXjqdb3ImbjppHmXzS5d3U74/F3R8WlLR8rBWeH4t9Yra+cCdczgEYbh8DmkhbPyrb7WHwks/wPl8E2CECNfkhyMD6J8wfWg6SsUtPORFb1kVMuLKvGplYFHG/v7vtmq0agfc0h0GLE4UIkzNmR4loWKiPX4SlVExpqzWqKxSwp2wWTC9DtboyIk8rx1CnHXWZefHwd3qKmTFyp+ho3NytdX8UUf3OTMXUwvHUaUyn4LRq61WSA509UptPqrLiLMYqK4W7P6wpaflYyio/FvPfI92AZzR9rhMEkNXzp9f2riokYkNBfhOGVFa3V1Z6nZ6MwK0647cXFnxRR/QUgd6S2mJPuP8xqchuwjgFPcIBK8mtOTWRutlkMTNNrz0yqPuzvIgbPsJ8FY/D/BeXut3lnrlmlT6+6ORWMZ2pLU5cgSiWn4Sr58OCwi6MyInCMdKpvwGY1r2gjtir57HC5PbobMAiuwS9c9KaZS0ZS3eW0ViXp3Yz8Fy5AXmRxvjVK6BzM0KcXawOUDnNNGdhFXumM6v6MIq2rBqnvdCT20Zryj1ZAe+X9nwKQCPNJCHVLoK0XMtOi3gdAeXZjKKMWEvpZjfTVORVyc8PqT4MtlhotGwUNaR3KHRa0ZaaUEVmetK7bEhLDM6E+7l+9HZjCn7dy1WE60WfW4WswOCcuo++Fn2dmIJN99Dzohsbr49Dhbl7Iydah0vcS8ZU9mAErlSO0R6x5HIHQnhf3f4/yfMU3hU50GVRdWkFy4oLWrBwTwv2kKX1ejQei+uN8T6wvLgn33b4z1sJR0pXd3MsoYKhgDFSNiyaI7Ixa03L6aeKQ3fH0FjseUPLsihEmOlComRwO9muJu9kS46yWdpzTTz1p59x7n2ffMXS4Rv7+VfiTD0L62V5FWwU8eH4vIp5YzFDOshyFQwl+4t4VmH+CFIYxHkzLItkewdjkvEWzRj4BNLXFdwq4tqa4SgIp4CwoKl2g0R3L+mOD2aFtWzoeHLBdEx1WkaXm3ryq/qnuaHTgJgFx+/x/s6gW/OYGnu409Po1d8LlII443sMnWYFjTOLqdFpkGB+dDo+5WIgaug8OF40pjoto8vNjfdtVwALse+BoQ9JwM9Hqh+QKK+70m+p0wWYhsGV5jiuj/vG8lNY30zH22ASzMbYxnbuRxAVTQ85bjVkTSWYwSwhOB6miro98mnTN2tnO3u0OjzdTNLiD4NZxUJMPbmMtga6+r+NFW1WmvzE6vpB6OS3y2C7i8Cn5DmOkkAe2UCc3TN3MeAis2HdzsF5S9yWEblLTGmt04BOyck4bAVBinodgs6LI1IOE2cXcViT04THJPCGz58QPpt6jVZ3ZQQWVQ+VTgPocjNg0D5DBJdzALbcR/OCtPWjMuH+mhAod/zyp6ZFTFZOsR7LLz1orMzS+vaJWTX7Mt4S3zeKOi3pFJwRO5sz8ngsbMO8PnVLeVMm4b1DEJ/NTv0cRjmO7t5/Tc0AQ4snmeJOLKpois21thnK3v4eTjEX+llAXyZPel3uNAgfL+JlnoSPy+IuC1NY+pT13prrKyiaCpIyJjOgt9q9ukqn25sRWFx3PE02bbPj6j5lo6fcyDy9j7qzZl8mZOg91GJO7u9hhL6A274wA1xOEcs2mUyYlEce/TkgaRNG4CYpYXXqnjqOCnkHy2x5lxeRPnVmK/4UVU30ZOjUa3E/8fdiFUb9fUIz5iti/WADbs/TZNvLd4oy4s0Vnd1sKyWvaHy202jNKNucXuLrtIIuNxfmWyWmrNeWGJTxqGomZzu+LeMzHU92nTa0paZT0pCC/YQG5zLZ3FK/8WDK1TV5GaHi1mYxUt0UtYiUOKbxs9tjaPRnDI2wf+y0dMNu0Vmwb6+oFGUeiGH307Cj6sHIvLmXquPfC1CA9dk2gNEt+fckVD8iKSsg4koqrwlXSqsQcGanzbPjzr6ejMChfeOl0wS63HSRIB9A+JgUrIsp91keGVITQBgpUljWKG6kbu0i8cv1cXacbtq9ETjfdLy15DVbeMKQvWGRIlJsroNXEsr6IoYYt+/xAEUpcQDfbgGzGL6qyvSj53vZgWk1ZgSu1BoBrXZQ5WbDhfU7ERzb6PKIDECHN60eaNGsXsCtfVNjeqFs2rsJ2L9vvHWaxJadbDZcJmEQwX+Bdd3G28sg3hTYbiVjQHkREcdzuU14XVGVgLubls+Oq/v7MQIf94+bTiPqMhNyrIYRos/4YGh0sDU2zMLTfyI7w57YF87ILSpUJkclQFrfftkGaf7t7p8gzHESeEHjHZKGBXGc5ATlb98zsIhSzAbZb2/ztOBFJoZeglxwZSt7+6ZMlt5745ixC9bndiaqoN/d0LRSrVp0YRVgvRCfYEb2+iKMOq0XZBHkYJOkEIhQqsTX/t7AMC9SIUaVpEsQFVInhzZ58MMaMAVY5VBRisrWD01FihJidoJ06XVcORDdPBrjUeb/GsTFfUDIpZocdLZe6D5MI7Ba8AmZr1lgekAqdxIh4RoPnL6GYBaQzQKS1k/0+qmRryB/SNYipG6OfkAkdPEVhSe0/Ahb1smgTWwi3cWTgcnSC3kaJZvrJBNi1Wm9ILV6JQJp9ds+EKzpgWWONxg3ICNrrxBQkK8X/Ao8ZzLRX6f1z8kkik7i7FkyFZtULSAZhDYTYIVFxQHlJc6+loB0C7MMKQZoc5ekQp5n8/SCnr2gZTkOopMif8DaTRmcU16BKn9vZcS1SMbBTaIezCrZwVCKQ1J1gAIZgl4rPqdJsZO2gqT2AhFrlQijMv1prrzUo9liySrI2C9mBU9yi9HFr6proqsA9egnExhNoh4MfvRZClM+vd0Dwz/2KqaX8FFYjTVPplm1r1xqgsgo1n2Ps7e31Gtq4m52HrvrbVv3yRJx+9inZfTUM3H0YYWiJot73dcHRZRjYX+U4aytKtOvRpd4JCyylFIkHrEekCJ6oKICZRBIu4oNatOtQgfbGFQYRMig8dWhbN8iUoXhEK4bTTSTHpDmrrsIhYo70KuIJ+ItKUnQK/41IDJCilKl93fpAe1RCUnvxBpcJ0O/Bi++FiJU6GVXewx2jCuw3UWBmB9F+XTtF68qYDaPtohRYDJZ+vUKEAPEa8oJyebp3/mGkVwvbhJ7Yb6nCpgmsZ/NwwewLiKwCrJHIZtT6f1dqy+YCLvW3tjp4z0QZIiffgK4eRBqA50MunCfIFJHMsk0YfNobMnSFMShxPhQJvZrYtwlCekewGjydt2RxTOh6/rdy7ONL56YaykXSX0oYpFWw5XOu73iZLsL4EZIvDqtfwdLOWIJd6wdb7heliN0VQrObhYtc8YlyNG2uY9fxDl7K6C82cRGf8rhsG9AWFce4cjwnlemsFIlRuZT1rsNEZ2gyzZeEg8Jwzp0sPUMadSRqbjJgiPu3sZi3lwrzj26OfqHME2yDBWMFJBsHo3eC6WSjjRCv3KZglcm9et2wYvyGKBN76e31BolNkRRR4WyM5nb5uSFyiw8m2lysmeZXOgOpkBzbt30RnAwxJ2Q9qLWx9c0qgSuc2iKclpQqWa1fiqJrt8r+8Pcu/dEJeZePY/qg0o146q4iMsj7wObVUQTei4pyMFBDcsutdHz9mS3iyBYrxK6nTxRlPnlvVIVExGLOk1W0EqJKqCbfAi8UK7lTx26NblN+lcX8kmzBnPYKddULD4KV5BMWECjh6JyHggnhBXQTtxPXwK+++iYXLwrHicTiWHxG2QaHNEPJiJR13XBF20aGdrqJ1L68Hl7u8UVUdBJU+pLkYeWYmzF/foCl1W/V/0agyW5xlEaaJOgSnEQ5pN3RpRdRCLG10VBHiHiKGpnp+au842UoeRlehlAWlTBYvpk7K1EQFIluie69s9RYXazjvbPVTdCjjNluz5Otzcgy1PE9GBNuVjxVNQoJe9sf2ERTTl3LQU5NWoQLRttj93JSrt63TYuaQJKCjMquibKL6QX442mIpcQc2AK1YGoFLRhs8h7wOQU0YNyO1SQggUaiQiMZ6CcFN2M/f3oDq0zWbpwAuKouc7GDlH751MNFVgi+FwKAwKXWWiNaH1dVcYIHktAFSmRXQhyCqMIybjGZVZBFSarRne6JTzQhwEciUiVY2x7G0dBJS5vf6/YIio6tW68GuTigEVySDYAFvQSudm21+wERFMXkHdQWU5EPomjsIKG6ioEhKQcmp0JWXtRK4nHZ5L3hssrIhLl160gDA81AjEWyZbcPG3dy8X04PKp+8Fmd555QlABfaSktt+63IAnCJ6/gGh3X0Qxlo6dBMUupq9k74ajB8CZqprVKKSbrBoLcteu/8q5yWeS947LK6IXdRlBQSgeauC5iSus+b29EyGmB5dP3Q82uzMXCUEF9JGS2mZuJlGkZJRuBsUUoPMJjQXl/RDVLOpADMwY7c2W2/KGirjrdBZ1y6mcsu4392x6iEBDicwiIkpakuBHkhP9AbvS3dK3fcTkkGVX90dSyl3sKrAldJMMgQ31mBtEt8wdJgEB1SUU/VQWFHIbfwVKRUc1vmLZqvrqb7fXS0RJTo2tWS/RDLd6oxNJdaVMufXTKyjvslZ5EUV7Ls0pqKxX5cDbxeamnZK6glzyfvGZRXSj7/8piCQAG4MixFWrnyRMtp5udHNLiVL7j/VRhYEbgyy39FVGCU3oPD09oLJKqBH0k4EGEdCgczXTJ3NUN0OVnFHm0RrHsi9+eKLEEhODo6iT0KAv2KrEBpVPZ65TffEhOig4GYeICWxBmzJOXb9FV5hP3hlRdhFt6gvECroIoQa24pZ1quQpk6Ov+Sopqk2DsWSn6Lb1bRsoRu4OJi4g75aynModjL3SreEbJq5D4Rs2GCWru/GaZBQEAO3vXzf+5wAE7Mb87GVm2ylI7C1SerFZeuZPm1M6C/vNZSzSOCRQuJXwmXQar3AhMSbEOO4idUyF22vU4ocgA+ufMH+gYiTwpOkrIu9cT0kR2ah4EAqq9QHL2MmXcVEU6uK2DVchp6G4QH9HheVU9DOQTOo6BKSUjpEvSn6nB1SbnN1Shv3tFB6SsN2KBpd7OGJJj+insvTIqTanVOJV4VP6JB6FNCQJBCFWlOqoMr+8S6piIkpJIsQoiKasYWA9VlR37wztL2TWWctpY4hrO1aWfpvkQExKQiaHvF/djDLfS+HtDBXOkBOTDjF02wYukhOhm7G/D538KpL0q2hiSJHvnIzK1lvn2g+216LAZuzbAzP5nfbTLNbARoVOPKkeaS7MqRIQogJiqdCNeqWUOkLQgYV22/h+FpLm1Tgr0mAkw9OnkdmJDSZ2SwcVFskjeXaVCJGWEssmLgiaUj7JweWbyU6AZf9UVM1LeWaDTqpmpyP9xpqjXMUK+4Q0r0G/FNYKR4qNY7vo+pz13xFiMircBET5/frOjUsicag/DZL1FOztrLq84qqVNIxhP4F76hz4+pUiduOtLOKiYHpbwCjmpzmaUCio41iqBIRFA0QKtR5TeJ8n6oCcppNHiWbL3WoKjzjNlA3RHlMJUzkED+iELZUOWSdbLwno3M6RA2gsuYwq2++LKoooqrrRFrQheimgi6SgtDqWbP8gaDdhvMgOqib1r986pZ2o0r+SDzkmoypRqoZ039GxGo4OhBNVaKSJBqbTBMHoMO8SDTVEFjPEflpYzAUrOk/L9XXtSvVVu6x155WK6hDUViqmbJ4B6V8+zytJNBgLNY4xmZRwBmNUxwE1Hyh1C+SD1sslDkqn5rJgKPt1Bbye3jmRqL5dBttdBNpQ8nLqMDn7u9Qt4EwhBk6k+7XB8p3p04TF79y7ENFHklPeIXEBEX3owP0KCkkAR7gi0tasWOL5TDpdUSzjxmQZdamm7Pzlz37tR1qkd1bISipmm+KIwaiGsYlpREYbAg5JuomIxjzz2XOKZlLcoPNyFC1S88+bmlBeUflYp3CSF0OUh3G9ZeQk6CsqjHQhff9EFduhr6KBD+pk9SsERV8R884qhIZXoo4jQJonRW4Vjgl8Jnl3uLzCYFnUKyeqaFkc1sBOCNw7If2XEE0nq7yQ9LKVPi8pwAeemt3XUG7P02SrIp0qu0rWS0uJFxbmDRflMiKHHpd0q8SAcFRm7b61ZTwTjQIemGTU8za33FM3AvmlyK6QPvJSQpnWeeBHJdUUuCL5xr3245V8KmYT5tPrmIrFrCg1FmtRj/Tcdh8s4ukjzSvvkqyIiE7d54QUdJKCCmjFPNLk7uAofCfoVvA0kcDhUbeswl1RE0LoRSR7DEnlHqlbn4hNBW86eXDD7T50dHsRwxwGkeJGgKqAvOfKcmLfXO6ZJqV7rgp+2MspwmeobvknpPqJKS2r33EZhA6JdS+xaNYooHrvoNoGzaQf1eqPmCnOLe+yvJA0Vib7FpiCoAr0gYOM9a3gmit334rdu1IPsUL/+r4EwE6eAYxB2qT9+h6/qbkNqg+/vkdZQrDLiyD6mqxBlNUJ9eOzbcnqy5vlLgixOP+fy7dvXrZRnP329iHPd397/z4j0Nm7LQzTJEvu83dhsn0frJP3H3/55d/ff/jwfltivA87++BfmdY2NaG5hUabScXhr9fgHKZZ/inIg7sgQxRfrLdctuU2SPNvd/8EYU68XV8YWfJrQ+W6wlqPoY+P+JHDaVifrEvh35UrJa4Rtxq8w017pzokayl6jjqJBQLpL5CcY/HFEcASTZ4gradO1fyLNSJHEhXbuP2b5T95afxvt3z5RR/hE6CefaSBOgkGeDDbRcFrGVOXQewmGWNWK70AskrRR7zIPoH7oIhyhvjtZx7r1/cMB7C89p5jNkYCsBysxd/9VmMXnu9Dt5gH5pDDzI22ASxON0UfsekIC9hJsMAjurUUtEk14e/rFKCFEeA3LFge7yTNl889M7YPTh6LdauKWRDqs+k0kCByifq49XLXBWy/Gon3yvLAiHbhA8o6SNcAKXZIs9jwKxCXPuZiu3xI0ly64vKp+silaKU33DQyn6qP/AWuweqh2N7F5DlnGpZJ0sf8ATN4x6oHzUeDeVLcRTB7YEUc9XlKJWORAvze8bf4ex52Ebsp+ojfd2sJYjdlbkLdiyi3F+Aji23cE4norpMMMIMU9YxElmyezubAJXmMJ+RFvIZPcI22l9GrcHJ2MxyI6CyiSArMJRpod+stjKso9Ixm10kx5y+w3eGX1GU8RiUb0ff5W/wl2YJrbtlk0/RRv4I8+A/w+lxGKaYxuylmiNLR4hLNcFcwZxcl6rPByEdR8tw4JJLruEzvxTkMatjt0uQJrG8CHLN9iSPEduD5ZIO5muQ98OIc5q1fJXkQiekjzGHVB3kl0kwGs6YgBqtVchIyulE3RR/xEm5hjhtE1jKmxVyiQUsfC6aB+IPB/KBemkTrTX6F1D5WUZLl0a/lM+KmLmb5xWTn24bF62572+8G7anKiJZ0Nk0ftXq++lv+gN14axcnGlucw7iGVhkQ43fSDeZvgeRWgEPJIzXgZL1m0Ni53JvbyG7X+PMzhrvmu4HKX5VhR5b+bqCcx1E5PSln/Y6KLkg3mX8v5XT6di/BF+cwp8bZyw6m5JjiU/CaiSnD5jGvhbg8EATR3JLnMti4Bhl7BaSzeeWTDaRppyTbej7VqNXfM7RX36QA8Jojn2rAn3TBFT5f6bInn2wyL5vzUnZiUgkm8qsqtHgNI3AJ4k3+wEowUQ7bGq5BChNuHGV5LGohCgaB4SSxKIcJ5XH8qrM4QLszTih2kkwwzxEf1HGxWNBumsl+aA3xTA6iuvTiAR+gsnsjWS6T9q+Cl7MXtA/izneoBBO8s4yjLfmkj4EqXqBN2SZJX1k2Y5KMdDK0H7uIn9CMRYXLx6tZdGkmA2mHfbbF9l4mydjcRsqfPAUwCu5gxMHLc9nVJO6EOIfBOMBYgc6nGuwGkuey75WDIDu4onSjXRK8fyXWiPMkrdt3CtDelNspyTMaHEUE4WOCrajYeYE7imATDffb8jsJ3MZb//qCvE5iDUZDC7fFVjzu4hymNQQvfTWwOQzpBtZVUcguTYJko1mH153T4vW0yHPOuYBLNUb+CbOHCGa5Ap7NYkCZUtZEALH7NdqH8YcC4hwGhwNoN0SKwpBZAbspJtZBDsoY41u0FsC0X41tlQvygq/ASlkmGKxBOIxTEAla102xQ1zmQYr9kwAOrsMdrqhz2tV4Fq+16mPzGXBYZV48i7GXiIjRRBmMVj0seDooQMQ+yoxGO2DN+lQZjXZi9HVsZhumuqktx0TrNciEEW0E/ejNbNSX5n2ck90uguxeQZhBH/8ngJsHZqLX3wyoI9jnme/sfsI1C1J9MqCXoD9fjPvTrBFq8aLIZlGXSrBIM015TO71EB9EgPN4aj7u59G9oq9NPDjOfsakmbv1YC9WFpVNM9H8M1AtZwJDBZ9qgfwVBFmRgjISjhC9k8OihpMt76XEJVrg4h9KbDqDqeMXObzkrX1corFDWfm4kdhIJMliWQemgbqKJod1L9r40sqe0Nlm42TTvnzn4mUje/dPw81GXnQYPxv8r6PXe9Vi4dkDk2ZkYZd5HjJJc3FprEuLxA+bZmIvrPQYfmfTSdFHrPQVDo/+bnw6mi2SYpfE+H6K8HS0k26gO0hQ7dDqUSBH/0T5l/FrN4ehx0F5xlZGluU8DujE2Ui9ymQOhU/W64u92vJuIfbkRecq9rA3G4/SfjVRPv1eGzpNcrRZl6IKkk3MnDDgTJvkk4m5rhxrme+dKP3oJqfGKt1WZadifKoBMiROSBxk+9mklRuwhP9iLavNV0u3wGyVlJdwxPh9ec3b/010HMIlGpqbb4J4wy4ZnYSpHVCHNnztjwPgHM0sh33nQk49csf0BwTPXzktkUucjcJVSU/HuxwliM1dDlnJYZStqrpTGAfpq3AZqZNMTky2oAzd1D0eqb8aiB2QnMMIxJwu10kw8XC5AsyZf/VpPuxXnhv64cIOlv3ForF50uO1UJ8qkr0Yn9hiVm30y/guPoxnFKCDHU2JMgxr1VXLjAt2aFRHbooILF+zHGz5DahGdqNDdrE9q5NgsDOFUYRtvrgcv0vhU0003srBUQwtSDYxcWU50sOJrkiHRuddXOX5bGq7ll44EOWwqqGMx1T6McprYXLZ1FQPgHDnpMhmN0pEGKiGp8lgYDZ9ydMACyjGatp+no9I7rxu5SSLFY+C6QhhZfG5WvZQ2ST9Al5IrBDW7txJMl7WZxLKZ1q105O1uYtmY3TuRZi/6imz+NnZ+i6yc7SxL9oLZdx9BTb58LmVvojphWFpQHumVaPMn3Hp9guuWXTSjgxsxcD+ONeRZafgVXc1wPexHE0F2dGXLM/x+EuNdTyk2r9DquPhzKEczkzltVLNFhLi1tXqWCkEZdwSe7VMVn7+CplAFBuL4bL3vIcs/d0AjcTDYZCqbybXD6LdfRH9A2TkVjh7D4FJNMa9SuSwTZr/KdPD3RcZ/v3t/r9xLlrdOfPfbVy1uhBj8XpdLbfTpb4bbBR2zdNVnSa1n002HXXoI3a30X7/Ywp2Qxl8GiWbOpSbOV8qSw/Ek2V1vMDrJBicj6AuXCcZH1qW+j75KHVWukrSxYL33UwXTSXUoOtnWb9kFW0T9XF/BlnVmy4k/X3ycbwCz5n9bFOWHna28YpKN2W6+YuJIgqSTn+ffNyvkyj6kWA16gaEScq90a0zb3shBpqvqN6TOHvmtYBuyuy2KI5+9ZLHWAyUtbG1tM8FlOhpZYrRRaA05ox57VeDE9wtF3W7+mRiXMkybEFjrSr1V3Ok8yTdBoIwxGyqOfIyYN/k6KYYGLK8h9/1HVaqefWVe/mBTjDAw0GAWBNd9W1889FFVvrvNM8KdinGJBp4zUiciOy8hS4DpKGK91VM0pS7IdyUy2QDY+ElOD7VDLkOHiUF5zLMZq1q30R2Waskjz1rLFXSksOsVOQZLZ71qc9mI89DtV/HXaOQON4F8Sun0ZYfTXCEvnR2/nk54nf07QnGISejuUSDNnKBvBamgbtKtvvArmv1V2Okj0KkjyZI/wV3eLsfRPzNVybJQCt4SGIgijTdSTCYP3WIXGb+tJ/HkPJT6fVkDjjfly1nko1aLys518N0cryZVR6+gpPPNskUUxw1g00zOAd5Ti5BnqONZJbw049PNUB+SAFQYQvSDcaoQJsrGAqR2TSLO3k/AtYFvJMy0fGs92NV10PpieRRzei1j7aLVOpiWQinPoC5yqiBnu/0+dTmJkakLoM4sydX3aT5cCat2zkyJg1lw5fq8kMZrf0p0R6W4bu7FDyVDyczC2YnZd/E+UTMXZ/LufF1jWJ55ikuOgw318+Qc7Gzqe/jupycJmtmA1h+MfXSK02YwqelmiQDzOrgvyq74K124hwGsqB9cEleiTSTwRgFG4Yo5Rejrf+sI1j9MT1mh/K+3LutfC263GR4jWIhw+VF56oo1y1eFBG5si9cCppEg6O+GP5egCUQ7GCZJAMzVRRsLraoPTiUA991QbKBg2LOmGrJh+nn4B9aJyvvUS7zlHgnZEmRuu47RIg281wLZh/0trr1/HTqppgjCq7cMklGd8HSZHsdFRv2HcRuitGhdVKE3LyiPs9mFtQeR26cX6NY+oeJi+4Dh/vYmZB3lBmFt/xksHoVEbPElF+mWQvmrskfd3Kqeuan8f8xd2RTXWdvPCQdL0o1OJaOo7LCw6wLuEaRs+jYe6b6OdkfSc7OPSbpgHVzTHh37rPku/3URNw5r3Tmq6SmyM+vSZpIqxgkWC1Z8D8XIMuRdo5nlkAf6CZPebA3d81qT4/F6ShsflzwMZKDG764+FztfPKXi23fLZY4fVu5fKNC1XTj48CyaWM7ftc+2WS8hd7aZcrQrtpTrfMg3cIsQ8p0eT/Icc1n0GzW/16Iuc5Bvy76Taiz7j6t+TobDjp7yfEFn+ikyB9QpTAkjgk+uEmFbMFZZnDDcJnfq/E+XNBrqlysMU3uIasnidLN0SsR31eJIJt+Xd/wwK6SR8AYDejvhmgnYQiyTIbZSTXQyLFfE9I6ZfJClD6b2X6epMXW3ZGmgbGYx4qyw0zaVbKDIQvRfJxq8vNXoU3vQF9ciyNrXM/i9tfeBTkifEnYwsPcIDi2k0NSeJjZQWpkIZqPk80OTALRO4edBGPveqFjvaFxsZSerF2x+qqPhN9KYWCqTyYGsCwXRTGhv5ujyUZSlG6OTiJUC3HLlKPMMpNZgbuwspVTo4qoz2lS7IRyqknZ5ysMV83aw0qW+vMUQgpPTaH61Ek4CixNnjnGphxIbSMiwIPaRnBsxaGk8FztXfO/hDUn7j6w8xoyFm4TphxO87kiKTfMNCGViW7PdxIM8fiQS9Rnk6NIwds5Fu/l+N15VdfDKxsCFx+RSzU5fi6PsSTQgmTDccHXDgsOl0kyb68Ylk81MCGW7zyJgblEY9zyOrDUPinLZM5xiyJNQRy+Cp6NF+YwqaEsdxOw/gTdFPM2dw8sZXOGz2Wwsw9ykcShPpvydXGX4/DGF3EYoYaJ2JvNYVnD2UtfDU0O8xpIiObmaT5VX8Q5HWtU9k2c07TGSiQo+sbmsKxB0Rc2h2UNqCw/98Q5LOUTkvMQ65hBdA6AkGQa2X3ULSSmRnYfdQvJrJHdyHkDF+GultZfDflDzHU2nFbPNgFcm2TaOj5CPP3d5JrMfRGvwVr0JCebZoL6HKTr6wTGefYTpACNLevYJ8lisM49gPAxKfKTPE/hXZED6T5PndOhxuw/t1FPVWUW89Vb5vIpSjdwRfIc07LRvHcSjXxn7GCJ9wVI6KKNLxIHC8QiIhVDndPEeSVd865e7VczJF4Fbb8aIgn6bNfDr0H2CNZqasrymLV58fT0kW9x+dUM6exlB1Pi9PI1ifMHHpTLYIv/DxAIqMym23HwJ5iCMP8E7iB7u0eWycQE1RSrYrR+SSKBOUqWy6UmEQfJc1nVdBrEj/xWS5jBGp+frMIMdvgXCzk0TrNCrSP0yZCbdCv0i7uANY+yiebrAtFJhFGexTkMZlqBdMYU/otM01UaxFkQ4p/cwqbI514bz6TqnO413oCsYGNw9+U1kY47HGFBQU9xDpcaRD2S5zLyhGi0PEWHFNlMLq+k4UOQAakVVpjBZF8FxXcvOgnmFr8qnp7Q3lenmaPiDRcODlzk5RqttNJpFzI58PETI30fjmXobdQN2AYw5m5WSLLo1/ElyK7Ac7VZv0qwx2soiPemyDab46B6w/09Q3unLzDL3R8NF0DaxN/Vgxnm8KixQLJzhvpuaKAQHk4YLhX7FvfpM7wn+yePzCWAtGEuPZhhmKuum0WhvxtI0Aysf8L8QchkXKIZriBUDPX5D8C4fnjVgT9Hu8JfqWMUtwje2JLnMud+0Rkcm2awOxBYa82ttBdZ3QJyHTHgdCZhBvO+o43pTrRXEqWbaD4h3EGsanA6JZNkgSm4scSmGejFIMZaP6/6Ut9N0QQN7CQYWAhBlnG35JuPJtzUkp0ofzw3CTIcsFRtJIYH9yPLkFmKsgO6IeEKJa5DbdL4+uS1x6et/14EhMpdqPargeIRw5w8dy88GeZTLZCF5758qgklZe21bau8nbZtFB44Wxwr13ugcnkVdlqSxbYOIRkkWQxUht5jUtfjUcWxqPVx6KfkOY6SYC2IX8YkmSxUdVGp2iPIYOIpG4I4AzUG56zPJxu0HcnPnwBuHtgX+6jvBi6QRbyOAF5lGOdH6ruxfF3gG68iCVsmzGt5viIBspyXZwxjuzyLyw65PLsvpVdc9KMru4BHq6R5TlbkSU8nH7CmSFto/diNeEQbs5EWyjCc6tfXu+wCI5Wqb6YopygFv/YiAGuSzOxOot08/X38vdzezSB8ilQGYnWZNTWK5QtVY75c70uSr9IgfEQdEx1asmkGqNgNUaSndBIMTxaB+AiUTTM6J4RPIBW/rMsl/gFmj7uxgkZymEVjmiyaOgXn4PV3CwOIeG4a24/NDQ2T6TB5kcY34HcSAdNReaGgrNQWZfmB2MjTJTffDORXkfJn97oBQZbE50lajhZra2cSTXDJsAOyd2dNHFyiNa7ck0OZ0XzcxMHn+VQTTg3u76/4oNH0dwOrz3oLY6GLXzfFhNLU9BVfHZRk2U/XnskW/YT8uUDC18fC30WzWvz7IOYtua+DtFJd+JuudIqpfU6E2E0xUXZaGouOpEXpk23aPZ7XDGGbrnuFWBikYE0OKsT97uaYYrU9yruab5Y7EDaeie3Yu4UTVkHbxBY2wxtGLPqcfuKefNsJHbJ78hrexjmHEZp8nFMsm2YkQp+/xRUZZO8LdJKNreL78/yGarAcFQoFso1yYQQ3kKIhbIMe/48eNOkwOHEIHvTGfXsUQmvfuKGSv+RhaQ8rO8KxX8aFhace6WnH5UeQQqTENjNhkWzvYBy4rxr9+PbjaAQ60AryWDCLBf5g4JGbsw+Xll8MThiDuLgPQnw7L0XbWuFtYFkeQ3cwgR+YkRsOiDfs5fH6mz7KT7hmQapPBvenBAdhX8yddYIMECKIjou5RAtc/EOJTWcw0MKzDG5itPuFhCMu2AcYRenmZ3g4RCl3fYlJM994YydJFpVNM3E8Ez0F1H49HNMIkqDho9h6wSQZ7ua+Ffm3ewJRBXbkN3V8lrmvfoMsef7WuX00OFSFpJssUbqBewN4ydEn/tEx6rvZxYnfC5iK7kvU3y2m8yKJ8zSJRFZeWZ7D3xD4nXMeJtvos+wkggEnNsmnUTeUljGZ5yW4yc3QQaR3eefUmwiXwA0qx9k2SESwKNu+cTMqm6TL34sgBdnN5o45YGETDbdBJ+t/FlnOH69ziQabGrL5kAHzqSZr2XUKliACoeBWRSdpjLVGhkimg2hh7CSY3PiIH/HxnlB/4RIP0PmrvsziGEmjQrGJniEtOoyMq+vjrzl2U4wcweui31NmH8ammbeTg3TEO4VxwIUiY9JM5Geco1EVRGKkE/TxzmEEYk6qt1/1kfCDj3HGaSnUZxPZeAWeWZlIPs1mHq8gSMm64jaRGxiLmawoO/9tp++XDvCTzjJnmjptCncSE/vsVOeB5UskTsd/+KfNaZ+43NRHPtKVh1tuzNaEZRadxcFdxCp89HcDNBAWKeDaRH02MLzzj4N9MX4ZLNkkjWma0ey6SVNqtF/ybXSarF/ZJtLfjdfj2n5+BfLnJH0ULs1cnnkJgOqTBzlQZbMVB9Liw0iFsnoWo/1qisRLGfr7cAvkVHrQA9gCYplA4stRF6KhbPQhdflh2IdUyti2y09jLkyCeGzGsdj2hOFOg/DxIianVnRAWjfWk4BaMKE20jDs6M1D36Oq79fXfe+ujNI+HiuwRUqL65mKCNGCVfVg5qqL45exrwPW46T9esAndAs0UJskffXDTSyaBSf1Qxy5aHZcVPtcemEiBszBBfTIQvvDQp9BDFIYenIVYNFsouP2Qsx9E/kf4LV8NLqD1H41QuJAjnsKIR+fhNENCBPXsM4NjAXnKsrOnWX92j2GMehfZBfriHMnLb/Nhg2/p17YsIGxYENF2T8WGy6jgrkHWX6ZwodZ9sKh+mXDqYzJ4QNYFxFYBdmjozGZQrIxJiuLz1WbXKLZF7OO/81HA7sk5yFg6hogPKmyOabKk923+CxNk5TTA9oEk9lAApmkOWcA6qaYIZ7FayFe/d2wfUUYgiwTt5BKM2wjT0Pq82wkQPNCqqM2VcPYaFPyssNM/JP1OkWDyrmPt5+NLup4eZRLtPzIF5+prKMgyIoUlJ6UjmZRGsrGHqouP9sVg7z8hjZ3z1ht60rYbpI+5g2+q9nFqj4dsDWjGv9PcFt6rHnhxgbNniEVEEeePHCeXBRpCuLQNch1BWMT2VpedK7MV7eYf0apm2LEeuy7SeZvY2D2ukxQIveYcifJ1FJynqTbIM8hG7aHTzXx0t9CpGyskso1kPHSZxINTpWLuwhmD6xuQ32e0jNsTpG/pL1O8KukaFNCXLUYp/JO0mxEGGLBYuvPVYODs5BpGhjDCDe6Tv5CBJ86lZMFIRAL1Xw0sEIkOxiyOM3HA3b6uE7JazjVgwKuZ6s0ltXRqhpgIF735Ip0niZbGXezaSacKcPsphjN7X+CMOemdPnRoGXgRXBZ3szyfAMCwRX5wPDIpLI5nL6eFPkDa3kSJFthNy8dSuGpHAcsMYhlBiVcJo4+2BSQ1TmkovRAtrO2SmEIBj55Mt9DUfBui7jd+8ycGNkbg5IzCScmFSMMtKINYNVw3+6antNM5rS43QVw46j91yhWToqyonM1ZPjSKPC1pi5I+WXKrbGriWEiLiZvRp+E5IFRN06mkSy4WV18GI4WvKRt/IZ2ZZzhJ0cnweziIn9v0cgolaRsvBDyxcDMk4E05jrUfjVoS5Bl/OLSfjVdFZYZO17tZ6P+fQL3QRHlaLavETfCIMq4zoqyzGbeVntfT/cvumBWJzs9CHNdkk7DsJQ85cE2K7gFyfu43Plz3aLFNOfkxqRNb59fgniNbwUFUcTGouykzGZaX4Hn7BLkOUj9GZjFmBaTXBdooLkurJ03OqvyjasamPmrjKeq7okT+98LUIA1obrbBKCALLheWXoYVr9OYZJCNlpL+9XM1sxbmE0R+GW2/WpioWbt0mal+VbU3wwOvsEuemUb0nw0xuGb1EkwmOQLZmovDJUYTm3ZT0VlAGGH5vSKPKrOrv/1ZzMsQdOoz1MrUnun8CweQPiYFL6i83JwNna1foy57mbmHJ2aPNaNN+vX5cVYMbY8l0m7V8HL2QvgyNBJMKBq8FJfCOfOVrtJBrrhzGN1+9tJzkWweIjYLMb0IWJGjdLM1c4dJooyjCnHjtGP3WbvZA/Bh0WKH1W8Dl5xrV9ghhjf1ddXjGrj+quNNMy8Y6tn0UTp+ujlI/EMZPPxgM/yWbL55TYPbDaaXH8NIyB6+6qTYIh3DVKYrLkVoptkso3Pg4iUZjZknQQTWxYaPjRwgN+VdVKmsJX7uvd2EUN8/CSc4GzaAc9zcqEA/osE1McdcV1XWDybFUUDY6Cja29hBuwu40vRyK0PcdAXNs0CVQJojiUIBtNJmA3X3wB8oFo/IuG6ttFYViubGmAoc3gVpPEDuxFov1ugfZSgfTxoHX2RJlmGdiORF45i0Wz2wr0Qh8tVk62kji7Zdq7YI7pgo6ouwROIuEWN+m5iukzSvL5twpgr6RSDU7UiioSAnQQDFXFXeagwRGs/T+Vifo16woX0bz6abJ7vQZqClMPqJBzW5cjzFPxekLvKzOFr89nE1Z8E7f8SZOzmkE6YjYhCH3LoHL2/BLGJtSQrOdeTnz9QcMP2zMV1B0id3tiE51eVniuf7J2+Si7XOg4zhrAZYHG5YYa2vHDDDzD93cRkFEbFGlzES4hKB8xGnE81OuiovLdRQi4+7uAzTOExvoI5G5qi+jSmR8tXkAfVNSpGOeummCFKH9HlEs1wBTSjPk/v0HsDYiSeTrKfcL0BOasIdtMMjgVJif9KYqbr9HdTtJ9psKtUKxFoJ9kUG+06ngUjxSWa4p4mWPizE5pNm8KPkXRoFWwE05l8HX+5OsmyJIQ4XlPMv4kKM+K7dXuy20UQczqlsKheQVWWY5enOrdMCUFr5Jpf/aUV3C6TIhW+26i12jXQomUPE7Npi2MzV0GKp7dlM2tiGTbz1/fC8XZhicb+ZsQQbSkZO0jMaFpkrtFnzQtNI904oYIZmxGIgxv6Ey2rD8n69gZkeQqxkrTAveyTEDqlub1sp0yZUUdY9NflyCZMBR6YRaPJjuKjpN7YTFOb3m6pe2iq4Hh8bj4KXpmntg/205ZHdRz+BtDDwAsa5zbQFc5kA30Kowh9bsy3GqPNFpENuclYdzEdacqA+Rx2BtqNMY0bhhT5NcTj+eYiuyqi6Le390GUAcPeOzPPNUi3MMOBVcsnD27p5yWUPNRXkgvAxeSns2uwl7o6x9HjwD3wWU+DHdcUCmsyeaPNKrISMmljyBpi+DmuNIfCAjfgOUjX1wmM86xyiL39noH1T5g/VMZglUdJb2Heh4QrosEXvRU5jkAXywOf9Dd4jotUHxn8CZxaVTfRcLgyPlQcBtSRj1g0nxKHxZ4jA/X3313NqTbu1f+rYKPWbUTZ+YiiJLHNo6PF8MCuqouVSUK7cV7sJQjJ+wpV21qxQTyAMUjZLI0xt/rS/J3VH/CABhvwNVmDKGvL4TeTtgHpUbYLQrKDX4NzmGbYNTy4CzJQZnn7BrX9CSKpVx+5VQaX36NFVMbqrDN8DWJ4D7J8lTyC+Le3H3/58PHtm5MIBhn2G4ju37552UZx9reQzNsgjpOcdP23tw95vvvb+/cZqTF7t4VhmmTJff4uTLbvg3XyHmH96f2HD+/BevueLV7BaqH88u81SpatO2ELqIPTapz/XgTk0/cYMrzx638AjtPqEb4B929kcuTX92zBXwW8hZvw21uIKUtmI3nqkniXBjh4R4xzAdKyt2+wuMGXQhuR814JX56WlhXET0EaPgRIEfkavJR3IH57+5dfjDE7h2ra0HnKu2BwyN14+UNgU3pcRXLD3uPotSQaVg1yB/tA6AMWJQNWguW0iNcRuEAzr7l2eA6jnF3M95Yp2/4xFbET/W8X8Rq8/Pb2f5OCf3tz8Z+3dNl/e0NG829vfnnzfxs3onOj054duvdW3bCY65HDs9eB8NN17VlsykxNQSdOKulp3QimuFNT6hXMhQvrY6YaYw1CuA0ivOqjXxlZvj/8FY0iFtK/vf2zhSAuT+cA0g+RlrMB+qxuscD9+RfjpYK4MitWuf+2DV7+uyloKcGp4B4Onf6ClK/VQ7G9i0kcLnugH2g87yKnAaBeeLEH8bU4dx2WK/5FX3KIucQQrOurbARmKpIPSxDX0Tnsx/E6SFETyOW45o6VG2LF6Uj8QrR1qWL/jCd2tECHkTsot2/Mk/UWxk1wfA+ANeNUQVPdhhq7fX2LvyRbcO24uHT9Ev0uMpx7ogcyUg6Kfht7EkXJc2OaB08QPDstYCe7XZo8gTV+5S/eLIuty3hfJblXvBqM3MNnOuvYPl+QVUS6VXISOq3/nP+pPdTysfA+RYK4uA/CvEhBilaE/AppPK1+4KuWz4hlfGNeZJ/hfb4IUietqMZwX0+r2GHf8geQXne87exaVscia5ZmtXj88IuFyCnwximHIV6qT9Zrpkqn5l9kn5LnOEoCN6W1wnAbmu9xVE7CGs6pZ4jo5Sz5ds/hWW0GK5Czlx1MyQ72U/AqQ9Ta/VWAJIYIAXTn7i9BtgyQ5gB8jGoXyXw7z5aX7ed1iIU6hp8aONmkANC6lk2/OkDls2MeNA4cALEK8eMmTyqQTnweF3lH41030Xk8IHai87jY+vD5YPOWj4ssO0eDWh82Oill6/JQM4hqtMUDPiezMQRpNp0KQulCgbPMiYRM6Er7QUUKCw4TEz+hKYbASt9bx81MnoSPnsx62MRC8E6eAojKwojCdDDbCNtotXrB2Ft/L5Pnsq/Vg2Juw4B0eHj/Sva950lat+8UoG2RC+xpED6S20T4tNbxIAJv0TDeRUnD7qsJDoNCli80MnBbbH0MTIkXvPjCIx0H6woKAv+qKGJznPm0eD0t8rzdq1tOGZz7J8weIpjl7oDVXI4A4kskmDsmVBu8BdK3CRQM3ezCNID3peNbtB62gmqbsSAvTg1Ux3KHcILIuiNaZxlUHU0cwBXcgh6jtin2Wbz2iFybms7iHKSZMy9W0quDCgZmoErCjVon2i+sICjnrpPMR4snyHIq6vb2DsZkxzMos6L216eDWXXJzaUXZRTjwajd3aZ4h/8J1wOifxmWNs2q5FvmNMB+BY6vA0g/p6F1YFSHVXwmB6HCzsEnkL7igTO3rnRLu9hWaGc/83Z0S7u04zTIQLWCOtsCGqyvIMiKFBBHRr9udE0VJ9shnUSaavCPblUWRsfSxaaMkSCwfLla+ysPHpBinyoflpgOICaDT7zlQ1Iad4J0CB/Gxn3oMFwaeg/6P1oc9Nc0cjd9f8+AHz8quVeWd92grspegmhazuio527qQaVseECqjrGyRVLskhi74Dst8xyKzOhh66VHTojJKujGqC0OXroNTOfagkcc/OVwBY+NhxF2BjIF1uIWz44sp0mONDDvbkv4ZorviVKznR/fpaPHUccD0M+xzDUkPiQW/uF1QRcFHzuhLeG/gEsPOv5X2SopLwmwyFZm2grjW/egQEfV0XPsQzr8TRBveszydl7antz8PJudZuicNRezxKH5eYuIRC6H/YDg+atALdMQsvq+46V0OhB9p+rNKYyDtDkPRFS7Ix/sFic0gBinR/KYT3CQnMMIxH2K1J9sHAevwLP+DDO9Z3BgLDPtva/h1IoBZamxHafasPKvt+0t29Q9s7A+NyVdR44l7U0RATq+tQfVfLkDg9tYqkheVSxA12sbldOZD7A23uEqoUMKSVH1bDc16LXU79lqqCjg8p3E0nPMN3hNYYmu74he6alOFD57ydMAR5sYUm+iz5AORKT12nQswjwskihJv4CX6vEMv+Dzi/RgqkodmLlxYl1KYujRqL8t6dSAi+wcbSmL9oLJ+NtcUw6kr0cdudAHF9IUNW9Dt/QfhhsPkA0HOXvxbnqn6H48fPB7+HA8MOht3f4dGBzt6VKcudjT9Q/765jK1cNBh7Hu0O+KGmrBTUk3vWPXCULrb1pfZHUIhEPwajVm0wPjz88FbCoqYvh7ASCBvIdYDJm7sKW9Ryk217bOtlR0LG+o7ft7HjSYGuw8SbeBY4SjGmsZtLEp5xXlx9N935P7exhBZ22XXAx1UoU8LOAXWWn1Pwk7Mfes3A78Hh9cBlkuXQ6sEL1Kb9y8y2QDY09+mRivviqsAWlyOkIHADdb1TkAl22FKB65WXN4BP32aC+ZwmeY9nbFJPG1vc5Jb2DC5dFuYifbXRC/esISnf7paMB1Qac5guBxKNYnGIcW23+muEtLFtSteMdVnMynDz7BPnoB+y+4u04yHE3FzlFKoAI9JDEQRwmzi51YR1Oaev3T33CI3jTcW+nZa4f9YGGHJaaxrFpanfRQAuTjvtfqObkEmFgXWdJ7meOjKd+tHlIA9PH/ZIqPpghIYchgO4U1/BE4qcKziklsbXbUnvTdtz7/KHN/Dmcw3h6V2MSIemW4rUE4hFZMDoRBhtMUJ1yb7u5S8ASD3rdVLC4qTSgUtfn0NEo2WCc8EBa9DOJNgSPCGfNoW9KJSYWno5yk0zNmJOv+DYnB2WRpV/QSRbrCWiiiBOhN6TZQsy/I9kk2V2/eWd5mPnoM+D9bHmObWIuXA5Gzg6zFNY0WRUTuzKhPRM2Pvci52RIMsOE7j4LNxRY1Hd9S6qWNuYPtTX5Y9xqH1WlKH+dljoMH34BM8Czm3s67yfWbmp69TG4TpaUGFzrA26k+OFhzsr2Oig2UBf3UPEhNilDO9g7HL1fgOTugp+Em51CPGjh5HsgPFI4D4gfJiwSep3L7R9qnzEN/PW4waljtqyBJFJ3E2fPBuJjhDln4XZNS3u15diKxfoDlR5K7vREx9DUiRLQD4ZrJl3l/3FO6cVUyz8+puJcl2lu0HbKsfi5AliMtFs+RORzSzVMDGf7okL4bfyCyoH8v+Je/mCvMnt7Y8eIAi0AqvscYErbX0nCdXWBr/1XCP4M4r6qGzkVxAukWZjgExg0IsaQ9XOZ3WYcGmUzN1Xk3YO2xPnvBVA2ikyJ/wHQNiTJwUOM++c0hf96k9WhdUFdKPMJWktMz+jfMW6vkEfjZRhK4kzAEWeYPlPh/oAF2uiigPenOk7TYHtBZ/irZwdB8elXF3IJjTD25tZ6L1NMXrnUuGNqE4d23q4FkfhDuOJAJQjpkzqJVsT2fIHgccc2OIdBK/1e17dAi2tJVKYmdjFE/XN8sx5dXcCsc48hXKJIht0QjocAcN+v7KYEOSfh8TpNiZymBqrLDuoRavRXi+YTiqlp1nOayD4GC555IqTqKlUEsnPspnsi0PBAZtRfi4dDYbQqjekm8w2Ba0hePlyAJntf4Ieqos/uxf+he9HcNFODYGOaav3OcALeL0KQkvr9UsC2x7JYPrCpMs0eo8u6e5xgeTZSsIk1BHL56u2hdA94E7fFtT3Dxv1rPyu5xlxu1fwS5b2GGNu05mgvRRRxGqKma5PiznSSuKzt7GaeyFa6sCXs/Ug87lY7T00o2jNPDqrJRe4YqMpis5pV1xBgS/BCvDUF0DsDQNJXXPDSB5TUPTe0K38/VMsIngzNi8y7soLUQ0TFYFUhTL5C2sx74VY0b8Byk6+sELXDZT5ACxFqOcRMfQPiYFPlJnqfwrsiB710jV0H2n1tPsYUqJUDi4Wfqe+YndFyj9e+89JF4xOFtDH79JAVIjizQ+Hf1FKthRyi0h5DbQOAmeVNMuf45hsLOHsFaRjrnli6envxEPMJgZy87mJKd09ckzh8GwP0HCPz0nebLTxAJt/wTuGtflLfz12xgqpCHX5Jo7WmseHCPjECBnwbxo7etFIPrbYrRuBcL35B1nCnPsBd3gacFqZLQRCnwGcMUO+agCfGv8inrNIizIOy+jj0IvDd2k1VwA7LCU9zYRbDDF6b9E4cH9thqtO9sdCL/Tb8ucNkM+DanXgfQl7M5E0XKC00rSLxXwUEii9JkOIity0Mw3vmeWdA7ghuwDWBM+aFbOH5/CfA7o9X+9SrBlvewE3TI42lIvfH7niH1/QtEcvlg4hNO/pIkKWpee1XMzedqhDAln+E90ecPkHXqrpkPXlvSafy+Z2D9E+YPlizEFHduSifIgneLypjMeiAMWmss1Cij5driaq4Ex+VMsCa1+3nQwJa8i6xuKrlqFTgqKDUY2n3tPO4JblBndxBrAr6UsQbR37WQJYix6uyrhSWcv+Z9BVlGXYx1fCejHRGim02m1pq5vBxQ3JimP15dVSZU166nfVnz70VQDYS9rP4ew5w8Dzf0iWJT0eAHiGP0ZpSeDH3gWe+XyvV6aJJ1axuadoOdyvk/jfuUPMdREqyd4w1dZDWUF8XoErF4nIEa0+kNeiz1fwK4ebBSC3VqOC3idQQsn7mXivYFvmvph0fNlv0rHMPjkJb9SRboKyoSitsdy9pZLmleH5y58khbNw/LyjO5Y3FJVCf/VIJwGkQBfjrARX3LBnec8bkJ83sYQNs/LF5eY8sP8O4aPqvZHs5TuhNK8lUahI8w3ng85iNubcMqJeSsDvg6TPwEIvgEUp2nFOfydFY9AQ7IitF0yeoKR1nSw/kUbzce3HpgoHvkRRrfgN9xQLpDGXb3G1GeBm5y/ceH3ekGBFkSnydpySt+lPSK4wDZ/2rs921AdV0QjK4SMfGQXR81ub+/Snw5sqserGbj75o/ekALCh8Xv+bibWKwQCbEm2cRpAe1SLpLy+sgrRQHJ8tTaReyO2aly7q9Et0Osvvx6uTyf+Jjj+HuQ6DZCVLE/ti4P9h+2sfquXdirhr55Q7RsHaLa8bxQGTexNNCTNtvu67DrfZeRYnmNn/xDYhzGCFyOwb+LeNnV+RzDaE9cGB4FUEPZAKIu+iL92YTTH4SRjkQFtmbUaiEyirYHDDlDZ9+NiXejyCFSNdpeBjtIu9gHBySxHssTGiq5YaZQ/UrxTaP8gRxcR+E+J5PirZVkht8rrVYq81arzaQdg2F/hOuhwP/MqzfQ5ABQnn7Y0CjavCPblU2byRkGdzEaAZCwpQXPe9QfbAwLdWHJThcoMVVkk5pl71/vd3D/m/m7eiWdmnHReb+MMXBbfzRehA++tiQkz3NtyL/dk8gSSeHiIInWVkPZDl15a/6/4Yut18DYnhrGfCW1hsbbvxgbwVz2OfwCM4B5dEn6h0cZ4f53wuYujkRUspfnKdJ5G7+lCr+I/DJx95hMZ3JhzaFTyIYeH+HwOOu0ckb2FVMl/fxDmOgJV20loJCWskSfcrx6ThW62giiZJ0+XsRpCC72dz5bme5c1j/Ew0TfcDr/dCjdLMaoaKLDCEtQQRCR+93D8uMF5buX3L4tpOK3FfaSxg/4tMwkVI2H2ej+n7CgcjVujte78h9b69xfE8jp2nBw3i5/HIK46ANfYQQ78gHS5kZ54hUGMpLG89hBGJfAh0/mRZnvm4jXeCQIwPsM1eIy0p73mHMqqnPZv2FU8ePgtp7fpSlfdiznFx7PDpY6J+r4TE4EHb2cJgjWCR4ke6Mucyisxjnd9LFliAsUmDYPi3TPP3ejjfT82WySRrL9iCmDkOcL/k2Ok3Wr75CxpXra20jvwL5c5I+uo2N2TSuzDUHMpvLPrqxSokxiFwwXrz0tYwHsAVkI3R3MC+lkz75llOm46qD2QkOJXs6yRh1OGY5DcLHi5gcr9BhJQ+EbXw4TE+r407uljzGfTbak2IFtmh1PhjL/SBrB37gFDWNi8jtDDyw+9cC0XSTpK/HMT7cMa7E3nGID3eICV1heGiHrD42DKgL5TugvocUAfvnP5GuancCPJyCehJGNyBMDiZY6cy3pQqDqPGZ4cU6MnCM0+aI7+mRI8Y0VETFxjuoD79Jm3eW9A1i4QNYFxFYBdnjgfCZP3+fJZp+8dopVpPWMaIm67tbwvNk9y0+S9PEKQAZfkt9mQdp7iGIAcY6i9eekJZFGIIs89UumlCW9n399b9+B+1AZqH1U8V+Xkz28PaIqeTWNwOBICtSUAWPOozh7l2SP9gsyeQ9GtSzZ6wF+Ua/wRyoeY5s/lTywHvTioc+IdFW+oMc2ejIRhaWyurV8D8K+/zFZqcof6m9i23DOrqOLNacc5lgAAOi6Ic8OU/SLRoyKgyDJ/hLuIWIH1YJ4Q+Dm1CCY63iLoLZw0DevOOdMfFgXl8z+5TgF8yQIo4G09WlRVv4IP4ptod4Gkt1yasj7uSHpGTE3Cw4q2QHw8nCtBkc75AQ+HX44gNhTHc3gfM02dqzYbe0233FxL4ZdFk3z9zi7p8g7IlsaKFz4MuYfqxG+B5m4LT4XWTVXvr0tXyp1hNY86CSC94YooDYAdCny+RQXAapHuFaLGw0LMCe+/5ovkY9R5YkBubDYMth9+m9e8OPFqDGRnkDH6LtLoCbQ9GJPR7KiNdcOzDs1z75tPe4AdZmL/LM4klI3tQ6EBYTvhzZneF/MbfRVHv/funRxda9P+K9vddJKoutpHvZM40NO6vXsCDLegW7DXApg5eZ081UfMcV3AdFlKOJTDgQlRrk7IdsKP9oboM2a+tpGJZSqjwQ5CPSq2rQum2gsXuzucGltaiMFXWLFvSuF/q9WWXxU7/YGT6IotcBJtkVeM4uAWbqA7Quijvn1c4oWUk1NmS4cRHXuFsCeFuZn7rxVhyFv/sE8aq4iSxsvsnmMYzU3wtQgHU53IcxO65TmKSOF8yxlbLnRMt8NcOgGseTxovNKvHe1FUyRENvwC56NWutAewQLV4sfCMilcY35OyVGL/yFUdmSSFw8snEIF5eYFLoVhpCv1va7RxiWH1q8QDCx6Q4uHCDvULDxuV7loE0yVOSOP91eW3NB+ZFtgpezl4A1VMbGARS35d025+MGCx08FsA9lPzkKJEcp2zOCHiIbw/BOIsMo5xFP3OQIOnRsMixe8IXQevmCCH9dQ52zvz2cMjeHh7dva+P2yvD4QdFq9hBLovYViNAIa5BmifvXb1BMuDiKC5afP4JpLGo9aj3dfzcPXkIob4AMLyxfRu6dlHRSEeyvBfJFYsqftA5pvwvqvG8HH0uF2g3QTaJa6dIlVLrpH6adCfbRpEPNPlkQT8tOxPjJHZRj9rWjpUIz96a6R1rAOD1TEi86PcSB7IXL2ug1h9cFmKGpSP4+869XeMaZJlSDePjiPoZwQNFrpDcSBFPbkETyByUwCXD0ma1x72XpywzlF2XUAt49uucj7w7XowpMur1ssNiEK+grAjTgVpClJfeJPcktKK5J6C3wtyW9Jl+1SGv/0SZH3xsDzdslqC8oreYUieQTyN9iJAFGUn/6OM5QxjwpHrawdC/9LfXjQKdotlHEbFGlzES4hgg2ZHZ3e2VLuLooTc2Yws8z216ucK5vyFaiskb2fsX0EeVPcmOFXFGtDttTMxpj/aefRGvAFIy0pPsp9wvQFOZ5klwn8lsZ8+lnA/02BXaQ2StuljIZX7uTMG9r08TbCIdZyXHry1SHfwS+vmFNd/JQpmxE3DZQGuMW75lUCYv65LkL9/5ehUZrbBoIq6mY7p9hvucdqiBk0wHk0HA4jpYFZV7etY0s03a0FbcoiRJG4taHODlpaHZL3AXbWbnF0g7SlaVmg1qoIazSjLAThegW27YjhZm5JDjHBt7qjtMBZjW0PojmpVldWoduqyM+y4jiTdfLMWtCWHGMlrkG5hhp1Lyqi2dARem2Fl8bQnLVWv1RgLKzaUijyElxv0TZ/sWK8qPuQ8dh1108nsPNozmNHzH91qla/+w8q4zYSW6kiq7Kgyu1k8rkojbUDdfqs2lIUHHNEb8ATB8xcQ7e6LKLZcgD2YvnS8XrwMR9lh6wGpizs15WeQVRQfwGH4NEo2dbyTQx3Lqn9aUZS07HSIZtdJZuFA2ZYcYpLia4N/lLH0Zjj0zRx4EC5ywIbF07z1WZYcRIInUfQjwUd/k74iMYLkRh09ibNnm9N0uuzgy+jhjsC0bwf6kw3lOHkTDTg0dBsc1+rt3VIP+AfIiLe0B6irxBBJxusnWZaEkIwsswsoHy++rf5nuP4sXr/BOxGUvUqvWrIE0f275tvXIsrhLoIhqvm3tx/esjPlW1y6Wb/B/tr4vsoiyMJgzVMBtX4tbUGnwd2GMEnd9vwPrhriBFOGjVkkcZanAaIsP71hHMJdEDEUYPJpCgLcuQaRTfkEdvhUK87FXdWpkXqEmq+4wWeo3UeHX99TfGPGTkJrPTeYolH8o7CTiELzYad2kZiEnZpDJY9y6Zd37z5wY9ciNceFNFT7cd9livg0VDb8E0uT5ijsZIdIjh0HquZDkN0ukyIN5RxRl+2MY/txFOHCHUGL2jIwbzVdHoG51EfukjrVx7KTs9kqSLGDiRdxccBsZjTkU7CZwjVjMjarlte9kmUilY1LOxhJZqKezVGQNRzWI8amV8Sn568RVXEb9lIetY3KXfWPKiANtsyyZ0zzlF1Ug4XN6aQfjAyje2Uix6Y2ItyikYdPIH1d4Xs/0rGlM3UGtZNgtAc0kIa++ELa1WF4w2hdo9o2NU80WpzEq3deijnTaBE/HZBazvbIRCufDV/tjcVyQqYa32ZpZrWa2GiJgzreB8Rylo5ouKSr7cB1E/bdgNnpzT4YMSt27HCFvBOuAzqs0JE2SZg+CKsZj78fCWRcLV1gVry3NyvcDJht/JXOXLxNvNoxV1puAEKD+O5vecdE46Smi9AZaTZpFPYTX1CSN6vJMQgLMiQYgRM1LmhJKta5kTUTnuw71hGMumSc/xBcaMIFk7Gf/GrfWHyXo30KatcT6iq4FTZ9XjxGt7fLW92UveepTncMeGkyVqrv9Xlkop79IxM1iyA13/adAYRXUWc+9AqmdZ/Ds2MG8yk6Ikt0GjedN1x9N7F5Xa9Ptf7/27uyHrdxJPxXFvMHgnnvXaBzboBck+7MPApqm+0W4rYaspxjf/1K1MWjqliSRVJy8hKkzSLr4EeySJFVXQ19euh/DLLImK/BIVE8zzOdwgFQRb59R1jS72MjIcvhII+YIC4WV2P6OAKs8JgIoVH1PNvvK48ejgcxCVOuS7xj5r31ooHFSzd+fDS0YbESWImFLl5GLC9NlL7sYhavTqMxi1c0XDUx1G/KQr6aPEqHKOkC56Pg6gnUHh1+DAIuSHJdHpDAC8xgg/mBGagWh6+aDiEK1rqn4evAVyetJsPw4+px1KuyCux0L8fXgZ1OWk2G4cfVY6dXZRXYqZ+8rwM3taT6x1r5w+rxItVYDVaa8AiJLfTYnvKIkkZGS4LuZz/f87m9OANaWkU43GryeHgx49qpscecJ4xmbb0/rcIw6KKiFlLy6YR+EGiaJAQa2VEcMXyywjYuAKyur/oYEKiO/wVBOhogsQHqiBgZ+rxz1Ay6qGMu1wAJCL6gB15TAbc4sK1oBlwi6ELNeGcDL+5M9+pHncYm3V+fyoe6xY0sNJbkRc94lAaaXDTh6mdAUr0xgIyGxdd5cXqUh7JzAw//vtjz1FpSfl09LgZd1gMCmecrNAqa5GIWDNqfLwMHQAK1RQMhkf82KarJztOyWA+d1/4cZCGSDG0RPEEHM4xH8LAYDXItYQoB5B7fYz7xEmHS4fdl2BlHki/A+cDEPqfrfEIouPcysl+D+i9SrGggkmGUPVySo3wXLdeqbKT9Ze134xo1OIx0g0fu/VVsmsOCJqSby0dNdA+3C8/05ZjuxH+zSpriZwLHlVpoGC5VclAeneBiAnFpanH4Ro/EBWINGCvj54hfAGL8OSUWvqSEcRc+eSNuyYjqpbQl8HgVLhh2BkXWBJjlxzCJA5uA8UrGASd2lJI32X35Ii22yadTnRrmKLb/ZOUDosP0bnQ8S+qk0BobfvQ3k7D76UxQ9LqwMAF2RXSIaL4OrNDULvU010CSg/IEcHpGIWAmtI32e7qKy8LaF3UoLNQbWhLUgvlIk3Gm9Whct+lDXorl+9m1lLYEza/rxtCgyPL97M/ie4X2T3nVwLGbnFZxPgkIrokDlq/+7BLSahUnmRDOZl0EHe74cuASbBqaihWtW+IG9qvzGCx6JeuEtIL1ecwrEQxAvR7LX8Y6UeWJESz31F7zjBzrwEEv8BZnlN2xM4GIfSzRV4j7kbYLTRkukM3vz/R/GEaP6K2Up+JQJ9MRHu4ae/KHFZEN10YruQAfWNVnFd5v/4An/KzyOzwWOr3E9G1zKciLtGhcluenw3YvyM8T7WcVhRL44qWWjoKJKZHhkpiFPr9oYbbwAyBLNw7PQcTlQGgVq9QSYBZyrZqErujLlYWt5X+DXwKwAn6Rn4Sr2B/mW/43T2KT3bevD6/LssjuTqVYAcZI+SG5MMq1o49Wbw1QhEX/+FT/mXD0UqceNx54QPA1NRK6MqTsCP2cRE2H0LkzKKUsazMBNrDQyZWvrW/g/JJz89lgiz5hUxrExnznOtymO3cMs6V4EYPMkCxq6YV4C4pKIzyEiOHHAHA5Iu7QfQp05q8AMW6Hx0RZRR4daH+nRZYeyn5ufZE/3mUHSZjgKePV9zAqkfYORisYdSzolg2CFknu54kXaiCvaKMU5Uihir1k/K1mb754oIZfd8/FaOytOgOef52qkqqXvhwyHKMakYoFveAip0fcQIuGnir20vC33jmRA8mLnf3WPOV1kHMfSVqEQJeHPoZcLBqDHjvOAMvFnDWaSvyd7k89SGkN/eAiLHKluhwxW0KfGJ6EJz9QbrQdgWezgdiwju5OclyGdTuGq/P+kpv08WkvXubfD/s8xZ8I9wTa+Uv/48LRAKsXHwm68aNh4TYTRaXfRmhx2J33rSQRN/66xISXVayXXpNF+fUigq0P+nCYqdItAFbL31LGAVHAbeM4/CxkozhcR20vEi8fSJbk424zrw9Ytkocplp3LghmswLM6QL9RgnNdHH46Pdyr7N9Wce79f68IdQ0ZWhGC2kRX86zCaeu/Nkt6jOK5+nm69vDTZlvvt6c7o6bImvugK7iNQUivJ4DGqNZ/dsKTLMxjv/icLd8z215oAu4Pp+Dudir9PX9fbavfhFJoLjzPUO9oeHXtT8+HVThMIv9qF2mSfC6yOFQsHjb6SgubHWydVrFulTp960C9PsKqOlOJK+L/DEcSnTmxhqnF60eH4ZCHI5qZywFILf5b3gsBB5DV8RzMSq/8ltl8nf5LlH+X3cU7mwYdJqvYJYF8XAVrpg0vnwXymZ+gKYqxfJidBEXAbVVbNbjoSrkvDUWTtGnrL9O4iS2rx7TbJ/If683dHYdjUjLHqwVBMGUIrxxB0X53QumcFP5wZWqEYedKl+8sE8PYvM1P5k35Kyf8XnLotQmMLs0TDJ3UC1aNJ934Bz29ANIREPWnGdWjRjnbnMqKo13n9KfMtbq20NWtztTyFXclTcZGwHrzMJ1x1G19GHxVHpiMfjoIjfTGs3Vz94iJYJKkaL5DQk9DSDzgnJMhGizbjR8vss36T77n9h2Mibv0sPuZO2Yld7vCdTuHn4MgkBLbF0Yu9QL6mBT+UGbrROHaSdhRHzNvbn0d7/T3Fdexn5yNfvI9uveZ/EtE9//K/ZP96f9oQ4yWnfJ0Lg8Ue8xVf1e1m7XbZ5g9Z2wa9sA0deXjb5yZcsBfHEGiBg33M/CXKdRkCNYTo+M4h0Th1rBnyisNDK806NBat47A60yS0eTVjnenZV9vnuRP8qNInNWU6qEnshU1trdFPX3C5quUFOPYhcYRvX/P+XHEp+POgqrD5sfw1x5Gg+lmaapXtEFAqiTLRqQPojvx5HzkVIl9Hykslab1H6/oPkINfUodoFhVP+/vo+Mz0cdhdWHAW+lT4DSTPNRr+gCAdTJFs/1zvf7v/MyO+w+i01ebNlbP6Ne8C2fyV/zy63CC5qjaMuP4hkDX/UP14fjd1EQ+7mexurW7ucwL2nOAdlcm75B6aWCaxBxGScIk46vop5Z8c8s1j11zXSAERxQ7V/OE6j4j5PH4ml9z1nGgyjsI5ZXMgBMPaqqGqLozvrzrXidFcfyZVqmd+nR/thX17oRJRBI5o9/NaVowJ6bzYN4TP/9x/Yur3o+vbNj/VjTkM7N/QrUksBdBZLKXWuspBzRmLJwmeMsSUbO5l9mx/YintX+UAQxGEodHF6kpdjJOwEWh6EI4jCUukyUbcpTISATdSWgibpCXg8QXAwCoj+Slih5n8q8ROz+qdM4ZoVotqxoV2lUVK9phC4RtLDYNm+tGGSqUfCsTaDGoqDs3VGxDd5WfJ8eTvep7CtiJtKpKDlUSrYsDiHc3HUK10A1HUt7vJoU4LA1iZhsCX40IyeH/kmmxaAvgdrvC10K1AMKnt+6ElD8rtDRfJeM870oH/ItwMUkgJiZNC6eZTVsKuh+q/wjaMwb5SBHncTBcPhQYfEaiiA2Q6mDw3B1yeIwFEEchlIXh/rujrgpC7mTPTb5VQBuIBnIGaR0SDEcsVqchyKIW13qnh2V4xB7UlQKwblQKWfwQTjgbbOnmiagHDrdNMXUlNNQuHQQxWN2PFauendYY+tjkYC6WVQOzq9+VG7tId1fn8qHejvRZCNCpaDJIYnoGg7p5ItfZLArZRBfWXxMWANe0t7mT9kG49MWEoxaCg4njAnZfkvBaf9NkZ+eMCZtIcGppXBwau+nW0za36H22yKmG/ulfqXZXxJG/VidjHJkdUqHFG+y+8ptLLYOKWAySAqYkikFwZnmxutGZBFQytDuZG1MJeWHvIRmUqUMZdIUO5h8Ft8rhT/l2aE84h0GUkGMQUKG/4Vsu4YizOdibbA6QqTH9GKKE6vfPotqO3CoN4ACnIKNctiMGolTPTOrMKCiSQKraVLx9nJYCkNsV4fRU/s7JJ8kd6dHZ4a07UWSg7Yja0ySji3XGIm4fSrTsWEdKAuJ3pLlPD5kDhqMP1mJkIusN01evpCOcysjp8LY8xSGQDxJRiMFyTLANUtLPqLX2houj6gPdm57QX0R6Pn0pQ4OSrRhi4VSBvFQip0nBTl4Jtr+Dp8M5IxTV0nVgwxuvy9G2XBRelvVF7Ij78CtoVEO2kwncR14YJHf7PMPjBI8DsGIR5w03orHp30KjlSYzHXyOFAyPxUQEtgk1KcDNuduYcAZWxTU+sJl+0YcRDXMqMnRJgG3BhaV60x0s0fPA5Qy8Fx0KHYw+VLgTJQyiIlS7Jooqtrb017cpsev0EShFYMThUbhstsQlc+221AG2m0odo1GkR6rgfOPyHYPkItulIPjTyfhMXyZVbuIIzwN2SQEW4XKeSRXFOKwAU/P+yL4KK4r5ZyeOOZYgIY4Sxk1s5oRt4CJRSegzr0MUucYVyLmAKNcKYXHuULAZ9UEoKLYNRQOlg2Rc8F4fEqzHdSlQxG8QHSlrqNULViNfXSqFYNHpRqFcxzKnqVWYJMCHoUGEeObwTtRlqJwjBOMEPueANE6ZNFC8lgCaKXwFRSFwIUeOy6MDSObBsSTTTaWObYvwQhZYvD2ImgUB+BwCKGEj4kQ4pHiMOTgCcD7hKeHFLBYAzToxzudzKl2PVi3+IUfkwBWWadxobDIj8eq8T3O1SYBkWdROU0NLUroYsRZhKr/lchusSsB/b+u0LVHTH8Qt1K0UnB/qBK4WCGfrYgvVrxPVd1nE0IRm4T6/pJcPz3tM7G9zVv6TLi/IneVcdBZFDwZWnK3BPp9CPwGB0LnvmLxWRyrKVjerWXcIGk/K+MXVSwK6ut0S8ToCPPLsuMDOU3O+XSd1KTss8P+KhHvuz3/+72WmG7sUSbnBJp5EJ0MdGOlAAIAYMIApIRMADXj8k7/nM4+v1JLsSs8PQHDU8VZaaWYT8plZb+1se1rkWBXU3SqMT3s6lZGX1oMlVvk2DXXpL/NqhCD9117SvOau/JOQL86W/FEb99C7wvA6kaR+WpBV3GC+t3C41YffoYAPdSw5V+M+v09WaLfLZr5e9z0S2RF1G0arybltiQ37Q07W3NONVwp8469VAq7Pw/WBM1iF/o1z21a7AQ4IjjVZurzhZmnczhHYces5BM50Nxjlfk0zBjUmJXmn1IjmQV4dnEkTQJW8IkT4H2J1gj1YGTyYpvoL0PQpVanI5QBXqo0WhAvUKbiarra/To6TE2o6jatj4kUeXSjqj/jNGqq5va1LFJvzlYgE2jPgQiXC6Sb3+2CHhrJyuQDosk9bzyGUlmgEMDrzKwWhAq0IbDci5ncgwQk9zZQAptEP11LuuM10Z7J0e47vzKuNvwMS2pMP64iWjHOHYHGsEdiXgyIu2r8ysTqBCiLqLcUk6lP2JK+XcA8IKEHU0DP8hoTkK/txqveHiFTSpsk86trHIfLetijzOkqGqbDFdUJZ++lgKr3x+D9lwJi8sSJiR433vQ2XY681wVrQgawynwYAp8EceJZ+nEJZnie7ffVRNq3TBjBIPVnAhaGzlC6C840NI1rbdH6HALGO3ytAexx/XgzQI+Mh+wQgC3oCrha5gNsqQ/2uFqvSTysblrhPJQeb5rubTlpDpvIhwnM9/GyJvr2fbyq3dNwUlWbyIeq5gN2WXP48fzNVb7fk2rqBD5UVF+3N3sm6PX6NNWaB/ZJ0yKsnEpyppBWDT04QF8PefY/QUXzQoH6JZ9yY3gVCeWQ1/yNio4X+mRL0O0GsFUy+sDspsQdIV5F9wJnKUwpuEgTgvdJWM70SPTN4E24jB7GNAz3OjiaYpmIiqJBuqO8ij7QxIksIlsbFSFkvOn6OCGknQAqH0axAprIqsqv86grb3i69TXIvCms3VEdNIbvoU5UOVGjmyD6qjQOkbUYKoPIYGwUu7Zdcd6ebZsku7WhOVvQOL0pR6LaLDViFboZRQ88bmWgE8apCkg3/5GKFt5H1oKj90xVlJqbDAof05I/9aBoQ8lwvwK/yAFXIG4wnH2RA4ptpLVCxiqayTSt3Zl2ARMMj+/XRZijj5+E28AkmVdxK/bTUG+mA5RBfuKbtE00/5do/6p2EbeST9X+7CE9iu0/WfmgcLAVd1WZTR2trhlTTFZF44VNN4Q2bof2cTPAFWZSBKyJjnhWsLaZTPNF7Xe2ffRa884LsczTx3pzTIgKiYcJUY1TN9QDQ9CNVxGIKke6QiS9D8eIiKInG+GExZvHLM5x4a40LzrimKYL2IePCYNiXqXNkIY33S2ama73qvEIk6FdXEudcCbBwZrW+krGTpy6EepuJDm3fCbhmvZ8WhRIx4QHUvqZ6oDolu1IpoJWnnHAzehslHb+/vZ9bcIMwpmouUygEY6TO3cEdsYVdW+AJ1ExRj4cfrQd/Y6QojMYiBoZOLGPwRHdFMSGEaWdf98Y2gxkWFnGxW5HxfkNxIqbq7bGjOU6AUFE2Fok5i4IrgnNEPhx24VnEEareghgom0klO/caKWZj4Uw2VpgUy10BNiRIshbLji1t2nCjoehtqCWejEGcU8Fp3YqhWgDqLEMkxCho7mvLNlNEKfucz3AZITdVi06JnC2FxO7F3FObW9DdG3m1BNJTrKp1gRuICjnpTQFlctyrSaeANPw2ORYy7+JSHeSXdepPKk1z29cpBll3MkEZcs2Kd1OEKNw2tVid1KNw/E4pztCzIky+GzoN4BCcpM+Pu3FkAkBV9ygJFwXIx9D47YguRYCqtynYtDuxUIqI5Tug6TpN2etFBOyOp494hz1ibXLJpp/tfKvqnWs2Z6VuhdttIq3RXvqyewsZhllkIs2hZHJ3HEWP6Z6mLN5l0R006487hNe/MHpU8gjfGcdHyf5jvQxsiFuLpj5zEQMTFeV+YdnXBP1yT4S4rOgTTT/90ArYUlTE81FMvFuN3u4ENQ+Bgqa/eOmv+s9c8/rSTqS10X+SNmDIvdhEDgfSTuqyPQiZ5viNh9hCIV47WZQspokVoYTYFYgyIlxDmdgaUY7nVYFawdrY2aTUKAA6XzgIYzaSnaSRE8MY6uO0uJKQMlqpBZUEhrjAMDKvtLu//G0KhOuzoBpShIgiQpwlYZbl0AJlvelgYsrlQvdln0UxEzKMuUClp7eJHl7yMos3ROXK6kKuJLTLlbCSVxumrtYjsQs5xujuzxqs3LbBa3rSV2yJfhWKi+zzsRwMGraGncsGJgaV/DMQDBQep6mCWfGnSnmoNcn7+uSuR7Nsw61+ycr1UNSuwcv8sOxLNKsmh9qb7TXrwt+dJsnWH3i1GF+Xm5zT4igBG090VQb6l7UnTZjxm7SCv4cZXWjKlN5XONFG1BJLcKFm5aNBDjHOK9F/5gFkrE0Rx1ElpXzDNuFoQJxCBPS4rMDXUVQXMkgw+1/LemMbaEzW/SPKCDnjmyDSqZznmG7aF8gomBCWnx2PLEIipvpgdjropVWCFgF5mo7wFqLpFtqlghXCqUZzD6EKYMXVIqeVmtUTLS4RlGX4kkOmtMXmdZqYF+P7+6cbeT2L7cTN1B6+5Q5o/JXz5pGatNX/SyKvuzqWZOwrP2h+rPaulY7v/f5VuyP8terZ59PVe1H0fz1Uhyz3dDEVdXmQcjUikOjHc3bw33e7f8MiTqSrrjPuVym27RMr4syqwPWV8WbyvuUqfjkSU19fHYntm8PH0/l06msVBaPd3ttd3n1jOZ/9cyS+aq5hX6cQ4VKzKxSQXw8PD9l+20v9+t0fzR21FgTLyrrvxHV701fVoOzFLuffUsf8gOzodZ8L8WTOGyrQdcloT5+PNyk38QU2b4cxTuxSzc/P9Whs+XBE9aIuyN0s1+9zNJdkT4e2zaG+tWfFYa3jz/+83+Vg9UoH/gHAA== + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.Designer.cs new file mode 100644 index 0000000000..eaf7caaa90 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class V222 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(V222)); + + string IMigrationMetadata.Id + { + get { return "201505272236124_V222"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.cs b/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.cs new file mode 100644 index 0000000000..0798205fb5 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.cs @@ -0,0 +1,68 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class V222 : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AlterColumn("dbo.Customer", "SystemName", c => c.String(maxLength: 500)); + CreateIndex("dbo.Product", "Deleted"); + CreateIndex("dbo.Category", "Deleted"); + CreateIndex("dbo.Manufacturer", "Deleted"); + CreateIndex("dbo.Customer", "Deleted"); + CreateIndex("dbo.Customer", "SystemName"); + CreateIndex("dbo.Order", "Deleted"); + } + + public override void Down() + { + DropIndex("dbo.Order", new[] { "Deleted" }); + DropIndex("dbo.Customer", new[] { "SystemName" }); + DropIndex("dbo.Customer", new[] { "Deleted" }); + DropIndex("dbo.Manufacturer", new[] { "Deleted" }); + DropIndex("dbo.Category", new[] { "Deleted" }); + DropIndex("dbo.Product", new[] { "Deleted" }); + AlterColumn("dbo.Customer", "SystemName", c => c.String()); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Products.Availability.IsNotActive", + "Not in assortment", + "Nicht im Sortiment"); + + builder.AddOrUpdate("Address.Fields.Required.Hint", + "* Input elements with asterisk are required and have to be filled out.", + "* Eingabefelder mit Sternchen sind Pflichfelder und mssen ausgefllt werden."); + + builder.AddOrUpdate("Admin.Products.BasePrice.Hint", + "Please keep in mind, the base price is depending on several factors and will therefore only be calculated reliable in the front end.", + "Bitte beachten Sie, dass der tatschliche Grundpreis von verschiedenen Faktoren abhngig ist und erst im Shop zuverlssig berechnet werden kann."); + + builder.AddOrUpdate("Admin.Help.Forums", + "Community", + "Community"); + + builder.AddOrUpdate("Admin.Help.Documentation", + "Documentation", + "Dokumentation"); + + builder.AddOrUpdate("Admin.Common.About", + "About SmartStore.NET", + "ber SmartStore.NET"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.resx b/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.resx new file mode 100644 index 0000000000..671dfc5bbc --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201505272236124_V222.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.Designer.cs new file mode 100644 index 0000000000..387e91d128 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class AclRecordCustomerRole : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(AclRecordCustomerRole)); + + string IMigrationMetadata.Id + { + get { return "201506181858349_AclRecordCustomerRole"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs new file mode 100644 index 0000000000..dbc7b21d2b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.cs @@ -0,0 +1,153 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class AclRecordCustomerRole : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateIndex("dbo.AclRecord", "CustomerRoleId"); + AddForeignKey("dbo.AclRecord", "CustomerRoleId", "dbo.CustomerRole", "Id", cascadeDelete: true); + } + + public override void Down() + { + DropForeignKey("dbo.AclRecord", "CustomerRoleId", "dbo.CustomerRole"); + DropIndex("dbo.AclRecord", new[] { "CustomerRoleId" }); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Error.PreProcessPayment", + "Unfortunately the selected payment method caused an error. Please correct your entries, try it again or select another payment method.", + "Die gewhlte Zahlungsart verursachte leider einen Fehler. Bitte korrigieren Sie Ihre Eingaben, versuchen Sie es erneut oder whlen Sie eine andere Zahlungsart."); + + builder.AddOrUpdate("Admin.Configuration.Category.Acl.AssignToSubCategoriesAndProducts", + "Transfer this ACL configuration to children", + "Diese Konfiguration fr Kindelemente bernehmen"); + + builder.AddOrUpdate("Admin.Configuration.Category.Acl.AssignToSubCategoriesAndProducts.Hint", + @"This function assigns the ACL configuration of this category to all subcategories and products included in this category.
+ Please keep in mind you have to save changes in the ACL configuration before you can assign them to all subcategories and products.
+ Attention: Please keep in mind that existing ACL records will be deleted.", + @"Diese Funktion bernimmt die Zugriffsrecht-Konfiguration dieser Warengruppe fr alle Unterwarengruppen und Produkte.
+ Bitte beachten Sie, dass die nderungen der Zugriffsrechte zunchst gespeichert werden mssen, bevor diese fr Unterkategorien und Produkte bernommen werden knnen.
+ Vorsicht: Bitte beachten Sie, dass vorhandene Zugriffsrechte berschrieben bzw. gelscht werden."); + + builder.AddOrUpdate("Admin.Configuration.Category.Stores.AssignToSubCategoriesAndProducts", + "Transfer this store configuration to children", + "Diese Konfiguration fr Kindelemente bernehmen"); + + builder.AddOrUpdate("Admin.Configuration.Category.Stores.AssignToSubCategoriesAndProducts.Hint", + @"This function assigns the store configuration of this category to all subcategories and products included in this category.
+ Please keep in mind you have to save changes in the store configuration before you can assign them to all subcategories and products.
+ Attention: Please keep in mind that existing store mappings will be deleted.", + @"Diese Funktion bernimmt die Shop-Konfiguration dieser Warengruppe fr alle Unterwarengruppen und Produkte.
+ Bitte beachten Sie, dass die nderungen an der Store-Konfiguration zunchst gespeichert werden mssen, bevor diese fr Unterkategorien und Produkte bernommen werden knnen.
+ Vorsicht: Bitte beachten Sie, dass vorhandene Store-Konfiguration berschrieben bzw. gelscht werden."); + + builder.AddOrUpdate("Admin.Configuration.Acl.NoRolesDefined", + "No customer roles defined", + "Es sind keine Kundengruppen definiert"); + + builder.AddOrUpdate("Admin.Orders.Fields.OrderGuid", + "Order reference number", + "Bestellreferenznummer", + "The internal order reference number. In contrast to the order number it already exists during checkout that is before order creation.", + "Die interne Bestellreferenznummer. Im Gegensatz zur Auftragsnummer existiert diese bereits im Kassenbereich, d.h. vor der eigentlichen Erstelllung des Auftrags."); + + builder.AddOrUpdate("Admin.Configuration.Payment.CannotActivatePaymentMethod") + .Value("de", "Das Plugin erlaubt keine Aktivierung dieser Zahlungsart."); + + builder.AddOrUpdate("Admin.Orders.Fields.PaymentMethod") + .Value("de", "Zahlungsart"); + + builder.AddOrUpdate("Admin.Orders.Fields.PaymentMethod.Hint") + .Value("de", "Die Zahlungsart fr diese Transaktion"); + + builder.AddOrUpdate("Admin.System.Warnings.PaymentMethods.NoActive") + .Value("de", "Es existieren keine aktiven Zahlungsarten."); + + builder.AddOrUpdate("Admin.System.Warnings.PaymentMethods.OK") + .Value("de", "Die Zahlungsarten sind OK."); + + builder.AddOrUpdate("Checkout.NoPaymentMethods") + .Value("de", "Es sind keine Zahlungsarten verfgbar."); + + builder.AddOrUpdate("Checkout.PaymentMethod") + .Value("de", "Zahlungsarten"); + + builder.AddOrUpdate("Order.PaymentMethod") + .Value("de", "Zahlungsart"); + + builder.AddOrUpdate("Admin.Configuration.Payment.CannotActivatePaymentMethod") + .Value("de", "Das Plugin erlaubt keine Aktivierung dieser Zahlungsart."); + + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportCapture", + "Supports capture", + "Buchung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportPartiallyRefund", + "Supports partial refund", + "Teilerstattung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportRefund", + "Supports refund", + "Erstattung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.SupportVoid", + "Supports void", + "Stornierung mglich"); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.Fields.RecurringPaymentType", + "Recurring payments", + "Wiederkehrende Zahlungen"); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturersOnHomepage", + "Show manufacturers on homepage", + "Zeige Hersteller auf der Homepage", + "Specifies whether manufacturers are displayed on the homepage.", + "Legt fest, ob Hersteller auf der Homepage angezeigt werden."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturerPictures", + "Show manufacturer pictures on homepage", + "Zeige Herstellerbilder auf der Homepage", + "Specifies whether manufacturers are displayed as images or textual links on the homepage.", + "Legt fest, ob Hersteller auf der Homepage als Bilder oder textuelle Links angezeigt werden."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNumberEnabled", + "Customers can enter a customer number", + "Kunden knnen Kundennummer hinterlegen", + "Specifies whether customers can enter a customer number.", + "Legt fest, ob Kunden eine Kundennummer hinterlegen knnen."); + + builder.AddOrUpdate("Account.Fields.CustomerNumber", + "Customer number", + "Kundennummer"); + + builder.AddOrUpdate("Admin.Configuration.Settings.Tax.VatRequired", + "Customers must enter a VATIN", + "Kunden mssen eine Steuernummer angeben", + "Specifies whether customers must enter a VAT identification number.", + "Legt fest, ob Kunden bei der Registrierung eine Steuernummer angeben mssen."); + + builder.AddOrUpdate("Account.Fields.Vat.Required", + "Please enter your VATIN", + "Bitte geben Sie Ihre Steuernummer an"); + + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.resx b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.resx new file mode 100644 index 0000000000..de6d366a44 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506181858349_AclRecordCustomerRole.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.Designer.cs new file mode 100644 index 0000000000..e5e31c1659 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class PaymentShippingRestrictions : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PaymentShippingRestrictions)); + + string IMigrationMetadata.Id + { + get { return "201506211043073_PaymentShippingRestrictions"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs new file mode 100644 index 0000000000..7f4f7300a3 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.cs @@ -0,0 +1,88 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class PaymentShippingRestrictions : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.PaymentMethod", + c => new + { + Id = c.Int(nullable: false, identity: true), + PaymentMethodSystemName = c.String(nullable: false, maxLength: 4000), + ExcludedCustomerRoleIds = c.String(maxLength: 500), + ExcludedCountryIds = c.String(maxLength: 2000), + ExcludedShippingMethodIds = c.String(maxLength: 500), + CountryExclusionContextId = c.Int(nullable: false), + MinimumOrderAmount = c.Decimal(precision: 18, scale: 4), + MaximumOrderAmount = c.Decimal(precision: 18, scale: 4), + AmountRestrictionContextId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) + .Index(t => t.PaymentMethodSystemName); + + AddColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds", c => c.String(maxLength: 500)); + AddColumn("dbo.ShippingMethod", "CountryExclusionContextId", c => c.Int(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.ShippingMethod", "CountryExclusionContextId"); + DropColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds"); + DropTable("dbo.PaymentMethod"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + context.MigrateSettings(x => + { + x.Add("localizationsettings.loadalllocalizedpropertiesonstartup", true); + x.Add("seosettings.loadallurlaliasesonstartup", true); + }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.Restrictions", + "Restrictions", + "Einschrnkungen"); + + builder.AddOrUpdate("Admin.Common.DeleteAll", + "Delete all", + "Alle lschen"); + + builder.AddOrUpdate("Admin.Common.RecordsDeleted", + "{0} records were deleted.", + "Es wurden {0} Datenstze gelscht."); + + builder.AddOrUpdate("Common.RequestProcessingFailed", + "The request could not be processed.
Controller: {0}, Action: {1}, Reason: {2}.", + "Die Anfrage konnte nicht ausgefhrt werden.
Controller: {0}, Action: {1}, Grund: {2}."); + + builder.AddOrUpdate("Admin.System.Warnings.SitemapReachable.OK", + "The sitemap for the store is reachable.", + "Die Sitemap fr den Shop ist erreichbar."); + + builder.AddOrUpdate("Admin.System.Warnings.SitemapReachable.Wrong", + "The sitemap for the store is not reachable.", + "Die Sitemap fr den Shop ist nicht erreichbar."); + + + builder.Delete("Admin.Configuration.Shipping.Restrictions.Updated"); + builder.Delete("Admin.Configuration.Shipping.Restrictions.Description"); + builder.Delete("Admin.Configuration.Shipping.Restrictions.Country"); + builder.Delete("Admin.Configuration.Shipping.Restrictions"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.resx b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.resx new file mode 100644 index 0000000000..43c6122456 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506211043073_PaymentShippingRestrictions.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.Designer.cs new file mode 100644 index 0000000000..8d36b523ab --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class Merge : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(Merge)); + + string IMigrationMetadata.Id + { + get { return "201506261018157_Merge"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.cs b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.cs new file mode 100644 index 0000000000..d5201b31f3 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.cs @@ -0,0 +1,16 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class Merge : DbMigration + { + public override void Up() + { + } + + public override void Down() + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.resx b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.resx new file mode 100644 index 0000000000..01a895415e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261018157_Merge.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.Designer.cs new file mode 100644 index 0000000000..11aadff013 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class PrimaryStoreCurrencyMultiStore : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PrimaryStoreCurrencyMultiStore)); + + string IMigrationMetadata.Id + { + get { return "201506261756463_PrimaryStoreCurrencyMultiStore"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs new file mode 100644 index 0000000000..b54d2c2f84 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.cs @@ -0,0 +1,160 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using System.Linq; + using System.Web.Hosting; + using SmartStore.Core.Data; + using SmartStore.Core.Domain.Configuration; + using SmartStore.Core.Domain.Directory; + using SmartStore.Core.Domain.Stores; + using SmartStore.Data.Setup; + + public partial class PrimaryStoreCurrencyMultiStore : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Store", "PrimaryStoreCurrencyId", c => c.Int(nullable: false, defaultValue: 1)); + AddColumn("dbo.Store", "PrimaryExchangeRateCurrencyId", c => c.Int(nullable: false, defaultValue: 1)); + + // avoid conflicts with foreign key constraint + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) + { + // what sql-server compact does not support here: + // - Update Set with a select sub-query + // - Select in variable via declare + // - Alter table to check/nocheck a constraint + // so the the foreign key check constraint fails here (and therefore this migration) if there's no currency with id 1. + + Sql("Update dbo.Store Set PrimaryStoreCurrencyId = (Select Min(Id) From dbo.Currency)"); + Sql("Update dbo.Store Set PrimaryExchangeRateCurrencyId = (Select Min(Id) From dbo.Currency)"); + } + + CreateIndex("dbo.Store", "PrimaryStoreCurrencyId"); + CreateIndex("dbo.Store", "PrimaryExchangeRateCurrencyId"); + + AddForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency", "Id"); + AddForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency", "Id"); + } + + public override void Down() + { + DropForeignKey("dbo.Store", "PrimaryStoreCurrencyId", "dbo.Currency"); + DropForeignKey("dbo.Store", "PrimaryExchangeRateCurrencyId", "dbo.Currency"); + + DropIndex("dbo.Store", new[] { "PrimaryExchangeRateCurrencyId" }); + DropIndex("dbo.Store", new[] { "PrimaryStoreCurrencyId" }); + + DropColumn("dbo.Store", "PrimaryExchangeRateCurrencyId"); + DropColumn("dbo.Store", "PrimaryStoreCurrencyId"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var settings = context.Set(); + var primaryStoreCurrencySetting = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryStoreCurrencyId"); + var primaryExchangeRateCurrencySetting = settings.FirstOrDefault(x => x.Name == "CurrencySettings.PrimaryExchangeRateCurrencyId"); + + int primaryStoreCurrencyId = primaryStoreCurrencySetting.Value.ToInt(); + int primaryExchangeRateCurrencyId = primaryExchangeRateCurrencySetting.Value.ToInt(); + + if (primaryStoreCurrencyId == 0) + primaryStoreCurrencyId = context.Set().First().Id; + + if (primaryExchangeRateCurrencyId == 0) + primaryExchangeRateCurrencyId = primaryStoreCurrencyId; + + var stores = context.Set().ToList(); + + stores.ForEach(x => + { + x.PrimaryStoreCurrencyId = primaryStoreCurrencyId; + x.PrimaryExchangeRateCurrencyId = primaryExchangeRateCurrencyId; + }); + + settings.Remove(primaryStoreCurrencySetting); + settings.Remove(primaryExchangeRateCurrencySetting); + + context.SaveChanges(); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Configuration.Currencies.DeleteOrPublishStoreConflict", + "The currency cannot be deleted or deactivated because it is attached to the store \"{0}\" as primary or exchange rate currency.", + "Die Whrung kann nicht gelscht oder deaktiviert werden, weil sie dem Shop \"{0}\" als Leit- oder Umrechnungswhrung zugeordnet ist."); + + //builder.AddOrUpdate("Admin.Configuration.Currencies.StoreLimitationConflict", + // "The store limitations must include store \"{0}\" because the currency is attached to it as primary or exchange rate currency.", + // "Die Shop-Eingrenzungen mssen den Shop \"{0}\" enthalten, da ihm die Whrung als Leit- oder Umrechnungswhrung zugeordnet ist."); + + builder.AddOrUpdate("Admin.Configuration.Stores.Fields.PrimaryStoreCurrencyId", + "Primary store currency", + "Leitwhrung", + "Specifies the the primary store currency.", + "Legt die Leitwhrung des Shops fest."); + + builder.AddOrUpdate("Admin.Configuration.Stores.Fields.PrimaryExchangeRateCurrencyId", + "Exchange rate currency", + "Umrechnungswhrung", + "Specifies the primary exchange rate currency for this store.", + "Legt die Umrechnungswhrung fr diesen Shop fest."); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.IsPrimaryStoreCurrency", + "Primary currency", + "Leitwhrung"); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.IsPrimaryExchangeRateCurrency", + "Exchange rate currency", + "Umrechnungswhrung"); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.PrimaryStoreCurrencyStores", + "Is primary store currency for", + "Ist Leitwhrung fr", + "A list of stores where the currency is primary store currency.", + "Eine Liste mit Shops, in denen die Whrung Leitwhrung ist."); + + builder.AddOrUpdate("Admin.Configuration.Currencies.Fields.PrimaryExchangeRateCurrencyStores", + "Is exchange rate currency for", + "Ist Umrechnungswhrung fr", + "A list of stores where the currency is primary exchange rate currency.", + "Eine Liste mit Shops, in denen die Whrung Umrechnungswhrung ist."); + + builder.AddOrUpdate("Admin.Configuration.Stores.Fields.SslEnabled", + "SSL", + "SSL", + "Specifies whether the store should be SSL secured.", + "Legt fest, ob der Shop SSL gesichert werden soll."); + + builder.AddOrUpdate("Admin.Configuration.Settings.News.MaxAgeInDays", + "Maximum age (in days)", + "Maximales Alter (in Tagen)", + "Specifies the maximum news age in days. Older news are not exported in the RSS feed.", + "Legt das maximale News-Alter in Tagen fest. ltere News werden im RSS-Feed nicht exportiert."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Blog.MaxAgeInDays", + "Maximum age (in days)", + "Maximales Alter (in Tagen)", + "Specifies the maximum news age in days. Older blog posts are not exported in the RSS feed.", + "Legt das maximale Blog-Alter in Tagen fest. ltere Blog-Eintrge werden im RSS-Feed nicht exportiert."); + + + builder.AddOrUpdate("Admin.Common.Deleted", + "Deleted", + "Gelscht"); + + + builder.Delete("Admin.Configuration.Currencies.CantDeletePrimary"); + builder.Delete("Admin.Configuration.Currencies.CantDeleteExchange"); + builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryStoreCurrency"); + builder.Delete("Admin.Configuration.Currencies.Fields.MarkAsPrimaryExchangeRateCurrency"); + builder.Delete("Forum.ForumFeedTitle"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.resx b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.resx new file mode 100644 index 0000000000..7e45cc22c4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201506261756463_PrimaryStoreCurrencyMultiStore.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.Designer.cs new file mode 100644 index 0000000000..cb29f9e05f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class MessageTemplateAttachments : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(MessageTemplateAttachments)); + + string IMigrationMetadata.Id + { + get { return "201507072138058_MessageTemplateAttachments"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs new file mode 100644 index 0000000000..d83d2520df --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.cs @@ -0,0 +1,40 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class MessageTemplateAttachments : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.MessageTemplate", "Attachment1FileId", c => c.Int()); + AddColumn("dbo.MessageTemplate", "Attachment2FileId", c => c.Int()); + AddColumn("dbo.MessageTemplate", "Attachment3FileId", c => c.Int()); + } + + public override void Down() + { + DropColumn("dbo.MessageTemplate", "Attachment3FileId"); + DropColumn("dbo.MessageTemplate", "Attachment2FileId"); + DropColumn("dbo.MessageTemplate", "Attachment1FileId"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Replace", + "Replace", + "Ersetzen"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.resx b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.resx new file mode 100644 index 0000000000..3970382b24 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507072138058_MessageTemplateAttachments.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.Designer.cs new file mode 100644 index 0000000000..0693d8660f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class DownloadGuidIndex : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(DownloadGuidIndex)); + + string IMigrationMetadata.Id + { + get { return "201507092146153_DownloadGuidIndex"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs new file mode 100644 index 0000000000..803e4557f6 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.cs @@ -0,0 +1,18 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class DownloadGuidIndex : DbMigration + { + public override void Up() + { + CreateIndex("dbo.Download", "DownloadGuid"); + } + + public override void Down() + { + DropIndex("dbo.Download", new[] { "DownloadGuid" }); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.resx b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.resx new file mode 100644 index 0000000000..457d21844b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507092146153_DownloadGuidIndex.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.Designer.cs new file mode 100644 index 0000000000..d738e053cf --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class TransientMedia : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(TransientMedia)); + + string IMigrationMetadata.Id + { + get { return "201507102159496_TransientMedia"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs new file mode 100644 index 0000000000..f70f8ba8a7 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.cs @@ -0,0 +1,51 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Tasks; + using SmartStore.Data.Setup; + + public partial class TransientMedia : DbMigration, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Download", "IsTransient", c => c.Boolean(nullable: false)); + AddColumn("dbo.Download", "UpdatedOnUtc", c => c.DateTime(nullable: false)); + AddColumn("dbo.Picture", "IsTransient", c => c.Boolean(nullable: false)); + AddColumn("dbo.Picture", "UpdatedOnUtc", c => c.DateTime(nullable: false)); + CreateIndex("dbo.Download", new[] { "UpdatedOnUtc", "IsTransient" }, name: "IX_UpdatedOn_IsTransient"); + CreateIndex("dbo.Picture", new[] { "UpdatedOnUtc", "IsTransient" }, name: "IX_UpdatedOn_IsTransient"); + } + + public override void Down() + { + DropIndex("dbo.Picture", "IX_UpdatedOn_IsTransient"); + DropIndex("dbo.Download", "IX_UpdatedOn_IsTransient"); + DropColumn("dbo.Picture", "UpdatedOnUtc"); + DropColumn("dbo.Picture", "IsTransient"); + DropColumn("dbo.Download", "UpdatedOnUtc"); + DropColumn("dbo.Download", "IsTransient"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.Set().AddOrUpdate(x => x.Type, + new ScheduleTask + { + Name = "Clear transient uploads", + CronExpression = "30 1,13 * * *", + Type = "SmartStore.Services.Media.TransientMediaClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + } + ); + + context.SaveChanges(); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.resx b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.resx new file mode 100644 index 0000000000..11d76add9f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507102159496_TransientMedia.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy923IcObIg+L5m+w8yPc2snZFKqi6zPm1VO0ZSZCnt6MImKemcfqGBkSAZzciIrLjw0mv7ZfuwnzS/MADikrjfIyIzK1+kZMDhABzuDofD4fhf/9///+v/fF5lrx5hWaVF/tvrd29+ev0K5kmxTPO731439e3/+Ovr//l//5//x6+ny9Xzq+893M8YDtXMq99e39f1+m9v31bJPVyB6s0qTcqiKm7rN0mxeguWxdv3P/3072/fvXsLEYrXCNerV79eNHmdriD5A/15UuQJXNcNyD4XS5hV3XdUckmwvvoCVrBagwT+9vpyBcr6si5K+OYDqMHrV0dZClA3LmF2+/oVyPOiBjXq5N++VfCyLov87nKNPoDs6mUNEdwtyCrYdf5vG3Dbcfz0Ho/j7aZijyppqrpYOSJ893NHmLd8dS/yvh4Ih0h3ikhcv+BRE/L99vrvDSCfvuVp/foV3+DfTrISAzMUPiFkRmBp/uZDWsIEfX15QyP6t1cc+L8NXPL+zfs3P7356d9enTRZ3ZTwtxw2dQmyf3t13txkafIf8OWqeID5b3mTZXTXUedRGfMBfTovizUs65cLeNsNaLF8/eotW+8tX3GoRtVph7nI65/fv371BTUObjI4cAZFEjKq32EOS1DD5Tmoa1jmGAck4xda59rC//atIVZEIvX61Wfw/Anmd/X9b69/QTJ0lj7DZf+h6wAiKxJAVKcuGyjpoL7RD7BKynTd8lBo24am0mqdgZdPRQKyCAO1auxruYSlaQr1mBbVB3gLEE/2aI6LIoMgNyD69e1GogxyBhu4PEVCkx3VNUjuV4hdPATuM6wqcAerN1KEB8FTt0URzNysHhXuCZoEzOOMSKHV5g03IwKoY1NomPcaKXr3008x5OgszaBAFIPokXW2k5U0B+UL0zH0U96vIO343nK0jkT+jMwO3OYELX8Bj+kdYQXJFLx+dQEzUljdp+uOoaSCft2Cn5XF6qLIVPqFQF1fFk2Z4LEVRtArUN7B2r7TFCqHvjO1TEOgvlqOhK4hG5C1zv5QPOVZAZZeanqZgjc9goNa1uiRjka/N+nQavvbUYiRad/j+lZmbsu4ulsUKolWUGo5Nyuma6tXo7GVKtpJ1WgyDBouzliwGsn1SjxOQ6fPaEyV3qCN09Ki+gKfQvlpUV2VAPWXWH1hqL6tl1jSvubf6qTHhVZjeJWuTAuQj7kayUg96EB1W+dlWpQELsQqxSupdsM1iu2EWzXuaWPYqFfF9IO7KiYZ2gVcZy9RxmfVziRjOjkZvYnjJBm9jcvm5p8wqcffgh0Xy5fRl7KTEvouHRLSYJuiTGEVuJlGaBQdMlgAxO5PkqLJ6+AdPcyXn0HegCx7cV6fldujzaakmmJ71G927LdH/YbKdkA0yU0jumaBpQNhYHTbOxYwaFfHdsvftqHxHIwbg5jqPCu//DKKy7t1DZscSpaN69v6WFS6FWKkEZ4XZR2m9dCWuTRs1sbqO6iqp6JcTt/yaY6BL6tgDwH2N7RHBmhVJbKAao10enAOXrDu/gzr+8LHHdXVr94wiA5aS8egFKEuX6oamnY5f7G1A10Z9jnJmiVcnpBJhyVeGxfLanTLd2gXL3Dli77J93GM4L7NS2RRrFEbLfmnGG03StIBLAHEZ/YcbFd+TvN01azIAeXRqjU5OisXJukKIC10XqJfXaTFX1+/usTnpoibjJjB80iYW2wXsEK0TmpfWtjrtrJYNkl93ORLxNhIzpCtWqY3TQ3P0qzG57rO6u4E1CAr7t6YUB8UoLqtDdFCZWAgejRE30HWBGNbVEg+0KYF7e7hMt6eb0M36QbJxJLXdP3NnsmhmrCNcqkbtLMSGoopugdZVbfVEStUIlpiR0LWx4OFYUG7uCTm2tbjO4dIRPIabeRDtwFmqzCGF/Ie7fXsgriiHeMhFhwUheO+RrJDTpfw6r5Z3eSUM8AX2Xc08TdZ8MwR5VDdeyj/0aLQovpnA84JDU5NevWQezYnWOZ4b6fPEum2qHct2A34mqujGSQLal6/OXjXoB23YVgNwL7ruk67Ghrh5sXBqNCox5ZEuLlQW+AclKjN38uiWaOOxLEvukVgkS/Tx3Tpd3AzzlLuevQ0+dqO+jdle0fLVZqfFKsVFfsyWmM918IVWpLDt5xocp6+5h+LFTyPYCt+hjVAIo4d3zqPVhybETc25TTj9q7SWhv0H2dkR1lWPA3uUPiYwqdgA/VovS6LR7i8QLozv7tsVmF886WoI2Ps0V0h9Z5xgw7uYzykXbzEVXGUBNv5n9JVWuPOkZUseIovH5rxhQ7kzS1IsMFQolWv/oK2PJtNwWjN/o5YbPRGFtXv6W19AsrgDVOPJ4ZtcQH/aNISfq3vEcVb5R/MKR3Ojami09aR4n+OGmzJ1mmCLZmj5ZLrQ/CYFtUmnD1OaHTozH3Ls1bAe4TBY0Sz0grc11sBp6f/qUNz+rxOS2JWfwAvPE47FEdJnT4SFDHY/iOoLgGycWCsWWWxOV4GQr3BsQRHdyWEtJkXcLa+QXYFn8e3GxfVBUyassUeqj06RCcvSQbbToXqOBrjOSzTIlj6Bpxk7SeIA2VlUeFj2za+IpgdF9UZmv7+HDjYulsuUyx5IOsxntxjB4S9W9k93B88nz6jXUiwLCyq0yqYnKg3J2g7dFfgg/zAI22Qo63QIn9EoonQ9Uf0gWZjXSQP0Y4MsDeWYDx6BCmqm2YU1kAvr7Sn3gtWmkcc+afiqR01XmkQttBJQRuE9PaFbN/PirLv4zFEu6/AgyaQPBTYW44zOwSfCuPdIMa4aGmJdiDDpjfYoiA+/S6II84ktRjb4I04GAkB4LJDRsVjj2esIlnAHTxuXo6but44FwJkC0P/SKv7LK3qOEg74c8gYl6k15njGV+cJ8g6J+jSJPz8iUYSfQX6mi3HbaDbmJxQsa/R27hcIzwgcxyIPc7LGu3R+zMxjysINK7TfBmAqXdnneb4TC0Kf3Vqi8EMR2aKTrFN2ibafFylsJXJYIWP1lBY1cPR4Umxuknz7hQtIhOiPvehCNXRep2l4RbzD5je3Y8niuw+Jjr6H+lyROwfx6XNsNKE6pMBUZgyiReQEC9GAmbQJ85uewMkxAGmj7B8wZUdvSd06izHqseggt3qE2XbPeD7DEHVlLBNC6aJvY5x87FvM24Y84AW/2BR25GWBC2QEy2DByqOe70L6oAljpOI5fhgkGJqxMZ5eV+0/hRQuns61DFG7ZI4LJHSWJW+9LqDvio2vvJNsIoaSogg0oC6BgzR2kAXaHPNAgoxNky5KryGBfIMB9rE6FhGdPkHOBkjtxQBUY4j6hxeZEOsHlDvFtMEOvEgqgEIcJ4dpw8RtX2nATX9l4GpxiCF9RzHeUrwaIfQwWh6z0GoOs6DefZ5OARXd7kF0fSYBVB1mIPy7C/Zgd6mbXY5Ol5X3X95Fc149BVU4zPU8hzvFbjTDu6agRP1KVWsVKc0jKc2/Q7KFBl1sn2ktvuaepoJsqilmiWbqp5TxaN2GrjDaF2H6D0uNleuhgdZQJEJ6XIlFzJArmzInw1rOsuDit1lIZQd5sBcu0z7cCTdHYplnCEUCrwgQshm3z414HAvxSNlcmfUDr8OUcjqtgwxuSMlBO1nJkakxrcK75Ui3TZS31+K7tTqm3LdlTuf/HYuM58MQK2XzKNmF11VnRTNGl9wXgbPjIhJfvwW5/SNzAyJjyRSFsqjG0yYeK5xIKZt/FVh2IqJG2+6gm4vv4ETliUtsOviJHExjOGRMI9BcF5YeyQ6VB3nq5NSDW3Ka0jGIQNUD0UKHXQdqN93B9wH6lEclmJ1W4aleKTrMfi2SqSWTQ786e5KHBc14tNJL+HgB1FGX5l6MYp1/eZwYSbKyNr7d7ECADtPm+NJFb4/dZn+C4a1zVz9qa6KNn8Hj9s7IqfD85UNHgvYd1hEAF2A/E4bsxUthUDEm2wjxC9s8c2hbTsF38uEAwKpSG697yl8+qzfVHlq49iHjx5bFvMBpGR/Y+2FbdW0tPebk6oeaNNjvkyw5AWAsLv8fQ8839jo6h8Md436akk01vMSFq/n/GWcm/OwsHhu4udIlx/35hGI2Ce3ogqRQxhPbjl946dOGJzhGUIO6mWq7GOqbcV0tpHXUuotDYpjNJXQOEpw3JgLU19jJPWR+AWjnK5R+A5SrJWbKC8pSMh+0WTQKoVyHL/K5RqOfmp1nGYZjnrscyMH3n7sL6XGQden7iUbCCZrtJPHZoNm0PA6N0WcyaMapTNwT9lwPxtmL1Dsljt/heM8nT4jRUU/xznBHnkT/zDeCZJyd6w9b/Jbe5go3IBXsGlEh9VG3ZZhIRjnFeyTIivKj/CZpI+evPWdeBjbdZ8V4eiVw3SQGnVbkXZasQ6CFtUZBHgiegNhRr+2cqXacKjFHYANsPoSwPBDsSkSAUfYwvncWjD1N8ou7ly8RhCuG2hsB/0wun6gyf2n0BEst1ret2Er6S/dMH8o5FBdYQT9EXJzyKb/UXRJJCVy0B7bHN81acQNxQmHEKXtClE6BBXtYFDRIc5m9+JsvE652MVdPOOSlQuGghQoxm6jvUobvs9o8USzEV7hzBNd+yTqplMx5D29vH49hS1v0t6xXNiYcJMkam3TqYcR5SPM1rdN9l+wIslPoyD7UvjgCrHhXe+hK+x2xW11x462WDpa5LCqkKyaUi8Ida45eVaMSFlDf9VeXS3o7KCXah/109scw6/D/kTdVk+j35t0aLX97ZFd2hA0FilPpunt80jNWLymHel1la6hs6JcgfCInw7bJcjGXzcmfYUmYvrno9vbNEsjbFRJVuDg3Uwky3pRtQEhRwnzvKP33QGb6JI4D0V/AlW9WB8tl2i/M35sQNR9A+76p+IuzT0vTeP6fW5pJQr/y8ItSRUmQ6/8rykwKmZdKBWj1kUQV1OnC/oZ5l7XTR5W0lcWRN1hDs611/yuQ9ftDuZ6Y9OI/eZhBKNLCeh6g4GOXTKQmwOVUJuBUBObBXOl9ekzNmlAdtTU99ioaZMfXcCk9Q5KRqCrIZ0GqwrCnNjVcp0gZAY0q/OiUtyRGYqlAxFLhV5LQLy6eFWs00TTR1Ku7iRbLO8lB+PaTeJikveQFEk7x5YI/eKKXbt0AdEuI8cxVlA1wQyItItyCKGrCjD3Lj+BcnlepHldfUyrWnXsL4FT9F4NJxmDBth1JH0MotVaIwBL1B8Ho1aAPKBz5ikqIag6myQPJSW/EkigvRoyaGs/ENR9Z482GkX+pkNw2NWr2zpLy6qeJC4cm6+TNGTa9UfaGhSrNchfJmhHHpRu2JEh7sAJXB/TPHE91TuhnkQZ0R9ARPPdVA29H72hf6RrbCuBzJCEKpIr6L7IofF5y0gvFvfv+m35flu9k2llSLoU9gvtALNZALkiYdHmy53XalpItZ3jIMUuMgDKjrJQYUmfenIFROt3OA7Ls7otw4JpmzbIJyKj6hwfwR5UgixWRv2rp+ITxERcVIVB0b6PoJCu7ksIbRv8OUKDSNHCMk24xgIfg/4Ogl288WJDogV1hEa/aPax/F204RacdC9Fw1xvKrfqjUtIYoaW7K6MVZz3t/RCoBgWs1ZIVkcpgNh5KVTQtpClh8cK1CPgpu6wDmnU0t4Hp8bTS4u7HNG6feE2OCbv9DnJmiWSdeYise7kK845WyeppHksAuQ04dn9zNlCyVJ6cgr1yhvHDhrZT12xtnuAvcxgOmgrI/MGP8A7j/F9c1PCxxQYtF6cjKHbYNZ5bds9zRNB+LVGTFBA2nDgGyEurcN1kHmNzHekCr4xZxFcEuemwAKn7kSst1fPMhqjCeIHQKjO0pSREl5ifZwVd0P8mrNI49rVGwrHdkS5d52ZJHIcDx47yOOZkD1GKUtRtL7eAG7YSVYusJIUKJiN2q4E8BBGcFgL1G19AvldA+6CYzZj3d5wzW5VLGMcwHldw2uZPXjb2q9sHb4TyfOvrsZ4UcdH2j5TN7Lim+eJncPF2G28YjnSASe1Tsm9KF6rIe/L1S6Ztl3tdbOymwTrBortI1MoXa5ZiKC1etMJ57WapJlK/0WA3/R4Dku2uq15fC39zHRU1275xmgf1f6jgZdwiqPMswzcLVZosDhpt/GuRoyrovX+PiQxgrerzUzXTsYFrIhqkytzGaRUY2oBBfWuhw46spOhDtaqEpwHDWvWdRHS2xJaG1TISE+D9q2bkkiOtElaVFi6zrPmLs0FJWK8lFg0iUz5RDGdIikF3qSyUyFeSuFccTs8ViIJCuV2eNuY3oWK4Q9QdQOMF/hyzt7/nzJ1gDY7gjnjgBcDfoFPlb9LF9d+Q6HYDh7rPbqT5B2Z0n2MKY3vlsRzH/cYpYxOTez1BnDD1rJygYmlQMEs23bFn19x/YOhpG5rx73Hl/dFGUMcHZs9I6pr6laj7ejmcdL+GX3uW+VRPTjNo4zMb8syLImybYpQKF1dWQjXCzjU+iz3tHhZAbxfRWsq+O2ciiz7XtRkS5aQxEPO1gBGUb3hEW2HDYt7dZRXTx7BPOqtzYBTvq/hCHFNw1ObGTWYuIPRwIbtm6muBcx7i+JgCOr5cOQY0pHMova65tdbxH+bFXaLHvQrsIpQiGEnIi0MK3pUkVTc6HLnRIqcuCpSJ4brCSFJooVO8dYTQRrioBvUbcXaJM6jH9qEbZ2lO/5d9WibtPvi6Wv+ERkS58RaDNwv4c3X7yS9zlWBNeX2XG2cZzc62oVK7S6AaGvZDoApkOp7f8t/o2PVet5yIZLpc9lCFXSZAKOOcpMAIzrodXVbplPNX34ZxXlWQhjthnys1KcIUafRMB5uCgyqNUqy0z5Lacv8gUuHTYpS29m11jKwXKVVZchByEOpsynqIUVNpAcPMy453D7XsGHSlAirQICDfvLWT6Pai/Poxs2jgKO3HJAKNZoQC3aOncx7CbEuLWmQtaFDfJBuDa9HusQ4TQq8fpbb0d2mEyQI65vsDJMJW/6KeZlw3zRNHSUJrKppGjzHF6DRptVKzcd+y1x7MXSk/My8knXL6uyla4dkyh6KldStNgmdDypU3RbJBB38RHMkPRwpMsp133RuvsIeJ33Ezl88d86RzmsOTRp12w5uEpgbukgDyjpJZUJXd5MCCtdnXWeCFBrBcdBo6rYIlbZGo+HZwghCEXXJCXWxKJa3kNzPRrs3E0K6/z2FT4EocEJsr4QICjyxprjH1+pdtyOE/VgQ3B6kkOpaxaMVTmuCqYMdkLR35Keuay1A+BIQqP0Pil/dFiHQ72XRrEc+ZR7prtaUwY1fNs/MBBEqyuKANWiUfcg+LhF/rledNzKs1ubXNBCnzakyuTanAcK1edeJIJVOcBz0ukbJ7L023ksZnypappWlcHUhfShNpk+81EU3t86aon1qrf3voCTUbRECTfTsCmkr+F1nMuBt8VOwr3YGOyvYV9kcH1Qi5MWZZptoHYmD7Ry84FspUZG1abTHPElScMxJU5YwT14meX6pb+wCbMJGP8AkXYHs9avzEv0iWuz1u7++fnWJMyj89vqv3rLABmKFztN3UE+pVi6bmxqpxGyRJ9kVRmtFrL84D4tpDKetn6KxK9wYmhvyivZUI2QanWakndaZZoRdY5OODDXkIMrujTHKEa0iKTYRQHYG4dg0Vbc8NoHVLY9N7Q7/+Kk9CQ+NzqS9rI/bClErozWBDO8mX8Ll0WrUkdCvAP+AJURsFyG9+j1MHoqmPqoRH900NZxyKy00Xv3naoLXTTvTI9Y1p6Pb2zRLkUxG2x+sR6cBuR+ENzX4ZeMSIv11gniLtZ28WQphoqPqx5tI3OVJzHCBNuMlMgDVA1yqpmTUEZ48Po7/kixu6PR5nZbEkfC5yOv7idv8LwjGpyctX+0jRx/gTRp8bYVCdZSQdfNjkS0n4A+x4YkYk2r4GOQPk2yAuTYnUTF0m4uTKZsb3hearsnFDZjAuOhWU2IADqnwxpb7Bm0Iyi6N61UJ8gok+OfGNJi86UlERtX4BayabHyyn4A1dqRPS3Cx0YlGe9ncDDb6tEM+b8rkHlRwSgf+OUh9L33zr6mOPS9dc3h/jhTOumlPSyb3Gn+AGaz36uUtzU74AuKjN+pusdWxxUdQfYFPnRfnS4Hv2STMq4ThR53sKY30yJOI0TUPuDn2lJULkRJSINeYPG3cYNuCLGSQLVF0zTtQsPcNfavQLv1jWtWF4sFEGeB1d4i76awaSjhO1oC6vgnye3pLNnLGQcgAr79VcPkjre+FwZihhUFZVHEdHKmFc75p+JukhBP6zxUJneXLvXr2pU0RpeoZLlb0bFMk7xlV7tqzC7iEcAWXtBI7Vb4FSkMZmcIILAzGXMP5+XXUd3XSwb5UJDtbIn0onir26dXaShsLkLy24wAUSo+HCgpfkytCj9eWWzSVVGEeAlbUbQ3HoIEe3larhbqJx3lna3MSY7vCbmoYFtn+oyAremhXe6HTKWMYCFYdZzWXl6TLrQXfQDQZtoOYq9vq6RUqocwKGgMZ8yJM9IPFkRRKT017a3dTw2Do9h8FudRDuyoUztCawmi3GpDcpgtSOOFK5qBY1G31fjNKK8ie+7DTTjEC5UYOVVhUfWdJtjQQwRvVIzwpmvVETu0LRIx1ih1EU3jthtamSXBzCXO8j51iZG1T0wzrM9psUflTR2tnUW24g7gP5/a3juSAcl+SrdxOwgJuOxq5JtWO51pVRxyRAlS5Kqvgg5ZkqodBN1AObyHZbMYRkYJvh0Sx88/bx99C0fy9Ad3ogzYdeVqfl2kyegjv0NDoEbtTjGaSkYwdYdz7NlobcWySsa2NTbtZwlynDW/9UDzlWQGWEZ6zWlQ9smhm/CckIHkFe7yOWyCsrX/A9O7eYetiuEvX5MsMIjMLjB/I0Cr4E5InLxZ/Kw2lo6oqEhyVvOyNFfmpR0QrSWX5mayqcP+uw0Gj9LhGchBpbZC2s2ro1gAl61hXqOlaDxFuV34hb0EE2ZUYxcGuVLcVxRr8Qr3ZMV12xf4qZrEJ9tjKPa1BE9gd7EvFTXLw7yVskoP1oKzTEnwHGdTwXaSr9i3BY+A4BhnIExi4LatGv2U2lQNtJM2gDWSTRbvIwtp0cILa0ALHP3GKHBBkM5qIx019GI/PkxpdRM0QQ3TQf+q2otggVyVIHhDFJwr0Jpd04+7uCM9A3/DxDzBLH2H54ll9ctvHOriOF3pF7J1ryJ86EJSGuN7oALGDDIAyCJCFCkr1RKOMoZQOTnezRBI6RYmkkx2iT+MvNwpDTDlQyatcWjz3K4gd8wv4B34z0t9BwKA5yIFGDmIkFIsmBLG2S3EOny4gqIr8rChbbpreDdLxLyRu7ygHBGEd0F+espva7gbs+HljLmtwe/ulmCJFzdFylebmq71/+SnKgyCMbouTV26Lrtj57qgpmij20jIIyb5TCha42SyIcXaCFqGweAoe02Fl08l/hJXtHJSdfeN4Qtie53lUpKc4RoRlNA9knLCQeVIsIZGEJeIhHBYxmscyjtGxC6p4w9yK3QWrpa5peHqPoQST7DTUsFHvGAsNydYSJZC5394eWd35rtCK5JhXBWPucpRD3w7J5RrJWn/HfdAFPidSoAZZcfdGi/ewPI6uz+WE/7pmE4F4rhU4edVZmqGBRXizHfH109e8G/Y5dbTknwTLOwG/l5RrWV0m8lYVxMeQrWo5+2Y1fOIxWj06WxLosDjSRYsqbPegHaq34tShPehNV4U38uNR44bZjKHB5GRSvOs+t6jz5zsRtEaYXpRbedp2FXgoA9C9umgbeuAYQflFV3sHhfdnUE067lWcF08vcsJZc4DYhuzUrsBd+LYMITmIlrdo/SXSI2WmtVq7Kl9vprKSLLd0sWodZWBi8OZ3UKYg36RrPylWN2kOAi1iM/IDL6vbunxoIrCy4e59neoOQeM08hnkzS1I8CSW52i2jVFncZp19E0bbjeRjsTC9iNdxkP2Me61KVBBQjnXaGRLtPgHi9rqEOeoqtK7HElRSvhosdSdQb+LcyzcRwli377jmVN/coEvwbrehKvIlbxgZ9pOHi8hlZk8xDn2Ib7Or0399ZYgbc97nYmqTqpGMYdutdcsftcsDsESsK2qcqxZ1495cmLRttqxalHLZ7C+LlZain0Hy+JwGjFd1WfYTP0YZ018Y/FNw4M9OLpC79BEc7RewecafVqtx0+Pj1Pz/NGkZfhldUpe8rosshhxITOdXvEi5KBeXXWqtyLlec5nPFJ/kG0d1xHqna0WQ+URkzyPWreAtMa1UvMaaaCtr3IsuCGJ4XmIuJgcVhGLVeQoS4Fh7xRBU8/k4h4t9UuopdSleY1tLhG0B25Xt6WgW3gczQ4JkSE6ssiK8vKPBpSwuri7GX1QrW9p+U8kCXRwf/TY0fa66QQNLSqECS3kMImQRCnAhuQwEdUQw6z9lOYPONB3zhx2rtbW9thZlnannbHmtSJdpbDsXOHey8+A47DW6DRbnPjPGLcs+qBozHSerutQL0PUiwHG0HM8UKnUD6x7zYJu5FoOIUiuAiym73TThGQPLxRqeqjbp9tHCmFG9Lk5j79U7X8HfaFua6JYBa7Vb6XuFGekRi+r7DTH8MEG0iVMEK/EGYThWLWotHdqIx0yfiruiuFQczYHJD/2epUdF8uXKd5aLfIayUt/HvUF1k9F+RB5dt103mdArusEqr4Oy0EDqttqyR/K9i2WebSph7Fmb7jfwxUke4GbzGcdJvWrNwyaAzeq2yKEGn1ZicSnFpt/TSvv46xdY3L/MUgeFjkJ3aBfxQ7YxCowHkQi6gSPti+Ode1+jvSUCtaTXoU2wQrbPmOFmFtUVWOSDasB1HocUTazdAzqFVwhOznoxFGG7qBI1G3NY519T/FL8JtI2+la9t2KWfMzYkR4V5QvEXiZR3Xg4wMfT8bHnXKPwMYcpgMXH7h4Mi4mU5EmQbFMxWpV5G94TAc2VrcVx32ERvR7WTTr6dkStTyDFBpcAyOFZo3pKjhKsguYFF5PHZPzBITuzYDkIHFjS9ycDlvtwbhz5M9imQ1jCL9SZDzLHnhUeZYthxC22gqwoB32tzJECos3Q/2DAO6zAF5mzd30rca6VPkJ5HcNuBtrJbtM7uGyyeAVqB58TnxQteoNjeQgS+q25olRRwZHkS8DH57CdafveqwQjrpYf81Py7IIfoTuEyD5usvaI306rnuaLz1rXjZJAqvKt1168LFiS+zt5dvbNEv9vC1D3Wrz86Bk1G0dLZcl4pPg0B6YwQjh5Z6LoPop2nZ0cmO1Z4/rAYqyU/lC0UQVIMLOfyCoEP/1j1A58/2HtIQJfjPtDYPpwPrqtgzrq+11EtfV5aWq4QrR4YlsRaZu/gKTzjLu+a/b58jsmPsDWsfyyi/cQpCUAdlBWA7Csk/CctKUJcwTn+d/N0LSIzkIh7dw/DKSp7CdmBOEQtf4SIIBx5aLTwVGEE5WG3/rWVGu0KRTOefHau9TukoRi10VbSh2qMFMBKy636aLnVv0nAk/RqLb0J4azWz0mxPWWhnxWrMKDBklOKo3AqqDkla3RdPp9yYdWm5/zxTsSWYwOMNRsU6TXQw7FfhXGnCqhhI25RrQwPxi6SOixfBCva/AsngO0qqR1hiR3ZiHYknqVRELE+LPf8JE+2zkOBYjzoQ2vVceJ0UDwfbJoupcjMcvR019H+6apxBeILt1nVI5OHxxjqRDaTZWZI6g1co1C08niFCCSfJAqGFd4/U3omPTexpa2fcNkKnnFGTQEkBc0+jTp8Ln4iWqdYcfa6ewHLS/ui2KTLjJrbmaY3zwdyQdOpJi4cisiOkZYK4FeDqwRwkmie5Rw0Z92pFuSKZUZOXa3kZXJS0ZY6gTDH9QKeq2ZnYlG1yE78dp1SsiwuGOz2oN0jsfB0a3OldvehwH1vXmnbECgYzblJEaxok9dm2JjenldTgMJUIUcDdpEEMO1UEavaVxJE1+nCSnaMqyLtgE6vzXtl0Ilf9IGYYiyfs0AbbtJCQJfiAmPHNl1LOgS5gv8b1vkGUvobiO6hok93iz8+4sdU7Rt6n9Pqj2z8ba1rryC3yqPkEs6oFHL4PKlGM8aE51W3KKBZ/FEJHUqcNfRjkDj6NPopodY15iO7mHyUPRBOXDb984eiOgOgiNRmj05sZI91F28tGUy/t0vcbw5+1V+1h4F9UVeD59hhQ1fFEhRH06i2gPn23HEzGx7C21p4/XGponS+Sw1xIdtnEG2tYRniaxrhj0HIm8lYhK+PBWg2mp5ikWKm3zqPbDAwcjaUB7zTW9zuIPNZyVnZfOusDJCzBfn4MXzAIf0wrHFPsrLQXCg9ZSt8WTLFRpkZnY0mAzfqxSOVPw0LVYeSNntnUEObOuGFXO4gnYQbI0TPySZJB9d9tTGjCic1imxTI8Sq0GGcEXeIOb3FrGIhnDLxHL+RrplukiT+sUZNusyeguWmmxa7aGWnUxgEZ9xUK7Bmco1/+p1TK/ZXPW515qmdxgSf9FHqciZPGK9CA4CPAbAeFBPavbipOKxi+higQPuc00Xy63of25mp4qr5tSGfUzKdU+gmRdb8A3+kYNJShSDWigqZcRaejTWXunI2URHRSJuq3zPj/8uzAVMOB5P4+T1t7VWBZVhcQiC+cyHtWBz7aVzxysmpAA+EPgu2GtvPsEH2EWfMfovijr4bra1LF0Zwg8XuOGzdx6SN8zckCU8haBQRwRFfTvwcUhBGJyWJawnKKtCe94m274wT+aNsdF2MUO8sjbR1Dps3/7kM7v6oLqyoL2qkK8KwqXsMuG4JEnPL9N75qy3bF2eA4qX93WPPGke5hmm4qt8MpN+vyGwnDgWG+O3dVHEkgaBR/OwfWq9r8D22hkn9zAinSZxeThT7JmCRf5ZYqaBIO/zT8C7BxUFb45hgrqKIEGPcLRaXGV1to0SnFamSSI/zOsQXeDT2fux2vsA6RCxSdob5q5inzv4ALmSCUfVT/SZXvIEoStxfKPIh+fDm1TP0qw7ux/oe829dFW+4mZt7CRHxd4gYugX8q0KIlWDjpPxgO7Arq0aD5zoV6TmxW1IreXbYbrIJhd0WYau9ZbiVxUZxm4q4YW/S9z6FuKtqojmqDJzV4QDelZYafgM1zdwLLXq1lx8/oVsdZ/e/2TMF0MLL4tQ7wAaEMMh0rv9JXaF686WMntmnZC6I9HVVUkKSFMh+PvDWzgkqPhNe4ON7TTfPmq3aqqq2x2te3M4d2wFBpxIaJ5ukZURqz02+v/SxioVXPD2fCmuQ/FU54VOGkN28JPb968e80bYl/zNizhFY5xwMGMJ6BKwFIULUTMJfulmyx8wI40UIX4Js1r0dBL8yRdg8x6KBwGS2MR93Boiy/5ANdYy+e19fTZdKK/3iV2ZGiPI6GJYr++pbjTmmmv6Vt9NizLVDAwrCebsk1ImJTpM9fGVnGpdCTT8qh0vmy6wF/3nJtTKWGjWcxN7dGEmU7Z0q1K2FkjMVvFzfoRzaZ6JXNq0xeq2mzs3Z1Xnqfkuerr7n8lT8vBZYzMQrpwsKINCdsqkM/PsvohTMCn+nmy6UBXZWsYs4uGsGUa/hn5MRiTe3pebGP7GZMdwgyMyc6TFWP2ERYzMWZ/SGHUlTygjBk3Zyb2bCjgtdeMZA/FY/ZiJFUnJmAhFV13Qat9SKvWDD5ao0nBbsBuNCmslIykqyRjqh7eham0bUgYzJJxg0jTSboLYfoq45FlaMFe7UegSf+ju1WPrU4LsshquVAm6npl2z+ZS0iEM0+il1qzIt0EOs6KRDb96OvPbcddI75JH2H5QgKLDBYWA6yx4TyMNxa1jNfofo62fOp6M50VJqWzFVdR9ebmrMEcGJYkAwsIFTQc5mOfKZtxWEa3ZqegHMV0XKqcL5su0AlftoJLLTeyPPzIPLrDe1nVGGZg0B3czeKchbeAbIpK445WBixjTBrOhSul+OfY3eo6MgFf6ei8C7vcjqmZYTA8YVBLyooaLejLc8YmJfyna2tr9KJxRNMpSON82nSFrrdVnG25osvqTMTPO7y668YxEwPv4CpPkjOm+d1nWN8Xy+sLiLClOJD2BPsGtM5Hc1UZE7O1XPjXoj3ZPooURvRGXtbIqEPT9ogYBV736JWdlkFL6UIDOpFF2oI9JeYXaO0IJhBl7RxZbSXbKrMJcXfV0siMHJyMDYdbm/YMyGO1Z714ZrmiDxMwj4Kmu8Q2rOoxTTMrLXFZiMUtYSStlozPTtL+TMhUUlrbtM9UnO9AvL/0unkeQ8UBIqj0UHy4eutwKC5iljCWHdP6jP04zTJktfQNGLvJwkenAofenhSidHlQo7vRsblDbeovX0FHj+G6iDtZhGZki5iC7PMbUKZRTKCxTPNltR5SmRxm0VdtSqz2Mg3aXpCebzJOqXhIW0vGr7IKLkyrb1DCuZukWdvGuVZDmYB9rebQph90YrpZePg4K+7Oi6o2860AKePVHsiFP0XEO8WTyu5PwIfKOdkZ3use470eGEfHJTywigOHF37dmFBAL+FDFYNvBx+qRjARK6rmx6b5vs7cHvkL+JjCp48wW982WY5tXqbA5Jw3VNf46YWaHs56U+tqv303uq3jareBTefIt5xnB59+W3E29sfPui1quDIbAgKkjKl7IBcmFhHvlCGg7P4EXKmck50wBHDv+7VjYBwdl/DAKg70MASk6CV8qGLw7eBD1QgmYkXV/Ng039eZzxAossysBRko6bJeZE63xlmEO6X5pF2fYi2WzcFOaDzc86O8esJRAIWQKIxlCgpOxWctiCu30YhllqGEgbeD1yQdn4jbJHNhZeIh+Fl57XtRE1dVUpTLa4pjdOyhqKPiQRrclRNVTSm4Us7u28GbhqFMxKeGubPl2bbWfJwLy1Va4QxN3Uh6lz8eqPpsTF9Nyr9cDSf+1bemORnCACOcINoRSQ4e/fxwJmKcPuOsliA7aup7zIttBjBugpS0saotI5Wuogv57DqwU4eOTkOaQEs6zbFNf2Y/jjwrymZF3K5GBhdBZdw8QLmwrgS1E59GCchRd2ICzlITd3fYiKRBtuQjFlbJSF1iZkdO4pDPxEryXkzFS3IC7w4zXZN/2yfTtJNNASrZyJmDaKQS9qH6tnVrpqr/UzGeZD5smt7U2gYl1nKNhZJphzyG+moxq5hvS/lO0vVpFR4zH9Z8twXmF8UvZiuJGnB8E4xCruI+KV9vCQsqxjCpDSfOj03zpMJsrNi+82sZSSwDlrFi92SHPRtKEdsHEEey33S9mICRdNS1aZ6tOTNHGfcDLFhELtpNn4e875Nx3U7uGPo8U99wSv/+Re8hr5iKS7S1dJnK6Ao++dzkDWpSj20fl1oNZQKmtZpDm37MnqpMOpJW8znxUyvGU3Fv25qEdaU6e0v5lhnEXEzLzJtNJ0iFeRd3Eqaj51EOTrm8u8b98Xh3hwUVPZ9qhRfnYpeYzZTuRIAcgeF2MaGJsveTst0OJi/5Pb2tTwAOiEBdvgcVXP5I6/sNB6nYxVBPxpZ9FReuNDWjUosy7o93t92yVxPwnuU0WHGiFMPsjMkYEQMLmfhFWkvHlL5Wo75BCXuqpGB+HWo1lAl5WjuHNv3o62wXD3+jRcyNkZmqk3Ez2+ruGKL2g5mLqaXzadMZpuK8ZuuXooY2e6QNnNJkxSDOJiuFd3dYU9HzqYxVcS62f490AZ+Q+JwXCEHVy4/R966rJGNDCbwLQ2qb2ykvvc1IJuBWm/nbCQ++bCB2hoCxprXak+5/XBryE5igpEc4YSW5NacnEgumypnpeu2Rw7o7y4u84xPIq3wetn9x6fvd7pl7VjHxBQOtYzpXX5y8AVkuPwVXbw8LSocwISdK58im/QHBvOEFfcZeu4gVDjpisAGPOSTpXZDVrOrJVLazisa2PLXegsiVC1g3ZY5fvYI2NyPk4HJzgIJ0s5ylTeyYzawbwyTWsm6edsJO3nTaUu+pKkS/tBdTATpZJgVp9gSU7Vp23OTLDGrPZjR15FYKC+5mqaibUp8fUmMYbbGw6NkkZohxKmx6sak1o4nMjcS4bChrjM6Eu7l+GIcxB7/u5CoijMIUVqGqMDqn7mKshWkQc7DpDkZesLnxTBwqhTZmTvROl7iTjKkdwQRcqZ2jHWLJyzVM0tvu9v9RXZfpTVNDWxbV19awrLyiBwsberCDLG03oulY3G6Od4Hl5SP5usZ/Xis4Urm6u+OSGhgaNE7Ghkd3ZD5mK7GcX1QChjuFxeLPG1aeRSmGLV1ItAzup9v15J1tydF2y1rW5KI/v8SFj332FcuGb/zlr8UztxT2y/IVuNPkhxNhNXLjISEMZrUJhorjZTzrcH4HZQryepiWk2J1k+YE8BpJTPoIy5erdKXJa+uGR0M4DQoPmlp3SHb3kh74aF5Yz45Opxdc59SmZ3S9uYVfNz7LDZ0Fiq3g+B3e3zkMaztEYwd3ehaj+nuDShBnfMvTIKmg8WyFaDAdksgHM/A5FwNZR7eD42VzatMzut628b7vCuCh9iMw9D4p+O3R6nukyvuhmD11tgjmYXCtO04Y466x/BzeN9f5dhCCrXG28YP7DrJmGKHArY6sqUXmICUETwRR0fdHLTYmqd1a6bEa8HySZMUfDlLFo5hbuJy2Brb2v48Xbass+ZnN9b2wya8vwWqdwQ/FU54VQJ3ZQA4embs45DK3Yd/P0XlL3pcJuUtOaavTAKbmbBx2lcISjTqBzIsjSg6Tg8s4bIB04TEFesfnTwifzb1G64cyAYvqp8qmA3S9LWBQkyNCgByBLXfRvaDs/aRMuLsuBCocv/1p6RFT1dOsx+pLDxYrs7K9XWJWy7FMt8SbZtGmJ0zFLWJnd0aejoV9mDembanuyiy8tw/qc9ipn6VZjbO7m6+pOeCw4kmuehCLarric61tC3WveYRzyIKZBex18qzX5Y5B8rDIL+siebhsbqqkTNuYMuOtOVNFmSgo6rhIgLHZnbpKZzuaCVjcdj5dNm1bx9UmY8NQb2Ke3kXb2XIsMzL0DloxR0kmeZ9YycVycBnzDpAu7KpA7+ggm59V9eOYgEP187Qz3rGj29s0Q1/gtSkJhgAp5ckeyIknBcyTP1al7MIUnKQirE3bc2f5Ia+0uRmf6irKh/h8F2dNUzM9aDu3pWgm/k7YiGi8j0hiPiPWB3fw+qwsVka+09SRb/1pcLeNvrqh6dnOojeTbMKNxLfpBV1vW5jvqnBlvU2NURmPamZ2thP7Mj3TiWS36cOm1oxbiDp9RJPzqbi7pn7jydTsI5R15JuJAcRtO6FuRWbEcZ3fwm2FcTyT7C2Mc2dlG7JVt4J9japSBjwSw+6m21E3gol5cydNx5N7mDwUDR9WKnxWZ4O0RCDNDimt65Qr0rZ1GVMLY9w67nYd3gQc7zrfVlLAV54xTW/SlIgUd+fghaSvXuQpxmt6MEBTS560l63glrdX15h9xvwodq1VZybgSqsZsOoHVW9ruLB/G0JgG1seUSGw4U2vR1ksm5dwq0k05lfKrqObgf1N823TJb7ubNLwqUhAlv4LLvs+Xn8C+V2DvQEqBlRXkXG8AO3C65qmJNw99HzruNo8jgn42DxvNp3o68zIsRZbO9OWznEr57uF24ro/pl2bzuyazslN6dQnRrVgGV/42UFyvrrzT9hUuMi+IzmOyEdA3le1ATL375V8CQrMRtUv72uy0ZUmRj1Jawl17Sq16/aYuVdN4EZeWSwgcvTFUgzZNmD5B4vI3KsEkAj+v6yjwzj5s6UfR8NPTOiavufJEUjHyVdbkTWLbqfYX1fSEfIAJjRGaL+pC0Yoz1dG7VqxRatBpmZddJKOU19mRHJCajhXVGmUIalK3wxjyZN6qaU4uiKbAmiw8RAWJMHv2uSllAlthIwM2oqUZcUJ5MjzW7g2olgYSzmo4X/DPLmFhBy6YSDBjOiNuF0QtavQVLmG9Z6A5IuXkJKuCHExNQRzAIqKSBlZqL3L72o1R0LYUaI1j98Q+QRWQLSnjEA1sQmC61cGDgQI8rjrLg7Lyoprr7MiKS3dGVINlsNExJsdMPLGu/1LmBFzCApQgmcEfkX+FSpVH9fZpbJIsuO8upJIYpDqRUiFQprJsC2o44D2hBBU09guUqrCtlobdyctFccjNkCeUbLcg6yo6a+x4ZmmxtV3YAO3tgYiZ1RcfBQaIfmqliniRIPKbVBBFQY7Hrxe1k0a2UvSKkREXEcynB0XljLlZd6s1yuWSWAZjUreRFdjl3+qL0ldh1CO/qpFMZQaIcGv7mtRNO+fG5AI761K6eX9E1eizVPZVltHhm1RKKiGPscqnG01GN28mEybw0a+8a+GCPvH/+yj515Jk/+rDHUVGnHTWPQJJmWjkebTdyrMftmbIlHslIrKUXSQdsh0iRv1DSgzcHp17BDa7ZN2OB2RirN4eTQ+e583NDYkCVAhpnK2GC0oQv5bpIU2FX/DIh4K7F05eYh3aPtJaHGjdz4YgDMxrf8Qo3UFlddinLY7F3B1ToDclaSwdm6Hl50iHkYa+2gwcmBmE0CmEPEa1pZ4mHMm9b+rol017q5BmRA863UoBkKzWye3MNlk8ErUD1I2ZwqNw+tv/wgHdrmNomJ9yCoED/9gOndvXQhZwBs0X1IkSVRKcSEh7HYTZUlzBOF36AtNBtRQgC/0nx3El42VFYuCWxYspFnhzgxOddS4Xv2qIhfX4+uDSw1qpPVGqR3UuL1ZRZcQkih1XUsiJXz4BOs0SbVNMVySPPA+cAjKQXEODFXtMp1XhUBZ7TUZef9qr2JIp7DsQ0b3Ha+JuqAV95lyYG8sbOYoZaaowEWwjyFZVFVqGKmQcnDWIxeKv02Uo9+1SpDqi0y21DgWesp35Sb6a102Mh9NdTBpuF48PosxfYbVUF3RthC8yewm0NxdaXhxH0Ymfq8UjjitWqgP4OnGqBOLPlzdJZCbtS7Zk8WtbRjYa0GxlQx0M2aWixSCa2409SY9KJmijnftWU6upIra9AkGJMF6XYk1NVNmQdx2fPF6+GcUaSoAlI9PHkFGe2EY1AN0RRYJZRSoYtApX7VMFNJlutDOx4uyUckKnFJPESsMajUr0E6LhJg1GPgQWU0oZdFDTkEVOOyS+/ivz5ar7MULq8Kup8iUbTw6lHpqsmIRcVOaGilxSqhm3oKolBuw582dBugXcbXV4pJswHnuCI3NCwP/NCQTFrBYoSyehEIJ0UrM8Sk44yl4NkXDtXqXfMSokwNyx88tOAIMzIZidhAnVi0GXToZquhpI8IaxyWUEVDJ0utr8Q8thbjGzbbCwKo/ajMFoMnuaYxGmgvus5wkMKpByMDl5GIi+zSkEeKcRKzk2mZDTVTMpS6jpEBlFU1LGZPRmMjEpJqsUeiq1lGpeBuAzXLahghpxFZNqLv+gJWdYmYHi6pgEKRiha11IM1V5bRVAhO1JDTogXZsrEZcThZ6cDG6yEAU0JJKaBmaDJ4Kb242EsduaQ4R6ZQn1dMQxseRD0CDlJGDyrIVkMKHtFERODiYNWkYAHN42CnNpgsLDoJcfRc5+OH6C8GUR2VeCJEKI0DQQCWeiM2kd06Z4SIS0IVJZFDCHKcZhnScUOAuIYqHKjFcNgaEejDIZyISF0Y+OYaoIZKAqx5VHwVHZ02QesW5BIQy/SQagI86CULKt/c75UQTV9BPUBtPRn5FGHxGhrqm5AQkgrfDyZkf2dASzwRSD0aAVZGJOoWg4YwIqoJiHFSrMhJyOYyhZweApx+HDx4sORJkUrooyS1/9blAj6m8OkjzNa3TZZj7cgUaHYxpprGDYcBQTBVLZvRaDdVMx7k7i+6aGVTBFKPToCV0Yu6eqMhlIhqZNnEDfb8vrkBJKeHAKcfBw8ezEVSpBL6KEntI5tFlmkZhQXQiAANJ3UWtLehdFLEoBiZMTb3uK7b+1jyodMg+p5TkKrhD7fKDESgUcncIjJKepLge1ET+4FkU6fvtsnJoQLXj0dRK1ztanAr6KaYAh/qcfflrrkbexIC6mtoxqmtKOU28cKfjo56/JplqxtrvN2ekYgKSIutmZFojlu9yYmku0Cp3frZVVQP2aq+jKKGK6IaKts1OfJ2cbhXqqWuBEo9LhFYRjf6tquGSBJkU1CERF2aScKBGYbBQiuJ0oeCmqjCoZuCLNf0xV0FTWgYwwgoUAU1gJkMNBIJDZiLyDGZo7sHreWMFsZqHtuxxOGJFpecGAJFg5QGfZ1cpzYoOBtZp8YSQ3VQ6FQcIiewB23aBJlmj64UTj0YGbiMNv11eQ1dpKhG9uK2ber0KQdh6r5Oi1rTYCrdKcstcL1Ji6QOB5NXUA9LW08XDsYnMLCIDZO3oYkNG42SXSYISzJKMg+bx8cmHh6BgGyyYSMz+4og8bco6cWDGORnA6mUQrO7jMc0DQk0YSUikE3nNSEkzoSYJlykzyByfY56fA8quPyR1vdURhCRNKYq6sEZasrIRmU/0VDNhFjFTrGci7LELteb5CxqGsormAcqraejn4Nm0rchIaVyjmJR8hs9odbkZGs5jpepPCZh2YZG13s4P49B9VMgBj21gVRqvC5ZkEnjUZjGJIEkoZDWHNXCq4ekqyajlCIfkoZo2hZGtmNlbRsl1FzJbbCeYuOI13euPOM2yYGYkoQchHpcLKAq9tJ8BZLDM6Zg0gm1rjdputREYAHNY2DgdSQxm2hylLLYORWVvbfOfRys0aPAA5r2wBx80H6axzWyU4HJnmbQ5lJInYKQVZBrBTbHm1brSJGOrLQ3nTezkBLW4qzIgpEcT58mZic+dd41nUJbpo/U4DoVoqwl101Cyj+tflIjV28mmXTi8amok0s1sMMgddIZSL+pZFRoWOOfUMI6jEvjrQik2DS+CzbmzHxHiAPUhAnI4OPGzk1LInliSwuSGSoaB6uvr7lqpUzaaSawoc2Rr19pMpVeq/KLSsTbA41GPt2xSZWCPmurTkF4dEBmUNsxRXQ50aefdRUeLTZf7tZTeEIx03bEek4VTBWQPIBJ0qucMgbMSAIaOjhzAI1LraPa/seiiiZnsG22BWsURgrYYtJQWp852TwJ1l2YLrODrkvm9dumdhBVzCv5mHMyqRGl6wj7gJfXdDAogqhCY5ppYpguSBOlMQ+ijTVFHhLiLxYesuBF53m5vm9da75a1/UevNZQHYPaWsOUhxmR/u274IpCh7nQ43Emkxadwxz1KX3dJ0rfA/WkGbkkwOi0XBYcdb+tgrezO2dS1deXYLXO4OZFSTV1OEjzkNgKwRTi0I2cgXZ4SYK5dyGjjwJSPSB5BRl96LcuNBRSIJzgisimZc0SLwLZDEWzjDuTZdKlmvLztz/N1o+yilEqVDU10qY5YnBqYWpiOpHRh4Bjkm4monGP2hpO0VyqOwxejcWK1OJjvi6U1zQ+1Smc4pEd7WGcsY6aBKaq0kwXyieDdLkdTA2NfFCnal+jKExV3AerURpRiTqNAhkeGDJaPQpI9cDkFaS5s6gnkHTJs+QIJ7B6hreKrjXhGyKQZig8rJQs1PNJOrIIuEYO1RAeIDJf1XRVaepKyitp9hKnQT6yAmOfWbo+K4uVjnQ6cN2KqKwlX365x6G0i60a9bSkuyocCEcBW49tUycy0SjEI5OMejfrWnhDS6bg1eA6paysJVf19MthWmWvxivTb8IzYlHJp2M2KZzdwHQs5kWpycIapQ99XUveFpOEOdrW1QQpWqKQxg6pXjPTBUXaticju+RRtgjBt+xLZdeLPK1TkGnuAegqqEeurSePyBXeWdMG5erQj3slRfqO3LX4BpyZmMq69gNXobAhse3VFcsWJVQ3Tqpvqkz6VTxznkw5tHrI6krKDJn8Y34agmqwj5xazLQiWa5EphXIuPKMseL8+rZFgEM7QZrDcij79S1+fHYFug+/vkUgCVzXDcg+F0uYVX1B/0rzpmb35dXlGiRYnf+Py9evnldZXv32+r6u1397+7YiqKs3qzQpi6q4rd8kxeotWBZv3//007+/fffu7arF8TZh9nW/cr0dWkKyhWabK8VJr5fwLC2r+gOowQ2oEMVPlisB7HIFyvrrzT9hUpMY12dOl/w6ULlvsH8Wjj40EmcOl2H7qK+Ff3cBlLhF3Gv4Bnftje5obEPRMzRIrBDIeKHi9EqsjhBcIuEBZS86XfcXS0SOImtW+eZvnv/UtfG/bP32iz2GD5B6bJVGxBQ44EurdQZe2ky6HEa2yBlnt9JLUHYl9hgX1Qd4C5qs5oi/+Szi+vUtxwE8r70VmI3TADwHW/K39EHBMEaXoPTieCs847A+1TiPiCuyx9mpMMyhokAIhfZ4z0F9zyJrv9hjwA+S8sPsvzkIEpp9ToDIlykVzud0Bdv9OI1l83VrBG9z0h4ia6pYAgvxUlcdR6L69n5vUg4PW2KP8Vs1xDJ8KzMWJ1/m3k8BZSC+4zQH+DURGcq+zB5rd1FHZHWmwE0D5IL0bb7aY8J5IPNK0G/UZ5eF9AtOM84uouSTC46rEqCWydaTxUQVOHDdeokfCv+af6sTjueYkq3RNMxbvpEW9rDlfCqVc16maBtfc0K3+eogHmWx4kSDfHHDIC5vm6/2mK4KFgf+26W22Iv+mz2WC7jOXviODB+d8YhdYgoc1OIJpw1PXGofJ5xEkw8OBl5DNpicYdd/dOhHseR4tv3iQIcSKpQUW+IwNryotD4xZnSbz264JF2jPjssN9Q78Ly24MucerjEb96BLHsROkmVbI2Sp4capuVpTB5qXl99HD3fLiri1Ht4AURNxBTY4/tInpShEbVfHFavouQwtF+cDORSNOo2X122mFX1VJTcLG2+OsxVDm4yeFnx87X57LYBaD0qSKstETemIKuEwcpAtkZuO/9//3ZkiOAyqDwk11B/JBONbvTypaqhxEpSArnsSpKsWcIlHci0WFb8HkUB5NFO+0yjugmq3B07+4yoshEJmMsOk/SQ4ML7ts5tzk+3BszFa5Onq2ZFHK1HqzaNMOu/EcsdsINnPXZJuT32tkb/kquaUDq47VFHxtDhIA1lwO6jtJxRjqPHNh3g8bAlDnzVD0RgJLrAAx8JtVAiHUpdPCznJbyEGcQPGfM+FqZoe/k8MmPH4OTpvCSkYR4J9dlVDBQYhUKX45j29JM/iem/Otn5ibgEbL66YzqHZYImlMRZyHDS5VMehVzeo+2C8gBWLHVyFiPVSsdfcU5jrtRh15Qu4dV9s7rJhR0dV2SP83tapTf8afHw0UFOmpssre55FUd9nvPMOb7HZ+cc3cMtjgiq3F+BT6y28UgUqrsvctmNlWhk5HkhEoUlXRcUMM4CuciX6WO6lPjYpAB7ojqbLFMiFgodrLvlKs27p0g5y44pcecvuEL6SLRCJcVO9H36mn9Ee+xzYdnkyxz2ebAG/wFfntp7T8wOjylxw6icLaHQDe9VWvOLEvXZYeazrHgaPBYkJyM3ejmEQwvrdVk8wuUFwA93XjbcSZik2EFWi9qAXg7h3vurogaZnD5SCK8xqBtRAjkfL10VRwlnG7El9hg/pau0xh0iaxnXY6HQoacPDddB/MHFY5M3tyCpmxKWaL2pvyCzjzeUVDD2rfyOuInF2X5x2flu3kZht72b7w796erIlnS+zOWI9Y8mLeHX+h7ncujvubJnrTII5xY2xoAcP1PuIL8N0lsAvyeKzICj5ZLDxsuyEdopjHNI6sLFcQ7f3eOA+JmlvzsY53nWiieVsYUx0SXlTh7TVpy+3irwyyHcqXH6vE5LEvH4AbxUcsrwMO6tkBtdBINMttRQDhtXUPF5gJjNq1jsoE2ZmnzvxVKnXuPTwKO7EkLRchRL3Y4eh4pXONxeOIPkil3kcrg+wwsmVeCiv7pKJy9JBj/B/I6Pp5VD+LZwDsu0EOZRBePRCjEwCBpBE8sgXCiPj5Tas1pBKTJFLjjPEB/0R1U8UrbMZT+0TLEkg6yvfXKP79PweyMVlFN8IXg+fUb7IDG+cFPggu+0EmhLPjkEeYHnE7QpuyvwCSMX68UWOdlkaD+2yB+RxKLK/ZmiYJTJgZyi5JMHub+XK3J2t5H6R48gzcBNmgno1VB+LckHIYdwOivVYBdLHXYDxVM79u7+Mz+5snKnXVJ6+0K8EWdF2ffvGKK9qbBTUgM6HEWA5KHAXlR8l004iuALHffb6sQ0wsbbPoeNuk3iDe4OweXzLodwbaE9CNe1wEM40g0uu6pCIKGk2Enq8Lpz3LwcN3Ut3DUTSp0x/0ir+yytag16HsSBMq2uySBi93O0DxMPBeQQDocDaDdEqqYJf12AKXEKreZROeP4mi0laDZfnX2VJ0LMHVPgsAbhXP4gk/SOLfHDeFmDEl9XhTjDuhgFq4X0a/E0X1q1x8M5cFjnXjzNcZSIjNFkAM4RQgwWKGMfLaBzzJBFezpAp50YnZOT24bp0nWqcaL1GlbStOaScRiBncYyPJJ+tF5nKb9XkALY4/8B07t7TtD7bw7Ukezz3Hd2P9Ilj6T75EAvyXg+Oo9nWCP06kUD5tGWTrEogeY8Jo96iA8zKEQ8DR938+heM9bhURDBf8aVuYf14KQG4jVrtszF8q9gt5xJHBViqQfmzxBUTQnbdOhS7AyERwuyQFWh0AMv/qHFTQO4Bn6Rw0vR2ycUOgeUtS/cy51EChDPNjAN9E0MEN6j2DwyqB0JDbY1QTbDwh12b72Pt3MPs1FXHSfOBv8bFk3S91h69sCVOXnYVZGHXNG2hDT2tWXqhy9z8Rd2doy4s2FK7DF29oqAj/7ufDpanRTNGgf9L4WbrmK5g+2gwOqHrZ8FcvRPjH8Vv7IQjhEH7Rlb+7yYEHFAF26N1utc5tgtFaL2es+7h9pTV91WtYej2UQsm68uxmfcLFLHRY0260qskmIXN2cKBNcm+eTirmvnWhV7Jys/hMnpcbVhq6pTMbHUAXNKgpAElJvPLr28g5fpv4T7j/1Xz7DA6qpoL+HI8Ztg3fv/VXYcIhQ6upsvQH7HLxlMwdwBqGM7vnYnAHAb3Sz7fedCTT1y+/17Cp8+C1aiULg1BlenPQPvcrRIfO5yqGqOY2x1zclShHFFLicmrpnwlGoHFvL0YEyBS4TLIauXWO532SmOnDC4/K8+TS01ES+uxjTi/BeamX16nSsiPAWsBGGAp0+LZRzW6ptWuT/8sFEDuWgyqEp3YgHuFAYg97gxBQ575zTLsFe6z1/CbZ2FUhebvAvBlKOWFLs44dq0G9iaZbO78M44NZxPa+fKKxEyCK8W2ARCqlY4KJ+W+gmQ7u00YH6zRJSBbnoGAAfH7nNdAjFLMfV5e1QydaYaqIspTD5KWFt9W32PqG5RfoTPJJsJ7xlnipyX9S3JPT+v2RnJH85i83GLGzFsv+mp8kn6eSMX1RkE2GbtVxbhRgVfvP/cSl8VjcKwNEJ/ptVj2X7GpfsvuQjClB0Y2IuB43FuIMvOwavhZkDsg0OaCqrDORXM4YBOj+twjLZ7x2iH46N9OT6aK66mk5bu1ZIoxlmbWcXfLFPV336DTKKKndVwO3oxhpf+7oCNZOzhMHXfXC5IZOvbJvsvWJF76/xNCa7QGe+XQo12KIsvMgbuXlT499fb/yYEkbEy8999gslYFFPxet+ssNOlvjtsFNZHyyVaWLhlh/rssunokzPxu43N9z+nYnfUwcdZcdcnm3PnS23tkXiybU5UeEyBw/kIGsJ5UYnJb6nvs88Ss9J1mi7HIhO4aGpRjbp+tu0rVtFNoT3eH6DqRsOipL/PPo9f4FPlL23a2uNKm2iosCXzyS8miiyNO/199nk/L7Lse4HNqAuY4AdYPOTWiGIkeUXtHuXVk2gFsCVbt0UJjPxXvB7uYKxNbaWJD3WyJU5XlSK9QxTjpad4bxn1dc6KcgUkiZL5UnfMl4B/RJotcXBkRU8QHDvx1dHtbZqlEo8qU+CAD6cp4l103bfp3UeLqo3f6Z9G4yjGFTpEzSiCiPyihT4BZKHK91Vc0Zy7IdyVT8Vdmkuv6Ymlbpj79FZK5ALA1qxV3ewEnsr3c+y+VClrjrNSnaVlVYusT312m3kR1ebrtGsUUsdrkL8IFm370QWPNJbOLz6vRvyOvj2meSLoaKHQoY9CqrET19RiLdu949e1/qszpvdSTO9dMP0jXePtPsjEu7lckYNVcF/kUJYLmylwkJ8+iS8nP5vPU2j5uex6IgPBN3pbSfIx61U1t/UwnRxvVl2Er+Tkc1PkilOe14MvczgHeSo+wbpGG8mqEMVPLHXAfF9CqMMtKXeYowZtrtJEipkv87g1+B3In6buSmY6no1+rBp6KD2TPmIf6wzTSiwuD+VkQrCtOip2wE987lzc5YjUbZpp/uSKLXKJa5/mcdsxnoSdS9poezVQ2GhUPrKmrz+WIz7exiCCaXFzU8LHFIhyy5bs2hI1E3P3Z41hfN1j8TzHlVcdh5s/gfyuwYnnOSz092nDaI6LJbepbb+4Rh62blnpg15DkQPOLpihq3sieiLlEA66YPPMlboRJZDDHIE7jijtFyd3xlbnDftzRgGPFVG6c+6JXnWF6fAei4cOV1fdVuO/7/FJk5E0BNKlYCh0OL7M0z8aeAklu3KuyMH1loG7xQr1ByfQEIcuKXYIuqw59zP5ML8M/qltsvZu6GVdkoiLqmjK0H2HDKOPnFuh2QW7re+9KE5siTtGyTVirsjlIPisLFbnWXPHvz7JljgdxBdNIsgV9XlrpKCPogrj/B6LZ8ybvOoucHiMnQl5vZozeNtPDqtXk3FLTPtlnrVg2y35w05O1872Wfx/zh3ZXFf0h6jPwMtfAx7PYFhV5XHWBdyiLAB26j1T/4jv96LmZY8r2mPbHBM+nPs8+W43LZFwzmsDFDutKYtdHIpmsipGSRFMFvzfG1jVyDrHkiWxB9jiOQ8rt92y2tGjfvoINs61Aowp4GqBvPq2+vnU70X7vhatCGT3CmNHlTpxE7Pv8mVTB7P3ceZkvqUR6G3J2OHnc63zsFylFQ5JaO88Ba75HDaf9d+IYltlMO61gyF9G7tPG75uDQedPtf40lJ21NT3qNE0IYEJMbhJh9mDs9zQjcNlca/7xwir76myWGKa3Ka8nSQrd8feqXhTIxIw+7a+4om9Kh4g5zSgvztiO0oSWFUqnEypg0WO45qQ1anSF7LyrZH2s6JsVuGBNAMaDznW1B1HaK+KdZrwKIaPcwm/eL3b9V734lyeLeR8K2607VziJsKXhC0iyAbB4yscisrjSAdpkUcxfJxNOjAJZK9LMgXONwaklwUcnYut9uT9it1Xe0z4hRoOTffJxQFW1bLMLPR3d2yqmZSVu2MnWbeleNuSg85y01kgXFn56qlJVdTvZdGspXpqKNnlaxlfhrWH1yz95zmUFBZNqfnEFBwUliXPHPJtjmS2ERUQwWwjeHzVoaLytvq7tv9i2TZx956d15C5CBOYdjrdZUVRbxwxIY3JMgIwBY74xDRS1GeXo0jJe0AebwDF3Xl1V947H4KQ81EodTl+bo+xFKglxY7zgq8dNgJersi9v3K0YqmDC7F9u0qOWCh0xttecVb6J1VA7hx30pQlzJMX8RaBHMKlhbbeBeDjCdgS9z6zB5YqmRGhHHb2oJZpHOqzK183NzVO2bzIkwx1TMbePIRnC/iCs76FAcK9BZJ2enhuUDcWOWRgi9qxySFdW+xUgmZsPIRnC5qx8BCeLaC6ouzJITz1E9LzKbYxQXYGoZRkFuAx2pYS0wI8RttSMluAOwVv4CrC1dL+qyN/yLnOh9N6aZOg2xS59k7Mek9/d7kmc9vkS7iUPTPKl7lgfQLl8rxI87r6AUuI5pYP7FOAOKxz9zB5KJr6qK7L9KapoXKfp4cMaLH6z1VmaKoFcV+9VSGfsnKHUKTIeToHy3utsMjXzgGWeF+AlC7a+CJ1cIJYRGZi6CFdglfKpRjqtfnqhkk0QTdfHTFJxuw3ws+geoBLPTVVMG59Pnl8fC/2uP3qhun0eZ2WJOjlc5HX9yJSAcAX/39BIKEyX+7HwR/SEib1B3iT8rd7VEAuLqihWpd39mORSdxRKqiQlmQcpIbyaukY5A/iVksK4I1fFFYpgB/+xYkaNS7zwtpnHVRhHsq9sC9uAO8e5Qvd1wVik0gzV8shHCStQTZjmf6LiOlVCfIKJPinsLBp4MJbE5lUDxne4gWsGj6vuAnWRTuucYYFDT3lECEtyEakhnKKhBisPM2ANGAul1fK5B5UUOmFlQK47KtS+d0LpsDd49flCJT6+/oyd6x4w4UTHjd1u0ZrvXTWlVwOfOLkfd+FYxl6G3UBVyDNhZsVChD7Nj6C6gt86jbrXwoc8ZpI8r1pwLbmOKjfcH+r0N7pY1rV4Q+hS1D65BS2QzPO4dHggeRlhvru6KCQHk44LhW7lvfp9/SW7J8iMpcEpQ9z2aEZh7n6tnks9HcHDVrB5Y+0vpcymVDohleSKob6/Cdg3Di8GsCfk13h78wxilsk74apody5X3YGx5c57A4k3lp3L+2i6ntAriMCwWaSAriPHW1M17K9kqzcxfJJ0nWKTQ3BpuSKPHBKbizxZQ52Mcyx1S+avtR3V2ySDjIFDh5CWFXCLfnhows3bchOjD+RmyQAe6xVB40RIfzIM2WWpu6IYUi4QUXo0KZoenvyPOJz3X9vAKEyi2rz1cHwyNP6vEwT+cmwWOqBWXruK5a6UFLVX9++qvvp20fpgbPHsXK/B2qXV+mgFSC+bUjJoABxMBmMx6Shx6OaY1Hv49APxVOeFWApyV/GFbksVH1VpdkjAXCJlE1gXsEehxCsLxY79B3pzx8wvbvnXyGkvjuEQDb5MoN4leGCH6nvzvr1BN94lWnYtmC7lucvJEFW8PKM0fguz/K6Yy7P4UvpFyH70Re/hEdXxfBEriySni7eY0uR9tDG8RuJGH3cRlZYxuHUuLHe7RA4rdR9c8VyjErway8SZEORm99Jtpunv0+/l9s5CcKnSG0i1hCp6bF4vrolr7rdmvyqBMkDGpjs0JIvc8CKwxBldgpT4HiyCOVHoHyZ0zlh+ghL+WvBQuGfQHrCnRU0pgApmtJlMbQpOQfvv3s4QOSy6ew/dnc0zGbD1E2ZX8A/SAbMQOOFQuVltmjrj8RGkS65xWaguIZUPL/XBQRVkZ8VZTtbvK+dK3TBS6Ydkr077+IQCr3xqiM5tIDu8yZPPi+WunAquL39IiaNpr87eH2WqzSXhvixJS6UpsRXfnVQAbKboT2zLfoF+fMEKd8YCz+LzWvxN6HYbs19DsrOdBFvutIlrv45GUa2xMXY2dBYdiQtK59t0x7xvGYM33Q/KsTCsIRLclAhHzcLMcdqe9B3Pd9crmEyRCZu5j4snbAOtU9uYTd846jFmOInH8nXtTQg2wDreBvnLM2Q8AlBsXyZkwp9+pp3ZFC9L8AUO3vFd+f5Dd1kBRoUGsw+xoUTupEMDWkf7Ph/8qRJ+8GJY/BgNO7boRRau8YNnf4lD0tHWNkRHv9lXFp57pmed16+gzJFRuwgCSfF6ibNQfiqYcbvP49OSEdaQR4abrHAHxwicmv+4dL2i8MJI8ibW5Dg23kl2tZKbwOrYBzDwSRxYE5hODC/4y+P99/ssfxIlzyS7pPD/SnJQdhH92AdUEFCBNlxsVDogRf/0OKmARys8KpK73K0+00JRyz4Bxhl5e5neDhFqXB9iStz33jjIEkeK1/mEngmewpo83V/XCNIgyYPcu8FV+S4m/va1F9vCYousaO4qRNBtn31G2XJi7fO7aLDoauk3GTJyh3CG+BzjT6Jj45R390uTvzRpKXsvkT/3UOcT4q8LotM5uVVwez/hiCuzEUQtsml7ChLgaA2yadJN5SeOZm3S3GTm6GjaO/2zmk0Fa5AN6oe5/ugUMEysF3jZlS3KC//aEAJq4u7G+6AhS903AYdLf/ZVLV4vC4UOmxqyOZDhVgsdVnLzkt4CTOYSG5VMEVTrDUqjEQcZAsjU+By4yN/wMd7UvtFKNzD4K+rFO30MT+GKcMBjYfm09TdfnM1doZ0/BSs6hC+L5vjGNrFrzPXOUL7gkHQsQH+6XNKIK83t6tYGQFQcu4C8sGB6avsNAc3Gb9Q0N8dsMGkKaHQJ+qzg8NOfFToo/OLQsVdMbi0uBWBLZpzJfxYr7LjYvnCd5H+7mIH5TVi7N7v9gXWT0X5wJtDcpjtUgDdpwh6oAPzVQfK6uNohbZ5HsfmqysmUcvQ38dbIOeyg+7hCpIdDVJfgbYQjcrHHtLXH4d9SKOcT6z9NOXCJMnj5JzDaUcY7hgkD4uceLvpRJZhrKdA6sGE1phGOi6NFdkb0dSPGyO7c1fN6LPhK7hCRkuoL1aG0YNV7dBsqy2OX9Q9B/xJ9ebrHnv2T9BE3RXlSxxu4rF5cJIZxYGLto6L+litKEzEIQsIHTuw0O6w0O8wh2WaRDpi5LH5ZNU0otj2TeR/wJf2sVkG0+arEyYByWFPIeXjoyS7gEkRmg52QOPBuZq6286ycf0e4zj0F9VimQlhaO23rWHDb2UUNhzQeLChpu6fiw0vs4a7P9V+mSP2UfUymv5FtLmcyck9XDYZvALVQ6AzmcLk40zWVt9Wa/ISSV/OBwwPHx38ksIbb67vu0lPqnyOqepi/TU/LcuiFOyATYGLNJAECGUtOIDYEjeMp/lSiq//7ti/JklgVcl7SJU59lGkIfV5azTA8LJioDXVo/GxptR1xxF8xcPnXg+ex3rMR7b8qBefubyjEFRNCdsIrEC3KI3Kxx+qr7+1KwZ5MQpt7p6w2cZqWLbIHucFvuPF4uo+7bE3o5v/Dylqsgo+UuKx+TOkBsWBJ/ecJ0+asoR5Epoct0PjkxFXXXVbma/vsfj8ClvixHr8eyvuOfUxe30qUKHwCCtT5OopOSvKFajrlE/3IZa6RPeuUmRsXBVdaCAX3csVOpwqNzdZWt3ztg31ec7IsG3KGKQcdYFfM0SbEhKqxQ6bLdoaFYZYsFnFC9UQ0HnoNAsc4yg3uk3xvRixdK4gC0IgHtXw0cELUazThMczfNzjoI/zkryi0SUiDz1bpXF5Ha3qEYzE65FCkc7KYqXibr7MhTNVONkSJ9n+J0xqQaTbj25XbcVLtq7Xa4Hkai1wPDLpfA7HL+1z2zxCodgL9/BCmhI9BbHHGoN4ZlDBpyIwBptC5HUOqak9ku9s06T06rZYPFvsoSzpr0e+311mTow5GoOSM4kgJpVjGGlFG8GrEb7ddT2nmS1ocbUG6V2g9d9j8QpSVFXdVkdGLIsCX2tikbRf5twah7oYZvMRExs6Uhw3i8zLQ2zAsK2sfZwk5Nne7oCMZwBJ8S6KTbwQkJYaCXkQUwiW4crm9/Phd5nx7QKQZXwuLKbEwUasa5DcYxl4d5aKgWGSYh/c7/W434fg/lmP+2c17plU3Rf4VH2CdQ3LeM47OU4PxWeLaCT9J21ddOjp4BxlXyLy48UCTGcG7EiA8Mk9TB6KJlYyLQGdjzlrxrGti/82J5Mjb+vhvVN3H0WOWw3l0u8r8Hz6DAUyMAUOVAXP/T0swaXJFjktX1udWi+e4bUtiiVCgjU5zhgqZtKkakLrgg9PBjClHjskKwuT3tnebUyaEr+Bcg5ecKux3p+WYfV7g9oS0zhyxzfPY5OV22OP9YrvzrnQebLF5bYIbDaZXn9JMihLVc8UOOI7h2VaLIUVgi1yOR2uQUZqc04RpsBlm4OmT/6WM1Myh2spVrj5Ik/rFGRSAefL9ljOSRxf+i+S/xIPJHRd4fH5rCgWOMaR9dNot/v87sApsZFgS/lda77MA6sCoTsuyR1spmBruP4C4vOHPudr6NpG4/Ja2fQIxuH18z430jt+I7D57oHtvQLb+7220U/KoqrQbiSLwlE8Np+9sBHF/nLVbCtpYCSUXwTUhJFPqKlP8BFmwqJGfXdxXRZl3Qd5cu5KusQh9LLJMilCpsDBRFx3B7oc0Taf54rsws+WCpl0h48um+dbWJawFHAxBft1J+GsxK/S4ytCXGzu8Nklwo7kyv0IKn5zSBdsjYpCH+o0OGlui8QnxYGq5rae/PyJcgptzlxCd4DU6Y1PVlxd7W3lk52zV8mdlsBpxih8Jlheb5ypbeNcxQmmv7u4jJKsWcJFfpmi2oDbiIulTgcdoKpwMC4qqOXHHSKAi73QVuYNhv6rg6sxrfkbod2nKSPVPsMadNHLnHHGlrhhVL55JRS64ZXQjPo8f/zbBcyRejqqfqTLO1jzhiBb5nAsSGr8o8i5odPfXbH9KMG6M61kSJliV9xo1/EkmSmh0BXvcYGVPy/QfJnTMS5apPnHXjZfHWUZP34tijP5Ov1ydVRVRZKSF5uFNQstpSRm9Ppovc5SzOmUwaJZqPT1+OWph1YZIWiNXIqrv7KB68uiKaXPJVmtdgNq2bKHiTn0JbCbV6DE4u3ZzZ5Yjt389a10vkNYYvC/OTHEppaKHRRuNCsy99i3mheGToZxQodmakYgAW7oT7Ss3hfL6wtY1WWKjaQTPEqThrCpLexlmTotoI2yMLcVyCZcAxGYxaLLgeqjpd7UTNO73q6paxu6nDQitJh8poXp/YNm2opYA6d/QBhh4iWdC5voDs9sE32cZhn6PLhvLWabr6Kacpe5ZnEG0pRDFnPaOdRhjOncMWTIL1M8n68W1Zcmy357fQuyCjqOPph5zmG5Siucz6zNNHxNZ3XW8pCpppD3goOnwS3YS99c4OwJyCPwmaHDgWsKhWs2fWPNKqoaKm3jyBpy9Nu40uwLC1zAJ1Auz4s0r6suIPb6WwWXP9L6vnMG6yJKjJXFGBKhigVfGBsKnAEWVwQ+MXd4GxcpExniKZzeVHexcIQ6MUwcDmkgH/HYYmocHvc2MpB5/OFmTrdx7/6/And620YGLibyIoUbGBsrRkQcarp4uSSsOxfFX4IwRV+hel8rdoiDNIclDzI4c7svw99V/wFPKLiDn4slzKpNPfxUwQqQEVVrkJAd/BKepWWFQ8PBDahgC/L6Fer7Y4q0Xn/k1jlc/shOsjZFVg/wGeTpLazqq+IB5r+9fv/Tu/evXx1lKahw3EB2+/rV8yrLq78lRG5Bnhc1Gfpvr+/rev23t28r0mL1ZpUmZVEVt/WbpFi9BcviLcL189t3797C5eotX71Da4Xlp3/vsVTVMqNnnDo47ea5f3v9W55yvPHrf0CB0/oZvoC3r1R65Ne3fMVfJbyFu/Db6xRTlkgjeWGKRJcCfK87x1CQ9Oz1K6xu8KXQQeW81aJvT0vbBvJHUCb3ABkin8Fzewfit9e//OSMkzlUs0Zdl2IIhoCZTVM7Bm7KjutI7jh6nDTuFjRZ3SO5SU1I6AMWAwPCBi7bXBtD1oY94URqbFxLvHj/bZEv4fNvr/8fUvNvrxb/ec1U/rdXZBL/9uqnV/+vczc67YhZjGZgH05on97TMOm7n35yZtM+RYcbfdpaKsJYiQdS8X2raCw3aQ7Kl/+2As//3RWTUeW8/8ld53xOV7B9XCYIsbUkfiie8qwAyz0Rvn44bVqQtqEmT/9oYEpQ3qZYKaoZzV3O0Papb5SEo9rqSnXfKTT97HvxZ4/vmLB4HJ7v4hdkHOqFD8tzLpEjL2Snz3X3tkMMbGjHA59C5nNRXZUA9YdYkhQaCzU3RA9fU0gGrffOh02ZeOS2N/hLnWLiB3fJvEL52AZ7opQ20S/+azBOzmwwFN0XG4zUwnB2XtuviuhdvSrG6OgFXGcvbr11QDtGj09OYmM8TpLYKIf8gJFtxjYQM4JuZ+978NrQ1dLGC+ImisNPvjESY3esFkEugaGbfc3WDtuAMNkJo28h6Z7uyTrRJaLTGf6//OJuVrb+APNuhcVtw2sfi0ov5D79PS/KOkSSkEFeykzK8I4NAemREbf5pS+roN0D3oe0/hqk3AgHolojyF2X4KQNt9oTwWPGRN++0Ez0X37ysGJOn8ktDCZ4YrGsYq+/QzNt6JqphfceS3HfBBt+N8JYujGQ9vDejuxAn/mlzdnLkqerZkVWt6MVWUL6ZRcm6Qpk2PWPflXEh//ur4jlsKcWzbpr99HgJ2qpxd7HP/pRyl4LtCdDx02+RByM5GXIG4d29DV/GruzimEzPndTiq4bZEgxKfn8eZ5NPBiGi8tvF3+R4dlrT/jpvE8N4cpMQ8UgTmrp6d0JrnpQV/ojyBAu7O8JjKVRh+sVsEzQhJP8DP4Gmo1F4bzRxrkoNMeUvj5ZxOZUduaAQX9Ml/Dqvlnd5NTWxgfRdzSfN1nQBFAvYwY46SOdrkb1QOidu1FV8n4pYtxC2Ep4DkrUBZLdbEiSFYax43SkftPHdOnoPglXO3a+nVH0DoKOjfNouUrz4VGxCAh7xukeiQmbanxv92v+Ee0EzwMXF/ZiedxFRrhfHoGM1A3zuJ09yrLiadhew8cUPgUtYEfrdVk8wiV+HT2/u2xWIfP9paij4uuRkUSq3GAD+xcLZXcUcFUcJUHrv5BAwB/V5UMTXURA3tyCpG5KWKIVof6CLJ6NfRCrld8Ry8TGuah+T2/rE1AGWUU9jvD1tHv84Wt9D8tz5rq0X8/6xySGpVmvHn1OpY4avHGq0wQv1UfLJddkUPcX1RCgEyGyJGxqvuVZK4Q9uqCRIaK3UvL1VsDntRnskJw+r9OS7GA/gBcVRpfwGZIEmiAM5+6PoLoEyHKAMWaVxeS+nefrh0TVoYHhc5ejuxLCFR/w4nGAMyBqn2uOEs4z5GgP0ycdEibBeoi+o/GdD+nVI2Bk0quH+Pqwj394AzVEl52hSe0PDIKMsmV7KwVkPbaTe3zRwccRZBvKtXlFKIQCp1UQCbm3hwIOQECO83znj0jEELL+9CbI0quL5CGSWw+7WAi+o0eQorppRuEMcNtI++i1eqV5tPF+Kp7asXYPMYdNA7Lh09sXsu89K8q+f8cQbYtC0B6D5IGkg8LXbQIPIvAWDeNbtDRkX0QMmBSyfHVHezEmpsXXHuDFwEcGDpcdKipgKJopitgcAx83L8dNXW/26p4ig6F/pNV9llZ1OMJOljOI+BIpZsaF6oPvBNnbBFWahPmFaQTRl46v2XLcBrptxgkVixO9jcs1wgMy74FYnWVQbQwPuVylKxghKI7GfZovI2LuXU2neQ3LKpgXO+3FYIUjM1Cn4SZtE+0XrlLYym6QzkeLJ6xq6tnEFb7dgJeSUZkV9b8/Hay6LGUho2ifoRuN2uw2JTr6H+lyROwfx6XNsCrF1jkD4rgKJ9YBZJzT0P5lKwpFzMtV23JKKh15+gjLFzyr7q4XtnaI44W+yu1z3ZSuHdKPY1DBbnkNdhQMuD5DUDUlJNfU9WGF3t0dNyZvaAb/YJvy8Ei28TdtBlyJWyz0KKAL74ElDriK4aZhEGIyxMR3eV+0nh+wCRePGIE2xBbtR7yDMQrA565yT6Nwv/i3CsYJslKHbEU3HPqm/DWIpVuNftMyzHboLJEImLozruqkaNY40ngZNGsiFpVHxDeEjxwfk1UwjFE3ePDS7eBXt1Y88tTe+6t4fMKPcKSQK2Irbokc5XJc1MgCix7ThPMOxRaUnu3iBDYdwpGY8MA4ZzbnKQkw8Qge7yuGGPg4Qu0y/RcMGQETnFVdFe0NAh6zlw+3w/GVPUWwMXXsov6QDX8B8juDz94vhDtSDGBkn9QWRm7thM9i3yLEZRQk90y/p/Dps8Rms9DA9lHnreraE2OoG03MhDxW+aL+4hHhDQtVbh4G9c8+IYeHxDpzJNbpDgr3TKTmvVE3nk024lrj7ATrdvt7lKSxH5mH636oGTpzPGkvmgyqkw94rQ6Xazi6g6p75GLINRAUQ9aH88VAtnkK6KpgEy4E+OA3SM+VEeVeU0UhprNRxEbeU1ixUQrE3hn5QRQ+fa5LQGfpHMOupA/g9kSlGR1iHhmQT4qsKD/C5+5d6bjIty8JsqsptWe+2pltKYWXzKL9Tc2gDiyqM7TlbjZXdyJEHI/MgfTFswMXxuBCmqLufWBr/2m4cQ/ZcJSDq+jnFhTdDyc3cU9uDqctxt7t3mnL4TBitw8j7MMo+rcI24T1e7Io9aPyMJGHmmFGyZp5vC2ezC+qPvNEUCDRrrLpnvGn/vkN9+BAc0Jfn9ty5nzLPlhVaYL90g11yM6KcgUCE0v1uC7B5k2n7UquFOma9dHtbZqlwaYwuY8bZCeNvbovqva8oE+DHhLtocl6rO1yWHbfT6CqlWvK/Kn9cfc+FXdpHilsFuPrr3lboHQ5f6Ff33QzDQQEIRsX2WOgbt0RMdj3x3rd7TluP5Zd8rhltENDzKTRkEnXWM+np1ZrkEd6/0N6vmhjRvcVg2QEocdpdB/TPPFwMHDVQ3pyQmU0CDQFiDy9i4nsfRRk/0jX50WFM+H4hapJ7Kj7IofyDG9+eS/7TFhzr3/2u5ZWCvZEexo9ve88PL3E+VZ1S2uQMUsQxbiOd/VUfIKYWIuqMN61ee/Kd1f3JYT2+H92xY9EBJZpwuEOSkn5HQSZzFuVT9rbsWkt9OxLH38W2d+GU55oLzrf5Yh6baq0INf3RM/YRHj6xZ67aaNqT5h7PCt3xnX15qaEjymQCVfoHbgZFbo1nx5nxR22Z/eERT+B/K7BmQideXRTM4hJpWfHgpa2c8TYvE7pcHLbOlajZC/vcJ1oElDYifQmQXgslFfgLo7jbzsvyh/iKeKfvE+xxe3Vy57o2VHW4p5GJ01GbhTpj4Tdz/3IweElHGGzepaBu8UKdR3fcTPSxj38+KLeryuz49o0bQT4ZY2TVl/AqmjKvTHBZ7dvenoamdwnAVCPXHo9wM/0wUnCi9V51tylqmSzlifJRZOo2T7g6OgLfKr26EnC2Tk0ogVOnqWKgwqnmImDKYoG3k7j9s+0T9kO+/WwwejRWl+UKbLsKK+e9ibGDg/IIyqd1Iruz/NTif3DP9+LOuxtkrEvWSGi7QnXzL7Mx+OeNlSt03lxTvSjLNHREjmRZfX3BlY1smKxjGzDAeN2WiDjH3vSZ1x7ogvMe8FffnE3mCO97RQlAhgh6fge41CwvZWFGxwD3MfoEv4ZKUBXPXUhhhMsV2mFz10vYII17f4yf8g6NIowDYkFwhBbz/XpM6YqyI6a+h7TNSHGwF7N++xXp+JFwvaztaDu1ERE22nOyNi/Yt66Kh5gnG0kQXeUJLCq4iEl8R9ogoOyMFkL3VlRNqs9Osu/KtZp4i5eXbWw1CFzC7fVM6V29sK5zQ1LnwzPu3Y3ksgH4Y49ERAyIHcW7artuIDgecQtByaIa2N39b5Dj1xUX1pNHOSMwvlwgxDgize4F4FPFHRYFFPuiY0kSgvcrO+mBton5fN7WTRrTw3U1R03JNTrGZrIJxRfulUnSJZjKBQsezKj6qBWRvFw7qZ6ImK5JzpqJ9TDvrHbHE71lnj7wbRkLBEvcBJ8UROo6HPy7sb+gU1SEJrkILAzXIqC4BwHYZe4SU18f6nhe+I5rBi4uiTWEVG19w4jJ0gf0oQ1ZQnz5CXaJfEe4QXYHN8aUq//1Vsq2eOuMGp/B3VsZYY27TWShWyRJxnqqiU5/uKnifvG8K3BKRq7wo0NjwJMNEKm0WlG2umGaUbYNTbpyFBDDsLq3hijxpDiT/HaALIzCMemqbrlsQmsbnlsanf441wtI3wyOiMOTw6P2gpRHaM1gSz1Blk7y5HfHLmAT6Bcnhdogat+wBIi1gpMHHkPk4eiqY/qukxvmhrG3jUKDVT/uYqUF6kzAhQRfq6xZ3Fy5w1W/zrKGElEHN7G4LdhSoj0yAmaf9ZO8Zp2hIWOEAqbCNylaIapML7AROHVA1yqSBfc05PHxzjZmjCy0+d1WpKd0+cir+9HwPtfEMQZO82XH1Kk3OoPkPBhSLzmgKZL6/ixyJaR5kpEHpERKOTHIH+ItpXi8EYTMRrv4iQ2yj5HVmS0ixsQaUHqNDQxCmImccWBOUgg/tW+ko4fNAQJ+/D6KOijsZuqgQtYNZES556ANb4wHZ84IuKIvUb7zsEmit/18wbXrWBsd+o5SGMFm3MZsKLQtEOJ9yo4wWXTugxH8XWNnY14ew806O3CBVyBNKeC1D2iwj8C/IRtt7n9UmC3fMJkJIp4VNLvCr9VyLb/mKLp2pvEi7M/wkmqurfeVQsLyJogh8nv6S0x9veQdfqhuU/epmbQ/H2r4PJHWt97shBXPbgrTAaG6O6WKZl1Txi0N2eoWUZruce9XQWekAPDntThh0Uju/kWVd9Vcg8L8NaLp9JAW7N1xA3DBRrsGj/aHs1SGzDGuzNyCXNsV8fqYYsuXvc+w6qibs0GviKymRFim832ppBbPMweJZUZxhM1jmVGc+183kdJ/96AbiL8dfW3PK3Jy3pjHzcODY1+ujjFaCYZydinof1+qV2vxyYZ29rYtBvtyC7+Ud2H4inPCrAMTka0qHpUUQyjT4jF8wr2OJU2odXqi7T+D5je3XuZhTYtHDf5MoMfQA3iOAi7t9zxRcw4POq27H/BCT72admfZYH+QqVJCbuA2UfSFcPbjFtuPNLezf3y8sweddwSNSh4lWA4BhnA7wqEmG/V6FE1MTdhcQ8DaP+Hx5NyfP0RHpTDBzmr/XloeEZNflWC5CHN7yKeAZKYt3GNEnKQB2OdNH6AWfoIS5s3IrflTbBeAPbIizEMyet+R1szwvmU6Dce3XvgYHvUTZlfwD9wtrp9mfbw61KRJm52+yeG3+kCgqrIz4qy5ZU4RnrHcZDsfy32+z5IbUMQnO4ZccmSQ188ub39UsSKctc9580n53V/EYFWFDFuhW1LtInDAlmQUJ8TUO7VIhmuLc9B2RkOQZ6n1i/kd8xK1w17/nozyeHHq7Pr/5mPPca7LIGkE5aI/bFzf7T9dIzVc+fUXDfzl2tEwz4sbpjHPdF5M4uFnLZf12w0rvVeRYstTH7x9YizNEPkDswK3CbX7sgXml975KzxOoLuiQDIhxiL97Ym0/wsjLInLLIzs9AplStwt8eUd3zT2pV430GZIltn4GG0i7xJc7BPGu+hcaGpVRhmneqfMPZ5sQfkzS1I8CWgEm2rFNf7QlvxNputnnQg/RoL+490OR7yj+PGPYAKEsr7HwM6NYN/sE35PKBQVeldjiQwJUxpeiX+nYdrqT8swbkEPa6SMLVD9v79dg/Hv7n3g60d0o9FFf5qxd5t/NF6kDzE2JCTPc3Xpv56S1CSQY6RIk+xsu7JchrKX/3/A12uPwPieNsw4DVtNw7c+M7fCxawzxExBGebR5+oR3KCA+b/aNIyLIiQMv7yuiyycPen0vCfgE/eG6fFVZL3TYSPshREf6Qg4q4xKBo4VE239/H2Y6IVQ/TWglJaqQpj6vH5ONbqaKLIivLyjwaUsLq4u4ndz3bnsPwnmib6gDf6oUcbZjVBQ4sKYbqEGUwCo98jLDNRWNq85Ih9Jw2Fr7Sf0vwBn4bJjLLtCTa6SmHZuh72SrHOdowULy00ftzQ/5C6rR1j6x0UhRDxLNj+CADPwZ6wcwS/s+TIuhT2/8E4L6vsNMfwQcvGJUyaEjr2z8qLSL8bEs1L9qm4KwYn3Ci7Mkc8H+tVdlwsX2KlvkK7TsS4vTvvC6yfivIhbG7cxLjbWe6JNLdjDGOVFscoesF58bK3Mu7hChKb7WZvXnwmY4qtp1zn1QYnk8dG9QSMM9bxmOUYJA+LnHiC6fR4e8I2MWI757VxZ4+gnOLqDX3oewVXaHXeGyfjKGsHfqgRdU3ILByMeORIlf5V8MMc7+8c99FIhyne2ykmdE2TfTsPirFhQENo3zOMPaUIcXz+k9mqfodV4xmoR0l2AZNib/Iqbvm2dAqHqOXpyGKZOYQAWTPUt/LAUFP6ObLmLjrSGBFiPs/N2PvTknu4bDJ4BaqHPeGzeJENl0j88mVQVhpcM05nYjjS62L9NT8tyyIo1RJ+UvqyBmUd4bo2xnWaLyNhumySBFZVrH7RhPI8HrA3H/rnoPZECr1fbI3zcKzsCQbXEThqbnsvEgRVU8IuTc5+TLdxSX7nsySTZznQyJ6wFRQb+wXmQMtjaPcXY0fe2nY89AGptrzaHz/4gY0mdnR2jyf/WdjnF5+NpvrBaha3D+vYxsF4c86nAiNwIIp9coezolyhKaMunEdC/yldpYgfrgrCHw53PiSnYs1Nllb3I8UtTndEJSKL+m7ThwK/1YQMcTSZoREx1soH8U+z2sfDXGpIUdPyz37GSmYszINzVazTZLaEVA6nQyTZd5+odU8YMzzK4KwsVv5syNYOu5lV+HeDrhsW2Nvc/BMmhhxuHjYHvnYWx2uEb5yBoMVvUXV76eOX9sHOSMiGp2NC8E2hCogfAH36VOxLxCE1ItyKh4+GR7DjoUOWj/JuI0sSB/N+sOW4+3Tj3vC9B1Jnp7xDCNJqDdK7fbGJIx7KyNdcP2Q4LH52sY+4AXbwHxLD9s8W/eQj48dJQp7f6w4mxBzAuhYsn/s2WpE+F1GsmHuqPCctCRPZM8RTCYfsgDdf4phekGUvIXiO6hok99iGeHeWCvEobsTe4HofEdfPjrisFckX+FR9glhw99CTIx9cVJ+O9GVPK+MXdy4TOndNEF53W332Fj+tpn5xd1eHK4Goi6TMmxGbbBGTk5zcw+ShaPYuO4lxzfWJm9rKvDvk5RkMf96GjsfAuaiuwPPpM6RG6oMGIenvLIQtrhPmFho9lM5fNPcpqYwwOA83i4giet7gYJVxSLsSVwIdXiZKmhKnHT8HL5gg+/UyIj86d+kRMUR4qmrrD9D4Ue8JO5y8JBlkE+d6zQBGcw7LtFC/AWx5DFaDjGALClMm4bwWb+BNFvQeIX5zkad1CjLPBxbZ2lt/M5mE+aT/IqmlSNt7Im/SSyMW0yfQ4/oE7SaKJl8GJbZT3MWI06G/+HSIhHepb/PF6dnPnPfAxz4bejpWJ99H66T3fUOH1TEj8tFuJPdEVs/7RBLvQpaiAcv76Xed9jvGsqgqZJtnhxmMM4MOC92+RGGgkXyCjzALMwAv74uytn1P3C7EC4HHfKB8se5OzmKfm40ZN2KV6BVRSJKVzotIiFNhWcIyFr5ZQo1tOnZW4pdJ8ZWDkO1Tm4LuI6hMOSkinXJdwjbOfT80zyjH5DuRpIHyk/9Z5nIL87KQGPA9oX8btGYV3mS1WOZJ1izhIr9MEVow7Oj8zpbOQVXhYDpUUAe7kXtkUcZ5ldbirSQvTNGiXD7DGnTBh3Ge+cYIwx5HkOOMR7uIoTQXEFlZ5VH1I13ewaCzzBbDP4r/3d6VNcdtK+u/kvLjfYhP3n1ulSzHjqu86FhyXPeJRc9QEivUcIrk2PH59Zc7sXQ3GhyAIMd5SaxBA719aCwEGgc3OnbNfSniYz9rQGTjt9U8kSr5YL6WL/MmxJ7ZL4s0L85Myd2q0zzMaG9xdtSvB5X29Nc5A/DQRqSPBCD9wAugN48cEjO7BYZQ9bytY1F+yzXOVNVCBGtvnrEBYuvMntVWfSmKbyfBVNOHJ9tjLfXiph5aHvP9daPqvM4pN8Tuoh3DWV4FONpZVmvgzHskkyqWnXWs6cPDw3bHsA8zw7dDE1yv9qxmeVXiNW9j51xPiuLbSTDV9OHJm6R4SsvmcEmXGk7MYzfHrWp77E4r8J3lY5CxZVTUm3ByDW3UaR70+uo++/G5XrftzGd7ewU9ev3e7Uf5m7NeScfnSBR5zWxeL152SoMKMMg/S4auskePfkq+pcn3P5LseH/KDjMHYAdbX5xTL07c0Sk82yFD9bNE+RKXvcU9HBh+meUPw6XhS/Vlrx8rFQFrn6622U1ezjhAOdX00Umb+yA/iy+dbRy6BkfjhLdVouaWYV7n6Wp6ieB5lv2ZN5/+gqZiXiBy14peHcrvc76mi3W9D6OX64Gw7/e4iw2dn5yFhia/4pRhbtb7d9084P+Ssj0t7aCpD7llSxjWr8oy36WtZ3sO/zklp2Tf3ZYeb+9Gze1dBfm/H/a/NKuRJnnb90OWT1l+bpPs/tfpx/enrEqPWbqr+f/72b9+/fW3Z2qX+Xjozlv/0hzcbi6uXMflLt7r5qjV2GNigJJLMiEUsoD/ozFtz8Y0n2fj7Do/lFUR1wbXe3162KXHOFONohAyA0Sj69ikWvIqOTZfuw4VqTmH8XArW2c+8lAcYDLGi+cCpthQi8Tr+SjQJCLRsXKB7E//aMMw5glZuKm8o4vFTs20EBpbQhhDVTnPsT9FQLOFQbCYJtQMBr9hL617hjfq/49ibigXfTv+tgjWZIFlQZQiL+gCLeQHWYo+HI7Cc8qrgBP4zVtzJuTFnwVOkIXWA6dpqRUETuPRDIdxqZ3Xq76bWhoP3YhNTT9uPabAZ4ow9weOJuOBkqtjbfLm+F0vfpqU0W1+KnbEWq+vK6/1xh8XCS7aQS5IFs/YGlVeAFz0wTWEJ324KTjM7uKiOabpJFxcMMysXB4CZsQBx2Aw64fXTcUyaMqmlV1MJLOZnq0xkI0IM4Sx8BPx8PhacCo+B17kgZVF0TX8o0/r1ux3qCc11hm7BIFBcaTyi4lholY2cSz0JkJUez79lhQ/7prbs6hvRSLJqVKB1RrQIhq6wgWqqh9sWI1rgmyhMTHO4pC7MeuamCtCQ3i6oGm5qpHNrHw1uNrMjmVAUC2/Z2m3axV407LJk34ftztnxYIblyJbqTm5YOsbmJI2W9jE7OEooQJX4lyH+g06qEhguReoWfvfTQSyZitWWBX2NjPCrQBsy4909uEt8GinXAz9lNStpU0Gje6mJuNLjdyC5Gm1aBH4wdd8cbFGCi8QVEywABIZ15wRxpx7zSvBpOmzDuB1xM8/BQptUBAMfvgF+aVwV9XrlFqub7WqSQSKvi6MifLK2JJLNo8pSR0LLAWD0nA73iGIDOtHJfdk29L429YBACZ0WLnrCdCe34dXBwb7LrogJCThwp2GG274jw8smqbWQw05PIw/LjLIqDlVIFE8x5lB4QVQRWaQQVjSWSYCIcswQbYIEBeLKxsfB4AVnlloaVS9TLOsntHDWZVmYcp0iNcm7m0XDSxesvHDo6FPLhnBSqx08FIyYkqijGUXM3gNGtkMXsFw1b1EclsVbe6Bsp0QRcPzMyi4RgLRo9OPi4ALklyWByTwAjPYYH5gBqrF4Ss+KhQEa0OClW3ga5BWkmH6cfM4GlXZBHaG/CvbwM4grSTD9OPmsTOqsgnsNIljtoGbRlL5Y237w+bx0qqxGax0SYYiXWhbT3lESSejJsHws5/v+VwvOkBLrwiHW0MeDi9qdlgxg6dxh1GtLftTK1wGXVTuX0o+mdAPAlWTLIFGdi5kDJ+s5McrAKvpqz4GBMrxPyFIrQESGqCGvMtL73daRdBVbXOZOsiC4Ft0w2su4FYHtg1FwDWCbqmIdzbwwka63/9uHoOLs6tT9di0uGsLlSF51RGP0kDO2EcSbj4CkurZADIYFl/nxemp3ZR1DTz8++LIU2pJ+HXzuJh02Q4I2tcyl0ZB90SnBoP+58vAAfAM6aqBELX/fVPkpyOKAoFEc17/8yIDUctQF8ETdDDDeAQPi9Ek1xpCCCC3vcd84iVA0OH7ctmI05KvYPKBiX2O63xCaPHZi6VfF52/tGIFA1H7GIGHQ3LU3EV6sbxtpP9l62fjOjU4jGSDB/b+JhbNy4JmyWkuHzXBZ7hDeqbPZfyQ/JHW0hQ/Ijiv1ErTcImSg/LIBBeTiEtSi8M3eCYuEGtAX7GPET8BxPgxJRS+WgnDDnztibg1I2qUUpfA41G4xbAzKbIlwKw/h0kY2CyYr8QOOKGzlLxJ76vruNhHN6fmgbUy2X9Jq0dEh/luNFxLGqSQGpt+9BdJ2H46ExSjLixMgK4IDhFprgMrNNelnmINJDkozwKTHisEOEKb9bxnqLgurH0Wu8JKZ0Nrgtpic6TZOJM8Gnba9CGvkvXPsxspdQm6X7eNoUmR9c+zPyXfa7Tf5HUD5RCcNrE/CQguiQOWb37vEtJqEzuZEM6cDoKG6fh64LJYGJqLFcktYRP7te+jrnkkG4TUkvV5fFdiMQCNeqx/GBtEbXeMYLnnes0zcrQNB7nAW55RtmMdgYi9LTFWCPuRdkhNuVwim38+0z9TjB5wtlKdikPzmE7i4ayxp/mwILIytZFKLmAOLOqzidnveIFn+ajyT3osNLyEnNvmrSDXcdFNWV6eDvssIT9P9J9VBErgi5dYagUTVSJlSqIW+vyihdnCD4A03Tg8JxHXA6FNjFJrgNmSY9UsdAUfrjRsrf8b/BqAteAX+Vm4Cv1hvud/e0x26X1/+/Cqqor066lKNoAxUn5ILoxy6+ij1dsCFGHRPx6bPyOOXmLoMeOBBwRfoZHQlSHlQOhnJ2o+hM6NoJSyrMUE2MBKgytfW9/A+Slj89lgCx6wKQ1CY36YOtzFD+YcZmuZRUwyQ7KIpRcyWxBUspghBEw/BoDLkHGH9ingzJ8BYlyHh0RZTR4caH/GRRofqjG2XudPX9NDSxjhT8aL92FEIukejFRgtS1olg2CFknu54oXaiCvaKMU5Ughir1m/G1mbb56oC4/7p6L0dBLdQY8/3OqS2ovfT6kOEYlIhELcsFFhkfcQKuGnij22vC33ZjIgeTFRr8th7wBcuYtSY0QcPnS25CrReOi244OYLmavUZViT/j7DSClNbQDy6WRW6rLkfMntAnhmfhyQ+UO20t8Kw2EBrWwaeTnCnDtieGm5v9Rbfx0zFLXuXfD1ke41eERwJp/2X8ceVogNULjwTZ+MGwcJcmRa3fLpHysBvPW7VE3PzrLSa8jGKj9JIswq8XkWx90ofDTJRuBbBa/5IyDIgWXDba4WclC8XpOGp/kHj9QNIktzvNvD1g6SpxmEruXBHMnALMOAX6ByU009XhY1zLvU6zqsl36/16w1JhStGMFlIjvpxrE0Zd+dEt6DWKl/Hur7eH2yrf/XV7+lruirQ7A7qJ2xSI8PIb0BjN5u9WYJrZTPxXh7v1z9zWB7oFx+dzMBd6lL7aZcBDmm63LzxhbhRdvhA7/XoRexeTPpvZu7i6v0+z+pckWugtg5Gh3ND069YvNE+qcJiFTpTQPr3hdeKEQ0HjrT9xcmEzHl2nTcx1av2+1YB+XwM1fkii10X+tBxKZObKvEku2jw+FIU4HEVnrAUgd/k/8FgJPCZXBJy2Vum32uTv8odI+HfjKHyyodDJs0albKEZ7MgVk8bX3IWymR+giUqxZjGyiKuA2iY2gMKhasm4ZQun4CHr+jHZ/ZWf1JNx2s84tjRKCWR66TKPuINq0aL5PPtmsKcfMCIasnCpVg2Y3253KmqNH27iH22O1beHtGnXUapVfLqlMlYS1amF286fqunD4il4YjX4GDI20xq58rO3DImgUqRoflNBzwOIW1DaZIZW6wbD57t8F2fpf5P9IGP0Lj48nLRVjeD9kUB09/TjIgjUxJaF0Uu9oA42lR+06TpxmA4SBsSX6wWAv3Od6tz/Mub8m5nr91/1PiXf0uT7H0l2vD9lhya5aOOSqfF213PEVP171Uy77vIIq2+EXd8GiL6xzPqolS4H8KUZIGKcbD8Lc4NGi2yTcTxixTskDqWC31BYSWS404NByu1ZgV6ZtaNJqhzurEqWP1znT+1CkRnVhCpLBzKRtXQmRfz9gsIVamordgvDqPn3TV5WeDwaKDQfdj8uc9TJHkqOwtSo6AoBNMgWDEgfku+lZTwSqiwdj0TWYpPS7xcUj1BTW7FbGEbNv5tzyHg8Gig0Hy54Gn0GlBzFo1HRFQJokC3c1DvPsj/zKj089OcruUs/pd7iSz6VvzQv1wovKEbRlrfiGQJfzQ9Xh/J7UhDruZFGc+vw8zI3aM4BmatF36T0WsE1ibiOHYRZ21dB96z4exbbDl2ONjAWB1T/l3EHKvylZFs8be8aiz2Ilr288nub+KXpVXWNpBj2+vN98jotyupVXMVf41L/2NfUuk0qIIHMs1+6UjRRz+3uMXmK//1s/zWvPR9/1XP8aGFI5Zackv3vT3GaXVVVvHvspuMAW5AO5g+SGgSZ0s1ovKciiN1UyleVVtColpFVp/xul59AY8rFEDOZwsCt/679Pqkec8h+SjnETyExMTReGdZlMFYBxTLWspWUIxpTFi5znCXJyNxj0hID2FQE9pix1MDhOq6Sh/YgicZhKoI4TKUmE6W76lQkkImGEtBEQyHPAwQXhYDwR9QTRe/j9hErtn+aNz/TIkECK0hFeU0iNIkg5VDXeUvFIFOJgmdtAjUaBWXvgYpt8L7i+/hwuo9bXxGRSKai5BAp2bIYhDBzlylMHVVdjej9VaUAu61KxGRL8KMZGTmMdy01BmMJ1P5YaFKg6VBwfBtKQPGHQkPzw8ut6MisEkDMVBoTz6ruNjV0v9WTaqjPK+UgR5nEwHD6uqXxmoogNlOpgcN03k3jMBVBHKZSE4fmwFdyWxXt9kfZPcYDcAPJQM4gpUGKaV9e4zwVQdyaUnN0FPbQ9KAoFIKxUChn8EE44G2zQ013fR8NN10xFXI6CpMOSfGUlmW9vht2+HR9NBJQN43KtHL4u57WHuLs6lQ9NmvQ7ukqVAqaHFxZkDUM0rVXeZHOLpRBfNviMmJ1+Jb2Lj+mO4xPX0gw6ik4nDAmZPs9Baf9N0V+OmJM+kKCU09h4NRfatCY9L9D7fdFzGns5+b65XiyHJ3HymTURFamNEjxJr2vp43F3iAFTAZJAVMypSA409x4bkQGAaEMdSdrYdpSfsgrKJIKZSiTrtjA5FPyvVb4Jk8PVYk7DKSCGIOEjPkXsuyairA5F2uBNRAiHpOLKU4sv31K6uXAoVkAJmAIVsphM0okRvXUJ6gBFVUSWE2VireWw967xFZ1GD21vkMeH+Wu9OhnRHV7keSg7cgas6Rjy2UjEden7dt9mAPbQsJbbTmPD/lgEcafrETIRdabJy9fSMO+lfIAh+1+CkMgniTWSEGepOCapSe38FpfwyCdkDhaE0Uog/gKxcZ1fA7uWPa/w+v2nLEn2lKNEIDbH4tRNlwM3dX1k9bMX8GFm1IO2kwmMW1HYEn89N0JjBLcrMCILfYB75KnYxaD/QgmM+0LTpTMjXxCAp2E2thncx7CNs5Yo6CiP5ftm+SQ1N2MCl06CThx16hMO5ZTej99z3IqA3ctp2IDk88FzkQog5gIxaZAUdfen7LkLi7/ggKFVAwGConCZLcpGZ5ut6kMtNtUbOqNSVzWHedLkj48QhNopRzsfzIJj+GrtJ7jl3AY0kkItgKVccOsKJLDDtzbHovgjbKhlLO3YYixAA2x02EVWdVEV0BgkQmoXSmF1NjHhUQ1QC8XSuF+LhDwWXV5nyh2HYWBZUdkHDCejnH6ALl0KoIHiKHU2DNaW1NjokoB9wuFiLHH/i6pqqQwIBcjxPbfIVqTkfWMOLq1dRrQ7DqZLXNsco0RssTgTajR/BXADgdCCe91IMSW4jDk4AnA+w4lJ1PQWAM06BcomcyodtOD9vipFZUAVlmmMaGwyMuybjzDueokIPI0KqOpodiNxmxOrK7/VSGLqqEEnCYNhaalVPw3cbRCKgWXUSKBiRXy7YX47ML73jLs/ROK6CTUR4To6njM0mR/l/f0aWL+FDpUxkGnUfBk6MnNEsgf9fFjCAid+ZzAp6SsQ3B7qphxDKL/NoqfttAoqE+sPRHDEernUcNXXpqc8/01akjZG2DjeRjex2f+R2gpl73tfhxnG5W5mxpNdLZSAKkPMGEAUkImgJpxAmW8SKhv84il2DmUkYAxfcRZSaXYRJHLSr9lpNtXI8HOV8hUNh42uZXhS42hcH7ecBI9ep02fUmoQJ1H76jVg/7TTQn1jHnNHD8/LtUkj8m3zfBOvT+XVbczSySfCieNItPiikEn1Vt9qBPomGkwg7g1g+BviQcXJGIlp2qtBDHymeZoPNus2wehxJVSDlK3aiBnsaErSmB1pci5+sMMzqw+fJMJuuuly78a9cdT04TfNRr3Hlcn+G1FdP1hryY1/49u+/OWuuacasT4ody46MYP5DYFWBM0i17o1zx3cfGQgD2CU82Rz1dmnmHlZoUdtZJP5ECxRyvzaRgb1KiV3IfUQGYBLuGUpEnACj5xAtw2khqhrg/NHmwj+Z4QOtTKdIQywL2lTgviPtJcXM1XexxHp9CEqq7T+gikyBUsUX2HYVRVzTzX0ki9TbYWMoF0OYyYcoF07qdd0LWztjJ5nWy255WrcSILFAJ4HcdqQahAGwLLvZjJ3ElAcm8dZWGTyNvU0bBPnfSb2/T0nV8ZVxu+lNdqTF+1I1pRNvCBxrArg14MiE/V+JWJ0QlQFlFvLSYTLzRGY7uAeUBCD6aALml2JiDvXtqr3n+LoZRWSdyrq3xXauthV3Tnq6iYDldUJnTupQVVH78njZ/ciOCJExMeV254dy5Hbm+DNSEDaGU+DIEHQZzYiR/XYIaXaZbVgXRsmTCCQurPBCwMnaH0kN9tahrXWqP12QWUrAxSA1iqBXszQFfOpwdmAFvQFXC11Ov4rT7YVXu5JnHNvmuFc23e3jRDpgHSHDqRDxOo2RLammgmBHtVh0QBpKo6kQ9V1XQGbc3px/MXV3mWkWrKBD5UFHMddGsmKJfBPNW6dAtR1yKsnEhyppBaDTlVxFgPSQIxQ0X1ZI54JIaaxvAqEsohuR06FQ35GsiWoGNCYKtkLgrnpsQnQryK5gFOU5hScJUmBA9msSbTluhzMJswGX0Z0zCm14ujKZSJqJwq5HSUV9EHmjh5ZtrWrPLF2JtuzBpD2gmg8mEULb1NW1X41Y267VFps74KmTeFpcPek8bwge6ZKkdirhtEX5HGILKUUWcSGcyUo9fWK7r1bN8k6daO5mxBw3iz7Ylis1SPFegcir5wv23T3jB2VUA691sqUrKnthacy2muolRsUih8hCV/6kG5p6LpfAV+kAOuQJxgOPsgB5TpSmqFzFzlyDS93Zl2Ad8ot/frKswxZtPCbaCSuFVcywQ21XO0gTLJT3yT1oncf4n2r+qQfy26qddnj3GZ7L+k1aPAQVfcVMWZOlJdNcNcWxXNHjffEFK/ndrHzQBXcKQIWBPt8azUfY5M81n0O9s+ci23cSGUecbMf4aAKJB4CIhi1sKpHpiQ0F5FIMcgORUi6X1MjIicim0jnCSJbsxi7BfmSm7REcY0Q/pGvE8oFG6VVhNc3g6naBwd7xWzU0ZTu7iWMqEjwcGa2vhKZtKcuxAaTiQZl3wq4ZbWfFJOUEPAAyn9hDog12nfk6kUpmdscDOcjdK697fvYxNqStZIfNkG6uE4uXFFoL+/I64N8Cd1lJ4PJ6Pte78hwawDA1E9Ayf20TmCm4JYMKK07teNS5uBTDLMONhtqOjeQKwsymJrzMy+MxBEJDFGMjCD4JrRDIEfs114BmG0KieEJtpGEju7RivN3BbCZGsLm2qlPUBPuUKecsGpvYUJPbGM2IJY6sUYxDkVnNqoFKINoMY6TEIkEufesmQ3Qey6u7qAyUjCLlrUJo26FxObB3FObW9ddGvmlN+inWVTqQncQNCzua0pqOdwt2riGTBdHpsca/k3ETmdZNc1Kk9qzZs3rtKMbQLXCGXLNindziJG4bQrJcGlGocT286fCDED5eLR0G8Cheg2fjpmyZSCDVdcoSSmLrOTvPlVeXz6QzoXC6mMUJo3kuafnNWeNGmr46+VnKM+MXbpRO5HK/+qatua/V6pedBGq3gbtOfuzDoxi5VBLtoUyrv2hr14m+rL7M2bJKKb1ojPv/EHP9dDbuEb6/jYyTc8V9Q2xH17yJ2ZiI5pquK+e4Y10fgoj3HYRih9DtvaY0Pd10X0HaEZ6g9v60TEV1GdyP3nUO19oK4m+vTPzKPt7GhBUPuIE+hjO7fjUXfHwJffxIleF/kTZQ+K3IdB4Od/+qBCvuZztinucgtDCMRbN4PwiFCkPSgExUOcnApp4INHfWAjXzHC2sHacGwSChQgnQ88LKM2/M5PBLxCBByh4dYlzIM9nNTZyfQWEt2WvgXEfNVozsEr+X2g6O0hrdI4Iw5VUhVwJecdqIRfQbrtzmAZXjY63xjDoVGdldkuaF1P6pItwadReU9TzUwDI777ZM4BA1PjCp6ZAAZ636prwvhk1Rxz0IHZe0BWA7GbANyvm7S3UqJmXLzOD2VVxGnzIEY9DRv1G5Ie3eURVp/YbXDPy2zuGZmToCUn+laNuAY1vzvj0E1SwW9WVleqMpXHNV61AYW3ebhwk57zAfYvzmvRP2aB14y6LQ7imaLzDDuknwJxCBPS4rMTXAVQXHiCiet/6dUm3UJntugfUcCjVW0b1GtU5xl2yPIFIgompMVn5xELoLj6vhZ7XNTe5QJGAVdtLzDWIu+VdUOE6Q0yB2af0pPBAypFT6tllQstrFHEoXjWBM04F5nX6sJzPf5052wj93+ZJ3ETpbdPmA6Vf/G8a6Qxfe3npBjLXjzvXvzrf6j/rJeu9crvfb5PsrL99cXzT6e69lPS/fUqKdOHqYkXdZuHpH2bdGp0oHl7uM+H9Z8i0UAyFI8viVfxPq7iq6JKm0T1dfGunn22b1m2OzXNY3Zfk/3bw8dTdTxVtcrJ09dMWl2+eE7zf/Fck/lFd/q8dKFCLWZaq5B8PLw8pdl+lPt1nJXKihpr4rq2/puk/r3zZd05q+Thx9jSh/zAbKg336vkmBz2dacbnlYvPx5u42/JHNk+l8m75CHe/bhpUma3G09YI2ZHyGZ/8SqNH4r4qezbmOrXf9YY3j/9/b//D7DeiAJiOAgA + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.Designer.cs new file mode 100644 index 0000000000..c4e3a3c11d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class QueuedEmailAttachments : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(QueuedEmailAttachments)); + + string IMigrationMetadata.Id + { + get { return "201507132241575_QueuedEmailAttachments"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.cs b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.cs new file mode 100644 index 0000000000..e174e25c2c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.cs @@ -0,0 +1,107 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Tasks; + using SmartStore.Data.Setup; + + public partial class QueuedEmailAttachments : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.QueuedEmailAttachment", + c => new + { + Id = c.Int(nullable: false, identity: true), + QueuedEmailId = c.Int(nullable: false), + StorageLocation = c.Int(nullable: false), + Path = c.String(maxLength: 1000), + FileId = c.Int(), + Data = c.Binary(), + Name = c.String(nullable: false, maxLength: 200), + MimeType = c.String(nullable: false, maxLength: 200), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.Download", t => t.FileId, cascadeDelete: true) + .ForeignKey("dbo.QueuedEmail", t => t.QueuedEmailId, cascadeDelete: true) + .Index(t => t.QueuedEmailId) + .Index(t => t.FileId); + + } + + public override void Down() + { + DropForeignKey("dbo.QueuedEmailAttachment", "QueuedEmailId", "dbo.QueuedEmail"); + DropForeignKey("dbo.QueuedEmailAttachment", "FileId", "dbo.Download"); + DropIndex("dbo.QueuedEmailAttachment", new[] { "FileId" }); + DropIndex("dbo.QueuedEmailAttachment", new[] { "QueuedEmailId" }); + DropTable("dbo.QueuedEmailAttachment"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + context.Set().AddOrUpdate(x => x.Type, + new ScheduleTask + { + Name = "Clear email queue", + CronExpression = "0 2 * * *", + Type = "SmartStore.Services.Messages.QueuedMessagesClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + } + ); + + context.SaveChanges(); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.AttachOrderPdfToOrderPlacedEmail", + "Attach order PDF to 'Order Placed' email", + "Bei Bestelleingang PDF mitsenden", + "Dynamically creates and attaches the order PDF to the 'Order Placed' customer notification email.", + "Erstellt bei Bestelleingang das Auftrags-PDF-Dokument und hngt es der Kunden-Benachrichtigungs-Email an"); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.AttachOrderPdfToOrderCompletedEmail", + "Attach order PDF to 'Order Completed' email", + "Bei Abschluss einer Bestellung PDF mitsenden", + "Dynamically creates and attaches the order PDF to the 'Order Completed' customer notification email.", + "Erstellt bei Abschluss einer Bestellung das Auftrags-PDF-Dokument und hngt es der Kunden-Benachrichtigungs-Email an"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.Fields.Attachments", + "Attachments", + "Anhnge"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.CouldNotDownloadAttachment", + "Could not download e-mail attachment: no data.", + "E-Mail Anhang konnte nicht herunterladen: Daten nicht verfgbar."); + + builder.AddOrUpdate("Admin.System.QueuedEmails.ErrorCreatingAttachment", + "An error occured while creating e-mail attachment", + "Whrend der Erstellung des E-Mail-Anhangs ist ein Fehler aufgetreten"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.ErrorEmptyAttachmentResult", + "The e-mail attachment data could not be downloaded from path '{0}'", + "Daten fr den E-Mail Anhang konnten nicht heruntergeladen werden. Pfad: {0}"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.ErrorNoPdfAttachment", + "The content type of the e-mail attachment must be 'application/pdf'", + "Der Inhaltstyp des E-Mail Anhangs muss 'application/pdf' sein"); + + builder.AddOrUpdate("Admin.System.QueuedEmails.List.AttachmentsCount", + "Number of attachments", + "Anzahl Anhnge"); + + builder.AddOrUpdate("Order.PdfInvoiceFileName", + "order-{0}.pdf", + "bestellung-{0}.pdf"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.resx b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.resx new file mode 100644 index 0000000000..4bcdc56bda --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507132241575_QueuedEmailAttachments.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.Designer.cs new file mode 100644 index 0000000000..c12151b6d9 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class CustomerTablePerf : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(CustomerTablePerf)); + + string IMigrationMetadata.Id + { + get { return "201507141647299_CustomerTablePerf"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.cs b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.cs new file mode 100644 index 0000000000..982225727d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.cs @@ -0,0 +1,35 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class CustomerTablePerf : DbMigration + { + public override void Up() + { + // without dropping the indexes we cannot adjust column lengths + DropIndex("dbo.Customer", "IX_Customer_Email"); + DropIndex("dbo.Customer", "IX_Customer_Username"); + + AlterColumn("dbo.Customer", "Username", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "Email", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "Password", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "PasswordSalt", c => c.String(maxLength: 500)); + AlterColumn("dbo.Customer", "LastIpAddress", c => c.String(maxLength: 100)); + + // recreate previously dropped indexes + CreateIndex("dbo.Customer", "Email", name: "IX_Customer_Email"); + CreateIndex("dbo.Customer", "Username", name: "IX_Customer_Username"); + } + + public override void Down() + { + //// INFO: (mc) Unnecessary + //AlterColumn("dbo.Customer", "LastIpAddress", c => c.String()); + //AlterColumn("dbo.Customer", "PasswordSalt", c => c.String()); + //AlterColumn("dbo.Customer", "Password", c => c.String()); + //AlterColumn("dbo.Customer", "Email", c => c.String(maxLength: 1000)); + //AlterColumn("dbo.Customer", "Username", c => c.String(maxLength: 1000)); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.resx b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.resx new file mode 100644 index 0000000000..5e18dcfce7 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507141647299_CustomerTablePerf.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.Designer.cs new file mode 100644 index 0000000000..2f16779b2a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class SortFilterHomepageProducts : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(SortFilterHomepageProducts)); + + string IMigrationMetadata.Id + { + get { return "201507200832223_SortFilterHomepageProducts"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.cs b/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.cs new file mode 100644 index 0000000000..c9e3918b69 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.cs @@ -0,0 +1,61 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using System.Web.Hosting; + using SmartStore.Core.Data; + using SmartStore.Data.Setup; + + public partial class SortFilterHomepageProducts : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Product", "HomePageDisplayOrder", c => c.Int(nullable: false)); + + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) + { + this.SqlFileOrResource("LatestProductLoadAllPaged.sql"); + } + } + + public override void Down() + { + DropColumn("dbo.Product", "HomePageDisplayOrder"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Unspecified", + "Unspecified", + "Nicht spezifiziert"); + + builder.AddOrUpdate("Admin.Catalog.Products.List.SearchIsPublished", + "Published", + "Verffentlicht", + "Filters for published or unpublished products.", + "Filtert nach verffentlichten bzw. unverffentlichten Produkten."); + + builder.AddOrUpdate("Admin.Catalog.Products.List.SearchHomePageProducts", + "Showed on home page", + "Auf Homepage angezeigt", + "Filters for products displayed or not displayed on homepage.", + "Filtert nach Produkten, die auf der Homepage angezeigt oder nicht angezeigt werden."); + + builder.AddOrUpdate("Admin.Catalog.Products.Fields.HomePageDisplayOrder", + "Homepage display order", + "Homepage Reihenfolge", + "Specifies the display order for products displayed on homepage. 1 represents the first element in the list.", + "Legt die Anzeige-Reihenfolge der Produkte auf der Homepage fest (1 steht bspw. fr das erste Element in der Liste)."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.resx b/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.resx new file mode 100644 index 0000000000..cff0d41d5c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507200832223_SortFilterHomepageProducts.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.Designer.cs new file mode 100644 index 0000000000..4412803c98 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class PaymentMethodDescription : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(PaymentMethodDescription)); + + string IMigrationMetadata.Id + { + get { return "201507210952098_PaymentMethodDescription"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs new file mode 100644 index 0000000000..b71dd98ac0 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.cs @@ -0,0 +1,66 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class PaymentMethodDescription : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.PaymentMethod", "FullDescription", c => c.String(maxLength: 4000)); + } + + public override void Down() + { + DropColumn("dbo.PaymentMethod", "FullDescription"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.ShortDescription", + "Short description", + "Kurzbeschreibung", + "Specifies a short description of the payment method.", + "Legt eine Kurzbeschreibung der Zahlungsmethode fest."); + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.FullDescription", + "Full description", + "Langtext", + "Specifies a full description of the payment method. It appears in the payment list in checkout.", + "Legt eine vollstndige Beschreibung der Zahlungsmethode fest. Sie erscheint in der Zahlungsliste im Kassenbereich."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.PriceDisplayType", + "Price display", + "Preisanzeige", + "Specifies whether or what type of price to be displayed in product lists.", + "Legt fest, ob bzw. welcher Typ von Preis in Produktlisten angezeigt werden soll."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.LowestPrice", + "Minimum feasible price", + "Minimal realisierbarer Preis"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.PreSelectedPrice", + "Price preselected on detail page", + "Auf der Detailseite vorgewhlter Preis"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.PriceWithoutDiscountsAndAttributes", + "Price without discounts and attributes", + "Preis ohne Rabatte und Attribute"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Catalog.PriceDisplayType.Hide", + "No price indication", + "Keine Preisanzeige"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.resx b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.resx new file mode 100644 index 0000000000..04f8e677a2 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507210952098_PaymentMethodDescription.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.Designer.cs new file mode 100644 index 0000000000..d9e3e0bca9 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class WebScheduler : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(WebScheduler)); + + string IMigrationMetadata.Id + { + get { return "201507242008201_WebScheduler"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.cs b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.cs new file mode 100644 index 0000000000..d9a437cb3c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.cs @@ -0,0 +1,97 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class WebScheduler : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ScheduleTask", "Alias", c => c.String(maxLength: 500)); + AddColumn("dbo.ScheduleTask", "NextRunUtc", c => c.DateTime()); + AddColumn("dbo.ScheduleTask", "IsHidden", c => c.Boolean(nullable: false)); + AddColumn("dbo.ScheduleTask", "ProgressPercent", c => c.Int()); + AddColumn("dbo.ScheduleTask", "ProgressMessage", c => c.String(maxLength: 1000)); + AlterColumn("dbo.ScheduleTask", "Name", c => c.String(nullable: false, maxLength: 500)); + AlterColumn("dbo.ScheduleTask", "Type", c => c.String(nullable: false, maxLength: 800)); + CreateIndex("dbo.ScheduleTask", "Type"); + CreateIndex("dbo.ScheduleTask", new[] { "NextRunUtc", "Enabled" }, name: "IX_NextRun_Enabled"); + CreateIndex("dbo.ScheduleTask", new[] { "LastStartUtc", "LastEndUtc" }, name: "IX_LastStart_LastEnd"); + } + + public override void Down() + { + DropIndex("dbo.ScheduleTask", "IX_LastStart_LastEnd"); + DropIndex("dbo.ScheduleTask", "IX_NextRun_Enabled"); + DropIndex("dbo.ScheduleTask", new[] { "Type" }); + //AlterColumn("dbo.ScheduleTask", "Type", c => c.String(nullable: false)); + //AlterColumn("dbo.ScheduleTask", "Name", c => c.String(nullable: false)); + DropColumn("dbo.ScheduleTask", "ProgressMessage"); + DropColumn("dbo.ScheduleTask", "ProgressPercent"); + DropColumn("dbo.ScheduleTask", "IsHidden"); + DropColumn("dbo.ScheduleTask", "NextRunUtc"); + DropColumn("dbo.ScheduleTask", "Alias"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.Delete("Admin.System.ScheduleTasks.RestartApplication"); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.NextRun", + "Next Run in", + "Nchste Ausfhrung in"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.LastStart", + "Last Run", + "Letzte Ausfhrung"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.AbnormalAbort", + "Abnormally aborted due to application shutdown", + "Abbruch erzwungen durch Herunterfahren der Anwendung"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.UpdateLocked", + "The task can not be edited while it is running.", + "Die Aufgabe kann nicht bearbeitet werden, whrend sie ausgefhrt wird."); + builder.AddOrUpdate("Admin.System.ScheduleTasks.CancellationRequested", + "Cancellation request has been submitted.", + "Abbruchanforderung wurde bermittelt."); + + builder.AddOrUpdate("Common.Waiting", + "Waiting", + "Wartend"); + + builder.AddOrUpdate("Time.Year", "Year", "Jahr"); + builder.AddOrUpdate("Time.Years", "Years", "Jahre"); + builder.AddOrUpdate("Time.Month", "Month", "Monat"); + builder.AddOrUpdate("Time.Months", "Months", "Monate"); + builder.AddOrUpdate("Time.Week", "Week", "Woche"); + builder.AddOrUpdate("Time.Weeks", "Weeks", "Wochen"); + builder.AddOrUpdate("Time.Day", "Day", "Tag"); + builder.AddOrUpdate("Time.Days", "Days", "Tage"); + builder.AddOrUpdate("Time.Hour", "Hour", "Stunde"); + builder.AddOrUpdate("Time.Hours", "Hours", "Stunden"); + builder.AddOrUpdate("Time.Minute", "Minute", "Minute"); + builder.AddOrUpdate("Time.Minutes", "Minutes", "Minuten"); + builder.AddOrUpdate("Time.Second", "Second", "Sekunde"); + builder.AddOrUpdate("Time.Seconds", "Seconds", "Sekunden"); + + builder.AddOrUpdate("Time.DayAbbr", "d", "Tg."); + builder.AddOrUpdate("Time.DaysAbbr", "d", "Tg."); + builder.AddOrUpdate("Time.HourAbbr", "h", "Std."); + builder.AddOrUpdate("Time.HoursAbbr", "h", "Std."); + builder.AddOrUpdate("Time.MinuteAbbr", "min", "Min."); + builder.AddOrUpdate("Time.MinutesAbbr", "min", "Min."); + builder.AddOrUpdate("Time.SecondAbbr", "sec", "Sek."); + builder.AddOrUpdate("Time.SecondsAbbr", "sec", "Sek."); + + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.resx b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.resx new file mode 100644 index 0000000000..7795c02827 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507242008201_WebScheduler.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.Designer.cs new file mode 100644 index 0000000000..8830d1f8ac --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class Merge2 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(Merge2)); + + string IMigrationMetadata.Id + { + get { return "201507250039446_Merge2"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.cs b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.cs new file mode 100644 index 0000000000..a26a4dfe70 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.cs @@ -0,0 +1,16 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class Merge2 : DbMigration + { + public override void Up() + { + } + + public override void Down() + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.resx b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.resx new file mode 100644 index 0000000000..483dbdf042 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201507250039446_Merge2.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.Designer.cs new file mode 100644 index 0000000000..fbd14a355a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class RemoveKeepAlive : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(RemoveKeepAlive)); + + string IMigrationMetadata.Id + { + get { return "201508042207146_RemoveKeepAlive"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs new file mode 100644 index 0000000000..8c0dc62ad6 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.cs @@ -0,0 +1,40 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using System.Web.Hosting; + using Core.Data; + using SmartStore.Data.Setup; + + public partial class RemoveKeepAlive : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) + { + Sql("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.Services.Common.KeepAliveTask, SmartStore.Services'"); + } + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.System.ScheduleTasks", + "Scheduled Tasks", + "Geplante Aufgaben"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.resx b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.resx new file mode 100644 index 0000000000..483dbdf042 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508042207146_RemoveKeepAlive.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.Designer.cs new file mode 100644 index 0000000000..532c012d7e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ExportFramework : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ExportFramework)); + + string IMigrationMetadata.Id + { + get { return "201508091512101_ExportFramework"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.cs new file mode 100644 index 0000000000..5203e70451 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.cs @@ -0,0 +1,485 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using System.Web.Hosting; + using SmartStore.Core.Data; + using SmartStore.Core.Domain.Customers; + using SmartStore.Core.Domain.Security; + using SmartStore.Data.Setup; + + public partial class ExportFramework : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.ExportDeployment", + c => new + { + Id = c.Int(nullable: false, identity: true), + ProfileId = c.Int(nullable: false), + Name = c.String(nullable: false, maxLength: 100), + Enabled = c.Boolean(nullable: false), + IsPublic = c.Boolean(nullable: false), + DeploymentTypeId = c.Int(nullable: false), + Username = c.String(maxLength: 400), + Password = c.String(maxLength: 400), + Url = c.String(maxLength: 4000), + FileSystemPath = c.String(maxLength: 400), + EmailAddresses = c.String(maxLength: 4000), + EmailSubject = c.String(maxLength: 400), + EmailAccountId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.ExportProfile", t => t.ProfileId, cascadeDelete: true) + .Index(t => t.ProfileId); + + CreateTable( + "dbo.ExportProfile", + c => new + { + Id = c.Int(nullable: false, identity: true), + Name = c.String(nullable: false, maxLength: 100), + FolderName = c.String(nullable: false, maxLength: 100), + ProviderSystemName = c.String(nullable: false, maxLength: 4000), + Enabled = c.Boolean(nullable: false), + SchedulingTaskId = c.Int(nullable: false), + Filtering = c.String(), + Projection = c.String(), + ProviderConfigData = c.String(), + Offset = c.Int(nullable: false), + Limit = c.Int(nullable: false), + BatchSize = c.Int(nullable: false), + PerStore = c.Boolean(nullable: false), + CompletedEmailAddresses = c.String(maxLength: 400), + CreateZipArchive = c.Boolean(nullable: false), + Cleanup = c.Boolean(nullable: false), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.ScheduleTask", t => t.SchedulingTaskId) + .Index(t => t.SchedulingTaskId); + + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) + { + this.SqlFileOrResource("LatestProductLoadAllPaged.sql"); + } + } + + public override void Down() + { + DropForeignKey("dbo.ExportDeployment", "ProfileId", "dbo.ExportProfile"); + DropForeignKey("dbo.ExportProfile", "SchedulingTaskId", "dbo.ScheduleTask"); + DropIndex("dbo.ExportProfile", new[] { "SchedulingTaskId" }); + DropIndex("dbo.ExportDeployment", new[] { "ProfileId" }); + DropTable("dbo.ExportProfile"); + DropTable("dbo.ExportDeployment"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var permissionMigrator = new PermissionMigrator(context); + + permissionMigrator.AddPermission(new PermissionRecord + { + Name = "Admin area. Manage Exports", + SystemName = "ManageExports", + Category = "Configuration" + }, new string[] { SystemCustomerRoleNames.Administrators }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Enabled", "Enabled", "Aktiviert"); + builder.AddOrUpdate("Common.Provider", "Provider", "Provider"); + builder.AddOrUpdate("Common.Profile", "Profile", "Profil"); + builder.AddOrUpdate("Common.Partition", "Partition", "Aufteilung"); + builder.AddOrUpdate("Common.Image", "Image", "Bild"); + builder.AddOrUpdate("Common.Filter", "Filter", "Filter"); + builder.AddOrUpdate("Common.Projection", "Projection", "Projektion"); + builder.AddOrUpdate("Common.Deployment", "Deployment", "Bereitstellung"); + builder.AddOrUpdate("Common.Website", "Website", "Web-Seite"); + builder.AddOrUpdate("Common.DetailDescription", "Detail description", "Detailbeschreibung"); + + builder.AddOrUpdate("Admin.Validation.UsernamePassword", "Please enter username and password", "Bitte geben Sie Benutzername und Passwort ein"); + builder.AddOrUpdate("Admin.Validation.Url", "Please enter a valid URL", "Bitte geben Sie eine gltige URL ein"); + builder.AddOrUpdate("Admin.Validation.Name", "Please enter a name", "Bitte geben Sie einen Namen ein"); + builder.AddOrUpdate("Admin.Validation.EmailAddress", "Please enter a valid email address", "Bitte geben Sie eine gltige E-Mail Adresse ein"); + + + builder.AddOrUpdate("Admin.DataExchange.Export.NoProfiles", + "There were no export profiles found.", + "Es wurden keine Exportprofile gefunden."); + + + builder.AddOrUpdate("Admin.DataExchange.Export.ProviderSystemName", + "Provider", + "Provider", + "Specifies the export provider. It is responsible for the individual formatting of the export data.", + "Legt den Export-Provider fest. Er ist fr die individuelle Formatierung der zu exportierenden Daten zustndig."); + + builder.AddOrUpdate("Admin.DataExchange.Export.EntityType", + "Object", + "Objekt", + "The object type the provider processes.", + "Der Objekttyp, den der Provider verarbeitet."); + + + builder.AddOrUpdate("Admin.DataExchange.Export.Name", + "Name of profile", + "Name des Profils", + "Specifies the name of the export profile.", + "Legt den Namen des Exportprofils fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.FileExtension", + "File type", + "Dateityp", + "The file type of the exported data.", + "Der Dateityp der exportierten Daten."); + + + + builder.AddOrUpdate("Admin.DataExchange.Export.BatchSize", + "Batch size", + "Stapelgre", + "Specifies the maximum number of records per export file. 0 is the default and means that all the records are exported in one file.", + "Legt die maximale Anzahl der Datenstze pro Exportdatei fest. 0 ist der Standard und bedeutet, dass alle Datenstze in eine Datei exportiert werden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.PerStore", + "Per store", + "Per Shop", + "Specifies whether to start a separate run-through for each store. For each shop a new file will be created.", + "Legt fest, ob fr jeden Shop ein separater Verarbeitungsdurchlauf erfolgen soll. Fr jeden Shop wird eine neue Datei erzeugt."); + + builder.AddOrUpdate("Admin.DataExchange.Export.CreateZipArchive", + "Create ZIP archive", + "ZIP-Archiv erstellen", + "Specifies whether to combine the export files in temporary a ZIP archive. The archive remains in the temporary folder of the export profile without further processing.", + "Legt fest, ob die Exportdateien in einem ZIP-Archiv zusammengefasst werden sollen. Das Archiv verbleibt im temporren Ordner des Exportprofils ohne weitere Vearbeitung."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Cleanup", + "Clean up at the end", + "Zum Schluss aufrumen", + "Specifies whether to delete unneeded files after deployment.", + "Legt fest, ob nicht mehr bentigte Dateien nach der Bereitstellung gelscht werden sollen."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Product", "Product", "Produkt"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Category", "Category", "Warengruppe"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Manufacturer", "Manufacturer", "Hersteller"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Customer", "Customer", "Kunde"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.Order", "Order", "Auftrag"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.StoreId", + "Store", + "Shop", + "Filter by store.", + "Nach Shop filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.CreatedFrom", + "Created from", + "Erstellt von", + "Filter by created date.", + "Nach dem Erstellungsdatum filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.CreatedTo", + "Created to", + "Erstellt bis", + "Filter by created date.", + "Nach dem Erstellungsdatum filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.IdMinimum", + "Product Id from", + "Produkt-ID von", + "Filter by product identifier.", + "Nach der Produkt-ID filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.IdMaximum", + "Product Id to", + "Produkt-ID bis", + "Filter by product identifier.", + "Nach der Produkt-ID filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.PriceMinimum", + "Price from", + "Preis von", + "Filter by price.", + "Nach dem Preis filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.PriceMaximum", + "Price to", + "Preis bis", + "Filter by price.", + "Nach dem Preis filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.AvailabilityMinimum", + "Availability from", + "Verfgbar von", + "Filter by availability quantity.", + "Nach der Verfgbarkeitsmenge filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.AvailabilityMaximum", + "Availability to", + "Verfgbar bis", + "Filter by availability quantity.", + "Nach der Verfgbarkeitsmenge filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.IsPublished", + "Published", + "Verffentlicht", + "Filter by publishing.", + "Nach Verffentlichung filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.CategoryIds", + "Categories", + "Warengruppen", + "Filter by categtories.", + "Nach Warengruppen filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.WithoutCategories", + "Without category mapping", + "Ohne Warengruppenzuordnung", + "Filter by missing category mapping.", + "Nach fehlender Warengruppenzuordnung filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.ManufacturerId", + "Manufacturer", + "Hersteller", + "Filter by manufacturer.", + "Nach Hersteller filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.WithoutManufacturers", + "Without manufacturer mapping", + "Ohne Herstellerzuordnung", + "Filter by missing manufacturer mapping.", + "Nach fehlender Herstellerzuordnung filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.ProductTagId", + "Product tag", + "Produkt-Tag", + "Filter by product tag.", + "Nach Produkt-Tag filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.FeaturedProducts", + "Only featured products", + "Nur empfohlene Produkte", + "Filter by featured products. Is only applied when the filtering by categories and manufacturers.", + "Nach empfohlenen Produkten filtern. Wird nur bei der Filterung nach Warengruppen und Hersteller angewendet."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.ProductType", + "Product type", + "Produkttyp", + "Filter by product type.", + "Nach Produkttyp filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.OrderStatusIds", + "Order status", + "Auftragsstatus", + "Filter by order status.", + "Nach Auftragsstaus filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.PaymentStatusIds", + "Payment status", + "Zahlungsstatus", + "Filter by payment status.", + "Nach Zahlungsstatus filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.ShippingStatusIds", + "Shipping status", + "Versandstatus", + "Filter by shipping status.", + "Nach Versandstatus filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.CustomerRoleIds", + "Customer roles", + "Kundengruppen", + "Filter by customer roles.", + "Nach Kundengruppen filtern."); + + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.StoreId", + "Store", + "Shop", + "Specifies the store to be applied to the export.", + "Legt den auf den Export anzuwendenden Shop fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.LanguageId", + "Language", + "Sprache", + "Specifies the language to be applied to the export.", + "Legt die auf den Export anzuwendende Sprache fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.CurrencyId", + "Currency", + "Whrung", + "Specifies the currency to be applied to the export.", + "Legt die auf den Export anzuwendende Whrung fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.CustomerId", + "Customer ID", + "Kunden-ID", + "Specifies the ID of the customer to be applied to the export. Is taken into account for price calculations for example.", + "Legt die ID des Kunden fest, auf den sich der Export beziehen soll. Wird z.B. bei Preisberechnungen bercksichtigt."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.DescriptionMerging", + "Product description", + "Artikelbeschreibung", + "Specifies what information to use for the description of the product.", + "Legt fest, welche Informationen zur Beschreibung des Artikel wie verwendet werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.DescriptionToPlainText", + "Remove HTML from description", + "HTML aus der Beschreibung entfernen", + "Specifies whether to remove all HTML from the product description for the export.", + "Legt fest, ob fr den Export alle HTML-Auszeichnungen aus der Artikelbeschreibung entfernt werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.AppendDescriptionText", + "Text to be appended", + "Anzuhngender Text", + "Specifies the text to be attached to the product description. If there are multiple texts then one of it is selected randomly.", + "Legt den an die Artikelbeschreibung anzuhngenden Text fest. Bei mehreren Texten wird einer per Zufall ausgewhlt."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.RemoveCriticalCharacters", + "Remove critical characters", + "Kritische Zeichen entfernen", + "Specifies whether to remove critical characters (like ) from the detail description.", + "Legt fest, ob kritische Zeichen (wie z.B. ) aus der Detailsbeschreibung entfernt werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.CriticalCharacters", + "Critical characters", + "Kritische Zeichen", + "List with characters to be removed from the detail description.", + "Liste mit Zeichen, die aus der Detailbeschreibung entfernt werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.PriceType", + "Product price", + "Produktpreis", + "Specifies the product price to be exported.", + "Legt den zu exportierenden Produktpreis fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.ConvertNetToGrossPrices", + "Convert net into gross prices", + "Netto- in Bruttopreise umrechnen", + "Specifies to convert net into gross prices.", + "Legt fest, dass Netto- in Bruttopreise umgerechnet werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.Brand", + "Manufacturer\\Brand", + "Hersteller\\Marke", + "Specifies the manufacturer or brand to be exported, if a product has no manufacturer assigned.", + "Legt den zu exportierenden Hersteller bzw. die Marke fest, wenn fr ein Produkt kein Hersteller zugeordnet ist."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.PictureSize", + "Product picture size", + "Produktbildgre", + "Specifies the size (in pixel) of the product image.", + "Legt die Gre (in Pixel) des Produktbildes fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.ShippingTime", + "Shipping time", + "Lieferzeit", + "Specifies the shipping time for products where it is unspecified.", + "Legt die Lieferzeit fr Produkte fest, wo diese nicht angegeben ist."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.ShippingCosts", + "Shipping costs", + "Versandkosten", + "The shipping costs to be exported.", + "Die zu exportierenden Versandkosten."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.FreeShippingThreshold", + "Free shipping threshold", + "Kostenloser Versand ab", + "Specifies the amount as from shipping is free.", + "Legt den Betrag fest, ab dem keine Versandkosten anfallen."); + + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.FileSystem", "File system", "Dateisystem"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.Email", "Email", "E-Mail"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.Http", "HTTP", "HTTP"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.Ftp", "FTP", "FTP"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.None", + "Not specified", "Nicht spezifiziert"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.ShortDescriptionOrNameIfEmpty", + "Short description or name if empty", "Kurzbeschreibung oder Name falls leer"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.ShortDescription", + "Short description", "Kurzbeschreibung"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.Description", + "Description", "Detailbeschreibung"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.NameAndShortDescription", + "Product name + short description", "Produktname + Kurzbeschreibung"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.NameAndDescription", + "Product name + long description", "Produktname + Detailbeschreibung"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.ManufacturerAndNameAndShortDescription", + "Manufacturer + Product name + short description", "Hersteller + Produktname + Kurzbeschreibung"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.ManufacturerAndNameAndDescription", + "Manufacturer + Product name + long description", "Hersteller + Produktname + Detailbeschreibung"); + + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.Name", + "Name", + "Name", + "Specifies the name of the deployment.", + "Legt den Namen der Bereitstellung fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.IsPublic", + "Copy to public folder", + "In ffentlichen Ordner kopieren", + "Specifies whether to copy the exported data into a folder that is accessible through the internet.", + "Legt fest, ob die exportierten Daten in einen bers Internet zugnglichen Ordner kopiert werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.FileSystemPath", + "Directory path", + "Ordnerpfad", + "Specifies the path (relative or absolute) where to deploy the data.", + "Legt den Pfad (relativ oder absolut) zu einem Ordner fest, in den die Daten bereitgestellt werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.DeploymentType", + "Type of deployment", + "Art der Bereitstellung", + "Specifies the deployment type.", + "Legt die Art Bereitstellung fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.Username", + "User name", + "Benutzername", + "Specifies the user name.", + "Legt den Benutzernamen fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.Password", + "Password", + "Passwort", + "Specifies the password.", + "Legt das Passwort fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.Url", + "URL\\Host", + "URL\\Host", + "Specifies the URL or host name where to send the data.", + "Legt die URL bzw. den Host-Namen fest, an die die Daten bermittelt werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.EmailAddresses", + "Email addresses to", + "E-Mail Adressen an", + "Specifies the email addresses where to send the data.", + "Legt die E-Mail Adressen fest, an die die Daten verschickt werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.EmailSubject", + "Email subject", + "E-Mail Betreff", + "Specifies the subject of the email.", + "Legt den Betreff der verschickten Daten fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.EmailAccountId", + "Email account", + "E-Mail Konto", + "Specifies the email account used to sent the data.", + "Legt das E-Mail Konto fest, ber welches die Daten verschickt werden sollen."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.resx new file mode 100644 index 0000000000..3f0be8609e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508091512101_ExportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.Designer.cs new file mode 100644 index 0000000000..da67ef8766 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class AddSyncMapping : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(AddSyncMapping)); + + string IMigrationMetadata.Id + { + get { return "201508121735397_AddSyncMapping"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.cs b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.cs new file mode 100644 index 0000000000..ce062a376e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.cs @@ -0,0 +1,113 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class AddSyncMapping : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.SyncMapping", + c => new + { + Id = c.Int(nullable: false, identity: true), + EntityId = c.Int(nullable: false), + SourceKey = c.String(nullable: false, maxLength: 150), + EntityName = c.String(nullable: false, maxLength: 100), + ContextName = c.String(nullable: false, maxLength: 100), + SourceHash = c.String(maxLength: 40), + CustomInt = c.Int(), + CustomString = c.String(), + CustomBool = c.Boolean(), + SyncedOnUtc = c.DateTime(nullable: false), + }) + .PrimaryKey(t => t.Id) + .Index(t => new { t.EntityId, t.EntityName, t.ContextName }, unique: true, name: "IX_SyncMapping_ByEntity") + .Index(t => new { t.SourceKey, t.EntityName, t.ContextName }, unique: true, name: "IX_SyncMapping_BySource"); + + } + + public override void Down() + { + DropIndex("dbo.SyncMapping", "IX_SyncMapping_BySource"); + DropIndex("dbo.SyncMapping", "IX_SyncMapping_ByEntity"); + DropTable("dbo.SyncMapping"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + string attachHint = "A file that is to be appended to each sent email (eg Terms, Conditions etc.)"; + string attachHintDe = "Eine Datei, die jedem gesendeten E-Mail angehangen werden soll (z.B. AGB, Widerrufsbelehrung etc.)"; + + builder.AddOrUpdate("Admin.ContentManagement.MessageTemplates.Fields.Attachment1FileId", + "Attachment 1", + "Anhang 1", + attachHint, + attachHintDe); + builder.AddOrUpdate("Admin.ContentManagement.MessageTemplates.Fields.Attachment2FileId", + "Attachment 2", + "Anhang 2", + attachHint, + attachHintDe); + builder.AddOrUpdate("Admin.ContentManagement.MessageTemplates.Fields.Attachment3FileId", + "Attachment 3", + "Anhang 3", + attachHint, + attachHintDe); + + builder.AddOrUpdate("Common.FileUploader.EnterUrl", + "Enter URL", + "URL eingeben"); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNumberEnabled", + "Save customer number", + "Kundennummer speichern", + "Specifies whether customer numbers can be saved.", + "Bestimmt ob Kundennummern hinterlegt werden knnen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.DisplayCustomerNumber", + "Display customer numbers in frontend", + "Kundennummern im Frontend anzeigen", + "Specifies whether customer numbers will be displayed to customers in their account area.", + "Bestimmt ob Kunden ihre Kundennummer in Ihrem Account-Bereich einsehen knnen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerCanEditNumberIfEmpty", + "Customers can enter a customer number", + "Kunden knnen Kundennummer hinterlegen", + "Specifies whether customers can enter a customer number if the customer number doesn't contain a value yet.", + "Bestimmt ob Kunden eine Kundennummer angeben knnen, wenn fr diese noch kein Wert hinterlegt wurde."); + + builder.AddOrUpdate("Common.FreeShipping", + "Free shipping", + "Versandkostenfrei"); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.ExtraRobotsDisallows", + "Extra Disallows for robots.txt", + "Extra Disallows fr robots.txt", + "Enter additional paths that should be included as Disallow entries in your robots.txt. Each entry has to be entered in a new line.", + "Geben Sie hier zustzliche Pfade an, die als Disallow-Eintrge zur robots.txt hinzugefgt werden sollen. Jeder Eintrag muss in einer neuen Zeile erfolgen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.DefaultSortOrderMode", + "Default product sort order", + "Standardsortierreihenfolge fr Produkte", + "Specifies the default product sort order.", + "Legt die Standardsortierreihenfolge fr Produkte fest."); + + builder.AddOrUpdate("Common.CustomerNumberAlreadyExists", + "Customer number already exists, please choose another.", + "Die von Ihnen gewhlte Kundennummer existiert bereits. Bitte geben Sie eine andere Kundennummer an."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.resx b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.resx new file mode 100644 index 0000000000..3299ad9347 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508121735397_AddSyncMapping.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.Designer.cs new file mode 100644 index 0000000000..85ac9e4af4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class CronExpressions : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(CronExpressions)); + + string IMigrationMetadata.Id + { + get { return "201508142203054_CronExpressions"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.cs b/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.cs new file mode 100644 index 0000000000..9f12663ade --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.cs @@ -0,0 +1,174 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Linq; + using System.Collections.Generic; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using SmartStore.Core.Domain.Tasks; + using SmartStore.Data.Setup; + + public partial class CronExpressions : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ScheduleTask", "CronExpression", c => c.String(maxLength: 1000, defaultValue: "0 */1 * * *" /* Every hour */)); + AddColumn("dbo.ScheduleTask", "RowVersion", c => c.Binary(nullable: false, fixedLength: true, timestamp: true, storeType: "rowversion")); + DropColumn("dbo.ScheduleTask", "Seconds"); + } + + public override void Down() + { + AddColumn("dbo.ScheduleTask", "Seconds", c => c.Int(nullable: false)); + DropColumn("dbo.ScheduleTask", "RowVersion"); + DropColumn("dbo.ScheduleTask", "CronExpression"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + // Seconds > CronExpressions + var table = context.Set(); + var tasks = table.ToList(); + + foreach (var task in tasks) + { + if (task.Type.Contains(".QueuedMessagesSendTask")) + { + task.CronExpression = "* * * * *"; // every Minute + } + else if (task.Type.Contains(".DeleteGuestsTask")) + { + task.CronExpression = "*/10 * * * *"; // every 10 Minutes + } + else if (task.Type.Contains(".ClearCacheTask")) + { + task.CronExpression = "0 */4 * * *"; // every 4 hrs + } + else if (task.Type.Contains(".UpdateExchangeRateTask")) + { + task.CronExpression = "0/15 * * * *"; // every 15 Minutes + } + else if (task.Type.Contains(".DeleteLogsTask")) + { + task.CronExpression = "0 1 * * *"; // At 01:00 + } + else if (task.Type.Contains(".TransientMediaClearTask")) + { + task.CronExpression = "30 1,13 * * *"; // At 01:30 and 13:30 + } + else if (task.Type.Contains(".QueuedMessagesClearTask")) + { + task.CronExpression = "0 2 * * *"; // At 02:00 + } + else if (task.Type.Contains(".UpdateRatingWidgetStateTask")) + { + task.CronExpression = "0 3 * * *"; // At 03:00 + } + else if (task.Type.Contains(".MailChimpSynchronizationTask")) + { + task.CronExpression = "0 */1 * * *"; // Every hour + } + else if (task.Type.Contains(".AmazonPay.DataPollingTask")) + { + task.CronExpression = "*/30 * * * *"; // Every 30 minutes + } + else if (task.Type.Contains(".NewsImportTask")) + { + task.CronExpression = "30 */12 * * *"; // At 30 minutes past the hour, every 12 hours + } + else if (task.Type.Contains(".TempFileCleanupTask")) + { + task.CronExpression = "30 3 * * *"; // At 03:30 + } + else if (task.Type.Contains(".BMEcat.FileImportTask")) + { + task.CronExpression = "30 2 * * *"; // At 02:30 + } + else if (task.Type.Contains(".StaticFileGenerationTask")) + { + task.CronExpression = "0 */6 * * *"; // Every 06 hours + } + else + { + task.CronExpression = "0 */1 * * *"; // Every hour + } + } + + context.SaveChanges(); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.Delete( + "Admin.System.ScheduleTasks.Seconds", + "Admin.System.ScheduleTasks.Seconds.Positive", + "Admin.System.ScheduleTasks.RunNow.Completed"); + + builder.AddOrUpdate("Common.Rule", + "Rule", + "Regel"); + builder.AddOrUpdate("Common.Scheduled", + "Scheduled", + "Geplant"); + builder.AddOrUpdate("Common.Unscheduled", + "Unscheduled", + "Ungeplant"); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.CronExpression", + "Cron Expression", + "Cron Ausdruck", + "An expression that defines the schedule for the automatic execution of the task.", + "Ein Ausdruck, der den Zeitplan fr die automatische Ausfhrung der Aufgabe festlegt."); + builder.AddOrUpdate("Admin.System.ScheduleTasks.Enabled.Hint", + "Enables the scheduled execution of the task in accordance with the cron expression", + "Aktiviert die geplante Ausfhrung der Aufgabe gem Cron Ausdruck"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.StopOnError", + "Disable on error", + "Bei Fehler deaktivieren", + "Check the box if the task should be disabled automatically when an error occurs during execution", + "Aktivieren Sie das Kstchen, wenn die Aufgabe bei Auftreten eines Fehlers whrend der Ausfhrung deaktiviert werden soll"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.LastStart.Hint", + "Start date of the last execution", + "Startdatum der letzten Ausfhrung"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.LastSuccess.Hint", + "Start date of the last successful execution", + "Startdatum der letzten erfolgreichen Ausfhrung"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.Duration.Hint", + "Duration of the latest execution ([h]:[min]:[sec])", + "Dauer der letzten Ausfhrung ([Std.]:[Min.]:[Sek.])"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.NextRun.Hint", + "Date of the next scheduled execution", + "Datum der nchsten geplanten Ausfhrung"); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.CronHelp", + "Cron Expressions help", + "Hilfe zu Cron-Ausdrcken"); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.FutureSchedules", + "Future schedules", + "Zuknftige Zeitplne"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.EditTask", + "Edit task", + "Aufgabe bearbeiten"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.ScheduleExecution", + "Schedule execution", + "Ausfhrung planen"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.InvalidCronExpression", + "The cron expression is invalid", + "Der Cron-Ausdruck ist ungltig"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.RunNow.Success", + "The task has been executed successfully", + "Aufgabe wurde erfolgreich ausgefhrt"); + builder.AddOrUpdate("Admin.System.ScheduleTasks.UpdateSuccess", + "The task has been updated successfully", + "Die Aufgabe wurde erfolgreich bearbeitet"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.resx b/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.resx new file mode 100644 index 0000000000..62a0f6a2fb --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508142203054_CronExpressions.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.Designer.cs new file mode 100644 index 0000000000..7884363732 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class Merge1 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(Merge1)); + + string IMigrationMetadata.Id + { + get { return "201508211346171_Merge1"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.cs b/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.cs new file mode 100644 index 0000000000..146e495730 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.cs @@ -0,0 +1,16 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class Merge1 : DbMigration + { + public override void Up() + { + } + + public override void Down() + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.resx b/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.resx new file mode 100644 index 0000000000..3f0be8609e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201508211346171_Merge1.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.Designer.cs new file mode 100644 index 0000000000..0bb342e80d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ExportFramework1 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ExportFramework1)); + + string IMigrationMetadata.Id + { + get { return "201509021536425_ExportFramework1"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.cs b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.cs new file mode 100644 index 0000000000..09f2dc6314 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.cs @@ -0,0 +1,369 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class ExportFramework1 : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ExportDeployment", "CreateZip", c => c.Boolean(nullable: false)); + AddColumn("dbo.ExportDeployment", "HttpTransmissionTypeId", c => c.Int(nullable: false)); + AddColumn("dbo.ExportDeployment", "HttpTransmissionType", c => c.Int(nullable: false)); + AddColumn("dbo.ExportDeployment", "PassiveMode", c => c.Boolean(nullable: false)); + AddColumn("dbo.ExportDeployment", "UseSsl", c => c.Boolean(nullable: false)); + AddColumn("dbo.ExportProfile", "FileNamePattern", c => c.String(maxLength: 400)); + AddColumn("dbo.ExportProfile", "EmailAccountId", c => c.Int(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.ExportProfile", "EmailAccountId"); + DropColumn("dbo.ExportProfile", "FileNamePattern"); + DropColumn("dbo.ExportDeployment", "UseSsl"); + DropColumn("dbo.ExportDeployment", "PassiveMode"); + DropColumn("dbo.ExportDeployment", "HttpTransmissionType"); + DropColumn("dbo.ExportDeployment", "HttpTransmissionTypeId"); + DropColumn("dbo.ExportDeployment", "CreateZip"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + context.Execute("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.Billiger.StaticFileGenerationTask, SmartStore.Billiger'"); + context.Execute("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.ElmarShopinfo.StaticFileGenerationTask, SmartStore.ElmarShopinfo'"); + context.Execute("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.Guenstiger.StaticFileGenerationTask, SmartStore.Guenstiger'"); + context.Execute("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.Shopwahl.StaticFileGenerationTask, SmartStore.Shopwahl'"); + + context.MigrateSettings(x => + { + x.DeleteGroup("BilligerSettings"); + x.DeleteGroup("ElmarShopinfoSettings"); + x.DeleteGroup("GuenstigerSettings"); + x.DeleteGroup("ShopwahlSettings"); + }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.ExportSelected", "Export selected", "Ausgewhlte exportieren"); + builder.AddOrUpdate("Admin.Common.ExportAll", "Export all", "Alle exportieren"); + builder.AddOrUpdate("Common.Public", "public", "ffentlich"); + + builder.AddOrUpdate("Admin.System.ScheduleTask", "Scheduled task", "Geplante Aufgabe"); + + builder.AddOrUpdate("Admin.DataExchange.Export.NoExportProvider", + "There were no export provider found.", + "Es wurden keine Export-Provider gefunden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.ProgressInfo", + "{0} of {1} records exported", + "{0} von {1} Datenstzen exportiert"); + + builder.AddOrUpdate("Admin.DataExchange.Export.FileNamePattern", + "Pattern for file names", + "Muster fr Dateinamen", + "Specifies the pattern for creating file names.", + "Legt das Muster fest, nach dem Dateinamen erzeugt werden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.EmailAccountId", + "Email notification", + "E-Mail Benachrichtigung", + "Specifies the email account used to send a notification message of the completion of the export.", + "Legt das E-Mail Konto fest, ber welches eine Benachrichtigung ber die Fertigstellung des Exports verschickt werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.CompletedEmailAddresses", + "Email addresses to", + "E-Mail Adressen an", + "Specifies the email addresses where to send the notification message.", + "Legt die E-Mail Adressen fest, an die die Benachrichtigung geschickt werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.CompletedEmail.Subject", + "Export of profile \"{0}\" has been finished", + "Export von Profil \"{0}\" ist abgeschlossen"); + + builder.AddOrUpdate("Admin.DataExchange.Export.CompletedEmail.Body", + "This is an automatic notification of store \"{0}\" about a recent data export.", + "Dies ist eine automatische Benachrichtung von Shop \"{0}\" ber einen erfolgten Datenexport."); + + builder.AddOrUpdate("Admin.DataExchange.Export.FolderName", + "Folder name", + "Ordnername", + "Specifies the name of the folder where to export the data.", + "Legt den Namen des Ordners fest, in den die Daten exportiert werden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.FolderAndFileName.Validate", + "Please enter a valid folder and file name. Example for file names: %File.Index%-%Profile.Id%-gmc-%Store.Name%", + "Bitte einen gltigen Ordner- und Dateinamen eingeben. Beispiel fr Dateinamen: %File.Index%-%Profile.Id%-gmc-%Store.Name%"); + + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.CreateZip", + "Create ZIP archive", + "ZIP-Archiv erstellen", + "Specifies whether to combine the export files in a ZIP archive and only to deploy the archive.", + "Legt fest, ob die Exportdateien in einem ZIP-Archiv zusammengefasst und nur das Archiv bereitgestellt werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.AttributeCombinationAsProduct", + "Export attribute combinations", + "Attributkombinationen exportieren", + "Specifies whether to export a standalone product for each active attribute combination.", + "Legt fest, ob fr jede aktive Attributkombination ein eigenstndiges Produkt exportiert werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.AttributeCombinationValueMerging", + "Attribute values", + "Attributwerte", + "Specifies if and how to further process the attribute values.", + "Legt fest, ob und wie die Werte der Attribute weiter verarbeitet werden sollen."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportAttributeValueMerging.None", + "Not specified", "Nicht spezifiziert"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportAttributeValueMerging.AppendAllValuesToName", + "Append all values to the product name", "Alle Werte an den Produktnamen anhngen"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.HttpTransmissionType", + "HTTP transmission type", + "HTTP bertragungsart", + "Specifies how to transmit the export files via HTTP.", + "Legt fest, aus welcher Art die Exportdateien per HTTP bertragen werden sollen."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportHttpTransmissionType.SimplePost", "Simple POST", "Einfacher POST"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportHttpTransmissionType.MultipartFormDataPost", "Multipart form data POST", "Multipart-Form-Data POST"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.PassiveMode", + "Passive mode", + "Passiver Modus", + "Specifies whether to exchange data in active or passive mode.", + "Legt fest, ob Daten im aktiven oder passiven Modus ausgetauscht werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.UseSsl", + "Use SSL", + "SSL verwenden", + "Specifies whether to use a SSL (Secure Sockets Layer) connection.", + "Legt fest, ob einen SSL (Secure Sockets Layer) Verbindung genutzt werden soll."); + + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.Note", + "Specify individual filters to limit the exported data.", + "Legen Sie individuelle Filter fest, um die zu exportierenden Daten einzugrenzen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.Note", + "The following information will be taken into account during the export and integrated in the process.", + "Die folgenden Angaben werden beim Export bercksichtigt und an entsprechenden Stellen in den Vorgang eingebunden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Configuration.Note", + "The following specific information will be taken into account by the provider during the export.", + "Die folgenden spezifischen Angaben werden durch den Provider beim Export bercksichtigt."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Configuration.NotRequired", + "The export provider {0} requires no further configuration.", + "Der Export-Provider {0} bentigt keine weitergehende Konfiguration."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.Note", + "Click Insert to add one or multiple publishing profiles to specify how to further proceed with the export files.", + "Legen Sie ber Hinzufgen ein oder mehrere Verffentlichungsprofile an, um festzulegen wie mit den Exportdateien weiter zu verfahren ist."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportOrderStatusChange.None", "None", "Keine"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportOrderStatusChange.Processing", "Processing", "Wird bearbeitet"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportOrderStatusChange.Complete", "Complete", "Komplett"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.OrderStatusChange", + "Change order status to", + "Auftragsstatus ndern in", + "Specifies if and how to change the status of the exported orders.", + "Legt fest, ob und wie der Status der exportierten Auftrge gendert werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.EnableProfileForPreview", + "The export profile is disabled. It must be enabled to preview the export data.", + "Das Exportprofil ist deaktiviert. Fr eine Exportvorschau muss das Exportprofil aktiviert sein."); + + builder.AddOrUpdate("Admin.DataExchange.Export.NoProfilesForProvider", + "There was no export profile of type {0} found. Create now a new export profile.", + "Es wurde kein Exportprofil vom Typ {0} gefunden. Jetzt ein neues Exportprofil anlegen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.ProfileForProvider", + "Export profile", + "Exportprofil", + "The export profile for this export provider.", + "Das Exportprofil fr diesen Export-Provider."); + + + RemoveObsoleteResources(builder); + } + + private void RemoveObsoleteResources(LocaleResourcesBuilder builder) + { + builder.Delete( + "Plugins.Feed.FreeShippingThreshold" + ); + + builder.Delete( + "Plugins.Feed.Billiger.ProductPictureSize", + "Plugins.Feed.Billiger.ProductPictureSize.Hint", + "Plugins.Feed.Billiger.TaskEnabled", + "Plugins.Feed.Billiger.TaskEnabled.Hint", + "Plugins.Feed.Billiger.StaticFileUrl", + "Plugins.Feed.Billiger.StaticFileUrl.Hint", + "Plugins.Feed.Billiger.GenerateStaticFileEachMinutes", + "Plugins.Feed.Billiger.GenerateStaticFileEachMinutes.Hint", + "Plugins.Feed.Billiger.BuildDescription", + "Plugins.Feed.Billiger.BuildDescription.Hint", + "Plugins.Feed.Billiger.Automatic", + "Plugins.Feed.Billiger.DescShort", + "Plugins.Feed.Billiger.DescLong", + "Plugins.Feed.Billiger.DescTitleAndShort", + "Plugins.Feed.Billiger.DescTitleAndLong", + "Plugins.Feed.Billiger.DescManuAndTitleAndShort", + "Plugins.Feed.Billiger.DescManuAndTitleAndLong", + "Plugins.Feed.Billiger.DescriptionToPlainText", + "Plugins.Feed.Billiger.DescriptionToPlainText.Hint", + "Plugins.Feed.Billiger.ShippingCost", + "Plugins.Feed.Billiger.ShippingCost.Hint", + "Plugins.Feed.Billiger.ShippingTime", + "Plugins.Feed.Billiger.ShippingTime.Hint", + "Plugins.Feed.Billiger.Brand", + "Plugins.Feed.Billiger.Brand.Hint", + "Plugins.Feed.Billiger.UseOwnProductNo", + "Plugins.Feed.Billiger.UseOwnProductNo.Hint", + "Plugins.Feed.Billiger.Store", + "Plugins.Feed.Billiger.Store.Hint", + "Plugins.Feed.Billiger.ConvertNetToGrossPrices", + "Plugins.Feed.Billiger.ConvertNetToGrossPrices.Hint", + "Plugins.Feed.Billiger.LanguageId", + "Plugins.Feed.Billiger.LanguageId.Hint", + "Plugins.Feed.Billiger.ConfigSaveNote", + "Plugins.Feed.Billiger.GeneratingNow", + "Plugins.Feed.Billiger.SuccessResult" + ); + + builder.Delete( + "Plugins.Feed.ElmarShopinfo.TaskEnabled", + "Plugins.Feed.ElmarShopinfo.TaskEnabled.Hint", + "Plugins.Feed.ElmarShopinfo.StaticFileUrl", + "Plugins.Feed.ElmarShopinfo.StaticFileUrl.Hint", + "Plugins.Feed.ElmarShopinfo.GenerateStaticFileEachMinutes", + "Plugins.Feed.ElmarShopinfo.GenerateStaticFileEachMinutes.Hint", + "Plugins.Feed.ElmarShopinfo.BuildDescription", + "Plugins.Feed.ElmarShopinfo.BuildDescription.Hint", + "Plugins.Feed.ElmarShopinfo.Automatic", + "Plugins.Feed.ElmarShopinfo.DescShort", + "Plugins.Feed.ElmarShopinfo.DescLong", + "Plugins.Feed.ElmarShopinfo.DescTitleAndShort", + "Plugins.Feed.ElmarShopinfo.DescTitleAndLong", + "Plugins.Feed.ElmarShopinfo.DescManuAndTitleAndShort", + "Plugins.Feed.ElmarShopinfo.DescManuAndTitleAndLong", + "Plugins.Feed.ElmarShopinfo.DescriptionToPlainText", + "Plugins.Feed.ElmarShopinfo.DescriptionToPlainText.Hint", + "Plugins.Feed.ElmarShopinfo.ProductPictureSize", + "Plugins.Feed.ElmarShopinfo.ProductPictureSize.Hint", + "Plugins.Feed.ElmarShopinfo.Currency", + "Plugins.Feed.ElmarShopinfo.Currency.Hint", + "Plugins.Feed.ElmarShopinfo.ShippingTime", + "Plugins.Feed.ElmarShopinfo.ShippingTime.Hint", + "Plugins.Feed.ElmarShopinfo.Brand", + "Plugins.Feed.ElmarShopinfo.Brand.Hint", + "Plugins.Feed.ElmarShopinfo.Store", + "Plugins.Feed.ElmarShopinfo.Store.Hint", + "Plugins.Feed.ElmarShopinfo.ConvertNetToGrossPrices", + "Plugins.Feed.ElmarShopinfo.ConvertNetToGrossPrices.Hint", + "Plugins.Feed.ElmarShopInfo.LanguageId", + "Plugins.Feed.ElmarShopInfo.LanguageId.Hint", + "Plugins.Feed.ElmarShopInfo.General", + "Plugins.Feed.ElmarShopInfo.General.Hint", + "Plugins.Feed.ElmarShopInfo.Automation", + "Plugins.Feed.ElmarShopInfo.Automation.Hint", + "Plugins.Feed.ElmarShopInfo.Address", + "Plugins.Feed.ElmarShopInfo.Address.Hint", + "Plugins.Feed.ElmarShopInfo.Contact", + "Plugins.Feed.ElmarShopInfo.Contact.Hint", + "Plugins.Feed.ElmarShopInfo.Generate", + "Plugins.Feed.ElmarShopInfo.ConfigSaveNote" + ); + + builder.Delete( + "Plugins.Feed.Guenstiger.TaskEnabled", + "Plugins.Feed.Guenstiger.TaskEnabled.Hint", + "Plugins.Feed.Guenstiger.StaticFileUrl", + "Plugins.Feed.Guenstiger.StaticFileUrl.Hint", + "Plugins.Feed.Guenstiger.GenerateStaticFileEachMinutes", + "Plugins.Feed.Guenstiger.GenerateStaticFileEachMinutes.Hint", + "Plugins.Feed.Guenstiger.BuildDescription", + "Plugins.Feed.Guenstiger.BuildDescription.Hint", + "Plugins.Feed.Guenstiger.Automatic", + "Plugins.Feed.Guenstiger.DescShort", + "Plugins.Feed.Guenstiger.DescLong", + "Plugins.Feed.Guenstiger.DescTitleAndShort", + "Plugins.Feed.Guenstiger.DescTitleAndLong", + "Plugins.Feed.Guenstiger.DescManuAndTitleAndShort", + "Plugins.Feed.Guenstiger.DescManuAndTitleAndLong", + "Plugins.Feed.Guenstiger.ProductPictureSize", + "Plugins.Feed.Guenstiger.ProductPictureSize.Hint", + "Plugins.Feed.Guenstiger.Brand", + "Plugins.Feed.Guenstiger.Brand.Hint", + "Plugins.Feed.Guenstiger.ShippingTime", + "Plugins.Feed.Guenstiger.ShippingTime.Hint", + "Plugins.Feed.Guenstiger.Store", + "Plugins.Feed.Guenstiger.Store.Hint", + "Plugins.Feed.Guenstiger.ConvertNetToGrossPrices", + "Plugins.Feed.Guenstiger.ConvertNetToGrossPrices.Hint", + "Plugins.Feed.Guenstiger.LanguageId", + "Plugins.Feed.Guenstiger.LanguageId.Hint", + "Plugins.Feed.Guenstiger.NoSpec", + "Plugins.Feed.Guenstiger.NoSpec.Hint", + "Plugins.Feed.Guenstiger.DescriptionToPlainText", + "Plugins.Feed.Guenstiger.DescriptionToPlainText.Hint", + "Plugins.Feed.Guenstiger.Generate", + "Plugins.Feed.Guenstiger.ConfigSaveNote" + ); + + builder.Delete( + "Plugins.Feed.Shopwahl.TaskEnabled", + "Plugins.Feed.Shopwahl.TaskEnabled.Hint", + "Plugins.Feed.Shopwahl.StaticFileUrl", + "Plugins.Feed.Shopwahl.StaticFileUrl.Hint", + "Plugins.Feed.Shopwahl.GenerateStaticFileEachMinutes", + "Plugins.Feed.Shopwahl.GenerateStaticFileEachMinutes.Hint", + "Plugins.Feed.Shopwahl.ShippingCost", + "Plugins.Feed.Shopwahl.ShippingCost.Hint", + "Plugins.Feed.Shopwahl.ShippingTime", + "Plugins.Feed.Shopwahl.ShippingTime.Hint", + "Plugins.Feed.Shopwahl.Currency", + "Plugins.Feed.Shopwahl.Currency.Hint", + "Plugins.Feed.Shopwahl.ProductPictureSize", + "Plugins.Feed.Shopwahl.ProductPictureSize.Hint", + "Plugins.Feed.Shopwahl.BuildDescription", + "Plugins.Feed.Shopwahl.BuildDescription.Hint", + "Plugins.Feed.Shopwahl.Automatic", + "Plugins.Feed.Shopwahl.DescShort", + "Plugins.Feed.Shopwahl.DescLong", + "Plugins.Feed.Shopwahl.DescTitleAndShort", + "Plugins.Feed.Shopwahl.DescTitleAndLong", + "Plugins.Feed.Shopwahl.DescManuAndTitleAndShort", + "Plugins.Feed.Shopwahl.DescManuAndTitleAndLong", + "Plugins.Feed.Shopwahl.NoSpec", + "Plugins.Feed.Shopwahl.UseOwnProductNo", + "Plugins.Feed.Shopwahl.UseOwnProductNo.Hint", + "Plugins.Feed.Shopwahl.DescriptionToPlainText", + "Plugins.Feed.Shopwahl.DescriptionToPlainText.Hint", + "Plugins.Feed.Shopwahl.Brand", + "Plugins.Feed.Shopwahl.Brand.Hint", + "Plugins.Feed.Shopwahl.ExportFormat", + "Plugins.Feed.Shopwahl.ExportFormat.Hint", + "Plugins.Feed.Shopwahl.Store", + "Plugins.Feed.Shopwahl.Store.Hint", + "Plugins.Feed.Shopwahl.ConvertNetToGrossPrices", + "Plugins.Feed.Shopwahl.ConvertNetToGrossPrices.Hint", + "Plugins.Feed.Shopwahl.LanguageId", + "Plugins.Feed.Shopwahl.LanguageId.Hint", + "Plugins.Feed.Shopwahl.Generate", + "Plugins.Feed.Shopwahl.ConfigSaveNote" + ); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.resx b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.resx new file mode 100644 index 0000000000..e07999aa4a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509021536425_ExportFramework1.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.Designer.cs new file mode 100644 index 0000000000..b8acae3dd9 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class Merge3 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(Merge3)); + + string IMigrationMetadata.Id + { + get { return "201509031112324_Merge3"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.cs b/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.cs new file mode 100644 index 0000000000..24ce9a2d5f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.cs @@ -0,0 +1,16 @@ +namespace SmartStore.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class Merge3 : DbMigration + { + public override void Up() + { + } + + public override void Down() + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.resx b/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.resx new file mode 100644 index 0000000000..e84ddc5393 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509031112324_Merge3.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.Designer.cs new file mode 100644 index 0000000000..1ff305bd2d --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ExportFramework2 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ExportFramework2)); + + string IMigrationMetadata.Id + { + get { return "201509150931528_ExportFramework2"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs new file mode 100644 index 0000000000..5bab264538 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.cs @@ -0,0 +1,276 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + + public partial class ExportFramework2 : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ExportProfile", "ResultInfo", c => c.String()); + } + + public override void Down() + { + DropColumn("dbo.ExportProfile", "ResultInfo"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + context.Execute("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.GoogleMerchantCenter.StaticFileGenerationTask, SmartStore.GoogleMerchantCenter'"); + context.Execute("DELETE FROM [dbo].[ScheduleTask] WHERE [Type] = 'SmartStore.BMEcat.StaticFileGenerationTask, SmartStore.BMEcat'"); + + context.MigrateSettings(x => + { + x.DeleteGroup("FroogleSettings"); + x.DeleteGroup("BMEcatExportSettings"); + x.DeleteGroup("OpenTransSettings"); + }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Common.Example", "Example", "Beispiel"); + builder.AddOrUpdate("Common.ShowAll", "Show all", "Alle anzeigen"); + builder.AddOrUpdate("Admin.Common.Selected", "Selected", "Ausgewhlte"); + builder.AddOrUpdate("Admin.Common.Entity", "Object", "Objekt"); + builder.AddOrUpdate("Admin.Common.Placeholder", "Placeholder", "Platzhalter"); + + + builder.AddOrUpdate("Admin.Common.FilesDeleted", + "{0} files were deleted", + "{0} Dateien wurden gelscht"); + + builder.AddOrUpdate("Admin.Common.FoldersDeleted", + "{0} folders were deleted", + "{0} Verzeichnisse wurden gelscht"); + + builder.AddOrUpdate("Admin.Common.ProviderNotLoaded", + "Cannot load the provider {0}.", + "Der Provider {0} konnte nicht geladen werden."); + + builder.AddOrUpdate("Admin.Common.NoEntriesSelected", + "No entries have been selected.", + "Es wurden keine Eintrge ausgewhlt."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Blog.ShowHeaderRSSUrl.Hint", + "Check to enable the blog RSS feed link in customers browser address bar.", + "Legt fest, ob der RSS-Feed-Link in der Adressleiste des Browsers angezeigt werden soll."); + + + builder.AddOrUpdate("Admin.System.SeNames", "SEO Names", "SEO Namen"); + builder.Delete("Admin.System.SeNames.DeleteSelected"); + + builder.AddOrUpdate("Admin.System.SeNames.Name", + "SEO Name", + "SEO Name", + "Specifies the SEO name.", + "Legt den SEO Namen fest."); + + builder.AddOrUpdate("Admin.System.SeNames.EntityId", + "Object ID", + "Objekt-ID", + "Specifies the ID of the associated object.", + "Legt die ID des zugehrigen Objektes fest."); + + builder.AddOrUpdate("Admin.System.SeNames.EntityName", + "Object", + "Objekt", + "Specifies the name of the associated object.", + "Legt den Namen der zugehrigen Objektes fest."); + + builder.AddOrUpdate("Admin.System.SeNames.IsActive", + "Is active", + "Ist aktiv", + "Specifies whether the SEO name is active or inactive.", + "Legt fest, ob der SEO Name aktiv oder inaktiv ist."); + + builder.AddOrUpdate("Admin.System.SeNames.Language", + "Language", + "Sprache", + "Specifies the language of the SEO name.", + "Legt die Sprache des SEO Namens fest."); + + builder.AddOrUpdate("Admin.System.SeNames.SlugsPerEntity", + "Names per object", + "Namen pro Objekt", + "The number of SEO names per object.", + "Die Anzahl der SEO Namen pro Objekt."); + + builder.AddOrUpdate("Admin.System.SeNames.ActiveSlugAlreadyExist", + "Only one active SEO name should be set per language.", + "Pro Sprache darf nur ein aktiver SEO Name festgelegt werden."); + + + builder.AddOrUpdate("Admin.DataExchange.Export.FileNamePatternDescriptions", + "ID of export profil;Folder name of export profil;SEO name of export profil;Store ID;SEO name of store;One based file index;Random number;UTC timestamp", + "ID des Exportprofils;Ordername des Exportprofils;SEO Name des Exportprofils;Shop ID;SEO Name des Shops;Mit 1 beginnender Dateiindex;Zufallszahl;UTC Zeitstempel"); + + builder.AddOrUpdate("Admin.DataExchange.Export.NotPreviewCompatible", + "This option is not taken into account in the preview.", + "Diese Option wird in der Vorschau nicht bercksichtigt."); + + builder.AddOrUpdate("Admin.DataExchange.Export.CloneProfile", + "Apply settings from", + "Einstellungen bernehmen von", + "Specifies an export profile from which to apply the settings.", + "Legt das Exportprofil fest, von welchem die Einstellungen bernommen werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.NonFileBasedExport.Note", + "The export provider does not explicit support any file type. Therefore, the export provider is responsible for futher deployment of export data.", + "Der Export-Provider untersttzt keinen expliziten Dateityp. Fr eine weitere Bereitstellung der Exportdaten ist daher der Export-Provider verantwortlich."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.NoGroupedProducts", + "Do not export grouped products", + "Keine Gruppenprodukte exportieren", + "Specifies whether to export grouped products. If this option is activated, then the associated products will be exported.", + "Legt fest, ob Gruppenprodukte exportiert werden sollen. Ist diese Option aktiviert, so werden die zur Gruppe gehrenden Produkte exportiert."); + + builder.AddOrUpdate("Admin.DataExchange.Export.NoFiltering", + "There is no filtering available.", + "Mglichkeiten der Filterung stehen nicht zur Verfgung."); + + builder.AddOrUpdate("Admin.DataExchange.Export.NoProjection", + "There is no projection available.", + "Mglichkeiten der Projektion stehen nicht zur Verfgung."); + + builder.AddOrUpdate("Admin.DataExchange.Export.NoPreview", + "There is no preview available for this entity type.", + "Eine Vorschau steht fr diesen Entittstyp nicht zur Verfgung."); + + + builder.Delete( + "Plugins.Feed.Froogle.TaskEnabled", + "Plugins.Feed.Froogle.TaskEnabled.Hint", + "Plugins.Feed.Froogle.StaticFileUrl", + "Plugins.Feed.Froogle.StaticFileUrl.Hint", + "Plugins.Feed.Froogle.GenerateStaticFileEachMinutes", + "Plugins.Feed.Froogle.GenerateStaticFileEachMinutes.Hint", + "Plugins.Feed.Froogle.Currency", + "Plugins.Feed.Froogle.Currency.Hint", + "Plugins.Feed.Froogle.ProductPictureSize", + "Plugins.Feed.Froogle.ProductPictureSize.Hint", + "Plugins.Feed.Froogle.AppendDescriptionText", + "Plugins.Feed.Froogle.AppendDescriptionText.Hint", + "Plugins.Feed.Froogle.BuildDescription", + "Plugins.Feed.Froogle.BuildDescription.Hint", + "Plugins.Feed.Froogle.Automatic", + "Plugins.Feed.Froogle.DescShort", + "Plugins.Feed.Froogle.DescLong", + "Plugins.Feed.Froogle.DescTitleAndShort", + "Plugins.Feed.Froogle.DescTitleAndLong", + "Plugins.Feed.Froogle.DescManuAndTitleAndShort", + "Plugins.Feed.Froogle.DescManuAndTitleAndLong", + "Plugins.Feed.Froogle.UseOwnProductNo", + "Plugins.Feed.Froogle.UseOwnProductNo.Hint", + "Plugins.Feed.Froogle.DescriptionToPlainText", + "Plugins.Feed.Froogle.DescriptionToPlainText.Hint", + "Plugins.Feed.Froogle.Brand", + "Plugins.Feed.Froogle.Brand.Hint", + "Plugins.Feed.Froogle.Store", + "Plugins.Feed.Froogle.Store.Hint", + "Plugins.Feed.Froogle.ConvertNetToGrossPrices", + "Plugins.Feed.Froogle.ConvertNetToGrossPrices.Hint", + "Plugins.Feed.Froogle.LanguageId", + "Plugins.Feed.Froogle.LanguageId.Hint", + "Plugins.Feed.Froogle.Generate", + "Plugins.Feed.Froogle.ConfigSaveNote", + "Plugins.Feed.Froogle.AvailabilityAvailableForOrder", + "Plugins.Feed.Froogle.GridEditNote", + "Plugins.Feed.Froogle.General", + "Plugins.Feed.Froogle.ProductData" + ); + + builder.Delete( + "Plugins.Feed.BMEcat.TaskEnabled", + "Plugins.Feed.BMEcat.TaskEnabled.Hint", + "Plugins.Feed.BMEcat.StaticFileUrl", + "Plugins.Feed.BMEcat.StaticFileUrl.Hint", + "Plugins.Feed.BMEcat.GenerateStaticFileEachMinutes", + "Plugins.Feed.BMEcat.GenerateStaticFileEachMinutes.Hint", + "Plugins.Feed.BMEcat.UseOwnProductNo", + "Plugins.Feed.BMEcat.UseOwnProductNo.Hint", + "Plugins.Feed.BMEcat.ShippingCostAustria", + "Plugins.Feed.BMEcat.ShippingCostAustria.Hint", + "Plugins.Feed.BMEcat.Currency", + "Plugins.Feed.BMEcat.Currency.Hint", + "Plugins.Feed.BMEcat.ProductPictureSize", + "Plugins.Feed.BMEcat.ProductPictureSize.Hint", + "Plugins.Feed.BMEcat.AppendDescriptionText", + "Plugins.Feed.BMEcat.AppendDescriptionText.Hint", + "Plugins.Feed.BMEcat.BuildDescription", + "Plugins.Feed.BMEcat.BuildDescription.Hint", + "Plugins.Feed.BMEcat.Automatic", + "Plugins.Feed.BMEcat.DescShort", + "Plugins.Feed.BMEcat.DescLong", + "Plugins.Feed.BMEcat.DescTitleAndShort", + "Plugins.Feed.BMEcat.DescTitleAndLong", + "Plugins.Feed.BMEcat.DescManuAndTitleAndShort", + "Plugins.Feed.BMEcat.DescManuAndTitleAndLong", + "Plugins.Feed.BMEcat.UseOwnProductNo", + "Plugins.Feed.BMEcat.UseOwnProductNo.Hint", + "Plugins.Feed.BMEcat.DescriptionToPlainText", + "Plugins.Feed.BMEcat.DescriptionToPlainText.Hint", + "Plugins.Feed.BMEcat.ShippingCost", + "Plugins.Feed.BMEcat.ShippingCost.Hint", + "Plugins.Feed.BMEcat.ShippingTime", + "Plugins.Feed.BMEcat.ShippingTime.Hint", + "Plugins.Feed.BMEcat.Brand", + "Plugins.Feed.BMEcat.Brand.Hint", + "Plugins.Feed.BMEcat.Store", + "Plugins.Feed.BMEcat.Store.Hint", + "Plugins.Feed.BMEcat.ConvertNetToGrossPrices", + "Plugins.Feed.BMEcat.ConvertNetToGrossPrices.Hint", + "Plugins.Feed.BMEcat.LanguageId", + "Plugins.Feed.BMEcat.LanguageId.Hint", + "Plugins.Feed.BMEcat.Generate", + "Plugins.Feed.BMEcat.ConfigSaveNote" + ); + + builder.Delete("Plugins.Widgets.OpenTrans.IsLexwareCompatibe"); + builder.Delete("Admin.System.Maintenance.DeleteExportedFolders.TotalDeleted"); + + // Common + builder.AddOrUpdate("StoreClosed", + "We'll be back.", + "Wir sind bald wieder da."); + builder.AddOrUpdate("StoreClosed.Hint", + "We're busy updating our online store for you and will be back soon.", + "Wir aktualisieren gerade das Angebot in unserem Online-Shop. Die Seite ist demnchst wieder verfgbar."); + + builder.AddOrUpdate("Admin.System.SystemInfo.UsedMemorySize", + "Used memory (RAM)", + "Benutzter Speicher (RAM)"); + builder.AddOrUpdate("Admin.System.SystemInfo.GarbageCollect", + "Collect", + "Aufrumen"); + builder.AddOrUpdate("Admin.System.SystemInfo.GarbageCollectSuccessful", + "The memory has been successfully cleaned up.", + "Der Arbeitsspeicher wurde erfolgreich aufgerumt."); + + builder.AddOrUpdate("Admin.Configuration.Themes.NoConfigurationRequired", + "Theme requires no configuration", + "Theme bentigt keine Konfiguration"); + + + builder.AddOrUpdate("Tax.LegalInfoFooter2", + "* All prices {0}, plus shipping", + "* Alle Preise {0}, zzgl. Versandkosten"); + + builder.AddOrUpdate("Tax.LegalInfoProductDetail2", + "{0} {1} {2}plus shipping", + "{0} {1} {2} zzgl. Versandkosten"); + + builder.AddOrUpdate("ShoppingCart.ShippingInfoLink", + "For a complete listing of all shipping costs please click here.", + "Eine vollstndige Liste aller Versandkosten finden Sie hier."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.resx b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.resx new file mode 100644 index 0000000000..f24f629459 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201509150931528_ExportFramework2.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.Designer.cs new file mode 100644 index 0000000000..766e90a409 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ExportFramework3 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ExportFramework3)); + + string IMigrationMetadata.Id + { + get { return "201511271019577_ExportFramework3"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs new file mode 100644 index 0000000000..ffbf880d57 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.cs @@ -0,0 +1,142 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using Core.Domain.Customers; + using Core.Domain.Security; + using Setup; + + public partial class ExportFramework3 : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ExportProfile", "SystemName", c => c.String(maxLength: 400)); + AddColumn("dbo.ExportProfile", "IsSystemProfile", c => c.Boolean(nullable: false)); + DropColumn("dbo.PaymentMethod", "ExcludedCustomerRoleIds"); + DropColumn("dbo.PaymentMethod", "ExcludedCountryIds"); + DropColumn("dbo.PaymentMethod", "ExcludedShippingMethodIds"); + DropColumn("dbo.PaymentMethod", "CountryExclusionContextId"); + DropColumn("dbo.PaymentMethod", "MinimumOrderAmount"); + DropColumn("dbo.PaymentMethod", "MaximumOrderAmount"); + DropColumn("dbo.PaymentMethod", "AmountRestrictionContextId"); + DropColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds"); + DropColumn("dbo.ShippingMethod", "CountryExclusionContextId"); + } + + public override void Down() + { + AddColumn("dbo.ShippingMethod", "CountryExclusionContextId", c => c.Int(nullable: false)); + AddColumn("dbo.ShippingMethod", "ExcludedCustomerRoleIds", c => c.String(maxLength: 500)); + AddColumn("dbo.PaymentMethod", "AmountRestrictionContextId", c => c.Int(nullable: false)); + AddColumn("dbo.PaymentMethod", "MaximumOrderAmount", c => c.Decimal(precision: 18, scale: 4)); + AddColumn("dbo.PaymentMethod", "MinimumOrderAmount", c => c.Decimal(precision: 18, scale: 4)); + AddColumn("dbo.PaymentMethod", "CountryExclusionContextId", c => c.Int(nullable: false)); + AddColumn("dbo.PaymentMethod", "ExcludedShippingMethodIds", c => c.String(maxLength: 500)); + AddColumn("dbo.PaymentMethod", "ExcludedCountryIds", c => c.String(maxLength: 2000)); + AddColumn("dbo.PaymentMethod", "ExcludedCustomerRoleIds", c => c.String(maxLength: 500)); + DropColumn("dbo.ExportProfile", "IsSystemProfile"); + DropColumn("dbo.ExportProfile", "SystemName"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var permissionMigrator = new PermissionMigrator(context); + + permissionMigrator.AddPermission(new PermissionRecord + { + Name = "Admin area. Manage Url Records", + SystemName = "ManageUrlRecords", + Category = "Configuration" + }, new string[] { SystemCustomerRoleNames.Administrators }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.Export.PDF", "PDF Export", "PDF Export"); + builder.AddOrUpdate("Admin.Common.TemporaryFiles", "Temporary files", "Temporre Dateien"); + builder.AddOrUpdate("Admin.Common.PublicFiles", "Public files", "ffentliche Dateien"); + builder.AddOrUpdate("Admin.Common.Of", "of", "von"); + + builder.AddOrUpdate("Admin.Common.NoTempFilesFound", + "There are no temporary files.", + "Es sind keine temporren Dateien vorhanden."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportEntityType.NewsLetterSubscription", + "Newsletter Subscribers", + "Newsletter Abonnenten"); + + builder.AddOrUpdate("Admin.DataExchange.Export.SystemName", + "System name of profile", + "Systemname des Profils", + "The system name of the export profile.", + "Der Systemname des Exportprofils."); + + builder.AddOrUpdate("Admin.DataExchange.Export.IsSystemProfile", + "System profile", + "Systemprofil", + "Indicates whether the export profile is a system profile. System profiles cannot be removed.", + "Gibt an, ob es sich bei dem Exportprofil um eine Systemprofil handelt. Systemprofile knnen nicht entfernt werden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.CannotDeleteSystemProfile", + "Cannot delete a system export profile.", + "Ein System-Exportprofil kann nicht gelscht werden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.MissingSystemProfile", + "The system export profile {0} was not found.", + "Das System-Exportprofil {0} wurde nicht gefunden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.ExportFiles", + "Export files", + "Exportdateien"); + + + builder.AddOrUpdate("Admin.Configuration.Payment.Methods.RestrictionNote", + "There were no possibilities found to restrict payment methods.", + "Es wurden keine Mglichkeiten zur Einschrnkung von Zahlungsarten gefunden."); + + builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.RestrictionNote", + "There were no possibilities found to restrict shipping methods.", + "Es wurden keine Mglichkeiten zur Einschrnkung von Versandarten gefunden."); + + + + builder.Delete( + "Admin.Configuration.Payment.Methods.ExcludedCustomerRole", + "Admin.Configuration.Payment.Methods.ExcludedShippingMethod", + "Admin.Configuration.Payment.Methods.ExcludedCountry", + "Admin.Configuration.Payment.Methods.MinimumOrderAmount", + "Admin.Configuration.Payment.Methods.MaximumOrderAmount", + "Admin.Configuration.Restrictions.AmountRestrictionContext", + "Enums.SmartStore.Core.Domain.Common.AmountRestrictionContextType.SubtotalAmount", + "Enums.SmartStore.Core.Domain.Common.AmountRestrictionContextType.TotalAmount", + "Enums.SmartStore.Core.Domain.Common.CountryRestrictionContextType.BillingAddress", + "Enums.SmartStore.Core.Domain.Common.CountryRestrictionContextType.ShippingAddress", + "Admin.Configuration.Shipping.Methods.ExcludedCustomerRole", + "Admin.Configuration.Shipping.Methods.ExcludedCountry", + "Admin.Configuration.Restrictions.CountryExclusionContext", + "Admin.Common.ExportToXml.All", + "Admin.Common.ExportToXml.Selected", + "Admin.Common.ExportToCsv.All", + "Admin.Common.ExportToCsv.Selected", + "Admin.Common.ExportToCsv", + "Admin.Common.ExportToPdf.TocTitle", + "PDFProductCatalog.SKU", + "PDFProductCatalog.Price", + "PDFProductCatalog.Manufacturer", + "PDFProductCatalog.Weight", + "PDFProductCatalog.Length", + "PDFProductCatalog.Width", + "PDFProductCatalog.Height", + "PDFProductCatalog.SpecificationAttributes", + "PDFProductCatalog.BundledItems", + "PDFProductCatalog.AssociatedProducts" + ); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.resx b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.resx new file mode 100644 index 0000000000..9c408d2cf0 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201511271019577_ExportFramework3.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.Designer.cs new file mode 100644 index 0000000000..a112acac53 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ImportFramework : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ImportFramework)); + + string IMigrationMetadata.Id + { + get { return "201512151526290_ImportFramework"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs new file mode 100644 index 0000000000..a7d561921c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.cs @@ -0,0 +1,421 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using Core.Domain.Customers; + using Core.Domain.Security; + using Core.Domain.Seo; + using Setup; + + public partial class ImportFramework : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + CreateTable( + "dbo.ImportProfile", + c => new + { + Id = c.Int(nullable: false, identity: true), + Name = c.String(nullable: false, maxLength: 100), + FolderName = c.String(nullable: false, maxLength: 100), + FileTypeId = c.Int(nullable: false), + EntityTypeId = c.Int(nullable: false), + Enabled = c.Boolean(nullable: false), + Skip = c.Int(nullable: false), + Take = c.Int(nullable: false), + FileTypeConfiguration = c.String(), + ColumnMapping = c.String(), + SchedulingTaskId = c.Int(nullable: false), + }) + .PrimaryKey(t => t.Id) + .ForeignKey("dbo.ScheduleTask", t => t.SchedulingTaskId) + .Index(t => t.SchedulingTaskId); + + } + + public override void Down() + { + DropForeignKey("dbo.ImportProfile", "SchedulingTaskId", "dbo.ScheduleTask"); + DropIndex("dbo.ImportProfile", new[] { "SchedulingTaskId" }); + DropTable("dbo.ImportProfile"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var permissionMigrator = new PermissionMigrator(context); + var activityLogMigrator = new ActivityLogTypeMigrator(context); + + permissionMigrator.AddPermission(new PermissionRecord + { + Name = "Admin area. Manage Imports", + SystemName = "ManageImports", + Category = "Configuration" + }, new string[] { SystemCustomerRoleNames.Administrators }); + + activityLogMigrator.AddActivityLogType("DeleteOrder", "Delete order", "Auftrag gelscht"); + + context.MigrateSettings(x => + { + var seoSettings = new SeoSettings(); + x.Add("seosettings.seonamecharconversion", seoSettings.SeoNameCharConversion); + }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.RecordsSkip", + "Skip", + "berspringen", + "Specifies the number of records to be skipped.", + "Legt die Anzahl der zu berspringenden Datenstze fest."); + + builder.AddOrUpdate("Common.Unknown", "Unknown", "Unbekannt"); + builder.AddOrUpdate("Common.Unavailable", "Unavailable", "Nicht verfgbar"); + builder.AddOrUpdate("Common.Language", "Language", "Sprache"); + builder.AddOrUpdate("Admin.Common.ImportFile", "Import file", "Importdatei"); + builder.AddOrUpdate("Admin.Common.ImportFiles", "Import files", "Importdateien"); + builder.AddOrUpdate("Admin.Common.CsvConfiguration", "CSV Configuration", "CSV Konfiguration"); + + builder.AddOrUpdate("Admin.Common.RecordsTake", + "Limit", + "Begrenzen", + "Specifies the maximum number of records to be processed.", + "Legt die maximale Anzahl der zu verarbeitenden Datenstze fest."); + + builder.AddOrUpdate("Admin.Common.FileTypeMustEqual", + "The file must be of the type {0}.", + "Die Datei muss vom Typ {0} sein."); + + builder.AddOrUpdate("Admin.DataExchange.Import.NoProfiles", + "There were no import profiles found.", + "Es wurden keine Importprofile gefunden."); + + builder.AddOrUpdate("Admin.DataExchange.Import.Name", + "Name of profile", + "Name des Profils", + "Specifies the name of the import profile.", + "Legt den Namen des Importprofils fest."); + + builder.AddOrUpdate("Admin.DataExchange.Import.ProgressInfo", + "{0} of {1} records processed", + "{0} von {1} Datenstzen verarbeitet"); + + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Product", "Product", "Produkt"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Customer", "Customer", "Kunde"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.NewsLetterSubscription", "Newsletter Subscriber", "Newsletter Abonnent"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportEntityType.Category", "Category", "Warengruppe"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportFileType.CSV", "Delimiter separated values (.csv, .txt, .tab)", "Trennzeichen getrennte Werte (.csv, .txt, .tab)"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ImportFileType.XLSX", "Excel (.xlsx)", "Excel (.xlsx)"); + + builder.AddOrUpdate("Admin.DataExchange.Import.FileUpload", + "Upload import file...", + "Importdatei hochladen..."); + + builder.AddOrUpdate("Admin.DataExchange.Import.MissingImportFile", + "Please upload an import file.", + "Bitte laden Sie eine Importdatei hoch."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.QuoteAllFields", + "Quote all fields", + "Alle Felder in Anfhrungszeichen", + "Specifies whether to set quotation marks around all field values.", + "Legt fest, ob die Werte aller Felder in Anfhrungszeichen gestellt werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.TrimValues", + "Trim values", + "berflssige Leerzeichen entfernen", + "Specifies whether to remove space characters at start and end of a field value.", + "Legt fest, ob Leerzeichen am Anfang und am Ende eines Feldwertes entfernt werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.SupportsMultiline", + "Supports multilines", + "Mehrzeilen erlaubt", + "Specifies whether field values with multilines are supported.", + "Legt fest, ob mehrzeilige Feldwerte untersttzt werden."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.Delimiter", + "Delimiter", + "Trennzeichen", + "Specifies the field separator.", + "Legt das zu verwendende Trennzeichen fr die Felder fest."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.Quote", + "Quote character", + "Anfhrungszeichen", + "Specifies the quotation character.", + "Legt das zu verwendende Anfhrungszeichen fest."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.Escape", + "Inner quote character", + "Inneres Anfhrungszeichen", + "Specifies the inner quote character used for escaping.", + "Legt das innere Anfhrungszeichen (Escaping) fest."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.Delimiter.Validation", + "Please enter a valid delimiter.", + "Geben Sie bitte ein gltiges Trennzeichen ein."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.Quote.Validation", + "Please enter a valid quote character.", + "Geben Sie bitte ein gltiges Anfhrungszeichen ein."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.Escape.Validation", + "Please enter a valid inner quote character (escaping).", + "Geben Sie bitte ein gltiges, inneres Anfhrungszeichen (Escaping) ein."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.EscapeDelimiter.Validation", + "Delimiter and inner quote character cannot be equal in CSV files.", + "Trennzeichen und inneres Anfhrungszeichen knnen in CSV Dateien nicht gleich sein."); + + builder.AddOrUpdate("Admin.DataExchange.Csv.QuoteDelimiter.Validation", + "Delimiter and quote character cannot be equal in CSV files.", + "Trennzeichen und Anfhrungszeichen knnen in CSV Dateien nicht gleich sein."); + + + builder.AddOrUpdate("Admin.Catalog.Products.Fields.BasePriceMeasureUnit", "Base price measure unit", "Grundpreis Maeinheit"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.ApprovedRatingSum", "Approved rating sum", "Summe genehmigter Bewertungen"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.NotApprovedRatingSum", "Not approved rating sum", "Summe nicht genehmigter Bewertungen"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.ApprovedTotalReviews", "Approved total reviews", "Summe genehmigter Rezensionen"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.NotApprovedTotalReviews", "Not approved total reviews", "Summe nicht genehmigter Rezensionen"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.HasTierPrices", "Has tier prices", "Hat Staffelpreise"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.LowestAttributeCombinationPrice", "Lowest attribute combination price", "Niedrigster Attributkombinationspreis"); + builder.AddOrUpdate("Admin.Catalog.Products.Fields.HasDiscountsApplied", "Has discounts applied", "Hat angewendete Rabatte"); + + builder.AddOrUpdate("Admin.Catalog.Categories.Fields.ParentCategory", "Parent category", "bergeordnete Warengruppe"); + + builder.AddOrUpdate("Admin.Customers.Customers.Fields.CustomerGuid", "Customer GUID", "Kunden GUID"); + builder.AddOrUpdate("Admin.Customers.Customers.Fields.PasswordSalt", "Password salt", "Passwort Salt"); + builder.AddOrUpdate("Admin.Customers.Customers.Fields.IsSystemAccount", "Is system account", "Ist Systemkonto"); + builder.AddOrUpdate("Admin.Customers.Customers.Fields.LastLoginDateUtc", "Last login date", "Letztes Login-Datum"); + + builder.AddOrUpdate("Admin.Promotions.NewsLetterSubscriptions.Fields.NewsLetterSubscriptionGuid", "Subscription GUID", "Abonnement GUID"); + + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Note", + "You can optionally set for each field of the import file whether and for which object property the data should be imported. Fields with equal names are always imported as long as they are not explicitly ignored. Not yet selected properties are highlighted in the selection list. It is also possible to define a default value which is applied when the import field is empty. Stored assignments becomes invalid and reset when the delimiter changes.", + "Sie knnen optional fr jedes Feld der Importdatei festlegen, ob und nach welcher Objekteigenschaft dessen Daten zu importieren sind. Gleichnamige Felder werden grundstzlich immer importiert, sofern sie nicht explizit ignoriert werden sollen. Noch nicht ausgewhlte Eigenschaften sind in der Auswahlliste hervorgehoben. Zudem ist die Angabe eines Standardwertes mglich, der angewendet wird, wenn das Importfeld leer ist. Durch nderung des Trennzeichens werden gespeicherte Zuordnungen ungltig und zurckgesetzt."); + + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.ImportField", "Import Field", "Importfeld"); + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.EntityProperty", "Object property", "Eigenschaft des Objektes"); + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.DefaultValue", "Default Value", "Standardwert"); + + + builder.Delete( + "Admin.DataExchange.Export.LastExecution", + "Admin.DataExchange.Export.Offset", + "Admin.DataExchange.Export.Limit", + "Admin.Promotions.NewsLetterSubscriptions.ImportEmailsSuccess", + "Admin.Common.ImportFromCsv", + "Admin.Common.CsvFile", + + "Admin.Common.ImportFromExcel", + "Admin.Common.ExcelFile", + "Admin.Common.ImportFromExcel.InProgress", + "Admin.Common.ImportFromExcel.LastResultTitle", + "Admin.Common.ImportFromExcel.ProcessedCount", + "Admin.Common.ImportFromExcel.QuickStats", + "Admin.Common.ImportFromExcel.ActiveSince", + "Admin.Common.ImportFromExcel.CancelPrompt", + "Admin.Common.ImportFromExcel.Cancel", + "Admin.Common.ImportFromExcel.Cancelled", + "Admin.Common.ImportFromExcel.DownloadReport", + "Admin.Common.ImportFromExcel.NoReportAvailable", + + "Admin.Configuration.ActivityLog.ActivityLog.Fields.ActivityLogTypeColumn", + "Plugins.ExchangeRate.EcbExchange.SetCurrencyToEURO" + ); + + builder.AddOrUpdate("ActivityLog.DeleteOrder", "Deleted order {0}", "Auftrag {0} gelscht"); + + builder.AddOrUpdate("Admin.System.SystemCustomerNames.SearchEngine", "Search Engine", "Suchmaschine"); + builder.AddOrUpdate("Admin.System.SystemCustomerNames.BackgroundTask", "Background Task", "Geplante Aufgabe"); + builder.AddOrUpdate("Admin.System.SystemCustomerNames.PdfConverter", "PDF Converter", "PDF-Konvertierer"); + + builder.AddOrUpdate("Admin.Configuration.ActivityLog.ActivityLog.Fields.CustomerSystemAccount", + "Customer system account", + "Kundensystemkonto", + "Filters results by customer system accounts.", + "Filtert Ergebnisse nach Kundenystemkonten."); + + builder.AddOrUpdate("Admin.Configuration.ActivityLog.ActivityLog.Fields.CustomerEmail", + "Customer Email", + "Kunden-E-Mail", + "Filters results by customer email address.", + "Filtert Ergebnisse nach E-Mail-Adresse der Kunden."); + + builder.AddOrUpdate("Admin.Configuration.Plugins.UnknownError", + "An unknown error occurred when calling a plugin. Please refer to the following message for details.", + "Beim Aufruf eines Plugins ist ein unbekannter Fehler aufgetreten. Details entnehmen Sie bitte der folgenden Meldung."); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.AllowUnicodeCharsInUrls", + "Allow unicode characters", + "Unicode-Zeichen erlauben", + "Check whether SEO names can contain letters that are classified as unicode characters.", + "Legt fest, ob als Unicode-Zeichen eingestufte Buchstaben in SEO relevanten Namen erlaubt sind."); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.SeoNameCharConversion", + "Characters to be converted", + "Zu konvertierende Zeichen", + "Allows an individual conversion of characters for SEO name creation. Enter the old and the new character separated by a semicolon, e.g. ;ae. Each entry has to be entered in a new line.", + "Ermglicht das individuelle Konvertieren von Zeichen bei der Erstellung SEO Namen. Geben Sie hier durch Semikolon getrennt das alte und das neue Zeichen ein, z.B. ;ae. Jeder Eintrag muss in einer neuen Zeile erfolgen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.TestSeoNameCreation", + "Check string", + "Zeichenkette prfen", + "Enter any string to check the SEO name creation. Changed settings must be saved before.", + "Geben Sie eine beliebige Zeichenkette ein, um daraus den SEO Namen zu erstellen. Genderte Einstellungen mssen zuvor gespeichert werden."); + + + builder.AddOrUpdate("Admin.System.Warnings.NoPermissionsDefined", + "There are no permissions defined.", + "Es sind keine Zugriffsrechte festgelegt."); + + builder.AddOrUpdate("Admin.System.Warnings.NoCustomerRolesDefined", + "There are no customer roles defined.", + "Es sind keine Kundengruppen festgelegt."); + + builder.AddOrUpdate("Admin.System.Warnings.AccessDeniedToAnonymousRequest", + "Access denied to anonymous request on {0}.", + "Zugriffsverweigerung durch anonyme Anfrage bei {0}."); + + builder.AddOrUpdate("Admin.System.Warnings.AccessDeniedToUser", + "Access denied to user #{0} '{1}' on {2}.", + "Zugriffsverweigerung durch Kunde #{0} '{1}' bei {2}."); + + builder.AddOrUpdate("Admin.Configuration.Countries.CannotDeleteDueToAssociatedAddresses", + "The country cannot be deleted because it has associated addresses.", + "Das Land kann nicht gelscht werden, weil ihm Adressen zugeordnet sind."); + + builder.AddOrUpdate("Admin.Configuration.Countries.States.CantDeleteWithAddresses", + "The state\\province cannot be deleted because it has associated addresses.", + "Das Bundesland\\Region kann nicht gelscht werden, weil ihm Adressen zugeordnet sind."); + + builder.AddOrUpdate("Admin.Configuration.Shipping.Methods.NoMethodsLoaded", + "No shipping methods could be loaded.", + "Es konnten keine Versandarten geladen werden."); + + builder.AddOrUpdate("Admin.System.Warnings.NoShipmentItems", + "No shipment items", + "Keine Versand-Artikel"); + + builder.AddOrUpdate("Admin.System.Warnings.DigitsOnly", + "Please enter digits only.", + "Bitte nur Ziffern eingeben."); + + builder.AddOrUpdate("Account.Register.Errors.CannotRegisterSearchEngine", + "A search engine can't be registered.", + "Eine Suchmaschine kann nicht registriert werden."); + + builder.AddOrUpdate("Account.Register.Errors.CannotRegisterTaskAccount", + "A background task account can't be registered.", + "Das Konto einer geplanten Aufgabe kann nicht registriert werden."); + + builder.AddOrUpdate("Account.Register.Errors.AlreadyRegistered", + "The customer is already registered.", + "Der Kunde ist bereits registriert."); + + builder.AddOrUpdate("Admin.Customers.CustomerRoles.CannotFoundRole", + "The customer role \"{0}\" cannot be found.", + "Die Kundengruppe \"{0}\" wurde nicht gefunden."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.RegisterCustomerRole", + "Customer role at registrations", + "Kundengruppe bei Registrierungen", + "Specifies a customer role that will be assigned to newly registered customers.", + "Legt eine Kundengruppe fest, die neu registrierten Kunden zugeordnet wird."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Order.DisplayOrdersOfAllStores", + "Display orders of all stores", + "Auftrge aller Shops anzeigen", + "Specifies whether to display the orders of all stores to the customer. If this option is disabled, only the orders of the current store are displayed.", + "Legt fest, ob dem Kunden die Auftrge aller Shops angezeigt werden sollen. Ist diese Option deaktiviert, so werden nur die Auftrge des aktuellen Shops angezeigt."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Order.GiftCards_Deactivated") + .Value("de", "Geschenkgutschein wird deaktiviert, wenn Auftragsstatus..."); + + builder.AddOrUpdate("Admin.Configuration.Languages.Fields.UniqueSeoCode.Required", + "Please select a SEO language code.", + "Bitte legen Sie einen SEO Sprach-Code fest."); + + builder.AddOrUpdate("Admin.Configuration.Languages.Fields.FlagImageFileName", + "Flag image", + "Flaggenbild", + "Specifies the flag image. The files for the flag images must be stored in /Content/Images/flags/.", + "Legt das Flaggenbild fest. Die Dateien der Flaggenbilder mssen in /Content/Images/flags/ liegen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.HideCategoryDefaultPictures", + "Hide default picture for categories", + "Standardbild bei Warengruppen ausblenden", + "Specifies whether to hide the default image for categories. The default image is shown when no image is assigned to a category.", + "Legt fest, ob das Standardbild bei Warengruppen ausgeblendet werden soll. Das Standardbild wird angezeigt, wenn der Warengruppe kein Bild zugeordnet ist."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.HideProductDefaultPictures", + "Hide default picture for products", + "Standardbild bei Produkten ausblenden", + "Specifies whether to hide the default image for products. The default image is shown when no image is assigned to a product.", + "Legt fest, ob das Standardbild bei Produkten ausgeblendet werden soll. Das Standardbild wird angezeigt, wenn dem Produkt kein Bild zugeordnet ist."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Media.MessageProductThumbPictureSize", + "Thumbnail size of products in emails", + "Thumbnail-Gre von Produkten in E-Mails", + "Specifies the thumbnail image size (pixels) of products in emails. Enter 0 to not display thumbnails.", + "Legt die Thumbnail-Bildgre (in Pixel) von Produkten in E-Mails fest. Geben Sie 0 ein, um keine Thumbnails anzuzeigen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.GeneralCommon.MetaRobotsContent", + "Meta robots", + "Meta Robots", + "Specifies if and how search engines indexing the pages of your store.", + "Legt fest, ob und wie Suchmaschinen die Seiten Ihres Shops indexieren."); + + builder.AddOrUpdate("Providers.ExchangeRate.EcbExchange.SetCurrencyToEURO", + "You can use ECB (European central bank) exchange rate provider only when exchange rate currency code is set to EURO.", + "Der EZB-Wechselkursdienst kann nur genutzt werden, wenn der Wechselkurs-Whrungscode auf EUR gesetzt ist."); + + + builder.AddOrUpdate("Common.Loading", "Loading", "Lade"); + builder.AddOrUpdate("Common.ShowMore", "Show more", "Mehr anzeigen"); + builder.AddOrUpdate("Common.Published", "Published", "Verffentlicht"); + builder.AddOrUpdate("Common.Unpublished", "Unpublished", "Unverffentlicht"); + builder.AddOrUpdate("Common.NotSelectable", "Not selectable", "Nicht auswhlbar"); + + builder.AddOrUpdate("Common.EntityPicker.SinglePickNote", + "Click on an item to select it and OK to apply it.", + "Klicken Sie auf ein Element, um es auszuwhlen und OK, um es zu bernehmen."); + + builder.AddOrUpdate("Common.EntityPicker.MultiPickNote", + "Click on an item to select or deselect it and OK to apply the selection.", + "Klicken Sie auf ein Element, um es aus- bzw. abzuwhlen und OK, um die Auswahl zu bernehmen."); + + builder.AddOrUpdate("Common.EntityPicker.NoMoreItemsFound", + "There were no more items found.", + "Es wurden keine weiteren Elemente gefunden."); + + builder.AddOrUpdate("Admin.Catalog.Products.BundleItems.NotesOnProductBundles", + "Notes on product bundles", + "Hinweise zu Produkt-Bundles"); + + builder.AddOrUpdate("Admin.Catalog.Products.RelatedProducts.AddNew", + "Add cross-selling product", + "Cross-Selling-Produkt hinzufgen"); + + builder.AddOrUpdate("Admin.Catalog.Products.RelatedProducts.SaveBeforeEdit", + "You need to save the product before you can add cross-selling products for this product page.", + "Sie mssen das Produkt speichern, bevor Sie Cross-Selling-Produkte hinzufgen knnen."); + + builder.AddOrUpdate("Admin.Catalog.Products.CrossSells.AddNew", + "Add checkout-selling product", + "Checkout-Selling-Produkt hinzufgen"); + + builder.AddOrUpdate("Admin.Catalog.Products.CrossSells.SaveBeforeEdit", + "You need to save the product before you can add checkout-selling products for this product page.", + "Sie mssen das Produkt speichern, bevor Sie Checkout-Selling-Produkte hinzufgen knnen."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.resx b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.resx new file mode 100644 index 0000000000..fa9e8cc53c --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201512151526290_ImportFramework.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.Designer.cs new file mode 100644 index 0000000000..b8d27247a3 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ImportFramework1 : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ImportFramework1)); + + string IMigrationMetadata.Id + { + get { return "201601262000441_ImportFramework1"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.cs b/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.cs new file mode 100644 index 0000000000..8c61a2784f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.cs @@ -0,0 +1,478 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using Setup; + + public partial class ImportFramework1 : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ImportProfile", "UpdateOnly", c => c.Boolean(nullable: false)); + AddColumn("dbo.ImportProfile", "KeyFieldNames", c => c.String(maxLength: 1000)); + AddColumn("dbo.ImportProfile", "ResultInfo", c => c.String()); + } + + public override void Down() + { + DropColumn("dbo.ImportProfile", "ResultInfo"); + DropColumn("dbo.ImportProfile", "KeyFieldNames"); + DropColumn("dbo.ImportProfile", "UpdateOnly"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.DataExchange.Import.MultipleFilesSameFileTypeNote", + "For multiple import files please make sure that they are of the same file type and that the content follows the same pattern (e.g. same column headings).", + "Bei mehreren Importdateien ist darauf zu achten, dass diese vom selben Dateityp sind und deren Inhalt demselben Schema folgt (z.B. gleiche Spaltenberschriften)."); + + builder.AddOrUpdate("Admin.DataExchange.Import.ProfileEntitySelectNote", + "Please select an object that you want to import.", + "Whlen Sie bitte ein Objekt aus, das Sie importieren mchten."); + + builder.AddOrUpdate("Admin.DataExchange.Import.ProfileCreationNote", + "Please upload an import file, enter a meaningful name for the import profile and save.", + "Laden Sie bitte eine Importdatei hoch, legen Sie einen aussagekrftigen Namen fr das Importprofil fest und speichern Sie."); + + builder.AddOrUpdate("Admin.DataExchange.Import.AddAnotherFile", + "Add import file...", + "Importdatei hinzufgen..."); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.RunNow.Progress.DataImportTask", + "The task is now running in the background. You will receive an email as soon as it is completed. The progress can be tracked in the import profile list.", + "Die Aufgabe wird jetzt im Hintergrund ausgefhrt. Sie erhalten eine E-Mail, sobald sie abgeschlossen ist. Den Fortschritt knnen Sie in der Importprofilliste verfolgen."); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.RunNow.Progress.DataExportTask", + "The task is now running in the background. You will receive an email as soon as it is completed. The progress can be tracked in the export profile list.", + "Die Aufgabe wird jetzt im Hintergrund ausgefhrt. Sie erhalten eine E-Mail, sobald sie abgeschlossen ist. Den Fortschritt knnen Sie in der Exportprofilliste verfolgen."); + + builder.AddOrUpdate("Admin.DataExchange.Import.DefaultProfileNames", + "My product import;My category import;My customer import;My newsletter subscription import", + "Mein Produktimport;Mein Warengruppenimport;Mein Kundenimport;Mein Newsletter-Abonnement-Import"); + + builder.AddOrUpdate("Admin.DataExchange.Import.LastImportResult", + "Last import result", + "Letztes Importergebnis"); + + builder.AddOrUpdate("Admin.Common.TotalRows", "Total rows", "Zeilen insgesamt"); + builder.AddOrUpdate("Admin.Common.Skipped", "Skipped", "Ausgelassen"); + builder.AddOrUpdate("Admin.Common.NewRecords", "New records", "Neue Datenstze"); + builder.AddOrUpdate("Admin.Common.Updated", "Updated", "Aktualisiert"); + builder.AddOrUpdate("Admin.Common.Warnings", "Warnings", "Warnungen"); + builder.AddOrUpdate("Admin.Common.Errors", "Errors", "Fehler"); + builder.AddOrUpdate("Admin.Common.UnsupportedEntityType", "Unsupported entity type '{0}'", "Nicht untersttzter Entittstyp '{0}'"); + builder.AddOrUpdate("Admin.Common.DataExchange", "Data exchange", "Datenaustausch"); + + builder.AddOrUpdate("Admin.DataExchange.Import.CompletedEmail.Body", + "This is an automatic notification of store \"{0}\" about a recent data import. Summary:", + "Dies ist eine automatische Benachrichtung von Shop \"{0}\" ber einen erfolgten Datenimport. Zusammenfassung:"); + + builder.AddOrUpdate("Admin.DataExchange.Import.CompletedEmail.Subject", + "Import of \"{0}\" has been finished", + "Import von \"{0}\" ist abgeschlossen"); + + builder.AddOrUpdate("Admin.DataExchange.Import.ColumnMapping", + "Assignment of import fields", + "Zuordnung der Importfelder"); + + builder.AddOrUpdate("Admin.DataExchange.Import.SelectTargetProperty", + "Create new assignment here", + "Hier neue Zuordnung vornehmen"); + + builder.AddOrUpdate("Admin.DataExchange.Import.UpdateOnly", + "Only update", + "Nur aktualisieren", + "If this option is enabled, only existing data is updated but no new records are added.", + "Ist diese Option aktiviert, werden nur vorhandene Daten aktualisiert, aber keine neue Datenstze hinzugefgt."); + + builder.AddOrUpdate("Admin.DataExchange.Import.KeyFieldNames", + "Key fields", + "Schlsselfelder", + "Existing records can be identified for updates on the basis of key fields. The key fields are processed in the order how they are defined here.", + "Anhand von Schlsselfeldern knnen vorhandene Datenstze zwecks Aktualisierung identifiziert werden. Die Schlsselfelder werden in der hier festgelegten Reihenfolge verarbeitet."); + + builder.AddOrUpdate("Admin.DataExchange.Import.Validate.OneKeyFieldRequired", + "At least one key field is required.", + "Es ist mindestens ein Schlsselfeld erforderlich."); + + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Validate.MultipleMappedIgnored", + "The following object properties were multiple assigned and thus ignored: {0}", + "Die folgenden Objekteigenschaft wurden mehrfach zugeodnet und deshalb ignoriert: {0}"); + + builder.AddOrUpdate("Admin.DataExchange.ColumnMapping.Validate.MappingsReset", + "The stored field assignments are invalid due to the change of the delimiter and were reset.", + "Die gespeicherten Feldzuordnungen sind aufgrund der nderung des Trennzeichens ungltig und wurden zurckgesetzt."); + + + builder.AddOrUpdate("Common.Download.NoDataAvailable", + "Download data is not available anymore.", + "Es sind keine Daten zum Herunterladen mehr verfgbar."); + + builder.AddOrUpdate("Common.Download.NotAvailable", + "Download is not available any more.", + "Der Download ist nicht mehr verfgbar."); + + builder.AddOrUpdate("Common.Download.SampleNotAvailable", + "Sample download is not available anymore.", + "Der Download einer Beispieldatei ist nicht mehr verfgbar."); + + builder.AddOrUpdate("Common.Download.HasNoSample", + "The product variant doesn't have a sample download.", + "Fr die Produktvariante ist der Download einer Beispieldatei nicht verfgbar."); + + builder.AddOrUpdate("Common.Download.NotAllowed", + "Downloads are not allowed.", + "Downloads sind nicht gestattet."); + + builder.AddOrUpdate("Common.Download.MaxNumberReached", + "You have reached the maximum number of downloads {0}.", + "Sie haben die maximale Anzahl an Downloads {0} erreicht."); + + builder.AddOrUpdate("Account.CustomerOrders.NotYourOrder", + "This is not your order.", + "Dieser Auftrag konnte Ihnen nicht zugeordnet werden."); + + builder.AddOrUpdate("Shipping.CouldNotLoadMethod", + "The shipping rate computation method could not be loaded.", + "Die Berechnungsmethode fr Versandkosten konnte nicht geladen werden."); + + builder.AddOrUpdate("Shipping.OneActiveMethodProviderRequired", + "At least one shipping rate computation method provider is required to be active.", + "Mindestens ein Provider zur Berechnung von Versandkosten muss aktiviert sein."); + + builder.AddOrUpdate("Payment.CouldNotLoadMethod", + "The payment method could not be loaded.", + "Die Zahlungsart konnte nicht geladen werden."); + + builder.AddOrUpdate("Payment.MethodNotAvailable", + "The payment method is not available.", + "Die Zahlungsart steht nicht zur Verfgung."); + + builder.AddOrUpdate("Payment.OneActiveMethodProviderRequired", + "At least one payment method provider is required to be active.", + "Mindestens ein Zahlungsart-Provider muss aktiviert sein."); + + builder.AddOrUpdate("Payment.RecurringPaymentNotSupported", + "Recurring payments are not supported by selected payment method.", + "Wiederkehrende Zahlungen sind fr die gewhlte Zahlungsart nicht mglich."); + + builder.AddOrUpdate("Payment.RecurringPaymentNotActive", + "Recurring payment is not active.", + "Wiederkehrende Zahlung ist inaktiv."); + + builder.AddOrUpdate("Payment.RecurringPaymentTypeUnknown", + "The recurring payment type is not supported.", + "Der Typ von wiederkehrender Zahlung wird nicht untersttzt."); + + builder.AddOrUpdate("Payment.CannotCalculateNextPaymentDate", + "The next payment date could not be calculated.", + "Das Datum der nchsten Zahlung kann nicht ermittelt werden."); + + builder.AddOrUpdate("Payment.PayingFailed", + "Unfortunately we can not handle this purchasing via your preferred payment method. Please select an alternate payment option to complete your order.", + "Leider knnen wir diesen Einkauf nicht ber die gewnschte Zahlungsart abwickeln. Bitte whlen Sie eine alternative Zahlungsoption aus, um Ihre Bestellung abzuschlieen."); + + builder.AddOrUpdate("Order.InitialOrderDoesNotExistForRecurringPayment", + "No initial order exists for the recurring payment.", + "Fr die wiederkehrende Zahlung existiert kein Ausgangsauftrag."); + + builder.AddOrUpdate("Order.CannotCalculateShippingTotal", + "The shipping total could not be calculated.", + "Die Versandkosten konnten nicht berechnet werden."); + + builder.AddOrUpdate("Order.CannotCalculateOrderTotal", + "The order total could not be calculated.", + "Die Auftragssumme konnte nicht berechnet werden."); + + builder.AddOrUpdate("Order.BillingAddressMissing", + "The billing address is missing.", + "Die Rechnungsanschrift fehlt."); + + builder.AddOrUpdate("Order.ShippingAddressMissing", + "The shipping address is missing.", + "Die Lieferanschrift fehlt."); + + builder.AddOrUpdate("Order.CountryNotAllowedForBilling", + "The country '{0}' is not allowed for billing.", + "Eine Rechnungslegung ist fr das Land '{0}' unzulssig."); + + builder.AddOrUpdate("Order.CountryNotAllowedForShipping", + "The country '{0}' is not allowed for shipping.", + "Ein Versand ist fr das Land '{0}' unzulssig."); + + builder.AddOrUpdate("Order.NoRecurringProducts", + "There are no recurring products.", + "Keine wiederkehrenden Produkte."); + + builder.AddOrUpdate("Order.NotFound", + "The order {0} was not found.", + "Der Auftrag {0} wurde nicht gefunden."); + + builder.AddOrUpdate("Order.CannotCancel", + "Cannot cancel order.", + "Der Auftrag kann nicht storniert werden."); + + builder.AddOrUpdate("Order.CannotMarkCompleted", + "Cannot mark order as completed.", + "Der Auftrag kann nicht als abgeschlossen markiert werden."); + + builder.AddOrUpdate("Order.CannotCapture", + "Cannot capture order.", + "Der Auftrag kann nicht gebucht werden."); + + builder.AddOrUpdate("Order.CannotMarkPaid", + "Cannot mark order as paid.", + "Der Auftrag kann nicht als bezahlt markiert werden."); + + builder.AddOrUpdate("Order.CannotRefund", + "Cannot do refund for order.", + "Eine Rckerstattung ist fr diesen Auftrag nicht mglich."); + + builder.AddOrUpdate("Order.CannotPartialRefund", + "Cannot do partial refund for order.", + "Eine Teilrckerstattung ist fr diesen Auftrag nicht mglich."); + + builder.AddOrUpdate("Order.CannotVoid", + "Cannot do void for order.", + "Eine Stornierung dieses Auftrages ist nicht mglich."); + + builder.AddOrUpdate("Shipment.AlreadyShipped", + "This shipment is already shipped.", + "Diese Sendung wird bereits ausgeliefert."); + + builder.AddOrUpdate("Shipment.AlreadyDelivered", + "This shipment is already delivered.", + "Diese Sendung wird bereits zugestellt."); + + builder.AddOrUpdate("Customer.DoesNotExist", + "The customer does not exist.", + "Der Kunde existiert nicht."); + + builder.AddOrUpdate("Checkout.AnonymousNotAllowed", + "An anonymous checkout is not allowed.", + "Ein anonymer Checkout ist nicht zulssig."); + + builder.AddOrUpdate("Common.Error.InvalidEmail", + "The email address is not valid.", + "Die E-Mail-Adresse ist ungltig."); + + builder.AddOrUpdate("Common.Error.NoActiveLanguage", + "No active language could be loaded.", + "Es wurde keine aktive Sprache gefunden."); + + builder.AddOrUpdate("Common.Error.NoEmailAccount", + "No email account could be loaded.", + "Es wurde kein E-Mail-Konto gefunden."); + + builder.AddOrUpdate("Admin.OrderNotice.RecurringPaymentCancellationError", + "Unable to cancel recurring payment for order {0}.", + "Es ist ein Fehler bei der Stornierung einer wiederkehrenden Zahlung fr Auftrag {0} aufgetreten."); + + builder.AddOrUpdate("Admin.OrderNotice.OrderRefundError", + "Unable to refund order {0}.", + "Es ist ein Fehler bei einer Rckerstattung zu Auftrag {0} aufgetreten."); + + builder.AddOrUpdate("Admin.OrderNotice.OrderPartiallyRefundError", + "Unable to partially refund order {0}.", + "Es ist ein Fehler bei einer Teilerstattung zu Auftrag {0} aufgetreten."); + + builder.AddOrUpdate("Admin.OrderNotice.OrderVoidError", + "Unable to void payment transaction of order {0}.", + "Es ist ein Fehler bei der Stornierung einer Zahlungstransaktion zu Auftrag {0} aufgetreten."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.SortFilterResultsByMatches", + "Sort filter results by number of matches", + "Filterergebnisse nach Trefferanzahl sortieren", + "Specifies to sort filter results by number of matches in descending order. If this option is deactivated then the result is sorted by the display order of the values.", + "Legt fest, das Filterergebnisse absteigend nach der Anzahl an bereinstimmungen sortiert werden. Ist diese Option deaktiviert, so wird in der fr die Werte festgelegten Reihenfolge sortiert."); + + builder.AddOrUpdate("Wishlist.IsDisabled", + "The wishlist is disabled.", + "Die Wunschliste ist deaktiviert."); + + builder.AddOrUpdate("ShoppingCart.IsDisabled", + "The shoping cart is disabled.", + "Der Warenkorb ist deaktiviert."); + + builder.AddOrUpdate("Products.NotFound", + "The product {0} was not found.", + "Das Produkt {0} wurde nicht gefunden."); + + builder.AddOrUpdate("Products.Variants.NotFound", + "The product variant {0} was not found.", + "Die Produktvariante {0} wurde nicht gefunden."); + + builder.AddOrUpdate("Reviews.NotFound", + "The product review {0} was not found.", + "Die Produktbewertung {0} wurde nicht gefunden."); + + builder.AddOrUpdate("Polls.AnswerNotFound", + "The poll answer {0} was not found.", + "Eine Umfrageantwort {0} wurde nicht gefunden."); + + builder.AddOrUpdate("Polls.NotAvailable", + "The poll is not available.", + "Die Umfrage ist nicht verfgbar."); + + builder.AddOrUpdate("Install.LanguageNotRegistered", + "The install language '{0}' is not registered.", + "Die Installationssprache '{0}' ist nicht registriert."); + + builder.AddOrUpdate("Admin.Catalog.Categories.DescriptionToggle", + "Show other description", + "Andere Beschreibung anzeigen"); + + builder.AddOrUpdate("Admin.Catalog.Categories.Fields.Description", + "Top description", + "Obere Beschreibung", + "Description of the category that is displayed above products on the category page.", + "Beschreibung der Warengruppe, die auf der Warengruppenseite oberhalb der Produkte angezeigt wird."); + + builder.AddOrUpdate("Common.CaptchaUnableToVerify", + "The API call to verify a CAPTCHA has failed.", + "Der API-Aufruf zur Prfung eines CAPTCHAs ist fehlgeschlagen."); + + builder.AddOrUpdate("Common.WrongCaptcha", + "Please confirm that you are not a \"robot\".", + "Bitte besttigen Sie, dass Sie kein \"Roboter\" sind."); + + builder.AddOrUpdate("DownloadableProducts.UserAgreementConfirmation", + "Yes, I agree to the user agreement for this product.", + "Ja, ich stimme der Nutzungsvereinbarung fr dieses Produkt zu."); + + builder.AddOrUpdate("DownloadableProducts.HasNoUserAgreement", + "The product has no user agreement.", + "Das Produkt besitzt keine Nutzungsvereinbarung."); + + builder.AddOrUpdate("Checkout.DownloadUserAgreement.PleaseAgree", + "Please agree to the user agreement for downloadable products.", + "Bitte stimmen Sie der Nutzungsvereinbarung fr herunterladbare Produkte zu."); + + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.OrderConfirmationPage", + "Order confirmation page", + "Bestellabschlussseite"); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ShowEsdRevocationWaiverBox", + "Show revocation waiver box for electronic services", + "Widerrufsverzichtbox fr elektronische Leistungen anzeigen", + "Specifies whether the customer must agree a revocation waiver for electronic services on the order confirmation page.", + "Legt fest, ob der Kunde auf der Bestellabschlussseite einem Widerrufsverzicht fr elektronische Leistungen zustimmen muss."); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ShowCommentBox", + "Show comment box", + "Kommentarbox anzeigen", + "Specifies whether comment box is displayed on the order confirmation page.", + "Legt fest, ob der Kunde auf der Bestellabschlussseite einen Kommentar zu seiner Bestellung hinterlegen kann."); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ShowConfirmOrderLegalHint", + "Show legal hints in order summary", + "Rechtliche Hinweise in der Warenkorbbersicht anzeigen", + "Specifies whether to show hints in order summary on the confirm order page. This text can be altered in the language resources.", + "Legt fest, ob rechtliche Hinweise in der Warenkorbbersicht auf der Bestellabschluseite angezeigt werden. Dieser Text kann in den Sprachresourcen gendert werden."); + + + builder.AddOrUpdate("Checkout.EsdRevocationWaiverConfirmation", + "Yes, I want access to the digital content immediately and know that my right of revocation expires with the access.", + "Ja, ich mchte sofort Zugang zu dem digitalen Inhalt und wei, dass mein Widerrufsrecht mit dem Zugang erlischt."); + + builder.AddOrUpdate("Checkout.EsdRevocationWaiverConfirmation.PleaseAgree", + "Please confirm that you would like access to the digital content immediately.", + "Bitte besttigen Sie, dass Sie sofort Zugang zu dem digitalen Inhalt wnschen."); + + + builder.AddOrUpdate("Admin.Configuration.Settings.DataExchange.MaxFileNameLength", + "Maximum length of file and folder names", + "Maximale Lnge von Datei- und Ordnernamen", + "Specifies the maximum length of file and folder names created during an import or export.", + "Legt die maximale Lnge von Datei- und Ordnernamen fest, die im Rahmen eines Imports\\Exports erzeugt wurden."); + + builder.AddOrUpdate("Admin.Configuration.Settings.DataExchange.ImageImportFolder", + "Image folder (relative path)", + "Bilderordner (relativer Pfad)", + "Specifies a relative path to a folder with images to be imported (e.g. Content\\Images).", + "Legt einen relativen Pfad zu einem Ordner mit zu importierenden Bildern fest (z.B. Inhalt\\Bilder)."); + + builder.AddOrUpdate("Admin.Configuration.Settings.DataExchange.ImageDownloadTimeout", + "Timeout for image download (minutes)", + "Zeitlimit fr Bilder-Download (Minuten)", + "Specifies the timeout for the image download in minutes.", + "Legt das Zeitlimit fr den Bilder-Download in Minuten fest."); + + builder.AddOrUpdate("Admin.System.Maintenance.SqlQuery.Succeeded", + "The SQL command was executed successfully.", + "Die SQL Anweisung wurde erfolgreich ausgefhrt."); + + builder.AddOrUpdate("Admin.DataExchange.Import.KeyFieldNames.Note", + "Please only use the ID field as a key field, if the data sourced from the same database to which it will be imported. Otherwise it is possible that the wrong records are updated.", + "Benutzen Sie das ID-Feld bitte nur dann als Schlsselfeld, wenn die Daten aus der derselben Datenbank stammen, in der sie importiert werden sollen. Ansonsten werden u.U. die falschen Datenstze aktualisiert."); + + builder.AddOrUpdate("Admin.Configuration.Settings.RewardPoints.RoundDownRewardPoints", + "Round down points", + "Punkte abrunden", + "Specifies whether to round down calculated points. Otherwise the bonus points will be rounded up.", + "Legt fest, ob bei der Punkteberechnung abgerundet werden soll. Ansonsten werden Bonuspunkte aufgerundet."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Order.GiftCards_Deactivated", + "Gift card deactivation order status", + "Geschenkgutschein wird deaktiviert, wenn Auftragsstatus..."); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.NewsLetterSubscription", + "Subscribe to newsletters", + "Abonnieren von Newslettern", + "Specifies if customers can subscribe to newsletters when ordering and if the checkbox is enabled by default.", + "Legt fest, ob Kunden bei einer Bestellung Newsletter abonnieren knnen und ob die Checkbox standardmig aktiviert ist."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutNewsLetterSubscription.None", "Do not show", "Nicht anzeigen"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutNewsLetterSubscription.Deactivated", "Show deactivated", "Deaktiviert anzeigen"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutNewsLetterSubscription.Activated", "Show activated", "Aktiviert anzeigen"); + + builder.AddOrUpdate("Common.Options", "Options", "Optionen"); + + builder.AddOrUpdate("Checkout.SubscribeToNewsLetter", + "Subscribed to newsletter", + "Newsletter abonnieren"); + + builder.AddOrUpdate("Admin.OrderNotice.NewsLetterSubscriptionAdded", + "Subscribed to newsletter", + "Newsletter wurde abonniert"); + + builder.AddOrUpdate("Admin.OrderNotice.NewsLetterSubscriptionRemoved", + "Newsletter subscriber has been removed", + "Newsletter-Abonnent wurde entfernt"); + + builder.AddOrUpdate("Admin.Orders.Fields.CaptureTransactionID", + "Capture transaction ID", + "Transaktions-ID fr Buchung", + "Capture transaction identifier received from your payment gateway.", + "Vom Zahlungsanbieter erhaltene Transaktions-ID fr die Buchung."); + + builder.AddOrUpdate("Admin.Orders.Fields.AuthorizationTransactionID", + "Authorization transaction ID", + "Transaktions-ID fr Autorisierung", + "Authorization transaction identifier received from your payment gateway.", + "Vom Zahlungsanbieter erhaltene Transaktions-ID fr die Autorisierung."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.SearchDescriptions", + "Search product description", + "Produktbeschreibung durchsuchen", + "Specifies whether the product description should be included in the search.", + "Legt fest, ob die Produktbeschreibung in der Suche einbezogen werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Projection.NumberOfPictures", + "Number of pictures", + "Anzahl der Bilder", + "Specifies the number of images per object to be exported.", + "Legt die Anzahl der zu exportierenden Bilder pro Objekt fest."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.resx b/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.resx new file mode 100644 index 0000000000..4e7843d120 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201601262000441_ImportFramework1.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy923LcuLIo+D4R8w8OP50zsY/ddq+OWLuje05IsmQrti9akmzvvV4UFAuSuMwiq3nRpSfmy+ZhPun8wgHAGwgk7iBZpa4Xu0QkEkAiM5FIJBL/6//7/3/7n4/r9MU9Ksokz35/+ebVTy9foCzOV0l2+/vLurr5H39/+T//7//z//jteLV+fPGtg/uZwOGaWfn7y7uq2vz6+nUZ36F1VL5aJ3GRl/lN9SrO16+jVf767U8//fvrN29eI4ziJcb14sVv53VWJWtE/8B/HuVZjDZVHaWf8hVKy/Y7LrmgWF98jtao3EQx+v3lxToqqosqL9Crd1EVvXxxkCYR7sYFSm9evoiyLK+iCnfy168luqiKPLu92OAPUXr5tEEY7iZKS9R2/tcB3HQcP70l43g9VOxQxXVZ5WtLhG9+bgnzmq/uRN6XPeEw6Y4xiasnMmpKvt9fXuabJH75gm/p16O0IFAj0h5R+mKwJHtF65XNf//2ggP6t54p3r56++qnVz/924ujOq3qAv2eoboqovTfXpzV12kS/wd6usx/oOz3rE5Ttqe4r7hs9AF/OivyDSqqp3N00/b/dPXyxetxvdd8xb4aU6cZ3GlW/fz25YvPuPHoOkU9IzCEoKN6jzJURBVanUVVhYqM4ECUlELrXFsXT2WF1uR31ybmPyxHL198ih4/ouy2uvv9Jf758sVJ8ohW3Ze2H1+zBIsdrlQVNdI1dZrFab1Cp9lFgpuMNl2Dh3meoigDhqnBV55FZfmQFytcUKEYD98XZYdwclpcJlU6PcUP89XT5I18QlWEOZqQrZylsXeojItk0yicGdqbZ64+JmssFqvLnAp06cvJ5yhboeKg/J6sblHli63B8s88m54OTVPfi2iDF9gKKzGh7yb1L+7yh9G8+Y38EDM3KgLolyLJC6qV1frdQHlcRreB5+K318Pqq16To8cjvNjc5sWTy8ocPb5iMOwXZ3lbmmX5bz/9ZDTJluz1Lik3afT0hbC8DaMa888Fqio6FmvewSrhJrmtCwr9qsWz5yBnDno7DQd9i9I6xEph2SyllZ66Tjz7MY+jNPkTrbo2Hbi3xdEwr4Bwz8bytprpsJtawMSKsts6urVkEQAPmTqE6fO+yOvN/Aq6b3+ppueS78/RfXJLGUgyky9fnKOUApR3yabxp4iSdTWAnxT5+jxPIYHuoa4u8rqIyfhyLehlVFDz2k2n9N3yVCUtnr0GkbelWQjfTCQu7cy0VFeuxFO0j2v/UaMLlB9hHKrWA2zcTtLo9nSNB3uSpEhD7l/MRqvZ4lap734s8KabylJ5579PdDXBlTqTqu5mMs5RSXVcKVegHKRch8oAe904UqNS6E7pultnHOogBhqHc69h9brO17rqaL3M1qVrfaEtzGlJpOssrW+TTFAiuqqXeR1DyiecVeWvFEDbSqtCnJTCGSrWSUmE8xzF1KlvrRAuUFwTf90rHtdeEcjbCnSYZLv5NznIevvLL1O0PXhDJ29ZKrxHlLdRQcQKXtZ5Hr7iqgwirIYUZFgD7iXELCoXh2FbvXzFItpLr7P0TiRBJwVCF5hVN7Q9P+P5Mno8fkTrjfepF0bUGuIEDzcF6qoHcZXcex8+nZaNVmuY3w9XUP1oqpR4zTCxYuJ3HIZ6zM26yLH82yskUq2k/+6VkLytUHuJJU2RNiZi8gPzYE4Hcmb+JfuA5eOMmvR+2A7SNH94X6OywvuSb3nljdDDJyKcE2G5e4cZ82sVd5jIn5fJWlv3OFs51vT1Nblt24imAbdpowLRpBuVQhacUu3j2gdZ+YDVmbRTTflVo0bH3WKKRJXOlXvr8AaZlyZvUOz1uUJHYSrtpi7/XK+vUfHlhmiw0m8AUzh1G/HxEzFI9iERtOkTJhd16CiMPg7qihXGcWclYKBukMF66wkWsZe2YBEF0xkvDqMStR0g1O0M3S6GTiudDZmsZdRgCZhq9iG21XGKlwsiiPthv0rI2+po9L5O+lab37bHniVuV3cCGeII8hjPcjp5KwZR6WEbOsmLdVT5LtgdtosorSbv+sFqnWRH+XrNRAxPd5OhDOZjOri5SdIEi4svtcN4nN6hFAW4R9E5rg7iOK+BEO4pfFdh+OhjVFanm4PVCm/RVNcZTANGNBqvQERTfsnA/aR1sElZfcxvk8x1g4rrUy7CqlqKwtkgaEkqOZvoVP8VAzaYAWKpsPoDILZ262GSpnia+7lXdZOHBfo6BpF3mIOz7TVv6am63cJcDRaN2G8eRrCypYCQie13YtWjljqEYQg5sfUnU6oeHz8SgyZKD+rqjpg0MQVS7XJUNcBpMKogzIlZLdsJwmZAvT7LywoeW18MDkQsFXoNgDh1sbnrKe8jLZd3clwM95KDse0m3fPDPaRFYOfGJUK/uGLbLp0jvMfALPIHddGCXRuBgF2EIYSuSsDsu/wQFauzPMmq8kOCkZATd7DfApyk93I4YAwKYNuRdEedRmuNAAyoPw5GrgB5QFsVeHGX0/pHeBN7io0yuO88FEh+KZBAezmkl1unJ6jDPaT1Os9etQj2e3p5WydJUVaBXLd683WWhnSb/jCtYBbbRNn017ePyAatEO/WaI/QKoS/3SdZLG5dNS0yF2AnG1Yrmm/maujt5A39M9kQWylKNbH8gU6V7/IMNYcfk7d1Ej3O1JLfflu+k2lkCFwKu4W2hxkWQK5IWLT5cuu1mhVSZec4SLGLIwBpR8dQfk73jlzWa/O7pEAxMc9etTj2y7O8Lc2COdG1KBobUraOjyCBJmWw4MGH/CMiRDwt57g0dXlXIGTa4M8BGsSKFhVJzDXmGEdTX/8Li9pl/i3ydvFuw9WpuQJ2zvEuGM8Bxt1x7SdU3eUSF9IY5mqo3Ki3ZOwQ00MDuyttFev9LbsQSIY1WiuA1REEEDsPQnltC8f0cLk10iLgpm6/DinUknodmirTyYyZpMLppdPbDNP66I5IwiRaiVEsc+gj3pq0UGFu8j02dj0MzBGmvXjL25I5GcKGAE5lrV5fF+g+iTRqIsyJ8DbYQU77XMf1XBB+5arvFb/Vn5AGCONqce1lXiHzLal8hd4kGsP0MrguauVgs8Gs5y98QeM6vm5Wkzit+iOZ0BEDssMnaWiBk1gfpvltH/BlLdKkdvmKwbEdobhtZy7R4/RRbGTwxKMcLui3wwiyFEPrqwFwYCeoXGAlEMibjZquePAQQbBfC+RthbrPFyoVr2WzgfIouzg2W2b3Tk3UrWwtviM2LNPRGM+r8Egvo9vpk0gvc//PME+2qatD39i25ckOM7LAKbsmOhFk1inYi+K0GvLOT+WSGeT6aI8VukIqFILL9RjCL6NPka/quDrHu3H04LKPi6oI9+jVCM92GH5tl7ZlgVS30hBuFiP1PKqYUz03onxA6eamTv8LlZeYU9IgyD7nLrjk1+Wa6YfvyrHcetVDMrfkIADxfhwIZX25k8XS0iLDm/NjhcdYVueKk2fJiKQ1xAugZtX87oJ29PfVPvv9glYbkub8b6EVuE2aqZkm8A2hZb8lZYKhT7NVcp+s6ihNn3ztkGUOwC7ucmwJz2gnnuD+zdnerNcCO65F600a4EZf2HwsHZ5w55D7DU2Ym6t0m9/dS6IrVLDdfmM9XdTrYFv9QBg7dNSI4gbt3cdwSPsIp4N423JNX/yopxe6KKtvopiYIAVeRyttlG6YZt9XiUrAwzRyWr5PbqqjqPA+7OnwhLBWyB2ppEBfqjtM8WY5CfAUGMU5GD+ae81BlFpNbGNyERHbRgerFdcH7zGdlu/yhyzNI/9z8haP78x9zdJGwDuE3mP81IXFf7kRcDpmIGrRHD9ukuYNpXfRE4/TDAW9KE5RhGD7D1F5EWGrCYWa1TE2ywsquDckg8jBbYEQazi6dmaEbBavyWl5TjJXFwEContER09xippO+eo4FuMZKpLcW/p6nHTtp4g9ZeWUhpQfZ6RKgHwYIRPcYn2aEMmL0g5jEwzY+69RnKyJb+qswL/aR5L//vLFBUm1jtdPh+4Hy3dyWh6X3uRkng/0ZRxs4pBzyeweiyZG18Qceu/cqjz+8Y86an0dXiq72a5RjAf3UYLrJimD1TM8DOyp84KVZAFH/jF/aEbdpiTxDh7Mq+TmiToETvKi6+MhwrsvP8SHUfyDvg9K3gH3TuNDdoME42lDS7wD6Te93hYF3fTjWUrW9TrMJDUYo8dwGCkB0KpFlqAZjFUsC6SDh/XTYV1Vg3PBQ7YI9PekvEuTsgqDtBX+FGHmxXp95L9xPvzE1jlFl8Te/qURkuAr0Jd0NW0D7cbkiB7DTtTGxQbjiVLLgZjj7OMayOG1Q4QCi6uNc3DE1LmzjrMKFWUQ/mrV1ggzmpgpWsU2a5t483GZoEYmvRU+XkNRWR1UWHVe1xU6ytfXSdYe6wVkQtxnrPNoqjcSQpsm/hbzd5Tc3k0niuN9THD035PVhNg/TEubfqXx1Sc9Ij9lEu7EItzlijBpErcoTFwcYHKPiidS2dJ70pmB2AQTD1p1lnSJ2tUnyLa7x/cJRWVdINIlhTkZ5FXKvs2DNRsO6atie7Tkxxi1GWnrbJUieqKl8UCFca837Z2hguRrCuX4GCEl1AiNk000ZY1YnvqyWRL7JRIMkulKr1roy3zwlQ+BMXIoIRhGAWobIshqA1WEz9UYUIjnGZXLApTGQI7xSc2syhOUCWBXLR9Io6tkoLIgJCm8LfG7nUnj8NLEWHVuMUWYGA8iG4AA59hx9hBR2XcWUNF/CEw2BhDWcRxnCcWjHEILo+g9ByHrOA/m2Of+EDxcWKEy5s63v3QHetOmL+23Lcr+w1UU41FXkI1PU8txvM11B4VCHcGJ+pQplqpTFsZRm36LigQbddA+Utl9RT3FBBnUks2SSVXHqeJRWw3cYrS2Q3QeF2unK3lwDCgyIVsu5cIRkHUiM+5sWNFZHlTs7hhC2mEOzLbLrA8H6G5fDHGGUCjwggjhFdPcmYpOyTBao7b/tY9rlrelifKd6E3zbmZCRGp8LcleKcbDDRCT2nVMxBjcqdU1Zbsrtz75XeJqYRtdVR7l9SbP2MRuzp4pAdNkGU+6maHxkVTKfHl0wESIZxsHotvGX+aarZi48WYrqPbyA5ywLCmBbRcnwMUwhUdCPwbBeWHskWhRtZwvv2fZtwnXAMYBAcqHAkL7pavpH5N3vmHUodgvxfK2NEvxRBduyP2XQC3rHPjz3ZU4zCvMp7Ne60mTaIbXmVoxCnWhZ39hJtArdeRGX6gAwNbTZnlSRW5SXSR/Ir+2R1d/ysscr1gornjczhE5LZ4v4+CxydJn0Q3peZTdKmO2wvBA4Ltx4eMXtvjm0Ladgoc739/m8/SbCBta3xL08GmS5xtCHz46bFn0B5DA/sbYC9uoaThZXX9S1QExSeq4MjE5HQ/gl6Gk64G17f4JrZLoVVt/b7gr1FdDosMki4ohZL39y0SQdHGGa5rERbmETXIXH+UnSYoy9e7g50CXHz+jB1+9fVpeFlFWJiFuSE2T4tLl5FZUITCE9uSW0zdu6mSE0z/nyF69mKYemWpbMZ9t5LSUOkuD5BhNJjSWEhw25kLXV0VqJOsjNcYvGOR0jcG3l2Kl3FByBZA/nuzndYqMHiQPlKxygyY/tWpfYgqUpb+/lBoG3fD+A95AMM83W3psBjS9hp8+0yjTaPREmKd/6Ge2hrvZ0HuBQrfc+iss5+n4ESsqbPtFM+6Rh/iH6U6QpLtj5XmT29ozisL1eN+ERbRfbeRtaRYCw3sF1kf0aV58QI/forSev/XWMP2YkzVn6jsVrlaw7T5riNn232oNuPaSI28r0G5rFGHviyxY4oY45AUgeazUwikntQc1M2eYTFLMgmyYrufZULJCl3f1+jpjXv12RdYmDt2eE5znePQiPwrpmKLhEcObQVytK3aRUNwSklfT3xhS1LU9N+GuNU17FUriWNFenQroDWLaMhqAedeDuIV0Ux3S7uBQ780QeVsD0bzz93RED4aI2vfej6iV2OxowkscVg2Ndml04TK6VCu3BnrYR5IDRGtymPZyKm8rkIUfKnbstDzBVk895DVd0B6Tv/PXc6jBteEBWH5vuP8hkT0RcIJ13uWis66/IVd49uaxv25gse31w+T6gSX3X0JHjLnV8Ir+uJL6nv7oD4kcyitMoD98kg2Y9D+ILgmkRPbaY5uvhMwapM9wwv5Ww3bdatjfQ9jBewj70Pxn5B9WBcaNF3cxLA4qFwwFECjEbgPOTuO/74Dx7m0IlfIJsgOBCd9o0CApxhtvWID8ec1NrHbYIS5jTRLyqt8QhM4jJdkkGGafMh2Yik8cRqtGZ0oCFRZLuihReWlO9VCdFacK7V5v2io87zcfwkTobo8GC5cgbwZRt0ulZ6Q1/PQiSCZ1uxI8A30cqgs60AXHBMovuNrbK7y/gmpScS+smRYQOV4X+Yitz07tMrr135ZhJHvRchatUH5c3VodLLOrZB0Fs7/68KYie6o/zyqQ73lZ3tYcz/zO8t7uQm8JB33nxvbVGDU2y0diNGHKlm/CaOLhtvMRi4OyTG4zLEXdWckcj8Mt8hLKaUmfPfQ/ewnjjhx2mv+5TgNYrRqdF+4RSerr/FJXX24oUmr32p/SeD+MocpLrnkzw7SqzLFmXH+CIIvp8r87DNbVxWqaJ13VtiaFumlVl2FrE68bW4njQXhcK2UR7W0/eVuafcxEFzuNoitCXuvc7juk0NrcZnOzW0d8d2Pht2B72ZO3FchwatEEO9Agb7fhT8xD7JNZYadlm5HAO4qEWZeyqshTgm0rEyPZWzQuD7sYLuLOBgvPcy7jAf2upnVsR6g+1DAYKo+YXpmyeqCH1riSal4tDZT1TZ/yUSMJ4eELuJjsVxGDVWSePOULHSVNFobraym1GVFCm0sU7Z7b5W1J6OYfr7ZDQqSJgiU5ey7+qKMClee315MPqvHhrv6FJWGNJkwg17zWPkNDfveYJ9sSUtUQwqz9mGQ/mAx1iySysbW2tsfOMrQ7zYw1pxVpeHjQMQF4h2C/zijktqXR+zrpW21+294jKPsHHr8W3sl9AFSTLSRdW1NlQSc7ddS8GDj5WAyynodp6PgRj6kMb69Cy9Szya9urPr6N0k9LO8ex179ydsKZB3AyVltr3W5J+QNc8BrGd/hnkWDGajmRd8xKPSsLwshGC0SsJDHs5avD8t7qHJR2u7imxfkP6B0c1OnGSpL/x28gDKYWnlBIljartAnaNqpatfNlyYC3PTOVwK/R2U7wHBhDaMOqsx7gcBXXFXBoNfUkJnwumpeDIjX6vIoXzvm6Ce1XzEotoPH2s7o7q6Hcms0jaHH6Y+lCKWdErVJub3DCDI6M7FXA+DA1lC5wMQgkDfLOuYp7vl1n5tY44uJsts6uvU/sw0kg/YXc4sQ4mjZ7AlVXXO3GixxwjIPuDcJOBoN4Z1E4mCzKfJ7tGrxHQFhtrbXKPMqPNLAqTOCJpjY57RxG5l0je10qXSNpUviADVeYEeF4Oo6hrDdKzHrMxw14GQF8Kf+SlPByQogDq0ii9KDuroja1pzYe0cxZhvXXZPXQagVyrEe5NBoYRaCvqaDMdrJtn8pP5QMsvN6G4S5XWcsE22R28ztvyF8DLlvnmaOohjvE2dp0H8532yQsWUz5JpPWOg4lQpkquh5qBJjSoIS4BZLa8d10le1OuzvHRxEdC65asexV6Fytu6zDdJHMotHSLcdv7NzOnZwWpVUA/oxPEhu5CVTalfepEClYlYKmgOAMTWeqQoKNtqusgCQp0cyhXdZID89VnbGS+FRnHsNZq8LUqlrdFoZLZCRCpd1Nf/QrFKO/5tmgtKnxtBKP26/y3BOzBPB0ZUVqQn3jFfLZ5QU9zha/SunSPqeSwIjXqUrgjjYljXcjBOa4Kugy0Q2Dv6U9W1BsB/CfDU/nvFL2+LEuh9kdebifPYmeZN3poIf1CrU7721MlhFgeiQYPsQ57jEvHXygk9yLBcm1+xQJw2Z8pgbc4C+GvzthNeKp3i2Ot1hZJ59tr4Wcp44PNHtcqAz5Gs1AV/fiTVJ07qop1ba03RpNBp/tsrCXlblEDaJGeBDhxIW963IYIGBHu/6J2kKSZW6wj1dlZgEdwo0BmQ9wKzRR2sI2GwnUVP5DQ5KLJPqLrLV1OeJEk45qguCpTFT0e45gyNNo2dR9VgAKujx//uLAuX0WO7oIZwvH2L9LkTA6qVi/q6wioxPc3i9JKgDRVqr2rs+HGexi5JY3huYhLONNcIR43OM9JW68wzwraxWUeGG7IQZfvGRsoRryIJMRGi9AShqWkqb3lqAstbnpraLX7V+WdADTc5k3ayPm0rVK1M1gQ2vOtshVa2CWGtm3mIitVZnmRV+R0VCLOdf0zv0R2Kf+T1cMd7zq200PgsKVQ70yNUDPvBzU2SJgFei+z3B5vJaUCDqsmmBqM/KhDWX0eYt8a2kzNLYUwEw/QTSbo8ixku0GbCV0jLH2glm5JJR3h0f/92loaOHzdJQR0Jn/JsSPM9U5v/haLp6cnKV5Pc9R26TgK8b92jOojpuvkhT1cz8IfY8EyMyTR8GGU/ZtkAc23OomLYNk+P5myOXlcZ8mTM0eTpdTSDcdGuptQA7K+wTi33Nd4QFMmfVNPQFBVRTH4OpsHsTc8iMrLGz1HJJAOeUMNviCN9XoKLjc402ov6urfR5x3yWV3Ed1GJ5nTgn0WJ69XBzgPSbNOnn5e2ObI/xwpnUzenJbN7jQM9cL29x5PsTvgckaM35rFeo2OLDxHJQtR6cT7nVf+iWbijzvEpDXjkScXoigccjj2hciFSAgSyjclTxg02LUAhg+MSSdecAwU739DXEu/SPyQleSAB7CAEeNUe4g6dlUMJx8kKUNvXNt8nN3Qjpx0EBHj1tUSr70l1JwxGDy0MyqCK7eBoLXJXU8Hf9Cqn0H+uSOgsX+7UMyzYklTXfbGkZ0MR3DOm3LZn52iF0BqtWCV23FjgQEdZKC1TaIGFwehrWL8ui/suvyzclYpkH5eIb1KOi116tTHSxgIkr+04AInS46H8MmeCitDhlZkGTQkqzH3Airyt/hjU08PbaDVfN7GXXaZdbc1X2KGGZpHtPgqyooa2tRdanTKFgWDU8bHmcpJ02FpwDUSDsO3FXN5WRy9fCR2toCGQtVn7JzpYnEihdNQ0t3aHGhpDt/soyKUa2lahcIbWHEa70YBgm85L4fgrmb1ikbfV+c0YrQCl6TPTTiEC5SYOVTgtu87Sp1qjAN6oDuFRXm9mcmqfY2JsSIrpWbx2fWvzJLi5QBnZx84xsqapeYb1CW+2aJasidshL8B13EHdh0v7WydyQNkvyUZuJ2EBNx0NrEmV47mS1RFHJAGVrsoyeK8lmemh1w2UfQ5Tk804JpL37ZAgdv7Zog/b8JZvllQ0jfnUIbx9Q5NH7M4xmllGMnWEcefbaGzEqUk2bm1q2i0S5jpveGv3/E2ANLSnZYcsmBn/EQtINjwtZLkFItq6eU/NnEM0d+nqbJUibGZF0wcyNAr+iObJC8XfUkPpoCzzmEQlrzpjBT71CGglySw/nVXl79+1OGgEj2uAg0hjg1TxlsiA+0x8S0QoVHTtLMRbIv3BpaddSVDs7Up5W0GswWaevDWS/WJMr2LmQ7DHVu5pNZrA7GAfFDfg4N9J2ICDda+s0wC+vQwq+C7QVfuG4CFwHEZplA3PcbmfBU3sup3LgTaRZlAGskHRLlBYmwpOUBtK4PAnToEDgkxGE/C4qQvjcdCFXURNH0O013/ytoLYIJdFFP/AFJ8p0Jte0g27u6M8g1zDx9+hNLlHxZNj9dltH+PgOl7oJbF3tiF/8kBQFuJq0AFiB0cA0iDAMZRXqicWZQiltHe66yWS0ilIJJ3LW3dh/OVaYQgpBzJ5haXFcb+C2TE7R3/UyOkZh9ZBMEKzlwOFHIRIKBZMCEJtl8IcPp2jqMyzk7xouGl+N0jLv4i6vYMcEPh1QH15ymxq+Rf0pov2qKKbm/bmxdQHK6t1kumv9v7tpyAPgox0W5i8clt0xc51R83QRLKXhiCAfScI5rnZzKlxdoQXIb94Ch7TfmVTyX+Ale0sKlr7xvKEsDnPc6jITnGICMtgHsgwYSHLpFjCIokKzEMkLGIyj2UYo2MXVPHA3JLdxVhLXbHw7B5DCgbsNOSwQe8YCw1Ba4kUSN9vZ4+s6nxXaAU45pXB6Lsc5NBXSLHmvggKqParoLwtTWC16RvCth5b9FjhT+vN9ElISAD0H3VSBHhWnPjQCHzL8KHwnpaX0ePxI2Ko4YoKIzrCbHCbF0/BFuKjPKuKPA1ha4R7kuC0pJFeyJpgcq3Paw16lw12E8OwV4AOG/SraR3BmWxc0cu/DLcSUAlTfHtNLG9LoNjED05NpNqpDX2w+hfmG9bdEdyabg7gZmjotMSYsNijOEBYqYcGNNdc8+ss3ka0VnaOZwFxXRC+bvMjed9DlyDcay15WzzJnnPmCX6sEk8jyENXYmXW92hWB/BGGlYMKmfhBGwvWQomfopT1CzNntJAEJ2hIsm9E0bQ0BeKzzPW8KLC0y6NV5lrMyDG0YTIR3iaJVUSpdusydguGmmxq3ENueoaAWr11Rja1uUlXf/nVstitjJLfe6klinT408f81sHjYxr3ZKAIAbLXhvL22LItE2nLuHyRW+HYuLIDIoyA3MlwA/SqwAT9JIKNujxAdsQdHIAlSt7G+YEWiBjCHVC4PcqRd5Wk2kZ9+ghL1RJn99M46jRuIcmegH3OCPAljaWMR/7LYX7JVDZFibPR3SPUv/3M/OiCnd9x7L1Eww+W/KdTZ+d1VvOHO0JXfjKLfpaTB9ngZkcFQUq5mhrxgAJDacVJEosi30DPvKsInuIqFS9QPQ3Jy5yM2JkxovSaAlnrNDXs9m3JRxUfvO+9ysB1V7/y9ti6eSdiijUBojOoL9ba5PEW+qqUUqiwL+gXMqhBClVgHrJ7FlB07L0C6+rwI7x7KVVIa0hwlsJD4WS1CFZg7cBWV//C8XKSPpfJgtbmt9iJRFMUYAoo9a9ffjUPIIVEGGfYtIX50Q6lGVjUI+O1crVGH5QpAowQZOqYG1dSmyeE33vWWhp3wcgXc8ZSD8fU/f8rIP27+uWw8+98pe31W47veP1whyIhQ7VUz2O0rPHFfAwilAoulYFCL+bPfEdWtUpuozKHw5sT6qVr1gke6aXt6VxaP4yjUPzALOLyr9j2qxuYcyz48cN4Uj1Rc83Ye4QNqcA0lb+vkXOYdD03XzJjovC38j5jC2+89rF+/Mxopcvi8qx7nG2cm21jmPMJ67tsmSbjsFOyw/JCgu27wThP2+JVJwhrMeFPKJmdfXu4ECDPs8fWm3dDzvJIhKxcJRnJDSAeAs/UXS0rbHMwR1wUKjNm59o5WrIxSk2+HOntzguSAQERveqR7Jf0eRtNaT3teIaLMtEg3dbB2Jd+Y7jFNuzaUAzku2b5LC+5dGrMSh7XA9BAAf2IJiXafm18JHC/FVffy+Az1kAL9L6dv5WQ0Vkfoyy2xovzXYzYP6oFGGMJPa5c0oCsPLsFY9pL1RTCxUe0fsirzfzMzduef5GRy/rzed7djhFMJa+yzu0Rt+iIiGoXLwjpH75aoRmL3fytiihAnDuLLcO/aThbZj92pTcT3G72G7kS9n8t+f2yfnQNl5IGeA0lY1XpqE8Z2R7rokICyPBH/JSmeMtkMflY36bnyUxkYDtSV7woVqnh/mKMYGmC4Zrgse6DMGfUfWQFz8mn92zIsGK6YmK8FHr1/JPMEVxHj/Gd3hXgMjTUs6oFVl0pI3AmXXICK+UtZgUOzpgMdeOtoZ9miBxZvQj48AlQxpBqccyBvXLHNR3y3otfZcUKCY3s151SPYrqrwt7fnaNA7EZmI0D+n+Mkl2U/PX6/7uupx8zAkCf7KauGFP8mKNJ522MG17H5N1glnsMm+sVe9DHiJg5d2i6TeWizK3HSPVbcfZCs9scAvLbnvzKaKZ4jx3OS2WvWqWt/UM/NQTbrUPo/jHaYZbiH94Xhs4iqoozW9fSTDuWTToBIMn9iGSzAa7fb1AyL+E9cDAfx2sYKNrK4TMSipr7ExMTqoBNR7HWYhUpZ+irL6JqE+huERrbFC4nRy1ugRCt1ck8raWWZ++JegBd1V9BW+Sll1tVvMNdJsxNAAv86j2fLzn49n4uFXuAdiYw7Tn4j0Xz8bF1FAiTxG0RpAzE48R7XlY3la/q3gTaHfydpmTJvMVv8jLEtvgqT+X8aj2fLatfGa+jjbJ6T6h6i53iS5t65evRoj2jKGYUJZQTVoo/bo6yfJGsuO8Q4yLzL8HTjz4jxrVaHWM+Sk9qKoovnPMO9te7ShfgQj3PClviyGY93193BM8CeSoa8RUxAnEzYgAaqsa1UZhoKiSkwS4zaBZ0/F6yV/6MYn28LK+J8rh9ilZI9LmDC3Lr/QnkksboKBfNeCDQ1EOJfgSFaC23lAGlUXfR7V0Q2C+Go6EreHlFx31M4im3utnhaYrkrzwfk2OsNP8d6ZJq9pokiDXmPP5B3eZzzK0c7RJn4KMz6idWcZ0dDR5E4dxPHkb+vxEgewQEkQ6fQhpyEiXC6zcLovE+/kAjMYpJ2Oz+MVxXvs/VYI7sSKHd1Ga9rMQILlJvzLDCU4C2wh86npzq8J0QCzJdSO6GgODAxnBqGycMaCXaTPulrttw+LZGzcaMVVtL36ZJOCzdbzqdlWGjesvQMw/wrO84HNk2MYqlngmwxDIem9flppU6RO13NyuuShTazUvEu8duomwVONVlcoCrmWH1OJYf72JkluXMLdeX3U49rpK3pZGW0x1MVdrY07UcCCbc8lwa6/odPMwsUaIPMIRejHkUO2l0VkaJ/KI4l1lY9o1SQPR9An/n9ceM1S+kJDbu8B3WLx2i9I94huHo4ih9luv2j9raxvrys/oofyIiKh7Buj3KhPGuNec8rZginkn+l9oKxdGn4T1fU14xeUTikrMtM2j2F43YUeY9vKikBe1pTHRq10LPxp2Tkg39Z3Y6QLfWuZ+h8U3K91WGEFSemR7YdkLy3MSltP1Ji8q3OpN4pSfa1R/LxzbJhwneYo5Z6G2MUeQNsPcWA6DKUwCpR/Jxq8jl9EP5IehySbwJfPfZ2IhOUlQuiJ/zZCsqeOKozy7SW7rYhwtOF2KpLReZ32qgolbO0cl1nKn2Y0qciNMU+27ERg5eTkiXI6k8aMWwIHuSPFfjcGHI105lHCoqwD1e57jKYvdc1SQkM4uJ9MrBtV+qVOp2RCJKhr+UOdhfTNNPiKjHBkTrZo0mdtjtZAtTWk+ySuk/DCpIJ5aPubQ1Or6NPWaQRsjy6qwxOp2JFns5k8yj1V5JMryHdqk+ZPjrQkexV6jydtqVyVflbaMUAeyek/LZrLDuFv/OZjQznm+etYNsTcwCHkJlDZTH+ESpiFthtcgKV6ranNZRFm5TuirVSGmAsI5vk9EVRcM5rBJbTxIga6am5xdGhwgB5oe2p7BU6oBBxfmYJZISXKPPjEZIT3isVyiulTpjm5kF5P4RfWqBx72RDIYYUckBfQLc3308/iN6u+NBnlbf02PH/nVkmpyhWN6izpIsuv8PsGEXfTi9mnZLlWd8HoG0gRyh/q5oEQewrwzx/4O/0mWxTncjx33NE5P9prwc/BBfrm5KZFnxDkNxPJDcRhV8d1F8qenZ/0MC3nzbMf2hKmRxxzpK8029mOwa2F4r3ZQxHchQm1Irdp+5ye1xQbjCL5I5WWP8demtIZbMOf6yMaSOtflUBJTMoBzvV6zpqQmr8NpeZJGt2U/q753qmQtBbNCsXRgLZ0+kbWMEdfxtH5C62tUdEonza9fvqBPFf3+8ieBBUawxDzC5isiue5RX+mNulKzLW1hgdDLZkJUk6TYLHtP0Oh4RN7SghN0kRDVeUYvYplN0yfckWSDu0tS6ZMBjiq/MZmCg7LM44SSsFvf6BMAjaLGSzMVz6vu5UOu/8fZ6kUjtspag5APnhGoAl4X6IgwMbFI//7y/xKGb9pgrxCZBrshcI28GY8JN/Ile4fIGvbigNpc5O5SGUcrUW1iiq7GX1qhIRepsAVVYvZIskrcICZZjOcttRkKh8Rwn0k62TfHl+D1AWVki2gzhyb9YN/JFPvTN8sRU0e7314zzGrAw9i+WnV9M2RgsIqUe1loa9aFm9o9vlWOYy6mVc7bTnAstuXbVQh4mrmUcq26GsS5fA0bxtW0BjDv+KVqZUs2xMrTVC/RIyiQFDlZpy2GP0K4U6IKdn0G6QTnYDcEEvf8ICsfUHFF+UTFFAycjM8aEFtuYxED/AYx8HbwGtDxmbgNmAuTlgn8Yrx2gffTJFSrybh5hW0vbIPFFVodEZcMzU8j4xJ9VYgjx7VsuNKgPWgZoIU6I8mGYnjXh6ivEm9Qrzr00k5D0CBdWEArsoAtmFNiealVjmAG2VXOkUn7bZXFhLj1dWqZkYOD2LAFsWFAHqs56/306pXo2HFiIUkfZmAeCU13iW3Gqkc3zWNpCctCY9wAIym1ZHh2AvszI1OBtDZpf1RxMQbrH8saDmNkHCCCQqw1PO1lzlsAZoCxzJjWZeyHSUqOfbsGtN0cwwenAofenBSidDlQo32Fe3ijTddfvoKKHi2sC1mEZhQOhe0zoHSjmEFj6ebLaD1kHiNcRF8dpvktOcfQO3gESIgvOyAbhhQR75SzR9r9GVhQOic74fQhvT/K1/TIvGccFZfwwDIObOFsmVBAD/ChjMG3gw9lI5iJFWXzY9J8V2c5F2TzsM5ZQl/jvGr/l3siQXDQITmCtHJKwm1AvkkY+fJcqR7CHF5K5TwZOSubKlvDmO2zXaZMw7+SOwVjci/rim1sP2OOh7AAY47nyYgxhwexl9nrtg++anUlDwjuaFoYq60Mj9dcM4ZznMg6MccORELXXdBq75Kyyc1+sMGTQlIttqNRnb+oKkFM1cHbMJWyDWiPbMa4XqRpJd2GMF2V6cjSt2Cu9gPQpPtxjv6okwI1Ib7aTkO1bCgTdL0y7R9AVwBOP4lOas2IdDPoOCMSmfSjq7+0HXeF+Sa5R8UTvfevsbBGwAobzsF4G6OGeI3t52TLp6o381lhIJ2NuIqptzRnHdbZKkWnFVofVFWRXNcVam5NXQ0lOoYzwaHgQ2l1BwY16op87WHGvK2bD5sRzicLNixg5Nnpa22PgLRDMdxLy+oZCYIX53Pt7eAGWzeWJfgankVzXl564y0OyJ6R52NhF+YNaVrIu7II7+2go6dtv3c39FteDRMIFRTc5uL/kTZjsU3fGkUpHcV8XCqdL5MudHW2hksNdSIPPzGP7vBSLhvDAgy6g0qUvP9yE1Gna6H1mEPAEGOycDZcCeJfwnuu6sgMfKWi8y540VumHg1jxBMatSStqNCCrjynbRLgP1VbW6MXtSOaT0Fq59OkK2y9reJswxUdqjMTP+/w6q4ax0IMvIOrfNv+xQbFyU3SpCHp3WimDKyurWBluKIDU2t6sIPsbTai+RjdbI53geXhkXyhL8hdSThSxn4OuMCbhQo0VhcNHboDXeExEsvlRcVjuDMIjgdvmPQOxrClC4mSwd10u5q8iy05ym4Zyxos+stLnP/YF1+xTPjGXf4aPEtLYbcsX0a3iuwwImzgiA0Ws9wEw8UBk780OL9FRRJlVT8tR/n6OskooFU8iykeBeEUKBxoatyhpQNkbDs6n16wnVOTnm1TWI1qfIYbOgMUW8HxO7y/sxjWdojGDu70DEb1jzqiGWK/ZomXVLB4tkI0Rh0C5GM08CUXA6ij28Hx0Jya9Iytt22877oCOKj9AAz9nBT89mj1Z6TKu6HoPXWmCJZhcKU7ThjjrrH8Et432/m2EIKtcbbxg6Opva9k3GrJmkpkFlJC8QQQFXV/5GKjk9qtlR6jAS8nSUb8YSFVPIqlhctqa2Bq/7t40bbKkl/YXH8WNvnVRUTecniXP2RpHq20vDUGD8xdHHLIbdj1c3LegvsyI3fBlDY6DRjVXIzDLhNU4FGTHKlsbnUZE8DgEIf1kDY8JkFvmQme8tnSa7R6KDOwqHqqTDrA1tsCBtU5IgTICdhyF90L0t7PyoS760I4R/cJejD1g42hFWtvA+iwAnMt7BIrKkcw37INz9HOseQHlG5u6jQjOV/HTGXEQdLqWqZlajrzr7x1OUPDIrNlbK0d2Nx8rp1nC8ZvKi7G/p/RQ0nvmGqTuQqQEFN3QDZMLCLeqWSu0u7PwJXSOTFpe/FkrqT3Xf7PnnFUXMIDyzjQIZkriB7gQxmDbwcfykYwEyvK5sek+a7O8mn4zR52g8GDJ6Jf6AG348cKFVmUHtTVHSFvE2LJPSonpY1RbYhUqoo25DPrwE5lr7ca0gzybjXHNr6RxRTASV7Ua5qDWsvgIijEzT2UDesCqK34NIg3WN6JGThLTtzdYaPLfJPEhnw0hpUyEgWz5iQO+UKsBPdiLl6CCbw7zHRF/31f5PVGzUkMoJSNrDmIRQqwD9O3rVszZf2fi/GA+TBpeqi1DUqs4RoDJdMMeQr11WCWMd+W8h3Q9XkV3mg+jPluC8wvhl/0VhIz4PAmGINcxn0gX28JC0rGMKsNJ86PSfO0wmKs+KVYmT9JBwFDrEjhbNgQRGz+El0g+03VixkYSUVdk+bHNRfmKO1+YAwWkIt20+cB9302rtvJHUOXs/5rGd2iDwnuTfHUJ8KXMp6ylurVA7aCy9sQcIOKZwy2j0uNhjID0xrNoUk/Fn/2ABxJo/ms+KkR47m4t2kNYF1QZ28p344GsRTTjubNpBO0wrKLOz3vUvMoBydd3m0P0Hm8u8OCkp7PtcKLc7FLzKYLnxMgJ2C4XQyZk/Z+VrbbwVC598lNdRQVq6sz3OW7qESr70l1N3CQjF009SC27KrYcKWuGZlahLg/3MUKw17NwHuG02DEiSCGxRlzZET0LKTjF7CWiildrUZ1gwB7yqRgeR1qNJQZeVo5hyb96OpsFw9/ZUXMjpFHVWfj5nGru2OImg9mKaYG59OkM6OKy5qtn/MKmeyRBjipyUpArE1WBu/usKak53MZq+JcbP8e6Rw9YPE5yzGCspMfre9dVQliQwDehiGVze2Ul95kJDNwq8n87YQHHxqImSGgrWms9sD9j01DbgIjNmuTVPwu2dDwczWRxmBgKvAWwirt9xjr7iwvcMdnkFd4HrZ/cen63eyZO1bR8cUIWsV0tr44uAEoy7WEq7eHBcEhzMiJ4ByZtN8jWDa8gHRjYxyxwkEHDDbgMZvHrIRzuyl7MpftLKOxKU9ttiBy5RxVdZGdoz9qZHIzAgaHzQEG0s5yBpvYMZtZNYZZrGXVPO2EnTx02lDvySoEv7QXUgFaWSY5bfYoKirmzWrl2YyiDmyljMHtLBV5U/LzQ/mT0uEWC4OezWKGaKfCpBdDrQVNZG4k2mVDWmNyJtzN9UM7jCX4dSdXEWEUurAKWYXJOXUXYy10g1iCTXcw8uIsT9NveYVH0V6wJh8OsvJB9VyvvA6YjogDt0pDpGgK4tah81vHsAZDmYFnDebOiG37WssZ6Xco/pHXfM5i4bPcaDdEABrxYF0rk960dch6EMa4ddxuO7wZWN92vo2MDL7ygt6UuC4wKW7PoifqZTzNEoJXd66jqAX7VsYV7NwrqsbMDzaC7MyMOjOLu8RgBoz6wdTbGi7sjvAEtjHlERkCE950Ojs3bB7gVp1oLK+UbUe3APvr5tukS3zdxaSBTOs9nvuP+e0V85vwjFQAFHUgnmdAbPhc1QrkU+Q6v3WcbTCeGZjZYO5MesFV3Qr21frZIOCJGHY3HWuqEczMmzvpTjPiQh33WXKdK7dtxasGCzHazjIYzSdyUV+XcZE0D4abZVkDq0hTxrDQ1qlj4KYWSr2m7MwMjKYn/k6wHR7vfVShT6gkQflXJ0W+1vKdog6cEJ4Ft0sDL29ofrYz6M0cLlQ98U16wdbbFua7zG1Zb6gxKeMxzSzOdmJf5mc6kewmfRhqLbenuLlJUvwFXeliagRIcDfRAVntJQTMs+e+knZhjp2AjLBGe9OFgwYP4pTLBE0GpdiVQuDwvjS1P56UoLdMpr78VkE9jll2p6p5srHjSL3lQj6qvCDPZyXrqHg6fozvouwWnWNRO6oL3ET8JI/90NUEg0BIJavID20rIOu2fZ9GFRr3aQY2NJ4Fk74o0GwHg9I/7DhzVCU8S47RL8yLYGfmZkKQ4BbcN6q/GNsdRvGP0wz3Jf5h52DRVYRYUFLHhim1ze6U59l0NDPwtul87oTnRjYYXZynpt7MPL2LwZ+GY1mQoXcwFPQfNarR6ngdJelBVUXxHT13P0kU2yt5FYiJQWgbFlY0Z/u0+dIcrB/KDMyrnz4jR2ay4I6LGcJVM5BYnY9YVkHDsI5sOm4CYNJRn7dOz+pGMi+PgvNl0gW23jZwKiNsLIvZqT2WMPMpW7ZVgJ0VErNV3Kwe0WKqF5hTk74w1RZj79P1Ji8q3LcbunzEd2hVp+gyKn9I+VpeBWLoEbQNIyuagZJZsD2fxsug79AMDKgnvkkn2npJdktqLsZ8x4/WzCevAj8f6sh8imaWYT59h2ZgPj3xd475cENp3oQqd2yi5gmxgpzxBlh73gPagexQFYMvv3TrhjIbz8pnzXCLfzPfbukY16mecJ0K10BFJzXrqKi+XP8LxRUpQo+YEWLqSouyLK8oll+/lugoLQh/lL+/rIpaZGaC+gJV7Kta5csXzXeGr9pHzAQe5apHj0dRhW7zIkEglr78SYsL/yLXGyE0bZEWxcc8jtLkT7RqZxDuFA+l79rHKLuto1sYW1tm1jl0URX0DmdJmU/aPQ5Oi/wMFeukLJPuvWUIMQ+jRTp+9lxEOD4b1/UwT1OwV/i7UeXm2qoMRXd72HBIquFokbSxFCBN+vATXUfInlYiNU2ZgcS0SWU+oeouB6d8DKFHiLUIwlJxj1Ur2LMRgDGxqbrKKhXNWxAtysM0vyWPCEK4ujI9NzUOW5CVOs+5BkX3SA2EY3iXSkcfleo01ptnSVzVBYijLTIliArTCMKYPCSbVFKgtWT2ATA9apQm96h4ukzWYE/ZctOBDwlyFGNn0w7Zou2vGZ8kaSVRYpo6po0qmWoMY8BbDfynKKtvIjr1qr6zYFrUOpxWyNoOXGxQnNwkMbWFevopegxX0OtJsNoXeoIEqk0FvGNj5s2YEu8yAm2vodQU0beoSKJsuFp/lK+vkyySEUdfS9vwP+qIfvmaJaCeYctdR2HRddMmTHBbI+U7Q5MlWHS+TYih08LtGR2ogfvzO93uIUEF3sbBpkZfqEXzGT2UMt3dlWmRHD9iHZtF6UFd3ZE9WyNEcmNaBa9trH8LGcLMPFBtgka6g2PfotYjimQYzHpB36aX9oKWahHRDAgQjjadhKHNwbyRAS+C8FOPGuzACxwwdvgRFUPsKoRm9JMJAvOulQka8saDFE3z0oYGjZjbHaYXmAPeYOMjsymHpNaGSGQUG6ff1o6WSZ4KD3OU21bbt3GGMrh/fCY53XaDz3kDbjvEFEW2aKUrjiz5kpa2UKoJGTdJUolYtmGCW+8nGK5ug64C9ka9OSrq3FOja3I9aP1RYK9MeiPc4JRq/nHQm9aCYe9KwTbL+F6ajmrdjRmQXsMVJJ00MuccoCSOTn+0M5nKrQrmMosGzddCgaYv1C88KEPYyFKqBB5Gb9fd4a08tSuvYcfhCMDAK5XDTok2Zl3rhaJB1BIvSx+XbtKJTxHVuNK+tOV6LxYcfAg6tWQBpBbb60u03qQSKYDgTB1XTyrEPIzxNlSBkwMx0OoEbKXw940h9AMv8rLEFVMFSh5GP/BmOZF7cUcABpthIEIF3hWDkUbm6DVI9XsuJrwL3GONYuy0PLneRMktKERdmV5qmoVFKTBjEKPd6UdU4d2iTtRhSIM+RyWW3u8oub0DyTgCMEX3LsHcUEp6ysNokY6CViCMXJCQThk/ZbFKFw/FBvv+8ekwvNfnz/KNkCqGy53ac+iYY2H18eHVcPjI1FGcIw4V+FNsNneOol4f6tAPWXqwKRyUmzbRRTmwTQwHsHycwphYpoRkj3/1VIShNeMDK0npx59a66gHY5+YdPwJ8hV3QiyST1NDPkh1RYiMwBG4goga/AAhubH6EzNPUyXrjQEUQ2HhQMo0R+8qaoxQTM1FQ+bq5vAfHjoLou45Aykbfh88oCECiwogA0hJBxKMz+WvsA7EujDGhigTFiBSxaCWfHT6yhDthBADBf0MWoDEahixP1nZ8ISrPowCoCQIqBgaBA/Si4ugUJELxDkxhbrMIQra8CDyEXCQED2YUBkFKXhEMxGBi2aRk2IMqB/HeGq9yTJGBxBHzXUOFOqv9TIdFckDQMkHIwJDhGHisxSEAXABVJES2Ycgh0maMg+LqajCgRoMZ1wjAH04hDMRqQ3mGrIEKKgkwOpHxVdR0WkIPTMgl4BYYQWGoFcXsKa0AkUg+UAEWIg0TAidgiYiqomtQtLgUb6mEdpDJB9MDwFOPQ4e3JthQKQAfaSkdrGaRxF4V30kHmA8w5AKwxesAJrSfKCgypyGsUJWtQRdACp1Llg9laDcD8rxcEkfAlGJS+ogYg2iqFvfvIqLBBiF/uRAQfliwhJVqphHNS27dKEgVwebTZqg1WXO9lMkihJePipVNYhYTHSxglZKrNDSJZ2CIJQb+NOEbj20zfi6SiFp1uOcVuT6huHQaAXJwAoGI4TqBSAciBagHTzOUAr+ahzmLVXvYzitGh6BK1S7kU4fI4NINA5lD0UbaQg5+/qvnGRG1bWDN8GiILAqdF5PeaPG5fI+ug4QflbaTuhtE2kVCwKMaxpR3JLEXAvTqlGxdSsyuhBwStLNSrTethquf0hpJsJqhyVUUVDM0BqUYp7auuEb1jOZAGo+Kj2DOZJrHu5iI4hUGwoQTj4YCBwiEXePSEEeEOMs29FRy+OLTVKGktfRMoC0qoLFzMmobQQgqRJ7ILrqZRQEtxuoXlb9CDnrggDfFzMgpKaidsjq+griSu/C6cmsaXNagqsuAF7Jru0Bx5YOaBQHkPbYwCNP9WVI1QmoQweg0y8zpgguJ+pbnbbCo8Tmyt1qCs8oZsqOGM+phKk83AhdRDG9+yr3IrBg+n0/A+3tQ2BxyXVU0/9QVFFcxTX1uxij0FLAFJOC0uoLyfpJMO7CfD4eVZf067dJbS+q6FfyKedkViNK1ZHxvXOn6Rih8KIKi2mhiRl1AZgd7h7/VFPkICHuYuEgC050Xpbru9aV5qtxXefBKw3VKaitNEx5mAnpT2/SXkkKLeZCjceaTEp0FnPUXSm2nyh1D+STpuUSD6PTcFmw1P2mCt7M7lxIVV9dROtNioYUInLqcJD6IY0reFOIQwfZfkOSFG/69OlQxu/nAfSRQMoHBFeA6MMmbFFQSIJwhjsVQ8uKJV4EMhmKYhm3JsusS/U5uk/Qg4HNwwFqJWAM7x1UB2OdkUQfULq5qdOMRMqOCrQ0k9c0HK4UQViqyptRyKasGQdyd9mYlAGvIpB8dAIsRC8mP5SCUCKqiQNeSYNdEOmQpgqmhwCnHgcP7s1FIFKAPlJS+4Tcay8ZSiAVUYZghQDx9rNfIlSlIVPG35tVlA/ZqD5EUU2iNQWVzZqcOGa/z86mpC4AJR+XCAzRjc0ZpyASgGwOitA8c3qScGCaYYyhpUTpMuDpqMKhm4MsV2z6OwlNWBjNCBhQCTUiPRlYJAANRun8QjJHm01QyRkNjNE8NmMJwxMNLpgYAkW9lAablFGlNhg4E1lnxhJCdTDoZBwCE9iBNjSjoMG1OhBOPhgIHKJNl3RSQRcQ1cRX6Zo2VfqUg9B1X6VFjWkwl+6EMnReDWnV5cHycAX5sJT1VMHyfBpQg8h5uA1F5PxklGzzqRqSsYG2HF/DLxMSsGkAoB7MzK4iSDc6UnrxIBr5GSClUqjfp/KY5iGBwnskApl0XuE1sibEPL6iLg/v1Rnu8V1UotX3pLpj8uqKpNFVkQ9OUxMiG5NDWEE1HWIZO4Xa1UPpka+GFMdyGsIV9AMF66noZ6GZ1G0ApJTOUShKfmUn1Jic41qW4x1VnpKw44Ym13sky7VG9TMgGj01QEo1XptyW6fxGExTkgBIy600R5Xw8iGpqkGUkmQVVxBN2cLEdizUtlZC9ZXsBusoNpZ4XefKMXkW9URLSchByMc1BpQlwALvrqrwTCmYbFr6qyHZvZwIY0D9GEbwKpLoTTQYJRTuK6Oy89a5S0am9SjwgLo9MAfvtZ/mcU3sVBi9QaDR5iCkSkFAFWCtMH4pQal1QKQTK+2h83oWksIanBUZMJLl6dPM7MQ/QKG5Xq4CV6kQaS1YNwkPZyj1kxz5XNfDhT6o5FIObDFIlXR60m8uGRUaVvgnpLAW41J4KzwpNlOcS56m3/KKplumx6Xsk6lAcIsCXBFqIq/lH8aiwC3J0ypJ+eqyIoDv1lwBT+UAK4RpXYV+N0QBEln2OI9qPTFtDxJy4I2hAHbL+OGdq9MsIa9qK7ZQqgoqg0NRDzZmhGeDlPaMCv20u3nwWaQr8UkjPTGldc0HLkNhQmLTXb9hiwDVtZPqknJ2eJzpSnioSaS5Clw+aEUtMAnt6HkqBTFVeCEbU3irKij5VPYRCGc2MJVV5ESpuWwhHU0MaaGjgXbsc45ZeFtMH3oEQ2uiIcBK0hAL7oEXXagFjHxiyo1fULs6KfK1inQqcIW1Jq8FX7vg3n1TxjPLUc9LusvcgnAMsPHYhjqBicYgnphk/Rt7VwonigikULA8LKiumWf/VMpawDWxw6R/3U97h0cCqVp4oArwWpaaBNtKEM4Q0nxBXtLD++JkHRVPx4/xXZTdonM8TcNbfcAmX1tJsSfX1YUfesh1qX31eEFqDq8VhiUl/cOYhmNow0GOKoWg2hjh1OSSvLWotC20deQj1VUFk7dLX45UkFTb0NR57iXtK5x2uir2g1W48IISdR6HHvh249VJAi8nCmj5AOWVIBrKXp1UUFDRwMSXaZmWr8aPTCppN4Y1GtioioZuxtQaIwVoxT2sORG3jZ76NGU6tpIta7AkmJIF2XbAq+/yKXMg7ujpy6vxW9IiVRXQ8mHKK0F05B/rVNBPgRg65R+/ox3g8psN5RTQ8gHKK8F324wpp0A8G+WGF02vzrqnSGV0A2B1gxOryGk2eoBVSzYAM6QFlbOhoNpvrxss5GQqSjJU9GW/vSYzsY7aD7+9xiAx2lR1lH7KVygtu4LuddqhZvvlxcUmiskhy/+4ePnicZ1m5e8v76pq8+vr1yVFXb5aJ3GRl/lN9SrO16+jVf767U8//fvrN29erxscr+PRFvk3rrd9S9h4xtt9rpQ8pbZCJ0lRVu+iKrqOSjwfR6u1AHaBDfDqy/W/UFzRI7pHbsn7rSd112Cbg6G5GSTOIYEmDuEOnPxu9ymkKWrrvyJ9egVefBpoeIKHRSafjhAxMy6ph2texFEaFWftg6md5l3hkedpvc6Gv3nek9e+eCortCa/x1jY7+bYTrM4rVcIW5QJrh1tuJ4JpRaYy7OoLB/wVh4XVIg8yMghhwDM8XeVx0iHr+aYLpMq5YjZfjLHcZivnsYomi/mGD6hKvoP9PTQuEhYTOMSO4zvEPOiN490VGiHF6AZ89kc18dkjVlrdZl3W3QWo1BojvccZStUHJTfkxXVzyxavswca1Pjn3nGDZ39bovtexFt2lgECOmo2Bb3xV3+AMyUUGiL9zAnJ8S8QPNlFrJcJHmBtSkny/1XS1m+jG4BcaZfRUy/vebUO7+CvBaWEG5B5xcks+UqelS+4WSxavWYBIeZydqlqj3NCiauXbar1ruk3KTRUxuIwWIal2zNbOMPJIjIb6JbJA6TLK25rRNMQ3/GKNpPFoYSIQI/kP7j1rDGxxx3PvkTrdru+6oDHp+LUjDAMQ3nNH3gcQxfLQyLNmUSj4v9boGNEARhI6zNqTHCyJU5YJUgtMcFyM2oYHu4vs9o5cXrklRdJiwurbqtOrHr8VGdNm/dQGzdF5rj/Zolf9ToAuVkgz7GyhWZ4zxJo9vTNe4PcauLQweKLUz7KuXsefJh+S3HWX2dJuUdbxUzn5+xgdNomYuqoKHSJfW3BVjHOIyuS5kWzTQyH3YN6novitO4xB4jsGpwRTZuHxIbdZbWtwnncRiX2GC8zOtYkCvm89ZIwRkq1klZJkNiOR8J4LE5cL8exbaudmHdnMPTgyyu4evWcJAulaQ596giuAw4R119W7nmpECou47ImRyjEguHUvR4/IjWG845x3y2wtUu300APodwVGaOlQZ/c9i6bzZatpGsJjRwrGjZkqkleCnNnaepp7bGGFw0NFhtF+yRUDq+PdqAmKQvWsYKJx7yL9kHrAbPaNLoUQe5Mgt5TdP84T29hn6Zf8srXnTF4jn2DXIvGmZzzODoaxXzrjS2xMbHswLxsd/n280tqG+6m6K+Wge+IWuoe2SVp9FApEUeQ/dtTs3zuV5fo+LLzbcm+dEI1bjoGe/ZhZvQvozI3pR2ZEc1iumYshEDiDWHkvATp6Ex3uLi319u/pvMtm9n7r972Pfd2fJMtO6a5bGw3y2M1k1/v2fUpeGzjQF8sNkU+b3oZxi+W4yzQHgtW33JhGVuXGLhpt2sJBjHJbNzKc+ch2l+2z7a4MCXytoT8WTT3CUJNRtPFVtgEQuEh0DyWfO9Yr8vPkvK92JMlLW6/kSaumlUUNPD53mjvprRi4zDfrfAFlWC26L7Zo6lfWznvxDePlQRd1QiFFrj/ZzL0fZl28XdzPNDvoyuRDUpzzftSzh/KLSI5IrKdjRcFBfzffF5ZB4Acpg6Ze1p1xJRuYxLlludureS+HGy37duixLGFe5hJs9tH7+vE4mF3JRY2I0leb2I3zAPXy0cN82Vq5HPpvm0RNR2V+ckL9aRaBIIpfaYL6K0grE2JRYuv9U6yTpNNPb2jUqsDkXhg4lRgUUPu6QEPCFHBXMfSrxDKRLuDfQf7Q83+vuW0PlGX7jUIeXHCO8N4B0tV7TkPpR05WN+m2SgE1cstcPcZTKSIhcAtmatGlJ2+KxVklwkBkuVtOY0KxW9yiWyPvPZbuZFVMPXedcorI43UcbHCnQfbfBgdVII0azMZ6tjmArhb/dJFgNBzVyhRR+FWxdHljcuWrZ7w69r3VdrTG9BTG9tMP0z2RBHS5SKIY1ckYVVcJdnqDkc4IwCtsBCfqJHCBvzeQ4tv5RdT2XAN9S9lSQXs15WcxpdKeo2W71GT4XL9jE44MB4KLLFCYfL8GUWfrWH/COqKlSclkBEsVhqgfmuQEiFGyi3OhJERRKDmPkyC71d05vMl/m3iDM7xyW7Fmb8zI7jO0b/hKq73DNsc4zL5baWBsG26ijpXWPHe8bhufP0NiOJve5I0gb+zHBctD2cydp2nozJonLhS3X9qRyq4YzoAMvw9XWB7pvkHdyCOSrZNXW+EHN3J6J+fN1hcTxthqtOw81hIzC3I3EFNRVbF2YJWJFDkQXONuSirXskeu1gCAtdkFf6RqRANjHftxxRmi/PJwJzn7gk5C3CndvKn3XZJQOc17sfz898Gk9GIjmL74pszpsKPDJ6e5zeuAdDXCQw5q18S8rkOkWn2Sq5T1Z1lKac3gcBZr0OcEdzrEnkXiy18LXVaSpFLBQuea7XMRFaY3tNPI0Dipe+ztDVkRufMMR+gdHwFrWdult4NMAHtK54CHsjq4kxu6jXsIXFFDuZVxL0MIR972nIGUwfEMJpDPJGpEAOPsKDmDu6Gpcsb5xc/Ki5DpIPFvIRZfVNFJMMFQVe0SroAEQGY97K+4q/et58sYkXGJ6GH4cKDN8t+tPWgYwGvswm9vSPOinQl+oOFb0NxkWhQhDWLQzmBox/VG4hvzXWW1jwY2JoHKxWHDZelrXQNrPbJfXmZ3f4buF0aevwM8t+t4jWytJGPJm846O4LaDcRv4eu+tNEvwwhD01jh83SUGdYe+ipxKmDA9j3woNBqEYINmSQ1lYN1F5EWFjC8EsAxRbaNNRTeFQXyi16jUJ8Du4LRASbVOx1C6asK8oxqQCxTZy2T+BxwsmU2Cjv9pKR09xij6i7La64zUYBOHawhkqklyYRxmMQyvUwKBoBE0MQVjFx90lm+Mswvs/QSmOimxwypMx8GVWMSIJkeQo7Wo3RzZCzIgEarkIy9PyuBRoSz/ZOBP7ZJ08m3FFVjYZcTxn91hiceXm0JHHLgWycWPm8Y9/1BF13fB+zFGR9YEHrX9wHyVpdJ2kAno5lFtL8CBgCIt5SDIFdrHUYjeQPzRjb0MnhcMHoNxql5TcPFF/x0ledP07RHhvKuyU5IAWBxZR/IOmGCaZ74Urdnyh5X5b/iSPsPE2f71H3iZ1heCpTdb1Gp53GMK2hehR1wIPYUk3tGqrJvzSBBRbSR1Zdw7rp8O6qoSwAqHUGvP3pLxLk7JSoOdBLCjT6JoUYXY/w/sw0TMGQ1gcFuDdEK2axPxto1GJjf9RQGWN40u6AtAMX629oUfkhBbygzYFFmvQBsVJlAK9G5e4YeyP4y6TNXBYp4R0a7E9sNO2x8NZcFjrXjzOKlSUEKNBAFarHlE8IywIYh8loNUO2LA9FaDVTuwyQY0ccpqRK7Jaz1E5PHV/lK+vk4zub4FxaIGtxoJ1YvO618Fmkyb8XgEEMMf/HSW3d/wjCO03C+oA+zz7nd33ZMUjaT9Z0AsYzwfr8fRrhFq9KMAc2lIpFinQkpF9QcOoAt0626YcIIqxJveoeCKTKPjPuDJzrJ0d+TVLhJNsvszG8i9Ru5wBjgqx1AHzJxSVdYFI3yTYRxAOLRysxTAjodABL/mhxM0CWOCvs1WK6OGl6O0TCm3xnqGCXDmHnUQSEMc2CA3UTfQQzqPIG1cT1r/KkbBgWxPG0y/cXnE8HRaHQB551Wkieci/nvHubY/BsweuzMrDjjklxiQSgjS4IvueyhBD5fbYIfXDlz2fsMf2BLI8yutNnol3hqByq7B3EKsbtm4W6NE/Nf5l/DqGsIw4aM7YsLUARRywhVuj9QI9weXx/tbuPb5F4uVELMNXG+Mz7IWhw7zCm3UpVqDYxs2ZRIJrk36ycdc1cy2L7oPK92FyalxNYKzsVEwstcCc0CAkAeXw2aaXt+gi+ZP3rPZfHcMCy8v8Au9L4wrGr4O17/8X6DhEKLR0N59HmXAdb1SweIjrxI6v3QkA3EY3S3hn0m44bm6iOq2+Jejhk2AlCoVbY3C12tPztkiDxOW2iKzmNMZW29xhkkX82zNckc2JyRqJz4cMXy3UDsrJ+2uZYMuNCmwiXD4j7sy//WQVdVNEWZkIQWujgjkEb9nrVGHkZITL/XLV3FITMMtvSCNu565XdzZJ64pobuGGcO8xCD08fUos07BW17TM/eGGjRnIeZ0iWVZAA3CrMADY4zYqsNg7N/mDJOkWxFIbm7wNwYRRA8U2TriywjsFas2yL5aJQbhyOJfWzqRXIiAIpxaiJ8IgXUIaWSsclEtL3QSAezsFmNssga9ygwAWjt3HqoiIguL8usPn7VHJzJmqpy5mMLkoYWX1bfU94rp58QE9Ai+WckXWy3rzUCy4rndFz9hUaNVVc1JJjimDWJ4DOnfjU4Vj++3P9ugXxigU2kdYwLEVLkYMbKtszymjv/KYML9Aklao6IPsuDVULLVwPSYrdHlXr68zIa8tV2SOs030MMbWf1zIGfisnXjbotR7HmxYMrCO57CHUPlalNOsAEMHYJUtfydDemzTDUTIr88WOOCj5o4UaV9q44E7K1BzUiTeBRwVbRufBzrMH2NzOdPXYth+u0V2oOp2lHpanmCVWw/39Xm+Eoqfv6nN5rkIwrAsQnemVWPZfsZl+w/cYh2V7RnYiYHDca4nyy7Bq/7bkNBRTywVZJFFMph9dJEa1z4GaPdigPaxL/tt87jczUCjF2hvkpgGLjPemwCmGoza3Wgzxbf95hs8kkarCCeHGlhLhdq4GIQ7QnyZbTBiF0MhiUccFT9jo1E1WZ7PGigwu7xyYIVuGomC+2DG/wvcgnoOnDgFDwbjvh3a3OwaN7T6lyblD7CyYzzuyzhYeemZXnZevkVFEmVg/oog86XA7z6PVkgnWkE8M/X659CdJ9dviHxFzy1jyK7mGjgoy+Q2Q6veu8LftwPKrbbcO5Pp4rSE3s8evi6zNxtspf9cc7EIXJGFnpogKyTdsX2pqy83FAW1OKCsdCLI1qx+LOv4rXMsJocVTV19adtkLhf7doUIyrVGe++LVxv9563hb4mhNIlJF86O20WHWltJ6kSAys2xk7Q/+JOQI5n9bsPAXVp/noOH7w7L1VGeVUWeQmlaZDDPf8MbVuYCCNvsUhYio8NyS9V2KW4aZzaJ9m7C+YOpcAm6SfU43weJCobAdo2b6SWMiz/qqEDl+e01cEODLbTc5h+s/lWXlfiehVBosWmnm2sZYrF0njDK+UxGKg7QwjgqsDl7z35I3zAUCqe87rDU/a7+0RwfXdi/JmOv9+RVp9FxXXvv64R3qoxKLOIFyv7Vm68F52fgy+z7KaD0xAflduDLbPRnVqEmayCvO5kCq4spQH4Hl+QOx4+4/VKwUpjPNrpxnyhCLLfUNEzucB9V06Nx0DWKutu/MQYvIjtcPlZdO3e/ah7ufp/NCclCrIxFv/S/c9phcWBkedVp+PhjlN3W5EEl3kJivls4YcRgV+tAV3r7EbgQabXY1Cm3tjZflgmx3Pb8sU1gbvNCNPiwb19kgbN9ibateyQe0cEQFlvE4blbeSNSoOWDeMOHtz7vwPiFVgRiVhZZlB7U1R1utI2HOkcxpaXPKqHC7LBy2KGbZjXprAyZ9WGZTGUt3DRvP9ltFghVTleEJjcJ766Ayu2xt04PXSMAmHlbX8jEXuY/ECeG7HdLbAcxttlLGc5RqZVlfJ+sUCHLPQWVb420n+RFvT7LS8+j7h6Ngxwr6k4jtJf5Jol5FP3HpYRffOPD+hHfs4PVCi/K3FrIfN7fRbEVDcoWAWSD4nEVDknlaaSDtsij6D8uJh2EBJC3fFRgsUVpsjtzu5Puo4VR3mnPsRXef7U4D0jwTpg7CWg+2Wxuy4o0LG5uh+/22GQzCZXbY6dZ0EC8TcleZ9nprMhfWbnqqVlV1PsirzegnupLdiGYQKFY2rWH1yzd5yWUFBFN0HwaFewVliHP7K8QT2S2URUQwGyjeFzVoaTyNDpx+zTY8+buqbynC0lNG4bvIzDNdNrLiqTeNGJCG4PuQ40KLPGJARjM5+WORcPsvNr8460PQUjKJ5TaHHw1aa0lqIFiy3m5qKKqFvByRfb9hdGKpRYuxCaXOIxYKLTG2+Qol/onZUD2HHdUFwXK4ifg8UQQwqaFpt45Vso8ZrbEvs+X0WO7HkHuBTmUTaQfeAOT+WzL1/V1lVdReprFKe4YxN48hGMLx4+6FnoI+xYuSf3++QfVWGBIzxaVY4MhbVtsVYJibDyEYwuKsfAQji3guqLswRCO+gnr+YTYmFF6ghBIMgPwEG2DxDQAD9E2SGYDcAtPalOFs0yHr5b8AXOdC6fB2dC5ItveETGG+td8N8d2jm7qbIVW0N1rvswG60NUrM7yJKvK76hAeG75ABwJiMU6d4fiH3k9XG6Q7vPUkB4tipeWJSD2q7csnAsqtwjmublJ0gRI5jgqcLDINxKLfGMdvkT2BVjp4o0vVgdHmEUgE0MNadF/XAsIjO6/2mESTdDhqyUmYMxuI/wUlT/QSk1NGYxdn4/u79+KPW6+2mE6ftwkBQ16+ZRnfAIMEMAV/3+hCKAyX+7Gwe+SAsXVO3Sd8PFyMiAbF1Rf7SCmK8iHPAXcUTIon5YgDpJDObV0GGU/xK0WCOCMXxRWEMAN/+mRHDUpc8LavmYmxdyXO2E/vY549yhfaL8uUJukjdeEV4gxhIWk1dhmLJI/qZjS2xlRDCV0VMH5tyYyqRrSv8VzVArZGHSwNtpxQ9LgKOgJQ/i0AI1IDmUVCdFbeYoBKcBsgsyL+C4qkdQLCwLY7KsSOE58VGDv8Wt2XrC/ryuzx0o2XFikN3XVrNFKL51xJZsDnzCZkHfhWIbdRp2jdZRkQrZZCYh5Gx8icpOu3ax/zqs+meS4HQXY1hwHdRvuryXeO31Iysr/bRcApcsDL2Zopjk8CvuELdVx4OGE5VLhLH4LMdf75IbunwIyF4DShbnM0EzDXF3bPBb2u4UGLdHqe1LdgUwmFNrhBV4AZT7/BRg3DK968Odsl35bc4zhFuBhNjmUPfdDZ3B8mcXuAPDW2ntpT8uuBzQJZARkFQEA7MeON6YbaK8EldtYPnGyIVfyRZuSK3LACdxY4sss7GKUEatfNH2Z77bYgA6OCiw8hKgshYcE+o823DSQnRp/UMo1AeAZa9VeYwQIP3K8hK6oO2EYEmlQEjo0FM1vT54FzPQQLpcCyYJKkyeAJ8NiqQNm8NxXLLWhpKy/rn2V99O1j+CBs8OxcrcHapZXcNASENc2QDJIQCxMBu0xqe/x6BS5nLu0R0BGAK7IZqHqqkrNHgDAJlI2RtmQVEpMWSYUW/Qd68/vQEZ39rtFCCR9eZisMlzwI/PdWr8ekRuvkIZtCrZrecaGiOcOvUfjujzDdadcnv2XUtrncVB+bq1WadBh3h0EgZH0bPEzthRZD20Yv5GI0cVtZIRlGk4NG+vdDIHTSu03WyyHuCQT0l+Ni+z8TtBunv0+/15u5ySInCI1qY18pKbD4vLIlrTqdmvyyyKKf+CBQYeWfJkFVhKGCNkpowLLk0UEH4HyZVbnhPSJFhCtUPgXkB5/ZwWLyUOK5nRZ9G0C5+DddwcHCCyb1v7jnclSfI6qusjIowrIN+nOCJWT2aKsPxEbBbrkFpqBwhpS4fxe5ygq8+wkL5rZ4n3tXKENXjrtiO7deReHUOiMVx7JoQS0nzc4naNYasOp0c1Ns/HlmHX4buH1Wa2TDAzxG5fYUJoRX/jqoARkN0N7Flv0c/rnEVa+IRb+MTanxV+HYrs191lUtKaLeNOVLbH1z0EYxyU2xs5AY+hIGipfbNO+5e8MdqPCLIwK8giFkBQbhlhitd3rO+BqlpfCE9A5aDwDHNOoPPIv57+N7KIQtvmVNuoRiK5T1KoKGLccyqbfl9Hj8SMSyDAqsDq0PMKyc5sXT0I+wHGRg+rb0jfr5LS1fbB2WxRLgJfLYJwhVMysr5UJrQuWAQQwpx7bvwLmJ72LeZviuiAXKNvrBqFOzSCsbidnhpimkTu+eXH/LJbvA/ytuS4stwVgs9n0+lOcoo8ouxVuZ7MFlvjOUJHkQrgMV2R5BkVr8ylB2AIrt1ngx1/sLRzFSVaQG2+nWVIlUQoKOF/2jOWcTgAu+Jjf+ok4g8hBupW1pxFspklwnyAWL+Udgm+V23ubd5k5CeZgDEoznngxKYxhIqctvRncPoXEqeNx0Zy7ieOMOBS4/vQft4aFvPWamz6bUY/hpj6ie5QKwbfMdyuveVGBsVXjEnOM5BU7EOGowGLh3sBPpGxcnkgJ68XHIxEeyO0/2mxpblBRoELANSrYTY+4lEsKcsKZxdwBAPPZZr2kr/1+iEreZGcLtkZF0UTjbG6OAEnPWXSuuc/VOCZa65g2xXtVYulSoh7qhZ1g71jtmml3VtDbJq3+9+P4MS4Hdtch2O7D+JMiX8u4my+z4UwZznGJlWwHea8pwCtr5TmKgPO3yPJErHU7HD41aamEq1V8sRPu/iaxFD0D8Yw1Rp+303Mb2KFx2QDK607ko4DT6jul0w/lOIMceVt3UHkR36FVnaLLqPzhGe3FYHKJ9FJWn4Zr/Df3B5jLhVe16ScbBZNnx48bwqhimmKuzEL5CylsbdPX2jouFMv35kt2XBS84h8VWMwaXsTOa1Eds98tvAIRjRYtKgHfuMQO43G2AvF13y37V9PXeuEeMmWWfRRnhPlsswR/SFYr/pXh4atVdN8tYfUzVMTAwTtXaI8X9K4IhRb+h/zhGypEqWW/b42mP4jTEA+b92ic/MLSutMo+KZtHsfw1RaTuGCw3+332Od5Ks3m3pXZCOLpKhVODptvW8OGX4sgbNijcWBDRd2/FhtepDWXF7T5ssRxtexxA/WjBkslx0MZKpI4UNgwj80lWZ4WxbZz9n+gp+YNyRGm4asVJgGJTX0g5aN1ukdbl9VCfHx5h9boW1QkxKj3Y+IRKgcO1tSfhn1po9wuqfk05ybyL8Rw7VugXn4G8tPFwQDX21bPgnCmaXmWeVGm4Aae/W6BjQQVime2zGdzXB/E57k/WL/Nnd/mZ0lMHgQAjvPZoiWvK3yo1ulhvhLWR/a79Wltl4TiM6oe8uIHeHArwFgFv2OBe6LS0j03KV63g2GsWzl+jO+wfYdoon91YzLQrVFtbad84827sbnc65BW3VYlp3pD1e3tVDG/o0NyRyLsH3NcKLwGNCqy3e+f5MU6qqqEf4xBLLVQhJ5PcEsFtL5Ok/KOXz2Yz0sq1l0I1HmXk2c1jrMVnlFuXriirVFhlE3aTwGMtBbM1VaTVt/2rWxgJ81uWPaHUfzjNMP9in+EC9GSIHXgKGNM0zBXsHwSAfMfBI6937UwiU9RVt9EdJ9QXKI1Xod8/XgQRgdWNUOzrSbdt4S898TfARu+zmE2LLUDaO/ih+EmHpvLhkCLYs9FW8dFrS4Pw0QcMqeQTw2GPQttHQudIzJVq3bqfG8ks7ic7iOrEUzDP71F9EZiKb1xwvZWgs3qPeud46ejIi/LC5SmQTiKx+aysGlRPF+uWmpZarIJNG+wei5KLCqXJUldf6KpZxuVPVwrBbK7BSh9jkUo3Br2+EeNarSiD40dVFUU3/nnwgBROrCLIZ5p2IZpnEfEFdk5E6JbRNzQIosIhTYszltLtpbSSSLGs3XfLNZH4fEZ22dn/K3HT8kaiSHUw9dtFLxg4uYnZPMtxkleJHwmzOGr3cUw8TqYLQaR6YavNtfJ+EtkdrXFXnTfLA7R0CZ94jvSf7TGI3ZpVGDhYzziPItHNrUPY84xST/Mfy2PnPxzHaFfljz+usAyfUlzpXHxHf1nO1xA15jPFkcpdNWOwZfI+TKrHq6IlzVK0yehk0zJ1ih5dqh+Wp7F5KDm1dUnOpgTn7W1ftC23ViLmmhUYBfDJIYwWa1eecFfcKFfLI6sS1RkwoCGrzaGX1mKOXOGr7Z3xi5Kfr6Gz1bje4duojqtsFZbYW5MorQUBguBbI3cHkXrTZTcep6CdlicTgBkVbfVbfucV1nfYJ2lTkqbm3GBDknHyFzOR3UYtpW1sb3ZrJ/NrXSeAYDiXRSbcFeCpjH+poqYczcqZRgHb9UbyLECFLvgfqvG/dYH989q3D/LcS+k6j6jh/IjqipUhAtignE6KD5TRBPpP7B1MfeUCm5eo98uAceMm+3diOj7hKKyLlCTl9530WdQOS35yvrbuuBPkZD0nLj1hQj3xMovt3MH0O38v0twk6W3QuaxuTOkAsWeJ585T56uN3lB3jW6SXzvzo5QOXCjpv62suJJnuIpFfGw3+3OHqH85Ox32xh+CN+4xNY1FiCd0o+EuyTffLE4JIp+8EdE9IvtbZkvGb/TYb+bY8Ma5yRB6Yr8xe3HuCJ7bjjKs5vkti6Ak3IJiM2FTIKsu6bC3cMcFdkcmZV1Wp1mN8Lp2/DdgleapGq4DyStmmByCqVbo1wvnrI4zEWkAZHLPSRV7YlOO4JdQ7rI6yJGQjYM5vNSV5roLeXHSkQ3KrAdqZjGmv1uey/mVHhHYvhsi+uiKiSXPrsSW4yHeZ5C+JrvNtZgFoN721HB1qiF40di6LxDmzQP8NgSj83lPFSLYhot0dp6wD2wG2t3nb8hF8q0OS3p/WKOFYevtk6bf/KWEvPZYmfSzy5kDoqlu32C65t35ENVbS6LKCvXCc1ZCtFMBuPXir4NWwOy2RCLYZF8me2RBnz+4374Q2uCJ0DjkqWPXgg/Jvfok5DtYVRgJT9CqEH3bcvWrCB+ghEq59Vq7yeg5MWiW2FFK0r2qNDWsSb20u0aAP7zPsGjk940AMptFtpWfbWswK23XOECPg7vfati9vHECtY489lqjoheFRwL7Hf7GW/cEWIMPFS+lF/hy81NibilpvtmeRIPnL9bxStEVXx3kfzJ8TDz2WIGsDjRJHFjuvdfl14+j/L1hr5CoLIipEAOxvNBEd8JJ6hiqQXmFEUZn+Oz/zj/kn1QlnmcUMefeOENFa3p2CQLvmITM2N6Ku63aWoK99k4eBYcsBdWItsqmrtqnCCAtWC01gvIIZYlZO575d3hy6i4RdBm3KjDLC7Lzv72GuQHc5a5uEvon839vyusW6siIe+uHxFhb+LoFa5Kg9qCg3JUpwEU8r8BU6Bvy5NvuAYCcI1Blz05p6He3EzTMewVo6tV6QFFaDEPYAPTvfOop62I1XP6e4QBJh7onN9Et3gWm+jDJCXGa/8Mp8Fs81VkU24z12OcnjTlkIWcdg61H2Nadwyb26uEzOeL0/Jznaa/v7yJ0pI3N3Wj92aed0lJLcarg80mTUiEapvcR7OoqOvxbNRBd4mDDNhJ1YDnXPWoA3CTspue60ZLrLn1iTiksy49hxVDDLVk7HAGZ9kwInOHfat5oe+kHye0aOZmhK7Z9v/L6Fa9PYHAJWmfBhiTjYiI2Hf34URQ484FmW2MaTFLwnhLKqshsyMst6Aw+m20IZ/LVvMcPUTF6ixPsqr8kOB+4PXna4lW35Pqro2UVOX00lYWs3gJVQz4QtuQ5wyMcQXgE32Ht9H81JEhnMLpNuE2exehTojNC4fUk494bCE1Do97GxlIP349C3W+VhLDFSUZKniQ3pnbfun/LrsPbe4icgyclkM9ct6zjihByk0UU1fNCp0kRVkRTruOStSAvHzRHZJ0x26tZ+2P9Cht3n3uAD5FWXKDyuoy/4Gy31++/enN25cv6NOt5L5eevPyxeM6zcpfYzqNUZblFR367y/vqmrz6+vXJW2xfLVO4iIv85vqVZyvX0er/DXG9fPrN29eo9X6NV+9RWuE5ad/77CU5WqUVYc5NO5CevNNEo956rf/QAIzdExyjm5eyPjpt9d8xd8AniRt//4yISSl4kwfIKN5HpuTUwKFaC9fviBsR44Ae9Z7rUTPHmk2zWT3URHfRcV/W0eP/53FVxXiK0lCb7M4rVfoNLtIMNpo0yG9JgdNll07LbuQGlxQoZi+CO2ObojPCTDOy6RKw1CsufEbANEnVEXtdZIyGMJR/rtAOMPRTrhA7M4d5yjDiuqg/J6syNLmganB8M88CzPGBt33Itq0zw1J+maO6+IufxjNgfsoD3NiBHnKZZ9DjFFzljjocMi+2Z7i7KmmWutHj7Cnbmd1P6T1X774FD1+RNltdff7y7/99JM10vEFMtMpNZ4FbA1VwgWB5zsDbx1moH3OUCMJZtZBd086+DzSZ52SP1FvSj+TGR3ujjCN8Ibpr6d4sXn8/eX/Qyv9+uL0P68EelyR2JK8zlb/9oLK0q8v3rz4f627wz7oG7xDf3PpEH3Oa3hpluf9MD37mfTMU5H1PZ2qk2+DddJZ4s3FteWjZyKlWr37xmUuWhod1Sl5Tkaj163Rf82SP2p0gfLmlT4Vclu78CSNbk/XuOtdRK4S/S8/2eI/r1IfCzGgmc88qeeOZGITp5Hp5rLaOSoBD9bOyp3HctTX7PXnTw7LT0fPSQyvDnlAA+y0JGmNz9L6Nsk8Nn6n5WVex3K299gW8fGFz4RTjTxinh62McP98os16n4/6ofYeK7lB5XPap695+WkQKjz8vssNJfR4/EjWm+8/FEYSbtgNbfywPXKRIl02bx8PLqNMFD+8cDjJlI+Si5P02fC8IsvwaE1a59CKYCzNYh5SPyrX7IPObnYduvF5wdpmj+8r1FZ4fX7W155IXOzWiGfUFSQo0BEsxU0eEgimioh82pH7+NsFQiT8x7BSgccZOUDf3S+s5qADMheCzS1tkQDfK7X16j4ckNko/Rh6om3dH2kV3uE8zwYiH272I6JhppejHS6GYXGmG3lzPZLB5tNkd/7LQTjlKVy/Wbm/qHZvpyQWbPpM+PPJh1u01BNvWgJRXmTEGG3nYc+YYjSRWbNcm3C3bBIZTEPofCe5MU6qmwOiOS4LqK0Ct3Pg9U6yY7y9Zo5N/eLbymD7MkObm6SNMFc7kc6/x3ZO0SvL49QyPW3g4Zud3zdKzYTbfqUXfZjoY9RWZmtM2/skQddIUhPP+a3SRbKpMb4KIdh3WuA0qiPwN0tO8tBQCAzIExGCEVi2nVHxGDeH+NlGbxaurOrMg0lNdoCmDJpMGTgGuyEiRz2RlmYwL72qrSDld1V9JIRjB7RQN4sdnAacdV9enLEBIl5EbSVpzchkb0NguyfyeYsL6sohc543Txad3mGmm1yEHwn0WNAbB7rn/mmBsrTsLPac5LIBepnLNul1dthWQY5+njIm3dNTssJAh4u7wqEzPH/bIsfiwgqkpjD7eRtbdIJXubfIi/recHAhyWcteP8JX8V2XeK1w0c4R+KR05vM0y9ozty1WwSDmENk2fCINNZiguuTdfXBbpPIohBfbffuxANdpjmt8QmfCYsuvjxs9ntIzNnhsnVLXO7qfVTesU3dscWLa4j1unmooU/51VolEPGDM+VZjsPolXX8FSL9dbdyPPtbMCo3Tm2iWdQ2p2dVbPtaEgLvqczBe4CvaxB7zIQrH4YvyVlgqGxgk/uk1X7Tqs7b0xiFF/c0YcmwkraCYYOjTP4AVfHOO17z35THS4SqsMRanex19Ijy6OL68WGNnoIYoCQJwmz24t6Hcj6CIKvQ3aJrcyUG6xn/0Kh7P09B/G23Jm5+FEHF5Eoq2+imFyTKvAKU8EuZd9W3leJesvogPO0fJ/cVEdR4bVn7HD4r8/n6I86KdCX6g4VZ6OMhK55ECi+YanXnnnbq5yabPWqJCZL/8FqxTXp1f3T8l3+kKV55Lelb3H4Tc3XLG2EsEPnNbJP3cHLlxsBn1PEY4vk+HGTNK8xvoueZBiNHH8tQhoyQBH6c/eHqLyISIr9ELM6xuRwlMnV9znLxAMjgWQHtwVCrO3mMq4Rokv0GCrS6RzFdVF4nuP0SI6e4hQ1asNP37H4zlCR5J5i2mOkSzhF6yVYp/T8q3+HxUeXhbpHhJUszUoWpR22xq/e76VRnKyjlCTswr9Kmnnrzd/xrpRcRMXLpEPXg4TJnZbHpRcJmZwtfkyCDRbieszusYhhZM2xkufmqMrjH/+oo3aD76HJmz0RxXdwHyW4bpIyOD2c2mAfnVavJAs23o/5QzPWNjbNbxqwDZ/cPNF99EledP07RHhb5IP2MIp/0ORIJL+eZ5Qn2aIRfKcNDfEWod9cepkUdPnCM5Os63WIiWnwRY+h8NGBo1WLKkHhTVHM5gT4sH46rKsql12xNhUZAv09Ke/SpKz8EbaynCLMl1gxj3weTl5UbG9TVEns5YsZIQi+dHxJV9M20G4zjsiZ2lRtXGwwnih1HojR8QfTRn8UcpmsQxxisLjbo5FAmDtX03FWoaL05sVWe42wookZqNVws7aJ9wuXCWpk10vn48UTldVBVRXJdV2ho3x9nWR0xzMps+L+dw8BlO1DAD6j+I6S27vpxHe8TQmO/nuymhD7h2lp069KoXVOjziswgl1YhAmVmTi6zbbcuMQHHlyj4onMqv2rpdxbR/HS2eXfs0S/hzToB/j2j79OIxK1C6v3o6CHtcnFJV1gUjvlKayfQavvomDNRv/EXqZ6JshP8ZNOXgkD+tslaImNyzgFvM9CmjQn6HitELrEG6aEUJChpD4Lu7yxvODtfYE4ZTd6v5M4ie0UQUu+cE6Gvn7xb+WZFpjPDjPc/X+0SkBW3DDoWvKXYPscHqS9oyrPMrrTZ6xlwKcdvICllARsd0k0eNjugr6MeqAhyzdFn518+s9+5zcWqQk8sgWsRG3BI5yOcwrbIEFj5EiD42EFpSO7cIESu3DkUbhhmHObM4SGmDikOKoq+hj4JNotYvkT+QzglFwVnmZX+DtY1zxmN0eQ2lwfBmfIoTKn0Nt+PMou9X47B04JGBMYVif1BZGbu2EzyKUg2abfR83UZ1W3xL08MntXrd5FHujup6JMdSO5jDJoiHJLabaNf3gtnLhCSR4NGrJXvpRTpKnZzor62eXkMPP6MFHgk/LyyLKyoSPMzJYCns5uGKQeL1IoZYs7y7pr4TZ3gh5ZiIFXuEwMYq6il6376azybbhrmZnTrS7/fXzSfXYjczBdd/X9J05nrTndYoCP194sUGTO6jaNBvwXW3bVacL5wuB7ByVFbbbqe3JZnqXYjVzfHVIz6QR5U5TxSCOngg7NDF5oZF3FJZslDyxt0a+F4WPH6siIi+vTmlXsgdwz0SlaR1iv9hbgUd5mhcf0CP4Aogv8nbxap6HCXy+N/HC2Mp+cyBFTqOeCQ8tbE21B3yuneCqe3UlUCBzPOXpsvywa46Lx4bOrQnuHScpZvM+5MvLo/QhWaHLu3p9nTGZEl0QtbfAl/duPTPvk7tK7hmk4ZdnoqGH8bnqx6aul3LsSet5EaBDQ80LP1ynJVaqzXmCjQDZstczO51deL2XnIuZJPjqa/o9uFCeYDVXD5d151e9thzIXjXfc2EILmQpat+Hce2/DDc+QzacJFQleKQCQ/d9rEbYWI19fIW2d7sXX7EPP/hrbQDpVb+bJKaE7HcYz2SJWthSgmnb6ASH/CNKbH4bVKIIm32/552DJjyrOzr3j06f0iZTEfSZCAA8xFC8tzXvQC7CKM+ERXZmFlqlchndPmPKW26gbIn3LSqSKAPvfz8Tok6QrXCKPILzZECc9E6/+y15E+zOl+SN0hE435F/tpdlD8oyuc2wBHab8wmy7ezvgHP+S/8HPBfe4Qynyv+5DvNyXrA0YXRP86WuvtxQlHSQUzwkw/LDM1lDpwiNUrg1w8QubVFcFCTq7SWQ6Y5aedPumfCir4Lr/u/pcvUpohGdgwa8YmfZ63ID35Zzr0NtsUneC/yJycPpnRS2Sdbss2Yxu4+sKvKUYPI7k5GK6Qx88jb4jZPnJsKTXMAO6LbwOnDzVdNNqPDzmGjJEJ21IEgrWWFIPb4cx5o9CJ3mxcUfdVSg8vz2OnQ/m63r6l94mtjU5OHT4NFN+AwNOca6TbLMBGFp/ZIj9p025L/SfkyyH4EegrLf5JlfV+meC3geerUbzvs66Ruqs+SPGiUU5U1C+DHkqfjXsn/o4GvhFegNoPF7X7bFF/JSOLFDUZOXK1TEPXgT3AnZ8SPuWxkqGmh/mXyZy+R99t5nopKWjqxQXps0C9iRX3E1Cage1Q7hjfYZS8jk08YsjRVJ+Yzu8j2nl4npPbIwqEjuuDCYgoQDbmd6x7/S+83b8a4vcKL+14zLNlbXxI4ssig9qKs7oiKbaKZzFGOCPRMV3i3K7su5pwo/XjPXYr2tfjJbp8wGLyDa1q0QGPsXwluX+Q8URkIouoM4RmUZDin+8x7vmguvzDHGQneSF/X6jDw18zwk7DLfJLG9eLXV/C4/Li3cRk8rmu2hzw5WK7x2hs9Ku2uXEKh8UO54JgJCB2TPom21HRcQMo/+LuY2karaLHKIQPncaGKvxz2/+b7v/TEqK9ILTy98i0Uy5Y7YaHInz53Qbmqg56R83hd5vXHUQG3d4Lc6/J/OCLz5+tyuOl6yHEKhENmDjKq9WpkkDm831RMVy2eio3ZCPTw3dgvoxTPm3IZ4z4Np6VjgKzpung2CT32av9yB2GL7hzYzbrs3dsjXxdX3O2FsE78690ZA4HNISGte4LZqvieOwwqBq028GxBVk8M3cFLnjjuP6qJAWfwEvZvliLhBeI6VjOHh69+dpfIyemxXJf8d9rdIct/QXZnhTXuFZSE9zeIUd3WyWL5RY8eP8zR2SRrrE5nPNMJRo/OMtNUN84ywbWzWkeGGLITVvrGRGsOKPyFrQ5SeIDQ1TeUtT01gectTU7vFHyYpO+WTyRnRJ8WxeStUdUzWBLbUa2ztrCZ+J+EcPUTF6izHC1z5HRUIs5Zf6MjRHYp/5PUQXh161yg0EOxSbGcESGKUbINMbm6SNPFOhNdb/ZsgY6QxNGQbQ96zKBDWI0d4/sd2itO0YyykdpiJIF0KZpgK4/NMdVj+QCsZ6bx7enR//zYYsuPHTVLQndOnPBvyPATE+18oCjN2li/fJVi5Ve/Q9fDAuts9kh7NQUzXgw95ugo0VyLygIzAID+Msh/BtlIc3mAixuI9PQqNsn12JzTa0+so0ILUamhqFLTxf2FkosbGXpH82bzsTOLmo3ic1G4S9MHYTdbAOSqZO/qe2mhD8qiEJ46IOGCv8b6zt4nCd/2sJnVLFNqdehYloSJ5u51is50JQ9MWJdmrYCHc1I3LcBJf19TZUrf3QIPdLpyjdZRkTCZLh3xIHyJyU6rd3H7Oqz7/3wRHJd2u8GuJbfsPCZ6uZ/NiwuIPB9Kq9q231fwCstyFxZh13ic31Nh/hqzTDc1+8oaaXvP3tUSr70l158hCXHXvrowelQvubpmTWZ8Jg3bmDDPLTu8MyfD4HBh2pPY/LJrYzXdadl2lyfAizxQNHTK8NdsE3DCc48FuyN3gYJZajzHcnZELlBG7OlQPG3ThuvcJlSWTENw7EVU3I9Q283QNz6D8esF+JtqvH0/QOJYFzbWzZa+0h7gHTnJQ0rvgUx839g1Nfro4x2hmGcnUp6HdfqlZr6cm2bi1qWk32ZFd+KO6Lj+N9z3r07JDFcQw+ohZPBuy+ng9OU60/vdpU2jTpzcdXzWXqvYjchEzDI/aLfvYRnkuiV8WXKApFXXsYJPI7TLvTki23XhkvZvPy8uzeNRxQ1Sv4FWK4TBKo2zIwuNkvpWTR9WE3ISFPQxg/R9Xnt62KxvnifkzQHfJhh6hPg/JW1CTXxZR/CPJbgOeAdKYt2mNEnqQh0KdNHbvWQRCN8cq1AnAM/Ji9ENyut/R1AxwPiX6jSf3HljYHlVdZCTxO3o2eUwCXJcKNHGL2z8h/E7nKCrz7CQvGl4JY6S3HIfo/tdgv++C1DQEweqeEZcHzvM5nOjmhmx8wqA7WK2TTBIJxucds84+M1IUIW6FbUu0icUCmdNQn6OoeFaLpL+2PIuK1nDw8jw1fiG3Y1a2rs/RKjvJ/seri+v/hY89prssgaUTFSRXfbjcuNOsnjun5oSLLs9Ez0FH55YPsgIb0218goluZQl8K8QhcJ6Wl9Hj8SNiRuqCBiM5wtN5mxdPnoEr8z0zZU0p24cf3UXzOb0vJAzOYdEUUUyb7cpFZexf4AkrgRaujrguyEWvNu77eR218KOzlx4RQ/DY7K08fPvf7V1bb9y4kv4rg3lcLE42szjAYpGzgO04EwPJxGM7Gey+CEo33RailnoldRIfYP/7UtSNl+JVpG7Jy0zcLBarip94LVaxWm8EDlfPuxSxSbydeqBmc4uKJJc7FZhN/PUJPuE26jbONENAoJkaPOgX3uTYipElVRKnjjc2bO3FP2kgFsc/vcsPG/nSKI2ARahBDwoM1h0o2PQp6hIhWf+6EVg2bw/bnBnKRexLh0WsdmXsEujxOquJLcZS4y7ezmiDNXmHvqJ0bKC4vKhMvUWMONaZhLy+ATiZRNH/zSGKfsDx0ew58wH5SpeIkYqKAhW++M1yVmmUc7Go752y3biT2CYR5Nu4FEKScJt6Ty5FJLwv/eh+I2MQrZLX9yGzr12gBA/WG53R8b6nWPTcFsTrvBuyNwLM8VeZb4r86A5DtvbIfBvuYtB1x8XJDZStw2O2nfIOxSNvNto9/OVzEznGE7P+DePS3c/7iHEbGQWcgzr7iS3t4UQo2AXS/e4J7c8peojLLxvpbe1O9O8OO9EL/D2odx5/d8nflWfX3081xACPN35Lbs2enF0ITE1mixof/8e0/x+edu8Grf+Bp4K7cxa11UdlDMfYOn3Iroti3CDeiuSadlymkcNmsc6yQo68XWXpGZB/XWejpcEs/Mvy0tEyZ5I+0sP+kghEw8bbV3lTvk32e2QRWAq6Mc4P9ahxi4odtZ5w8LDrOElOakZre5d/+4QKengr8m9fu18kQ38TNq0eOXyd56abSnzbKDhuW9PwCOLP0G017vLUxWWDqT1q4XWDV25piFXTx+InoCYE1H16Pnhn6uOu1yVAt3n4rLp/k93WvC59YA2r0CRJ8w0KzNg7TyaQ27izDevjLGOwPTyhI/oUF0nNaiNIIzrZdKdRKknLAc6EJ4gQ/lrLmms4sBDOGwFJkAkLuH4bPwmWqfV1OMCldm6DrhvHYvgtnRrV2/bhXX7Ib5NdHQF7Gb7cb6tjepnvqflr3P1qcwPZPQ7/A1Xf8uKL7765LZJjXDyTT6fLYubyAAjiMvIxEmF5/R1rmR0QCZk9Vj6YmYWY5s73LfcfZSR0uNZRJeFjedu7N4dMw9cOF+/ymoGFUcz9Td7kxRF3GRW13BN751SvwOd5/pwm5dMcPvxeL76ACdpnLPrXeR1//jrb484cOwXarcHex+Rp6kYGoKWfQgRbT1/Guy83Gea/+7JF5yAPz8nnfbQ8uxfSFJf+7+Ps/BiTpXbxgI54zN7MkVOQ4eBTUucLEZOZjWYc+NFb99r2Zx9vt4/bYe9nF2+3i+9QSqza9PRGerifrl96WS38NoZL6GG4yMvyHqXpzx7004PmgyOdwXorZqd1kieZU8b8Mn7Vo4jKbhlUzLjP/jyjM9qT5CQXVRXvnjb0MJvSzX6DwVQe59mN1YoPqD7yonvWLfqXZj51uQp4k7h4kzS1xvi40VHpsS6fkywunp0O+7VfpMsTyfd4Cwg7eloxdvkSN/L93RZJXoyM6VU/8/Duc1wzNTiUt/cLzr2L+pCHEPQOndJnO2kt2IaQ+EpIOj2W4+Vu55ulyRselxG6vhf1cyvq86j/Hg8LD0UyMsoIZuLl3WqzhNk5Jklla4+b7lG2r4/84jTtO82jhyQt6UbmCTA1HjvN/t3+GrPdZurXBixvU5cM7/Le5oXM39zs5q3EvWCprOGisyy1kS1cGDdeN/dlav6ZgGq/Ro/xOa3w4EYQiGsF+O6u4uMpTg5buTuCPgtH10l40nNjZjTTTX+r7Xz1b35J1DwT+dEOll02Znjh1kyCzRtSMaL72Lgli1/G+fCwV6yXpvo4fK2dRD7DUdZL4HTDztgDr9888vp3S17GA8kf6Fv5DtUf7gY9HmDlvAZGkSxGjR6jfitTQbhmaxG1vhrsO8yR66fxg4Df/SDgjuLbbL/5czJ9j+LyXKA21dVGvg/dfOsSgC5seLu7Gheh3U1D3TW2GHqNP5es3NAw+xNGk8Lo5njCm3/c5mOymTdiQTD0Jk/rLMBBWGPT1yx9eMn64DP+QdKX5DRGhIf4CxpTv/EE/5CNW8ljFL9JULqv//L/Cqrr9Ks8e0wO5yKGrt4d3x+l52PWuZH74HiHynNa3WSPwrWNW0K0Jj4Rlq6OUGS/bOPrh3gHdP+c7X4AT3wTaw+WiC6fGy6Dxf/1l5vyI9n4/OcvD7jvXW4t8nOxQ+ArbWvxGl5q8egP1+H5k+o1wlhzvhTlNVUVqDp6YiIvGb9XYXT9zV1XoOr4NSJpYnTYWMCIxE43oyL6NDzuq8LXiN4wvMxz2QWI0TiO+yjwA4br7/Xy9DU6pfmW8na0622nty+PSu+n+RbIHtaNNyV5nbgbw6M5V/qfYQHqlu+jA9z49bTR5ajLA3CTu1EHvgZxBOwDCVTV6aGIs/KYkLCI460KcRzl7IW/quaYwPbhgLmHiNGlkYt5CXujKL6uovu4rKkBm3xF76ln44637lb39pZzzc+jkLmPQup/tZr7BrO5F731aFzkXxNslZB++jdlO0K1EB1zBevhkGe+XTyIG4wXX6tj/Gc9lPo6kOmw0Rz10L7nSzqV+fD4WKJRbmDkNn4Mg8u42j3dJ/8cNZPf4o+QxLJahIdCHfaURAq3WwK4edfiVe8FZjf2ZjZFcXa2WD+bv9JCRbtcayJt0mFBXSZcnl8kzsBgPbpdoI5+1gYbttzJiSy8xDPodbITh6se5Ei1TliNh+jmQdtV/W255WVlGRl3etOgU38DLVpOdjyDkcn3BlUsu7mvGSZ4VgOiLqmXQ992LEx7tW3KqVeZttw+l7E9SYtvJ8FQM0RPvk5KMvl1gSVcurLjYfyBtm059SXTmJ0lqarjvkpafks4DVVD9uat+7N0285sm1prX9LiW5/QtjVD9GTLvf3fQ+x0OSnvGxU5bsxtrTStKaUCdPI7ydBUDjlnjl0L206co9fAC5g9l7/mvc3T9FNeR4ScNbeASYbxkR8ZVvQiK7+5BFSj64bohNrNt8tXvVX7t/o9JJUY29TRi6hhaJLDzyhQAu6EmwrxeTcNvbSbmiHAcZnmhx8FHL76srbZbV46PHYeagZcHd2hrwn69halp8dzmjluRFfRsYzCzoubrvooUf6Ky9biIQ4OaUG33ptzRUT1N3c0/eRtuKkd7IebHSdvgQaZ/43KB2zF1AOrP3JLTjKsX5RlvktIz3bXKCRAeePsdYdK4pcWdVmJOPBfZ/tf6uXrkLaok+gepY9/G358f06r5JQmOyzCP359+Sv/yXzImoymv1yQe6/6NKPcxXvRHFiNvVQGQHJWHpCAle1fhCbxZ4yK5nn9VZ6VVRFjc4vffJLtklOc8vbgCA2Hh1rTniVf8hqdUFZfyav0NmmXzjUltt83w/WAzh6vXlCgMsBa8k8Sc5LItiKg0WKLKGNLtwExRqdV4Eu45aL33GV0D3wqVDfztZleFgsngZ7yDlMlH0sYBJCCSSYApvmdrqR9s0vcBYD1IS4OiN8kDsCQAkHV8T8gSK0BMjdANSelU4EzT9N1TM61pCzIyA+rn4KJGuuYdfsD1UgU2ranAqKkkVGQoPs5zBxp2ose0NIqYjQLYvLZ8MJ5p+AtDN7K7CrUOukk+pUay4HpUb5oEnTBvkZysXqKIJjjTDAB+gx8rSQNmzhXLQSTugUZ0OuSfv4hUGiDgtngJ/fSmwp3VVwh4rGd7VAEeykuCmO0vCy22JLVY4pRxwJLs0Gpc9HzCKJ/+9vfXgo9N3DqHC9pTv1vawcA6FW68K5XgHb8N7w4MNh/ohNCghFuNmD0rk/9UxDd0rqrAZ4pTTTJ8I7dkCiBx5lO4QlQpXRjlzSpdr+bCVmaBbLFALFZXNn08Qywkj9vmBpVl0lav9WEn3Y4YUozfVmNe+tFg1FbrPHnRwMJDJRVEazEQievVmhQlL5sM5NXp5HN5DUbrjq3wHVccHTSMjIMP67+oqNXxaSt+S872icxCUlzHbX/l995tOXMpUP32zQ3H4zArCBcUZgbEMhCYZDE6WPSYku7GDiBT+aEzoR68UeBE2Sh5cBp8KmdZ8XUvez0OC7pFs7dm11modP/uPYxBX6SLOv+mUeT/j3qxQmbvM5U0opvcKfa1WX6cfhxksFFeAcOyRIYW73KE4BL/e5d0qb6bfTsMNNdk9oMFxuGmVWXzwEzRXyE2WDWTq+rGsugJZtQtpmRzGZ5tsSBrEeYZhibfyE+P74mXIq7wEsZd2JSdHX/uEP/e04KVD+OlR9pL2nsogQGxWHKNzOG0VrZjGNzHyJEuOeTr6h4fqhDokv7liZiOpUpsNoDWoyGvnAhVTUMNqzmNUq2uTFxec72KarjGVxUVZF8PleoCV4aDSW6SY6iBDqYLp3yBEqqmVpIgTjk1CizcVCMynU1kWGovRzotlhdzeGo6wezvnWZG86Z7lwQzLwCTDtb/kSJutGF4KM/B5EEp1zW0RYnNISsDR1s8RrZnGstBlermdZmBNX0g5Xdvc/MQ1WdSf4xJndPxYRXf3SzDDu2YO1XgIw2RnBYhlMBgwq5EmM7NOygIxUJLA8CNev+9zMCWTdLV1gU9lYzwy0AbNPPdPbD2zIW5vcntEsekx0p6o861gM2WH5ILhnlRgAoUW8NUIRF/3Cq/4xM9KKf5enxYAaEUE9/FboaSNkRhnkK6A6hse+EVcqatA8zWOjgaq5taOD8kGPzaLDNPmCrNJgb81T2BX2swKWsIgaZQV9sqnQjqwVKJYsVwoyR1ABwmTkXSfoU6MwfAWKmHT4nyuCkNdMC7VNcJHFW9WPrVX78nGSEcHYHEYVsELSU5FtyK1EpaiLFkjxOVPhbzd588UCdft4di9G5t+oG8PzzHJOg+R+zRI5RhojGAluwyeFRbqBFQ48We2n4W++YaALJzY5+ax7yOsjpjyQFQqDLpz6GXCwaJz129ADLxZw18kp8itNzD1K1hmFwMS1yibomYraEITHshKcwUG60tcAzz2BuWM++nJzwOcZMC8PVrf6i+/h4StHr/FuW5jGfn5U6g+kImPOX/seFowFWb34ksMafDQsPCSqwfnW8Z3kWZsqt2CXTC8FEkFmsl56Rhfp1E2lcBn1MGqOlWwCslr+lnAdEE24b7fAz90axy3m8joB4nbSMDMOPqw+I16ti0tbsAfH6kK1WufYWFalTN8FOmKZskpBWkFo209z8EWHXmytviaCbalE1Gnh1hfnAd/29QkUWpxfn6qnm2DgxcckbFz3iqTRg5FITrn4EVKpnA8jZsPgmL85HEsPYN/DkBwl9mwwn6tfV42LQZT0geMhPyW5qFJBGRRi0P28DB40y6wFCRP77e5GfT1IUUCRC57U/TzIRkQZFEQJBR2aYgOAxamiQawlDCCC3fY+FxMsMg455X0474hDyBSw+ZGKP6bqQEJp89WLZr5OuX4hYs4HoQ7EPkudHtXYhbTJM2l/Wnt6nUcOkIdbgM/f+KjbN04JmymWuOWpmX+F2MTY/lvEBvU2wNMVzBAcHXWgsVVpyUB6WYDPRVBm1TNqdPZwqiDXgW7EfI34AiJmPKXPhi0g478RH7lqXjKheSlGCgJesk2FnUGRNgFm+W8c8sJnQrcMOOHO7dfyePFZXcbGPbs/F7iku0f6vpHqS6ODejRr/w04KhtnwY7iRZKq4y70uRpgAu2J2iDBrHVgh1y4NNNZAkoPyTLDosUKAJ7RZr3u6isvC2kf6U1joamhJUJtsjeSMM6ZH5102/ZFXaPnr7FpKUYLm13VjaFBk+evsO/QNo/02xwzKbnBaxfkkIDgjDli++rNLSKtVnGRCOPM6CWqW48uBy2TDkCtWmG6Zz+/w/ik51cmoFj2TdUKyAf36H9cNoF6P5U9jnajkxAiW27XXAiNHOHBgC8IEVLTpWE8gMj6W6CvMe0lbi3Hye0evmaJ+XtP/yhl9xtVKdS6yOiMiCuBrHGg9TInMLW2Ykg2sgWl9VrH67R/wTD+qWGFzfWOLFfA468+5ts2JIFdxUVGp/kKmpdTAhJeIW5LwhdtJHynoZtLmAtJFChBaxSy1BJhNOVc5oWv26UrA1vLv4JcArAlv5J1wNffF/NUT2n3Jz3zIM+Fn+QgmUDJDmVg6zdtmUC21aCGDmmnsGQaQEg2Nhju+6ozbvt25wBofbuNncvR4kyU1X08nkKrTabZhbv/GF677WFHQx6hNqicWg4/uIkOtka9+DnZwACqlFC3sDYkbQPyC0ubChK87Gz5rGHzFPfEuP0TUv+uOlJ80cHTMiQNfNgkgqVZl0oQ6t1DZLAzuaKVMmuNEXATUVrHznA9VU+43beE0+1bTP37CxYDkobMNyKwGKuSZ7/35c7krkibV5MThP+i2xefUbOnqYSHqtAqQYP2+xhV6j8ragTN6U+TH6VDCNs6dhrFFq8cHp5BJi3RnLAUgD/lPeCwEHkNXzLeqfXxMUvwLiiYKzdA3yDIafl37/eygitHuZma/j4tdygU2rLXQjgyEaOYIm73o3O4mnSR8oWimQHDq9bFZjdR157tMq/KiDk6eHOPi+fr77inODugOfxFX5wI3sXtWwKslYKHV/Wg+yhAR2Bux5pdAmID0CoOHRg+ThhQdsAxokD9+YmIGTDCWnw0Ml/Huy02GZdl9CbrJDTL7SIRnRJLSrH6xK9NsFTtmGe6W7/OxPNBN6AEyBnNzO4L8eUZntL8+xkl6UVXx7olctr9JFEtt+9RQQSAHSs4lMAMpVp9xCtbL6NgnmXH1TYkdNcLv1MHTGCImODxTMMkARwkvw1ggZMlNFRxdRs3R8i0BW9QwJlVlXMf+EAOaLQxmG9OomrPB7+Z4yosKy/aIB9jofveE9ucUPcTlF/nDR5qI2fsxBea7SEYGhiNXEuYdo1TnMHhhdTJpsJUwyQ61jDPmcJkfKowMXNqV7UGF1Wl1UMENpXnjAwvqML5fg+X6YcUHBKILwyyerPveC9govQw3gY9zrsxv8zT9lFcY7+2VS91RA1Nydd8ffuHfqxqMD3nE19Oei7V14XRjXZnFLS7fPnMAIhQavMIbdb7VaTABzNSWt2pzDnzVP1xk5TfFUSpFwvdq9/Mko9gojPk6y5KYa0HYGkScNYfsVX4kM6XhAEZVmXrsopvm08j2v29oxJKa2qq5iWEEJ8J1zQQcMBuxJZI8jUtWeYInxk8n23yXOWl+sByOqCpTD0d008ylDf37hoYjqamtmpsYRvW/xeRKXC8KGaaGH6e5CrRHkqfhCDbPMvDTyTajsy25aLxDXxP07S1KT4/nNKsjr5ju9ST1J9/zyeQALr8Bog0NYWY9YtX2nDhkCnSuDi2VtM9nQ5Rf7wXIGAsEE1N5GchyGtZmHcvMwbydUWtFQ9UKnLAc4bQ+hyt7DE3rZnWN61TP9UeFa6Cicy/M9+hNUpTV67iKP8eleI9T17pHVf8Ih+SmbX6mOrP9vb6kOsb/+HX/Ocd9HX9OhyrCgMMxjr9fxRU6kLARInu6FGyEJtA0hf9VHyQCzfQlUBN9oYb9u3wXp8k/0b7rcaAhgAZqEiDTNR5nhzN5Iia22ReBTfWlJuqh+6ogZ7Flfi52YGsgmVRJgVIjxS0qjklZYox3h9yCBCIJ1LpIpWmZfbsjtMoWQy2yFDo98zSFdCM/g/qQEgOu3YUFyLsrlLXQlRvaql+GSM3VU6gs1hMZNqtoT92QtoX+KZ/QQF8C8e8LdQrUfmvgQNiXgOJ3hboBsI1z+h5VTzn06fAE4HDI0ejarPDwjIexr3g6hb4brhxskSXRNDicMAltDUVQM0Op7ivqFlLiJ9SVgN9PV6hhP2TkFfgPRVADQ6kOZvIJVz3bGk+1t8muOhdQf/cloIm6QrMeULTCESj6I2qJovcxwbVx/9SRppMCHeEBDqRS9RpDqBMBpclXVDw/JEdIe7YYbJShMLM2HUNYZnCaRmFzmsy28T4c4JskreCJTFvFSDShlpmkio9LoFDBsqMyxmVb8X2cnR9jAmmFcVgqlRw0pbEsGiH0rbMUZprfn9AueUx2ZAtERfuU2UBGr7IGXMfYLnD1D+3bI3FyVJKDc6WyhpN0xnLZSGTapw8xtF+jCxW9RcrN2vkUF0mcDbFGr/Lj5ySLJf1iUkkhl7KeRt4/zzH55WOWQNMOWwzJwFK4WcfcJJqpt/m//XfEV5QLZCaJNS55PdvAvaZmacktMNLW0C0M+pdv4qKgLwIXBH2p7rwmQcVtkYBreaoMPKsZijWNDE4rQhtDEdREXarlfv0dT+dZnF6cq6f6RK0ZmqTnCWpySAp1DY10JMCWZANDlUHtkuIyMtrEEFrZqR5dqGjI7ISPEMsaUfJvKUz4/17k55OskbZQ0VJLoWmpjd8sNNL+DvFviwy3FGzGXOmegiVTbSpYSo0UcN5eQQqYDJICpjSUQtGyujWzbpQML1SZtDuN9i1U1lq4kaZM2khTrGkEzE4pNAdSQQ2DhAZnSpIt8FAkO0cy2uyyie+krcg7jaXQmpTJigUYkymHzciQaNXjk1AAKvIksJo8le4YSEyMIJ4HiTTgwZBIZtu4bAUlIzQSw2zVJA1jDvS+hBLGgYTYUhwDOcwE0B9v00GPxSNuuhQ85qYJzJtqYoirmmsoNE02RNpbLEgzqUYmmgBRXuFlCEujWI2whNoNCRsiEtiCsASqlSNHquvDIR6h2HtDGdhvQ7FufGTelYpjI1MMjosMhRaWqXQjQJXBUEwNl/gfC3kjVBnUCFWsW0ehDOHNlmpwF0nAdZVApdsiYh6I7F8/g1elXDm4VWRJtHdMOXgL0P4O3ynlBvcMQwA1cVrqi+ALxa7URPT+1APWoC+WKmJ6bCKNeiQ0LKUEb85kxBanxA/oeErhoQQm050aD5SGt2EKCUQS1e2YccvdMaW8YYFCddpp2uwdqsn28mtMngBeW7A0OiMXeVli5qm8VZEENLJApTNys/aR3nlz5aCBWRLtCS0YGAU4qgXp4DNbkNRcEHXz2kb1R2pMECTxCI0pBo/MGArtF3s8xckBGreGIvgL7Up1I1OzAlINSjwFOB7xRAbnnu9QVaFCMzzLCGVnohCt1gRxicfRv1ByeIL6lCuH1WdIzBp8nWBwl7DaIomiWYpK0zIXk0ZoliuH2uRIdLP+c7ZTTPp0KTjn0wTaw24+tgVwwM2TwIfaPJVRy3KrcuXyNk2tyrv0aTz21OQmPoNRTWp+98s4TsldvSR0el+sO1TiJTrx2TZwNWu1lXu0CRQqz7mWCOkb7o6mFX4SIonqjDu6OJ3SBO0f8pY+sZBCvhwRKMxkaMn1EnQuSgb33IbX3dFAZwzK3sXSzLvV3MuViZRvfq8rxLAQbSKQyJxVWSqDqbd/EQrOt32pbJLtCQw8FOVNMaUyP0XTpuQvxWRYA0gVkAOobSTSiWHQttAg9QxC7bweDa7vVB2FG/tQgX+1QeUC4/zwsQhyH3u2psK/vuFi4i//glXf1DT0WwO9XWDqYEaB3lQMFlE+k7A3hzDH0+NYGd23ZhctY1ZRrqrsZQPRVPdaQckJGttBrsoXCt5N+RAXB1Q5mLKtKDeAVGGVgss0IZ7GlN8jSxDiE6RfojQqQy9N3FRrnpNEDUdYOZpkpJBCDfYpTF9P8sjFXkV2eR5163PULuoT5XhiXlmuJPzggyiqfsah4MJtXABmsucoQQwoH0XMKytGEkBZiXpLMRn9WCbq+QLmAQkDmAJ6ANSYQPmux171dg+qUpon8a8ut58m9WTPv9xV5EwnV5Ql9N5LE6rebyz7owbF4Ckn1q8awBWDUnHJWQrDIKgh5IOgnNhLPy7BDJdJWkdH7jkrjMCRhjOBEYZGKN0FDRlYy7UWaEN+AtyLX4aB7BmvvRm6p5rKpbFIFGJ5zD83JTWlT0kdlsnMS8aof9EIrJZhSsUSmH0+2ax/4ReYbD3w9WVTnSvyrn53GKtXH44AIqoByb8Y9ftHgIp+F2j89zh/Vt981rLHwPZqqo7yFbO8STW5Uvw7a6KU7A01WBM0i1gY1jzyud+kmqc+X5h5uksYK+zwlUIiBxp7hLKQhrFBDV/J/5A6k1mAp/fg+lFdISROgBgDDBNV0ADnyTZiowNIp1qWTqEMEK2g0UIRhcAVV+5qS1/+R3S4Aqk1jKprVRSDLNDKyuMmqHlJYibArHVxDzwYuDWJfjUnrRJsWefaAV7MYmWQDZqiX8oOqwOpJUTaEGsZSVAP2hAeVzK8ano8CKTB0DCRCZhwI4pdD0jnf+cDBTIhlZUBSpx7ngu2QjchhYC8jme1IFRIGYHlQcyk/0hA8mAfyjwmkQSm0RtHUzGYmdTBZmhuhhFkHO7KFMFyJJF+wJs0BzaKmxi9XcwMYsCVDTyk4C0JIOQbrerGbSGs5DaxqRb6BYieo0oXJzl1uGNWwT+WOWmlSoMYQ+GkJKfWKiXRBlBjGSZRBKwyPSwwZjHBOYJBsC/aojbhuoKYWD+Jm9QO9omuzZxsBDQnmzIs5AaCgrURU6iCsK3VxA4wnR6bJtYKbyLlctK4rlZ5pdZm68ZFmpFEdYmkzRqbVM1nEqOY8GUi46iYw9Fu3BdChgPl5KNh2HuA6D4+nlI0RESUK85RKpYuXFzGZtkiibk4ocp9SMaIdVwXVZZQ6j2C3J3whVCTpLo8iuQY9RVzl0jkf7YKr2oXN1PpMiUSyUV2d5nio3uSmsOP/jwDTZ/uqCvoIT7CXU73kXh+TyLR1MB/dPInOHOZSBW8VelvaVYxBJpMAtoSblaBae1N14enVdoJoAphFCGOLqlK/epHXRIDV68vRxZMYSai76AxHKnXUeWIDqor0Zem0YjMhO4dRAZD8oq1xYp+e7ZlqezWhma0oPP0JvkSabaqL5ai8yj6xN8tia9r8GwApJML7vpmgIkqTWrBQaNdFVWNTRxFiGEpnHpQkOtocK+T+/HBFRS7t9F+fFBIbYaLMkS2J9O0dje0S0M9ul8XYY4+bLfcBjyJX8WFkONDPU+bnkF+xVZWJPK/lQ2vahfoPbrF+7OnuET7v5LqiWpBVFxXxZs6TF0+lD2pKg1T724I5rsd+MvNAFfwpAhYU/rFG+UI8GSaj3S/G9uHreV3XJjLPH2KAc2ASJEEGBDp9AhDPTDzgb2KQDID5VJISR9iYaRI3kCYmGRj8GMW7Xehr+QXHfOYpssTIf8mOAq/SvOZNO67MBGeXnfQaTCiga9cS5bQk+BgTWF+VabscN0IdSE3tFs+nnBNez4m+YhmwAMpwwx1QFKV9ktW5UoZccBt0NlSWv/9HTouAJ/7RfNkSUWu3RF4eaIky3rTfv2aTDYeDKT6MuTEIT6O2U2h2DBKaf3vG6c2A5wrKAIyGQEjh2ldBV5kyZca4OjyKal5iR4jhpmRXOYbNsdQdJMlVRKnirWkqoLvdSScSamdejTZkcYbo1sri03p7SKtG0hdJSd4EW6W3sohytWQ1CkSEjyJllORK6ZyOAFVM6Wrs0rJ+Mh4eDaJauoC6ULMWtOorVM3uJq8en7UEtKB6S+QYepg98hQ/onhIk6ZSMLF8Y5OOxa9KfKjyh4q8hAGgTOstQsbZcK00aZ4yC0MQRGv3Qx9erhIsX8Tifxv3IQUd01NafY6l5E9BaIcw2M7SKnva3cnLCEdXjvGy5LQucQrzUm0ruQYF8/X33dPcXZAd9i0Qwo1YFuiraQyCpvTrTUInK+N3aHQaeaabQmYRW6kEcgfxtqz1OtSW5I3TjkZauuEGPo0efMII9MkeP7MpNi366r4377PayIwQVr0JoEHUgW1wnfB2YVfmRDuvnkAYZLfbZRZIjbDmtIoLK1cMSjrG9FHlc1NZhqZQYKhg2nDFCR0Ja9qLQQxTB6ziE2dK9pIQa2YT4CEvs20okjUy3AA87URFuo0bC7O4DbmUFCHNAeYaK35DpX501zNMeSAi3rWMmMAtN4VAXiI+e4oNoocdm5pLOhEU1F9YHSVZ2VVxEk9q+Ddab846UIxP+SRmKAK2N/54q1fEznEbWaXDZLEXc36QZeMy4PZ6cQdBpakyNVKWeUImdUkVAoyU6AwWctEq43kGB51QNK2++4xmSxF2jjDDs/U1Obq6dTCGz+Dm0FtKs+cae8zqemAXck4juHxBGTmazYuipR74ww7RIpXm6unUwtvHIl+BrXbXaSQMtB4VpPUVzzQ9t/WBDOpVE1xR65Pv+ixm5gCK6OzNQ1Vl+u7HvM5wU1rWjeuEyPXvPtGG1kfd4Yj9H/65V/1Vy8aJrXhcS+joi979aJJitr+gP+s8iI+oPf5HqUl+fXVi7szrn1EzV+vUZkcBhavMM8MkTzRA9OO5iZ7rAO+k3SanEQdSVfc522v4n1cxRdFldRxLXHxDn9LJN0v8TKpz4M+o/1N9uFcnc4VVhkdP6fMofOrF+r2X70QZH7VBNorfaiAxUywCuhDdnlO0n0v95s4LbntpozFFbb+7wj/3vQl/jQrdHjuOf2RZ4aMWvPhTSrK9viTe0DHU4qZlR+y+/grcpHtY4neoUO8e76t03gRpxkZE31HsGZ/9TqJD0V8LFseQ338J8bw/vj9v/4fmgz6ciGyCAA= + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.Designer.cs new file mode 100644 index 0000000000..f7e948a531 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ThirdPartyEmailHandOver : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ThirdPartyEmailHandOver)); + + string IMigrationMetadata.Id + { + get { return "201603121451066_ThirdPartyEmailHandOver"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.cs b/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.cs new file mode 100644 index 0000000000..9b5970f35a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.cs @@ -0,0 +1,235 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using SmartStore.Data.Setup; + using SmartStore.Core.Domain.Media; + using System.Linq; + + public partial class ThirdPartyEmailHandOver : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.Order", "AcceptThirdPartyEmailHandOver", c => c.Boolean(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.Order", "AcceptThirdPartyEmailHandOver"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + // Some users have disabled the "TransientMediaClearTask" due to a bug. + // When the task is enabled again, it would delete media files, which are marked as transient + // but are permanent actually. To avoid this, we have to set IsTransient to false. + var transientPictures = context.Set().Where(x => x.IsTransient == true).ToList(); + transientPictures.Each(x => x.IsTransient = false); + + var transientDownloads = context.Set().Where(x => x.IsTransient == true).ToList(); + transientDownloads.Each(x => x.IsTransient = false); + + context.SaveChanges(); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.Common.Ignore", "Ignore", "Ignorieren"); + builder.AddOrUpdate("Common.My", "My", "Mein"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutThirdPartyEmailHandOver.None", "Do not show", "Nicht anzeigen"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutThirdPartyEmailHandOver.Deactivated", "Show deactivated", "Deaktiviert anzeigen"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Orders.CheckoutThirdPartyEmailHandOver.Activated", "Show activated", "Aktiviert anzeigen"); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ThirdPartyEmailHandOver", + "Consent for email transfer to third parties", + "Zustimmung zur E-Mail Weitergabe an Dritte", + "Specifies whether customers can agree to a transferring of their email address to third parties when ordering, and whether the checkbox is enabled by default during checkout.", + "Legt fest, ob Kunden bei einer Bestellung der Weitergabe ihrer E-Mail Adresse an Dritte zustimmen knnen und ob die Checkbox dafr standardmig aktiviert ist."); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ThirdPartyEmailHandOverLabel", + "Text for email transfer consent", + "Text fr E-Mail Weitergabe", + "Specifies the text to be displayed to the customer. Please choose a specific reason, e.g. 'I agree to the transfer and storage of my email address for TrustedShops buyer protection.'", + "Legt den Text fr die Zustimmung zur Weitergabe der E-Mail Adresse an Dritte fest. Whlen Sie bitte einen konkreten Grund fr die Weitergabe, z.B. 'Mit der bermittlung und Speicherung meiner E-Mail-Adresse zur Abwicklung des Kuferschutzes durch Trusted Shops bin ich einverstanden.'"); + + builder.AddOrUpdate("Admin.Configuration.Settings.ShoppingCart.ThirdPartyEmailHandOverLabel.Default", + "I agree to the transfer and storage of my email address by third parties.", + "Mit der bermittlung und Speicherung meiner E-Mail-Adresse durch dritte Parteien bin ich einverstanden."); + + builder.AddOrUpdate("Admin.Orders.Fields.AcceptThirdPartyEmailHandOver", + "Accepts transfer of email", + "Akzeptiert Weitergabe der E-Mail", + "Indicates whether the customer has agreed to a transfer of his email address to third parties.", + "Gibt an, ob der Kunde bei der Bestellung einer Weitergabe seiner E-Mail Adresse an Dritte zugestimmt hat oder nicht."); + + builder.AddOrUpdate("Admin.OrderNotice.OrderCaptureError", + "Unable to capture payment for order {0}.", + "Es ist ein Fehler bei der Zahlungsbuchung zu Auftrag {0} aufgetreten."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDescriptionMerging.None", + "None", "Keine"); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.ShowManufacturerPicturesInProductDetail", + "Show manufacturer pictures", + "Bilder von Herstellern anzeigen", + "Specifies whether to show manufacturer pictures on product detail page.", + "Legt fest, ob Herstellerbilder auf der Produktdetailseite angezeigt werden sollen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Catalog.HideManufacturerDefaultPictures", + "Hide default picture for manufacturers", + "Standardbild bei Herstellern ausblenden", + "Specifies whether to hide the default image for manufacturers. The default image is shown when no image is assigned to a manufacturer.", + "Legt fest, ob das Standardbild bei Herstellern ausgeblendet werden soll. Das Standardbild wird angezeigt, wenn dem Hersteller kein Bild zugeordnet ist."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Partition.Note", + "With the following settings you can partition the data to be exported. This includes
  • Skipping the first n records
  • The maximum number of records to be exported
  • The number of records per export file
  • Export data for each shop in a separate file
By default, all data of a store will be exported into one file.", + "Mit den folgenden Einstellungen lassen sich die zu exportierenden Daten aufteilen. Dazu zhlt
  • Das berspringen der ersten n Datenstze
  • Die maximale Anzahl zu exportierender Datenstze
  • Die Anzahl der Datenstze pro Exportdatei
  • Daten von jedem Shop in eine separate Datei exportieren
Standardmig werden alle Daten eines Shops in eine Datei exportiert."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Partition.Validate", + "Partitioning setting values must be greater than or equal to 0.", + "Einstellungen zur Aufteilung mssen grer oder gleich 0 sein."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.IsActiveSubscriber", + "Only active subscribers", + "Nur aktive Abonnenten", + "Filter by active or inactive newsletter subscribers.", + "Nach aktiven bzw. inaktiven Newsletter Abonnenten filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.IsActiveCustomer", + "Only active customers", + "Nur aktive Kunden", + "Filter by active or inactive customers.", + "Nach aktiven bzw. inaktiven Kunden filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.IsTaxExempt", + "Only tax exempt customers", + "Nur MwSt. befreite Kunden", + "Filter by tax exempt customers.", + "Nach MwSt. befreiten Kunden filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.BillingCountryIds", + "Billing countries", + "Rechnungslnder", + "Filter by billing countries.", + "Nach Rechnungslndern filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.ShippingCountryIds", + "Shipping countries", + "Versandlnder", + "Filter by shipping countries.", + "Nach Versandlndern filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.LastActivityFrom", + "Last activity from", + "Zuletzt aktiv von", + "Filter by date of last store activity.", + "Nach dem Datum der letzten Shop Aktivitt filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.LastActivityTo", + "Last active until", + "Zuletzt aktiv bis", + "Filter by date of last store activity.", + "Nach dem Datum der letzten Shop-Aktivitt filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.HasSpentAtLeastAmount", + "Has spent amount x", + "Hat Betrag x ausgegeben", + "Filter by spent amount.", + "Nach dem insgesamt ausgegebenen Betrag filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Filter.HasPlacedAtLeastOrders", + "Has placed x orders", + "Hat x Bestellungen", + "Filter by number of placed orders.", + "Nach der Anzahl der gettigten Bestellungen filtern."); + + builder.AddOrUpdate("Admin.DataExchange.Export.SystemProfileNote", + "The following list contains system profiles, which are provided by plugins such as the Data Export Plugin. You can customize system profiles as desired, but cannot create new ones. These profiles also add additional action buttons. You will find these above data lists, such as the product or order list.", + "Die folgende Liste enthlt Systemprofile, die von Plugins wie bspw. dem Datenexporte Plugin bereitgestellt werden. Sie knnen Systemprofile nach Belieben anpassen, aber keine Neuen erstellen. Fr diese Profile stehen auerdem zustzliche Aktions-Buttons zur Verfgung. Sie finden diese ber den entsprechenden Listen, wie z.B. der Produkt- oder Auftragsliste."); + + builder.AddOrUpdate("Admin.DataExchange.AddNewProfile", + "New profile", + "Neues Profil"); + + builder.AddOrUpdate("Admin.DataExchange.Import.ProfileCreationNote", + "Please select the import object and upload an import file.", + "Whlen Sie bitte das zu importierende Objekt und laden Sie eine Importdatei hoch."); + + builder.Delete("Admin.DataExchange.Import.ProfileEntitySelectNote"); + + builder.AddOrUpdate("Admin.Configuration.Restriction.SaveBeforeEdit", + "You need to save before you can specify restrictions.", + "Sie mssen zunchst speichern, bevor Sie Einschrnkungen festlegen knnen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNumberMethod", + "Customer numbers", + "Kundennummern", + "Specifies whether to assign customer numbers and whether they should be created automatically.", + "Legt fest, ob Kundennummern vergeben werden und ob diese automatisch vergeben werden sollen."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.CustomerNumberVisibility", + "Customer number presentation", + "Darstellung der Kundennummer", + "Specifies the presentation and handling of the customer number to the customer.", + "Legt die Darstellung und Handhabung der Kundennummer gegenber dem Kunden fest."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNumberMethod.Disabled", "Disabled", "Deaktiviert"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNumberMethod.Enabled", "Enabled", "Aktiviert"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNumberMethod.AutomaticallySet", "Automatically assigned", "Automatisch vergeben"); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNumberVisibility.None", "Do not display", "Nicht anzeigen"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNumberVisibility.Display", "Display", "Anzeigen"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNumberVisibility.EditableIfEmpty", "Editable if empty", "Editierbar falls leer"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.Customers.CustomerNumberVisibility.Editable", "Always editable", "Immer editierbar"); + + builder.AddOrUpdate("Admin.Common.FileInUse", + "The file is in use and cannot be opened.", + "Die Datei ist in Benutzung und kann daher nicht geffnet werden."); + + + builder.AddOrUpdate("Admin.DataExchange.Export.UserProfilesTitle", + "User profiles", + "Benutzerprofile"); + builder.AddOrUpdate("Admin.DataExchange.Export.SystemProfilesTitle", + "System profiles", + "Systemprofile"); + + builder.AddOrUpdate("Admin.DataExchange.Export.CompletedEmailAddresses", + "Email addresses to", + "E-Mail Adressen an", + "Specifies the email addresses where to send the notification message.", + "Legt die E-Mail Adressen fest, an die die Benachrichtigung geschickt werden soll."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.EmailAddresses", + "Email addresses to", + "E-Mail Adressen an", + "Specifies the email addresses where to send the data.", + "Legt die E-Mail Adressen fest, an die die Daten verschickt werden soll."); + + builder.AddOrUpdate("Admin.Common.FileNotFound", "File not found", "Datei nicht gefunden"); + + builder.AddOrUpdate("Admin.Common.EnterEmailAdress", + "Please enter an email address.", + "Bitte geben Sie eine E-Mail-Adresse ein."); + + builder.AddOrUpdate("Admin.Configuration.EmailAccounts.TestingEmail", + "Testing email functionality.", + "Test der E-Mail-Funktion."); + + builder.AddOrUpdate("Admin.Common.EmailSuccessfullySent", + "The email has been successfully sent.", + "Die E-Mail wurde erfolgreich versendet."); + + builder.AddOrUpdate("Admin.Common.SkipAndTakeGreaterThanOrEqualZero", + "Values for skip and limit must be greater than or equal to 0.", + "Werte fr berspringen und Begrenzen mssen grer oder gleich 0 sein."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.resx b/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.resx new file mode 100644 index 0000000000..43d0084f04 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201603121451066_ThirdPartyEmailHandOver.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.Designer.cs new file mode 100644 index 0000000000..90e9ba6504 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class GtinMpnIndex : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(GtinMpnIndex)); + + string IMigrationMetadata.Id + { + get { return "201605020640016_GtinMpnIndex"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.cs b/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.cs new file mode 100644 index 0000000000..98f1936ecc --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.cs @@ -0,0 +1,19 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + + public partial class GtinMpnIndex : DbMigration + { + public override void Up() + { + CreateIndex("dbo.Product", "ManufacturerPartNumber"); + CreateIndex("dbo.Product", "Gtin"); + } + + public override void Down() + { + DropIndex("dbo.Product", new[] { "Gtin" }); + DropIndex("dbo.Product", new[] { "ManufacturerPartNumber" }); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.resx b/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.resx new file mode 100644 index 0000000000..15bcc90554 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605020640016_GtinMpnIndex.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.Designer.cs new file mode 100644 index 0000000000..1fa094db33 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class SwapColumnMappingValues : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(SwapColumnMappingValues)); + + string IMigrationMetadata.Id + { + get { return "201605061916117_SwapColumnMappingValues"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.cs b/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.cs new file mode 100644 index 0000000000..f16431d45b --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.cs @@ -0,0 +1,105 @@ +namespace SmartStore.Data.Migrations +{ + using System.Collections.Generic; + using System.Data.Entity.Migrations; + using System.Linq; + using Core.Domain; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using Setup; + + public partial class SwapColumnMappingValues : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + } + + public override void Down() + { + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + var importProfiles = context.Set().Where(x => x.ColumnMapping != null).ToList(); + + foreach (var profile in importProfiles) + { + var dic = new Dictionary>(); + var storeMapping = true; + + try + { + var json = JObject.Parse(profile.ColumnMapping); + + foreach (var kvp in json) + { + dynamic value = kvp.Value; + + var mappedName = (string)value.MappedName; + var property = (string)value.Property; + var defaultValue = (string)value.Default; + + if (mappedName.HasValue()) + { + // break migration because data is already migrated + storeMapping = false; + break; + } + else if (property.HasValue()) + { + if (!kvp.Key.IsCaseInsensitiveEqual(property) || defaultValue.HasValue()) + { + // swap value + dic.Add(property, new Dictionary + { + { "MappedName", kvp.Key }, + { "Default", defaultValue } + }); + } + else + { + // ignore because persisting not required anymore + } + } + else + { + // explicitly ignored property + dic.Add(property, new Dictionary + { + { "MappedName", property }, + { "Default", "[IGNOREPROPERTY]" } + }); + } + } + } + catch + { + storeMapping = true; + dic.Clear(); + } + + if (storeMapping) + { + if (dic.Any()) + profile.ColumnMapping = JsonConvert.SerializeObject(dic); + else + profile.ColumnMapping = null; + } + } + + context.SaveChanges(); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.Delete("Admin.DataExchange.ColumnMapping.Validate.MultipleMappedIgnored"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.resx b/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.resx new file mode 100644 index 0000000000..15bcc90554 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605061916117_SwapColumnMappingValues.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy923LcuLIo+D4R8w8OP50zsY/ddq+OWLuje05IsmQrti9akmzvvV4UFAuSuMwiq3nRpSfmy+ZhPun8wgHAGwgk7iBZpa4Xu0QkEkAikUgkMhP/6//7/3/7n4/r9MU9Ksokz35/+ebVTy9foCzOV0l2+/vLurr5H39/+T//7//z//jteLV+fPGtg/uZwOGaWfn7y7uq2vz6+nUZ36F1VL5aJ3GRl/lN9SrO16+jVf767U8//fvrN29eI4ziJcb14sVv53VWJWtE/8B/HuVZjDZVHaWf8hVKy/Y7LrmgWF98jtao3EQx+v3lxToqqosqL9Crd1EVvXxxkCYR7sYFSm9evoiyLK+iCnfy168luqiKPLu92OAPUXr5tEEY7iZKS9R2/tcB3HQcP70l43g9VOxQxXVZ5WtLhG9+bgnzmq/uRN6XPeEw6Y4xiasnMmpKvt9fXuabJH75gm/p16O0IFAj0h5R+mKwJHtF65XNf//2ggP6t54p3r765dVPr376txdHdVrVBfo9Q3VVROm/vTirr9Mk/g/0dJn/QNnvWZ2mbE9xX3HZ6AP+dFbkG1RUT+fopu3/6erli9fjeq/5in01pk4zuNOs+vntyxefcePRdYp6RmAIQUf1HmWoiCq0OouqChUZwYEoKYXWubYunsoKrcnvrk3Mf3gdvXzxKXr8iLLb6u73l/jnyxcnySNadV/afnzNErzscKWqqJGuqdMsTusVOs0uEtxktOkaPMzzFEUZMEwNvvIsKsuHvFjhggrFePi+KDuEk9PiMqnS6Sl+mK+eJm/kE6oizNGEbOUsjb1DZVwkm0bgzNDePHP1MVnjZbG6zOmCLn05+RxlK1QclN+T1S2qfLE1WP6ZZ9PToWnqexFt8AZbYSEm9N2k/sVd/jCaN7+RH2LmRkUA+VIkeUGlslq+GwiPy+g28Fz89nrYfdV7cvR4hDeb27x4ctmZo8dXDIb95ixvS7Mt/+2nn4wm2ZK93iXlJo2evhCWt2FUY/65QFVFx2LNO1gk3CS3dUGhX7V49hzkzEFvp+Ggb1Fah9gpLJultNJT14lnP+ZxlCZ/olXXpgP3tjga5hUQ7tlY3lYzHXZTC6hYUXZbR7eWLALgIVOHMH3eF3m9mV9A9+0v1fRc6/tzdJ/cUgaSzOTLF+copQDlXbJp7CniyroawE+KfH2ep9CC7qGuLvK6iMn4ci3oZVRQ9dpNpvTd8hQlLZ69BJG3pdkI30y0XNqZaamu3ImnaB/X/qNGFyg/wjhUrQc4uJ2k0e3pGg/2JEmRhty/mI1Wc8StUt/zWOBDN11L5Z3/OdFVBVfKTCq6m8k4RyWVcaVcgHKQchkqA+xl40iMSqE7oeuunXGogyhoHM69hNXLOl/tqqP1MkeXrvWFjjCnJVldZ2l9m2SCENFVvczrGBI+4bQqf6EA6lZaEeIkFM5QsU5KsjjPUUyN+tYC4QLFNbHXveJx7QWBvK1Al0m2h3+Ti6y3v/wyRduDNXTylqWL94jyNirIsoK3dZ6Hr7gqwxJWQwprWAPutYhZVC4Gw7Z6+YpFtF+9zqt3ohV0UiB0gVl1Q9vzU54vo8fjR7TeeN96YUStIk7wcFOgrnoQV8m99+XTadlItYb5/XAFlY+mQomXDBMLJv7EYSjH3LSLHK9/e4FEqpX0370QkrcV6iyxpCrS+kRMfmEezOhA7sy/ZB/w+jijKr0ftoM0zR/e16is8LnkW155I/SwiQj3RHjdvcOM+bWKO0zkz8tkra17nK0ca/ramtyObUTSgMe0UYGo0o1KIQ1OKfZx7YOsfMDiTNqppvyqEaPjbjFFokjnyr1leIPMS5I3KPbyXCGjMJV2U5Z/rtfXqPhyQyRY6TeAKYy6zfLxW2LQ2oeWoE2fMLmoQUeh9HFQV+xiHHdWAgbKBhmst5xgEXtJCxZRMJnx4jAqUdsBQt1O0e186LSrsyGT9Ro12AKmmn2IbXWc4mWCCGJ+2O8S8rY6Gr2vk77V5rfttWeJ29XdQIa4gjzGs5xO3oqBV3rYhk7yYh1Vvht2h+0iSqvJu36wWifZUb5eMx7D00UylMFsTAc3N0ma4OXiS+0wFqd3KEUB4ig6w9VBHOc14MI9he0qDB99jMrqdHOwWuEjmiqcwdRhRCPxCkQk5ZcMPE9aO5uU1cf8NslcD6i4PuUiLKqlKJwVgpakkruJTvRfMWCDGiCWCrs/AGKrtx4maYqnuZ97VTd5WKCvYxB5hzk4217zmp6q2y3M1aDRiP3mYQQtWwoIqdh+N1Y9aqlBGIaQE1t/M6Xq8fEjUWii9KCu7ohKE1Mg1SlHVQOcBqMKwpyY1bKdIKwG1OuzvKzgsfXF4EDEUqHXAIhTF5tYT3kfabm8k+NiuJccjG036Zkf7iEtAjs3LhH6xRXbdukc4TMGZpE/qIkW7NoIBOwiDCF0VQJm3+WHqFid5UlWlR8SjITcuIP9FuAkvZfDAWNQANuOpLvqNNprBGBA/HEwcgHIA9qKwIu7nNY/wofYU6yUwX3noUDyS4EE2sshvcw6PUEd4pDW6zx71SLYn+nlbZ0kRVkFMt3q1ddZGtId+sO0gllsE2XTh28fkQNaIcbWaK/QKoS/3SdZLB5dNS0yAbCTDatdmm/maujt5A39M9kQXSlKNb78gW6V7/IMNZcfk7d1Ej3O1JLfeVt+kmnWELgVdhttDzNsgFyRsGnz5dZ7NbtIlZ3jIMUujgCkHR1D+RndO3JZ783vkgLFRD171eLYb8/ytjQb5kRhUdQ3pGwNH0EcTcpgzoMP+UdEiHhazhE0dXlXIGTa4M8BGsSCFhVJzDXm6EdTX/8LL7XL/FvkbeLdhtCpuRx2zvEpGM8Bxt1x7SdU3eUSE9IY5mqo3Ii3ZGwQ00MDpyttFevzLbsRSIY12iuA3REEEDsPQnkdC8f0cIkaaRFwU7ffhxRiSb0PTZXpZMZMUuHk0ulthml9dEdWwiRSiREsc8gjXpu0EGFu63us7HoomCNM++Utb0tmZAjrAjiVtnp9XaD7JNKIiTA3wtugBzmdcx33c2HxK3d9L/+t/oY0gBtXi2u/5hVrviWV76I38cYwDQbXea0cbDaY9fwXX1C/jq+b1SRGq/5KJrTHgOzySepa4LSsD9P8tnf4sl7SpHb5isGxHa64bWcu0eP0Xmxk8MSiHM7pt8MIshRD66sBcGAnqFxgJRDIm42arnjwEEGw3wvkbYWK5wuVitey2UB5lF0Mmy2ze6cm6na2Ft8R65bpqIznVXikl9Ht9Emkl4n/M8yTbWrq0De2bXmyw4wscMquiW4EmX0KtqI47Ya88VO5ZQYJH+2xQiGkQiG4XY8h/DL6FPmqjqtzfBpHDy7nuKiKcI9ejfBsh+LXdmlbNkh1Kw3hZlFSz6OKudVzI8oHlG5u6vS/UHmJOSUNguxz7oJLHi7XTD8cK8dy61UPyUTJQQBifBwIZR3cyWJpaZHhw/mxwmIsq3PFrWfJiKQ1xABQs2p+saAd/X2lz/68oJWGpDn/KLQCt0kzNdMEviGk7LekTDD0abZK7pNVHaXpk68esswF2MVdjjXhGfXEE9y/OdubNSyw41q03qQBIvrC5mPp8IS7h9wfaMJErtJjfheXRHeoYKf9Rnu6qNfBjvqBMHboqBLFDdq7j+GQ9h5OB/G25Zq++FFPv+iirL6JYqKCFHgfrbReumGafV8lqgUeppHT8n1yUx1FhfdlT4cnhLZCYqSSAn2p7jDFm+0kwFNgFOeg/GjimoMItZroxiQQEetGB6sV1wfvMZ2W7/KHLM0j/3vyFo/vzH3N0maBdwi9x/ipc4v/ciPgdMxA1KI5ftwkzRtK76InHqcZChooTlGEYPsPUXkRYa0JhZrVMTbLABXcG5JB5OC2QIhVHF07M0I2i9XktDwnmauLAA7RPaKjpzhFTad8ZRyL8QwVSe69+nqcdO+niD3Xyil1KT/OSJUA+TBCJrjF8jQhKy9KO4yNM2Bvv0Zxsia2qbMC/2ofSf77yxcXJNU63j8duh8s38lpeVx6k5N5PtCXcbCKQ+4ls3u8NDG6xufQ++RW5fGPf9RRa+vwEtnNcY1iPLiPElw3SRmsnu5hYE+dN6wkCzjyj/lDM+o2JYm382BeJTdP1CBwkhddHw8RPn35IT6M4h/0fVDyDrh3Gh9yGiQYTxta4hNIf+j11ijooR/PUrKu12EmqcEYPYbDSAmAVi2yBM2grOK1QDp4WD8d1lU1GBc81haB/p6Ud2lSVmGQtos/RZh5sVwf2W+cLz+xdk7RJbG3fWmEJPgO9CVdTdtAezA5otewE7VxscF4otRyIOY4e78Gcnnt4KHA4mr9HBwxdeas46xCRRmEv1qxNcKMJmaKVrDN2iY+fFwmqFmT3gIf76GorA4qLDqv6wod5evrJGuv9QIyIe4zlnk01RtxoU0Tf435O0pu76ZbiuNzTHD035PVhNg/TEubfqfxlSc9Ij9hEu7GIlxwRZg0iVvkJi4OMLlHxROpbGk96dRArIKJF606TbpE7e4T5Njd4/uEorIuEOmSQp0M8ipl3+bBmnWH9BWxPVryY4zajLR1tkoRvdHSWKDCmNeb9s5QQfI1hTJ8jJASaoTGySaaskYsT33ZbIn9Fgk6yXSlVy30ZT7YygfHGDmU4AyjALV1EWSlgcrD52oMKPjzjMplDkpjIEf/pGZW5QnKBLCrlg+k3lUyUJkTkhTelvjdyaQxeGl8rDqzmMJNjAeRDUCAc+w4e4mo7DsLqOg/BCYbAwjrOI6zhOJRDqGFUfSeg5B1nAdz7HN/CR7OrVDpc+fbX3oCvWnTl/bHFmX/4SqK8agryManqeU43ibcQSFQR3CiPGWKpeKUhXGUpt+iIsFKHXSOVHZfUU8xQQa1ZLNkUtVxqnjUVgO3GK3tEJ3HxerpSh4cA4pMyJZLuXAEZJ3IjLsbVnSWBxW7O4aQdpgDs+0ya8MButsXQ5whFAq8IEJ4+TR3qqJTMoxWqe1/7f2a5W1pvHwnetO8m5kQnhpfS3JWivFwA/ikdh0TMQY3anVN2Z7KrW9+lwgtbL2ryqO83uQZm9jN2TIlYJos40k3M9Q/kq4yXx4dMBHi2fqB6I7xl7nmKCYevNkKqrP8ACdsS0pg280JMDFMYZHQj0EwXhhbJFpULefL4yz7NuEawDggQPlQQGi/dDX9Y/LOEUYdiv1WLG9LsxVPFHBD4l8Ctawz4M8XK3GYV5hPZw3rSZNohteZ2mUUKqBnHzAT6JU6EtEXygGwtbRZ3lSRSKqL5E/k1/Yo9Ke8zPGOheKKx+3skdPi+TJ2HpssfRY9kJ5H2a3SZysMDwSOjQvvv7DFkUPbdgse7n5/m+/TbyKsaH1L0MOnSZ5vCH356HBk0V9AAucbYytsI6bhZHX9TVUHxCSp48rE5HQ8gF+Gkq4H1rr7J7RKoldt/b3irhBfDYkOkywqBpf19i+ThaTzM1zTJC7KLWySWHyUnyQpytSng58DBT9+Rg++cvu0vCyirExCREhNk+LS5eZWFCEwhPbmlpM3buJkhNM/58hevJimHpnqWDGfbuS0lTqvBsk1mmzRWK7gsD4Xur4qUiNZX6kxdsEgt2sMvv0qVq4bSq4A648n+3mdIqMHyQMlq9ygyW+t2peYAmXp74NSw6Ab3n/ABwjm+WZLi82Appfw02caZRqNngjz9A/9zNZwNxt6K1Dollt7heU8HT9iQYV1v2jGM/Lg/zDdDZL0dKy8b3Lbe0ZeuB7vm7CI9ruNvC3NRmAYV2B9RZ/mxQf0+C1K6/lbbxXTjznZc6aOqXDVgm3PWYPPtv9Ra8C1XznytgKdtkYe9r7IgiVuiEMGAMl9pRZOOam9qJk5w2SSYhZk3XQ974aSFbq8q9fXGfPqtyuyNnHo9tzgPMerF/lVSMcUDY8YRgZxta7YTUIRJSSvpo8YUtS1vTfhwpqmDYWSGFa0oVMBrUFMW0YDMO96ELOQbqpD6h0c6r0aIm9rIJp3/p6O6MEQUf3e+xG1EqsdjXuJw66hkS6NLFxGlmrXrYEc9lnJAbw1OUz7dSpvK5CGH8p37LQ8wVpPPeQ1XVAfk7/z13OoQdjwACyPG+5/SNaeCDjBPu8S6Kzrb8gdno089pcNLLa9fJhcPrDk/kvIiDG3Gobojyup4/RHf0jWobzCBPLDJ9mASf+DyJJAQmQvPbY5JGRWJ32GE/ZRDdsV1bCPQ9jBOIS9a/4zsg+rHOPGm7voFgeVC4oCCBTitAFnp/E/d8B49zqESvgEOYHAhG8kaJAU4401LED+vCYSqx12iGCsSVxe9QeC0HmkJIcEw+xTpgNT8YnDaNXoTEmgwmJJFyUqL8mpHqqz4FSh3ctNW4Hn/eZDGA/d7ZFg4RLkzbDU7VLpGUkNP7kIkkndrgTPQB+H6oIMdMExgfALLvb2Au+vIJpU3AtLpgWWHC+LfJatz0ntMrr1P5ZhJPul5by0QtlxdXt1sMyukn0UzP7qw5uK7Kn+PKtAvudleVtzPPM7y3u7C70lHPSdG9tXY9TYLB+J0bgpW74Jo/GH285HLA7KMrnN8Crq7krmeBxukZdQTkv67KH/3UsYc+Rw0vzPdRpAa9XIvHCPSFJb55e6+nJDkVK91/6WxvthDFVecs2bGaZVZYY14/oTOFlMl//dYbCuJlbTPOmqtjUp1E2rugxbm3jdWEscD8IjrJRFtNf95G1pzjETBXYaeVeEDOvc7hhSaG9us7nZ7SO+p7HwR7D92pO3FUhxatEEu9Agb7fhT8xD7JNpYadlm5HA24uE2ZeyqshTgm0rEyPZazQuD7sYbuLOCgvPcy7jAe2upnVsR6i+1DAYKo+YhkxZPdBDa1xJJa+WBsr6pk/5qJGEsPAF3Ez2u4jBLjJPnvKFrpImc8P11ZTajCih1SWKds/t8rYkdPP3V9uhRaTxgiU5ey7+qKMClee315MPqrHhrv6FV8IaTZhArnmtfYaG/OKYJzsSUtEQQq39mGQ/mAx1iySysdW2tkfPMtQ7zZQ1px1peHjQMQF4h2C/zyjWbUuj93XSt9r8to0jKPsHHr8W3sl9AFSTbSRdW1NlQScnddS8GDj5WAyynodp6PgRj6kMr69C29Szya9uLPr6N0k9NO8ex178ydsKpB3AyVltw7rcE/KGueC19O9wz6LBDFTzou8YFHrWl4UQlBYJWMjrWcvXh+U9VJkobU/xzQvyH1C6uanTDJWl/wleQBlMrLwgHixtV+gTNO1UtfvmS5MF3PTOdwV+j8p2gOHcGkYdVKn3AoGvuKqCQq+pIVPhddW8GBDv1eVRvnbM0U9qv2JQbAePtZ3Rxa6HMms0jaHH6a+lCKWdErVJub3DCDI6M7FXA+DA1lC5wMQgkDfLOuYp7vl1n5tYY4uJsts6uvW/sw20Bu0Dc4sQy9Gy2RMquuZuNVjihGUecG8ScDQSwjuJxMFmU+T3aNXiOwLcbG3DKPMqPNLAqTOCJpjY57RxG5l0j+1kqXSPpVviADXeYEeF4O46hrA9KzH7M+w14KQF8Lf+SlXBSQsgBq0ii9KDuroje1oTsHaOYsy3LqenLgPQKxXivcqgEEItBX1VhuM1k2x+UnsomeVmdDeJMhwnbJPt1duMLX8hvEy5b56mDuIYH1PnaRD/eZ+sUDHls2RayxgoOFWC5GqoOUhSowrCFmBWy+vEdZIX9fosL11MBLRu+apHsReh8rYu800ShzJLh3C3nf8wc3p2sFoV1AI6sX/ILmRlU8qXfkmBwkQsFSQHAGKrPVIUlG01XWQBoU4O5YpuMkD+8qztjJdAozj2Ek3eFqXS1kg0MlshPJUu6ut/oVglHf82TYDS52YhlH7d/5bgE5inASMqK9ITb5+vFk+oKe7wNXLXzhD1PDaERjxKd4RxMSxrORinPUHXwRYI7B39qepaA+C/BXhK/73gl7dFCfS+yOvNxHnsTPMmb42HPyjVKV97yuQwmwORoEHOIc9xi/hr5YQe1rBcml+xQJw0Z8pgac4C+EvzthNeIp3i2Mt1hZB59tL4Wa7xwPePapEB3yNZiQv+/kgqT5zERTu31pKiSaHT/LcXEvK2KIG0Sc4CXTiQtryjIYI6BHu/6J2kKSZWawj1NlbgJbhRoDMg7wVmizpYR8JgO4ueyG1yUGSfUHWXr6a8SZJwzFFdFCiLn45wzRkabRo7j6pBAVZ7j//deS1cRo/thhrC8PYt0udODChWLurrCovE9DSL00uCNpSrvaqx48d5GrskjeG5iYk701wjHDU6z0hbqTPPCNvGZh0ZbshiKds3NhKOeBdJiIoQpScITU1TectTE1je8tTUbvGr7j8DSrjJmbRb69O2QsXKZE1gxbvOVmhlmxDWupmHqFid5UlWld9RgTDb+fv0Ht2h+EdeDzHecx6lhcZnSaHaqR6hfNgPbm6SNAnwWmR/PthMTgPqVE0ONRj9UYGw/DrCvDXWnZxZCmMiGKafSNLlWdRwgTYTvkJa/kAr2ZRMOsKj+/u3szR0/LhJCmpI+JRnQ5rvmdr8LxRNT092fTXJXd+h6yTA+9Y9qoOY7psf8nQ1A3+IDc/EmEzDh1H2Y5YDMNfmLCKGbfP0aM7maLjKkCdjjiZPr6MZlIt2N6UKYB/COvW6r/GBoEj+pJKGpqiIYvJzUA1mb3qWJSNr/ByVTDLgCSX8hhjS5yW42OhMo72or3sdfd4hn9VFfBeVaE4D/lmUuIYOdhaQ5pg+/by0zZHzORY4m7q5LZndahzogevtvZ5kT8LniFy9MY/1Gl1bfIhIFqLWivM5r/oXzXyJRkJbNtXlXYL7F+HPNFrpQ5Stvtw7nKyk96jjKyDwPpWu0SsecLhThcoFNwwQyNbhT+mU2LQA+SOOSyRdc/ZC7AxPX8voFn1ISvL6AthBCPCqvSEeOiuHEu6qFaC2T3m+T27oKVE7CAjw6muJVt+T6k4YjB5aGJRBFdvB0VokEFTB3zROVOg/VyR0li936hmWGpI82n2xpGdDEdwzpty2Z+dohdAarVgJedyo90BHWSgtU2iBhcHoa1g/XYv7Lo9E7kpFso9LxAcvx8UuvdoYSWMBkpd2HIBE6PFQfmk5QUHo8IRNg6YEBebeG0beVn/H6mk+bqSarw3aS+nT7rbmO+xQQ7PJdh+FtaKGttUXWpkyhYJg1PGx5HJa6bC24OrlBmHbL3N5Wx29fFfoaAcNgax9EmCiW8uJBEpHTXNtd6ihUXS7j8K6VEPbChRO0ZpDaTcaEKzTeQkcfyGzFyzytjqjHCMVoByAZtIphBfexH4Qp2XXWfoObBTA1NUhPMrrzUwW83NMjA3JXz2LSbBvbZ7sORcoI+fYOUbWNDXPsD7hwxZNwTVxO+R5uY47qG1yaWPuRAYo+y3ZyOwkbOCmo4ElqXI8V7I64ogkoNJdWQbvtSUzPfQKb9knSDU5jGMieYeeBNHzzxZ9NYfXfLOkojnSp/YP7hua3B14jtHMMpKp3Zc720ajI05NsnFrU9NuER/aeX1nu7d1AuS4PS07ZMHU+I94gWTDu0WWRyAirZvH2sw5RBOoV2erFGE1K5reS6IR8Ec0CV8o/pYqSgdlmcfE5XnVKSvwrUdALUmm+em0Kn/7rsVFI3hdA1xEGiukiodKBtxn4kMlQqGia2chHirpLy499UqCYq9XytsKog028+Qtkew3YxrnmQ/OHlt5ptVIArOLfXC5ARf/TosNuFj3SmkN4NuvQQXfBYrjbwgeAsdhlEbZ8NaX+13QxKbbuQxoE0kGpSMb5O0CubWp4ASxoQQOf+MU2CHIZDQBr5s6Nx4HWdh51PQ+RHv5J28riA5yWUTxD0zxmbzIaQRw2NMd5Rnk6pv+DqXJPSqeHKvPrvsYO9fxi17ie2fr8id3BGUhrgYZIHZwBCB1AhxDeeWRYlGGEEp7o7t+RVI6BfGkc3lIL4y9XLsYQq4D2XqFV4vjeQWzY3aO/qiR0xsRrYFghGa/DhTrIES2smCLINRxKczl0zmKyjw7yYuGm+Y3g7T8i6jZO8gFgV8H1JFZZlPLP883nbdHFd3ctJEXU1+srNZJpo8b/ttPQV4bGcm2MEnrtih+z/VEzdBEcpaGIIBzJwjmedjMqXJ2hDchP38KHtN+Z1Ot/wA721lUtPqN5Q1hc5/nUJGd4hAelsEskGHcQpbJ34SXJCowDxG3iMkslmGUjl0QxQNzS04XYyl1xcKzZwwpGHDSkMMGjTEWGoL2EimQvt/OFlnV/a7QCnDNK4PRdznIpa+Qv819ExRQ7XdBeVsax2rTB4ptLbboscKf1pvpM5wQB+g/6qQI8GY5saER+JbhQ+E9LS+jx+NHxFDDFRVGdITZ4DYvnoJtxEd5VhV5GkLXCPfewWlJPb2QNcHkUp+XGjSWDTYTw7BXgAwb5KtpHcGYbFzRy74MtxJQCFN8e0ksb0ug2MSvWU0k2qkOfbD6F+Yb1twRXJtuLuBmaOi0xJjwskdxALdSDwloLrnml1m8jmgt7BzvAuK6IHzdJl/yjkOXINxLLXlbPMmec+YJfqwSSyPIQ1diZdb2aFYHsEYaVgy6zsItsP3KUjDxU5yiZmv2XA0E0Rkqktw7YQR1faH4PH0NLyo87VJ/lbkOA6IfTYhkh6dZUiVRus2SjO2ikRS7GteQi64RoFZejaFtTV7S/X9usSxmK7OU505imTI9/vQxv3WQyLjWLXEIYrDspbG8LYZM23TrEi4Z9XYIJo7M4FJmYK4E+GH1KsAEuaSCDXp9wDYE3RxA5crehrmBFsgYQpwQ+L1IkbfVpHHGPXrIC1VG6TfTGGo05qGJntc9zgiwpY5lzMd+W+F+C1S2hcnzEd2j1P9xzryowoXvWLZ+gsFnS76z6bOzeq8zR31C575yi74W0/tZYCZHRYGKOdqa0UFCw2kF8RLLYl+HjzyryBkiKlXPG/3NiYvclBiZ8qJUWsIpK/RpbvbhCgeR3zwe/kpAtZf/8rZYOnmnIgp1AKIz6G/W2iTxlppqlCtR4F9wXcqhhFWqAPVas2cFTcvSb7yuC3aMZ79aFas1hHsr4aFQK3VI1uCtQNbX/0Kx0pP+l8nclubXWIkHUxTAy6g1bx8+NS9sBUTYp5j0xTmRDGXZGJSjY7FyNYYfBKkCTJCkKlhbkxKb50TfexZa2vcBSNdzBtLPxtS9besg/fu65fBzL/zlbbXHTm9/vTAXYqFd9VSPo/TscQU8jCIUiqZVAcIvsie+Q6s6RZdR+cOB7Um18hWLZM/08rY0Bs1fpjFoHmB2Udl3TJvVbYx5dvy4IRypDvR8EyaGsLkFkLby9y0yDoOq7+ZLdlwU/krOZ6zxndcu1p+PEQ2+LCrHusfZyrXVOo4xn7i2y5JtOgY7LT8kK7ywfScI/3lLVsUZwnJcyCNqVldvDg406PP8oZXW/bCTLCIeC0d5RlwDiLXwE0VH2xqvObgDDgK1eVAUrVwVuTjFCn/u9BbHBfGAwOhe9Uj2O5q8rYb0vlpcg2UZb/Du6EC0K99xnGJ9Ng2oRrJ9k1zWtzx6NQZlr+shCODCHgTzUi2/Fj6rMH/V198vwOe8AC/S+nb+VkN5ZH6Mstsab812M2D+qBRhjCT2iTklDlh59orHtF9UUy8qPKL3RV5v5mdu3PL8jY5e1pvP9uxwi2C8+i7v0Bp9i4qEoHKxjpD65asRmv26k7dFCRWAc2eJOvRbDW/DnNem5H6K20V3I1/K5r89t0/Oh7b+QkoHp6l0vDINZTkjx3ONR1iYFfwhL5U53gJZXD7mt/lZEpMVsD3JCz5U6/QwXzEq0HTOcI3zWJch+DOqHvLix+Sze1YkWDA90SV81Nq1/BNMUZzHj/EdPhUg8rSUM2pFFh1pI3BmHTLCK2UtJsWODljMtaOtYZ8mSJwZ/cg4cMmQRlDqsYxB/TIH9d2y3kvfJQWKSWTWqw7JfkeVt6W9X5vGgNhMjOYh3V8myW5q/nrd3123k485QeBPVhMz7ElerPGk0xambe9jsk4wi13mjbbqfclDFlh5t2j6jeW8zG3HSGXbcbbCMxtcw7I73nyKaKY4z1NOi2UvmuVtPQM79YRH7cMo/nGa4RbiH55hA0dRFaX57SsJxj2LBp1g8MY+RJLZYNHXC7j8S1gPdPzXwQo6urZCyKykssbOxOSkGlDjcZyFSFX6Kcrqm4jaFIpLtMYKhdvNUStLIHR7QSJva5n96VuCHnBX1SF4k7TsqrOaH6DbjKEBeJlHtefjPR/PxsetcA/AxhymPRfvuXg2LqaKEnmKoFWCnJl4jGjPw/K2+lPFm0Cnk7fL3DSZ7/hFXpZYB0/9uYxHteezbeUz8320SU73CVV3uYt3aVu/fDVCtGcMxYSyhGrSQun31Um2N5Id5x1iTGT+PXDiwX/UqEarY8xP6UFVRfGdY97ZNrSjfAUi3POkvC2GYN7x+rgneBLIVdeIqYgRiJsRAdRWNKqVwkBeJScJEM2g2dPxfskH/Zh4e3hp3xPlcPuUrBFpc4aW5SH9iSRoA1zoVw34YFCUQwm2RAWorTWUQWXR91Et3RCYr4YjYWt42UVH/QwiqffyWSHpiiQvvF+TI+w0f8w0aVXrTRIkjDmff3CX+SxDO0eb9CnI+IzamWVMR0eTN3EYx5O3oc9PFEgPIU6k07uQhvR0ucDC7bJIvJ8PwGiccjI2m18c57X/UyW4EytyeRelaT8LAZKb9DsznOAksI7Ap6431ypMB8SSXDeiqzEwOJARjErHGQN6qTbjbrnrNiyevXKjWaaq48Uvkzh8toZX3anKsHF9AMT8IzzLCz5Hhq2vYolnMgyBrM/2ZalJlT5Ry010zUWZWot5kXjv0E2EVzXeVelawLXskFpc6683UXLr4ubWy6sOx15WydvSSIupAnO1OuZEDQfSOZd0t/byTjd3E2sWkYc7Qr8MOVT71ei8GieyiOJTZaPaNUkD0fQJ/5/XGTNUvpCQx7vAMSxep0XpGfGNw1XEUPutV+2ftbWNZeVn9FB+RGSpezro9yITxriXnPK2YIp5J/pf6CgXRp6EtX1NGOLyCUUlZtrmUWyvSNgRpv16UawXtaYx0atdCz8adk5IN3VM7HSOby1zv8PLNyvddhhhpfTI9otlv1ie02I5XW/yosKt3iRO+blG9feLY9sWx0meYs5ZqG3MEaTNMBHLYTCFSaD0I9n4deQy+oH8MDTZBL5k/udMvEhOEpSuyF8zJGvquOIoz26S27oYewtOlyIprddZn6pg4tbOUYml3Gl2o/LcCNNU+24ERk5ejgiXI2n8qAVwoTsS/Fdj8OFKVw4lXOoqQP2e53jKYvccFcSls8vJ9IpBtd/qVGI2RKKKhj/UeVjfTJOPyChHxkS7Jk3m9lgtpEtTmk/yCik/TLoQTy0fc2hqdX2aes+gjZFtVdhidSeSLHazJ5n7qjwSYfkObdL8yTFqgkexl2jyttpdyVekLbOoA2m9p2Uz2WHMrf8cVGjnPF8964Y4Gxi4vARKm6n3cAnTkDbDa5AUr1W1uSyirFwn9NWqEFMB4RzHE1HRBYM5HFIbC1KgUHOTu0uDC+RA00PbM3hKNeDgwlzMklWS3KNPTEZID38sF68uVbqjG1lgEr+pXvXAw5lIBiOciKSAfm6uj34Wv1H9vdIgb+uvafEjv1pSTS5wTKOogyS7zu8TTNhFA7dPy3ar6havpyNNIHOonwlK5CHMO3Oc7/CfZFucw/zYcU9j9GTDhJ+DDfLLzU2JPD3OqSOWH4rDqIrvLpI/PS3rZ3iRN892bI+bGnnMkb7SbKM/BgsLw2e1gyK+C+FqQ2rV9ic/qS42KEdwIJWXPsaHTWkVt2DG9ZGOJTWuy6EkqmQA43q9ZlVJTV6H0/IkjW7LflZ9Y6pkLQXTQvHqwFI6fSJ7GbNcx9P6Ca2vUdEJnTS/fvmCPlX0+8ufBBYYwRL1CKuviOS6R32lN+pKzbG0hQVcL5sJUU2S4rDsPUGj6xF5SwtO0EVCROcZDcQym6ZPuCPJBneXpNInAxxVfmMyBQdlmccJJWG3v9EnABpBjbdmujyvupcPuf4fZ6sXzbJV1hoW+WAZgSrgfYGOCBMTL+nfX/5fwvBNG+wFItNgNwSukTfjMeFGvmTvENnDXhxQnYvELpVxtBLFJqboavylXTQkkAprUCVmjySrxANiksV43lKboXBIDM+ZpJN9c3wJ3h9QRo6INnNo0g/2nUyxP32zHDF1tPvtNcOsBjyM9atV1zdDBgarSLmXhbZmXbip3eNb5TjmYlrlvO0Ex2Jdvt2FgKeZSynXqqtBnMvXsGFcTWsA845fqla2ZEOsPE31K3oEBZIiJ/u0xfBHCHdqqYJdn2F1gnOwGwsS9/wgKx9QcUX5RMUUDJyMzxoQW25jEQP8BjHwdvAa0PGZuA2YC5OWCfxivHaBz9PEVavJuHmFdS+sg8UVWh0RkwzNTyPjEn1ViCPHtWy40qA9aBughTolyYZi+NSHqK0SH1CvOvTSTkPQIF1YQCuygC2YU2L5VascwQxrVzlHJu23VRZbxK2tU8uMHBzEhi2IDQPyWM1Z76dXr0TDjhMLSfowA/NIaLpLbDMWPbppHq+WsCw0xg0wklJKhmcnsD8zMhVIa5P2RxUXY7D+sazhMkbGASIoxFrD017mvAVgBhjLjGldxn6YpOTat2tA280xfHAqcOjNSSGuLgdqtK9wD2+06frLV1DRo4V1IYvQjMKgsH0KlG4UM0gs3XwZ7YfMY4SLyKvDNL8l9xh6A48ACfFlB2TDkCLinTL2SLs/AwtK52QnjD6k90f5ml6Z94yj4hIeWMaBLZwtEwroAT6UMfh28KFsBDOxomx+TJrv6ixngmwe1jlL6GucV+3/ckskCA4aJEeQVkZJuA3INgkjX54r1UOYw0qpnCcjY2VTZWsYs322y5Rp+Fdyp2BM7mVdsY3tZ8zxEBZgzPE8GTHm8CD2Mmfd9sFXrazkAcETTQtjdZTh8ZpLxnCGE1kn5jiBSOi6C1LtXVI2udkPNnhSSKrFdjSq+xdVJYipOngbplK2AZ2RzRjXizTtSrchTFdlOrL0LZiL/QA06X6coz/qpECNi6+201AtG8oE3a9M+wfQFYDTT6KTWDMi3QwyzohEJv3o6i+tx11hvknuUfFE4/41GtYIWKHDOShvY9QQr7H9nGz7VPVmPi0MpLMRVzH1luaswzpbpei0QuuDqiqS67pCTdTU1VCiYzgTHAo+lFZ3YFCjrsj3HmbM23r4sBnhfGvBhgWMLDt9re1ZIO1QDM/SsnpGC8GL87n2dvCArRvLEnwNz6I5Ly998BYHZM/I87GwC/OGVC3kXVmE93bQ0NO235sb+iOvhgmECgpuc7H/SJuxOKZvjaCUjmI+LpXOl0kXujpbw6WGMpGHn5hHd3grl41hAQbdQSFK3n+5iajRtdBazCFgiDFZOBuuBPEvYT1XdWQGvlLReRes6C1Tj4Yx4gmNWJJWVEhBV57TNgnwn6qtrZGL2hHNJyC182nSFbbeVnG24Y4O1ZmJn3d4d1eNYyEG3sFdvm3/YoPi5CZp0pD0ZjRTBlbXVrAyXNGBqTU92EH2NhvRfIxuNse7wPLwSL7QF+SuJBwpYz8HXGBkoQKNVaChQ3egEB6jZbn8UvEY7gwLx4M3THoHY9jSjUTJ4G6yXU3exbYcZbeM1xq89Jdfcf5jX3zHMuEb9/XX4Fl6FXbb8mV0q8gOI8IG9thgMctVMFwcMPlLg/NbVCRRVvXTcpSvr5OMAlr5s5jiURBOgcKBpsYdWtpBxraj88kF2zk16dk2udWoxmd4oDNAsRUcv8PnO4thbcfS2MGTnsGo/lFHNEPs1yzxWhUsnq1YGqMOAetjNPAlNwOoo9vB8dCcmvSMrbdtvO+6AziI/QAM/ZwE/PZI9Wckyruh6C11pgiWYXClOU4Y466x/BLWN9v5tlgEW2Ns4wdHU3tfybjVkjWVyCxWCcUTYKmo+yNfNrpVu7Wrx2jAy60kI/6wWFU8iqUXl9XRwFT/d7GibZUmv7C6/ix08quLiLzl8C5/yNI8Wml5awwemLs45JDZsOvn5LwF92VG7oIpbXQbMKq5GIddJqjAoyY5Utnc6jImgMEhDushbXhMgt4yEzzls6X3aPVQZmBR9VSZdICttwUMqjNECJATsOUumhekvZ+VCXfXhHCO7hP0YGoHG0Mr9t4G0GEH5lrYJVZUjmC+bRueo51jyQ8o3dzUaUZyvo6ZyoiDpNW1TMvUdOZfeetyhoaXzJaxtXZgc/O5dp4tGL+puBj7f0YPJY0x1SZzFSAhpu6AbJhYRLxTyVyl3Z+BK6VzYtL24slcSe+7/J8946i4hAeWcaBDMlcQPcCHMgbfDj6UjWAmVpTNj0nzXZ3l0/CbPewGgwdPRL/QA27HjxUqsig9qKs7Qt7GxZJ7VE5KG6PaEKlUFW3IZ9aBncpebzWkGda71Rzb2EYWEwAneVGvaQ5qLYOLoBA391A2rAugtuLTINZgeSdm4Cw5cXeHjS7zTRIb8tEYVspIFMyakzjkC7ES3Iu5eAkm8O4w0xX9932R1xs1JzGAUjay5iAWKcA+TN+2bs+U9X8uxgPmw6TpodY2CLGGawyETDPkKcRXg1nGfFvKd0DX5xV4o/kw5rstUL8YftFrScyAw6tgDHIZ94F8vSUsKBnDrDqcOD8mzdMKi7Hil2Jl/iQdBAyxIoWzYUMQsflLdIH0N1UvZmAkFXVNmh/XXJijtOeBMVhALtpNmwfc99m4bidPDF3O+q9ldIs+JLg3xVOfCF/KeMpaqlcP2Aoub0PADSqeMdg+LjUaygxMazSHJv1Y/NkDcCSN5LPip2YZz8W9TWsA64Iye0v5djSIpZh2NG8mnaAVlt3c6X2Xmkc5OOn2bnuBzuPdHRaU9HyuHV6ci11iNp37nAA5AcPtosuctPezst0Ousq9T26qo6hYXZ3hLt9FJVp9T6q7gYNk7KKpB7FlV8WGK3XNyMQixP3hAisMezUD7xlOgxEnghgWZ8yREtGzkI5fwFoqpnTVGtUNAuwpWwXLy1CjoczI08o5NOlHV2e7ePgru8TsGHlUdTZuHre6O4qo+WCWYmpwPk06M6q4rNr6Oa+QyRlpgJOqrATEWmVl8O4Oa0p6PpeyKs7F9p+RztEDXj5nOUZQdutHa3tXVYLYEIC3YUhlcztlpTcZyQzcajJ/O2HBhwZipghoaxqLPfD8Y9OQ24IRm7VJKn6XbKj7uZpIYzAwFXgLYZX2e4x1d7YXuOMzrFd4HrZ/c+n63ZyZO1bR8cUIWsV0trY4uAEoy7WEq7eHBcEhzMiJ4ByZtN8jWNa9gHRjY+yxwkEHdDbgMZv7rIQzuyl7MpfuLKOxKU9ttsBz5RxVdZGdoz9qZBIZAYPD6gADaac5g03smM6sGsMs2rJqnnZCTx46bSj3ZBWCB+2FFIBWmklOmz2Kiop5s1p5N6OoA2spY3A7TUXelPz+UP6kdLjNwqBns6gh2qkw6cVQa0EVmRuJdtuQ1picCXdz/9AOYwl+3cldRBiFzq1CVmFyTt1FXwvdIJZg0x30vDjL0/RbXuFRtAHW5MNBVj6onuuV1wHTEXHgVmmIFE1B3Dp0fusY1mAoM/CswdwZsW1fazkl/Q7FP/Kaz1ksfJYr7YYIQCUerGul0pu2DmkPwhi3jttthzcD69vOt5GSwVde0JoS1wUmxe1Z9EStjKdZQvDq7nUUtWDbyriCnXlF1Zj5xUaQk5lRZ2YxlxjMgFE/mHpbw4XdFZ7ANqY8IkNgwptOd+eGzQPcqlsaywtl29EtwP66+TbpEl93sdVApvUez/3H/PaK+U14RroAFHUgnmdAbPhc1QpkU+Q6v3WcbTCeGZjZYO5MesFV3Qr21drZIOCJGHY3DWuqEczMmztpTjPiQh33WXKdK7dtxasGCzHazjIYzSdyUV+XcZE0D4abZVkDq0hTxrDQ1qlj4KYWSr2m7MwMjKYn/k6wHR7vfVShT6gkTvlXJ0W+1vKdog6cEJ4Ft0sDL29ofrYz6M0cJlQ98U16wdbbFua7zG1Zb6gxKeMxzSzOdmJf5mc6kewmfRhqLXemuLlJUvwFXel8agRI8DTRAVmdJQTMs+e+knZhjpOAjLBGZ9OFnQYP4pTLBE0GpTiVQuDwuTS1v56UoLdMpr78UUE9jllOp6p5stHjSL3lXD6qvCDPZyXrqHg6fozvouwWneOldlQXuIn4Se77oasJOoGQSlaeH9pWQNZt+z6NKDTu0wxsaDwLJn1RoNkOBqV/2HHmqEp4lhyjX5gXwc7MzYQgwS24b1R/MbY7jOIfpxnuS/zDzsCiqwixoKSODVNqm90py7PpaGbgbdP53AnLjWwwOj9PTb2ZeXoXnT8Nx7IgQ++gK+g/alSj1fE6StKDqoriO3rvfpIojlfyKhATg9A2LKxozvZp86U5WD+UGZhXP31GhsxkwRMXM4SrZiCxOh+xrIKGYR3ZdNwEwKSjPm+dnNWNZF4eBefLpAtsvW3gVGaxsSxmJ/ZYwswnbNlWAXZWrJit4mb1iBYTvcCcmvSFqbYYe5+uN3lR4b7d0O0jvkOrOkWXUflDytfyKhBDj6BtGFnRDJTMgu35NFYGfYdmYEA98U060dZLsltSczHmO360Zj55Ffj5UEfmUzSzDPPpOzQD8+mJv3PMhxtK88ZVuWMTNU+IFeSMN8Da8x7QDqSHqhh8+a1bN5TZeFY+a4ZH/Jv5TkvHuE71hOtUuAYqulWzjorqy/W/UFyRIvSIGSGmprQoy/KKYvn1a4mO0oLwR/n7y6qoRWYmqC9Qxb6qVb580Xxn+Kp9xEzgUa569HgUVeg2LxIEYunLn7S48C8S3gihaYu0KD7mcZQmf6JVO4Nwp3gofdc+RtltHd3C2Noys86hi6qgMZwlZT5p9zg4LfIzVKyTsky695YhxDyMFun42XMR4fhuXNfDPE3BXuHvRpWbsFUZii562HBIquFokbS+FCBNevcTXUfImVayapoygxXTJpX5hKq7HJzyMYQeIZYiCK+KeyxawZ6NAIyJTcVVVqlo3oJoUR6m+S15RBDC1ZXpuakx2IKs1FnONSi6R2ogHMO7VDr6qESnsdw8S+KqLkAcbZEpQVSYRhDG5CHZpJICrSWzD4DpUaM0uUfF02WyBnvKlpsOfEiQoxg7m3bIFm0fZnySpJVEiGnqmDaqZKoxjAFvNfCfoqy+iejUq/rOgmlR63BaIWs7cLFBcXKTxFQX6umn6DFcQS8nwWpf6A0SKDYV8I6NmTdjSrzLCNS9hlJTRN+iIomyIbT+KF9fJ1kkI46+lrbhf9QR/fI1S0A5w5a7jsKi66ZNmOC2Rsp3hiZLsOh8mxBDJ4XbOzpQAvf3d7rTQ4IKfIyDVY2+UIvmM3ooZbK7K9MiOX7EMjaL0oO6uiNntmYRyZVpFby2sf4tZAgz80C1CRrpCY59i1qPKJJhMOsFfZte2gtaqkVEMyBAONp0EoY6B/NGBrwJwk89arADL3DA2OFHVAyxqxCa0U+2EJh3rUzQkDcepGialzY0aMTc7jC9wBzwBgcfmU45JLU2RCKj2Dj9tna0TPJUeJij3Lbavo0zlMH94zPJ6Y4bfM4b8NghpiiyRSvdcWTJl7S0hVJNyLhJkkrEsg0T3Ho7wRC6DZoK2Ih6c1TUuKdG1+R60NqjwF6Z9EaI4JRK/rHTm1aDYWOlYJ1lHJemo1oXMQPSawhB0q1G5p4DXImj2x/tTKZyrYIJZtGg+Voo0PSF+o0HZQgrWUqRwMPo9bo7fJSneuU1bDgcARhYpXLYKNH6rGutUNSJWmJl6f3STTrxKaISV9qXtlxvxYKdD0GjlsyB1OJ4fYnWm1SyCiA4U8PVkwoxD2N8DFXg5EAMpDoBWynsfWMI/cCLvCxxxVSBkofRD7zZTuRW3BGAwWEY8FCBT8Wgp5E5eg1S/ZmLce8Cz1gjHzstT643UXILLqKuTL9qmo1FuWDGIEan04+owqdF3VKHIQ36HJV49X5Hye0dSMYRgCm6dwnmhlLSUx5Gi3TktAJh5JyEdML4KYtVsngoNjj3j2+H4bM+f5dvhFQxXO7WnkPHXAurrw+vhstHpo7iHnGowN9is7lzFPV6V4d+yNKLTeGi3LSJzsuBbWK4gOX9FMbEMiUke/2rpyIMrRkfWElKP/7WWkc9GPvEpONvkK+4G2KRfJoa8kGqK0JkBK7AFUTU4AcIyY3Vn5h5mipZbwygGAoLB1KmuXpXUWOEYmouGjJXN5f/8NBZEHXPGUjZ8HvnAQ0RWFQAGUBKOpBgfC9/hWUgloUxVkQZtwCRKga15KPTV4ZoJ7gYKOhn0AK0rIYR+5OVdU+46t0oAEqCgIqhQfAgvTgPChW5QJwTU6jLHKKgDQ8iHwEHCdGDcZVRkIJHNBMROG8WOSnGgPpxjKfWmyxjdABx1FznQKE+rJfpqEgeAEo+GBEYIgzjn6UgDIALoIqUyD4EOUzSlHlYTEUVDtRgOOMaAejDIZyJSK0z15AlQEElAVY/Kr6Kik6D65kBuQTECi0wBL06hzWlFigCyQciwEKkYVzoFDQRUU2sFZIGj/I19dAePPlgeghw6nHw4N4MAyIF6CMltYvWPPLAu+o98QDlGYZUKL5gBVCV5h0FVeo0jBXSqiXoAlCpM8HqqQTlflCOh0v6EIhKXFIHEWsQQd3a5lVcJMAo5CcHCq4vxi1RJYp5VNOyS+cKcnWw2aQJWl3mbD9Foijh5aNSVYOIxXgXK2ilxAptXdIpCEK5gT9N6NZD24yvqxSSZj3OaZdc3zDsGq0gGVjBYIRQvQCEA9ECtIPHGUrAX43dvKXifQynFcMjcIVoN5LpY2QQicau7KFoI3UhZ1//lZPMqLp28CZYFARWuc7rKW/UuHy9j8IBws9K2wm9biKtYkGAcU0jiluSmGthWjEqtm5FRhcCTkm6WYnW61ZD+IeUZiKsdlhCFQXFDLVBKeaptRu+YT2TCaDmo9IzmCO55uEu1oNIdaAA4eSDgcAhEnFxRArygBhnOY6OWh4HNkkZSl5HywDSqgoWMyejthGApErsgeiqX6MguN1A9WvVj5CzbghwvJgBITUVtUNW11cQVxoLpyezps1pCa4KALyShe0B15YOaBQXkPbYwCtPdTCk6gbUoQPQ7ZcZUwRfJ+qoTtvFo8Tmyt1qCs+4zJQdMZ5TCVN5mBE6j2Ia+yq3IrBg+nM/A+1tQ2BxyWVU0/9QVFGE4praXYxRaClgiklBaXVAsn4SjLswn41H1SX9/m1S24sq+p18yjmZVYlSdWQcd+40HSMUXlRhMS00MaMuALPDxfFPNUUOK8R9WTisBSc6L8v1XetK9dW4rvPglYrqFNRWKqY8zIT0p5G0V5JCi7lQ47EmkxKdxRx1IcX2E6XugXzStFzioXQabguWst9UwJvpnQuJ6quLaL1J0ZBCRE4dDlI/pHEFbwpx6CDdb0iS4k2fPh3K+P08gD4SSPmA4AoQfdiELQoKSRDOEFMxtKzY4kUgk6EotnFrssy6VZ+j+wQ9GOg8HKB2BYzhvZ3qYKwzkugDSjc3dZoRT9lRgZZm8pqGw5UiCEtVeTOKtSlrxoHcXTYmpcOrCCQfnQAL0YvJD6UglIhqYodX0mDnRDqkqYLpIcCpx8GDe3MRiBSgj5TUPi732iBDCaTCyxCsEMDffvYgQlUaMqX/vVlF+ZCN6kMU1SRaU1DZrMmJffb77GxK6gJQ8nGJwBDd2JxxCiIByOagCM0zpycJB6YZxhhaSpQuA56OKhy6Ochyxaa/k9CEhdGMgAGVUCPSk4FFAtBglM4vJHO02QSVnNHAGM1jM5YwPNHggokhUNRLaLBJGVVig4EzWevMWEKIDgadjENgAjvQhmYUNAirA+Hkg4HAIdp0SScVdAFRTRxK17SpkqcchK77KilqTIO5ZCeUofNqSKsud5aHK8iHpayncpbn04AaeM7DbSg85yejZJtP1ZCMDbTl+Bp+mZCATQMA9WBmdl2C9KAjpRcPolk/A6R0FerPqTymeUigsB6JQCadV1iNrAkxj62oy8N7dYZ7fBeVaPU9qe6YvLoiaXRV5IPT1ITIxuQQVlBNh1jGTqFO9VB65KshxbGchnAF/UDBeir6WUgmdRsAKaVzFIqSX9kJNSbnuJbleEeVpyTsuKHJ5R7Jcq0R/QyIRk4NkFKJ16bc1kk8BtOUJADScivVUSW8fEiqahClJFnFFURTtjCxHgu1rV2h+kp2g3VcNpZ4XefKMXkWtURLSchByMc1BpQlwAJjV1V4plyYbFr6qyHZvZwIY0D9GEbwKpLoVTQYJeTuK6Oy89G5S0amtSjwgLozMAfvdZ7mcU1sVBi9QaCR5iCkSkBAFWCpMH4pQSl1QKQTC+2h83oWksIa3BUZMJLl7dPM7MQ/QKEJL1eBq0SItBYsm4SHM5TySY58rvBwoQ+qdSkHthikanV60m+uNSo0rLBPSGEtxqWwVnhSbCY/lzxNv+UVTbdMr0vZJ1MB5xYFuMLVRF7L341FgVuSp1WS8tVlRwDfrbkCnsoBdgjTugr5bogCJLLscR7VfmLaHrTIgTeGAugt44d3rk6zhLyqrThCqSqoFA5FPViZEZ4NUuozKvTTnubBZ5GuxCeN9MSU1jUfuAyFCYlNT/2GLQJU106qS8rZ4XGmK+GhJpHmKnD5oBW1wCS0o+epFMRU4YV0TOGtqqDkU+lHIJzZwFRakROl5tKFdDQxpIWOBtqxzzlm4W0xvesRDK3xhgArSV0suAdedK4WMPKJKTd+Qe3qpMjXKtKpwBXamrwWHHbBvfum9GeWo56XdJe5BeEYYOOxDXUCE41BPDHJ+jf2rhRGFBFIIWB5WFBcM8/+qYS1gGtig0n/up82hkcCqdp4oArwXpaaONtKEM7g0nxBXtLD5+JkHRVPx4/xXZTdonM8TcNbfcAhX1tJcSbX1YUfesh1qX31eEFqDq8VhiUl/cOYhmNow0GOKoWg2hjh1OSSvLWo1C20deQj1VUFk7dLX45UkFTb0NR57iXtK4x2uir2g1WY8IISdR6DHvh249VJAm8nCmj5AOWVIBrKXp1UUFDRwMTBtEzLV+NHJpW0G8MaDWxURUM3Y2qNkQK04h7WnIjbRk99mjIdW8mWNVgSTMmCbDtg6Lt8yhyIO3r68mr8lrRIVQW0fJjyShAd+cc6FfRTIIZu+cfvaAcIfrOhnAJaPkB5JTi2zZhyCsSzUW540fTqrHuKVEY3AFY3OLGKnGajB1i1ZAMwQ1JQORsKqv32usFCbqaiJENFX/bbazIT66j98NtrDBKjTVVH6ad8hdKyK+hepx1qtl9eXGyimFyy/I+Lly8e12lW/v7yrqo2v75+XVLU5at1Ehd5md9Ur+J8/Tpa5a/f/vTTv79+8+b1usHxOh4dkX/jetu3hJVnfNznSslTait0khRl9S6qouuoxPNxtFoLYBdYAa++XP8LxRW9onvktrzfelJ3DbY5GJrIIHEOCTQxCHfg5Hd7TiFNUV3/FenTKzDwaaDhCR4WmXw6QsTMuKQernkRR2lUnLUPpnaSd4VHnqf1Ohv+5nlPXvviqazQmvweY2G/m2M7zeK0XiGsUSa4drTheiaUWmAuz6KyfMBHeVxQIfIgI4ccAjDH31UeIx2+mmO6TKqUI2b7yRzHYb56GqNovphj+ISq6D/Q00NjImExjUvsML5DzIvePNJRoR1egGbMZ3NcH5M1Zq3VZd4d0VmMQqE53nOUrVBxUH5PVlQ+s2j5MnOsTY1/5hk3dPa7LbbvRbRpfREgpKNiW9wXd/kDMFNCoS3ew5zcEPMLmi+zWMtFkhdYmnJruf9quZYvo1tgOdOvIqbfXnPind9BXgtbCLeh8xuS2XYVPSrfcLLYtXpMgsHMZO9S1Z5mBxP3Lttd611SbtLoqXXEYDGNS7ZmtvEH4kTkN9EtEodJltbc1gmmrj9jFO0nC0WJEIEfSP9xa1jjY447n/yJVm33fcUBj89FKBjgmIZzmj7wOIavFopFmzKJx8V+t8BGCIKwEtbm1Bhh5MocsEoQ2uMC1s2oYHu4vs9o5cXrklRdJiwurbqtMrHr8VGdNm/dQGzdF5rj/Zolf9ToAuXkgD7GyhWZ4zxJo9vTNe4PMauLQweKLVT7KuX0efJh+SPHWX2dJuUdrxUzn5+xgtNImYuqoK7SJbW3BdjHOIyuW5kWzTRrPuwe1PVeXE7jEnuMwK7BFdmYfYhv1Fla3yacxWFcYoPxMq9jYV0xn7dmFZyhYp2UZTIklvNZATw2B+7Xo9jW3S6smXN4epDFNXzdGg7SpZI05x6VB5cB56irbyvXnBQIdeGInMoxKrEwKEWPx49oveGMc8xnK1zt9t044HMIR2XmWKnzN4et+2YjZZuV1bgGjgUtWzL1Cl5Kcudp6imtMQYXCQ1W2wV9JJSMb682ICbpi5bRwomF/Ev2AYvBM5o0etRBrsxivaZp/vCehqFf5t/yil+6YvEc5wa5FQ2zOWZw9LWKeVMaW2Jj41mB+Njv853mFpQ3XaSor9SBI2QNZY+s8jQSiLTIY+i+zSl5Ptfra1R8ufnWJD8aoRoXPeMzuxAJ7cuIbKS0IzuqUUzHlM0ygFhzKAk/cRoa4yMu/v3l5r/JdPt25v67h37f3S3PROuuWR4L+91Cad308T2jLg2fbRTgg82myO9FO8Pw3WKcBcJ72epLJmxz4xILM+1mJcE4LpmdS3nmPEzz2/bRBge+VNaeiCeb5i6Jq9l4qtgCC18gPASSz5rvFft98VlSvhdjIqzV9SeS1E2jgpgePs/r9dWMXmQc9rsFtqgSzBbdN3Ms7WM7/4Xw8aGKuKsSodAa7+dcjrYv2y7uZp4f8mV0JapJeb5pX8L5Q6GFJ1dUtqPhvLiY74vPI/MAkMPUKWtPu5eIwmVcstzu1L2VxI+T/b51R5QwpnAPNXlu/fh9nUg05KbEQm8syetF/IF5+GphuGlCrkY2m+bTEl7bXZ2TvFhHokoglNpjvojSCsbalFiY/FbrJOsk0djaNyqxuhSFLyZGBRY97JIS8IQcFcx9KfEOpUiIG+g/2l9u9PGW0P1GX7jUJeXHCJ8N4BMtV7TkOZR05WN+m2SgEVcstcPcZTKSIhcAtmavGlJ2+OxVklwkBluVtOY0OxUN5RJZn/lsN/MiquHrvHsUFsebKON9BbqPNniwOCkEb1bms9U1TIXwt/skiwGnZq7Qoo9C1MWRZcRFy3Zv+H2t+2qN6S2I6a0Npn8mG2JoiVLRpZErstAK7vIMNZcDnFLAFlisn+gRwsZ8nkPKL6XX0zXg6+reriQXtV5WcxpZKco2W7lGb4XL9jE44MJ4KLLFCbvL8GUWdrWH/COqKlScloBHsVhqgfmuQEiFGyi3uhJERRKDmPkyC7ld00jmy/xbxKmd45JdczN+ZtfxHaN/QtVd7um2OcblEq2lQbCtMkoaa+wYZxyeO09vM5LY644kbeDvDMdF28OZrG7nyZgsKhe+VNefyqAaTokOsA1fXxfovknewW2Yo5JdE+cLMXd3I+rH1x0Wx9tmuOo03BzWA3M7EldQVbE1YZaAFjkUWeBsXS7aukei1Q6GsJAFeaVvRApk4/N9yxGl+fJ8PDD3iUtCRhHu3FH+rMsuGeC+3v16fubbeDISyV18V2Rz31TgkdHocRpxD7q4SGDMW/mWlMl1ik6zVXKfrOooTTm5DwLMGg5wR3OsSda9WGpha6vTVIpYKFzyXq9jIrTG+pp4GwcULx3O0NWRK58wxH6D0fAW1Z26KDzq4ANqVzyEvZLV+Jhd1GtYw2KKndQrCXoYwr731OUMpg8I4TQGeSNSIAcb4UHMXV2NS5ZXTi5+1FwHyQeL9RFl9U0UkwwVBd7RKugCRAZj3sr7ig89b77Y+AsMT8OPXQWG7xb9aetASgNfZuN7+kedFOhLdYeKXgfjvFAhCOsWBnUDxj8qt1i/NZZbeOHHRNE4WK04bPxa1kLbzG6X1Juf3eG7hdGlrcPPLPvdwlsrS5vlyeQdH/ltAeU26++xC2+S4Ich7Klx/LhJCmoMexc9lTBleBj7VqgzCMUArS05lIV2E5UXEVa2EMwyQLGFNB3VFC71hVKrXhMHv4PbAiFRNxVL7bwJ+4qiTypQbLMu+yfw+IXJFNjIr7bS0VOcoo8ou63ueAkGQbi2cIaKJBfmUQbj0ApVMCgaQRJDEFb+cXfJ5jiL8PlPEIqjIhuc8mQMfJmVj0hCVnKUdrWbKxvBZ0QCtZyH5Wl5XAq0pZ9sjIl9sk6ezbgiK52MGJ6ze7xiceXm0pHHLgWyMWPm8Y9/1BE13fB2zFGR9YUHrX9wHyVpdJ2kAno5lFtL8CBgCIt5SDIFdrHU4jSQPzRjb10nhcsHoNzqlJTcPFF7x0ledP07RPhsKpyU5IAWFxZR/IOmGCaZ74UQO77Q8rwtf5JHOHibv94jb5OaQvDUJut6Dc87DGHbQvSoa4GHsKQbWrVVE35rAoqtVh3Zdw7rp8O6qgS3AqHUGvP3pLxLk7JSoOdBLCjTyJoUYXY/w+cw0TIGQ1hcFuDTEK2axHy00ajExv4ooLLG8SVdAWiGr9bW0CNyQwvZQZsCiz1og+IkSoHejUvcMPbXcZfJGrisU0K6tdhe2Gnb4+EsOKw1Lx5nFSpKiNEgAKtdjwieERYEsY8S0OoEbNieCtDqJHaZoGYdcpKRK7Laz1E5PHV/lK+vk4yeb4FxaIGtxoJlYvO618Fmkyb8WQEEMMf/HSW3d/wjCO03C+oA5zz7k933ZMUjaT9Z0AsYzwfr8fR7hFq8KMAc2lIJFinQkp59Qd2oAkWdbVMOEMVYk3tUPJFJFOxnXJk51k6P/Jolwk02X2aj+Zeo3c4AQ4VY6oD5E4rKukCkbxLsIwiHFg7WopuRUOiAl/xQ4mYBLPDX2SpF9PJStPYJhbZ4z1BBQs5hI5EExLENQgN1Ez2E8yjyxtSE5a9yJCzY1rjx9Bu3lx9Ph8XBkUdedRpPHvKvp79722Pw7oErs7KwY06JMYkEJw2uyL6nMsRQuT12SPzwZc/H7bG9gSyP8nqTZ2LMEFRu5fYOYnXD1s0Cvfqnyr+MX8cQlh4HzR0b1hYgjwO2cGukXqAnuDze39q9x7eIv5yIZfhqo3yGDRg6zCt8WJdiBYptzJxJJJg26Scbc10z1zLvPqh87yanxtU4xspuxcRSC8wJdUISUA6fbXp5iy6SP3nLav/V0S2wvMwv8Lk0rmD8Olj7/n+BrkOEQktz83mUCeF4o4LFXVwnNnztjgPgNppZwhuTdsNwcxPVafUtQQ+fBC1RKNwahauVnp7RIg0Sl2gRWc1plK22ucMki/i3Z7gimxuTNRKfDxm+WogdlJP31zJBlxsV2Hi4fEbcnX/7ycrrpoiyMhGc1kYFcyy8ZcOpwqyTES734Kq5V03ALL8hlbidC6/udJLWFNFE4YYw7zEIPSx9SizTsFbXtMz84YaNGch5nSJZVkADcCs3ANjiNiqwODs3+YMk6RbEUhudvHXBhFEDxTZGuLLCJwWqzbIvlolOuHI4l9bOpCEREIRTC9ETYZAuIY2sFQ7KpaVuAsCznQLMbZbAV7lBAAvD7mNVRERAcXbd4fP2iGTmTtVTFjOYXISwsvq22h5x3bz4gB6BF0u5IuttvXkoFtzXu6JnrCq04qq5qSTXlEE0zwGdu/KpwrH9+md79QtjFArtPSxg3woXJQbWVbbnltFfeEyYXyBJK1T0TnbcHiqWWpgekxW6vKvX15mQ15YrMsfZJnoYY+s/LmQMfNZGvG0R6j0PNiwZWMZz2EOIfC3KaXaAoQOwyJa/kyG9tukGIuTXZwsc8FF1R4q0L7WxwJ0VqLkpEmMBR0XbxueBLvPH2Fzu9LUYtl9vkV2oul2lnpYnWOTWQ7w+z1dC8fNXtdk8F0EYlkXozrRqLNvPuGz/gSjWUdmegZ0YOBznerLsErzqfwwJ7fXEUkHmWSSD2XsXqXHtfYB2zwdo7/uyPzaPy90UNBpAe5PE1HGZsd4EUNVg1O5Kmym+7Vff4JE0UkW4OdTAWgrUxsQgxAjxZbbOiJ0PhcQfcVT8jJVG1WR5PmugwOzyyoEVumlWFNwHM/5fIArqOXDiFDwYjPt26HCza9zQyl+alD/Azo7xuG/jYOWlZ3rZefkWFUmUgfkrgsyXAr/7PFohnWgH8czU659Dd55cvyHyFT23jCG7mmvgoCyT2wyteusKH28HlFsduXcm08VpCb2fPXxd5mw26Er/ueZ8EbgiCzk1QVZIemL7UldfbigKqnFAWelEkK3Z/VjW8dvnWEwOO5q6+tK6yVwm9u1yEZRLjTbuixcb/eet4W+JojSJShdOj9tFg1pbSWpEgMrNsZO0P/iTkCOZ/W7DwF1af56Dh+8O29VRnlVFnkJpWmQwz//AG3bNBVhss6+yEBkdltuqtktwUz+zSaR3484fTIRL0E0qx/k+SEQwBLZr3EyDMC7+qKMClee310CEBltoecw/WP2rLivxPQuh0OLQTg/XMsRi6TxulPOpjHQ5QBvjqMDm7j37IX3DUCicMtxhqfiu/tEcH1nYvyZjL/fkVaeRcV177+uEN6qMSiz8Bcr+1ZuvBWdn4Mvs+ymg9MQH5Xbgy2zkZ1ahJmsgLzuZAqvAFCC/g0tyh+NH3H4paCnMZxvZuE8UIZZbShomd7iPqOnROMgaRd3tPxiDgcgOwceqsHP3UPNw8X02NyQLsTJe+qV/zGmHxYGR5VWn4eOPUXZbkweVeA2J+W5hhBGdXa0dXWn0IxAQabXZ1Cm3tzZflnGx3Pb8sY1jbvNCNPiwb19kgbN9ibateyRe0cEQFkfE4blbeSNSoOWdeMO7tz5vx/iFdgSiVhZZlB7U1R1utPWHOkcxpaXPLqHC7LBz2KGbZjfptAyZ9mGZTGUtRJq3n+wOC4QqpytCk5uEN1dA5fbYW6OHrhEAzLytL2RiL/MfiFuG7HdLbAcx1tlLGc5RqZVmfJ+sUCHLPQWVb81qP8mLen2Wl55X3T0ah3WsqDvNor3MN0nMo+g/LrX4xTc+rB/xPTtYrfCmzO2FzOd9LIrt0qBsEWBtUDyui0NSeZrVQVvkUfQfF1sdhASQtXxUYHFEabI7c6eT7qOFUt5Jz7EW3n+1uA9I8EmYuwloPtkcbsuKNCwebofv9thkMwmV22OnWdBAvE3JXmbZyazIX1i5yqlZRdT7Iq83oJzqS3bBmUAhWNq9h5cs3eclhBRZmqD6NCrYCyxDntmHEE+ktlEREEBto3hcxaGk8jQycfsk2PPm7qmspwutmtYN32fBNNNpv1Yk9aZZJrQxKB5qVGCJT3TAYD4vdy0a5uTV5h9vbQhCUj6h1Obiq0lrLUENFFvOy0UVVbWAlyuy7y+MViy1MCE2ucRhxEKhNd4mR7nUPikDsue4o7ooUBY/AY8nghA2LTT1zrFQ5jGzJfZ9vowe2/0IMi/IoWw8/cAITOazLV/X11VeRelpFqe4YxB78xCOLRw/6lroIexbuCT1++cfVGOBIT1bVI4NhrRtsRUJirHxEI4tKMbCQzi2gOuKaw+GcJRPWM4nRMeM0hOEQJIZgIdoGySmAXiItkEyG4BbWFKbKpxmOny15A+Y61w4Dc6GzhXZ9o4sY6h/zXdzbOfops5WaAXFXvNlNlgfomJ1lidZVX5HBcJzyzvgSEAs9rk7FP/I6yG4QXrOU0N6tCgGLUtA7HdvmTsXVG7hzHNzk6QJkMxxVOCgkW8kGvnG2n2JnAuw0MUHXywOjjCLQCqGGtKi/7gW4Bjdf7XDJKqgw1dLTMCY3Ub4KSp/oJWamjIYuz4f3d+/FXvcfLXDdPy4SQrq9PIpz/gEGCCAK/7/QhFAZb7cjYPfJQWKq3foOuH95WRANiaovtpBTHeQD3kKmKNkUD4tQRwkh3Jq6TDKfohHLRDAGb+4WEEAN/ynR3LUpMwJa/uamRRzX+6E/fQ64s2jfKH9vkB1ktZfE94hxhAWK63GOmOR/EmXKY3OiGIooaMKzr81kUnVkP4tnqNSyMagg7WRjhuSBkdBTxjCpwVoRHIoK0+IXstTDEgBZuNkXsR3UYmkVlgQwOZclcB+4qMCe4tfc/KC7X1dmT1WcuDCS3pTV80erbTSGVeyufAJkwl5F65l2GPUOVpHSSZkm5WAmLfxISKRdO1h/XNe9ckkx+0owCzkXhyjTXV5l+AeR/gz9RP+EGWrL/fCIUANujVXUN0h/2uJz2sfkrLyf08GQOnyqIwZmmkurMI+m0vlKnghYrk9OS/5hZjrfXJDz2wBmQtA6cJcZmimYa6ubR4L+91Capdo9T2p7kAmEwrt8AKvjjKf/wKMG4ZXPfhztkDjVgVkuAV4DE4OZc/90L0fX2axMwMWYnvL8GnZ9YAmnoyATCYAgP3Y8WF4A53PoHIbbStONiQNgKjHckUOOIEoKb7MQhdHGTlpiOo2890WG9DBUYGFVRKVpfB4Qf/RhpsGslOFE0rzJgA8Y6naS4wALk+Oge+KuhO6PpEGJe5KQ9H8+uRZwOwS4fI3kMyrNGEDeBstljpgBu+axVIbSsr669pXeT9d+whecjtcZXdnoGZ7BQctAXFtAySDBMRCZdBezfpeyU6RP7pLtQRkIeCKbDaqrqpU7QEAbLxzY5QNiazENGlCsUXfsfz8DmSRZ79buF3S147JLsM5XDLfreXrEYmyhSRsU7Bd2zNWRDxP6D0a1+0Zrjvl9uy/ldI+jwMBcmuxSh0d8+7yCfTeZ4ufsabIWoXD2I1EjC5mIyMs03BqWP/yZgicVGq/2WI5xCWZkHJrXGRnd4JO8+z3+c9yO7eCyM1Vk07JZ9V0WFwe9pJW3W5JfllE8Q88MOiilC+zwEpcHyE9ZVRgeZuJ4GtXvszqbpI+CwOiFQr/AqvH31jBYvJYRXOaLPo2gbv37ruDAQRem9b2453JjHyOqrrIyEMOyDfRzwiVk9qirD8RGwUKrAvNQGEVqXB2r3MUlXl2khfNbPG2dq7QBi+ddkTP7ryJQyh0xiv3HlEC2s8bnEJSLLXh1Ojmpjn4csw6fLew+qzWSQa6FY5LbCjNLF84XFECspvuRItt+jn98wgL3xAb/xib0+avQ7HdkvssKlrVRYyuZUts7XMQxnGJjbIz0Bi6kobKFzu0b/nbht2oMAujgjx8ISTihiGW2G338g4IB/MSeAI6B4lngGMakUf+5ey3kZ0Xwja/DEctAtF1ilpRAeOWQ9n0+zJ6PH5EAhlGBVaXlkd47dzmxZOQg3Bc5CD6tvSdPDltbR/J3RbBEuC1NBhnCBEz6wtpQuuCZgABzCnH9i+P+a3exaxNcV2QoM02xCHUrRmE1e3mzBDTNOuOb148P4vlewd/a64Ly20B2Gw2uf4Up+gjym6FiHC2wBLfGSqSXHCX4Yos76BobT4NCVtgZTYL/OCMvYajuMkKEmV3miVVEqXgAufLnvE6pxOACz7mt35LnEHksLqVtadZ2EyT4DlBLF7KOgRHsttbm3eZOQnmYAxKs6x4MSmMYSKjLY1Gbp9f4sTxuGjO08RxRgwKXH/6j1vDQt5yzU2ezSjHcFMf0T1KBedb5ruV1byoQN+qcYk5RvJyHohwVGCxcW/gZ1k2Ls+yhLXi45EIj/L2H22ONDeoKFAh4BoV7KZFXMolBbnhzGLuAoD5bLNf0heGP0Qlr7KzBVsjomhyczYfSIBE6yw613zrahwT7XVMm2JclVi61FIP9apPsLezdk21OytotEkr//04fozLgd11CLb7Mv6kyNcy7ubLbDhThnNcYrW2g7wRFeBlt/IcRcD9W2R5I9aaHQ6fmlRYQmgVX+yEu48klqJnIJ6xxOhzhXoeAzs0LgdAed2JbBRwKn+nFP6hDGeQIW/rLiov4ju0qlN0GZU/PL29GEwunl7K6tNwjf/h/gBzufCSN/1kI2Dy7PhxQxhVTI3MlVkIfyFtrm3KXFvDhWL73nzJjouCF/yjAotZw5vYeS2KY/a7hVUgot6iRSXgG5fYYTzOViC+7rtl/2r6QjDcQ6bMso/ijDCfbbbgD8lqxb9sPHy18u67Jax+hooYuHjnCu3xgtYVodDC/pA/fEOFuGrZ71sj6Q/iNMRj6j0aJ7uwtO40Ar5pm8cxfLXFJG4Y7Hf7M/Z5nkozyHdlNgvxdJUKN4fNt61hw69FEDbs0TiwoaLuX4sNL9Kay0XafFniulr2oIL6IYWlkuOhDBVJHMhtmMfmkixPi2LbOfs/0FPzbuUI0/DVCpOAxKY+kPLROt2jrclqIT6+vENr9C0qEqLU+zHxCJUDB2vqT8O+tFHulNR8mvMQ+RdiuPb9US87A/npYmCA622rZUG407S8y7woU/AAz363wEacCsU7W+azOa4P4pPgH6zfA89v87MkJo8QANf5bNGS4QofqnV6mK+E/ZH9bn1b2yWh+Iyqh7z4AV7cCjBWzu94wT3R1dI9cSmG28Ew1q0cP8Z3WL9D9HEBdWMy0K0RbW2nfP3Nu7G5xHVIq26rkFO92+r2XquY39EhuSNZ7B9zXCi8QDQqsj3vn+TFOqqqhH8AQiy1EISez35LF2h9nSblHb97MJ+XFKy74KjzLidPeRxnKzyj3LxwRVsjwiibtJ8CKGktmKuuJq2+7UfZwEaa3dDsD6P4x2mG+xX/COeiJUHqwFHGmKZhrmD5JALmPwjse79rbhKfoqy+ieg5obhEa7wP+drxIIwOrGqGZltVum8JeWOKjwEbvs6hNix1Amhj8cNwE4/N5UCgRbHnoq3jolaWh2EiDpmTy6cGw56Fto6FzhGZqlU7db4RySwup3hkNYJp+KfXiN5INKU3TtjeSrBZvaG9c/x0VORleYHSNAhH8dhcNjYtiufLVUttS002gebdV89NiUXlsiWp60809WyjssdypUB2UYDS51iEwq1hj3/UqEYr+tDYQVVF8Z1/LgwQpQO7GOKZhm2YxnlEXJGdMSG6RcQMLbKIUGjD4ry2ZKspnSSiP1v3zWJ/FB6fsX12xl97/JSskehCPXzdxoUXbLn5LbL5NuMkLxI+E+bw1S4wTAwHs8UgMt3w1SacjA8is6st9qL7ZnGJhjbpE9+R/qM1HrFLowILG+MRZ1k8sql9GHOGSfph/rA8cvPPdYR+WfL66wKv6UuaK43z7+g/2+ECusZ8trhKobt2DL5EzpdZ9XBFrKxRmj4JnWRKtkbIs0P1k/IsJgcxr64+0cWc+Kyt9YO27cFalESjAjsfJtGFyWr3ygs+wIV+sbiyLlGRCQMavtoofmUp5swZvtrGjF2U/HwNn63G9w7dRHVaYam2wtyYRGkpDBYC2Zp1exStN1Fy63kL2mFxugGQVd1Ws+1z3mV9nXWWuiltIuMCXZKOkbncj+owbCtrY32z2T+bqHSeAYDiXVw24UKCplH+pvKYc1cqZRgHa9UbyLACFLvgfqvG/dYH989q3D/LcS8k6j6jh/IjqipUhHNignE6CD5TRBPJP7B1MfeUCm5epd8uAceMh+3d8Oj7hKKyLlCTl95302dQOW35yvrbuuFPkZD0nJj1BQ/3xMout3MX0O38v0twk6W3QOaxuTOkAsWeJ585T56uN3lB3jW6SXxjZ0eoHLhRU39bWfEkT/GUinjY73Z3j1B+cva7rQ8/hG9cYmsaC5BO6UfCBck3XywuiaIf/BUR/WIbLfMl40867HdzbFjinCQoXZG/uPMYV2TPDUd5dpPc1gVwUy4BsQnIJMi6MBUuDnNUZHNlVtZpdZrdCLdvw3cLXmmSquE+kLRqgsoplG6NcL14yuIwgUgDIpc4JFXtiW47goUhXeR1ESMhGwbzeamQJhql/FiJ6EYFtiMV01iz323jYk6FdySGz7a4LqpCEvTZldhiPMzzFMLXfLfRBrMYPNuOCrZGLBw/EkXnHdqkeYDHlnhsLvehWhTTSIlW1wPiwG6szXX+ilwo1ea0pPHFHCsOX22NNv/kNSXms8XJpJ9dSB0US3f7Btc378iHqtpcFlFWrhOasxSimQzGrxV9G7YKZHMgFt0i+TLbKw34/sf98ofWBG+AxiVLX70Qfkzu0Sch28OowGr9CK4G3bct27OC2AlGqJx3q72dgJIXL90KC1pxZY8KbQ1rYi/dwgDwn/cJHp000gAot9loW/HVsgK333KFC9g4vM+titnHEyto48xnqzkiclUwLLDf7We8MUeIPvBQ+VJ2hS83NyXitprum+VNPHD/buWvEFXx3UXyJ8fDzGeLGcDLiSaJG9O9/7r09nmUrzf0FQKVFiEFclCeD4r4TrhBFUstMKcoyvgcn/3H+bfsg7LM44Qa/sSAN1S0qmOTLPiKTcyM6amIb9PUFOLZOHgWHNAXViLbKpq7aowggLZgtNcLyCGWJWTue+Xd4cuouEXQYdyowywuy87+9hrkB3OWubhL6J9N/N8Vlq1VkZB314/IYm/86BWmSoPagoFyVKcBFPK/AVOgb8uTb7gGAnCNQZc9Oaeh3txM0zHsFSOrVekBRWgxD2AD073zqKetiNVz+nuEASYe6JzfRLd4FpvowyQlymv/DKfBbPNVZFNuM9djnJ405ZCFnHYOtR9jWncMq9urhMzni9Pyc52mv7+8idKSVzd1o/dmnndJSTXGq4PNJk2Ih2qb3Eezqajr8WzUQXeJgwzYSdWA51z1qANwk7KbnvtGS6y55Yk4pLMuPYcVQwy1ZOxwBmfZMCJzh32reaHvpB8ntGjmZoSu2fb/y+hWfTyBwCVpnwYYk4OIiNj39OFEUOPOBZltjGkxTcL4SCqrIdMjLI+gMPpt1CGfy1HzHD1ExeosT7Kq/JDgfuD952uJVt+T6q71lFTl9NJWFrN4CVUM+ELbkOcMjHEF4BN9h7dR/dSRIZzA6Q7hNmcXoU6IwwuH1JOPeGwhJQ6PexsZSD9+PQt1tlbiwxUlGSp4kN6Y237p/y67D23uInINnJZDPXLfs44oQcpNFFNTzQqdJEVZEU67jkrUgLx80V2SdNdurWXtj/Qobd597gA+RVlyg8rqMv+Bst9fvv3pzduXL+jTrSReL715+eJxnWblrzGdxijL8ooO/feXd1W1+fX165K2WL5aJ3GRl/lN9SrO16+jVf4a4/r59Zs3r9Fq/Zqv3qI1wvLTv3dYynI1yqrDXBp3Lr35JonHPPXbfyCBGTomOUc3L2T89NtrvuJvAE+Stn9/mRCS0uVMHyCjeR6bm1MChWgvX74gbEeuAHvWe61Ez15pNs1k91ER30XFf1tHj/+dxVcV4itJQm+zOK1X6DS7SDDaaNMhvSYXTZZdOy07lxpcUKGYvgjtjm7wzwkwzsukSsNQrIn4DYDoE6qiNpykDIZwlP8uEM5wtBMCiN254xxlWFAdlN+TFdnaPDA1GP6ZZ2HG2KD7XkSb9rkhSd/McV3c5Q+jOXAf5WFOlCDPddnnEGPEnCUOOhxybranOHurqZb60SNsqdtZ2Q9J/ZcvPkWPH1F2W939/vJvP/1kjXQcQGY6pcazgLWhSggQeL4z8NZhBtrnDDUrwUw76OKkg88jfdYp+RP1qvQzmdEhdoRphFdMfz3Fm83j7y//H1rp1xen/3kl0OOK+Jbkdbb6txd0Lf364s2L/9e6O+yDvsE79DeXDtHnvIaXZnneD9Ozn0nPPAVZ39OpOvk2WCedV7z5cm356JmsUq3cfeMyFy2NjuqUPCejkevW6L9myR81ukB580qfCrmtXniSRrena9z1ziNXif6Xn2zxn1epj4YYUM1nntRzRzKxitOs6SZY7RyVgAVrZ9edx3bU1+zl508O209Hz0kUrw55QAXstCRpjc/S+jbJPA5+p+VlXsdytvc4FvH+hc+EU40sYp4WtjHD/fKLNer+POqH2Hiu5ReVz2qeveflpECos/L7bDSX0ePxI1pvvOxRGEm7YTVReeB+ZSJEumxePhbdZjFQ/vHA47akfIRcnqbPhOEX34JDS9Y+hVIAY2sQ9ZDYV79kH3IS2HbrxecHaZo/vK9RWeH9+1teeSFz01ohm1BUkKtARLMVNHhIIpoqIfNqR+/jbBUIk/MZwUoGHGTlA391vrOSgAzIXgo0tbZEAnyu19eo+HJD1kbpw9QTH+l6T6/2Cud5MBD7drEdEw01vRjpdDNyjTE7ypmdlw42myK/99sIxilL5fLNzPxDs305IbNm02fGn0063KahmlrREoryJiGL3XYe+oQhShOZNcu1CXfDIpX5PITCe5IX66iyuSCS47qI0ip0Pw9W6yQ7ytdr5t7cz7+lDHImO7i5SdIEc7kf6fxPZO8QDV8eoZDLbwcJ3Z74uldsJjr0Kbvsx0Ifo7Iy22fe2CMPukOQnn7Mb5MslEqN8VEOw7LXAKVRH4HYLTvNQUAgUyBMRgh5Ytp1R8Rg3h/jbRkMLd3ZXZm6khodAUyZNBgycA92wkQue6MsjGNfGyrtoGV3Fb3WCEaPqCNvFjsYjbjqPj05YpzEvAjarqc3IZG9DYLsn8nmLC+rKIXueN0sWnd5hppjchB8J9FjQGwe+5/5oQbK07Cz0nMSzwVqZyzbrdXbYFkGufp4yJt3TU7LCRweLu8KhMzx/2yLHy8RVCQxh9vJ2tqkE7zMv0Ve2vOCjg9LGGvH+Uv+KmvfyV83sId/KB45vc0w9Y7uSKjZJBzCKibPhEGm0xQX3Juurwt0n0QQg/oev3fBG+wwzW+JTvhMWHTx62ez6CMzY4ZJ6Ja53tTaKb38G7trixbXEWt0c5HCn/MqNMohY4bnTrOdF9GqMDzVZr11EXm+nQ3otTvHMfEMSruzs2K2HQ1pwfd2psBdoMEaNJaBYPXD+C0pEwyNBXxyn6zad1rdeWMSpfjijj40EXalnWDo0DiDX3B1jNO+9+w31eE8oTocoU4Xeyk90jw6v16saKOHIAoIeZIwu72o14G0jyD4OmSXWMtMucF69i8Uyt7ecxBvS8zMxY86+BKJsvomikmYVIF3mAo2KZvf6zp04X2VAOfJCRs8Ld8nN9VRVHidNjsc/jv7OfqjTgr0pbpDxdkol6FrBgWKb1AStLfl9sKqJpNTJTFRGg5WK65Jr+6flu/yhyzNIz9jQIvDb2q+ZmmzfDt0XiP71F3ZfLkR8Dn5SrZIjh83SfOO47voSYbRyGTYIqTOBhShP3d/iMqLiCTnDzGrY0wOl6BcfZ9bUDww4oJ2cFsgxGp9LuMaIbpEj6F8pM5RXBeF5w1Qj+ToKU5RIzb85B2L7wwVSe65THuMdPOnaL0W1im9OetfcPGRZaEikLCQpfnMorTD1ljk+1M4ipN1lJJUX/hXSXN2vfk7Ps+SEFa8TTp0PYiD3Wl5XHqRkMn24sckWNUhRsvsHi8xjKy5kPI8VlV5/OMfddSaBjwkeXOaovgO7qME101SBqeHORzso9PulWTBxvsxf2jG2nq1+U0D1v6Tmyd6Aj/Ji65/hwgfqHzQHkbxD5pWiWTm8/QPJYc7gu+0oSE+XPTHUi+Vgm5feGaSdb0OMTENvugxFD46cLRqUSUovCqK2ZwAH9ZPh3VV5bLgbNMlQ6C/J+VdmpSVP8J2LacI8yUWzCNriZP9FevbFFUSe1lxRgiCbx1f0tW0DbTHjCNyGzdVGxcbjCdKnQdidHHCtNFfolwm6xDXHyzu9lIlEObOSHWcVagovXmxlV4jrGhiBmol3Kxt4vPCZYKatesl8/HmicrqoKqK5Lqu0FG+vk4yeuKZlFlx/7snBMr2CQGfUXxHye3ddMt3fEwJjv57spoQ+4dpadPvSqFlTo84rMAJddcQxstk4kCdbYlVBEee3KPiicyqvellXNvH8NLppV+zhL8BNejHuLZPPw6jErXbq7ehoMf1CUVlXSDSO6WqbJ/7q2/iYM16joTeJvpmyI9xUw4WycM6W6WoySoLmMV8rwIa9GeoOK3QOoSZZoSQkCEkvou7vLH8YKk9gSNmt7s/E88LrT+CS2axjkb+dvGvJZnWGA/O80a+f65KwBZcceiacpcgO5zYpL3jKo/yepNnbDiB00lewBLKl7abJHrxTHdBP0Yd8JCt28Kubh4YtM/mrUVKfJZsERtxS2D/mMO8whpYcO8q8kRJ6IXSsV0YF6u9I9PIUTHMnc1ZQl1THJIjdRV9FHzi53aR/Il8RjBy6yov8wt8fIwrHrPbMyoNji/jW4RQmXeoDn8eZbcam70DhwT0Rgxrk9pCn6+dsFmEMtBss+3jJqrT6luCHj65RYSb+783ouuZKEPtaA6TLBrS42KqXdMPbjsXnkCCRyOW7Fc/ykna9UynZf3s4nL4GT34rODT8rKIsjLh/YwMtsJ+HVwxSLzeslCvLO8u6YPJbGNJntmSAoM/TJSirqJX3N50Otk2RHl26kR72l8/nySR3cgcTPd9Td+Z40l7Xqco8MOHFxs0uYGqTdABR3nb7jqdO18IZOeorLDeTnVPNke8FKuZ4atDeib1KHeaKgZx9ETYofHJC428o7DkoOSJvVXyvSh8/FgVEXmzdUq9kr2AeyYiTWsQ+8VeCzzK07z4gB7Bt0N8kbebV/OwTOD7vYk3xnbtNxdS5DbqmfDQwtpUe8Hn2gmuuldXAjkyx1PeLssvu+YIWTY0bk0QsZykmM17ly8vi9KHZIUu7+r1dcbkWHRB1MaPL2/dembWJ3eR3DNIwy/PREIP43OVj01dL+HYk9YzEKBDQ9ULP1ynJRaqzX2CzQKyZa9ndju78H4vuRczSQ3W1/R7qqE8wWKuHoJ15xe9thzIBqnvuTAEF7IUte/DuPZfhhufIRtO4qoS3FOBofveVyOsr8bev0Lbu93zr9i7H/y1DoA01O8miSkh+xPGM9miFtaUYNo2MsEh/4gSm98BlQjC5tzvGXPQuGd1V+f+3ulT6mQqgj6TBQAPMRTvbc0LkoswyjNhkZ2ZhVaoXEa3z5jylgcoW+J9i4okysD472dC1AnyHMJJBufJneh5RJsypt89St4Eu3OQvFE6AucY+WcbLHtQlslthldgdzifINvOPgacs1/6P/258AlnuFX+z3WYN/eCpQmjZ5ovdfXlhqKkg5ziCRqWH57JHjqFa5TCrBnGd2mL/KKgpd4GgUx31cqrds+EF30FXPd/T5erTxH16Bwk4BU7y17BDXxbzr0OdcQmeS/wJyYPp3dS2CZZs8+exZw+sqrIU4LJ705Gukxn4JO3wSNOntsSniQAO6DZwuvCzVdMN67Cz2OiJUN0loIgrWSFIeX4chxr9pR0mhcXf9RRgcrz2+vQ/WyOrqt/4WliU5OHT4NHD+EzNOTo6zbJNhOEpfVbjth32pD/TvsxyX4EekLK/pBnHq7SPRfwPORqN5z3ddI3VGfJHzVKKMqbBOlePbG9gC77hw6+Fl6O3gAav5dpW3whg8KJHoqavFyhPO7BSHAnZMePuG9lKG+gfTD5MsHkffbeZyKSlvasUIZNmjnsyENcTRyqR7VDWKN9xhIy+bQxS2NBUj6jWL7n9KYxjSMLg4rkjguDKYg74Hamd/wrvfy8HS8CAzfqf02/bGNxTfTIIovSg7q6IyKy8WY6RzEm2DMR4d2m7L6de4rw4zUTFuut9ZPZOmUOeAHRtmaFwNi/EN66zH+gMCuEojuIY1SW4ZDiP+/xqbnwyhxjvOhO8qJen5GnZp7HCrvMN0lsv7zaan7Bj0svbqOnFc3O0GcHqxXeO8Nnpd21IAS6Pih3PJMFQgdkz6JttR1fIGQe/U3MbSJVtVrk4IHyuZHEXo97fvN9GfxjVFakF55W+BaLZModsdHkTp4nod2UQM9J+Lwv8nrjKIHausGjOvyfzgh8+Prc7jpeazmEQCFrD1Kq9mJlEj+83RRPdFk+Exm1E+LhubFbQCueMec2xHseTEvHAofouFk2CD71bf5yF2KLnR/azLjt2dghXxdX3++GsU386twbAYHPJSGteYHbqvmeOA4rBK428W5AVE0O38BJnTvuPKqLAmXxE/RuliPiBuE5FjKGl69/d16Vl9Fjuyv5n7C/RZJ4Q3dhhg/tFV4L6WkWp7irk/nyjRo7fpynsUvSWJ/IfKYRjhqdZ6StbJhnhG1js44MN2SxWO0bG4kxLPgTsjdE6QlCU9NU3vLUBJa3PDW1W/xhkrJTPpmcEX1SHJu3QkXHZE1gTb3G2s5q4ncSztFDVKzOcrzBld9RgTBr+bmOHN2h+EdeD+7VoU+NQgPBgmI7JUDio2TrZHJzk6SJdyK8XuvfBBkj9aEhxxjynkWBsBw5wvM/1lOcph1jIbXDTATpUjDFVBifZ6rD8gdayUjn3dOj+/u3wZAdP26Sgp6cPuXZkOchIN7/QlGYsbN8+S7Bwq16h66HB9bd4kh6NAcx3Q8+5Okq0FyJyAMyAoP8MMp+BDtKcXiDLTEW7+lRaJTtszuh0Z5eR4E2pFZCU6Wg9f8LsyZqrOwVyZ/Ny87Ebz6Kx0ntJkEfjN1kDZyjkonR95RGG5JHJTxxRMQBe43Pnb1OFL7rZzWpW6LQ5tSzKAnlydudFJvjTBiatijJWQUvwk3dmAwnsXVNnS11ey802OPCOVpHScZksnTIh/QhIpFS7eH2c171+f+83LvjGG2qy7sE9zTCn6m/6IcoW325t1FyrR8k/FriQ8OHBPPBs3mKYfEXCWlV+9bban6eXu6r0Jh13ic39BTxDFmnG5r95A01vebva4lW35PqzpGFuOreXRm9VhfcjjMnsz4TBu30JGaWnR4wkuHxuYnsSO1/CzWx/fC07LpKs+xFnrkfOmT4zLcJeBI5x4PdkKDjYCpgjzFcMMoFyojCHqqHDbpw3fuEypLJNO6d4aqbEar0edqcZxB+/cJ+JtKvH09QB5kF1bWzZWPlQwSYk+SWNMh86nvMvqHJry3nGM0sI5n6mrU7LzX79dQkG7c2Ne0muwsMfwfYJb7xDuA+LTtUQRSjj5jFsyFdkNdb5kTqf582Nzd909PxuXSpaD8iEZ5heNRu28c6ynPJKLPgBk2pqGMHU+lFXfTy7upl25VH1mz6vKw8i7szN0T18oqlGA6jNMqG9D5O6ls5ubtOyENY2FsG1v5x5Wltu7Ixnpi/L3SXbOjd7PNYeQtK8ssiin8k2W3Ay0XqTDetUkJvCFGoK8zuoYxA6ObYhboF8IysGP2QnAJHmpoB7qdEu/Hk1gML3aOqi4xklEfPJkFKgDisQBO3uP4Twu50jqIyz07youGVMEp6y3GInn8NzvsuSE19G6wCmLgEc57v7EQ3N+TgEwbdwWqdZBIXMz6hmXVam5GgCBFuti1uLBYbZE59iI6i4lltkv7S8iwqWsXBy/LU2IXcrlnZuj5Xq+wk+1+v/u/2rq03blxJ/5XBPC4WJ5tZHGCxyFnAdpyJgWTisZ0Mdl8EpZtuC1FLvZI6iQ+w/30p6sZL8SpSt+RlJm4Wi1XFT7wWq2Yf/2e+9gj3CgN/naiog+D7C7obZvZc3TAnvKDZyDgHXZ1bZnoFNqZLzO1EtrI1ffsR++B5Uz7E36+/I0pTFzaYyRXuzkNePI90XJkuf5W1pWwzSrp/mltKXCQo5zBpiizChtFyGTJ+pvbx+wVaHHXszkX9gqx1KN/WVQuvnf3XI3Lw7pu9yMs3VuuNwOHqeZciNju4Uw/UbG5RkeRypwKzib8+wSfcRt3GmaYeCDRTgwf9wmMfWzGypEri1PHGhq29+CcNxOL4p3f5YSNfGqURsAg16EGBwbojEJu+cV0iJOtfNwLL5lFjm4xDuYh96bCI1a6MXSJIXmc1scVYatzF2xltsCbv0FeUjo1AlxeVqbeIEcc6RZHXNwAnk/D8vzmE5w84Ppq9kz4gX3kYMVJRUaDCF79ZziqNkjkW9b1Ttht3EttkmHwbl0KsE25T78mliMQNpl/zb2QMolXy+j5k9rULlDnCeqMzOpD4FIue24J4nXdD9kaAOf4q802RH91hyNYemcjDXQy67rgAvIHSgHhM41PeoXjkzUa7h798bkLSeGLWv2Fcuvt5H4puI6OAc7RoP0GrPZwIBbtAut89of05RQ9x+WUjva3dif7dYSd6gb8H9c7j7y6JwfLs+vuphhjg8cZvya3Zk7MLganJbFHj4/+Y9v/D0+7doPU/8FRwd86itvqoVOQYW6cP2XVRjBvEW5Fc85nLNHLYLNbpW8iRt6ssPQPyr+tstDSYhX9ZXjpa5kzyUnrYXxKBaNh4+ypvyrfJfo9GRazCfx7qUeMWFTtqPeHgYddxkpzUjNb2Lv/2CRX08Fbk3752v0iG/iYeWz1y+DrPTTeVUbdRcNy2puERxJ+h22rc5amLywZTe9TC6wav3NIQq6aPxU9ATQio+/R88M7Ux12vS+Rv8/BZdf8mu615XfrAGlahyb7mGxSYsXeeTCC3cWcb1sdZxmB7eEJH9CkukprVRpBGdLLpTqMclZYDnAlPECH8tZY113BgIZw3ApIgExZw/TZ+EixT6+twgEvt3AZdN47F8Fs656q37cO7/JDfJrs6tPYyfLnfVsf0Mt9T89e4+9XmBrJ7HP4Hqr7lxRfffXNbJMe4eCafTpcezeUBEMRl5GMkwvL6O9YyOyASi3usfDAzCzHNne9b7j/KSOhwraPK7sfytndvDpnfrx0u3uU1AwujmPubvMmLI+4yKhy6J/bOOWSBz/P8OU3Kpzl8+L1efAETtM8g96/zOrD9dbbHnTl2CrRbg72PydPUjQxASz+FCLaevox3X24yzH/3ZYvOQR6ek8/7aHl2L6QpLv3fx9n5MSZL7eIBHfGYvZkjpyDDwaekTkQiZkkbzTjwo7fute3PPt5uH7fD3s8u3m4X36GUWLXp6Y30cD9dv/SyWvhtDJfQw3CRl+U9StOfPeinB80HRzo19lbMTuskz16njPll/KpHEZXdMqiYcZ/9eUZntCfJSS6qKt49behhNqWb/QaDqTzOsxurFR9QfeRF96xb9C/NfOpyFfAmcfEmaWqN8XGjo9JjXT4nWVw8Ox32a79IlyeS7/EWEHb0tGLs8iVu5Pu7LZK8GBnTq37m4d3nuGZqcChv7xecexf1IQ8h6B06pc920lqwDSHxlZDNeizHy93ON0uTNzwuI3R9L+rnVtTnUf89HhYeimRklBHMxMu71WYJs3NMksrWHjfdo2xfH/nFadp3mkcPSVrSjcwTYGo8dpr9u/01ZrvN1K8NWN6mLhne5b3NC5m/udnNW4l7wVJZw0VnWWojW7gwbrxu7svU/DMB1X6NHuNzWuHBjSAQ1wrw3V3Fx1OcHLZydwR9Fo6uk/Ck58bMaKab/lbb+erf/JKoeSbyox0su2zM8MKtmQSbN6RiRPexcUsWv4zz4WGvWC9N9XH4WjuJfIajrJfA6YadsQdev3nk9e+WvIwHkj/Qt/Idqj/cDXo8wMp5DYwiWYwaPUb9VqaCcM3WImp9Ndh3mCPXT+MHAb/7QcAdxbfZfvPnZPoexeW5QG2qq418H7r51iUAXdjwdnc1LkK7m4a6a2wx9Bp/Llm5oWH2J4wmhdHN8YQ3/7jNx2Qzb8SCYOhNntZZgIOwxqavWfrwkvXBZ/yDpC/JaYwID/EXNKZ+4wn+IRu3kscofpOgdF//5f8VVNfpV3n2mBzORQxdvTu+P0rPx6xzI/fB8Q6V57S6yR6Faxu3hGhNfCIsXR2hyH7ZxtcP8Q7o/jnb/QCe+CbWHiwRXT43XAaL/+svN+VHsvH5z18ecN+73Frk52KHwFfa1uI1vNTi0R+uw/Mn1WuEseZ8KcprqipQdfTERF4yfq/C6Pqbu65A1fFrRNLE6LCxgBGJnW5GRfRpeNxXha8RvWF4meeyCxCjcRz3UeAHDNff6+Xpa3RK8y3l7WjX205vXx6V3k/zLZA9rBtvSvI6cTeGR3Ou9D/DAtQt30cHuPHraaPLUZcH4CZ3ow58DeII2AcSqKrTQxFn5TEhYRHHWxXiOMrZC39VzTGB7cMBcw8Ro0sjF/MS9kZRfF1F93FZUwM2+YreU8/GHW/dre7tLeean0chcx+F1P9qNfcNZnMveuvRuMi/JtgqIf30b8p2hGohOuYK1sMhz3y7eBA3GC++Vsf4z3oo9XUg02GjOeqhfc+XdCrz4fGxRKPcwMht/BgGl3G1e7pP/jlqJr/FHyGJZbUID4U67CmJFG63BHDzrsWr3gvMbuzNbIri7GyxfjZ/pYWKdrnWRNqkw4K6TLg8v0icgcF6dLtAHf2sDTZsuZMTWXiJZ9DrZCcOVz3IkWqdsBoP0c2Dtqv623LLy8oyMu70pkGn/gZatJzseAYjk+8Nqlh2c18zTPCsBkRdUi+Hvu1YmPZq25RTrzJtuX0uY3uSFt9OgqFmiJ58nZRk8usCS7h0ZcfD+ANt23LqS6YxO0tSVcd9lbT8lnAaqobszVv3Z+m2ndk2tda+pMW3PqFta4boyZZ7+7+H2OlyUt43KnLcmNtaaVpTSgXo5HeSoakccs4cuxa2nThHr4EXMHsuf817m6fpp7yOCDlrbgGTDOMjPzKs6EVWfnMJqEbXDdEJtZtvl696q/Zv9XtIKjG2qaMXUcPQJIefUaAE3Ak3FeLzbhp6aTc1Q4DjMs0PPwo4fPVlbbPbvHR47DzUDLg6ukNfE/TtLUpPj+c0c9yIrqJjGYWdFzdd9VGi/BWXrcVDHBzSgm69N+eKiOpv7mj6ydtwUzvYDzc7Tt4CDTL/G5UP2IqpB1Z/5JacZFi/KMt8l5Ce7a5RSIDyxtnrDpXELy3qshJx4L/O9r/Uy9chbVEn0T1KH/82/Pj+nFbJKU12WIR//PryV/6T+ZA1GU1/uSD3XvVpRrmL96I5sBp7qQyA5Kw8IAEr278ITeLPGBXN8/qrPCurIsbmFr/5JNslpzjl7cERGg4PtaY9S77kNTqhrL6SV+lt0i6da0psv2+G6wGdPV69oEBlgLXknyTmJJFtRUCjxRZRxpZuA2KMTqvAl3DLRe+5y+ge+FSobuZrM70sFk4CPeUdpko+ljAIIAWTTABM8ztdSftml7gLAOtDXBwQv0kcgCEFgqrjf0CQWgNkboBqTkqnAmeepuuYnGtJWZCRH1Y/BRM11jHr9geqkSi0bU8FREkjoyBB93OYOdK0Fz2gpVXEaBbE5LPhhfNOwVsYvJXZVah10kn0KzWWA9OjfNEk6IJ9jeRi9RRBMMeZYAL0GfhaSRo2ca5aCCZ1CzKg1yX9/EOg0AYFs8FP7qU3Fe6quELEYzvboQj2UlwUxmh5WWyxJavHFKOOBZZmg1LnoucRRP/2t7+9FHpu4NQ5XtKc+t/WDgDQq3ThXa8A7fhveHFgsP9EJ4QEI9xswOhdn/qnILqldVcDPFOaaJLhHbshUQKPM53CE6BK6cYuaVLtfjcTsjQLZIsBYrO4sunjGWAlf94wNaouk7R+qwk/7XDClGb6shr31osGo7ZY48+PBhIYKKsiWImFTl6t0KAofdlmJq9OI5vJazZcdW6B67jg6KRlZBh+XP1FR6+KSVvzX3a0T2ISkuY6av8vv/Noy5lLh+63aW4+GIFZQbiiMDcgkIXCIInTx6TFlnYxcAKfzAmdCfXijwInyELLgdPgUzvPiql72elxXNItnLs3u8xCp/9x7WMK/CRZ1v0zjyb9e9SLEzZ5namkFd/gTrWry/Tj8OMkg4vwDhySJTC2epUnAJf63bukTfXb6NlhprsmtRkuNgwzqy6fA2aK+AizwaydXlc1lkFLNqFsMyOZzfJsiQNZjzDNMDb/Qnx+fE24FHeBlzLuxKTo6v5xh/73nBSofhwrP9Je0thFCQyKw5RvZgyjtbIZx+Y+RIhwzydfUfH8UIdEl/YtTcR0KlNgtQe0GA194UKqahhsWM1rlGxzY+LynO1TVMczuKiqIvl8rlATvDQaSnSTHEUJdDBdOuUJlFQztZACccipUWbjoBiV62oiw1B7OdBtsbqaw1HXD2Z96zI3nDPduSCYeQWYdrb8iRJ1owvBR38OIglOuayjLU5oCFkbOtjiNbI511oMrlYzrc0IqukHK7t7n5mHqjqT/GNM7p6KCa/+6GYZdmzB2q8AGW2M4LAMpwIGFXIlxnZo2EFHKhJYHgRq1v3vZwSybpausCjsrWaGWwDYpp/p7Ie3ZSzM709olzwmO1LUH3WsB2yw/JBcMsqNAFCi3hqgCIv+4VT/GZnoRT/L0+PBDAihnv4qdDWQsiMM8xTQHUJj3wmrlDVpH2aw0MHVXNvQwPkhx+bRYJt9wFZpMDfmqewL+liBS1lFDDKDvthU6UZWC5RKFiuEGSOpAeAycy6S9CnQmT8CxEw7fE6UwUlrpgXap7hI4qzqx9ar/Pg5yQjh7A4iCtkgaCnJt+RWolLURIoleZyo8LeavfnigTr9vDsWo3Nv1Q3g+ec5JkHzP2aJHKMMEY0FtmCTw6PcQIuGHi320vC33jHRBJKbHf3WPOR1kNMfSQqEQJdPfQy5WDROeuzoAZaLOWvklfgUp+cepGoNw+BiWuQSdU3EbAlDYtgJT2Gg3GhrgWeewdywnn05OeFzjJkWhqtb/UX38fGUotf5tyzNYz4/K3UG0xEw5y/9jwtHA6ze/EhgjT8bFh4SVGD96njP8izMlFuxS6YXgokgs1gvPSML9esm0rgM+pg0Rku3AFgtf0s5D4gm3Dba4WfujWKX83gdAfE6aRkZhh9XHxCvV8WkrdkD4vUhW61y7S0qUqdugp0wTdkkIa0gtWymufkjwq43V94SQTfVomo08OoK84Hv+nuFiixOL87VU82xcWLikjcuesRTacDIpSZc/QioVM8GkLNh8U1enI8khrFv4MkPEvo2GU7Ur6vHxaDLekDwkJ+S3dQoII2KMGh/3gYOGmXWA4SI/Pf3Ij+fpCigSITOa3+eZCIiDYoiBIKOzDABwWPU0CDXEoYQQG77HguJlxkGHfO+nHbEIeQLWHzIxB7TdSEhNPnqxbJfJ12/ELFmA9GHYh8kz49q7ULaZJi0v6w9vU+jhklDrMFn7v1VbJqnBc2Uy1xz1My+wu1ibH4s4wN6m2BpiucIDg660FiqtOSgPCzBZqKpMmqZtDt7OFUQa8C3Yj9G/AAQMx9T5sIXkXDeiY/ctS4ZUb2UogQBL1knw86gyJoAs3y3jnlgM6Fbhx1w5nbr+D15rK7iYh/dnovdU1yi/V9J9STRwb0bNf6HnRQMs+HHcCPJVHGXe12MMAF2xewQYdY6sEKuXRporIEkB+WZYNFjhQBPaLNe93QVl4W1j/SnsNDV0JKgNtkayRlnTI/Ou2z6I6/Q8tfZtZSiBM2v68bQoMjy19l36BtG+22OGZTd4LSK80lAcEYcsHz1Z5eQVqs4yYRw5nUS1CzHlwOXyYYhV6ww3TKf3+H9U3Kqk1EteibrhGQD+vU/rhtAvR7Ln8Y6UcmJESy3a68FRo5w4MAWhAmoaNOxnkBkfCzRV5j3krYW4+T3jl4zRf28pv+VM/qMq5XqXGR1RkQUwNc40HqYEplb2jAlG1gD0/qsYvXbP+CZflSxwub6xhYr4HHWn3NtmxNBruKiolL9hUxLqYEJLxG3JOELt5M+UtDNpM0FpIsUILSKWWoJMJtyrnJC1+zTlYCt5d/BLwFYE97IO+Fq7ov5qye0+5Kf+ZBnws/yEUygZIYysXSat82gWmrRQgY109gzDCAlGhoNd3zVGbd9u3OBNT7cxs/k6PEmS2q+nk4gVafTbMPc/o0vXPexoqCPUZtUTywGH91FhlojX/0c7OAAVEopWtgbEjeA+AWlzYUJX3c2fNYw+Ip74l1+iKh/1x0pP2ng6JgTB75sEkBSrcqkCXVuobJZGNzRSpk0x4m4CKitYuc5H6qm3G/awmn2raZ//ISLAclDZxuQWQ1UyDPf+/PnclckTarJicN/0G2Lz6nZ0tXDQtRpFSDB+n2NK/QelbUDZ/SmyI/ToYRtnDsNY4tWjw9OIZMW6c5YCkAe8p/wWAg8hq6Yb1X7+Jik+BcUTRSaoW+QZTT8uvb72UEVo93NzH4fF7uUC2xYa6EdGQjRzBE2e9G53U06SfhC0UyB4NTrY7MaqevOd5lW5UUdnDw5xsXz9ffdU5wd0B3+Iq7OBW5i96yAV0vAQqv70XyUISKwN2LNL4EwAekVBg+NHiYNKTpgGdAgf/zExAyYYCw/Gxgu492XmwzLsvsSdJMbZPaRCM+IJKVZ/WJXptkqdswy3C3f52N5oJvQA2QM5uZ2BPnzjM5of32Mk/SiquLdE7lsf5Moltr2qaGCQA6UnEtgBlKsPuMUrJfRsU8y4+qbEjtqhN+pg6cxRExweKZgkgGOEl6GsUDIkpsqOLqMmqPlWwK2qGFMqsq4jv0hBjRbGMw2plE1Z4PfzfGUFxWW7REPsNH97gntzyl6iMsv8oePNBGz92MKzHeRjAwMR64kzDtGqc5h8MLqZNJgK2GSHWoZZ8zhMj9UGBm4tCvbgwqr0+qgghtK88YHFtRhfL8Gy/XDig8IRBeGWTxZ970XsFF6GW4CH+dcmd/mafoprzDe2yuXuqMGpuTqvj/8wr9XNRgf8oivpz0Xa+vC6ca6MotbXL595gBEKDR4hTfqfKvTYAKYqS1v1eYc+Kp/uMjKb4qjVIqE79Xu50lGsVEY83WWJTHXgrA1iDhrDtmr/EhmSsMBjKoy9dhFN82nke1/39CIJTW1VXMTwwhOhOuaCThgNmJLJHkal6zyBE+Mn062+S5z0vxgORxRVaYejuimmUsb+vcNDUdSU1s1NzGM6n+LyZW4XhQyTA0/TnMVaI8kT8MRbJ5l4KeTbUZnW3LReIe+JujbW5SeHs9pVkdeMd3rSepPvueTyQFcfgNEGxrCzHrEqu05ccgU6FwdWippn8+GKL/eC5AxFggmpvIykOU0rM06lpmDeTuj1oqGqhU4YTnCaX0OV/YYmtbN6hrXqZ7rjwrXQEXnXpjv0ZukKKvXcRV/jkvxHqeudY+q/hEOyU3b/Ex1Zvt7fUl1jP/x6/5zjvs6/pwOVYQBh2Mcf7+KK3QgYSNE9nQp2AhNoGkK/6s+SASa6UugJvpCDft3+S5Ok3+ifdfjQEMADdQkQKZrPM4OZ/JETGyzLwKb6ktN1EP3VUHOYsv8XOzA1kAyqZICpUaKW1Qck7LEGO8OuQUJRBKodZFK0zL7dkdolS2GWmQpdHrmaQrpRn4G9SElBly7CwuQd1coa6ErN7RVvwyRmqunUFmsJzJsVtGeuiFtC/1TPqGBvgTi3xfqFKj91sCBsC8Bxe8KdQNgG+f0PaqecujT4QnA4ZCj0bVZ4eEZD2Nf8XQKfTdcOdgiS6JpcDhhEtoaiqBmhlLdV9QtpMRPqCsBv5+uUMN+yMgr8B+KoAaGUh3M5BOuerY1nmpvk111LqD+7ktAE3WFZj2gaIUjUPRH1BJF72OCa+P+qSNNJwU6wgMcSKXqNYZQJwJKk6+oeH5IjpD2bDHYKENhZm06hrDM4DSNwuY0mW3jfTjAN0lawROZtoqRaEItM0kVH5dAoYJlR2WMy7bi+zg7P8YE0grjsFQqOWhKY1k0QuhbZynMNL8/oV3ymOzIFoiK9imzgYxeZQ24jrFd4Oof2rdH4uSoJAfnSmUNJ+mM5bKRyLRPH2Jov0YXKnqLlJu18ykukjgbYo1e5cfPSRZL+sWkkkIuZT2NvH+eY/LLxyyBph22GJKBpXCzjrlJNFNv83/774ivKBfITBJrXPJ6toF7Tc3SkltgpK2hWxj0L9/ERUFfBC4I+lLdeU2CitsiAdfyVBl4VjMUaxoZnFaENoYiqIm6VMv9+juezrM4vThXT/WJWjM0Sc8T1OSQFOoaGulIgC3JBoYqg9olxWVktIkhtLJTPbpQ0ZDZCR8hljWi5N9SmPD/vcjPJ1kjbaGipZZC01Ibv1lopP0d4t8WGW4p2Iy50j0FS6baVLCUGingvL2CFDAZJAVMaSiFomV1a2bdKBleqDJpdxrtW6istXAjTZm0kaZY0wiYnVJoDqSCGgYJDc6UJFvgoUh2jmS02WUT30lbkXcaS6E1KZMVCzAmUw6bkSHRqscnoQBU5ElgNXkq3TGQmBhBPA8SacCDIZHMtnHZCkpGaCSG2apJGsYc6H0JJYwDCbGlOAZymAmgP96mgx6LR9x0KXjMTROYN9XEEFc111BommyItLdYkGZSjUw0AaK8wssQlkaxGmEJtRsSNkQksAVhCVQrR45U14dDPEKx94YysN+GYt34yLwrFcdGphgcFxkKLSxT6UaAKoOhmBou8T8W8kaoMqgRqli3jkIZwpst1eAukoDrKoFKt0XEPBDZv34Gr0q5cnCryJJo75hy8Bag/R2+U8oN7hmGAGritNQXwReKXamJ6P2pB6xBXyxVxPTYRBr1SGhYSgnenMmILU6JH9DxlMJDCUymOzUeKA1vwxQSiCSq2zHjlrtjSnnDAoXqtNO02TtUk+3l15g8Aby2YGl0Ri7yssTMU3mrIgloZIFKZ+Rm7SO98+bKQQOzJNoTWjAwCnBUC9LBZ7Ygqbkg6ua1jeqP1JggSOIRGlMMHpkxFNov9niKkwM0bg1F8BfalepGpmYFpBqUeApwPOKJDM4936GqQoVmeJYRys5EIVqtCeISj6N/oeTwBPUpVw6rz5CYNfg6weAuYbVFEkWzFJWmZS4mjdAsVw61yZHoZv3nbKeY9OlScM6nCbSH3XxsC+CAmyeBD7V5KqOW5VblyuVtmlqVd+nTeOypyU18BqOa1Pzul3Gckrt6Sej0vlh3qMRLdOKzbeBq1mor92gTKFSecy0R0jfcHU0r/CREEtUZd3RxOqUJ2j/kLX1iIYV8OSJQmMnQkusl6FyUDO65Da+7o4HOGJS9i6WZd6u5lysTKd/8XleIYSHaRCCROauyVAZTb/8iFJxv+1LZJNsTGHgoyptiSmV+iqZNyV+KybAGkCogB1DbSKQTw6BtoUHqGYTaeT0aXN+pOgo39qEC/2qDygXG+eFjEeQ+9mxNhX99w8XEX/4Fq76paei3Bnq7wNTBjAK9qRgsonwmYW8OYY6nx7Eyum/NLlrGrKJcVdnLBqKp7rWCkhM0toNclS8UvJvyIS4OqHIwZVtRbgCpwioFl2lCPI0pv0eWIMQnSL9EaVSGXpq4qdY8J4kajrByNMlIIYUa7FOYvp7kkYu9iuzyPOrW56hd1CfK8cS8slxJ+MEHUVT9jEPBhdu4AMxkz1GCGFA+iphXVowkgLIS9ZZiMvqxTNTzBcwDEgYwBfQAqDGB8l2PvertHlSlNE/iX11uP03qyZ5/uavImU6uKEvovZcmVL3fWPZHDYrBU06sXzWAKwal4pKzFIZBUEPIB0E5sZd+XIIZLpO0jo7cc1YYgSMNZwIjDI1QugsaMrCWay3QhvwEuBe/DAPZM157M3RPNZVLY5EoxPKYf25Kakqfkjosk5mXjFH/ohFYLcOUiiUw+3yyWf/CLzDZeuDry6Y6V+Rd/e4wVq8+HAFEVAOSfzHq948AFf0u0Pjvcf6svvmsZY+B7dVUHeUrZnmTanKl+HfWRCnZG2qwJmgWsTCseeRzv0k1T32+MPN0lzBW2OErhUQONPYIZSENY4MavpL/IXUmswBP78H1o7pCSJwAMQYYJqqgAc6TbcRGB5BOtSydQhkgWkGjhSIKgSuu3NWWvvyP6HAFUmsYVdeqKAZZoJWVx01Q85LETIBZ6+IeeDBwaxL9ak5aJdiyzrUDvJjFyiAbNEW/lB1WB1JLiLQh1jKSoB60ITyuZHjV9HgQSIOhYSITMOFGFLsekM7/zgcKZEIqKwOUOPc8F2yFbkIKAXkdz2pBqJAyAsuDmEn/kYDkwT6UeUwiCUyjN46mYjAzqYPN0NwMI8g43JUpguVIIv2AN2kObBQ3MXq7mBnEgCsbeEjBWxJAyDda1Y3bQljJbWJTLfQLED1HlS5Ocupwx6yCfyxz0kqVBjGGwklJTq1VSqINoMYyTKIIWGV6WGDMYoJzBINgX7RFbcJ1BTGxfhI3qR3sE12bOdkIaE42ZVjIDQQFayOmUAVhW6uJHWA6PTZNrBXeRMrlpHFdrfJKrc3WjYs0I4nqEkmbNTapms8kRjHhy0TGUTGHo924L4QMB8rJR8Ow9wDRfXw8pWiIiChXnKNULF24uIzNskUSc3FClfuQjBHruC6qLKHUewS5O+ELoSZJdXkUyTHqK+Yukcj/bBVe1S5uptJlSiSSi+zuMsVH9yQ1hx/9eQaaPt1RV9BDfIS7nO4j8fyeRKKpgf/o5E9w5jKRKnir0t/SrGIINJkEtCXcrALT2puuD0+rtBNAFcIoQhxdUpX61Y+6JAauXl+OLJjCTETfQWM4Uq+jyhEdVFeiL02jEZkJ3TuIDIbkFWuLFf32bMtS2a0NzWhB5+lN8iXSbFVfLEXnUfSJv1sSX9fg2QBIJxfc9c0AE1Wa1IKDRrsqqhqbOIoQw1I49aAg19HgXif344MrKHZvo/34oJDaDBdliGxPpmntbmiXhnp0vy7CHH3YbrkNeBK/igshx4d6njY9g/yKraxI5H8rG17VLtB7dIv3Z09xifZ/JdUT1YKouK6KN3WYunwoe1JVGqbe3RDMdzvwl5sBruBJEbCm9Is3yhHgyTQf6X43tg9by++4MJd5+hQDmgGRIgkwINLpEYZ6YOYDexWBZAbKpZCSPsTCSJG8gTAxycbgxyza70JfyS865jFNlydC/k1wFH6V5jNp3HdhIjy97qDTYEQDX7mWLKEnwcGawvyqTNnhuhHqQm5ot3w84Zr2fEzyEc2AB1KGGeqApCrtl6zKlTLigNugs6W0/vs7dFwAPveL5smSily7I/DyREmW9ab9+jWZbDwYSPVlyIlDfByzm0KxYZTS+t83Tm0GOFdQBGQyAkYO07oKvMiSLzXA0eVTUvMSPUYMMyO5zDdsjqHoJkuqJE4Va0lVBd/rSDiTUjv1aLIjjTdGt1YWm9LbRVo3kLpKTvAi3Cy9lUOUqyGpUyQkeBItpyJXTOVwAqpmSldnlZLxkfHwbBLV1AXShZi1plFbp25wNXn1/KglpAPTXyDD1MHukaH8E8NFnDKRhIvjHZ12LHpT5EeVPVTkIQwCZ1hrFzbKhGmjTfGQWxiCIl67Gfr0cJFi/yYS+d+4CSnumprS7HUuI3sKRDmGx3aQUt/X7k5YQjq8doyXJaFziVeak2hdyTEunq+/757i7IDusGmHFGrAtkRbSWUUNqdbaxA4Xxu7Q6HTzDXbEjCL3EgjkD+MtWep16W2JG+ccjLU1gkx9Gny5hFGpknw/JlJsW/XVfG/fZ/XRGCCtOhNAg+kCmqF74KzC78yIdx98wDCJL/bKLNEbIY1pVFYWrliUNY3oo8qm5vMNDKDBEMH04YpSOhKXtVaCGKYPGYRmzpXtJGCWjGfAAl9m2lFkaiX4QDmayMs1GnYXJzBbcyhoA5pDjDRWvMdKvOnuZpjyAEX9axlxgBovSsC8BDz3VFsFDns3NJY0ImmovrA6CrPyqqIk3pWwbvTfnHShWJ+yCMxQRWwv/PFW78mcojbzC4bJIm7mvWDLhmXB7PTiTsMLEmRq5WyyhEyq0moFGSmQGGylolWG8kxPOqApG333WMyWYq0cYYdnqmpzdXTqYU3fgY3g9pUnjnT3mdS0wG7knEcw+MJyMzXbFwUKffGGXaIFK82V0+nFt44Ev0Mare7SCFloPGsJqmveKDtv60JZlKpmuKOXJ9+0WM3MQVWRmdrGqou13c95nOCm9a0blwnRq559402sj7uDEfo//TLv+qvXjRMasPjXkZFX/bqRZMUtf0B/1nlRXxA7/M9Skvy66sXd2dc+4iav16jMjkMLF5hnhkieaIHph3NTfZYB3wn6TQ5iTqSrrjP217F+7iKL4oqqeNa4uId/pZIul/iZVKfB31G+5vsw7k6nSusMjp+TplD51cv1O2/eiHI/KoJtFf6UAGLmWAV0Ifs8pyk+17uN3FacttNGYsrbP3fEf696Uv8aVbo8Nxz+iPPDBm15sObVJTt8Sf3gI6nFDMrP2T38VfkItvHEr1Dh3j3fFun8SJOMzIm+o5gzf7qdRIfivhYtjyG+vhPjOH98ft//T8Nhl+ShbMIAA== + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.Designer.cs new file mode 100644 index 0000000000..6cac518be6 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ImportExtraData : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ImportExtraData)); + + string IMigrationMetadata.Id + { + get { return "201605111140288_ImportExtraData"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.cs b/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.cs new file mode 100644 index 0000000000..191ace97ba --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.cs @@ -0,0 +1,72 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using Setup; + + public partial class ImportExtraData : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ImportProfile", "ExtraData", c => c.String()); + } + + public override void Down() + { + DropColumn("dbo.ImportProfile", "ExtraData"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + context.MigrateSettings(x => + { + x.Add("MediaSettings.VariantValueThumbPictureSize", "20"); + x.Delete("MediaSettings.AutoCompleteSearchThumbPictureSize"); + }); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.DataExchange.Import.NumberOfPictures", + "Number of pictures", + "Anzahl der Bilder", + "Specifies the number of images per object to be imported.", + "Legt die Anzahl der zu importierenden Bilder pro Objekt fest."); + + builder.Update("Admin.Configuration.Settings.Catalog.DefaultPageSizeOptions") + .Value("en", "Number of displayed products per page"); + + builder.AddOrUpdate("Admin.Validation.ValueGreaterZero", + "The value must be greater than 0.", + "Der Wert muss grer 0 sein."); + + builder.AddOrUpdate("Admin.Configuration.Settings.Order.OrderListPageSize", + "Number of displayed orders per page", + "Anzahl der Auftrge pro Seite", + "Specifies the number of displayed orders per page.", + "Legt die Anzahl der dargestellten Auftrge pro Seite fest."); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.RunningError", + "Error while running scheduled task \"{0}\"", + "Fehler beim Ausfhren der Aufgabe \"{0}\""); + + builder.AddOrUpdate("Admin.System.ScheduleTasks.Cancellation", + "The scheduled task \"{0}\" has been canceled", + "Die geplante Aufgabe \"{0}\" wurde abgebrochen"); + + builder.AddOrUpdate("Admin.Common.HttpStatus", + "HTTP status {0} ({1}).", + "HTTP-Status {0} ({1})."); + + builder.AddOrUpdate("Admin.System.Warnings.SitemapReachable.MethodNotAllowed", + "The reachability of the sitemap could not be validated.", + "Die Erreichbarkeit der Sitemap konnte nicht berprft werden."); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.resx b/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.resx new file mode 100644 index 0000000000..738509bbb4 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605111140288_ImportExtraData.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.Designer.cs new file mode 100644 index 0000000000..d4625babee --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class CheckoutAttributeMultiStore : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(CheckoutAttributeMultiStore)); + + string IMigrationMetadata.Id + { + get { return "201605191216116_CheckoutAttributeMultiStore"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.cs b/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.cs new file mode 100644 index 0000000000..1b6ba5a31f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.cs @@ -0,0 +1,17 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + + public partial class CheckoutAttributeMultiStore : DbMigration + { + public override void Up() + { + AddColumn("dbo.CheckoutAttribute", "LimitedToStores", c => c.Boolean(nullable: false)); + } + + public override void Down() + { + DropColumn("dbo.CheckoutAttribute", "LimitedToStores"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.resx b/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.resx new file mode 100644 index 0000000000..d743254b0e --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605191216116_CheckoutAttributeMultiStore.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAOy923LcuLIo+D4R8w8OP50zsY/ddq+OWLuje05IsmQrti9akmzvvV4UFAuSuMwiq3nRpSfmy+ZhPun8wgHAGwgk7iBZpa4Xu0QkEkAikUgkMhP/6//7/3/7n4/r9MU9Ksokz35/+ebVTy9foCzOV0l2+/vLurr5H39/+T//7//z//jteLV+fPGtg/uZwOGaWfn7y7uq2vz6+nUZ36F1VL5aJ3GRl/lN9SrO16+jVf767U8//fvrN29eI4ziJcb14sVv53VWJWtE/8B/HuVZjDZVHaWf8hVKy/Y7LrmgWF98jtao3EQx+v3lxToqqosqL9Crd1EVvXxxkCYR7sYFSm9evoiyLK+iCnfy168luqiKPLu92OAPUXr5tEEY7iZKS9R2/tcB3HQcP70l43g9VOxQxXVZ5WtLhG9+bgnzmq/uRN6XPeEw6Y4xiasnMmpKvt9fXuabJH75gm/p16O0IFAj0h5R+mKwJHtF65XNf//2ggP6t54p3r765dVPr376txdHdVrVBfo9Q3VVROm/vTirr9Mk/g/0dJn/QNnvWZ2mbE9xX3HZ6AP+dFbkG1RUT+fopu3/6erli9fjeq/5in01pk4zuNOs+vntyxefcePRdYp6RmAIQUf1HmWoiCq0OouqChUZwYEoKYXWubYunsoKrcnvrk3Mf3gdvXzxKXr8iLLb6u73l/jnyxcnySNadV/afnzNErzscKWqqJGuqdMsTusVOs0uEtxktOkaPMzzFEUZMEwNvvIsKsuHvFjhggrFePi+KDuEk9PiMqnS6Sl+mK+eJm/kE6oizNGEbOUsjb1DZVwkm0bgzNDePHP1MVnjZbG6zOmCLn05+RxlK1QclN+T1S2qfLE1WP6ZZ9PToWnqexFt8AZbYSEm9N2k/sVd/jCaN7+RH2LmRkUA+VIkeUGlslq+GwiPy+g28Fz89nrYfdV7cvR4hDeb27x4ctmZo8dXDIb95ixvS7Mt/+2nn4wm2ZK93iXlJo2evhCWt2FUY/65QFVFx2LNO1gk3CS3dUGhX7V49hzkzEFvp+Ggb1Fah9gpLJultNJT14lnP+ZxlCZ/olXXpgP3tjga5hUQ7tlY3lYzHXZTC6hYUXZbR7eWLALgIVOHMH3eF3m9mV9A9+0v1fRc6/tzdJ/cUgaSzOTLF+copQDlXbJp7CniyroawE+KfH2ep9CC7qGuLvK6iMn4ci3oZVRQ9dpNpvTd8hQlLZ69BJG3pdkI30y0XNqZaamu3ImnaB/X/qNGFyg/wjhUrQc4uJ2k0e3pGg/2JEmRhty/mI1Wc8StUt/zWOBDN11L5Z3/OdFVBVfKTCq6m8k4RyWVcaVcgHKQchkqA+xl40iMSqE7oeuunXGogyhoHM69hNXLOl/tqqP1MkeXrvWFjjCnJVldZ2l9m2SCENFVvczrGBI+4bQqf6EA6lZaEeIkFM5QsU5KsjjPUUyN+tYC4QLFNbHXveJx7QWBvK1Al0m2h3+Ti6y3v/wyRduDNXTylqWL94jyNirIsoK3dZ6Hr7gqwxJWQwprWAPutYhZVC4Gw7Z6+YpFtF+9zqt3ohV0UiB0gVl1Q9vzU54vo8fjR7TeeN96YUStIk7wcFOgrnoQV8m99+XTadlItYb5/XAFlY+mQomXDBMLJv7EYSjH3LSLHK9/e4FEqpX0370QkrcV6iyxpCrS+kRMfmEezOhA7sy/ZB/w+jijKr0ftoM0zR/e16is8LnkW155I/SwiQj3RHjdvcOM+bWKO0zkz8tkra17nK0ca/ramtyObUTSgMe0UYGo0o1KIQ1OKfZx7YOsfMDiTNqppvyqEaPjbjFFokjnyr1leIPMS5I3KPbyXCGjMJV2U5Z/rtfXqPhyQyRY6TeAKYy6zfLxW2LQ2oeWoE2fMLmoQUeh9HFQV+xiHHdWAgbKBhmst5xgEXtJCxZRMJnx4jAqUdsBQt1O0e186LSrsyGT9Ro12AKmmn2IbXWc4mWCCGJ+2O8S8rY6Gr2vk77V5rfttWeJ29XdQIa4gjzGs5xO3oqBV3rYhk7yYh1Vvht2h+0iSqvJu36wWifZUb5eMx7D00UylMFsTAc3N0ma4OXiS+0wFqd3KEUB4ig6w9VBHOc14MI9he0qDB99jMrqdHOwWuEjmiqcwdRhRCPxCkQk5ZcMPE9aO5uU1cf8NslcD6i4PuUiLKqlKJwVgpakkruJTvRfMWCDGiCWCrs/AGKrtx4maYqnuZ97VTd5WKCvYxB5hzk4217zmp6q2y3M1aDRiP3mYQQtWwoIqdh+N1Y9aqlBGIaQE1t/M6Xq8fEjUWii9KCu7ohKE1Mg1SlHVQOcBqMKwpyY1bKdIKwG1OuzvKzgsfXF4EDEUqHXAIhTF5tYT3kfabm8k+NiuJccjG036Zkf7iEtAjs3LhH6xRXbdukc4TMGZpE/qIkW7NoIBOwiDCF0VQJm3+WHqFid5UlWlR8SjITcuIP9FuAkvZfDAWNQANuOpLvqNNprBGBA/HEwcgHIA9qKwIu7nNY/wofYU6yUwX3noUDyS4EE2sshvcw6PUEd4pDW6zx71SLYn+nlbZ0kRVkFMt3q1ddZGtId+sO0gllsE2XTh28fkQNaIcbWaK/QKoS/3SdZLB5dNS0yAbCTDatdmm/maujt5A39M9kQXSlKNb78gW6V7/IMNZcfk7d1Ej3O1JLfeVt+kmnWELgVdhttDzNsgFyRsGnz5dZ7NbtIlZ3jIMUujgCkHR1D+RndO3JZ783vkgLFRD171eLYb8/ytjQb5kRhUdQ3pGwNH0EcTcpgzoMP+UdEiHhazhE0dXlXIGTa4M8BGsSCFhVJzDXm6EdTX/8LL7XL/FvkbeLdhtCpuRx2zvEpGM8Bxt1x7SdU3eUSE9IY5mqo3Ii3ZGwQ00MDpyttFevzLbsRSIY12iuA3REEEDsPQnkdC8f0cIkaaRFwU7ffhxRiSb0PTZXpZMZMUuHk0ulthml9dEdWwiRSiREsc8gjXpu0EGFu63us7HoomCNM++Utb0tmZAjrAjiVtnp9XaD7JNKIiTA3wtugBzmdcx33c2HxK3d9L/+t/oY0gBtXi2u/5hVrviWV76I38cYwDQbXea0cbDaY9fwXX1C/jq+b1SRGq/5KJrTHgOzySepa4LSsD9P8tnf4sl7SpHb5isGxHa64bWcu0eP0Xmxk8MSiHM7pt8MIshRD66sBcGAnqFxgJRDIm42arnjwEEGw3wvkbYWK5wuVitey2UB5lF0Mmy2ze6cm6na2Ft8R65bpqIznVXikl9Ht9Emkl4n/M8yTbWrq0De2bXmyw4wscMquiW4EmX0KtqI47Ya88VO5ZQYJH+2xQiGkQiG4XY8h/DL6FPmqjqtzfBpHDy7nuKiKcI9ejfBsh+LXdmlbNkh1Kw3hZlFSz6OKudVzI8oHlG5u6vS/UHmJOSUNguxz7oJLHi7XTD8cK8dy61UPyUTJQQBifBwIZR3cyWJpaZHhw/mxwmIsq3PFrWfJiKQ1xABQs2p+saAd/X2lz/68oJWGpDn/KLQCt0kzNdMEviGk7LekTDD0abZK7pNVHaXpk68esswF2MVdjjXhGfXEE9y/OdubNSyw41q03qQBIvrC5mPp8IS7h9wfaMJErtJjfheXRHeoYKf9Rnu6qNfBjvqBMHboqBLFDdq7j+GQ9h5OB/G25Zq++FFPv+iirL6JYqKCFHgfrbReumGafV8lqgUeppHT8n1yUx1FhfdlT4cnhLZCYqSSAn2p7jDFm+0kwFNgFOeg/GjimoMItZroxiQQEetGB6sV1wfvMZ2W7/KHLM0j/3vyFo/vzH3N0maBdwi9x/ipc4v/ciPgdMxA1KI5ftwkzRtK76InHqcZChooTlGEYPsPUXkRYa0JhZrVMTbLABXcG5JB5OC2QIhVHF07M0I2i9XktDwnmauLAA7RPaKjpzhFTad8ZRyL8QwVSe69+nqcdO+niD3Xyil1KT/OSJUA+TBCJrjF8jQhKy9KO4yNM2Bvv0Zxsia2qbMC/2ofSf77yxcXJNU63j8duh8s38lpeVx6k5N5PtCXcbCKQ+4ls3u8NDG6xufQ++RW5fGPf9RRa+vwEtnNcY1iPLiPElw3SRmsnu5hYE+dN6wkCzjyj/lDM+o2JYm382BeJTdP1CBwkhddHw8RPn35IT6M4h/0fVDyDrh3Gh9yGiQYTxta4hNIf+j11ijooR/PUrKu12EmqcEYPYbDSAmAVi2yBM2grOK1QDp4WD8d1lU1GBc81haB/p6Ud2lSVmGQtos/RZh5sVwf2W+cLz+xdk7RJbG3fWmEJPgO9CVdTdtAezA5otewE7VxscF4otRyIOY4e78Gcnnt4KHA4mr9HBwxdeas46xCRRmEv1qxNcKMJmaKVrDN2iY+fFwmqFmT3gIf76GorA4qLDqv6wod5evrJGuv9QIyIe4zlnk01RtxoU0Tf435O0pu76ZbiuNzTHD035PVhNg/TEubfqfxlSc9Ij9hEu7GIlxwRZg0iVvkJi4OMLlHxROpbGk96dRArIKJF606TbpE7e4T5Njd4/uEorIuEOmSQp0M8ipl3+bBmnWH9BWxPVryY4zajLR1tkoRvdHSWKDCmNeb9s5QQfI1hTJ8jJASaoTGySaaskYsT33ZbIn9Fgk6yXSlVy30ZT7YygfHGDmU4AyjALV1EWSlgcrD52oMKPjzjMplDkpjIEf/pGZW5QnKBLCrlg+k3lUyUJkTkhTelvjdyaQxeGl8rDqzmMJNjAeRDUCAc+w4e4mo7DsLqOg/BCYbAwjrOI6zhOJRDqGFUfSeg5B1nAdz7HN/CR7OrVDpc+fbX3oCvWnTl/bHFmX/4SqK8agryManqeU43ibcQSFQR3CiPGWKpeKUhXGUpt+iIsFKHXSOVHZfUU8xQQa1ZLNkUtVxqnjUVgO3GK3tEJ3HxerpSh4cA4pMyJZLuXAEZJ3IjLsbVnSWBxW7O4aQdpgDs+0ya8MButsXQ5whFAq8IEJ4+TR3qqJTMoxWqe1/7f2a5W1pvHwnetO8m5kQnhpfS3JWivFwA/ikdh0TMQY3anVN2Z7KrW9+lwgtbL2ryqO83uQZm9jN2TIlYJos40k3M9Q/kq4yXx4dMBHi2fqB6I7xl7nmKCYevNkKqrP8ACdsS0pg280JMDFMYZHQj0EwXhhbJFpULefL4yz7NuEawDggQPlQQGi/dDX9Y/LOEUYdiv1WLG9LsxVPFHBD4l8Ctawz4M8XK3GYV5hPZw3rSZNohteZ2mUUKqBnHzAT6JU6EtEXygGwtbRZ3lSRSKqL5E/k1/Yo9Ke8zPGOheKKx+3skdPi+TJ2HpssfRY9kJ5H2a3SZysMDwSOjQvvv7DFkUPbdgse7n5/m+/TbyKsaH1L0MOnSZ5vCH356HBk0V9AAucbYytsI6bhZHX9TVUHxCSp48rE5HQ8gF+Gkq4H1rr7J7RKoldt/b3irhBfDYkOkywqBpf19i+ThaTzM1zTJC7KLWySWHyUnyQpytSng58DBT9+Rg++cvu0vCyirExCREhNk+LS5eZWFCEwhPbmlpM3buJkhNM/58hevJimHpnqWDGfbuS0lTqvBsk1mmzRWK7gsD4Xur4qUiNZX6kxdsEgt2sMvv0qVq4bSq4A648n+3mdIqMHyQMlq9ygyW+t2peYAmXp74NSw6Ab3n/ABwjm+WZLi82Appfw02caZRqNngjz9A/9zNZwNxt6K1Dollt7heU8HT9iQYV1v2jGM/Lg/zDdDZL0dKy8b3Lbe0ZeuB7vm7CI9ruNvC3NRmAYV2B9RZ/mxQf0+C1K6/lbbxXTjznZc6aOqXDVgm3PWYPPtv9Ra8C1XznytgKdtkYe9r7IgiVuiEMGAMl9pRZOOam9qJk5w2SSYhZk3XQ974aSFbq8q9fXGfPqtyuyNnHo9tzgPMerF/lVSMcUDY8YRgZxta7YTUIRJSSvpo8YUtS1vTfhwpqmDYWSGFa0oVMBrUFMW0YDMO96ELOQbqpD6h0c6r0aIm9rIJp3/p6O6MEQUf3e+xG1EqsdjXuJw66hkS6NLFxGlmrXrYEc9lnJAbw1OUz7dSpvK5CGH8p37LQ8wVpPPeQ1XVAfk7/z13OoQdjwACyPG+5/SNaeCDjBPu8S6Kzrb8gdno089pcNLLa9fJhcPrDk/kvIiDG3Gobojyup4/RHf0jWobzCBPLDJ9mASf+DyJJAQmQvPbY5JGRWJ32GE/ZRDdsV1bCPQ9jBOIS9a/4zsg+rHOPGm7voFgeVC4oCCBTitAFnp/E/d8B49zqESvgEOYHAhG8kaJAU4401LED+vCYSqx12iGCsSVxe9QeC0HmkJIcEw+xTpgNT8YnDaNXoTEmgwmJJFyUqL8mpHqqz4FSh3ctNW4Hn/eZDGA/d7ZFg4RLkzbDU7VLpGUkNP7kIkkndrgTPQB+H6oIMdMExgfALLvb2Au+vIJpU3AtLpgWWHC+LfJatz0ntMrr1P5ZhJPul5by0QtlxdXt1sMyukn0UzP7qw5uK7Kn+PKtAvudleVtzPPM7y3u7C70lHPSdG9tXY9TYLB+J0bgpW74Jo/GH285HLA7KMrnN8Crq7krmeBxukZdQTkv67KH/3UsYc+Rw0vzPdRpAa9XIvHCPSFJb55e6+nJDkVK91/6WxvthDFVecs2bGaZVZYY14/oTOFlMl//dYbCuJlbTPOmqtjUp1E2rugxbm3jdWEscD8IjrJRFtNf95G1pzjETBXYaeVeEDOvc7hhSaG9us7nZ7SO+p7HwR7D92pO3FUhxatEEu9Agb7fhT8xD7JNpYadlm5HA24uE2ZeyqshTgm0rEyPZazQuD7sYbuLOCgvPcy7jAe2upnVsR6i+1DAYKo+YhkxZPdBDa1xJJa+WBsr6pk/5qJGEsPAF3Ez2u4jBLjJPnvKFrpImc8P11ZTajCih1SWKds/t8rYkdPP3V9uhRaTxgiU5ey7+qKMClee315MPqrHhrv6FV8IaTZhArnmtfYaG/OKYJzsSUtEQQq39mGQ/mAx1iySysdW2tkfPMtQ7zZQ1px1peHjQMQF4h2C/zyjWbUuj93XSt9r8to0jKPsHHr8W3sl9AFSTbSRdW1NlQScnddS8GDj5WAyynodp6PgRj6kMr69C29Szya9uLPr6N0k9NO8ex178ydsKpB3AyVltw7rcE/KGueC19O9wz6LBDFTzou8YFHrWl4UQlBYJWMjrWcvXh+U9VJkobU/xzQvyH1C6uanTDJWl/wleQBlMrLwgHixtV+gTNO1UtfvmS5MF3PTOdwV+j8p2gOHcGkYdVKn3AoGvuKqCQq+pIVPhddW8GBDv1eVRvnbM0U9qv2JQbAePtZ3Rxa6HMms0jaHH6a+lCKWdErVJub3DCDI6M7FXA+DA1lC5wMQgkDfLOuYp7vl1n5tYY4uJsts6uvW/sw20Bu0Dc4sQy9Gy2RMquuZuNVjihGUecG8ScDQSwjuJxMFmU+T3aNXiOwLcbG3DKPMqPNLAqTOCJpjY57RxG5l0j+1kqXSPpVviADXeYEeF4O46hrA9KzH7M+w14KQF8Lf+SlXBSQsgBq0ii9KDuroje1oTsHaOYsy3LqenLgPQKxXivcqgEEItBX1VhuM1k2x+UnsomeVmdDeJMhwnbJPt1duMLX8hvEy5b56mDuIYH1PnaRD/eZ+sUDHls2RayxgoOFWC5GqoOUhSowrCFmBWy+vEdZIX9fosL11MBLRu+apHsReh8rYu800ShzJLh3C3nf8wc3p2sFoV1AI6sX/ILmRlU8qXfkmBwkQsFSQHAGKrPVIUlG01XWQBoU4O5YpuMkD+8qztjJdAozj2Ek3eFqXS1kg0MlshPJUu6ut/oVglHf82TYDS52YhlH7d/5bgE5inASMqK9ITb5+vFk+oKe7wNXLXzhD1PDaERjxKd4RxMSxrORinPUHXwRYI7B39qepaA+C/BXhK/73gl7dFCfS+yOvNxHnsTPMmb42HPyjVKV97yuQwmwORoEHOIc9xi/hr5YQe1rBcml+xQJw0Z8pgac4C+EvzthNeIp3i2Mt1hZB59tL4Wa7xwPePapEB3yNZiQv+/kgqT5zERTu31pKiSaHT/LcXEvK2KIG0Sc4CXTiQtryjIYI6BHu/6J2kKSZWawj1NlbgJbhRoDMg7wVmizpYR8JgO4ueyG1yUGSfUHWXr6a8SZJwzFFdFCiLn45wzRkabRo7j6pBAVZ7j//deS1cRo/thhrC8PYt0udODChWLurrCovE9DSL00uCNpSrvaqx48d5GrskjeG5iYk701wjHDU6z0hbqTPPCNvGZh0ZbshiKds3NhKOeBdJiIoQpScITU1TectTE1je8tTUbvGr7j8DSrjJmbRb69O2QsXKZE1gxbvOVmhlmxDWupmHqFid5UlWld9RgTDb+fv0Ht2h+EdeDzHecx6lhcZnSaHaqR6hfNgPbm6SNAnwWmR/PthMTgPqVE0ONRj9UYGw/DrCvDXWnZxZCmMiGKafSNLlWdRwgTYTvkJa/kAr2ZRMOsKj+/u3szR0/LhJCmpI+JRnQ5rvmdr8LxRNT092fTXJXd+h6yTA+9Y9qoOY7psf8nQ1A3+IDc/EmEzDh1H2Y5YDMNfmLCKGbfP0aM7maLjKkCdjjiZPr6MZlIt2N6UKYB/COvW6r/GBoEj+pJKGpqiIYvJzUA1mb3qWJSNr/ByVTDLgCSX8hhjS5yW42OhMo72or3sdfd4hn9VFfBeVaE4D/lmUuIYOdhaQ5pg+/by0zZHzORY4m7q5LZndahzogevtvZ5kT8LniFy9MY/1Gl1bfIhIFqLWivM5r/oXzXyJRkJbNtXlXYL7F+HPNFrpQ5Stvtw7nKyk96jjKyDwPpWu0SsecLhThcoFNwwQyNbhT+mU2LQA+SOOSyRdc/ZC7AxPX8voFn1ISvL6AthBCPCqvSEeOiuHEu6qFaC2T3m+T27oKVE7CAjw6muJVt+T6k4YjB5aGJRBFdvB0VokEFTB3zROVOg/VyR0li936hmWGpI82n2xpGdDEdwzpty2Z+dohdAarVgJedyo90BHWSgtU2iBhcHoa1g/XYv7Lo9E7kpFso9LxAcvx8UuvdoYSWMBkpd2HIBE6PFQfmk5QUHo8IRNg6YEBebeG0beVn/H6mk+bqSarw3aS+nT7rbmO+xQQ7PJdh+FtaKGttUXWpkyhYJg1PGx5HJa6bC24OrlBmHbL3N5Wx29fFfoaAcNgax9EmCiW8uJBEpHTXNtd6ihUXS7j8K6VEPbChRO0ZpDaTcaEKzTeQkcfyGzFyzytjqjHCMVoByAZtIphBfexH4Qp2XXWfoObBTA1NUhPMrrzUwW83NMjA3JXz2LSbBvbZ7sORcoI+fYOUbWNDXPsD7hwxZNwTVxO+R5uY47qG1yaWPuRAYo+y3ZyOwkbOCmo4ElqXI8V7I64ogkoNJdWQbvtSUzPfQKb9knSDU5jGMieYeeBNHzzxZ9NYfXfLOkojnSp/YP7hua3B14jtHMMpKp3Zc720ajI05NsnFrU9NuER/aeX1nu7d1AuS4PS07ZMHU+I94gWTDu0WWRyAirZvH2sw5RBOoV2erFGE1K5reS6IR8Ec0CV8o/pYqSgdlmcfE5XnVKSvwrUdALUmm+em0Kn/7rsVFI3hdA1xEGiukiodKBtxn4kMlQqGia2chHirpLy499UqCYq9XytsKog028+Qtkew3YxrnmQ/OHlt5ptVIArOLfXC5ARf/TosNuFj3SmkN4NuvQQXfBYrjbwgeAsdhlEbZ8NaX+13QxKbbuQxoE0kGpSMb5O0CubWp4ASxoQQOf+MU2CHIZDQBr5s6Nx4HWdh51PQ+RHv5J28riA5yWUTxD0zxmbzIaQRw2NMd5Rnk6pv+DqXJPSqeHKvPrvsYO9fxi17ie2fr8id3BGUhrgYZIHZwBCB1AhxDeeWRYlGGEEp7o7t+RVI6BfGkc3lIL4y9XLsYQq4D2XqFV4vjeQWzY3aO/qiR0xsRrYFghGa/DhTrIES2smCLINRxKczl0zmKyjw7yYuGm+Y3g7T8i6jZO8gFgV8H1JFZZlPLP883nbdHFd3ctJEXU1+srNZJpo8b/ttPQV4bGcm2MEnrtih+z/VEzdBEcpaGIIBzJwjmedjMqXJ2hDchP38KHtN+Z1Ot/wA721lUtPqN5Q1hc5/nUJGd4hAelsEskGHcQpbJ34SXJCowDxG3iMkslmGUjl0QxQNzS04XYyl1xcKzZwwpGHDSkMMGjTEWGoL2EimQvt/OFlnV/a7QCnDNK4PRdznIpa+Qv819ExRQ7XdBeVsax2rTB4ptLbboscKf1pvpM5wQB+g/6qQI8GY5saER+JbhQ+E9LS+jx+NHxFDDFRVGdITZ4DYvnoJtxEd5VhV5GkLXCPfewWlJPb2QL8Eme51AEEI0NA62OsOwV4BIHMS1aR3BNm1c0ctcDbcSUKZTfHvBLm9LoNjEj2NNtFNQlfxg9S/MN6z1JLhy3tznzdDQaYkx4WWP4gBeqh4C1VxyzS+zeJXTWtg5Xi3EdUH4us3l5B3WLkG4l1rytniSPedEFvxYJYZLkIeuxMqsKdOsDmDcNKwYdJ2FW2D7laVg4qc4Rc3W7LkaCKIzVCS5d/4J6klD8Xm6Ll5UeNql7i8LnS0C5U48zZIqidJtlmRsF42k2NW4hlx0jQC18moMbWtBk+7/c4tlMfmZpTx3EsuU6fGnj/mtg0TGtW6JfxGDZS+N5W0xZNqmS5xwua23QzBxZAaXMgNzJcAPq1cBJsglFWzQ2wi2IegiAipX9jbMhbZAxhDihMDvRYq8rSYrNO7RQ16oElS/mcZQozEPTfRa73FGgC11LGM+9tsK91ug2vSe335E9yj1f+szL6pw0UCWrZ9g8Nly+Wz6ZK/e68xRn9B5w9yir8X0bhuYyVFRoGKOtmb0t9BwWkGczrLY138kzypyhohK1WtJf3PiIjclRqa8KJWWcMoKfembfQfDQeQ3b5G/ElDt5b+8LZZO3pmNQh2A6Az6m7U2SbylphrlShT4F1yXcihhlSpAvdbsWUGzvPQbr+uCHePZr1bFag3hLUt4KNRKHXI/eCuQ9fW/UKx0zP9lMi+o+TVW4hAVBXBaas3bh0/Ng10BEfYZK31xTiRDWTYG5ehYrFyN4QdBqgATJKkK1takxKZN0feehZb2fQDS9ZyB9LMxdU/lOkj/vm45/NwLf3lb7bHT2/0vzIWY4+2c3EiseGulZ48r4J0VoVA0rQoQfoFC8R1a1Sm6jMofDmxPqpWvWCR7ppe3pTFo/jKNQfMAs4vKvmParG5jzLPjxw3hSHXc6JswIYnNLYC0lb9vkXEYVH03X7LjovBXcj5jje+8drH+fIxoLGdROdY9zlaurdZxjPnEtV2WbNMx2Gn5IVnhhe07QfjPW7IqzhCW40JaUrO6enNwoEGf5w+ttO6HnWQR8Vg4yjPiGkCshZ8oOtrWeM3BHXAQqM37pGjlqsjFKVb4c6enPS6IBwRG96pHst/R5G01pPfV4hosy3iDd0cHol35juMU67NpQDWS7Zvksr7l0asxKHtdD0EAF/YgmJdq+bXwWYX5q77+fgE+5wV4kda387caLNorym5rvDXbzYD5G1WEMZLYJ4SVOGDl2Sse035RTb2o8IjeF3m9mZ+5ccvzNzp6qG8+27PDLYLx6ru8Q2v0LSoSgsrFOkLql69GaPbrTt4WJVQAzp0l6tBvNbwNc16bkvspbhfdjcY9N//tuX1yPrT1F1I6OE2l45VpKMsZOZ5rPMLCrOAPealMGRfI4vIxv83PkpisgO3JhfChWqeH+YpRgaZzhmucx7qEw59R9ZAXPyaf3bMiwYLpiS7ho9au5Z+viuI8fozv8KkAkZeqnFErkvJIG4ET9ZARXilrMRl7dMBi6h5tDfusQ+LM6EfGgUuGNIJSj2UM6peIqO+W9V76LilQTCKzXnVI9juqvC3t/do0BsRmYjTv8v4ySbJU88fw/u66nXzMCQJ/spqYYU/yYo0nnbYwbXu+WXp4oUUWWHm3aPqN5bzMbcdIZdtxtsIzG1zDsjvefIpo4jnPU06LZS+a5W09Azv1hEftwyj+cZrhFuIfnmEDR1EVpfntKwnGPYsGnWDwxj5Eztpg0dcLuPxLWA90/NfBCjq6tkLIJKeyxs7EXKcaUONxnIXIfPopyuqbiNoUiku0xgqF281RK0sgdHtBIm9rmf3pW4IecFfVIXiTtOyqs5ofoNsEpAF4mUe15+M9H8/Gx61wD8DGHKY9F++5eDYupooSedmgVYKcmXiMaM/D8rb6U8WbQKeTt8vcNJnv+EVellgHT/25jEe157Nt5TPzfbRJTvcJVXe5i3dpW798NUK0ZwzFhLKEatJC6ffVSbY3kh3nHWJMZP49cOLBf9SoRqtjzE/pQVVF8Z1j3tk2tKN8BSLc86S8LYZg3vH6uCd4EshV14ipiBGImxEB1FY0qpXCQF4lJwkQzaDZ0/F+yQf9mHh7eGnfE+Vw+5SsEWlzhpblIf2JJGgDXOhXDfhgUJRDCbZEBaitNZRBZdH3US3dEJivhiNha3jZRUf9DCKp9/JZIemKJC+8H6cj7DR/zDRpVetNEiSMOZ9/cJf5LEM7R5v0Kcj4jNqZZUxHR5M3cRjHk7ehz08USA8hTqTTu5CG9HS5wMLtski8nw/AaJxyMjabXxzntf9TJbgTK3J5F6VpPwsBkpv0OzOc4CSwjsCnrjfXKkwHxJJcN6KrMTA4kBGMSscZA3qpNuNuues2LJ69cqNZpqrjxS+TOHy2hlfdqcqwcX0AxPwjPMsLPkeGra9iiWcyDIGsz/ZlqUmVPlHLTXTNRZlai3mReO/QTYRXNd5V6VrAteyQWlzrrzdRcuvi5tbLqw7HXlbJ29JIi6kCc7U65kQNB9I5l3S39vJON3cTaxaRhztCvww5VPvV6LwaJ7KI4lNlo9o1SQPR9An/n9cZM1S+kJDHu8AxLF6nRekZ8Y3DVcRQ+61X7Z+1tY1l5Wf0UH5EZKl7Ouj3IhPGuJec8rZginkn+l/oKBdGnoS1fU0Y4vIJRSVm2uZRbK9I2BGm/XpRrBe1pjHRq10LPxp2Tkg3dUzsdI5vLXO/w8s3K912GGGl9Mj2i2W/WJ7TYjldb/Kiwq3eJE75uUb194tj2xbHSZ5izlmobcwRpM0wEcthMIVJoPQj2fh15DL6gfwwNNkEvmT+50y8SE4SlK7IXzMka+q44ijPbpLbuhh7C05lezh+xMKGdc+bMBlTWq+zPinCxK2doxLL09PsRuUjEqap9oUKjJy8UREuG9P4+Qzg6ni0xVyNwYfLYzmUcH2sAPV7COQpi92zYRDu7LI/vWJQ7TdVxbIOkhKj4Q91xtc302Q+MsrGMdH+TNPGPVYLae2U5pO8d8oPky7EU8tnI5paXZ+m3jNoY2QDFzZz3dkni90sV+ZeMY9EWL5DmzR/cozP4FHsJZq8rXZX8hVpyyzqQPr1adlMdhjD7j8HZd05o1jPuiFOIQbONYESdOp9acI0pM0lGySZbFVtLosoK9cJfR8rxFRAOMeRS1R0wWAOx+HGVhUoqN3kltTgqjrQ9ND2DB5tDTi4MFfAZJUk9+gTk3vSw/PLxX9MlVjpRhYCxW+qVz3wcCaSwQgnIimgn0Pto59tcVR/rzTI2/pr2hbJr5ZUkwsc03jtIGm18/sEE3bREPHTst2qusXr6bITyPDqZ4ISeQjzzhznO/wn2RbnMHR23NOYV2exeM5og/xyc1MiT9926vLlh+IwquK7i+RPTxv+GV7kzQMh2+MQR56NpO9B2+iPwQLQ8FntoIjvQjj1kFq1/clPqosNyhEcsuWlj/EBWlrFLZhxfaRjSY3rciiJKhnAuF6vWVVSk0HitDxJo9uyn1Xf6C1ZS8G0ULw6sJROn8hexizX8bR+QutrVHRCJ82vX76gjyL9/vIngQVGsEQ9wuorIln1UV/pjbpScyxtYQEnz2ZCVJOkOCx7T9DoekTe0oITdJEQ0XlGQ77MpukT7kiywd0lSfvJAEeV35hMwUFZ5nFCSdjtb/SxgUZQ462ZLs+r7o1Frv/H2epFs2yVtYZFPlhGoAp4X6AjwsTES/r3l/+XMHzTBnuByDTYDYFr5M14TLiRL9k7RPawFwdU5yJRUmUcrUSxiSm6Gn9pFw0J2cIaVInZI8kq8YCYZDGet9RmKBwSw3Mm6WTfHF+C9weUkSOizRya9IN9kVPsT98sR0wd7X57zTCrAQ9j/WrV9c2QgcEqUu5loa1ZF25q9/hWOY65mFY5bzvBsViXb3ch4BHoUsq16moQ5/I1bBhX0xrAvOM3sZUt2RArT1P9ih5BgaTIyT5tMfwRwp1aqmDXZ1id4BzsxoLEPT/IygdUXFE+UTEFAyfjswbElttYxAC/QQy8HbwGdHwmbgPmwqRlAr8Yr13g8zRx1Wpye15h3QvrYHGFVkfEJEMz4ci4RF8V4shxLRuuNGgP2gZooU5JsqEYPvUhaqvEB9SrDr200xA0SBcW0IosYAvmlFh+1SpHMMPaVc6RSfttlcUWcWvr1DIjBwexYQtiw4A8VnPW++nVK9Gw48RCkj7MwDwSmu4S24xFj26ax6slLAuNcQOMpJSS4dkJ7M+MTAXS2qT9UcXFGKx/lmu4jJFxgAgKsdbwiJg5bwGYAcYyY1qXsR8mKbn27RrQdnMMH5wKHHpzUoiry4Ea7Xvfw2twuv7yFVT0aGFdyCI0ozAobJ8CpRvFDBJLN19G+yHz7OEi8uowzW/JPYbewCNAQnzZAdkwpIh4p4w90u7PwILSOdkJow/p/VG+plfmPeOouIQHlnFgC2fLhAJ6gA9lDL4dfCgbwUysKJsfk+a7OsuZIJsnfM4S+u7nVfu/3BIJgoMGyRGklVESbgOyTcLIl+dK9RDmsFIq58nIWNlU2RrGbB8IM2Ua/j3eKRiTe8NXbGP7GXM8hAUYczxPRow5PL29zFm3fVpWKyt5QPBE08JYHWV4vOaSMZzhRNaJOU4gErruglR7l5RNFviDDZ4UktSxHY3q/kVVCWKqDt6GqZRtQGdkM8b1Ik270m0I01WZjix9C+ZiPwBNuh/n6I86KVDj4qvtNFTLhjJB9yvT/gF0BeD0k+gk1oxIN4OMMyKRST+6+kvrcVeYb5J7VDzRuH+NhjUCVuhwDsrbGDXEa2w/J9s+Vb2ZTwsD6WzEVUy9pTnrsM5WKTqt0Pqgqorkuq5QEzV1NZToGM4Eh4IPpdUdGNSoK/K9hxnzth4+bEY431qwYQEjy05fa3sWSDsUw7O0rJ7RQvDifK69HTxg68ayBF/Ds2jOy0sfvMUB2TPyfCzswrwhVQt5VxbhvR009LTt9+aG/sirYQKhgoLbXOw/0mYsjulbIyilo5iPS6XzZdKFrs7WcKmhTOThJ+bRHd7KZWNYgEF3UIiSl2ZuImp0LbQWcwgYYkwWzoYrQfxLWM9VHZmBr1R03gUresvUo2GMeEIjlqQVFVLQlee0TQL8p2pra+SidkTzCUjtfJp0ha23VZxtuKNDdWbi5x3e3VXjWIiBd3CXb9u/2KA4uUmaNCS9Gc2UgdW1FawMV3Rgak0PdpC9zUY0H6ObzfEusDw8ki/0rborCUfK2M8BFxhZqEBjFWjo0B0ohMdoWS6/VDyGO8PC8eANk97BGLZ0I1EyuJtsV5N3sS1H2S3jtQYv/eVXnP/YF9+xTPjGff01eJZehd22fBndKrLDiLCBPTZYzHIVDBcHTP7S4PwWFUmUVf20HOXr6ySjgFb+LKZ4FIRToHCgqXGHlnaQse3ofHLBdk5NerZNbjWq8Rke6AxQbAXH7/D5zmJY27E0dvCkZzCqf9QRzRD7NUu8VgWLZyuWxqhDwPoYDXzJzQDq6HZwPDSnJj1j620b77vuAA5iPwBDPycBvz1S/RmJ8m4oekudKYJlGFxpjhPGuGssv4T1zXa+LRbB1hjb+MHR1N5XMm61ZE0lMotVQvEEWCrq/siXjW7Vbu3qMRrwcivJiD8sVhWPYunFZXU0MNX/XaxoW6XJL6yuPwud/OoiIm85vMsfsjSPVlreGoMH5i4OOWQ27Po5OW/BfZmRu2BKG90GjGouxmGXCSrwqEmOVDa3uowJYHCIw3pIGx6ToLfMBE/5bOk9Wj2UGVhUPVUmHWDrbQGD6gwRAuQEbLmL5gVp72dlwt01IZyj+wQ9mNrBxtCKvbcBdNiBuRZ2iRWVI5hv24bnaOdY8gNKNzd1mpGcr2OmMuIgaXUt0zI1nflX3rqcoeEls2VsrR3Y3HyunWcLxm8qLsb+n9FDSWNMtclcBUiIqTsgGyYWEe9UMldp92fgSumcmLS9eDJX0vsu/2fPOCou4YFlHOiQzBVED/ChjMG3gw9lI5iJFWXzY9J8V2f5NPxmD7vB4MET0S/0gNvxY4WKLEoP6uqOkLdxseQelZPSxqg2RCpVRRvymXVgp7LXWw1phvVuNcc2tpHFBMBJXtRrmoNay+AiKMTNPZQN6wKorfg0iDVY3okZOEtO3N1ho8t8k8SGfDSGlTISBbPmJA75QqwE92IuXoIJvDvMdEX/fV/k9UbNSQyglI2sOYhFCrAP07et2zNl/Z+L8YD5MGl6qLUNQqzhGgMh0wx5CvHVYJYx35byHdD1eQXeaD6M+W4L1C+GX/RaEjPg8CoYg1zGfSBfbwkLSsYwqw4nzo9J87TCYqz4pViZP0kHAUOsSOFs2BBEbP4SXSD9TdWLGRhJRV2T5sc1F+Yo7XlgDBaQi3bT5gH3fTau28kTQ5ez/msZ3aIPCe5N8dQnwpcynrKW6tUDtoLL2xBwg4pnDLaPS42GMgPTGs2hST8Wf/YAHEkj+az4qVnGc3Fv0xrAuqDM3lK+HQ1iKaYdzZtJJ2iFZTd3et+l5lEOTrq9216g83h3hwUlPZ9rhxfnYpeYTec+J0BOwHC76DIn7f2sbLeDrnLvk5vqKCpWV2e4y3dRiVbfk+pu4CAZu2jqQWzZVbHhSl0zMrEIcX+4wArDXs3Ae4bTYMSJIIbFGXOkRPQspOMXsJaKKV21RnWDAHvKVsHyMtRoKDPytHIOTfrR1dkuHv7KLjE7Rh5VnY2bx63ujiJqPpilmBqcT5POjCouq7Z+zitkckYa4KQqKwGxVlkZvLvDmpKez6WsinOx/Wekc/SAl89ZjhGU3frR2t5VlSA2BOBtGFLZ3E5Z6U1GMgO3mszfTljwoYGYKQLamsZiDzz/2DTktmDEZm2Sit8lG+p+ribSGAxMBd5CWKX9HmPdne0F7vgM6xWeh+3fXLp+N2fmjlV0fDGCVjGdrS0ObgDKci3h6u1hQXAIM3IiOEcm7fcIlnUvIN3YGHuscNABnQ14zOY+K+HMbsqezKU7y2hsylObLfBcOUdVXWTn6I8amURGwOCwOsBA2mnOYBM7pjOrxjCLtqyap53Qk4dOG8o9WYXgQXshBaCVZpLTZo+iomLerFbezSjqwFrKGNxOU5E3Jb8/lD8pHW6zMOjZLGqIdipMejHUWlBF5kai3TakNSZnwt3cP7TDWIJfd3IXEUahc6uQVZicU3fR10I3iCXYdAc9L87yNP2WV3gUbYA1+XCQlQ+q53rldcB0RBy4VRoiRVMQtw6d3zqGNRjKDDxrMHdGbNvXWk5Jv0Pxj7zmcxYLn+VKuyECUIkH61qp9KatQ9qDMMat43bb4c3A+rbzbaRk8JUXtKbEdYFJcXsWPVEr42mWELy6ex1FLdi2Mq5gZ15RNWZ+sRHkZGbUmVnMJQYzYNQPpt7WcGF3hSewjSmPyBCY8KbT3blh8wC36pbG8kLZdnQLsL9uvk26xNddbDWQab3Hc/8xv71ifhOekS4ARR2I5xkQGz5XtQLZFLnObx1nG4xnBmY2mDuTXnBVt4J9tXY2CHgiht1Nw5pqBDPz5k6a04y4UMd9llznym1b8arBQoy2swxG84lc1NdlXCTNg+FmWdbAKtKUMSy0deoYuKmFUq8pOzMDo+mJvxNsh8d7H1XoEyqJU/7VSZGvtXynqAMnhGfB7dLAyxuan+0MejOHCVVPfJNesPW2hfkuc1vWG2pMynhMM4uzndiX+ZlOJLtJH4Zay50pbm6SFH9BVzqfGgESPE10QFZnCQHz7LmvpF2Y4yQgI6zR2XRhp8GDOOUyQZNBKU6lEDh8Lk3trycl6C2TqS9/VFCPY5bTqWqebPQ4Um85l48qL8jzWck6Kp6OH+O7KLtF53ipHdUFbiJ+kvt+6GqCTiCkkpXnh7YVkHXbvk8jCo37NAMbGs+CSV8UaLaDQekfdpw5qhKeJcfoF+ZFsDNzMyFIcAvuG9VfjO0Oo/jHaYb7Ev+wM7DoKkIsKKljw5TaZnfK8mw6mhl423Q+d8JyIxuMzs9TU29mnt5F50/DsSzI0DvoCvqPGtVodbyOkvSgqqL4jt67nySK45W8CsTEILQNCyuas33afGkO1g9lBubVT5+RITNZ8MTFDOGqGUiszkcsq6BhWEc2HTcBMOmoz1snZ3UjmZdHwfky6QJbbxs4lVlsLIvZiT2WMPMJW7ZVgJ0VK2aruFk9osVELzCnJn1hqi3G3qfrTV5UuG83dPuI79CqTtFlVP6Q8rW8CsTQI2gbRlY0AyWzYHs+jZVB36EZGFBPfJNOtPWS7JbUXIz5jh+tmU9eBX4+1JH5FM0sw3z6Ds3AfHri7xzz4YbSvHFV7thEzRNiBTnjDbD2vAe0A+mhKgZffuvWDWU2npXPmuER/2a+09IxrlM94ToVroGKbtWso6L6cv0vFFekCD1iRoipKS3KsryiWH79WqKjtCD8Uf7+sipqkZkJ6gtUsa9qlS9fNN8ZvmofMRN4lKsePR5FFbrNiwSBWPryJy0u/IuEN0Jo2iItio95HKXJn2jVziDcKR5K37WPUXZbR7cwtrbMrHPooipoDGdJmU/aPQ5Oi/wMFeukLJPuvWUIMQ+jRTp+9lxEOL4b1/UwT1OwV/i7UeUmbFWGooseNhySajhaJK0vBUiT3v1E1xFyppWsmqbMYMW0SWU+oeouB6d8DKFHiKUIwqviHotWsGcjAGNiU3GVVSqatyBalIdpfkseEYRwdWV6bmoMtiArdZZzDYrukRoIx/AulY4+KtFpLDfPkriqCxBHW2RKEBWmEYQxeUg2qaRAa8nsA2B61ChN7lHxdJmswZ6y5aYDHxLkKMbOph2yRduHGZ8kaSURYpo6po0qmWoMY8BbDfynKKtvIjr1qr6zYFrUOpxWyNoOXGxQnNwkMdWFevopegxX0MtJsNoXeoMEik0FvGNj5s2YEu8yAnWvodQU0beoSKJsCK0/ytfXSRbJiKOvpW34H3VEv3zNElDOsOWuo7DoumkTJritkfKdockSLDrfJsTQSeH2jg6UwP39ne70kKACH+NgVaMv1KL5jB5KmezuyrRIjh+xjM2i9KCu7siZrVlEcmVaBa9trH8LGcLMPFBtgkZ6gmPfotYjimQYzHpB36aX9oKWahHRDAgQjjadhKHOwbyRAW+C8FOPGuzACxwwdvgRFUPsKoRm9JMtBOZdKxM05I0HKZrmpQ0NGjG3O0wvMAe8wcFHplMOSa0NkcgoNk6/rR0tkzwVHuYot622b+MMZXD/+ExyuuMGn/MGPHaIKYps0Up3HFnyJS1toVQTMm6SpBKxbMMEt95OMIRug6YCNqLeHBU17qnRNbketPYosFcmvREiOKWSf+z0ptVg2FgpWGcZx6XpqNZFzID0GkKQdKuRuecAV+Lo9kc7k6lcq2CCWTRovhYKNH2hfuNBGcJKllIk8DB6ve4OH+WpXnkNGw5HAAZWqRw2SrQ+61orFHWillhZer90k058iqjElfalLddbsWDnQ9CoJXMgtTheX6L1JpWsAgjO1HD1pELMwxgfQxU4ORADqU7AVgp73xhCP/AiL0tcMVWg5GH0A2+2E7kVdwRgcBgGPFTgUzHoaWSOXoNUf+Zi3LvAM9bIx07Lk+tNlNyCi6gr06+aZmNRLpgxiNHp9COq8GlRt9RhSIM+RyVevd9RcnsHknEEYIruXYK5oZT0lIfRIh05rUAYOSchnTB+ymKVLB6KDc7949th+KzP3+UbIVUMl7u159Ax18Lq68Or4fKRqaO4Rxwq8LfYbO4cRb3e1aEfsvRiU7goN22i83JgmxguYHk/hTGxTAnJXv/qqQhDa8YHVpLSj7+11lEPxj4x6fgb5Cvuhlgkn6aGfJDqihAZgStwBRE1+AFCcmP1J2aepkrWGwMohsLCgZRprt5V1BihmJqLhszVzeU/PHQWRN1zBlI2/N55QEMEFhVABpCSDiQY38tfYRmIZWGMFVHGLUCkikEt+ej0lSHaCS4GCvoZtAAtq2HE/mRl3ROuejcKgJIgoGJoEDxIL86DQkUuEOfEFOoyhyhow4PIR8BBQvRgXGUUpOARzUQEzptFTooxoH4c46n1JssYHUAcNdc5UKgP62U6KpIHgJIPRgSGCMP4ZykIA+ACqCIlsg9BDpM0ZR4WU1GFAzUYzrhGAPpwCGciUuvMNWQJUFBJgNWPiq+iotPgemZALgGxQgsMQa/OYU2pBYpA8oEIsBBpGBc6BU1EVBNrhaTBo3xNPbQHTz6YHgKcehw8uDfDgEgB+khJ7aI1jzzwrnpPPEB5hiEVii9YAVSleUdBlToNY4W0agm6AFTqTLB6KkG5H5Tj4ZI+BKISl9RBxBpEULe2eRUXCTAK+cmBguuLcUtUiWIe1bTs0rmCXB1sNmmCVpc520+RKEp4+ahU1SBiMd7FClopsUJbl3QKglBu4E8TuvXQNuPrKoWkWY9z2iXXNwy7RitIBlYwGCFULwDhQLQA7eBxhhLwV2M3b6l4H8NpxfAIXCHajWT6GBlEorEreyjaSF3I2dd/5SQzqq4dvAkWBYFVrvN6yhs1Ll/vo3CA8LPSdkKvm0irWBBgXNOI4pYk5lqYVoyKrVuR0YWAU5JuVqL1utUQ/iGlmQirHZZQRUExQ21Qinlq7YZvWM9kAqj5qPQM5kiuebiL9SBSHShAOPlgIHCIRFwckYI8IMZZjqOjlseBTVKGktfRMoC0qoLFzMmobQQgqRJ7ILrq1ygIbjdQ/Vr1I+SsGwIcL2ZASE1F7ZDV9RXElcbC6cmsaXNagqsCAK9kYXvAtaUDGsUFpD028MpTHQypugF16AB0+2XGFMHXiTqq03bxKLG5creawjMuM2VHjOdUwlQeZoTOo5jGvsqtCCyY/tzPQHvbEFhcchnV9D8UVRShuKZ2F2MUWgqYYlJQWh2QrJ8E4y7MZ+NRdUm/f5vU9qKKfiefck5mVaJUHRnHnTtNxwiFF1VYTAtNzKgLwOxwcfxTTZHDCnFfFg5rwYnOy3J917pSfTWu6zx4paI6BbWViikPMyH9aSTtlaTQYi7UeKzJpERnMUddSLH9RKl7IJ80LZd4KJ2G24Kl7DcV8GZ650Ki+uoiWm9SNKQQkVOHg9QPaVzBm0IcOkj3G5KkeNOnT4cyfj8PoI8EUj4guAJEHzZhi4JCEoQzxFQMLSu2eBHIZCiKbdyaLLNu1efoPkEPBjoPB6hdAWN4b6c6GOuMJPqA0s1NnWbEU3ZUoKWZvKbhcKUIwlJV3oxibcqacSB3l41J6fAqAslHJ8BC9GLyQykIJaKa2OGVNNg5kQ5pqmB6CHDqcfDg3lwEIgXoIyW1j8u9NshQAqnwMgQrBPC3nz2IUJWGTOl/b1ZRPmSj+hBFNYnWFFQ2a3Jin/0+O5uSugCUfFwiMEQ3NmecgkgAsjkoQvPM6UnCgWmGMYaWEqXLgKejCoduDrJcsenvJDRhYTQjYEAl1Ij0ZGCRADQYpfMLyRxtNkElZzQwRvPYjCUMTzS4YGIIFPUSGmxSRpXYYOBM1jozlhCig0En4xCYwA60oRkFDcLqQDj5YCBwiDZd0kkFXUBUE4fSNW2q5CkHoeu+Sooa02Au2Qll6Lwa0qrLneXhCvJhKeupnOX5NKAGnvNwGwrP+cko2eZTNSRjA205voZfJiRg0wBAPZiZXZcgPehI6cWDaNbPACldhfpzKo9pHhIorEcikEnnFVYja0LMYyvq8vBeneEe30UlWn1Pqjsmr65IGl0V+eA0NSGyMTmEFVTTIZaxU6hTPZQe+WpIcSynIVxBP1Cwnop+FpJJ3QZASukchaLkV3ZCjck5rmU53lHlKQk7bmhyuUeyXGtEPwOikVMDpFTitSm3dRKPwTQlCYC03Ep1VAkvH5KqGkQpSVZxBdGULUysx0Jta1eovpLdYB2XjSVe17lyTJ5FLdFSEnIQ8nGNAWUJsMDYVRWeKRcmm5b+akh2LyfCGFA/hhG8iiR6FQ1GCbn7yqjsfHTukpFpLQo8oO4MzMF7nad5XBMbFUZvEGikOQipEhBQBVgqjF9KUEodEOnEQnvovJ6FpLAGd0UGjGR5+zQzO/EPUGjCy1XgKhEirQXLJuHhDKV8kiOfKzxc6INqXcqBLQapWp2e9JtrjQoNK+wTUliLcSmsFZ4Um8nPJU/Tb3lF0y3T61L2yVTAuUUBrnA1kdfyd2NR4JbkaZWkfHXZEcB3a66Ap3KAHcK0rkK+G6IAiSx7nEe1n5i2By1y4I2hAHrL+OGdq9MsIa9qK45QqgoqhUNRD1ZmhGeDlPqMCv20p3nwWaQr8UkjPTGldc0HLkNhQmLTU79hiwDVtZPqknJ2eJzpSnioSaS5Clw+aEUtMAnt6HkqBTFVeCEdU3irKij5VPoRCGc2MJVW5ESpuXQhHU0MaaGjgXbsc45ZeFtM73oEQ2u8IcBKUhcL7oEXnasFjHxiyo1fULs6KfK1inQqcIW2Jq8Fh11w774p/ZnlqOcl3WVuQTgG2HhsQ53ARGMQT0yy/o29K4URRQRSCFgeFhTXzLN/KmEt4JrYYNK/7qeN4ZFAqjYeqAK8l6UmzrYShDO4NF+Ql/TwuThZR8XT8WN8F2W36BxP0/BWH3DI11ZSnMl1deGHHnJdal89XpCaw2uFYUlJ/zCm4RjacJCjSiGoNkY4Nbkkby0qdQttHflIdVXB5O3SlyMVJNU2NHWee0n7CqOdror9YBUmvKBEncegB77deHWSwNuJAlo+QHkliIayVycVFFQ0MHEwLdPy1fiRSSXtxrBGAxtV0dDNmFpjpACtuIc1J+K20VOfpkzHVrJlDZYEU7Ig2w4Y+i6fMgfijp6+vBq/JS1SVQEtH6a8EkRH/rFOBf0UiKFb/vE72gGC32wop4CWD1BeCY5tM6acAvFslBteNL06654ildENgNUNTqwip9noAVYt2QDMkBRUzoaCar+9brCQm6koyVDRl/32mszEOmo//PYag8RoU9VR+ilfobTsCrrXaYea7ZcXF5soJpcs/+Pi5YvHdZqVv7+8q6rNr69flxR1+WqdxEVe5jfVqzhfv45W+eu3P/3076/fvHm9bnC8jkdH5N+43vYtYeUZH/e5UvKU2gqdJEVZvYuq6Doq8XwcrdYC2AVWwKsv1/9CcUWv6B65Le+3ntRdg20OhiYySJxDAk0Mwh04+d2eU0hTVNd/Rfr0Cgx8Gmh4godFJp+OEDEzLqmHa17EURoVZ+2DqZ3kXeGR52m9zoa/ed6T1754Kiu0Jr/HWNjv5thOszitVwhrlAmuHW24ngmlFpjLs6gsH/BRHhdUiDzIyCGHAMzxd5XHSIev5pgukyrliNl+MsdxmK+exiiaL+YYPqEq+g/09NCYSFhM4xI7jO8Q86I3j3RUaIcXoBnz2RzXx2SNWWt1mXdHdBajUGiO9xxlK1QclN+TFZXPLFq+zBxrU+OfecYNnf1ui+17EW1aXwQI6ajYFvfFXf4AzJRQaIv3MCc3xPyC5sss1nKR5AWWptxa7r9aruXL6BZYzvSriOm315x453eQ18IWwm3o/IZktl1Fj8o3nCx2rR6TYDAz2btUtafZwcS9y3bXepeUmzR6ah0xWEzjkq2ZbfyBOBH5TXSLxGGSpTW3dYKp688YRfvJQlEiROAH0n/cGtb4mOPOJ3+iVdt9X3HA43MRCgY4puGcpg88juGrhWLRpkzicbHfLbARgiCshLU5NUYYuTIHrBKE9riAdTMq2B6u7zNaefG6JFWXCYtLq26rTOx6fFSnzVs3EFv3heZ4v2bJHzW6QDk5oI+xckXmOE/S6PZ0jftDzOri0IFiC9W+Sjl9nnxY/shxVl+nSXnHa8XM52es4DRS5qIqqKt0Se1tAfYxDqPrVqZFM82aD7sHdb0Xl9O4xB4jsGtwRTZmH+IbdZbWtwlncRiX2GC8zOtYWFfM561ZBWeoWCdlmQyJ5XxWAI/Ngfv1KLZ1twtr5hyeHmRxDV+3hoN0qSTNuUflwWXAOerq28o1JwVCXTgip3KMSiwMStHj8SNabzjjHPPZCle7fTcO+BzCUZk5Vur8zWHrvtlI2WZlNa6BY0HLlky9gpeS3HmaekprjMFFQoPVdkEfCSXj26sNiEn6omW0cGIh/5J9wGLwjCaNHnWQK7NYr2maP7ynYeiX+be84peuWDzHuUFuRcNsjhkcfa1i3pTGltjYeFYgPvb7fKe5BeVNFynqK3XgCFlD2SOrPI0EIi3yGLpvc0qez/X6GhVfbr41yY9GqMZFz/jMLkRC+zIiGyntyI5qFNMxZbMMINYcSsJPnIbG+IiLf3+5+W8y3b6duf/uod93d8sz0bprlsfCfrdQWjd9fM+oS8NnGwX4YLMp8nvRzjB8txhngfBetvqSCdvcuMTCTLtZSTCOS2bnUp45D9P8tn20wYEvlbUn4smmuUviajaeKrbAwhcID4Hks+Z7xX5ffJaU78WYCGt1/YkkddOoIKaHz/N6fTWjFxmH/W6BLaoEs0X3zRxL+9jOfyF8fKgi7qpEKLTG+zmXo+3Ltou7meeHfBldiWpSnm/al3D+UGjhyRWV7Wg4Ly7m++LzyDwA5DB1ytrT7iWicBmXLLc7dW8l8eNkv2/dESWMKdxDTZ5bP35fJxINuSmx0BtL8noRf2AevloYbpqQq5HNpvm0hNd2V+ckL9aRqBIIpfaYL6K0grE2JRYmv9U6yTpJNLb2jUqsLkXhi4lRgUUPu6QEPCFHBXNfSrxDKRLiBvqP9pcbfbwldL/RFy51SfkxwmcD+ETLFS15DiVd+ZjfJhloxBVL7TB3mYykyAWArdmrhpQdPnuVJBeJwVYlrTnNTkVDuUTWZz7bzbyIavg67x6FxfEmynhfge6jDR4sTgrBm5X5bHUNUyH87T7JYsCpmSu06KMQdXFkGXHRst0bfl/rvlpjegtiemuD6Z/JhhhaolR0aeSKLLSCuzxDzeUApxSwBRbrJ3qEsDGf55DyS+n1dA34urq3K8lFrZfVnEZWirLNVq7RW+GyfQwOuDAeimxxwu4yfJmFXe0h/4iqChWnJeBRLJZaYL4rEFLhBsqtrgRRkcQgZr7MQm7XNJL5Mv8WcWrnuGTX3Iyf2XV8x+ifUHWXe7ptjnG5RGtpEGyrjJLGGjvGGYfnztPbjCT2uiNJG/g7w3HR9nAmq9t5MiaLyoUv1fWnMqiGU6IDbMPX1wW6b5J3cBvmqGTXxPlCzN3diPrxdYfF8bYZrjoNN4f1wNyOxBVUVWxNmCWgRQ5FFjhbl4u27pFotYMhLGRBXukbkQLZ+HzfckRpvjwfD8x94pKQUYQ7d5Q/67JLBrivd7+en/k2noxEchffFdncNxV4ZDR6nEbcgy4uEhjzVr4lZXKdotNsldwnqzpKU07ugwCzhgPc0RxrknUvllrY2uo0lSIWCpe81+uYCK2xvibexgHFS4czdHXkyicMsd9gNLxFdacuCo86+IDaFQ9hr2Q1PmYX9RrWsJhiJ/VKgh6GsO89dTmD6QNCOI1B3ogUyMFGeBBzV1fjkuWVk4sfNddB8sFifURZfRPFJENFgXe0CroAkcGYt/K+4kPPmy82/gLD0/BjV4Hhu0V/2jqQ0sCX2fie/lEnBfpS3aGi18E4L1QIwrqFQd2A8Y/KLdZvjeUWXvgxUTQOVisOG7+WtdA2s9sl9eZnd/huYXRp6/Azy3638NbK0mZ5MnnHR35bQLnN+nvswpsk+GEIe2ocP26SghrD3kVPJUwZHsa+FeoMQjFAa0sOZaHdROVFhJUtBLMMUGwhTUc1hUt9odSq18TB7+C2QEjUTcVSO2/CvqLokwoU26zL/gk8fmEyBTbyq6109BSn6CPKbqs7XoJBEK4tnKEiyYV5lME4tEIVDIpGkMQQhJV/3F2yOc4ifP4ThOKoyAanPBkDX2blI5KQlRylXe3mykbwGZFALedheVoelwJt6ScbY2KfrJNnM67ISicjhufsHq9YXLm5dOSxS4FszJh5/OMfdURNN7wdc1RkfeFB6x/cR0kaXSepgF4O5dYSPAgYwmIekkyBXSy1OA3kD83YW9dJ4fIBKLc6JSU3T9TecZIXXf8OET6bCiclOaDFhUUU/6AphknmeyHEji+0PG/Ln+QRDt7mr/fI26SmEDy1ybpew/MOQ9i2ED3qWuAhLOmGVm3VhN+agGKrVUf2ncP66bCuKsGtQCi1xvw9Ke/SpKwU6HkQC8o0siZFmN3P8DlMtIzBEBaXBfg0RKsmMR9tNCqxsT8KqKxxfElXAJrhq7U19Ijc0EJ20KbAYg/aoDiJUqB34xI3jP113GWyBi7rlJBuLbYXdtr2eDgLDmvNi8dZhYoSYjQIwGrXI4JnhAVB7KMEtDoBG7anArQ6iV0mqFmHnGTkiqz2c1QOT90f5evrJKPnW2AcWmCrsWCZ2LzudbDZpAl/VgABzPF/R8ntHf8IQvvNgjrAOc/+ZPc9WfFI2k8W9ALG88F6PP0eoRYvCjCHtlSCRQq0pGdfUDeqQFFn25QDRDHW5B4VT2QSBfsZV2aOtdMjv2aJcJPNl9lo/iVqtzPAUCGWOmD+hKKyLhDpmwT7CMKhhYO16GYkFDrgJT+UuFkAC/x1tkoRvbwUrX1CoS3eM1SQkHPYSCQBcWyD0EDdRA/hPIq8MTVh+ascCQu2NW48/cbt5cfTYXFw5JFXncaTh/zr6e/e9hi8e+DKrCzsmFNiTCLBSYMrsu+pDDFUbo8dEj982fNxe2xvIMujvN7kmRgzBJVbub2DWN2wdbNAr/6p8i/j1zGEpcdBc8eGtQXI44At3BqpF+gJLo/3t3bv8S3iLydiGb7aKJ9hA4YO8wof1qVYgWIbM2cSCaZN+snGXNfMtcy7Dyrfu8mpcTWOsbJbMbHUAnNCnZAElMNnm17eoovkT96y2n91dAssL/MLfC6NKxi/Dta+/1+g6xCh0NLcfB5lQjjeqGBxF9eJDV+74wC4jWaW8Mak3TDc3ER1Wn1L0MMnQUsUCrdG4Wqlp2e0SIPEJVpEVnMaZatt7jDJIv7tGa7I5sZkjcTnQ4avFmIH5eT9tUzQ5UYFNh4unxF3599+svK6KaKsTASntVHBHAtv2XCqMOtkhMs9uGruVRMwy29IJW7nwqs7naQ1RTRRuCHMewxCD0ufEss0rNU1LTN/uGFjBnJep0iWFdAA3MoNALa4jQoszs5N/iBJugWx1EYnb10wYdRAsY0RrqzwSYFqs+yLZaITrhzOpbUzaUgEBOHUQvREGKRLSCNrhYNyaambAPBspwBzmyXwVW4QwMKw+1gVERFQnF13+Lw9Ipm5U/WUxQwmFyGsrL6ttkdcNy8+oEfgxVKuyHpbbx6KBff1rugZqwqtuGpuKsk1ZRDNc0DnrnyqcGy//tle/cIYhUJ7DwvYt8JFiYF1le25ZfQXHhPmF0jSChW9kx23h4qlFqbHZIUu7+r1dSbkteWKzHG2iR7G2PqPCxkDn7URb1uEes+DDUsGlvEc9hAiX4tymh1g6AAssuXvZEivbbqBCPn12QIHfFTdkSLtS20scGcFam6KxFjAUdG28Xmgy/wxNpc7fS2G7ddbZBeqblepp+UJFrn1EK/P85VQ/PxVbTbPRRCGZRG6M60ay/YzLtt/IIp1VLZnYCcGDse5niy7BK/6H0NCez2xVJB5Fslg9t5Falx7H6Dd8wHa+77sj83jcjcFjQbQ3iQxdVxmrDcBVDUYtbvSZopv+9U3eCSNVBFuDjWwlgK1MTEIMUJ8ma0zYudDIfFHHBU/Y6VRNVmezxooMLu8cmCFbpoVBffBjP8XiIJ6Dpw4BQ8G474dOtzsGje08pcm5Q+ws2M87ts4WHnpmV52Xr5FRRJlYP6KIPOlwO8+j1ZIJ9pBPDP1+ufQnSfXb4h8Rc8tY8iu5ho4KMvkNkOr3rrCx9sB5VZH7p3JdHFaQu9nD1+XOZsNutJ/rjlfBK7IQk5NkBWSnti+1NWXG4qCahxQVjoRZGt2P5Z1/PY5FpPDjqauvrRuMpeJfbtcBOVSo4374sVG/3lr+FuiKE2i0oXT43bRoNZWkhoRoHJz7CTtD/4k5Ehmv9swcJfWn+fg4bvDdnWUZ1WRp1CaFhnM8z/whl1zARbb7KssREaH5baq7RLc1M9sEunduPMHE+ESdJPKcb4PEhEMge0aN9MgjIs/6qhA5fntNRChwRZaHvMPVv+qy0p8z0IotDi008O1DLFYOo8b5XwqI10O0MY4KrC5e89+SN8wFAqnDHdYKr6rfzTHRxb2r8nYyz151WlkXNfe+zrhjSqjEgt/gbJ/9eZrwdkZ+DL7fgooPfFBuR34Mhv5mVWoyRrIy06mwCowBcjv4JLc4fgRt18KWgrz2UY27hNFiOWWkobJHe4jano0DrJGUXf7D8ZgILJD8LEq7Nw91DxcfJ/NDclCrIyXfukfc9phcWBkedVp+PhjlN3W5EElXkNivlsYYURnV2tHVxr9CAREWm02dcrtrc2XZVwstz1/bOOY27wQDT7s2xdZ4Gxfom3rHolXdDCExRFxeO5W3ogUaHkn3vDurc/bMX6hHYGolUUWpQd1dYcbbf2hzlFMaemzS6gwO+wcduim2U06LUOmfVgmU1kLkebtJ7vDAqHK6YrQ5CbhzRVQuT321uihawQAM2/rC5nYy/wH4pYh+90S20GMdfZShnNUaqUZ3ycrVMhyT0HlW7PaT/KiXp/lpedVd4/GYR0r6k6zaC/zTRLzKPqPSy1+8Y0P60d8zw5WK7wpc3sh83kfi2K7NChbBFgbFI/r4pBUnmZ10BZ5FP3HxVYHIQFkLR8VWBxRmuzO3Omk+2ihlHfSc6yF918t7gMSfBLmbgKaTzaH27IiDYuH2+G7PTbZTELl9thpFjQQb1Oyl1l2MivyF1aucmpWEfW+yOsNKKf6kl1wJlAIlnbv4SVL93kJIUWWJqg+jQr2AsuQZ/YhxBOpbVQEBFDbKB5XcSipPI1M3D4J9ry5eyrr6UKrpnXD91kwzXTarxVJvWmWCW0MiocaFVjiEx0wmM/LXYuGOXm1+cdbG4KQlE8otbn4atJaS1ADxZbzclFFVS3g5Yrs+wujFUstTIhNLnEYsVBojbfJUS61T8qA7DnuqC4KlMVPwOOJIIRNC029cyyUecxsiX2fL6PHdj+CzAtyKBtPPzACk/lsy9f1dZVXUXqaxSnuGMTePIRjC8ePuhZ6CPsWLkn9/vkH1VhgSM8WlWODIW1bbEWCYmw8hGMLirHwEI4t4Lri2oMhHOUTlvMJ0TGj9AQhkGQG4CHaBolpAB6ibZDMBuAWltSmCqeZDl8t+QPmOhdOg7Ohc0W2vSPLGOpf890c2zm6qbMVWkGx13yZDdaHqFid5UlWld9RgfDc8g44EhCLfe4OxT/yeghukJ7z1JAeLYpByxIQ+91b5s4FlVs489zcJGkCJHMcFTho5BuJRr6xdl8i5wIsdPHBF4uDI8wikIqhhrToP64FOEb3X+0wiSro8NUSEzBmtxF+isofaKWmpgzGrs9H9/dvxR43X+0wHT9ukoI6vXzKMz4BBgjgiv+/UARQmS934+B3SYHi6h26Tnh/ORmQjQmqr3YQ0x3kQ54C5igZlE9LEAfJoZxaOoyyH+JRCwRwxi8uVhDADf/pkRw1KXPC2r5mJsXclzthP72OePMoX2i/L1CdpPXXhHeIMYTFSquxzlgkf9JlSqMzohhK6KiC829NZFI1pH+L56gUsjHoYG2k44akwVHQE4bwaQEakRzKyhOi1/IUA1KA2TiZF/FdVCKpFRYEsDlXJbCf+KjA3uLXnLxge19XZo+VHLjwkt7UVbNHK610xpVsLnzCZELehWsZ9hh1jtZRkgnZZiUg5m18iEgkXXtY/5xXfTLJcTsKMAu5F8doU13eJbjHEf5M/YQ/RNnqy71wCFCDbs0VVHfI/1ri89qHpKz835MBULo8KmOGZpoLq7DP5lK5Cl6IWG5Pzkt+IeZ6n9zQM1tA5gJQujCXGZppmKtrm8fCfreQ2iVafU+qO5DJhEI7vMCro8znvwDjhuFVD/6cLdC4VQEZbgEeg5ND2XM/dO/Hl1nszICF2N4yfFp2PaCJJyMgkwkAYD92fBjeQOczqNxG24qTDUkDIOqxXJEDTiBKii+z0MVRRk4aorrNfLfFBnRwVGBhlURlKTxe0H+04aaB7FThhNK8CQDPWKr2EiOAy5Nj4Lui7oSuT6RBibvSUDS/PnkWMLtEuPwNJPMqTdgA3kaLpQ6YwbtmsdSGkrL+uvZV3k/XPoKX3A5X2d0ZqNlewUFLQFzbAMkgAbFQGbRXs75XslPkj+5SLQFZCLgim42qqypVewAAG+/cGGVDIisxTZpQbNF3LD+/A1nk2e8Wbpf0tWOyy3AOl8x3a/l6RKJsIQnbFGzX9owVEc8Teo/GdXuG6065PftvpbTP40CA3FqsUkfHvLt8Ar332eJnrCmyVuEwdiMRo4vZyAjLNJwa1r+8GQInldpvtlgOcUkmpNwaF9nZnaDTPPt9/rPczq0gcnPVpFPyWTUdFpeHvaRVt1uSXxZR/AMPDLoo5csssBLXR0hPGRVY3mYi+NqVL7O6m6TPwoBohcK/wOrxN1awmDxW0Zwmi75N4O69++5gAIHXprX9eGcyI5+jqi4y8pAD8k30M0LlpLYo60/ERoEC60IzUFhFKpzd6xxFZZ6d5EUzW7ytnSu0wUunHdGzO2/iEAqd8cq9R5SA9vMGp5AUS204Nbq5aQ6+HLMO3y2sPqt1koFuheMSG0ozyxcOV5SA7KY70WKbfk7/PMLCN8TGP8bmtPnrUGy35D6LilZ1EaNr2RJb+xyEcVxio+wMNIaupKHyxQ7tW/62YTcqzMKoIA9fCIm4YYgldtu9vAPCwbwEnoDOQeIZ4JhG5JF/OfttZOeFsM0vw1GLQHSdolZUwLjlUDb9vowejx+RQIZRgdWl5RFeO7d58STkIBwXOYi+LX0nT07bUI/k7mi6HEE6BHiFDcYZQnTN+vKa0LqgcUAAc8rH/YtmflJhMStWXBckGLQNnQh1GwdhdbuRM8Q0zbrjmxfP5WL5PnDAmuvCclsANptNrj/FKfqIslsh0pwtsMR3hookF9xwuCLLuy1am09vwhZYmeMCP2QTTnMKFb13miVVEqXgAufLnvE6pxOACz7mt35LnEHksLqVtadZ2EyT4PlDLF7K6gRHyNtbsXeZOQnmYAxKs7d4MSmMYSJjMI1ybp914sTxuGjO08RxRgwVXH/6j1vDQt5yzU2ezSjHcFMf0T1KBade5ruVNb6oQJ+tcYk5RvIiH4hwVGCxcW/g5142Ls+9hL0dwCMRHvvtP9ocaW5QUaBCwDUq2E1Lu5RLCnJzmsXcxQLz2Wa/pC8Xf4hKXmVnC7ZGRNGk6WyekQAJ3Fl0rnnc1Tgm2uuYNsV4LbF0qaUe6rWgYG9y7Zpqd1bQKJZW/vtx/BiXA7vrEGz3Jf9Jka9l3M2X2XCmDOe4xGptB3l7KsCLceU5ioB7vcjypq01Oxw+NSm2hJAtvtgJdx+hLEXPQDxjidHnIPU8BnZoXA6A8roT2SjgJwKcngYIZTiDDHlyM95SnmTxHVrVKbqMyh+eXmQMJhcPMmX1abjG/3B/gLlceCGcfrIRMHl2/LghjCqmXObKLIS/kI7XNhWvreFCsX1vvmTHRcEL/lGBxazhTey8FsUx+93CKhBRL9SiEvCNS+wwHmcrEF/33bJ/NX15GO4hU2bZR3FGmM82W/CHZLXiX0wevlp5Dd4SVj9DRQxcvHOF9nhB64pQaGF/yB++oUJctez3rZH0B3Ea4pH2Ho2TXVhadxoB37TN4xi+2mISNwz2u/0Z+zxPpZnpuzKbhXi6SoWbw+bb1rDh1yIIG/ZoHNhQUfevxYYXac3lOG2+LOLoJ3moQf1Aw1JJ91CGiiQO5I7MY3NJwqdFse2c/R/oqXkPc4Rp+GqFSUBiUx9IJWmdRtLWZLUQH1/eoTX6FhUJUer9mHiEyoGDNfWnYV/aKHdKaj7NeYj8CzFc66jtZWcgP10MDHC9bbUsCHealneZF2UKHuDZ7xbYiFOheGfLfDbH9UF8avyD9Tvj+W1+lsTkcQPgOp8tWjIM4kO1Tg/zlbA/st+tb2u75BafUfWQFz/Ai1sBxsr5HS+4J7pauqczxTA+GMa6lePH+A7rd4g+WqBuTAa6NaKt7ZSvv3k3Npe4DmnVbRVyqvdg3d6BFfNGOiSNJIv9Y44LhZeNRkW25/2TvFhHVZXwD0uIpfPFR0kXaH2dJuUdv3swn5cUrLvgqPMuJ0+EHGcrPKPcvHBFWyPCKJu0nwIoaS2Yq64mrb7tR9nARprd0OwPo/jHaYb7Ff8I56IlQerAUcaYpmGuYHkqAuZVCOx7v2tuEp+irL6J6DmhuERrvA/52vEgjA6saoZmW1W6bwl5u4qPARu+zqE2LHUCaGP8w3ATj83lQKBFseeireOiVpaHYSIOmZPLpwbDnoW2joXOEZmqVTt1vhHJLC6neGQ1gmn4p9eI3kg0pTdO2N5KsFm9zb1z/HRU5GV5gdI0CEfx2Fw2Ni2K58tVS21LTTaB5j1Zz02JReWyJanrTzT1bKOyR3ilQHZRgNJnXoTCrWGPf9SoRiv6gNlBVUXxnX8uDBClA7sY4pmGbZjGeURckZ0xIbpFxAwtsohQaMPivLZkqymdJKI/W/fNYn8UHrWxfc7GX3v8lKyR6EI9fN3GhRdsufktsvk24yQvEj7D5vDVLjBMDAezxSAy3fDVJpyMDyKzqy32ovtmcYmGNukT35H+ozUesUujAgsb4xFnWTyyqX0Yc4ZJ+mH+sDxy8891hH5Z8vrrAq/pS5orjfPv6D/b4QK6xny2uEqhu3YMvnDOl1n1cEWsrFGaPgmdZEq2RsizQ/WT8iwmBzGvrj7RxZz4XK71Q7ntwVqURKMCOx8m0YXJavfKCz7AhX6xuLIuUZEJAxq+2ih+ZSnmzBm+2saMXZT8fA2frcb3Dt1EdVphqbbC3JhEaSkMFgLZmnV7FK03UXLreQvaYXG6AZBV3Vaz7XPeZXc0mXEbGRfoknSMzOV+VIdhW1kb65vN/tlEpfMMABTv4rIJFxI0jfI3lcecu1IpwzhYq95AhhWg2AX3WzXutz64f1bj/lmOeyFR9xk9lB9RVaEinBMTjNNB8Jkimkj+ga2LuadUcPMq/XYJOGY8bO+GR98nFJV1gZq89L6bPoPKactX1t/WDX+KhKTnxKwveLgnVna5nbuAbuf/XYKbLL0FMo/NnSEVKPY8+cx58nS9yQvyXtJN4hs7O0LlwI2a+tvKiid5iqdUxMN+t7t7hPKTs99tffghfOMSW9NYgHRKPxIuSL75YnFJFP3gr4joF9tomS8Zf9Jhv5tjwxLnJEHpivzFnce4IntuOMqzm+S2LoCbcgmIxYw+VkUkXlYzn22COwmCLuSFi+kcFdlcv5V1Wp1mN8JN3vDdgu+aBG24DyRFm6C+CqVbI6gvnrI4TFDTgMglpklVe6Kbk2AhTRd5XcRIyKzBfF4qPIpGPD9WIrpRge1IxZTY7HfbGJtT4U2K4bMtrouqkASQdiW2GA/zPIXwNd9tNMssBs/Jo4KtEQvHj0Rpeoc2aR7g4SYem8vdqhbFNFKi1RuBmLIba9Ofv1IYSk06LWmsMseKw1dbA9A/ea2L+WxxyulnF1ItxdLdvg32zWHyoao2l0WUleuE5j+FaCaD8WtF34atMtocrkUXS77M9noEvktyv0iiNcHbpHHJ0tc4hB+Te/RJyBwxKrBaP4LbQvdty/asIDaHESrn3Wpvc6DkxUu3woJWXNmjQlsjndhLt5AC/Od9gkcnjVoAym022lZ8tazA7bdc4QL2Eu9zq2L28cQK2jjz2WqOiFwVjBTsd/sZb0wbookCKl/KrvDl5qZE3FbTfbO81Qfu8q18H6IqvrtI/uR4mPlsMQN4OdGEc2O691+X3j6P8vWGvmig0iKkQA7K80ER3wm3sWKpBeYURRmfL7T/OP+WfVCWeZxQI6IYPIeKVnVsEg9fsUmeMT0VsXKamkJsHAfPggP6wkpkW0VzV40RBNAWjPZ6ATnEsoTMfa+8O3wZFbcIOowbdZjFZdnZ316D/GDOMhd3Cf2ziSW8wrK1KhLyhvsRWeyNT77CVGlQWzBQjuo0gEIuOWAK9G158g3XQACuMeiyJ+c01JubaTqGvWJktSrVoAgt5hRsYLo3I/W0FbF6Tn+PMMDEA53zm+gWz2ITfZikRHntn/Q0mG2+imzKbeZ6jNOTphyykNPOofZjTOuOYXV7lZD5fHFafq7T9PeXN1Fa8uqmbvTezPMuKanGeHWw2aQJ8XZtEwVpNhV1PZ6NOuguCZEBO6ka8JyrHnUAblJ203PfaIk1tzwRh3TWpfqwYoihlowdzuCMHUZk7rBvNS/0nfTjhBbN3IzQNdv+fxndqo8nELgkhdQAY3IQERH7nj6cCGrcuSCzjTEtpkkYH0llNWR6hOURFEa/jTrkczlqnqOHqFid5UlWlR8S3A+8/3wt0ep7Ut21Xpeq/GDaymJGMKGKAV9oG/KcgTGuAHyi7/A2qp86MoQTON0h3ObsItQJcXjhkHryEY8tpMThcW8jA+nHr2ehztZKfLiiJEMFD9Ibc9sv/d9l96HNg0SugdNyqEfue9YRJUi5iWJqqlmhk6QoK8Jp11GJGpCXL7pLku7arbWs/ZEepc0b0h3ApyhLblBZXeY/UPb7y7c/vXn78gV9BpbE/qU3L188rtOs/DWm0xhlWV7Rof/+8q6qNr++fl3SFstX6yQu8jK/qV7F+fp1tMpfY1w/v37z5jVarV/z1Vu0Rlh++vcOS1muRhl6mEvjzj043yTxmKd++w8kMEPHJOfo5oWMn357zVf8DeBJ0vbvLxNCUrqc6WNmNGdkc3NKoBDt5csXhO3IFWDPeq+V6NkrzaaZ7D4q4ruo+G/r6PG/s/iqQnxxSehtFqf1Cp1mFwlGG206pNfkosmya6dl51KDCyoU09el3dEN/jkBxnmZVGkYijXRwwEQfUJV1IamlMEQjnLpBcIZjnZCMLI7d5yjDAuqg/J7siJbmwemBsM/8yzMGBt034to0z5dJOmbOa6Lu/xhNAfuozzMiRLkuS77fGSMmLPEQYdDzs32FGdvNdVSP3qELXU7K/shqf/yxafo8SPKbqu731/+7aefrJGOg9FMp9R4FrA2VAkBAs93Bt46zED7NKJmJZhpB13MdfB5pE9EJX+iXpV+JjM6xI4wjfCK6a+neLN5/P3l/0Mr/fri9D+vBHpcEd+SvM5W//aCrqVfX7x58f9ad4d9HDh4h/7m0iH6NNjwai3P+2F69jPpmacg63s6VSffBuuk84o3X64tHz2TVaqVu29c5qKl0VGdkqdpNHLdGv3XLPmjRhcob178UyG31QtP0uj2dI273nnkKtH/8pMt/vMq9dEQA6r5zPN87kgmVnGaNd0Eq52jErBg7ey689iO+pq9/PzJYfvp6DmJ4tUhD6iAnZYkRfJZWt8mmcfB77S8zOtYzvYexyLev/CZcKqRRczTwjZmuF9+sUbdn0f9EBvPtfyi8lnNs/e8nBQIdVZ+n43mMno8fkTrjZc9CiNpN6wmKg/cr0yESJcZzMei2ywGyj8eeNyWlI+Qy9P0mTD84ltwaMnap2MKYGwNoh4S++qX7ENOAttuvfj8IE3zh/c1Kiu8f3/LKy9kblorZBOKCnIViGi2ggYPSWpTJWRe7eh9nK0CYXI+I1jJgIOsfOCvzndWEpAB2UuBptaWSIDP9foaFV9uyNoofZh64iNd7+nVXuE8DwZi30G2Y6KhphcjnW5GrjFmRzmz89LBZlPk934bwTj9qVy+mZl/aOYwJ2TWbPrM+LNJrds0VFMrWkJR3iRksdvOQ58wRGkis2a5NnlvWKQyn4dQeE/yYh1VNhdEclwXUVqF7ufBap1kR/l6zdyb+/m3lEHOZAc3N0maYC73I53/iewdouHLIxRy+e0godsTX/cizkSHPmWX/VjoY1RWZvvMG3vkQXcI0tOP+W2ShVKpMT7KYVj2GqA06iMQu2WnOQgIZAqEyQghT0y77ogYzPtjvC2DoaU7uytTV1KjI4ApkwZDBu7BTpjIZW+UhXHsa0OlHbTsrqLXGsHoEXXkzWIHoxFX3acnR4yTmBdB2/X0JiSyt0GQ/TPZnOVlFaXQHa+bResuz1BzTA6C7yR6DIjNY/8zP9RAeRp2VnpO4rlA7Yxlu7V6GyzLIFcfD3nzRsppOYHDw+VdgZA5/p9t8eMlgook5nA7WVubdIKX+bfIS3te0PFhCWPtOH/JX2XtO/nrBvbwD8Ujp7cZpt7RHQk1m4RDWMXkmTDIdJrignvT9XWB7pMIYlDf4/cueIMdpvkt0QmfCYsufv1sFn1kZswwCd0y15taO6WXf2N3bdHiOmKNbi5S+HNehUY5ZMzw3Gm28yJaFYan2qy3LiLPt7MBvXbnOCaeQWl3dlbMtqMhLfjezhS4CzRYg8YyEKx+GL8lZYKhsYBP7pNV++arO29MohRf3NGHJsKutBMMHRpn8AuujnHat6P9pjqcJ1SHI9TpYi+lR5pH59eLFW30EEQBIc8bZrcX9TqQ9hEEX4fsEmuZKTdYz/6FQtnbew7ibYmZufhRB18iUVbfRDEJkyrwDlPBJmXze12HLryvEuA8OWGDp+X75KY6igqv02aHw39nP0d/1EmBvlR3qDgb5TJ0zaBA8Q1Kgva23F5Y1WRyqiQmSsPBasU16dX90/Jd/pCleeRnDGhx+E3N1yxtlm+Hzmtkn7ormy83Aj4nX8kWyfHjJmnehHwXPckwGpkMW4TU2YAi9OfuD1F5EZHk/CFmdYzJ4RKUq+9zC4oHRlzQDm4LhFitz2VcI0SX6DGUj9Q5iuui8LwB6pEcPcUpasSGn7xj8Z2hIsk9l2mPkW7+FK3XwjqlN2f9Cy4+sixUBBIWsjSfWZR22BqLfH8KR3GyjlKS6gv/KmnOrjd/x+dZEsKKt0mHrgdxsDstj0svEjLZXvyYBKs6xGiZ3eMlhpE1F1Kex6oqj3/8o45a04CHJG9OUxTfwX2U4LpJyuD0MIeDfXTavZIs2Hg/5g/NWFuvNr9pwNp/cvNET+AnedH17xDhA5UP2sMo/kHTKpHMfJ7+oeRwR/CdNjTEh4v+WOqlUtDtC89Msq7XISamwRc9hsJHB45WLaoEhVdFMZsT4MP66bCuqlwWnG26ZAj096S8S5Oy8kfYruUUYb7EgnlkLXGyv2J9m6JKYi8rzghB8K3jS7qatoH2mHFEbuOmauNig/FEqfNAjC5OmDb6S5TLZB3i+oPF3V6qBMLcGamOswoVpTcvttJrhBVNzECthJu1TXxeuExQs3a9ZD7ePFFZHVRVkVzXFTrK19dJRk88kzIr7n/3hEDZPiHgM4rvKLm9m275jo8pwdF/T1YTYv8wLW36XSm0zOkRhxU4oe4awniZTByosy2xiuDIk3tUPJFZtTe9jGv7GF46vfRrlvA3oAb9GNf26cdhVKJ2e/U2FPS4PqGorAtEeqdUle1zf/VNHKxZz5HQ20TfDPkxbsrBInlYZ6sUNVllAbOY71VAg/4MFacVWocw04wQEjKExHdxlzeWHyy1J3DE7Hb3Z+J5ofVHcMks1tHI3y7+tSTTGuPBed7I989VCdiCKw5dU+4SZIcTm7R3XOVRXm/yjA0ncDrJC1hC+dJ2k0Qvnuku6MeoAx6ydVvY1c0Dg/bZvLVIic+SLWIjbgnsH3OYV1gDC+5dRZ4oCb1QOrYL42K1d2QaOSqGubM5S6hrikNypK6ij4JP/Nwukj+RzwhGbl3lZX6Bj49xxWN2e0alwfFlfIsQKvMO1eHPo+xWY7N34JCA3ohhbVJb6PO1EzaLUAaabbZ93ER1Wn1L0MMnt4hwc//3RnQ9E2WoHc1hkkVDelxMtWv6wW3nwhNI8GjEkv3qRzlJu57ptKyfXVwOP6MHnxV8Wl4WUVYmvJ+RwVbYr4MrBonXWxbqleXdJX0wmW0syTNbUmDwh4lS1FX0itubTifbhijPTp1oT/vr55MkshuZg+m+r+k7czxpz+sUBX748GKDJjdQtQk64Chv212nc+cLgewclRXW26nuyeaIl2I1M3x1SM+kHuVOU8Ugjp4IOzQ+eaGRdxSWHJQ8sbdKvheFjx+rIiJvtk6pV7IXcM9EpGkNYr/Ya4FHeZoXH9Aj+HaIL/J282oelgl8vzfxxtiu/eZCitxGPRMeWlibai/4XDvBVffqSiBH5njK22X5ZdccIcuGxq0JIpaTFLN57/LlZVH6kKzQ5V29vs6YHIsuiNr48eWtW8/M+uQuknsGafjlmUjoYXyu8rGp6yUce9J6BgJ0aKh64YfrtMRCtblPsFlAtuz1zG5nF97vJfdiJqnB+pp+TzWUJ1jM1UOw7vyi15YD2SD1PReG4EKWovZ9GNf+y3DjM2TDSVxVgnsqMHTf+2qE9dXY+1doe7d7/hV794O/1gGQhvrdJDElZH/CeCZb1MKaEkzbRiY45B9RYvM7oBJB2Jz7PWMOGves7urc3zt9Sp1MRdBnsgDgIYbiva15QXIRRnkmLLIzs9AKlcvo9hlT3vIAZUu8b1GRRBkY//1MiDpBnkM4yeA8uRM9j2hTxvS7R8mbYHcOkjdKR+AcI/9sg2UPyjK5zfAK7A7nE2Tb2ceAc/ZL/6c/Fz7hDLfK/7kO8+ZesDRh9Ezzpa6+3FCUdJBTPEHD8sMz2UOncI1SmDXD+C5tkV8UtNTbIJDprlp51e6Z8KKvgOv+7+ly9SmiHp2DBLxiZ9kruIFvy7nXoY7YJO8F/sTk4fROCtska/bZs5jTR1YVeUow+d3JSJfpDHzyNnjEyXNbwpMEYAc0W3hduPmK6cZV+HlMtGSIzlIQpJWsMKQcX45jzZ6STvPi4o86KlB5fnsdup/N0XX1LzxNbGry8Gnw6CF8hoYcfd0m2WaCsLR+yxH7Thvy32k/JtmPQE9I2R/yzMNVuucCnodc7Ybzvk76huos+aNGCUV5kyDdqye2F9Bl/9DB18LL0RtA4/cybYsvZFA40UNRk5crlMc9GAnuhOz4EfetDOUNtA8mXyaYvM/e+0xE0tKeFcqwSTOHHXmIq4lD9ah2CGu0z1hCJp82ZmksSMpnFMv3nN40pnFkYVCR3HFhMAVxB9zO9I5/pZeft+NFYOBG/a/pl20srokeWWRRelBXd0RENt5M5yjGBHsmIrzblN23c08RfrxmwmK9tX4yW6fMAS8g2tasEBj7F8Jbl/kPFGaFUHQHcYzKMhxS/Oc9PjUXXpljjBfdSV7U6zPy1MzzWGGX+SaJ7ZdXW80v+HHpxW30tKLZGfrsYLXCe2f4rLS7FoRA1wfljmeyQOiA7Fm0rbbjC4TMo7+JuU2kqlaLHDxQPjeS2Otxz2++L4N/jMqK9MLTCt9ikUy5Izaa3MnzJLSbEug5CZ/3RV5vHCVQWzd4VIf/0xmBD1+f213Hay2HEChk7UFK1V6sTOKHt5viiS7LZyKjdkI8PDd2C2jFM+bchnjPg2npWOAQHTfLBsGnvs1f7kJssfNDmxm3PRs75Ovi6vvdMLaJX517IyDwuSSkNS9wWzXfE8dhhcDVJt4NiKrJ4Rs4qXPHnUd1UaAsfoLezXJE3CA8x0LG8PL1786r8jJ6bHcl/xP2t0gSb+guzPChvcJrIT3N4hR3dTJfvlFjx4/zNHZJGusTmc80wlGj84y0lQ3zjLBtbNaR4YYsFqt9YyMxhgV/QvaGKD1BaGqayluemsDylqemdos/TFJ2yieTM6JPimPzVqjomKwJrKnXWNtZTfxOwjl6iIrVWY43uPI7KhBmLT/XkaM7FP/I68G9OvSpUWggWFBspwRIfJRsnUxubpI08U6E12v9myBjpD405BhD3rMoEJYjR3j+x3qK07RjLKR2mIkgXQqmmArj80x1WP5AKxnpvHt6dH//Nhiy48dNUtCT06c8G/I8BMT7XygKM3aWL98lWLhV79D18MC6WxxJj+YgpvvBhzxdBZorEXlARmCQH0bZj2BHKQ5vsCXG4j09Co2yfXYnNNrT6yjQhtRKaKoUtP5/YdZEjZW9IvmzedmZ+M1H8Tip3STog7GbrIFzVDIx+p7SaEPyqIQnjog4YK/xubPXicJ3/awmdUsU2px6FiWhPHm7k2JznAlD0xYlOavgRbipG5PhJLauqbOlbu+FBntcOEfrKMmYTJYO+ZA+RCRSqj3cfs6rPv+fl3t3HKNNdXmX4J5G+DP1F/0QZasv9zZKrvWDhF9LfGj4kGA+eDZPMSz+IiGtat96W83P08t9FRqzzvvkhp4iniHrdEOzn7yhptf8fS3R6ntS3TmyEFfduyuj1+qC23HmZNZnwqCdnsTMstMDRjI8PjeRHan9b6Emth+ell1XaZa9yDP3Q4cMn/k2AU8i53iwGxJ0HEwF7DGGC0a5QBlR2EP1sEEXrnufUFkymca9M1x1M0KVPk+b8wzCr1/Yz0T69eMJ6iCzoLp2tmysfIgAc5LckgaZT32P2Tc0+bXlHKOZZSRTX7N256Vmv56aZOPWpqbdZHeB4e8Au8Q33gHcp2WHKohi9BGzeDakC/J6y5xI/e/T5uamb3o6PpcuFe1HJMIzDI/abftYR3kuGWUW3KApFXXsYCq9qIte3l29bLvyyJpNn5eVZ3F35oaoXl6xFMNhlEbZkN7HSX0rJ3fXCXkIC3vLwNo/rjytbVc2xhPz94Xukg29m30eK29BSX5ZRPGPJLsNeLlInemmVUroDSEKdYXZPZQRCN0cu1C3AJ6RFaMfklPgSFMzwP2UaDee3HpgoXtUdZGRjPLo2SRICRCHFWjiFtd/QtidzlFU5tlJXjS8EkZJbzkO0fOvwXnfBampb4NVABOXYM7znZ3o5oYcfMKgO1itk0ziYsYnNLNOazMSFCHCzbbFjcVig8ypD9FRVDyrTdJfWp5FRas4eFmeGruQ2zUrW9fnavV/t3dtvXHjSvqvDOZxsTjZzOIAi0XOArbjTAwkE4/tZLD7IijddFuIWuqV1El8gP3vS1E3XopXkbolLzNxs1isKn7itVhFd/L469XZx/+Zrz3CvcLAXycq6iD4/oLuhpk9VzfMCS9oNjLOQVfnlplegY3pEnM7ka1sTd9+xD543pQP8ffr74jS1IUNZnKFu/OQF88jHVemy19lbanxGSXDRwYRvvIt5UASlHOYf0UWYSNyuYw+P7ME+f2YLU5NdueifozW+qZv69aG187+6xE5eHfzXuQ9Hqv1RuBw9bxLEZto3KkHaja3qEhyuX+C2Rqivgwg3EZd7JlmMZhs0ofeDdmKkSVVEqeOlz9s7cW/jiAWxz+9yw8b+dIojYD1rEEPCgzWHczY9LnsEiFZ/7oRWDbvI9u8HspF7EuHRax2ZewSjPI6q4ktxlLjLt7OaIM1eYe+onRsMLu8qEwdT4w41tmOvD4nOJlE+v/NIdJ/wPHR7Mn1AflK6YiRiooCFb74zXLsaZQXsqivsLLduEPdJlnl27gUwqZwm3pP3kkkBDEdGGAjYxCtktenJrOvXaAkFNYbndExyadY9NwWxIG9G7I3Aszxt6JvivzoDkO29sicIO5i0HXHxfINlFHEY0ag8g7FIy9J2j385XMT3cYTs/455NI92fuodhsZBZwDT/uJf+3hRMj2WMrcG2b3hPbnFD3E5ZeN9LZ2J/p3h53oBf4e1DuPv7vkGMuz6++nGmKA8xy/JbdmT84uBKYms0WNj/9j2v8PT7t3g9b/wFPB3TmL2uqjsppjbJ0+ZNdFMW4Qb0VyTY0u08hhs1hngiFH3q6y9AzIv66z0dJgFv5leelomTNJcelhf0kEomHj7au8Kd8m+z0aFfwK/3moR41bVOyo9YSDs17HSXJSM1rbu/zbJ1TQw1uRf/va/SIZ+pvQbvXI4es8N91Uct5GwXHbmoZHEH+Gbqtxl6cuLhtM7VELrxu8cktDrJo+Fj8BNSGg7tPzwTtTLw5eDkHEzSNx1f2b7LbmwOkDa1iFJpGbb1Bgxt55MjHhxp1tWB9nGYPt4Qkd0ae4SGpWG0Ea0cmmO43SXVoOcCY8QYTw11rWXMOBhXDeCEiCTFjA9dv4SbBMra/DAS61cxt03TgWw2/p9K3etg/v8kN+m+zqKN3LcAt/Wx3Ty3xPzV/j7lebG8junfkfqPqWF198981tkRzj4pl8Ol2mNZe3RBCXke+aCMvr71jL7IBIWO+x8sHMLMQ0d75vuf8oI6HDtY4qUSDL2969OWSqwHa4eJfXDCyMYu5v8iYvjrjLqMjqntg7PzoBPs/z5zQpn+bw4fd68QVM0D7j5b/O6xj519ked+bYKdBuDfY+Jq9cNzIALf0UIth6+jLefbnJMP/dly06B3l4mT7v++fZvZCmuPR/H2fnx5gstYsHdMRj9maOnIIMB5+SOqeJmHBtNOPAj966h7s/+3i7fdwOez+7eLtdfIdSYtWmpzfSw/10/dLLauG3MVxCD8NFXpb3KE1/9qCfHjQfHOks21sxO62TPBGeMnyY8aseRYB3y/hkxn325xmd0Z7kObmoqnj3tKGH2ZRu9hsMpvI4z26sVnxA9ZEX3bNugcQ086nLVcCbxMWbpKk1xseNDnCPdfmcZHHx7HTYr/0iXZ5IvsdbQNjR04qxy5e4ke/vtkjyYmR4sPqZh3ef45qpwaG8vV9w7l3UhzyEoHfolD7bSWvBNoTEV0Ji7LEcL3c73yxN3vC4jND1vaifW1GfR/33eFh4KJKRUUYwEy/vVpslzM4x3ypbe9x0j7J9feQXp2nfaR49JGlJNzJPgFn22Gn27/bXmO02U782YHmbumR4l/c2L2T+5mY3byXuBUtlDRedZamNbOHCuPG6uS9T888EVPs1eozPaYUHN4JAXCvAd3cVH09xctjK3RH0WTi6TsKTnhszo5lu+lvt8PEm22ciP9rBssvGDC/cmkmweUMqBocfG7dk8cs4Hx72ivXSVB+Hr7WTyGc4ynoJnG7YGXvg9ZtHXv9uyct4IPkDfSvfofrD3aDHA6yc18AoksWo0WPUb2UqCNdsLaLWV4N9hzly/TR+EPC7HwTcUXyb7Td/TqbvUVyeC9RmzdrI96Gbb10C0IUNb3dX4yK0u2mou8YWQ6/x55KVGxpmf8JoUhjdHE9484/bfEw280YsCIbe5GmdUDgIa2z6mqUPL1kffMY/SPqSnMaI8BB/QWPqN57gH7JxK3mM4jcJSvf1X/5fQXWdfpVnj8nhXMTQ1bvTFu36e1XE3lJ4X+Xp+Zh1Tuk+ON6h8pxWN9mjcAnklqmtiXaEpavjHdkvAvn6IV4V3T9nux/Ar9/E2oMlosvnhstg8X/95ab8SLZR//nLA+57lzuQ/FzsEPjm21q8hpdaPHoYcHhMpXrbMNacL0V5TVUFqo6e5si7yO9VGF1/c9cVqDp+xUmaGB2EFjAisdPNqPhADY/7qvA1ojcML/Ncdp1iNI7jPgr8HOL6e73YfY1Oab6lLCDt6t3pJc2j0pdqvuW2h1XoTUneOu7G8GhOqf5nWM66ZQ/pADd+dW501erynNzkptWBr0FUAvuwBFV1eijirDwmJMjieKtCHEe5juGvqjl0sH2GYO5vYnQF5WJewt4oJrCr6D6ufmrAJl/Re+oRuuMdvpUXgOVc8/NgZe6Dlfpfrea+wWzuk289Ghf51wRbJaTX/03ZjlAtRMdc6Ho4MppvFw/iBuPF1+oY/1kPpb6OdzpsNAdH3s55PJ/KfHh8LNEopzJytz+GwWVc7Z7uk3+Omslv8UdIImMtwt+hDqJK4o7bLQHcfHXxqvcCsxt7z5uiODtbrJ/N33yhol2uNXE76SCjLhMuzy8SZ2CwHt0uUEc/a4MNW+7kRBZeoiP0OtmJw1UPcqRaZ9LGQ3TzPO6q/rbcsryyjIw7vWnQqb+BFi0nO57ByFR+gyqW3dzXDBOKqwFRlyLMoW87Fqa92jbl1KtMW26fy9iepMW3k2CoGaInXyclmfy6MBUuXdnxMP5A27ac+pJpzM6SVNVxXyUtvyWchqohe/PW/ZG7bWe2Ta21L2nxrU9o25oherLl3v7vIXa6nJT3jYocN+a2VprWlFIBOvmdZGgqh5wzx66FbSfO0WvgBcyey1/z3uZp+imv40vOmqnAJF/5yI8MK3qRld9cwrPRdUN0Qu003GW/3qr9W/0ekkqMlOroRdQwNMkIaBR2AXfCTYX4LJ6GPt9NzRDguEzzw48CDl99WdvsNi8dnk4PNQOuju7Q1wR9e4vS0+M5zRw3oqvoWEZh58VNV32UKH/FZWvxEAeHtKBb78254qv6mzuafvI23NTu+sPNjpO3QIPM/0blA7Zi6oHVH7klJxnWL8oy3yWkZ7trFBLuvHH2ukMl8UuLuhxHHPivs/0v9fJ1SILUSXSP0se/DT++P6dVckqTHRbhH7++/JX/ZD5kTX7UXy7IvVd9mlHu4r1oDqzGXioDIDkrD0jAyvYvQpP4M0ZF81j/Ks/KqoixucVvPsl2ySlOeXtwhIbDQ61pz5IveY1OKKuv5FV6m7RLZ64S2++b4XpAZ49XLyhQGWAt+SeJYElkWxHQaLFFlLGl24AYo9Mq8CXcctF77jK6Bz4Vqpv52kwvi4WTQE95h6mSjyUMAkjBJBMA0/xOV9K+2SXuAsD6EBcHxG8SB2BIgaDq+B8QpNYAmRugmpPSqcCZp+k6JudaUhZk5IfVT8FEjXXMuv2BaiQKbdtTAVHSyChI0P0cZo407UUPaGkVMZoFMflseOG8U/AWBm9ldhVqnXQS/UqN5cD0KF80CbpgXyO5WD1FEMxxJpgAfQa+VpKGTZyrFoJJ3YIM6HVJP/8QKLRBwWzwk3vpTYW7Kq4Q8djOdiiCvRQXhTFaXhZbbMnqMcWoY4Gl2aDUueh5BNG//e1vL4WeGzh1jpc0p/63tQMA9CpdeNcrQDv+G14cGOw/0QkhwQg3GzB616f+KYhuad3VAM+UJppkeMduSJTA40yn8ASoUrqxS5pUu9/NhCzNAtligNgsrmz6eAZYyZ83TI2qyySt32rCTzucMKWZvqzGvfWiwagt1vjzo4EEBsqqCFZioZNXKzQoSl+2mcmr08hm8poNV51b4DouODppGRmGH1d/0dGrYtLW/Jcd7ZOYhCTNjtr/y+882nLm0qH7bZqbD0ZgVhCuKMwNCGShMEji9DFpsaVdDJzAJ3NCZ0K9+KPACbLQcuA0+NTOs2LqXnZ6HJd0C+fuzS6z0Ol/XPuYAj9JlnX/zKNJ/x714oRNXuc9acU3uFPt6jL9OPw4yeAivAOHZAmMrV7lCcClfvcuaVP9Nnp2mOmuSW2Giw3DzKrL54CZIj7CbDBrp9dVjWXQkk0o28xIZrM8W+JA1iNMM4zNvxCfH18TLsVd4KWMOzEpurp/3KH/PScFqh/Hyo+0lzR2UQKD4jDlmxnDaK1sxrG5DxEi3PPJV1Q8P9Qh0aV9SxMxncoUWO0BLUZDX7iQqhoGG1bzGiXb3Ji4PGf7FNXxDC6qqkg+nyvUBC+NhhLdJEdRAh1Ml055AiXVTC2kQBxyapTZOChG5bqayDDUXg50W6yu5nDU9YNZ37rMDedMdy4IZl4Bpp0tf6JE3ehC8NGfg0iCUy7raIsTGkLWhg62eI1szrUWg6vVTGszgmr6wcru3mfmoarOS/8Yk7unYsKrP7pZhh1bsPYrQEYbIzgsw6mAQYVcibEdGnbQkYoElgeBmnX/+xmBrJulKywKe6uZ4RYAtulnOvvhbRkL8/sT2iWPyY4U9Ucd6wEbLD8kl4xyIwCUqLcGKMKifzjVf0YmetHP8vR4MANCqKe/Cl0NpOwIwzwFdIfQ2HfCKmVN2ocZLHRwNdc2NHB+yLF5NNhmH7BVGsyNeSr7gj5W4FJWEYPMoC82VbqR1QKlksUKYcZIagC4zJyLJH0KdOaPADHTDp8TZXDSmmmB9ikukjir+rH1Kj9+TjJCOLuDiEI2CFpK8i25lagUNZFiSR4nKvytZm++eKBOP++OxejcW3UDeP55jknQ/I9ZIscoQ0RjgS3Y5PAoN9CioUeLvTT8rXdMNIHkZke/NQ95HeT0R5ICIdDlUx9DLhaNkx47eoDlYs4aeSU+xem5B6lawzC4mBa5RF0TMVvCkBh2wlMYKDfaWuCZZzA3rGdfTk74HGOmheHqVn/RfXw8peh1/i1L85jPz0qdwXQEzPlL/+PC0QCrNz8SWOPPhoWHBBVYvzreszwLM+VW7JLphWAiyCzWS8/IQv26iTQugz4mjdHSLQBWy99SzgOiCbeNdviZe6PY5TxeR0C8TlpGhuHH1QfE61UxaWv2gHh9yFarXHuLitSpm2AnTFM2SUgrSC2baW7+iLDrzZW3RNBNtagaDby6wnzgu/5eoSKL04tz9VRzbJyYuOSNix7xVBowcqkJVz8CKtWzAeRsWHyTF+cjiWHsG3jyg4S+TYYT9evqcTHosh4QPOSnZDc1CkijIgzan7eBg0aZ9QAhIv/9vcjPJykKKBKh89qfJ5mISIOiCIGgIzNMQPAYNTTItYQhBJDbvsdC4mWGQce8L6cdcQj5AhYfMrHHdF1ICE2+erHs10nXL0Ss2UD0odgHyfOjWruQNhkm7S9rT+/TqGHSEGvwmXt/FZvmaUEz5TLXHDWzr3C7GJsfy/iA3iZYmuI5goODLjSWKi05KA9LsJloqoxaJu3OHk4VxBrwrdiPET8AxMzHlLnwRSScd+Ijd61LRlQvpShBwEvWybAzKLImwCzfrWMe2Ezo1mEHnLndOn5PHquruNhHt+di9xSXaP9XUj1JdHDvRo3/YScFw2z4MdxIMlXc5V4XI0yAXTE7RJi1DqyQa5cGGmsgyUF5Jlj0WCHAE9qs1z1dxWVh7SP9KSx0NbQkqE22RnLGGdOj8y6b/sgrtPx1di2lKEHz67oxNCiy/HX2HfqG0X6bYwZlNzit4nwSEJwRByxf/dklpNUqTjIhnHmdBDXL8eXAZbJhyBUrTLfM53d4/5Sc6mRUi57JOiHZgH79j+sGUK/H8qexTlRyYgTL7dprgZEjHDiwBWECKtp0rCcQGR9L9BXmvaStxTj5vaPXTFE/r+l/5Yw+42qlOhdZnRERBfA1DrQepkTmljZMyQbWwLQ+q1j99g94ph9VrLC5vrHFCnic9edc2+ZEkKu4qKhUfyHTUmpgwkvELUn4wu2kjxR0M2lzAekiBQitYpZaAsymnKuc0DX7dCVga/l38EsA1oQ38k64mvti/uoJ7b7kZz7kmfCzfAQTKJmhTCyd5m0zqJZatJBBzTT2DANIiYZGwx1fdcZt3+5cYI0Pt/EzOXq8yZKar6cTSNXpNNswt3/jC9d9rCjoY9Qm1ROLwUd3kaHWyFc/Bzs4AJVSihb2hsQNIH5BaXNhwtedDZ81DL7inniXHyLq33VHyk8aODrmxIEvmwSQVKsyaUKdW6hsFgZ3tFImzXEiLgJqq9h5zoeqKfebtnCafavpHz/hYkDy0NkGZFYDFfLM9/78udwVSZNqcuLwH3Tb4nNqtnT1sBB1WgVIsH5f4wq9R2XtwBm9KfLjdChhG+dOw9ii1eODU8ikRbozlgKQh/wnPBYCj6Er5lvVPj4mKf4FRROFZugbZBkNv679fnZQxWh3M7Pfx8Uu5QIb1lpoRwZCNHOEzV50bneTThK+UDRTIDj1+tisRuq6812mVXlRBydPjnHxfP199xRnB3SHv4irc4Gb2D0r4NUSsNDqfjQfZYgI7I1Y80sgTEB6hcFDo4dJQ4oOWAY0yB8/MTEDJhjLzwaGy3j35SbDsuy+BN3kBpl9JMIzIklpVr/YlWm2ih2zDHfL9/lYHugm9AAZg7m5HUH+PKMz2l8f4yS9qKp490Qu298kiqW2fWqoIJADJecSmIEUq884BetldOyTzLj6psSOGuF36uBpDBETHJ4pmGSAo4SXYSwQsuSmCo4uo+Zo+ZaALWoYk6oyrmN/iAHNFgazjWlUzdngd3M85UWFZXvEA2x0v3tC+3OKHuLyi/zhI03E7P2YAvNdJCMDw5ErCfOOUapzGLywOpk02EqYZIdaxhlzuMwPFUYGLu3K9qDC6rQ6qOCG0rzxgQV1GN+vwXL9sOIDAtGFYRZP1n3vBWyUXoabwMc5V+a3eZp+yiuM9/bKpe6ogSm5uu8Pv/DvVQ3Ghzzi62nPxdq6cLqxrsziFpdvnzkAEQoNXuGNOt/qNJgAZmrLW7U5B77qHy6y8pviKJUi4Xu1+3mSUWwUxnydZUnMtSBsDSLOmkP2Kj+SmdJwAKOqTD120U3zaWT73zc0YklNbdXcxDCCE+G6ZgIOmI3YEkmexiWrPMET46eTbb7LnDQ/WA5HVJWphyO6aebShv59Q8OR1NRWzU0Mo/rfYnIlrheFDFPDj9NcBdojydNwBJtnGfjpZJvR2ZZcNN6hrwn69halp8dzmtWRV0z3epL6k+/5ZHIAl98A0YaGMLMesWp7ThwyBTpXh5ZK2uezIcqv9wJkjAWCiam8DGQ5DWuzjmXmYN7OqLWioWoFTliOcFqfw5U9hqZ1s7rGdarn+qPCNVDRuRfme/QmKcrqdVzFn+NSvMepa92jqn+EQ3LTNj9Tndn+Xl9SHeN//Lr/nOO+jj+nQxVhwOEYx9+v4godSNgIkT1dCjZCE2iawv+qDxKBZvoSqIm+UMP+Xb6L0+SfaN/1ONAQQAM1CZDpGo+zw5k8ERPb7IvApvpSE/XQfVWQs9gyPxc7sDWQTKqkQKmR4hYVx6QsMca7Q25BApEEal2k0rTMvt0RWmWLoRZZCp2eeZpCupGfQX1IiQHX7sIC5N0Vylroyg1t1S9DpObqKVQW64kMm1W0p25I20L/lE9ooC+B+PeFOgVqvzVwIOxLQPG7Qt0A2MY5fY+qpxz6dHgCcDjkaHRtVnh4xsPYVzydQt8NVw62yJJoGhxOmIS2hiKomaFU9xV1CynxE+pKwO+nK9SwHzLyCvyHIqiBoVQHM/mEq55tjafa22RXnQuov/sS0ERdoVkPKFrhCBT9EbVE0fuY4Nq4f+pI00mBjvAAB1Kpeo0h1ImA0uQrKp4fkiOkPVsMNspQmFmbjiEsMzhNo7A5TWbbeB8O8E2SVvBEpq1iJJpQy0xSxcclUKhg2VEZ47Kt+D7Ozo8xgbTCOCyVSg6a0lgWjRD61lkKM83vT2iXPCY7sgWion3KbCCjV1kDrmNsF7j6h/btkTg5KsnBuVJZw0k6Y7lsJDLt04cY2q/RhYreIuVm7XyKiyTOhlijV/nxc5LFkn4xqaSQS1lPI++f55j88jFLoGmHLYZkYCncrGNuEs3U2/zf/jviK8oFMpPEGpe8nm3gXlOztOQWGGlr6BYG/cs3cVHQF4ELgr5Ud16ToOK2SMC1PFUGntUMxZpGBqcVoY2hCGqiLtVyv/6Op/MsTi/O1VN9otYMTdLzBDU5JIW6hkY6EmBLsoGhyqB2SXEZGW1iCK3sVI8uVDRkdsJHiGWNKPm3FCb8fy/y80nWSFuoaKml0LTUxm8WGml/h/i3RYZbCjZjrnRPwZKpNhUspUYKOG+vIAVMBkkBUxpKoWhZ3ZpZN0qGF6pM2p1G+xYqay3cSFMmbaQp1jQCZqcUmgOpoIZBQoMzJckWeCiSnSMZbXbZxHfSVuSdxlJoTcpkxQKMyZTDZmRItOrxSSgAFXkSWE2eSncMJCZGEM+DRBrwYEgks21ctoKSERqJYbZqkoYxB3pfQgnjQEJsKY6BHGYC6I+36aDH4hE3XQoec9ME5k01McRVzTUUmiYbIu0tFqSZVCMTTYAor/AyhKVRrEZYQu2GhA0RCWxBWALVypEj1fXhEI9Q7L2hDOy3oVg3PjLvSsWxkSkGx0WGQgvLVLoRoMpgKKaGS/yPhbwRqgxqhCrWraNQhvBmSzW4iyTgukqg0m0RMQ9E9q+fwatSrhzcKrIk2jumHLwFaH+H75Ryg3uGIYCaOC31RfCFYldqInp/6gFr0BdLFTE9NpFGPRIallKCN2cyYotT4gd0PKXwUAKT6U6NB0rD2zCFBCKJ6nbMuOXumFLesEChOu00bfYO1WR7+TUmTwCvLVganZGLvCwx81TeqkgCGlmg0hm5WftI77y5ctDALIn2hBYMjAIc1YJ08JktSGouiLp5baP6IzUmCJJ4hMYUg0dmDIX2iz2e4uQAjVtDEfyFdqW6kalZAakGJZ4CHI94IoNzz3eoqlChGZ5lhLIzUYhWa4K4xOPoXyg5PEF9ypXD6jMkZg2+TjC4S1htkUTRLEWlaZmLSSM0y5VDbXIkuln/OdspJn26FJzzaQLtYTcf2wI44OZJ4ENtnsqoZblVuXJ5m6ZW5V36NB57anITn8GoJjW/+2Ucp+SuXhI6vS/WHSrxEp34bBu4mrXayj3aBAqV51xLhPQNd0fTCj8JkUR1xh1dnE5pgvYPeUufWEghX44IFGYytOR6CToXJYN7bsPr7migMwZl72Jp5t1q7uXKRMo3v9cVYliINhFIZM6qLJXB1Nu/CAXn275UNsn2BAYeivKmmFKZn6JpU/KXYjKsAaQKyAHUNhLpxDBoW2iQegahdl6PBtd3qo7CjX2owL/aoHKBcX74WAS5jz1bU+Ff33Ax8Zd/wapvahr6rYHeLjB1MKNAbyoGiyifSdibQ5jj6XGsjO5bs4uWMasoV1X2soFoqnutoOQEje0gV+ULBe+mfIiLA6ocTNlWlBtAqrBKwWWaEE9jyu+RJQjxCdIvURqVoZcmbqo1z0mihiOsHE0yUkihBvsUpq8neeRiryK7PI+69TlqF/WJcjwxryxXEn7wQRRVP+NQcOE2LgAz2XOUIAaUjyLmlRUjCaCsRL2lmIx+LBP1fAHzgIQBTAE9AGpMoHzXY696uwdVKc2T+FeX20+TerLnX+4qcqaTK8oSeu+lCVXvN5b9UYNi8JQT61cN4IpBqbjkLIVhENQQ8kFQTuylH5dghsskraMj95wVRuBIw5nACEMjlO6Chgys5VoLtCE/Ae7FL8NA9ozX3gzdU03l0lgkCrE85p+bkprSp6QOy2TmJWPUv2gEVsswpWIJzD6fbNa/8AtMth74+rKpzhV5V787jNWrD0cAEdWA5F+M+v0jQEW/CzT+e5w/q28+a9ljYHs1VUf5ilnepJpcKf6dNVFK9oYarAmaRSwMax753G9SzVOfL8w83SWMFXb4SiGRA409QllIw9ighq/kf0idySzA03tw/aiuEBInQIwBhokqaIDzZBux0QGkUy1Lp1AGiFbQaKGIQuCKK3e1pS//IzpcgdQaRtW1KopBFmhl5XET1LwkMRNg1rq4Bx4M3JpEv5qTVgm2rHPtAC9msTLIBk3RL2WH1YHUEiJtiLWMJKgHbQiPKxleNT0eBNJgaJjIBEy4EcWuB6Tzv/OBApmQysoAJc49zwVboZuQQkBex7NaECqkjMDyIGbSfyQgebAPZR6TSALT6I2jqRjMTOpgMzQ3wwgyDndlimA5kkg/4E2aAxvFTYzeLmYGMeDKBh5S8JYEEPKNVnXjthBWcpvYVAv9AkTPUaWLk5w63DGr4B/LnLRSpUGMoXBSklNrlZJoA6ixDJMoAlaZHhYYs5jgHMEg2BdtUZtwXUFMrJ/ETWoH+0TXZk42ApqTTRkWcgNBwdqIKVRB2NZqYgeYTo9NE2uFN5FyOWlcV6u8UmuzdeMizUiiukTSZo1NquYziVFM+DKRcVTM4Wg37gshw4Fy8tEw7D1AdB8fTykaIiLKFecoFUsXLi5js2yRxFycUOU+JGPEOq6LKkso9R5B7k74QqhJUl0eRXKM+oq5SyTyP1uFV7WLm6l0mRKJ5CK7u0zx0T1JzeFHf56Bpk931BX0EB/hLqf7SDy/J5FoauA/OvkTnLlMpAreqvS3NKsYAk0mAW0JN6vAtPam68PTKu0EUIUwihBHl1SlfvWjLomBq9eXIwumMBPRd9AYjtTrqHJEB9WV6EvTaERmQvcOIoMhecXaYkW/PduyVHZrQzNa0Hl6k3yJNFvVF0vReRR94u+WxNc1eDYA0skFd30zwESVJrXgoNGuiqrGJo4ixLAUTj0oyHU0uNfJ/fjgCord22g/PiikNsNFGSLbk2lauxvapaEe3a+LMEcftltuA57Er+JCyPGhnqdNzyC/YisrEvnfyoZXtQv0Ht3i/dlTXKL9X0n1RLUgKq6r4k0dpi4fyp5UlYapdzcE890O/OVmgCt4UgSsKf3ijXIEeDLNR7rfje3D1vI7Lsxlnj7FgGZApEgCDIh0eoShHpj5wF5FIJmBcimkpA+xMFIkbyBMTLIx+DGL9rvQV/KLjnlM0+WJkH8THIVfpflMGvddmAhPrzvoNBjRwFeuJUvoSXCwpjC/KlN2uG6EupAb2i0fT7imPR+TfEQz4IGUYYY6IKlK+yWrcqWMOOA26Gwprf/+Dh0XgM/9onmypCLX7gi8PFGSZb1pv35NJhsPBlJ9GXLiEB/H7KZQbBiltP73jVObAc4VFAGZjICRw7SuAi+y5EsNcHT5lNS8RI8Rw8xILvMNm2MousmSKolTxVpSVcH3OhLOpNROPZrsSOON0a2Vxab0dpHWDaSukhO8CDdLb+UQ5WpI6hQJCZ5Ey6nIFVM5nICqmdLVWaVkfGQ8PJtENXWBdCFmrWnU1qkbXE1ePT9qCenA9BfIMHWwe2Qo/8RwEadMJOHieEenHYveFPlRZQ8VeQiDwBnW2oWNMmHaaFM85BaGoIjXboY+PVyk2L+JRP43bkKKu6amNHudy8ieAlGO4bEdpNT3tbsTlpAOrx3jZUnoXOKV5iRaV3KMi+fr77unODugO2zaIYUasC3RVlIZhc3p1hoEztfG7lDoNHPNtgTMIjfSCOQPY+1Z6nWpLckbp5wMtXVCDH2avHmEkWkSPH9mUuzbdVX8b9/nNRGYIC16k8ADqYJa4bvg7MKvTAh33zyAMMnvNsosEZthTWkUllauGJT1jeijyuYmM43MIMHQwbRhChK6kle1FoIYJo9ZxKbOFW2koFbMJ0BC32ZaUSTqZTiA+doIC3UaNhdncBtzKKhDmgNMtNZ8h8r8aa7mGHLART1rmTEAWu+KADzEfHcUG0UOO7c0FnSiqag+MLrKs7Iq4qSeVfDutF+cdKGYH/JITFAF7O988daviRziNrPLBknirmb9oEvG5cHsdOIOA0tS5GqlrHKEzGoSKgWZKVCYrGWi1UZyDI86IGnbffeYTJYibZxhh2dqanP1dGrhjZ/BzaA2lWfOtPeZ1HTArmQcx/B4AjLzNRsXRcq9cYYdIsWrzdXTqYU3jkQ/g9rtLlJIGWg8q0nqKx5o+29rgplUqqa4I9enX/TYTUyBldHZmoaqy/Vdj/mc4KY1rRvXiZFr3n2jjayPO8MR+j/98q/6qxcNk9rwuJdR0Ze9etEkRW1/wH9WeREf0Pt8j9KS/Prqxd0Z1z6i5q/XqEwOA4tXmGeGSJ7ogWlHc5M91gHfSTpNTqKOpCvu87ZX8T6u4ouiSuq4lrh4h78lku6XeJnU50Gf0f4m+3CuTucKq4yOn1Pm0PnVC3X7r14IMr9qAu2VPlTAYiZYBfQhuzwn6b6X+02cltx2U8biClv/d4R/b/oSf5oVOjz3nP7IM0NGrfnwJhVle/zJPaDjKcXMyg/ZffwVucj2sUTv0CHePd/WabyI04yMib4jWLO/ep3EhyI+li2PoT7+E2N4f/z+X/8P3XNok3u1CAA= + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.Designer.cs new file mode 100644 index 0000000000..e3a2d0014f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class ExportRevision : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ExportRevision)); + + string IMigrationMetadata.Id + { + get { return "201605201911421_ExportRevision"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.cs b/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.cs new file mode 100644 index 0000000000..d168932260 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.cs @@ -0,0 +1,204 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using System.Linq; + using Core.Domain; + using Core.Domain.DataExchange; + using Setup; + using Utilities; + + public partial class ExportRevision : DbMigration, ILocaleResourcesProvider, IDataSeeder + { + public override void Up() + { + AddColumn("dbo.ExportDeployment", "ResultInfo", c => c.String()); + AddColumn("dbo.ExportDeployment", "SubFolder", c => c.String(maxLength: 400)); + AlterColumn("dbo.ExportProfile", "FolderName", c => c.String(nullable: false, maxLength: 400)); + DropColumn("dbo.ExportDeployment", "CreateZip"); + } + + public override void Down() + { + AddColumn("dbo.ExportDeployment", "CreateZip", c => c.Boolean(nullable: false)); + AlterColumn("dbo.ExportProfile", "FolderName", c => c.String(nullable: false, maxLength: 100)); + DropColumn("dbo.ExportDeployment", "SubFolder"); + DropColumn("dbo.ExportDeployment", "ResultInfo"); + } + + public bool RollbackOnFailure + { + get { return false; } + } + + public void Seed(SmartObjectContext context) + { + context.MigrateLocaleResources(MigrateLocaleResources); + + // migrate folder name to folder path + var rootPath = "~/App_Data/ExportProfiles/"; + var exportProfiles = context.Set().ToList(); + + foreach (var profile in exportProfiles) + { + if (!profile.FolderName.EmptyNull().StartsWith(rootPath)) + { + profile.FolderName = rootPath + profile.FolderName; + } + } + + context.SaveChanges(); + + // migrate public file system deployment to new public deployment + if (context.ColumnExists("ExportDeployment", "IsPublic")) + { + var fileSystemDeploymentTypeId = (int)ExportDeploymentType.FileSystem; + var publicFolderDeploymentTypeId = (int)ExportDeploymentType.PublicFolder; + + context.ExecuteSqlCommand("Update [ExportDeployment] Set DeploymentTypeId = {0} Where DeploymentTypeId = {1} And IsPublic = 1", + true, null, publicFolderDeploymentTypeId, fileSystemDeploymentTypeId); + + context.ColumnDelete("ExportDeployment", "IsPublic"); + } + + var oldFileManagerPath = CommonHelper.MapPath("~/Content/filemanager"); + FileSystemHelper.ClearDirectory(oldFileManagerPath, true); + } + + public void MigrateLocaleResources(LocaleResourcesBuilder builder) + { + builder.AddOrUpdate("Admin.DataExchange.Export.FolderName", + "Folder path", + "Ordnerpfad", + "Specifies the relative path of the folder where to export the data.", + "Legt den relativen Pfad des Ordners fest, in den die Daten exportiert werden."); + + builder.AddOrUpdate("Admin.DataExchange.Export.FileNamePattern.Validate", + "Please enter a valid pattern for file names. Example for file names: %Store.Id%-%Profile.Id%-%File.Index%-%Profile.SeoName%", + "Bitte ein gltiges Muster fr Dateinamen eingeben. Beispiel: %Store.Id%-%Profile.Id%-%File.Index%-%Profile.SeoName%"); + + builder.AddOrUpdate("Admin.DataExchange.Export.FolderName.Validate", + "Please enter a valid, relative folder path for the export data.", + "Bitte einen gltigen, relativen Ordnerpfad fr die zu exportierenden Daten eingeben."); + + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.Http", "HTTP POST", "HTTP POST"); + builder.AddOrUpdate("Enums.SmartStore.Core.Domain.DataExchange.ExportDeploymentType.PublicFolder", "Public folder", "ffentlicher Ordner"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.SubFolder", + "Name of subfolder", + "Name des Unterordners", + "Specifies the name of a subfolder where to publish the data.", + "Legt den Namen eines Unterordners fest, in den die Daten verffentlicht werden sollen."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.ZipUsageNote", + "If there are a large number of export files, it is recommended to use the option Create ZIP archive. This saves time and avoids problems, such as a full email mailbox.", + "Bei einer groen Anzahl an Exportdateien wird empfohlen die Option ZIP-Archiv erstellen zu benutzen. Das spart Zeit und vermeidet Probleme, wie z.B. ein volles E-Mail Postfach."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Cleanup", + "Clean up after successful deployment", + "Nach erfolgreicher Verffentlichung aufrumen", + "Specifies whether to delete unneeded files after all deployments succeeded.", + "Legt fest, ob nicht mehr bentigte Dateien gelscht werden sollen, nachdem alle Verffentlichungen erfolgreich waren."); + + builder.AddOrUpdate("Admin.Common.FtpStatus", + "FTP status {0} ({1}).", + "FTP-Status {0} ({1})."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.CopyFileFailed", + "At least one file could not be copied.", + "Mindestens eine Datei konnte nicht kopiert werden."); + + builder.AddOrUpdate("Admin.Common.LastRun", "Last run", "Letzte Ausfhrung"); + builder.AddOrUpdate("Admin.Common.SuccessfulOn", "Successful on", "Erfolgreich am"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.Name", + "Name of profile", + "Name des Profils", + "Specifies the name of the publishing profile.", + "Legt den Namen des Verffentlichungsprofils fest."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.ProfilesTitle", + "Publishing profiles", + "Verffentlichungsprofile"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.NoProfiles", + "There are no publishing profiles.", + "Es liegen keine Verffentlichungsprofile vor."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.Note", + "Click New profile to add one or multiple publishing profiles to specify how to further proceed with the export files.", + "Legen Sie ber Neues Profil ein oder mehrere Verffentlichungsprofile an, um festzulegen wie mit den Exportdateien weiter zu verfahren ist."); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.PublishingTarget", + "Publishing target", + "Verffentlichungsziel"); + + builder.AddOrUpdate("Admin.DataExchange.Export.Deployment.DeploymentType", + "Publishing type", + "Art der Verffentlichung", + "Specifies the type of publishing.", + "Legt die Art Verffentlichung fest."); + + builder.AddOrUpdate("Common.Publishing", + "Publishing", + "Verffentlichung"); + + builder.AddOrUpdate("Common.NoFilesAvailable", + "There are no files available.", + "Es sind keine Dateien vorhanden."); + + builder.AddOrUpdate("Common.CopyToClipboard", "Copy to clipboard", "In die Zwischenablage kopieren"); + builder.AddOrUpdate("Common.CopyToClipboard.Succeeded", "Copied!", "Kopiert!"); + builder.AddOrUpdate("Common.CopyToClipboard.Failded", "Failed to copy.", "Kopieren ist fehlgeschlagen."); + + builder.AddOrUpdate("Products.NoBundledItems", + "No bundle items available", + "Keine Bundle-Bestandteile vorhanden"); + + builder.AddOrUpdate("Common.NoFileUploaded", + "There was no file uploaded.", + "Es wurde keine Datei hochgeladen."); + + builder.AddOrUpdate("Products.BasePriceInfo", + "Content: {0} {1} ({2} / {3} {1})", + "Inhalt: {0} {1} ({2} / {3} {1})"); + + builder.AddOrUpdate("Products.BasePriceInfo.LanguageInsensitive", + "{0} {1} ({2} / {3} {1})", + "{0} {1} ({2} / {3} {1})"); + + builder.AddOrUpdate("PrivateMessages.Disabled", + "Private messages are disabled.", + "Private Nachrichten sind deaktiviert."); + + builder.AddOrUpdate("Common.MethodNotSupportedForGuests", + "This function is not available for guests.", + "Diese Funktion steht fr Gste nicht zur Verfgung."); + + builder.AddOrUpdate("ContactUs.PrivacyAgreement", + "Privacy consent", + "Einwilligungserklrung Datenschutz"); + + builder.AddOrUpdate("ContactUs.PrivacyAgreement.MustBeAccepted", + "Please agree to the storage of your data.", + "Bitte stimmen Sie der Speicherung Ihrer Daten zu."); + + builder.AddOrUpdate("ContactUs.PrivacyAgreement.DetailText", + "Yes I've read the privacy terms and agree that my data given by me can be stored electronically. My data will thereby only be used to process my inquiry.", + "Ja, ich habe die Datenschutzerklrung zur Kenntnis genommen und bin damit einverstanden, dass die von mir angegebenen Daten elektronisch erhoben und gespeichert werden. Meine Daten werden dabei nur zur Bearbeitung meiner Anfrage genutzt."); + + builder.AddOrUpdate("Admin.Configuration.Settings.CustomerUser.DisplayPrivacyAgreementOnContactUs", + "Get privacy consent for contact requests", + "Einwilligungserklrung im Kontaktformular fordern", + "Specifies whether a checkbox will be displayed on the contact page which requests the user to agree on storage of his data.", + "Bestimmt ob im Kontaktformular eine Checkbox angezeigt wird, die den Benutzer auffordert der Speicherung seiner Daten zuzustimmen."); + + + builder.Delete( + "Admin.DataExchange.Export.FolderAndFileName.Validate", + "Admin.DataExchange.Export.Deployment.IsPublic", + "Admin.DataExchange.Export.Deployment.CreateZip", + "Admin.Common.TemporaryFiles", + "Admin.Common.NoTempFilesFound"); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.resx b/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.resx new file mode 100644 index 0000000000..a653f94065 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201605201911421_ExportRevision.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.Designer.cs b/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.Designer.cs new file mode 100644 index 0000000000..16b788408f --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class FixExportDeploymentIsPublic : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(FixExportDeploymentIsPublic)); + + string IMigrationMetadata.Id + { + get { return "201607111548571_FixExportDeploymentIsPublic"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.cs b/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.cs new file mode 100644 index 0000000000..f48207c9fc --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.cs @@ -0,0 +1,21 @@ +namespace SmartStore.Data.Migrations +{ + using System.Data.Entity.Migrations; + using System.Web.Hosting; + using Core.Data; + + public partial class FixExportDeploymentIsPublic : DbMigration + { + public override void Up() + { + if (HostingEnvironment.IsHosted && DataSettings.Current.IsSqlServer) + { + Sql("IF EXISTS(SELECT TOP 1 1 FROM sys.objects o INNER JOIN sys.columns c ON o.object_id = c.object_id WHERE o.name = 'ExportDeployment' AND c.name = 'IsPublic') ALTER TABLE [dbo].[ExportDeployment] DROP COLUMN [IsPublic];"); + } + } + + public override void Down() + { + } + } +} diff --git a/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.resx b/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.resx new file mode 100644 index 0000000000..55e598ca59 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Migrations/201607111548571_FixExportDeploymentIsPublic.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + + dbo + + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs index ea5109256d..49ae7dd7a8 100644 --- a/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs +++ b/src/Libraries/SmartStore.Data/Migrations/MigrationsConfiguration.cs @@ -10,6 +10,7 @@ public sealed class MigrationsConfiguration : DbMigrationsConfiguration - /// Object context - ///
+ /// + /// Object context + /// [DbConfigurationType(typeof(SmartDbConfiguration))] public abstract class ObjectContextBase : DbContext, IDbContext { private static bool? s_isSqlServer2012OrHigher = null; - #region Ctor /// @@ -45,6 +41,7 @@ protected ObjectContextBase(string nameOrConnectionString, string alias = null) : base(nameOrConnectionString) { this.HooksEnabled = true; + this.AutoCommitEnabled = true; this.Alias = null; this.EventPublisher = NullEventPublisher.Instance; } @@ -81,7 +78,7 @@ private void PerformPreSaveActions(out IList modifiedEntries, out if (hooksEnabled) { modifiedHookEntries = modifiedEntries - .Select(x => new HookedEntityEntry() + .Select(x => new HookedEntityEntry { Entity = x.Entity, PreSaveState = (SmartStore.Core.Data.EntityState)((int)x.State) @@ -139,12 +136,6 @@ public bool HooksEnabled #region IDbContext members - protected override void Dispose(bool disposing) - { - this.EventPublisher = null; - base.Dispose(disposing); - } - public virtual string CreateDatabaseScript() { return ((IObjectContextAdapter)this).ObjectContext.CreateDatabaseScript(); @@ -194,11 +185,14 @@ private IEnumerable ToParameters(params object[] parameters) } var result = this.Database.SqlQuery(commandText, parameters).ToList(); - using (var scope = new DbContextScope(this, autoDetectChanges: false)) + if (!ForceNoTracking) { - for (int i = 0; i < result.Count; i++) + using (var scope = new DbContextScope(this, autoDetectChanges: false)) { - result[i] = AttachEntityToContext(result[i]); + for (int i = 0; i < result.Count; i++) + { + result[i] = Attach(result[i]); + } } } return result; @@ -226,9 +220,12 @@ private IEnumerable ToParameters(params object[] parameters) // database call var reader = cmd.ExecuteReader(); var result = ((IObjectContextAdapter)(this)).ObjectContext.Translate(reader).ToList(); - for (int i = 0; i < result.Count; i++) + if (!ForceNoTracking) { - result[i] = AttachEntityToContext(result[i]); + for (int i = 0; i < result.Count; i++) + { + result[i] = Attach(result[i]); + } } // close up the reader, we're done saving results reader.Close(); @@ -335,12 +332,19 @@ public IDictionary GetModifiedProperties(BaseEntity entity) var props = new Dictionary(); var entry = this.Entry(entity); - var modifiedPropertyNames = from p in entry.CurrentValues.PropertyNames - where entry.Property(p).IsModified - select p; - foreach (var name in modifiedPropertyNames) + + // be aware of the entity state. you cannot get modified properties for detached entities. + if (entry.State != System.Data.Entity.EntityState.Detached) { - props.Add(name, entry.Property(name).OriginalValue); + var modifiedProperties = from p in entry.CurrentValues.PropertyNames + let prop = entry.Property(p) + where prop.IsModified + select prop; + + foreach (var prop in modifiedProperties) + { + props.Add(prop.Name, prop.OriginalValue); + } } return props; @@ -355,7 +359,7 @@ public override int SaveChanges() // SAVE NOW!!! bool validateOnSaveEnabled = this.Configuration.ValidateOnSaveEnabled; this.Configuration.ValidateOnSaveEnabled = false; - int result = this.Commit(); + int result = base.SaveChanges(); this.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabled; PerformPostSaveActions(modifiedEntries, modifiedHookEntries); @@ -372,7 +376,7 @@ public override Task SaveChangesAsync() // SAVE NOW!!! bool validateOnSaveEnabled = this.Configuration.ValidateOnSaveEnabled; this.Configuration.ValidateOnSaveEnabled = false; - var result = this.CommitAsync(); + var result = base.SaveChangesAsync(); result.ContinueWith((t) => { @@ -383,10 +387,10 @@ public override Task SaveChangesAsync() return result; } - // codehint: sm-add (required for UoW implementation) + // required for UoW implementation public string Alias { get; internal set; } - // codehint: sm-add (performance on bulk inserts) + // performance on bulk inserts public bool AutoDetectChangesEnabled { get @@ -399,7 +403,7 @@ public bool AutoDetectChangesEnabled } } - // codehint: sm-add (performance on bulk inserts) + // performance on bulk inserts public bool ValidateOnSaveEnabled { get @@ -412,7 +416,6 @@ public bool ValidateOnSaveEnabled } } - // codehint: sm-add public bool ProxyCreationEnabled { get @@ -425,6 +428,33 @@ public bool ProxyCreationEnabled } } + public bool LazyLoadingEnabled + { + get + { + return this.Configuration.LazyLoadingEnabled; + } + set + { + this.Configuration.LazyLoadingEnabled = value; + } + } + + public bool ForceNoTracking { get; set; } + + public bool AutoCommitEnabled { get; set; } + + public ITransaction BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified) + { + var dbContextTransaction = this.Database.BeginTransaction(isolationLevel); + return new DbContextTransactionWrapper(dbContextTransaction); + } + + public void UseTransaction(DbTransaction transaction) + { + this.Database.UseTransaction(transaction); + } + #endregion #region Utils @@ -466,79 +496,70 @@ protected internal bool IsSqlServer2012OrHigher() return s_isSqlServer2012OrHigher.Value; } - /// - /// Attach an entity to the context or return an already attached entity (if it was already attached) - /// - /// TEntity - /// Entity - /// Attached entity - protected virtual TEntity AttachEntityToContext(TEntity entity) where TEntity : BaseEntity, new() + public TEntity Attach(TEntity entity) where TEntity : BaseEntity { - // little hack here until Entity Framework really supports stored procedures - // otherwise, navigation properties of loaded entities are not loaded until an entity is attached to the context - var alreadyAttached = Set().Local.Where(x => x.Id == entity.Id).FirstOrDefault(); + var dbSet = Set(); + var alreadyAttached = dbSet.Local.FirstOrDefault(x => x.Id == entity.Id); + if (alreadyAttached == null) { - // attach new entity - Set().Attach(entity); + dbSet.Attach(entity); return entity; } - else + + return alreadyAttached; + } + + public bool IsAttached(TEntity entity) where TEntity : BaseEntity + { + if (entity != null) { - // entity is already loaded. - return alreadyAttached; + return Set().Local.Any(x => x.Id == entity.Id); } - } - public bool IsAttached(TEntity entity) where TEntity : BaseEntity, new() - { - Guard.ArgumentNotNull(() => entity); - return Set().Local.Where(x => x.Id == entity.Id).FirstOrDefault() != null; + return false; } - public void DetachEntity(TEntity entity) where TEntity : BaseEntity, new() + public void DetachEntity(TEntity entity) where TEntity : BaseEntity { - Guard.ArgumentNotNull(() => entity); - if (this.IsAttached(entity)) - { - ((IObjectContextAdapter)this).ObjectContext.Detach(entity); - } + this.Entry(entity).State = System.Data.Entity.EntityState.Detached; } - public void Detach(object entity) + public int DetachEntities(bool unchangedEntitiesOnly = true) where TEntity : class { - ((IObjectContextAdapter)this).ObjectContext.Detach(entity); - } + Func predicate = x => + { + if (x.Entity is TEntity) + { + if (x.State == System.Data.Entity.EntityState.Detached) + return false; - public int DetachAll() - { - var attachedEntities = this.ChangeTracker.Entries() - .Where(x => x.State != System.Data.Entity.EntityState.Detached) - .ToList(); - attachedEntities.Each(x => this.Entry(x.Entity).State = System.Data.Entity.EntityState.Detached); + if (unchangedEntitiesOnly) + return x.State == System.Data.Entity.EntityState.Unchanged; + + return true; + } + + return false; + }; + + var attachedEntities = this.ChangeTracker.Entries().Where(predicate).ToList(); + attachedEntities.Each(entry => entry.State = System.Data.Entity.EntityState.Detached); return attachedEntities.Count; } - public void ChangeState(TEntity entity, System.Data.Entity.EntityState newState) + public void ChangeState(TEntity entity, System.Data.Entity.EntityState newState) where TEntity : BaseEntity { - ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.ChangeObjectState(entity, newState); + Console.WriteLine("ChangeState ORIGINAL"); + this.Entry(entity).State = newState; } - public bool SetToUnchanged(TEntity entity) + public void ReloadEntity(TEntity entity) where TEntity : BaseEntity { - try - { - ChangeState(entity, System.Data.Entity.EntityState.Unchanged); - return true; - } - catch (Exception exc) - { - exc.Dump(); - return false; - } + this.Entry(entity).Reload(); } - private string FormatValidationExceptionMessage(IEnumerable results) + private string FormatValidationExceptionMessage(IEnumerable results) { var sb = new StringBuilder(); sb.Append("Entity validation failed" + Environment.NewLine); @@ -569,9 +590,10 @@ private void IgnoreMergedData(IList entries, bool ignore) foreach (var entry in entries) { var entityWithPossibleMergedData = entry.Entity as IMergedData; - if (entityWithPossibleMergedData != null) + { entityWithPossibleMergedData.MergedDataIgnore = ignore; + } } } catch { } @@ -579,68 +601,35 @@ private void IgnoreMergedData(IList entries, bool ignore) #endregion - #region EF helpers + #region Nested classes - private int Commit() + private class DbContextTransactionWrapper : ITransaction { - int result = 0; - bool commitFailed = false; - do - { - commitFailed = false; + private readonly DbContextTransaction _tx; - try - { - result = base.SaveChanges(); - } - catch (DbUpdateConcurrencyException ex) - { - commitFailed = true; + public DbContextTransactionWrapper(DbContextTransaction tx) + { + Guard.ArgumentNotNull(() => tx); - foreach (var entry in ex.Entries) - { - entry.Reload(); - } - } + _tx = tx; } - while (commitFailed); - - return result; - } - - private Task CommitAsync() - { - var tcs = new TaskCompletionSource(); - - base.SaveChangesAsync().ContinueWith((t) => + + public void Commit() { - if (!t.IsFaulted) - { - //if (t.IsCanceled) - //{ - // tcs.TrySetCanceled(); - // return; - //} - tcs.TrySetResult(t.Result); - return; - } + _tx.Commit(); + } - var ex = t.Exception.InnerException; - if (ex != null && ex is DbUpdateConcurrencyException) - { - // try again - tcs.TrySetResult(this.CommitAsync().Result); - } - else - { - tcs.TrySetException(ex); - } - }); + public void Rollback() + { + _tx.Rollback(); + } - return tcs.Task; + public void Dispose() + { + _tx.Dispose(); + } } #endregion - - } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Data/Setup/Builder/ActivityLogTypeMigrator.cs b/src/Libraries/SmartStore.Data/Setup/Builder/ActivityLogTypeMigrator.cs new file mode 100644 index 0000000000..b397af928a --- /dev/null +++ b/src/Libraries/SmartStore.Data/Setup/Builder/ActivityLogTypeMigrator.cs @@ -0,0 +1,68 @@ +using System.Data.Entity; +using System.Linq; +using SmartStore.Core.Domain.Configuration; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Logging; + +namespace SmartStore.Data.Setup +{ + internal class ActivityLogTypeMigrator + { + private readonly SmartObjectContext _ctx; + private readonly DbSet _activityLogTypeRecords; + + public ActivityLogTypeMigrator(SmartObjectContext ctx) + { + Guard.ArgumentNotNull(() => ctx); + + _ctx = ctx; + _activityLogTypeRecords = _ctx.Set(); + } + + private Language GetDefaultAdminLanguage(DbSet settingRecords, DbSet languageRecords) + { + const string settingKey = "LocalizationSettings.DefaultAdminLanguageId"; + + var defaultAdminLanguageSetting = settingRecords.FirstOrDefault(x => x.Name == settingKey && x.StoreId == 0); + + if (defaultAdminLanguageSetting == null) + defaultAdminLanguageSetting = settingRecords.FirstOrDefault(x => x.Name == settingKey); + + if (defaultAdminLanguageSetting != null) + { + var defaultAdminLanguageId = defaultAdminLanguageSetting.Value.ToInt(); + if (defaultAdminLanguageId != 0) + { + var language = languageRecords.FirstOrDefault(x => x.Id == defaultAdminLanguageId); + if (language != null) + return language; + } + } + + return languageRecords.First(); + } + + public void AddActivityLogType(string systemKeyword, string enName, string deName) + { + Guard.ArgumentNotEmpty(() => systemKeyword); + Guard.ArgumentNotEmpty(() => enName); + Guard.ArgumentNotEmpty(() => deName); + + var record = _activityLogTypeRecords.FirstOrDefault(x => x.SystemKeyword == systemKeyword); + + if (record == null) + { + var language = GetDefaultAdminLanguage(_ctx.Set(), _ctx.Set()); + + _activityLogTypeRecords.Add(new ActivityLogType + { + Enabled = true, + SystemKeyword = systemKeyword, + Name = (language.UniqueSeoCode.IsCaseInsensitiveEqual("de") ? deName : enName) + }); + + _ctx.SaveChanges(); + } + } + } +} diff --git a/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesBuilder.cs b/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesBuilder.cs index 5b67d5472b..20a2a5b8ad 100644 --- a/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesBuilder.cs +++ b/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesBuilder.cs @@ -12,6 +12,7 @@ internal class LocaleResourceEntry public string Value { get; set; } public string Lang { get; set; } + public bool UpdateOnly { get; set; } public bool Important { get; set; } } @@ -49,6 +50,29 @@ public void DeleteFor(string lang, params string[] keys) keys.Each(x => _entries.Add(new LocaleResourceEntry { Key = x, Lang = lang, Important = true })); } + /// + /// Updates existing locale resources + /// + /// The key of the resource + /// IResourceAddBuilder + public IResourceAddBuilder Update(string key) + { + Guard.ArgumentNotEmpty(() => key); + + Action fn = (string v, string l, bool isHint) => + { + string k = key; + if (isHint) + { + k += ".Hint"; + } + + _entries.Add(new LocaleResourceEntry { Key = k, Value = v, Lang = l, UpdateOnly = true }); + }; + + return new ResourceAddBuilder(key, fn); + } + /// /// Adds or updates locale resources /// diff --git a/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs b/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs index a1a60c4735..92d059bec8 100644 --- a/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs +++ b/src/Libraries/SmartStore.Data/Setup/Builder/LocaleResourcesMigrator.cs @@ -35,7 +35,7 @@ public void Migrate(IEnumerable entries, bool updateTouched using (var scope = new DbContextScope(_ctx, autoDetectChanges: false)) { - var langMap = _languages.ToDictionary(x => x.UniqueSeoCode.EmptyNull().ToLower()); + var langMap = _languages.ToDictionarySafe(x => x.UniqueSeoCode.EmptyNull().ToLower()); var toDelete = new List(); var toUpdate = new List(); @@ -55,7 +55,7 @@ public void Migrate(IEnumerable entries, bool updateTouched bool isLocal; var db = GetResource(entry.Key, lang.Value.Id, toAdd, out isLocal); - if (db == null && entry.Value.HasValue()) + if (db == null && entry.Value.HasValue() && !entry.UpdateOnly) { // ADD action toAdd.Add(new LocaleStringResource { LanguageId = lang.Value.Id, ResourceName = entry.Key, ResourceValue = entry.Value }); @@ -102,7 +102,7 @@ public void Migrate(IEnumerable entries, bool updateTouched toUpdate.Each(x => _ctx.Entry(x).State = System.Data.Entity.EntityState.Modified); // save now - _ctx.SaveChanges(); + int affectedRows = _ctx.SaveChanges(); } } diff --git a/src/Libraries/SmartStore.Data/Setup/Builder/PermissionMigrator.cs b/src/Libraries/SmartStore.Data/Setup/Builder/PermissionMigrator.cs new file mode 100644 index 0000000000..fe509e1cdf --- /dev/null +++ b/src/Libraries/SmartStore.Data/Setup/Builder/PermissionMigrator.cs @@ -0,0 +1,55 @@ +using System.Data.Entity; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Security; + +namespace SmartStore.Data.Setup +{ + internal class PermissionMigrator + { + private readonly SmartObjectContext _ctx; + private readonly DbSet _permissionRecords; + private readonly IQueryable _customerRoles; + + public PermissionMigrator(SmartObjectContext ctx) + { + Guard.ArgumentNotNull(() => ctx); + + _ctx = ctx; + _permissionRecords = _ctx.Set(); + _customerRoles = _ctx.Set().Expand(x => x.PermissionRecords); + } + + public void AddPermission(PermissionRecord permission, string[] rolesToMap) + { + Guard.ArgumentNotNull(() => permission); + Guard.ArgumentNotNull(() => rolesToMap); + + if (permission.SystemName.IsEmpty()) + return; + + var permissionRecord = _permissionRecords.FirstOrDefault(x => x.SystemName == permission.SystemName); + + if (permissionRecord == null) + { + _permissionRecords.Add(permission); + + _ctx.SaveChanges(); + } + + permissionRecord = _permissionRecords.FirstOrDefault(x => x.SystemName == permission.SystemName); + + foreach (var roleName in rolesToMap) + { + var role = _customerRoles.FirstOrDefault(x => x.SystemName == roleName); + if (role != null && !role.PermissionRecords.Any(x => x.SystemName == permission.SystemName)) + { + role.PermissionRecords.Add(permissionRecord); + } + } + + _ctx.SaveChanges(); + } + } +} diff --git a/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs b/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs index 70bebdd73d..44f470e318 100644 --- a/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs +++ b/src/Libraries/SmartStore.Data/Setup/IDbMigrationExtensions.cs @@ -16,7 +16,7 @@ namespace SmartStore.Data.Setup public static class IDbMigrationExtensions { - public static void SqlFile(this IDbMigration migration, string fileName, Assembly assembly = null, string location = null) + public static void SqlFileOrResource(this IDbMigration migration, string fileName, Assembly assembly = null, string location = null) { Guard.ArgumentNotEmpty(() => fileName); diff --git a/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs b/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs index 966cc527c9..b3181690c2 100644 --- a/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs +++ b/src/Libraries/SmartStore.Data/Setup/MigrateDatabaseInitializer.cs @@ -89,7 +89,7 @@ public virtual void InitializeDatabase(TContext context) // prior integrating EF Migrations. // Running the Migrator with initial DDL would crash in this case as // the db objects exist already. Therefore we set a suppression flag - // which we read in the corresposnding InitialMigration to exit early. + // which we read in the corresponding InitialMigration to exit early. DbMigrationContext.Current.SetSuppressInitialCreate(true); } } diff --git a/src/Libraries/SmartStore.Data/Setup/MigratorUtils.cs b/src/Libraries/SmartStore.Data/Setup/MigratorUtils.cs index c9c0707aef..334f4fd96b 100644 --- a/src/Libraries/SmartStore.Data/Setup/MigratorUtils.cs +++ b/src/Libraries/SmartStore.Data/Setup/MigratorUtils.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Data.Entity.Migrations; +using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using SmartStore.Data.Migrations; namespace SmartStore.Data.Setup { @@ -101,5 +103,72 @@ private static TType CreateTypeInstance(string typeName) where TType : cl return newType as TType; } + + public static void ExecutePendingResourceMigrations(string resPath, SmartObjectContext dbContext) + { + Guard.ArgumentNotNull(() => dbContext); + + string headPath = Path.Combine(resPath, "head.txt"); + if (!File.Exists(headPath)) + return; + + string resHead = File.ReadAllText(headPath).Trim(); + if (!MigratorUtils.IsValidMigrationId(resHead)) + return; + + var migrator = new DbMigrator(new MigrationsConfiguration()); + var migrations = GetPendingResourceMigrations(migrator, resHead); + + foreach (var id in migrations) + { + if (IsAutomaticMigration(id)) + continue; + + if (!IsValidMigrationId(id)) + continue; + + // Resolve and instantiate the DbMigration instance from the assembly + var migration = CreateMigrationInstanceByMigrationId(id, migrator.Configuration); + + var provider = migration as ILocaleResourcesProvider; + if (provider == null) + continue; + + var builder = new LocaleResourcesBuilder(); + provider.MigrateLocaleResources(builder); + + var resEntries = builder.Build(); + var resMigrator = new LocaleResourcesMigrator(dbContext); + resMigrator.Migrate(resEntries); + } + } + + private static IEnumerable GetPendingResourceMigrations(DbMigrator migrator, string resHead) + { + var local = migrator.GetLocalMigrations(); + var atHead = false; + + if (local.Last().IsCaseInsensitiveEqual(resHead)) + yield break; + + foreach (var id in local) + { + if (!atHead) + { + if (!id.IsCaseInsensitiveEqual(resHead)) + { + continue; + } + else + { + atHead = true; + continue; + } + } + + yield return id; + } + } + } } diff --git a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs index b7fbe105b3..c5c2745302 100644 --- a/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs +++ b/src/Libraries/SmartStore.Data/Setup/SeedData/InvariantSeedData.cs @@ -56,7 +56,7 @@ public void Initialize(SmartObjectContext context) public IList Pictures() { - var entities = new List() + var entities = new List { CreatePicture(File.ReadAllBytes(_sampleImagesPath + "company_logo.png"), "image/png", GetSeName("company-logo")), CreatePicture(File.ReadAllBytes(_sampleImagesPath + "clouds.png"), "image/png", GetSeName("slider-bg")), @@ -73,6 +73,10 @@ public IList Stores() var seName = GetSeName("company-logo"); var imgCompanyLogo = _ctx.Set().Where(x => x.SeoFilename == seName).FirstOrDefault(); + var currency = _ctx.Set().FirstOrDefault(x => x.CurrencyCode == "EUR"); + if (currency == null) + currency = _ctx.Set().First(); + var entities = new List() { new Store() @@ -82,7 +86,9 @@ public IList Stores() Hosts = "yourstore.com,www.yourstore.com", SslEnabled = false, DisplayOrder = 1, - LogoPictureId = imgCompanyLogo.Id + LogoPictureId = imgCompanyLogo.Id, + PrimaryStoreCurrencyId = currency.Id, + PrimaryExchangeRateCurrencyId = currency.Id } }; this.Alter(entities); @@ -298,7 +304,9 @@ public IList Countries() DisplayOrder = 1, Published = true, }; + #region US Regions + cUsa.StateProvinces.Add(new StateProvince() { Name = "AA (Armed Forces Americas)", @@ -733,6 +741,9 @@ public IList Countries() Published = true, DisplayOrder = 1, }); + + #endregion + var cCanada = new Country { Name = "Canada", @@ -745,7 +756,10 @@ public IList Countries() DisplayOrder = 2, Published = true, }; - cCanada.StateProvinces.Add(new StateProvince() + + #region CA Regions + + cCanada.StateProvinces.Add(new StateProvince() { Name = "Alberta", Abbreviation = "AB", @@ -877,7 +891,7 @@ public IList Countries() DisplayOrder = -1, Published = true }, - cUsa, + cUsa, cCanada, //other countries @@ -3722,20 +3736,21 @@ public IList CustomerRoles() SystemName = SystemCustomerRoleNames.Guests, }; var entities = new List - { - crAdministrators, - crForumModerators, - crRegistered, - crGuests - }; + { + crAdministrators, + crForumModerators, + crRegistered, + crGuests + }; this.Alter(entities); return entities; } public Address AdminAddress() { - string addressThreeLetterIsoCode = "USA"; - var cCountry = this.Countries().Where(x => x.ThreeLetterIsoCode == addressThreeLetterIsoCode); + var cCountry = _ctx.Set() + .Where(x => x.ThreeLetterIsoCode == "USA") + .FirstOrDefault(); var entity = new Address() { @@ -3748,10 +3763,8 @@ public Address AdminAddress() Address1 = "1234 Main Road", Address2 = "", City = "New York", - StateProvince = cCountry.FirstOrDefault().StateProvinces.FirstOrDefault(), - - //StateProvince = _stateProvinceRepository.Table.Where(sp => sp.Name == "New York").FirstOrDefault(), - Country = cCountry.FirstOrDefault(), + StateProvince = cCountry.StateProvinces.FirstOrDefault(), + Country = cCountry, ZipPostalCode = "12212", CreatedOnUtc = DateTime.UtcNow, }; @@ -3761,7 +3774,7 @@ public Address AdminAddress() public Customer SearchEngineUser() { - var entity = new Customer() + var entity = new Customer { Email = "builtin@search-engine-record.com", CustomerGuid = Guid.NewGuid(), @@ -3780,7 +3793,7 @@ public Customer SearchEngineUser() public Customer BackgroundTaskUser() { - var entity = new Customer() + var entity = new Customer { Email = "builtin@background-task-record.com", CustomerGuid = Guid.NewGuid(), @@ -3797,6 +3810,25 @@ public Customer BackgroundTaskUser() return entity; } + public Customer PdfConverterUser() + { + var entity = new Customer + { + Email = "builtin@pdf-converter-record.com", + CustomerGuid = Guid.NewGuid(), + PasswordFormat = PasswordFormat.Clear, + AdminComment = "Built-in system record used for the PDF converter.", + Active = true, + IsSystemAccount = true, + SystemName = SystemCustomerNames.PdfConverter, + CreatedOnUtc = DateTime.UtcNow, + LastActivityDateUtc = DateTime.UtcNow, + }; + + this.Alter(entity); + return entity; + } + public IList EmailAccounts() { var entities = new List() @@ -3821,7 +3853,7 @@ public IList MessageTemplates() { var eaGeneral = this.EmailAccounts().FirstOrDefault(x => x.Email != null); - string cssString = @""; + string cssString = @""; string templateHeader = cssString + "
"; string templateFooter = "
"; @@ -3951,7 +3983,7 @@ public IList MessageTemplates() { Name = "OrderCancelled.CustomerNotification", Subject = "%Store.Name%. Your order cancelled", - Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Your order has been cancelled. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Zahlart: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, + Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Your order has been cancelled. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Payment Method: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -3959,7 +3991,7 @@ public IList MessageTemplates() { Name = "OrderCompleted.CustomerNotification", Subject = "%Store.Name%. Your order completed", - Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Your order has been completed. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Zahlart: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, + Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Your order has been completed. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Payment Method: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -3967,7 +3999,7 @@ public IList MessageTemplates() { Name = "ShipmentDelivered.CustomerNotification", Subject = "Your order from %Store.Name% has been delivered.", - Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Good news! You order has been delivered.
Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Zahlart: %Order.PaymentMethod%

Delivered Products:

%Shipment.Product(s)%

" + templateFooter, + Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Good news! You order has been delivered.
Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Payment Method: %Order.PaymentMethod%

Delivered Products:

%Shipment.Product(s)%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -3976,7 +4008,7 @@ public IList MessageTemplates() { Name = "OrderPlaced.CustomerNotification", Subject = "Order receipt from %Store.Name%.", - Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Thanks for buying from %Store.Name%. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Zahlart: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, + Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%,
Thanks for buying from %Store.Name%. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Payment Method: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -3984,7 +4016,7 @@ public IList MessageTemplates() { Name = "OrderPlaced.StoreOwnerNotification", Subject = "%Store.Name%. Purchase Receipt for Order #%Order.OrderNumber%", - Body = templateHeader + "

%Store.Name%



%Order.CustomerFullName% (%Order.CustomerEmail%) has just placed an order from your store. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Zahlart: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, + Body = templateHeader + "

%Store.Name%



%Order.CustomerFullName% (%Order.CustomerEmail%) has just placed an order from your store. Below is the summary of the order.

Order Number: %Order.OrderNumber%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Payment Method: %Order.PaymentMethod%

%Order.Product(s)%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -3992,7 +4024,7 @@ public IList MessageTemplates() { Name = "ShipmentSent.CustomerNotification", Subject = "Your order from %Store.Name% has been shipped.", - Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%!,
Good news! You order has been shipped.
Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Zahlart: %Order.PaymentMethod%

Shipped Products:

%Shipment.Product(s)%

" + templateFooter, + Body = templateHeader + "

%Store.Name%



Hello %Order.CustomerFullName%!,
Good news! You order has been shipped.
Order Number: %Order.OrderNumber%
Order Details: %Order.OrderURLForCustomer%
Date Ordered: %Order.CreatedOn%



Billing Address
%Order.BillingFirstName% %Order.BillingLastName%
%Order.BillingAddress1%
%Order.BillingCity% %Order.BillingZipPostalCode%
%Order.BillingStateProvince% %Order.BillingCountry%



Shipping Address
%Order.ShippingFirstName% %Order.ShippingLastName%
%Order.ShippingAddress1%
%Order.ShippingCity% %Order.ShippingZipPostalCode%
%Order.ShippingStateProvince% %Order.ShippingCountry%

Shipping Method: %Order.ShippingMethod%
Payment Method: %Order.PaymentMethod%

Shipped Products:

%Shipment.Product(s)%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -4016,7 +4048,7 @@ public IList MessageTemplates() { Name = "ReturnRequestStatusChanged.CustomerNotification", Subject = "%Store.Name%. Return request status was changed.", - Body = templateHeader + "

%Store.Name%



Hello %Customer.FullName%,
Your return request #%ReturnRequest.ID% status has been changed.

" + templateFooter, + Body = templateHeader + "

%Store.Name%



Hello %Customer.FullName%,
Your return request #%ReturnRequest.ID% status has been changed: %ReturnRequest.Status%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -4056,7 +4088,7 @@ public IList MessageTemplates() { Name = "Product.AskQuestion", Subject = "%Store.Name% - Question concerning '%Product.Name%' from %ProductQuestion.SenderName%", - Body = templateHeader + "

%ProductQuestion.Message%

%ProductQuestion.Message%

SKU: %Product.Sku%
Email: %ProductQuestion.SenderEmail%
Name: %ProductQuestion.SenderName%
Phone: %ProductQuestion.SenderPhone%

" + templateFooter, + Body = templateHeader + "

%ProductQuestion.Message%

SKU: %Product.Sku%
Email: %ProductQuestion.SenderEmail%
Name: %ProductQuestion.SenderName%
Phone: %ProductQuestion.SenderPhone%

" + templateFooter, IsActive = true, EmailAccountId = eaGeneral.Id, }, @@ -4141,14 +4173,6 @@ public IList Topics() Title = "Shipping & Returns", Body = "

Put your shipping & returns information here. You can edit this in the admin site.

" }, - new Topic - { - SystemName = "PageNotFound", - IncludeInSitemap = false, - IsPasswordProtected = false, - Title = "", - Body = "

The page requested by you wasn't found, and we have a guess why.

  • If you typed the URL directly, please make sure the spelling is correct.
  • The page no longer exists.

" - }, //codehint: sm-add begin new Topic @@ -4226,8 +4250,6 @@ public IList Settings() }, new CurrencySettings() { - PrimaryStoreCurrencyId = _ctx.Set().First().Id, - PrimaryExchangeRateCurrencyId = _ctx.Set().First().Id, }, new MeasureSettings() { @@ -4746,54 +4768,70 @@ public IList ScheduleTasks() { var entities = new List { - new ScheduleTask() + new ScheduleTask { Name = "Send emails", - Seconds = 60, + CronExpression = "* * * * *", // every Minute Type = "SmartStore.Services.Messages.QueuedMessagesSendTask, SmartStore.Services", Enabled = true, StopOnError = false, }, - new ScheduleTask() - { - Name = "Keep alive", - Seconds = 300, - Type = "SmartStore.Services.Common.KeepAliveTask, SmartStore.Services", - Enabled = true, - StopOnError = false, - }, - new ScheduleTask() + new ScheduleTask { Name = "Delete guests", - Seconds = 600, + CronExpression = "*/10 * * * *", // Every 10 minutes Type = "SmartStore.Services.Customers.DeleteGuestsTask, SmartStore.Services", Enabled = true, StopOnError = false, }, - new ScheduleTask() + new ScheduleTask { Name = "Delete logs", - Seconds = 86400, // 1 day + CronExpression = "0 1 * * *", // At 01:00 Type = "SmartStore.Services.Logging.DeleteLogsTask, SmartStore.Services", Enabled = true, StopOnError = false, }, - new ScheduleTask() + new ScheduleTask { Name = "Clear cache", - Seconds = 600, + CronExpression = "0 */4 * * *", // Every 04 hours Type = "SmartStore.Services.Caching.ClearCacheTask, SmartStore.Services", Enabled = false, StopOnError = false, }, - new ScheduleTask() + new ScheduleTask { Name = "Update currency exchange rates", - Seconds = 900, + CronExpression = "0/15 * * * *", // Every 15 minutes Type = "SmartStore.Services.Directory.UpdateExchangeRateTask, SmartStore.Services", Enabled = true, StopOnError = false, }, + new ScheduleTask + { + Name = "Clear transient uploads", + CronExpression = "30 1,13 * * *", // At 01:30 and 13:30 + Type = "SmartStore.Services.Media.TransientMediaClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + }, + new ScheduleTask + { + Name = "Clear email queue", + CronExpression = "0 2 * * *", // At 02:00 + Type = "SmartStore.Services.Messages.QueuedMessagesClearTask, SmartStore.Services", + Enabled = true, + StopOnError = false, + }, + new ScheduleTask + { + Name = "Cleanup temporary files", + CronExpression = "30 3 * * *", // At 03:30 + Type = "SmartStore.Services.Common.TempFileCleanupTask, SmartStore.Services", + Enabled = true, + StopOnError = false + } }; this.Alter(entities); return entities; @@ -5658,6 +5696,16 @@ public IList ProductAttributes() { Name = "Game", Alias = "Game" + }, + new ProductAttribute + { + Name = "Color", + Alias = "iPhone color" + }, + new ProductAttribute + { + Name = "Memory capacity", + Alias = "Memory capacity" } }; @@ -5669,6 +5717,95 @@ public IList ProductVariantAttributes() { var entities = new List(); + #region iPhone + + var productIphone = _ctx.Set().First(x => x.Sku == "Apple-1001"); + var attributeMemoryCapacity = _ctx.Set().First(x => x.Alias == "Memory capacity"); + var attributeIphoneIphoneColor = _ctx.Set().First(x => x.Alias == "iPhone color"); + + var attributeIphoneMemoryCapacity = new ProductVariantAttribute() + { + Product = productIphone, + ProductAttribute = attributeMemoryCapacity, + IsRequired = true, + DisplayOrder = 1, + AttributeControlType = AttributeControlType.DropdownList + }; + + attributeIphoneMemoryCapacity.ProductVariantAttributeValues.Add(new ProductVariantAttributeValue() + { + Name = "16 GB", + Alias = "16gb", + IsPreSelected = true, + DisplayOrder = 1, + Quantity = 1, + ValueType = ProductVariantAttributeValueType.Simple + }); + + attributeIphoneMemoryCapacity.ProductVariantAttributeValues.Add(new ProductVariantAttributeValue() + { + Name = "64 GB", + Alias = "64gb", + DisplayOrder = 2, + Quantity = 1, + ValueType = ProductVariantAttributeValueType.Simple, + PriceAdjustment = 100.0M + }); + + attributeIphoneMemoryCapacity.ProductVariantAttributeValues.Add(new ProductVariantAttributeValue() + { + Name = "128 GB", + Alias = "128gb", + DisplayOrder = 3, + Quantity = 1, + ValueType = ProductVariantAttributeValueType.Simple, + PriceAdjustment = 200.0M + }); + + entities.Add(attributeIphoneMemoryCapacity); + + + var attributeIphoneColor = new ProductVariantAttribute() + { + Product = productIphone, + ProductAttribute = attributeIphoneIphoneColor, + IsRequired = true, + DisplayOrder = 2, + AttributeControlType = AttributeControlType.DropdownList + }; + + attributeIphoneColor.ProductVariantAttributeValues.Add(new ProductVariantAttributeValue() + { + Name = "Silver", + Alias = "silver", + IsPreSelected = true, + DisplayOrder = 1, + Quantity = 1, + ValueType = ProductVariantAttributeValueType.Simple + }); + + attributeIphoneColor.ProductVariantAttributeValues.Add(new ProductVariantAttributeValue() + { + Name = "Gold", + Alias = "gold", + DisplayOrder = 2, + Quantity = 1, + ValueType = ProductVariantAttributeValueType.Simple + }); + + attributeIphoneColor.ProductVariantAttributeValues.Add(new ProductVariantAttributeValue() + { + Name = "Space gray", + Alias = "spacegray", + DisplayOrder = 3, + Quantity = 1, + ValueType = ProductVariantAttributeValueType.Simple + }); + + entities.Add(attributeIphoneColor); + + #endregion iPhone + #region attributeDualshock3ControllerColor var productPs3 = _ctx.Set().First(x => x.Sku == "Sony-PS399000"); @@ -5932,7 +6069,7 @@ public IList ProductTags() Name = "iPhone" }; - _ctx.Set().Where(pt => pt.MetaTitle == "Apple iPhone 5 32 GB").FirstOrDefault().ProductTags.Add(productTagIphone); + _ctx.Set().Where(pt => pt.MetaTitle == "Apple iPhone 6").FirstOrDefault().ProductTags.Add(productTagIphone); #endregion tag iPhone @@ -5993,6 +6130,7 @@ public IList CategoriesFirstLevel() var categoryBooks = new Category { Name = "Books", + Alias = "Books", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, @@ -6008,11 +6146,12 @@ public IList CategoriesFirstLevel() var categoryComputers = new Category { Name = "Computers", + Alias = "Computers", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_computers.jpeg"), "image/jpeg", GetSeName("Computers")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_computers.png"), "image/png", GetSeName("Computers")), Published = true, DisplayOrder = 2, CreatedOnUtc = DateTime.UtcNow, @@ -6028,7 +6167,7 @@ public IList CategoriesFirstLevel() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_gaming.jpg"), "image/jpeg", GetSeName("Gaming")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_gaming.png"), "image/png", GetSeName("Gaming")), Published = true, DisplayOrder = 3, CreatedOnUtc = DateTime.UtcNow, @@ -6039,13 +6178,14 @@ public IList CategoriesFirstLevel() var categoryCellPhones = new Category { Name = "Cell phones", + Alias = "Cell phones", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", //ParentCategoryId = categoryElectronics.Id, - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_cell_phones.jpeg"), "image/jpeg", GetSeName("Cell phones")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_cellphone.png"), "image/png", GetSeName("Cell phones")), Published = true, DisplayOrder = 4, CreatedOnUtc = DateTime.UtcNow, @@ -6056,11 +6196,12 @@ public IList CategoriesFirstLevel() var categoryDigitalDownloads = new Category { Name = "Instant music", + Alias = "Instant music", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_digital_downloads.jpeg"), "image/jpeg", GetSeName("Digital downloads")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_digitaldownloads.jpg"), "image/jpeg", GetSeName("Digital downloads")), Published = true, DisplayOrder = 6, CreatedOnUtc = DateTime.UtcNow, @@ -6071,11 +6212,12 @@ public IList CategoriesFirstLevel() var categoryGiftCards = new Category { Name = "Gift Cards", + Alias = "Gift Cards", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_gift_cards.jpeg"), "image/jpeg", GetSeName("Gift Cards")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_giftcards.png"), "image/png", GetSeName("Gift Cards")), Published = true, DisplayOrder = 12, CreatedOnUtc = DateTime.UtcNow, @@ -6086,11 +6228,12 @@ public IList CategoriesFirstLevel() var categoryWatches = new Category { Name = "Watches", + Alias = "Watches", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0001514_uhren.jpeg"), "image/jpeg", GetSeName("Watches")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_watches.png"), "image/png", GetSeName("Watches")), Published = true, DisplayOrder = 10, CreatedOnUtc = DateTime.UtcNow, @@ -6124,6 +6267,7 @@ public IList CategoriesSecondLevel() var categoryBooksSpiegel = new Category { Name = "SPIEGEL-Bestseller", + Alias = "SPIEGEL-Bestseller", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, @@ -6140,6 +6284,7 @@ public IList CategoriesSecondLevel() var categoryBooksCookAndEnjoy = new Category { Name = "Cook and enjoy", + Alias = "Cook and enjoy", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, @@ -6156,12 +6301,13 @@ public IList CategoriesSecondLevel() var categoryDesktops = new Category { Name = "Desktops", + Alias = "Desktops", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", ParentCategoryId = _ctx.Set().Where(x => x.MetaTitle == "Computers").First().Id, - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_desktops.jpg"), "image/jpeg", GetSeName("Desktops")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_desktops.png"), "image/png", GetSeName("Desktops")), PriceRanges = "-1000;1000-1200;1200-;", Published = true, DisplayOrder = 1, @@ -6173,12 +6319,13 @@ public IList CategoriesSecondLevel() var categoryNotebooks = new Category { Name = "Notebooks", + Alias = "Notebooks", CategoryTemplateId = categoryTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", ParentCategoryId = _ctx.Set().Where(x => x.MetaTitle == "Computers").First().Id, - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_notebooks.jpg"), "image/pjpeg", GetSeName("Notebooks")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_notebooks.png"), "image/png", GetSeName("Notebooks")), Published = true, DisplayOrder = 2, CreatedOnUtc = DateTime.UtcNow, @@ -6195,7 +6342,7 @@ public IList CategoriesSecondLevel() AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", ParentCategoryId = _ctx.Set().Where(x => x.MetaTitle == "Gaming").First().Id, - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_gaming_accessories.jpg"), "image/jpeg", GetSeName("Gaming Accessories")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_gaming_accessories.png"), "image/png", GetSeName("Gaming Accessories")), Published = true, DisplayOrder = 2, CreatedOnUtc = DateTime.UtcNow, @@ -6212,7 +6359,7 @@ public IList CategoriesSecondLevel() AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", ParentCategoryId = _ctx.Set().Where(x => x.MetaTitle == "Gaming").First().Id, - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_games.jpg"), "image/jpeg", GetSeName("Games")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_games.png"), "image/png", GetSeName("Games")), Published = true, DisplayOrder = 3, CreatedOnUtc = DateTime.UtcNow, @@ -6220,22 +6367,6 @@ public IList CategoriesSecondLevel() MetaTitle = "Games" }; - //var categorySoftware = new Category - //{ - // Name = "Software", - // CategoryTemplateId = categoryTemplateInGridAndLines.Id, - // PageSize = 12, - // AllowCustomersToSelectPageSize = true, - // PageSizeOptions = "12,18,36,72,150", - // ParentCategoryId = _ctx.Set().Where(x => x.MetaTitle =="Computers" ).FirstOrDefault().Id, - // PictureId = pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "category_software.jpg"), "image/pjpeg", pictureService.GetPictureSeName("Software"), true, false).Id, - // Published = true, - // DisplayOrder = 2, - // CreatedOnUtc = DateTime.UtcNow, - // UpdatedOnUtc = DateTime.UtcNow, - // MetaTitle = "Software" - //}; - #endregion category definitions var entities = new List @@ -6269,69 +6400,123 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000746_apple_125.jpeg"), "image/pjpeg", GetSeName("Apple")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer_apple.png"), "image/png", GetSeName("Apple")), Published = true, - DisplayOrder = 2, + DisplayOrder = 1, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; #endregion Apple - #region Samsung - - var manufacturerSamsung = new Manufacturer + #region Android + + var manufacturerAndroid = new Manufacturer + { + Name = "Android", + ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, + PageSize = 12, + AllowCustomersToSelectPageSize = true, + PageSizeOptions = "12,18,36,72,150", + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-android.png"), "image/png", GetSeName("Android")), + Published = true, + DisplayOrder = 2, + CreatedOnUtc = DateTime.UtcNow, + UpdatedOnUtc = DateTime.UtcNow + }; + + #endregion Android + + #region LG + + var manufacturerLG = new Manufacturer + { + Name = "LG", + ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, + PageSize = 12, + AllowCustomersToSelectPageSize = true, + PageSizeOptions = "12,18,36,72,150", + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-lg.png"), "image/png", GetSeName("LG")), + Published = true, + DisplayOrder = 3, + CreatedOnUtc = DateTime.UtcNow, + UpdatedOnUtc = DateTime.UtcNow + }; + + #endregion LG + + #region Dell + + var manufacturerDell = new Manufacturer + { + Name = "Dell", + ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, + PageSize = 12, + AllowCustomersToSelectPageSize = true, + PageSizeOptions = "12,18,36,72,150", + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-dell.png"), "image/png", GetSeName("Dell")), + Published = true, + DisplayOrder = 4, + CreatedOnUtc = DateTime.UtcNow, + UpdatedOnUtc = DateTime.UtcNow + }; + + #endregion Dell + + #region HP + + var manufacturerHP = new Manufacturer + { + Name = "HP", + ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, + PageSize = 12, + AllowCustomersToSelectPageSize = true, + PageSizeOptions = "12,18,36,72,150", + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-hp.png"), "image/png", GetSeName("HP")), + Published = true, + DisplayOrder = 5, + CreatedOnUtc = DateTime.UtcNow, + UpdatedOnUtc = DateTime.UtcNow + }; + + #endregion HP + + #region Microsoft + + var manufacturerMicrosoft = new Manufacturer + { + Name = "Microsoft", + ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, + PageSize = 12, + AllowCustomersToSelectPageSize = true, + PageSizeOptions = "12,18,36,72,150", + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-microsoft.png"), "image/png", GetSeName("Microsoft")), + Published = true, + DisplayOrder = 6, + CreatedOnUtc = DateTime.UtcNow, + UpdatedOnUtc = DateTime.UtcNow + }; + + #endregion Microsoft + + #region Samsung + + var manufacturerSamsung = new Manufacturer { Name = "Samsung", ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000904_samsung_125.jpeg"), "image/pjpeg", GetSeName("Samsung")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-samsung.png"), "image/png", GetSeName("Samsung")), Published = true, - DisplayOrder = 2, + DisplayOrder = 7, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; #endregion Samsung - #region LG - - var manufacturerLG = new Manufacturer - { - Name = "LG", - ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, - PageSize = 12, - AllowCustomersToSelectPageSize = true, - PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000900_lg.jpeg"), "image/pjpeg", GetSeName("LG")), - Published = true, - DisplayOrder = 2, - CreatedOnUtc = DateTime.UtcNow, - UpdatedOnUtc = DateTime.UtcNow - }; - - #endregion LG - - #region HP - - var manufacturerHP = new Manufacturer - { - Name = "HP", - ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, - PageSize = 12, - AllowCustomersToSelectPageSize = true, - PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "HP_Logo_2012.svg.png"), "image/png", GetSeName("HP")), - Published = true, - DisplayOrder = 2, - CreatedOnUtc = DateTime.UtcNow, - UpdatedOnUtc = DateTime.UtcNow - }; - - #endregion HP - #region Acer var manufacturerAcer = new Manufacturer @@ -6343,14 +6528,13 @@ public IList Manufacturers() PageSizeOptions = "12,18,36,72,150", Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "acer-logo.jpg"), "image/pjpeg", GetSeName("Acer")), Published = true, - DisplayOrder = 2, + DisplayOrder = 8, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; #endregion Acer - #region TrekStor var manufacturerTrekStor = new Manufacturer @@ -6360,9 +6544,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000993_trekstor.jpeg"), "image/pjpeg", GetSeName("TrekStor")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-trekstor.png"), "image/png", GetSeName("TrekStor")), Published = true, - DisplayOrder = 2, + DisplayOrder = 9, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6378,33 +6562,15 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000994_western-digital.jpeg"), "image/pjpeg", GetSeName("Western Digital")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-westerndigital.png"), "image/png", GetSeName("Western Digital")), Published = true, - DisplayOrder = 2, + DisplayOrder = 10, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; #endregion Western Digital - #region Dell - - var manufacturerDell = new Manufacturer - { - Name = "Dell", - ManufacturerTemplateId = manufacturerTemplateInGridAndLines.Id, - PageSize = 12, - AllowCustomersToSelectPageSize = true, - PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "Dell_Logo.png"), "image/pjpeg", GetSeName("Dell")), - Published = true, - DisplayOrder = 2, - CreatedOnUtc = DateTime.UtcNow, - UpdatedOnUtc = DateTime.UtcNow - }; - - #endregion Dell - #region MSI var manufacturerMSI = new Manufacturer @@ -6414,9 +6580,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "msi_logo1.jpg"), "image/pjpeg", GetSeName("MSI")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-msi.png"), "image/png", GetSeName("MSI")), Published = true, - DisplayOrder = 2, + DisplayOrder = 11, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6432,9 +6598,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0001085_canon.jpeg"), "image/pjpeg", GetSeName("Canon")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-canon.png"), "image/png", GetSeName("Canon")), Published = true, - DisplayOrder = 2, + DisplayOrder = 12, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6450,9 +6616,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0001086_casio.jpeg"), "image/pjpeg", GetSeName("Casio")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-casio.png"), "image/png", GetSeName("Casio")), Published = true, - DisplayOrder = 2, + DisplayOrder = 13, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6468,9 +6634,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0001087_panasonic.jpeg"), "image/pjpeg", GetSeName("Panasonic")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-panasonic.png"), "image/png", GetSeName("Panasonic")), Published = true, - DisplayOrder = 2, + DisplayOrder = 14, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6486,9 +6652,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000898_blackberry.jpeg"), "image/pjpeg", GetSeName("BlackBerry")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-blackberry.png"), "image/png", GetSeName("BlackBerry")), Published = true, - DisplayOrder = 2, + DisplayOrder = 15, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6504,9 +6670,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000899_htc.png"), "image/pjpeg", GetSeName("HTC")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-htc.png"), "image/png", GetSeName("HTC")), Published = true, - DisplayOrder = 2, + DisplayOrder = 16, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6522,9 +6688,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0001591_festina.jpeg"), "image/pjpeg", GetSeName("Festina")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer_festina.png"), "image/png", GetSeName("Festina")), Published = true, - DisplayOrder = 2, + DisplayOrder = 17, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6540,9 +6706,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0001328_certina_125.jpeg"), "image/pjpeg", GetSeName("Certina")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer-certina.png"), "image/png", GetSeName("Certina")), Published = true, - DisplayOrder = 2, + DisplayOrder = 18, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6558,9 +6724,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-logo.jpg"), "image/pjpeg", GetSeName("Sony")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer_sony.png"), "image/png", GetSeName("Sony")), Published = true, - DisplayOrder = 2, + DisplayOrder = 19, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6576,9 +6742,9 @@ public IList Manufacturers() PageSize = 12, AllowCustomersToSelectPageSize = true, PageSizeOptions = "12,18,36,72,150", - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "ubisoft-logo.jpg"), "image/pjpeg", GetSeName("Ubisoft")), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "manufacturer_ubisoft.png"), "image/png", GetSeName("Ubisoft")), Published = true, - DisplayOrder = 2, + DisplayOrder = 20, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow }; @@ -6616,6 +6782,8 @@ public IList Products() #region category Gift Cards + var categoryGiftCards = this._ctx.Set().First(c => c.Alias == "Gift Cards"); + #region product5GiftCard var product5GiftCard = new Product() @@ -6623,6 +6791,7 @@ public IList Products() ProductType = ProductType.SimpleProduct, VisibleIndividually = true, Name = "$5 Virtual Gift Card", + IsEsd = true, ShortDescription = "$5 Gift Card. Gift Cards must be redeemed through our site Web site toward the purchase of eligible products.", FullDescription = "

Gift Cards must be redeemed through our site Web site toward the purchase of eligible products. Purchases are deducted from the GiftCard balance. Any unused balance will be placed in the recipient's GiftCard account when redeemed. If an order exceeds the amount of the GiftCard, the balance must be paid with a credit card or other available payment method.

", Sku = "P-1000", @@ -6643,6 +6812,7 @@ public IList Products() AllowBackInStockSubscriptions = false }; + product5GiftCard.ProductCategories.Add(new ProductCategory() { Category = categoryGiftCards, DisplayOrder = 1 }); //var productTag = _productTagRepository.Table.Where(pt => pt.Name == "gift").FirstOrDefault(); //productTag.ProductCount++; @@ -6651,7 +6821,7 @@ public IList Products() product5GiftCard.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_5giftcart.jpeg"), "image/jpeg", GetSeName(product5GiftCard.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_giftcart.png"), "image/png", GetSeName(product5GiftCard.Name)), DisplayOrder = 1, }); @@ -6664,6 +6834,7 @@ public IList Products() ProductType = ProductType.SimpleProduct, VisibleIndividually = true, Name = "$25 Virtual Gift Card", + IsEsd = true, ShortDescription = "$25 Gift Card. Gift Cards must be redeemed through our site Web site toward the purchase of eligible products.", FullDescription = "

Gift Cards must be redeemed through our site Web site toward the purchase of eligible products. Purchases are deducted from the GiftCard balance. Any unused balance will be placed in the recipient's GiftCard account when redeemed. If an order exceeds the amount of the GiftCard, the balance must be paid with a credit card or other available payment method.

", Sku = "P-1001", @@ -6684,9 +6855,11 @@ public IList Products() AllowBackInStockSubscriptions = false }; + product25GiftCard.ProductCategories.Add(new ProductCategory() { Category = categoryGiftCards, DisplayOrder = 1 }); + product25GiftCard.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_25giftcart.jpeg"), "image/jpeg", GetSeName(product25GiftCard.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_giftcart.png"), "image/png", GetSeName(product25GiftCard.Name)), DisplayOrder = 1, }); @@ -6699,6 +6872,7 @@ public IList Products() ProductType = ProductType.SimpleProduct, VisibleIndividually = true, Name = "$50 Virtual Gift Card", + IsEsd = true, ShortDescription = "$50 Gift Card. Gift Cards must be redeemed through our site Web site toward the purchase of eligible products.", FullDescription = "

Gift Cards must be redeemed through our site Web site toward the purchase of eligible products. Purchases are deducted from the GiftCard balance. Any unused balance will be placed in the recipient's GiftCard account when redeemed. If an order exceeds the amount of the GiftCard, the balance must be paid with a credit card or other available payment method.

", Sku = "P-1002", @@ -6719,9 +6893,11 @@ public IList Products() AllowBackInStockSubscriptions = false }; + product50GiftCard.ProductCategories.Add(new ProductCategory() { Category = categoryGiftCards, DisplayOrder = 1 }); + product50GiftCard.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_50giftcart.jpeg"), "image/jpeg", GetSeName(product50GiftCard.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_giftcart.png"), "image/png", GetSeName(product50GiftCard.Name)), DisplayOrder = 1, }); @@ -6731,6 +6907,10 @@ public IList Products() #region category books + var categorySpiegelBestseller = this._ctx.Set().First(c => c.Alias == "SPIEGEL-Bestseller"); + var categoryCookAndEnjoy = this._ctx.Set().First(c => c.Alias == "Cook and enjoy"); + var categoryBooks = this._ctx.Set().First(c => c.Alias == "Books"); + #region productBooksUberMan var productBooksUberMan = new Product() @@ -6757,6 +6937,8 @@ public IList Products() IsShipEnabled = true }; + productBooksUberMan.ProductCategories.Add(new ProductCategory() { Category = categorySpiegelBestseller, DisplayOrder = 1 }); + //pictures productBooksUberMan.ProductPictures.Add(new ProductPicture() { @@ -6770,7 +6952,6 @@ public IList Products() AllowFiltering = true, ShowOnProductPage = true, DisplayOrder = 3, - // Edition -> bound SpecificationAttributeOption = _ctx.Set().Where(sa => sa.DisplayOrder == 13).Single().SpecificationAttributeOptions.Where(sao => sao.DisplayOrder == 1).Single() }); productBooksUberMan.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() @@ -6778,7 +6959,6 @@ public IList Products() AllowFiltering = true, ShowOnProductPage = true, DisplayOrder = 3, - // Category -> bound SpecificationAttributeOption = _ctx.Set().Where(sa => sa.DisplayOrder == 14).Single().SpecificationAttributeOptions.Where(sao => sao.DisplayOrder == 7).Single() }); productBooksUberMan.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() @@ -6786,7 +6966,6 @@ public IList Products() AllowFiltering = true, ShowOnProductPage = true, DisplayOrder = 3, - // Language -> German SpecificationAttributeOption = _ctx.Set().Where(sa => sa.DisplayOrder == 12).Single().SpecificationAttributeOptions.Where(sao => sao.DisplayOrder == 1).Single() }); #endregion productBooksUberMan @@ -6818,6 +6997,8 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productBooksGefangeneDesHimmels.ProductCategories.Add(new ProductCategory() { Category = categorySpiegelBestseller, DisplayOrder = 1 }); + //pictures productBooksGefangeneDesHimmels.ProductPictures.Add(new ProductPicture() { @@ -6834,6 +7015,7 @@ public IList Products() // Edition -> bound SpecificationAttributeOption = _ctx.Set().Where(sa => sa.DisplayOrder == 13).Single().SpecificationAttributeOptions.Where(sao => sao.DisplayOrder == 1).Single() }); + productBooksGefangeneDesHimmels.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() { AllowFiltering = true, @@ -6880,10 +7062,12 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productBooksBestGrillingRecipes.ProductCategories.Add(new ProductCategory() { Category = categoryCookAndEnjoy, DisplayOrder = 1 }); + //pictures productBooksBestGrillingRecipes.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000937_best-grilling-recipes.jpeg"), "image/jpeg", GetSeName(productBooksBestGrillingRecipes.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_bestgrillingrecipes.jpg"), "image/jpeg", GetSeName(productBooksBestGrillingRecipes.Name)), DisplayOrder = 1, }); @@ -6942,10 +7126,12 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 1).Single() }; + productBooksCookingForTwo.ProductCategories.Add(new ProductCategory() { Category = categoryCookAndEnjoy, DisplayOrder = 1 }); + //pictures productBooksCookingForTwo.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000938_cooking-for-two.jpeg"), "image/jpeg", GetSeName(productBooksCookingForTwo.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_cookingfortwo.jpg"), "image/jpeg", GetSeName(productBooksCookingForTwo.Name)), DisplayOrder = 1, }); @@ -7004,6 +7190,8 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 2).Single() }; + productBooksAutosDerSuperlative.ProductCategories.Add(new ProductCategory() { Category = categoryBooks, DisplayOrder = 1 }); + //pictures productBooksAutosDerSuperlative.ProductPictures.Add(new ProductPicture() { @@ -7067,6 +7255,8 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productBooksBildatlasMotorraeder.ProductCategories.Add(new ProductCategory() { Category = categoryBooks, DisplayOrder = 1 }); + //pictures productBooksBildatlasMotorraeder.ProductPictures.Add(new ProductPicture() { @@ -7129,6 +7319,8 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productBooksAutoBuch.ProductCategories.Add(new ProductCategory() { Category = categoryBooks, DisplayOrder = 1 }); + //pictures productBooksAutoBuch.ProductPictures.Add(new ProductPicture() { @@ -7191,6 +7383,8 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productBooksFastCars.ProductCategories.Add(new ProductCategory() { Category = categoryBooks, DisplayOrder = 1 }); + //pictures productBooksFastCars.ProductPictures.Add(new ProductPicture() { @@ -7253,6 +7447,8 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 1).Single() }; + productBooksMotorradAbenteuer.ProductCategories.Add(new ProductCategory() { Category = categoryBooks, DisplayOrder = 1 }); + //pictures productBooksMotorradAbenteuer.ProductPictures.Add(new ProductPicture() { @@ -7292,6 +7488,10 @@ public IList Products() #region computer + var categoryComputer = this._ctx.Set().First(c => c.Alias == "Computers"); + var categoryNotebooks = this._ctx.Set().First(c => c.Alias == "Notebooks"); + var categoryDesktops = this._ctx.Set().First(c => c.Alias == "Desktops"); + #region productComputerDellInspiron23 var productComputerDellInspiron23 = new Product() @@ -7319,12 +7519,15 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productComputerDellInspiron23.ProductCategories.Add(new ProductCategory() { Category = categoryComputer, DisplayOrder = 1 }); + productComputerDellInspiron23.ProductCategories.Add(new ProductCategory() { Category = categoryDesktops, DisplayOrder = 1 }); + #region pictures //pictures productComputerDellInspiron23.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000953_dell-inspiron-one-23.jpeg"), "image/jpeg", GetSeName(productComputerDellInspiron23.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_dellinspiron23.png"), "image/png", GetSeName(productComputerDellInspiron23.Name)), DisplayOrder = 1, }); productComputerDellInspiron23.ProductPictures.Add(new ProductPicture() @@ -7424,12 +7627,15 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productComputerDellOptiplex3010.ProductCategories.Add(new ProductCategory() { Category = categoryComputer, DisplayOrder = 1 }); + productComputerDellOptiplex3010.ProductCategories.Add(new ProductCategory() { Category = categoryDesktops, DisplayOrder = 1 }); + #region pictures //pictures productComputerDellOptiplex3010.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000953_dell-inspiron-one-23.jpeg"), "image/jpeg", GetSeName(productComputerDellOptiplex3010.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_dellinspiron23.png"), "image/png", GetSeName(productComputerDellOptiplex3010.Name)), DisplayOrder = 1, }); productComputerDellOptiplex3010.ProductPictures.Add(new ProductPicture() @@ -7536,6 +7742,9 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 0).Single() }; + productComputerAcerAspireOne.ProductCategories.Add(new ProductCategory() { Category = categoryComputer, DisplayOrder = 1 }); + productComputerAcerAspireOne.ProductCategories.Add(new ProductCategory() { Category = categoryNotebooks, DisplayOrder = 1 }); + #region manufacturer //manufacturer @@ -7569,7 +7778,7 @@ public IList Products() #region pictures productComputerAcerAspireOne.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "acer-aspire-one.jpg"), "image/jpeg", GetSeName(productComputerAcerAspireOne.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_aceraspiresl1500.png"), "image/png", GetSeName(productComputerAcerAspireOne.Name)), DisplayOrder = 1, }); productComputerAcerAspireOne.ProductPictures.Add(new ProductPicture() @@ -7591,22 +7800,24 @@ public IList Products() #region Smartphones - #region productSmartPhonesAppleIphone5 + var categoryCellPhones = this._ctx.Set().First(c => c.Alias == "Cell phones"); + + #region productSmartPhonesAppleIphone - var productSmartPhonesAppleIphone5 = new Product() + var productSmartPhonesAppleIphone = new Product() { ProductType = ProductType.SimpleProduct, VisibleIndividually = true, - Name = "Apple iPhone 5 32 GB", + Name = "Apple iPhone 6", ShortDescription = "The biggest thing to happen to iPhone since iPhone.", - FullDescription = "

The iPhone 5 at a glance. New design.

With 7.6 mm and 112 g3 the iPhone 5 has a remarkably thin and light design. It is made of anodized aluminum. The beveled edges are precision cut with a diamond.
Brilliant 4 \"Retina Display.
Now you can see everything more vivid and detailed. And although the screen is bigger, it has the same width as the iPhone 4S and is therefore just as easily operated with one hand. Powerful A6 chip. Compared with the A5 chip, he has up to twice the CPU and graphics performance. And despite its speed, the iPhone 5 has a fantastic battery life. Ultra-fast mobile data. The iPhone 5 supports the latest wireless technologies and can be even more so with the world verbinden.4Und networks and Wi-Fi is faster.

Delivery 6 Apple iPhone 5 with iOS EarPods with Remote and Mic to USB Cable Lightning USB Power Adapter (Power Supply) Choose the iPhone that suits you. 16 GB, 32 GB or 64 GB capacity? The iPhone is available in three capacities: 16, 32 and 64 GB. \"GB\" stands for gigabytes. The more gigabytes your iPhone, the more space you have. For content such as apps, games, photos, HD videos, music, movies and more In a large music or photo library, or if you frequently invite HD movies to an iPhone recommends using a larger capacity. If your music or photo library is small or you do or buy rare films, ranging from an iPhone with a smaller memory size for you. With time comes along Some of content on your iPhone. Therefore, you should consider your growing storage needs of the iPhone purchase. The unlocked iPhone The unlocked iPhone is not dependent on any cellular network, which means that you can decide for any supported GSM network worldwide. Buy an iPhone without a contract at the Apple Online Store, then look for a tariff for the iPhone, which covers only the SIM card. Or contact your current provider if you want to keep your current rate.

PrePaid
If you want a contract, you can choose one of the \"prepaid\" starter packs of available network operators in the Apple Online Store. With \"prepaid\" you get your iPhone and ready. Compatible with a SIM card A credit check is not required. You pay online just for what you use, and can switch the network provider at any time. \"Prepaid\" is a good option if you want to use when traveling abroad prefer a local supplier. Which SIM card do I need? It does not matter if you are a new contract, further Lead your existing contract or \"prepaid\" choose - you will need a compatible SIM card. For the iPhone 5, it takes a nano-SIM card for the iPhone 4S and the iPhone 4 is a micro-SIM card. For more details you get with your wireless carrier. Cellular networks and Wi-Fi

A1428 GSM model: UMTS / HSPA + / DC-HSDPA (850, 900, 1900, 2100 MHz) GSM / EDGE (850, 900, 1800, 1900 MHz), LTE (Band 4 and 17)
Model A1429 * CDMA: CDMA EV-DO Rev. A and Rev. B (800, 1900, 2100 MHz), UMTS / HSPA + / DC-HSDPA (850, 900, 1900, 2100 MHz) GSM / EDGE (850, 900 , 1800, 1900 MHz), LTE band (1, 3, 5, 13, 25)
* A1429 GSM model: UMTS / HSPA + / DC-HSDPA (850, 900, 1900, 2100 MHz) GSM / EDGE (850, 900, 1800, 1900 MHz), LTE (Volume 1, 3, 5)
802.11a/b/g/n Wi-Fi (802.11n 2.4 GHz and 5 GHz)
Bluetooth 4.0
Display Retina Display 4 \"widescreen Multi-Touch display (10.16 cm diagonal) 1136 x 640 pixels at 326 ppi Typical contrast ratio: 500 cd/m2 simultaneously resistant oleophobic coating on the front support for display of multiple languages ​​and characters: 800:1 Maximum brightness typical Camera, photos and videos 8-megapixel iSight camera Panorama Video recording, HD (1080p) up to 30 frames per second with audio FaceTime HD camera with 1.2-megapixel still images and HD video (720p) for up to 30 frames per second Autofocus Tap to focus video photos and facial recognition in video and photos LED flash Improved video stabilization for geotagging photos and videos Audio Support for AirPlay Mirroring to Apple TV with 720p AirPlay video streaming to Apple TV (3rd generation) up to 1080p and Apple TV (2nd generation) up to 720p Video formats supported: H.264 video up to 1080p, 30 frames per second, High Profile level 4.1 with AAC-LC audio up to 160 kbit / s, 48kHz, stereo audio in m4v, mp4 and mov... , MPEG-4 video, up to 2.5 Mbit / s, 640 x 480 pixels, 30 frames per second, Simple Profile with AAC-LC audio up to 160 Kbps m4v / s, 48 ​​kHz, stereo audio in. , mp4 and mov file formats Motion JPEG (M-JPEG)... up to 35 Mbit / s, 1280 x 720 pixels, 30 frames per second, audio in ulaw, PCM stereo audio in avi format

", - Sku = "P-1015", + FullDescription = "

Available in silver, gold, and space gray, iPhone 6 Plus features an A8 chip, Touch ID, faster LTE wireless, a new 8MP iSight camera with Focus Pixels, and iOS 8.

Weight and Dimensions: Height: 6.22 inches (158.1 mm), Width: 3.06 inches (77.8 mm), Depth: 0.28 inch (7.1 mm), Weight: 6.07 ounces (172 grams).

  • A8 chip with 64-bit architecture. M8 motion coprocessor.
  • New 8-megapixel iSight camera with 1.5µ pixels. Autofocus with Focus Pixels.
  • 1080p HD video recording (30 fps or 60 fps).
  • Retina HD display. 4.7-inch (diagonal) LED-backlit widescreen Multi Touch display with IPS technology.
  • 1334-by-750-pixel resolution at 326 ppi. 1400:1 contrast ratio (typical). 500 cd/m2 max brightness (typical).
  • Fingerprint identity sensor built into the Home button.
  • 802.11a/b/g/n/ac Wi-Fi. Bluetooth 4.0 wireless technology. NFC.
  • RAM 1GB, Internal storage 16GB.
  • Colors: Silver, Gold, Space Gray.

", + Sku = "Apple-1001", ProductTemplateId = productTemplateSimple.Id, AllowCustomerReviews = true, Published = true, CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow, - MetaTitle = "Apple iPhone 5 32 GB", + MetaTitle = "Apple iPhone 6", ShowOnHomePage = true, Price = 579.00M, ManageInventoryMethod = ManageInventoryMethod.DontManageStock, @@ -7619,32 +7830,34 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 2).Single() }; + productSmartPhonesAppleIphone.ProductCategories.Add(new ProductCategory() { Category = categoryCellPhones, DisplayOrder = 1 }); + #region pictures //pictures - productSmartPhonesAppleIphone5.ProductPictures.Add(new ProductPicture() + productSmartPhonesAppleIphone.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000789-apple-iphone-5-32-gb.jpg"), "image/jpeg", GetSeName(productSmartPhonesAppleIphone5.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000789-apple-iphone.jpg"), "image/jpeg", GetSeName(productSmartPhonesAppleIphone.Name)), DisplayOrder = 1, }); - productSmartPhonesAppleIphone5.ProductPictures.Add(new ProductPicture() + productSmartPhonesAppleIphone.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000785-apple-iphone-5-32-gb.jpg"), "image/jpeg", GetSeName(productSmartPhonesAppleIphone5.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000785-apple-iphone.png"), "image/png", GetSeName(productSmartPhonesAppleIphone.Name)), DisplayOrder = 2, }); - productSmartPhonesAppleIphone5.ProductPictures.Add(new ProductPicture() + productSmartPhonesAppleIphone.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000786-apple-iphone-5-32-gb.jpg"), "image/jpeg", GetSeName(productSmartPhonesAppleIphone5.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000786-apple-iphone.png"), "image/png", GetSeName(productSmartPhonesAppleIphone.Name)), DisplayOrder = 3, }); - productSmartPhonesAppleIphone5.ProductPictures.Add(new ProductPicture() + productSmartPhonesAppleIphone.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000787-apple-iphone-5-32-gb.jpg"), "image/jpeg", GetSeName(productSmartPhonesAppleIphone5.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000787-apple-iphone.jpg"), "image/jpeg", GetSeName(productSmartPhonesAppleIphone.Name)), DisplayOrder = 4, }); - productSmartPhonesAppleIphone5.ProductPictures.Add(new ProductPicture() + productSmartPhonesAppleIphone.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000788-apple-iphone-5-32-gb.jpg"), "image/jpeg", GetSeName(productSmartPhonesAppleIphone5.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0000788-apple-iphone.png"), "image/png", GetSeName(productSmartPhonesAppleIphone.Name)), DisplayOrder = 5, }); @@ -7655,7 +7868,7 @@ public IList Products() #region manufacturer //manufacturer - productSmartPhonesAppleIphone5.ProductManufacturers.Add(new ProductManufacturer() + productSmartPhonesAppleIphone.ProductManufacturers.Add(new ProductManufacturer() { Manufacturer = _ctx.Set().Where(c => c.Name == "Apple").Single(), DisplayOrder = 1, @@ -7665,7 +7878,7 @@ public IList Products() #region SpecificationAttributes //attributes - productSmartPhonesAppleIphone5.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() + productSmartPhonesAppleIphone.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() { AllowFiltering = true, ShowOnProductPage = true, @@ -7673,7 +7886,7 @@ public IList Products() // housing > alu SpecificationAttributeOption = _ctx.Set().Where(sa => sa.DisplayOrder == 8).Single().SpecificationAttributeOptions.Where(sao => sao.DisplayOrder == 4).Single() }); - productSmartPhonesAppleIphone5.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() + productSmartPhonesAppleIphone.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() { AllowFiltering = true, ShowOnProductPage = true, @@ -7681,7 +7894,7 @@ public IList Products() // manufacturer > apple SpecificationAttributeOption = _ctx.Set().Where(sa => sa.DisplayOrder == 20).Single().SpecificationAttributeOptions.Where(sao => sao.DisplayOrder == 1).Single() }); - productSmartPhonesAppleIphone5.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() + productSmartPhonesAppleIphone.ProductSpecificationAttributes.Add(new ProductSpecificationAttribute() { AllowFiltering = true, ShowOnProductPage = true, @@ -7691,19 +7904,22 @@ public IList Products() }); #endregion SpecificationAttributes - #endregion productSmartPhonesAppleIphone5 + #endregion productSmartPhonesAppleIphone #endregion Smartphones #region Instant Download Music + var categoryMusic = this._ctx.Set().First(c => c.Alias == "Instant music"); + #region Antonio Vivaldi: then spring - var productInstantDownloadVivaldi = new Product() + var productInstantDownloadVivaldi = new Product { ProductType = ProductType.SimpleProduct, VisibleIndividually = true, Name = "Antonio Vivaldi: spring", + IsEsd = true, ShortDescription = "MP3, 320 kbit/s", FullDescription = "

Antonio Vivaldi: Spring

Antonio Lucio Vivaldi (March 4, 1678 in Venice, † 28 July 1741 in Vienna) was a Venetian composer and violinist in the Baroque.

The Four Seasons (Le quattro stagioni Italian) is perhaps the most famous works of Antonio Vivaldi. It's four violin concertos with extra-musical programs, each portraying a concert season. This is the individual concerts one - probably written by Vivaldi himself - Sonnet preceded by consecutive letters in front of the lines and in the appropriate places in the score arrange the verbal description of the music.

Vivaldi had previously always been experimenting with non-musical programs, which often reflected in his tracks, the exact interpretation of the individual points score is unusual for him. His experience as a virtuoso violinist allowed him access to particularly effective playing techniques, as an opera composer, he had developed a strong sense of effects, both of which benefitted from him.

As the title suggests, especially to imitate natural phenomena - gentle winds, severe storms and thunderstorms are elements that are common to all four concerts. There are also various birds and even a dog, further human activities such as hunting, a barn dance, ice skating, including stumbling and falling to the heavy sleep of a drunkard.

The work dates from 1725 and is available in two print editions, which appeared more or less simultaneously published in Amsterdam and Paris.

", Sku = "P-1016", @@ -7722,7 +7938,7 @@ public IList Products() AllowBackInStockSubscriptions = false, IsDownload = true, HasSampleDownload = true, - SampleDownload = new Download() + SampleDownload = new Download { DownloadGuid = Guid.NewGuid(), ContentType = "audio/mp3", @@ -7733,6 +7949,8 @@ public IList Products() } }; + productInstantDownloadVivaldi.ProductCategories.Add(new ProductCategory() { Category = categoryMusic, DisplayOrder = 1 }); + #region pictures //pictures @@ -7774,6 +7992,7 @@ public IList Products() ProductType = ProductType.SimpleProduct, VisibleIndividually = true, Name = "Ludwig van Beethoven: For Elise", + IsEsd = true, ShortDescription = "Ludwig van Beethoven's most popular compositions", FullDescription = "

The score was not published until 1867, 40 years after the composer's death in 1827. The discoverer of the piece, Ludwig Nohl, affirmed that the original autographed manuscript, now lost, was dated 27 April 1810.[4] The version of \"Für Elise\" we hear today is an earlier version that was transcribed by Ludwig Nohl. There is a later version, with drastic changes to the accompaniment which was transcribed from a later manuscript by Barry Cooper. The most notable difference is in the first theme, the left-hand arpeggios are delayed by a 16th note beat. There are a few extra bars in the transitional section into the B section; and finally, the rising A minor arpeggio figure is moved later into the piece. The tempo marking Poco Moto is believed to have been on the manuscript that Ludwig Nohl transcribed (now lost). The later version includes the marking Molto Grazioso. It is believed that Beethoven intended to add the piece to a cycle of bagatelles.[citation needed]

Therese Malfatti, widely believed to be the dedicatee of \"Für Elise\" The pianist and musicologist Luca Chiantore (es) argued in his thesis and his 2010 book Beethoven al piano that Beethoven might not have been the person who gave the piece the form that we know today. Chiantore suggested that the original signed manuscript, upon which Ludwig Nohl claimed to base his transcription, may never have existed.[5] On the other hand, the musicologist Barry Cooper stated, in a 1984 essay in The Musical Times, that one of two surviving sketches closely resembles the published version.[6]

", Sku = "P-1017", @@ -7804,6 +8023,8 @@ public IList Products() } }; + productInstantDownloadBeethoven.ProductCategories.Add(new ProductCategory() { Category = categoryMusic, DisplayOrder = 1 }); + #region pictures //pictures @@ -7837,19 +8058,22 @@ public IList Products() #endregion SpecificationAttributes #endregion Beethoven für Elise + #endregion Instant Download Music #region watches + var categoryWatches = this._ctx.Set().First(c => c.Alias == "Watches"); + #region productWatchesCertinaDSPodiumBigSize var productWatchesCertinaDSPodiumBigSize = new Product() { ProductType = ProductType.SimpleProduct, VisibleIndividually = true, - Name = "Certina DS Podium Big Size ", + Name = "Certina DS Podium Big Size", ShortDescription = "C001.617.26.037.00", - FullDescription = "

The iPhone 5 at a glance. New design.

With 7.6 mm and 112 g3 the iPhone 5 has a remarkably thin and light design. It is made of anodized aluminum. The beveled edges are precision cut with a diamond.
Brilliant 4 \"Retina Display.
Now you can see everything more vivid and detailed. And although the screen is bigger, it has the same width as the iPhone 4S and is therefore just as easily operated with one hand. Powerful A6 chip. Compared with the A5 chip, he has up to twice the CPU and graphics performance. And despite its speed, the iPhone 5 has a fantastic battery life. Ultra-fast mobile data. The iPhone 5 supports the latest wireless technologies and can be even more so with the world verbinden.4Und networks and Wi-Fi is faster.

Delivery 6 Apple iPhone 5 with iOS EarPods with Remote and Mic to USB Cable Lightning USB Power Adapter (Power Supply) Choose the iPhone that suits you. 16 GB, 32 GB or 64 GB capacity? The iPhone is available in three capacities: 16, 32 and 64 GB. \"GB\" stands for gigabytes. The more gigabytes your iPhone, the more space you have. For content such as apps, games, photos, HD videos, music, movies and more In a large music or photo library, or if you frequently invite HD movies to an iPhone recommends using a larger capacity. If your music or photo library is small or you do or buy rare films, ranging from an iPhone with a smaller memory size for you. With time comes along Some of content on your iPhone. Therefore, you should consider your growing storage needs of the iPhone purchase. The unlocked iPhone The unlocked iPhone is not dependent on any cellular network, which means that you can decide for any supported GSM network worldwide. Buy an iPhone without a contract at the Apple Online Store, then look for a tariff for the iPhone, which covers only the SIM card. Or contact your current provider if you want to keep your current rate.

PrePaid
If you want a contract, you can choose one of the \"prepaid\" starter packs of available network operators in the Apple Online Store. With \"prepaid\" you get your iPhone and ready. Compatible with a SIM card A credit check is not required. You pay online just for what you use, and can switch the network provider at any time. \"Prepaid\" is a good option if you want to use when traveling abroad prefer a local supplier. Which SIM card do I need? It does not matter if you are a new contract, further Lead your existing contract or \"prepaid\" choose - you will need a compatible SIM card. For the iPhone 5, it takes a nano-SIM card for the iPhone 4S and the iPhone 4 is a micro-SIM card. For more details you get with your wireless carrier. Cellular networks and Wi-Fi

A1428 GSM model: UMTS / HSPA + / DC-HSDPA (850, 900, 1900, 2100 MHz) GSM / EDGE (850, 900, 1800, 1900 MHz), LTE (Band 4 and 17)
Model A1429 * CDMA: CDMA EV-DO Rev. A and Rev. B (800, 1900, 2100 MHz), UMTS / HSPA + / DC-HSDPA (850, 900, 1900, 2100 MHz) GSM / EDGE (850, 900 , 1800, 1900 MHz), LTE band (1, 3, 5, 13, 25)
* A1429 GSM model: UMTS / HSPA + / DC-HSDPA (850, 900, 1900, 2100 MHz) GSM / EDGE (850, 900, 1800, 1900 MHz), LTE (Volume 1, 3, 5)
802.11a/b/g/n Wi-Fi (802.11n 2.4 GHz and 5 GHz)
Bluetooth 4.0
Display Retina Display 4 \"widescreen Multi-Touch display (10.16 cm diagonal) 1136 x 640 pixels at 326 ppi Typical contrast ratio: 500 cd/m2 simultaneously resistant oleophobic coating on the front support for display of multiple languages ​​and characters: 800:1 Maximum brightness typical Camera, photos and videos 8-megapixel iSight camera Panorama Video recording, HD (1080p) up to 30 frames per second with audio FaceTime HD camera with 1.2-megapixel still images and HD video (720p) for up to 30 frames per second Autofocus Tap to focus video photos and facial recognition in video and photos LED flash Improved video stabilization for geotagging photos and videos Audio Support for AirPlay Mirroring to Apple TV with 720p AirPlay video streaming to Apple TV (3rd generation) up to 1080p and Apple TV (2nd generation) up to 720p Video formats supported: H.264 video up to 1080p, 30 frames per second, High Profile level 4.1 with AAC-LC audio up to 160 kbit / s, 48kHz, stereo audio in m4v, mp4 and mov... , MPEG-4 video, up to 2.5 Mbit / s, 640 x 480 pixels, 30 frames per second, Simple Profile with AAC-LC audio up to 160 Kbps m4v / s, 48 ​​kHz, stereo audio in. , mp4 and mov file formats Motion JPEG (M-JPEG)... up to 35 Mbit / s, 1280 x 720 pixels, 30 frames per second, audio in ulaw, PCM stereo audio in avi format

", + FullDescription = "

Since 1888, Certina has maintained an enviable reputation for its excellent watches and reliable movements. From the time of its integration into the SMH (today's Swatch Group) in the early 1980s, every Certina has been equipped with a high-quality ETA movement.

In a quartz watch movement, high-frequency oscillations are generated in a tiny synthetic crystal, then divided down electronically to provide the extreme accuracy of the Certina internal clock. A battery supplies the necessary energy.

The quartz movement is sometimes equipped with an end-of-life (EOL) indicator. When the seconds hand begins moving in four-second increments, the battery should be replaced within two weeks.

An automatic watch movement is driven by a rotor. Arm and wrist movements spin the rotor, which in turn winds the main spring. Energy is continuously produced, eliminating the need for a battery. The rate precision therefore depends on a rigorous manufacturing process and the original calibration, as well as the lifestyle of the user.

Most automatic movements are driven by an offset rotor. To earn the title of chronometer, a watch must be equipped with a movement that has obtained an official rate certificate from the COSC (Contrôle Officiel Suisse des Chronomètres). To obtain this, precision tests in different positions and at different temperatures must be carried out. These tests take place over a 15-day period. Thermocompensated means that the effective temperature inside the watch is measured and taken into account when improving precision. This allows fluctuations in the rate precision of a normal quartz watch due to temperature variations to be reduced by several seconds a week. The precision is 20 times more accurate than on a normal quartz watch, i.e. +/- 10 seconds per year (0.07 seconds/day).

", Sku = "P-1018", ProductTemplateId = productTemplateSimple.Id, AllowCustomerReviews = true, @@ -7869,12 +8093,14 @@ public IList Products() DeliveryTime = _ctx.Set().Where(sa => sa.DisplayOrder == 2).Single() }; + productWatchesCertinaDSPodiumBigSize.ProductCategories.Add(new ProductCategory() { Category = categoryWatches, DisplayOrder = 1 }); + #region pictures //pictures productWatchesCertinaDSPodiumBigSize.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "0001424-certina-ds-podium-big-size-herrenchronograph.jpg"), "image/jpeg", GetSeName(productWatchesCertinaDSPodiumBigSize.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_certina_ds_podium_big.png"), "image/png", GetSeName(productWatchesCertinaDSPodiumBigSize.Name)), DisplayOrder = 1, }); @@ -7972,7 +8198,7 @@ public IList Products() productPs3.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-ps3-black.jpg"), "image/jpeg", GetSeName(productPs3.Name) + "-black"), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_sony_ps3_black.png"), "image/png", GetSeName(productPs3.Name) + "-black"), DisplayOrder = 1 }); productPs3.ProductPictures.Add(new ProductPicture() @@ -8012,7 +8238,7 @@ public IList Products() productDualshock3Controller.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-Dualshock3WirelessCont.jpg"), "image/jpeg", GetSeName(productDualshock3Controller.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_playstation3dualshock3.png"), "image/png", GetSeName(productDualshock3Controller.Name)), DisplayOrder = 1 }); @@ -8087,7 +8313,7 @@ public IList Products() productBundlePs3AssassinCreed.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-PS3AssassinsCreedBundle.jpg"), "image/jpeg", GetSeName(productBundlePs3AssassinCreed.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-PS3AssassinsCreedBundle.png"), "image/png", GetSeName(productBundlePs3AssassinCreed.Name)), DisplayOrder = 1 }); @@ -8125,7 +8351,7 @@ public IList Products() productPs4.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-ps4.jpg"), "image/jpeg", GetSeName(productPs4.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_sony_ps4.png"), "image/png", GetSeName(productPs4.Name)), DisplayOrder = 1 }); @@ -8160,7 +8386,7 @@ public IList Products() productDualshock4Controller.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-Dualshock4WirelessCont.jpg"), "image/jpeg", GetSeName(productDualshock4Controller.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_sony_dualshock4_wirelesscontroller.png"), "image/png", GetSeName(productDualshock4Controller.Name)), DisplayOrder = 1 }); @@ -8195,7 +8421,7 @@ public IList Products() productPs4Camera.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-ps4-camera.jpg"), "image/jpeg", GetSeName(productPs4Camera.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_sony_ps4_camera.png"), "image/png", GetSeName(productPs4Camera.Name)), DisplayOrder = 1 }); @@ -8233,7 +8459,7 @@ public IList Products() productBundlePs4.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-ps4-bundle.jpg"), "image/jpeg", GetSeName(productBundlePs4.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_sony_ps4_bundle.png"), "image/png", GetSeName(productBundlePs4.Name)), DisplayOrder = 1 }); @@ -8271,7 +8497,7 @@ public IList Products() productGroupAccessories.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_gaming_accessories.jpg"), "image/jpeg", GetSeName(productGroupAccessories.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "category_gaming_accessories.png"), "image/png", GetSeName(productGroupAccessories.Name)), DisplayOrder = 1 }); @@ -8412,7 +8638,7 @@ public IList Products() productPs3OneGame.ProductPictures.Add(new ProductPicture() { - Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "sony-ps3-plus-game.jpg"), "image/jpeg", GetSeName(productPs3OneGame.Name)), + Picture = CreatePicture(File.ReadAllBytes(sampleImagesPath + "product_sony_ps3_plus_game.png"), "image/png", GetSeName(productPs3OneGame.Name)), DisplayOrder = 1 }); @@ -8420,12 +8646,11 @@ public IList Products() #endregion gaming - var entities = new List { product5GiftCard, product25GiftCard, product50GiftCard, productBooksUberMan, productBooksGefangeneDesHimmels, productBooksBestGrillingRecipes, productBooksCookingForTwo, productBooksAutosDerSuperlative, productBooksBildatlasMotorraeder, productBooksAutoBuch, productBooksFastCars, - productBooksMotorradAbenteuer, productComputerDellInspiron23, productComputerDellOptiplex3010,productSmartPhonesAppleIphone5, + productBooksMotorradAbenteuer, productComputerDellInspiron23, productComputerDellOptiplex3010,productSmartPhonesAppleIphone, productInstantDownloadVivaldi, productComputerAcerAspireOne, productInstantDownloadBeethoven, productWatchesCertinaDSPodiumBigSize, productPs3, productDualshock3Controller, productAssassinsCreed3, productBundlePs3AssassinCreed, productPs4, productDualshock4Controller, productPs4Camera, productBundlePs4, @@ -8682,6 +8907,43 @@ public IList DeliveryTimes() #endregion Deliverytimes + #region QuantityUnits + + public IList QuantityUnits() + { + var entities = new List() + { + new QuantityUnit + { + Name = "Piece", + Description = "Piece", + IsDefault = true, + DisplayOrder = 0, + }, + new QuantityUnit + { + Name = "Box", + Description = "Box", + DisplayOrder = 1, + }, + new QuantityUnit + { + Name = "Parcel", + Description = "Parcel", + DisplayOrder = 2, + }, + new QuantityUnit + { + Name = "Palette", + Description = "Palette", + DisplayOrder = 3, + }, + }; + this.Alter(entities); + return entities; + } + + #endregion #region BlogPost public IList BlogPosts() @@ -8724,11 +8986,11 @@ public IList NewsItems() { AllowComments = true, Language = defaultLanguage, - Title = "smartstore.net new release!", - Short = "smartstore.net includes everything you need to begin your e-commerce online store.", - Full = "

SmartStore.net includes everything you need to begin your e-commerce online store.
We have thought of everything and it's all included!

smartstore.net is a fully customizable shop-system. It's stable and highly usable.
From downloads to documentation, www.smartstore.com offers a comprehensive base of information, resources, and support to the smartstore.net community.

", + Title = "SmartStore.NET new release!", + Short = "SmartStore.NET includes everything you need to begin your e-commerce online store.", + Full = "

SmartStore.NET includes everything you need to begin your e-commerce online store.
We have thought of everything and it's all included!

From downloads to documentation, www.smartstore.com offers a comprehensive base of information, resources, and support to the SmartStore.NET community.

", Published = true, - MetaTitle = "smartstore.net new release!", + MetaTitle = "SmartStore.NET new release!", CreatedOnUtc = DateTime.Now }; var news2 = new NewsItem() @@ -8736,11 +8998,10 @@ public IList NewsItems() AllowComments = true, Language = defaultLanguage, Title = "New online store is open!", - Short = "The new smartstore.net store is open now! We are very excited to offer our new range of products. We will be constantly adding to our range so please register on our site, this will enable you to keep up to date with any new products.", + Short = "The new SmartStore.NET store is open now! We are very excited to offer our new range of products. We will be constantly adding to our range so please register on our site, this will enable you to keep up to date with any new products.", Full = "

Our online store is officially up and running. Stock up for the holiday season! We have a great selection of items. We will be constantly adding to our range so please register on our site, this will enable you to keep up to date with any new products.

All shipping is worldwide and will leave the same day an order is placed! Happy Shopping and spread the word!!

", Published = true, MetaTitle = "New online store is open!", - //CreatedOnUtc = DateTime.UtcNow.AddSeconds(1), CreatedOnUtc = DateTime.Now }; @@ -8943,6 +9204,10 @@ protected virtual void Alter(IList entities) { } + protected virtual void Alter(IList entities) + { + } + protected virtual void Alter(IList entities) { } diff --git a/src/Libraries/SmartStore.Data/Setup/TestDatabaseInitializer.cs b/src/Libraries/SmartStore.Data/Setup/TestDatabaseInitializer.cs deleted file mode 100644 index 26128ae48f..0000000000 --- a/src/Libraries/SmartStore.Data/Setup/TestDatabaseInitializer.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Migrations; -using System.Data.Entity.Migrations.Infrastructure; - -namespace SmartStore.Data.Tests -{ - public class TestDatabaseInitializer : IDatabaseInitializer - where TContext : DbContext, new() - where TConfig : DbMigrationsConfiguration, new() - { - private readonly string _connectionString; - - public TestDatabaseInitializer(string connectionString) - { - Guard.ArgumentNotEmpty(() => connectionString); - this._connectionString = connectionString; - } - - protected virtual TConfig CreateConfiguration() - { - var config = new TConfig(); - config.TargetDatabase = new DbConnectionInfo(_connectionString, "System.Data.SqlServerCe.4.0"); - return config; - } - - - public void InitializeDatabase(TContext context) - { - var config = this.CreateConfiguration(); - new DbMigrator(config).Update(); - } - } -} diff --git a/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs b/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs index 476f612085..f67db1a271 100644 --- a/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs +++ b/src/Libraries/SmartStore.Data/SmartDbConfiguration.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; using System.Data.Entity; +using System.Data.Entity.Core.Common; using System.Data.Entity.Infrastructure; using System.Data.Entity.Infrastructure.DependencyResolution; using System.Linq; +using EFCache; using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; using SmartStore.Data.Setup; +using SmartStore.Data.Caching; namespace SmartStore.Data { @@ -24,6 +28,26 @@ public SmartDbConfiguration() if (provider != null) { base.SetDefaultConnectionFactory(provider.GetConnectionFactory()); + + // prepare EntityFramework 2nd level cache + ICache cache = null; + try + { + var innerCache = EngineContext.Current.Resolve>(); + cache = new EfCacheImpl(innerCache(typeof(SmartStore.Core.Caching.StaticCache))); + } + catch + { + cache = new InMemoryCache(); + } + + var transactionHandler = new CacheTransactionHandler(cache); + AddInterceptor(transactionHandler); + + Loaded += + (sender, args) => args.ReplaceService( + (s, _) => new CachingProviderServices(s, transactionHandler, + new EfCachingPolicy())); } } } diff --git a/src/Libraries/SmartStore.Data/SmartObjectContext.cs b/src/Libraries/SmartStore.Data/SmartObjectContext.cs index 97a8982b71..bbe46338db 100644 --- a/src/Libraries/SmartStore.Data/SmartObjectContext.cs +++ b/src/Libraries/SmartStore.Data/SmartObjectContext.cs @@ -12,14 +12,12 @@ using SmartStore.Data.Setup; namespace SmartStore.Data -{ - +{ /// /// Object context /// public class SmartObjectContext : ObjectContextBase { - static SmartObjectContext() { var initializer = new MigrateDatabaseInitializer @@ -53,7 +51,7 @@ protected override void OnModelCreating(DbModelBuilder modelBuilder) // && type.BaseType != null // && type.BaseType.IsGenericType // && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)); - + var typesToRegister = from t in Assembly.GetExecutingAssembly().GetTypes() where t.Namespace.HasValue() && t.BaseType != null && diff --git a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj index 5a94befe6b..ff7fd39e2b 100644 --- a/src/Libraries/SmartStore.Data/SmartStore.Data.csproj +++ b/src/Libraries/SmartStore.Data/SmartStore.Data.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,7 +10,7 @@ Properties SmartStore.Data SmartStore.Data - v4.5 + v4.5.1 512 @@ -62,20 +62,24 @@ MinimumRecommendedRules.ruleset - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True + + + ..\..\packages\EntityFramework.Cache.1.0.0\lib\net45\EFCache.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False - ..\..\packages\EntityFramework.SqlServerCompact.6.1.0\lib\net45\EntityFramework.SqlServerCompact.dll + ..\..\packages\EntityFramework.SqlServerCompact.6.1.3\lib\net45\EntityFramework.SqlServerCompact.dll True @@ -89,9 +93,9 @@ True ..\..\packages\Microsoft.SqlServer.Scripting.11.0.2100.61\lib\Microsoft.SqlServer.Smo.dll - - False - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True @@ -115,6 +119,15 @@ Properties\AssemblyVersionInfo.cs + + + + + + + + + 201403112331027_Initial.cs @@ -171,6 +184,10 @@ 201406122329031_ContentDeliveryNetwork.cs + + + 201406262150229_Providers.cs + 201407191010096_BetterReturnRequest.cs @@ -179,6 +196,220 @@ 201408071158147_MultistorePoll.cs + + + 201408291450443_CheckoutCommmentBox.cs + + + + 201409150936394_CustomerNameFormat.cs + + + + 201410091620122_NewRes.cs + + + + 201411182201537_EuEsd.cs + + + + 201411182202431_V21Final.cs + + + + 201412081934318_V211.cs + + + + 201501191849483_WidgetWrapContent.cs + + + + 201501221417371_DefaultViewModeForCategories.cs + + + + 201502191643156_QtyUnitsAndOrderItemTaxRate.cs + + + + 201502202248081_NewIndexesV22.cs + + + + 201502280342294_LocalizedPropertyIndex.cs + + + + 201503032227054_V22Res.cs + + + + 201503101851123_PdfConverterUser.cs + + + + 201502120858030_Licensing.cs + + + + 201504131412183_NewCategoryProperties.cs + + + + 201504171629262_V22Final.cs + + + + 201504232202590_AutoUpdateRes.cs + + + + 201504270946381_TempFileCleanupTask.cs + + + + 201504290937512_SendEmailsManually.cs + + + + 201505052021483_PdfConverterRoleFix.cs + + + + 201505061813010_CountryMultistore.cs + + + + 201505272236124_V222.cs + + + + 201506181858349_AclRecordCustomerRole.cs + + + + 201506211043073_PaymentShippingRestrictions.cs + + + + 201506261018157_Merge.cs + + + + 201506261756463_PrimaryStoreCurrencyMultiStore.cs + + + + 201507132241575_QueuedEmailAttachments.cs + + + + 201507072138058_MessageTemplateAttachments.cs + + + + 201507092146153_DownloadGuidIndex.cs + + + + 201507102159496_TransientMedia.cs + + + + 201507141647299_CustomerTablePerf.cs + + + + 201507200832223_SortFilterHomepageProducts.cs + + + + 201507210952098_PaymentMethodDescription.cs + + + + 201507242008201_WebScheduler.cs + + + + 201507250039446_Merge2.cs + + + + 201508042207146_RemoveKeepAlive.cs + + + + 201508121735397_AddSyncMapping.cs + + + + 201508142203054_CronExpressions.cs + + + + 201509031112324_Merge3.cs + + + + 201508091512101_ExportFramework.cs + + + + 201508211346171_Merge1.cs + + + + 201509021536425_ExportFramework1.cs + + + + 201509150931528_ExportFramework2.cs + + + + 201511271019577_ExportFramework3.cs + + + + 201512151526290_ImportFramework.cs + + + + 201601262000441_ImportFramework1.cs + + + + 201603121451066_ThirdPartyEmailHandOver.cs + + + + 201605020640016_GtinMpnIndex.cs + + + + 201605061916117_SwapColumnMappingValues.cs + + + + 201605111140288_ImportExtraData.cs + + + + 201605191216116_CheckoutAttributeMultiStore.cs + + + + 201605201911421_ExportRevision.cs + + + + 201607111548571_FixExportDeploymentIsPublic.cs + + + @@ -187,7 +418,6 @@ - @@ -224,7 +454,6 @@ - @@ -362,12 +591,174 @@ 201406122329031_ContentDeliveryNetwork.cs + + 201406262150229_Providers.cs + 201407191010096_BetterReturnRequest.cs 201408071158147_MultistorePoll.cs + + 201408291450443_CheckoutCommmentBox.cs + + + 201409150936394_CustomerNameFormat.cs + + + 201410091620122_NewRes.cs + + + 201411182201537_EuEsd.cs + + + 201411182202431_V21Final.cs + + + 201412081934318_V211.cs + + + 201501191849483_WidgetWrapContent.cs + + + 201501221417371_DefaultViewModeForCategories.cs + + + 201502191643156_QtyUnitsAndOrderItemTaxRate.cs + + + 201502202248081_NewIndexesV22.cs + + + 201502280342294_LocalizedPropertyIndex.cs + + + 201503032227054_V22Res.cs + + + 201503101851123_PdfConverterUser.cs + + + 201502120858030_Licensing.cs + + + 201504131412183_NewCategoryProperties.cs + + + 201504171629262_V22Final.cs + + + 201504232202590_AutoUpdateRes.cs + + + 201504270946381_TempFileCleanupTask.cs + + + 201504290937512_SendEmailsManually.cs + + + 201505052021483_PdfConverterRoleFix.cs + + + 201505061813010_CountryMultistore.cs + + + 201505272236124_V222.cs + + + 201506181858349_AclRecordCustomerRole.cs + + + 201506211043073_PaymentShippingRestrictions.cs + + + 201506261018157_Merge.cs + + + 201506261756463_PrimaryStoreCurrencyMultiStore.cs + + + 201507132241575_QueuedEmailAttachments.cs + + + 201507072138058_MessageTemplateAttachments.cs + + + 201507092146153_DownloadGuidIndex.cs + + + 201507102159496_TransientMedia.cs + + + 201507141647299_CustomerTablePerf.cs + + + 201507200832223_SortFilterHomepageProducts.cs + + + 201507210952098_PaymentMethodDescription.cs + + + 201507242008201_WebScheduler.cs + + + 201507250039446_Merge2.cs + + + 201508042207146_RemoveKeepAlive.cs + + + 201508121735397_AddSyncMapping.cs + + + 201508142203054_CronExpressions.cs + + + 201509031112324_Merge3.cs + + + 201508091512101_ExportFramework.cs + + + 201508211346171_Merge1.cs + + + 201509021536425_ExportFramework1.cs + + + 201509150931528_ExportFramework2.cs + + + 201511271019577_ExportFramework3.cs + + + 201512151526290_ImportFramework.cs + + + 201601262000441_ImportFramework1.cs + + + 201603121451066_ThirdPartyEmailHandOver.cs + + + 201605020640016_GtinMpnIndex.cs + + + 201605061916117_SwapColumnMappingValues.cs + + + 201605111140288_ImportExtraData.cs + + + 201605191216116_CheckoutAttributeMultiStore.cs + + + 201605201911421_ExportRevision.cs + + + 201607111548571_FixExportDeploymentIsPublic.cs + @@ -383,6 +774,10 @@ + + + + diff --git a/src/Libraries/SmartStore.Data/Sql/LatestProductLoadAllPaged.sql b/src/Libraries/SmartStore.Data/Sql/LatestProductLoadAllPaged.sql new file mode 100644 index 0000000000..522b70dc27 --- /dev/null +++ b/src/Libraries/SmartStore.Data/Sql/LatestProductLoadAllPaged.sql @@ -0,0 +1,688 @@ +ALTER PROCEDURE [dbo].[ProductLoadAllPaged] +( + @CategoryIds nvarchar(MAX) = null, --a list of category IDs (comma-separated list). e.g. 1,2,3 + @ManufacturerId int = 0, + @StoreId int = 0, + @ParentGroupedProductId int = 0, + @ProductTypeId int = null, --product type identifier, null - load all products + @VisibleIndividuallyOnly bit = 0, --0 - load all products , 1 - "visible indivially" only + @ProductTagId int = 0, + @FeaturedProducts bit = null, --0 featured only , 1 not featured only, null - load all products + @PriceMin decimal(18, 4) = null, + @PriceMax decimal(18, 4) = null, + @Keywords nvarchar(4000) = null, + @SearchDescriptions bit = 0, --a value indicating whether to search by a specified "keyword" in product descriptions + @SearchSku bit = 0, --a value indicating whether to search by a specified "keyword" in product SKU + @SearchProductTags bit = 0, --a value indicating whether to search by a specified "keyword" in product tags + @UseFullTextSearch bit = 0, + @FullTextMode int = 0, --0 - using CONTAINS with , 5 - using CONTAINS and OR with , 10 - using CONTAINS and AND with + @FilteredSpecs nvarchar(MAX) = null, --filter by attributes (comma-separated list). e.g. 14,15,16 + @LanguageId int = 0, + @OrderBy int = 0, --0 - position, 5 - Name: A to Z, 6 - Name: Z to A, 10 - Price: Low to High, 11 - Price: High to Low, 15 - creation date + @AllowedCustomerRoleIds nvarchar(MAX) = null, --a list of customer role IDs (comma-separated list) for which a product should be shown (if a subjet to ACL) + @PageIndex int = 0, + @PageSize int = 2147483644, + @ShowHidden bit = 0, + @LoadFilterableSpecificationAttributeOptionIds bit = 0, --a value indicating whether we should load the specification attribute option identifiers applied to loaded products (all pages) + @WithoutCategories bit = null, + @WithoutManufacturers bit = null, + @IsPublished bit = null, + @HomePageProducts bit = null, + @IdMin int = 0, + @IdMax int = 0, + @AvailabilityMin int = null, + @AvailabilityMax int = null, + @CreatedFromUtc nvarchar(MAX) = null, + @CreatedToUtc nvarchar(MAX) = null, + @FilterableSpecificationAttributeOptionIds nvarchar(MAX) = null OUTPUT, --the specification attribute option identifiers applied to loaded products (all pages). returned as a comma separated list of identifiers + @TotalRecords int = null OUTPUT +) +AS +BEGIN + + /* Products that filtered by keywords */ + CREATE TABLE #KeywordProducts + ( + [ProductId] int NOT NULL + ) + + DECLARE + @SearchKeywords bit, + @sql nvarchar(max), + @sql_orderby nvarchar(max) + + SET NOCOUNT ON + + --filter by keywords + SET @Keywords = isnull(@Keywords, '') + SET @Keywords = rtrim(ltrim(@Keywords)) + IF ISNULL(@Keywords, '') != '' + BEGIN + SET @SearchKeywords = 1 + + IF @UseFullTextSearch = 1 + BEGIN + --remove wrong chars (' ") + SET @Keywords = REPLACE(@Keywords, '''', '') + SET @Keywords = REPLACE(@Keywords, '"', '') + + --full-text search + IF @FullTextMode = 0 + BEGIN + --0 - using CONTAINS with + SET @Keywords = ' "' + @Keywords + '*" ' + END + ELSE + BEGIN + --5 - using CONTAINS and OR with + --10 - using CONTAINS and AND with + + --clean multiple spaces + WHILE CHARINDEX(' ', @Keywords) > 0 + SET @Keywords = REPLACE(@Keywords, ' ', ' ') + + DECLARE @concat_term nvarchar(100) + IF @FullTextMode = 5 --5 - using CONTAINS and OR with + BEGIN + SET @concat_term = 'OR' + END + IF @FullTextMode = 10 --10 - using CONTAINS and AND with + BEGIN + SET @concat_term = 'AND' + END + + --now let's build search string + declare @fulltext_keywords nvarchar(4000) + set @fulltext_keywords = N'' + declare @index int + + set @index = CHARINDEX(' ', @Keywords, 0) + + -- if index = 0, then only one field was passed + IF(@index = 0) + set @fulltext_keywords = ' "' + @Keywords + '*" ' + ELSE + BEGIN + DECLARE @first BIT + SET @first = 1 + WHILE @index > 0 + BEGIN + IF (@first = 0) + SET @fulltext_keywords = @fulltext_keywords + ' ' + @concat_term + ' ' + ELSE + SET @first = 0 + + SET @fulltext_keywords = @fulltext_keywords + '"' + SUBSTRING(@Keywords, 1, @index - 1) + '*"' + SET @Keywords = SUBSTRING(@Keywords, @index + 1, LEN(@Keywords) - @index) + SET @index = CHARINDEX(' ', @Keywords, 0) + end + + -- add the last field + IF LEN(@fulltext_keywords) > 0 + SET @fulltext_keywords = @fulltext_keywords + ' ' + @concat_term + ' ' + '"' + SUBSTRING(@Keywords, 1, LEN(@Keywords)) + '*"' + END + SET @Keywords = @fulltext_keywords + END + END + ELSE + BEGIN + --usual search by PATINDEX + SET @Keywords = '%' + @Keywords + '%' + END + --PRINT @Keywords + + --product name + SET @sql = ' + INSERT INTO #KeywordProducts ([ProductId]) + SELECT p.Id + FROM Product p with (NOLOCK) + WHERE ' + IF @UseFullTextSearch = 1 + SET @sql = @sql + 'CONTAINS(p.[Name], @Keywords) ' + ELSE + SET @sql = @sql + 'PATINDEX(@Keywords, p.[Name]) > 0 ' + + + --localized product name + SET @sql = @sql + ' + UNION + SELECT lp.EntityId + FROM LocalizedProperty lp with (NOLOCK) + WHERE + lp.LocaleKeyGroup = N''Product'' + AND lp.LanguageId = ' + ISNULL(CAST(@LanguageId AS nvarchar(max)), '0') + ' + AND lp.LocaleKey = N''Name''' + IF @UseFullTextSearch = 1 + SET @sql = @sql + ' AND CONTAINS(lp.[LocaleValue], @Keywords) ' + ELSE + SET @sql = @sql + ' AND PATINDEX(@Keywords, lp.[LocaleValue]) > 0 ' + + + IF @SearchDescriptions = 1 + BEGIN + --product short description + SET @sql = @sql + ' + UNION + SELECT p.Id + FROM Product p with (NOLOCK) + WHERE ' + IF @UseFullTextSearch = 1 + SET @sql = @sql + 'CONTAINS(p.[ShortDescription], @Keywords) ' + ELSE + SET @sql = @sql + 'PATINDEX(@Keywords, p.[ShortDescription]) > 0 ' + + + --product full description + SET @sql = @sql + ' + UNION + SELECT p.Id + FROM Product p with (NOLOCK) + WHERE ' + IF @UseFullTextSearch = 1 + SET @sql = @sql + 'CONTAINS(p.[FullDescription], @Keywords) ' + ELSE + SET @sql = @sql + 'PATINDEX(@Keywords, p.[FullDescription]) > 0 ' + + + + --localized product short description + SET @sql = @sql + ' + UNION + SELECT lp.EntityId + FROM LocalizedProperty lp with (NOLOCK) + WHERE + lp.LocaleKeyGroup = N''Product'' + AND lp.LanguageId = ' + ISNULL(CAST(@LanguageId AS nvarchar(max)), '0') + ' + AND lp.LocaleKey = N''ShortDescription''' + IF @UseFullTextSearch = 1 + SET @sql = @sql + ' AND CONTAINS(lp.[LocaleValue], @Keywords) ' + ELSE + SET @sql = @sql + ' AND PATINDEX(@Keywords, lp.[LocaleValue]) > 0 ' + + + --localized product full description + SET @sql = @sql + ' + UNION + SELECT lp.EntityId + FROM LocalizedProperty lp with (NOLOCK) + WHERE + lp.LocaleKeyGroup = N''Product'' + AND lp.LanguageId = ' + ISNULL(CAST(@LanguageId AS nvarchar(max)), '0') + ' + AND lp.LocaleKey = N''FullDescription''' + IF @UseFullTextSearch = 1 + SET @sql = @sql + ' AND CONTAINS(lp.[LocaleValue], @Keywords) ' + ELSE + SET @sql = @sql + ' AND PATINDEX(@Keywords, lp.[LocaleValue]) > 0 ' + END + + --SKU + IF @SearchSku = 1 + BEGIN + SET @sql = @sql + ' + UNION + SELECT p.Id + FROM Product p with (NOLOCK) + LEFT OUTER JOIN ProductVariantAttributeCombination pvac with(NOLOCK) ON pvac.ProductId = p.Id + WHERE ' + IF @UseFullTextSearch = 1 + SET @sql = @sql + '(CONTAINS(pvac.[Sku], @Keywords) OR CONTAINS(p.[Sku], @Keywords)) ' + ELSE + SET @sql = @sql + 'PATINDEX(@Keywords, pvac.[Sku]) > 0 OR PATINDEX(@Keywords, p.[Sku]) > 0 ' + END + + IF @SearchProductTags = 1 + BEGIN + --product tag + SET @sql = @sql + ' + UNION + SELECT pptm.Product_Id + FROM Product_ProductTag_Mapping pptm with(NOLOCK) INNER JOIN ProductTag pt with(NOLOCK) ON pt.Id = pptm.ProductTag_Id + WHERE ' + IF @UseFullTextSearch = 1 + SET @sql = @sql + 'CONTAINS(pt.[Name], @Keywords) ' + ELSE + SET @sql = @sql + 'PATINDEX(@Keywords, pt.[Name]) > 0 ' + + --localized product tag + SET @sql = @sql + ' + UNION + SELECT pptm.Product_Id + FROM LocalizedProperty lp with (NOLOCK) INNER JOIN Product_ProductTag_Mapping pptm with(NOLOCK) ON lp.EntityId = pptm.ProductTag_Id + WHERE + lp.LocaleKeyGroup = N''ProductTag'' + AND lp.LanguageId = ' + ISNULL(CAST(@LanguageId AS nvarchar(max)), '0') + ' + AND lp.LocaleKey = N''Name''' + IF @UseFullTextSearch = 1 + SET @sql = @sql + ' AND CONTAINS(lp.[LocaleValue], @Keywords) ' + ELSE + SET @sql = @sql + ' AND PATINDEX(@Keywords, lp.[LocaleValue]) > 0 ' + END + + --PRINT (@sql) + EXEC sp_executesql @sql, N'@Keywords nvarchar(4000)', @Keywords + + END + ELSE + BEGIN + SET @SearchKeywords = 0 + END + + --filter by category IDs + SET @CategoryIds = isnull(@CategoryIds, '') + CREATE TABLE #FilteredCategoryIds + ( + CategoryId int not null + ) + INSERT INTO #FilteredCategoryIds (CategoryId) + SELECT CAST(data as int) FROM [sm_splitstring_to_table](@CategoryIds, ',') + DECLARE @CategoryIdsCount int + SET @CategoryIdsCount = (SELECT COUNT(1) FROM #FilteredCategoryIds) + + --filter by attributes + SET @FilteredSpecs = isnull(@FilteredSpecs, '') + CREATE TABLE #FilteredSpecs + ( + SpecificationAttributeOptionId int not null + ) + INSERT INTO #FilteredSpecs (SpecificationAttributeOptionId) + SELECT CAST(data as int) FROM [sm_splitstring_to_table](@FilteredSpecs, ',') + DECLARE @SpecAttributesCount int + SET @SpecAttributesCount = (SELECT COUNT(1) FROM #FilteredSpecs) + + --filter by customer role IDs (access control list) + SET @AllowedCustomerRoleIds = isnull(@AllowedCustomerRoleIds, '') + CREATE TABLE #FilteredCustomerRoleIds + ( + CustomerRoleId int not null + ) + INSERT INTO #FilteredCustomerRoleIds (CustomerRoleId) + SELECT CAST(data as int) FROM [sm_splitstring_to_table](@AllowedCustomerRoleIds, ',') + + --paging + DECLARE @PageLowerBound int + DECLARE @PageUpperBound int + DECLARE @RowsToReturn int + SET @RowsToReturn = @PageSize * (@PageIndex + 1) + SET @PageLowerBound = @PageSize * @PageIndex + SET @PageUpperBound = @PageLowerBound + @PageSize + 1 + + CREATE TABLE #DisplayOrderTmp + ( + [Id] int IDENTITY (1, 1) NOT NULL, + [ProductId] int NOT NULL + ) + + SET @sql = ' + INSERT INTO #DisplayOrderTmp ([ProductId]) + SELECT p.Id + FROM + Product p with (NOLOCK)' + + IF @CategoryIdsCount > 0 + BEGIN + SET @sql = @sql + ' + LEFT JOIN Product_Category_Mapping pcm with (NOLOCK) + ON p.Id = pcm.ProductId' + END + + IF @ManufacturerId > 0 + BEGIN + SET @sql = @sql + ' + LEFT JOIN Product_Manufacturer_Mapping pmm with (NOLOCK) + ON p.Id = pmm.ProductId' + END + + IF ISNULL(@ProductTagId, 0) != 0 + BEGIN + SET @sql = @sql + ' + LEFT JOIN Product_ProductTag_Mapping pptm with (NOLOCK) + ON p.Id = pptm.Product_Id' + END + + --searching by keywords + IF @SearchKeywords = 1 + BEGIN + SET @sql = @sql + ' + JOIN #KeywordProducts kp + ON p.Id = kp.ProductId' + END + + SET @sql = @sql + ' + WHERE + p.Deleted = 0' + + --filter by category + IF @CategoryIdsCount > 0 + BEGIN + SET @sql = @sql + ' + AND pcm.CategoryId IN (SELECT CategoryId FROM #FilteredCategoryIds)' + + IF @FeaturedProducts IS NOT NULL + BEGIN + SET @sql = @sql + ' + AND pcm.IsFeaturedProduct = ' + CAST(@FeaturedProducts AS nvarchar(max)) + END + END + + --filter by manufacturer + IF @ManufacturerId > 0 + BEGIN + SET @sql = @sql + ' + AND pmm.ManufacturerId = ' + CAST(@ManufacturerId AS nvarchar(max)) + + IF @FeaturedProducts IS NOT NULL + BEGIN + SET @sql = @sql + ' + AND pmm.IsFeaturedProduct = ' + CAST(@FeaturedProducts AS nvarchar(max)) + END + END + + --filter by parent grouped product identifer + IF @ParentGroupedProductId > 0 + BEGIN + SET @sql = @sql + ' + AND p.ParentGroupedProductId = ' + CAST(@ParentGroupedProductId AS nvarchar(max)) + END + + --filter by product type + IF @ProductTypeId is not null + BEGIN + SET @sql = @sql + ' + AND p.ProductTypeId = ' + CAST(@ProductTypeId AS nvarchar(max)) + END + + --filter by visible individually + IF @VisibleIndividuallyOnly = 1 + BEGIN + SET @sql = @sql + ' + AND p.VisibleIndividually = 1' + END + + --filter by product tag + IF ISNULL(@ProductTagId, 0) != 0 + BEGIN + SET @sql = @sql + ' + AND pptm.ProductTag_Id = ' + CAST(@ProductTagId AS nvarchar(max)) + END + + --homepage products + IF (@HomePageProducts is not null) + BEGIN + SET @sql = @sql + ' + AND p.ShowOnHomePage = ' + CAST(@HomePageProducts AS nvarchar(max)) + END + + --is published + IF (@IsPublished is null) + BEGIN + IF @ShowHidden = 0 + BEGIN + SET @sql = @sql + ' + AND p.Published = 1' + END + END + ELSE IF (@IsPublished = 1) + BEGIN + SET @sql = @sql + ' + AND p.Published = 1' + END + ELSE IF (@IsPublished = 0) + BEGIN + SET @sql = @sql + ' + AND p.Published = 0' + END + + --show hidden + IF @ShowHidden = 0 + BEGIN + SET @sql = @sql + ' + AND p.Deleted = 0 + AND (getutcdate() BETWEEN ISNULL(p.AvailableStartDateTimeUtc, ''1/1/1900'') and ISNULL(p.AvailableEndDateTimeUtc, ''1/1/2999''))' + END + + --min price + IF @PriceMin > 0 + BEGIN + SET @sql = @sql + ' + AND ( + ( + --special price (specified price and valid date range) + (p.SpecialPrice IS NOT NULL AND (getutcdate() BETWEEN isnull(p.SpecialPriceStartDateTimeUtc, ''1/1/1900'') AND isnull(p.SpecialPriceEndDateTimeUtc, ''1/1/2999''))) + AND + (p.SpecialPrice >= ' + CAST(@PriceMin AS nvarchar(max)) + ') + ) + OR + ( + --regular price (price isnt specified or date range isnt valid) + (p.SpecialPrice IS NULL OR (getutcdate() NOT BETWEEN isnull(p.SpecialPriceStartDateTimeUtc, ''1/1/1900'') AND isnull(p.SpecialPriceEndDateTimeUtc, ''1/1/2999''))) + AND + (p.Price >= ' + CAST(@PriceMin AS nvarchar(max)) + ') + ) + )' + END + + --max price + IF @PriceMax > 0 + BEGIN + SET @sql = @sql + ' + AND ( + ( + --special price (specified price and valid date range) + (p.SpecialPrice IS NOT NULL AND (getutcdate() BETWEEN isnull(p.SpecialPriceStartDateTimeUtc, ''1/1/1900'') AND isnull(p.SpecialPriceEndDateTimeUtc, ''1/1/2999''))) + AND + (p.SpecialPrice <= ' + CAST(@PriceMax AS nvarchar(max)) + ') + ) + OR + ( + --regular price (price isnt specified or date range isnt valid) + (p.SpecialPrice IS NULL OR (getutcdate() NOT BETWEEN isnull(p.SpecialPriceStartDateTimeUtc, ''1/1/1900'') AND isnull(p.SpecialPriceEndDateTimeUtc, ''1/1/2999''))) + AND + (p.Price <= ' + CAST(@PriceMax AS nvarchar(max)) + ') + ) + )' + END + + --show hidden and ACL + IF @ShowHidden = 0 + BEGIN + SET @sql = @sql + ' + AND (p.SubjectToAcl = 0 OR EXISTS ( + SELECT 1 FROM #FilteredCustomerRoleIds [fcr] + WHERE + [fcr].CustomerRoleId IN ( + SELECT [acl].CustomerRoleId + FROM [AclRecord] acl with (NOLOCK) + WHERE [acl].EntityId = p.Id AND [acl].EntityName = ''Product'' + ) + ))' + END + + --show hidden and filter by store + IF @StoreId > 0 + BEGIN + SET @sql = @sql + ' + AND (p.LimitedToStores = 0 OR EXISTS ( + SELECT 1 FROM [StoreMapping] sm with (NOLOCK) + WHERE [sm].EntityId = p.Id AND [sm].EntityName = ''Product'' and [sm].StoreId=' + CAST(@StoreId AS nvarchar(max)) + ' + ))' + END + + --filter by product identifier + IF @IdMin != 0 + BEGIN + SET @sql = @sql + ' + AND p.Id >= ' + CAST(@IdMin AS nvarchar(max)) + END + + IF @IdMax != 0 + BEGIN + SET @sql = @sql + ' + AND p.Id <= ' + CAST(@IdMax AS nvarchar(max)) + END + + --filter by availability + IF @AvailabilityMin is not null + BEGIN + SET @sql = @sql + ' + AND p.StockQuantity >= ' + CAST(@AvailabilityMin AS nvarchar(max)) + END + + IF @AvailabilityMax is not null + BEGIN + SET @sql = @sql + ' + AND p.StockQuantity <= ' + CAST(@AvailabilityMax AS nvarchar(max)) + END + + --filter by creation date + IF @CreatedFromUtc is not null + BEGIN + SET @sql = @sql + ' + AND p.CreatedOnUtc >= ''' + CAST(@CreatedFromUtc AS nvarchar(max)) + '''' + END + + IF @CreatedToUtc is not null + BEGIN + SET @sql = @sql + ' + AND p.CreatedOnUtc <= ''' + CAST(@CreatedToUtc AS nvarchar(max)) + '''' + END + + --filter by specs + IF @SpecAttributesCount > 0 + BEGIN + SET @sql = @sql + ' + AND NOT EXISTS ( + SELECT 1 FROM #FilteredSpecs [fs] + WHERE + [fs].SpecificationAttributeOptionId NOT IN ( + SELECT psam.SpecificationAttributeOptionId + FROM Product_SpecificationAttribute_Mapping psam with (NOLOCK) + WHERE psam.AllowFiltering = 1 AND psam.ProductId = p.Id + ) + )' + END + + IF (@WithoutCategories is not null) + BEGIN + IF (@WithoutCategories = 1) + BEGIN + SET @sql = @sql + ' + AND NOT EXISTS (SELECT 1 FROM [Product_Category_Mapping] pcm with (NOLOCK) WHERE [pcm].[ProductId] = p.Id)' + END + ELSE IF (@WithoutCategories = 0) + BEGIN + SET @sql = @sql + ' + AND EXISTS (SELECT 1 FROM [Product_Category_Mapping] pcm with (NOLOCK) WHERE [pcm].[ProductId] = p.Id)' + END + END + + IF (@WithoutManufacturers is not null) + BEGIN + IF (@WithoutManufacturers = 1) + BEGIN + SET @sql = @sql + ' + AND NOT EXISTS (SELECT 1 FROM [Product_Manufacturer_Mapping] pmm with (NOLOCK) WHERE [pmm].[ProductId] = p.Id)' + END + ELSE IF (@WithoutManufacturers = 0) + BEGIN + SET @sql = @sql + ' + AND EXISTS (SELECT 1 FROM [Product_Manufacturer_Mapping] pmm with (NOLOCK) WHERE [pmm].[ProductId] = p.Id)' + END + END + + --sorting + SET @sql_orderby = '' + IF @OrderBy = 5 /* Name: A to Z */ + SET @sql_orderby = ' p.[Name] ASC' + ELSE IF @OrderBy = 6 /* Name: Z to A */ + SET @sql_orderby = ' p.[Name] DESC' + ELSE IF @OrderBy = 10 /* Price: Low to High */ + SET @sql_orderby = ' p.[Price] ASC' + ELSE IF @OrderBy = 11 /* Price: High to Low */ + SET @sql_orderby = ' p.[Price] DESC' + ELSE IF @OrderBy = 15 /* creation date */ + SET @sql_orderby = ' p.[CreatedOnUtc] DESC' + ELSE /* default sorting, 0 (position) */ + BEGIN + --category position (display order) + IF @CategoryIdsCount > 0 SET @sql_orderby = ' pcm.DisplayOrder ASC' + + --manufacturer position (display order) + IF @ManufacturerId > 0 + BEGIN + IF LEN(@sql_orderby) > 0 SET @sql_orderby = @sql_orderby + ', ' + SET @sql_orderby = @sql_orderby + ' pmm.DisplayOrder ASC' + END + + --parent grouped product specified (sort associated products) + IF @ParentGroupedProductId > 0 + BEGIN + IF LEN(@sql_orderby) > 0 SET @sql_orderby = @sql_orderby + ', ' + SET @sql_orderby = @sql_orderby + ' p.[DisplayOrder] ASC' + END + + --name + IF LEN(@sql_orderby) > 0 SET @sql_orderby = @sql_orderby + ', ' + SET @sql_orderby = @sql_orderby + ' p.[Name] ASC' + END + + SET @sql = @sql + ' + ORDER BY' + @sql_orderby + + --PRINT (@sql) + EXEC sp_executesql @sql + + DROP TABLE #FilteredCategoryIds + DROP TABLE #FilteredSpecs + DROP TABLE #FilteredCustomerRoleIds + DROP TABLE #KeywordProducts + + CREATE TABLE #PageIndex + ( + [IndexId] int IDENTITY (1, 1) NOT NULL, + [ProductId] int NOT NULL + ) + INSERT INTO #PageIndex ([ProductId]) + SELECT ProductId + FROM #DisplayOrderTmp + GROUP BY ProductId + ORDER BY min([Id]) + + --total records + SET @TotalRecords = @@rowcount + + DROP TABLE #DisplayOrderTmp + + --prepare filterable specification attribute option identifier (if requested) + IF @LoadFilterableSpecificationAttributeOptionIds = 1 + BEGIN + CREATE TABLE #FilterableSpecs + ( + [SpecificationAttributeOptionId] int NOT NULL + ) + INSERT INTO #FilterableSpecs ([SpecificationAttributeOptionId]) + SELECT DISTINCT [psam].SpecificationAttributeOptionId + FROM [Product_SpecificationAttribute_Mapping] [psam] with (NOLOCK) + WHERE [psam].[AllowFiltering] = 1 + AND [psam].[ProductId] IN (SELECT [pi].ProductId FROM #PageIndex [pi]) + + --build comma separated list of filterable identifiers + SELECT @FilterableSpecificationAttributeOptionIds = COALESCE(@FilterableSpecificationAttributeOptionIds + ',' , '') + CAST(SpecificationAttributeOptionId as nvarchar(4000)) + FROM #FilterableSpecs + + DROP TABLE #FilterableSpecs + END + + --return products + SELECT TOP (@RowsToReturn) + p.* + FROM + #PageIndex [pi] + INNER JOIN Product p with (NOLOCK) on p.Id = [pi].[ProductId] + WHERE + [pi].IndexId > @PageLowerBound AND + [pi].IndexId < @PageUpperBound + ORDER BY + [pi].IndexId + + DROP TABLE #PageIndex +END diff --git a/src/Libraries/SmartStore.Data/Sql/StoredProcedures.Inverse.sql b/src/Libraries/SmartStore.Data/Sql/StoredProcedures.Inverse.sql index 9f0c19521a..fb7180e930 100644 --- a/src/Libraries/SmartStore.Data/Sql/StoredProcedures.Inverse.sql +++ b/src/Libraries/SmartStore.Data/Sql/StoredProcedures.Inverse.sql @@ -1,16 +1,16 @@ -DROP PROCEDURE [ProductLoadAllPaged] +DROP PROCEDURE [dbo].[ProductLoadAllPaged] GO DROP PROCEDURE [dbo].[ProductTagCountLoadAll] GO -DROP PROCEDURE [FullText_IsSupported] +DROP PROCEDURE [dbo].[FullText_IsSupported] GO -DROP PROCEDURE [FullText_Enable] +DROP PROCEDURE [dbo].[FullText_Enable] GO -DROP PROCEDURE [FullText_Disable] +DROP PROCEDURE [dbo].[FullText_Disable] GO diff --git a/src/Libraries/SmartStore.Data/Sql/StoredProcedures.sql b/src/Libraries/SmartStore.Data/Sql/StoredProcedures.sql index ae558f429a..4f93be5a39 100644 --- a/src/Libraries/SmartStore.Data/Sql/StoredProcedures.sql +++ b/src/Libraries/SmartStore.Data/Sql/StoredProcedures.sql @@ -63,7 +63,7 @@ END GO -CREATE PROCEDURE [ProductLoadAllPaged] +CREATE PROCEDURE [dbo].[ProductLoadAllPaged] ( @CategoryIds nvarchar(MAX) = null, --a list of category IDs (comma-separated list). e.g. 1,2,3 @ManufacturerId int = 0, @@ -676,7 +676,7 @@ END GO -CREATE PROCEDURE [FullText_IsSupported] +CREATE PROCEDURE [dbo].[FullText_IsSupported] AS BEGIN EXEC(' @@ -693,7 +693,7 @@ GO -CREATE PROCEDURE [FullText_Enable] +CREATE PROCEDURE [dbo].[FullText_Enable] AS BEGIN --create catalog @@ -731,7 +731,7 @@ GO -CREATE PROCEDURE [FullText_Disable] +CREATE PROCEDURE [dbo].[FullText_Disable] AS BEGIN EXEC(' diff --git a/src/Libraries/SmartStore.Data/app.config b/src/Libraries/SmartStore.Data/app.config index 28f3c10058..284b7ee573 100644 --- a/src/Libraries/SmartStore.Data/app.config +++ b/src/Libraries/SmartStore.Data/app.config @@ -4,8 +4,12 @@ - + + + + + - \ No newline at end of file + diff --git a/src/Libraries/SmartStore.Data/packages.config b/src/Libraries/SmartStore.Data/packages.config index 57fe8e8337..b1c169951c 100644 --- a/src/Libraries/SmartStore.Data/packages.config +++ b/src/Libraries/SmartStore.Data/packages.config @@ -1,9 +1,10 @@  - - - + + + + - + \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Authentication/External/AuthorizeState.cs b/src/Libraries/SmartStore.Services/Authentication/External/AuthorizeState.cs index dcc6c9762c..35e853bbfc 100644 --- a/src/Libraries/SmartStore.Services/Authentication/External/AuthorizeState.cs +++ b/src/Libraries/SmartStore.Services/Authentication/External/AuthorizeState.cs @@ -17,7 +17,7 @@ public AuthorizeState(string returnUrl, OpenAuthenticationStatus openAuthenticat _returnUrl = returnUrl; AuthenticationStatus = openAuthenticationStatus; - //in way SEO friendly language URLs will be persisted + // in a way SEO friendly language URLs will be persisted if (AuthenticationStatus == OpenAuthenticationStatus.Authenticated) Result = new RedirectResult(!string.IsNullOrEmpty(_returnUrl) ? _returnUrl : "~/"); } diff --git a/src/Libraries/SmartStore.Services/Authentication/External/IExternalAuthenticationMethod.cs b/src/Libraries/SmartStore.Services/Authentication/External/IExternalAuthenticationMethod.cs index 7f965a28f8..6e8029ce4a 100644 --- a/src/Libraries/SmartStore.Services/Authentication/External/IExternalAuthenticationMethod.cs +++ b/src/Libraries/SmartStore.Services/Authentication/External/IExternalAuthenticationMethod.cs @@ -8,17 +8,8 @@ namespace SmartStore.Services.Authentication.External /// /// Provides an interface for creating external authentication methods /// - public partial interface IExternalAuthenticationMethod : IPlugin - { - /// - /// Gets a route for plugin configuration - /// - /// Action name - /// Controller name - /// Route values - void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); - - + public partial interface IExternalAuthenticationMethod : IProvider, IUserEditable + { /// /// Gets a route for displaying plugin in public store /// diff --git a/src/Libraries/SmartStore.Services/Authentication/External/IOpenAuthenticationService.cs b/src/Libraries/SmartStore.Services/Authentication/External/IOpenAuthenticationService.cs index 725d61d015..929adbb89a 100644 --- a/src/Libraries/SmartStore.Services/Authentication/External/IOpenAuthenticationService.cs +++ b/src/Libraries/SmartStore.Services/Authentication/External/IOpenAuthenticationService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Authentication.External { @@ -12,21 +13,21 @@ public partial interface IOpenAuthenticationService ///
/// Load records allows only in specified store; pass 0 to load all records /// Payment methods - IList LoadActiveExternalAuthenticationMethods(int storeId = 0); + IEnumerable> LoadActiveExternalAuthenticationMethods(int storeId = 0); /// /// Load external authentication method by system name /// /// System name /// Found external authentication method - IExternalAuthenticationMethod LoadExternalAuthenticationMethodBySystemName(string systemName); + Provider LoadExternalAuthenticationMethodBySystemName(string systemName, int storeId = 0); /// /// Load all external authentication methods /// /// Load records allows only in specified store; pass 0 to load all records /// External authentication methods - IList LoadAllExternalAuthenticationMethods(int storeId = 0); + IEnumerable> LoadAllExternalAuthenticationMethods(int storeId = 0); bool AccountExists(OpenAuthenticationParameters parameters); diff --git a/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthenticationService.cs b/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthenticationService.cs index c8329b84fa..aad91d8ff2 100644 --- a/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthenticationService.cs +++ b/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthenticationService.cs @@ -17,31 +17,47 @@ public partial class OpenAuthenticationService : IOpenAuthenticationService private readonly IPluginFinder _pluginFinder; private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; private readonly IRepository _externalAuthenticationRecordRepository; - private readonly ISettingService _settingService; // codehint: sm-add + private readonly ISettingService _settingService; + private readonly IProviderManager _providerManager; - public OpenAuthenticationService(IRepository externalAuthenticationRecordRepository, + public OpenAuthenticationService( + IRepository externalAuthenticationRecordRepository, IPluginFinder pluginFinder, ExternalAuthenticationSettings externalAuthenticationSettings, ICustomerService customerService, - ISettingService settingService) + ISettingService settingService, + IProviderManager providerManager) { this._externalAuthenticationRecordRepository = externalAuthenticationRecordRepository; this._pluginFinder = pluginFinder; this._externalAuthenticationSettings = externalAuthenticationSettings; this._customerService = customerService; - this._settingService = settingService; // codehint: sm-add + this._settingService = settingService; + this._providerManager = providerManager; } + /// + /// Load all external authentication methods + /// + /// Load records allows only in specified store; pass 0 to load all records + /// External authentication methods + public virtual IEnumerable> LoadAllExternalAuthenticationMethods(int storeId = 0) + { + return _providerManager.GetAllProviders(storeId); + } + /// /// Load active external authentication methods /// /// Load records allows only in specified store; pass 0 to load all records /// Payment methods - public virtual IList LoadActiveExternalAuthenticationMethods(int storeId = 0) + public virtual IEnumerable> LoadActiveExternalAuthenticationMethods(int storeId = 0) { - return LoadAllExternalAuthenticationMethods(storeId) - .Where(provider => _externalAuthenticationSettings.ActiveAuthenticationMethodSystemNames.Contains(provider.PluginDescriptor.SystemName, StringComparer.InvariantCultureIgnoreCase)) - .ToList(); + var allMethods = LoadAllExternalAuthenticationMethods(storeId); + var activeMethods = allMethods + .Where(p => _externalAuthenticationSettings.ActiveAuthenticationMethodSystemNames.Contains(p.Metadata.SystemName, StringComparer.InvariantCultureIgnoreCase)); + + return activeMethods; } /// @@ -49,26 +65,9 @@ public virtual IList LoadActiveExternalAuthentica /// /// System name /// Found external authentication method - public virtual IExternalAuthenticationMethod LoadExternalAuthenticationMethodBySystemName(string systemName) - { - var descriptor = _pluginFinder.GetPluginDescriptorBySystemName(systemName); - if (descriptor != null) - return descriptor.Instance(); - - return null; - } - - /// - /// Load all external authentication methods - /// - /// Load records allows only in specified store; pass 0 to load all records - /// External authentication methods - public virtual IList LoadAllExternalAuthenticationMethods(int storeId = 0) + public virtual Provider LoadExternalAuthenticationMethodBySystemName(string systemName, int storeId = 0) { - return _pluginFinder - .GetPlugins() - .Where(x => storeId == 0 || _settingService.GetSettingByKey(x.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) - .ToList(); + return _providerManager.GetProvider(systemName, storeId); } diff --git a/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthentificationExtentions.cs b/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthentificationExtentions.cs index bacd917bb7..1db598a637 100644 --- a/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthentificationExtentions.cs +++ b/src/Libraries/SmartStore.Services/Authentication/External/OpenAuthentificationExtentions.cs @@ -1,12 +1,13 @@ using System; +using System.Linq; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Authentication.External { public static class OpenAuthenticationExtentions { - public static bool IsMethodActive(this IExternalAuthenticationMethod method, - ExternalAuthenticationSettings settings) + public static bool IsMethodActive(this Provider method, ExternalAuthenticationSettings settings) { if (method == null) throw new ArgumentNullException("method"); @@ -16,10 +17,8 @@ public static bool IsMethodActive(this IExternalAuthenticationMethod method, if (settings.ActiveAuthenticationMethodSystemNames == null) return false; - foreach (string activeMethodSystemName in settings.ActiveAuthenticationMethodSystemNames) - if (method.PluginDescriptor.SystemName.Equals(activeMethodSystemName, StringComparison.InvariantCultureIgnoreCase)) - return true; - return false; + + return settings.ActiveAuthenticationMethodSystemNames.Contains(method.Metadata.SystemName, StringComparer.OrdinalIgnoreCase); } } } diff --git a/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs b/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs index d13a5d60b5..05cddc7f7b 100644 --- a/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs +++ b/src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs @@ -1,6 +1,7 @@ using System; using System.Web; using System.Web.Security; +using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Services.Customers; @@ -11,7 +12,7 @@ namespace SmartStore.Services.Authentication ///
public partial class FormsAuthenticationService : IAuthenticationService { - private readonly HttpContextBase _httpContext; + private readonly HttpContextBase _httpContext; private readonly ICustomerService _customerService; private readonly CustomerSettings _customerSettings; private readonly TimeSpan _expirationTimeSpan; @@ -24,8 +25,7 @@ public partial class FormsAuthenticationService : IAuthenticationService /// HTTP context /// Customer service /// Customer settings - public FormsAuthenticationService(HttpContextBase httpContext, - ICustomerService customerService, CustomerSettings customerSettings) + public FormsAuthenticationService(HttpContextBase httpContext, ICustomerService customerService, CustomerSettings customerSettings) { this._httpContext = httpContext; this._customerService = customerService; @@ -33,7 +33,6 @@ public FormsAuthenticationService(HttpContextBase httpContext, this._expirationTimeSpan = FormsAuthentication.Timeout; } - public virtual void SignIn(Customer customer, bool createPersistentCookie) { var now = DateTime.UtcNow.ToLocalTime(); @@ -77,18 +76,42 @@ public virtual Customer GetAuthenticatedCustomer() if (_cachedCustomer != null) return _cachedCustomer; - if (_httpContext == null || - _httpContext.Request == null || - !_httpContext.Request.IsAuthenticated || - !(_httpContext.User.Identity is FormsIdentity)) - { + if (_httpContext == null || _httpContext.Request == null || !_httpContext.Request.IsAuthenticated || _httpContext.User == null) return null; - } - var formsIdentity = (FormsIdentity)_httpContext.User.Identity; - var customer = GetAuthenticatedCustomerFromTicket(formsIdentity.Ticket); - if (customer != null && customer.Active && !customer.Deleted && customer.IsRegistered()) - _cachedCustomer = customer; + Customer customer = null; + FormsIdentity formsIdentity = null; + SmartStoreIdentity smartNetIdentity = null; + + if ((formsIdentity = _httpContext.User.Identity as FormsIdentity) != null) + { + customer = GetAuthenticatedCustomerFromTicket(formsIdentity.Ticket); + } + else if ((smartNetIdentity = _httpContext.User.Identity as SmartStoreIdentity) != null) + { + customer = _customerService.GetCustomerById(smartNetIdentity.CustomerId); + } + + if (customer != null && customer.Active && !customer.Deleted && customer.IsRegistered()) + { + if (customer.LastLoginDateUtc == null) + { + try + { + // This is most probably the very first "login" after registering. Delete the + // ASP.NET anonymous id cookie so that a new guest account can be created + // upon signing out. + System.Web.Security.AnonymousIdentificationModule.ClearAnonymousIdentifier(); + } + finally + { + customer.LastLoginDateUtc = DateTime.UtcNow; + _customerService.UpdateCustomer(customer); + } + } + _cachedCustomer = customer; + } + return _cachedCustomer; } @@ -101,10 +124,12 @@ public virtual Customer GetAuthenticatedCustomerFromTicket(FormsAuthenticationTi if (String.IsNullOrWhiteSpace(usernameOrEmail)) return null; + var customer = _customerSettings.UsernamesEnabled ? _customerService.GetCustomerByUsername(usernameOrEmail) : _customerService.GetCustomerByEmail(usernameOrEmail); + return customer; } - } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs index 79a9d607e2..f3bb8103bb 100644 --- a/src/Libraries/SmartStore.Services/Blogs/BlogService.cs +++ b/src/Libraries/SmartStore.Services/Blogs/BlogService.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using System.Linq; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Blogs; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; +using SmartStore.Services.Localization; namespace SmartStore.Services.Blogs { @@ -15,13 +15,14 @@ namespace SmartStore.Services.Blogs ///
public partial class BlogService : IBlogService { - #region Fields private readonly IRepository _blogPostRepository; private readonly IRepository _storeMappingRepository; - private readonly ICacheManager _cacheManager; - private readonly IEventPublisher _eventPublisher; + private readonly ICommonServices _services; + private readonly ILanguageService _languageService; + + private readonly BlogSettings _blogSettings; #endregion @@ -29,13 +30,15 @@ public partial class BlogService : IBlogService public BlogService(IRepository blogPostRepository, IRepository storeMappingRepository, - ICacheManager cacheManager, - IEventPublisher eventPublisher) + ICommonServices services, + ILanguageService languageService, + BlogSettings blogSettings) { _blogPostRepository = blogPostRepository; _storeMappingRepository = storeMappingRepository; - _cacheManager = cacheManager; - _eventPublisher = eventPublisher; + _services = services; + _languageService = languageService; + _blogSettings = blogSettings; this.QuerySettings = DbQuerySettings.Default; } @@ -58,7 +61,7 @@ public virtual void DeleteBlogPost(BlogPost blogPost) _blogPostRepository.Delete(blogPost); //event notification - _eventPublisher.EntityDeleted(blogPost); + _services.EventPublisher.EntityDeleted(blogPost); } /// @@ -84,17 +87,25 @@ public virtual BlogPost GetBlogPostById(int blogPostId) /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned blog posts /// Blog posts public virtual IPagedList GetAllBlogPosts(int storeId, int languageId, - DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false) + DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null) { var query = _blogPostRepository.Table; + if (dateFrom.HasValue) query = query.Where(b => dateFrom.Value <= b.CreatedOnUtc); + if (dateTo.HasValue) query = query.Where(b => dateTo.Value >= b.CreatedOnUtc); + if (languageId > 0) query = query.Where(b => languageId == b.LanguageId); + + if (maxAge.HasValue) + query = query.Where(b => b.CreatedOnUtc >= maxAge.Value); + if (!showHidden) { var utcNow = DateTime.UtcNow; @@ -202,7 +213,7 @@ public virtual void InsertBlogPost(BlogPost blogPost) _blogPostRepository.Insert(blogPost); //event notification - _eventPublisher.EntityInserted(blogPost); + _services.EventPublisher.EntityInserted(blogPost); } /// @@ -217,7 +228,7 @@ public virtual void UpdateBlogPost(BlogPost blogPost) _blogPostRepository.Update(blogPost); //event notification - _eventPublisher.EntityUpdated(blogPost); + _services.EventPublisher.EntityUpdated(blogPost); } /// diff --git a/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs b/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs index eabf47a802..682ddbe191 100644 --- a/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs +++ b/src/Libraries/SmartStore.Services/Blogs/IBlogService.cs @@ -33,9 +33,10 @@ public partial interface IBlogService /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned blog posts /// Blog posts IPagedList GetAllBlogPosts(int storeId, int languageId, - DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false); + DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null); /// /// Gets all blog posts diff --git a/src/Libraries/SmartStore.Services/Catalog/AdjustInventoryResult.cs b/src/Libraries/SmartStore.Services/Catalog/AdjustInventoryResult.cs new file mode 100644 index 0000000000..91867ebe55 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Catalog/AdjustInventoryResult.cs @@ -0,0 +1,50 @@ + +namespace SmartStore.Services.Catalog +{ + public class AdjustInventoryResult + { + private int? _stockQuantityOld; + private int? _stockQuantityNew; + + /// + /// The stock quantity before adjustment + /// + public int StockQuantityOld + { + get + { + return _stockQuantityOld ?? 0; + } + set + { + _stockQuantityOld = value; + } + } + + /// + /// The stock quantity after adjustment + /// + public int StockQuantityNew + { + get + { + return _stockQuantityNew ?? 0; + } + set + { + _stockQuantityNew = value; + } + } + + /// + /// Determines whether the adjustment resulted in a clear, unique stock quantity update. For instance false for bundle products. + /// + public bool HasClearStockQuantityResult + { + get + { + return _stockQuantityOld.HasValue && _stockQuantityNew.HasValue; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/Catalog/CategoryExtensions.cs b/src/Libraries/SmartStore.Services/Catalog/CategoryExtensions.cs index 939501292a..39825192a6 100644 --- a/src/Libraries/SmartStore.Services/Catalog/CategoryExtensions.cs +++ b/src/Libraries/SmartStore.Services/Catalog/CategoryExtensions.cs @@ -47,17 +47,17 @@ public static IList SortCategoriesForTree(this IList source, /// Product identifier /// Category identifier /// A ProductCategory that has the specified values; otherwise null - public static ProductCategory FindProductCategory(this IList source, - int productId, int categoryId) + public static ProductCategory FindProductCategory(this IList source, int productId, int categoryId) { - foreach (var productCategory in source) - if (productCategory.ProductId == productId && productCategory.CategoryId == categoryId) - return productCategory; - + foreach (var productCategory in source) + { + if (productCategory.ProductId == productId && productCategory.CategoryId == categoryId) + return productCategory; + } return null; } - public static string GetFullCategoryName(this Category category) + public static string GetCategoryNameWithAlias(this Category category) { if (category != null) { @@ -77,7 +77,7 @@ public static string GetCategoryNameWithPrefix(this Category category, ICategory { if (String.IsNullOrEmpty(result)) { - result = category.GetFullCategoryName(); + result = category.GetCategoryNameWithAlias(); } else { @@ -103,14 +103,13 @@ public static string GetCategoryBreadCrumb(this Category category, ICategoryServ while (category != null && !category.Deleted) { - // codehint: sm-edit if (String.IsNullOrEmpty(result)) { - result = category.GetFullCategoryName(); + result = category.GetCategoryNameWithAlias(); } else { - result = category.GetFullCategoryName() + " >> " + result; + result = category.GetCategoryNameWithAlias() + " >> " + result; } int parentId = category.ParentCategoryId; diff --git a/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs b/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs index 1c9b264638..86d8e52b2a 100644 --- a/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/CategoryService.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; @@ -9,6 +9,7 @@ using SmartStore.Core.Domain.Security; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; +using SmartStore.Services.Customers; using SmartStore.Services.Localization; using SmartStore.Services.Security; using SmartStore.Services.Stores; @@ -21,6 +22,7 @@ namespace SmartStore.Services.Catalog public partial class CategoryService : ICategoryService { #region Constants + private const string CATEGORIES_BY_PARENT_CATEGORY_ID_KEY = "SmartStore.category.byparent-{0}-{1}-{2}-{3}"; private const string PRODUCTCATEGORIES_ALLBYCATEGORYID_KEY = "SmartStore.productcategory.allbycategoryid-{0}-{1}-{2}-{3}-{4}-{5}"; private const string PRODUCTCATEGORIES_ALLBYPRODUCTID_KEY = "SmartStore.productcategory.allbyproductid-{0}-{1}-{2}-{3}"; @@ -44,7 +46,10 @@ public partial class CategoryService : ICategoryService private readonly IStoreMappingService _storeMappingService; private readonly IAclService _aclService; private readonly Lazy> _navigationFilters; - + private readonly ICustomerService _customerService; + private readonly IProductService _productService; + private readonly IStoreService _storeService; + #endregion #region Ctor @@ -72,7 +77,10 @@ public CategoryService(ICacheManager cacheManager, IEventPublisher eventPublisher, IStoreMappingService storeMappingService, IAclService aclService, - Lazy> navigationFilters) + Lazy> navigationFilters, + ICustomerService customerService, + IProductService productService, + IStoreService storeService) { this._cacheManager = cacheManager; this._categoryRepository = categoryRepository; @@ -86,6 +94,9 @@ public CategoryService(ICacheManager cacheManager, this._storeMappingService = storeMappingService; this._aclService = aclService; this._navigationFilters = navigationFilters; + this._customerService = customerService; + this._productService = productService; + this._storeService = storeService; this.QuerySettings = DbQuerySettings.Default; } @@ -109,13 +120,184 @@ private void DeleteAllCategories(IList categories, bool delete) var childCategories = GetAllCategoriesByParentCategoryId(category.Id, true); DeleteAllCategories(childCategories, delete); - } + } } #endregion #region Methods + public virtual void InheritAclIntoChildren(int categoryId, + bool touchProductsWithMultipleCategories = false, + bool touchExistingAcls = false, + bool categoriesOnly = false) + { + + var category = GetCategoryById(categoryId); + var subcategories = GetAllCategoriesByParentCategoryId(categoryId, true); + var context = new ProductSearchContext { PageSize = int.MaxValue, ShowHidden = true }; + context.CategoryIds.AddRange(subcategories.Select(x => x.Id)); + context.CategoryIds.Add(categoryId); + var products = _productService.SearchProducts(context); + var allCustomerRoles = _customerService.GetAllCustomerRoles(true); + var categoryCustomerRoles = _aclService.GetCustomerRoleIdsWithAccess(category); + + using (var scope = new DbContextScope(ctx: _aclRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) + { + _aclRepository.AutoCommitEnabled = false; + + foreach (var subcategory in subcategories) + { + if (subcategory.SubjectToAcl != category.SubjectToAcl) + { + subcategory.SubjectToAcl = category.SubjectToAcl; + _categoryRepository.Update(subcategory); + } + + var existingAclRecords = _aclService.GetAclRecords(subcategory).ToDictionarySafe(x => x.CustomerRoleId); + + foreach (var customerRole in allCustomerRoles) + { + if (categoryCustomerRoles.Contains(customerRole.Id)) + { + if (!existingAclRecords.ContainsKey(customerRole.Id)) + { + _aclRepository.Insert(new AclRecord { CustomerRole = customerRole, CustomerRoleId = customerRole.Id, EntityId = subcategory.Id, EntityName = "Category" }); + } + } + else + { + AclRecord aclRecordToDelete; + if (existingAclRecords.TryGetValue(customerRole.Id, out aclRecordToDelete)) + { + _aclRepository.Delete(aclRecordToDelete); + } + } + } + } + + _aclRepository.Context.SaveChanges(); + + foreach (var product in products) + { + if (product.SubjectToAcl != category.SubjectToAcl) + { + product.SubjectToAcl = category.SubjectToAcl; + _productRepository.Update(product); + } + + var existingAclRecords = _aclService.GetAclRecords(product).ToDictionarySafe(x => x.CustomerRoleId); + + foreach (var customerRole in allCustomerRoles) + { + if (categoryCustomerRoles.Contains(customerRole.Id)) + { + if (!existingAclRecords.ContainsKey(customerRole.Id)) + { + _aclRepository.Insert(new AclRecord { CustomerRole = customerRole, CustomerRoleId = customerRole.Id, EntityId = product.Id, EntityName = "Product" }); + } + } + else + { + AclRecord aclRecordToDelete; + if (existingAclRecords.TryGetValue(customerRole.Id, out aclRecordToDelete)) + { + _aclRepository.Delete(aclRecordToDelete); + } + } + } + } + + _aclRepository.Context.SaveChanges(); + } + } + + public virtual void InheritStoresIntoChildren(int categoryId, + bool touchProductsWithMultipleCategories = false, + bool touchExistingAcls = false, + bool categoriesOnly = false) + { + + var category = GetCategoryById(categoryId); + var subcategories = GetAllCategoriesByParentCategoryId(categoryId, true); + var context = new ProductSearchContext { PageSize = int.MaxValue , ShowHidden = true }; + context.CategoryIds.AddRange(subcategories.Select(x => x.Id)); + context.CategoryIds.Add(categoryId); + var products = _productService.SearchProducts(context); + + var allStores = _storeService.GetAllStores(); + var categoryStoreMappings = _storeMappingService.GetStoresIdsWithAccess(category); + + using (var scope = new DbContextScope(ctx: _storeMappingRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) + { + _storeMappingRepository.AutoCommitEnabled = false; + + foreach (var subcategory in subcategories) + { + if (subcategory.LimitedToStores != category.LimitedToStores) + { + subcategory.LimitedToStores = category.LimitedToStores; + _categoryRepository.Update(subcategory); + } + + var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(subcategory).ToDictionary(x => x.StoreId); + + foreach (var store in allStores) + { + if (categoryStoreMappings.Contains(store.Id)) + { + if (!existingStoreMappingsRecords.ContainsKey(store.Id)) + { + _storeMappingRepository.Insert(new StoreMapping { StoreId = store.Id, EntityId = subcategory.Id, EntityName = "Category" }); + } + } + else + { + StoreMapping storeMappingToDelete; + if (existingStoreMappingsRecords.TryGetValue(store.Id, out storeMappingToDelete)) + { + _storeMappingRepository.Delete(storeMappingToDelete); + } + } + } + } + + _storeMappingRepository.Context.SaveChanges(); + + foreach (var product in products) + { + if (product.LimitedToStores != category.LimitedToStores) + { + product.LimitedToStores = category.LimitedToStores; + _productRepository.Update(product); + } + + var existingStoreMappingsRecords = _storeMappingService.GetStoreMappings(product).ToDictionary(x => x.StoreId); + + foreach (var store in allStores) + { + if (categoryStoreMappings.Contains(store.Id)) + { + if (!existingStoreMappingsRecords.ContainsKey(store.Id)) + { + _storeMappingRepository.Insert(new StoreMapping { StoreId = store.Id, EntityId = product.Id, EntityName = "Product" }); + } + } + else + { + StoreMapping storeMappingToDelete; + if (existingStoreMappingsRecords.TryGetValue(store.Id, out storeMappingToDelete)) + { + _storeMappingRepository.Delete(storeMappingToDelete); + } + } + } + } + + _storeMappingRepository.Context.SaveChanges(); + } + } + /// /// Delete category /// @@ -132,6 +314,51 @@ public virtual void DeleteCategory(Category category, bool deleteChilds = false) var childCategories = GetAllCategoriesByParentCategoryId(category.Id, true); DeleteAllCategories(childCategories, deleteChilds); } + + public virtual IQueryable GetCategories( + string categoryName = "", + bool showHidden = false, + string alias = null, + bool applyNavigationFilters = true, + int storeId = 0) + { + var query = _categoryRepository.Table; + + if (!showHidden) + query = query.Where(c => c.Published); + + if (categoryName.HasValue()) + query = query.Where(c => c.Name.Contains(categoryName) || c.FullName.Contains(categoryName)); + + if (alias.HasValue()) + query = query.Where(c => c.Alias.Contains(alias)); + + if (showHidden) + { + if (!QuerySettings.IgnoreMultiStore && storeId > 0) + { + query = from c in query + join sm in _storeMappingRepository.Table + on new { c1 = c.Id, c2 = "Category" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into c_sm + from sm in c_sm.DefaultIfEmpty() + where !c.LimitedToStores || storeId == sm.StoreId + select c; + + query = from c in query + group c by c.Id into cGroup + orderby cGroup.Key + select cGroup.FirstOrDefault(); + } + } + else + { + query = ApplyHiddenCategoriesFilter(query, applyNavigationFilters, _storeContext.CurrentStore.Id); + } + + query = query.Where(c => !c.Deleted); + + return query; + } /// /// Gets all categories @@ -142,30 +369,23 @@ public virtual void DeleteCategory(Category category, bool deleteChilds = false) /// A value indicating whether to show hidden records /// Alias to be filtered /// Whether to apply instances to the actual categories query. Never applied when is true + /// A value indicating whether categories without parent category in provided category list (source) should be ignored + /// Store identifier; 0 to load all records /// Categories - /// codehint: sm-edit - public virtual IPagedList GetAllCategories(string categoryName = "", int pageIndex = 0, int pageSize = int.MaxValue, bool showHidden = false, string alias = null, bool applyNavigationFilters = true) + public virtual IPagedList GetAllCategories(string categoryName = "", int pageIndex = 0, int pageSize = int.MaxValue, bool showHidden = false, string alias = null, + bool applyNavigationFilters = true, bool ignoreCategoriesWithoutExistingParent = true, int storeId = 0) { - var query = _categoryRepository.Table; - if (!showHidden) - query = query.Where(c => c.Published); - if (!String.IsNullOrWhiteSpace(categoryName)) - query = query.Where(c => c.Name.Contains(categoryName)); - if (!String.IsNullOrWhiteSpace(alias)) - query = query.Where(c => c.Alias.Contains(alias)); - query = query.Where(c => !c.Deleted); - query = query.OrderBy(c => c.ParentCategoryId).ThenBy(c => c.DisplayOrder); - - if (!showHidden) - { - query = ApplyHiddenCategoriesFilter(query, applyNavigationFilters); - query = query.OrderBy(c => c.ParentCategoryId).ThenBy(c => c.DisplayOrder); - } + var query = GetCategories(categoryName, showHidden, alias, applyNavigationFilters, storeId); + + query = query + .OrderBy(x => x.ParentCategoryId) + .ThenBy(x => x.DisplayOrder) + .ThenBy(x => x.Name); var unsortedCategories = query.ToList(); // sort categories - var sortedCategories = unsortedCategories.SortCategoriesForTree(ignoreCategoriesWithoutExistingParent: true); + var sortedCategories = unsortedCategories.SortCategoriesForTree(ignoreCategoriesWithoutExistingParent: ignoreCategoriesWithoutExistingParent); // paging return new PagedList(sortedCategories, pageIndex, pageSize); @@ -179,7 +399,8 @@ public virtual IPagedList GetAllCategories(string categoryName = "", i /// Category collection public IList GetAllCategoriesByParentCategoryId(int parentCategoryId, bool showHidden = false) { - string key = string.Format(CATEGORIES_BY_PARENT_CATEGORY_ID_KEY, parentCategoryId, showHidden, _workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id); + int storeId = _storeContext.CurrentStore.Id; + string key = string.Format(CATEGORIES_BY_PARENT_CATEGORY_ID_KEY, parentCategoryId, showHidden, _workContext.CurrentCustomer.Id, storeId); return _cacheManager.Get(key, () => { var query = _categoryRepository.Table; @@ -191,7 +412,7 @@ public IList GetAllCategoriesByParentCategoryId(int parentCategoryId, if (!showHidden) { - query = ApplyHiddenCategoriesFilter(query, false); + query = ApplyHiddenCategoriesFilter(query, false, storeId); query = query.OrderBy(c => c.DisplayOrder); } @@ -201,13 +422,13 @@ public IList GetAllCategoriesByParentCategoryId(int parentCategoryId, } - protected virtual IQueryable ApplyHiddenCategoriesFilter(IQueryable query, bool applyNavigationFilters) + protected virtual IQueryable ApplyHiddenCategoriesFilter(IQueryable query, bool applyNavigationFilters, int storeId = 0) { // ACL (access control list) - var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); - if (!QuerySettings.IgnoreAcl) { + var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); + query = from c in query join acl in _aclRepository.Table on new { c1 = c.Id, c2 = "Category" } equals new { c1 = acl.EntityId, c2 = acl.EntityName } into c_acl @@ -216,19 +437,18 @@ from acl in c_acl.DefaultIfEmpty() select c; } - if (!QuerySettings.IgnoreMultiStore) + // Store mapping + if (!QuerySettings.IgnoreMultiStore && storeId > 0) { - //Store mapping - var currentStoreId = _storeContext.CurrentStore.Id; query = from c in query join sm in _storeMappingRepository.Table on new { c1 = c.Id, c2 = "Category" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into c_sm from sm in c_sm.DefaultIfEmpty() - where !c.LimitedToStores || currentStoreId == sm.StoreId + where !c.LimitedToStores || storeId == sm.StoreId select c; } - //only distinct categories (group by ID) + // only distinct categories (group by ID) query = from c in query group c by c.Id into cGroup orderby cGroup.Key @@ -377,24 +597,27 @@ public virtual IPagedList GetProductCategoriesByCategoryId(int if (categoryId == 0) return new PagedList(new List(), pageIndex, pageSize); - string key = string.Format(PRODUCTCATEGORIES_ALLBYCATEGORYID_KEY, showHidden, categoryId, pageIndex, pageSize, _workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id); + int storeId = _storeContext.CurrentStore.Id; + string key = string.Format(PRODUCTCATEGORIES_ALLBYCATEGORYID_KEY, showHidden, categoryId, pageIndex, pageSize, _workContext.CurrentCustomer.Id, storeId); + return _cacheManager.Get(key, () => { var query = from pc in _productCategoryRepository.Table join p in _productRepository.Table on pc.ProductId equals p.Id - where pc.CategoryId == categoryId && - !p.Deleted && - (showHidden || p.Published) - orderby pc.DisplayOrder + where pc.CategoryId == categoryId && !p.Deleted && (showHidden || p.Published) select pc; if (!showHidden) { - query = ApplyHiddenProductCategoriesFilter(query); - query = query.OrderBy(pc => pc.DisplayOrder); + query = ApplyHiddenProductCategoriesFilter(query, storeId); } + query = query + .OrderBy(pc => pc.DisplayOrder) + .ThenBy(pc => pc.Id); // required for paging! + var productCategories = new PagedList(query, pageIndex, pageSize); + return productCategories; }); } @@ -413,8 +636,7 @@ public virtual IList GetProductCategoriesByProductId(int produc string key = string.Format(PRODUCTCATEGORIES_ALLBYPRODUCTID_KEY, showHidden, productId, _workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id); return _cacheManager.Get(key, () => { - var table = _productCategoryRepository.Table; - var query = from pc in _productCategoryRepository.Expand(table, x => x.Category) + var query = from pc in _productCategoryRepository.Table.Expand(x => x.Category) join c in _categoryRepository.Table on pc.CategoryId equals c.Id where pc.ProductId == productId && !c.Deleted && @@ -443,35 +665,89 @@ orderby pc.DisplayOrder }); } - protected virtual IQueryable ApplyHiddenProductCategoriesFilter(IQueryable query) + public virtual Multimap GetProductCategoriesByProductIds(int[] productIds, bool? hasDiscountsApplied = null, bool showHidden = false) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from pc in _productCategoryRepository.TableUntracked.Expand(x => x.Category).Expand(x => x.Category.Picture) + join c in _categoryRepository.Table on pc.CategoryId equals c.Id + where productIds.Contains(pc.ProductId) && !c.Deleted && (showHidden || c.Published) + orderby pc.DisplayOrder + select pc; + + if (hasDiscountsApplied.HasValue) + { + query = query.Where(x => x.Category.HasDiscountsApplied == hasDiscountsApplied); + } + + var list = query.ToList(); + + if (!showHidden) + { + list = list.Where(x => _aclService.Authorize(x.Category) && _storeMappingService.Authorize(x.Category)).ToList(); + } + + var map = list.ToMultimap(x => x.ProductId, x => x); + + return map; + } + + public virtual Multimap GetProductCategoriesByCategoryIds(int[] categoryIds) + { + Guard.ArgumentNotNull(() => categoryIds); + + var query = _productCategoryRepository.TableUntracked + .Where(x => categoryIds.Contains(x.CategoryId)) + .OrderBy(x => x.DisplayOrder); + + var map = query + .ToList() + .ToMultimap(x => x.CategoryId, x => x); + + return map; + } + + protected virtual IQueryable ApplyHiddenProductCategoriesFilter(IQueryable query, int storeId = 0) { + bool group = false; + //ACL (access control list) - var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles - .Where(cr => cr.Active).Select(cr => cr.Id).ToList(); + if (!QuerySettings.IgnoreAcl) + { + group = true; + var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles.Where(cr => cr.Active).Select(cr => cr.Id).ToList(); - query = from pc in query - join c in _categoryRepository.Table on pc.CategoryId equals c.Id - join acl in _aclRepository.Table - on new { c1 = c.Id, c2 = "Category" } equals new { c1 = acl.EntityId, c2 = acl.EntityName } into c_acl - from acl in c_acl.DefaultIfEmpty() - where !c.SubjectToAcl || allowedCustomerRolesIds.Contains(acl.CustomerRoleId) - select pc; + query = from pc in query + join c in _categoryRepository.Table on pc.CategoryId equals c.Id + join acl in _aclRepository.Table + on new { c1 = c.Id, c2 = "Category" } equals new { c1 = acl.EntityId, c2 = acl.EntityName } into c_acl + from acl in c_acl.DefaultIfEmpty() + where !c.SubjectToAcl || allowedCustomerRolesIds.Contains(acl.CustomerRoleId) + select pc; + } //Store mapping - var currentStoreId = _storeContext.CurrentStore.Id; - query = from pc in query - join c in _categoryRepository.Table on pc.CategoryId equals c.Id - join sm in _storeMappingRepository.Table - on new { c1 = c.Id, c2 = "Category" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into c_sm - from sm in c_sm.DefaultIfEmpty() - where !c.LimitedToStores || currentStoreId == sm.StoreId - select pc; - - //only distinct categories (group by ID) - query = from pc in query - group pc by pc.Id into pcGroup - orderby pcGroup.Key - select pcGroup.FirstOrDefault(); + if (!QuerySettings.IgnoreMultiStore && storeId > 0) + { + group = true; + query = from pc in query + join c in _categoryRepository.Table on pc.CategoryId equals c.Id + join sm in _storeMappingRepository.Table + on new { c1 = c.Id, c2 = "Category" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into c_sm + from sm in c_sm.DefaultIfEmpty() + where !c.LimitedToStores || storeId == sm.StoreId + select pc; + } + + if (group) + { + //only distinct categories (group by ID) + query = from pc in query + group pc by pc.Id into pcGroup + orderby pcGroup.Key + select pcGroup.FirstOrDefault(); + } return query; } @@ -527,7 +803,8 @@ public virtual void UpdateProductCategory(ProductCategory productCategory) _eventPublisher.EntityUpdated(productCategory); } - public virtual string GetCategoryPath(Product product, int? languageId, Func pathLookup, Action addPathToCache, Func categoryLookup) + public virtual string GetCategoryPath(Product product, int? languageId, Func pathLookup, Action addPathToCache, Func categoryLookup, + ProductCategory prodCategory = null) { if (product == null) return string.Empty; @@ -539,7 +816,7 @@ public virtual string GetCategoryPath(Product product, int? languageId, Func(); var path = new List(); - var productCategory = GetProductCategoriesByProductId(product.Id).FirstOrDefault(); + var productCategory = prodCategory ?? GetProductCategoriesByProductId(product.Id).FirstOrDefault(); if (productCategory != null && productCategory.Category != null) { diff --git a/src/Libraries/SmartStore.Services/Catalog/CompareProductsService.cs b/src/Libraries/SmartStore.Services/Catalog/CompareProductsService.cs index d9bfb3cf6c..8f4085d2c9 100644 --- a/src/Libraries/SmartStore.Services/Catalog/CompareProductsService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/CompareProductsService.cs @@ -145,13 +145,20 @@ public virtual void AddProductToCompareList(int productId) var oldProductIds = GetComparedProductIds(); var newProductIds = new List(); newProductIds.Add(productId); - foreach (int oldProductId in oldProductIds) - if (oldProductId != productId) - newProductIds.Add(oldProductId); + + foreach (int oldProductId in oldProductIds) + { + if (oldProductId != productId) + newProductIds.Add(oldProductId); + } var compareCookie = _httpContext.Request.Cookies.Get(COMPARE_PRODUCTS_COOKIE_NAME); - if (compareCookie == null) - compareCookie = new HttpCookie(COMPARE_PRODUCTS_COOKIE_NAME); + if (compareCookie == null) + { + compareCookie = new HttpCookie(COMPARE_PRODUCTS_COOKIE_NAME); + compareCookie.HttpOnly = true; + } + compareCookie.Values.Clear(); int maxProducts = 4; int i = 1; diff --git a/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs b/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs index bd94bae15d..f786bf9c78 100644 --- a/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/CopyProductService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Media; using SmartStore.Services.Localization; @@ -83,15 +84,15 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli var utcNow = DateTime.UtcNow; // product download & sample download - int downloadId = product.DownloadId; - int? sampleDownloadId = product.SampleDownloadId; + int downloadId = 0; + int? sampleDownloadId = null; if (product.IsDownload) { var download = _downloadService.GetDownloadById(product.DownloadId); if (download != null) { - var downloadCopy = new Download() + var downloadCopy = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = download.UseDownloadUrl, @@ -102,6 +103,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli Extension = download.Extension, IsNew = download.IsNew, }; + _downloadService.InsertDownload(downloadCopy); downloadId = downloadCopy.Id; } @@ -111,7 +113,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli var sampleDownload = _downloadService.GetDownloadById(product.SampleDownloadId.GetValueOrDefault()); if (sampleDownload != null) { - var sampleDownloadCopy = new Download() + var sampleDownloadCopy = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = sampleDownload.UseDownloadUrl, @@ -122,6 +124,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli Extension = sampleDownload.Extension, IsNew = sampleDownload.IsNew }; + _downloadService.InsertDownload(sampleDownloadCopy); sampleDownloadId = sampleDownloadCopy.Id; } @@ -129,7 +132,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli } // product - productCopy = new Product() + productCopy = new Product { ProductTypeId = product.ProductTypeId, ParentGroupedProductId = product.ParentGroupedProductId, @@ -140,6 +143,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli ProductTemplateId = product.ProductTemplateId, AdminComment = product.AdminComment, ShowOnHomePage = product.ShowOnHomePage, + HomePageDisplayOrder = product.HomePageDisplayOrder, MetaKeywords = product.MetaKeywords, MetaDescription = product.MetaDescription, MetaTitle = product.MetaTitle, @@ -170,6 +174,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli IsShipEnabled = product.IsShipEnabled, IsFreeShipping = product.IsFreeShipping, AdditionalShippingCharge = product.AdditionalShippingCharge, + IsEsd = product.IsEsd, IsTaxExempt = product.IsTaxExempt, TaxCategoryId = product.TaxCategoryId, ManageInventoryMethod = product.ManageInventoryMethod, @@ -210,6 +215,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli CreatedOnUtc = utcNow, UpdatedOnUtc = utcNow, DeliveryTimeId = product.DeliveryTimeId, + QuantityUnitId = product.QuantityUnitId, BasePriceEnabled = product.BasePriceEnabled, BasePriceMeasureUnit = product.BasePriceMeasureUnit, BasePriceAmount = product.BasePriceAmount, @@ -273,8 +279,11 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli _pictureService.LoadPictureBinary(picture), picture.MimeType, _pictureService.GetPictureSeName(newName), - true); - _productService.InsertProductPicture(new ProductPicture() + true, + false, + false); + + _productService.InsertProductPicture(new ProductPicture { ProductId = productCopy.Id, PictureId = pictureCopy.Id, @@ -286,7 +295,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli // product <-> categories mappings foreach (var productCategory in product.ProductCategories) { - var productCategoryCopy = new ProductCategory() + var productCategoryCopy = new ProductCategory { ProductId = productCopy.Id, CategoryId = productCategory.CategoryId, @@ -300,7 +309,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli // product <-> manufacturers mappings foreach (var productManufacturers in product.ProductManufacturers) { - var productManufacturerCopy = new ProductManufacturer() + var productManufacturerCopy = new ProductManufacturer { ProductId = productCopy.Id, ManufacturerId = productManufacturers.ManufacturerId, @@ -314,30 +323,28 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli // product <-> releated products mappings foreach (var relatedProduct in _productService.GetRelatedProductsByProductId1(product.Id, true)) { - _productService.InsertRelatedProduct( - new RelatedProduct() - { - ProductId1 = productCopy.Id, - ProductId2 = relatedProduct.ProductId2, - DisplayOrder = relatedProduct.DisplayOrder - }); + _productService.InsertRelatedProduct(new RelatedProduct + { + ProductId1 = productCopy.Id, + ProductId2 = relatedProduct.ProductId2, + DisplayOrder = relatedProduct.DisplayOrder + }); } // product <-> cross sells mappings foreach (var csProduct in _productService.GetCrossSellProductsByProductId1(product.Id, true)) { - _productService.InsertCrossSellProduct( - new CrossSellProduct() - { - ProductId1 = productCopy.Id, - ProductId2 = csProduct.ProductId2, - }); + _productService.InsertCrossSellProduct(new CrossSellProduct + { + ProductId1 = productCopy.Id, + ProductId2 = csProduct.ProductId2, + }); } // product specifications foreach (var productSpecificationAttribute in product.ProductSpecificationAttributes) { - var psaCopy = new ProductSpecificationAttribute() + var psaCopy = new ProductSpecificationAttribute { ProductId = productCopy.Id, SpecificationAttributeOptionId = productSpecificationAttribute.SpecificationAttributeOptionId, @@ -345,6 +352,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli ShowOnProductPage = productSpecificationAttribute.ShowOnProductPage, DisplayOrder = productSpecificationAttribute.DisplayOrder }; + _specificationAttributeService.InsertProductSpecificationAttribute(psaCopy); } @@ -358,9 +366,10 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli // product <-> attributes mappings var associatedAttributes = new Dictionary(); var associatedAttributeValues = new Dictionary(); + foreach (var productVariantAttribute in _productAttributeService.GetProductVariantAttributesByProductId(product.Id)) { - var productVariantAttributeCopy = new ProductVariantAttribute() + var productVariantAttributeCopy = new ProductVariantAttribute { ProductId = productCopy.Id, ProductAttributeId = productVariantAttribute.ProductAttributeId, @@ -369,15 +378,17 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli AttributeControlTypeId = productVariantAttribute.AttributeControlTypeId, DisplayOrder = productVariantAttribute.DisplayOrder }; + _productAttributeService.InsertProductVariantAttribute(productVariantAttributeCopy); //save associated value (used for combinations copying) associatedAttributes.Add(productVariantAttribute.Id, productVariantAttributeCopy.Id); // product variant attribute values var productVariantAttributeValues = _productAttributeService.GetProductVariantAttributeValues(productVariantAttribute.Id); + foreach (var productVariantAttributeValue in productVariantAttributeValues) { - var pvavCopy = new ProductVariantAttributeValue() + var pvavCopy = new ProductVariantAttributeValue { ProductVariantAttributeId = productVariantAttributeCopy.Id, Name = productVariantAttributeValue.Name, @@ -390,6 +401,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli LinkedProductId = productVariantAttributeValue.LinkedProductId, Quantity = productVariantAttributeValue.Quantity, }; + _productAttributeService.InsertProductVariantAttributeValue(pvavCopy); //save associated value (used for combinations copying) @@ -406,7 +418,12 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli } // attribute combinations - foreach (var combination in _productAttributeService.GetAllProductVariantAttributeCombinations(product.Id)) + using (var scope = new DbContextScope(lazyLoading: false, forceNoTracking: false)) + { + scope.LoadCollection(product, (Product p) => p.ProductVariantAttributeCombinations); + } + + foreach (var combination in product.ProductVariantAttributeCombinations) { //generate new AttributesXml according to new value IDs string newAttributesXml = ""; @@ -432,22 +449,20 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli var newPvav = _productAttributeService.GetProductVariantAttributeValueById(newPvavId); if (newPvav != null) { - newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, - newPva, newPvav.Id.ToString()); + newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, newPva, newPvav.Id.ToString()); } } } else { //just a text - newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, - newPva, oldPvaValueStr); + newAttributesXml = _productAttributeParser.AddProductAttribute(newAttributesXml, newPva, oldPvaValueStr); } } } } } - var combinationCopy = new ProductVariantAttributeCombination() + var combinationCopy = new ProductVariantAttributeCombination { ProductId = productCopy.Id, AttributesXml = newAttributesXml, @@ -466,6 +481,7 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli BasePriceAmount = combination.BasePriceAmount, BasePriceBaseAmount = combination.BasePriceBaseAmount, DeliveryTimeId = combination.DeliveryTimeId, + QuantityUnitId = combination.QuantityUnitId, IsActive = combination.IsActive //IsDefaultCombination = combination.IsDefaultCombination }; @@ -475,15 +491,14 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli // tier prices foreach (var tierPrice in product.TierPrices) { - _productService.InsertTierPrice( - new TierPrice() - { - ProductId = productCopy.Id, - StoreId = tierPrice.StoreId, - CustomerRoleId = tierPrice.CustomerRoleId, - Quantity = tierPrice.Quantity, - Price = tierPrice.Price - }); + _productService.InsertTierPrice(new TierPrice + { + ProductId = productCopy.Id, + StoreId = tierPrice.StoreId, + CustomerRoleId = tierPrice.CustomerRoleId, + Quantity = tierPrice.Quantity, + Price = tierPrice.Price + }); } // product <-> discounts mapping @@ -499,10 +514,11 @@ public virtual Product CopyProduct(Product product, string newName, bool isPubli _productService.UpdateHasDiscountsApplied(productCopy); // associated products - if (copyAssociatedProducts) + if (copyAssociatedProducts && product.ProductType != ProductType.BundledProduct) { - var searchContext = new ProductSearchContext() + var searchContext = new ProductSearchContext { + OrderBy = ProductSortingEnum.Position, ParentGroupedProductId = product.Id, PageSize = int.MaxValue, ShowHidden = true diff --git a/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs b/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs index 4b38817f64..c19242429d 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ICategoryService.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; @@ -10,6 +12,31 @@ namespace SmartStore.Services.Catalog /// public partial interface ICategoryService { + + /// + /// Assign acl to sub-categories and products + /// + /// Category Id + /// Reserved for future use: Whether to assign acl's to products which are contained in multiple categories. + /// Reserved for future use: Whether to delete existing Acls. + /// Reserved for future use: Whether to assign acl's only to categories. + void InheritAclIntoChildren(int categoryId, + bool touchProductsWithMultipleCategories = false, + bool touchExistingAcls = false, + bool categoriesOnly = false); + + /// + /// Assign stores to sub-categories and products + /// + /// Category Id + /// Reserved for future use: Whether to assign acl's to products which are contained in multiple categories. + /// Reserved for future use: Whether to delete existing Acls. + /// Reserved for future use: Whether to assign acl's only to categories. + void InheritStoresIntoChildren(int categoryId, + bool touchProductsWithMultipleCategories = false, + bool touchExistingAcls = false, + bool categoriesOnly = false); + /// /// Delete category /// @@ -17,6 +44,22 @@ public partial interface ICategoryService /// Whether to delete child categories or to set them to no parent. void DeleteCategory(Category category, bool deleteChilds = false); + /// + /// Gets categories + /// + /// Category name + /// A value indicating whether to show hidden records + /// Alias to be filtered + /// Whether to apply instances to the actual categories query. Never applied when is true + /// Store identifier; 0 to load all records + /// Category query + IQueryable GetCategories( + string categoryName = "", + bool showHidden = false, + string alias = null, + bool applyNavigationFilters = true, + int storeId = 0); + /// /// Gets all categories /// @@ -26,8 +69,11 @@ public partial interface ICategoryService /// A value indicating whether to show hidden records /// Alias to be filtered /// Whether to apply instances to the actual categories query. Never applied when is true + /// A value indicating whether categories without parent category in provided category list (source) should be ignored + /// Store identifier; 0 to load all records /// Categories - IPagedList GetAllCategories(string categoryName = "", int pageIndex = 0, int pageSize = int.MaxValue, bool showHidden = false, string alias = null, bool applyNavigationFilters = true); + IPagedList GetAllCategories(string categoryName = "", int pageIndex = 0, int pageSize = int.MaxValue, bool showHidden = false, string alias = null, + bool applyNavigationFilters = true, bool ignoreCategoriesWithoutExistingParent = true, int storeId = 0); /// /// Gets all categories filtered by parent category identifier @@ -93,6 +139,22 @@ IPagedList GetProductCategoriesByCategoryId(int categoryId, /// Product category mapping collection IList GetProductCategoriesByProductId(int productId, bool showHidden = false); + /// + /// Gets product category mappings + /// + /// Product identifiers + /// A value indicating whether to filter categories with applied discounts + /// A value indicating whether to show hidden records + /// Map with product category mappings + Multimap GetProductCategoriesByProductIds(int[] productIds, bool? hasDiscountsApplied = null, bool showHidden = false); + + /// + /// Gets product category mappings + /// + /// Category identifiers + /// Map with product category mappings + Multimap GetProductCategoriesByCategoryIds(int[] categoryIds); + /// /// Gets a product category mapping /// @@ -120,8 +182,10 @@ IPagedList GetProductCategoriesByCategoryId(int categoryId, /// A delegate for fast (cached) path lookup /// A callback that saves the resolved path to a cache (when pathLookup returned null) /// A delegate for fast (cached) category lookup + /// First product category of product /// Category breadcrumb for product - string GetCategoryPath(Product product, int? languageId, Func pathLookup, Action addPathToCache, Func categoryLookup); + string GetCategoryPath(Product product, int? languageId, Func pathLookup, Action addPathToCache, Func categoryLookup, + ProductCategory prodCategory = null); } public static class ICategoryServiceExtensions diff --git a/src/Libraries/SmartStore.Services/Catalog/IManufacturerService.cs b/src/Libraries/SmartStore.Services/Catalog/IManufacturerService.cs index 63f8b647a8..24917da095 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IManufacturerService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IManufacturerService.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; @@ -15,6 +17,14 @@ public partial interface IManufacturerService /// Manufacturer void DeleteManufacturer(Manufacturer manufacturer); + /// + /// Get manufacturer query + /// + /// A value indicating whether to show hidden records + /// Store identifier + /// Manufacturer query + IQueryable GetManufacturers(bool showHidden = false, int storeId = 0); + /// /// Gets all manufacturers /// @@ -22,24 +32,26 @@ public partial interface IManufacturerService /// Manufacturer collection IList GetAllManufacturers(bool showHidden = false); - /// - /// Gets all manufacturers - /// - /// Manufacturer name - /// A value indicating whether to show hidden records - /// Manufacturer collection - IList GetAllManufacturers(string manufacturerName, bool showHidden = false); - - /// - /// Gets all manufacturers - /// - /// Manufacturer name - /// Page index - /// Page size - /// A value indicating whether to show hidden records - /// Manufacturers - IPagedList GetAllManufacturers(string manufacturerName, - int pageIndex, int pageSize, bool showHidden = false); + /// + /// Gets all manufacturers + /// + /// Manufacturer name + /// Whether to filter result by store identifier + /// A value indicating whether to show hidden records + /// Manufacturer collection + IList GetAllManufacturers(string manufacturerName, int storeId = 0, bool showHidden = false); + + /// + /// Gets all manufacturers + /// + /// Manufacturer name + /// Page index + /// Page size + /// Whether to filter result by store identifier + /// A value indicating whether to show hidden records + /// Manufacturers + IPagedList GetAllManufacturers(string manufacturerName, + int pageIndex, int pageSize, int storeId = 0, bool showHidden = false); /// /// Gets a manufacturer @@ -85,6 +97,20 @@ IPagedList GetProductManufacturersByManufacturerId(int manu /// Product manufacturer mapping collection IList GetProductManufacturersByProductId(int productId, bool showHidden = false); + /// + /// Get product manufacturers by manufacturer identifiers + /// + /// Manufacturer identifiers + /// Product manufacturers + Multimap GetProductManufacturersByManufacturerIds(int[] manufacturerIds); + + /// + /// Get product manufacturers by product identifiers + /// + /// Product identifiers + /// Product manufacturers + Multimap GetProductManufacturersByProductIds(int[] productIds); + /// /// Gets a product manufacturer mapping /// diff --git a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs index 9777824f0a..e3c7b9d5a6 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IPriceCalculationService.cs @@ -11,6 +11,13 @@ namespace SmartStore.Services.Catalog /// public partial interface IPriceCalculationService { + /// + /// Creates a price calculation context + /// + /// Products. null to lazy load data if required. + /// Price calculation context + PriceCalculationContext CreatePriceCalculationContext(IEnumerable products = null); + /// /// Get product special price (is valid) /// @@ -59,13 +66,15 @@ decimal GetFinalPrice(Product product, /// A value indicating whether include discounts or not for final price computation /// Shopping cart item quantity /// A product bundle item + /// Object with cargo data for better performance /// Final price decimal GetFinalPrice(Product product, Customer customer, decimal additionalCharge, bool includeDiscounts, int quantity, - ProductBundleItemData bundleItem = null); + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null); /// /// Gets the final price including bundle per-item pricing @@ -77,26 +86,43 @@ decimal GetFinalPrice(Product product, /// A value indicating whether include discounts or not for final price computation /// Shopping cart item quantity /// A product bundle item + /// Object with cargo data for better performance /// Final price - decimal GetFinalPrice(Product product, IList bundleItems, - Customer customer, decimal additionalCharge, bool includeDiscounts, int quantity, ProductBundleItemData bundleItem = null); + decimal GetFinalPrice(Product product, + IEnumerable bundleItems, + Customer customer, + decimal additionalCharge, + bool includeDiscounts, + int quantity, + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null); /// /// Get the lowest possible price for a product. /// /// Product + /// Object with cargo data for better performance /// Whether to display the from message. /// The lowest price. - decimal GetLowestPrice(Product product, out bool displayFromMessage); + decimal GetLowestPrice(Product product, PriceCalculationContext context, out bool displayFromMessage); /// /// Get the lowest price of a grouped product. /// - /// Grouped product. - /// Products associated to product. - /// The associated product with the lowest price. + /// Grouped product + /// Object with cargo data for better performance + /// Products associated to product + /// The associated product with the lowest price /// The lowest price. - decimal? GetLowestPrice(Product product, IEnumerable associatedProducts, out Product lowestPriceProduct); + decimal? GetLowestPrice(Product product, PriceCalculationContext context, IEnumerable associatedProducts, out Product lowestPriceProduct); + + /// + /// Get the initial price including preselected attributes + /// + /// Product + /// Object with cargo data for better performance + /// Preselected price + decimal GetPreselectedPrice(Product product, PriceCalculationContext context); /// /// Gets the product cost @@ -155,13 +181,15 @@ decimal GetDiscountAmount(Product product, /// Product quantity /// Applied discount /// A product bundle item + /// Object with cargo data for better performance /// Discount amount decimal GetDiscountAmount(Product product, Customer customer, decimal additionalCharge, int quantity, out Discount appliedDiscount, - ProductBundleItemData bundleItem = null); + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null); /// diff --git a/src/Libraries/SmartStore.Services/Catalog/IPriceFormatter.cs b/src/Libraries/SmartStore.Services/Catalog/IPriceFormatter.cs index 4e6b84ab11..584c3f40e9 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IPriceFormatter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IPriceFormatter.cs @@ -42,8 +42,7 @@ public partial interface IPriceFormatter /// A value indicating whether to show tax suffix /// Language /// Price - string FormatPrice(decimal price, bool showCurrency, - string currencyCode, bool showTax, Language language); + string FormatPrice(decimal price, bool showCurrency, string currencyCode, bool showTax, Language language); /// /// Formats the price @@ -54,8 +53,7 @@ string FormatPrice(decimal price, bool showCurrency, /// Language /// A value indicating whether price includes tax /// Price - string FormatPrice(decimal price, bool showCurrency, - string currencyCode, Language language, bool priceIncludesTax); + string FormatPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax); /// /// Formats the price @@ -66,8 +64,19 @@ string FormatPrice(decimal price, bool showCurrency, /// Language /// A value indicating whether price includes tax /// Price - string FormatPrice(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax); + string FormatPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax); + + /// + /// Formats the price + /// + /// Price + /// A value indicating whether to show a currency + /// Target currency + /// Language + /// A value indicating whether price includes tax + /// A value indicating whether to show tax suffix + /// Price + string FormatPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax, bool showTax); /// /// Formats the price @@ -79,8 +88,7 @@ string FormatPrice(decimal price, bool showCurrency, /// A value indicating whether price includes tax /// A value indicating whether to show tax suffix /// Price - string FormatPrice(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax); + string FormatPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax); /// @@ -100,9 +108,21 @@ string FormatPrice(decimal price, bool showCurrency, /// Language /// A value indicating whether price includes tax /// Price - string FormatShippingPrice(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax); - /// + string FormatShippingPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax); + + /// + /// Formats the shipping price + /// + /// Price + /// A value indicating whether to show a currency + /// Target currency code + /// Language + /// A value indicating whether price includes tax + /// A value indicating whether to show tax suffix + /// Price + string FormatShippingPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax, bool showTax); + + /// /// Formats the shipping price /// /// Price @@ -112,8 +132,7 @@ string FormatShippingPrice(decimal price, bool showCurrency, /// A value indicating whether price includes tax /// A value indicating whether to show tax suffix /// Price - string FormatShippingPrice(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax); + string FormatShippingPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax); /// /// Formats the shipping price @@ -124,8 +143,7 @@ string FormatShippingPrice(decimal price, bool showCurrency, /// Language /// A value indicating whether price includes tax /// Price - string FormatShippingPrice(decimal price, bool showCurrency, - string currencyCode, Language language, bool priceIncludesTax); + string FormatShippingPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax); @@ -146,8 +164,19 @@ string FormatShippingPrice(decimal price, bool showCurrency, /// Language /// A value indicating whether price includes tax /// Price - string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax); + string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax); + + /// + /// Formats the payment method additional fee + /// + /// Price + /// A value indicating whether to show a currency + /// Target currency code + /// Language + /// A value indicating whether price includes tax + /// A value indicating whether to show tax suffix + /// Price + string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax, bool showTax); /// /// Formats the payment method additional fee @@ -159,8 +188,7 @@ string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, /// A value indicating whether price includes tax /// A value indicating whether to show tax suffix /// Price - string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax); + string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax); /// /// Formats the payment method additional fee @@ -171,8 +199,7 @@ string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, /// Language /// A value indicating whether price includes tax /// Price - string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, - string currencyCode, Language language, bool priceIncludesTax); + string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax); diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs index 21fd8bcdc7..f8565562e5 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeParser.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -using SmartStore.Core.Domain.Catalog; using SmartStore.Collections; +using SmartStore.Core.Domain.Catalog; namespace SmartStore.Services.Catalog { @@ -14,63 +14,63 @@ public partial interface IProductAttributeParser /// /// Gets selected product variant attributes as a map of integer ids with their corresponding values. /// - /// Attributes XML + /// XML formatted attributes /// The deserialized map - Multimap DeserializeProductVariantAttributes(string attributes); - - /// - /// Gets selected product variant attributes - /// - /// Attributes - /// Selected product variant attributes - IList ParseProductVariantAttributes(string attributes); + Multimap DeserializeProductVariantAttributes(string attributesXml); - /// - /// Gets selected product variant attributes - /// - /// The attribute ids - /// Selected product variant attributes - IEnumerable ParseProductVariantAttributes(ICollection ids); + /// + /// Gets selected product variant attributes + /// + /// XML formatted attributes + /// Selected product variant attributes + IList ParseProductVariantAttributes(string attributesXml); /// /// Get product variant attribute values /// - /// Attributes + /// XML formatted attributes /// Product variant attribute values - IEnumerable ParseProductVariantAttributeValues(string attributes); + IEnumerable ParseProductVariantAttributeValues(string attributesXml); - /// - /// Gets selected product variant attribute value - /// - /// Attributes - /// Product variant attribute identifier - /// Product variant attribute value - IList ParseValues(string attributes, int productVariantAttributeId); + /// + /// Get list of product variant attribute values + /// + /// Map of combined attributes + /// Product variant attributes + /// List of product variant attribute values + IList ParseProductVariantAttributeValues(Multimap attributeCombination, IEnumerable attributes); + + /// + /// Gets selected product variant attribute value + /// + /// XML formatted attributes + /// Product variant attribute identifier + /// Product variant attribute value + IList ParseValues(string attributesXml, int productVariantAttributeId); /// /// Adds an attribute /// - /// Attributes + /// XML formatted attributes /// Product variant attribute /// Value /// Attributes - string AddProductAttribute(string attributes, ProductVariantAttribute pva, string value); + string AddProductAttribute(string attributesXml, ProductVariantAttribute pva, string value); /// /// Are attributes equal /// - /// The attributes of the first product - /// The attributes of the second product + /// The attributes of the first product + /// The attributes of the second product /// Result - bool AreProductAttributesEqual(string attributes1, string attributes2); + bool AreProductAttributesEqual(string attributeXml1, string attributeXml2); - /// - /// Finds a product variant attribute combination by attributes stored in XML - /// - /// Product - /// Attributes in XML format - /// Found product variant attribute combination - ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml); + /// + /// Finds a product variant attribute combination by attributes stored in XML + /// + /// Product identifier + /// XML formatted attributes + /// Found product variant attribute combination ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml); /// @@ -80,14 +80,48 @@ public partial interface IProductAttributeParser /// List items with following structure: Product.Id, ProductAttribute.Id, Product_ProductAttribute_Mapping.Id, ProductVariantAttributeValue.Id List> DeserializeQueryData(string jsonData); + /// + /// Deserializes attribute data + /// + /// List with deserialized data + /// XML formatted attributes + /// Product identifier + /// Bundle item identifier + void DeserializeQueryData(List> queryData, string attributesXml, int productId, int bundleItemId = 0); + /// /// Serializes attribute data /// + /// XML formatted attributes /// Product identifier - /// Attribute XML string /// Whether to URL encode /// Json string with attribute data - string SerializeQueryData(int productId, string attributesXml, bool urlEncode = true); + string SerializeQueryData(string attributesXml, int productId, bool urlEncode = true); + + /// + /// Serializes attribute data + /// + /// List with deserialized data + /// Whether to URL encode + /// Json string with attribute data + string SerializeQueryData(List> queryData, bool urlEncode = true); + + /// + /// Gets the URL of the product page including attributes query string + /// + /// XML formatted attributes + /// Product identifier + /// Product SEO name + /// URL of the product page including attributes query string + string GetProductUrlWithAttributes(string attributesXml, int productId, string productSeName); + + /// + /// Gets the URL of the product page including attributes query string + /// + /// Attribute query data + /// Product SEO name + /// URL of the product page including attributes query string + string GetProductUrlWithAttributes(List> queryData, string productSeName); #endregion @@ -96,26 +130,26 @@ public partial interface IProductAttributeParser /// /// Add gift card attrbibutes /// - /// Attributes + /// XML formatted attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message /// Attributes - string AddGiftCardAttribute(string attributes, string recipientName, + string AddGiftCardAttribute(string attributesXml, string recipientName, string recipientEmail, string senderName, string senderEmail, string giftCardMessage); /// /// Get gift card attrbibutes /// - /// Attributes + /// XML formatted attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message - void GetGiftCardAttribute(string attributes, out string recipientName, + void GetGiftCardAttribute(string attributesXml, out string recipientName, out string recipientEmail, out string senderName, out string senderEmail, out string giftCardMessage); diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs index c23e5de26e..eacf65250e 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductAttributeService.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; +using SmartStore.Collections; using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Media; +using SmartStore.Core; namespace SmartStore.Services.Catalog { @@ -59,6 +60,14 @@ public partial interface IProductAttributeService /// Product variant attribute mapping collection IList GetProductVariantAttributesByProductId(int productId); + /// + /// Gets product variant attribute mappings by multiple product identifiers + /// + /// The product identifiers + /// An optional control type filter. null loads all controls regardless of type. + /// A map with product id as key and a collection of variant attributes as value. + Multimap GetProductVariantAttributesByProductIds(int[] productIds, AttributeControlType? controlType); + /// /// Gets a product variant attribute mapping /// @@ -66,13 +75,13 @@ public partial interface IProductAttributeService /// Product variant attribute mapping ProductVariantAttribute GetProductVariantAttributeById(int productVariantAttributeId); - // codehint: sm-add - /// - /// Gets multiple product variant attribute mappings by their keys - /// - /// a list of keys - /// Product variant attribute mappings - IEnumerable GetProductVariantAttributesByIds(params int[] ids); + /// + /// Gets product variant attribute mappings + /// + /// Enumerable of product variant attribute mapping identifiers + /// Collection of already loaded product attribute mappings to reduce database round trips + /// + IList GetProductVariantAttributesByIds(IEnumerable productVariantAttributeIds, IEnumerable attributes = null); /// /// Inserts a product variant attribute mapping @@ -110,7 +119,6 @@ public partial interface IProductAttributeService /// Product variant attribute value ProductVariantAttributeValue GetProductVariantAttributeValueById(int productVariantAttributeValueId); - // codehint: sm-add /// /// Gets multiple product variant attribute value /// @@ -140,12 +148,30 @@ public partial interface IProductAttributeService /// Product variant attribute combination void DeleteProductVariantAttributeCombination(ProductVariantAttributeCombination combination); - /// - /// Gets all product variant attribute combinations - /// + /// + /// Gets all product variant attribute combinations + /// /// Product identifier - /// Product variant attribute combination collection - IList GetAllProductVariantAttributeCombinations(int productId); + /// Page index + /// Page size + /// Specifies whether loaded entities should be tracked by the state manager + /// Product variant attribute combination collection + IPagedList GetAllProductVariantAttributeCombinations(int productId, int pageIndex, int pageSize, bool untracked = true); + + /// + /// Gets a distinct list of picture identifiers. + /// Only pictures that are explicitly assigned to combinations are taken into account. + /// + /// Product id + /// Picture ids + IList GetAllProductVariantAttributeCombinationPictureIds(int productId); + + /// + /// Gets product variant attribute combinations by multiple product identifiers + /// + /// The product identifiers + /// A map with product id as key and a collection of product variant attribute combinations as value. + Multimap GetProductVariantAttributeCombinations(int[] productIds); /// /// Get the lowest price of all combinations for a product @@ -155,12 +181,19 @@ public partial interface IProductAttributeService decimal? GetLowestCombinationPrice(int productId); /// - /// Gets a product variant attribute combination + /// Gets a product variant attribute combination by identifier /// /// Product variant attribute combination identifier /// Product variant attribute combination ProductVariantAttributeCombination GetProductVariantAttributeCombinationById(int productVariantAttributeCombinationId); + /// + /// /// Gets a product variant attribute combination by SKU + /// + /// SKU + /// Product variant attribute combination + ProductVariantAttributeCombination GetProductVariantAttributeCombinationBySku(string sku); + /// /// Inserts a product variant attribute combination /// @@ -226,4 +259,17 @@ public partial interface IProductAttributeService #endregion } + + public static class IProductAttributeServiceExtensions + { + /// + /// Gets all product variant attribute combinations + /// + /// Product identifier + /// Product variant attribute combination collection + public static IList GetAllProductVariantAttributeCombinations(this IProductAttributeService service, int productId) + { + return service.GetAllProductVariantAttributeCombinations(productId, 0, int.MaxValue, true); + } + } } diff --git a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs index 57beb164f2..0b1f7649d5 100644 --- a/src/Libraries/SmartStore.Services/Catalog/IProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/IProductService.cs @@ -1,8 +1,12 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Orders; namespace SmartStore.Services.Catalog @@ -70,6 +74,15 @@ public partial interface IProductService /// Whether to search localized values. IQueryable PrepareProductSearchQuery(ProductSearchContext ctx, IEnumerable allowedCustomerRolesIds = null, bool searchLocalizedValue = false); + /// + /// Builds a product query based on the options in ProductSearchContext parameter. + /// + /// Parameters to build the query. + /// Data projector + /// Customer role ids (ACL). + /// Whether to search localized values. + IQueryable PrepareProductSearchQuery(ProductSearchContext ctx, Expression> selector, IEnumerable allowedCustomerRolesIds = null, bool searchLocalizedValue = false); + /// /// Update product review totals /// @@ -92,16 +105,31 @@ public partial interface IProductService /// /// Gets a product by GTIN /// - /// SKU + /// GTIN /// Product - Product GetProductByGtin(string sku); - + Product GetProductByGtin(string gtin); + + /// + /// Gets a product by manufacturer part number (MPN) + /// + /// Manufacturer part number + /// Product + Product GetProductByManufacturerPartNumber(string manufacturerPartNumber); + + /// + /// Gets a product by name + /// + /// Product name + /// Product + Product GetProductByName(string name); + /// /// Adjusts inventory /// /// Shopping cart item /// A value indicating whether to increase or descrease product stock quantity - void AdjustInventory(OrganizedShoppingCartItem sci, bool decrease); + /// Adjust inventory result + AdjustInventoryResult AdjustInventory(OrganizedShoppingCartItem sci, bool decrease); /// /// Adjusts inventory @@ -109,7 +137,8 @@ public partial interface IProductService /// Order item /// A value indicating whether to increase or descrease product stock quantity /// Quantity - void AdjustInventory(OrderItem orderItem, bool decrease, int quantity); + /// Adjust inventory result + AdjustInventoryResult AdjustInventory(OrderItem orderItem, bool decrease, int quantity); /// /// Adjusts inventory @@ -118,7 +147,8 @@ public partial interface IProductService /// A value indicating whether to increase or descrease product stock quantity /// Quantity /// Attributes in XML format - void AdjustInventory(Product product, bool decrease, int quantity, string attributesXml); + /// Adjust inventory result + AdjustInventoryResult AdjustInventory(Product product, bool decrease, int quantity, string attributesXml); /// /// Update HasTierPrices property (used for performance optimization) @@ -138,6 +168,27 @@ public partial interface IProductService /// Product void UpdateHasDiscountsApplied(Product product); + /// + /// Get product tags by product identifiers + /// + /// Product identifiers + /// Map of product tags + Multimap GetProductTagsByProductIds(int[] productIds); + + /// + /// Get applied discounts by product identifiers + /// + /// Product identifiers + /// Map of applied discounts + Multimap GetAppliedDiscountsByProductIds(int[] productIds); + + /// + /// Get product specification attributes by product identifiers + /// + /// Product identifiers + /// Map of product specification attributes + Multimap GetProductSpecificationAttributesByProductIds(int[] productIds); + #endregion #region Related products @@ -175,6 +226,13 @@ public partial interface IProductService /// Related product void UpdateRelatedProduct(RelatedProduct relatedProduct); + /// + /// Ensure existence of all mutually related products + /// + /// First product identifier + /// Number of inserted related products + int EnsureMutuallyRelatedProducts(int productId1); + #endregion #region Cross-sell products @@ -220,6 +278,13 @@ public partial interface IProductService /// Cross-sells IList GetCrosssellProductsByShoppingCart(IList cart, int numberOfProducts); + /// + /// Ensure existence of all mutually cross selling products + /// + /// First product identifier + /// Number of inserted cross selling products + int EnsureMutuallyCrossSellProducts(int productId1); + #endregion #region Tier prices @@ -237,6 +302,15 @@ public partial interface IProductService /// Tier price TierPrice GetTierPriceById(int tierPriceId); + /// + /// Gets tier prices by product identifiers + /// + /// Product identifiers + /// Filter tier prices by customer + /// Filter tier prices by store + /// Map of tier prices + Multimap GetTierPricesByProductIds(int[] productIds, Customer customer = null, int storeId = 0); + /// /// Inserts a tier price /// @@ -266,6 +340,14 @@ public partial interface IProductService /// Product pictures IList GetProductPicturesByProductId(int productId); + /// + /// Get product pictures by product identifiers + /// + /// Product identifiers + /// Whether to only load the first picture for each product + /// Product pictures + Multimap GetProductPicturesByProductIds(int[] productIds, bool onlyFirstPicture = false); + /// /// Gets a product picture /// @@ -322,6 +404,14 @@ public partial interface IProductService /// List of bundle items IList GetBundleItems(int bundleProductId, bool showHidden = false); + /// + /// Get bundle items by product identifiers + /// + /// Product identifiers + /// A value indicating whether to show hidden records + /// Map of bundle items + Multimap GetBundleItemsByProductIds(int[] productIds, bool showHidden = false); + #endregion } diff --git a/src/Libraries/SmartStore.Services/Catalog/ISpecificationAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/ISpecificationAttributeService.cs index b5f2ce20bd..e9bc4a786e 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ISpecificationAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ISpecificationAttributeService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using SmartStore.Core.Domain.Catalog; namespace SmartStore.Services.Catalog @@ -20,8 +21,15 @@ public partial interface ISpecificationAttributeService /// /// Gets specification attributes /// - /// Specification attributes - IList GetSpecificationAttributes(); + /// Specification attribute query + IQueryable GetSpecificationAttributes(); + + /// + /// Gets specification attributes by identifier + /// + /// Identifiers + /// Specification attribute query + IQueryable GetSpecificationAttributesByIds(int[] ids); /// /// Deletes a specification attribute @@ -123,7 +131,6 @@ IList GetProductSpecificationAttributesByProductI /// Product specification attribute mapping void UpdateProductSpecificationAttribute(ProductSpecificationAttribute productSpecificationAttribute); - /// codehint: sm-add void UpdateProductSpecificationMapping(int specificationAttributeId, string field, bool value); #endregion diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs new file mode 100644 index 0000000000..3f7315905b --- /dev/null +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/CategoryImporter.cs @@ -0,0 +1,489 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core.Async; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Seo; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Events; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; +using SmartStore.Services.Seo; +using SmartStore.Services.Stores; +using SmartStore.Utilities; + +namespace SmartStore.Services.Catalog.Importer +{ + public class CategoryImporter : EntityImporterBase + { + private readonly IRepository _categoryRepository; + private readonly IRepository _pictureRepository; + private readonly ICommonServices _services; + private readonly ICategoryTemplateService _categoryTemplateService; + private readonly IPictureService _pictureService; + private readonly ILocalizedEntityService _localizedEntityService; + private readonly FileDownloadManager _fileDownloadManager; + + private static readonly Dictionary>> _localizableProperties = new Dictionary>> + { + { "Name", x => x.Name }, + { "FullName", x => x.FullName }, + { "Description", x => x.Description }, + { "BottomDescription", x => x.BottomDescription }, + { "MetaKeywords", x => x.MetaKeywords }, + { "MetaDescription", x => x.MetaDescription }, + { "MetaTitle", x => x.MetaTitle } + }; + + public CategoryImporter( + IRepository categoryRepository, + IRepository pictureRepository, + ICommonServices services, + ICategoryTemplateService categoryTemplateService, + IPictureService pictureService, + ILocalizedEntityService localizedEntityService, + FileDownloadManager fileDownloadManager) + { + _categoryRepository = categoryRepository; + _pictureRepository = pictureRepository; + _services = services; + _categoryTemplateService = categoryTemplateService; + _pictureService = pictureService; + _localizedEntityService = localizedEntityService; + _fileDownloadManager = fileDownloadManager; + } + + protected override void Import(ImportExecuteContext context) + { + var srcToDestId = new Dictionary(); + + var templateViewPaths = _categoryTemplateService.GetAllCategoryTemplates().ToDictionarySafe(x => x.ViewPath, x => x.Id); + + using (var scope = new DbContextScope(ctx: context.Services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) + { + var segmenter = context.DataSegmenter; + + Initialize(context); + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.GetCurrentBatch(); + + // Perf: detach all entities + _categoryRepository.Context.DetachAll(false); + + context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); + + try + { + ProcessCategories(context, batch, templateViewPaths, srcToDestId); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessCategories"); + } + + // reduce batch to saved (valid) products. + // No need to perform import operations on errored products. + batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray(); + + // update result object + context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); + context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); + + // process slugs + if (segmenter.HasColumn("SeName", true) || batch.Any(x => x.IsNew || x.NameChanged)) + { + try + { + _categoryRepository.Context.AutoDetectChangesEnabled = true; + ProcessSlugs(context, batch, typeof(Category).Name); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSlugs"); + } + finally + { + _categoryRepository.Context.AutoDetectChangesEnabled = false; + } + } + + // process store mappings + if (segmenter.HasColumn("StoreIds")) + { + try + { + ProcessStoreMappings(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessStoreMappings"); + } + } + + // localizations + try + { + ProcessLocalizations(context, batch, _localizableProperties); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessLocalizedProperties"); + } + + // process pictures + if (srcToDestId.Any() && segmenter.HasColumn("ImageUrl") && !segmenter.IsIgnored("PictureId")) + { + try + { + _categoryRepository.Context.AutoDetectChangesEnabled = true; + ProcessPictures(context, batch, srcToDestId); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessPictures"); + } + finally + { + _categoryRepository.Context.AutoDetectChangesEnabled = false; + } + } + } + + // map parent id of inserted categories + if (srcToDestId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentCategoryId") && !segmenter.IsIgnored("ParentCategoryId")) + { + segmenter.Reset(); + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.GetCurrentBatch(); + _categoryRepository.Context.DetachAll(false); + + try + { + ProcessParentMappings(context, batch, srcToDestId); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessParentMappings"); + } + } + } + } + } + + protected virtual int ProcessPictures( + ImportExecuteContext context, + IEnumerable> batch, + Dictionary srcToDestId) + { + Picture picture = null; + var equalPictureId = 0; + + foreach (var row in batch) + { + try + { + var srcId = row.GetDataValue("Id"); + var urlOrPath = row.GetDataValue("ImageUrl"); + + if (srcId != 0 && srcToDestId.ContainsKey(srcId) && urlOrPath.HasValue()) + { + var currentPictures = new List(); + var category = _categoryRepository.GetById(srcToDestId[srcId].DestinationId); + var seoName = _pictureService.GetPictureSeName(row.EntityDisplayName); + var image = CreateDownloadImage(urlOrPath, seoName, 1); + + if (category != null && image != null) + { + if (image.Url.HasValue() && !image.Success.HasValue) + { + AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image })); + } + + if ((image.Success ?? false) && File.Exists(image.Path)) + { + Succeeded(image); + var pictureBinary = File.ReadAllBytes(image.Path); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + if (category.PictureId.HasValue && (picture = _pictureRepository.GetById(category.PictureId.Value)) != null) + currentPictures.Add(picture); + + pictureBinary = _pictureService.ValidatePicture(pictureBinary); + pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out equalPictureId); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + if ((picture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, true, false, false)) != null) + { + category.PictureId = picture.Id; + + _categoryRepository.Update(category); + } + } + else + { + context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "ImageUrls"); + } + } + } + else if (image.Url.HasValue()) + { + context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls"); + } + } + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.ToAllMessages(), row.GetRowInfo(), "ImageUrls"); + } + } + + var num = _categoryRepository.Context.SaveChanges(); + + return num; + } + + protected virtual int ProcessLocalizations( + ImportExecuteContext context, + IEnumerable> batch, + string[] localizedProperties) + { + if (localizedProperties.Length == 0) + { + return 0; + } + + bool shouldSave = false; + + foreach (var row in batch) + { + foreach (var prop in localizedProperties) + { + var lambda = _localizableProperties[prop]; + foreach (var lang in context.Languages) + { + var code = lang.UniqueSeoCode; + string value; + + if (row.TryGetDataValue(prop /* ColumnName */, code, out value)) + { + _localizedEntityService.SaveLocalizedValue(row.Entity, lambda, value, lang.Id); + shouldSave = true; + } + } + } + } + + if (shouldSave) + { + // commit whole batch at once + return context.Services.DbContext.SaveChanges(); + } + + return 0; + } + + protected virtual int ProcessParentMappings( + ImportExecuteContext context, + IEnumerable> batch, + Dictionary srcToDestId) + { + foreach (var row in batch) + { + var id = row.GetDataValue("Id"); + var rawParentId = row.GetDataValue("ParentCategoryId"); + var parentId = rawParentId.ToInt(-1); + + if (id != 0 && parentId != -1 && srcToDestId.ContainsKey(id) && srcToDestId.ContainsKey(parentId)) + { + // only touch hierarchical data if child and parent were inserted + if (srcToDestId[id].Inserted && srcToDestId[parentId].Inserted && srcToDestId[id].DestinationId != 0) + { + var category = _categoryRepository.GetById(srcToDestId[id].DestinationId); + if (category != null) + { + category.ParentCategoryId = srcToDestId[parentId].DestinationId; + + _categoryRepository.Update(category); + } + } + } + } + + var num = _categoryRepository.Context.SaveChanges(); + + return num; + } + + protected virtual int ProcessCategories( + ImportExecuteContext context, + IEnumerable> batch, + Dictionary templateViewPaths, + Dictionary srcToDestId) + { + _categoryRepository.AutoCommitEnabled = true; + + Category lastInserted = null; + Category lastUpdated = null; + var defaultTemplateId = templateViewPaths["CategoryTemplate.ProductsInGridOrLines"]; + + foreach (var row in batch) + { + Category category = null; + var id = row.GetDataValue("Id"); + var name = row.GetDataValue("Name"); + + foreach (var keyName in context.KeyFieldNames) + { + switch (keyName) + { + case "Id": + if (id != 0) + category = _categoryRepository.GetById(id); + break; + case "Name": + if (name.HasValue()) + category = _categoryRepository.Table.FirstOrDefault(x => x.Name == name); + break; + } + + if (category != null) + break; + } + + if (category == null) + { + if (context.UpdateOnly) + { + ++context.Result.SkippedRecords; + continue; + } + + // a Name is required with new categories + if (!row.Segmenter.HasColumn("Name")) + { + ++context.Result.SkippedRecords; + context.Result.AddError("The 'Name' field is required for new categories. Skipping row.", row.GetRowInfo(), "Name"); + continue; + } + + category = new Category(); + } + + row.Initialize(category, name ?? category.Name); + + if (!row.IsNew && !category.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) + { + // Perf: use this later for SeName updates. + row.NameChanged = true; + } + + row.SetProperty(context.Result, (x) => x.Name); + row.SetProperty(context.Result, (x) => x.FullName); + row.SetProperty(context.Result, (x) => x.Description); + row.SetProperty(context.Result, (x) => x.BottomDescription); + row.SetProperty(context.Result, (x) => x.MetaKeywords); + row.SetProperty(context.Result, (x) => x.MetaDescription); + row.SetProperty(context.Result, (x) => x.MetaTitle); + row.SetProperty(context.Result, (x) => x.PageSize, 12); + row.SetProperty(context.Result, (x) => x.AllowCustomersToSelectPageSize, true); + row.SetProperty(context.Result, (x) => x.PageSizeOptions); + row.SetProperty(context.Result, (x) => x.PriceRanges); + row.SetProperty(context.Result, (x) => x.ShowOnHomePage); + row.SetProperty(context.Result, (x) => x.HasDiscountsApplied); + row.SetProperty(context.Result, (x) => x.Published, true); + row.SetProperty(context.Result, (x) => x.DisplayOrder); + row.SetProperty(context.Result, (x) => x.Alias); + row.SetProperty(context.Result, (x) => x.DefaultViewMode); + // With new entities, "LimitedToStores" is an implicit field, meaning + // it has to be set to true by code if it's absent but "StoreIds" exists. + row.SetProperty(context.Result, (x) => x.LimitedToStores, !row.GetDataValue>("StoreIds").IsNullOrEmpty()); + + string tvp; + if (row.TryGetDataValue("CategoryTemplateViewPath", out tvp, row.IsTransient)) + { + category.CategoryTemplateId = (tvp.HasValue() && templateViewPaths.ContainsKey(tvp) ? templateViewPaths[tvp] : defaultTemplateId); + } + + row.SetProperty(context.Result, (x) => x.CreatedOnUtc, UtcNow); + category.UpdatedOnUtc = UtcNow; + + if (id != 0 && !srcToDestId.ContainsKey(id)) + { + srcToDestId.Add(id, new ImportCategoryMapping { Inserted = row.IsTransient }); + } + + if (row.IsTransient) + { + _categoryRepository.Insert(category); + lastInserted = category; + } + else + { + _categoryRepository.Update(category); + lastUpdated = category; + } + } + + // commit whole batch at once + var num = _categoryRepository.Context.SaveChanges(); + + // get new category ids + foreach (var row in batch) + { + var id = row.GetDataValue("Id"); + + if (id != 0 && srcToDestId.ContainsKey(id)) + srcToDestId[id].DestinationId = row.Entity.Id; + } + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + { + _services.EventPublisher.EntityInserted(lastInserted); + } + + if (lastUpdated != null) + { + _services.EventPublisher.EntityUpdated(lastUpdated); + } + + return num; + } + + public static string[] SupportedKeyFields + { + get + { + return new string[] { "Id", "Name" }; + } + } + + public static string[] DefaultKeyFields + { + get + { + return new string[] { "Name", "Id" }; + } + } + + public class ImportCategoryMapping + { + public int DestinationId { get; set; } + public bool Inserted { get; set; } + } + } + +} diff --git a/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs new file mode 100644 index 0000000000..6228f5b443 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Catalog/Importer/ProductImporter.cs @@ -0,0 +1,738 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core.Async; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Events; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; +using SmartStore.Utilities; + +namespace SmartStore.Services.Catalog.Importer +{ + public class ProductImporter : EntityImporterBase + { + private readonly IRepository _productPictureRepository; + private readonly IRepository _productManufacturerRepository; + private readonly IRepository _productCategoryRepository; + private readonly IRepository _productRepository; + private readonly ICommonServices _services; + private readonly ILocalizedEntityService _localizedEntityService; + private readonly IPictureService _pictureService; + private readonly IManufacturerService _manufacturerService; + private readonly ICategoryService _categoryService; + private readonly IProductService _productService; + private readonly IProductTemplateService _productTemplateService; + private readonly FileDownloadManager _fileDownloadManager; + + private static readonly Dictionary>> _localizableProperties = new Dictionary>> + { + { "Name", x => x.Name }, + { "ShortDescription", x => x.ShortDescription }, + { "FullDescription", x => x.FullDescription }, + { "MetaKeywords", x => x.MetaKeywords }, + { "MetaDescription", x => x.MetaDescription }, + { "MetaTitle", x => x.MetaTitle }, + { "BundleTitleText", x => x.BundleTitleText } + }; + + public ProductImporter( + IRepository productPictureRepository, + IRepository productManufacturerRepository, + IRepository productCategoryRepository, + IRepository productRepository, + ICommonServices services, + ILocalizedEntityService localizedEntityService, + IPictureService pictureService, + IManufacturerService manufacturerService, + ICategoryService categoryService, + IProductService productService, + IProductTemplateService productTemplateService, + FileDownloadManager fileDownloadManager) + { + _productPictureRepository = productPictureRepository; + _productManufacturerRepository = productManufacturerRepository; + _productCategoryRepository = productCategoryRepository; + _productRepository = productRepository; + _services = services; + _localizedEntityService = localizedEntityService; + _pictureService = pictureService; + _manufacturerService = manufacturerService; + _categoryService = categoryService; + _productService = productService; + _productTemplateService = productTemplateService; + _fileDownloadManager = fileDownloadManager; + } + + protected override void Import(ImportExecuteContext context) + { + var srcToDestId = new Dictionary(); + + var templateViewPaths = _productTemplateService.GetAllProductTemplates().ToDictionarySafe(x => x.ViewPath, x => x.Id); + + using (var scope = new DbContextScope(ctx: _productRepository.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) + { + var segmenter = context.DataSegmenter; + + Initialize(context); + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.GetCurrentBatch(); + + // Perf: detach all entities + _productRepository.Context.DetachAll(false); + + context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); + + // =========================================================================== + // 1.) Import products + // =========================================================================== + try + { + ProcessProducts(context, batch, templateViewPaths, srcToDestId); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProducts"); + } + + // reduce batch to saved (valid) products. + // No need to perform import operations on errored products. + batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray(); + + // update result object + context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); + context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); + + // =========================================================================== + // 2.) Import SEO Slugs + // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE, + // as Slugs are going to be validated against existing ones in DB. + // =========================================================================== + if (segmenter.HasColumn("SeName", true) || batch.Any(x => x.IsNew || x.NameChanged)) + { + try + { + _productRepository.Context.AutoDetectChangesEnabled = true; + ProcessSlugs(context, batch, typeof(Product).Name); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessSlugs"); + } + finally + { + _productRepository.Context.AutoDetectChangesEnabled = false; + } + } + + // =========================================================================== + // 3.) Import StoreMappings + // =========================================================================== + if (segmenter.HasColumn("StoreIds")) + { + try + { + ProcessStoreMappings(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessStoreMappings"); + } + } + + // =========================================================================== + // 4.) Import Localizations + // =========================================================================== + try + { + ProcessLocalizations(context, batch, _localizableProperties); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessLocalizations"); + } + + // =========================================================================== + // 5.) Import product category mappings + // =========================================================================== + if (segmenter.HasColumn("CategoryIds")) + { + try + { + ProcessProductCategories(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductCategories"); + } + } + + // =========================================================================== + // 6.) Import product manufacturer mappings + // =========================================================================== + if (segmenter.HasColumn("ManufacturerIds")) + { + try + { + ProcessProductManufacturers(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductManufacturers"); + } + } + + // =========================================================================== + // 7.) Import product picture mappings + // =========================================================================== + if (segmenter.HasColumn("ImageUrls")) + { + try + { + ProcessProductPictures(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessProductPictures"); + } + } + } + + // =========================================================================== + // 8.) Map parent id of inserted products + // =========================================================================== + if (srcToDestId.Any() && segmenter.HasColumn("Id") && segmenter.HasColumn("ParentGroupedProductId") && !segmenter.IsIgnored("ParentGroupedProductId")) + { + segmenter.Reset(); + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.GetCurrentBatch(); + + _productRepository.Context.DetachAll(false); + + try + { + ProcessProductMappings(context, batch, srcToDestId); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessParentMappings"); + } + } + } + } + } + + protected virtual int ProcessProducts( + ImportExecuteContext context, + IEnumerable> batch, + Dictionary templateViewPaths, + Dictionary srcToDestId) + { + _productRepository.AutoCommitEnabled = false; + + Product lastInserted = null; + Product lastUpdated = null; + var defaultTemplateId = templateViewPaths["ProductTemplate.Simple"]; + + foreach (var row in batch) + { + Product product = null; + var id = row.GetDataValue("Id"); + + foreach (var keyName in context.KeyFieldNames) + { + var keyValue = row.GetDataValue(keyName); + + if (keyValue.HasValue() || id > 0) + { + switch (keyName) + { + case "Id": + product = _productService.GetProductById(id); + break; + case "Sku": + product = _productService.GetProductBySku(keyValue); + break; + case "Gtin": + product = _productService.GetProductByGtin(keyValue); + break; + case "ManufacturerPartNumber": + product = _productService.GetProductByManufacturerPartNumber(keyValue); + break; + case "Name": + product = _productService.GetProductByName(keyValue); + break; + } + } + + if (product != null) + break; + } + + if (product == null) + { + if (context.UpdateOnly) + { + ++context.Result.SkippedRecords; + continue; + } + + // a Name is required for new products. + if (!row.HasDataValue("Name")) + { + ++context.Result.SkippedRecords; + context.Result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name"); + continue; + } + + product = new Product(); + } + + var name = row.GetDataValue("Name"); + + row.Initialize(product, name ?? product.Name); + + if (!row.IsNew) + { + if (!product.Name.Equals(name, StringComparison.OrdinalIgnoreCase)) + { + // Perf: use this later for SeName updates. + row.NameChanged = true; + } + } + + row.SetProperty(context.Result, (x) => x.ProductTypeId, (int)ProductType.SimpleProduct); + row.SetProperty(context.Result, (x) => x.VisibleIndividually, true); + row.SetProperty(context.Result, (x) => x.Name); + row.SetProperty(context.Result, (x) => x.ShortDescription); + row.SetProperty(context.Result, (x) => x.FullDescription); + row.SetProperty(context.Result, (x) => x.AdminComment); + row.SetProperty(context.Result, (x) => x.ShowOnHomePage); + row.SetProperty(context.Result, (x) => x.HomePageDisplayOrder); + row.SetProperty(context.Result, (x) => x.MetaKeywords); + row.SetProperty(context.Result, (x) => x.MetaDescription); + row.SetProperty(context.Result, (x) => x.MetaTitle); + row.SetProperty(context.Result, (x) => x.AllowCustomerReviews, true); + row.SetProperty(context.Result, (x) => x.ApprovedRatingSum); + row.SetProperty(context.Result, (x) => x.NotApprovedRatingSum); + row.SetProperty(context.Result, (x) => x.ApprovedTotalReviews); + row.SetProperty(context.Result, (x) => x.NotApprovedTotalReviews); + row.SetProperty(context.Result, (x) => x.Published, true); + row.SetProperty(context.Result, (x) => x.Sku); + row.SetProperty(context.Result, (x) => x.ManufacturerPartNumber); + row.SetProperty(context.Result, (x) => x.Gtin); + row.SetProperty(context.Result, (x) => x.IsGiftCard); + row.SetProperty(context.Result, (x) => x.GiftCardTypeId); + row.SetProperty(context.Result, (x) => x.RequireOtherProducts); + row.SetProperty(context.Result, (x) => x.RequiredProductIds); // TODO: global scope + row.SetProperty(context.Result, (x) => x.AutomaticallyAddRequiredProducts); + row.SetProperty(context.Result, (x) => x.IsDownload); + row.SetProperty(context.Result, (x) => x.DownloadId); + row.SetProperty(context.Result, (x) => x.UnlimitedDownloads, true); + row.SetProperty(context.Result, (x) => x.MaxNumberOfDownloads, 10); + row.SetProperty(context.Result, (x) => x.DownloadExpirationDays); + row.SetProperty(context.Result, (x) => x.DownloadActivationTypeId, 1); + row.SetProperty(context.Result, (x) => x.HasSampleDownload); + row.SetProperty(context.Result, (x) => x.SampleDownloadId, (int?)null, ZeroToNull); // TODO: global scope + row.SetProperty(context.Result, (x) => x.HasUserAgreement); + row.SetProperty(context.Result, (x) => x.UserAgreementText); + row.SetProperty(context.Result, (x) => x.IsRecurring); + row.SetProperty(context.Result, (x) => x.RecurringCycleLength, 100); + row.SetProperty(context.Result, (x) => x.RecurringCyclePeriodId); + row.SetProperty(context.Result, (x) => x.RecurringTotalCycles, 10); + row.SetProperty(context.Result, (x) => x.IsShipEnabled, true); + row.SetProperty(context.Result, (x) => x.IsFreeShipping); + row.SetProperty(context.Result, (x) => x.AdditionalShippingCharge); + row.SetProperty(context.Result, (x) => x.IsEsd); + row.SetProperty(context.Result, (x) => x.IsTaxExempt); + row.SetProperty(context.Result, (x) => x.TaxCategoryId, 1); // TODO: global scope + row.SetProperty(context.Result, (x) => x.ManageInventoryMethodId); + row.SetProperty(context.Result, (x) => x.StockQuantity, 10000); + row.SetProperty(context.Result, (x) => x.DisplayStockAvailability); + row.SetProperty(context.Result, (x) => x.DisplayStockQuantity); + row.SetProperty(context.Result, (x) => x.MinStockQuantity); + row.SetProperty(context.Result, (x) => x.LowStockActivityId); + row.SetProperty(context.Result, (x) => x.NotifyAdminForQuantityBelow, 1); + row.SetProperty(context.Result, (x) => x.BackorderModeId); + row.SetProperty(context.Result, (x) => x.AllowBackInStockSubscriptions); + row.SetProperty(context.Result, (x) => x.OrderMinimumQuantity, 1); + row.SetProperty(context.Result, (x) => x.OrderMaximumQuantity, 10000); + row.SetProperty(context.Result, (x) => x.AllowedQuantities); + row.SetProperty(context.Result, (x) => x.DisableBuyButton); + row.SetProperty(context.Result, (x) => x.DisableWishlistButton); + row.SetProperty(context.Result, (x) => x.AvailableForPreOrder); + row.SetProperty(context.Result, (x) => x.CallForPrice); + row.SetProperty(context.Result, (x) => x.Price); + row.SetProperty(context.Result, (x) => x.OldPrice); + row.SetProperty(context.Result, (x) => x.ProductCost); + row.SetProperty(context.Result, (x) => x.SpecialPrice); + row.SetProperty(context.Result, (x) => x.SpecialPriceStartDateTimeUtc); + row.SetProperty(context.Result, (x) => x.SpecialPriceEndDateTimeUtc); + row.SetProperty(context.Result, (x) => x.CustomerEntersPrice); + row.SetProperty(context.Result, (x) => x.MinimumCustomerEnteredPrice); + row.SetProperty(context.Result, (x) => x.MaximumCustomerEnteredPrice, 1000); + // HasTierPrices... ignore as long as no tier prices are imported + // LowestAttributeCombinationPrice... ignore as long as no combinations are imported + row.SetProperty(context.Result, (x) => x.Weight); + row.SetProperty(context.Result, (x) => x.Length); + row.SetProperty(context.Result, (x) => x.Width); + row.SetProperty(context.Result, (x) => x.Height); + row.SetProperty(context.Result, (x) => x.DisplayOrder); + row.SetProperty(context.Result, (x) => x.DeliveryTimeId); // TODO: global scope + row.SetProperty(context.Result, (x) => x.QuantityUnitId); // TODO: global scope + row.SetProperty(context.Result, (x) => x.BasePriceEnabled); + row.SetProperty(context.Result, (x) => x.BasePriceMeasureUnit); + row.SetProperty(context.Result, (x) => x.BasePriceAmount); + row.SetProperty(context.Result, (x) => x.BasePriceBaseAmount); + row.SetProperty(context.Result, (x) => x.BundleTitleText); + row.SetProperty(context.Result, (x) => x.BundlePerItemShipping); + row.SetProperty(context.Result, (x) => x.BundlePerItemPricing); + row.SetProperty(context.Result, (x) => x.BundlePerItemShoppingCart); + row.SetProperty(context.Result, (x) => x.AvailableStartDateTimeUtc); + row.SetProperty(context.Result, (x) => x.AvailableEndDateTimeUtc); + // With new entities, "LimitedToStores" is an implicit field, meaning + // it has to be set to true by code if it's absent but "StoreIds" exists. + row.SetProperty(context.Result, (x) => x.LimitedToStores, !row.GetDataValue>("StoreIds").IsNullOrEmpty()); + + string tvp; + if (row.TryGetDataValue("ProductTemplateViewPath", out tvp, row.IsTransient)) + { + product.ProductTemplateId = (tvp.HasValue() && templateViewPaths.ContainsKey(tvp) ? templateViewPaths[tvp] : defaultTemplateId); + } + + row.SetProperty(context.Result, (x) => x.CreatedOnUtc, UtcNow); + product.UpdatedOnUtc = UtcNow; + + if (id != 0 && !srcToDestId.ContainsKey(id)) + { + srcToDestId.Add(id, new ImportProductMapping { Inserted = row.IsTransient }); + } + + if (row.IsTransient) + { + _productRepository.Insert(product); + lastInserted = product; + } + else + { + _productRepository.Update(product); + lastUpdated = product; + } + } + + // commit whole batch at once + var num = _productRepository.Context.SaveChanges(); + + // get new product ids + foreach (var row in batch) + { + var id = row.GetDataValue("Id"); + + if (id != 0 && srcToDestId.ContainsKey(id)) + srcToDestId[id].DestinationId = row.Entity.Id; + } + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + { + _services.EventPublisher.EntityInserted(lastInserted); + } + + if (lastUpdated != null) + { + _services.EventPublisher.EntityUpdated(lastUpdated); + } + + return num; + } + + protected virtual int ProcessProductMappings( + ImportExecuteContext context, + IEnumerable> batch, + Dictionary srcToDestId) + { + _productRepository.AutoCommitEnabled = false; + + foreach (var row in batch) + { + var id = row.GetDataValue("Id"); + var parentGroupedProductId = row.GetDataValue("ParentGroupedProductId"); + + if (id != 0 && parentGroupedProductId != 0 && srcToDestId.ContainsKey(id) && srcToDestId.ContainsKey(parentGroupedProductId)) + { + // only touch relationship if child and parent were inserted + if (srcToDestId[id].Inserted && srcToDestId[parentGroupedProductId].Inserted && srcToDestId[id].DestinationId != 0) + { + var product = _productRepository.GetById(srcToDestId[id].DestinationId); + if (product != null) + { + product.ParentGroupedProductId = srcToDestId[parentGroupedProductId].DestinationId; + _productRepository.Update(product); + } + } + } + } + + var num = _productRepository.Context.SaveChanges(); + + return num; + } + + protected virtual void ProcessProductPictures(ImportExecuteContext context, IEnumerable> batch) + { + // true, cause pictures must be saved and assigned an id prior adding a mapping. + _productPictureRepository.AutoCommitEnabled = true; + + ProductPicture lastInserted = null; + var equalPictureId = 0; + var numberOfPictures = (context.ExtraData.NumberOfPictures ?? int.MaxValue); + + foreach (var row in batch) + { + var imageUrls = row.GetDataValue>("ImageUrls"); + if (imageUrls.IsNullOrEmpty()) + continue; + + var imageNumber = 0; + var displayOrder = -1; + var seoName = _pictureService.GetPictureSeName(row.EntityDisplayName); + var imageFiles = new List(); + + // collect required image file infos + foreach (var urlOrPath in imageUrls) + { + var image = CreateDownloadImage(urlOrPath, seoName, ++imageNumber); + + if (image != null) + imageFiles.Add(image); + + if (imageFiles.Count >= numberOfPictures) + break; + } + + // download images + if (imageFiles.Any(x => x.Url.HasValue())) + { + // async downloading in batch processing is inefficient cause only the image processing benefits from async, + // not the record processing itself. a per record processing may speed up the import. + + AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, imageFiles.Where(x => x.Url.HasValue() && !x.Success.HasValue))); + } + + // import images + foreach (var image in imageFiles.OrderBy(x => x.DisplayOrder)) + { + try + { + if ((image.Success ?? false) && File.Exists(image.Path)) + { + Succeeded(image); + var pictureBinary = File.ReadAllBytes(image.Path); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + var currentProductPictures = _productPictureRepository.TableUntracked.Expand(x => x.Picture) + .Where(x => x.ProductId == row.Entity.Id) + .ToList(); + + var currentPictures = currentProductPictures + .Select(x => x.Picture) + .ToList(); + + if (displayOrder == -1) + { + displayOrder = (currentProductPictures.Any() ? currentProductPictures.Select(x => x.DisplayOrder).Max() : 0); + } + + pictureBinary = _pictureService.ValidatePicture(pictureBinary); + pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out equalPictureId); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + // no equal picture found in sequence + var newPicture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, true, false, false); + if (newPicture != null) + { + var mapping = new ProductPicture + { + ProductId = row.Entity.Id, + PictureId = newPicture.Id, + DisplayOrder = ++displayOrder + }; + + _productPictureRepository.Insert(mapping); + lastInserted = mapping; + } + } + else + { + context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString()); + } + } + } + else if (image.Url.HasValue()) + { + context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString()); + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.ToAllMessages(), row.GetRowInfo(), "ImageUrls" + image.DisplayOrder.ToString()); + } + } + } + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + { + _services.EventPublisher.EntityInserted(lastInserted); + } + } + + protected virtual int ProcessProductManufacturers(ImportExecuteContext context, IEnumerable> batch) + { + _productManufacturerRepository.AutoCommitEnabled = false; + + ProductManufacturer lastInserted = null; + + foreach (var row in batch) + { + var manufacturerIds = row.GetDataValue>("ManufacturerIds"); + if (!manufacturerIds.IsNullOrEmpty()) + { + try + { + foreach (var id in manufacturerIds) + { + if (_productManufacturerRepository.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null) + { + // ensure that manufacturer exists + var manufacturer = _manufacturerService.GetManufacturerById(id); + if (manufacturer != null) + { + var productManufacturer = new ProductManufacturer + { + ProductId = row.Entity.Id, + ManufacturerId = manufacturer.Id, + IsFeaturedProduct = false, + DisplayOrder = 1 + }; + _productManufacturerRepository.Insert(productManufacturer); + lastInserted = productManufacturer; + } + } + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "ManufacturerIds"); + } + } + } + + // commit whole batch at once + var num = _productManufacturerRepository.Context.SaveChanges(); + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + + return num; + } + + protected virtual int ProcessProductCategories(ImportExecuteContext context, IEnumerable> batch) + { + _productCategoryRepository.AutoCommitEnabled = false; + + ProductCategory lastInserted = null; + + foreach (var row in batch) + { + var categoryIds = row.GetDataValue>("CategoryIds"); + if (!categoryIds.IsNullOrEmpty()) + { + try + { + foreach (var id in categoryIds) + { + if (_productCategoryRepository.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.CategoryId == id).FirstOrDefault() == null) + { + // ensure that category exists + var category = _categoryService.GetCategoryById(id); + if (category != null) + { + var productCategory = new ProductCategory + { + ProductId = row.Entity.Id, + CategoryId = category.Id, + IsFeaturedProduct = false, + DisplayOrder = 1 + }; + _productCategoryRepository.Insert(productCategory); + lastInserted = productCategory; + } + } + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "CategoryIds"); + } + } + } + + // commit whole batch at once + var num = _productCategoryRepository.Context.SaveChanges(); + + // Perf: notify only about LAST insertion and update + if (lastInserted != null) + _services.EventPublisher.EntityInserted(lastInserted); + + return num; + } + + + private int? ZeroToNull(object value, CultureInfo culture) + { + int result; + if (CommonHelper.TryConvert(value, culture, out result) && result > 0) + { + return result; + } + + return (int?)null; + } + + public static string[] SupportedKeyFields + { + get + { + return new string[] { "Id", "Sku", "Gtin", "ManufacturerPartNumber", "Name" }; + } + } + + public static string[] DefaultKeyFields + { + get + { + return new string[] { "Sku", "Gtin", "ManufacturerPartNumber" }; + } + } + + public class ImportProductMapping + { + public int DestinationId { get; set; } + public bool Inserted { get; set; } + } + } +} diff --git a/src/Libraries/SmartStore.Services/Catalog/ManufacturerExtensions.cs b/src/Libraries/SmartStore.Services/Catalog/ManufacturerExtensions.cs deleted file mode 100644 index 9d29a61c29..0000000000 --- a/src/Libraries/SmartStore.Services/Catalog/ManufacturerExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using SmartStore.Core.Domain.Catalog; - -namespace SmartStore.Services.Catalog -{ - /// - /// Extensions - /// - public static class ManufacturerExtensions - { - /// - /// Returns a ProductManufacturer that has the specified values - /// - /// Source - /// Product identifier - /// Manufacturer identifier - /// A ProductManufacturer that has the specified values; otherwise null - public static ProductManufacturer FindProductManufacturer(this IList source, - int productId, int manufacturerId) - { - foreach (var productManufacturer in source) - if (productManufacturer.ProductId == productId && productManufacturer.ManufacturerId == manufacturerId) - return productManufacturer; - - return null; - } - - } -} diff --git a/src/Libraries/SmartStore.Services/Catalog/ManufacturerService.cs b/src/Libraries/SmartStore.Services/Catalog/ManufacturerService.cs index ca5bdf1f8d..9128610551 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ManufacturerService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ManufacturerService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; @@ -89,6 +90,32 @@ public virtual void DeleteManufacturer(Manufacturer manufacturer) UpdateManufacturer(manufacturer); } + public virtual IQueryable GetManufacturers(bool showHidden = false, int storeId = 0) + { + var query = _manufacturerRepository.Table + .Where(m => !m.Deleted); + + if (!showHidden) + query = query.Where(m => m.Published); + + if (!QuerySettings.IgnoreMultiStore && storeId > 0) + { + query = from m in query + join sm in _storeMappingRepository.Table + on new { c1 = m.Id, c2 = "Manufacturer" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into m_sm + from sm in m_sm.DefaultIfEmpty() + where !m.LimitedToStores || storeId == sm.StoreId + select m; + + query = from m in query + group m by m.Id into mGroup + orderby mGroup.Key + select mGroup.FirstOrDefault(); + } + + return query; + } + /// /// Gets all manufacturers /// @@ -96,65 +123,43 @@ public virtual void DeleteManufacturer(Manufacturer manufacturer) /// Manufacturer collection public virtual IList GetAllManufacturers(bool showHidden = false) { - return GetAllManufacturers(null, showHidden); + return GetAllManufacturers(null, 0, showHidden); } /// /// Gets all manufacturers /// /// Manufacturer name + /// Whether to filter result by store identifier /// A value indicating whether to show hidden records /// Manufacturer collection - public virtual IList GetAllManufacturers(string manufacturerName, bool showHidden = false) + public virtual IList GetAllManufacturers(string manufacturerName, int storeId = 0, bool showHidden = false) { - var query = _manufacturerRepository.Table; - if (!showHidden) - query = query.Where(m => m.Published); - if (!String.IsNullOrWhiteSpace(manufacturerName)) - query = query.Where(m => m.Name.Contains(manufacturerName)); - query = query.Where(m => !m.Deleted); - query = query.OrderBy(m => m.DisplayOrder); - - //Store mapping - if (!showHidden) - { - //Store mapping - if (!QuerySettings.IgnoreMultiStore) - { - var currentStoreId = _storeContext.CurrentStore.Id; - query = from m in query - join sm in _storeMappingRepository.Table - on new { c1 = m.Id, c2 = "Manufacturer" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into m_sm - from sm in m_sm.DefaultIfEmpty() - where !m.LimitedToStores || currentStoreId == sm.StoreId - select m; - } + var query = GetManufacturers(showHidden, storeId); - //only distinct manufacturers (group by ID) - query = from m in query - group m by m.Id into mGroup - orderby mGroup.Key - select mGroup.FirstOrDefault(); + if (manufacturerName.HasValue()) + query = query.Where(m => m.Name.Contains(manufacturerName)); - query = query.OrderBy(m => m.DisplayOrder); - } + query = query.OrderBy(m => m.DisplayOrder) + .ThenBy(m => m.Name); var manufacturers = query.ToList(); return manufacturers; } - - /// - /// Gets all manufacturers - /// - /// Manufacturer name - /// Page index - /// Page size - /// A value indicating whether to show hidden records - /// Manufacturers - public virtual IPagedList GetAllManufacturers(string manufacturerName, - int pageIndex, int pageSize, bool showHidden = false) + + /// + /// Gets all manufacturers + /// + /// Manufacturer name + /// Page index + /// Page size + /// Whether to filter result by store identifier + /// A value indicating whether to show hidden records + /// Manufacturers + public virtual IPagedList GetAllManufacturers(string manufacturerName, + int pageIndex, int pageSize, int storeId = 0, bool showHidden = false) { - var manufacturers = GetAllManufacturers(manufacturerName, showHidden); + var manufacturers = GetAllManufacturers(manufacturerName, storeId, showHidden); return new PagedList(manufacturers, pageIndex, pageSize); } @@ -239,8 +244,7 @@ public virtual void DeleteProductManufacturer(ProductManufacturer productManufac /// Page size /// A value indicating whether to show hidden records /// Product manufacturer collection - public virtual IPagedList GetProductManufacturersByManufacturerId(int manufacturerId, - int pageIndex, int pageSize, bool showHidden = false) + public virtual IPagedList GetProductManufacturersByManufacturerId(int manufacturerId, int pageIndex, int pageSize, bool showHidden = false) { if (manufacturerId == 0) return new PagedList(new List(), pageIndex, pageSize); @@ -299,7 +303,7 @@ public virtual IList GetProductManufacturersByProductId(int string key = string.Format(PRODUCTMANUFACTURERS_ALLBYPRODUCTID_KEY, showHidden, productId, _workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id); return _cacheManager.Get(key, () => { - var query = from pm in _productManufacturerRepository.Table + var query = from pm in _productManufacturerRepository.Table.Expand(x => x.Manufacturer.Picture) join m in _manufacturerRepository.Table on pm.ManufacturerId equals m.Id where pm.ProductId == productId && @@ -336,6 +340,40 @@ orderby mGroup.Key return productManufacturers; }); } + + public virtual Multimap GetProductManufacturersByManufacturerIds(int[] manufacturerIds) + { + Guard.ArgumentNotNull(() => manufacturerIds); + + var query = _productManufacturerRepository.TableUntracked + .Where(x => manufacturerIds.Contains(x.ManufacturerId)) + .OrderBy(x => x.DisplayOrder); + + var map = query + .ToList() + .ToMultimap(x => x.ManufacturerId, x => x); + + return map; + } + + public virtual Multimap GetProductManufacturersByProductIds(int[] productIds) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from pm in _productManufacturerRepository.TableUntracked.Expand(x => x.Manufacturer).Expand(x => x.Manufacturer.Picture) + join m in _manufacturerRepository.TableUntracked on pm.ManufacturerId equals m.Id + where productIds.Contains(pm.ProductId) + select pm; + + var map = query + .OrderBy(x => x.ProductId) + .ThenBy(x => x.DisplayOrder) + .ToList() + .ToMultimap(x => x.ProductId, x => x); + + return map; + } /// /// Gets a product manufacturer mapping diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs new file mode 100644 index 0000000000..4645f4eac0 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationContext.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Discounts; + +namespace SmartStore.Services.Catalog +{ + /// + /// Cargo data to reduce database round trips during price calculation + /// + public class PriceCalculationContext + { + protected List _productIds; + private List _productIdsTierPrices; + private List _productIdsAppliedDiscounts; + + private Func> _funcAttributes; + private Func> _funcAttributeCombinations; + private Func> _funcTierPrices; + private Func> _funcProductCategories; + private Func> _funcAppliedDiscounts; + + private LazyMultimap _attributes; + private LazyMultimap _attributeCombinations; + private LazyMultimap _tierPrices; + private LazyMultimap _productCategories; + private LazyMultimap _appliedDiscounts; + + public PriceCalculationContext(IEnumerable products, + Func> attributes, + Func> attributeCombinations, + Func> tierPrices, + Func> productCategories, + Func> appliedDiscounts) + { + if (products == null) + { + _productIds = new List(); + _productIdsTierPrices = new List(); + _productIdsAppliedDiscounts = new List(); + } + else + { + _productIds = new List(products.Select(x => x.Id)); + _productIdsTierPrices = new List(products.Where(x => x.HasTierPrices).Select(x => x.Id)); + _productIdsAppliedDiscounts = new List(products.Where(x => x.HasDiscountsApplied).Select(x => x.Id)); + } + + _funcAttributes = attributes; + _funcAttributeCombinations = attributeCombinations; + _funcTierPrices = tierPrices; + _funcProductCategories = productCategories; + _funcAppliedDiscounts = appliedDiscounts; + } + + public void Clear() + { + if (_attributes != null) + _attributes.Clear(); + if (_attributeCombinations != null) + _attributeCombinations.Clear(); + if (_tierPrices != null) + _tierPrices.Clear(); + if (_productCategories != null) + _productCategories.Clear(); + if (_appliedDiscounts != null) + _appliedDiscounts.Clear(); + } + + public LazyMultimap Attributes + { + get + { + if (_attributes == null) + { + _attributes = new LazyMultimap(keys => _funcAttributes(keys), _productIds); + } + return _attributes; + } + } + + public LazyMultimap AttributeCombinations + { + get + { + if (_attributeCombinations == null) + { + _attributeCombinations = new LazyMultimap(keys => _funcAttributeCombinations(keys), _productIds); + } + return _attributeCombinations; + } + } + + public LazyMultimap TierPrices + { + get + { + if (_tierPrices == null) + { + _tierPrices = new LazyMultimap(keys => _funcTierPrices(keys), _productIdsTierPrices); + } + return _tierPrices; + } + } + + public LazyMultimap ProductCategories + { + get + { + if (_productCategories == null) + { + _productCategories = new LazyMultimap(keys => _funcProductCategories(keys), _productIds); + } + return _productCategories; + } + } + + public LazyMultimap AppliedDiscounts + { + get + { + if (_appliedDiscounts == null) + { + _appliedDiscounts = new LazyMultimap(keys => _funcAppliedDiscounts(keys), _productIdsAppliedDiscounts); + } + return _appliedDiscounts; + } + } + + public void Collect(IEnumerable productIds) + { + Attributes.Collect(productIds); + AttributeCombinations.Collect(productIds); + TierPrices.Collect(productIds); + ProductCategories.Collect(productIds); + AppliedDiscounts.Collect(productIds); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs index f770bc65a0..ca45f495d7 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceCalculationService.cs @@ -1,12 +1,16 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; -using SmartStore.Core; +using System.Web; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Orders; using SmartStore.Services.Discounts; +using SmartStore.Services.Media; +using SmartStore.Services.Tax; namespace SmartStore.Services.Catalog { @@ -15,32 +19,42 @@ namespace SmartStore.Services.Catalog /// public partial class PriceCalculationService : IPriceCalculationService { - private readonly IWorkContext _workContext; - private readonly IStoreContext _storeContext; private readonly IDiscountService _discountService; private readonly ICategoryService _categoryService; private readonly IProductAttributeParser _productAttributeParser; private readonly IProductService _productService; private readonly ShoppingCartSettings _shoppingCartSettings; private readonly CatalogSettings _catalogSettings; + private readonly IProductAttributeService _productAttributeService; + private readonly IDownloadService _downloadService; + private readonly ICommonServices _services; + private readonly HttpRequestBase _httpRequestBase; + private readonly ITaxService _taxService; - public PriceCalculationService(IWorkContext workContext, - IStoreContext storeContext, + public PriceCalculationService( IDiscountService discountService, ICategoryService categoryService, IProductAttributeParser productAttributeParser, IProductService productService, ShoppingCartSettings shoppingCartSettings, - CatalogSettings catalogSettings) + CatalogSettings catalogSettings, + IProductAttributeService productAttributeService, + IDownloadService downloadService, + ICommonServices services, + HttpRequestBase httpRequestBase, + ITaxService taxService) { - this._workContext = workContext; - this._storeContext = storeContext; this._discountService = discountService; this._categoryService = categoryService; this._productAttributeParser = productAttributeParser; this._productService = productService; this._shoppingCartSettings = shoppingCartSettings; this._catalogSettings = catalogSettings; + this._productAttributeService = productAttributeService; + this._downloadService = downloadService; + this._services = services; + this._httpRequestBase = httpRequestBase; + this._taxService = taxService; } #region Utilities @@ -51,30 +65,44 @@ public PriceCalculationService(IWorkContext workContext, /// Product /// Customer /// Discounts - protected virtual IList GetAllowedDiscounts(Product product, - Customer customer) + protected virtual IList GetAllowedDiscounts(Product product, Customer customer, PriceCalculationContext context = null) { - var allowedDiscounts = new List(); + var result = new List(); if (_catalogSettings.IgnoreDiscounts) - return allowedDiscounts; + return result; if (product.HasDiscountsApplied) { //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls - foreach (var discount in product.AppliedDiscounts) - { - if (_discountService.IsDiscountValid(discount, customer) && - discount.DiscountType == DiscountType.AssignedToSkus && - !allowedDiscounts.ContainsDiscount(discount)) - allowedDiscounts.Add(discount); - } + IEnumerable appliedDiscounts = null; + + if (context == null) + appliedDiscounts = product.AppliedDiscounts; + else + appliedDiscounts = context.AppliedDiscounts.Load(product.Id); + + if (appliedDiscounts != null) + { + foreach (var discount in appliedDiscounts) + { + if (discount.DiscountType == DiscountType.AssignedToSkus && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) + { + result.Add(discount); + } + } + } } - //performance optimization - //load all category discounts just to ensure that we have at least one + //performance optimization. load all category discounts just to ensure that we have at least one if (_discountService.GetAllDiscounts(DiscountType.AssignedToCategories).Any()) { - var productCategories = _categoryService.GetProductCategoriesByProductId(product.Id); + IEnumerable productCategories = null; + + if (context == null) + productCategories = _categoryService.GetProductCategoriesByProductId(product.Id); + else + productCategories = context.ProductCategories.Load(product.Id); + if (productCategories != null) { foreach (var productCategory in productCategories) @@ -85,38 +113,20 @@ protected virtual IList GetAllowedDiscounts(Product product, { //we use this property ("HasDiscountsApplied") for performance optimziation to avoid unnecessary database calls var categoryDiscounts = category.AppliedDiscounts; + foreach (var discount in categoryDiscounts) { - if (_discountService.IsDiscountValid(discount, customer) && - discount.DiscountType == DiscountType.AssignedToCategories && - !allowedDiscounts.ContainsDiscount(discount)) - allowedDiscounts.Add(discount); + if (discount.DiscountType == DiscountType.AssignedToCategories && !result.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) + { + result.Add(discount); + } } } } } } - return allowedDiscounts; - } - - /// - /// Gets a preferred discount - /// - /// Product - /// Customer - /// Additional charge - /// Product quantity - /// Preferred discount - protected virtual Discount GetPreferredDiscount(Product product, - Customer customer, decimal additionalCharge = decimal.Zero, int quantity = 1) - { - if (_catalogSettings.IgnoreDiscounts) - return null; - var allowedDiscounts = GetAllowedDiscounts(product, customer); - decimal finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity); - var preferredDiscount = allowedDiscounts.GetPreferredDiscount(finalPriceWithoutDiscount); - return preferredDiscount; + return result; } /// @@ -126,20 +136,34 @@ protected virtual Discount GetPreferredDiscount(Product product, /// Customer /// Quantity /// Price - protected virtual decimal? GetMinimumTierPrice(Product product, Customer customer, int quantity) + protected virtual decimal? GetMinimumTierPrice(Product product, Customer customer, int quantity, PriceCalculationContext context = null) { - if (!product.HasTierPrices) + if (!product.HasTierPrices) return decimal.Zero; - var tierPrices = product.TierPrices - .OrderBy(tp => tp.Quantity) - .FilterByStore(_storeContext.CurrentStore.Id) - .FilterForCustomer(customer) - .ToList() - .RemoveDuplicatedQuantities(); + IEnumerable tierPrices = null; + + if (context == null) + { + tierPrices = product.TierPrices + .OrderBy(tp => tp.Quantity) + .FilterByStore(_services.StoreContext.CurrentStore.Id) + .FilterForCustomer(customer) + .ToList() + .RemoveDuplicatedQuantities(); + } + else + { + tierPrices = context.TierPrices.Load(product.Id) + .RemoveDuplicatedQuantities(); + } + + if (tierPrices == null) + return decimal.Zero; int previousQty = 1; decimal? previousPrice = null; + foreach (var tierPrice in tierPrices) { //check quantity @@ -156,6 +180,120 @@ protected virtual Discount GetPreferredDiscount(Product product, return previousPrice; } + protected virtual decimal GetPreselectedPrice(Product product, PriceCalculationContext context, ProductBundleItemData bundleItem, IEnumerable bundleItems) + { + var taxRate = decimal.Zero; + var attributesTotalPriceBase = decimal.Zero; + var preSelectedPriceAdjustmentBase = decimal.Zero; + var isBundle = (product.ProductType == ProductType.BundledProduct); + var isBundleItemPricing = (bundleItem != null && bundleItem.Item.BundleProduct.BundlePerItemPricing); + var isBundlePricing = (bundleItem != null && !bundleItem.Item.BundleProduct.BundlePerItemPricing); + var bundleItemId = (bundleItem == null ? 0 : bundleItem.Item.Id); + + var selectedAttributes = new NameValueCollection(); + var selectedAttributeValues = new List(); + var attributes = context.Attributes.Load(product.Id); + + // 1. fill selectedAttributes with initially selected attributes + foreach (var attribute in attributes.Where(x => x.ProductVariantAttributeValues.Count > 0 && x.ShouldHaveValues())) + { + int preSelectedValueId = 0; + ProductVariantAttributeValue defaultValue = null; + var selectedValueIds = new List(); + var pvaValues = attribute.ProductVariantAttributeValues; + + foreach (var pvaValue in pvaValues) + { + ProductBundleItemAttributeFilter attributeFilter = null; + + if (bundleItem.FilterOut(pvaValue, out attributeFilter)) + continue; + + if (preSelectedValueId == 0 && attributeFilter != null && attributeFilter.IsPreSelected) + preSelectedValueId = attributeFilter.AttributeValueId; + + if (!isBundlePricing && pvaValue.IsPreSelected) + { + decimal attributeValuePriceAdjustment = GetProductVariantAttributeValuePriceAdjustment(pvaValue); + decimal priceAdjustmentBase = _taxService.GetProductPrice(product, attributeValuePriceAdjustment, out taxRate); + + preSelectedPriceAdjustmentBase = decimal.Add(preSelectedPriceAdjustmentBase, priceAdjustmentBase); + } + } + + // value pre-selected by a bundle item filter discards the default pre-selection + if (preSelectedValueId != 0 && (defaultValue = pvaValues.FirstOrDefault(x => x.Id == preSelectedValueId)) != null) + { + //defaultValue.IsPreSelected = true; + selectedAttributeValues.Add(defaultValue); + selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, defaultValue.Id, product.Id, bundleItemId); + } + else + { + foreach (var value in pvaValues.Where(x => x.IsPreSelected)) + { + selectedAttributeValues.Add(value); + selectedAttributes.AddProductAttribute(attribute.ProductAttributeId, attribute.Id, value.Id, product.Id, bundleItemId); + } + } + } + + // 2. find attribute combination for selected attributes and merge it + if (!isBundle && selectedAttributes.Count > 0) + { + var attributeXml = selectedAttributes.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _services.Localization, + _downloadService, _catalogSettings, _httpRequestBase, new List(), true, bundleItemId); + + var combinations = context.AttributeCombinations.Load(product.Id); + + var selectedCombination = combinations.FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, attributeXml)); + + if (selectedCombination != null && selectedCombination.IsActive && selectedCombination.Price.HasValue) + { + product.MergedDataValues = new Dictionary { { "Price", selectedCombination.Price.Value } }; + + if (selectedCombination.BasePriceAmount.HasValue) + product.MergedDataValues.Add("BasePriceAmount", selectedCombination.BasePriceAmount.Value); + + if (selectedCombination.BasePriceBaseAmount.HasValue) + product.MergedDataValues.Add("BasePriceBaseAmount", selectedCombination.BasePriceBaseAmount.Value); + } + } + + if (_catalogSettings.EnableDynamicPriceUpdate && !isBundlePricing) + { + if (selectedAttributeValues.Count > 0) + { + selectedAttributeValues.Each(x => attributesTotalPriceBase += GetProductVariantAttributeValuePriceAdjustment(x)); + } + else + { + attributesTotalPriceBase = preSelectedPriceAdjustmentBase; + } + } + + if (bundleItem != null) + { + bundleItem.AdditionalCharge = attributesTotalPriceBase; + } + + var result = GetFinalPrice(product, bundleItems, _services.WorkContext.CurrentCustomer, attributesTotalPriceBase, true, 1, bundleItem, context); + return result; + } + + public virtual PriceCalculationContext CreatePriceCalculationContext(IEnumerable products = null) + { + var context = new PriceCalculationContext(products, + x => _productAttributeService.GetProductVariantAttributesByProductIds(x, null), + x => _productAttributeService.GetProductVariantAttributeCombinations(x), + x => _productService.GetTierPricesByProductIds(x, _services.WorkContext.CurrentCustomer, _services.StoreContext.CurrentStore.Id), + x => _categoryService.GetProductCategoriesByProductIds(x, true), + x => _productService.GetAppliedDiscountsByProductIds(x) + ); + + return context; + } + #endregion #region Methods @@ -200,7 +338,7 @@ protected virtual Discount GetPreferredDiscount(Product product, public virtual decimal GetFinalPrice(Product product, bool includeDiscounts) { - var customer = _workContext.CurrentCustomer; + var customer = _services.WorkContext.CurrentCustomer; return GetFinalPrice(product, customer, includeDiscounts); } @@ -234,22 +372,14 @@ public virtual decimal GetFinalPrice(Product product, return GetFinalPrice(product, customer, additionalCharge, includeDiscounts, 1); } - /// - /// Gets the final price - /// - /// Product - /// The customer - /// Additional charge - /// A value indicating whether include discounts or not for final price computation - /// Shopping cart item quantity - /// A product bundle item - /// Final price - public virtual decimal GetFinalPrice(Product product, + public virtual decimal GetFinalPrice( + Product product, Customer customer, decimal additionalCharge, bool includeDiscounts, int quantity, - ProductBundleItemData bundleItem = null) + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null) { //initial price decimal result = product.Price; @@ -262,40 +392,38 @@ public virtual decimal GetFinalPrice(Product product, //tier prices if (product.HasTierPrices && !bundleItem.IsValid()) { - decimal? tierPrice = GetMinimumTierPrice(product, customer, quantity); - if (tierPrice.HasValue) - result = Math.Min(result, tierPrice.Value); + decimal? tierPrice = GetMinimumTierPrice(product, customer, quantity, context); + if (tierPrice.HasValue) + result = Math.Min(result, tierPrice.Value); } //discount + additional charge if (includeDiscounts) { Discount appliedDiscount = null; - decimal discountAmount = GetDiscountAmount(product, customer, additionalCharge, quantity, out appliedDiscount, bundleItem); + decimal discountAmount = GetDiscountAmount(product, customer, additionalCharge, quantity, out appliedDiscount, bundleItem, context); result = result + additionalCharge - discountAmount; } else { result = result + additionalCharge; } + if (result < decimal.Zero) result = decimal.Zero; + return result; } - /// - /// Gets the final price including bundle per-item pricing - /// - /// Product - /// Bundle items - /// The customer - /// Additional charge - /// A value indicating whether include discounts or not for final price computation - /// Shopping cart item quantity - /// A product bundle item - /// Final price - public virtual decimal GetFinalPrice(Product product, IList bundleItems, - Customer customer, decimal additionalCharge, bool includeDiscounts, int quantity, ProductBundleItemData bundleItem = null) + public virtual decimal GetFinalPrice( + Product product, + IEnumerable bundleItems, + Customer customer, + decimal additionalCharge, + bool includeDiscounts, + int quantity, + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null) { if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing) { @@ -304,22 +432,24 @@ public virtual decimal GetFinalPrice(Product product, IList x.IsValid())) { - var itemPrice = GetFinalPrice(itemData.Item.Product, customer, itemData.AdditionalCharge, includeDiscounts, 1, itemData); + decimal itemPrice = GetFinalPrice(itemData.Item.Product, customer, itemData.AdditionalCharge, includeDiscounts, 1, itemData, context); + result = result + decimal.Multiply(itemPrice, itemData.Item.Quantity); } return (result < decimal.Zero ? decimal.Zero : result); } - return GetFinalPrice(product, customer, additionalCharge, includeDiscounts, quantity, bundleItem); + return GetFinalPrice(product, customer, additionalCharge, includeDiscounts, quantity, bundleItem, context); } /// /// Get the lowest possible price for a product. /// /// Product + /// Object with cargo data for better performance /// Whether to display the from message. /// The lowest price. - public virtual decimal GetLowestPrice(Product product, out bool displayFromMessage) + public virtual decimal GetLowestPrice(Product product, PriceCalculationContext context, out bool displayFromMessage) { if (product == null) throw new ArgumentNullException("product"); @@ -327,15 +457,16 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa if (product.ProductType == ProductType.GroupedProduct) throw Error.InvalidOperation("Choose the other override for products of type grouped product."); - displayFromMessage = false; + // note: attribute price adjustments were never regarded here cause of many reasons + + if (context == null) + context = CreatePriceCalculationContext(); - IList bundleItems = null; bool isBundlePerItemPricing = (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing); - if (isBundlePerItemPricing) - bundleItems = _productService.GetBundleItems(product.Id); + displayFromMessage = isBundlePerItemPricing; - decimal lowestPrice = GetFinalPrice(product, bundleItems, _workContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); + var lowestPrice = GetFinalPrice(product, null, _services.WorkContext.CurrentCustomer, decimal.Zero, true, int.MaxValue, null, context); if (product.LowestAttributeCombinationPrice.HasValue && product.LowestAttributeCombinationPrice.Value < lowestPrice) { @@ -343,29 +474,29 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa displayFromMessage = true; } - if (!displayFromMessage) + if (lowestPrice == decimal.Zero && product.Price == decimal.Zero) { - foreach (var attribute in product.ProductVariantAttributes) - { - if (attribute.ProductVariantAttributeValues.Any(x => x.PriceAdjustment != decimal.Zero)) - { - displayFromMessage = true; - break; - } - } + lowestPrice = product.LowestAttributeCombinationPrice ?? decimal.Zero; + } + + if (!displayFromMessage && product.ProductType != ProductType.BundledProduct) + { + var attributes = context.Attributes.Load(product.Id); + displayFromMessage = attributes.Any(x => x.ProductVariantAttributeValues.Any(y => y.PriceAdjustment != decimal.Zero)); + } + + if (!displayFromMessage && product.HasTierPrices && !isBundlePerItemPricing) + { + var tierPrices = context.TierPrices.Load(product.Id) + .RemoveDuplicatedQuantities(); + + displayFromMessage = (tierPrices.Count > 0 && !(tierPrices.Count == 1 && tierPrices.First().Quantity <= 1)); } return lowestPrice; } - /// - /// Get the lowest price of a grouped product. - /// - /// Grouped product. - /// Products associated to product. - /// The associated product with the lowest price. - /// The lowest price. - public virtual decimal? GetLowestPrice(Product product, IEnumerable associatedProducts, out Product lowestPriceProduct) + public virtual decimal? GetLowestPrice(Product product, PriceCalculationContext context, IEnumerable associatedProducts, out Product lowestPriceProduct) { if (product == null) throw new ArgumentNullException("product"); @@ -376,12 +507,16 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa if (product.ProductType != ProductType.GroupedProduct) throw Error.InvalidOperation("Choose the other override for products not of type grouped product."); - lowestPriceProduct = product; + lowestPriceProduct = null; decimal? lowestPrice = null; + var customer = _services.WorkContext.CurrentCustomer; + + if (context == null) + context = CreatePriceCalculationContext(); foreach (var associatedProduct in associatedProducts) { - var tmpPrice = GetFinalPrice(associatedProduct, _workContext.CurrentCustomer, decimal.Zero, true, int.MaxValue); + var tmpPrice = GetFinalPrice(associatedProduct, customer, decimal.Zero, true, int.MaxValue, null, context); if (associatedProduct.LowestAttributeCombinationPrice.HasValue && associatedProduct.LowestAttributeCombinationPrice.Value < tmpPrice) { @@ -394,9 +529,55 @@ public virtual decimal GetLowestPrice(Product product, out bool displayFromMessa lowestPriceProduct = associatedProduct; } } + + if (lowestPriceProduct == null) + lowestPriceProduct = associatedProducts.FirstOrDefault(); + return lowestPrice; } + /// + /// Get the initial price including preselected attributes + /// + /// Product + /// Object with cargo data for better performance + /// Preselected price + public virtual decimal GetPreselectedPrice(Product product, PriceCalculationContext context) + { + if (product == null) + throw new ArgumentNullException("product"); + + var result = decimal.Zero; + + if (context == null) + context = CreatePriceCalculationContext(); + + if (product.ProductType == ProductType.BundledProduct) + { + var bundleItems = _productService.GetBundleItems(product.Id); + + var productIds = bundleItems.Select(x => x.Item.ProductId).ToList(); + productIds.Add(product.Id); + + context.Collect(productIds); + + foreach (var bundleItem in bundleItems.Where(x => x.Item.Product.CanBeBundleItem())) + { + // fetch bundleItems.AdditionalCharge for all bundle items + var unused = GetPreselectedPrice(bundleItem.Item.Product, context, bundleItem, bundleItems); + } + + result = GetPreselectedPrice(product, context, null, bundleItems); + } + else + { + result = GetPreselectedPrice(product, context, null, null); + } + + return result; + } + + /// /// Gets the product cost /// @@ -413,6 +594,7 @@ public virtual decimal GetProductCost(Product product, string attributesXml) _productAttributeParser .ParseProductVariantAttributeValues(attributesXml) .Where(x => x.ValueType == ProductVariantAttributeValueType.ProductLinkage) + .ToList() .Each(x => { var linkedProduct = _productService.GetProductById(x.LinkedProductId); @@ -431,7 +613,7 @@ public virtual decimal GetProductCost(Product product, string attributesXml) /// Discount amount public virtual decimal GetDiscountAmount(Product product) { - var customer = _workContext.CurrentCustomer; + var customer = _services.WorkContext.CurrentCustomer; return GetDiscountAmount(product, customer, decimal.Zero); } @@ -478,52 +660,56 @@ public virtual decimal GetDiscountAmount(Product product, return GetDiscountAmount(product, customer, additionalCharge, 1, out appliedDiscount); } - /// - /// Gets discount amount - /// - /// Product - /// The customer - /// Additional charge - /// Product quantity - /// Applied discount - /// A product bundle item - /// Discount amount - public virtual decimal GetDiscountAmount(Product product, + public virtual decimal GetDiscountAmount( + Product product, Customer customer, decimal additionalCharge, int quantity, out Discount appliedDiscount, - ProductBundleItemData bundleItem = null) + ProductBundleItemData bundleItem = null, + PriceCalculationContext context = null) { appliedDiscount = null; decimal appliedDiscountAmount = decimal.Zero; + decimal finalPriceWithoutDiscount = decimal.Zero; if (bundleItem.IsValid()) { if (bundleItem.Item.Discount.HasValue && bundleItem.Item.BundleProduct.BundlePerItemPricing) { - appliedDiscount = new Discount() + appliedDiscount = new Discount { UsePercentage = bundleItem.Item.DiscountPercentage, DiscountPercentage = bundleItem.Item.Discount.Value, DiscountAmount = bundleItem.Item.Discount.Value }; + + finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context); + appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount); } } else { - //we don't apply discounts to products with price entered by a customer - if (product.CustomerEntersPrice) + // dont't apply when customer entered price or discounts should be ignored completely + if (product.CustomerEntersPrice || _catalogSettings.IgnoreDiscounts) + { return appliedDiscountAmount; + } - appliedDiscount = GetPreferredDiscount(product, customer, additionalCharge, quantity); - } + var allowedDiscounts = GetAllowedDiscounts(product, customer, context); + if (allowedDiscounts.Count == 0) + { + return appliedDiscountAmount; + } - if (appliedDiscount != null) - { - decimal finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem); - appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount); - } + finalPriceWithoutDiscount = GetFinalPrice(product, customer, additionalCharge, false, quantity, bundleItem, context); + appliedDiscount = allowedDiscounts.GetPreferredDiscount(finalPriceWithoutDiscount); + + if (appliedDiscount != null) + { + appliedDiscountAmount = appliedDiscount.GetDiscountAmount(finalPriceWithoutDiscount); + } + } return appliedDiscountAmount; } @@ -562,6 +748,11 @@ public virtual decimal GetUnitPrice(OrganizedShoppingCartItem shoppingCartItem, { if (shoppingCartItem.ChildItems != null) { + foreach (var bundleItem in shoppingCartItem.ChildItems) + { + bundleItem.Item.Product.MergeWithCombination(bundleItem.Item.AttributesXml, _productAttributeParser); + } + var bundleItems = shoppingCartItem.ChildItems.Where(x => x.BundleItemData.IsValid()).Select(x => x.BundleItemData).ToList(); finalPrice = GetFinalPrice(product, bundleItems, customer, decimal.Zero, includeDiscounts, shoppingCartItem.Item.Quantity); @@ -569,25 +760,23 @@ public virtual decimal GetUnitPrice(OrganizedShoppingCartItem shoppingCartItem, } else { - var combination = _productAttributeParser.FindProductVariantAttributeCombination(product, shoppingCartItem.Item.AttributesXml); + product.MergeWithCombination(shoppingCartItem.Item.AttributesXml, _productAttributeParser); - if (combination != null && combination.Price.HasValue) - { - finalPrice = combination.Price.Value; - } - else + var attributesTotalPrice = decimal.Zero; + + var pvaValuesEnum = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml); + + if (pvaValuesEnum != null) { - decimal attributesTotalPrice = decimal.Zero; - var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml); + var pvaValues = pvaValuesEnum.ToList(); - if (pvaValues != null) + foreach (var pvaValue in pvaValues) { - foreach (var pvaValue in pvaValues) - attributesTotalPrice += GetProductVariantAttributeValuePriceAdjustment(pvaValue); + attributesTotalPrice += GetProductVariantAttributeValuePriceAdjustment(pvaValue); } - - finalPrice = GetFinalPrice(product, customer, attributesTotalPrice, includeDiscounts, shoppingCartItem.Item.Quantity, shoppingCartItem.BundleItemData); } + + finalPrice = GetFinalPrice(product, customer, attributesTotalPrice, includeDiscounts, shoppingCartItem.Item.Quantity, shoppingCartItem.BundleItemData); } } @@ -626,7 +815,7 @@ public virtual decimal GetDiscountAmount(OrganizedShoppingCartItem shoppingCartI { decimal attributesTotalPrice = decimal.Zero; - var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml); + var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml).ToList(); foreach (var pvaValue in pvaValues) { attributesTotalPrice += GetProductVariantAttributeValuePriceAdjustment(pvaValue); diff --git a/src/Libraries/SmartStore.Services/Catalog/PriceFormatter.cs b/src/Libraries/SmartStore.Services/Catalog/PriceFormatter.cs index 3401de0113..b53310d921 100644 --- a/src/Libraries/SmartStore.Services/Catalog/PriceFormatter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/PriceFormatter.cs @@ -55,10 +55,13 @@ protected string GetCurrencyString(decimal amount, bool showCurrency, Currency t { string result = string.Empty; - IFormatProvider fmt = NumberFormatInfo.CurrentInfo; + var fmt = NumberFormatInfo.CurrentInfo; try { - fmt = CultureInfo.CreateSpecificCulture(targetCurrency.DisplayLocale); + fmt = CultureInfo.CreateSpecificCulture(targetCurrency.DisplayLocale).NumberFormat; + + if (!showCurrency) + fmt.CurrencySymbol = ""; } catch { } @@ -87,26 +90,11 @@ protected string GetCurrencyString(decimal amount, bool showCurrency, Currency t #region Methods - /// - /// Formats the price - /// - /// Price - /// Price public string FormatPrice(decimal price) { - // codehint: sm-edit - bool showCurrency = false; //true; - var targetCurrency = _workContext.WorkingCurrency; - return FormatPrice(price, showCurrency, targetCurrency); + return FormatPrice(price, true, _workContext.WorkingCurrency); } - /// - /// Formats the price - /// - /// Price - /// A value indicating whether to show a currency - /// Target currency - /// Price public string FormatPrice(decimal price, bool showCurrency, Currency targetCurrency) { var language = _workContext.WorkingLanguage; @@ -123,13 +111,6 @@ public string FormatPrice(decimal price, bool showCurrency, Currency targetCurre return FormatPrice(price, showCurrency, targetCurrency, language, priceIncludesTax); } - /// - /// Formats the price - /// - /// Price - /// A value indicating whether to show a currency - /// A value indicating whether to show tax suffix - /// Price public string FormatPrice(decimal price, bool showCurrency, bool showTax) { var targetCurrency = _workContext.WorkingCurrency; @@ -147,24 +128,9 @@ public string FormatPrice(decimal price, bool showCurrency, bool showTax) return FormatPrice(price, showCurrency, targetCurrency, language, priceIncludesTax, showTax); } - /// - /// Formats the price - /// - /// Price - /// A value indicating whether to show a currency - /// Currency code - /// A value indicating whether to show tax suffix - /// Language - /// Price - public string FormatPrice(decimal price, bool showCurrency, - string currencyCode, bool showTax, Language language) + public string FormatPrice(decimal price, bool showCurrency, string currencyCode, bool showTax, Language language) { - var currency = _currencyService.GetCurrencyByCode(currencyCode); - if (currency == null) - { - currency = new Currency(); - currency.CurrencyCode = currencyCode; - } + var currency = _currencyService.GetCurrencyByCode(currencyCode) ?? new Currency { CurrencyCode = currencyCode }; bool priceIncludesTax = false; switch (_workContext.TaxDisplayType) { @@ -180,55 +146,25 @@ public string FormatPrice(decimal price, bool showCurrency, language, priceIncludesTax, showTax); } - /// - /// Formats the price - /// - /// Price - /// A value indicating whether to show a currency - /// Currency code - /// Language - /// A value indicating whether price includes tax - /// Price - public string FormatPrice(decimal price, bool showCurrency, - string currencyCode, Language language, bool priceIncludesTax) + public string FormatPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax) { - var currency = _currencyService.GetCurrencyByCode(currencyCode); - if (currency == null) - { - currency = new Currency(); - currency.CurrencyCode = currencyCode; - } - return FormatPrice(price, showCurrency, currency, language, priceIncludesTax); + bool showTax = _taxSettings.DisplayTaxSuffix; + return FormatPrice(price, showCurrency, currencyCode, language, priceIncludesTax, showTax); } - /// - /// Formats the price - /// - /// Price - /// A value indicating whether to show a currency - /// Target currency - /// Language - /// A value indicating whether price includes tax - /// Price - public string FormatPrice(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax) + public string FormatPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax, bool showTax) + { + var currency = _currencyService.GetCurrencyByCode(currencyCode) ?? new Currency { CurrencyCode = currencyCode }; + return FormatPrice(price, showCurrency, currency, language, priceIncludesTax, showTax); + } + + public string FormatPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax) { bool showTax = _taxSettings.DisplayTaxSuffix; - return FormatPrice(price, showCurrency, targetCurrency, language, - priceIncludesTax, showTax); + return FormatPrice(price, showCurrency, targetCurrency, language, priceIncludesTax, showTax); } - /// - /// Formats the price - /// - /// Price - /// A value indicating whether to show a currency - /// Target currency - /// Language - /// A value indicating whether price includes tax - /// A value indicating whether to show tax suffix - /// Price - public string FormatPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax) + public string FormatPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax) { // Round before rendering (also take "BitCoin" into account, where more than 2 decimal places are relevant) price = targetCurrency.CurrencyCode.IsCaseInsensitiveEqual("btc") ? Math.Round(price, 6) : Math.Round(price, 2); @@ -257,12 +193,7 @@ public string FormatPrice(decimal price, bool showCurrency, Currency targetCurr } - /// - /// Formats the shipping price - /// - /// Price - /// A value indicating whether to show a currency - /// Price + public string FormatShippingPrice(decimal price, bool showCurrency) { var targetCurrency = _workContext.WorkingCurrency; @@ -280,67 +211,31 @@ public string FormatShippingPrice(decimal price, bool showCurrency) return FormatShippingPrice(price, showCurrency, targetCurrency, language, priceIncludesTax); } - /// - /// Formats the shipping price - /// - /// Price - /// A value indicating whether to show a currency - /// Target currency - /// Language - /// A value indicating whether price includes tax - /// Price - public string FormatShippingPrice(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax) + public string FormatShippingPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax) { bool showTax = _taxSettings.ShippingIsTaxable && _taxSettings.DisplayTaxSuffix; return FormatShippingPrice(price, showCurrency, targetCurrency, language, priceIncludesTax, showTax); } - /// - /// Formats the shipping price - /// - /// Price - /// A value indicating whether to show a currency - /// Target currency - /// Language - /// A value indicating whether price includes tax - /// A value indicating whether to show tax suffix - /// Price - public string FormatShippingPrice(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax) + public string FormatShippingPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax, bool showTax) + { + var currency = _currencyService.GetCurrencyByCode(currencyCode) ?? new Currency { CurrencyCode = currencyCode }; + return FormatPrice(price, showCurrency, currency, language, priceIncludesTax, showTax); + } + + public string FormatShippingPrice(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax) { return FormatPrice(price, showCurrency, targetCurrency, language, priceIncludesTax, showTax); } - /// - /// Formats the shipping price - /// - /// Price - /// A value indicating whether to show a currency - /// Currency code - /// Language - /// A value indicating whether price includes tax - /// Price - public string FormatShippingPrice(decimal price, bool showCurrency, - string currencyCode, Language language, bool priceIncludesTax) + public string FormatShippingPrice(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax) { - var currency = _currencyService.GetCurrencyByCode(currencyCode); - if (currency == null) - { - currency = new Currency(); - currency.CurrencyCode = currencyCode; - } + var currency = _currencyService.GetCurrencyByCode(currencyCode) ?? new Currency { CurrencyCode = currencyCode }; return FormatShippingPrice(price, showCurrency, currency, language, priceIncludesTax); } - /// - /// Formats the payment method additional fee - /// - /// Price - /// A value indicating whether to show a currency - /// Price public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency) { var targetCurrency = _workContext.WorkingCurrency; @@ -359,68 +254,31 @@ public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency) language, priceIncludesTax); } - /// - /// Formats the payment method additional fee - /// - /// Price - /// A value indicating whether to show a currency - /// Target currency - /// Language - /// A value indicating whether price includes tax - /// Price - public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax) + public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax) { bool showTax = _taxSettings.PaymentMethodAdditionalFeeIsTaxable && _taxSettings.DisplayTaxSuffix; return FormatPaymentMethodAdditionalFee(price, showCurrency, targetCurrency, language, priceIncludesTax, showTax); } - /// - /// Formats the payment method additional fee - /// - /// Price - /// A value indicating whether to show a currency - /// Target currency - /// Language - /// A value indicating whether price includes tax - /// A value indicating whether to show tax suffix - /// Price - public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, - Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax) + public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax, bool showTax) + { + var currency = _currencyService.GetCurrencyByCode(currencyCode) ?? new Currency { CurrencyCode = currencyCode }; + return FormatPrice(price, showCurrency, currency, language, priceIncludesTax, showTax); + } + + public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, Currency targetCurrency, Language language, bool priceIncludesTax, bool showTax) { - return FormatPrice(price, showCurrency, targetCurrency, language, - priceIncludesTax, showTax); + return FormatPrice(price, showCurrency, targetCurrency, language, priceIncludesTax, showTax); } - /// - /// Formats the payment method additional fee - /// - /// Price - /// A value indicating whether to show a currency - /// Currency code - /// Language - /// A value indicating whether price includes tax - /// Price - public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, - string currencyCode, Language language, bool priceIncludesTax) + public string FormatPaymentMethodAdditionalFee(decimal price, bool showCurrency, string currencyCode, Language language, bool priceIncludesTax) { - var currency = _currencyService.GetCurrencyByCode(currencyCode); - if (currency == null) - { - currency = new Currency(); - currency.CurrencyCode = currencyCode; - } - return FormatPaymentMethodAdditionalFee(price, showCurrency, currency, - language, priceIncludesTax); + var currency = _currencyService.GetCurrencyByCode(currencyCode) ?? new Currency { CurrencyCode = currencyCode }; + return FormatPaymentMethodAdditionalFee(price, showCurrency, currency, language, priceIncludesTax); } - /// - /// Formats a tax rate - /// - /// Tax rate - /// Formatted tax rate public string FormatTaxRate(decimal taxRate) { return taxRate.ToString("G29"); diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeFormatter.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeFormatter.cs index cf2d05e809..5bbbb5665a 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeFormatter.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeFormatter.cs @@ -182,12 +182,12 @@ public string FormatAttributes(Product product, string attributes, if (priceAdjustmentBase > 0) { - string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment, false, false); + string priceAdjustmentStr = _priceFormatter.FormatPrice(priceAdjustment, true, false); pvaAttribute += string.Format(" [+{0}]", priceAdjustmentStr); } else if (priceAdjustmentBase < decimal.Zero) { - string priceAdjustmentStr = _priceFormatter.FormatPrice(-priceAdjustment, false, false); + string priceAdjustmentStr = _priceFormatter.FormatPrice(-priceAdjustment, true, false); pvaAttribute += string.Format(" [-{0}]", priceAdjustmentStr); } } diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs index 33e5cac5d9..cf4531f322 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeParser.cs @@ -1,44 +1,60 @@ using System; -using System.Linq; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; using System.Xml; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Collections; +using System.Xml.Linq; using Newtonsoft.Json; -using System.Web; +using SmartStore.Collections; +using SmartStore.Core.Caching; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; namespace SmartStore.Services.Catalog { - /// - /// Product attribute parser - /// - public partial class ProductAttributeParser : IProductAttributeParser + /// + /// Product attribute parser + /// + public partial class ProductAttributeParser : IProductAttributeParser { - private readonly IProductAttributeService _productAttributeService; + // 0 = ProductId, 1 = AttributeXml Hash + private const string ATTRIBUTECOMBINATION_BY_ID_HASH = "SmartStore.parsedattributecombination.id-{0}-{1}"; + + private readonly IProductAttributeService _productAttributeService; + private readonly IRepository _pvacRepository; + private readonly ICacheManager _cacheManager; - public ProductAttributeParser(IProductAttributeService productAttributeService) + public ProductAttributeParser( + IProductAttributeService productAttributeService, + IRepository pvacRepository, + ICacheManager cacheManager) { - this._productAttributeService = productAttributeService; + _productAttributeService = productAttributeService; + _pvacRepository = pvacRepository; + _cacheManager = cacheManager; } - #region Product attributes + #region Product attributes - /// + /// /// Gets selected product variant attribute identifiers /// - /// Attributes + /// Attributes /// Selected product variant attribute identifiers - private IEnumerable ParseProductVariantAttributeIds(string attributes) + private IEnumerable ParseProductVariantAttributeIds(string attributesXml) { var ids = new List(); - if (String.IsNullOrEmpty(attributes)) + if (String.IsNullOrEmpty(attributesXml)) yield break; try { var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); var nodeList = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute"); foreach (var node in nodeList.Cast()) @@ -55,126 +71,177 @@ private IEnumerable ParseProductVariantAttributeIds(string attributes) } } finally { } - } - public virtual Multimap DeserializeProductVariantAttributes(string attributes) - { - var attrs = new Multimap(); - if (String.IsNullOrEmpty(attributes)) - return attrs; - - try - { - var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); - - var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute"); - foreach (var node1 in nodeList1.Cast()) // codehint: sm-edit - { - string sid = node1.GetAttribute("ID").Trim(); - if (sid.HasValue()) - { - int id = 0; - if (int.TryParse(sid, out id)) - { - - var nodeList2 = node1.SelectNodes(@"ProductVariantAttributeValue/Value").Cast(); - foreach (var node2 in nodeList2) - { - string value = node2.InnerText.Trim(); - attrs.Add(id, value); - } - } - } - } - } - catch (Exception exc) - { - Debug.Write(exc.ToString()); - } - - return attrs; - } + //public virtual Multimap DeserializeProductVariantAttributes(string attributesXml) + //{ + // var attrs = new Multimap(); + // if (String.IsNullOrEmpty(attributesXml)) + // return attrs; + + // try + // { + // var xmlDoc = new XmlDocument(); + // xmlDoc.LoadXml(attributesXml); + + // var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute"); + // foreach (var node1 in nodeList1.Cast()) + // { + // string sid = node1.GetAttribute("ID").Trim(); + // if (sid.HasValue()) + // { + // int id = 0; + // if (int.TryParse(sid, out id)) + // { + + // var nodeList2 = node1.SelectNodes(@"ProductVariantAttributeValue/Value").Cast(); + // foreach (var node2 in nodeList2) + // { + // string value = node2.InnerText.Trim(); + // attrs.Add(id, value); + // } + // } + // } + // } + // } + // catch (Exception exc) + // { + // Debug.Write(exc.ToString()); + // } + + // return attrs; + //} + + public virtual Multimap DeserializeProductVariantAttributes(string attributesXml) + { + var attrs = new Multimap(); + if (String.IsNullOrEmpty(attributesXml)) + return attrs; - /// - /// Gets selected product variant attributes - /// - /// Attributes - /// Selected product variant attributes - public virtual IList ParseProductVariantAttributes(string attributes) - { - var pvaCollection = new List(); + try + { + var doc = XDocument.Parse(attributesXml); - // codehint: sm-edit - var ids = ParseProductVariantAttributeIds(attributes); - return this.ParseProductVariantAttributes(ids.ToList()).ToList(); - } + // Attributes/ProductVariantAttribute + foreach (var node1 in doc.Descendants("ProductVariantAttribute")) + { + string sid = node1.Attribute("ID").Value; + if (sid.HasValue()) + { + int id = 0; + if (int.TryParse(sid, out id)) + { + // ProductVariantAttributeValue/Value + foreach (var node2 in node1.Descendants("Value")) + { + attrs.Add(id, node2.Value); + } + } + } + } + } + catch (Exception exc) + { + Debug.Write(exc.ToString()); + } - public virtual IEnumerable ParseProductVariantAttributes(ICollection ids) - { + return attrs; + } - if (ids != null) - { - if (ids.Count == 1) - { - var pva = _productAttributeService.GetProductVariantAttributeById(ids.ElementAt(0)); - if (pva != null) - { - return new ProductVariantAttribute[] { pva }; - } - } - else - { - return _productAttributeService.GetProductVariantAttributesByIds(ids.ToArray()).ToList(); - } - } + /// + /// Gets selected product variant attributes + /// + /// Attributes + /// Selected product variant attributes + public virtual IList ParseProductVariantAttributes(string attributesXml) + { + var ids = ParseProductVariantAttributeIds(attributesXml); - return Enumerable.Empty(); - } + return _productAttributeService.GetProductVariantAttributesByIds(ids.ToList()); + } - /// - /// Get product variant attribute values - /// - /// Attributes - /// Product variant attribute values - public virtual IEnumerable ParseProductVariantAttributeValues(string attributes) + public virtual IEnumerable ParseProductVariantAttributeValues(string attributeXml) { - var pvaValues = Enumerable.Empty(); + //var pvaValues = Enumerable.Empty(); - var attrs = DeserializeProductVariantAttributes(attributes); - var pvaCollection = ParseProductVariantAttributes(attrs.Keys); + var allIds = new List(); + var attrs = DeserializeProductVariantAttributes(attributeXml); + var pvaCollection = _productAttributeService.GetProductVariantAttributesByIds(attrs.Keys); foreach (var pva in pvaCollection) { if (!pva.ShouldHaveValues()) continue; - var pvaValuesStr = attrs[pva.Id]; //ParseValues(attributes, pva.Id); - var ids = from id in pvaValuesStr - where id.HasValue() - select id.ToInt(); - var values = _productAttributeService.GetProductVariantAttributeValuesByIds(ids.ToArray()); + var pvaValuesStr = attrs[pva.Id]; + + var ids = + from id in pvaValuesStr + where id.HasValue() + select id.ToInt(); - pvaValues = pvaValues.Concat(values); + allIds.AddRange(ids); + + //var values = _productAttributeService.GetProductVariantAttributeValuesByIds(ids.ToArray()); + //pvaValues = pvaValues.Concat(values); } - return pvaValues; + int[] allDistinctIds = allIds.Distinct().ToArray(); + + var values = _productAttributeService.GetProductVariantAttributeValuesByIds(allDistinctIds); + + return values; } - /// - /// Gets selected product variant attribute value - /// - /// Attributes - /// Product variant attribute identifier - /// Product variant attribute value - public virtual IList ParseValues(string attributes, int productVariantAttributeId) + public virtual IList ParseProductVariantAttributeValues(Multimap attributeCombination, IEnumerable attributes) + { + var result = new List(); + + if (attributeCombination == null || !attributeCombination.Any()) + return result; + + var allValueIds = new List(); + + foreach (var pva in attributes.Where(x => x.ShouldHaveValues()).OrderBy(x => x.DisplayOrder)) + { + if (attributeCombination.ContainsKey(pva.Id)) + { + var pvaValuesStr = attributeCombination[pva.Id]; + var ids = pvaValuesStr.Where(x => x.HasValue()).Select(x => x.ToInt()); + + allValueIds.AddRange(ids); + } + } + + foreach (int id in allValueIds.Distinct()) + { + foreach (var attribute in attributes) + { + var attributeValue = attribute.ProductVariantAttributeValues.FirstOrDefault(x => x.Id == id); + if (attributeValue != null && !result.Any(x => x.Id == attributeValue.Id)) + { + result.Add(attributeValue); + break; + } + } + } + + return result; + } + + /// + /// Gets selected product variant attribute value + /// + /// Attributes + /// Product variant attribute identifier + /// Product variant attribute value + public virtual IList ParseValues(string attributesXml, int productVariantAttributeId) { var selectedProductVariantAttributeValues = new List(); try { var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute"); foreach (XmlNode node1 in nodeList1) @@ -209,87 +276,80 @@ public virtual IList ParseValues(string attributes, int productVariantAt /// /// Adds an attribute /// - /// Attributes + /// Attributes /// Product variant attribute /// Value /// Attributes - public virtual string AddProductAttribute(string attributes, ProductVariantAttribute pva, string value) + public virtual string AddProductAttribute(string attributesXml, ProductVariantAttribute pva, string value) { - return pva.AddProductAttribute(attributes, value); + return pva.AddProductAttribute(attributesXml, value); } - /// - /// Are attributes equal - /// - /// The attributes of the first product - /// The attributes of the second product - /// Result - public virtual bool AreProductAttributesEqual(string attributes1, string attributes2) + public virtual bool AreProductAttributesEqual(string attributeXml1, string attributeXml2) { - // codehint: sm-edit (massiv) + if (attributeXml1.IsCaseInsensitiveEqual(attributeXml2)) + return true; - var attrs1 = DeserializeProductVariantAttributes(attributes1); - var attrs2 = DeserializeProductVariantAttributes(attributes2); + var attributes1 = DeserializeProductVariantAttributes(attributeXml1); + var attributes2 = DeserializeProductVariantAttributes(attributeXml2); - if (attrs1.Count == attrs2.Count) - { - var pva1Collection = ParseProductVariantAttributes(attrs2.Keys); - var pva2Collection = ParseProductVariantAttributes(attrs1.Keys); - foreach (var pva1 in pva1Collection) - { - foreach (var pva2 in pva2Collection) - { - if (pva1.Id == pva2.Id) - { - var pvaValues1Str = attrs2[pva1.Id]; // ParseValues(attributes2, pva1.Id); - var pvaValues2Str = attrs1[pva2.Id]; // ParseValues(attributes1, pva2.Id); - if (pvaValues1Str.Count == pvaValues2Str.Count) - { - foreach (string str1 in pvaValues1Str) - { - bool hasAttribute = pvaValues2Str.Any(x => x.IsCaseInsensitiveEqual(str1)); - if (!hasAttribute) - { - return false; - } - } - } - else - { - return false; - } - } - } - } - } - else - { - return false; - } + if (attributes1.Count != attributes2.Count) + return false; - return true; - } + foreach (var kvp in attributes1) + { + if (!attributes2.ContainsKey(kvp.Key)) + { + // the second list does not contain this id: not equal! + return false; + } - /// - /// Finds a product variant attribute combination by attributes stored in XML - /// - /// Product - /// Attributes in XML format - /// Found product variant attribute combination - public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(Product product, string attributesXml) - { - if (product == null) - throw new ArgumentNullException("product"); + // compare the values + var values1 = kvp.Value; + var values2 = attributes2[kvp.Key]; - return FindProductVariantAttributeCombination(product.Id, attributesXml); + if (values1.Count != values2.Count) + { + // number of values differ: not equal! + return false; + } + + foreach (var value1 in values1) + { + var str1 = value1.TrimSafe(); + + if (!values2.Any(x => x.TrimSafe().IsCaseInsensitiveEqual(str1))) + { + // the second values list for this attribute does not contain this value: not equal! + return false; + } + } + } + + return true; } - public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination(int productId, string attributesXml) + public virtual ProductVariantAttributeCombination FindProductVariantAttributeCombination( + int productId, + string attributesXml) { - if (attributesXml.HasValue()) + if (attributesXml.IsEmpty()) + return null; + + var attributesHash = attributesXml.Hash(Encoding.UTF8); + var cacheKey = ATTRIBUTECOMBINATION_BY_ID_HASH.FormatInvariant(productId, attributesHash); + + var result = _cacheManager.Get(cacheKey, () => { - //existing combinations - var combinations = _productAttributeService.GetAllProductVariantAttributeCombinations(productId); + var query = from x in _pvacRepository.TableUntracked + where x.ProductId == productId + select new + { + x.Id, + x.AttributesXml + }; + + var combinations = query.ToList(); if (combinations.Count == 0) return null; @@ -297,63 +357,110 @@ public virtual ProductVariantAttributeCombination FindProductVariantAttributeCom { bool attributesEqual = AreProductAttributesEqual(combination.AttributesXml, attributesXml); if (attributesEqual) - return combination; + return _productAttributeService.GetProductVariantAttributeCombinationById(combination.Id); } - } - return null; + + return null; + }); + + return result; } - /// - /// Deserializes attribute data from an URL query string - /// - /// Json data query string - /// List items with following structure: Product.Id, ProductAttribute.Id, Product_ProductAttribute_Mapping.Id, ProductVariantAttributeValue.Id public virtual List> DeserializeQueryData(string jsonData) { - if (jsonData.HasValue()) + try { - if (jsonData.StartsWith("[")) - return JsonConvert.DeserializeObject>>(jsonData); + if (jsonData.HasValue()) + { + if (jsonData.StartsWith("[")) + { + return JsonConvert.DeserializeObject>>(jsonData); + } - return new List>() { JsonConvert.DeserializeObject>(jsonData) }; + return new List> { JsonConvert.DeserializeObject>(jsonData) }; + } } + catch { } + return new List>(); } - - /// - /// Serializes attribute data - /// - /// Product identifier - /// Attribute XML string - /// Whether to URL encode - /// Json string with attribute data - public virtual string SerializeQueryData(int productId, string attributesXml, bool urlEncode = true) + + public virtual void DeserializeQueryData(List> queryData, string attributesXml, int productId, int bundleItemId = 0) { + Guard.ArgumentNotNull(() => queryData); + if (attributesXml.HasValue() && productId != 0) { - var data = new List>(); var attributeValues = ParseProductVariantAttributeValues(attributesXml).ToList(); foreach (var value in attributeValues) { - data.Add(new List + var lst = new List { productId, value.ProductVariantAttribute.ProductAttributeId, value.ProductVariantAttributeId, value.Id - }); - } + }; - if (data.Count > 0) - { - string result = JsonConvert.SerializeObject(data); - return (urlEncode ? HttpUtility.UrlEncode(result) : result); + if (bundleItemId != 0) + lst.Add(bundleItemId); + + queryData.Add(lst); } } + } + + public virtual string SerializeQueryData(string attributesXml, int productId, bool urlEncode = true) + { + var data = new List>(); + + DeserializeQueryData(data, attributesXml, productId); + + return SerializeQueryData(data, urlEncode); + } + + public virtual string SerializeQueryData(List> queryData, bool urlEncode = true) + { + if (queryData.Count > 0) + { + var result = JsonConvert.SerializeObject(queryData); + + return (urlEncode ? HttpUtility.UrlEncode(result) : result); + } + return ""; } + private string CreateProductUrl(string queryString, string productSeName) + { + var url = UrlHelper.GenerateUrl( + "Product", + null, + null, + new RouteValueDictionary(new { SeName = productSeName }), + RouteTable.Routes, + HttpContext.Current.Request.RequestContext, + false); + + if (queryString.HasValue()) + { + url = string.Concat(url, url.Contains("?") ? "&" : "?", "attributes=", queryString); + } + + return url; + } + + public virtual string GetProductUrlWithAttributes(string attributesXml, int productId, string productSeName) + { + return CreateProductUrl(SerializeQueryData(attributesXml, productId), productSeName); + } + + public virtual string GetProductUrlWithAttributes(List> queryData, string productSeName) + { + return CreateProductUrl(SerializeQueryData(queryData), productSeName); + } + #endregion #region Gift card attributes @@ -361,14 +468,14 @@ public virtual string SerializeQueryData(int productId, string attributesXml, bo /// /// Add gift card attrbibutes /// - /// Attributes + /// Attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message /// Attributes - public string AddGiftCardAttribute(string attributes, string recipientName, + public string AddGiftCardAttribute(string attributesXml, string recipientName, string recipientEmail, string senderName, string senderEmail, string giftCardMessage) { string result = string.Empty; @@ -380,14 +487,14 @@ public string AddGiftCardAttribute(string attributes, string recipientName, senderEmail = senderEmail.Trim(); var xmlDoc = new XmlDocument(); - if (String.IsNullOrEmpty(attributes)) + if (String.IsNullOrEmpty(attributesXml)) { var element1 = xmlDoc.CreateElement("Attributes"); xmlDoc.AppendChild(element1); } else { - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); } var rootElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes"); @@ -431,13 +538,13 @@ public string AddGiftCardAttribute(string attributes, string recipientName, /// /// Get gift card attrbibutes /// - /// Attributes + /// Attributes /// Recipient name /// Recipient email /// Sender name /// Sender email /// Message - public void GetGiftCardAttribute(string attributes, out string recipientName, + public void GetGiftCardAttribute(string attributesXml, out string recipientName, out string recipientEmail, out string senderName, out string senderEmail, out string giftCardMessage) { @@ -450,7 +557,7 @@ public void GetGiftCardAttribute(string attributes, out string recipientName, try { var xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(attributes); + xmlDoc.LoadXml(attributesXml); var recipientNameElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes/GiftCardInfo/RecipientName"); var recipientEmailElement = (XmlElement)xmlDoc.SelectSingleNode(@"//Attributes/GiftCardInfo/RecipientEmail"); diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs index cda03df832..3a886d0913 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductAttributeService.cs @@ -1,51 +1,42 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Events; using SmartStore.Services.Media; -using SmartStore.Core.Infrastructure; -using SmartStore.Data; -using System.Text; -using System.Linq.Expressions; -using SmartStore.Core.Domain.Media; +using SmartStore.Core; namespace SmartStore.Services.Catalog { - /// - /// Product attribute service - /// + public partial class ProductAttributeService : IProductAttributeService { - #region Constants private const string PRODUCTATTRIBUTES_ALL_KEY = "SmartStore.productattribute.all"; - private const string PRODUCTVARIANTATTRIBUTES_ALL_KEY = "SmartStore.productvariantattribute.all-{0}"; - private const string PRODUCTVARIANTATTRIBUTEVALUES_ALL_KEY = "SmartStore.productvariantattributevalue.all-{0}"; - private const string PRODUCTATTRIBUTES_PATTERN_KEY = "SmartStore.productattribute."; - private const string PRODUCTVARIANTATTRIBUTES_PATTERN_KEY = "SmartStore.productvariantattribute."; - private const string PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY = "SmartStore.productvariantattributevalue."; - private const string PRODUCTATTRIBUTES_BY_ID_KEY = "SmartStore.productattribute.id-{0}"; - private const string PRODUCTVARIANTATTRIBUTES_BY_ID_KEY = "SmartStore.productvariantattribute.id-{0}"; - private const string PRODUCTVARIANTATTRIBUTEVALUES_BY_ID_KEY = "SmartStore.productvariantattributevalue.id-{0}"; + private const string PRODUCTATTRIBUTES_BY_ID_KEY = "SmartStore.productattribute.id-{0}"; + private const string PRODUCTATTRIBUTES_PATTERN_KEY = "SmartStore.productattribute."; - #endregion + private const string PRODUCTVARIANTATTRIBUTES_ALL_KEY = "SmartStore.productvariantattribute.all-{0}"; + private const string PRODUCTVARIANTATTRIBUTES_BY_ID_KEY = "SmartStore.productvariantattribute.id-{0}"; + // 0 = ProductId, 1 = PageIndex, 2 = PageSize + private const string PRODUCTVARIANTATTRIBUTES_COMBINATIONS_BY_ID_KEY = "SmartStore.productvariantattribute.combinations.id-{0}-{1}-{2}"; + private const string PRODUCTVARIANTATTRIBUTES_PATTERN_KEY = "SmartStore.productvariantattribute."; - #region Fields + private const string PRODUCTVARIANTATTRIBUTEVALUES_ALL_KEY = "SmartStore.productvariantattributevalue.all-{0}"; + private const string PRODUCTVARIANTATTRIBUTEVALUES_BY_ID_KEY = "SmartStore.productvariantattributevalue.id-{0}"; + private const string PRODUCTVARIANTATTRIBUTEVALUES_PATTERN_KEY = "SmartStore.productvariantattributevalue."; - private readonly IRepository _productAttributeRepository; + private readonly IRepository _productAttributeRepository; private readonly IRepository _productVariantAttributeRepository; - private readonly IRepository _productVariantAttributeCombinationRepository; + private readonly IRepository _pvacRepository; private readonly IRepository _productVariantAttributeValueRepository; private readonly IRepository _productBundleItemAttributeFilterRepository; private readonly IEventPublisher _eventPublisher; private readonly ICacheManager _cacheManager; private readonly IPictureService _pictureService; - #endregion - - #region Ctor /// /// Ctor @@ -53,13 +44,13 @@ public partial class ProductAttributeService : IProductAttributeService /// Cache manager /// Product attribute repository /// Product variant attribute mapping repository - /// Product variant attribute combination repository + /// Product variant attribute combination repository /// Product variant attribute value repository /// Event published public ProductAttributeService(ICacheManager cacheManager, IRepository productAttributeRepository, IRepository productVariantAttributeRepository, - IRepository productVariantAttributeCombinationRepository, + IRepository pvacRepository, IRepository productVariantAttributeValueRepository, IRepository productBundleItemAttributeFilterRepository, IEventPublisher eventPublisher, @@ -68,27 +59,43 @@ public ProductAttributeService(ICacheManager cacheManager, _cacheManager = cacheManager; _productAttributeRepository = productAttributeRepository; _productVariantAttributeRepository = productVariantAttributeRepository; - _productVariantAttributeCombinationRepository = productVariantAttributeCombinationRepository; + _pvacRepository = pvacRepository; _productVariantAttributeValueRepository = productVariantAttributeValueRepository; _productBundleItemAttributeFilterRepository = productBundleItemAttributeFilterRepository; _eventPublisher = eventPublisher; _pictureService = pictureService; } - #endregion + #region Utilities + + private IList GetSwitchedLoadedAttributeMappings(ICollection productVariantAttributeIds) + { + if (productVariantAttributeIds != null && productVariantAttributeIds.Count > 0) + { + if (productVariantAttributeIds.Count == 1) + { + var pva = GetProductVariantAttributeById(productVariantAttributeIds.ElementAt(0)); + if (pva != null) + { + return new List { pva }; + } + } + else + { + return _productVariantAttributeRepository.GetMany(productVariantAttributeIds).ToList(); + } + } - //// Autowired Dependency (is a proptery dependency to avoid circularity) - //public virtual IProductAttributeParser AttributeParser { get; set; } + return new List(); + } - #region Methods + #endregion - #region Product attributes + #region Methods - /// - /// Deletes a product attribute - /// - /// Product attribute - public virtual void DeleteProductAttribute(ProductAttribute productAttribute) + #region Product attributes + + public virtual void DeleteProductAttribute(ProductAttribute productAttribute) { if (productAttribute == null) throw new ArgumentNullException("productAttribute"); @@ -104,10 +111,6 @@ public virtual void DeleteProductAttribute(ProductAttribute productAttribute) _eventPublisher.EntityDeleted(productAttribute); } - /// - /// Gets all product attributes - /// - /// Product attribute collection public virtual IList GetAllProductAttributes() { string key = PRODUCTATTRIBUTES_ALL_KEY; @@ -121,11 +124,6 @@ orderby pa.Name }); } - /// - /// Gets a product attribute - /// - /// Product attribute identifier - /// Product attribute public virtual ProductAttribute GetProductAttributeById(int productAttributeId) { if (productAttributeId == 0) @@ -137,10 +135,6 @@ public virtual ProductAttribute GetProductAttributeById(int productAttributeId) }); } - /// - /// Inserts a product attribute - /// - /// Product attribute public virtual void InsertProductAttribute(ProductAttribute productAttribute) { if (productAttribute == null) @@ -156,10 +150,6 @@ public virtual void InsertProductAttribute(ProductAttribute productAttribute) _eventPublisher.EntityInserted(productAttribute); } - /// - /// Updates the product attribute - /// - /// Product attribute public virtual void UpdateProductAttribute(ProductAttribute productAttribute) { if (productAttribute == null) @@ -179,10 +169,6 @@ public virtual void UpdateProductAttribute(ProductAttribute productAttribute) #region Product variant attributes mappings (ProductVariantAttribute) - /// - /// Deletes a product variant attribute mapping - /// - /// Product variant attribute mapping public virtual void DeleteProductVariantAttribute(ProductVariantAttribute productVariantAttribute) { if (productVariantAttribute == null) @@ -198,11 +184,6 @@ public virtual void DeleteProductVariantAttribute(ProductVariantAttribute produc _eventPublisher.EntityDeleted(productVariantAttribute); } - /// - /// Gets product variant attribute mappings by product identifier - /// - /// The product identifier - /// Product variant attribute mapping collection public virtual IList GetProductVariantAttributesByProductId(int productId) { string key = string.Format(PRODUCTVARIANTATTRIBUTES_ALL_KEY, productId); @@ -218,34 +199,73 @@ orderby pva.DisplayOrder }); } - /// - /// Gets a product variant attribute mapping - /// - /// Product variant attribute mapping identifier - /// Product variant attribute mapping + public virtual Multimap GetProductVariantAttributesByProductIds(int[] productIds, AttributeControlType? controlType) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from pva in _productVariantAttributeRepository.TableUntracked.Expand(x => x.ProductAttribute).Expand(x => x.ProductVariantAttributeValues) + where productIds.Contains(pva.ProductId) + select pva; + + if (controlType.HasValue) + { + query = query.Where(x => x.AttributeControlTypeId == ((int)controlType.Value)); + } + + var map = query + .OrderBy(x => x.ProductId) + .ThenBy(x => x.DisplayOrder) + .ToList() + .ToMultimap(x => x.ProductId, x => x); + + return map; + } + public virtual ProductVariantAttribute GetProductVariantAttributeById(int productVariantAttributeId) { if (productVariantAttributeId == 0) return null; string key = string.Format(PRODUCTVARIANTATTRIBUTES_BY_ID_KEY, productVariantAttributeId); - return _cacheManager.Get(key, () => { + + return _cacheManager.Get(key, () => + { return _productVariantAttributeRepository.GetById(productVariantAttributeId); }); } - // codehint: sm-add - public virtual IEnumerable GetProductVariantAttributesByIds(params int[] ids) - { - if (ids == null || ids.Length == 0) - { - return Enumerable.Empty(); - } + public virtual IList GetProductVariantAttributesByIds(IEnumerable productVariantAttributeIds, IEnumerable attributes = null) + { + if (productVariantAttributeIds != null) + { + if (attributes != null) + { + var ids = new List(); + var result = new List(); - return _productVariantAttributeRepository.GetMany(ids); - } + foreach (var id in productVariantAttributeIds) + { + var pva = attributes.FirstOrDefault(x => x.Id == id); + if (pva == null) + ids.Add(id); + else + result.Add(pva); + } + + var newLoadedMappings = GetSwitchedLoadedAttributeMappings(ids); + + result.AddRange(newLoadedMappings); + + return result; + } + + return GetSwitchedLoadedAttributeMappings(productVariantAttributeIds.ToList()); + } + + return new List(); + } - // codehint: sm-add public virtual IEnumerable GetProductVariantAttributeValuesByIds(params int[] productVariantAttributeValueIds) { if (productVariantAttributeValueIds == null || productVariantAttributeValueIds.Length == 0) @@ -256,10 +276,6 @@ public virtual IEnumerable GetProductVariantAttrib return _productVariantAttributeValueRepository.GetMany(productVariantAttributeValueIds); } - /// - /// Inserts a product variant attribute mapping - /// - /// The product variant attribute mapping public virtual void InsertProductVariantAttribute(ProductVariantAttribute productVariantAttribute) { if (productVariantAttribute == null) @@ -275,10 +291,6 @@ public virtual void InsertProductVariantAttribute(ProductVariantAttribute produc _eventPublisher.EntityInserted(productVariantAttribute); } - /// - /// Updates the product variant attribute mapping - /// - /// The product variant attribute mapping public virtual void UpdateProductVariantAttribute(ProductVariantAttribute productVariantAttribute) { if (productVariantAttribute == null) @@ -298,10 +310,6 @@ public virtual void UpdateProductVariantAttribute(ProductVariantAttribute produc #region Product variant attribute values (ProductVariantAttributeValue) - /// - /// Deletes a product variant attribute value - /// - /// Product variant attribute value public virtual void DeleteProductVariantAttributeValue(ProductVariantAttributeValue productVariantAttributeValue) { if (productVariantAttributeValue == null) @@ -317,11 +325,6 @@ public virtual void DeleteProductVariantAttributeValue(ProductVariantAttributeVa _eventPublisher.EntityDeleted(productVariantAttributeValue); } - /// - /// Gets product variant attribute values by product identifier - /// - /// The product variant attribute mapping identifier - /// Product variant attribute mapping collection public virtual IList GetProductVariantAttributeValues(int productVariantAttributeId) { string key = string.Format(PRODUCTVARIANTATTRIBUTEVALUES_ALL_KEY, productVariantAttributeId); @@ -336,11 +339,6 @@ orderby pvav.DisplayOrder }); } - /// - /// Gets a product variant attribute value - /// - /// Product variant attribute value identifier - /// Product variant attribute value public virtual ProductVariantAttributeValue GetProductVariantAttributeValueById(int productVariantAttributeValueId) { if (productVariantAttributeValueId == 0) @@ -353,10 +351,6 @@ public virtual ProductVariantAttributeValue GetProductVariantAttributeValueById( }); } - /// - /// Inserts a product variant attribute value - /// - /// The product variant attribute value public virtual void InsertProductVariantAttributeValue(ProductVariantAttributeValue productVariantAttributeValue) { if (productVariantAttributeValue == null) @@ -372,10 +366,6 @@ public virtual void InsertProductVariantAttributeValue(ProductVariantAttributeVa _eventPublisher.EntityInserted(productVariantAttributeValue); } - /// - /// Updates the product variant attribute value - /// - /// The product variant attribute value public virtual void UpdateProductVariantAttributeValue(ProductVariantAttributeValue productVariantAttributeValue) { if (productVariantAttributeValue == null) @@ -411,52 +401,95 @@ private void CombineAll(List> toCombine, List } } - /// - /// Deletes a product variant attribute combination - /// - /// Product variant attribute combination public virtual void DeleteProductVariantAttributeCombination(ProductVariantAttributeCombination combination) { if (combination == null) throw new ArgumentNullException("combination"); - _productVariantAttributeCombinationRepository.Delete(combination); + _pvacRepository.Delete(combination); //event notification _eventPublisher.EntityDeleted(combination); } - /// - /// Gets all product variant attribute combinations - /// - /// Product identifier - /// Product variant attribute combination collection - public virtual IList GetAllProductVariantAttributeCombinations(int productId) - { + public virtual IPagedList GetAllProductVariantAttributeCombinations( + int productId, + int pageIndex, + int pageSize, + bool untracked = true) + { + if (productId == 0) + { + return new PagedList(new List(), pageIndex, pageSize); + } + + string key = string.Format(PRODUCTVARIANTATTRIBUTES_COMBINATIONS_BY_ID_KEY, productId, 0, int.MaxValue); + return _cacheManager.Get(key, () => + { + var query = from pvac in (untracked ? _pvacRepository.TableUntracked : _pvacRepository.Table) + orderby pvac.Id + where pvac.ProductId == productId + select pvac; + + var combinations = new PagedList(query, pageIndex, pageSize); + return combinations; + }); + } + + public virtual IList GetAllProductVariantAttributeCombinationPictureIds(int productId) + { + var pictureIds = new List(); + if (productId == 0) - return new List(); + return pictureIds; - var query = from pvac in _productVariantAttributeCombinationRepository.Table - orderby pvac.Id - where pvac.ProductId == productId - select pvac; + var query = from pvac in _pvacRepository.TableUntracked + where + pvac.ProductId == productId + && pvac.IsActive + && !String.IsNullOrEmpty(pvac.AssignedPictureIds) + select pvac.AssignedPictureIds; - var combinations = query.ToList(); - return combinations; - } + var data = query.ToList(); + if (data.Any()) + { + int id; + var ids = string.Join(",", data).SplitSafe(",").Distinct(); + + foreach (string str in ids) + { + if (int.TryParse(str, out id) && !pictureIds.Exists(i => i == id)) + pictureIds.Add(id); + } + } + + return pictureIds; + } + + public virtual Multimap GetProductVariantAttributeCombinations(int[] productIds) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from pvac in _pvacRepository.TableUntracked + where productIds.Contains(pvac.ProductId) + select pvac; + + var map = query + .OrderBy(x => x.ProductId) + .ToList() + .ToMultimap(x => x.ProductId, x => x); + + return map; + } - /// - /// Get the lowest price of all combinations for a product - /// - /// Product identifier - /// Lowest price public virtual decimal? GetLowestCombinationPrice(int productId) { if (productId == 0) return null; var query = - from pvac in _productVariantAttributeCombinationRepository.Table + from pvac in _pvacRepository.Table where pvac.ProductId == productId && pvac.Price != null && pvac.IsActive orderby pvac.Price ascending select pvac.Price; @@ -465,51 +498,45 @@ orderby pvac.Price ascending return price; } - /// - /// Gets a product variant attribute combination - /// - /// Product variant attribute combination identifier - /// Product variant attribute combination public virtual ProductVariantAttributeCombination GetProductVariantAttributeCombinationById(int productVariantAttributeCombinationId) { if (productVariantAttributeCombinationId == 0) return null; - var combination = _productVariantAttributeCombinationRepository.GetById(productVariantAttributeCombinationId); + var combination = _pvacRepository.GetById(productVariantAttributeCombinationId); return combination; } - /// - /// Inserts a product variant attribute combination - /// - /// Product variant attribute combination + public virtual ProductVariantAttributeCombination GetProductVariantAttributeCombinationBySku(string sku) + { + if (sku.IsEmpty()) + return null; + + var combination = _pvacRepository.Table.FirstOrDefault(x => x.Sku == sku); + return combination; + } + public virtual void InsertProductVariantAttributeCombination(ProductVariantAttributeCombination combination) { if (combination == null) throw new ArgumentNullException("combination"); - // codehint: sm-add //if (combination.IsDefaultCombination) //{ // EnsureSingleDefaultVariant(combination); //} - _productVariantAttributeCombinationRepository.Insert(combination); + _pvacRepository.Insert(combination); //event notification _eventPublisher.EntityInserted(combination); } - /// - /// Updates a product variant attribute combination - /// - /// Product variant attribute combination public virtual void UpdateProductVariantAttributeCombination(ProductVariantAttributeCombination combination) { if (combination == null) throw new ArgumentNullException("combination"); - // codehint: sm-add //if (combination.IsDefaultCombination) //{ // EnsureSingleDefaultVariant(combination); @@ -534,23 +561,16 @@ public virtual void UpdateProductVariantAttributeCombination(ProductVariantAttri // } //} - _productVariantAttributeCombinationRepository.Update(combination); + _pvacRepository.Update(combination); //event notification _eventPublisher.EntityUpdated(combination); } - /// - /// Creates all variant attribute combinations - /// - /// The product public virtual void CreateAllProductVariantAttributeCombinations(Product product) { // delete all existing combinations - foreach(var itm in GetAllProductVariantAttributeCombinations(product.Id)) - { - DeleteProductVariantAttributeCombination(itm); - } + _pvacRepository.DeleteAll(x => x.ProductId == product.Id); var attributes = GetProductVariantAttributesByProductId(product.Id); if (attributes == null || attributes.Count <= 0) @@ -571,26 +591,43 @@ public virtual void CreateAllProductVariantAttributeCombinations(Product product { CombineAll(toCombine, resultMatrix, 0, tmp); - foreach (var values in resultMatrix) + using (var scope = new DbContextScope(ctx: _pvacRepository.Context, autoCommit: false, autoDetectChanges: false, validateOnSave: false, hooksEnabled: false)) { - string attrXml = ""; - foreach (var x in values) - { - attrXml = attributes[values.IndexOf(x)].AddProductAttribute(attrXml, x.Id.ToString()); + ProductVariantAttributeCombination combination = null; + + var idx = 0; + foreach (var values in resultMatrix) + { + idx++; + + string attrXml = ""; + for (var i = 0; i < values.Count; ++i) + { + var value = values[i]; + attrXml = attributes[i].AddProductAttribute(attrXml, value.Id.ToString()); + } + + combination = new ProductVariantAttributeCombination + { + ProductId = product.Id, + AttributesXml = attrXml, + StockQuantity = 10000, + AllowOutOfStockOrders = true, + IsActive = true + }; + + _pvacRepository.Insert(combination); } - var combination = new ProductVariantAttributeCombination() + scope.Commit(); + + if (combination != null) { - ProductId = product.Id, - AttributesXml = attrXml, - StockQuantity = 10000, - AllowOutOfStockOrders = true, - IsActive = true - }; - - _productVariantAttributeCombinationRepository.Insert(combination); - _eventPublisher.EntityInserted(combination); + // Perf: publish event for last one only + _eventPublisher.EntityInserted(combination); + } } + } //foreach (var y in resultMatrix) { @@ -608,7 +645,7 @@ public virtual bool VariantHasAttributeCombinations(int productId) return false; var query = - from c in _productVariantAttributeCombinationRepository.Table + from c in _pvacRepository.Table where c.ProductId == productId select c; @@ -619,10 +656,6 @@ from c in _productVariantAttributeCombinationRepository.Table #region Product bundle item attribute filter - /// - /// Inserts a product bundle item attribute filter - /// - /// Product bundle item attribute filter public virtual void InsertProductBundleItemAttributeFilter(ProductBundleItemAttributeFilter attributeFilter) { if (attributeFilter == null) @@ -636,10 +669,6 @@ public virtual void InsertProductBundleItemAttributeFilter(ProductBundleItemAttr } } - /// - /// Updates the product bundle item attribute filter - /// - /// Product bundle item attribute filter public virtual void UpdateProductBundleItemAttributeFilter(ProductBundleItemAttributeFilter attributeFilter) { if (attributeFilter == null) @@ -650,10 +679,6 @@ public virtual void UpdateProductBundleItemAttributeFilter(ProductBundleItemAttr _eventPublisher.EntityUpdated(attributeFilter); } - /// - /// Deletes a product bundle item attribute filter - /// - /// Product bundle item attribute filter public virtual void DeleteProductBundleItemAttributeFilter(ProductBundleItemAttributeFilter attributeFilter) { if (attributeFilter == null) @@ -664,10 +689,6 @@ public virtual void DeleteProductBundleItemAttributeFilter(ProductBundleItemAttr _eventPublisher.EntityDeleted(attributeFilter); } - /// - /// Deletes all attribute filters of a bundle item - /// - /// Bundle item public virtual void DeleteProductBundleItemAttributeFilter(ProductBundleItem bundleItem) { if (bundleItem != null && bundleItem.Id != 0) @@ -681,11 +702,6 @@ from x in _productBundleItemAttributeFilterRepository.Table } } - /// - /// Deletes product bundle item attribute filters - /// - /// Attribute identifier - /// Attribute value identifier public virtual void DeleteProductBundleItemAttributeFilter(int attributeId, int attributeValueId) { var attributeFilterQuery = @@ -696,10 +712,6 @@ from x in _productBundleItemAttributeFilterRepository.Table attributeFilterQuery.ToList().Each(x => DeleteProductBundleItemAttributeFilter(x)); } - /// - /// Deletes product bundle item attribute filters - /// - /// Attribute identifier public virtual void DeleteProductBundleItemAttributeFilter(int attributeId) { var attributeFilterQuery = diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductExtensions.cs b/src/Libraries/SmartStore.Services/Catalog/ProductExtensions.cs index 2281c2410c..051fc841f2 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductExtensions.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductExtensions.cs @@ -1,17 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; -using SmartStore.Core.Data; +using SmartStore.Core; using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Media; using SmartStore.Core.Infrastructure; +using SmartStore.Services.Directory; using SmartStore.Services.Localization; using SmartStore.Services.Media; using SmartStore.Services.Seo; +using SmartStore.Services.Tax; namespace SmartStore.Services.Catalog { - public static class ProductExtensions + public static class ProductExtensions { public static ProductVariantAttributeCombination MergeWithCombination(this Product product, string selectedAttributes) { @@ -22,19 +25,17 @@ public static ProductVariantAttributeCombination MergeWithCombination(this Produ { Guard.ArgumentNotNull(productAttributeParser, "productAttributeParser"); - if (selectedAttributes.IsNullOrEmpty()) + if (selectedAttributes.IsEmpty()) return null; - // let's find appropriate record - var combination = product - .ProductVariantAttributeCombinations - .Where(x => x.IsActive == true) - .FirstOrDefault(x => productAttributeParser.AreProductAttributesEqual(x.AttributesXml, selectedAttributes)); + // let's find appropriate record + var combination = productAttributeParser.FindProductVariantAttributeCombination(product.Id, selectedAttributes); - if (combination != null) + if (combination != null && combination.IsActive) { product.MergeWithCombination(combination); } + return combination; } @@ -70,6 +71,9 @@ public static void MergeWithCombination(this Product product, ProductVariantAttr if (combination.DeliveryTimeId.HasValue && combination.DeliveryTimeId.Value > 0) product.MergedDataValues.Add("DeliveryTimeId", combination.DeliveryTimeId); + if (combination.QuantityUnitId.HasValue && combination.QuantityUnitId.Value > 0) + product.MergedDataValues.Add("QuantityUnitId", combination.QuantityUnitId); + if (combination.Length.HasValue) product.MergedDataValues.Add("Length", combination.Length.Value); if (combination.Width.HasValue) @@ -83,9 +87,9 @@ public static void MergeWithCombination(this Product product, ProductVariantAttr product.MergedDataValues.Add("BasePriceBaseAmount", combination.BasePriceBaseAmount); } - public static void GetAllCombinationImageIds(this IList combinations, List imageIds) + public static IList GetAllCombinationPictureIds(this IEnumerable combinations) { - Guard.ArgumentNotNull(imageIds, "imageIds"); + var pictureIds = new List(); if (combinations != null) { @@ -101,21 +105,23 @@ public static void GetAllCombinationImageIds(this IList i == id)) - imageIds.Add(id); + if (int.TryParse(str, out id) && !pictureIds.Exists(i => i == id)) + pictureIds.Add(id); } } } + + return pictureIds; } - /// - /// Finds a related product item by specified identifiers - /// - /// Source - /// The first product identifier - /// The second product identifier - /// Related product - public static RelatedProduct FindRelatedProduct(this IList source, + /// + /// Finds a related product item by specified identifiers + /// + /// Source + /// The first product identifier + /// The second product identifier + /// Related product + public static RelatedProduct FindRelatedProduct(this IList source, int productId1, int productId2) { foreach (RelatedProduct relatedProduct in source) @@ -215,24 +221,23 @@ public static string FormatStockMessage(this Product product, ILocalizationServi /// Product /// Localization service /// The stock message - public static bool DisplayDeliveryTimeAccordingToStock(this Product product) + public static bool DisplayDeliveryTimeAccordingToStock(this Product product, CatalogSettings catalogSettings) { if (product == null) throw new ArgumentNullException("product"); - bool displayDeliveryTime = true; - if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock || product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes) { + if (catalogSettings.DeliveryTimeIdForEmptyStock.HasValue && product.StockQuantity <= 0) + return true; + return (product.StockQuantity > 0); } - - return displayDeliveryTime; + return true; } - public static bool ProductTagExists(this Product product, - int productTagId) + public static bool ProductTagExists(this Product product, int productTagId) { if (product == null) throw new ArgumentNullException("product"); @@ -294,41 +299,93 @@ public static int[] ParseRequiredProductIds(this Product product) } /// - /// Gets the base price + /// Gets the base price info /// /// Product /// Localization service /// Price formatter + /// Currency service + /// Tax service + /// Price calculation service + /// Target currency /// Price adjustment - /// Whether the result string should be language independent - /// The base price - public static string GetBasePriceInfo(this Product product, ILocalizationService localizationService, IPriceFormatter priceFormatter, - decimal priceAdjustment = decimal.Zero, bool languageIndependent = false) + /// Whether the result string should be language insensitive + /// The base price info + public static string GetBasePriceInfo(this Product product, + ILocalizationService localizationService, + IPriceFormatter priceFormatter, + ICurrencyService currencyService, + ITaxService taxService, + IPriceCalculationService priceCalculationService, + Currency currency, + decimal priceAdjustment = decimal.Zero, + bool languageInsensitive = false) { - if (product == null) - throw new ArgumentNullException("product"); - - if (localizationService == null && !languageIndependent) - throw new ArgumentNullException("localizationService"); + Guard.ArgumentNotNull(() => product); + Guard.ArgumentNotNull(() => currencyService); + Guard.ArgumentNotNull(() => taxService); + Guard.ArgumentNotNull(() => priceCalculationService); + Guard.ArgumentNotNull(() => currency); if (product.BasePriceHasValue && product.BasePriceAmount != Decimal.Zero) { - decimal price = decimal.Add(product.Price, priceAdjustment); - decimal basePriceValue = Convert.ToDecimal((price / product.BasePriceAmount) * product.BasePriceBaseAmount); + var workContext = EngineContext.Current.Resolve(); - string basePrice = priceFormatter.FormatPrice(basePriceValue, false, false); - string unit = "{0} {1}".FormatWith(product.BasePriceBaseAmount, product.BasePriceMeasureUnit); + var taxrate = decimal.Zero; + var currentPrice = priceCalculationService.GetFinalPrice(product, workContext.CurrentCustomer, true); + var price = taxService.GetProductPrice(product, decimal.Add(currentPrice, priceAdjustment), out taxrate); + + price = currencyService.ConvertFromPrimaryStoreCurrency(price, currency); - if (languageIndependent) - { - return "{0} / {1}".FormatWith(basePrice, unit); - } + return product.GetBasePriceInfo(price, localizationService, priceFormatter, currency, languageInsensitive); + } - return localizationService.GetResource("Products.BasePriceInfo").FormatWith(basePrice, unit); - } return ""; } + /// + /// Gets the base price info + /// + /// Product + /// The calculated product price + /// Localization service + /// Price formatter + /// Target currency + /// Whether the result string should be language insensitive + /// The base price info + public static string GetBasePriceInfo(this Product product, + decimal productPrice, + ILocalizationService localizationService, + IPriceFormatter priceFormatter, + Currency currency, + bool languageInsensitive = false) + { + Guard.ArgumentNotNull(() => product); + Guard.ArgumentNotNull(() => localizationService); + Guard.ArgumentNotNull(() => priceFormatter); + Guard.ArgumentNotNull(() => currency); + + if (product.BasePriceHasValue && product.BasePriceAmount != Decimal.Zero) + { + var value = Convert.ToDecimal((productPrice / product.BasePriceAmount) * product.BasePriceBaseAmount); + var valueFormatted = priceFormatter.FormatPrice(value, true, currency); + var amountFormatted = Math.Round(product.BasePriceAmount.Value, 2).ToString("G29"); + + var infoTemplate = localizationService.GetResource(languageInsensitive ? "Products.BasePriceInfo.LanguageInsensitive" : "Products.BasePriceInfo"); + + var result = infoTemplate.FormatInvariant( + amountFormatted, + product.BasePriceMeasureUnit, + valueFormatted, + product.BasePriceBaseAmount + ); + + return result; + } + + return ""; + } + public static string GetProductTypeLabel(this Product product, ILocalizationService localizationService) { if (product != null && product.ProductType != ProductType.SimpleProduct) diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductSearchContext.cs b/src/Libraries/SmartStore.Services/Catalog/ProductSearchContext.cs index 2f9f92362e..001e18789b 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductSearchContext.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductSearchContext.cs @@ -31,17 +31,37 @@ public ProductSearchContext() /// Only implemented in LINQ mode at the moment public IList ProductIds { get; set; } + /// + /// Minimum product identifier + /// + public int IdMin { get; set; } + + /// + /// Maximum product identifier + /// + public int IdMax { get; set; } + /// /// A value indicating whether ALL given must be assigned to the resulting products (default is ANY) /// /// Only works in LINQ mode at the moment public bool MatchAllcategories { get; set; } + /// + /// A value indicating whether to load products without any catgory mapping + /// + public bool? WithoutCategories { get; set; } + /// /// Manufacturer identifier; 0 to load all records /// public int ManufacturerId { get; set; } + /// + /// A value indicating whether to load products without any manufacturer mapping + /// + public bool? WithoutManufacturers { get; set; } + /// /// A value indicating whether loaded products are marked as featured (relates only to categories and manufacturers). 0 to load featured products only, 1 to load not featured products only, null to load all products /// @@ -148,5 +168,35 @@ public ProductSearchContext() /// Can be useful in customization scenarios. /// public string Origin { get; set; } + + /// + /// A value indicating whether to load only published or non published products + /// + public bool? IsPublished { get; set; } + + /// + /// A value indicating whether to load only products displayed on the homepage + /// + public bool? HomePageProducts { get; set; } + + /// + /// Search by minimum availability + /// + public int? AvailabilityMinimum { get; set; } + + /// + /// Search by maximum availability + /// + public int? AvailabilityMaximum { get; set; } + + /// + /// Search by created from date + /// + public DateTime? CreatedFromUtc { get; set; } + + /// + /// Search by created to date + /// + public DateTime? CreatedToUtc { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs index 87649a4f75..6dc93b582d 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductService.cs @@ -1,12 +1,17 @@ using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; +using System.Linq.Expressions; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Security; @@ -41,7 +46,7 @@ public partial class ProductService : IProductService private readonly IRepository _storeMappingRepository; private readonly IRepository _productPictureRepository; private readonly IRepository _productSpecificationAttributeRepository; - private readonly IRepository _productVariantAttributeCombinationRepository; // codehint: sm-add + private readonly IRepository _productVariantAttributeCombinationRepository; private readonly IRepository _productBundleItemRepository; private readonly IProductAttributeService _productAttributeService; private readonly IProductAttributeParser _productAttributeParser; @@ -49,12 +54,10 @@ public partial class ProductService : IProductService private readonly IWorkflowMessageService _workflowMessageService; private readonly IDataProvider _dataProvider; private readonly IDbContext _dbContext; - private readonly ICacheManager _cacheManager; - private readonly IWorkContext _workContext; - private readonly IStoreContext _storeContext; + private readonly ICacheManager _cacheManager; private readonly LocalizationSettings _localizationSettings; private readonly CommonSettings _commonSettings; - private readonly IEventPublisher _eventPublisher; + private readonly ICommonServices _services; #endregion @@ -84,7 +87,7 @@ public partial class ProductService : IProductService /// Localization settings /// Common settings /// Event published - public ProductService(ICacheManager cacheManager, + public ProductService( IRepository productRepository, IRepository relatedProductRepository, IRepository crossSellProductRepository, @@ -100,13 +103,13 @@ public ProductService(ICacheManager cacheManager, IProductAttributeParser productAttributeParser, ILanguageService languageService, IWorkflowMessageService workflowMessageService, - IDataProvider dataProvider, IDbContext dbContext, - IWorkContext workContext, - IStoreContext storeContext, - LocalizationSettings localizationSettings, CommonSettings commonSettings, - IEventPublisher eventPublisher) + IDataProvider dataProvider, + IDbContext dbContext, + ICacheManager cacheManager, + LocalizationSettings localizationSettings, + CommonSettings commonSettings, + ICommonServices services) { - this._cacheManager = cacheManager; this._productRepository = productRepository; this._relatedProductRepository = relatedProductRepository; this._crossSellProductRepository = crossSellProductRepository; @@ -124,11 +127,10 @@ public ProductService(ICacheManager cacheManager, this._workflowMessageService = workflowMessageService; this._dataProvider = dataProvider; this._dbContext = dbContext; - this._workContext = workContext; - this._storeContext = storeContext; + this._cacheManager = cacheManager; this._localizationSettings = localizationSettings; this._commonSettings = commonSettings; - this._eventPublisher = eventPublisher; + this._services = services; this.QuerySettings = DbQuerySettings.Default; } @@ -136,12 +138,91 @@ public ProductService(ICacheManager cacheManager, public DbQuerySettings QuerySettings { get; set; } #endregion - - #region Methods - #region Products + #region Utilities - /// + protected virtual int EnsureMutuallyRelatedProducts(List productIds) + { + int count = 0; + + foreach (int id1 in productIds) + { + var mutualAssociations = ( + from rp in _relatedProductRepository.Table + join p in _productRepository.Table on rp.ProductId2 equals p.Id + where !p.Deleted && rp.ProductId2 == id1 + select rp).ToList(); + + foreach (int id2 in productIds) + { + if (id1 == id2) + continue; + + if (!mutualAssociations.Any(x => x.ProductId1 == id2)) + { + int maxDisplayOrder = _relatedProductRepository.TableUntracked + .Where(x => x.ProductId1 == id2) + .OrderByDescending(x => x.DisplayOrder) + .Select(x => x.DisplayOrder) + .FirstOrDefault(); + + var newRelatedProduct = new RelatedProduct + { + ProductId1 = id2, + ProductId2 = id1, + DisplayOrder = maxDisplayOrder + 1 + }; + + InsertRelatedProduct(newRelatedProduct); + ++count; + } + } + } + + return count; + } + + protected virtual int EnsureMutuallyCrossSellProducts(List productIds) + { + int count = 0; + + foreach (int id1 in productIds) + { + var mutualAssociations = ( + from rp in _crossSellProductRepository.Table + join p in _productRepository.Table on rp.ProductId2 equals p.Id + where !p.Deleted && rp.ProductId2 == id1 + select rp).ToList(); + + foreach (int id2 in productIds) + { + if (id1 == id2) + continue; + + if (!mutualAssociations.Any(x => x.ProductId1 == id2)) + { + var newCrossSellProduct = new CrossSellProduct + { + ProductId1 = id2, + ProductId2 = id1 + }; + + InsertCrossSellProduct(newCrossSellProduct); + ++count; + } + } + } + + return count; + } + + #endregion + + #region Methods + + #region Products + + /// /// Delete a product /// /// Product @@ -151,8 +232,21 @@ public virtual void DeleteProduct(Product product) throw new ArgumentNullException("product"); product.Deleted = true; - //delete product + product.DeliveryTimeId = null; + product.QuantityUnitId = null; + UpdateProduct(product); + + if (product.ProductType == ProductType.GroupedProduct) + { + var associatedProducts = _productRepository.Table + .Where(x => x.ParentGroupedProductId == product.Id) + .ToList(); + + associatedProducts.ForEach(x => x.ParentGroupedProductId = 0); + + _dbContext.SaveChanges(); + } } /// @@ -161,12 +255,12 @@ public virtual void DeleteProduct(Product product) /// Product collection public virtual IList GetAllProductsDisplayedOnHomePage() { - var query = from p in _productRepository.Table - orderby p.Name - where p.Published && - !p.Deleted && - p.ShowOnHomePage - select p; + var query = + from p in _productRepository.Table + orderby p.HomePageDisplayOrder + where p.Published && !p.Deleted && p.ShowOnHomePage + select p; + var products = query.ToList(); return products; } @@ -202,17 +296,13 @@ public virtual IList GetProductsByIds(int[] productIds) where productIds.Contains(p.Id) select p; var products = query.ToList(); - - //sort by passed identifiers - var sortedProducts = new List(); - foreach (int id in productIds) - { - var product = products.Find(x => x.Id == id); - if (product != null) - sortedProducts.Add(product); - } - return sortedProducts; + // sort by passed identifier sequence + var sortQuery = from i in productIds + join p in products on i equals p.Id + select p; + + return sortQuery.ToList(); } /// @@ -231,7 +321,7 @@ public virtual void InsertProduct(Product product) _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(product); + _services.EventPublisher.EntityInserted(product); } /// @@ -249,16 +339,16 @@ public virtual void UpdateProduct(Product product, bool publishEvent = true) modified = _productRepository.IsModified(product); } - //update + // update _productRepository.Update(product); - //cache + // cache _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); - //event notification + // event notification if (publishEvent && modified) { - _eventPublisher.EntityUpdated(product); + _services.EventPublisher.EntityUpdated(product); } } @@ -271,18 +361,13 @@ public virtual int CountProducts(ProductSearchContext ctx) return query.Distinct().Count(); } - /// - /// Search products - /// codehint: sm-edit (changed input parameter) - /// public virtual IPagedList SearchProducts(ProductSearchContext ctx) { - // codehint: sm-edit (turn off nc filtering, we have our own) ctx.LoadFilterableSpecificationAttributeOptionIds = false; ctx.FilterableSpecificationAttributeOptionIds = new List(); - _eventPublisher.Publish(new ProductsSearchingEvent(ctx)); + _services.EventPublisher.Publish(new ProductsSearchingEvent(ctx)); //search by keyword bool searchLocalizedValue = false; @@ -305,7 +390,7 @@ public virtual IPagedList SearchProducts(ProductSearchContext ctx) ctx.CategoryIds.Remove(0); //Access control list. Allowed customer roles - var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles + var allowedCustomerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles .Where(cr => cr.Active).Select(cr => cr.Id).ToList(); if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduresSupported) @@ -317,7 +402,7 @@ public virtual IPagedList SearchProducts(ProductSearchContext ctx) //pass categry identifiers as comma-delimited string string commaSeparatedCategoryIds = ""; - if (ctx.CategoryIds != null) + if (ctx.CategoryIds != null && !(ctx.WithoutCategories ?? false)) { for (int i = 0; i < ctx.CategoryIds.Count; i++) { @@ -367,7 +452,7 @@ public virtual IPagedList SearchProducts(ProductSearchContext ctx) var pManufacturerId = _dataProvider.GetParameter(); pManufacturerId.ParameterName = "ManufacturerId"; - pManufacturerId.Value = ctx.ManufacturerId; + pManufacturerId.Value = (ctx.WithoutManufacturers ?? false) ? 0 : ctx.ManufacturerId; pManufacturerId.DbType = DbType.Int32; var pStoreId = _dataProvider.GetParameter(); @@ -480,6 +565,57 @@ public virtual IPagedList SearchProducts(ProductSearchContext ctx) pLoadFilterableSpecificationAttributeOptionIds.Value = ctx.LoadFilterableSpecificationAttributeOptionIds; pLoadFilterableSpecificationAttributeOptionIds.DbType = DbType.Boolean; + var pWithoutCategories = _dataProvider.GetParameter(); + pWithoutCategories.ParameterName = "WithoutCategories"; + pWithoutCategories.Value = (ctx.WithoutCategories.HasValue ? (object)ctx.WithoutCategories.Value : DBNull.Value); + pWithoutCategories.DbType = DbType.Boolean; + + var pWithoutManufacturers = _dataProvider.GetParameter(); + pWithoutManufacturers.ParameterName = "WithoutManufacturers"; + pWithoutManufacturers.Value = (ctx.WithoutManufacturers.HasValue ? (object)ctx.WithoutManufacturers.Value : DBNull.Value); + pWithoutManufacturers.DbType = DbType.Boolean; + + var pIsPublished = _dataProvider.GetParameter(); + pIsPublished.ParameterName = "IsPublished"; + pIsPublished.Value = (ctx.IsPublished.HasValue ? (object)ctx.IsPublished.Value : DBNull.Value); + pIsPublished.DbType = DbType.Boolean; + + var pHomePageProducts = _dataProvider.GetParameter(); + pHomePageProducts.ParameterName = "HomePageProducts"; + pHomePageProducts.Value = (ctx.HomePageProducts.HasValue ? (object)ctx.HomePageProducts.Value : DBNull.Value); + pHomePageProducts.DbType = DbType.Boolean; + + var pIdMin = _dataProvider.GetParameter(); + pIdMin.ParameterName = "IdMin"; + pIdMin.Value = ctx.IdMin; + pIdMin.DbType = DbType.Int32; + + var pIdMax = _dataProvider.GetParameter(); + pIdMax.ParameterName = "IdMax"; + pIdMax.Value = ctx.IdMin; + pIdMax.DbType = DbType.Int32; + + var pAvailabilityMin = _dataProvider.GetParameter(); + pAvailabilityMin.ParameterName = "AvailabilityMin"; + pAvailabilityMin.Value = ctx.AvailabilityMinimum.HasValue ? (object)ctx.AvailabilityMinimum.Value : DBNull.Value; + pAvailabilityMin.DbType = DbType.Int32; + + var pAvailabilityMax = _dataProvider.GetParameter(); + pAvailabilityMax.ParameterName = "AvailabilityMax"; + pAvailabilityMax.Value = ctx.AvailabilityMaximum.HasValue ? (object)ctx.AvailabilityMaximum.Value : DBNull.Value; + pAvailabilityMax.DbType = DbType.Int32; + + var pCreatedFromUtc = _dataProvider.GetParameter(); + pCreatedFromUtc.ParameterName = "CreatedFromUtc"; + pCreatedFromUtc.Value = ctx.CreatedFromUtc.HasValue ? (object)ctx.CreatedFromUtc.Value.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) : DBNull.Value; + pCreatedFromUtc.DbType = DbType.String; + + var pCreatedToUtc = _dataProvider.GetParameter(); + pCreatedToUtc.ParameterName = "CreatedToUtc"; + pCreatedToUtc.Value = ctx.CreatedToUtc.HasValue ? (object)ctx.CreatedToUtc.Value.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) : DBNull.Value; + pCreatedToUtc.DbType = DbType.String; + + var pFilterableSpecificationAttributeOptionIds = _dataProvider.GetParameter(); pFilterableSpecificationAttributeOptionIds.ParameterName = "FilterableSpecificationAttributeOptionIds"; pFilterableSpecificationAttributeOptionIds.Direction = ParameterDirection.Output; @@ -518,19 +654,29 @@ public virtual IPagedList SearchProducts(ProductSearchContext ctx) pPageSize, pShowHidden, pLoadFilterableSpecificationAttributeOptionIds, + pWithoutCategories, + pWithoutManufacturers, + pIsPublished, + pHomePageProducts, + pIdMin, + pIdMax, + pAvailabilityMin, + pAvailabilityMax, + pCreatedFromUtc, + pCreatedToUtc, pFilterableSpecificationAttributeOptionIds, pTotalRecords); - //get filterable specification attribute option identifier + + // get filterable specification attribute option identifier string filterableSpecificationAttributeOptionIdsStr = (pFilterableSpecificationAttributeOptionIds.Value != DBNull.Value) ? (string)pFilterableSpecificationAttributeOptionIds.Value : ""; - if (ctx.LoadFilterableSpecificationAttributeOptionIds && - !string.IsNullOrWhiteSpace(filterableSpecificationAttributeOptionIdsStr)) + if (ctx.LoadFilterableSpecificationAttributeOptionIds && !string.IsNullOrWhiteSpace(filterableSpecificationAttributeOptionIdsStr)) { - // codehint: sm-edit ctx.FilterableSpecificationAttributeOptionIds.AddRange(filterableSpecificationAttributeOptionIdsStr .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Select(x => Convert.ToInt32(x.Trim()))); } - //return products + + // return products int totalRecords = (pTotalRecords.Value != DBNull.Value) ? Convert.ToInt32(pTotalRecords.Value) : 0; return new PagedList(products, ctx.PageIndex, ctx.PageSize, totalRecords); @@ -631,27 +777,41 @@ where psa.AllowFiltering } } - /// - /// Builds a product query based on the options in ProductSearchContext parameter. - /// - /// Parameters to build the query. - /// Customer role ids (ACL). - /// Whether to search localized values. - public virtual IQueryable PrepareProductSearchQuery(ProductSearchContext ctx, IEnumerable allowedCustomerRolesIds = null, bool searchLocalizedValue = false) - { - if (allowedCustomerRolesIds == null) - { - allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles.Where(cr => cr.Active).Select(cr => cr.Id).ToList(); - } - - // products - var query = ctx.Query ?? _productRepository.Table; - query = query.Where(p => !p.Deleted); + public virtual IQueryable PrepareProductSearchQuery( + ProductSearchContext ctx, + IEnumerable allowedCustomerRolesIds = null, + bool searchLocalizedValue = false) + { + return PrepareProductSearchQuery(ctx, x => x, allowedCustomerRolesIds, searchLocalizedValue); + } - if (!ctx.ShowHidden) - { - query = query.Where(p => p.Published); - } + public virtual IQueryable PrepareProductSearchQuery( + ProductSearchContext ctx, + Expression> selector, + IEnumerable allowedCustomerRolesIds = null, + bool searchLocalizedValue = false) + { + Guard.ArgumentNotNull(() => ctx); + Guard.ArgumentNotNull(() => selector); + + if (allowedCustomerRolesIds == null) + { + allowedCustomerRolesIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(cr => cr.Active).Select(cr => cr.Id).ToList(); + } + + // products + var query = ctx.Query ?? _productRepository.Table; + query = query.Where(p => !p.Deleted); + + if (!ctx.IsPublished.HasValue) + { + if (!ctx.ShowHidden) + query = query.Where(p => p.Published); + } + else + { + query = query.Where(p => p.Published == ctx.IsPublished.Value); + } if (ctx.ParentGroupedProductId > 0) { @@ -663,6 +823,11 @@ public virtual IQueryable PrepareProductSearchQuery(ProductSearchContex query = query.Where(p => p.VisibleIndividually); } + if (ctx.HomePageProducts.HasValue) + { + query = query.Where(p => p.ShowOnHomePage == ctx.HomePageProducts.Value); + } + if (ctx.ProductType.HasValue) { int productTypeId = (int)ctx.ProductType.Value; @@ -673,6 +838,34 @@ public virtual IQueryable PrepareProductSearchQuery(ProductSearchContex { query = query.Where(x => ctx.ProductIds.Contains(x.Id)); } + else + { + if (ctx.IdMin != 0) + query = query.Where(x => x.Id >= ctx.IdMin); + + if (ctx.IdMax != 0) + query = query.Where(x => x.Id <= ctx.IdMax); + } + + if (ctx.AvailabilityMinimum.HasValue) + { + query = query.Where(x => x.StockQuantity >= ctx.AvailabilityMinimum.Value); + } + + if (ctx.AvailabilityMaximum.HasValue) + { + query = query.Where(x => x.StockQuantity <= ctx.AvailabilityMaximum.Value); + } + + if (ctx.CreatedFromUtc.HasValue) + { + query = query.Where(x => x.CreatedOnUtc >= ctx.CreatedFromUtc.Value); + } + + if (ctx.CreatedToUtc.HasValue) + { + query = query.Where(x => x.CreatedOnUtc <= ctx.CreatedToUtc.Value); + } //The function 'CurrentUtcDateTime' is not supported by SQL Server Compact. //That's why we pass the date value @@ -726,115 +919,123 @@ public virtual IQueryable PrepareProductSearchQuery(ProductSearchContex (!p.AvailableEndDateTimeUtc.HasValue || p.AvailableEndDateTimeUtc.Value > nowUtc)); } - // searching by keyword - if (!String.IsNullOrWhiteSpace(ctx.Keywords)) - { - query = from p in query - join lp in _localizedPropertyRepository.Table on p.Id equals lp.EntityId into p_lp - from lp in p_lp.DefaultIfEmpty() - from pt in p.ProductTags.DefaultIfEmpty() - where (p.Name.Contains(ctx.Keywords)) || - (ctx.SearchDescriptions && p.ShortDescription.Contains(ctx.Keywords)) || - (ctx.SearchDescriptions && p.FullDescription.Contains(ctx.Keywords)) || - (ctx.SearchProductTags && pt.Name.Contains(ctx.Keywords)) || + // searching by keyword + if (!String.IsNullOrWhiteSpace(ctx.Keywords)) + { + query = from p in query + join lp in _localizedPropertyRepository.Table on p.Id equals lp.EntityId into p_lp + from lp in p_lp.DefaultIfEmpty() + from pt in p.ProductTags.DefaultIfEmpty() + where (p.Name.Contains(ctx.Keywords)) || + (ctx.SearchDescriptions && p.ShortDescription.Contains(ctx.Keywords)) || + (ctx.SearchDescriptions && p.FullDescription.Contains(ctx.Keywords)) || + (ctx.SearchSku && p.Sku.Contains(ctx.Keywords)) || + (ctx.SearchProductTags && pt.Name.Contains(ctx.Keywords)) || //localized values - (searchLocalizedValue && lp.LanguageId == ctx.LanguageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "Name" && lp.LocaleValue.Contains(ctx.Keywords)) || - (ctx.SearchDescriptions && searchLocalizedValue && lp.LanguageId == ctx.LanguageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "ShortDescription" && lp.LocaleValue.Contains(ctx.Keywords)) || - (ctx.SearchDescriptions && searchLocalizedValue && lp.LanguageId == ctx.LanguageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "FullDescription" && lp.LocaleValue.Contains(ctx.Keywords)) - //UNDONE search localized values in associated product tags - select p; - } + (searchLocalizedValue && lp.LanguageId == ctx.LanguageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "Name" && lp.LocaleValue.Contains(ctx.Keywords)) || + (ctx.SearchDescriptions && searchLocalizedValue && lp.LanguageId == ctx.LanguageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "ShortDescription" && lp.LocaleValue.Contains(ctx.Keywords)) || + (ctx.SearchDescriptions && searchLocalizedValue && lp.LanguageId == ctx.LanguageId && lp.LocaleKeyGroup == "Product" && lp.LocaleKey == "FullDescription" && lp.LocaleValue.Contains(ctx.Keywords)) + //UNDONE search localized values in associated product tags + select p; + } - if (!ctx.ShowHidden && !QuerySettings.IgnoreAcl) - { - // ACL - query = from p in query - join acl in _aclRepository.Table on p.Id equals acl.EntityId into p_acl - from acl in p_acl.DefaultIfEmpty() - where !p.SubjectToAcl || (acl.EntityName == "Product" && allowedCustomerRolesIds.Contains(acl.CustomerRoleId)) - select p; - } + if (!ctx.ShowHidden && !QuerySettings.IgnoreAcl) + { + query = + from p in query + join acl in _aclRepository.Table on new { pid = p.Id, pname = "Product" } equals new { pid = acl.EntityId, pname = acl.EntityName } into pacl + from acl in pacl.DefaultIfEmpty() + where !p.SubjectToAcl || allowedCustomerRolesIds.Contains(acl.CustomerRoleId) + select p; + } if (ctx.StoreId > 0 && !QuerySettings.IgnoreMultiStore) { - //Store mapping - query = from p in query - join sm in _storeMappingRepository.Table on p.Id equals sm.EntityId into p_sm - from sm in p_sm.DefaultIfEmpty() - where !p.LimitedToStores || (sm.EntityName == "Product" && ctx.StoreId == sm.StoreId) - select p; + query = + from p in query + join sm in _storeMappingRepository.Table on new { pid = p.Id, pname = "Product" } equals new { pid = sm.EntityId, pname = sm.EntityName } into psm + from sm in psm.DefaultIfEmpty() + where !p.LimitedToStores || ctx.StoreId == sm.StoreId + select p; } - // search by specs - if (ctx.FilteredSpecs != null && ctx.FilteredSpecs.Count > 0) - { - query = from p in query - where !ctx.FilteredSpecs - .Except( - p.ProductSpecificationAttributes.Where(psa => psa.AllowFiltering).Select( - psa => psa.SpecificationAttributeOptionId)) - .Any() - select p; - } - - // category filtering - if (ctx.CategoryIds != null && ctx.CategoryIds.Count > 0) - { - //search in subcategories - if (ctx.MatchAllcategories) - { - query = from p in query - where ctx.CategoryIds.All(i => p.ProductCategories.Any(p2 => p2.CategoryId == i)) - from pc in p.ProductCategories - where (!ctx.FeaturedProducts.HasValue || ctx.FeaturedProducts.Value == pc.IsFeaturedProduct) - select p; - } - else - { - query = from p in query - from pc in p.ProductCategories.Where(pc => ctx.CategoryIds.Contains(pc.CategoryId)) - where (!ctx.FeaturedProducts.HasValue || ctx.FeaturedProducts.Value == pc.IsFeaturedProduct) - select p; - } - } + // search by specs + if (ctx.FilteredSpecs != null && ctx.FilteredSpecs.Count > 0) + { + query = + from p in query + where !ctx.FilteredSpecs.Except + ( + p.ProductSpecificationAttributes + .Where(psa => psa.AllowFiltering) + .Select(psa => psa.SpecificationAttributeOptionId) + ).Any() + select p; + } - // manufacturer filtering - if (ctx.ManufacturerId > 0) - { - query = from p in query - from pm in p.ProductManufacturers.Where(pm => pm.ManufacturerId == ctx.ManufacturerId) - where (!ctx.FeaturedProducts.HasValue || ctx.FeaturedProducts.Value == pm.IsFeaturedProduct) - select p; - } + // category filtering + if (ctx.WithoutCategories.HasValue) + { + if (ctx.WithoutCategories.Value) + query = query.Where(x => x.ProductCategories.Count == 0); + else + query = query.Where(x => x.ProductCategories.Count > 0); + } + else if (ctx.CategoryIds != null && ctx.CategoryIds.Count > 0) + { + //search in subcategories + if (ctx.MatchAllcategories) + { + query = from p in query + where ctx.CategoryIds.All(i => p.ProductCategories.Any(p2 => p2.CategoryId == i)) + from pc in p.ProductCategories + where (!ctx.FeaturedProducts.HasValue || ctx.FeaturedProducts.Value == pc.IsFeaturedProduct) + select p; + } + else + { + query = from p in query + from pc in p.ProductCategories.Where(pc => ctx.CategoryIds.Contains(pc.CategoryId)) + where (!ctx.FeaturedProducts.HasValue || ctx.FeaturedProducts.Value == pc.IsFeaturedProduct) + select p; + } + } - // related products filtering - //if (relatedToProductId > 0) - //{ - // query = from p in query - // join rp in _relatedProductRepository.Table on p.Id equals rp.ProductId2 - // where (relatedToProductId == rp.ProductId1) - // select p; - //} - - // tag filtering - if (ctx.ProductTagId > 0) - { - query = from p in query - from pt in p.ProductTags.Where(pt => pt.Id == ctx.ProductTagId) - select p; - } + // manufacturer filtering + if (ctx.WithoutManufacturers.HasValue) + { + if (ctx.WithoutManufacturers.Value) + query = query.Where(x => x.ProductManufacturers.Count == 0); + else + query = query.Where(x => x.ProductManufacturers.Count > 0); + } + else if (ctx.ManufacturerId > 0) + { + query = from p in query + from pm in p.ProductManufacturers.Where(pm => pm.ManufacturerId == ctx.ManufacturerId) + where (!ctx.FeaturedProducts.HasValue || ctx.FeaturedProducts.Value == pm.IsFeaturedProduct) + select p; + } - //// only distinct products (group by ID) - //// if we use standard Distinct() method, then all fields will be compared (low performance) - //// it'll not work in SQL Server Compact when searching products by a keyword) - //query = from p in query - // group p by p.Id - // into pGroup - // orderby pGroup.Key - // select pGroup.FirstOrDefault(); + // related products filtering + //if (relatedToProductId > 0) + //{ + // query = from p in query + // join rp in _relatedProductRepository.Table on p.Id equals rp.ProductId2 + // where (relatedToProductId == rp.ProductId1) + // select p; + //} + + // tag filtering + if (ctx.ProductTagId > 0) + { + query = from p in query + from pt in p.ProductTags.Where(pt => pt.Id == ctx.ProductTagId) + select p; + } - return query; - } + return query.Select(selector); + } /// /// Update product review totals @@ -877,24 +1078,25 @@ public virtual void UpdateProductReviewTotals(Product product) /// Result public virtual IList GetLowStockProducts() { - //Track inventory for product + // Track inventory for product var query1 = from p in _productRepository.Table orderby p.MinStockQuantity where !p.Deleted && - p.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStock && - p.MinStockQuantity >= p.StockQuantity + p.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStock && + p.MinStockQuantity >= p.StockQuantity select p; var products1 = query1.ToList(); - //Track inventory for product by product attributes + // Track inventory for product by product attributes var query2 = from p in _productRepository.Table from pvac in p.ProductVariantAttributeCombinations where !p.Deleted && - p.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStockByAttributes && - pvac.StockQuantity <= 0 + p.ManageInventoryMethodId == (int)ManageInventoryMethod.ManageStockByAttributes && + pvac.StockQuantity <= 0 select p; - //only distinct products (group by ID) - //if we use standard Distinct() method, then all fields will be compared (low performance) + + // only distinct products (group by ID) + // if we use standard Distinct() method, then all fields will be compared (low performance) query2 = from p in query2 group p by p.Id into pGroup orderby pGroup.Key @@ -920,8 +1122,7 @@ public virtual Product GetProductBySku(string sku) var query = from p in _productRepository.Table orderby p.DisplayOrder, p.Id - where !p.Deleted && - p.Sku == sku + where !p.Deleted && p.Sku == sku select p; var product = query.FirstOrDefault(); return product; @@ -930,7 +1131,7 @@ public virtual Product GetProductBySku(string sku) /// /// Gets a product by GTIN /// - /// GTIN + /// GTIN /// Product public virtual Product GetProductByGtin(string gtin) { @@ -948,28 +1149,61 @@ orderby p.Id return product; } + public virtual Product GetProductByManufacturerPartNumber(string manufacturerPartNumber) + { + if (manufacturerPartNumber.IsEmpty()) + return null; + + manufacturerPartNumber = manufacturerPartNumber.Trim(); + + var product = _productRepository.Table + .Where(x => !x.Deleted && x.ManufacturerPartNumber == manufacturerPartNumber) + .OrderBy(x => x.Id) + .FirstOrDefault(); + + return product; + } + + public virtual Product GetProductByName(string name) + { + if (name.IsEmpty()) + return null; + + name = name.Trim(); + + var product = _productRepository.Table + .Where(x => !x.Deleted && x.Name == name) + .OrderBy(x => x.Id) + .FirstOrDefault(); + + return product; + } + /// /// Adjusts inventory /// /// Shopping cart item /// A value indicating whether to increase or descrease product stock quantity - public virtual void AdjustInventory(OrganizedShoppingCartItem sci, bool decrease) + /// Adjust inventory result + public virtual AdjustInventoryResult AdjustInventory(OrganizedShoppingCartItem sci, bool decrease) { if (sci == null) throw new ArgumentNullException("cartItem"); if (sci.Item.Product.ProductType == ProductType.BundledProduct && sci.Item.Product.BundlePerItemShoppingCart) { - if (sci.ChildItems == null) - return; - - foreach (var child in sci.ChildItems.Where(x => x.Item.Id != sci.Item.Id)) - AdjustInventory(child.Item.Product, decrease, sci.Item.Quantity * child.Item.Quantity, child.Item.AttributesXml); - //AdjustInventory(child, decrease); + if (sci.ChildItems != null) + { + foreach (var child in sci.ChildItems.Where(x => x.Item.Id != sci.Item.Id)) + { + AdjustInventory(child.Item.Product, decrease, sci.Item.Quantity * child.Item.Quantity, child.Item.AttributesXml); + } + } + return new AdjustInventoryResult(); } else { - AdjustInventory(sci.Item.Product, decrease, sci.Item.Quantity, sci.Item.AttributesXml); + return AdjustInventory(sci.Item.Product, decrease, sci.Item.Quantity, sci.Item.AttributesXml); } } @@ -979,7 +1213,8 @@ public virtual void AdjustInventory(OrganizedShoppingCartItem sci, bool decrease /// Order item /// A value indicating whether to increase or descrease product stock quantity /// Quantity - public virtual void AdjustInventory(OrderItem orderItem, bool decrease, int quantity) + /// Adjust inventory result + public virtual AdjustInventoryResult AdjustInventory(OrderItem orderItem, bool decrease, int quantity) { if (orderItem == null) throw new ArgumentNullException("orderItem"); @@ -1001,10 +1236,11 @@ public virtual void AdjustInventory(OrderItem orderItem, bool decrease, int quan } } } + return new AdjustInventoryResult(); } else { - AdjustInventory(orderItem.Product, decrease, quantity, orderItem.AttributesXml); + return AdjustInventory(orderItem.Product, decrease, quantity, orderItem.AttributesXml); } } @@ -1015,12 +1251,13 @@ public virtual void AdjustInventory(OrderItem orderItem, bool decrease, int quan /// A value indicating whether to increase or descrease product stock quantity /// Quantity /// Attributes in XML format - public virtual void AdjustInventory(Product product, bool decrease, int quantity, string attributesXml) + /// Adjust inventory result + public virtual AdjustInventoryResult AdjustInventory(Product product, bool decrease, int quantity, string attributesXml) { if (product == null) throw new ArgumentNullException("product"); - var prevStockQuantity = product.StockQuantity; + var result = new AdjustInventoryResult(); switch (product.ManageInventoryMethod) { @@ -1031,11 +1268,11 @@ public virtual void AdjustInventory(Product product, bool decrease, int quantity break; case ManageInventoryMethod.ManageStock: { - int newStockQuantity = 0; + result.StockQuantityOld = product.StockQuantity; if (decrease) - newStockQuantity = product.StockQuantity - quantity; + result.StockQuantityNew = product.StockQuantity - quantity; else - newStockQuantity = product.StockQuantity + quantity; + result.StockQuantityNew = product.StockQuantity + quantity; bool newPublished = product.Published; bool newDisableBuyButton = product.DisableBuyButton; @@ -1045,37 +1282,38 @@ public virtual void AdjustInventory(Product product, bool decrease, int quantity switch (product.LowStockActivity) { case LowStockActivity.DisableBuyButton: - newDisableBuyButton = product.MinStockQuantity >= newStockQuantity; - newDisableWishlistButton = product.MinStockQuantity >= newStockQuantity; + newDisableBuyButton = product.MinStockQuantity >= result.StockQuantityNew; + newDisableWishlistButton = product.MinStockQuantity >= result.StockQuantityNew; break; case LowStockActivity.Unpublish: - newPublished = product.MinStockQuantity <= newStockQuantity; + newPublished = product.MinStockQuantity <= result.StockQuantityNew; break; } - product.StockQuantity = newStockQuantity; + product.StockQuantity = result.StockQuantityNew; product.DisableBuyButton = newDisableBuyButton; product.DisableWishlistButton = newDisableWishlistButton; product.Published = newPublished; + UpdateProduct(product); //send email notification - if (decrease && product.NotifyAdminForQuantityBelow > newStockQuantity) + if (decrease && product.NotifyAdminForQuantityBelow > result.StockQuantityNew) _workflowMessageService.SendQuantityBelowStoreOwnerNotification(product, _localizationSettings.DefaultAdminLanguageId); } break; case ManageInventoryMethod.ManageStockByAttributes: { - var combination = _productAttributeParser.FindProductVariantAttributeCombination(product, attributesXml); + var combination = _productAttributeParser.FindProductVariantAttributeCombination(product.Id, attributesXml); if (combination != null) { - int newStockQuantity = 0; + result.StockQuantityOld = combination.StockQuantity; if (decrease) - newStockQuantity = combination.StockQuantity - quantity; + result.StockQuantityNew = combination.StockQuantity - quantity; else - newStockQuantity = combination.StockQuantity + quantity; + result.StockQuantityNew = combination.StockQuantity + quantity; - combination.StockQuantity = newStockQuantity; + combination.StockQuantity = result.StockQuantityNew; _productAttributeService.UpdateProductVariantAttributeCombination(combination); } } @@ -1096,17 +1334,7 @@ public virtual void AdjustInventory(Product product, bool decrease, int quantity AdjustInventory(linkedProduct, decrease, quantity * x.Quantity, ""); }); - //TODO send back in stock notifications? - //if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock && - // product.BackorderMode == BackorderMode.NoBackorders && - // product.AllowBackInStockSubscriptions && - // product.StockQuantity > 0 && - // prevStockQuantity <= 0 && - // product.Published && - // !product.Deleted) - //{ - // //_backInStockSubscriptionService.SendNotificationsToSubscribers(product); - //} + return result; } /// @@ -1156,6 +1384,71 @@ public virtual void UpdateHasDiscountsApplied(Product product) UpdateProduct(product); } + public virtual Multimap GetProductTagsByProductIds(int[] productIds) + { + Guard.ArgumentNotNull(() => productIds); + + var query = _productRepository.TableUntracked + .Expand(x => x.ProductTags) + .Where(x => productIds.Contains(x.Id)) + .Select(x => new + { + ProductId = x.Id, + Tags = x.ProductTags + }); + + var map = new Multimap(); + + foreach (var item in query.ToList()) + { + foreach (var tag in item.Tags) + map.Add(item.ProductId, tag); + } + + return map; + } + + public virtual Multimap GetAppliedDiscountsByProductIds(int[] productIds) + { + Guard.ArgumentNotNull(() => productIds); + + var query = _productRepository.TableUntracked + .Expand(x => x.AppliedDiscounts.Select(y => y.DiscountRequirements)) + .Where(x => productIds.Contains(x.Id)) + .Select(x => new + { + ProductId = x.Id, + Discounts = x.AppliedDiscounts + }); + + var map = new Multimap(); + + foreach (var item in query.ToList()) + { + foreach (var discount in item.Discounts) + map.Add(item.ProductId, discount); + } + + return map; + } + + public virtual Multimap GetProductSpecificationAttributesByProductIds(int[] productIds) + { + Guard.ArgumentNotNull(() => productIds); + + var query = _productSpecificationAttributeRepository.TableUntracked + .Expand(x => x.SpecificationAttributeOption) + .Expand(x => x.SpecificationAttributeOption.SpecificationAttribute) + .Where(x => productIds.Contains(x.ProductId)); + + var map = query + .OrderBy(x => x.DisplayOrder) + .ToList() + .ToMultimap(x => x.ProductId, x => x); + + return map; + } + #endregion #region Related products @@ -1172,7 +1465,7 @@ public virtual void DeleteRelatedProduct(RelatedProduct relatedProduct) _relatedProductRepository.Delete(relatedProduct); //event notification - _eventPublisher.EntityDeleted(relatedProduct); + _services.EventPublisher.EntityDeleted(relatedProduct); } /// @@ -1185,13 +1478,11 @@ public virtual IList GetRelatedProductsByProductId1(int productI { var query = from rp in _relatedProductRepository.Table join p in _productRepository.Table on rp.ProductId2 equals p.Id - where rp.ProductId1 == productId1 && - !p.Deleted && - (showHidden || p.Published) + where rp.ProductId1 == productId1 && !p.Deleted && (showHidden || p.Published) orderby rp.DisplayOrder select rp; - var relatedProducts = query.ToList(); + var relatedProducts = query.ToList(); return relatedProducts; } @@ -1221,7 +1512,7 @@ public virtual void InsertRelatedProduct(RelatedProduct relatedProduct) _relatedProductRepository.Insert(relatedProduct); //event notification - _eventPublisher.EntityInserted(relatedProduct); + _services.EventPublisher.EntityInserted(relatedProduct); } /// @@ -1236,9 +1527,26 @@ public virtual void UpdateRelatedProduct(RelatedProduct relatedProduct) _relatedProductRepository.Update(relatedProduct); //event notification - _eventPublisher.EntityUpdated(relatedProduct); + _services.EventPublisher.EntityUpdated(relatedProduct); } + /// + /// Ensure existence of all mutually related products + /// + /// First product identifier + /// Number of inserted related products + public virtual int EnsureMutuallyRelatedProducts(int productId1) + { + var relatedProducts = GetRelatedProductsByProductId1(productId1, true); + var productIds = relatedProducts.Select(x => x.ProductId2).ToList(); + + if (productIds.Count > 0 && !productIds.Any(x => x == productId1)) + productIds.Add(productId1); + + int count = EnsureMutuallyRelatedProducts(productIds); + return count; + } + #endregion #region Cross-sell products @@ -1255,7 +1563,7 @@ public virtual void DeleteCrossSellProduct(CrossSellProduct crossSellProduct) _crossSellProductRepository.Delete(crossSellProduct); //event notification - _eventPublisher.EntityDeleted(crossSellProduct); + _services.EventPublisher.EntityDeleted(crossSellProduct); } /// @@ -1303,7 +1611,7 @@ public virtual void InsertCrossSellProduct(CrossSellProduct crossSellProduct) _crossSellProductRepository.Insert(crossSellProduct); //event notification - _eventPublisher.EntityInserted(crossSellProduct); + _services.EventPublisher.EntityInserted(crossSellProduct); } /// @@ -1318,7 +1626,7 @@ public virtual void UpdateCrossSellProduct(CrossSellProduct crossSellProduct) _crossSellProductRepository.Update(crossSellProduct); //event notification - _eventPublisher.EntityUpdated(crossSellProduct); + _services.EventPublisher.EntityUpdated(crossSellProduct); } /// @@ -1369,6 +1677,24 @@ public virtual IList GetCrosssellProductsByShoppingCart(IList + /// Ensure existence of all mutually cross selling products + /// + /// First product identifier + /// Number of inserted cross selling products + public virtual int EnsureMutuallyCrossSellProducts(int productId1) + { + var crossSellProducts = GetCrossSellProductsByProductId1(productId1, true); + var productIds = crossSellProducts.Select(x => x.ProductId2).ToList(); + + if (productIds.Count > 0 && !productIds.Any(x => x == productId1)) + productIds.Add(productId1); + + int count = EnsureMutuallyCrossSellProducts(productIds); + return count; + } + #endregion #region Tier prices @@ -1387,7 +1713,7 @@ public virtual void DeleteTierPrice(TierPrice tierPrice) _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(tierPrice); + _services.EventPublisher.EntityDeleted(tierPrice); } /// @@ -1404,6 +1730,31 @@ public virtual TierPrice GetTierPriceById(int tierPriceId) return tierPrice; } + public virtual Multimap GetTierPricesByProductIds(int[] productIds, Customer customer = null, int storeId = 0) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from x in _tierPriceRepository.TableUntracked + where productIds.Contains(x.ProductId) + select x; + + if (storeId != 0) + query = query.Where(x => x.StoreId == 0 || x.StoreId == storeId); + + query = query.OrderBy(x => x.ProductId).ThenBy(x => x.Quantity); + + var list = query.ToList(); + + if (customer != null) + list = list.FilterForCustomer(customer).ToList(); + + var map = list + .ToMultimap(x => x.ProductId, x => x); + + return map; + } + /// /// Inserts a tier price /// @@ -1418,7 +1769,7 @@ public virtual void InsertTierPrice(TierPrice tierPrice) _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(tierPrice); + _services.EventPublisher.EntityInserted(tierPrice); } /// @@ -1435,7 +1786,7 @@ public virtual void UpdateTierPrice(TierPrice tierPrice) _cacheManager.RemoveByPattern(PRODUCTS_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(tierPrice); + _services.EventPublisher.EntityUpdated(tierPrice); } #endregion @@ -1451,13 +1802,12 @@ public virtual void DeleteProductPicture(ProductPicture productPicture) if (productPicture == null) throw new ArgumentNullException("productPicture"); - // codehint: sm-add UnassignDeletedPictureFromVariantCombinations(productPicture); _productPictureRepository.Delete(productPicture); //event notification - _eventPublisher.EntityDeleted(productPicture); + _services.EventPublisher.EntityDeleted(productPicture); } private void UnassignDeletedPictureFromVariantCombinations(ProductPicture productPicture) @@ -1505,6 +1855,33 @@ orderby pp.DisplayOrder return productPictures; } + public virtual Multimap GetProductPicturesByProductIds(int[] productIds, bool onlyFirstPicture = false) + { + var query = + from pp in _productPictureRepository.TableUntracked.Expand(x => x.Picture) + where productIds.Contains(pp.ProductId) + orderby pp.ProductId, pp.DisplayOrder + select pp; + + if (onlyFirstPicture) + { + var map = query.GroupBy(x => x.ProductId, x => x) + .Select(x => x.FirstOrDefault()) + .ToList() + .ToMultimap(x => x.ProductId, x => x); + + return map; + } + else + { + var map = query + .ToList() + .ToMultimap(x => x.ProductId, x => x); + + return map; + } + } + /// /// Gets a product picture /// @@ -1531,7 +1908,7 @@ public virtual void InsertProductPicture(ProductPicture productPicture) _productPictureRepository.Insert(productPicture); //event notification - _eventPublisher.EntityInserted(productPicture); + _services.EventPublisher.EntityInserted(productPicture); } /// @@ -1546,7 +1923,7 @@ public virtual void UpdateProductPicture(ProductPicture productPicture) _productPictureRepository.Update(productPicture); //event notification - _eventPublisher.EntityUpdated(productPicture); + _services.EventPublisher.EntityUpdated(productPicture); } #endregion @@ -1574,7 +1951,7 @@ public virtual void InsertBundleItem(ProductBundleItem bundleItem) _productBundleItemRepository.Insert(bundleItem); //event notification - _eventPublisher.EntityInserted(bundleItem); + _services.EventPublisher.EntityInserted(bundleItem); } /// @@ -1589,7 +1966,7 @@ public virtual void UpdateBundleItem(ProductBundleItem bundleItem) _productBundleItemRepository.Update(bundleItem); //event notification - _eventPublisher.EntityUpdated(bundleItem); + _services.EventPublisher.EntityUpdated(bundleItem); } /// @@ -1604,7 +1981,7 @@ public virtual void DeleteBundleItem(ProductBundleItem bundleItem) _productBundleItemRepository.Delete(bundleItem); //event notification - _eventPublisher.EntityDeleted(bundleItem); + _services.EventPublisher.EntityDeleted(bundleItem); } /// @@ -1635,7 +2012,7 @@ join p in _productRepository.Table on pbi.ProductId equals p.Id orderby pbi.DisplayOrder select pbi; - query = _productBundleItemRepository.Expand(query, x => x.Product); + query = query.Expand(x => x.Product); var bundleItemData = new List(); @@ -1644,6 +2021,24 @@ orderby pbi.DisplayOrder return bundleItemData; } + public virtual Multimap GetBundleItemsByProductIds(int[] productIds, bool showHidden = false) + { + Guard.ArgumentNotNull(() => productIds); + + var query = + from pbi in _productBundleItemRepository.TableUntracked + join p in _productRepository.TableUntracked on pbi.ProductId equals p.Id + where productIds.Contains(pbi.BundleProductId) && !p.Deleted && (showHidden || (pbi.Published && p.Published)) + orderby pbi.DisplayOrder + select pbi; + + var map = query + .ToList() + .ToMultimap(x => x.BundleProductId, x => x); + + return map; + } + #endregion #endregion diff --git a/src/Libraries/SmartStore.Services/Catalog/ProductTagService.cs b/src/Libraries/SmartStore.Services/Catalog/ProductTagService.cs index 53cad4b1a5..a80d073138 100644 --- a/src/Libraries/SmartStore.Services/Catalog/ProductTagService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/ProductTagService.cs @@ -11,10 +11,10 @@ namespace SmartStore.Services.Catalog { - /// - /// Product tag service - /// - public partial class ProductTagService : IProductTagService + /// + /// Product tag service + /// + public partial class ProductTagService : IProductTagService { #region Constants @@ -36,6 +36,7 @@ public partial class ProductTagService : IProductTagService #region Fields private readonly IRepository _productTagRepository; + private readonly IRepository _storeMappingRepository; private readonly IDataProvider _dataProvider; private readonly IDbContext _dbContext; private readonly CommonSettings _commonSettings; @@ -55,7 +56,9 @@ public partial class ProductTagService : IProductTagService /// Common settings /// Cache manager /// Event published - public ProductTagService(IRepository productTagRepository, + public ProductTagService( + IRepository productTagRepository, + IRepository storeMappingRepository, IDataProvider dataProvider, IDbContext dbContext, CommonSettings commonSettings, @@ -63,14 +66,19 @@ public ProductTagService(IRepository productTagRepository, IEventPublisher eventPublisher) { _productTagRepository = productTagRepository; + _storeMappingRepository = storeMappingRepository; _dataProvider = dataProvider; _dbContext = dbContext; _commonSettings = commonSettings; _cacheManager = cacheManager; _eventPublisher = eventPublisher; - } - #endregion + QuerySettings = DbQuerySettings.Default; + } + + public DbQuerySettings QuerySettings { get; set; } + + #endregion #region Nested classes @@ -94,55 +102,38 @@ private Dictionary GetProductCount(int storeId) string key = string.Format(PRODUCTTAG_COUNT_KEY, storeId); return _cacheManager.Get(key, () => { + IEnumerable tagCount = null; if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduresSupported) { - //stored procedures are enabled and supported by the database. - //It's much faster than the LINQ implementation below + //stored procedures are enabled and supported by the database. It's much faster than the LINQ implementation below - #region Use stored procedure - - //prepare parameters var pStoreId = _dataProvider.GetParameter(); pStoreId.ParameterName = "StoreId"; pStoreId.Value = storeId; pStoreId.DbType = DbType.Int32; - - //invoke stored procedure - var result = _dbContext.SqlQuery( - "Exec ProductTagCountLoadAll @StoreId", - pStoreId); - - var dictionary = new Dictionary(); - foreach (var item in result) - dictionary.Add(item.ProductTagId, item.ProductCount); - return dictionary; - - #endregion + tagCount = _dbContext.SqlQuery("Exec ProductTagCountLoadAll @StoreId", pStoreId); } else { //stored procedures aren't supported. Use LINQ - #region Search products - var query = from pt in _productTagRepository.Table - select new - { - Id = pt.Id, - ProductCount = pt.Products - //published and not deleted product/variants - .Count(p => !p.Deleted && p.Published) - //UNDOEN filter by store identifier if specified ( > 0 ) - }; - - var dictionary = new Dictionary(); - foreach (var item in query) - dictionary.Add(item.Id, item.ProductCount); - return dictionary; - - #endregion + tagCount = _productTagRepository.Table + .Select(pt => new ProductTagWithCount + { + ProductTagId = pt.Id, + ProductCount = (storeId > 0 && !QuerySettings.IgnoreMultiStore) ? + (from p in pt.Products + join sm in _storeMappingRepository.Table on new { pid = p.Id, pname = "Product" } equals new { pid = sm.EntityId, pname = sm.EntityName } into psm + from sm in psm.DefaultIfEmpty() + where (!p.LimitedToStores || storeId == sm.StoreId) && !p.Deleted && p.Published + select p).Count() : + pt.Products.Count(p => !p.Deleted && p.Published) + }); } + + return tagCount.ToDictionary(x => x.ProductTagId, x => x.ProductCount); }); } @@ -265,10 +256,11 @@ public virtual void UpdateProductTag(ProductTag productTag) public virtual int GetProductCount(int productTagId, int storeId) { var dictionary = GetProductCount(storeId); + if (dictionary.ContainsKey(productTagId)) return dictionary[productTagId]; - else - return 0; + + return 0; } #endregion diff --git a/src/Libraries/SmartStore.Services/Catalog/RecentlyViewedProductsService.cs b/src/Libraries/SmartStore.Services/Catalog/RecentlyViewedProductsService.cs index 22958b6364..13b86c2e3d 100644 --- a/src/Libraries/SmartStore.Services/Catalog/RecentlyViewedProductsService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/RecentlyViewedProductsService.cs @@ -107,8 +107,11 @@ public virtual void AddProductToRecentlyViewedList(int productId) } var recentlyViewedCookie = _httpContext.Request.Cookies.Get("SmartStore.RecentlyViewedProducts"); - if (recentlyViewedCookie == null) - recentlyViewedCookie = new HttpCookie("SmartStore.RecentlyViewedProducts"); + if (recentlyViewedCookie == null) + { + recentlyViewedCookie = new HttpCookie("SmartStore.RecentlyViewedProducts"); + recentlyViewedCookie.HttpOnly = true; + } recentlyViewedCookie.Values.Clear(); int maxProducts = _catalogSettings.RecentlyViewedProductsNumber; diff --git a/src/Libraries/SmartStore.Services/Catalog/SpecificationAttributeService.cs b/src/Libraries/SmartStore.Services/Catalog/SpecificationAttributeService.cs index 5273f63503..cc146a0f5b 100644 --- a/src/Libraries/SmartStore.Services/Catalog/SpecificationAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Catalog/SpecificationAttributeService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; @@ -73,16 +74,36 @@ public virtual SpecificationAttribute GetSpecificationAttributeById(int specific /// /// Gets specification attributes /// - /// Specification attributes - public virtual IList GetSpecificationAttributes() + /// Specification attribute query + public virtual IQueryable GetSpecificationAttributes() { - var query = from sa in _specificationAttributeRepository.Table - orderby sa.DisplayOrder, sa.Name - select sa; - var specificationAttributes = query.ToList(); - return specificationAttributes; + var query = + from sa in _specificationAttributeRepository.Table + orderby sa.DisplayOrder, sa.Name + select sa; + + return query; } + /// + /// Gets specification attributes by identifier + /// + /// Identifiers + /// Specification attribute query + public virtual IQueryable GetSpecificationAttributesByIds(int[] ids) + { + if (ids == null || ids.Length == 0) + return null; + + var query = + from sa in _specificationAttributeRepository.Table + where ids.Contains(sa.Id) + orderby sa.DisplayOrder, sa.Name + select sa; + + return query; + } + /// /// Deletes a specification attribute /// @@ -92,7 +113,7 @@ public virtual void DeleteSpecificationAttribute(SpecificationAttribute specific if (specificationAttribute == null) throw new ArgumentNullException("specificationAttribute"); - // codehint: sm-add (delete localized properties of options) + // (delete localized properties of options) var options = GetSpecificationAttributeOptionsBySpecificationAttribute(specificationAttribute.Id); foreach (var itm in options) { DeleteSpecificationAttributeOption(itm); @@ -335,9 +356,8 @@ public virtual void UpdateProductSpecificationAttribute(ProductSpecificationAttr _eventPublisher.EntityUpdated(productSpecificationAttribute); } - /// codehint: sm-add public virtual void UpdateProductSpecificationMapping(int specificationAttributeId, string field, bool value) { - if (specificationAttributeId == 0 || field.IsNullOrEmpty()) + if (specificationAttributeId == 0 || field.IsEmpty()) return; bool isAllowFiltering = field.IsCaseInsensitiveEqual("AllowFiltering"); diff --git a/src/Libraries/SmartStore.Services/Cms/IWidget.cs b/src/Libraries/SmartStore.Services/Cms/IWidget.cs index 48a913a987..935756d117 100644 --- a/src/Libraries/SmartStore.Services/Cms/IWidget.cs +++ b/src/Libraries/SmartStore.Services/Cms/IWidget.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; using System.Web.Routing; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Cms { /// /// Provides an interface for creating widgets /// - public partial interface IWidget + public partial interface IWidget : IProvider, IUserEditable { /// /// Gets widget zones where this widget should be rendered @@ -19,7 +20,7 @@ public partial interface IWidget /// /// Widget zone where it's displayed /// The model of the parent view context - /// The of the current store + /// The id of the current store /// Action name /// Controller name /// Route values diff --git a/src/Libraries/SmartStore.Services/Cms/IWidgetPlugin.cs b/src/Libraries/SmartStore.Services/Cms/IWidgetPlugin.cs deleted file mode 100644 index 2b8863bb09..0000000000 --- a/src/Libraries/SmartStore.Services/Cms/IWidgetPlugin.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Plugins; - -namespace SmartStore.Services.Cms -{ - /// - /// Provides an interface for widget plugins - /// - public partial interface IWidgetPlugin : IWidget, IPlugin - { - /// - /// Gets a route for plugin configuration - /// - /// Action name - /// Controller name - /// Route values - void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); - } -} diff --git a/src/Libraries/SmartStore.Services/Cms/IWidgetService.cs b/src/Libraries/SmartStore.Services/Cms/IWidgetService.cs index 59fcb73066..8e4faf8bb5 100644 --- a/src/Libraries/SmartStore.Services/Cms/IWidgetService.cs +++ b/src/Libraries/SmartStore.Services/Cms/IWidgetService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Cms { @@ -12,7 +13,7 @@ public partial interface IWidgetService /// /// Load records allows only in specified store; pass 0 to load all records /// Widgets - IList LoadActiveWidgets(int storeId = 0); + IEnumerable> LoadActiveWidgets(int storeId = 0); /// @@ -21,20 +22,20 @@ public partial interface IWidgetService /// Widget zone /// Load records allows only in specified store; pass 0 to load all records /// Widgets - IList LoadActiveWidgetsByWidgetZone(string widgetZone, int storeId = 0); + IEnumerable> LoadActiveWidgetsByWidgetZone(string widgetZone, int storeId = 0); /// /// Load widget by system name /// /// System name /// Found widget - IWidgetPlugin LoadWidgetBySystemName(string systemName); + Provider LoadWidgetBySystemName(string systemName); /// /// Load all widgets /// /// Load records allows only in specified store; pass 0 to load all records /// Widgets - IList LoadAllWidgets(int storeId = 0); + IEnumerable> LoadAllWidgets(int storeId = 0); } } diff --git a/src/Libraries/SmartStore.Services/Cms/WidgetExtensions.cs b/src/Libraries/SmartStore.Services/Cms/WidgetExtensions.cs new file mode 100644 index 0000000000..5b4632827d --- /dev/null +++ b/src/Libraries/SmartStore.Services/Cms/WidgetExtensions.cs @@ -0,0 +1,30 @@ +using System; +using System.Linq; +using SmartStore.Core.Domain.Cms; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.Cms +{ + public static class WidgetExtensions + { + public static bool IsWidgetActive(this Provider widget, WidgetSettings widgetSettings) + { + Guard.ArgumentNotNull(() => widget); + + return widget.ToLazy().IsWidgetActive(widgetSettings); + } + + public static bool IsWidgetActive(this Lazy widget, WidgetSettings widgetSettings) + { + Guard.ArgumentNotNull(() => widget); + Guard.ArgumentNotNull(() => widgetSettings); + + if (widgetSettings.ActiveWidgetSystemNames == null) + { + return false; + } + + return widgetSettings.ActiveWidgetSystemNames.Contains(widget.Metadata.SystemName, StringComparer.OrdinalIgnoreCase); + } + } +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Cms/WidgetExtentions.cs b/src/Libraries/SmartStore.Services/Cms/WidgetExtentions.cs deleted file mode 100644 index 0359f3f024..0000000000 --- a/src/Libraries/SmartStore.Services/Cms/WidgetExtentions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using SmartStore.Core.Domain.Cms; - -namespace SmartStore.Services.Cms -{ - public static class WidgetExtentions - { - public static bool IsWidgetActive(this IWidgetPlugin widget, WidgetSettings widgetSettings) - { - Guard.ArgumentNotNull(() => widget); - Guard.ArgumentNotNull(() => widgetSettings); - - if (widgetSettings.ActiveWidgetSystemNames == null) - { - return false; - } - - foreach (string systemName in widgetSettings.ActiveWidgetSystemNames) - { - if (widget.PluginDescriptor.SystemName.Equals(systemName, StringComparison.InvariantCultureIgnoreCase)) - return true; - } - - return false; - } - } -} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Cms/WidgetService.cs b/src/Libraries/SmartStore.Services/Cms/WidgetService.cs index 56b5cea6d7..e4077ac400 100644 --- a/src/Libraries/SmartStore.Services/Cms/WidgetService.cs +++ b/src/Libraries/SmartStore.Services/Cms/WidgetService.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; +using SmartStore.Core.Caching; using SmartStore.Core.Domain.Cms; using SmartStore.Core.Plugins; using SmartStore.Services.Configuration; @@ -13,11 +15,16 @@ namespace SmartStore.Services.Cms public partial class WidgetService : IWidgetService { - #region Fields + #region Fields & Consts + + private const string WIDGETS_ACTIVE_KEY = "SmartStore.widgets.active-{0}"; + private const string WIDGETS_ZONEMAPPED_KEY = "SmartStore.widgets.zonemapped-{0}"; private readonly IPluginFinder _pluginFinder; private readonly WidgetSettings _widgetSettings; - private readonly ISettingService _settingService; // codehint: sm-add + private readonly ISettingService _settingService; + private readonly IProviderManager _providerManager; + private readonly ICacheManager _cacheManager; #endregion @@ -29,27 +36,47 @@ public partial class WidgetService : IWidgetService /// Plugin finder /// Widget settings /// Plugin service - public WidgetService(IPluginFinder pluginFinder, WidgetSettings widgetSettings, ISettingService settingService) + public WidgetService( + IPluginFinder pluginFinder, + WidgetSettings widgetSettings, + ISettingService settingService, + IProviderManager providerManager, + ICacheManager cacheManager) { this._pluginFinder = pluginFinder; this._widgetSettings = widgetSettings; - this._settingService = settingService; // codehint: sm-add + this._settingService = settingService; + this._providerManager = providerManager; + this._cacheManager = cacheManager; } #endregion #region Methods + /// + /// Load all widgets + /// + /// Load records allows only in specified store; pass 0 to load all records + /// Widgets + public virtual IEnumerable> LoadAllWidgets(int storeId = 0) + { + return _providerManager.GetAllProviders(storeId); + } + /// /// Load active widgets /// /// Load records allows only in specified store; pass 0 to load all records /// Widgets - public virtual IList LoadActiveWidgets(int storeId = 0) + public virtual IEnumerable> LoadActiveWidgets(int storeId = 0) { - return LoadAllWidgets(storeId) - .Where(x => _widgetSettings.ActiveWidgetSystemNames.Contains(x.PluginDescriptor.SystemName, StringComparer.InvariantCultureIgnoreCase)) - .ToList(); + var activeWidgets = _cacheManager.Get(WIDGETS_ACTIVE_KEY.FormatInvariant(storeId), () => { + var allWigets = LoadAllWidgets(storeId); + return allWigets.Where(p => _widgetSettings.ActiveWidgetSystemNames.Contains(p.Metadata.SystemName, StringComparer.InvariantCultureIgnoreCase)); + }); + + return activeWidgets; } /// @@ -58,14 +85,37 @@ public virtual IList LoadActiveWidgets(int storeId = 0) /// Widget zone /// Load records allows only in specified store; pass 0 to load all records /// Widgets - public virtual IList LoadActiveWidgetsByWidgetZone(string widgetZone, int storeId = 0) + public virtual IEnumerable> LoadActiveWidgetsByWidgetZone(string widgetZone, int storeId = 0) { - if (String.IsNullOrWhiteSpace(widgetZone)) - return new List(); + if (widgetZone.IsEmpty()) + return Enumerable.Empty>(); + + var mappedWidgets = _cacheManager.Get(WIDGETS_ZONEMAPPED_KEY.FormatInvariant(storeId), () => { + var activeWidgets = LoadActiveWidgets(storeId); + var map = new Multimap>(); + + foreach (var widget in activeWidgets) + { + var zones = widget.Value.GetWidgetZones(); + if (zones != null && zones.Any()) + { + foreach (var zone in zones.Select(x => x.ToLower())) + { + map.Add(zone, widget); + } + } + } + + return map; + }); + + widgetZone = widgetZone.ToLower(); + if (mappedWidgets.ContainsKey(widgetZone)) + { + return mappedWidgets[widgetZone]; + } - return LoadActiveWidgets(storeId) - .Where(x => x.GetWidgetZones().Contains(widgetZone, StringComparer.InvariantCultureIgnoreCase)) - .ToList(); + return Enumerable.Empty>(); } /// @@ -73,26 +123,9 @@ public virtual IList LoadActiveWidgetsByWidgetZone(string widgetZ /// /// System name /// Found widget - public virtual IWidgetPlugin LoadWidgetBySystemName(string systemName) - { - var descriptor = _pluginFinder.GetPluginDescriptorBySystemName(systemName); - if (descriptor != null) - return descriptor.Instance(); - - return null; - } - - /// - /// Load all widgets - /// - /// Load records allows only in specified store; pass 0 to load all records - /// Widgets - public virtual IList LoadAllWidgets(int storeId = 0) + public virtual Provider LoadWidgetBySystemName(string systemName) { - return _pluginFinder - .GetPlugins() - .Where(x => storeId == 0 || _settingService.GetSettingByKey(x.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) - .ToList(); + return _providerManager.GetProvider(systemName); } #endregion diff --git a/src/Libraries/SmartStore.Services/Common/AddressExtentions.cs b/src/Libraries/SmartStore.Services/Common/AddressExtentions.cs index adad7b6413..1055aaa340 100644 --- a/src/Libraries/SmartStore.Services/Common/AddressExtentions.cs +++ b/src/Libraries/SmartStore.Services/Common/AddressExtentions.cs @@ -1,48 +1,128 @@ using System; +using System.Linq; using System.Collections.Generic; -using SmartStore.Core; +using System.Text; using SmartStore.Core.Domain.Common; namespace SmartStore.Services.Common { public static class AddressExtentions { - /// - /// Find an address - /// - /// Source - /// First name - /// Last name - /// Phone number - /// Email - /// Fax number - /// Company - /// Address 1 - /// Address 2 - /// City - /// State/province identifier - /// Zip postal code - /// Country identifier - /// Address - public static Address FindAddress(this List
source, - string firstName, string lastName, string phoneNumber, - string email, string faxNumber, string company, string address1, - string address2, string city, int? stateProvinceId, - string zipPostalCode, int? countryId) + /// + /// Find first occurrence of an address + /// + /// Addresses to be searched + /// Address to find + /// First occurrence of address + public static Address FindAddress(this ICollection
source, Address address) + { + return source.FindAddress( + address.FirstName, + address.LastName, + address.PhoneNumber, + address.Email, + address.FaxNumber, + address.Company, + address.Address1, + address.Address2, + address.City, + address.StateProvinceId, + address.ZipPostalCode, + address.CountryId + ); + } + + /// + /// Find an address + /// + /// Source + /// First name + /// Last name + /// Phone number + /// Email + /// Fax number + /// Company + /// Address 1 + /// Address 2 + /// City + /// State/province identifier + /// Zip postal code + /// Country identifier + /// Address + public static Address FindAddress( + this ICollection
source, + string firstName, + string lastName, + string phoneNumber, + string email, + string faxNumber, + string company, + string address1, + string address2, + string city, + int? stateProvinceId, + string zipPostalCode, + int? countryId) { - return source.Find((a) => ((String.IsNullOrEmpty(a.FirstName) && String.IsNullOrEmpty(firstName)) || a.FirstName == firstName) && - ((String.IsNullOrEmpty(a.LastName) && String.IsNullOrEmpty(lastName)) || a.LastName == lastName) && - ((String.IsNullOrEmpty(a.PhoneNumber) && String.IsNullOrEmpty(phoneNumber)) || a.PhoneNumber == phoneNumber) && - ((String.IsNullOrEmpty(a.Email) && String.IsNullOrEmpty(email)) || a.Email == email) && - ((String.IsNullOrEmpty(a.FaxNumber) && String.IsNullOrEmpty(faxNumber)) || a.FaxNumber == faxNumber) && - ((String.IsNullOrEmpty(a.Company) && String.IsNullOrEmpty(company)) || a.Company == company) && - ((String.IsNullOrEmpty(a.Address1) && String.IsNullOrEmpty(address1)) || a.Address1 == address1) && - ((String.IsNullOrEmpty(a.Address2) && String.IsNullOrEmpty(address2)) || a.Address2 == address2) && - ((String.IsNullOrEmpty(a.City) && String.IsNullOrEmpty(city)) || a.City == city) && - ((a.StateProvinceId.IsNullOrDefault() && stateProvinceId.IsNullOrDefault()) || a.StateProvinceId == stateProvinceId) && - ((String.IsNullOrEmpty(a.ZipPostalCode) && String.IsNullOrEmpty(zipPostalCode)) || a.ZipPostalCode == zipPostalCode) && - ((a.CountryId.IsNullOrDefault() && countryId.IsNullOrDefault()) || a.CountryId == countryId)); + Func addressMatcher = (x) => + { + return x.Email.IsCaseInsensitiveEqual(email) + && x.LastName.IsCaseInsensitiveEqual(lastName) + && x.FirstName.IsCaseInsensitiveEqual(firstName) + && x.Address1.IsCaseInsensitiveEqual(address1) + && x.Address2.IsCaseInsensitiveEqual(address2) + && x.Company.IsCaseInsensitiveEqual(company) + && x.ZipPostalCode.IsCaseInsensitiveEqual(zipPostalCode) + && x.City.IsCaseInsensitiveEqual(city) + && x.PhoneNumber.IsCaseInsensitiveEqual(phoneNumber) + && x.FaxNumber.IsCaseInsensitiveEqual(faxNumber) + && x.StateProvinceId == stateProvinceId + && x.CountryId == countryId; + }; + + return source.FirstOrDefault(addressMatcher); } + /// Returns the full name of the address. + public static string GetFullName(this Address address) + { + if (address != null) + { + var sb = new StringBuilder(address.FirstName); + + sb.Grow(address.LastName, " "); + + if (address.Company.HasValue()) + { + sb.Grow("({0})".FormatWith(address.Company), " "); + } + return sb.ToString(); + } + return null; + } + + /// + /// Checks whether the postal data of two addresses are equal. + /// + public static bool IsPostalDataEqual(this Address address, Address other) + { + if (address != null && other != null) + { + if (address.FirstName.IsCaseInsensitiveEqual(other.FirstName) && + address.LastName.IsCaseInsensitiveEqual(other.LastName) && + address.Company.IsCaseInsensitiveEqual(other.Company) && + address.Address1.IsCaseInsensitiveEqual(other.Address1) && + address.Address2.IsCaseInsensitiveEqual(other.Address2) && + address.ZipPostalCode.IsCaseInsensitiveEqual(other.ZipPostalCode) && + address.City.IsCaseInsensitiveEqual(other.City) && + address.StateProvinceId == other.StateProvinceId && + address.CountryId == other.CountryId) + { + return true; + } + } + + return false; + } } } diff --git a/src/Libraries/SmartStore.Services/Common/AddressService.cs b/src/Libraries/SmartStore.Services/Common/AddressService.cs index 026b110713..6ba5546ccb 100644 --- a/src/Libraries/SmartStore.Services/Common/AddressService.cs +++ b/src/Libraries/SmartStore.Services/Common/AddressService.cs @@ -4,6 +4,7 @@ using SmartStore.Core.Domain.Common; using SmartStore.Services.Directory; using SmartStore.Core.Events; +using System.Collections.Generic; namespace SmartStore.Services.Common { @@ -62,7 +63,6 @@ public virtual void DeleteAddress(Address address) _eventPublisher.EntityDeleted(address); } - /// codehint: sm-add public virtual void DeleteAddress(int id) { var address = GetAddressById(id); @@ -116,6 +116,18 @@ public virtual Address GetAddressById(int addressId) return address; } + public virtual IList
GetAddressByIds(int[] addressIds) + { + Guard.ArgumentNotNull(() => addressIds); + + var query = + from x in _addressRepository.TableUntracked.Expand(x => x.Country).Expand(x => x.StateProvince) + where addressIds.Contains(x.Id) + select x; + + return query.ToList(); + } + /// /// Inserts an address /// diff --git a/src/Libraries/SmartStore.Services/Common/FulltextService.cs b/src/Libraries/SmartStore.Services/Common/FulltextService.cs index c5e571269b..847b89c032 100644 --- a/src/Libraries/SmartStore.Services/Common/FulltextService.cs +++ b/src/Libraries/SmartStore.Services/Common/FulltextService.cs @@ -47,8 +47,15 @@ public virtual bool IsFullTextSupported() if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduresSupported) { //stored procedures are enabled and supported by the database. - var result = _dbContext.SqlQuery("EXEC [FullText_IsSupported]"); - return result.FirstOrDefault() > 0; + try + { + var result = _dbContext.SqlQuery("EXEC [FullText_IsSupported]"); + return result.Any() && result.FirstOrDefault() > 0; + } + catch + { + return false; + } } else { diff --git a/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs b/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs index e3d58978bb..8f23424525 100644 --- a/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Common/GenericAttributeService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; @@ -165,6 +166,20 @@ public virtual IList GetAttributesForEntity(int entityId, stri }); } + public virtual Multimap GetAttributesForEntity(int[] entityIds, string keyGroup) + { + Guard.ArgumentNotNull(() => entityIds); + + var query = _genericAttributeRepository.TableUntracked + .Where(x => entityIds.Contains(x.EntityId) && x.KeyGroup == keyGroup); + + var map = query + .ToList() + .ToMultimap(x => x.EntityId, x => x); + + return map; + } + /// /// Get queryable attributes /// @@ -194,48 +209,54 @@ public virtual void SaveAttribute(BaseEntity entity, string key, TPro if (entity == null) throw new ArgumentNullException("entity"); - string keyGroup = entity.GetUnproxiedEntityType().Name; + SaveAttribute(entity.Id, key, entity.GetUnproxiedEntityType().Name, value, storeId); + } - var props = GetAttributesForEntity(entity.Id, keyGroup) + public virtual void SaveAttribute(int entityId, string key, string keyGroup, TPropType value, int storeId = 0) + { + Guard.ArgumentNotZero(entityId, "entityId"); + + var props = GetAttributesForEntity(entityId, keyGroup) .Where(x => x.StoreId == storeId) .ToList(); - var prop = props.FirstOrDefault(ga => - ga.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)); //should be culture invariant - string valueStr = value.Convert(); + var prop = props.FirstOrDefault(ga => + ga.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)); // should be culture invariant - if (prop != null) - { - if (string.IsNullOrWhiteSpace(valueStr)) - { - //delete - DeleteAttribute(prop); - } - else - { - //update - prop.Value = valueStr; - UpdateAttribute(prop); - } - } - else - { - if (!string.IsNullOrWhiteSpace(valueStr)) - { - //insert - prop = new GenericAttribute() - { - EntityId = entity.Id, - Key = key, - KeyGroup = keyGroup, - Value = valueStr, + string valueStr = value.Convert(); + + if (prop != null) + { + if (string.IsNullOrWhiteSpace(valueStr)) + { + // delete + DeleteAttribute(prop); + } + else + { + // update + prop.Value = valueStr; + UpdateAttribute(prop); + } + } + else + { + if (!string.IsNullOrWhiteSpace(valueStr)) + { + // insert + prop = new GenericAttribute + { + EntityId = entityId, + Key = key, + KeyGroup = keyGroup, + Value = valueStr, StoreId = storeId - }; - InsertAttribute(prop); - } - } - } + }; + InsertAttribute(prop); + } + } + } - #endregion - } + #endregion + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Common/IAddressService.cs b/src/Libraries/SmartStore.Services/Common/IAddressService.cs index 3aa5c9338c..37faa65bea 100644 --- a/src/Libraries/SmartStore.Services/Common/IAddressService.cs +++ b/src/Libraries/SmartStore.Services/Common/IAddressService.cs @@ -1,5 +1,6 @@ +using System.Collections.Generic; using SmartStore.Core.Domain.Common; namespace SmartStore.Services.Common @@ -15,7 +16,6 @@ public partial interface IAddressService /// Address void DeleteAddress(Address address); - /// codehint: sm-add void DeleteAddress(int id); /// @@ -39,6 +39,13 @@ public partial interface IAddressService /// Address Address GetAddressById(int addressId); + /// + /// Gets addresses by address identifiers + /// + /// Address identifiers + /// Addresses + IList
GetAddressByIds(int[] addressIds); + /// /// Inserts an address /// diff --git a/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs b/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs index 4aabb70b7b..c584c4ad4c 100644 --- a/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Common/IGenericAttributeService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Common; @@ -40,9 +41,17 @@ public partial interface IGenericAttributeService ///
/// Entity identifier /// Key group - /// Get attributes + /// Generic attributes IList GetAttributesForEntity(int entityId, string keyGroup); + /// + /// Get attributes + /// + /// Entity identifiers + /// Key group + /// Generic attributes + Multimap GetAttributesForEntity(int[] entityIds, string keyGroup); + /// /// Get queryable attributes /// @@ -60,5 +69,16 @@ public partial interface IGenericAttributeService /// Value /// Store identifier; pass 0 if this attribute will be available for all stores void SaveAttribute(BaseEntity entity, string key, TPropType value, int storeId = 0); - } + + /// + /// Save attribute value + /// + /// Property type + /// Entity identifier + /// The key + /// The key group + /// Property type + /// Store identifier; pass 0 if this attribute will be available for all stores + void SaveAttribute(int entityId, string key, string keyGroup, TPropType value, int storeId = 0); + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Common/IMiscPlugin.cs b/src/Libraries/SmartStore.Services/Common/IMiscPlugin.cs deleted file mode 100644 index 357fd8801d..0000000000 --- a/src/Libraries/SmartStore.Services/Common/IMiscPlugin.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Web.Routing; -using SmartStore.Core.Plugins; - -namespace SmartStore.Services.Common -{ - /// - /// Misc plugin interface. - /// It's used by the plugins that have a configuration page but don't fit any other category (such as payment or tax plugins) - /// - public partial interface IMiscPlugin : IPlugin - { - /// - /// Gets a route for plugin configuration - /// - /// Action name - /// Controller name - /// Route values - void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); - } -} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Common/IPdfService.cs b/src/Libraries/SmartStore.Services/Common/IPdfService.cs deleted file mode 100644 index b71479aa3a..0000000000 --- a/src/Libraries/SmartStore.Services/Common/IPdfService.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Shipping; - -namespace SmartStore.Services.Common -{ - /// - /// Customer service interface - /// - public partial interface IPdfService - { - /// - /// Print an order to PDF - /// - /// Stream - /// Orders - /// Language - void PrintOrdersToPdf(Stream stream, IList orders, Language lang); - - /// - /// Print an order to PDF - /// - /// Orders - byte[] PrintOrdersToPdf(IList orders); - - - /// - /// Print packaging slips to PDF - /// - /// Stream - /// Shipments - /// Language - void PrintPackagingSlipsToPdf(Stream stream, IList shipments, Language lang); - - /// - /// Print packaging slips to PDF - /// - /// Shipments - byte[] PrintPackagingSlipsToPdf(IList shipments); - - - /// - /// Print product collection to PDF - /// - /// Stream - /// Products - /// Language - void PrintProductsToPdf(Stream stream, IList products, Language lang); - - /// - /// Print product collection to PDF - /// - /// Products - byte[] PrintProductsToPdf(IList products); - } -} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Common/IUserAgent.cs b/src/Libraries/SmartStore.Services/Common/IUserAgent.cs new file mode 100644 index 0000000000..a232323b07 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Common/IUserAgent.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.Services.Common +{ + + public interface IUserAgent + { + string RawValue { get; set; } + + UserAgentInfo UserAgent { get; } + DeviceInfo Device { get; } + OSInfo OS { get; } + + bool IsBot { get; } + bool IsMobileDevice { get; } + bool IsTablet { get; } + bool IsPdfConverter { get; } + } + + public sealed class DeviceInfo + { + public DeviceInfo(string family, bool isBot) + { + this.Family = family; + this.IsBot = isBot; + } + public override string ToString() + { + return this.Family; + } + public string Family { get; private set; } + public bool IsBot { get; private set; } + } + + public sealed class OSInfo + { + public OSInfo(string family, string major, string minor, string patch, string patchMinor) + { + this.Family = family; + this.Major = major; + this.Minor = minor; + this.Patch = patch; + this.PatchMinor = patchMinor; + } + public override string ToString() + { + var str = VersionString.Format(Major, Minor, Patch, PatchMinor); + return (this.Family + (!string.IsNullOrEmpty(str) ? (" " + str) : null)); + } + public string Family { get; private set; } + public string Major { get; private set; } + public string Minor { get; private set; } + public string Patch { get; private set; } + public string PatchMinor { get; private set; } + + private static string FormatVersionString(params string[] parts) + { + return string.Join(".", (from v in parts + where !string.IsNullOrEmpty(v) + select v).ToArray()); + } + } + + public sealed class UserAgentInfo + { + private static readonly HashSet s_Bots = new HashSet(StringComparer.InvariantCultureIgnoreCase) + { + "BingPreview" + }; + + private bool? _isBot; + + public UserAgentInfo(string family, string major, string minor, string patch) + { + this.Family = family; + this.Major = major; + this.Minor = minor; + this.Patch = patch; + } + public override string ToString() + { + var str = VersionString.Format(Major, Minor, Patch); + return (this.Family + (!string.IsNullOrEmpty(str) ? (" " + str) : null)); + } + public string Family { get; private set; } + public string Major { get; private set; } + public string Minor { get; private set; } + public string Patch { get; private set; } + public bool IsBot + { + get + { + if (!_isBot.HasValue) + { + _isBot = s_Bots.Contains(Family); + } + return _isBot.Value; + } + } + } + + internal static class VersionString + { + public static string Format(params string[] parts) + { + return string.Join(".", (from v in parts + where !string.IsNullOrEmpty(v) + select v).ToArray()); + } + } + + +} diff --git a/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs b/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs deleted file mode 100644 index 170c11300b..0000000000 --- a/src/Libraries/SmartStore.Services/Common/KeepAliveTask.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Net; -using SmartStore.Core; -using SmartStore.Services.Tasks; - -namespace SmartStore.Services.Common -{ - /// - /// Represents a task for keeping the site alive - /// - public partial class KeepAliveTask : ITask - { - private readonly IStoreContext _storeContext; - - public KeepAliveTask(IStoreContext storeContext) - { - this._storeContext = storeContext; - } - - public void Execute(TaskExecutionContext ctx) - { - var storeUrl = _storeContext.CurrentStore.Url.TrimEnd('\\').EnsureEndsWith("/"); - string url = storeUrl + "keepalive/index"; - - try - { - using (var wc = new WebClient()) - { - //wc.Headers.Add("SmartStore.NET"); // makes problems - wc.DownloadString(url); - } - } - catch (WebException ex) - { - if (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null) - { - var resp = (HttpWebResponse)ex.Response; - if (resp.StatusCode == HttpStatusCode.NotFound) // HTTP 404 - { - // the page was not found (as it can be expected with some webservers) - return; - } - } - // throw any other exception - this should not occur - throw; - } - } - } -} diff --git a/src/Libraries/SmartStore.Services/Common/MobileDeviceHelper.cs b/src/Libraries/SmartStore.Services/Common/MobileDeviceHelper.cs index ab1736189f..98576528cc 100644 --- a/src/Libraries/SmartStore.Services/Common/MobileDeviceHelper.cs +++ b/src/Libraries/SmartStore.Services/Common/MobileDeviceHelper.cs @@ -15,7 +15,7 @@ public partial class MobileDeviceHelper : IMobileDeviceHelper private readonly ThemeSettings _themeSettings; private readonly IWorkContext _workContext; private readonly IStoreContext _storeContext; - private readonly HttpContextBase _httpConttext; + private readonly IUserAgent _userAgent; #endregion @@ -26,13 +26,16 @@ public partial class MobileDeviceHelper : IMobileDeviceHelper ///
/// Work context /// Store context - public MobileDeviceHelper(ThemeSettings themeSettings, IWorkContext workContext, - IStoreContext storeContext, HttpContextBase httpContext) + public MobileDeviceHelper( + ThemeSettings themeSettings, + IWorkContext workContext, + IStoreContext storeContext, + IUserAgent userAgent) { this._themeSettings = themeSettings; this._workContext = workContext; this._storeContext = storeContext; - this._httpConttext = httpContext; + this._userAgent = userAgent; } #endregion @@ -47,20 +50,7 @@ public MobileDeviceHelper(ThemeSettings themeSettings, IWorkContext workContext, /// Result public virtual bool IsMobileDevice() { - if (_themeSettings.EmulateMobileDevice) - return true; - - //comment the code below if you want tablets to be recognized as mobile devices. - //SmartStore.NET uses the free edition of the 51degrees.mobi library for detecting browser mobile properties. - //by default this property (IsTablet) is always false. you will need the premium edition in order to get it supported. - bool isTablet = false; - if (bool.TryParse(_httpConttext.Request.Browser["IsTablet"], out isTablet) && isTablet) - return false; - - if (_httpConttext.Request.Browser.IsMobileDevice) - return true; - - return false; + return _themeSettings.EmulateMobileDevice || (_userAgent.IsMobileDevice && !_userAgent.IsTablet); } /// diff --git a/src/Libraries/SmartStore.Services/Common/PdfService.cs b/src/Libraries/SmartStore.Services/Common/PdfService.cs deleted file mode 100644 index 4f4331b96e..0000000000 --- a/src/Libraries/SmartStore.Services/Common/PdfService.cs +++ /dev/null @@ -1,1262 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using iTextSharp.text; -using iTextSharp.text.pdf; -using SmartStore.Core; -using SmartStore.Core.Domain; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Domain.Tax; -using SmartStore.Core.Html; -using SmartStore.Services.Catalog; -using SmartStore.Services.Directory; -using SmartStore.Services.Helpers; -using SmartStore.Services.Localization; -using SmartStore.Services.Media; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; -using System.Globalization; -using SmartStore.Services.Stores; - -namespace SmartStore.Services.Common -{ - /// - /// PDF service - /// - public partial class PdfService : IPdfService - { - #region Fields - - private readonly ILocalizationService _localizationService; - private readonly IOrderService _orderService; - private readonly IPaymentService _paymentService; - private readonly IDateTimeHelper _dateTimeHelper; - private readonly IPriceFormatter _priceFormatter; - private readonly ICurrencyService _currencyService; - private readonly IMeasureService _measureService; - private readonly IPictureService _pictureService; - private readonly IProductService _productService; - private readonly IProductAttributeParser _productAttributeParser; - private readonly IWebHelper _webHelper; - private readonly IStoreService _storeService; - private readonly IStoreContext _storeContext; - private readonly IWorkContext _workContext; - - private readonly CatalogSettings _catalogSettings; - private readonly CurrencySettings _currencySettings; - private readonly MeasureSettings _measureSettings; - private readonly PdfSettings _pdfSettings; - private readonly TaxSettings _taxSettings; - private readonly StoreInformationSettings _storeInformationSettings; - private readonly AddressSettings _addressSettings; - - private readonly CompanyInformationSettings _companyInformationSettings; - private readonly BankConnectionSettings _bankConnectionSettings; - private readonly ContactDataSettings _contactDataSettings; - - #endregion - - #region Ctor - - public PdfService(ILocalizationService localizationService, IOrderService orderService, - IPaymentService paymentService, - IDateTimeHelper dateTimeHelper, IPriceFormatter priceFormatter, - ICurrencyService currencyService, IMeasureService measureService, - IPictureService pictureService, IProductService productService, - IProductAttributeParser productAttributeParser, IStoreService storeService, - IStoreContext storeContext, - IWorkContext workContext, - IWebHelper webHelper, - CatalogSettings catalogSettings, CurrencySettings currencySettings, - MeasureSettings measureSettings, PdfSettings pdfSettings, TaxSettings taxSettings, - StoreInformationSettings storeInformationSettings, AddressSettings addressSettings, - CompanyInformationSettings companyInformationSettings, BankConnectionSettings bankConnectionSettings, - ContactDataSettings contactDataSettings) - { - this._localizationService = localizationService; - this._orderService = orderService; - this._paymentService = paymentService; - this._dateTimeHelper = dateTimeHelper; - this._priceFormatter = priceFormatter; - this._currencyService = currencyService; - this._measureService = measureService; - this._pictureService = pictureService; - this._productService = productService; - this._productAttributeParser = productAttributeParser; - this._storeService = storeService; - this._storeContext = storeContext; - this._workContext = workContext; - this._webHelper = webHelper; - this._currencySettings = currencySettings; - this._catalogSettings = catalogSettings; - this._measureSettings = measureSettings; - this._pdfSettings = pdfSettings; - this._taxSettings = taxSettings; - this._storeInformationSettings = storeInformationSettings; - this._addressSettings = addressSettings; - this._companyInformationSettings = companyInformationSettings; - this._bankConnectionSettings = bankConnectionSettings; - this._contactDataSettings = contactDataSettings; - } - - #endregion - - #region Utilities - - protected virtual Font GetFont() - { - //SmartStore.NET supports unicode characters - //SmartStore.NET uses Free Serif font by default (~/App_Data/Pdf/OpenSans-Regular.ttf file) - string fontPath = Path.Combine(_webHelper.MapPath("~/App_Data/Pdf/"), _pdfSettings.FontFileName); - var baseFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); - var font = new Font(baseFont, 10, Font.NORMAL); - return font; - } - - #endregion - - #region Methods - - /// - /// Print an order to PDF - /// - /// Stream - /// Orders - /// Language - public virtual void PrintOrdersToPdf(Stream stream, IList orders, Language lang) - { - if (stream == null) - throw new ArgumentNullException("stream"); - - if (orders == null) - throw new ArgumentNullException("orders"); - - if (lang == null) - throw new ArgumentNullException("lang"); - - - var pageSize = PageSize.A4; - - if (_pdfSettings.LetterPageSizeEnabled) - { - pageSize = PageSize.LETTER; - } - - - var doc = new Document(pageSize, 40, 40, 40, 80); - var writer = PdfWriter.GetInstance(doc, stream); - writer.PageEvent = new OrderPdfPageEvents(_pictureService, _pdfSettings, _companyInformationSettings, _bankConnectionSettings, _contactDataSettings, - _localizationService, lang, _storeContext); - doc.Open(); - - //fonts - var titleFont = GetFont(); - titleFont.SetStyle(Font.BOLD); - titleFont.Color = BaseColor.BLACK; - var font = GetFont(); - var attributesFont = GetFont(); - attributesFont.SetStyle(Font.ITALIC); - - int ordCount = orders.Count; - int ordNum = 0; - - foreach (var order in orders) - { - #region Header - - //logo - var logoPicture = _pictureService.GetPictureById(_pdfSettings.LogoPictureId); - var logoExists = logoPicture != null; - - ////header - var headerTable = new PdfPTable(logoExists ? 2 : 1); - headerTable.WidthPercentage = 100f; - if (logoExists) - headerTable.SetWidths(new[] { 50, 50 }); - - //store info - var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - - var cell = new PdfPCell(); - cell.Border = Rectangle.NO_BORDER; - cell.HorizontalAlignment = Element.ALIGN_LEFT; - var pOrderId = new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Order#", lang.Id), order.GetOrderNumber()), titleFont); - pOrderId.Alignment = Element.ALIGN_LEFT; - cell.AddElement(pOrderId); - //var anchor = new Anchor(_storeInformationSettings.StoreUrl.Trim(new char[] { '/' }), font); - //anchor.Reference = _storeInformationSettings.StoreUrl; - //var pAnchor = new Paragraph(anchor); - //pAnchor.Alignment = Element.ALIGN_LEFT; - //cell.AddElement(pAnchor); - var pDate = new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.OrderDate", lang.Id), _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc).ToString("D", new CultureInfo(lang.LanguageCulture))), font); - pDate.Alignment = Element.ALIGN_LEFT; - cell.AddElement(pDate); - headerTable.AddCell(cell); - - //logo - if (logoExists) - { - var logoFilePath = _pictureService.GetThumbLocalPath(logoPicture, 0, false); - if (logoFilePath.HasValue()) - { - var img = Image.GetInstance(logoFilePath); - img.ScaleToFit(250, 40); - var cellLogo = new PdfPCell(img); - cellLogo.Border = Rectangle.NO_BORDER; - cellLogo.HorizontalAlignment = Element.ALIGN_RIGHT; - headerTable.AddCell(cellLogo); - } - } - doc.Add(headerTable); - - PdfContentByte cb = writer.DirectContent; - cb.MoveTo(pageSize.Left + 40f, pageSize.Top - 80f); - cb.LineTo(pageSize.Right - 40f, pageSize.Top - 80f); - cb.Stroke(); - - #endregion - - #region Addresses - - var fontSmall = new Font(iTextSharp.text.Font.FontFamily.HELVETICA, 7, iTextSharp.text.Font.NORMAL); - - var addressTable = new PdfPTable(2); - addressTable.WidthPercentage = 100f; - addressTable.SetWidths(new[] { 50, 50 }); - - //billing address - string company = String.Format("{0}, {1}, {2} {3}", _companyInformationSettings.CompanyName, - _companyInformationSettings.Street, - _companyInformationSettings.ZipCode, - _companyInformationSettings.City); - - cell = new PdfPCell(); - cell.Border = Rectangle.NO_BORDER; - cell.AddElement(new Paragraph(" ")); - cell.AddElement(new Paragraph(" ")); - - Chunk chkHeader = new Chunk(company, fontSmall); - chkHeader.SetUnderline(.5f, -2f); - cell.AddElement(new Paragraph(chkHeader)); - - if (_addressSettings.CompanyEnabled && !String.IsNullOrEmpty(order.BillingAddress.Company)) - { - cell.AddElement(new Paragraph(order.BillingAddress.Company, font)); - } - cell.AddElement(new Paragraph(String.Format(order.BillingAddress.FirstName + " " + order.BillingAddress.LastName), font)); - if (_addressSettings.StreetAddressEnabled) - { - cell.AddElement(new Paragraph(order.BillingAddress.Address1, font)); - } - if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(order.BillingAddress.Address2)) - { - cell.AddElement(new Paragraph(order.BillingAddress.Address2, font)); - } - if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled || _addressSettings.CountryEnabled && order.BillingAddress.Country != null) - { - cell.AddElement(new Paragraph(String.Format("{0} {1} - {2} {3}", - order.BillingAddress.Country != null ? order.BillingAddress.Country.GetLocalized(x => x.TwoLetterIsoCode, lang.Id) : "", - order.BillingAddress.StateProvince != null ? "(" + order.BillingAddress.StateProvince.GetLocalized(x => x.Name, lang.Id) + ")": "", - order.BillingAddress.ZipPostalCode, - order.BillingAddress.City ), font)); - } - - addressTable.AddCell(cell); - - //legal + shop infos - cell = new PdfPCell(); - cell.Border = Rectangle.NO_BORDER; - var paragraph = new Paragraph(_companyInformationSettings.CompanyName, font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - paragraph = new Paragraph(_companyInformationSettings.Street, font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - paragraph = new Paragraph(_companyInformationSettings.ZipCode + " " + _companyInformationSettings.City, font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - cell.AddElement(new Paragraph(" ", fontSmall)); - - //email - paragraph = new Paragraph(_contactDataSettings.CompanyEmailAddress, font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - //url - paragraph = new Paragraph(store.Url, font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - //phone - paragraph = new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Phone", lang.Id), _contactDataSettings.CompanyTelephoneNumber), font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - //fax - paragraph = new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.Fax", lang.Id), _contactDataSettings.CompanyFaxNumber), font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - //tax number/ust-id - paragraph = new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.TaxNumber", lang.Id), _companyInformationSettings.TaxNumber), font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - //vat id - paragraph = new Paragraph(String.Format(_localizationService.GetResource("PDFInvoice.VatId", lang.Id), _companyInformationSettings.VatId), font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - //commercial register heading - paragraph = new Paragraph(_localizationService.GetResource("PDFInvoice.CommercialRegisterHeading", lang.Id), font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - //handelregister - paragraph = new Paragraph(_companyInformationSettings.CommercialRegister, font); - paragraph.Alignment = Element.ALIGN_RIGHT; - cell.AddElement(paragraph); - - addressTable.AddCell(cell); - - doc.Add(addressTable); - doc.Add(new Paragraph(" ")); - - #endregion - - #region Products - //products - doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.Product(s)", lang.Id), titleFont)); - doc.Add(new Paragraph(" ")); - - float cellPadding = 4f; - var orderItems = _orderService.GetAllOrderItems(order.Id, null, null, null, null, null, null); - - var productsTable = new PdfPTable(_catalogSettings.ShowProductSku ? 5 : 4); - productsTable.WidthPercentage = 100f; - productsTable.SetWidths(_catalogSettings.ShowProductSku ? new[] { 40, 15, 15, 15, 15 } : new[] { 40, 20, 20, 20 }); - - //product name - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductName", lang.Id), font)); - cell.Padding = cellPadding; - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_LEFT; - productsTable.AddCell(cell); - - //SKU - if (_catalogSettings.ShowProductSku) - { - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.SKU", lang.Id), font)); - cell.Padding = cellPadding; - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - } - - //price - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductPrice", lang.Id), font)); - cell.Padding = cellPadding; - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_RIGHT; - productsTable.AddCell(cell); - - //qty - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductQuantity", lang.Id), font)); - cell.Padding = cellPadding; - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - - //total - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.ProductTotal", lang.Id), font)); - cell.Padding = cellPadding; - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_RIGHT; - productsTable.AddCell(cell); - - for (int i = 0; i < orderItems.Count; i++) - { - var orderItem = orderItems[i]; - var p = orderItem.Product; - - //product name - string name = p.GetLocalized(x => x.Name, lang.Id); - cell = new PdfPCell(); - cell.Padding = cellPadding; - cell.HorizontalAlignment = Element.ALIGN_LEFT; - cell.AddElement(new Paragraph(name, font)); - - if (p.ProductType == ProductType.BundledProduct) - { - var itemParagraph = new Paragraph("", font); - itemParagraph.IndentationLeft = 25; - - var bundleData = orderItem.GetBundleData(); - foreach (var bundleItem in bundleData) - { - if (bundleData.IndexOf(bundleItem) != 0) - itemParagraph.Add(new Paragraph(" ")); - - if (bundleItem.PerItemShoppingCart && bundleItem.Quantity > 1) - itemParagraph.Add(new Paragraph("{0} × {1}".FormatWith(bundleItem.ProductName, bundleItem.Quantity), font)); - else - itemParagraph.Add(new Paragraph(bundleItem.ProductName, font)); - - if (bundleItem.PerItemShoppingCart) - { - decimal priceWithDiscount = _currencyService.ConvertCurrency(bundleItem.PriceWithDiscount, order.CurrencyRate); - itemParagraph.Add(new Paragraph(_priceFormatter.FormatPrice(priceWithDiscount, true, order.CustomerCurrencyCode, lang, false), font)); - } - - if (bundleItem.AttributesInfo.HasValue()) - itemParagraph.Add(new Paragraph(HtmlUtils.ConvertHtmlToPlainText(bundleItem.AttributesInfo, true, true), attributesFont)); - } - cell.AddElement(itemParagraph); - } - else - { - var attributesParagraph = new Paragraph(HtmlUtils.ConvertHtmlToPlainText(orderItem.AttributeDescription, true, true), attributesFont); - cell.AddElement(attributesParagraph); - } - - productsTable.AddCell(cell); - - //SKU - if (_catalogSettings.ShowProductSku) - { - p.MergeWithCombination(orderItem.AttributesXml, _productAttributeParser); - cell = new PdfPCell(new Phrase(p.Sku ?? String.Empty, font)); - cell.Padding = cellPadding; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - } - - //price - string unitPrice = string.Empty; - switch (order.CustomerTaxDisplayType) - { - case TaxDisplayType.ExcludingTax: - { - var unitPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.UnitPriceExclTax, order.CurrencyRate); - unitPrice = _priceFormatter.FormatPrice(unitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false); - } - break; - case TaxDisplayType.IncludingTax: - { - var unitPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.UnitPriceInclTax, order.CurrencyRate); - unitPrice = _priceFormatter.FormatPrice(unitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true); - } - break; - } - cell = new PdfPCell(new Phrase(unitPrice, font)); - cell.Padding = cellPadding; - cell.HorizontalAlignment = Element.ALIGN_RIGHT; - productsTable.AddCell(cell); - - //qty - cell = new PdfPCell(new Phrase(orderItem.Quantity.ToString(), font)); - cell.Padding = cellPadding; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - - //total - string subTotal = string.Empty; - switch (order.CustomerTaxDisplayType) - { - case TaxDisplayType.ExcludingTax: - { - var priceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.PriceExclTax, order.CurrencyRate); - subTotal = _priceFormatter.FormatPrice(priceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false); - } - break; - case TaxDisplayType.IncludingTax: - { - var priceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.PriceInclTax, order.CurrencyRate); - subTotal = _priceFormatter.FormatPrice(priceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true); - } - break; - } - cell = new PdfPCell(new Phrase(subTotal, font)); - cell.Padding = cellPadding; - cell.HorizontalAlignment = Element.ALIGN_RIGHT; - productsTable.AddCell(cell); - } - doc.Add(productsTable); - - #endregion - - #region Checkout attributes - - if (!String.IsNullOrEmpty(order.CheckoutAttributeDescription)) - { - doc.Add(new Paragraph(" ")); - string attributes = HtmlUtils.ConvertHtmlToPlainText(order.CheckoutAttributeDescription, true, true); - var pCheckoutAttributes = new Paragraph(attributes, font); - pCheckoutAttributes.Alignment = Element.ALIGN_RIGHT; - doc.Add(pCheckoutAttributes); - doc.Add(new Paragraph(" ")); - } - - #endregion - - #region Totals - - //subtotal - doc.Add(new Paragraph(" ")); - switch (order.CustomerTaxDisplayType) - { - case TaxDisplayType.ExcludingTax: - { - var orderSubtotalExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate); - string orderSubtotalExclTaxStr = _priceFormatter.FormatPrice(orderSubtotalExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), orderSubtotalExclTaxStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - case TaxDisplayType.IncludingTax: - { - var orderSubtotalInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate); - string orderSubtotalInclTaxStr = _priceFormatter.FormatPrice(orderSubtotalInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Sub-Total", lang.Id), orderSubtotalInclTaxStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - } - //discount (applied to order subtotal) - if (order.OrderSubTotalDiscountExclTax > decimal.Zero) - { - switch (order.CustomerTaxDisplayType) - { - case TaxDisplayType.ExcludingTax: - { - var orderSubTotalDiscountExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountExclTax, order.CurrencyRate); - string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderSubTotalDiscountInCustomerCurrencyStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - case TaxDisplayType.IncludingTax: - { - var orderSubTotalDiscountInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountInclTax, order.CurrencyRate); - string orderSubTotalDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderSubTotalDiscountInCustomerCurrencyStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - } - } - - //shipping - if (order.ShippingStatus != ShippingStatus.ShippingNotRequired) - { - switch (order.CustomerTaxDisplayType) - { - case TaxDisplayType.ExcludingTax: - { - var orderShippingExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingExclTax, order.CurrencyRate); - string orderShippingExclTaxStr = _priceFormatter.FormatShippingPrice(orderShippingExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Shipping", lang.Id), orderShippingExclTaxStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - case TaxDisplayType.IncludingTax: - { - var orderShippingInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingInclTax, order.CurrencyRate); - string orderShippingInclTaxStr = _priceFormatter.FormatShippingPrice(orderShippingInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Shipping", lang.Id), orderShippingInclTaxStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - } - } - - //payment fee - if (order.PaymentMethodAdditionalFeeExclTax > decimal.Zero) - { - switch (order.CustomerTaxDisplayType) - { - case TaxDisplayType.ExcludingTax: - { - var paymentMethodAdditionalFeeExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeExclTax, order.CurrencyRate); - string paymentMethodAdditionalFeeExclTaxStr = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, false); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.PaymentMethodAdditionalFee", lang.Id), paymentMethodAdditionalFeeExclTaxStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - case TaxDisplayType.IncludingTax: - { - var paymentMethodAdditionalFeeInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeInclTax, order.CurrencyRate); - string paymentMethodAdditionalFeeInclTaxStr = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, lang, true); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.PaymentMethodAdditionalFee", lang.Id), paymentMethodAdditionalFeeInclTaxStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - break; - } - } - - //tax - string taxStr = string.Empty; - var taxRates = new SortedDictionary(); - bool displayTax = true; - bool displayTaxRates = true; - if (_taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax) - { - displayTax = false; - } - else - { - if (order.OrderTax == 0 && _taxSettings.HideZeroTax) - { - displayTax = false; - displayTaxRates = false; - } - else - { - taxRates = order.TaxRatesDictionary; - - displayTaxRates = _taxSettings.DisplayTaxRates && taxRates.Count > 0; - displayTax = !displayTaxRates; - - var orderTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTax, order.CurrencyRate); - taxStr = _priceFormatter.FormatPrice(orderTaxInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang); - } - } - if (displayTax) - { - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Tax", lang.Id), taxStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - if (displayTaxRates) - { - foreach (var item in taxRates) - { - string taxRate = String.Format(_localizationService.GetResource("PDFInvoice.TaxRate", lang.Id), _priceFormatter.FormatTaxRate(item.Key)); - string taxValue = _priceFormatter.FormatPrice(_currencyService.ConvertCurrency(item.Value, order.CurrencyRate), true, order.CustomerCurrencyCode, false, lang); - - var p = new Paragraph(String.Format("{0} {1}", taxRate, taxValue), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - } - - //discount (applied to order total) - if (order.OrderDiscount > decimal.Zero) - { - var orderDiscountInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderDiscount, order.CurrencyRate); - string orderDiscountInCustomerCurrencyStr = _priceFormatter.FormatPrice(-orderDiscountInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang); - - var p = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.Discount", lang.Id), orderDiscountInCustomerCurrencyStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - - //gift cards - foreach (var gcuh in order.GiftCardUsageHistory) - { - string gcTitle = string.Format(_localizationService.GetResource("PDFInvoice.GiftCardInfo", lang.Id), gcuh.GiftCard.GiftCardCouponCode); - string gcAmountStr = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(gcuh.UsedValue, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, lang); - - var p = new Paragraph(String.Format("{0} {1}", gcTitle, gcAmountStr), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - - //reward points - if (order.RedeemedRewardPointsEntry != null) - { - string rpTitle = string.Format(_localizationService.GetResource("PDFInvoice.RewardPoints", lang.Id), -order.RedeemedRewardPointsEntry.Points); - string rpAmount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(order.RedeemedRewardPointsEntry.UsedAmount, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, lang); - - var p = new Paragraph(String.Format("{0} {1}", rpTitle, rpAmount), font); - p.Alignment = Element.ALIGN_RIGHT; - doc.Add(p); - } - - //order total - var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate); - string orderTotalStr = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, lang); - - - var pTotal = new Paragraph(String.Format("{0} {1}", _localizationService.GetResource("PDFInvoice.OrderTotal", lang.Id), orderTotalStr), titleFont); - pTotal.Alignment = Element.ALIGN_RIGHT; - doc.Add(pTotal); - - #endregion - - #region Order notes - - if (_pdfSettings.RenderOrderNotes) - { - var orderNotes = order.OrderNotes - .Where(on => on.DisplayToCustomer) - .OrderByDescending(on => on.CreatedOnUtc) - .ToList(); - if (orderNotes.Count > 0) - { - doc.Add(new Paragraph(_localizationService.GetResource("PDFInvoice.OrderNotes", lang.Id), titleFont)); - - doc.Add(new Paragraph(" ")); - - var notesTable = new PdfPTable(2); - notesTable.WidthPercentage = 100f; - notesTable.SetWidths(new[] { 30, 70 }); - - //created on - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.CreatedOn", lang.Id), font)); - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - notesTable.AddCell(cell); - - //note - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFInvoice.OrderNotes.Note", lang.Id), font)); - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - notesTable.AddCell(cell); - - foreach (var orderNote in orderNotes) - { - cell = new PdfPCell(); - cell.AddElement(new Paragraph(_dateTimeHelper.ConvertToUserTime(orderNote.CreatedOnUtc, DateTimeKind.Utc).ToString(), font)); - cell.HorizontalAlignment = Element.ALIGN_LEFT; - notesTable.AddCell(cell); - - cell = new PdfPCell(); - cell.AddElement(new Paragraph(HtmlUtils.ConvertHtmlToPlainText(orderNote.FormatOrderNoteText(), true, true), font)); - cell.HorizontalAlignment = Element.ALIGN_LEFT; - notesTable.AddCell(cell); - } - doc.Add(notesTable); - } - } - - #endregion - - ordNum++; - if (ordNum < ordCount) - { - doc.NewPage(); - } - } - doc.Close(); - } - - /// - /// Print an order to PDF - /// - /// Orders - public virtual byte[] PrintOrdersToPdf(IList orders) - { - byte[] bytes = null; - using (var stream = new MemoryStream()) - { - PrintOrdersToPdf(stream, orders, _workContext.WorkingLanguage); - bytes = stream.ToArray(); - } - return bytes; - } - - - /// - /// Print packaging slips to PDF - /// - /// Stream - /// Shipments - /// Language - public virtual void PrintPackagingSlipsToPdf(Stream stream, IList shipments, Language lang) - { - if (stream == null) - throw new ArgumentNullException("stream"); - - if (shipments == null) - throw new ArgumentNullException("shipments"); - - var pageSize = PageSize.A4; - - if (_pdfSettings.LetterPageSizeEnabled) - { - pageSize = PageSize.LETTER; - } - - var doc = new Document(pageSize); - var writer = PdfWriter.GetInstance(doc, stream); - - doc.Open(); - - //fonts - var titleFont = GetFont(); - titleFont.SetStyle(Font.BOLD); - titleFont.Color = BaseColor.BLACK; - var font = GetFont(); - var attributesFont = GetFont(); - attributesFont.SetStyle(Font.ITALIC); - - int shipmentCount = shipments.Count; - int shipmentNum = 0; - - foreach (var shipment in shipments) - { - var order = shipment.Order; - if (order.ShippingAddress != null) - { - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Shipment", lang.Id), shipment.Id), titleFont)); - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Order", lang.Id), order.GetOrderNumber()), titleFont)); - - if (_addressSettings.CompanyEnabled && !String.IsNullOrEmpty(order.ShippingAddress.Company)) - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Company", lang.Id), order.ShippingAddress.Company), font)); - - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Name", lang.Id), order.ShippingAddress.FirstName + " " + order.ShippingAddress.LastName), font)); - if (_addressSettings.PhoneEnabled) - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Phone", lang.Id), order.ShippingAddress.PhoneNumber), font)); - if (_addressSettings.StreetAddressEnabled) - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Address", lang.Id), order.ShippingAddress.Address1), font)); - - if (_addressSettings.StreetAddress2Enabled && !String.IsNullOrEmpty(order.ShippingAddress.Address2)) - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.Address2", lang.Id), order.ShippingAddress.Address2), font)); - - if (_addressSettings.CityEnabled || _addressSettings.StateProvinceEnabled || _addressSettings.ZipPostalCodeEnabled) - doc.Add(new Paragraph(String.Format("{0}, {1} {2}", order.ShippingAddress.City, order.ShippingAddress.StateProvince != null ? order.ShippingAddress.StateProvince.GetLocalized(x => x.Name, lang.Id) : "", order.ShippingAddress.ZipPostalCode), font)); - - if (_addressSettings.CountryEnabled && order.ShippingAddress.Country != null) - doc.Add(new Paragraph(String.Format("{0}", order.ShippingAddress.Country != null ? order.ShippingAddress.Country.GetLocalized(x => x.Name, lang.Id) : ""), font)); - - doc.Add(new Paragraph(" ")); - - doc.Add(new Paragraph(String.Format(_localizationService.GetResource("PDFPackagingSlip.ShippingMethod", lang.Id), order.ShippingMethod), font)); - doc.Add(new Paragraph(" ")); - - var productsTable = new PdfPTable(3); - productsTable.WidthPercentage = 100f; - productsTable.SetWidths(new[] { 60, 20, 20 }); - - //product name - var cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFPackagingSlip.ProductName", lang.Id), font)); - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - - //SKU - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFPackagingSlip.SKU", lang.Id), font)); - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - - //qty - cell = new PdfPCell(new Phrase(_localizationService.GetResource("PDFPackagingSlip.QTY", lang.Id), font)); - cell.BackgroundColor = BaseColor.LIGHT_GRAY; - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - - foreach (var si in shipment.ShipmentItems) - { - //product name - var orderItem = _orderService.GetOrderItemById(si.OrderItemId); - if (orderItem == null) - continue; - - var p = orderItem.Product; - string name = p.GetLocalized(x => x.Name, lang.Id); - cell = new PdfPCell(); - cell.AddElement(new Paragraph(name, font)); - cell.HorizontalAlignment = Element.ALIGN_LEFT; - var attributesParagraph = new Paragraph(HtmlUtils.ConvertHtmlToPlainText(orderItem.AttributeDescription, true, true), attributesFont); - cell.AddElement(attributesParagraph); - productsTable.AddCell(cell); - - //SKU - p.MergeWithCombination(orderItem.AttributesXml, _productAttributeParser); - cell = new PdfPCell(new Phrase(p.Sku ?? String.Empty, font)); - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - - //qty - cell = new PdfPCell(new Phrase(si.Quantity.ToString(), font)); - cell.HorizontalAlignment = Element.ALIGN_CENTER; - productsTable.AddCell(cell); - } - doc.Add(productsTable); - } - - shipmentNum++; - if (shipmentNum < shipmentCount) - { - doc.NewPage(); - } - } - - - doc.Close(); - } - - /// - /// Print packaging slips to PDF - /// - /// Shipments - public virtual byte[] PrintPackagingSlipsToPdf(IList shipments) - { - byte[] bytes = null; - using (var stream = new MemoryStream()) - { - PrintPackagingSlipsToPdf(stream, shipments, _workContext.WorkingLanguage); - bytes = stream.ToArray(); - } - return bytes; - } - - - /// - /// Print product collection to PDF - /// - /// Stream - /// Products - /// Language - public virtual void PrintProductsToPdf(Stream stream, IList products, Language lang) - { - if (stream == null) - throw new ArgumentNullException("stream"); - - if (products == null) - throw new ArgumentNullException("products"); - - if (lang == null) - throw new ArgumentNullException("lang"); - - var pageSize = PageSize.A4; - - if (_pdfSettings.LetterPageSizeEnabled) - { - pageSize = PageSize.LETTER; - } - - var doc = new Document(pageSize); - PdfWriter.GetInstance(doc, stream); - doc.Open(); - - //fonts - var titleFont = GetFont(); - titleFont.SetStyle(Font.BOLD); - titleFont.Color = BaseColor.BLACK; - var font = GetFont(); - - int productNumber = 1; - int prodCount = products.Count; - string currencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; - string measureWeightName = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; - string labelPrice = _localizationService.GetResource("PDFProductCatalog.Price", lang.Id); - string labelSku = _localizationService.GetResource("PDFProductCatalog.SKU", lang.Id); - string labelWeight = _localizationService.GetResource("PDFProductCatalog.Weight", lang.Id); - string labelStock = _localizationService.GetResource("PDFProductCatalog.StockQuantity", lang.Id); - - foreach (var product in products) - { - string productName = product.GetLocalized(x => x.Name, lang.Id); - string productFullDescription = product.GetLocalized(x => x.FullDescription, lang.Id); - - doc.Add(new Paragraph(String.Format("{0}. {1}", productNumber, productName), titleFont)); - doc.Add(new Paragraph(" ")); - doc.Add(new Paragraph(HtmlUtils.StripTags(HtmlUtils.ConvertHtmlToPlainText(productFullDescription)), font)); - doc.Add(new Paragraph(" ")); - - if (product.ProductType == ProductType.SimpleProduct || product.ProductType == ProductType.BundledProduct) - { - doc.Add(new Paragraph(String.Format("{0}: {1} {2}", labelPrice, product.Price.ToString("0.00"), currencyCode), font)); - doc.Add(new Paragraph(String.Format("{0}: {1}", labelSku, product.Sku), font)); - - if (product.IsShipEnabled && product.Weight > Decimal.Zero) - doc.Add(new Paragraph(String.Format("{0}: {1} {2}", labelWeight, product.Weight.ToString("0.00"), measureWeightName), font)); - - if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock) - doc.Add(new Paragraph(String.Format("{0}: {1}", labelStock, product.StockQuantity), font)); - - doc.Add(new Paragraph(" ")); - } - - var pictures = _pictureService.GetPicturesByProductId(product.Id); - if (pictures.Count > 0) - { - var table = new PdfPTable(2); - table.WidthPercentage = 100f; - - for (int i = 0; i < pictures.Count; i++) - { - var pic = pictures[i]; - if (pic != null) - { - var picBinary = _pictureService.LoadPictureBinary(pic); - if (picBinary != null && picBinary.Length > 0) - { - var pictureLocalPath = _pictureService.GetThumbLocalPath(pic, 200, false); - if (pictureLocalPath.HasValue()) { - var cell = new PdfPCell(Image.GetInstance(pictureLocalPath)); - cell.HorizontalAlignment = Element.ALIGN_LEFT; - cell.Border = Rectangle.NO_BORDER; - cell.PaddingBottom = 5f; - table.AddCell(cell); - } - } - } - } - - if (pictures.Count % 2 > 0) - { - var cell = new PdfPCell(new Phrase(" ")); - cell.Border = Rectangle.NO_BORDER; - table.AddCell(cell); - } - - doc.Add(table); - doc.Add(new Paragraph(" ")); - } - - if (product.ProductType == ProductType.GroupedProduct) - { - //grouped product. render its associated products - int pNum = 1; - var searchContext = new ProductSearchContext() - { - ParentGroupedProductId = product.Id, - PageSize = int.MaxValue, - ShowHidden = true - }; - - foreach (var associatedProduct in _productService.SearchProducts(searchContext)) - { - doc.Add(new Paragraph(String.Format("{0}-{1}. {2}", productNumber, pNum, associatedProduct.GetLocalized(x => x.Name, lang.Id)), font)); - doc.Add(new Paragraph(" ")); - - //uncomment to render associated product description - //string apDescription = associatedProduct.GetLocalized(x => x.ShortDescription, lang.Id); - //if (!String.IsNullOrEmpty(apDescription)) - //{ - // doc.Add(new Paragraph(HtmlHelper.StripTags(HtmlHelper.ConvertHtmlToPlainText(apDescription)), font)); - // doc.Add(new Paragraph(" ")); - //} - - //uncomment to render associated product picture - //var apPicture = _pictureService.GetPicturesByProductId(associatedProduct.Id).FirstOrDefault(); - //if (apPicture != null) - //{ - // var picBinary = _pictureService.LoadPictureBinary(apPicture); - // if (picBinary != null && picBinary.Length > 0) - // { - // var pictureLocalPath = _pictureService.GetThumbLocalPath(apPicture, 200, false); - // doc.Add(Image.GetInstance(pictureLocalPath)); - // } - //} - - doc.Add(new Paragraph(String.Format("{0}: {1} {2}", labelPrice, associatedProduct.Price.ToString("0.00"), currencyCode), font)); - doc.Add(new Paragraph(String.Format("{0}: {1}", labelSku, associatedProduct.Sku), font)); - - if (associatedProduct.IsShipEnabled && associatedProduct.Weight > Decimal.Zero) - doc.Add(new Paragraph(String.Format("{0}: {1} {2}", labelWeight, associatedProduct.Weight.ToString("0.00"), measureWeightName), font)); - - if (associatedProduct.ManageInventoryMethod == ManageInventoryMethod.ManageStock) - doc.Add(new Paragraph(String.Format("{0}: {1}", labelStock, associatedProduct.StockQuantity), font)); - - doc.Add(new Paragraph(" ")); - - pNum++; - } - } - else if (product.ProductType == ProductType.BundledProduct) - { - int pNum = 1; - - foreach (var item in _productService.GetBundleItems(product.Id).Select(x => x.Item)) - { - doc.Add(new Paragraph("{0}-{1}. {2}".FormatWith(productNumber, pNum, item.GetLocalizedName(lang.Id)), font)); - - doc.Add(new Paragraph(String.Format("{0}: {1} {2}", labelPrice, item.Product.Price.ToString("0.00"), currencyCode), font)); - doc.Add(new Paragraph(String.Format("{0}: {1}", labelSku, item.Product.Sku), font)); - - if (item.Product.IsShipEnabled && item.Product.Weight > Decimal.Zero) - doc.Add(new Paragraph(String.Format("{0}: {1} {2}", labelWeight, item.Product.Weight.ToString("0.00"), measureWeightName), font)); - - if (item.Product.ManageInventoryMethod == ManageInventoryMethod.ManageStock) - doc.Add(new Paragraph(String.Format("{0}: {1}", labelStock, item.Product.StockQuantity), font)); - - doc.Add(new Paragraph(" ")); - - pNum++; - } - } - - productNumber++; - - if (productNumber <= prodCount) - { - doc.NewPage(); - } - } - - doc.Close(); - } - - /// - /// Print product collection to PDF - /// - /// Products - public virtual byte[] PrintProductsToPdf(IList products) - { - byte[] bytes = null; - using (var stream = new MemoryStream()) - { - PrintProductsToPdf(stream, products, _workContext.WorkingLanguage); - bytes = stream.ToArray(); - } - return bytes; - } - - #endregion - - - #region PdfEvents - - public class OrderPdfPageEvents : PdfPageEventHelper - { - private readonly ILocalizationService _localizationService; - private readonly IPictureService _pictureService; - private readonly PdfSettings _pdfSettings; - private readonly CompanyInformationSettings _companyInformationSettings; - private readonly BankConnectionSettings _bankConnectionSettings; - private readonly ContactDataSettings _contactDataSettings; - private readonly IStoreContext _storeContext; - private readonly Language _lang; - - public OrderPdfPageEvents(IPictureService pictureService, PdfSettings pdfSettings, - CompanyInformationSettings companyInformationSettings, BankConnectionSettings bankConnectionSettings, - ContactDataSettings contactDataSettings, - ILocalizationService localizationService, Language lang, - IStoreContext storeContext) - { - this._localizationService = localizationService; - this._pictureService = pictureService; - this._pdfSettings = pdfSettings; - this._companyInformationSettings = companyInformationSettings; - this._bankConnectionSettings = bankConnectionSettings; - this._contactDataSettings = contactDataSettings; - this._storeContext = storeContext; - this._lang = lang; - } - - private float MilimetersToPoints(int mm) - { - return iTextSharp.text.Utilities.MillimetersToPoints(Convert.ToSingle(mm)); - } - - public override void OnEndPage(PdfWriter writer, Document document) - { - base.OnEndPage(writer, document); - Rectangle pageSize = document.PageSize; - PdfContentByte m_Cb = writer.DirectContent; - m_Cb.MoveTo(pageSize.GetLeft(MilimetersToPoints(15)), pageSize.GetBottom(MilimetersToPoints(15)) + 40); - m_Cb.LineTo(pageSize.GetRight(MilimetersToPoints(15)), pageSize.GetBottom(MilimetersToPoints(15)) + 40); - m_Cb.Stroke(); - - //variables - var font = new Font(iTextSharp.text.Font.FontFamily.HELVETICA, 8, iTextSharp.text.Font.NORMAL); - - // Header - Logo - - //logo - //var logoPicture = _pictureService.GetPictureById(_pdfSettings.LogoPictureId); - //var logoExists = logoPicture != null; - - ////header - //var headerTable = new PdfPTable(logoExists ? 2 : 1); - //headerTable.WidthPercentage = 100f; - //if (logoExists) - // headerTable.SetWidths(new[] { 50, 50 }); - - ////logo - //if (logoExists) - //{ - // var logoFilePath = _pictureService.GetPictureLocalPath(logoPicture, 0, false); - // //var img = Image.GetInstance(logoFilePath); - // //var cellLogo = new PdfPCell(img); - // //cellLogo.Border = Rectangle.NO_BORDER; - // //headerTable.AddCell(cellLogo); - // //document.Add(headerTable); - - // Image img = Image.GetInstance(logoFilePath); - // img.SetAbsolutePosition(pageSize.GetRight(MilimetersToPoints(20)) - img.ScaledWidth + 10, pageSize.GetTop(MilimetersToPoints(10) + img.ScaledHeight)); - // document.Add(img); - //} - - // Footer - var tableCompanyInfo = new PdfPTable(3); - tableCompanyInfo.WidthPercentage = 80; - tableCompanyInfo.SetTotalWidth(new float[] {200, 200, 200}); - - var cellInfo = new PdfPCell(); - var cellContact = new PdfPCell(); - var cellBank = new PdfPCell(); - - //border - cellInfo.Border = 0; - cellContact.Border = 0; - cellBank.Border = 0; - cellInfo.HorizontalAlignment = Element.ALIGN_LEFT; - cellContact.HorizontalAlignment = Element.ALIGN_CENTER; - cellBank.HorizontalAlignment = Element.ALIGN_RIGHT; - - cellInfo.AddElement(new Phrase(_companyInformationSettings.CompanyName, font)); - cellInfo.AddElement(new Phrase(_companyInformationSettings.Salutation + - (String.IsNullOrEmpty(_companyInformationSettings.Title) ? (_companyInformationSettings.Title + " ") : "") + - _companyInformationSettings.Firstname + " " + _companyInformationSettings.Lastname - , font)); - cellInfo.AddElement(new Phrase(_companyInformationSettings.Street + " " + _companyInformationSettings.Street2, font)); - cellInfo.AddElement(new Phrase(_companyInformationSettings.ZipCode + " " + _companyInformationSettings.City, font)); - cellInfo.AddElement(new Phrase(_companyInformationSettings.CountryName + (!String.IsNullOrEmpty(_companyInformationSettings.StateName) ? (", " + _companyInformationSettings.StateName) : ""), font)); - - cellContact.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.Url", _lang.Id), _storeContext.CurrentStore.Url), font)); - cellContact.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.Mail", _lang.Id), _contactDataSettings.ContactEmailAddress), font)); - cellContact.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.Fon", _lang.Id), _contactDataSettings.CompanyTelephoneNumber), font)); - cellContact.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.Fax", _lang.Id), _contactDataSettings.CompanyFaxNumber), font)); - - cellBank.AddElement(new Phrase(_bankConnectionSettings.Bankname, font)); - cellBank.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.Bankcode", _lang.Id), _bankConnectionSettings.Bankcode), font)); - cellBank.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.AccountNumber", _lang.Id), _bankConnectionSettings.AccountNumber), font)); - cellBank.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.AccountHolder", _lang.Id), _bankConnectionSettings.AccountHolder), font)); - cellBank.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.Iban", _lang.Id), _bankConnectionSettings.Iban), font)); - cellBank.AddElement(new Phrase(String.Format(_localizationService.GetResource("PDFInvoice.Footer.Bic", _lang.Id), _bankConnectionSettings.Bic), font)); - - - tableCompanyInfo.AddCell(cellInfo); - tableCompanyInfo.AddCell(cellContact); - tableCompanyInfo.AddCell(cellBank); - - tableCompanyInfo.WriteSelectedRows(0, 6, pageSize.GetLeft(MilimetersToPoints(15)), pageSize.GetBottom(MilimetersToPoints(15)) + 40, m_Cb); - } - } - - - - #endregion - - } -} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Common/TempFileCleanupTask.cs b/src/Libraries/SmartStore.Services/Common/TempFileCleanupTask.cs new file mode 100644 index 0000000000..a07dfe8cce --- /dev/null +++ b/src/Libraries/SmartStore.Services/Common/TempFileCleanupTask.cs @@ -0,0 +1,16 @@ +using SmartStore.Services.Tasks; +using SmartStore.Utilities; + +namespace SmartStore.Services.Common +{ + /// + /// Task to cleanup temporary files + /// + public partial class TempFileCleanupTask : ITask + { + public void Execute(TaskExecutionContext ctx) + { + FileSystemHelper.TempCleanup(); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs b/src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs new file mode 100644 index 0000000000..a6b8e24305 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Web; +using SmartStore.Utilities; +using uap = UAParser; + +namespace SmartStore.Services.Common +{ + + public class UAParserUserAgent : IUserAgent + { + private readonly static uap.Parser s_uap; + private static readonly Regex s_pdfConverterPattern = new Regex(@"wkhtmltopdf", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + + # region Mobile UAs, OS & Devices + + private static readonly HashSet s_MobileOS = new HashSet(StringComparer.InvariantCultureIgnoreCase) + { + "Android", + "iOS", + "Windows Mobile", + "Windows Phone", + "Windows CE", + "Symbian OS", + "BlackBerry OS", + "BlackBerry Tablet OS", + "Firefox OS", + "Brew MP", + "webOS", + "Bada", + "Kindle", + "Maemo" + }; + + private static readonly HashSet s_MobileBrowsers = new HashSet(StringComparer.InvariantCultureIgnoreCase) + { + "Googlebot-Mobile", + "Baiduspider-mobile", + "Android", + "Firefox Mobile", + "Opera Mobile", + "Opera Mini", + "Mobile Safari", + "Amazon Silk", + "webOS Browser", + "MicroB", + "Ovi Browser", + "NetFront", + "NetFront NX", + "Chrome Mobile", + "Chrome Mobile iOS", + "UC Browser", + "Tizen Browser", + "Baidu Explorer", + "QQ Browser Mini", + "QQ Browser Mobile", + "IE Mobile", + "Polaris", + "ONE Browser", + "iBrowser Mini", + "Nokia Services (WAP) Browser", + "Nokia Browser", + "Nokia OSS Browser", + "BlackBerry WebKit", + "BlackBerry", "Palm", + "Palm Blazer", + "Palm Pre", + "Teleca Browser", + "SEMC-Browser", + "PlayStation Portable", + "Nokia", + "Maemo Browser", + "Obigo", + "Bolt", + "Iris", + "UP.Browser", + "Minimo", + "Bunjaloo", + "Jasmine", + "Dolfin", + "Polaris", + "Skyfire" + }; + + private static readonly HashSet s_MobileDevices = new HashSet(StringComparer.InvariantCultureIgnoreCase) + { + "BlackBerry", + "MI PAD", + "iPhone", + "iPad", + "iPod", + "Kindle", + "Kindle Fire", + "Nokia", + "Lumia", + "Palm", + "DoCoMo", + "HP TouchPad", + "Xoom", + "Motorola", + "Generic Feature Phone", + "Generic Smartphone" + }; + + #endregion + + private readonly HttpContextBase _httpContext; + + private string _rawValue; + private UserAgentInfo _userAgent; + private DeviceInfo _device; + private OSInfo _os; + + private bool? _isBot; + private bool? _isMobileDevice; + private bool? _isTablet; + private bool? _isPdfConverter; + + static UAParserUserAgent() + { + //s_uap = uap.Parser.GetDefault(); + s_uap = uap.Parser.FromYamlFile(CommonHelper.MapPath("~/App_Data/ua-parser.regexes.yaml")); + } + + public UAParserUserAgent(HttpContextBase httpContext) + { + this._httpContext = httpContext; + } + + public string RawValue + { + get + { + if (_rawValue == null) + { + if (_httpContext.Request != null) + { + _rawValue = _httpContext.Request.UserAgent.EmptyNull(); + } + else + { + _rawValue = ""; + } + } + + return _rawValue; + } + // for (unit) test purpose + set + { + _rawValue = value; + _userAgent = null; + _device = null; + _os = null; + _isBot = null; + _isMobileDevice = null; + _isTablet = null; + _isPdfConverter = null; + } + } + + public virtual UserAgentInfo UserAgent + { + get + { + if (_userAgent == null) + { + var tmp = s_uap.ParseUserAgent(this.RawValue); + _userAgent = new UserAgentInfo(tmp.Family, tmp.Major, tmp.Minor, tmp.Patch); + } + return _userAgent; + } + } + + public virtual DeviceInfo Device + { + get + { + if (_device == null) + { + var tmp = s_uap.ParseDevice(this.RawValue); + _device = new DeviceInfo(tmp.Family, tmp.IsSpider()); + } + return _device; + } + } + + public virtual OSInfo OS + { + get + { + if (_os == null) + { + var tmp = s_uap.ParseOS(this.RawValue); + _os = new OSInfo(tmp.Family, tmp.Major, tmp.Minor, tmp.Patch, tmp.PatchMinor); + } + return _os; + } + } + + public virtual bool IsBot + { + get + { + if (!_isBot.HasValue) + { + // empty useragent > bad bot! + _isBot = this.RawValue.IsEmpty() || _httpContext.Request.Browser.Crawler || this.Device.IsBot || this.UserAgent.IsBot; + } + return _isBot.Value; + } + } + + public virtual bool IsMobileDevice + { + get + { + if (!_isMobileDevice.HasValue) + { + _isMobileDevice = + s_MobileOS.Contains(this.OS.Family) || + s_MobileBrowsers.Contains(this.UserAgent.Family) || + s_MobileDevices.Contains(this.Device.Family); + } + return _isMobileDevice.Value; + } + } + + public virtual bool IsTablet + { + get + { + if (!_isTablet.HasValue) + { + _isTablet = + Regex.IsMatch(this.Device.Family, "iPad|Kindle Fire|Nexus 10|Xoom|Transformer|MI PAD|IdeaTab", RegexOptions.CultureInvariant) || + this.OS.Family == "BlackBerry Tablet OS"; + } + return _isTablet.Value; + } + } + + public virtual bool IsPdfConverter + { + get + { + if (!_isPdfConverter.HasValue) + { + _isPdfConverter = s_pdfConverterPattern.IsMatch(this.RawValue); + } + return _isPdfConverter.Value; + } + } + } + + internal static class DeviceExtensions + { + internal static bool IsSpider(this UAParser.Device device) + { + return device.Family.Equals("Spider", StringComparison.InvariantCultureIgnoreCase); + } + } + +} diff --git a/src/Libraries/SmartStore.Services/CommonServices.cs b/src/Libraries/SmartStore.Services/CommonServices.cs index f1f3634e11..0d6b989990 100644 --- a/src/Libraries/SmartStore.Services/CommonServices.cs +++ b/src/Libraries/SmartStore.Services/CommonServices.cs @@ -8,11 +8,16 @@ using SmartStore.Services.Localization; using SmartStore.Core.Logging; using SmartStore.Services.Security; +using SmartStore.Services.Configuration; +using SmartStore.Services.Stores; +using Autofac; +using SmartStore.Services.Helpers; namespace SmartStore.Services { public class CommonServices : ICommonServices { + private readonly IComponentContext _container; private readonly Lazy _cache; private readonly Lazy _dbContext; private readonly Lazy _storeContext; @@ -23,9 +28,13 @@ public class CommonServices : ICommonServices private readonly Lazy _customerActivity; private readonly Lazy _notifier; private readonly Lazy _permissions; - + private readonly Lazy _settings; + private readonly Lazy _storeService; + private readonly Lazy _dateTimeHelper; + public CommonServices( - Func> cache, + IComponentContext container, + Func> cache, Lazy dbContext, Lazy storeContext, Lazy webHelper, @@ -34,8 +43,12 @@ public CommonServices( Lazy localization, Lazy customerActivity, Lazy notifier, - Lazy permissions) + Lazy permissions, + Lazy settings, + Lazy storeService, + Lazy dateTimeHelper) { + this._container = container; this._cache = cache("static"); this._dbContext = dbContext; this._storeContext = storeContext; @@ -46,8 +59,19 @@ public CommonServices( this._customerActivity = customerActivity; this._notifier = notifier; this._permissions = permissions; + this._settings = settings; + this._storeService = storeService; + this._dateTimeHelper = dateTimeHelper; + } + + public IComponentContext Container + { + get + { + return _container; + } } - + public ICacheManager Cache { get @@ -120,7 +144,6 @@ public INotifier Notifier } } - public IPermissionService Permissions { get @@ -128,5 +151,30 @@ public IPermissionService Permissions return _permissions.Value; } } + + public ISettingService Settings + { + get + { + return _settings.Value; + } + } + + + public IStoreService StoreService + { + get + { + return _storeService.Value; + } + } + + public IDateTimeHelper DateTimeHelper + { + get + { + return _dateTimeHelper.Value; + } + } } } diff --git a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs index f5950f57f7..aa688a4e96 100644 --- a/src/Libraries/SmartStore.Services/Configuration/SettingService.cs +++ b/src/Libraries/SmartStore.Services/Configuration/SettingService.cs @@ -2,19 +2,15 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Configuration; using SmartStore.Core.Data; using SmartStore.Core.Domain.Configuration; -using SmartStore.Core.Infrastructure; using SmartStore.Core.Events; -using Fasterflect; using System.Linq.Expressions; using System.Reflection; -using SmartStore.Core.Plugins; -using System.ComponentModel; -using SmartStore.Utilities; +using SmartStore.ComponentModel; +using System.Collections; namespace SmartStore.Services.Configuration { @@ -77,11 +73,11 @@ protected virtual IDictionary> GetAllSettingsCa string key = string.Format(SETTINGS_ALL_KEY); return _cacheManager.Get(key, () => { - var query = from s in _settingRepository.Table + var query = from s in _settingRepository.TableUntracked orderby s.Name, s.StoreId select s; var settings = query.ToList(); - var dictionary = new Dictionary>(); + var dictionary = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (var s in settings) { var settingName = s.Name.ToLowerInvariant(); @@ -151,7 +147,6 @@ public virtual void UpdateSetting(Setting setting, bool clearCache = true) _eventPublisher.EntityUpdated(setting); } - /// codehint: sm-add private T LoadSettingsJson(int storeId = 0) { Type t = typeof(T); @@ -164,6 +159,7 @@ private T LoadSettingsJson(int storeId = 0) { JsonConvert.PopulateObject(rawSetting, settings); } + return settings; } @@ -180,7 +176,6 @@ private void SaveSettingsJson(T settings) ClearCache(); } - /// codehint: sm-add private void DeleteSettingsJson() { Type t = typeof(T); @@ -234,13 +229,14 @@ public virtual Setting GetSettingById(int settingId) var settingsByKey = settings[key]; var setting = settingsByKey.FirstOrDefault(x => x.StoreId == storeId); - //load shared value? + // load shared value? if (setting == null && storeId > 0 && loadSharedValueIfNotFound) setting = settingsByKey.FirstOrDefault(x => x.StoreId == 0); if (setting != null) return setting.Value.Convert(); } + return defaultValue; } @@ -298,7 +294,6 @@ public virtual bool SettingExists(T settings, /// Store identifier for which settigns should be loaded public virtual T LoadSetting(int storeId = 0) where T : ISettings, new() { - // codehint: sm-add if (typeof(T).HasAttribute(true)) { return LoadSettingsJson(storeId); @@ -306,52 +301,66 @@ public virtual bool SettingExists(T settings, var settings = Activator.CreateInstance(); - foreach (var prop in typeof(T).GetProperties()) + foreach (var fastProp in FastProperty.GetProperties(typeof(T)).Values) { + var prop = fastProp.Property; + // get properties we can read and write to - if (!prop.CanRead || !prop.CanWrite) + if (!prop.CanWrite) continue; var key = typeof(T).Name + "." + prop.Name; - //load by store + // load by store string setting = GetSettingByKey(key, storeId: storeId, loadSharedValueIfNotFound: true); - if (setting == null) - { - if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) - { - // convenience: don't return null for simple list types - var listArg = prop.PropertyType.GetGenericArguments()[0]; - object list = null; - - if (listArg == typeof(int)) - list = new List(); - else if (listArg == typeof(decimal)) - list = new List(); - else if (listArg == typeof(string)) - list = new List(); - - if (list != null) + if (setting == null) + { + if (fastProp.IsSequenceType) + { + if ((fastProp.GetValue(settings) as IEnumerable) != null) { - prop.SetValue(settings, list, null); + // Instance of IEnumerable<> was already created, most likely in the constructor of the settings concrete class. + // In this case we shouldn't let the EnumerableConverter create a new instance but keep this one. + continue; } } + else + { + #region Obsolete ('EnumerableConverter' can handle this case now) + //if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) + //{ + // // convenience: don't return null for simple list types + // var listArg = prop.PropertyType.GetGenericArguments()[0]; + // object list = null; + + // if (listArg == typeof(int)) + // list = new List(); + // else if (listArg == typeof(decimal)) + // list = new List(); + // else if (listArg == typeof(string)) + // list = new List(); + + // if (list != null) + // { + // fastProp.SetValue(settings, list); + // } + //} + #endregion + + continue; + } - continue; - } + } - var converter = CommonHelper.GetTypeConverter(prop.PropertyType); + var converter = TypeConverterFactory.GetConverter(prop.PropertyType); if (converter == null || !converter.CanConvertFrom(typeof(string))) continue; - if (!converter.IsValid(setting)) - continue; - - object value = converter.ConvertFromInvariantString(setting); + object value = converter.ConvertFrom(setting); //set property - prop.SetValue(settings, value, null); + fastProp.SetValue(settings, value); } return settings; @@ -370,7 +379,7 @@ public virtual void SetSetting(string key, T value, int storeId = 0, bool cle Guard.ArgumentNotEmpty(() => key); key = key.Trim().ToLowerInvariant(); - string valueStr = CommonHelper.GetTypeConverter(typeof(T)).ConvertToInvariantString(value); + var str = value.Convert(); var allSettings = GetAllSettingsCached(); var settingForCaching = allSettings.ContainsKey(key) ? @@ -380,16 +389,16 @@ public virtual void SetSetting(string key, T value, int storeId = 0, bool cle { //update var setting = GetSettingById(settingForCaching.Id); - setting.Value = valueStr; + setting.Value = str; UpdateSetting(setting, clearCache); } else { //insert - var setting = new Setting() + var setting = new Setting { Name = key, - Value = valueStr, + Value = str, StoreId = storeId }; InsertSetting(setting, clearCache); @@ -413,18 +422,19 @@ public virtual void SetSetting(string key, T value, int storeId = 0, bool cle /* We do not clear cache after each setting update. * This behavior can increase performance because cached settings will not be cleared * and loaded from database after each update */ - foreach (var prop in typeof(T).GetProperties()) + foreach (var prop in FastProperty.GetProperties(typeof(T)).Values) { // get properties we can read and write to - if (!prop.CanRead || !prop.CanWrite) + if (!prop.IsPublicSettable) continue; - if (!CommonHelper.GetTypeConverter(prop.PropertyType).CanConvertFrom(typeof(string))) + var converter = TypeConverterFactory.GetConverter(prop.Property.PropertyType); + if (converter == null || !converter.CanConvertFrom(typeof(string))) continue; string key = typeof(T).Name + "." + prop.Name; - //Duck typing is not supported in C#. That's why we're using dynamic type - dynamic value = settings.TryGetPropertyValue(prop.Name); + // Duck typing is not supported in C#. That's why we're using dynamic type + dynamic value = prop.GetValue(settings); SetSetting(key, value ?? "", storeId, false); } @@ -462,13 +472,13 @@ public virtual void SaveSetting(T settings, } string key = typeof(T).Name + "." + propInfo.Name; - //Duck typing is not supported in C#. That's why we're using dynamic type - dynamic value = settings.TryGetPropertyValue(propInfo.Name); + // Duck typing is not supported in C#. That's why we're using dynamic type + var fastProp = FastProperty.GetProperty(propInfo, PropertyCachingStrategy.EagerCached); + dynamic value = fastProp.GetValue(settings); SetSetting(key, value ?? "", storeId, false); } - /// codehint: sm-add public virtual void UpdateSetting(T settings, Expression> keySelector, bool overrideForStore, int storeId = 0) where T : ISettings, new() { if (overrideForStore || storeId == 0) @@ -551,7 +561,6 @@ public virtual void DeleteSetting(T settings, DeleteSetting(key, storeId); } - /// codehint: sm-add public virtual void DeleteSetting(string key, int storeId = 0) { if (key.HasValue()) @@ -571,15 +580,15 @@ from s in _settingRepository.Table /// /// Deletes all settings with its key beginning with rootKey. /// - /// codehint: sm-add /// Number of deleted settings public virtual int DeleteSettings(string rootKey) { int result = 0; + if (rootKey.HasValue()) { try { - string sqlDelete = "Delete From Setting Where Name Like '{0}%'".FormatWith(rootKey.EndsWith(".") ? rootKey : rootKey + "."); + string sqlDelete = "DELETE FROM [Setting] WHERE [Name] LIKE '{0}%'".FormatWith(rootKey.EndsWith(".") ? rootKey : rootKey + "."); result = _settingRepository.Context.ExecuteSqlCommand(sqlDelete); // cache @@ -590,6 +599,7 @@ public virtual int DeleteSettings(string rootKey) { exc.Dump(); } } + return result; } diff --git a/src/Libraries/SmartStore.Services/Customers/CustomerExtentions.cs b/src/Libraries/SmartStore.Services/Customers/CustomerExtentions.cs index 412303bc5a..afc1acdbe0 100644 --- a/src/Libraries/SmartStore.Services/Customers/CustomerExtentions.cs +++ b/src/Libraries/SmartStore.Services/Customers/CustomerExtentions.cs @@ -21,8 +21,7 @@ public static class CustomerExtentions /// Customer role system name /// A value indicating whether we should look only in active customer roles /// Result - public static bool IsInCustomerRole(this Customer customer, - string customerRoleSystemName, bool onlyActiveCustomerRoles = true) + public static bool IsInCustomerRole(this Customer customer, string customerRoleSystemName, bool onlyActiveCustomerRoles = true) { if (customer == null) throw new ArgumentNullException("customer"); @@ -44,40 +43,54 @@ public static bool IsInCustomerRole(this Customer customer, /// Result public static bool IsBackgroundTaskAccount(this Customer customer) { - if (customer == null) - throw new ArgumentNullException("customer"); + Guard.ArgumentNotNull(() => customer); - if (!customer.IsSystemAccount || String.IsNullOrEmpty(customer.SystemName)) - return false; + if (!customer.IsSystemAccount || customer.SystemName.IsEmpty()) + return false; var result = customer.SystemName.Equals(SystemCustomerNames.BackgroundTask, StringComparison.InvariantCultureIgnoreCase); return result; } /// - /// Gets a value indicating whether customer a search engine + /// Gets a value indicating whether customer is a search engine /// /// Customer /// Result public static bool IsSearchEngineAccount(this Customer customer) { - if (customer == null) - throw new ArgumentNullException("customer"); + Guard.ArgumentNotNull(() => customer); - if (!customer.IsSystemAccount || String.IsNullOrEmpty(customer.SystemName)) - return false; + if (!customer.IsSystemAccount || customer.SystemName.IsEmpty()) + return false; var result = customer.SystemName.Equals(SystemCustomerNames.SearchEngine, StringComparison.InvariantCultureIgnoreCase); return result; } - /// - /// Gets a value indicating whether customer is administrator - /// - /// Customer - /// A value indicating whether we should look only in active customer roles - /// Result - public static bool IsAdmin(this Customer customer, bool onlyActiveCustomerRoles = true) + /// + /// Gets a value indicating whether customer is the pdf converter + /// + /// Customer + /// Result + public static bool IsPdfConverter(this Customer customer) + { + Guard.ArgumentNotNull(() => customer); + + if (!customer.IsSystemAccount || customer.SystemName.IsEmpty()) + return false; + + var result = customer.SystemName.Equals(SystemCustomerNames.PdfConverter, StringComparison.InvariantCultureIgnoreCase); + return result; + } + + /// + /// Gets a value indicating whether customer is administrator + /// + /// Customer + /// A value indicating whether we should look only in active customer roles + /// Result + public static bool IsAdmin(this Customer customer, bool onlyActiveCustomerRoles = true) { return IsInCustomerRole(customer, SystemCustomerRoleNames.Administrators, onlyActiveCustomerRoles); } @@ -194,22 +207,75 @@ public static string FormatUserName(this Customer customer, bool stripTooLong) case CustomerNameFormat.ShowUsernames: result = customer.Username; break; + case CustomerNameFormat.ShowFirstName: + result = customer.GetAttribute(SystemCustomerAttributeNames.FirstName); + break; + case CustomerNameFormat.ShowNameAndCity: + { + var firstName = customer.GetAttribute(SystemCustomerAttributeNames.FirstName); + var lastName = customer.GetAttribute(SystemCustomerAttributeNames.LastName); + var city = customer.GetAttribute(SystemCustomerAttributeNames.City); + + if (firstName.IsEmpty()) + { + var address = customer.Addresses.FirstOrDefault(); + if (address != null) + { + firstName = address.FirstName; + lastName = address.LastName; + city = address.City; + } + } + + result = firstName; + if (lastName.HasValue()) + { + result = "{0} {1}.".FormatWith(result, lastName.First()); + } + + if (city.HasValue()) + { + var from = EngineContext.Current.Resolve().GetResource("Common.ComingFrom"); + result = "{0} {1} {2}".FormatWith(result, from, city); + } + } + break; default: break; } - if (stripTooLong) + if (stripTooLong && result.HasValue()) { - int maxLength = 0; // TODO make this setting configurable + int maxLength = EngineContext.Current.Resolve().CustomerNameFormatMaxLength; if (maxLength > 0 && result.Length > maxLength) { - result = result.Substring(0, maxLength); + result = result.Truncate(maxLength, "..."); } } return result; } + /// + /// Find any email address of customer + /// + public static string FindEmail(this Customer customer) + { + if (customer != null) + { + if (customer.Email.HasValue()) + return customer.Email; + + if (customer.BillingAddress != null && customer.BillingAddress.Email.HasValue()) + return customer.BillingAddress.Email; + + if (customer.ShippingAddress != null && customer.ShippingAddress.Email.HasValue()) + return customer.ShippingAddress.Email; + } + return null; + } + + #region Shopping cart public static int CountProductsInCart(this Customer customer, ShoppingCartType cartType, int? storeId = null) @@ -221,14 +287,15 @@ public static int CountProductsInCart(this Customer customer, ShoppingCartType c return count; } - public static List GetCartItems(this Customer customer, ShoppingCartType cartType, int? storeId = null, bool orderById = false) + + public static List GetCartItems(this Customer customer, ShoppingCartType cartType, int? storeId = null) { var rawItems = customer.ShoppingCartItems.Filter(cartType, storeId); - if (orderById) - rawItems = rawItems.OrderByDescending(x => x.Id); - - var organizedItems = rawItems.ToList().Organize(); + var organizedItems = rawItems + .OrderByDescending(x => x.Id) + .ToList() + .Organize(); return organizedItems.ToList(); } diff --git a/src/Libraries/SmartStore.Services/Customers/CustomerRegisteredEvent.cs b/src/Libraries/SmartStore.Services/Customers/CustomerRegisteredEvent.cs new file mode 100644 index 0000000000..76bc89b1de --- /dev/null +++ b/src/Libraries/SmartStore.Services/Customers/CustomerRegisteredEvent.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using SmartStore.Core.Domain.Customers; + +namespace SmartStore.Services.Customers +{ + /// + /// An event message, which gets published after customer was registered + /// + public class CustomerRegisteredEvent + { + public Customer Customer + { + get; + set; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs b/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs index 2ee2141309..49fb4587aa 100644 --- a/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs +++ b/src/Libraries/SmartStore.Services/Customers/CustomerRegistrationService.cs @@ -2,26 +2,27 @@ using System.Linq; using SmartStore.Core; using SmartStore.Core.Domain.Customers; -using SmartStore.Services.Localization; +using SmartStore.Core.Events; +using SmartStore.Core.Localization; using SmartStore.Services.Messages; using SmartStore.Services.Security; namespace SmartStore.Services.Customers { - /// - /// Customer registration service - /// - public partial class CustomerRegistrationService : ICustomerRegistrationService + /// + /// Customer registration service + /// + public partial class CustomerRegistrationService : ICustomerRegistrationService { #region Fields private readonly ICustomerService _customerService; private readonly IEncryptionService _encryptionService; private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService; - private readonly ILocalizationService _localizationService; private readonly RewardPointsSettings _rewardPointsSettings; private readonly CustomerSettings _customerSettings; private readonly IStoreContext _storeContext; + private readonly IEventPublisher _eventPublisher; #endregion @@ -33,30 +34,33 @@ public partial class CustomerRegistrationService : ICustomerRegistrationService public CustomerRegistrationService(ICustomerService customerService, IEncryptionService encryptionService, INewsLetterSubscriptionService newsLetterSubscriptionService, - ILocalizationService localizationService, RewardPointsSettings rewardPointsSettings, CustomerSettings customerSettings, - IStoreContext storeContext) + IStoreContext storeContext, IEventPublisher eventPublisher) { this._customerService = customerService; this._encryptionService = encryptionService; this._newsLetterSubscriptionService = newsLetterSubscriptionService; - this._localizationService = localizationService; this._rewardPointsSettings = rewardPointsSettings; this._customerSettings = customerSettings; this._storeContext = storeContext; - } + this._eventPublisher = eventPublisher; - #endregion + T = NullLocalizer.Instance; + } - #region Methods + #endregion - /// - /// Validate customer - /// - /// Username or email - /// Password - /// Result - public virtual bool ValidateCustomer(string usernameOrEmail, string password) + public Localizer T { get; set; } + + #region Methods + + /// + /// Validate customer + /// + /// Username or email + /// Password + /// Result + public virtual bool ValidateCustomer(string usernameOrEmail, string password) { Customer customer = null; if (_customerSettings.UsernamesEnabled) @@ -109,48 +113,46 @@ public virtual bool ValidateCustomer(string usernameOrEmail, string password) /// Result public virtual CustomerRegistrationResult RegisterCustomer(CustomerRegistrationRequest request) { - if (request == null) - throw new ArgumentNullException("request"); - - if (request.Customer == null) - throw new ArgumentException("Can't load current customer"); + Guard.ArgumentNotNull(() => request); + Guard.ArgumentNotNull(() => request.Customer); var result = new CustomerRegistrationResult(); + if (request.Customer.IsSearchEngineAccount()) { - result.AddError("Search engine can't be registered"); + result.AddError(T("Account.Register.Errors.CannotRegisterSearchEngine")); return result; } if (request.Customer.IsBackgroundTaskAccount()) { - result.AddError("Background task account can't be registered"); + result.AddError(T("Account.Register.Errors.CannotRegisterTaskAccount")); return result; } if (request.Customer.IsRegistered()) { - result.AddError("Current customer is already registered"); + result.AddError(T("Account.Register.Errors.AlreadyRegistered")); return result; } if (String.IsNullOrEmpty(request.Email)) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.EmailIsNotProvided")); + result.AddError(T("Account.Register.Errors.EmailIsNotProvided")); return result; } if (!request.Email.IsEmail()) { - result.AddError(_localizationService.GetResource("Common.WrongEmail")); + result.AddError(T("Common.WrongEmail")); return result; } if (String.IsNullOrWhiteSpace(request.Password)) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.PasswordIsNotProvided")); + result.AddError(T("Account.Register.Errors.PasswordIsNotProvided")); return result; } if (_customerSettings.UsernamesEnabled) { if (String.IsNullOrEmpty(request.Username)) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.UsernameIsNotProvided")); + result.AddError(T("Account.Register.Errors.UsernameIsNotProvided")); return result; } } @@ -158,14 +160,14 @@ public virtual CustomerRegistrationResult RegisterCustomer(CustomerRegistrationR //validate unique user if (_customerService.GetCustomerByEmail(request.Email) != null) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.EmailAlreadyExists")); + result.AddError(T("Account.Register.Errors.EmailAlreadyExists")); return result; } if (_customerSettings.UsernamesEnabled) { if (_customerService.GetCustomerByUsername(request.Username) != null) { - result.AddError(_localizationService.GetResource("Account.Register.Errors.UsernameAlreadyExists")); + result.AddError(T("Account.Register.Errors.UsernameAlreadyExists")); return result; } } @@ -177,44 +179,52 @@ public virtual CustomerRegistrationResult RegisterCustomer(CustomerRegistrationR switch (request.PasswordFormat) { - case PasswordFormat.Clear: - { - request.Customer.Password = request.Password; - } - break; - case PasswordFormat.Encrypted: - { - request.Customer.Password = _encryptionService.EncryptText(request.Password); - } - break; - case PasswordFormat.Hashed: - { - string saltKey = _encryptionService.CreateSaltKey(5); - request.Customer.PasswordSalt = saltKey; - request.Customer.Password = _encryptionService.CreatePasswordHash(request.Password, saltKey, _customerSettings.HashedPasswordFormat); - } - break; - default: - break; + case PasswordFormat.Clear: + request.Customer.Password = request.Password; + break; + case PasswordFormat.Encrypted: + request.Customer.Password = _encryptionService.EncryptText(request.Password); + break; + case PasswordFormat.Hashed: + string saltKey = _encryptionService.CreateSaltKey(5); + request.Customer.PasswordSalt = saltKey; + request.Customer.Password = _encryptionService.CreatePasswordHash(request.Password, saltKey, _customerSettings.HashedPasswordFormat); + break; } request.Customer.Active = request.IsApproved; - - //add to 'Registered' role - var registeredRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered); - if (registeredRole == null) - throw new SmartException("'Registered' role could not be loaded"); + + if (_customerSettings.RegisterCustomerRoleId != 0) + { + var customerRole = _customerService.GetCustomerRoleById(_customerSettings.RegisterCustomerRoleId); + request.Customer.CustomerRoles.Add(customerRole); + } + + //add to 'Registered' role + var registeredRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered); + if (registeredRole == null) + { + throw new SmartException(T("Admin.Customers.CustomerRoles.CannotFoundRole", "Registered")); + } + request.Customer.CustomerRoles.Add(registeredRole); + //remove from 'Guests' role var guestRole = request.Customer.CustomerRoles.FirstOrDefault(cr => cr.SystemName == SystemCustomerRoleNames.Guests); - if (guestRole != null) - request.Customer.CustomerRoles.Remove(guestRole); + if (guestRole != null) + { + request.Customer.CustomerRoles.Remove(guestRole); + } - //Add reward points for customer registration (if enabled) - if (_rewardPointsSettings.Enabled && _rewardPointsSettings.PointsForRegistration > 0) - request.Customer.AddRewardPointsHistoryEntry(_rewardPointsSettings.PointsForRegistration, _localizationService.GetResource("RewardPoints.Message.RegisteredAsCustomer")); + //Add reward points for customer registration (if enabled) + if (_rewardPointsSettings.Enabled && _rewardPointsSettings.PointsForRegistration > 0) + { + request.Customer.AddRewardPointsHistoryEntry(_rewardPointsSettings.PointsForRegistration, T("RewardPoints.Message.RegisteredAsCustomer")); + } _customerService.UpdateCustomer(request.Customer); + _eventPublisher.Publish(new CustomerRegisteredEvent { Customer = request.Customer }); + return result; } @@ -231,19 +241,19 @@ public virtual PasswordChangeResult ChangePassword(ChangePasswordRequest request var result = new PasswordChangeResult(); if (String.IsNullOrWhiteSpace(request.Email)) { - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.EmailIsNotProvided")); + result.AddError(T("Account.ChangePassword.Errors.EmailIsNotProvided")); return result; } if (String.IsNullOrWhiteSpace(request.NewPassword)) { - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.PasswordIsNotProvided")); + result.AddError(T("Account.ChangePassword.Errors.PasswordIsNotProvided")); return result; } var customer = _customerService.GetCustomerByEmail(request.Email); if (customer == null) { - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.EmailNotFound")); + result.AddError(T("Account.ChangePassword.Errors.EmailNotFound")); return result; } @@ -268,7 +278,7 @@ public virtual PasswordChangeResult ChangePassword(ChangePasswordRequest request bool oldPasswordIsValid = oldPwd == customer.Password; if (!oldPasswordIsValid) - result.AddError(_localizationService.GetResource("Account.ChangePassword.Errors.OldPasswordDoesntMatch")); + result.AddError(T("Account.ChangePassword.Errors.OldPasswordDoesntMatch")); if (oldPasswordIsValid) requestIsValid = true; @@ -323,14 +333,14 @@ public virtual void SetEmail(Customer customer, string newEmail) string oldEmail = customer.Email; if (!newEmail.IsEmail()) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.NewEmailIsNotValid")); + throw new SmartException(T("Account.EmailUsernameErrors.NewEmailIsNotValid")); if (newEmail.Length > 100) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.EmailTooLong")); + throw new SmartException(T("Account.EmailUsernameErrors.EmailTooLong")); var customer2 = _customerService.GetCustomerByEmail(newEmail); if (customer2 != null && customer.Id != customer2.Id) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.EmailAlreadyExists")); + throw new SmartException(T("Account.EmailUsernameErrors.EmailAlreadyExists")); customer.Email = newEmail; _customerService.UpdateCustomer(customer); @@ -366,11 +376,11 @@ public virtual void SetUsername(Customer customer, string newUsername) newUsername = newUsername.Trim(); if (newUsername.Length > 100) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.UsernameTooLong")); + throw new SmartException(T("Account.EmailUsernameErrors.UsernameTooLong")); var user2 = _customerService.GetCustomerByUsername(newUsername); if (user2 != null && customer.Id != user2.Id) - throw new SmartException(_localizationService.GetResource("Account.EmailUsernameErrors.UsernameAlreadyExists")); + throw new SmartException(T("Account.EmailUsernameErrors.UsernameAlreadyExists")); customer.Username = newUsername; _customerService.UpdateCustomer(customer); diff --git a/src/Libraries/SmartStore.Services/Customers/CustomerService.cs b/src/Libraries/SmartStore.Services/Customers/CustomerService.cs index 4d0325505c..d48fe10d6c 100644 --- a/src/Libraries/SmartStore.Services/Customers/CustomerService.cs +++ b/src/Libraries/SmartStore.Services/Customers/CustomerService.cs @@ -3,31 +3,37 @@ using System.Diagnostics; using System.Globalization; using System.Linq; +using System.Linq.Expressions; +using System.Web; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Forums; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Events; using SmartStore.Core.Localization; +using SmartStore.Core.Fakes; using SmartStore.Services.Common; using SmartStore.Services.Localization; namespace SmartStore.Services.Customers { - /// - /// Customer service - /// - public partial class CustomerService : ICustomerService + /// + /// Customer service + /// + public partial class CustomerService : ICustomerService { - #region Constants + #region Constants - private const string CUSTOMERROLES_ALL_KEY = "SmartStore.customerrole.all-{0}"; + private const string CUSTOMERROLES_ALL_KEY = "SmartStore.customerrole.all-{0}"; private const string CUSTOMERROLES_BY_SYSTEMNAME_KEY = "SmartStore.customerrole.systemname-{0}"; private const string CUSTOMERROLES_PATTERN_KEY = "SmartStore.customerrole."; + #endregion #region Fields @@ -35,39 +41,40 @@ public partial class CustomerService : ICustomerService private readonly IRepository _customerRepository; private readonly IRepository _customerRoleRepository; private readonly IRepository _gaRepository; + private readonly IRepository _rewardPointsHistoryRepository; private readonly IGenericAttributeService _genericAttributeService; - private readonly ICacheManager _cacheManager; - private readonly IEventPublisher _eventPublisher; + private readonly ICommonServices _services; + private readonly ICacheManager _cache; private readonly RewardPointsSettings _rewardPointsSettings; + private readonly HttpContextBase _httpContext; + private readonly IUserAgent _userAgent; - #endregion + #endregion + + #region Ctor - #region Ctor - - /// - /// Ctor - /// - /// Cache manager - /// Customer repository - /// Customer role repository - /// Generic attribute repository - /// Generic attribute service - /// Event published - public CustomerService(ICacheManager cacheManager, + public CustomerService( IRepository customerRepository, IRepository customerRoleRepository, IRepository gaRepository, + IRepository rewardPointsHistoryRepository, IGenericAttributeService genericAttributeService, - IEventPublisher eventPublisher, - RewardPointsSettings rewardPointsSettings) + ICommonServices services, + ICacheManager cache, + RewardPointsSettings rewardPointsSettings, + HttpContextBase httpContext, + IUserAgent userAgent) { - this._cacheManager = cacheManager; this._customerRepository = customerRepository; this._customerRoleRepository = customerRoleRepository; this._gaRepository = gaRepository; + this._rewardPointsHistoryRepository = rewardPointsHistoryRepository; this._genericAttributeService = genericAttributeService; - this._eventPublisher = eventPublisher; + this._services = services; + this._cache = cache; this._rewardPointsSettings = rewardPointsSettings; + this._httpContext = httpContext; + this._userAgent = userAgent; T = NullLocalizer.Instance; } @@ -84,26 +91,6 @@ public CustomerService(ICacheManager cacheManager, #region Customers - /// - /// Gets all customers - /// - /// Customer registration from; null to load all customers - /// Customer registration to; null to load all customers - /// A list of customer role identifiers to filter by (at least one match); pass null or empty list in order to load all customers; - /// Email; null to load all customers - /// Username; null to load all customers - /// First name; null to load all customers - /// Last name; null to load all customers - /// Day of birth; 0 to load all customers - /// Month of birth; 0 to load all customers - /// Company; null to load all customers - /// Phone; null to load all customers - /// Phone; null to load all customers - /// Value indicating whther to load customers only with shopping cart - /// Value indicating what shopping cart type to filter; userd when 'loadOnlyWithShoppingCart' param is 'true' - /// Page index - /// Page size - /// Customer collection public virtual IPagedList GetAllCustomers(DateTime? registrationFrom, DateTime? registrationTo, int[] customerRoleIds, string email, string username, string firstName, string lastName, int dayOfBirth, int monthOfBirth, @@ -236,13 +223,6 @@ public virtual IPagedList GetAllCustomers(DateTime? registrationFrom, return customers; } - /// - /// Gets all customers by affiliate identifier - /// - /// Affiliate identifier - /// Page index - /// Page size - /// Customers public virtual IPagedList GetAllCustomers(int affiliateId, int pageIndex, int pageSize) { var query = _customerRepository.Table; @@ -254,11 +234,6 @@ public virtual IPagedList GetAllCustomers(int affiliateId, int pageInd return customers; } - /// - /// Gets all customers by customer format (including deleted ones) - /// - /// Password format - /// Customers public virtual IList GetAllCustomersByPasswordFormat(PasswordFormat passwordFormat) { int passwordFormatId = (int)passwordFormat; @@ -270,14 +245,6 @@ public virtual IList GetAllCustomersByPasswordFormat(PasswordFormat pa return customers; } - /// - /// Gets online customers - /// - /// Customer last activity date (from) - /// A list of customer role identifiers to filter by (at least one match); pass null or empty list in order to load all customers; - /// Page index - /// Page size - /// Customer collection public virtual IPagedList GetOnlineCustomers(DateTime lastActivityFromUtc, int[] customerRoleIds, int pageIndex, int pageSize) { @@ -292,10 +259,6 @@ public virtual IPagedList GetOnlineCustomers(DateTime lastActivityFrom return customers; } - /// - /// Delete a customer - /// - /// Customer public virtual void DeleteCustomer(Customer customer) { if (customer == null) @@ -308,11 +271,6 @@ public virtual void DeleteCustomer(Customer customer) UpdateCustomer(customer); } - /// - /// Gets a customer - /// - /// Customer identifier - /// A customer public virtual Customer GetCustomerById(int customerId) { if (customerId == 0) @@ -322,11 +280,6 @@ public virtual Customer GetCustomerById(int customerId) return customer; } - /// - /// Get customers by identifiers - /// - /// Customer identifiers - /// Customers public virtual IList GetCustomersByIds(int[] customerIds) { if (customerIds == null || customerIds.Length == 0) @@ -347,11 +300,11 @@ where customerIds.Contains(c.Id) return sortedCustomers; } - /// - /// Gets a customer by GUID - /// - /// Customer GUID - /// A customer + public virtual IList GetSystemAccountCustomers() + { + return _customerRepository.Table.Where(x => x.IsSystemAccount).ToList(); + } + public virtual Customer GetCustomerByGuid(Guid customerGuid) { if (customerGuid == Guid.Empty) @@ -365,11 +318,6 @@ orderby c.Id return customer; } - /// - /// Get customer by email - /// - /// Email - /// Customer public virtual Customer GetCustomerByEmail(string email) { if (string.IsNullOrWhiteSpace(email)) @@ -383,29 +331,20 @@ orderby c.Id return customer; } - /// - /// Get customer by system name - /// - /// System name - /// Customer public virtual Customer GetCustomerBySystemName(string systemName) { if (string.IsNullOrWhiteSpace(systemName)) return null; - var query = from c in _customerRepository.Table - orderby c.Id - where c.SystemName == systemName - select c; - var customer = query.FirstOrDefault(); - return customer; + var query = from c in _customerRepository.Table + orderby c.Id + where c.SystemName == systemName + select c; + var customer = query.FirstOrDefault(); + + return customer; } - /// - /// Get customer by username - /// - /// Username - /// Customer public virtual Customer GetCustomerByUsername(string username) { if (string.IsNullOrWhiteSpace(username)) @@ -420,35 +359,63 @@ orderby c.Id return customer; } - /// - /// Insert a guest customer - /// - /// Customer - public virtual Customer InsertGuestCustomer() + public virtual Customer InsertGuestCustomer(Guid? customerGuid = null) { - var customer = new Customer() + var customer = new Customer { - CustomerGuid = Guid.NewGuid(), + CustomerGuid = customerGuid ?? Guid.NewGuid(), Active = true, CreatedOnUtc = DateTime.UtcNow, LastActivityDateUtc = DateTime.UtcNow, }; - //add to 'Guests' role + // add to 'Guests' role var guestRole = GetCustomerRoleBySystemName(SystemCustomerRoleNames.Guests); if (guestRole == null) throw new SmartException("'Guests' role could not be loaded"); + customer.CustomerRoles.Add(guestRole); - _customerRepository.Insert(customer); + _customerRepository.Insert(customer); + + var clientIdent = _services.WebHelper.GetClientIdent(); + if (clientIdent.HasValue()) + { + //_genericAttributeService.SaveAttribute(customer, "ClientIdent", clientIdent); + } return customer; } + + public virtual Customer FindGuestCustomerByClientIdent(string clientIdent = null, int maxAgeSeconds = 60) + { + if (_httpContext.IsFakeContext() || _userAgent.IsBot || _userAgent.IsPdfConverter) + { + return null; + } + + clientIdent = clientIdent.NullEmpty() ?? _services.WebHelper.GetClientIdent(); + if (clientIdent.IsEmpty()) + { + return null; + } + + var dateFrom = DateTime.UtcNow.AddSeconds(maxAgeSeconds * -1); + + var query = from a in _gaRepository.TableUntracked + join c in _customerRepository.Table on a.EntityId equals c.Id into Customers + from c in Customers.DefaultIfEmpty() + where c.LastActivityDateUtc >= dateFrom + && c.Username == null + && c.Email == null + && a.KeyGroup == "Customer" + && a.Key == "ClientIdent" + && a.Value == clientIdent + select c; + + return query.FirstOrDefault(); + } - /// - /// Insert a customer - /// - /// Customer public virtual void InsertCustomer(Customer customer) { if (customer == null) @@ -456,14 +423,9 @@ public virtual void InsertCustomer(Customer customer) _customerRepository.Insert(customer); - //event notification - _eventPublisher.EntityInserted(customer); + _services.EventPublisher.EntityInserted(customer); } - /// - /// Updates the customer - /// - /// Customer public virtual void UpdateCustomer(Customer customer) { if (customer == null) @@ -471,20 +433,9 @@ public virtual void UpdateCustomer(Customer customer) _customerRepository.Update(customer); - //event notification - _eventPublisher.EntityUpdated(customer); + _services.EventPublisher.EntityUpdated(customer); } - /// - /// Reset data required for checkout - /// - /// Customer - /// Store identifier - /// A value indicating whether to clear coupon code - /// A value indicating whether to clear selected checkout attributes - /// A value indicating whether to clear "Use reward points" flag - /// A value indicating whether to clear selected shipping method - /// A value indicating whether to clear selected payment method public virtual void ResetCheckoutData(Customer customer, int storeId, bool clearCouponCodes = false, bool clearCheckoutAttributes = false, bool clearRewardPoints = true, bool clearShippingMethod = true, @@ -528,71 +479,129 @@ public virtual void ResetCheckoutData(Customer customer, int storeId, UpdateCustomer(customer); } - /// - /// Delete guest customer records - /// - /// Customer registration from; null to load all customers - /// Customer registration to; null to load all customers - /// A value indicating whether to delete customers only without shopping cart - /// Number of deleted customers - public virtual int DeleteGuestCustomers(DateTime? registrationFrom, DateTime? registrationTo, bool onlyWithoutShoppingCart) + public virtual int DeleteGuestCustomers(DateTime? registrationFrom, DateTime? registrationTo, bool onlyWithoutShoppingCart, int maxItemsToDelete = 5000) { - var guestRole = GetCustomerRoleBySystemName(SystemCustomerRoleNames.Guests); - if (guestRole == null) - throw new SmartException("'Guests' role could not be loaded"); + var ctx = _customerRepository.Context; - var query = _customerRepository.Table; - if (registrationFrom.HasValue) - query = query.Where(c => registrationFrom.Value <= c.CreatedOnUtc); - if (registrationTo.HasValue) - query = query.Where(c => registrationTo.Value >= c.CreatedOnUtc); - query = query.Where(c => c.CustomerRoles.Select(cr => cr.Id).Contains(guestRole.Id)); - if (onlyWithoutShoppingCart) - query = query.Where(c => !c.ShoppingCartItems.Any()); - //no orders - query = query.Where(c => !c.Orders.Any()); - //no customer content - query = query.Where(c => !c.CustomerContent.Any()); - //ensure that customers doesn't have forum posts or topics - query = query.Where(c => !c.ForumTopics.Any()); - query = query.Where(c => !c.ForumPosts.Any()); - //don't delete system accounts - query = query.Where(c => !c.IsSystemAccount); - var customers = query.ToList(); - - int numberOfDeletedCustomers = 0; - foreach (var c in customers) - { - try - { - //delete from database - _customerRepository.Delete(c); - numberOfDeletedCustomers++; - - //delete attributes - var attributes = _genericAttributeService.GetAttributesForEntity(c.Id, "Customer"); - foreach (var attribute in attributes) - { - _genericAttributeService.DeleteAttribute(attribute); - } - } - catch (Exception exc) - { - Debug.WriteLine(exc); - } - } - - return numberOfDeletedCustomers; + using (var scope = new DbContextScope(ctx: ctx, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true, autoCommit: false)) + { + var guestRole = GetCustomerRoleBySystemName(SystemCustomerRoleNames.Guests); + if (guestRole == null) + throw new SmartException("'Guests' role could not be loaded"); + + var query = _customerRepository.Table; + + if (registrationFrom.HasValue) + query = query.Where(c => registrationFrom.Value <= c.CreatedOnUtc); + if (registrationTo.HasValue) + query = query.Where(c => registrationTo.Value >= c.CreatedOnUtc); + + query = query.Where(c => c.CustomerRoles.Select(cr => cr.Id).Contains(guestRole.Id)); + + if (onlyWithoutShoppingCart) + query = query.Where(c => !c.ShoppingCartItems.Any()); + + // no orders + query = JoinWith(query, x => x.CustomerId); + + // no customer content + query = JoinWith(query, x => x.CustomerId); + + // no forum posts + query = JoinWith(query, x => x.CustomerId); + + // no forum topics + query = JoinWith(query, x => x.CustomerId); + + //don't delete system accounts + query = query.Where(c => !c.IsSystemAccount); + + // only distinct items + query = from c in query + group c by c.Id + into cGroup + orderby cGroup.Key + select cGroup.FirstOrDefault(); + query = query.OrderBy(c => c.Id); + + var customers = query.Take(maxItemsToDelete).ToList(); + + int numberOfDeletedCustomers = 0; + foreach (var c in customers) + { + try + { + // delete attributes (using GenericAttributeService would incorporate caching... which is bad in long running processes) + var gaQuery = from ga in _gaRepository.Table + where ga.EntityId == c.Id && + ga.KeyGroup == "Customer" + select ga; + var attributes = gaQuery.ToList(); + + _gaRepository.DeleteRange(attributes); + + // delete customer + _customerRepository.Delete(c); + numberOfDeletedCustomers++; + + if (numberOfDeletedCustomers % 1000 == 0) + { + // save changes all 1000th item + try + { + scope.Commit(); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + // save the rest + scope.Commit(); + + return numberOfDeletedCustomers; + } } + private IQueryable JoinWith(IQueryable query, Expression> customerIdSelector) where T : BaseEntity + { + var inner = _customerRepository.Context.Set().AsNoTracking(); + + /* + * Lamda join created with LinqPad. ORIGINAL: + from c in customers + join inner in ctx.Set().AsNoTracking() on c.Id equals inner.CustomerId into c_inner + from inner in c_inner.DefaultIfEmpty() + where !c_inner.Any() + select c; + */ + query = query + .GroupJoin( + inner, + c => c.Id, + customerIdSelector, + (c, i) => new { Customer = c, Inner = i }) + .SelectMany( + x => x.Inner.DefaultIfEmpty(), + (a, b) => new { a, b } + ) + .Where(x => !(x.a.Inner.Any())) + .Select(x => x.a.Customer); + + return query; + } + #endregion #region Customer roles - /// - /// Delete a customer role - /// - /// Customer role public virtual void DeleteCustomerRole(CustomerRole customerRole) { if (customerRole == null) @@ -603,17 +612,11 @@ public virtual void DeleteCustomerRole(CustomerRole customerRole) _customerRoleRepository.Delete(customerRole); - _cacheManager.RemoveByPattern(CUSTOMERROLES_PATTERN_KEY); + _cache.RemoveByPattern(CUSTOMERROLES_PATTERN_KEY); - //event notification - _eventPublisher.EntityDeleted(customerRole); + _services.EventPublisher.EntityDeleted(customerRole); } - /// - /// Gets a customer role - /// - /// Customer role identifier - /// Customer role public virtual CustomerRole GetCustomerRoleById(int customerRoleId) { if (customerRoleId == 0) @@ -622,18 +625,13 @@ public virtual CustomerRole GetCustomerRoleById(int customerRoleId) return _customerRoleRepository.GetById(customerRoleId); } - /// - /// Gets a customer role - /// - /// Customer role system name - /// Customer role public virtual CustomerRole GetCustomerRoleBySystemName(string systemName) { if (String.IsNullOrWhiteSpace(systemName)) return null; string key = string.Format(CUSTOMERROLES_BY_SYSTEMNAME_KEY, systemName); - return _cacheManager.Get(key, () => + return _cache.Get(key, () => { var query = from cr in _customerRoleRepository.Table orderby cr.Id @@ -644,15 +642,10 @@ orderby cr.Id }); } - /// - /// Gets all customer roles - /// - /// A value indicating whether to show hidden records - /// Customer role collection public virtual IList GetAllCustomerRoles(bool showHidden = false) { string key = string.Format(CUSTOMERROLES_ALL_KEY, showHidden); - return _cacheManager.Get(key, () => + return _cache.Get(key, () => { var query = from cr in _customerRoleRepository.Table orderby cr.Name @@ -663,10 +656,6 @@ orderby cr.Name }); } - /// - /// Inserts a customer role - /// - /// Customer role public virtual void InsertCustomerRole(CustomerRole customerRole) { if (customerRole == null) @@ -674,16 +663,11 @@ public virtual void InsertCustomerRole(CustomerRole customerRole) _customerRoleRepository.Insert(customerRole); - _cacheManager.RemoveByPattern(CUSTOMERROLES_PATTERN_KEY); + _cache.RemoveByPattern(CUSTOMERROLES_PATTERN_KEY); - //event notification - _eventPublisher.EntityInserted(customerRole); + _services.EventPublisher.EntityInserted(customerRole); } - /// - /// Updates the customer role - /// - /// Customer role public virtual void UpdateCustomerRole(CustomerRole customerRole) { if (customerRole == null) @@ -691,22 +675,15 @@ public virtual void UpdateCustomerRole(CustomerRole customerRole) _customerRoleRepository.Update(customerRole); - _cacheManager.RemoveByPattern(CUSTOMERROLES_PATTERN_KEY); + _cache.RemoveByPattern(CUSTOMERROLES_PATTERN_KEY); - //event notification - _eventPublisher.EntityUpdated(customerRole); + _services.EventPublisher.EntityUpdated(customerRole); } #endregion #region Reward points - /// - /// Add or remove reward points for a product review - /// - /// The customer - /// The product - /// Whether to add or remove points public virtual void RewardPointsForProductReview(Customer customer, Product product, bool add) { if (_rewardPointsSettings.Enabled && _rewardPointsSettings.PointsForProductReview > 0) @@ -719,6 +696,25 @@ public virtual void RewardPointsForProductReview(Customer customer, Product prod } } + public virtual Multimap GetRewardPointsHistoriesByCustomerIds(int[] customerIds) + { + Guard.ArgumentNotNull(() => customerIds); + + var query = + from x in _rewardPointsHistoryRepository.TableUntracked + where customerIds.Contains(x.CustomerId) + select x; + + var map = query + .OrderBy(x => x.CustomerId) + .ThenByDescending(x => x.CreatedOnUtc) + .ThenByDescending(x => x.Id) + .ToList() + .ToMultimap(x => x.CustomerId, x => x); + + return map; + } + #endregion Reward points #endregion diff --git a/src/Libraries/SmartStore.Services/Customers/DeleteGuestsTask.cs b/src/Libraries/SmartStore.Services/Customers/DeleteGuestsTask.cs index ce7c180402..35dbb85d43 100644 --- a/src/Libraries/SmartStore.Services/Customers/DeleteGuestsTask.cs +++ b/src/Libraries/SmartStore.Services/Customers/DeleteGuestsTask.cs @@ -21,7 +21,7 @@ public DeleteGuestsTask(ICustomerService customerService) public void Execute(TaskExecutionContext ctx) { //60*24 = 1 day - var olderThanMinutes = 1440; //TODO: move to settings + var olderThanMinutes = 1440; // TODO: move to settings _customerService.DeleteGuestCustomers(null, DateTime.UtcNow.AddMinutes(-olderThanMinutes), true); } } diff --git a/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs b/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs index 2675f3c3bc..57a2c6f8c9 100644 --- a/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs +++ b/src/Libraries/SmartStore.Services/Customers/ICustomerService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Customers; @@ -87,12 +88,18 @@ IPagedList GetOnlineCustomers(DateTime lastActivityFromUtc, /// Customers IList GetCustomersByIds(int[] customerIds); - /// - /// Gets a customer by GUID - /// - /// Customer GUID - /// A customer - Customer GetCustomerByGuid(Guid customerGuid); + /// + /// Get system account customers + /// + /// System account customers + IList GetSystemAccountCustomers(); + + /// + /// Gets a customer by GUID + /// + /// Customer GUID + /// A customer + Customer GetCustomerByGuid(Guid customerGuid); /// /// Get customer by email @@ -118,14 +125,26 @@ IPagedList GetOnlineCustomers(DateTime lastActivityFromUtc, /// /// Insert a guest customer /// + /// The customer GUID. Pass null to create a random one. /// Customer - Customer InsertGuestCustomer(); + Customer InsertGuestCustomer(Guid? customerGuid = null); - /// - /// Insert a customer - /// - /// Customer - void InsertCustomer(Customer customer); + /// + /// Tries to find a guest/anonymous customer record by client ident. This method should be called when an + /// anonymous visitor rejects cookies and therefore cannot be identified automatically. + /// + /// + /// The client ident string, which is a hashed combination of client IP address and user agent. + /// Call to obtain an ident string, or pass null to let this method obtain it automatically. + /// The max age of the newly created guest customer record. The shorter, the better (default is 1 min.) + /// The identified customer or null + Customer FindGuestCustomerByClientIdent(string clientIdent = null, int maxAgeSeconds = 60); + + /// + /// Insert a customer + /// + /// Customer + void InsertCustomer(Customer customer); /// /// Updates the customer @@ -155,8 +174,7 @@ void ResetCheckoutData(Customer customer, int storeId, /// Customer registration to; null to load all customers /// A value indicating whether to delete customers only without shopping cart /// Number of deleted customers - int DeleteGuestCustomers(DateTime? registrationFrom, - DateTime? registrationTo, bool onlyWithoutShoppingCart); + int DeleteGuestCustomers(DateTime? registrationFrom, DateTime? registrationTo, bool onlyWithoutShoppingCart, int maxItemsToDelete = 5000); #endregion @@ -213,6 +231,13 @@ int DeleteGuestCustomers(DateTime? registrationFrom, /// Whether to add or remove points void RewardPointsForProductReview(Customer customer, Product product, bool add); + /// + /// Gets reward points histories + /// + /// Customer identifiers + /// Reward points histories + Multimap GetRewardPointsHistoriesByCustomerIds(int[] customerIds); + #endregion Reward points } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs new file mode 100644 index 0000000000..452f281fb8 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Customers/Importer/CustomerImporter.cs @@ -0,0 +1,653 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core.Async; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Events; +using SmartStore.Services.Affiliates; +using SmartStore.Services.Common; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Directory; +using SmartStore.Services.Helpers; +using SmartStore.Services.Media; +using SmartStore.Services.Security; +using SmartStore.Utilities; + +namespace SmartStore.Services.Customers.Importer +{ + public class CustomerImporter : EntityImporterBase + { + private const string _attributeKeyGroup = "Customer"; + + private readonly IRepository _customerRepository; + private readonly IRepository _pictureRepository; + private readonly ICommonServices _services; + private readonly IGenericAttributeService _genericAttributeService; + private readonly ICustomerService _customerService; + private readonly IPictureService _pictureService; + private readonly IAffiliateService _affiliateService; + private readonly ICountryService _countryService; + private readonly IStateProvinceService _stateProvinceService; + private readonly FileDownloadManager _fileDownloadManager; + private readonly CustomerSettings _customerSettings; + private readonly DateTimeSettings _dateTimeSettings; + private readonly ForumSettings _forumSettings; + + public CustomerImporter( + IRepository customerRepository, + IRepository pictureRepository, + ICommonServices services, + IGenericAttributeService genericAttributeService, + ICustomerService customerService, + IPictureService pictureService, + IAffiliateService affiliateService, + ICountryService countryService, + IStateProvinceService stateProvinceService, + FileDownloadManager fileDownloadManager, + CustomerSettings customerSettings, + DateTimeSettings dateTimeSettings, + ForumSettings forumSettings) + { + _customerRepository = customerRepository; + _pictureRepository = pictureRepository; + _services = services; + _genericAttributeService = genericAttributeService; + _customerService = customerService; + _pictureService = pictureService; + _affiliateService = affiliateService; + _countryService = countryService; + _stateProvinceService = stateProvinceService; + _fileDownloadManager = fileDownloadManager; + _customerSettings = customerSettings; + _dateTimeSettings = dateTimeSettings; + _forumSettings = forumSettings; + } + + + protected override void Import(ImportExecuteContext context) + { + var customer = _services.WorkContext.CurrentCustomer; + var allowManagingCustomerRoles = _services.Permissions.Authorize(StandardPermissionProvider.ManageCustomerRoles, customer); + + var allAffiliateIds = _affiliateService.GetAllAffiliates(true) + .Select(x => x.Id) + .ToList(); + + var allCountries = new Dictionary(); + foreach (var country in _countryService.GetAllCountries(true)) + { + if (!allCountries.ContainsKey(country.TwoLetterIsoCode)) + allCountries.Add(country.TwoLetterIsoCode, country.Id); + + if (!allCountries.ContainsKey(country.ThreeLetterIsoCode)) + allCountries.Add(country.ThreeLetterIsoCode, country.Id); + } + + var allStateProvinces = _stateProvinceService.GetAllStateProvinces(true) + .ToDictionarySafe(x => new Tuple(x.CountryId, x.Abbreviation), x => x.Id); + + var allCustomerNumbers = new HashSet( + _genericAttributeService.GetAttributes(SystemCustomerAttributeNames.CustomerNumber, _attributeKeyGroup).Select(x => x.Value), + StringComparer.OrdinalIgnoreCase); + + using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) + { + var segmenter = context.DataSegmenter; + + Initialize(context); + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.GetCurrentBatch(); + + _customerRepository.Context.DetachAll(false); + + context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); + + // =========================================================================== + // Process customers + // =========================================================================== + try + { + ProcessCustomers(context, batch, allAffiliateIds); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessCustomers"); + } + + // reduce batch to saved (valid) records. + // No need to perform import operations on errored records. + batch = batch.Where(x => x.Entity != null && !x.IsTransient).ToArray(); + + // update result object + context.Result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); + context.Result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); + + // =========================================================================== + // Process generic attributes + // =========================================================================== + try + { + ProcessGenericAttributes(context, batch, allCountries, allStateProvinces, allCustomerNumbers); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessGenericAttributes"); + } + + // =========================================================================== + // Process avatars + // =========================================================================== + if (_customerSettings.AllowCustomersToUploadAvatars) + { + try + { + ProcessAvatars(context, batch); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessAvatars"); + } + } + + // =========================================================================== + // Process addresses + // =========================================================================== + try + { + _services.DbContext.AutoDetectChangesEnabled = true; + ProcessAddresses(context, batch, allCountries, allStateProvinces); + } + catch (Exception exception) + { + context.Result.AddError(exception, segmenter.CurrentSegment, "ProcessAddresses"); + } + finally + { + _services.DbContext.AutoDetectChangesEnabled = false; + } + } + } + } + + protected virtual int ProcessCustomers( + ImportExecuteContext context, + IEnumerable> batch, + List allAffiliateIds) + { + _customerRepository.AutoCommitEnabled = true; + + Customer lastInserted = null; + Customer lastUpdated = null; + var currentCustomer = _services.WorkContext.CurrentCustomer; + + var guestRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Guests); + var registeredRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered); + var forumModeratorRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.ForumModerators); + + var customerQuery = _customerRepository.Table.Expand(x => x.Addresses); + + foreach (var row in batch) + { + Customer customer = null; + var id = row.GetDataValue("Id"); + var email = row.GetDataValue("Email"); + + foreach (var keyName in context.KeyFieldNames) + { + switch (keyName) + { + case "Id": + if (id != 0) + { + customer = customerQuery.FirstOrDefault(x => x.Id == id); + } + break; + case "CustomerGuid": + var customerGuid = row.GetDataValue("CustomerGuid"); + if (customerGuid.HasValue()) + { + var guid = new Guid(customerGuid); + customer = customerQuery.FirstOrDefault(x => x.CustomerGuid == guid); + } + break; + case "Email": + if (email.HasValue()) + { + customer = customerQuery.FirstOrDefault(x => x.Email == email); + } + break; + case "Username": + var userName = row.GetDataValue("Username"); + if (userName.HasValue()) + { + customer = customerQuery.FirstOrDefault(x => x.Username == userName); + } + break; + } + + if (customer != null) + break; + } + + if (customer == null) + { + if (context.UpdateOnly) + { + ++context.Result.SkippedRecords; + continue; + } + + customer = new Customer + { + CustomerGuid = new Guid(), + AffiliateId = 0, + Active = true + }; + } + else + { + _customerRepository.Context.LoadCollection(customer, (Customer x) => x.CustomerRoles); + } + + var isGuest = row.GetDataValue("IsGuest"); + var isRegistered = row.GetDataValue("IsRegistered"); + var isAdmin = row.GetDataValue("IsAdministrator"); + var isForumModerator = row.GetDataValue("IsForumModerator"); + var affiliateId = row.GetDataValue("AffiliateId"); + + row.Initialize(customer, email ?? id.ToString()); + + row.SetProperty(context.Result, (x) => x.CustomerGuid); + row.SetProperty(context.Result, (x) => x.Username); + row.SetProperty(context.Result, (x) => x.Email); + + if (email.HasValue() && currentCustomer.Email.IsCaseInsensitiveEqual(email)) + { + context.Result.AddInfo("Security. Ignored password of current customer (who started this import).", row.GetRowInfo(), "Password"); + } + else + { + row.SetProperty(context.Result, (x) => x.Password); + row.SetProperty(context.Result, (x) => x.PasswordFormatId); + row.SetProperty(context.Result, (x) => x.PasswordSalt); + } + + row.SetProperty(context.Result, (x) => x.AdminComment); + row.SetProperty(context.Result, (x) => x.IsTaxExempt); + row.SetProperty(context.Result, (x) => x.Active); + + row.SetProperty(context.Result, (x) => x.CreatedOnUtc, UtcNow); + row.SetProperty(context.Result, (x) => x.LastActivityDateUtc, UtcNow); + + if (affiliateId > 0 && allAffiliateIds.Contains(affiliateId)) + { + customer.AffiliateId = affiliateId; + } + + if (isAdmin) + { + context.Result.AddInfo("Security. Ignored administrator role.", row.GetRowInfo(), "IsAdministrator"); + } + + UpsertRole(row, guestRole, isGuest); + UpsertRole(row, registeredRole, isRegistered); + UpsertRole(row, forumModeratorRole, isForumModerator); + + if (row.IsTransient) + { + _customerRepository.Insert(customer); + lastInserted = customer; + } + else + { + _customerRepository.Update(customer); + lastUpdated = customer; + } + } + + var num = _customerRepository.Context.SaveChanges(); + + if (lastInserted != null) + { + _services.EventPublisher.EntityInserted(lastInserted); + } + + if (lastUpdated != null) + { + _services.EventPublisher.EntityUpdated(lastUpdated); + } + + return num; + } + + protected virtual int ProcessAddresses( + ImportExecuteContext context, + IEnumerable> batch, + Dictionary allCountries, + Dictionary, int> allStateProvinces) + { + foreach (var row in batch) + { + ImportAddress("BillingAddress.", row, context, allCountries, allStateProvinces); + ImportAddress("ShippingAddress.", row, context, allCountries, allStateProvinces); + } + + return _services.DbContext.SaveChanges(); + } + + private void ImportAddress( + string fieldPrefix, + ImportRow row, + ImportExecuteContext context, + Dictionary allCountries, + Dictionary, int> allStateProvinces) + { + // last name is mandatory for an address to be imported or updated + if (!row.HasDataValue(fieldPrefix + "LastName")) + return; + + var address = new Address + { + CreatedOnUtc = UtcNow + }; + + var childRow = new ImportRow
(row.Segmenter, row.DataRow, row.Position); + childRow.Initialize(address, row.EntityDisplayName); + + childRow.SetProperty(context.Result, fieldPrefix + "LastName", x => x.LastName); + childRow.SetProperty(context.Result, fieldPrefix + "FirstName", x => x.FirstName); + childRow.SetProperty(context.Result, fieldPrefix + "Email", x => x.Email); + childRow.SetProperty(context.Result, fieldPrefix + "Company", x => x.Company); + childRow.SetProperty(context.Result, fieldPrefix + "City", x => x.City); + childRow.SetProperty(context.Result, fieldPrefix + "Address1", x => x.Address1); + childRow.SetProperty(context.Result, fieldPrefix + "Address2", x => x.Address2); + childRow.SetProperty(context.Result, fieldPrefix + "ZipPostalCode", x => x.ZipPostalCode); + childRow.SetProperty(context.Result, fieldPrefix + "PhoneNumber", x => x.PhoneNumber); + childRow.SetProperty(context.Result, fieldPrefix + "FaxNumber", x => x.FaxNumber); + + childRow.SetProperty(context.Result, fieldPrefix + "CountryId", x => x.CountryId); + if (childRow.Entity.CountryId == null) + { + // try with country code + childRow.SetProperty(context.Result, fieldPrefix + "CountryCode", x => x.CountryId, converter: (val, ci) => CountryCodeToId(allCountries, val.ToString())); + } + + var countryId = childRow.Entity.CountryId; + + if (countryId.HasValue) + { + childRow.SetProperty(context.Result, fieldPrefix + "StateProvinceId", x => x.StateProvinceId); + if (childRow.Entity.StateProvinceId == null) + { + // try with state abbreviation + childRow.SetProperty(context.Result, fieldPrefix + "StateAbbreviation", x => x.StateProvinceId, converter: (val, ci) => StateAbbreviationToId(allStateProvinces, countryId, val.ToString())); + } + } + + if (!childRow.IsDirty) + { + // Not one single property could be set. Get out! + return; + } + + var appliedAddress = row.Entity.Addresses.FindAddress(address); + + if (appliedAddress == null) + { + appliedAddress = address; + row.Entity.Addresses.Add(appliedAddress); + } + + if (fieldPrefix == "BillingAddress.") + { + row.Entity.BillingAddress = appliedAddress; + } + else if (fieldPrefix == "ShippingAddress.") + { + row.Entity.ShippingAddress = appliedAddress; + } + + _customerRepository.Update(row.Entity); + } + + protected virtual int ProcessGenericAttributes( + ImportExecuteContext context, + IEnumerable> batch, + Dictionary allCountries, + Dictionary, int> allStateProvinces, + HashSet allCustomerNumbers) + { + foreach (var row in batch) + { + SaveAttribute(row, SystemCustomerAttributeNames.FirstName); + SaveAttribute(row, SystemCustomerAttributeNames.LastName); + + if (_dateTimeSettings.AllowCustomersToSetTimeZone) + SaveAttribute(row, SystemCustomerAttributeNames.TimeZoneId); + + if (_customerSettings.GenderEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Gender); + + if (_customerSettings.DateOfBirthEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.DateOfBirth); + + if (_customerSettings.CompanyEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Company); + + if (_customerSettings.StreetAddressEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress); + + if (_customerSettings.StreetAddress2Enabled) + SaveAttribute(row, SystemCustomerAttributeNames.StreetAddress2); + + if (_customerSettings.ZipPostalCodeEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.ZipPostalCode); + + if (_customerSettings.CityEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.City); + + if (_customerSettings.CountryEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.CountryId); + + if (_customerSettings.CountryEnabled && _customerSettings.StateProvinceEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.StateProvinceId); + + if (_customerSettings.PhoneEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Phone); + + if (_customerSettings.FaxEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Fax); + + if (_forumSettings.ForumsEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.ForumPostCount); + + if (_forumSettings.SignaturesEnabled) + SaveAttribute(row, SystemCustomerAttributeNames.Signature); + + var countryId = CountryCodeToId(allCountries, row.GetDataValue("CountryCode")); + var stateId = StateAbbreviationToId(allStateProvinces, countryId, row.GetDataValue("StateAbbreviation")); + + if (countryId.HasValue) + { + SaveAttribute(row, SystemCustomerAttributeNames.CountryId, countryId.Value); + } + + if (stateId.HasValue) + { + SaveAttribute(row, SystemCustomerAttributeNames.StateProvinceId, stateId.Value); + } + + string customerNumber = null; + + if (_customerSettings.CustomerNumberMethod == CustomerNumberMethod.AutomaticallySet) + customerNumber = row.Entity.Id.ToString(); + else + customerNumber = row.GetDataValue("CustomerNumber"); + + if (customerNumber.IsEmpty() || !allCustomerNumbers.Contains(customerNumber)) + { + SaveAttribute(row, SystemCustomerAttributeNames.CustomerNumber, customerNumber); + + if (!customerNumber.IsEmpty()) + allCustomerNumbers.Add(customerNumber); + } + } + + return _services.DbContext.SaveChanges(); + } + + protected virtual int ProcessAvatars( + ImportExecuteContext context, + IEnumerable> batch) + { + foreach (var row in batch) + { + var urlOrPath = row.GetDataValue("AvatarPictureUrl"); + if (urlOrPath.IsEmpty()) + continue; + + Picture picture = null; + var equalPictureId = 0; + var currentPictures = new List(); + var seoName = _pictureService.GetPictureSeName(row.EntityDisplayName); + + var image = CreateDownloadImage(urlOrPath, seoName, 1); + if (image == null) + continue; + + if (image.Url.HasValue() && !image.Success.HasValue) + { + AsyncRunner.RunSync(() => _fileDownloadManager.DownloadAsync(DownloaderContext, new FileDownloadManagerItem[] { image })); + } + + if ((image.Success ?? false) && File.Exists(image.Path)) + { + Succeeded(image); + var pictureBinary = File.ReadAllBytes(image.Path); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + var currentPictureId = row.Entity.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId); + if (currentPictureId != 0 && (picture = _pictureRepository.GetById(currentPictureId)) != null) + { + currentPictures.Add(picture); + } + + pictureBinary = _pictureService.ValidatePicture(pictureBinary); + pictureBinary = _pictureService.FindEqualPicture(pictureBinary, currentPictures, out equalPictureId); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + if ((picture = _pictureService.InsertPicture(pictureBinary, image.MimeType, seoName, true, false, false)) != null) + { + _pictureRepository.Context.SaveChanges(); + SaveAttribute(row, SystemCustomerAttributeNames.AvatarPictureId, picture.Id); + } + } + else + { + context.Result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "AvatarPictureUrl"); + } + } + } + else + { + context.Result.AddInfo("Download of an image failed.", row.GetRowInfo(), "AvatarPictureUrl"); + } + } + + return _services.DbContext.SaveChanges(); + } + + public static string[] SupportedKeyFields + { + get + { + return new string[] { "Id", "CustomerGuid", "Email", "Username" }; + } + } + + public static string[] DefaultKeyFields + { + get + { + return new string[] { "Email" }; + } + } + + private int? CountryCodeToId(Dictionary allCountries, string code) + { + int countryId; + if (code.HasValue() && allCountries.TryGetValue(code, out countryId) && countryId != 0) + { + return countryId; + } + + return null; + } + + private int? StateAbbreviationToId(Dictionary, int> allStateProvinces, int? countryId, string abbreviation) + { + if (countryId.HasValue && abbreviation.HasValue()) + { + var key = Tuple.Create(countryId.Value, abbreviation); + + int stateId; + if (allStateProvinces.TryGetValue(key, out stateId) && stateId != 0) + { + return stateId; + } + } + + return null; + } + + private void SaveAttribute(ImportRow row, string key) + { + SaveAttribute(row, key, row.GetDataValue(key)); + } + + private void SaveAttribute(ImportRow row, string key) + { + + SaveAttribute(row, key, row.GetDataValue(key)); + } + + private void SaveAttribute(ImportRow row, string key, TPropType value) + { + if (row.IsTransient) + return; + + if (row.IsNew || value != null) + { + _genericAttributeService.SaveAttribute(row.Entity.Id, key, _attributeKeyGroup, value); + } + } + + private void UpsertRole(ImportRow row, CustomerRole role, bool value) + { + if (role == null) + return; + + var hasRole = row.Entity.CustomerRoles.Any(x => x.SystemName == role.SystemName); + + if (value && !hasRole) + { + row.Entity.CustomerRoles.Add(role); + } + else if (!value && hasRole) + { + row.Entity.CustomerRoles.Remove(role); + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvConfiguration.cs b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvConfiguration.cs new file mode 100644 index 0000000000..1680cf2d55 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvConfiguration.cs @@ -0,0 +1,296 @@ +using System; +using System.Linq; +using Newtonsoft.Json; + +namespace SmartStore.Services.DataExchange.Csv +{ + /// + /// Specifies the action to take when a parsing error has occured. + /// + public enum ParseErrorAction + { + /// + /// Raises the event. + /// + RaiseEvent = 0, + + /// + /// Tries to advance to next line. + /// + AdvanceToNextLine = 1, + + /// + /// Throws an exception. + /// + ThrowException = 2, + } + + /// + /// Specifies the action to take when a field is missing. + /// + public enum MissingFieldAction + { + /// + /// Treat as a parsing error. + /// + ParseError = 0, + + /// + /// Replaces by an empty value. + /// + ReplaceByEmpty = 1, + + /// + /// Replaces by a null value (). + /// + ReplaceByNull = 2, + } + + public class CsvConfiguration + { + private char _delimiter; + private char _escape; + private char _quote; + private string _quoteString; + private char[] _quotableChars; + + public CsvConfiguration() + { + _escape = '"'; + _delimiter = ';'; + _quote = '"'; + _quoteString = new String(new char[] { _escape, _quote }); + + Comment = '#'; + HasHeaders = true; + SkipEmptyLines = true; + SupportsMultiline = true; + DefaultHeaderName = "Column"; + + BuildQuotableChars(); + } + + private void BuildQuotableChars() + { + _quotableChars = new char[] { '\r', '\n', _delimiter, _quote }; + } + + internal char[] QuotableChars + { + get { return _quotableChars; } + } + + /// + /// Gets an Excel friendly configuration where the result can be directly edited by Excel + /// + public static CsvConfiguration ExcelFriendlyConfiguration + { + get + { + return new CsvConfiguration + { + Delimiter = ';', + Quote = '"', + Escape = '"', + SupportsMultiline = false + }; + } + } + + /// + /// Gets an array with preset characters + /// + public static char[] PresetCharacters + { + get { return new char[] { '\n', '\r', '\0' }; } + } + + /// + /// Gets the comment character indicating that a line is commented out (default: #). + /// + /// The comment character indicating that a line is commented out. + public char Comment + { + get; + set; + } + + /// + /// Gets the escape character letting insert quotation characters inside a quoted field (default: "). + /// + /// The escape character letting insert quotation characters inside a quoted field. + public char Escape + { + get { return _escape; } + set + { + if (value == _escape) + return; + + if (PresetCharacters.Contains(value)) + { + throw new SmartException("'{0}' is not a valid escape char.".FormatInvariant(value)); + } + if (value == _delimiter) + { + throw new SmartException("Escape and delimiter chars cannot be equal in CSV files."); + } + + _escape = value; + _quoteString = new String(new char[] { _escape, _quote }); + } + } + + /// + /// Gets the delimiter character separating each field (default: ;). + /// + /// The delimiter character separating each field. + public char Delimiter + { + get { return _delimiter; } + set + { + if (value == _delimiter) + return; + + if (PresetCharacters.Contains(value)) + { + throw new SmartException("'{0}' is not a valid delimiter char.".FormatInvariant(value)); + } + if (value == _quote) + { + throw new SmartException("Quote and delimiter chars cannot be equal in CSV files."); + } + + _delimiter = value; + BuildQuotableChars(); + + } + } + + /// + /// Gets the quotation character wrapping every field (default: "). + /// + /// The quotation character wrapping every field. + public char Quote + { + get { return _quote; } + set + { + if (value == _quote) + return; + + if (PresetCharacters.Contains(value)) + { + throw new SmartException("'{0}' is not a valid quote char.".FormatInvariant(value)); + } + if (value == _delimiter) + { + throw new SmartException("Quote and delimiter chars cannot be equal in CSV files."); + } + + _quote = value; + _quoteString = new String(new char[] { _escape, _quote }); + BuildQuotableChars(); + } + } + + /// + /// Gets the concatenation of escape and quote char + /// + [JsonIgnore] + public string QuoteString + { + get + { + return _quoteString; + } + } + + public bool QuoteAllFields + { + get; + set; + } + + /// + /// Indicates if field names are located on the first non commented line (default: true). + /// + /// if field names are located on the first non commented line, otherwise, . + public bool HasHeaders + { + get; + set; + } + + /// + /// Indicates if spaces at the start and end of a field are trimmed (default: false). + /// + /// if spaces at the start and end of a field are trimmed, otherwise, . + public bool TrimValues + { + get; + set; + } + + /// + /// Contains the value which denotes a DbNull-value. + /// + public string NullValue + { + get; + set; + } + + /// + /// Gets or sets the default action to take when a parsing error has occured. + /// + /// The default action to take when a parsing error has occured. + public ParseErrorAction DefaultParseErrorAction + { + get; + set; + } + + /// + /// Gets or sets the action to take when a field is missing. + /// + /// The action to take when a field is missing. + public MissingFieldAction MissingFieldAction + { + get; + set; + } + + /// + /// Gets or sets a value indicating if the reader supports multiline fields (default: true). + /// + /// A value indicating if the reader supports multiline field. + public bool SupportsMultiline + { + get; + set; + } + + /// + /// Gets or sets a value indicating if the reader will skip empty lines (default: true). + /// + /// A value indicating if the reader will skip empty lines. + public bool SkipEmptyLines + { + get; + set; + } + + /// + /// Gets or sets the default header name when it is an empty string or only whitespaces (default: Column). + /// The header index will be appended to the specified name. + /// + /// The default header name when it is an empty string or only whitespaces. + public string DefaultHeaderName + { + get; + set; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvConfigurationConverter.cs b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvConfigurationConverter.cs new file mode 100644 index 0000000000..4a81792a19 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvConfigurationConverter.cs @@ -0,0 +1,65 @@ +using System; +using System.Globalization; +using Newtonsoft.Json; +using SmartStore.ComponentModel; + +namespace SmartStore.Services.DataExchange.Csv +{ + public class CsvConfigurationConverter : TypeConverterBase + { + public CsvConfigurationConverter() + : base(typeof(object)) + { + } + + public override bool CanConvertFrom(Type type) + { + return type == typeof(string); + } + + public override bool CanConvertTo(Type type) + { + return type == typeof(string); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value is string) + { + return JsonConvert.DeserializeObject((string)value); + } + + return base.ConvertFrom(culture, value); + } + + public T ConvertFrom(string value) + { + if (value.HasValue()) + return (T)ConvertFrom(CultureInfo.InvariantCulture, value); + + return default(T); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + if (to == typeof(string)) + { + if (value is CsvConfiguration) + { + return JsonConvert.SerializeObject(value); + } + else + { + return string.Empty; + } + } + + return base.ConvertTo(culture, format, value, to); + } + + public string ConvertTo(object value) + { + return (string)ConvertTo(CultureInfo.InvariantCulture, null, value, typeof(string)); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvDataReader.cs b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvDataReader.cs new file mode 100644 index 0000000000..9fbe870a2b --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvDataReader.cs @@ -0,0 +1,389 @@ +// Wrapper for LumenWorks CsvReader (fork by phatcher) +// ---------------------------------------------------- +// LumenWorks.Framework.IO.CsvReader +// Copyright (c) 2006 Sébastien Lorion +// https://github.com/phatcher/CsvReader/ +// +// MIT license (http://en.wikipedia.org/wiki/MIT_License) + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LumenWorks.Framework.IO.Csv; + +namespace SmartStore.Services.DataExchange.Csv +{ + /// + /// Represents a reader that provides fast, non-cached, forward-only access to CSV data. + /// + public class CsvDataReader : DisposableObject, IDataReader, IEnumerable + { + private readonly CsvReader _csv; + private readonly IDataReader _reader; + + /// + /// Initializes a new instance of the CsvDataReader class. + /// + /// A pointing to the CSV file. + public CsvDataReader(TextReader reader) + : this(reader, new CsvConfiguration()) + { + } + + /// + /// Initializes a new instance of the CsvDataReader class. + /// + /// A pointing to the CSV file. + public CsvDataReader(TextReader reader, CsvConfiguration configuration) + { + Guard.ArgumentNotNull(() => reader); + Guard.ArgumentNotNull(() => configuration); + + this.Configuration = configuration; + + _csv = new CsvReader( + reader, + configuration.HasHeaders, + configuration.Delimiter, + configuration.Quote, + configuration.Escape, + configuration.Comment, + configuration.TrimValues ? ValueTrimmingOptions.All : ValueTrimmingOptions.None, + configuration.NullValue); + + _csv.SupportsMultiline = configuration.SupportsMultiline; + _csv.SkipEmptyLines = configuration.SkipEmptyLines; + _csv.DefaultHeaderName = configuration.DefaultHeaderName; + _csv.DefaultParseErrorAction = (LumenWorks.Framework.IO.Csv.ParseErrorAction)((int)configuration.DefaultParseErrorAction); + _csv.MissingFieldAction = (LumenWorks.Framework.IO.Csv.MissingFieldAction)((int)configuration.MissingFieldAction); + + _reader = _csv; + } + + public CsvConfiguration Configuration + { + get; + private set; + } + + #region Public wrapper members + + /// + /// Gets the field headers. + /// + /// The field headers or an empty array if headers are not supported. + /// + /// The instance has been disposed of. + /// + public string[] GetFieldHeaders() + { + return _csv.GetFieldHeaders(); + } + + public bool EndOfStream + { + get + { + return _csv.EndOfStream; + } + } + + /// + /// Gets the current row index in the CSV file (0-based). + /// + /// The current row index in the CSV file. + public long CurrentRowIndex + { + get + { + return _csv.CurrentRecordIndex; + } + } + + public void CopyCurrentRowTo(string[] array) + { + _csv.CopyCurrentRecordTo(array); + } + + /// + /// Gets the current row's raw CSV data. + /// + /// The current raw CSV data. + public string GetRawData() + { + return _csv.GetCurrentRawData(); + } + + /// + /// Gets the field with the specified name. must be . + /// + /// + /// The field with the specified name. + /// + /// + /// is or an empty string. + /// + /// + /// The CSV does not have headers ( property is ). + /// + /// + /// not found. + /// + /// + /// The CSV appears to be corrupt at the current position. + /// + /// + /// The instance has been disposed of. + /// + public string this[string field] + { + get + { + return _csv[field]; + } + } + + /// + /// Gets the field at the specified index. + /// + /// The field at the specified index. + /// + /// must be included in [0, [. + /// + /// + /// No record read yet. Call ReadLine() first. + /// + /// + /// The CSV appears to be corrupt at the current position. + /// + /// + /// The instance has been disposed of. + /// + public virtual string this[int index] + { + get + { + return _csv[index]; + } + } + + #endregion + + #region IDataReader (implicit) + + public int FieldCount + { + get + { + return _reader.FieldCount; + } + } + + public bool Read() + { + return _csv.ReadNextRecord(); + } + + public int GetOrdinal(string name) + { + return _reader.GetOrdinal(name); + } + + #endregion + + #region IDataReader (explicit) + + object IDataRecord.this[string name] + { + get + { + return _reader[name]; + } + } + + object IDataRecord.this[int i] + { + get + { + return _reader[i]; + } + } + + int IDataReader.Depth + { + get + { + return _reader.Depth; + } + } + + bool IDataReader.IsClosed + { + get + { + return _reader.IsClosed; + } + } + + int IDataReader.RecordsAffected + { + get + { + return _reader.RecordsAffected; + } + } + + void IDataReader.Close() + { + _reader.Close(); + } + + bool IDataRecord.GetBoolean(int i) + { + return _reader.GetBoolean(i); + } + + byte IDataRecord.GetByte(int i) + { + return _reader.GetByte(i); + } + + long IDataRecord.GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) + { + return _reader.GetBytes(i, fieldOffset, buffer, bufferoffset, length); + } + + char IDataRecord.GetChar(int i) + { + return _reader.GetChar(i); + } + + long IDataRecord.GetChars(int i, long fieldOffset, char[] buffer, int bufferoffset, int length) + { + return _reader.GetChars(i, fieldOffset, buffer, bufferoffset, length); + } + + IDataReader IDataRecord.GetData(int i) + { + return _reader.GetData(i); + } + + string IDataRecord.GetDataTypeName(int i) + { + return _reader.GetDataTypeName(i); + } + + DateTime IDataRecord.GetDateTime(int i) + { + return _reader.GetDateTime(i); + } + + decimal IDataRecord.GetDecimal(int i) + { + return _reader.GetDecimal(i); + } + + double IDataRecord.GetDouble(int i) + { + return _reader.GetDouble(i); + } + + Type IDataRecord.GetFieldType(int i) + { + return _reader.GetFieldType(i); + } + + float IDataRecord.GetFloat(int i) + { + return _reader.GetFloat(i); + } + + Guid IDataRecord.GetGuid(int i) + { + return _reader.GetGuid(i); + } + + short IDataRecord.GetInt16(int i) + { + return _reader.GetInt16(i); + } + + int IDataRecord.GetInt32(int i) + { + return _reader.GetInt32(i); + } + + long IDataRecord.GetInt64(int i) + { + return _reader.GetInt64(i); + } + + string IDataRecord.GetName(int i) + { + return _reader.GetName(i); + } + + DataTable IDataReader.GetSchemaTable() + { + return _reader.GetSchemaTable(); + } + + string IDataRecord.GetString(int i) + { + return _reader.GetString(i); + } + + object IDataRecord.GetValue(int i) + { + return _reader.GetGuid(i); + } + + int IDataRecord.GetValues(object[] values) + { + return _reader.GetValues(values); + } + + bool IDataRecord.IsDBNull(int i) + { + return _reader.IsDBNull(i); + } + + bool IDataReader.NextResult() + { + return _reader.NextResult(); + } + + #endregion + + #region IEnumerable + + IEnumerator IEnumerable.GetEnumerator() + { + return _csv.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _csv.GetEnumerator(); + } + + #endregion + + #region Disposable + + protected override void OnDispose(bool disposing) + { + if (disposing) + { + _csv.Dispose(); + } + } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvWriter.cs b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvWriter.cs new file mode 100644 index 0000000000..8bb9942052 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Csv/CsvWriter.cs @@ -0,0 +1,194 @@ +// Customized version of CsvHelper from Josh Close: +// ------------------------------------------------ +// Copyright 2009-2015 Josh Close and Contributors +// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. +// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. +// http://csvhelper.com + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SmartStore.Services.DataExchange.Csv +{ + /// + /// SImple utility class used to write CSV files. + /// + public class CsvWriter : DisposableObject + { + private TextWriter _writer; + private readonly IList _currentRow = new List(); + private int? _fieldCount; + + public CsvWriter(TextWriter writer) + : this(writer, new CsvConfiguration()) + { + } + + public CsvWriter(TextWriter writer, CsvConfiguration configuration) + { + Guard.ArgumentNotNull(() => writer); + Guard.ArgumentNotNull(() => configuration); + + _writer = writer; + this.Configuration = configuration; + } + + public CsvConfiguration Configuration + { + get; + private set; + } + + /// + /// Writes a sequence of fields to the CSV file. The fields + /// may get quotes added to it. + /// When all fields are written for a row, + /// must be called + /// to complete writing of the current row. + /// + /// The fields to write. + public virtual void WriteFields(IEnumerable fields) + { + Guard.ArgumentNotNull(() => fields); + fields.Each(x => WriteField(x)); + } + + /// + /// Writes a sequence of fields to the CSV file. This will + /// ignore any need to quote and ignore the + /// + /// and just quote based on the shouldQuote + /// parameter. + /// When all fields are written for a row, + /// must be called + /// to complete writing of the current row. + /// + /// The fields to write. + /// True to quote the fields, otherwise false. + public virtual void WriteFields(IEnumerable fields, bool shouldQuote) + { + Guard.ArgumentNotNull(() => fields); + fields.Each(x => WriteField(x, shouldQuote)); + } + + /// + /// Writes the field to the CSV file. The field + /// may get quotes added to it. + /// When all fields are written for a row, + /// must be called + /// to complete writing of the current row. + /// + /// The field to write. + public virtual void WriteField(string field) + { + var shouldQuote = Configuration.QuoteAllFields; + + if (!string.IsNullOrEmpty(field)) + { + if (Configuration.TrimValues) + { + field = field.Trim(); + } + + if (!Configuration.SupportsMultiline) + { + field = field.Replace('\r', ' ').Replace('\n', ' '); + } + + if (shouldQuote + || field[0] == ' ' + || field[field.Length - 1] == ' ' + || field.IndexOfAny(Configuration.QuotableChars) > -1) + { + shouldQuote = true; + } + } + + WriteField(field, shouldQuote); + } + + /// + /// Writes the field to the CSV file. This will + /// ignore any need to quote and ignore the + /// + /// and just quote based on the shouldQuote + /// parameter. + /// When all fields are written for a row, + /// must be called + /// to complete writing of the current row. + /// + /// The field to write. + /// True to quote the field, otherwise false. + public virtual void WriteField(string field, bool shouldQuote) + { + // All quotes must be escaped. + if (shouldQuote && !string.IsNullOrEmpty(field)) + { + field = field.Replace(Configuration.Quote.ToString(), Configuration.QuoteString); + } + + if (shouldQuote) + { + field = Configuration.Quote + (field ?? string.Empty) + Configuration.Quote; + } + + _currentRow.Add(field ?? string.Empty); + } + + /// + /// Ends writing of the current row + /// and starts a new row. + /// + public virtual void NextRow() + { + WriteRow(_currentRow.ToArray()); + _currentRow.Clear(); + } + + public string CurrentRawValue() + { + var row = string.Join(Configuration.Delimiter.ToString(), _currentRow); + return row; + } + + private void WriteRow(string[] fields) + { + CheckDisposed(); + + if (fields.Length == 0) + { + throw new SmartException("Cannot write an empty row to the CSV file."); + } + + if (!_fieldCount.HasValue) + { + _fieldCount = fields.Length; + } + + if (_fieldCount.Value != fields.Length) + { + throw new SmartException("The field count of the current row does not match the previous row's field count."); + } + + var row = string.Join(Configuration.Delimiter.ToString(), fields); + _writer.WriteLine(row); + } + + protected override void OnDispose(bool disposing) + { + if (disposing) + { + if (_writer != null) + { + _writer.Dispose(); + _writer = null; + } + } + } + + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Excel/ExcelDataReader.cs b/src/Libraries/SmartStore.Services/DataExchange/Excel/ExcelDataReader.cs new file mode 100644 index 0000000000..d46879193c --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Excel/ExcelDataReader.cs @@ -0,0 +1,612 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using OfficeOpenXml; + +namespace SmartStore.Services.DataExchange.Excel +{ + public class ExcelDataReader : DisposableObject, IDataReader + { + private ExcelPackage _package; + private ExcelWorksheet _sheet; + private int _totalRows; + private int _totalColumns; + + private bool _initialized; + private string[] _columns; + private Dictionary _columnIndexes; + private int _currentRowIndex; + private bool _eof; + + private readonly object _lock = new object(); + + public ExcelDataReader(Stream source, bool hasHeaders) + { + Guard.ArgumentNotNull(() => source); + + _package = new ExcelPackage(source); + + // get the first worksheet in the workbook + _sheet = _package.Workbook.Worksheets.FirstOrDefault(); + if (_sheet == null) + { + throw Error.InvalidOperation("The excel package does not contain any worksheet."); + } + + if (_sheet.Dimension == null) + { + throw Error.InvalidOperation("The excel worksheet does not contain any data."); + } + + HasHeaders = hasHeaders; + DefaultHeaderName = "Column"; + + _totalColumns = _sheet.Dimension.End.Column; + _totalRows = _sheet.Dimension.End.Row - (hasHeaders ? 1 : 0); + + _currentRowIndex = -1; + } + + #region Configuration + + public bool HasHeaders + { + get; + private set; + } + + public string DefaultHeaderName + { + get; + set; + } + + #endregion + + #region public members + + public bool MoveToStart() + { + return MoveTo(0); + } + + public bool MoveToEnd() + { + return MoveTo(_totalRows - 1); + } + + public bool MoveTo(int row) + { + EnsureInitialize(); + ValidateDataReader(validateInitialized: false); + + if (row < 0 || row >= _totalRows) + return false; + + _currentRowIndex = row; + _eof = false; + + return true; + } + + public bool EndOfStream + { + get { return _eof; } + } + + public int TotalRows + { + get + { + EnsureInitialize(); + return _totalRows; + } + } + + public IReadOnlyCollection GetColumnHeaders() + { + EnsureInitialize(); + return _columns.AsReadOnly(); + } + + public int CurrentRowIndex + { + get + { + return _currentRowIndex; + } + } + + public string GetFormatted(int i) + { + ValidateDataReader(); + return _sheet.Cells[ExcelRowIndex(_currentRowIndex), i + 1].Text; + } + + public int GetColumnIndex(string name) + { + Guard.ArgumentNotEmpty(name, "name"); + + EnsureInitialize(); + + int index; + + if (_columnIndexes != null && _columnIndexes.TryGetValue(name, out index)) + return index; + else + return -1; + } + + #endregion + + #region IDataReader + + bool IDataReader.NextResult() + { + ValidateDataReader(validateInitialized: false); + return false; + } + + public bool Read() + { + ValidateDataReader(validateInitialized: false); + return ReadNextRow(false); + } + + int IDataReader.Depth + { + get + { + ValidateDataReader(validateInitialized: false); + return 0; + } + } + + bool IDataReader.IsClosed + { + get + { + return _eof; + } + } + + int IDataReader.RecordsAffected + { + get + { + return -1; + } + } + + void IDataReader.Close() + { + Dispose(); + } + + + public int FieldCount + { + get + { + EnsureInitialize(); + return _totalColumns; + } + } + + public object this[string name] + { + get + { + int index = GetColumnIndex(name); + + if (index < 0) + Error.Argument("name", "'{0}' column header not found.".FormatInvariant(name)); + + return this[index]; + } + } + + public object this[int i] + { + get + { + ValidateDataReader(); + // Excel indexes start from 1 + return _sheet.GetValue(ExcelRowIndex(_currentRowIndex), i + 1); + } + } + + public bool GetBoolean(int i) + { + object value = this[i]; + + int result; + if (Int32.TryParse(value.ToString(), out result)) + return (result != 0); + else + return Boolean.Parse(value.ToString()); + } + + public byte GetByte(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) + { + ValidateDataReader(); + return CopyFieldToArray(i, fieldOffset, buffer, bufferoffset, length); + } + + public char GetChar(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public long GetChars(int i, long fieldOffset, char[] buffer, int bufferoffset, int length) + { + ValidateDataReader(); + return CopyFieldToArray(i, fieldOffset, buffer, bufferoffset, length); + } + + IDataReader IDataRecord.GetData(int i) + { + ValidateDataReader(); + + if (i == 0) + return this; + else + return null; + } + + string IDataRecord.GetDataTypeName(int i) + { + return this[i].GetType().FullName; + } + + public DateTime GetDateTime(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public decimal GetDecimal(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public double GetDouble(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public Type GetFieldType(int i) + { + return this[i].GetType(); + } + + public float GetFloat(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public Guid GetGuid(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public short GetInt16(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public int GetInt32(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public long GetInt64(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public string GetName(int i) + { + EnsureInitialize(); + ValidateDataReader(validateInitialized: false); + + if (i < 0 || i >= _columns.Length) + { + throw new ArgumentOutOfRangeException("i", i, + "Column index must be included within [0, {0}], but specified column index was: '{1}'.".FormatInvariant(_columns.Length, i)); + } + + return _columns[i]; + } + + public int GetOrdinal(string name) + { + return GetColumnIndex(name); + } + + DataTable IDataReader.GetSchemaTable() + { + EnsureInitialize(); + ValidateDataReader(validateInitialized: false); + + var schema = new DataTable("SchemaTable") + { + Locale = CultureInfo.InvariantCulture, + MinimumCapacity = _columns.Length + }; + + schema.Columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.BaseColumnName, typeof(string)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.BaseTableName, typeof(string)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.ColumnName, typeof(string)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.ColumnSize, typeof(int)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.DataType, typeof(object)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.IsAliased, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.IsExpression, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.IsKey, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.IsLong, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.IsUnique, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.NumericPrecision, typeof(short)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.NumericScale, typeof(short)).ReadOnly = true; + schema.Columns.Add(SchemaTableColumn.ProviderType, typeof(int)).ReadOnly = true; + + schema.Columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string)).ReadOnly = true; + schema.Columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string)).ReadOnly = true; + schema.Columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool)).ReadOnly = true; + schema.Columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool)).ReadOnly = true; + + // null marks columns that will change for each row + object[] schemaRow = + { + true, // 00- AllowDBNull + null, // 01- BaseColumnName + string.Empty, // 02- BaseSchemaName + string.Empty, // 03- BaseTableName + null, // 04- ColumnName + null, // 05- ColumnOrdinal + int.MaxValue, // 06- ColumnSize + typeof(string), // 07- DataType + false, // 08- IsAliased + false, // 09- IsExpression + false, // 10- IsKey + false, // 11- IsLong + false, // 12- IsUnique + DBNull.Value, // 13- NumericPrecision + DBNull.Value, // 14- NumericScale + (int) DbType.String, // 15- ProviderType + string.Empty, // 16- BaseCatalogName + string.Empty, // 17- BaseServerName + false, // 18- IsAutoIncrement + false, // 19- IsHidden + true, // 20- IsReadOnly + false // 21- IsRowVersion + }; + + int r = ExcelRowIndex(0); + + for (int i = 0; i < _columns.Length; i++) + { + schemaRow[1] = _columns[i]; // Base column name + schemaRow[4] = _columns[i]; // Column name + schemaRow[5] = i; // Column ordinal + + // get data type from 1st row only + var firstValue = _sheet.Cells[r, i + 1].Value; + schemaRow[7] = firstValue != null ? firstValue.GetType() : typeof(string); + + schema.Rows.Add(schemaRow); + } + + return schema; + } + + public string GetString(int i) + { + return this[i].Convert(CultureInfo.CurrentCulture); + } + + public object GetValue(int i) + { + ValidateDataReader(); + return ((IDataRecord)this).IsDBNull(i) ? DBNull.Value : this[i]; + } + + int IDataRecord.GetValues(object[] values) + { + var record = (IDataRecord)this; + + for (int i = 0; i < _totalColumns; i++) + { + values[i] = record.GetValue(i); + } + + return _totalColumns; + } + + bool IDataRecord.IsDBNull(int i) + { + return this[i] == null; + } + + #endregion + + #region Helper + + /// + /// Reads the next record. + /// + /// + /// Indicates if the reader will proceed to the next record after having read headers. + /// if it stops after having read headers; otherwise, . + /// + /// if a record has been successfully reads; otherwise, . + /// + /// The instance has been disposed of. + /// + protected virtual bool ReadNextRow(bool onlyReadHeaders) + { + if (_eof) + return false; + + CheckDisposed(); + + if (!_initialized) + { + _columns = new string[_totalColumns]; + _columnIndexes = new Dictionary(_totalColumns, StringComparer.OrdinalIgnoreCase); + + for (int i = 1; i <= _totalColumns; i++) + { + // Excel indexes start from 1 + string name = null; + if (HasHeaders) + { + name = _sheet.GetValue(1, i).NullEmpty(); + } + + name = name ?? (DefaultHeaderName ?? "Column") + i; + + _columns[i - 1] = name; + _columnIndexes[name] = i - 1; + } + + if (_columns.Select(x => x.ToLower()).Distinct().ToArray().Length != _columns.Length) + { + _columns = null; + _columnIndexes = null; + throw Error.InvalidOperation("The first row cannot contain duplicate column names."); + } + + _initialized = true; + + if (!onlyReadHeaders) + { + return ReadNextRow(false); + } + } + else + { + _currentRowIndex++; + if (_currentRowIndex >= _totalRows) + { + _eof = true; + return false; + } + } + + return true; + } + + private int ExcelRowIndex(int i) + { + // Excel indexes start from 1 + return i + (HasHeaders ? 2 : 1); + } + + /// + /// Ensures that the reader is initialized. + /// + private void EnsureInitialize() + { + if (!_initialized) + { + ReadNextRow(true); + } + + Debug.Assert(_columns != null); + Debug.Assert(_columns.Length > 0 || (_columns.Length == 0 && _columnIndexes == null)); + } + + private void ValidateDataReader(bool validateInitialized = true, bool validateNotClosed = true) + { + if (validateInitialized && (!_initialized || _currentRowIndex < 0)) + throw new InvalidOperationException("No current record. Call Read() to initialize the reader."); + + if (validateNotClosed && IsDisposed) + throw new InvalidOperationException("This operation is invalid when the reader is closed."); + } + + private long CopyFieldToArray(int column, long columnOffset, Array destinationArray, int destinationOffset, int length) + { + EnsureInitialize(); + + if (column < 0 || column >= _totalColumns) + { + throw new ArgumentOutOfRangeException("column", column, + "Column index must be included within [0, {0}], but specified column index was: '{1}'.".FormatInvariant(_totalColumns, column)); + } + + if (columnOffset < 0 || columnOffset >= int.MaxValue) + throw new ArgumentOutOfRangeException("fieldOffset"); + + // Array.Copy(...) will do the remaining argument checks + + if (length == 0) + return 0; + + string value = this[column].ToString(); + + if (value == null) + value = string.Empty; + + if (destinationArray.GetType() == typeof(char[])) + Array.Copy(value.ToCharArray((int)columnOffset, length), 0, destinationArray, destinationOffset, length); + else + { + char[] chars = value.ToCharArray((int)columnOffset, length); + byte[] source = new byte[chars.Length]; + ; + + for (int i = 0; i < chars.Length; i++) + source[i] = Convert.ToByte(chars[i]); + + Array.Copy(source, 0, destinationArray, destinationOffset, length); + } + + return length; + } + + #endregion + + #region IDisposable Support + + protected override void OnDispose(bool disposing) + { + if (disposing) + { + try + { + _sheet = null; + if (_package != null) + { + lock (_lock) + { + if (_package != null) + { + _package.Dispose(); + _package = null; + _eof = true; + } + } + } + } + catch { } + } + } + + #endregion + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/DataExportResult.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/DataExportResult.cs new file mode 100644 index 0000000000..c9d3fa26f2 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/DataExportResult.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace SmartStore.Services.DataExchange.Export +{ + [Serializable] + public class DataExportResult + { + public DataExportResult() + { + Files = new List(); + } + + /// + /// Whether the export succeeded + /// + public bool Succeeded + { + get { return LastError.IsEmpty(); } + } + + /// + /// Last error + /// + [XmlIgnore] + public string LastError { get; set; } + + /// + /// Files created by last export + /// + public List Files { get; set; } + + /// + /// The path of the folder with the export files + /// + [XmlIgnore] + public string FileFolder { get; set; } + + [Serializable] + public class ExportFileInfo + { + /// + /// Store identifier, can be 0. + /// + public int StoreId { get; set; } + + /// + /// Name of file + /// + public string FileName { get; set; } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/DataExportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/DataExportTask.cs new file mode 100644 index 0000000000..f32f06c625 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/DataExportTask.cs @@ -0,0 +1,53 @@ +using System.Linq; +using SmartStore.Core.Localization; +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.DataExchange.Export +{ + // note: namespace persisted in ScheduleTask.Type + public partial class DataExportTask : ITask + { + private readonly IDataExporter _exporter; + private readonly IExportProfileService _exportProfileService; + + public DataExportTask( + IDataExporter exporter, + IExportProfileService exportProfileService) + { + _exporter = exporter; + _exportProfileService = exportProfileService; + } + + public Localizer T { get; set; } + + public void Execute(TaskExecutionContext ctx) + { + var profileId = ctx.ScheduleTask.Alias.ToInt(); + var profile = _exportProfileService.GetExportProfileById(profileId); + + // load provider + var provider = _exportProfileService.LoadProvider(profile.ProviderSystemName); + if (provider == null) + throw new SmartException(T("Admin.Common.ProviderNotLoaded", profile.ProviderSystemName.NaIfEmpty())); + + // build export request + var request = new DataExportRequest(profile, provider); + + request.ProgressValueSetter = delegate (int val, int max, string msg) + { + ctx.SetProgress(val, max, msg, true); + }; + + if (ctx.Parameters.ContainsKey("SelectedIds")) + { + request.EntitiesToExport = ctx.Parameters["SelectedIds"] + .SplitSafe(",") + .Select(x => x.ToInt()) + .ToList(); + } + + // process! + _exporter.Export(request, ctx.CancellationToken); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/DataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/DataExporter.cs new file mode 100644 index 0000000000..e6b182c270 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/DataExporter.cs @@ -0,0 +1,1440 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading; +using System.Web; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Email; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Services.Catalog; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; +using SmartStore.Services.DataExchange.Export.Deployment; +using SmartStore.Services.DataExchange.Export.Internal; +using SmartStore.Services.Directory; +using SmartStore.Services.Helpers; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; +using SmartStore.Services.Messages; +using SmartStore.Services.Orders; +using SmartStore.Services.Security; +using SmartStore.Services.Seo; +using SmartStore.Services.Shipping; +using SmartStore.Services.Tax; +using SmartStore.Utilities; +using SmartStore.Utilities.Threading; + +namespace SmartStore.Services.DataExchange.Export +{ + public partial class DataExporter : IDataExporter + { + private static readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); + + #region Dependencies + + private readonly ICommonServices _services; + private readonly IDbContext _dbContext; + private readonly Lazy _priceFormatter; + private readonly Lazy _dateTimeHelper; + private readonly Lazy _exportProfileService; + private readonly Lazy _localizedEntityService; + private readonly Lazy _languageService; + private readonly Lazy _urlRecordService; + private readonly Lazy _pictureService; + private readonly Lazy _priceCalculationService; + private readonly Lazy _currencyService; + private readonly Lazy _taxService; + private readonly Lazy _categoryService; + private readonly Lazy _productAttributeParser; + private readonly Lazy _productAttributeService; + private readonly Lazy _productTemplateService; + private readonly Lazy _categoryTemplateService; + private readonly Lazy _productService; + private readonly Lazy _orderService; + private readonly Lazy _manufacturerService; + private readonly ICustomerService _customerService; + private readonly Lazy _addressService; + private readonly Lazy _countryService; + private readonly Lazy _shipmentService; + private readonly Lazy _genericAttributeService; + private readonly Lazy _emailAccountService; + private readonly Lazy _queuedEmailService; + private readonly Lazy _emailSender; + private readonly Lazy _deliveryTimeService; + private readonly Lazy _quantityUnitService; + + private readonly Lazy>_customerRepository; + private readonly Lazy> _subscriptionRepository; + private readonly Lazy> _orderRepository; + + private readonly Lazy _mediaSettings; + private readonly Lazy _contactDataSettings; + private readonly Lazy _customerSettings; + private readonly Lazy _catalogSettings; + + public DataExporter( + ICommonServices services, + IDbContext dbContext, + Lazy priceFormatter, + Lazy dateTimeHelper, + Lazy exportProfileService, + Lazy localizedEntityService, + Lazy languageService, + Lazy urlRecordService, + Lazy pictureService, + Lazy priceCalculationService, + Lazy currencyService, + Lazy taxService, + Lazy categoryService, + Lazy productAttributeParser, + Lazy productAttributeService, + Lazy productTemplateService, + Lazy categoryTemplateService, + Lazy productService, + Lazy orderService, + Lazy manufacturerService, + ICustomerService customerService, + Lazy addressService, + Lazy countryService, + Lazy shipmentService, + Lazy genericAttributeService, + Lazy emailAccountService, + Lazy queuedEmailService, + Lazy emailSender, + Lazy deliveryTimeService, + Lazy quantityUnitService, + Lazy> customerRepository, + Lazy> subscriptionRepository, + Lazy> orderRepository, + Lazy mediaSettings, + Lazy contactDataSettings, + Lazy customerSettings, + Lazy catalogSettings) + { + _services = services; + _dbContext = dbContext; + _priceFormatter = priceFormatter; + _dateTimeHelper = dateTimeHelper; + _exportProfileService = exportProfileService; + _localizedEntityService = localizedEntityService; + _languageService = languageService; + _urlRecordService = urlRecordService; + _pictureService = pictureService; + _priceCalculationService = priceCalculationService; + _currencyService = currencyService; + _taxService = taxService; + _categoryService = categoryService; + _productAttributeParser = productAttributeParser; + _productAttributeService = productAttributeService; + _productTemplateService = productTemplateService; + _categoryTemplateService = categoryTemplateService; + _productService = productService; + _orderService = orderService; + _manufacturerService = manufacturerService; + _customerService = customerService; + _addressService = addressService; + _countryService = countryService; + _shipmentService = shipmentService; + _genericAttributeService = genericAttributeService; + _emailAccountService = emailAccountService; + _queuedEmailService = queuedEmailService; + _emailSender = emailSender; + _deliveryTimeService = deliveryTimeService; + _quantityUnitService = quantityUnitService; + + _customerRepository = customerRepository; + _subscriptionRepository = subscriptionRepository; + _orderRepository = orderRepository; + + _mediaSettings = mediaSettings; + _contactDataSettings = contactDataSettings; + _customerSettings = customerSettings; + _catalogSettings = catalogSettings; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + #endregion + + #region Utilities + + private void SetProgress(DataExporterContext ctx, int loadedRecords) + { + try + { + if (!ctx.IsPreview && loadedRecords > 0) + { + int totalRecords = ctx.RecordsPerStore.Sum(x => x.Value); + + if (ctx.Request.Profile.Limit > 0 && totalRecords > ctx.Request.Profile.Limit) + totalRecords = ctx.Request.Profile.Limit; + + ctx.RecordCount = Math.Min(ctx.RecordCount + loadedRecords, totalRecords); + var msg = ctx.ProgressInfo.FormatInvariant(ctx.RecordCount, totalRecords); + ctx.Request.ProgressValueSetter.Invoke(ctx.RecordCount, totalRecords, msg); + } + } + catch { } + } + + private void SetProgress(DataExporterContext ctx, string message) + { + try + { + if (!ctx.IsPreview && message.HasValue()) + { + ctx.Request.ProgressValueSetter.Invoke(0, 0, message); + } + } + catch { } + } + + private bool HasPermission(DataExporterContext ctx) + { + if (ctx.Request.HasPermission) + return true; + + var customer = _services.WorkContext.CurrentCustomer; + + if (customer.SystemName == SystemCustomerNames.BackgroundTask) + return true; + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Product || + ctx.Request.Provider.Value.EntityType == ExportEntityType.Category || + ctx.Request.Provider.Value.EntityType == ExportEntityType.Manufacturer) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog, customer); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Customer) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageCustomers, customer); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Order) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageOrders, customer); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.NewsLetterSubscription) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers, customer); + + return true; + } + + private void DetachAllEntitiesAndClear(DataExporterContext ctx) + { + try + { + _dbContext.DetachAll(); + } + catch (Exception exception) + { + ctx.Log.Warning("Detaching all entities failed.", exception); + } + + try + { + // now again attach what is globally required + _dbContext.Attach(ctx.Request.Profile); + _dbContext.AttachRange(ctx.Stores.Values); + } + catch (Exception exception) + { + ctx.Log.Warning("Re-attaching entities failed.", exception); + } + + try + { + if (ctx.ProductExportContext != null) + ctx.ProductExportContext.Clear(); + + if (ctx.OrderExportContext != null) + ctx.OrderExportContext.Clear(); + + if (ctx.ManufacturerExportContext != null) + ctx.ManufacturerExportContext.Clear(); + + if (ctx.CategoryExportContext != null) + ctx.CategoryExportContext.Clear(); + + if (ctx.CustomerExportContext != null) + ctx.CustomerExportContext.Clear(); + } + catch { } + } + + private IExportDataSegmenterProvider CreateSegmenter(DataExporterContext ctx, int pageIndex = 0) + { + var offset = Math.Max(ctx.Request.Profile.Offset, 0) + (pageIndex * PageSize); + var limit = (ctx.IsPreview ? PageSize : Math.Max(ctx.Request.Profile.Limit, 0)); + var recordsPerSegment = (ctx.IsPreview ? 0 : Math.Max(ctx.Request.Profile.BatchSize, 0)); + var totalCount = Math.Max(ctx.Request.Profile.Offset, 0) + ctx.RecordsPerStore.First(x => x.Key == ctx.Store.Id).Value; + + switch (ctx.Request.Provider.Value.EntityType) + { + case ExportEntityType.Product: + ctx.ExecuteContext.DataSegmenter = new ExportDataSegmenter + ( + skip => GetProducts(ctx, skip), + entities => + { + // load data behind navigation properties for current queue in one go + ctx.ProductExportContext = new ProductExportContext(entities, + x => _productAttributeService.Value.GetProductVariantAttributesByProductIds(x, null), + x => _productAttributeService.Value.GetProductVariantAttributeCombinations(x), + x => _productService.Value.GetTierPricesByProductIds(x, (ctx.Projection.CurrencyId ?? 0) != 0 ? ctx.ContextCustomer : null, ctx.Store.Id), + x => _categoryService.Value.GetProductCategoriesByProductIds(x, null, true), + x => _manufacturerService.Value.GetProductManufacturersByProductIds(x), + x => _productService.Value.GetProductPicturesByProductIds(x), + x => _productService.Value.GetProductTagsByProductIds(x), + x => _productService.Value.GetAppliedDiscountsByProductIds(x), + x => _productService.Value.GetProductSpecificationAttributesByProductIds(x), + x => _productService.Value.GetBundleItemsByProductIds(x, true) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Order: + ctx.ExecuteContext.DataSegmenter = new ExportDataSegmenter + ( + skip => GetOrders(ctx, skip), + entities => + { + ctx.OrderExportContext = new OrderExportContext(entities, + x => _customerService.GetCustomersByIds(x), + x => _customerService.GetRewardPointsHistoriesByCustomerIds(x), + x => _addressService.Value.GetAddressByIds(x), + x => _orderService.Value.GetOrderItemsByOrderIds(x), + x => _shipmentService.Value.GetShipmentsByOrderIds(x) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Manufacturer: + ctx.ExecuteContext.DataSegmenter = new ExportDataSegmenter + ( + skip => GetManufacturers(ctx, skip), + entities => + { + ctx.ManufacturerExportContext = new ManufacturerExportContext(entities, + x => _manufacturerService.Value.GetProductManufacturersByManufacturerIds(x), + x => _pictureService.Value.GetPicturesByIds(x) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Category: + ctx.ExecuteContext.DataSegmenter = new ExportDataSegmenter + ( + skip => GetCategories(ctx, skip), + entities => + { + ctx.CategoryExportContext = new CategoryExportContext(entities, + x => _categoryService.Value.GetProductCategoriesByCategoryIds(x), + x => _pictureService.Value.GetPicturesByIds(x) + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.Customer: + ctx.ExecuteContext.DataSegmenter = new ExportDataSegmenter + ( + skip => GetCustomers(ctx, skip), + entities => + { + ctx.CustomerExportContext = new CustomerExportContext(entities, + x => _genericAttributeService.Value.GetAttributesForEntity(x, "Customer") + ); + }, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + case ExportEntityType.NewsLetterSubscription: + ctx.ExecuteContext.DataSegmenter = new ExportDataSegmenter + ( + skip => GetNewsLetterSubscriptions(ctx, skip), + null, + entity => Convert(ctx, entity), + offset, PageSize, limit, recordsPerSegment, totalCount + ); + break; + + default: + ctx.ExecuteContext.DataSegmenter = null; + break; + } + + return ctx.ExecuteContext.DataSegmenter as IExportDataSegmenterProvider; + } + + private bool CallProvider(DataExporterContext ctx, string streamId, string method, string path) + { + if (method != "Execute" && method != "OnExecuted") + throw new SmartException("Unknown export method {0}.".FormatInvariant(method.NaIfEmpty())); + + try + { + ctx.ExecuteContext.DataStreamId = streamId; + + using (ctx.ExecuteContext.DataStream = new MemoryStream()) + { + if (method == "Execute") + { + ctx.Request.Provider.Value.Execute(ctx.ExecuteContext); + } + else if (method == "OnExecuted") + { + ctx.Request.Provider.Value.OnExecuted(ctx.ExecuteContext); + } + + if (ctx.IsFileBasedExport && path.HasValue() && ctx.ExecuteContext.DataStream.Length > 0) + { + if (!ctx.ExecuteContext.DataStream.CanSeek) + { + ctx.Log.Warning("Data stream seems to be closed!"); + } + + ctx.ExecuteContext.DataStream.Seek(0, SeekOrigin.Begin); + + using (_rwLock.GetWriteLock()) + using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) + { + ctx.Log.Information("Creating file {0}.".FormatInvariant(path)); + ctx.ExecuteContext.DataStream.CopyTo(fileStream); + } + } + } + } + catch (Exception exception) + { + ctx.ExecuteContext.Abort = DataExchangeAbortion.Hard; + ctx.Log.Error("The provider failed at the {0} method: {1}.".FormatInvariant(method, exception.ToAllMessages()), exception); + ctx.Result.LastError = exception.ToString(); + } + finally + { + if (ctx.ExecuteContext.DataStream != null) + { + ctx.ExecuteContext.DataStream.Dispose(); + ctx.ExecuteContext.DataStream = null; + } + + if (ctx.ExecuteContext.Abort == DataExchangeAbortion.Hard && ctx.IsFileBasedExport && path.HasValue()) + { + FileSystemHelper.Delete(path); + } + } + + return (ctx.ExecuteContext.Abort != DataExchangeAbortion.Hard); + } + + private bool Deploy(DataExporterContext ctx, string zipPath) + { + var allSucceeded = true; + var deployments = ctx.Request.Profile.Deployments.OrderBy(x => x.DeploymentTypeId).Where(x => x.Enabled); + + if (deployments.Count() == 0) + return false; + + var context = new ExportDeploymentContext + { + T = T, + Log = ctx.Log, + FolderContent = ctx.FolderContent, + ZipPath = zipPath, + CreateZipArchive = ctx.Request.Profile.CreateZipArchive + }; + + foreach (var deployment in deployments) + { + IFilePublisher publisher = null; + + context.Result = new DataDeploymentResult + { + LastExecutionUtc = DateTime.UtcNow + }; + + try + { + switch (deployment.DeploymentType) + { + case ExportDeploymentType.Email: + publisher = new EmailFilePublisher(_emailAccountService.Value, _queuedEmailService.Value); + break; + case ExportDeploymentType.FileSystem: + publisher = new FileSystemFilePublisher(); + break; + case ExportDeploymentType.Ftp: + publisher = new FtpFilePublisher(); + break; + case ExportDeploymentType.Http: + publisher = new HttpFilePublisher(); + break; + case ExportDeploymentType.PublicFolder: + publisher = new PublicFolderPublisher(); + break; + } + + if (publisher != null) + { + publisher.Publish(context, deployment); + + if (!context.Result.Succeeded) + allSucceeded = false; + } + } + catch (Exception exception) + { + allSucceeded = false; + + if (context.Result != null) + { + context.Result.LastError = exception.ToAllMessages(); + } + + ctx.Log.Error("Deployment \"{0}\" of type {1} failed: {2}".FormatInvariant( + deployment.Name, deployment.DeploymentType.ToString(), exception.Message), exception); + } + + deployment.ResultInfo = XmlHelper.Serialize(context.Result); + + _exportProfileService.Value.UpdateExportDeployment(deployment); + } + + return allSucceeded; + } + + private void SendCompletionEmail(DataExporterContext ctx, string zipPath) + { + var emailAccount = _emailAccountService.Value.GetEmailAccountById(ctx.Request.Profile.EmailAccountId); + + if (emailAccount == null) + emailAccount = _emailAccountService.Value.GetDefaultEmailAccount(); + + var downloadUrl = "{0}Admin/Export/DownloadExportFile/{1}?name=".FormatInvariant(_services.WebHelper.GetStoreLocation(ctx.Store.SslEnabled), ctx.Request.Profile.Id); + + var languageId = ctx.Projection.LanguageId ?? 0; + var smtpContext = new SmtpContext(emailAccount); + var message = new EmailMessage(); + + var storeInfo = "{0} ({1})".FormatInvariant(ctx.Store.Name, ctx.Store.Url); + var intro =_services.Localization.GetResource("Admin.DataExchange.Export.CompletedEmail.Body", languageId).FormatInvariant(storeInfo); + var body = new StringBuilder(intro); + + if (ctx.Result.LastError.HasValue()) + { + body.AppendFormat("

{0}

", ctx.Result.LastError); + } + + if (ctx.IsFileBasedExport && File.Exists(zipPath)) + { + var fileName = Path.GetFileName(zipPath); + body.AppendFormat("

{2}

", downloadUrl, HttpUtility.UrlEncode(fileName), fileName); + } + + if (ctx.IsFileBasedExport && ctx.Result.Files.Any()) + { + body.Append("

"); + foreach (var file in ctx.Result.Files) + { + body.AppendFormat("

", downloadUrl, HttpUtility.UrlEncode(file.FileName), file.FileName); + } + body.Append("

"); + } + + message.From = new EmailAddress(emailAccount.Email, emailAccount.DisplayName); + + if (ctx.Request.Profile.CompletedEmailAddresses.HasValue()) + message.To.AddRange(ctx.Request.Profile.CompletedEmailAddresses.SplitSafe(",").Where(x => x.IsEmail()).Select(x => new EmailAddress(x))); + + if (message.To.Count == 0 && _contactDataSettings.Value.CompanyEmailAddress.HasValue()) + message.To.Add(new EmailAddress(_contactDataSettings.Value.CompanyEmailAddress)); + + if (message.To.Count == 0) + message.To.Add(new EmailAddress(emailAccount.Email, emailAccount.DisplayName)); + + message.Subject = _services.Localization.GetResource("Admin.DataExchange.Export.CompletedEmail.Subject", languageId) + .FormatInvariant(ctx.Request.Profile.Name); + + message.Body = body.ToString(); + + _emailSender.Value.SendEmail(smtpContext, message); + + //_queuedEmailService.Value.InsertQueuedEmail(new QueuedEmail + //{ + // From = emailAccount.Email, + // FromName = emailAccount.DisplayName, + // To = message.To.First().Address, + // Subject = message.Subject, + // Body = message.Body, + // CreatedOnUtc = DateTime.UtcNow, + // EmailAccountId = emailAccount.Id, + // SendManually = true + //}); + //_dbContext.SaveChanges(); + } + + #endregion + + #region Getting data + + private IQueryable GetProductQuery(DataExporterContext ctx, int skip, int take) + { + IQueryable query = null; + + if (ctx.Request.ProductQuery == null) + { + var searchContext = new ProductSearchContext + { + OrderBy = ProductSortingEnum.CreatedOn, + ProductIds = ctx.Request.EntitiesToExport, + StoreId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId), + VisibleIndividuallyOnly = true, + PriceMin = ctx.Filter.PriceMinimum, + PriceMax = ctx.Filter.PriceMaximum, + IsPublished = ctx.Filter.IsPublished, + WithoutCategories = ctx.Filter.WithoutCategories, + WithoutManufacturers = ctx.Filter.WithoutManufacturers, + ManufacturerId = ctx.Filter.ManufacturerId ?? 0, + FeaturedProducts = ctx.Filter.FeaturedProducts, + ProductType = ctx.Filter.ProductType, + ProductTagId = ctx.Filter.ProductTagId ?? 0, + IdMin = ctx.Filter.IdMinimum ?? 0, + IdMax = ctx.Filter.IdMaximum ?? 0, + AvailabilityMinimum = ctx.Filter.AvailabilityMinimum, + AvailabilityMaximum = ctx.Filter.AvailabilityMaximum + }; + + if (!ctx.Filter.IsPublished.HasValue) + searchContext.ShowHidden = true; + + if (ctx.Filter.CategoryIds != null && ctx.Filter.CategoryIds.Length > 0) + searchContext.CategoryIds = ctx.Filter.CategoryIds.ToList(); + + if (ctx.Filter.CreatedFrom.HasValue) + searchContext.CreatedFromUtc = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedFrom.Value, _dateTimeHelper.Value.CurrentTimeZone); + + if (ctx.Filter.CreatedTo.HasValue) + searchContext.CreatedToUtc = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedTo.Value, _dateTimeHelper.Value.CurrentTimeZone); + + query = _productService.Value.PrepareProductSearchQuery(searchContext); + + query = query.OrderByDescending(x => x.CreatedOnUtc); + } + else + { + query = ctx.Request.ProductQuery; + } + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetProducts(DataExporterContext ctx, int skip) + { + // we use ctx.EntityIdsPerSegment to avoid exporting products multiple times per segment\file (cause of associated products). + + var result = new List(); + + var products = GetProductQuery(ctx, skip, PageSize).ToList(); + + foreach (var product in products) + { + if (product.ProductType == ProductType.SimpleProduct || product.ProductType == ProductType.BundledProduct) + { + if (!ctx.EntityIdsPerSegment.Contains(product.Id)) + { + result.Add(product); + ctx.EntityIdsPerSegment.Add(product.Id); + } + } + else if (product.ProductType == ProductType.GroupedProduct) + { + if (ctx.Projection.NoGroupedProducts && !ctx.IsPreview) + { + var associatedSearchContext = new ProductSearchContext + { + OrderBy = ProductSortingEnum.Position, + PageSize = int.MaxValue, + StoreId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId), + VisibleIndividuallyOnly = true, + ParentGroupedProductId = product.Id + }; + + foreach (var associatedProduct in _productService.Value.SearchProducts(associatedSearchContext)) + { + if (!ctx.EntityIdsPerSegment.Contains(associatedProduct.Id)) + { + result.Add(associatedProduct); + ctx.EntityIdsPerSegment.Add(associatedProduct.Id); + } + } + } + else + { + if (!ctx.EntityIdsPerSegment.Contains(product.Id)) + { + result.Add(product); + ctx.EntityIdsPerSegment.Add(product.Id); + } + } + } + } + + SetProgress(ctx, products.Count); + + return result; + } + + private IQueryable GetOrderQuery(DataExporterContext ctx, int skip, int take) + { + var query = _orderService.Value.GetOrders( + ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId, + ctx.Projection.CustomerId ?? 0, + ctx.Filter.CreatedFrom.HasValue ? (DateTime?)_dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedFrom.Value, _dateTimeHelper.Value.CurrentTimeZone) : null, + ctx.Filter.CreatedTo.HasValue ? (DateTime?)_dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedTo.Value, _dateTimeHelper.Value.CurrentTimeZone) : null, + ctx.Filter.OrderStatusIds, + ctx.Filter.PaymentStatusIds, + ctx.Filter.ShippingStatusIds, + null, + null, + null); + + if (ctx.Request.EntitiesToExport.Any()) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); + + query = query.OrderByDescending(x => x.CreatedOnUtc); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetOrders(DataExporterContext ctx, int skip) + { + var orders = GetOrderQuery(ctx, skip, PageSize).ToList(); + + if (ctx.Projection.OrderStatusChange != ExportOrderStatusChange.None) + { + ctx.SetLoadedEntityIds(orders.Select(x => x.Id)); + } + + SetProgress(ctx, orders.Count); + + return orders; + } + + private IQueryable GetManufacturerQuery(DataExporterContext ctx, int skip, int take) + { + var showHidden = !ctx.Filter.IsPublished.HasValue; + var storeId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + + var query = _manufacturerService.Value.GetManufacturers(showHidden, storeId); + + if (ctx.Request.EntitiesToExport.Any()) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); + + query = query.OrderBy(x => x.DisplayOrder); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetManufacturers(DataExporterContext ctx, int skip) + { + var manus = GetManufacturerQuery(ctx, skip, PageSize).ToList(); + + SetProgress(ctx, manus.Count); + + return manus; + } + + private IQueryable GetCategoryQuery(DataExporterContext ctx, int skip, int take) + { + var showHidden = !ctx.Filter.IsPublished.HasValue; + var storeId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + + var query = _categoryService.Value.GetCategories(null, showHidden, null, true, storeId); + + if (ctx.Request.EntitiesToExport.Any()) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); + + query = query + .OrderBy(x => x.ParentCategoryId) + .ThenBy(x => x.DisplayOrder); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetCategories(DataExporterContext ctx, int skip) + { + var categories = GetCategoryQuery(ctx, skip, PageSize).ToList(); + + SetProgress(ctx, categories.Count); + + return categories; + } + + private IQueryable GetCustomerQuery(DataExporterContext ctx, int skip, int take) + { + var query = _customerRepository.Value.TableUntracked + .Expand(x => x.BillingAddress) + .Expand(x => x.ShippingAddress) + .Expand(x => x.Addresses.Select(y => y.Country)) + .Expand(x => x.Addresses.Select(y => y.StateProvince)) + .Expand(x => x.CustomerRoles) + .Where(x => !x.Deleted); + + if (ctx.Filter.IsActiveCustomer.HasValue) + query = query.Where(x => x.Active == ctx.Filter.IsActiveCustomer.Value); + + if (ctx.Filter.IsTaxExempt.HasValue) + query = query.Where(x => x.IsTaxExempt == ctx.Filter.IsTaxExempt.Value); + + if (ctx.Filter.CustomerRoleIds != null && ctx.Filter.CustomerRoleIds.Length > 0) + query = query.Where(x => x.CustomerRoles.Select(y => y.Id).Intersect(ctx.Filter.CustomerRoleIds).Any()); + + if (ctx.Filter.BillingCountryIds != null && ctx.Filter.BillingCountryIds.Length > 0) + query = query.Where(x => x.BillingAddress != null && ctx.Filter.BillingCountryIds.Contains(x.BillingAddress.Id)); + + if (ctx.Filter.ShippingCountryIds != null && ctx.Filter.ShippingCountryIds.Length > 0) + query = query.Where(x => x.ShippingAddress != null && ctx.Filter.ShippingCountryIds.Contains(x.ShippingAddress.Id)); + + if (ctx.Filter.LastActivityFrom.HasValue) + { + var activityFrom = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.LastActivityFrom.Value, _dateTimeHelper.Value.CurrentTimeZone); + query = query.Where(x => activityFrom <= x.LastActivityDateUtc); + } + + if (ctx.Filter.LastActivityTo.HasValue) + { + var activityTo = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.LastActivityTo.Value, _dateTimeHelper.Value.CurrentTimeZone); + query = query.Where(x => activityTo >= x.LastActivityDateUtc); + } + + if (ctx.Filter.HasSpentAtLeastAmount.HasValue) + { + query = query + .Join(_orderRepository.Value.Table, x => x.Id, y => y.CustomerId, (x, y) => new { Customer = x, Order = y }) + .GroupBy(x => x.Customer.Id) + .Select(x => new + { + Customer = x.FirstOrDefault().Customer, + OrderTotal = x.Sum(y => y.Order.OrderTotal) + }) + .Where(x => x.OrderTotal >= ctx.Filter.HasSpentAtLeastAmount.Value) + .Select(x => x.Customer); + } + + if (ctx.Filter.HasPlacedAtLeastOrders.HasValue) + { + query = query + .Join(_orderRepository.Value.Table, x => x.Id, y => y.CustomerId, (x, y) => new { Customer = x, Order = y }) + .GroupBy(x => x.Customer.Id) + .Select(x => new + { + Customer = x.FirstOrDefault().Customer, + OrderCount = x.Count() + }) + .Where(x => x.OrderCount >= ctx.Filter.HasPlacedAtLeastOrders.Value) + .Select(x => x.Customer); + } + + if (ctx.Request.EntitiesToExport.Any()) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); + + query = query.OrderByDescending(x => x.CreatedOnUtc); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetCustomers(DataExporterContext ctx, int skip) + { + var customers = GetCustomerQuery(ctx, skip, PageSize).ToList(); + + SetProgress(ctx, customers.Count); + + return customers; + } + + private IQueryable GetNewsLetterSubscriptionQuery(DataExporterContext ctx, int skip, int take) + { + var storeId = (ctx.Request.Profile.PerStore ? ctx.Store.Id : ctx.Filter.StoreId); + + var query = _subscriptionRepository.Value.TableUntracked; + + if (storeId > 0) + query = query.Where(x => x.StoreId == storeId); + + if (ctx.Filter.IsActiveSubscriber.HasValue) + query = query.Where(x => x.Active == ctx.Filter.IsActiveSubscriber.Value); + + if (ctx.Filter.CreatedFrom.HasValue) + { + var createdFrom = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedFrom.Value, _dateTimeHelper.Value.CurrentTimeZone); + query = query.Where(x => createdFrom <= x.CreatedOnUtc); + } + + if (ctx.Filter.CreatedTo.HasValue) + { + var createdTo = _dateTimeHelper.Value.ConvertToUtcTime(ctx.Filter.CreatedTo.Value, _dateTimeHelper.Value.CurrentTimeZone); + query = query.Where(x => createdTo >= x.CreatedOnUtc); + } + + if (ctx.Request.EntitiesToExport.Any()) + query = query.Where(x => ctx.Request.EntitiesToExport.Contains(x.Id)); + + query = query + .OrderBy(x => x.StoreId) + .ThenBy(x => x.Email); + + if (skip > 0) + query = query.Skip(skip); + + if (take != int.MaxValue) + query = query.Take(take); + + return query; + } + + private List GetNewsLetterSubscriptions(DataExporterContext ctx, int skip) + { + var subscriptions = GetNewsLetterSubscriptionQuery(ctx, skip, PageSize).ToList(); + + SetProgress(ctx, subscriptions.Count); + + return subscriptions; + } + + #endregion + + private List Init(DataExporterContext ctx, int? totalRecords = null) + { + // Init base things that are even required for preview. Init all other things (regular export) in ExportCoreOuter. + List result = null; + + if (ctx.Projection.CurrencyId.HasValue) + ctx.ContextCurrency = _currencyService.Value.GetCurrencyById(ctx.Projection.CurrencyId.Value); + else + ctx.ContextCurrency = _services.WorkContext.WorkingCurrency; + + if (ctx.Projection.CustomerId.HasValue) + ctx.ContextCustomer = _customerService.GetCustomerById(ctx.Projection.CustomerId.Value); + else + ctx.ContextCustomer = _services.WorkContext.CurrentCustomer; + + if (ctx.Projection.LanguageId.HasValue) + ctx.ContextLanguage = _languageService.Value.GetLanguageById(ctx.Projection.LanguageId.Value); + else + ctx.ContextLanguage = _services.WorkContext.WorkingLanguage; + + ctx.Stores = _services.StoreService.GetAllStores().ToDictionary(x => x.Id, x => x); + ctx.Languages = _languageService.Value.GetAllLanguages(true).ToDictionary(x => x.Id, x => x); + + if (!ctx.IsPreview && ctx.Request.Profile.PerStore) + { + result = new List(ctx.Stores.Values.Where(x => x.Id == ctx.Filter.StoreId || ctx.Filter.StoreId == 0)); + } + else + { + int? storeId = (ctx.Filter.StoreId == 0 ? ctx.Projection.StoreId : ctx.Filter.StoreId); + + ctx.Store = ctx.Stores.Values.FirstOrDefault(x => x.Id == (storeId ?? _services.StoreContext.CurrentStore.Id)); + + result = new List { ctx.Store }; + } + + // get total records for progress + foreach (var store in result) + { + ctx.Store = store; + + int totalCount = 0; + + if (totalRecords.HasValue) + { + totalCount = totalRecords.Value; // speed up preview by not counting total at each page + } + else + { + switch (ctx.Request.Provider.Value.EntityType) + { + case ExportEntityType.Product: + totalCount = GetProductQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Order: + totalCount = GetOrderQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Manufacturer: + totalCount = GetManufacturerQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Category: + totalCount = GetCategoryQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.Customer: + totalCount = GetCustomerQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); + break; + case ExportEntityType.NewsLetterSubscription: + totalCount = GetNewsLetterSubscriptionQuery(ctx, ctx.Request.Profile.Offset, int.MaxValue).Count(); + break; + } + } + + ctx.RecordsPerStore.Add(store.Id, totalCount); + } + + return result; + } + + private void ExportCoreInner(DataExporterContext ctx, Store store) + { + if (ctx.ExecuteContext.Abort != DataExchangeAbortion.None) + return; + + var fileIndex = 0; + var dataExchangeSettings = _services.Settings.LoadSetting(store.Id); + + ctx.Store = store; + + { + var logHead = new StringBuilder(); + logHead.AppendLine(); + logHead.AppendLine(new string('-', 40)); + logHead.AppendLine("SmartStore.NET:\t\tv." + SmartStoreVersion.CurrentFullVersion); + logHead.Append("Export profile:\t\t" + ctx.Request.Profile.Name); + logHead.AppendLine(ctx.Request.Profile.Id == 0 ? " (volatile)" : " (Id {0})".FormatInvariant(ctx.Request.Profile.Id)); + + if (ctx.Request.Provider.Metadata.FriendlyName.HasValue()) + logHead.AppendLine("Export provider:\t{0} ({1})".FormatInvariant(ctx.Request.Provider.Metadata.FriendlyName, ctx.Request.Profile.ProviderSystemName)); + else + logHead.AppendLine("Export provider:\t{0}".FormatInvariant(ctx.Request.Profile.ProviderSystemName)); + + var plugin = ctx.Request.Provider.Metadata.PluginDescriptor; + logHead.Append("Plugin:\t\t\t"); + logHead.AppendLine(plugin == null ? "".NaIfEmpty() : "{0} ({1}) v.{2}".FormatInvariant(plugin.FriendlyName, plugin.SystemName, plugin.Version.ToString())); + + logHead.AppendLine("Entity:\t\t\t" + ctx.Request.Provider.Value.EntityType.ToString()); + + try + { + var uri = new Uri(store.Url); + logHead.AppendLine("Store:\t\t\t{0} (Id {1})".FormatInvariant(uri.DnsSafeHost.NaIfEmpty(), ctx.Store.Id)); + } + catch { } + + var customer = _services.WorkContext.CurrentCustomer; + logHead.Append("Executed by:\t\t" + (customer.Email.HasValue() ? customer.Email : customer.SystemName)); + + ctx.Log.Information(logHead.ToString()); + } + + ctx.ExecuteContext.Store = ToDynamic(ctx, ctx.Store); + ctx.ExecuteContext.MaxFileNameLength = dataExchangeSettings.MaxFileNameLength; + + var publicDeployment = ctx.Request.Profile.Deployments.FirstOrDefault(x => x.DeploymentType == ExportDeploymentType.PublicFolder); + ctx.ExecuteContext.HasPublicDeployment = (publicDeployment != null); + ctx.ExecuteContext.PublicFolderPath = publicDeployment.GetDeploymentFolder(true); + + var fileExtension = (ctx.Request.Provider.Value.FileExtension.HasValue() ? ctx.Request.Provider.Value.FileExtension.ToLower().EnsureStartsWith(".") : ""); + + + using (var segmenter = CreateSegmenter(ctx)) + { + if (segmenter == null) + { + throw new SmartException("Unsupported entity type '{0}'.".FormatInvariant(ctx.Request.Provider.Value.EntityType.ToString())); + } + + if (segmenter.TotalRecords <= 0) + { + ctx.Log.Information("There are no records to export."); + } + + while (ctx.ExecuteContext.Abort == DataExchangeAbortion.None && segmenter.HasData) + { + segmenter.RecordPerSegmentCount = 0; + ctx.ExecuteContext.RecordsSucceeded = 0; + + string path = null; + + if (ctx.IsFileBasedExport) + { + var resolvedPattern = ctx.Request.Profile.ResolveFileNamePattern(ctx.Store, ++fileIndex, ctx.ExecuteContext.MaxFileNameLength); + + ctx.ExecuteContext.FileName = resolvedPattern + fileExtension; + path = Path.Combine(ctx.ExecuteContext.Folder, ctx.ExecuteContext.FileName); + } + + if (CallProvider(ctx, null, "Execute", path)) + { + ctx.Log.Information("Provider reports {0} successfully exported record(s).".FormatInvariant(ctx.ExecuteContext.RecordsSucceeded)); + + if (ctx.IsFileBasedExport && File.Exists(path)) + { + ctx.Result.Files.Add(new DataExportResult.ExportFileInfo + { + StoreId = ctx.Store.Id, + FileName = ctx.ExecuteContext.FileName + }); + } + } + + ctx.EntityIdsPerSegment.Clear(); + + if (ctx.ExecuteContext.IsMaxFailures) + ctx.Log.Warning("Export aborted. The maximum number of failures has been reached."); + + if (ctx.CancellationToken.IsCancellationRequested) + ctx.Log.Warning("Export aborted. A cancellation has been requested."); + + DetachAllEntitiesAndClear(ctx); + } + + if (ctx.ExecuteContext.Abort != DataExchangeAbortion.Hard) + { + // always call OnExecuted + if (ctx.ExecuteContext.ExtraDataUnits.Count == 0) + ctx.ExecuteContext.ExtraDataUnits.Add(new ExportDataUnit()); + + ctx.ExecuteContext.ExtraDataUnits.ForEach(x => + { + var path = (x.FileName.HasValue() ? Path.Combine(ctx.ExecuteContext.Folder, x.FileName) : null); + CallProvider(ctx, x.Id, "OnExecuted", path); + }); + + ctx.ExecuteContext.ExtraDataUnits.Clear(); + } + } + } + + private void ExportCoreOuter(DataExporterContext ctx) + { + if (ctx.Request.Profile == null || !ctx.Request.Profile.Enabled) + return; + + var logPath = ctx.Request.Profile.GetExportLogPath(); + var zipPath = ctx.Request.Profile.GetExportZipPath(); + + FileSystemHelper.Delete(logPath); + FileSystemHelper.Delete(zipPath); + FileSystemHelper.ClearDirectory(ctx.FolderContent, false); + + using (var logger = new TraceLogger(logPath)) + { + try + { + ctx.Log = logger; + ctx.ExecuteContext.Log = logger; + ctx.ProgressInfo = T("Admin.DataExchange.Export.ProgressInfo"); + + if (!ctx.Request.Provider.IsValid()) + throw new SmartException("Export aborted because the export provider is not valid."); + + if (!HasPermission(ctx)) + throw new SmartException("You do not have permission to perform the selected export."); + + foreach (var item in ctx.Request.CustomData) + { + ctx.ExecuteContext.CustomProperties.Add(item.Key, item.Value); + } + + if (ctx.Request.Profile.ProviderConfigData.HasValue()) + { + var configInfo = ctx.Request.Provider.Value.ConfigurationInfo; + if (configInfo != null) + { + ctx.ExecuteContext.ConfigurationData = XmlHelper.Deserialize(ctx.Request.Profile.ProviderConfigData, configInfo.ModelType); + } + } + + // lazyLoading: false, proxyCreation: false impossible. how to identify all properties of all data levels of all entities + // that require manual resolving for now and for future? fragile, susceptible to faults (e.g. price calculation)... + using (var scope = new DbContextScope(_dbContext, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true)) + { + ctx.DeliveryTimes = _deliveryTimeService.Value.GetAllDeliveryTimes().ToDictionary(x => x.Id); + ctx.QuantityUnits = _quantityUnitService.Value.GetAllQuantityUnits().ToDictionary(x => x.Id); + ctx.ProductTemplates = _productTemplateService.Value.GetAllProductTemplates().ToDictionary(x => x.Id, x => x.ViewPath); + ctx.CategoryTemplates = _categoryTemplateService.Value.GetAllCategoryTemplates().ToDictionary(x => x.Id, x => x.ViewPath); + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Product) + { + var allCategories = _categoryService.Value.GetAllCategories(showHidden: true, applyNavigationFilters: false); + ctx.Categories = allCategories.ToDictionary(x => x.Id); + } + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Order) + { + ctx.Countries = _countryService.Value.GetAllCountries(true).ToDictionary(x => x.Id, x => x); + } + + if (ctx.Request.Provider.Value.EntityType == ExportEntityType.Customer) + { + var subscriptionEmails = _subscriptionRepository.Value.TableUntracked + .Where(x => x.Active) + .Select(x => x.Email) + .Distinct() + .ToList(); + + ctx.NewsletterSubscriptions = new HashSet(subscriptionEmails, StringComparer.OrdinalIgnoreCase); + } + + var stores = Init(ctx); + + ctx.ExecuteContext.Language = ToDynamic(ctx, ctx.ContextLanguage); + ctx.ExecuteContext.Customer = ToDynamic(ctx, ctx.ContextCustomer); + ctx.ExecuteContext.Currency = ToDynamic(ctx, ctx.ContextCurrency); + + stores.ForEach(x => ExportCoreInner(ctx, x)); + } + + if (!ctx.IsPreview && ctx.ExecuteContext.Abort != DataExchangeAbortion.Hard) + { + if (ctx.IsFileBasedExport) + { + if (ctx.Request.Profile.CreateZipArchive) + { + ZipFile.CreateFromDirectory(ctx.FolderContent, zipPath, CompressionLevel.Fastest, false); + } + + if (ctx.Request.Profile.Deployments.Any(x => x.Enabled)) + { + SetProgress(ctx, T("Common.Publishing")); + + var allDeploymentsSucceeded = Deploy(ctx, zipPath); + + if (allDeploymentsSucceeded && ctx.Request.Profile.Cleanup) + { + logger.Information("Cleaning up export folder"); + + FileSystemHelper.ClearDirectory(ctx.FolderContent, false); + } + } + } + + if (ctx.Request.Profile.EmailAccountId != 0 && ctx.Request.Profile.CompletedEmailAddresses.HasValue()) + { + SendCompletionEmail(ctx, zipPath); + } + else if (ctx.Request.Profile.IsSystemProfile && !ctx.Supports(ExportFeatures.CanOmitCompletionMail)) + { + SendCompletionEmail(ctx, zipPath); + } + } + } + catch (Exception exception) + { + logger.ErrorsAll(exception); + ctx.Result.LastError = exception.ToString(); + } + finally + { + try + { + if (!ctx.IsPreview && ctx.Request.Profile.Id != 0) + { + ctx.Request.Profile.ResultInfo = XmlHelper.Serialize(ctx.Result); + + _exportProfileService.Value.UpdateExportProfile(ctx.Request.Profile); + } + } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } + + DetachAllEntitiesAndClear(ctx); + + try + { + ctx.NewsletterSubscriptions.Clear(); + ctx.ProductTemplates.Clear(); + ctx.CategoryTemplates.Clear(); + ctx.Countries.Clear(); + ctx.Languages.Clear(); + ctx.QuantityUnits.Clear(); + ctx.DeliveryTimes.Clear(); + ctx.CategoryPathes.Clear(); + ctx.Categories.Clear(); + ctx.Stores.Clear(); + + ctx.Request.CustomData.Clear(); + + ctx.ExecuteContext.CustomProperties.Clear(); + ctx.ExecuteContext.Log = null; + ctx.Log = null; + } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } + } + } + + if (ctx.IsPreview || ctx.ExecuteContext.Abort == DataExchangeAbortion.Hard) + return; + + // post process order entities + if (ctx.EntityIdsLoaded.Any() && ctx.Request.Provider.Value.EntityType == ExportEntityType.Order && ctx.Projection.OrderStatusChange != ExportOrderStatusChange.None) + { + using (var logger = new TraceLogger(logPath)) + { + try + { + int? orderStatusId = null; + + if (ctx.Projection.OrderStatusChange == ExportOrderStatusChange.Processing) + orderStatusId = (int)OrderStatus.Processing; + else if (ctx.Projection.OrderStatusChange == ExportOrderStatusChange.Complete) + orderStatusId = (int)OrderStatus.Complete; + + using (var scope = new DbContextScope(_dbContext, false, null, false, false, false, false)) + { + foreach (var chunk in ctx.EntityIdsLoaded.Chunk()) + { + var entities = _orderRepository.Value.Table.Where(x => chunk.Contains(x.Id)).ToList(); + + entities.ForEach(x => x.OrderStatusId = (orderStatusId ?? x.OrderStatusId)); + + _dbContext.SaveChanges(); + } + } + + logger.Information("Updated order status for {0} order(s).".FormatInvariant(ctx.EntityIdsLoaded.Count())); + } + catch (Exception exception) + { + logger.ErrorsAll(exception); + ctx.Result.LastError = exception.ToString(); + } + } + } + } + + /// + /// The name of the public export folder + /// + public static string PublicFolder + { + get { return "Exchange"; } + } + + public static int PageSize + { + get { return 100; } + } + + public DataExportResult Export(DataExportRequest request, CancellationToken cancellationToken) + { + var ctx = new DataExporterContext(request, cancellationToken); + + ExportCoreOuter(ctx); + + cancellationToken.ThrowIfCancellationRequested(); + + return ctx.Result; + } + + public IList Preview(DataExportRequest request, int pageIndex, int? totalRecords = null) + { + var resultData = new List(); + var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); + + var ctx = new DataExporterContext(request, cancellation.Token, true); + + var unused = Init(ctx, totalRecords); + + if (!HasPermission(ctx)) + throw new SmartException(T("Admin.AccessDenied")); + + using (var segmenter = CreateSegmenter(ctx, pageIndex)) + { + if (segmenter == null) + { + throw new SmartException(T("Admin.Common.UnsupportedEntityType", ctx.Request.Provider.Value.EntityType.ToString())); + } + + while (segmenter.HasData) + { + segmenter.RecordPerSegmentCount = 0; + + while (segmenter.ReadNextSegment()) + { + resultData.AddRange(segmenter.CurrentSegment); + } + } + + DetachAllEntitiesAndClear(ctx); + } + + if (ctx.Result.LastError.HasValue()) + { + _services.Notifier.Error(ctx.Result.LastError); + } + + return resultData; + } + + public int GetDataCount(DataExportRequest request) + { + var cancellation = new CancellationTokenSource(TimeSpan.FromMinutes(5.0)); + + var ctx = new DataExporterContext(request, cancellation.Token, true); + + var unused = Init(ctx); + + var totalCount = ctx.RecordsPerStore.First().Value; + + return totalCount; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/DataDeploymentResult.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/DataDeploymentResult.cs new file mode 100644 index 0000000000..7fff7a46e5 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/DataDeploymentResult.cs @@ -0,0 +1,23 @@ +using System; + +namespace SmartStore.Services.DataExchange.Export.Deployment +{ + [Serializable] + public class DataDeploymentResult + { + /// + /// Whether the deployment succeeded + /// + public bool Succeeded + { + get { return LastError.IsEmpty(); } + } + + public string LastError { get; set; } + + /// + /// Last execution date + /// + public DateTime LastExecutionUtc { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/EmailFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/EmailFilePublisher.cs new file mode 100644 index 0000000000..298d476c41 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/EmailFilePublisher.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using System.Linq; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Email; +using SmartStore.Core.IO; +using SmartStore.Core.Logging; +using SmartStore.Services.Messages; + +namespace SmartStore.Services.DataExchange.Export.Deployment +{ + public class EmailFilePublisher : IFilePublisher + { + private IEmailAccountService _emailAccountService; + private IQueuedEmailService _queuedEmailService; + + public EmailFilePublisher( + IEmailAccountService emailAccountService, + IQueuedEmailService queuedEmailService) + { + _emailAccountService = emailAccountService; + _queuedEmailService = queuedEmailService; + } + + public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) + { + var emailAccount = _emailAccountService.GetEmailAccountById(deployment.EmailAccountId); + var smtpContext = new SmtpContext(emailAccount); + var count = 0; + + foreach (var email in deployment.EmailAddresses.SplitSafe(",").Where(x => x.IsEmail())) + { + var queuedEmail = new QueuedEmail + { + From = emailAccount.Email, + FromName = emailAccount.DisplayName, + SendManually = false, + To = email, + Subject = deployment.EmailSubject.NaIfEmpty(), + CreatedOnUtc = DateTime.UtcNow, + EmailAccountId = deployment.EmailAccountId + }; + + foreach (var path in context.GetDeploymentFiles()) + { + var name = Path.GetFileName(path); + + queuedEmail.Attachments.Add(new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Blob, + Data = File.ReadAllBytes(path), + Name = name, + MimeType = MimeTypes.MapNameToMimeType(name) + }); + } + + _queuedEmailService.InsertQueuedEmail(queuedEmail); + ++count; + } + + context.Log.Information("{0} email(s) created and queued for deployment.".FormatInvariant(count)); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/FileSystemFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/FileSystemFilePublisher.cs new file mode 100644 index 0000000000..6bb56682e1 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/FileSystemFilePublisher.cs @@ -0,0 +1,22 @@ +using System.IO; +using SmartStore.Core.Domain; +using SmartStore.Core.Logging; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Export.Deployment +{ + public class FileSystemFilePublisher : IFilePublisher + { + public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) + { + var targetFolder = deployment.GetDeploymentFolder(true); + + if (!FileSystemHelper.CopyDirectory(new DirectoryInfo(context.FolderContent), new DirectoryInfo(targetFolder))) + { + context.Result.LastError = context.T("Admin.DataExchange.Export.Deployment.CopyFileFailed"); + } + + context.Log.Information("Copied export data files to " + targetFolder); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/FtpFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/FtpFilePublisher.cs new file mode 100644 index 0000000000..7a0954a1c7 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/FtpFilePublisher.cs @@ -0,0 +1,74 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using SmartStore.Core.Domain; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.DataExchange.Export.Deployment +{ + public class FtpFilePublisher : IFilePublisher + { + public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) + { + var bytesRead = 0; + var succeededFiles = 0; + var url = deployment.Url; + var buffLength = 32768; + byte[] buff = new byte[buffLength]; + var deploymentFiles = context.GetDeploymentFiles().ToList(); + var lastIndex = (deploymentFiles.Count - 1); + + if (!url.StartsWith("ftp://", StringComparison.InvariantCultureIgnoreCase)) + url = "ftp://" + url; + + foreach (var path in deploymentFiles) + { + var fileUrl = url.EnsureEndsWith("/") + Path.GetFileName(path); + + var request = (FtpWebRequest)WebRequest.Create(fileUrl); + request.Method = WebRequestMethods.Ftp.UploadFile; + request.KeepAlive = (deploymentFiles.IndexOf(path) != lastIndex); + request.UseBinary = true; + request.Proxy = null; + request.UsePassive = deployment.PassiveMode; + request.EnableSsl = deployment.UseSsl; + + if (deployment.Username.HasValue()) + request.Credentials = new NetworkCredential(deployment.Username, deployment.Password); + + request.ContentLength = (new FileInfo(path)).Length; + + var requestStream = request.GetRequestStream(); + + using (var stream = new FileStream(path, FileMode.Open)) + { + while ((bytesRead = stream.Read(buff, 0, buffLength)) != 0) + { + requestStream.Write(buff, 0, bytesRead); + } + } + + requestStream.Close(); + + using (var response = (FtpWebResponse)request.GetResponse()) + { + var statusCode = (int)response.StatusCode; + + if (statusCode >= 200 && statusCode <= 299) + { + ++succeededFiles; + } + else + { + context.Result.LastError = context.T("Admin.Common.FtpStatus", statusCode, response.StatusCode.ToString()); + + context.Log.Error("The FTP transfer failed. FTP status {0} ({1}). File {3}".FormatInvariant(statusCode, response.StatusCode.ToString(), path)); + } + } + } + + context.Log.Information("{0} file(s) successfully uploaded via FTP.".FormatInvariant(succeededFiles)); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/HttpFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/HttpFilePublisher.cs new file mode 100644 index 0000000000..4f0d9df8d8 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/HttpFilePublisher.cs @@ -0,0 +1,77 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.DataExchange.Export.Deployment +{ + public class HttpFilePublisher : IFilePublisher + { + public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) + { + var succeededFiles = 0; + var url = deployment.Url; + + if (!url.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) && !url.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase)) + url = "http://" + url; + + if (deployment.HttpTransmissionType == ExportHttpTransmissionType.MultipartFormDataPost) + { + var countFiles = 0; + ICredentials credentials = null; + + if (deployment.Username.HasValue()) + credentials = new NetworkCredential(deployment.Username, deployment.Password); + + using (var handler = new HttpClientHandler { Credentials = credentials }) + using (var client = new HttpClient(handler)) + using (var formData = new MultipartFormDataContent()) + { + foreach (var path in context.GetDeploymentFiles()) + { + byte[] fileData = File.ReadAllBytes(path); + formData.Add(new ByteArrayContent(fileData), "file {0}".FormatInvariant(++countFiles), Path.GetFileName(path)); + } + + var response = client.PostAsync(url, formData).Result; + + if (response.IsSuccessStatusCode) + { + succeededFiles = countFiles; + } + else if (response.Content != null) + { + context.Result.LastError = context.T("Admin.Common.HttpStatus", (int)response.StatusCode, response.StatusCode.ToString()); + + var content = response.Content.ReadAsStringAsync().Result; + + var msg = "Multipart form data upload failed. HTTP status {0} ({1}). Response: {2}".FormatInvariant( + (int)response.StatusCode, response.StatusCode.ToString(), content.NaIfEmpty().Truncate(2000, "...")); + + context.Log.Error(msg); + } + } + } + else + { + using (var webClient = new WebClient()) + { + if (deployment.Username.HasValue()) + webClient.Credentials = new NetworkCredential(deployment.Username, deployment.Password); + + foreach (var path in context.GetDeploymentFiles()) + { + webClient.UploadFile(url, path); + + ++succeededFiles; + } + } + } + + context.Log.Information("{0} file(s) successfully uploaded via HTTP ({1}).".FormatInvariant(succeededFiles, deployment.HttpTransmissionType.ToString())); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/IFilePublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/IFilePublisher.cs new file mode 100644 index 0000000000..1ae3301ec4 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/IFilePublisher.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.IO; +using SmartStore.Core.Domain; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.DataExchange.Export.Deployment +{ + public interface IFilePublisher + { + void Publish(ExportDeploymentContext context, ExportDeployment deployment); + } + + + public class ExportDeploymentContext + { + public Localizer T { get; set; } + public ILogger Log { get; set; } + + public string FolderContent { get; set; } + + public string ZipPath { get; set; } + public bool CreateZipArchive { get; set; } + + public DataDeploymentResult Result { get; set; } + + public IEnumerable GetDeploymentFiles() + { + if (!CreateZipArchive) + { + return System.IO.Directory.EnumerateFiles(FolderContent, "*", SearchOption.AllDirectories); + } + + if (File.Exists(ZipPath)) + { + return new string[] { ZipPath }; + } + + return new string[0]; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/PublicFolderPublisher.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/PublicFolderPublisher.cs new file mode 100644 index 0000000000..d438e808a2 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Deployment/PublicFolderPublisher.cs @@ -0,0 +1,44 @@ +using System.IO; +using SmartStore.Core.Domain; +using SmartStore.Core.Logging; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Export.Deployment +{ + public class PublicFolderPublisher : IFilePublisher + { + public virtual void Publish(ExportDeploymentContext context, ExportDeployment deployment) + { + var destinationFolder = deployment.GetDeploymentFolder(true); + + if (destinationFolder.IsEmpty()) + return; + + if (!System.IO.Directory.Exists(destinationFolder)) + { + System.IO.Directory.CreateDirectory(destinationFolder); + } + + if (context.CreateZipArchive) + { + if (File.Exists(context.ZipPath)) + { + var destinationFile = Path.Combine(destinationFolder, Path.GetFileName(context.ZipPath)); + + File.Copy(context.ZipPath, destinationFile, true); + + context.Log.Information("Copied zipped export data to " + destinationFile); + } + } + else + { + if (!FileSystemHelper.CopyDirectory(new DirectoryInfo(context.FolderContent), new DirectoryInfo(destinationFolder))) + { + context.Result.LastError = context.T("Admin.DataExchange.Export.Deployment.CopyFileFailed"); + } + + context.Log.Information("Copied export data files to " + destinationFolder); + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/DynamicEntityHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/DynamicEntityHelper.cs new file mode 100644 index 0000000000..1917084af2 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/DynamicEntityHelper.cs @@ -0,0 +1,1327 @@ +using System; +using System.Collections.Generic; +using System.Data.Entity; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Web; +using SmartStore.ComponentModel; +using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Seo; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Html; +using SmartStore.Services.Catalog; +using SmartStore.Services.DataExchange.Export.Events; +using SmartStore.Services.DataExchange.Export.Internal; +using SmartStore.Services.Localization; +using SmartStore.Services.Seo; + +namespace SmartStore.Services.DataExchange.Export +{ + public partial class DataExporter + { + private void PrepareProductDescription(DataExporterContext ctx, dynamic dynObject, Product product) + { + try + { + var languageId = (ctx.Projection.LanguageId ?? 0); + string description = ""; + + // description merging + if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.None) + { + // export empty description + } + else if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.ShortDescriptionOrNameIfEmpty) + { + description = dynObject.FullDescription; + + if (description.IsEmpty()) + description = dynObject.ShortDescription; + if (description.IsEmpty()) + description = dynObject.Name; + } + else if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.ShortDescription) + { + description = dynObject.ShortDescription; + } + else if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.Description) + { + description = dynObject.FullDescription; + } + else if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.NameAndShortDescription) + { + description = ((string)dynObject.Name).Grow((string)dynObject.ShortDescription, " "); + } + else if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.NameAndDescription) + { + description = ((string)dynObject.Name).Grow((string)dynObject.FullDescription, " "); + } + else if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.ManufacturerAndNameAndShortDescription || + ctx.Projection.DescriptionMerging == ExportDescriptionMerging.ManufacturerAndNameAndDescription) + { + var productManus = ctx.ProductExportContext.ProductManufacturers.Load(product.Id); + + if (productManus != null && productManus.Any()) + description = productManus.First().Manufacturer.GetLocalized(x => x.Name, languageId, true, false); + + description = description.Grow((string)dynObject.Name, " "); + + if (ctx.Projection.DescriptionMerging == ExportDescriptionMerging.ManufacturerAndNameAndShortDescription) + description = description.Grow((string)dynObject.ShortDescription, " "); + else + description = description.Grow((string)dynObject.FullDescription, " "); + } + + // append text + if (ctx.Projection.AppendDescriptionText.HasValue() && ((string)dynObject.ShortDescription).IsEmpty() && ((string)dynObject.FullDescription).IsEmpty()) + { + string[] appendText = ctx.Projection.AppendDescriptionText.SplitSafe(","); + if (appendText.Length > 0) + { + var rnd = (new Random()).Next(0, appendText.Length - 1); + + description = description.Grow(appendText.SafeGet(rnd), " "); + } + } + + // remove critical characters + if (description.HasValue() && ctx.Projection.RemoveCriticalCharacters) + { + foreach (var str in ctx.Projection.CriticalCharacters.SplitSafe(",")) + description = description.Replace(str, ""); + } + + // convert to plain text + if (description.HasValue() && ctx.Projection.DescriptionToPlainText) + { + //Regex reg = new Regex("<[^>]+>", RegexOptions.IgnoreCase); + //description = HttpUtility.HtmlDecode(reg.Replace(description, "")); + + description = HtmlUtils.ConvertHtmlToPlainText(description); + description = HtmlUtils.StripTags(HttpUtility.HtmlDecode(description)); + } + + dynObject.FullDescription = description; + } + catch { } + } + + private decimal? ConvertPrice(DataExporterContext ctx, Product product, decimal? price) + { + if (price.HasValue) + { + if (ctx.Projection.ConvertNetToGrossPrices) + { + decimal taxRate; + price = _taxService.Value.GetProductPrice(product, price.Value, true, ctx.ContextCustomer, out taxRate); + } + + if (price != decimal.Zero) + { + price = _currencyService.Value.ConvertFromPrimaryStoreCurrency(price.Value, ctx.ContextCurrency, ctx.Store); + } + } + return price; + } + + private decimal CalculatePrice( + DataExporterContext ctx, + Product product, + ProductVariantAttributeCombination combination, + IList attributeValues) + { + var price = product.Price; + var priceCalculationContext = ctx.ProductExportContext as PriceCalculationContext; + + if (combination != null) + { + // price for attribute combination + var attributesTotalPriceBase = decimal.Zero; + + if (attributeValues != null) + { + attributeValues.Each(x => attributesTotalPriceBase += _priceCalculationService.Value.GetProductVariantAttributeValuePriceAdjustment(x)); + } + + price = _priceCalculationService.Value.GetFinalPrice(product, null, ctx.ContextCustomer, attributesTotalPriceBase, true, 1, null, priceCalculationContext); + } + else if (ctx.Projection.PriceType.HasValue) + { + // price for product + if (ctx.Projection.PriceType.Value == PriceDisplayType.LowestPrice) + { + bool displayFromMessage; + price = _priceCalculationService.Value.GetLowestPrice(product, priceCalculationContext, out displayFromMessage); + } + else if (ctx.Projection.PriceType.Value == PriceDisplayType.PreSelectedPrice) + { + price = _priceCalculationService.Value.GetPreselectedPrice(product, priceCalculationContext); + } + else if (ctx.Projection.PriceType.Value == PriceDisplayType.PriceWithoutDiscountsAndAttributes) + { + price = _priceCalculationService.Value.GetFinalPrice(product, null, ctx.ContextCustomer, decimal.Zero, false, 1, null, priceCalculationContext); + } + } + + return ConvertPrice(ctx, product, price) ?? price; + } + + private List GetLocalized(DataExporterContext ctx, T entity, params Expression>[] keySelectors) + where T : BaseEntity, ILocalizedEntity + { + if (ctx.Languages.Count <= 1) + return null; + + var localized = new List(); + + var localeKeyGroup = typeof(T).Name; + var isSlugSupported = typeof(ISlugSupported).IsAssignableFrom(typeof(T)); + + foreach (var language in ctx.Languages) + { + var languageCulture = language.Value.LanguageCulture.EmptyNull().ToLower(); + + // add SeName + if (isSlugSupported) + { + var value = _urlRecordService.Value.GetActiveSlug(entity.Id, localeKeyGroup, language.Value.Id); + if (value.HasValue()) + { + dynamic exp = new HybridExpando(); + exp.Culture = languageCulture; + exp.LocaleKey = "SeName"; + exp.LocaleValue = value; + + localized.Add(exp); + } + } + + foreach (var keySelector in keySelectors) + { + var member = keySelector.Body as MemberExpression; + var propInfo = member.Member as PropertyInfo; + string localeKey = propInfo.Name; + var value = _localizedEntityService.Value.GetLocalizedValue(language.Value.Id, entity.Id, localeKeyGroup, localeKey); + + // we better not export empty values. the risk is to high that they are imported and unnecessary fill databases. + if (value.HasValue()) + { + dynamic exp = new HybridExpando(); + exp.Culture = languageCulture; + exp.LocaleKey = localeKey; + exp.LocaleValue = value; + + localized.Add(exp); + } + } + } + + return (localized.Count == 0 ? null : localized); + } + + private dynamic ToDynamic(DataExporterContext ctx, Currency currency) + { + if (currency == null) + return null; + + dynamic result = new DynamicEntity(currency); + + result.Name = currency.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + result._Localized = GetLocalized(ctx, currency, x => x.Name); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Language language) + { + if (language == null) + return null; + + dynamic result = new DynamicEntity(language); + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Country country) + { + if (country == null) + return null; + + dynamic result = new DynamicEntity(country); + + result.Name = country.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + result._Localized = GetLocalized(ctx, country, x => x.Name); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Address address) + { + if (address == null) + return null; + + dynamic result = new DynamicEntity(address); + + result.Country = ToDynamic(ctx, address.Country); + + if (address.StateProvinceId.GetValueOrDefault() > 0) + { + dynamic sp = new DynamicEntity(address.StateProvince); + + sp.Name = address.StateProvince.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + sp._Localized = GetLocalized(ctx, address.StateProvince, x => x.Name); + + result.StateProvince = sp; + } + else + { + result.StateProvince = null; + } + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, RewardPointsHistory points) + { + if (points == null) + return null; + + dynamic result = new DynamicEntity(points); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Customer customer) + { + if (customer == null) + return null; + + dynamic result = new DynamicEntity(customer); + + result.BillingAddress = null; + result.ShippingAddress = null; + result.Addresses = null; + result.CustomerRoles = null; + + result.RewardPointsHistory = null; + result._RewardPointsBalance = 0; + + result._GenericAttributes = null; + result._HasNewsletterSubscription = false; + + result._FullName = null; + result._AvatarPictureUrl = null; + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Store store) + { + if (store == null) + return null; + + dynamic result = new DynamicEntity(store); + + result.PrimaryStoreCurrency = ToDynamic(ctx, store.PrimaryStoreCurrency); + result.PrimaryExchangeRateCurrency = ToDynamic(ctx, store.PrimaryExchangeRateCurrency); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, DeliveryTime deliveryTime) + { + if (deliveryTime == null) + return null; + + dynamic result = new DynamicEntity(deliveryTime); + + result.Name = deliveryTime.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + result._Localized = GetLocalized(ctx, deliveryTime, x => x.Name); + + return result; + } + + private void ToDeliveryTime(DataExporterContext ctx, dynamic parent, int? deliveryTimeId) + { + if (ctx.DeliveryTimes != null) + { + if (deliveryTimeId.HasValue && ctx.DeliveryTimes.ContainsKey(deliveryTimeId.Value)) + parent.DeliveryTime = ToDynamic(ctx, ctx.DeliveryTimes[deliveryTimeId.Value]); + else + parent.DeliveryTime = null; + } + } + + private dynamic ToDynamic(DataExporterContext ctx, QuantityUnit quantityUnit) + { + if (quantityUnit == null) + return null; + + dynamic result = new DynamicEntity(quantityUnit); + + result.Name = quantityUnit.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + result.Description = quantityUnit.GetLocalized(x => x.Description, ctx.Projection.LanguageId ?? 0, true, false); + + result._Localized = GetLocalized(ctx, quantityUnit, + x => x.Name, + x => x.Description); + + return result; + } + + private void ToQuantityUnit(DataExporterContext ctx, dynamic parent, int? quantityUnitId) + { + if (ctx.QuantityUnits != null) + { + if (quantityUnitId.HasValue && ctx.QuantityUnits.ContainsKey(quantityUnitId.Value)) + parent.QuantityUnit = ToDynamic(ctx, ctx.QuantityUnits[quantityUnitId.Value]); + else + parent.QuantityUnit = null; + } + } + + private dynamic ToDynamic(DataExporterContext ctx, Picture picture, int thumbPictureSize, int detailsPictureSize) + { + if (picture == null) + return null; + + dynamic result = new DynamicEntity(picture); + var relativeUrl = _pictureService.Value.GetPictureUrl(picture, 0, false); + + result._FileName = relativeUrl.Substring(relativeUrl.LastIndexOf("/") + 1); + result._RelativeUrl = relativeUrl; + result._ThumbImageUrl = _pictureService.Value.GetPictureUrl(picture, thumbPictureSize, false, ctx.Store.Url); + result._ImageUrl = _pictureService.Value.GetPictureUrl(picture, detailsPictureSize, false, ctx.Store.Url); + result._FullSizeImageUrl = _pictureService.Value.GetPictureUrl(picture, 0, false, ctx.Store.Url); + + result._ThumbLocalPath = _pictureService.Value.GetThumbLocalPath(picture); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, ProductVariantAttribute pva) + { + if (pva == null) + return null; + + dynamic result = new DynamicEntity(pva); + + dynamic attribute = new DynamicEntity(pva.ProductAttribute); + + attribute.Name = pva.ProductAttribute.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + attribute.Description = pva.ProductAttribute.GetLocalized(x => x.Description, ctx.Projection.LanguageId ?? 0, true, false); + + attribute.Values = pva.ProductVariantAttributeValues + .OrderBy(x => x.DisplayOrder) + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + dyn.Name = x.GetLocalized(y => y.Name, ctx.Projection.LanguageId ?? 0, true, false); + dyn._Localized = GetLocalized(ctx, x, y => y.Name); + + return dyn; + }) + .ToList(); + + attribute._Localized = GetLocalized(ctx, pva.ProductAttribute, + x => x.Name, + x => x.Description); + + result.Attribute = attribute; + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, ProductVariantAttributeCombination pvac) + { + if (pvac == null) + return null; + + dynamic result = new DynamicEntity(pvac); + + ToDeliveryTime(ctx, result, pvac.DeliveryTimeId); + ToQuantityUnit(ctx, result, pvac.QuantityUnitId); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Manufacturer manufacturer) + { + if (manufacturer == null) + return null; + + dynamic result = new DynamicEntity(manufacturer); + + result.Name = manufacturer.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + result.SeName = manufacturer.GetSeName(ctx.Projection.LanguageId ?? 0, true, false); + result.Description = manufacturer.GetLocalized(x => x.Description, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaKeywords = manufacturer.GetLocalized(x => x.MetaKeywords, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaDescription = manufacturer.GetLocalized(x => x.MetaDescription, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaTitle = manufacturer.GetLocalized(x => x.MetaTitle, ctx.Projection.LanguageId ?? 0, true, false); + + result.Picture = null; + + result._Localized = GetLocalized(ctx, manufacturer, + x => x.Name, + x => x.Description, + x => x.MetaKeywords, + x => x.MetaDescription, + x => x.MetaTitle); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Category category) + { + if (category == null) + return null; + + dynamic result = new DynamicEntity(category); + + result.Name = category.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + result.SeName = category.GetSeName(ctx.Projection.LanguageId ?? 0, true, false); + result.FullName = category.GetLocalized(x => x.FullName, ctx.Projection.LanguageId ?? 0, true, false); + result.Description = category.GetLocalized(x => x.Description, ctx.Projection.LanguageId ?? 0, true, false); + result.BottomDescription = category.GetLocalized(x => x.BottomDescription, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaKeywords = category.GetLocalized(x => x.MetaKeywords, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaDescription = category.GetLocalized(x => x.MetaDescription, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaTitle = category.GetLocalized(x => x.MetaTitle, ctx.Projection.LanguageId ?? 0, true, false); + + result.Picture = null; + + if (ctx.CategoryTemplates.ContainsKey(category.CategoryTemplateId)) + result._CategoryTemplateViewPath = ctx.CategoryTemplates[category.CategoryTemplateId]; + else + result._CategoryTemplateViewPath = ""; + + result._Localized = GetLocalized(ctx, category, + x => x.Name, + x => x.FullName, + x => x.Description, + x => x.BottomDescription, + x => x.MetaKeywords, + x => x.MetaDescription, + x => x.MetaTitle); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Product product) + { + if (product == null) + return null; + + dynamic result = new DynamicEntity(product); + + result.Name = product.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + result.SeName = product.GetSeName(ctx.Projection.LanguageId ?? 0, true, false); + result.ShortDescription = product.GetLocalized(x => x.ShortDescription, ctx.Projection.LanguageId ?? 0, true, false); + result.FullDescription = product.GetLocalized(x => x.FullDescription, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaKeywords = product.GetLocalized(x => x.MetaKeywords, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaDescription = product.GetLocalized(x => x.MetaDescription, ctx.Projection.LanguageId ?? 0, true, false); + result.MetaTitle = product.GetLocalized(x => x.MetaTitle, ctx.Projection.LanguageId ?? 0, true, false); + result.BundleTitleText = product.GetLocalized(x => x.BundleTitleText, ctx.Projection.LanguageId ?? 0, true, false); + + result.AppliedDiscounts = null; + result.TierPrices = null; + result.ProductAttributes = null; + result.ProductAttributeCombinations = null; + result.ProductPictures = null; + result.ProductCategories = null; + result.ProductManufacturers = null; + result.ProductTags = null; + result.ProductSpecificationAttributes = null; + result.ProductBundleItems = null; + + result._Localized = GetLocalized(ctx, product, + x => x.Name, + x => x.ShortDescription, + x => x.FullDescription, + x => x.MetaKeywords, + x => x.MetaDescription, + x => x.MetaTitle, + x => x.BundleTitleText); + + return result; + } + + private dynamic ToDynamic( + DataExporterContext ctx, + Product product, + ICollection combinations, + ProductVariantAttributeCombination combination) + { + product.MergeWithCombination(combination); + + var languageId = (ctx.Projection.LanguageId ?? 0); + var pictureSize = _mediaSettings.Value.ProductDetailsPictureSize; + var numberOfPictures = (ctx.Projection.NumberOfPictures ?? int.MaxValue); + int[] pictureIds = (combination == null ? new int[0] : combination.GetAssignedPictureIds()); + + if (ctx.Supports(ExportFeatures.CanIncludeMainPicture) && ctx.Projection.PictureSize > 0) + pictureSize = ctx.Projection.PictureSize; + + var perfLoadId = (ctx.IsPreview ? 0 : product.Id); // perf preview (it's a compromise) + IEnumerable productPictures = ctx.ProductExportContext.ProductPictures.Load(perfLoadId); + var productManufacturers = ctx.ProductExportContext.ProductManufacturers.Load(perfLoadId); + var productCategories = ctx.ProductExportContext.ProductCategories.Load(product.Id); + var productAttributes = ctx.ProductExportContext.Attributes.Load(product.Id); + var productTags = ctx.ProductExportContext.ProductTags.Load(product.Id); + var specificationAttributes = ctx.ProductExportContext.ProductSpecificationAttributes.Load(product.Id); + + var variantAttributes = (combination != null ? _productAttributeParser.Value.DeserializeProductVariantAttributes(combination.AttributesXml) : null); + var variantAttributeValues = (combination != null ? _productAttributeParser.Value.ParseProductVariantAttributeValues(variantAttributes, productAttributes) : null); + + if (pictureIds.Length > 0) + productPictures = productPictures.Where(x => pictureIds.Contains(x.PictureId)); + + productPictures = productPictures.Take(numberOfPictures); + + dynamic dynObject = ToDynamic(ctx, product); + + #region gerneral data + + dynObject._CategoryName = null; + dynObject._CategoryPath = null; + dynObject._AttributeCombination = null; + dynObject._AttributeCombinationValues = null; + dynObject._AttributeCombinationId = (combination == null ? 0 : combination.Id); + dynObject._DetailUrl = ctx.Store.Url.EnsureEndsWith("/") + (string)dynObject.SeName; + + if (combination == null) + dynObject._UniqueId = product.Id.ToString(); + else + dynObject._UniqueId = string.Concat(product.Id, "-", combination.Id); + + dynObject.Price = CalculatePrice(ctx, product, combination, variantAttributeValues); + + dynObject._BasePriceInfo = product.GetBasePriceInfo(_services.Localization, _priceFormatter.Value, _currencyService.Value, _taxService.Value, + _priceCalculationService.Value, ctx.ContextCurrency, decimal.Zero, true); + + if (ctx.ProductTemplates.ContainsKey(product.ProductTemplateId)) + dynObject._ProductTemplateViewPath = ctx.ProductTemplates[product.ProductTemplateId]; + else + dynObject._ProductTemplateViewPath = ""; + + if (combination != null) + { + if (ctx.Supports(ExportFeatures.UsesAttributeCombination)) + { + dynObject._AttributeCombination = variantAttributes; + dynObject._AttributeCombinationValues = variantAttributeValues; + } + + if (ctx.Projection.AttributeCombinationValueMerging == ExportAttributeValueMerging.AppendAllValuesToName) + { + var valueNames = variantAttributeValues + .Select(x => x.GetLocalized(y => y.Name, languageId, true, false)) + .ToList(); + + dynObject.Name = ((string)dynObject.Name).Grow(string.Join(", ", valueNames), " "); + } + + var attributeQueryString = _productAttributeParser.Value.SerializeQueryData(combination.AttributesXml, product.Id); + if (attributeQueryString.HasValue()) + { + var url = (string)dynObject._DetailUrl; + dynObject._DetailUrl = string.Concat(url, url.Contains("?") ? "&" : "?", "attributes=", attributeQueryString); + } + } + + if (ctx.Categories.Count > 0) + { + dynObject._CategoryPath = _categoryService.Value.GetCategoryPath( + product, + null, + x => ctx.CategoryPathes.ContainsKey(x) ? ctx.CategoryPathes[x] : null, + (id, value) => ctx.CategoryPathes[id] = value, + x => ctx.Categories.ContainsKey(x) ? ctx.Categories[x] : _categoryService.Value.GetCategoryById(x), + productCategories.OrderBy(x => x.DisplayOrder).FirstOrDefault() + ); + } + + ToDeliveryTime(ctx, dynObject, product.DeliveryTimeId); + ToQuantityUnit(ctx, dynObject, product.QuantityUnitId); + + dynObject.ProductPictures = productPictures + .OrderBy(x => x.DisplayOrder) + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + dyn.Picture = ToDynamic(ctx, x.Picture, _mediaSettings.Value.ProductThumbPictureSize, pictureSize); + + return dyn; + }) + .ToList(); + + dynObject.ProductManufacturers = productManufacturers + .OrderBy(x => x.DisplayOrder) + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + dyn.Manufacturer = ToDynamic(ctx, x.Manufacturer); + + if (x.Manufacturer != null && x.Manufacturer.PictureId.HasValue) + dyn.Manufacturer.Picture = ToDynamic(ctx, x.Manufacturer.Picture, _mediaSettings.Value.ManufacturerThumbPictureSize, _mediaSettings.Value.ManufacturerThumbPictureSize); + else + dyn.Manufacturer.Picture = null; + + return dyn; + }) + .ToList(); + + dynObject.ProductCategories = productCategories + .OrderBy(x => x.DisplayOrder) + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + dyn.Category = ToDynamic(ctx, x.Category); + + if (x.Category != null && x.Category.PictureId.HasValue) + dyn.Category.Picture = ToDynamic(ctx, x.Category.Picture, _mediaSettings.Value.CategoryThumbPictureSize, _mediaSettings.Value.CategoryThumbPictureSize); + + if (dynObject._CategoryName == null) + dynObject._CategoryName = (string)dyn.Category.Name; + + return dyn; + }) + .ToList(); + + dynObject.ProductAttributes = productAttributes + .OrderBy(x => x.DisplayOrder) + .Select(x => ToDynamic(ctx, x)) + .ToList(); + + dynObject.ProductAttributeCombinations = (combinations ?? Enumerable.Empty()) + .Select(x => + { + dynamic dyn = ToDynamic(ctx, x); + var assignedPictures = new List(); + + foreach (int pictureId in x.GetAssignedPictureIds().Take(numberOfPictures)) + { + var assignedPicture = productPictures.FirstOrDefault(y => y.PictureId == pictureId); + if (assignedPicture != null && assignedPicture.Picture != null) + { + assignedPictures.Add(ToDynamic(ctx, assignedPicture.Picture, _mediaSettings.Value.ProductThumbPictureSize, pictureSize)); + } + } + + dyn.Pictures = assignedPictures; + + return dyn; + }) + .ToList(); + + if (product.HasTierPrices) + { + var tierPrices = ctx.ProductExportContext.TierPrices.Load(product.Id) + .RemoveDuplicatedQuantities(); + + dynObject.TierPrices = tierPrices + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + return dyn; + }) + .ToList(); + } + + if (product.HasDiscountsApplied) + { + var appliedDiscounts = ctx.ProductExportContext.AppliedDiscounts.Load(product.Id); + + dynObject.AppliedDiscounts = appliedDiscounts + .Select(x => ToDynamic(ctx, x)) + .ToList(); + } + + dynObject.ProductTags = productTags + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + dyn.Name = x.GetLocalized(y => y.Name, languageId, true, false); + dyn.SeName = x.GetSeName(languageId); + dyn._Localized = GetLocalized(ctx, x, y => y.Name); + + return dyn; + }) + .ToList(); + + dynObject.ProductSpecificationAttributes = specificationAttributes + .Select(x => ToDynamic(ctx, x)) + .ToList(); + + if (product.ProductType == ProductType.BundledProduct) + { + var bundleItems = ctx.ProductExportContext.ProductBundleItems.Load(perfLoadId); + + dynObject.ProductBundleItems = bundleItems + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + dyn.Name = x.GetLocalized(y => y.Name, languageId, true, false); + dyn.ShortDescription = x.GetLocalized(y => y.ShortDescription, languageId, true, false); + dyn._Localized = GetLocalized(ctx, x, y => y.Name, y => y.ShortDescription); + + return dyn; + }) + .ToList(); + } + + #endregion + + #region more attribute controlled data + + if (ctx.Supports(ExportFeatures.CanProjectDescription)) + { + PrepareProductDescription(ctx, dynObject, product); + } + + if (ctx.Supports(ExportFeatures.OffersBrandFallback)) + { + string brand = null; + var productManus = ctx.ProductExportContext.ProductManufacturers.Load(perfLoadId); + + if (productManus != null && productManus.Any()) + brand = productManus.First().Manufacturer.GetLocalized(x => x.Name, languageId, true, false); + + if (brand.IsEmpty()) + brand = ctx.Projection.Brand; + + dynObject._Brand = brand; + } + + if (ctx.Supports(ExportFeatures.CanIncludeMainPicture)) + { + if (productPictures != null && productPictures.Any()) + { + var firstPicture = productPictures.First().Picture; + dynObject._MainPictureUrl = _pictureService.Value.GetPictureUrl(firstPicture, ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); + dynObject._MainPictureRelativeUrl = _pictureService.Value.GetPictureUrl(firstPicture, ctx.Projection.PictureSize); + } + else if (!_catalogSettings.Value.HideProductDefaultPictures) + { + dynObject._MainPictureUrl = _pictureService.Value.GetDefaultPictureUrl(ctx.Projection.PictureSize, storeLocation: ctx.Store.Url); + dynObject._MainPictureRelativeUrl = _pictureService.Value.GetDefaultPictureUrl(ctx.Projection.PictureSize); + } + else + { + dynObject._MainPictureUrl = null; + dynObject._MainPictureRelativeUrl = null; + } + } + + if (ctx.Supports(ExportFeatures.UsesSkuAsMpnFallback) && product.ManufacturerPartNumber.IsEmpty()) + { + dynObject.ManufacturerPartNumber = product.Sku; + } + + if (ctx.Supports(ExportFeatures.OffersShippingTimeFallback)) + { + dynamic deliveryTime = dynObject.DeliveryTime; + dynObject._ShippingTime = (deliveryTime == null ? ctx.Projection.ShippingTime : deliveryTime.Name); + } + + if (ctx.Supports(ExportFeatures.OffersShippingCostsFallback)) + { + dynObject._FreeShippingThreshold = ctx.Projection.FreeShippingThreshold; + + if (product.IsFreeShipping || (ctx.Projection.FreeShippingThreshold.HasValue && (decimal)dynObject.Price >= ctx.Projection.FreeShippingThreshold.Value)) + dynObject._ShippingCosts = decimal.Zero; + else + dynObject._ShippingCosts = ctx.Projection.ShippingCosts; + } + + if (ctx.Supports(ExportFeatures.UsesOldPrice)) + { + if (product.OldPrice != decimal.Zero && product.OldPrice != (decimal)dynObject.Price && !(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) + { + if (ctx.Projection.ConvertNetToGrossPrices) + { + decimal taxRate; + dynObject._OldPrice = _taxService.Value.GetProductPrice(product, product.OldPrice, true, ctx.ContextCustomer, out taxRate); + } + else + { + dynObject._OldPrice = product.OldPrice; + } + } + else + { + dynObject._OldPrice = null; + } + } + + if (ctx.Supports(ExportFeatures.UsesSpecialPrice)) + { + dynObject._SpecialPrice = null; // special price which is valid now + dynObject._FutureSpecialPrice = null; // special price which is valid now and in future + dynObject._RegularPrice = null; // price as if a special price would not exist + + if (!(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) + { + if (product.SpecialPrice.HasValue && product.SpecialPriceEndDateTimeUtc.HasValue) + { + var endDate = DateTime.SpecifyKind(product.SpecialPriceEndDateTimeUtc.Value, DateTimeKind.Utc); + if (endDate > DateTime.UtcNow) + { + dynObject._FutureSpecialPrice = ConvertPrice(ctx, product, product.SpecialPrice.Value); + } + } + + var specialPrice = _priceCalculationService.Value.GetSpecialPrice(product); + + dynObject._SpecialPrice = ConvertPrice(ctx, product, specialPrice); + + if (specialPrice.HasValue || dynObject._FutureSpecialPrice != null) + { + decimal tmpSpecialPrice = product.SpecialPrice.Value; + product.SpecialPrice = null; + + dynObject._RegularPrice = CalculatePrice(ctx, product, combination, variantAttributeValues); + + product.SpecialPrice = tmpSpecialPrice; + } + } + } + + #endregion + + return dynObject; + } + + private dynamic ToDynamic(DataExporterContext ctx, Order order) + { + if (order == null) + return null; + + dynamic result = new DynamicEntity(order); + + result.OrderNumber = order.GetOrderNumber(); + result.OrderStatus = order.OrderStatus.GetLocalizedEnum(_services.Localization, ctx.Projection.LanguageId ?? 0); + result.PaymentStatus = order.PaymentStatus.GetLocalizedEnum(_services.Localization, ctx.Projection.LanguageId ?? 0); + result.ShippingStatus = order.ShippingStatus.GetLocalizedEnum(_services.Localization, ctx.Projection.LanguageId ?? 0); + + result.Customer = null; + result.BillingAddress = null; + result.ShippingAddress = null; + result.Store = null; + result.Shipments = null; + + result.RedeemedRewardPointsEntry = ToDynamic(ctx, order.RedeemedRewardPointsEntry); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, OrderItem orderItem) + { + if (orderItem == null) + return null; + + dynamic result = new DynamicEntity(orderItem); + + orderItem.Product.MergeWithCombination(orderItem.AttributesXml, _productAttributeParser.Value); + + result.Product = ToDynamic(ctx, orderItem.Product); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Shipment shipment) + { + if (shipment == null) + return null; + + dynamic result = new DynamicEntity(shipment); + + result.ShipmentItems = shipment.ShipmentItems + .Select(x => + { + dynamic exp = new DynamicEntity(x); + + return exp; + }) + .ToList(); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, Discount discount) + { + if (discount == null) + return null; + + dynamic result = new DynamicEntity(discount); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, ProductSpecificationAttribute psa) + { + if (psa == null) + return null; + + var option = psa.SpecificationAttributeOption; + + dynamic result = new DynamicEntity(psa); + + dynamic dynAttribute = new DynamicEntity(option.SpecificationAttribute); + + dynAttribute.Name = option.SpecificationAttribute.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + dynAttribute._Localized = GetLocalized(ctx, option.SpecificationAttribute, x => x.Name); + + dynamic dynOption = new DynamicEntity(option); + + dynOption.Name = option.GetLocalized(x => x.Name, ctx.Projection.LanguageId ?? 0, true, false); + dynOption._Localized = GetLocalized(ctx, option, x => x.Name); + + dynOption.SpecificationAttribute = dynAttribute; + + result.SpecificationAttributeOption = dynOption; + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, GenericAttribute genericAttribute) + { + if (genericAttribute == null) + return null; + + dynamic result = new DynamicEntity(genericAttribute); + + return result; + } + + private dynamic ToDynamic(DataExporterContext ctx, NewsLetterSubscription subscription) + { + if (subscription == null) + return null; + + dynamic result = new DynamicEntity(subscription); + + return result; + } + + + private List Convert(DataExporterContext ctx, Product product) + { + var result = new List(); + + var combinations = ctx.ProductExportContext.AttributeCombinations.Load(product.Id); + + if (!ctx.IsPreview && ctx.Projection.AttributeCombinationAsProduct && combinations.Where(x => x.IsActive).Count() > 0) + { + //var productType = typeof(Product); + //var productValues = new Dictionary(); + var dbContext = _dbContext as DbContext; + + foreach (var combination in combinations.Where(x => x.IsActive)) + { + product = _dbContext.Attach(product); + var entry = dbContext.Entry(product); + + // the returned object is not the entity and is not being tracked by the context. + // it also does not have any relationships set to other objects. + // CurrentValues only includes database (thus primitive) values. + var productClone = entry.CurrentValues.ToObject() as Product; + _dbContext.DetachEntity(product); + + var dynObject = ToDynamic(ctx, productClone, combinations, combination); + result.Add(dynObject); + } + } + else + { + var dynObject = ToDynamic(ctx, product, combinations, null); + result.Add(dynObject); + } + + if (result.Any()) + { + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = result.First(), + EntityType = ExportEntityType.Product, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + } + + return result; + } + + private List Convert(DataExporterContext ctx, Order order) + { + var result = new List(); + + if (!ctx.IsPreview) + { + ctx.OrderExportContext.Addresses.Collect(order.ShippingAddressId.HasValue ? order.ShippingAddressId.Value : 0); + ctx.OrderExportContext.Addresses.Load(order.BillingAddressId); + } + + var perfLoadId = (ctx.IsPreview ? 0 : order.Id); + var customers = ctx.OrderExportContext.Customers.Load(order.CustomerId); + var rewardPointsHistories = ctx.OrderExportContext.RewardPointsHistories.Load(ctx.IsPreview ? 0 : order.CustomerId); + var orderItems = ctx.OrderExportContext.OrderItems.Load(perfLoadId); + var shipments = ctx.OrderExportContext.Shipments.Load(perfLoadId); + + dynamic dynObject = ToDynamic(ctx, order); + + if (ctx.Stores.ContainsKey(order.StoreId)) + { + dynObject.Store = ToDynamic(ctx, ctx.Stores[order.StoreId]); + } + + dynObject.Customer = ToDynamic(ctx, customers.FirstOrDefault(x => x.Id == order.CustomerId)); + + dynObject.Customer.RewardPointsHistory = rewardPointsHistories + .Select(x => ToDynamic(ctx, x)) + .ToList(); + + if (rewardPointsHistories.Count > 0) + { + dynObject.Customer._RewardPointsBalance = rewardPointsHistories + .OrderByDescending(x => x.CreatedOnUtc) + .ThenByDescending(x => x.Id) + .FirstOrDefault() + .PointsBalance; + } + + if (ctx.OrderExportContext.Addresses.ContainsKey(order.BillingAddressId)) + { + dynObject.BillingAddress = ToDynamic(ctx, ctx.OrderExportContext.Addresses[order.BillingAddressId].FirstOrDefault()); + } + + if (order.ShippingAddressId.HasValue && ctx.OrderExportContext.Addresses.ContainsKey(order.ShippingAddressId.Value)) + { + dynObject.ShippingAddress = ToDynamic(ctx, ctx.OrderExportContext.Addresses[order.ShippingAddressId.Value].FirstOrDefault()); + } + + dynObject.OrderItems = orderItems + .Select(e => + { + dynamic dyn = ToDynamic(ctx, e); + + if (ctx.ProductTemplates.ContainsKey(e.Product.ProductTemplateId)) + dyn.Product._ProductTemplateViewPath = ctx.ProductTemplates[e.Product.ProductTemplateId]; + else + dyn.Product._ProductTemplateViewPath = ""; + + dyn.Product._BasePriceInfo = e.Product.GetBasePriceInfo(_services.Localization, _priceFormatter.Value, _currencyService.Value, _taxService.Value, + _priceCalculationService.Value, ctx.ContextCurrency, decimal.Zero, true); + + ToDeliveryTime(ctx, dyn.Product, e.Product.DeliveryTimeId); + ToQuantityUnit(ctx, dyn.Product, e.Product.QuantityUnitId); + + return dyn; + }) + .ToList(); + + dynObject.Shipments = shipments + .Select(x => ToDynamic(ctx, x)) + .ToList(); + + result.Add(dynObject); + + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Order, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + + return result; + } + + private List Convert(DataExporterContext ctx, Manufacturer manufacturer) + { + var result = new List(); + + var productManufacturers = ctx.ManufacturerExportContext.ProductManufacturers.Load(manufacturer.Id); + + dynamic dynObject = ToDynamic(ctx, manufacturer); + + if (!ctx.IsPreview && manufacturer.PictureId.HasValue) + { + var numberOfPictures = (ctx.Projection.NumberOfPictures ?? int.MaxValue); + var pictures = ctx.ManufacturerExportContext.Pictures.Load(manufacturer.PictureId.Value).Take(numberOfPictures); + + if (pictures.Any()) + dynObject.Picture = ToDynamic(ctx, pictures.First(), _mediaSettings.Value.ManufacturerThumbPictureSize, _mediaSettings.Value.ManufacturerThumbPictureSize); + } + + dynObject.ProductManufacturers = productManufacturers + .OrderBy(x => x.DisplayOrder) + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + return dyn; + }) + .ToList(); + + result.Add(dynObject); + + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Manufacturer, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + + return result; + } + + private List Convert(DataExporterContext ctx, Category category) + { + var result = new List(); + + var productCategories = ctx.CategoryExportContext.ProductCategories.Load(category.Id); + + dynamic dynObject = ToDynamic(ctx, category); + + if (!ctx.IsPreview && category.PictureId.HasValue) + { + var numberOfPictures = (ctx.Projection.NumberOfPictures ?? int.MaxValue); + var pictures = ctx.CategoryExportContext.Pictures.Load(category.PictureId.Value).Take(numberOfPictures); + + if (pictures.Any()) + dynObject.Picture = ToDynamic(ctx, pictures.First(), _mediaSettings.Value.CategoryThumbPictureSize, _mediaSettings.Value.CategoryThumbPictureSize); + } + + dynObject.ProductCategories = productCategories + .OrderBy(x => x.DisplayOrder) + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + return dyn; + }) + .ToList(); + + result.Add(dynObject); + + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Category, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + + return result; + } + + private List Convert(DataExporterContext ctx, Customer customer) + { + var result = new List(); + + var perfLoadId = (ctx.IsPreview ? 0 : customer.Id); + var genericAttributes = ctx.CustomerExportContext.GenericAttributes.Load(perfLoadId); + + dynamic dynObject = ToDynamic(ctx, customer); + + dynObject.BillingAddress = ToDynamic(ctx, customer.BillingAddress); + dynObject.ShippingAddress = ToDynamic(ctx, customer.ShippingAddress); + + dynObject.Addresses = customer.Addresses + .Select(x => ToDynamic(ctx, x)) + .ToList(); + + dynObject.CustomerRoles = customer.CustomerRoles + .Select(x => + { + dynamic dyn = new DynamicEntity(x); + + return dyn; + }) + .ToList(); + + dynObject._GenericAttributes = genericAttributes + .Select(x => ToDynamic(ctx, x)) + .ToList(); + + dynObject._HasNewsletterSubscription = ctx.NewsletterSubscriptions.Contains(customer.Email, StringComparer.CurrentCultureIgnoreCase); + + var attrFirstName = genericAttributes.FirstOrDefault(x => x.Key == SystemCustomerAttributeNames.FirstName); + var attrLastName = genericAttributes.FirstOrDefault(x => x.Key == SystemCustomerAttributeNames.LastName); + + string firstName = (attrFirstName == null ? "" : attrFirstName.Value); + string lastName = (attrLastName == null ? "" : attrLastName.Value); + + if (firstName.IsEmpty() && lastName.IsEmpty()) + { + var address = customer.Addresses.FirstOrDefault(); + if (address != null) + { + firstName = address.FirstName; + lastName = address.LastName; + } + } + + dynObject._FullName = firstName.Grow(lastName, " "); + + if (_customerSettings.Value.AllowCustomersToUploadAvatars) + { + var pictureId = genericAttributes.FirstOrDefault(x => x.Key == SystemCustomerAttributeNames.AvatarPictureId); + if (pictureId != null) + { + // reduce traffic and do not export default avatar + dynObject._AvatarPictureUrl = _pictureService.Value.GetPictureUrl(pictureId.Value.ToInt(), _mediaSettings.Value.AvatarPictureSize, false, ctx.Store.Url); + } + } + + result.Add(dynObject); + + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.Customer, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + + return result; + } + + private List Convert(DataExporterContext ctx, NewsLetterSubscription subscription) + { + var result = new List(); + dynamic dynObject = ToDynamic(ctx, subscription); + result.Add(dynObject); + + _services.EventPublisher.Publish(new RowExportingEvent + { + Row = dynObject, + EntityType = ExportEntityType.NewsLetterSubscription, + ExportRequest = ctx.Request, + ExecuteContext = ctx.ExecuteContext + }); + + + return result; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Events/RowExportingEvent.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Events/RowExportingEvent.cs new file mode 100644 index 0000000000..0b96526e00 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Events/RowExportingEvent.cs @@ -0,0 +1,35 @@ +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange.Export.Events +{ + // TODO: Another event message must be implemented, say 'ColumnsBuildingEvent' + // The consumer of this event (most likely a plugin) could push a list of specific column headers + // into the global export definition. + + public class RowExportingEvent + { + public dynamic Row + { + get; + internal set; + } + + public ExportEntityType EntityType + { + get; + internal set; + } + + public DataExportRequest ExportRequest + { + get; + internal set; + } + + public ExportExecuteContext ExecuteContext + { + get; + internal set; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportConfigurationInfo.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportConfigurationInfo.cs new file mode 100644 index 0000000000..2cfb17796d --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportConfigurationInfo.cs @@ -0,0 +1,25 @@ +using System; + +namespace SmartStore.Services.DataExchange.Export +{ + /// + /// Serves information about export provider specific configuration + /// + public class ExportConfigurationInfo + { + /// + /// The partial view name for the configuration + /// + public string PartialViewName { get; set; } + + /// + /// Type of the view model + /// + public Type ModelType { get; set; } + + /// + /// Callback to initialize the view model. Can be null. + /// + public Action Initialize { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportDataSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportDataSegmenter.cs new file mode 100644 index 0000000000..c84182c6e0 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportDataSegmenter.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using SmartStore.Core; + +namespace SmartStore.Services.DataExchange.Export +{ + public interface IExportDataSegmenterConsumer + { + /// + /// Total number of records + /// + int TotalRecords { get; } + + /// + /// Gets current data segment + /// + IReadOnlyCollection CurrentSegment { get; } + + /// + /// Reads the next segment + /// + /// + bool ReadNextSegment(); + } + + internal interface IExportDataSegmenterProvider : IExportDataSegmenterConsumer, IDisposable + { + /// + /// Whether there is data available + /// + bool HasData { get; } + + /// + /// Record per segment counter + /// + int RecordPerSegmentCount { get; set; } + } + + public class ExportDataSegmenter : IExportDataSegmenterProvider where T : BaseEntity + { + private Func> _load; + private Action> _loaded; + private Func> _convert; + + private int _offset; + private int _take; + private int _limit; + private int _recordsPerSegment; + private int _totalRecords; + + private int _skip; + private int _countRecords; + + private Queue _data; + + public ExportDataSegmenter( + Func> load, + Action> loaded, + Func> convert, + int offset, + int take, + int limit, + int recordsPerSegment, + int totalRecords) + { + _load = load; + _loaded = loaded; + _convert = convert; + _offset = offset; + _take = take; + _limit = limit; + _recordsPerSegment = recordsPerSegment; + _totalRecords = totalRecords; + + _skip = _offset; + } + + /// + /// Total number of records + /// + public int TotalRecords + { + get + { + var total = Math.Max(_totalRecords - _offset, 0); + + if (_limit > 0 && _limit < total) + return _limit; + + return total; + } + } + + /// + /// Number of processed records + /// + public int RecordCount + { + get { return _countRecords; } + } + + /// + /// Record per segment counter + /// + public int RecordPerSegmentCount { get; set; } + + /// + /// Whether there is data available + /// + public bool HasData + { + get + { + if (_limit > 0 && _countRecords >= _limit) + return false; + + if (_data != null && _data.Count > 0) + return true; + + if (_skip >= _totalRecords) + return false; + + return true; + } + } + + /// + /// Gets current data segment + /// + public IReadOnlyCollection CurrentSegment + { + get + { + T entity; + var records = new List(); + + while (_data.Count > 0 && (entity = _data.Dequeue()) != null) + { + _convert(entity).Each(x => records.Add(x)); + + if (++_countRecords >= _limit && _limit > 0) + return records; + + if (++RecordPerSegmentCount >= _recordsPerSegment && _recordsPerSegment > 0) + return records; + } + + return records; + } + } + + /// + /// Reads the next segment + /// + /// + public bool ReadNextSegment() + { + if (_limit > 0 && _countRecords >= _limit) + return false; + + if (_recordsPerSegment > 0 && RecordPerSegmentCount >= _recordsPerSegment) + return false; + + // do not make the queue longer than necessary + if (_recordsPerSegment > 0 && _data != null && _data.Count >= _recordsPerSegment) + return true; + + if (_skip >= _totalRecords) + return false; + + if (_data != null) + _skip += _take; + + if (_data != null && _data.Count > 0) + { + var data = new List(_data); + data.AddRange(_load(_skip)); + + _data = new Queue(data); + } + else + { + _data = new Queue(_load(_skip)); + } + + // give provider the opportunity to make something with entity ids + if (_loaded != null) + { + _loaded(_data.AsReadOnly()); + } + + return (_data.Count > 0); + } + + /// + /// Dispose and reset segmenter instance + /// + public void Dispose() + { + if (_data != null) + _data.Clear(); + + _skip = _offset; + _countRecords = 0; + RecordPerSegmentCount = 0; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportExecuteContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportExecuteContext.cs new file mode 100644 index 0000000000..d5f2860ff8 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportExecuteContext.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.DataExchange.Export +{ + public class ExportExecuteContext + { + private DataExportResult _result; + private CancellationToken _cancellation; + private DataExchangeAbortion _providerAbort; + + internal ExportExecuteContext(DataExportResult result, CancellationToken cancellation, string folder) + { + _result = result; + _cancellation = cancellation; + Folder = folder; + ExtraDataUnits = new List(); + CustomProperties = new Dictionary(); + } + + /// + /// Provides the data to be exported + /// + public IExportDataSegmenterConsumer DataSegmenter { get; set; } + + /// + /// The store context to be used for the export + /// + public dynamic Store { get; internal set; } + + /// + /// The customer context to be used for the export + /// + public dynamic Customer { get; internal set; } + + /// + /// The currency context to be used for the export + /// + public dynamic Currency { get; internal set; } + + /// + /// The language context to be used for the export + /// + public dynamic Language { get; internal set; } + + /// + /// Projection data + /// + public ExportProjection Projection { get; internal set; } + + /// + /// To log information into the export log file + /// + public ILogger Log { get; internal set; } + + /// + /// Indicates whether and how to abort the export + /// + public DataExchangeAbortion Abort + { + get + { + if (_cancellation.IsCancellationRequested || IsMaxFailures) + return DataExchangeAbortion.Hard; + + return _providerAbort; + } + set + { + _providerAbort = value; + } + } + + public bool IsMaxFailures + { + get { return RecordsFailed > 11; } + } + + /// + /// Identifier of current data stream. Can be null. + /// + public string DataStreamId { get; set; } + + /// + /// Stream used to write data to + /// + public Stream DataStream { get; internal set; } + + /// + /// List with extra data units/streams required by provider + /// + public List ExtraDataUnits { get; private set; } + + /// + /// The maximum allowed file name length + /// + public int MaxFileNameLength { get; internal set; } + + /// + /// The name of the current export file + /// + public string FileName { get; internal set; } + + /// + /// The path of the export content folder + /// + public string Folder { get; private set; } + + /// + /// Whether the profile has a public deployment into "Exchange" folder + /// + public bool HasPublicDeployment { get; internal set; } + + /// + /// The local path to the public export folder "Exchange". null if the profile has no public deployment. + /// + public string PublicFolderPath { get; internal set; } + + /// + /// Provider specific configuration data + /// + public object ConfigurationData { get; internal set; } + + /// + /// Use this dictionary for any custom data required along the export + /// + public Dictionary CustomProperties { get; set; } + + /// + /// Number of successful processed records + /// + public int RecordsSucceeded { get; set; } + + /// + /// Number of failed records + /// + public int RecordsFailed { get; set; } + + /// + /// Processes an exception that occurred while exporting a record + /// + /// Exception + public void RecordException(Exception exception, int entityId) + { + ++RecordsFailed; + + Log.Error("Error while processing record with id {0}: {1}".FormatInvariant(entityId, exception.ToAllMessages()), exception); + + if (IsMaxFailures) + _result.LastError = exception.ToString(); + } + + public ProgressValueSetter ProgressValueSetter { get; internal set; } + + /// + /// Allows to set a progress message + /// + /// Output message + public void SetProgress(string message) + { + if (ProgressValueSetter != null && message.HasValue()) + { + try + { + ProgressValueSetter.Invoke(0, 0, message); + } + catch { } + } + } + } + + public class ExportDataUnit + { + /// + /// Your Id to identify this stream within a list of streams + /// + public string Id { get; set; } + + /// + /// Stream used to write data to + /// + public Stream DataStream { get; internal set; } + + /// + /// The name of the file to be created + /// + public string FileName { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportExtensions.cs new file mode 100644 index 0000000000..0371702eec --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportExtensions.cs @@ -0,0 +1,258 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using SmartStore.Core; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Export +{ + public static class ExportExtensions + { + /// + /// Returns a value indicating whether the export provider is valid + /// + /// Export provider + /// true provider is valid, false provider is invalid. + public static bool IsValid(this Provider provider) + { + return provider != null && provider.Value != null; + } + + /// + /// Gets the localized friendly name or the system name as fallback + /// + /// Export provider + /// Localization service + /// Provider name + public static string GetName(this Provider provider, ILocalizationService localizationService) + { + var systemName = provider.Metadata.SystemName; + var resourceName = provider.Metadata.ResourceKeyPattern.FormatInvariant(systemName, "FriendlyName"); + var name = localizationService.GetResource(resourceName, 0, false, systemName, true); + + return (name.IsEmpty() ? systemName : name); + } + + /// + /// Get temporary folder for an export profile + /// + /// Export profile + /// Folder path + public static string GetExportFolder(this ExportProfile profile, bool content = false, bool create = false) + { + var path = CommonHelper.MapPath(string.Concat(profile.FolderName, content ? "/Content" : "")); + + if (create && !System.IO.Directory.Exists(path)) + System.IO.Directory.CreateDirectory(path); + + return path; + } + + /// + /// Get log file path for an export profile + /// + /// Export profile + /// Log file path + public static string GetExportLogPath(this ExportProfile profile) + { + return Path.Combine(profile.GetExportFolder(), "log.txt"); + } + + /// + /// Gets the ZIP path for a profile + /// + /// Export profile + /// ZIP file path + public static string GetExportZipPath(this ExportProfile profile) + { + var name = (new DirectoryInfo(profile.FolderName)).Name; + if (name.IsEmpty()) + name = "ExportData"; + + return Path.Combine(profile.GetExportFolder(), name.ToValidFileName() + ".zip"); + } + + /// + /// Gets existing export files for an export profile + /// + /// Export profile + /// Export provider + /// List of file names + public static IEnumerable GetExportFiles(this ExportProfile profile, Provider provider) + { + var exportFolder = profile.GetExportFolder(true); + + if (System.IO.Directory.Exists(exportFolder) && provider.Value.FileExtension.HasValue()) + { + var filter = "*.{0}".FormatInvariant(provider.Value.FileExtension.ToLower()); + + return System.IO.Directory.EnumerateFiles(exportFolder, filter, SearchOption.AllDirectories).OrderBy(x => x); + } + + return Enumerable.Empty(); + } + + /// + /// Get number of existing export files + /// + /// Export profile + /// Export provider + /// Number of export files + public static int GetExportFileCount(this ExportProfile profile, Provider provider) + { + var result = profile.GetExportFiles(provider).Count(); + + if (File.Exists(profile.GetExportZipPath())) + ++result; + + return result; + } + + /// + /// Resolves the file name pattern for an export profile + /// + /// Export profile + /// Store + /// One based file index + /// The maximum length of the file name + /// Resolved file name pattern + public static string ResolveFileNamePattern(this ExportProfile profile, Store store, int fileIndex, int maxFileNameLength) + { + var sb = new StringBuilder(profile.FileNamePattern); + + sb.Replace("%Profile.Id%", profile.Id.ToString()); + sb.Replace("%Profile.FolderName%", profile.FolderName); + sb.Replace("%Store.Id%", store.Id.ToString()); + sb.Replace("%File.Index%", fileIndex.ToString("D4")); + + if (profile.FileNamePattern.Contains("%Profile.SeoName%")) + sb.Replace("%Profile.SeoName%", SeoHelper.GetSeName(profile.Name, true, false).Replace("/", "").Replace("-", "")); + + if (profile.FileNamePattern.Contains("%Store.SeoName%")) + sb.Replace("%Store.SeoName%", profile.PerStore ? SeoHelper.GetSeName(store.Name, true, false) : "allstores"); + + if (profile.FileNamePattern.Contains("%Random.Number%")) + sb.Replace("%Random.Number%", CommonHelper.GenerateRandomInteger().ToString()); + + if (profile.FileNamePattern.Contains("%Timestamp%")) + sb.Replace("%Timestamp%", DateTime.UtcNow.ToString("s", CultureInfo.InvariantCulture)); + + var result = sb.ToString() + .ToValidFileName("") + .Truncate(maxFileNameLength); + + return result; + } + + /// + /// Get path of the deployment folder + /// + /// Export deployment + /// Deployment folder path + public static string GetDeploymentFolder(this ExportDeployment deployment, bool create = false) + { + if (deployment == null) + return null; + + string path = null; + + if (deployment.DeploymentType == ExportDeploymentType.PublicFolder) + { + if (deployment.SubFolder.HasValue()) + path = Path.Combine(HttpRuntime.AppDomainAppPath, DataExporter.PublicFolder, deployment.SubFolder); + else + path = Path.Combine(HttpRuntime.AppDomainAppPath, DataExporter.PublicFolder); + } + else if (deployment.DeploymentType == ExportDeploymentType.FileSystem) + { + if (deployment.FileSystemPath.IsEmpty()) + return null; + + if (Path.IsPathRooted(deployment.FileSystemPath)) + { + path = deployment.FileSystemPath; + } + else + { + path = FileSystemHelper.ValidateRootPath(deployment.FileSystemPath); + path = CommonHelper.MapPath(path); + } + } + + if (create && !System.IO.Directory.Exists(path)) + System.IO.Directory.CreateDirectory(path); + + return path; + } + + /// + /// Get url of the public folder and take filtering and projection into consideration + /// + /// Export deployment + /// Common services + /// Store entity + /// Absolute URL of the public folder (always ends with /) or null + public static string GetPublicFolderUrl(this ExportDeployment deployment, ICommonServices services, Store store = null) + { + if (deployment != null && deployment.DeploymentType == ExportDeploymentType.PublicFolder) + { + if (store == null) + { + var filter = XmlHelper.Deserialize(deployment.Profile.Filtering); + var storeId = filter.StoreId; + + if (storeId == 0) + { + var projection = XmlHelper.Deserialize(deployment.Profile.Projection); + storeId = (projection.StoreId ?? 0); + } + + store = (storeId == 0 ? services.StoreContext.CurrentStore : services.StoreService.GetStoreById(storeId)); + } + + var url = string.Concat( + store.Url.EnsureEndsWith("/"), + DataExporter.PublicFolder.EnsureEndsWith("/"), + deployment.SubFolder.HasValue() ? deployment.SubFolder.EnsureEndsWith("/") : "" + ); + + return url; + } + + return null; + } + + /// + /// Get icon class for a deployment type + /// + /// Deployment type + /// Icon class + public static string GetIconClass(this ExportDeploymentType type) + { + switch (type) + { + case ExportDeploymentType.FileSystem: + return "fa-folder-open-o"; + case ExportDeploymentType.Email: + return "fa-envelope-o"; + case ExportDeploymentType.Http: + return "fa-globe"; + case ExportDeploymentType.Ftp: + return "fa-files-o"; + case ExportDeploymentType.PublicFolder: + return "fa-unlock"; + default: + return "fa-question"; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportFeaturesAttribute.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportFeaturesAttribute.cs new file mode 100644 index 0000000000..eee6f1554e --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportFeaturesAttribute.cs @@ -0,0 +1,15 @@ +using System; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange.Export +{ + /// + /// Declares data processing types supported by an export provider. + /// Projection type controls whether to display corresponding projection fields while editing an export profile. + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public sealed class ExportFeaturesAttribute : Attribute + { + public ExportFeatures Features { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportProfileService.cs new file mode 100644 index 0000000000..1814ae56ae --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportProfileService.cs @@ -0,0 +1,365 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Events; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; +using SmartStore.Services.Tasks; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Export +{ + public partial class ExportProfileService : IExportProfileService + { + private const string _defaultFileNamePattern = "%Store.Id%-%Profile.Id%-%File.Index%-%Profile.SeoName%"; + + private readonly IRepository _exportProfileRepository; + private readonly IRepository _exportDeploymentRepository; + private readonly IEventPublisher _eventPublisher; + private readonly IScheduleTaskService _scheduleTaskService; + private readonly IProviderManager _providerManager; + private readonly DataExchangeSettings _dataExchangeSettings; + private readonly ILocalizationService _localizationService; + + public ExportProfileService( + IRepository exportProfileRepository, + IRepository exportDeploymentRepository, + IEventPublisher eventPublisher, + IScheduleTaskService scheduleTaskService, + IProviderManager providerManager, + DataExchangeSettings dataExchangeSettings, + ILocalizationService localizationService) + { + _exportProfileRepository = exportProfileRepository; + _exportDeploymentRepository = exportDeploymentRepository; + _eventPublisher = eventPublisher; + _scheduleTaskService = scheduleTaskService; + _providerManager = providerManager; + _dataExchangeSettings = dataExchangeSettings; + _localizationService = localizationService; + } + + public virtual ExportProfile InsertExportProfile( + string providerSystemName, + string name, + string fileExtension, + ExportFeatures features, + bool isSystemProfile = false, + string profileSystemName = null, + int cloneFromProfileId = 0) + { + Guard.ArgumentNotEmpty(() => providerSystemName); + + var profileCount = _exportProfileRepository.Table.Count(x => x.ProviderSystemName == providerSystemName); + + if (name.IsEmpty()) + name = providerSystemName; + + if (!isSystemProfile) + name = string.Concat(_localizationService.GetResource("Common.My"), " ", name); + + name = string.Concat(name, " ", profileCount + 1); + + var cloneProfile = GetExportProfileById(cloneFromProfileId); + + ScheduleTask task = null; + ExportProfile profile = null; + + if (cloneProfile == null) + { + task = new ScheduleTask + { + CronExpression = "0 */6 * * *", // every six hours + Type = typeof(DataExportTask).AssemblyQualifiedNameWithoutVersion(), + Enabled = false, + StopOnError = false, + IsHidden = true + }; + } + else + { + task = cloneProfile.ScheduleTask.Clone(); + task.LastEndUtc = task.LastStartUtc = task.LastSuccessUtc = null; + } + + task.Name = string.Concat(name, " Task"); + + _scheduleTaskService.InsertTask(task); + + if (cloneProfile == null) + { + profile = new ExportProfile + { + FileNamePattern = _defaultFileNamePattern + }; + + if (isSystemProfile) + { + profile.Enabled = true; + profile.PerStore = false; + profile.CreateZipArchive = false; + profile.Cleanup = false; + } + else + { + // what we do here is to preset typical settings for feed creation + // but on the other hand they may be untypical for generic data export\exchange + var projection = new ExportProjection + { + RemoveCriticalCharacters = true, + CriticalCharacters = "¼,½,¾", + PriceType = PriceDisplayType.PreSelectedPrice, + NoGroupedProducts = (features.HasFlag(ExportFeatures.CanOmitGroupedProducts) ? true : false), + DescriptionMerging = ExportDescriptionMerging.Description + }; + + var filter = new ExportFilter + { + IsPublished = true + }; + + profile.Projection = XmlHelper.Serialize(projection); + profile.Filtering = XmlHelper.Serialize(filter); + } + } + else + { + profile = cloneProfile.Clone(); + } + + profile.IsSystemProfile = isSystemProfile; + profile.Name = name; + profile.ProviderSystemName = providerSystemName; + profile.SchedulingTaskId = task.Id; + + var cleanedSystemName = providerSystemName + .Replace("Exports.", "") + .Replace("Feeds.", "") + .Replace("/", "") + .Replace("-", ""); + + var folderName = SeoHelper.GetSeName(cleanedSystemName, true, false) + .ToValidPath() + .Truncate(_dataExchangeSettings.MaxFileNameLength); + + profile.FolderName = "~/App_Data/ExportProfiles/" + FileSystemHelper.CreateNonExistingDirectoryName(CommonHelper.MapPath("~/App_Data/ExportProfiles"), folderName); + + if (profileSystemName.IsEmpty() && isSystemProfile) + profile.SystemName = cleanedSystemName; + else + profile.SystemName = profileSystemName; + + _exportProfileRepository.Insert(profile); + + + task.Alias = profile.Id.ToString(); + _scheduleTaskService.UpdateTask(task); + + if (fileExtension.HasValue() && !isSystemProfile) + { + if (cloneProfile == null) + { + if (features.HasFlag(ExportFeatures.CreatesInitialPublicDeployment)) + { + var subFolder = FileSystemHelper.CreateNonExistingDirectoryName(CommonHelper.MapPath("~/" + DataExporter.PublicFolder), folderName); + + profile.Deployments.Add(new ExportDeployment + { + ProfileId = profile.Id, + Enabled = true, + DeploymentType = ExportDeploymentType.PublicFolder, + Name = profile.Name, + SubFolder = subFolder + }); + + UpdateExportProfile(profile); + } + } + else + { + foreach (var deployment in cloneProfile.Deployments) + { + profile.Deployments.Add(deployment.Clone()); + } + + UpdateExportProfile(profile); + } + } + + _eventPublisher.EntityInserted(profile); + + return profile; + } + + public virtual ExportProfile InsertExportProfile( + Provider provider, + bool isSystemProfile = false, + string profileSystemName = null, + int cloneFromProfileId = 0) + { + Guard.ArgumentNotNull(() => provider); + + var profile = InsertExportProfile( + provider.Metadata.SystemName, + provider.GetName(_localizationService), + provider.Value.FileExtension, + provider.Metadata.ExportFeatures, + isSystemProfile, + profileSystemName, + cloneFromProfileId); + + return profile; + } + + public virtual void UpdateExportProfile(ExportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + profile.FolderName = FileSystemHelper.ValidateRootPath(profile.FolderName); + + _exportProfileRepository.Update(profile); + + _eventPublisher.EntityUpdated(profile); + } + + public virtual void DeleteExportProfile(ExportProfile profile, bool force = false) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + if (!force && profile.IsSystemProfile) + throw new SmartException(_localizationService.GetResource("Admin.DataExchange.Export.CannotDeleteSystemProfile")); + + int scheduleTaskId = profile.SchedulingTaskId; + var folder = profile.GetExportFolder(); + + _exportProfileRepository.Delete(profile); + + var scheduleTask = _scheduleTaskService.GetTaskById(scheduleTaskId); + _scheduleTaskService.DeleteTask(scheduleTask); + + _eventPublisher.EntityDeleted(profile); + + if (System.IO.Directory.Exists(folder)) + { + FileSystemHelper.ClearDirectory(folder, true); + } + } + + public virtual IQueryable GetExportProfiles(bool? enabled = null) + { + var query = _exportProfileRepository.Table + .Expand(x => x.ScheduleTask) + .Expand(x => x.Deployments); + + if (enabled.HasValue) + { + query = query.Where(x => x.Enabled == enabled.Value); + } + + query = query + .OrderBy(x => x.IsSystemProfile) + .ThenBy(x => x.Name); + + return query; + } + + public virtual ExportProfile GetExportProfileById(int id) + { + if (id == 0) + return null; + + var profile = _exportProfileRepository.Table + .Expand(x => x.ScheduleTask) + .Expand(x => x.Deployments) + .FirstOrDefault(x => x.Id == id); + + return profile; + } + + public virtual ExportProfile GetSystemExportProfile(string providerSystemName) + { + if (providerSystemName.IsEmpty()) + return null; + + var query = GetExportProfiles(true); + + var profile = query + .Where(x => x.IsSystemProfile && x.ProviderSystemName == providerSystemName) + .FirstOrDefault(); + + return profile; + } + + public virtual IList GetExportProfilesBySystemName(string providerSystemName) + { + if (providerSystemName.IsEmpty()) + return new List(); + + var profiles = _exportProfileRepository.Table + .Expand(x => x.ScheduleTask) + .Expand(x => x.Deployments) + .Where(x => x.ProviderSystemName == providerSystemName) + .ToList(); + + return profiles; + } + + + public virtual IEnumerable> LoadAllExportProviders(int storeId = 0, bool showHidden = true) + { + var allProviders = _providerManager.GetAllProviders(storeId) + .Where(x => x.IsValid() && (showHidden || !x.Metadata.IsHidden)) + //.OrderBy(x => x.Metadata.SystemName) + .OrderBy(x => x.Metadata.FriendlyName); + + return allProviders; + } + + public virtual Provider LoadProvider(string systemName, int storeId = 0) + { + var provider = _providerManager.GetProvider(systemName, storeId); + + return (provider.IsValid() ? provider : null); + } + + public virtual ExportDeployment GetExportDeploymentById(int id) + { + if (id == 0) + return null; + + var deployment = _exportDeploymentRepository.Table + .Expand(x => x.Profile) + .FirstOrDefault(x => x.Id == id); + + return deployment; + } + + public virtual void UpdateExportDeployment(ExportDeployment deployment) + { + if (deployment == null) + throw new ArgumentNullException("deployment"); + + _exportDeploymentRepository.Update(deployment); + + _eventPublisher.EntityUpdated(deployment); + } + + public virtual void DeleteExportDeployment(ExportDeployment deployment) + { + if (deployment == null) + throw new ArgumentNullException("deployment"); + + _exportDeploymentRepository.Delete(deployment); + + _eventPublisher.EntityDeleted(deployment); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportProviderBase.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportProviderBase.cs new file mode 100644 index 0000000000..c77638f60b --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportProviderBase.cs @@ -0,0 +1,50 @@ +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange.Export +{ + public abstract class ExportProviderBase : IExportProvider + { + /// + /// The exported entity type + /// + public virtual ExportEntityType EntityType + { + get { return ExportEntityType.Product; } + } + + /// + /// File extension of the export files (without dot). Return null for a non file based, on-the-fly export. + /// + public virtual string FileExtension + { + get { return null; } + } + + /// + /// Get provider specific configuration information. Return null when no provider specific configuration is required. + /// + public virtual ExportConfigurationInfo ConfigurationInfo + { + get { return null; } + } + + public void Execute(ExportExecuteContext context) + { + Export(context); + } + + /// + /// Export data to a file + /// + /// Export execution context + protected abstract void Export(ExportExecuteContext context); + + /// + /// Called once per store when export execution ended + /// + /// Export execution context + public virtual void OnExecuted(ExportExecuteContext context) + { + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/ExportXmlHelper.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportXmlHelper.cs new file mode 100644 index 0000000000..68c8b78d55 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/ExportXmlHelper.cs @@ -0,0 +1,918 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; +using System.Xml; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Media; + +namespace SmartStore.Services.DataExchange.Export +{ + public class ExportXmlHelper : IDisposable + { + private XmlWriter _writer; + private CultureInfo _culture; + private bool _doNotDispose; + + public ExportXmlHelper(XmlWriter writer, bool doNotDispose = false, CultureInfo culture = null) + { + _writer = writer; + _doNotDispose = doNotDispose; + _culture = (culture == null ? CultureInfo.InvariantCulture : culture); + } + public ExportXmlHelper(Stream stream, XmlWriterSettings settings = null, CultureInfo culture = null) + { + if (settings == null) + { + settings = DefaultSettings; + } + + _writer = XmlWriter.Create(stream, settings); + _culture = (culture == null ? CultureInfo.InvariantCulture : culture); + } + + public static XmlWriterSettings DefaultSettings + { + get + { + return new XmlWriterSettings + { + Encoding = Encoding.UTF8, + CheckCharacters = false, + Indent = true, + IndentChars = "\t" + }; + } + } + + public ExportXmlExclude Exclude { get; set; } + + public XmlWriter Writer + { + get { return _writer; } + } + + public void Dispose() + { + if (_writer != null && !_doNotDispose) + { + _writer.Dispose(); + } + } + + public void WriteLocalized(dynamic parentNode) + { + if (parentNode == null || parentNode._Localized == null) + return; + + _writer.WriteStartElement("Localized"); + foreach (dynamic item in parentNode._Localized) + { + _writer.WriteStartElement((string)item.LocaleKey); + _writer.WriteAttributeString("culture", (string)item.Culture); + _writer.WriteString(((string)item.LocaleValue).RemoveInvalidXmlChars()); + _writer.WriteEndElement(); // item.LocaleKey + } + _writer.WriteEndElement(); // Localized + } + + public void WriteGenericAttributes(dynamic parentNode) + { + if (parentNode == null || parentNode._GenericAttributes == null) + return; + + _writer.WriteStartElement("GenericAttributes"); + foreach (dynamic genericAttribute in parentNode._GenericAttributes) + { + GenericAttribute entity = genericAttribute.Entity; + + _writer.WriteStartElement("GenericAttribute"); + _writer.Write("Id", entity.ToString()); + _writer.Write("EntityId", entity.EntityId.ToString()); + _writer.Write("KeyGroup", entity.KeyGroup); + _writer.Write("Key", entity.Key); + _writer.Write("Value", (string)genericAttribute.Value); + _writer.Write("StoreId", entity.StoreId.ToString()); + _writer.WriteEndElement(); // GenericAttribute + } + _writer.WriteEndElement(); // GenericAttributes + } + + public void WriteAddress(dynamic address, string node) + { + if (address == null) + return; + + Address entity = address.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("FirstName", entity.FirstName); + _writer.Write("LastName", entity.LastName); + _writer.Write("Email", entity.Email); + _writer.Write("Company", entity.Company); + _writer.Write("CountryId", entity.CountryId.HasValue ? entity.CountryId.Value.ToString() : ""); + _writer.Write("StateProvinceId", entity.StateProvinceId.HasValue ? entity.StateProvinceId.Value.ToString() : ""); + _writer.Write("City", entity.City); + _writer.Write("Address1", entity.Address1); + _writer.Write("Address2", entity.Address2); + _writer.Write("ZipPostalCode", entity.ZipPostalCode); + _writer.Write("PhoneNumber", entity.PhoneNumber); + _writer.Write("FaxNumber", entity.FaxNumber); + _writer.Write("CreatedOnUtc", entity.CreatedOnUtc.ToString(_culture)); + + if (address.Country != null) + { + dynamic country = address.Country; + Country entityCountry = address.Country.Entity; + + _writer.WriteStartElement("Country"); + _writer.Write("Id", entityCountry.Id.ToString()); + _writer.Write("Name", (string)country.Name); + _writer.Write("AllowsBilling", entityCountry.AllowsBilling.ToString()); + _writer.Write("AllowsShipping", entityCountry.AllowsShipping.ToString()); + _writer.Write("TwoLetterIsoCode", entityCountry.TwoLetterIsoCode); + _writer.Write("ThreeLetterIsoCode", entityCountry.ThreeLetterIsoCode); + _writer.Write("NumericIsoCode", entityCountry.NumericIsoCode.ToString()); + _writer.Write("SubjectToVat", entityCountry.SubjectToVat.ToString()); + _writer.Write("Published", entityCountry.Published.ToString()); + _writer.Write("DisplayOrder", entityCountry.DisplayOrder.ToString()); + _writer.Write("LimitedToStores", entityCountry.LimitedToStores.ToString()); + + WriteLocalized(country); + + _writer.WriteEndElement(); // Country + } + + if (address.StateProvince != null) + { + dynamic stateProvince = address.StateProvince; + StateProvince entityStateProvince = address.StateProvince.Entity; + + _writer.WriteStartElement("StateProvince"); + _writer.Write("Id", entityStateProvince.Id.ToString()); + _writer.Write("CountryId", entityStateProvince.CountryId.ToString()); + _writer.Write("Name", (string)stateProvince.Name); + _writer.Write("Abbreviation", (string)stateProvince.Abbreviation); + _writer.Write("Published", entityStateProvince.Published.ToString()); + _writer.Write("DisplayOrder", entityStateProvince.DisplayOrder.ToString()); + + WriteLocalized(stateProvince); + + _writer.WriteEndElement(); // StateProvince + } + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteCurrency(dynamic currency, string node) + { + if (currency == null) + return; + + Currency entity = currency.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("Name", (string)currency.Name); + _writer.Write("CurrencyCode", entity.CurrencyCode); + _writer.Write("Rate", entity.Rate.ToString(_culture)); + _writer.Write("DisplayLocale", entity.DisplayLocale); + _writer.Write("CustomFormatting", entity.CustomFormatting); + _writer.Write("LimitedToStores", entity.LimitedToStores.ToString()); + _writer.Write("Published", entity.Published.ToString()); + _writer.Write("DisplayOrder", entity.DisplayOrder.ToString()); + _writer.Write("CreatedOnUtc", entity.CreatedOnUtc.ToString(_culture)); + _writer.Write("UpdatedOnUtc", entity.UpdatedOnUtc.ToString(_culture)); + _writer.Write("DomainEndings", entity.DomainEndings); + + WriteLocalized(currency); + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteRewardPointsHistory(dynamic rewardPoints, string node) + { + if (rewardPoints == null) + return; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + foreach (dynamic rewardPoint in rewardPoints) + { + RewardPointsHistory entity = rewardPoint.Entity; + + _writer.WriteStartElement("RewardPointsHistory"); + _writer.Write("Id", entity.ToString()); + _writer.Write("CustomerId", entity.ToString()); + _writer.Write("Points", entity.Points.ToString()); + _writer.Write("PointsBalance", entity.PointsBalance.ToString()); + _writer.Write("UsedAmount", entity.UsedAmount.ToString(_culture)); + _writer.Write("Message", (string)rewardPoint.Message); + _writer.Write("CreatedOnUtc", entity.CreatedOnUtc.ToString(_culture)); + _writer.WriteEndElement(); // RewardPointsHistory + } + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteDeliveryTime(dynamic deliveryTime, string node) + { + if (deliveryTime == null) + return; + + DeliveryTime entity = deliveryTime.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("Name", (string)deliveryTime.Name); + _writer.Write("DisplayLocale", entity.DisplayLocale); + _writer.Write("ColorHexValue", entity.ColorHexValue); + _writer.Write("DisplayOrder", entity.DisplayOrder.ToString()); + + WriteLocalized(deliveryTime); + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteQuantityUnit(dynamic quantityUnit, string node) + { + if (quantityUnit == null) + return; + + QuantityUnit entity = quantityUnit.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("Name", (string)quantityUnit.Name); + _writer.Write("Description", (string)quantityUnit.Description); + _writer.Write("DisplayLocale", entity.DisplayLocale); + _writer.Write("DisplayOrder", entity.DisplayOrder.ToString()); + _writer.Write("IsDefault", entity.IsDefault.ToString()); + + WriteLocalized(quantityUnit); + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WritePicture(dynamic picture, string node) + { + if (picture == null) + return; + + Picture entity = picture.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("SeoFilename", (string)picture.SeoFilename); + _writer.Write("MimeType", (string)picture.MimeType); + _writer.Write("ThumbImageUrl", (string)picture._ThumbImageUrl); + _writer.Write("ImageUrl", (string)picture._ImageUrl); + _writer.Write("FullSizeImageUrl", (string)picture._FullSizeImageUrl); + _writer.Write("FileName", (string)picture._FileName); + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteCategory(dynamic category, string node) + { + if (category == null) + return; + + Category entity = category.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + + if (!Exclude.HasFlag(ExportXmlExclude.Category)) + { + _writer.Write("Name", (string)category.Name); + _writer.Write("FullName", (string)category.FullName); + _writer.Write("Description", (string)category.Description); + _writer.Write("BottomDescription", (string)category.BottomDescription); + _writer.Write("CategoryTemplateId", entity.CategoryTemplateId.ToString()); + _writer.Write("CategoryTemplateViewPath", (string)category._CategoryTemplateViewPath); + _writer.Write("MetaKeywords", (string)category.MetaKeywords); + _writer.Write("MetaDescription", (string)category.MetaDescription); + _writer.Write("MetaTitle", (string)category.MetaTitle); + _writer.Write("SeName", (string)category.SeName); + _writer.Write("ParentCategoryId", entity.ParentCategoryId.ToString()); + _writer.Write("PictureId", entity.PictureId.HasValue ? entity.PictureId.Value.ToString() : ""); + _writer.Write("PageSize", entity.PageSize.ToString()); + _writer.Write("AllowCustomersToSelectPageSize", entity.AllowCustomersToSelectPageSize.ToString()); + _writer.Write("PageSizeOptions", entity.PageSizeOptions); + _writer.Write("PriceRanges", entity.PriceRanges); + _writer.Write("ShowOnHomePage", entity.ShowOnHomePage.ToString()); + _writer.Write("HasDiscountsApplied", entity.HasDiscountsApplied.ToString()); + _writer.Write("Published", entity.Published.ToString()); + _writer.Write("Deleted", entity.Deleted.ToString()); + _writer.Write("DisplayOrder", entity.DisplayOrder.ToString()); + _writer.Write("CreatedOnUtc", entity.CreatedOnUtc.ToString(_culture)); + _writer.Write("UpdatedOnUtc", entity.UpdatedOnUtc.ToString(_culture)); + _writer.Write("SubjectToAcl", entity.SubjectToAcl.ToString()); + _writer.Write("LimitedToStores", entity.LimitedToStores.ToString()); + _writer.Write("Alias", (string)category.Alias); + _writer.Write("DefaultViewMode", entity.DefaultViewMode); + + WritePicture(category.Picture, "Picture"); + + WriteLocalized(category); + } + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteManufacturer(dynamic manufacturer, string node) + { + if (manufacturer == null) + return; + + Manufacturer entity = manufacturer.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("Name", (string)manufacturer.Name); + _writer.Write("SeName", (string)manufacturer.SeName); + _writer.Write("Description", (string)manufacturer.Description); + _writer.Write("ManufacturerTemplateId", entity.ManufacturerTemplateId.ToString()); + _writer.Write("MetaKeywords", (string)manufacturer.MetaKeywords); + _writer.Write("MetaDescription", (string)manufacturer.MetaDescription); + _writer.Write("MetaTitle", (string)manufacturer.MetaTitle); + _writer.Write("PictureId", entity.PictureId.HasValue ? entity.PictureId.Value.ToString() : ""); + _writer.Write("PageSize", entity.PageSize.ToString()); + _writer.Write("AllowCustomersToSelectPageSize", entity.AllowCustomersToSelectPageSize.ToString()); + _writer.Write("PageSizeOptions", entity.PageSizeOptions); + _writer.Write("PriceRanges", entity.PriceRanges); + _writer.Write("Published", entity.Published.ToString()); + _writer.Write("Deleted", entity.Deleted.ToString()); + _writer.Write("DisplayOrder", entity.DisplayOrder.ToString()); + _writer.Write("CreatedOnUtc", entity.CreatedOnUtc.ToString(_culture)); + _writer.Write("UpdatedOnUtc", entity.UpdatedOnUtc.ToString(_culture)); + + WritePicture(manufacturer.Picture, "Picture"); + + WriteLocalized(manufacturer); + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteProduct(dynamic product, string node) + { + if (product == null) + return; + + Product entity = product.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + decimal? basePriceAmount = product.BasePriceAmount; + int? basePriceBaseAmount = product.BasePriceBaseAmount; + decimal? lowestAttributeCombinationPrice = product.LowestAttributeCombinationPrice; + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("Name", (string)product.Name); + _writer.Write("SeName", (string)product.SeName); + _writer.Write("ShortDescription", (string)product.ShortDescription); + _writer.Write("FullDescription", (string)product.FullDescription); + _writer.Write("AdminComment", (string)product.AdminComment); + _writer.Write("ProductTemplateId", entity.ProductTemplateId.ToString()); + _writer.Write("ProductTemplateViewPath", (string)product._ProductTemplateViewPath); + _writer.Write("ShowOnHomePage", entity.ShowOnHomePage.ToString()); + _writer.Write("HomePageDisplayOrder", entity.HomePageDisplayOrder.ToString()); + _writer.Write("MetaKeywords", (string)product.MetaKeywords); + _writer.Write("MetaDescription", (string)product.MetaDescription); + _writer.Write("MetaTitle", (string)product.MetaTitle); + _writer.Write("AllowCustomerReviews", entity.AllowCustomerReviews.ToString()); + _writer.Write("ApprovedRatingSum", entity.ApprovedRatingSum.ToString()); + _writer.Write("NotApprovedRatingSum", entity.NotApprovedRatingSum.ToString()); + _writer.Write("ApprovedTotalReviews", entity.ApprovedTotalReviews.ToString()); + _writer.Write("NotApprovedTotalReviews", entity.NotApprovedTotalReviews.ToString()); + _writer.Write("Published", entity.Published.ToString()); + _writer.Write("CreatedOnUtc", entity.CreatedOnUtc.ToString(_culture)); + _writer.Write("UpdatedOnUtc", entity.UpdatedOnUtc.ToString(_culture)); + _writer.Write("SubjectToAcl", entity.SubjectToAcl.ToString()); + _writer.Write("LimitedToStores", entity.LimitedToStores.ToString()); + _writer.Write("ProductTypeId", entity.ProductTypeId.ToString()); + _writer.Write("ParentGroupedProductId", entity.ParentGroupedProductId.ToString()); + _writer.Write("Sku", (string)product.Sku); + _writer.Write("ManufacturerPartNumber", (string)product.ManufacturerPartNumber); + _writer.Write("Gtin", (string)product.Gtin); + _writer.Write("IsGiftCard", entity.IsGiftCard.ToString()); + _writer.Write("GiftCardTypeId", entity.GiftCardTypeId.ToString()); + _writer.Write("RequireOtherProducts", entity.RequireOtherProducts.ToString()); + _writer.Write("RequiredProductIds", entity.RequiredProductIds); + _writer.Write("AutomaticallyAddRequiredProducts", entity.AutomaticallyAddRequiredProducts.ToString()); + _writer.Write("IsDownload", entity.IsDownload.ToString()); + _writer.Write("DownloadId", entity.DownloadId.ToString()); + _writer.Write("UnlimitedDownloads", entity.UnlimitedDownloads.ToString()); + _writer.Write("MaxNumberOfDownloads", entity.MaxNumberOfDownloads.ToString()); + _writer.Write("DownloadExpirationDays", entity.DownloadExpirationDays.HasValue ? entity.DownloadExpirationDays.Value.ToString() : ""); + _writer.Write("DownloadActivationTypeId", entity.DownloadActivationTypeId.ToString()); + _writer.Write("HasSampleDownload", entity.HasSampleDownload.ToString()); + _writer.Write("SampleDownloadId", entity.SampleDownloadId.HasValue ? entity.SampleDownloadId.Value.ToString() : ""); + _writer.Write("HasUserAgreement", entity.HasUserAgreement.ToString()); + _writer.Write("UserAgreementText", entity.UserAgreementText); + _writer.Write("IsRecurring", entity.IsRecurring.ToString()); + _writer.Write("RecurringCycleLength", entity.RecurringCycleLength.ToString()); + _writer.Write("RecurringCyclePeriodId", entity.RecurringCyclePeriodId.ToString()); + _writer.Write("RecurringTotalCycles", entity.RecurringTotalCycles.ToString()); + _writer.Write("IsShipEnabled", entity.IsShipEnabled.ToString()); + _writer.Write("IsFreeShipping", entity.IsFreeShipping.ToString()); + _writer.Write("AdditionalShippingCharge", entity.AdditionalShippingCharge.ToString(_culture)); + _writer.Write("IsTaxExempt", entity.IsTaxExempt.ToString()); + _writer.Write("TaxCategoryId", entity.TaxCategoryId.ToString()); + _writer.Write("ManageInventoryMethodId", entity.ManageInventoryMethodId.ToString()); + _writer.Write("StockQuantity", entity.StockQuantity.ToString()); + _writer.Write("DisplayStockAvailability", entity.DisplayStockAvailability.ToString()); + _writer.Write("DisplayStockQuantity", entity.DisplayStockQuantity.ToString()); + _writer.Write("MinStockQuantity", entity.MinStockQuantity.ToString()); + _writer.Write("LowStockActivityId", entity.LowStockActivityId.ToString()); + _writer.Write("NotifyAdminForQuantityBelow", entity.NotifyAdminForQuantityBelow.ToString()); + _writer.Write("BackorderModeId", entity.BackorderModeId.ToString()); + _writer.Write("AllowBackInStockSubscriptions", entity.AllowBackInStockSubscriptions.ToString()); + _writer.Write("OrderMinimumQuantity", entity.OrderMinimumQuantity.ToString()); + _writer.Write("OrderMaximumQuantity", entity.OrderMaximumQuantity.ToString()); + _writer.Write("AllowedQuantities", entity.AllowedQuantities); + _writer.Write("DisableBuyButton", entity.DisableBuyButton.ToString()); + _writer.Write("DisableWishlistButton", entity.DisableWishlistButton.ToString()); + _writer.Write("AvailableForPreOrder", entity.AvailableForPreOrder.ToString()); + _writer.Write("CallForPrice", entity.CallForPrice.ToString()); + _writer.Write("Price", entity.Price.ToString(_culture)); + _writer.Write("OldPrice", entity.OldPrice.ToString(_culture)); + _writer.Write("ProductCost", entity.ProductCost.ToString(_culture)); + _writer.Write("SpecialPrice", entity.SpecialPrice.HasValue ? entity.SpecialPrice.Value.ToString(_culture) : ""); + _writer.Write("SpecialPriceStartDateTimeUtc", entity.SpecialPriceStartDateTimeUtc.HasValue ? entity.SpecialPriceStartDateTimeUtc.Value.ToString(_culture) : ""); + _writer.Write("SpecialPriceEndDateTimeUtc", entity.SpecialPriceEndDateTimeUtc.HasValue ? entity.SpecialPriceEndDateTimeUtc.Value.ToString(_culture) : ""); + _writer.Write("CustomerEntersPrice", entity.CustomerEntersPrice.ToString()); + _writer.Write("MinimumCustomerEnteredPrice", entity.MinimumCustomerEnteredPrice.ToString(_culture)); + _writer.Write("MaximumCustomerEnteredPrice", entity.MaximumCustomerEnteredPrice.ToString(_culture)); + _writer.Write("HasTierPrices", entity.HasTierPrices.ToString()); + _writer.Write("HasDiscountsApplied", entity.HasDiscountsApplied.ToString()); + _writer.Write("Weight", ((decimal)product.Weight).ToString(_culture)); + _writer.Write("Length", ((decimal)product.Length).ToString(_culture)); + _writer.Write("Width", ((decimal)product.Width).ToString(_culture)); + _writer.Write("Height", ((decimal)product.Height).ToString(_culture)); + _writer.Write("AvailableStartDateTimeUtc", entity.AvailableStartDateTimeUtc.HasValue ? entity.AvailableStartDateTimeUtc.Value.ToString(_culture) : ""); + _writer.Write("AvailableEndDateTimeUtc", entity.AvailableEndDateTimeUtc.HasValue ? entity.AvailableEndDateTimeUtc.Value.ToString(_culture) : ""); + _writer.Write("BasePriceEnabled", ((bool)product.BasePriceEnabled).ToString()); + _writer.Write("BasePriceMeasureUnit", (string)product.BasePriceMeasureUnit); + _writer.Write("BasePriceAmount", basePriceAmount.HasValue ? basePriceAmount.Value.ToString(_culture) : ""); + _writer.Write("BasePriceBaseAmount", basePriceBaseAmount.HasValue ? basePriceBaseAmount.Value.ToString() : ""); + _writer.Write("BasePriceHasValue", ((bool)product.BasePriceHasValue).ToString()); + _writer.Write("BasePriceInfo", (string)product._BasePriceInfo); + _writer.Write("VisibleIndividually", entity.VisibleIndividually.ToString()); + _writer.Write("DisplayOrder", entity.DisplayOrder.ToString()); + _writer.Write("BundleTitleText", entity.BundleTitleText); + _writer.Write("BundlePerItemPricing", entity.BundlePerItemPricing.ToString()); + _writer.Write("BundlePerItemShipping", entity.BundlePerItemShipping.ToString()); + _writer.Write("BundlePerItemShoppingCart", entity.BundlePerItemShoppingCart.ToString()); + _writer.Write("LowestAttributeCombinationPrice", lowestAttributeCombinationPrice.HasValue ? lowestAttributeCombinationPrice.Value.ToString(_culture) : ""); + _writer.Write("IsEsd", entity.IsEsd.ToString()); + + WriteLocalized(product); + + WriteDeliveryTime(product.DeliveryTime, "DeliveryTime"); + + WriteQuantityUnit(product.QuantityUnit, "QuantityUnit"); + + if (product.AppliedDiscounts != null) + { + _writer.WriteStartElement("AppliedDiscounts"); + foreach (dynamic discount in product.AppliedDiscounts) + { + Discount entityDiscount = discount.Entity; + + _writer.WriteStartElement("AppliedDiscount"); + _writer.Write("Id", entityDiscount.Id.ToString()); + _writer.Write("Name", (string)discount.Name); + _writer.Write("DiscountTypeId", entityDiscount.DiscountTypeId.ToString()); + _writer.Write("UsePercentage", entityDiscount.UsePercentage.ToString()); + _writer.Write("DiscountPercentage", entityDiscount.DiscountPercentage.ToString(_culture)); + _writer.Write("DiscountAmount", entityDiscount.DiscountAmount.ToString(_culture)); + _writer.Write("StartDateUtc", entityDiscount.StartDateUtc.HasValue ? entityDiscount.StartDateUtc.Value.ToString(_culture) : ""); + _writer.Write("EndDateUtc", entityDiscount.EndDateUtc.HasValue ? entityDiscount.EndDateUtc.Value.ToString(_culture) : ""); + _writer.Write("RequiresCouponCode", entityDiscount.RequiresCouponCode.ToString()); + _writer.Write("CouponCode", entityDiscount.CouponCode); + _writer.Write("DiscountLimitationId", entityDiscount.DiscountLimitationId.ToString()); + _writer.Write("LimitationTimes", entityDiscount.LimitationTimes.ToString()); + _writer.WriteEndElement(); // AppliedDiscount + } + _writer.WriteEndElement(); // AppliedDiscounts + } + + if (product.TierPrices != null) + { + _writer.WriteStartElement("TierPrices"); + foreach (dynamic tierPrice in product.TierPrices) + { + TierPrice entityTierPrice = tierPrice.Entity; + + _writer.WriteStartElement("TierPrice"); + _writer.Write("Id", entityTierPrice.Id.ToString()); + _writer.Write("ProductId", entityTierPrice.ProductId.ToString()); + _writer.Write("StoreId", entityTierPrice.StoreId.ToString()); + _writer.Write("CustomerRoleId", entityTierPrice.CustomerRoleId.HasValue ? entityTierPrice.CustomerRoleId.Value.ToString() : ""); + _writer.Write("Quantity", entityTierPrice.Quantity.ToString()); + _writer.Write("Price", entityTierPrice.Price.ToString(_culture)); + _writer.WriteEndElement(); // TierPrice + } + _writer.WriteEndElement(); // TierPrices + } + + if (product.ProductTags != null) + { + _writer.WriteStartElement("ProductTags"); + foreach (dynamic tag in product.ProductTags) + { + _writer.WriteStartElement("ProductTag"); + _writer.Write("Id", ((int)tag.Id).ToString()); + _writer.Write("Name", (string)tag.Name); + _writer.Write("SeName", (string)tag.SeName); + + WriteLocalized(tag); + + _writer.WriteEndElement(); // ProductTag + } + _writer.WriteEndElement(); // ProductTags + } + + if (product.ProductAttributes != null) + { + _writer.WriteStartElement("ProductAttributes"); + foreach (dynamic pva in product.ProductAttributes) + { + ProductVariantAttribute entityPva = pva.Entity; + + _writer.WriteStartElement("ProductAttribute"); + _writer.Write("Id", entityPva.Id.ToString()); + _writer.Write("TextPrompt", (string)pva.TextPrompt); + _writer.Write("IsRequired", entityPva.IsRequired.ToString()); + _writer.Write("AttributeControlTypeId", entityPva.AttributeControlTypeId.ToString()); + _writer.Write("DisplayOrder", entityPva.DisplayOrder.ToString()); + + _writer.WriteStartElement("Attribute"); + _writer.Write("Id", ((int)pva.Attribute.Id).ToString()); + _writer.Write("Alias", (string)pva.Attribute.Alias); + _writer.Write("Name", (string)pva.Attribute.Name); + _writer.Write("Description", (string)pva.Attribute.Description); + + WriteLocalized(pva.Attribute); + + _writer.WriteEndElement(); // Attribute + + _writer.WriteStartElement("AttributeValues"); + foreach (dynamic value in pva.Attribute.Values) + { + ProductVariantAttributeValue entityPvav = value.Entity; + + _writer.WriteStartElement("AttributeValue"); + _writer.Write("Id", entityPvav.Id.ToString()); + _writer.Write("Alias", (string)value.Alias); + _writer.Write("Name", (string)value.Name); + _writer.Write("ColorSquaresRgb", (string)value.ColorSquaresRgb); + _writer.Write("PriceAdjustment", ((decimal)value.PriceAdjustment).ToString(_culture)); + _writer.Write("WeightAdjustment", ((decimal)value.WeightAdjustment).ToString(_culture)); + _writer.Write("IsPreSelected", entityPvav.IsPreSelected.ToString()); + _writer.Write("DisplayOrder", entityPvav.DisplayOrder.ToString()); + _writer.Write("ValueTypeId", entityPvav.ValueTypeId.ToString()); + _writer.Write("LinkedProductId", entityPvav.LinkedProductId.ToString()); + _writer.Write("Quantity", entityPvav.Quantity.ToString()); + + WriteLocalized(value); + + _writer.WriteEndElement(); // AttributeValue + } + _writer.WriteEndElement(); // AttributeValues + + _writer.WriteEndElement(); // ProductAttribute + } + _writer.WriteEndElement(); // ProductAttributes + } + + if (product.ProductAttributeCombinations != null) + { + _writer.WriteStartElement("ProductAttributeCombinations"); + foreach (dynamic combination in product.ProductAttributeCombinations) + { + ProductVariantAttributeCombination entityPvac = combination.Entity; + + _writer.WriteStartElement("ProductAttributeCombination"); + _writer.Write("Id", entityPvac.Id.ToString()); + _writer.Write("StockQuantity", entityPvac.StockQuantity.ToString()); + _writer.Write("AllowOutOfStockOrders", entityPvac.AllowOutOfStockOrders.ToString()); + _writer.Write("AttributesXml", entityPvac.AttributesXml); + _writer.Write("Sku", entityPvac.Sku); + _writer.Write("Gtin", entityPvac.Gtin); + _writer.Write("ManufacturerPartNumber", entityPvac.ManufacturerPartNumber); + _writer.Write("Price", entityPvac.Price.HasValue ? entityPvac.Price.Value.ToString(_culture) : ""); + _writer.Write("Length", entityPvac.Length.HasValue ? entityPvac.Length.Value.ToString(_culture) : ""); + _writer.Write("Width", entityPvac.Width.HasValue ? entityPvac.Width.Value.ToString(_culture) : ""); + _writer.Write("Height", entityPvac.Height.HasValue ? entityPvac.Height.Value.ToString(_culture) : ""); + _writer.Write("BasePriceAmount", entityPvac.BasePriceAmount.HasValue ? entityPvac.BasePriceAmount.Value.ToString(_culture) : ""); + _writer.Write("BasePriceBaseAmount", entityPvac.BasePriceBaseAmount.HasValue ? entityPvac.BasePriceBaseAmount.Value.ToString() : ""); + _writer.Write("AssignedPictureIds", entityPvac.AssignedPictureIds); + _writer.Write("DeliveryTimeId", entityPvac.DeliveryTimeId.HasValue ? entityPvac.DeliveryTimeId.Value.ToString() : ""); + _writer.Write("IsActive", entityPvac.IsActive.ToString()); + + WriteDeliveryTime(combination.DeliveryTime, "DeliveryTime"); + + WriteQuantityUnit(combination.QuantityUnit, "QuantityUnit"); + + _writer.WriteStartElement("Pictures"); + foreach (dynamic assignedPicture in combination.Pictures) + { + WritePicture(assignedPicture, "Picture"); + } + _writer.WriteEndElement(); // Pictures + + _writer.WriteEndElement(); // ProductAttributeCombination + } + _writer.WriteEndElement(); // ProductAttributeCombinations + } + + if (product.ProductPictures != null) + { + _writer.WriteStartElement("ProductPictures"); + foreach (dynamic productPicture in product.ProductPictures) + { + ProductPicture entityProductPicture = productPicture.Entity; + + _writer.WriteStartElement("ProductPicture"); + _writer.Write("Id", entityProductPicture.Id.ToString()); + _writer.Write("DisplayOrder", entityProductPicture.DisplayOrder.ToString()); + + WritePicture(productPicture.Picture, "Picture"); + + _writer.WriteEndElement(); // ProductPicture + } + _writer.WriteEndElement(); // ProductPictures + } + + if (product.ProductCategories != null) + { + _writer.WriteStartElement("ProductCategories"); + foreach (dynamic productCategory in product.ProductCategories) + { + ProductCategory entityProductCategory = productCategory.Entity; + + _writer.WriteStartElement("ProductCategory"); + _writer.Write("Id", entityProductCategory.Id.ToString()); + _writer.Write("DisplayOrder", entityProductCategory.DisplayOrder.ToString()); + _writer.Write("IsFeaturedProduct", entityProductCategory.IsFeaturedProduct.ToString()); + + WriteCategory(productCategory.Category, "Category"); + + _writer.WriteEndElement(); // ProductCategory + } + _writer.WriteEndElement(); // ProductCategories + } + + if (product.ProductManufacturers != null) + { + _writer.WriteStartElement("ProductManufacturers"); + foreach (dynamic productManu in product.ProductManufacturers) + { + ProductManufacturer entityProductManu = productManu.Entity; + + _writer.WriteStartElement("ProductManufacturer"); + + _writer.Write("Id", entityProductManu.Id.ToString()); + _writer.Write("DisplayOrder", entityProductManu.DisplayOrder.ToString()); + _writer.Write("IsFeaturedProduct", entityProductManu.IsFeaturedProduct.ToString()); + + WriteManufacturer(productManu.Manufacturer, "Manufacturer"); + + _writer.WriteEndElement(); // ProductManufacturer + } + _writer.WriteEndElement(); // ProductManufacturers + } + + if (product.ProductSpecificationAttributes != null) + { + _writer.WriteStartElement("ProductSpecificationAttributes"); + foreach (dynamic psa in product.ProductSpecificationAttributes) + { + ProductSpecificationAttribute entityPsa = psa.Entity; + + _writer.WriteStartElement("ProductSpecificationAttribute"); + + _writer.Write("Id", entityPsa.Id.ToString()); + _writer.Write("ProductId", entityPsa.ProductId.ToString()); + _writer.Write("SpecificationAttributeOptionId", entityPsa.SpecificationAttributeOptionId.ToString()); + _writer.Write("AllowFiltering", entityPsa.AllowFiltering.ToString()); + _writer.Write("ShowOnProductPage", entityPsa.ShowOnProductPage.ToString()); + _writer.Write("DisplayOrder", entityPsa.DisplayOrder.ToString()); + + dynamic option = psa.SpecificationAttributeOption; + SpecificationAttributeOption entitySao = option.Entity; + SpecificationAttribute entitySa = option.SpecificationAttribute.Entity; + + _writer.WriteStartElement("SpecificationAttributeOption"); + _writer.Write("Id", entitySao.Id.ToString()); + _writer.Write("SpecificationAttributeId", entitySao.SpecificationAttributeId.ToString()); + _writer.Write("DisplayOrder", entitySao.DisplayOrder.ToString()); + _writer.Write("Name", (string)option.Name); + + WriteLocalized(option); + + _writer.WriteStartElement("SpecificationAttribute"); + _writer.Write("Id", entitySa.Id.ToString()); + _writer.Write("Name", (string)option.SpecificationAttribute.Name); + _writer.Write("DisplayOrder", entitySa.DisplayOrder.ToString()); + + WriteLocalized(option.SpecificationAttribute); + + _writer.WriteEndElement(); // SpecificationAttribute + _writer.WriteEndElement(); // SpecificationAttributeOption + + _writer.WriteEndElement(); // ProductSpecificationAttribute + } + _writer.WriteEndElement(); // ProductSpecificationAttributes + } + + if (product.ProductBundleItems != null) + { + _writer.WriteStartElement("ProductBundleItems"); + foreach (dynamic bundleItem in product.ProductBundleItems) + { + ProductBundleItem entityPbi = bundleItem.Entity; + + _writer.WriteStartElement("ProductBundleItem"); + _writer.Write("Id", entityPbi.Id.ToString()); + _writer.Write("ProductId", entityPbi.ProductId.ToString()); + _writer.Write("BundleProductId", entityPbi.BundleProductId.ToString()); + _writer.Write("Quantity", entityPbi.Quantity.ToString()); + _writer.Write("Discount", entityPbi.Discount.HasValue ? entityPbi.Discount.Value.ToString(_culture) : ""); + _writer.Write("DiscountPercentage", entityPbi.DiscountPercentage.ToString()); + _writer.Write("Name", (string)bundleItem.Name); + _writer.Write("ShortDescription", (string)bundleItem.ShortDescription); + _writer.Write("FilterAttributes", entityPbi.FilterAttributes.ToString()); + _writer.Write("HideThumbnail", entityPbi.HideThumbnail.ToString()); + _writer.Write("Visible", entityPbi.Visible.ToString()); + _writer.Write("Published", entityPbi.Published.ToString()); + _writer.Write("DisplayOrder", ((int)bundleItem.DisplayOrder).ToString()); + _writer.Write("CreatedOnUtc", entityPbi.CreatedOnUtc.ToString(_culture)); + _writer.Write("UpdatedOnUtc", entityPbi.UpdatedOnUtc.ToString(_culture)); + + WriteLocalized(bundleItem); + + _writer.WriteEndElement(); // ProductBundleItem + } + _writer.WriteEndElement(); // ProductBundleItems + } + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + + public void WriteCustomer(dynamic customer, string node) + { + if (customer == null) + return; + + Customer entity = customer.Entity; + + if (node.HasValue()) + { + _writer.WriteStartElement(node); + } + + _writer.Write("Id", entity.Id.ToString()); + _writer.Write("CustomerGuid", entity.CustomerGuid.ToString()); + _writer.Write("Username", entity.Username); + _writer.Write("Email", entity.Email); + _writer.Write("Password", entity.Password); + _writer.Write("PasswordFormatId", entity.PasswordFormatId.ToString()); + _writer.Write("PasswordSalt", entity.PasswordSalt); + _writer.Write("AdminComment", entity.AdminComment); + _writer.Write("IsTaxExempt", entity.IsTaxExempt.ToString()); + _writer.Write("AffiliateId", entity.AffiliateId.ToString()); + _writer.Write("Active", entity.Active.ToString()); + _writer.Write("Deleted", entity.Deleted.ToString()); + _writer.Write("IsSystemAccount", entity.IsSystemAccount.ToString()); + _writer.Write("SystemName", entity.SystemName); + _writer.Write("LastIpAddress", entity.LastIpAddress); + _writer.Write("CreatedOnUtc", entity.CreatedOnUtc.ToString(_culture)); + _writer.Write("LastLoginDateUtc", entity.LastLoginDateUtc.HasValue ? entity.LastLoginDateUtc.Value.ToString(_culture) : ""); + _writer.Write("LastActivityDateUtc", entity.LastActivityDateUtc.ToString(_culture)); + _writer.Write("RewardPointsBalance", ((int)customer._RewardPointsBalance).ToString()); + + if (customer.CustomerRoles != null) + { + _writer.WriteStartElement("CustomerRoles"); + foreach (dynamic role in customer.CustomerRoles) + { + CustomerRole entityRole = role.Entity; + + _writer.WriteStartElement("CustomerRole"); + _writer.Write("Id", entityRole.Id.ToString()); + _writer.Write("Name", (string)role.Name); + _writer.Write("FreeShipping", entityRole.FreeShipping.ToString()); + _writer.Write("TaxExempt", entityRole.TaxExempt.ToString()); + _writer.Write("TaxDisplayType", entityRole.TaxDisplayType.HasValue ? entityRole.TaxDisplayType.Value.ToString() : ""); + _writer.Write("Active", entityRole.Active.ToString()); + _writer.Write("IsSystemRole", entityRole.IsSystemRole.ToString()); + _writer.Write("SystemName", entityRole.SystemName); + _writer.WriteEndElement(); // CustomerRole + } + _writer.WriteEndElement(); // CustomerRoles + } + + WriteRewardPointsHistory(customer.RewardPointsHistory, "RewardPointsHistories"); + WriteAddress(customer.BillingAddress, "BillingAddress"); + WriteAddress(customer.ShippingAddress, "ShippingAddress"); + + if (customer.Addresses != null) + { + _writer.WriteStartElement("Addresses"); + foreach (dynamic address in customer.Addresses) + { + WriteAddress(address, "Address"); + } + _writer.WriteEndElement(); // Addresses + } + + WriteGenericAttributes(customer); + + if (node.HasValue()) + { + _writer.WriteEndElement(); + } + } + } + + + /// + /// Allows to exclude XML nodes from export + /// + [Flags] + public enum ExportXmlExclude + { + None = 0, + Category = 1 + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/IDataExporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/IDataExporter.cs new file mode 100644 index 0000000000..34b96faf24 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/IDataExporter.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.DataExchange.Export +{ + public interface IDataExporter + { + DataExportResult Export(DataExportRequest request, CancellationToken cancellationToken); + + IList Preview(DataExportRequest request, int pageIndex, int? totalRecords = null); + + int GetDataCount(DataExportRequest request); + } + + + public class DataExportRequest + { + private readonly static ProgressValueSetter _voidProgressValueSetter = DataExportRequest.SetProgress; + + public DataExportRequest(ExportProfile profile, Provider provider) + { + Guard.ArgumentNotNull(() => profile); + Guard.ArgumentNotNull(() => provider); + + Profile = profile; + Provider = provider; + ProgressValueSetter = _voidProgressValueSetter; + + EntitiesToExport = new List(); + CustomData = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + public ExportProfile Profile { get; private set; } + + public Provider Provider { get; private set; } + + public ProgressValueSetter ProgressValueSetter { get; set; } + + public bool HasPermission { get; set; } + + public IList EntitiesToExport { get; set; } + + public IDictionary CustomData { get; private set; } + + public IQueryable ProductQuery { get; set; } + + + private static void SetProgress(int val, int max, string msg) + { + // do nothing + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/IExportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/IExportProfileService.cs new file mode 100644 index 0000000000..b0b0c8a6bd --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/IExportProfileService.cs @@ -0,0 +1,122 @@ +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.DataExchange.Export +{ + public interface IExportProfileService + { + /// + /// Inserts an export profile + /// + /// Provider system name + /// The name of the profile + /// File extension supported by provider + /// Features supportde by provider + /// Whether the new profile is a system profile + /// Profile system name + /// Identifier of a profile the settings should be copied from + /// New export profile + ExportProfile InsertExportProfile( + string providerSystemName, + string name, + string fileExtension, + ExportFeatures features, + bool isSystemProfile = false, + string profileSystemName = null, + int cloneFromProfileId = 0); + + /// + /// Inserts an export profile + /// + /// Export provider + /// Whether the new profile is a system profile + /// Profile system name + /// Identifier of a profile the settings should be copied from + /// New export profile + ExportProfile InsertExportProfile( + Provider provider, + bool isSystemProfile = false, + string profileSystemName = null, + int cloneFromProfileId = 0); + + /// + /// Updates an export profile + /// + /// Export profile + void UpdateExportProfile(ExportProfile profile); + + /// + /// Deletes an export profile + /// + /// Export profile + /// Whether to delete system profiles + void DeleteExportProfile(ExportProfile profile, bool force = false); + + /// + /// Get queryable export profiles + /// + /// Whether to filter enabled or disabled profiles + /// Export profiles + IQueryable GetExportProfiles(bool? enabled = null); + + /// + /// Gets an export profile by identifier + /// + /// Export profile identifier + /// Export profile + ExportProfile GetExportProfileById(int id); + + /// + /// Gets system export profile by provider system name + /// + /// Provider system name + /// + ExportProfile GetSystemExportProfile(string providerSystemName); + + /// + /// Gets export profiles by provider system name + /// + /// Provider system name + /// List of export profiles + IList GetExportProfilesBySystemName(string providerSystemName); + + + /// + /// Load all export providers + /// + /// Store identifier + /// Whether to load hidden providers + /// Export providers + IEnumerable> LoadAllExportProviders(int storeId = 0, bool showHidden = true); + + /// + /// Load export provider by system name + /// + /// Provider system name + /// Store identifier + /// Export provider + Provider LoadProvider(string systemName, int storeId = 0); + + /// + /// Get export deployment by identifier + /// + /// Export deployment identifier + /// Export deployment + ExportDeployment GetExportDeploymentById(int id); + + /// + /// Update an export deployment + /// + /// Export deployment + void UpdateExportDeployment(ExportDeployment deployment); + + /// + /// Deleted an export deployment + /// + /// Export deployment + void DeleteExportDeployment(ExportDeployment deployment); + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/IExportProvider.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/IExportProvider.cs new file mode 100644 index 0000000000..60be2e11a9 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/IExportProvider.cs @@ -0,0 +1,35 @@ +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.DataExchange.Export +{ + public partial interface IExportProvider : IProvider, IUserEditable + { + /// + /// The exported entity type + /// + ExportEntityType EntityType { get; } + + /// + /// File extension of the export files (without dot). Return null for a non file based, on-the-fly export. + /// + string FileExtension { get; } + + /// + /// Get provider specific configuration information. Return null when no provider specific configuration is required. + /// + ExportConfigurationInfo ConfigurationInfo { get; } + + /// + /// Export data to a file + /// + /// Export execution context + void Execute(ExportExecuteContext context); + + /// + /// Called once per store when export execution ended + /// + /// Export execution context + void OnExecuted(ExportExecuteContext context); + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/CategoryExportContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/CategoryExportContext.cs new file mode 100644 index 0000000000..ab6665b31e --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/CategoryExportContext.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Media; + +namespace SmartStore.Services.DataExchange.Export.Internal +{ + internal class CategoryExportContext + { + protected List _categoryIds; + protected List _pictureIds; + + private Func> _funcProductCategories; + private Func> _funcPictures; + + private LazyMultimap _productCategories; + private LazyMultimap _pictures; + + public CategoryExportContext( + IEnumerable categories, + Func> productCategories, + Func> pictures) + { + if (categories == null) + { + _categoryIds = new List(); + _pictureIds = new List(); + } + else + { + _categoryIds = new List(categories.Select(x => x.Id)); + _pictureIds = new List(categories.Where(x => (x.PictureId ?? 0) != 0).Select(x => x.PictureId ?? 0)); + } + + _funcProductCategories = productCategories; + _funcPictures = pictures; + } + + public void Clear() + { + if (_productCategories != null) + _productCategories.Clear(); + if (_pictures != null) + _pictures.Clear(); + + _categoryIds.Clear(); + _pictureIds.Clear(); + } + + public LazyMultimap ProductCategories + { + get + { + if (_productCategories == null) + { + _productCategories = new LazyMultimap(keys => _funcProductCategories(keys), _categoryIds); + } + return _productCategories; + } + } + + public LazyMultimap Pictures + { + get + { + if (_pictures == null) + { + _pictures = new LazyMultimap(keys => _funcPictures(keys).ToMultimap(x => x.Id, x => x), _pictureIds); + } + return _pictures; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/CustomerExportContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/CustomerExportContext.cs new file mode 100644 index 0000000000..918cb3e110 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/CustomerExportContext.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; + +namespace SmartStore.Services.DataExchange.Export.Internal +{ + public class CustomerExportContext + { + protected List _customerIds; + + private Func> _funcGenericAttributes; + + private LazyMultimap _genericAttributes; + + public CustomerExportContext( + IEnumerable customers, + Func> genericAttributes) + { + if (customers == null) + { + _customerIds = new List(); + } + else + { + _customerIds = new List(customers.Select(x => x.Id)); + } + + _funcGenericAttributes = genericAttributes; + } + + public void Clear() + { + if (_genericAttributes != null) + _genericAttributes.Clear(); + + _customerIds.Clear(); + } + + public LazyMultimap GenericAttributes + { + get + { + if (_genericAttributes == null) + { + _genericAttributes = new LazyMultimap(keys => _funcGenericAttributes(keys), _customerIds); + } + return _genericAttributes; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/DataExporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/DataExporterContext.cs new file mode 100644 index 0000000000..5c6c1315dd --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/DataExporterContext.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.DataExchange.Export.Internal +{ + internal class DataExporterContext + { + public DataExporterContext( + DataExportRequest request, + CancellationToken cancellationToken, + bool isPreview = false) + { + Request = request; + CancellationToken = cancellationToken; + Filter = XmlHelper.Deserialize(request.Profile.Filtering); + Projection = XmlHelper.Deserialize(request.Profile.Projection); + IsPreview = isPreview; + + FolderContent = request.Profile.GetExportFolder(true, true); + + Categories = new Dictionary(); + CategoryPathes = new Dictionary(); + DeliveryTimes = new Dictionary(); + QuantityUnits = new Dictionary(); + Stores = new Dictionary(); + Languages = new Dictionary(); + Countries = new Dictionary(); + ProductTemplates = new Dictionary(); + CategoryTemplates = new Dictionary(); + NewsletterSubscriptions = new HashSet(); + + RecordsPerStore = new Dictionary(); + EntityIdsLoaded = new List(); + EntityIdsPerSegment = new List(); + + Result = new DataExportResult + { + FileFolder = (IsFileBasedExport ? FolderContent : null) + }; + + ExecuteContext = new ExportExecuteContext(Result, CancellationToken, FolderContent); + ExecuteContext.Projection = XmlHelper.Deserialize(request.Profile.Projection); + + if (!IsPreview) + { + ExecuteContext.ProgressValueSetter = Request.ProgressValueSetter; + } + } + + /// + /// All entity identifiers per export + /// + public List EntityIdsLoaded { get; set; } + public void SetLoadedEntityIds(IEnumerable ids) + { + EntityIdsLoaded = EntityIdsLoaded + .Union(ids) + .Distinct() + .ToList(); + } + + /// + /// All entity identifiers per segment (to avoid exporting products multiple times) + /// + public List EntityIdsPerSegment { get; set; } + + public int RecordCount { get; set; } + public Dictionary RecordsPerStore { get; set; } + public string ProgressInfo { get; set; } + + public DataExportRequest Request { get; private set; } + public CancellationToken CancellationToken { get; private set; } + public bool IsPreview { get; private set; } + + public bool Supports(ExportFeatures feature) + { + return (!IsPreview && Request.Provider.Metadata.ExportFeatures.HasFlag(feature)); + } + + public ExportFilter Filter { get; private set; } + public ExportProjection Projection { get; private set; } + public Currency ContextCurrency { get; set; } + public Customer ContextCustomer { get; set; } + public Language ContextLanguage { get; set; } + + public TraceLogger Log { get; set; } + public Store Store { get; set; } + + public string FolderContent { get; private set; } + + public bool IsFileBasedExport + { + get { return Request.Provider == null || Request.Provider.Value == null || Request.Provider.Value.FileExtension.HasValue(); } + } + + // data loaded once per export + public Dictionary Categories { get; set; } + public Dictionary CategoryPathes { get; set; } + public Dictionary DeliveryTimes { get; set; } + public Dictionary QuantityUnits { get; set; } + public Dictionary Stores { get; set; } + public Dictionary Languages { get; set; } + public Dictionary Countries { get; set; } + public Dictionary ProductTemplates { get; set; } + public Dictionary CategoryTemplates { get; set; } + public HashSet NewsletterSubscriptions { get; set; } + + // data loaded once per page + public ProductExportContext ProductExportContext { get; set; } + public OrderExportContext OrderExportContext { get; set; } + public ManufacturerExportContext ManufacturerExportContext { get; set; } + public CategoryExportContext CategoryExportContext { get; set; } + public CustomerExportContext CustomerExportContext { get; set; } + + public ExportExecuteContext ExecuteContext { get; set; } + public DataExportResult Result { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/DynamicEntity.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/DynamicEntity.cs new file mode 100644 index 0000000000..874d43e7e3 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/DynamicEntity.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using SmartStore.ComponentModel; + +namespace SmartStore.Services.DataExchange.Export.Internal +{ + internal class DynamicEntity : HybridExpando + { + public DynamicEntity(DynamicEntity dynamicEntity) + : this(dynamicEntity.WrappedObject) + { + MergeRange(dynamicEntity); + } + + public DynamicEntity(object entity) + : base(entity) + { + base.Properties["Entity"] = entity; + } + + public void Merge(string name, object value) + { + Properties[name] = value; + } + + public void MergeRange(IDictionary other) + { + foreach (var kvp in other) + { + Properties[kvp.Key] = kvp.Value; + } + } + + protected override bool TrySetMemberCore(string name, object value) + { + Properties[name] = value; + return true; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/ManufacturerExportContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/ManufacturerExportContext.cs new file mode 100644 index 0000000000..82c607f5ad --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/ManufacturerExportContext.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Media; + +namespace SmartStore.Services.DataExchange.Export.Internal +{ + internal class ManufacturerExportContext + { + protected List _manufacturerIds; + protected List _pictureIds; + + private Func> _funcProductManufacturers; + private Func> _funcPictures; + + private LazyMultimap _productManufacturers; + private LazyMultimap _pictures; + + public ManufacturerExportContext( + IEnumerable manufacturers, + Func> productManufacturers, + Func> pictures) + { + if (manufacturers == null) + { + _manufacturerIds = new List(); + _pictureIds = new List(); + } + else + { + _manufacturerIds = new List(manufacturers.Select(x => x.Id)); + _pictureIds = new List(manufacturers.Where(x => (x.PictureId ?? 0) != 0).Select(x => x.PictureId ?? 0)); + } + + _funcProductManufacturers = productManufacturers; + _funcPictures = pictures; + } + + public void Clear() + { + if (_productManufacturers != null) + _productManufacturers.Clear(); + if (_pictures != null) + _pictures.Clear(); + + _manufacturerIds.Clear(); + _pictureIds.Clear(); + } + + public LazyMultimap ProductManufacturers + { + get + { + if (_productManufacturers == null) + { + _productManufacturers = new LazyMultimap(keys => _funcProductManufacturers(keys), _manufacturerIds); + } + return _productManufacturers; + } + } + + public LazyMultimap Pictures + { + get + { + if (_pictures == null) + { + _pictures = new LazyMultimap(keys => _funcPictures(keys).ToMultimap(x => x.Id, x => x), _pictureIds); + } + return _pictures; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/OrderExportContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/OrderExportContext.cs new file mode 100644 index 0000000000..9ebe5c25a5 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/OrderExportContext.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Shipping; + +namespace SmartStore.Services.DataExchange.Export.Internal +{ + internal class OrderExportContext + { + protected List _orderIds; + protected List _customerIds; + protected List _addressIds; + + private Func> _funcCustomers; + private Func> _funcRewardPointsHistories; + private Func> _funcAddresses; + private Func> _funcOrderItems; + private Func> _funcShipments; + + private LazyMultimap _customers; + private LazyMultimap _rewardPointsHistories; + private LazyMultimap
_addresses; + private LazyMultimap _orderItems; + private LazyMultimap _shipments; + + public OrderExportContext(IEnumerable orders, + Func> customers, + Func> rewardPointsHistory, + Func> addresses, + Func> orderItems, + Func> shipments) + { + if (orders == null) + { + _orderIds = new List(); + _customerIds = new List(); + _addressIds = new List(); + } + else + { + _orderIds = new List(orders.Select(x => x.Id)); + _customerIds = new List(orders.Select(x => x.CustomerId)); + + _addressIds = orders.Select(x => x.BillingAddressId) + .Union(orders.Select(x => x.ShippingAddressId ?? 0)) + .Where(x => x != 0) + .Distinct() + .ToList(); + } + + _funcCustomers = customers; + _funcRewardPointsHistories = rewardPointsHistory; + _funcAddresses = addresses; + _funcOrderItems = orderItems; + _funcShipments = shipments; + } + + public void Clear() + { + if (_customers != null) + _customers.Clear(); + if (_rewardPointsHistories != null) + _rewardPointsHistories.Clear(); + if (_addresses != null) + _addresses.Clear(); + if (_orderItems != null) + _orderItems.Clear(); + if (_shipments != null) + _shipments.Clear(); + + _orderIds.Clear(); + _customerIds.Clear(); + _addressIds.Clear(); + } + + public LazyMultimap Customers + { + get + { + if (_customers == null) + { + _customers = new LazyMultimap(keys => _funcCustomers(keys).ToMultimap(x => x.Id, x => x), _customerIds); + } + return _customers; + } + } + + public LazyMultimap RewardPointsHistories + { + get + { + if (_rewardPointsHistories == null) + { + _rewardPointsHistories = new LazyMultimap(keys => _funcRewardPointsHistories(keys), _customerIds); + } + return _rewardPointsHistories; + } + } + + public LazyMultimap
Addresses + { + get + { + if (_addresses == null) + { + _addresses = new LazyMultimap
(keys => _funcAddresses(keys).ToMultimap(x => x.Id, x => x), _addressIds); + } + return _addresses; + } + } + + public LazyMultimap OrderItems + { + get + { + if (_orderItems == null) + { + _orderItems = new LazyMultimap(keys => _funcOrderItems(keys), _orderIds); + } + return _orderItems; + } + } + + public LazyMultimap Shipments + { + get + { + if (_shipments == null) + { + _shipments = new LazyMultimap(keys => _funcShipments(keys), _orderIds); + } + return _shipments; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/ProductExportContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/ProductExportContext.cs new file mode 100644 index 0000000000..6a76e1ffef --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Export/Internal/ProductExportContext.cs @@ -0,0 +1,148 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using SmartStore.Collections; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Services.Catalog; + +namespace SmartStore.Services.DataExchange.Export.Internal +{ + internal class ProductExportContext : PriceCalculationContext + { + private List _productIdsBundleItems; + + private Func> _funcProductManufacturers; + private Func> _funcProductPictures; + private Func> _funcProductTags; + private Func> _funcProductSpecificationAttributes; + private Func> _funcProductBundleItems; + + private LazyMultimap _productManufacturers; + private LazyMultimap _productPictures; + private LazyMultimap _productTags; + private LazyMultimap _productSpecificationAttributes; + private LazyMultimap _productBundleItems; + + public ProductExportContext( + IEnumerable products, + Func> attributes, + Func> attributeCombinations, + Func> tierPrices, + Func> productCategories, + Func> productManufacturers, + Func> productPictures, + Func> productTags, + Func> productAppliedDiscounts, + Func> productSpecificationAttributes, + Func> productBundleItems) + : base(products, + attributes, + attributeCombinations, + tierPrices, + productCategories, + productAppliedDiscounts) + { + if (products == null) + { + _productIdsBundleItems = new List(); + } + else + { + _productIdsBundleItems = new List(products.Where(x => x.ProductType == ProductType.BundledProduct).Select(x => x.Id)); + } + + _funcProductManufacturers = productManufacturers; + _funcProductPictures = productPictures; + _funcProductTags = productTags; + _funcProductSpecificationAttributes = productSpecificationAttributes; + _funcProductBundleItems = productBundleItems; + } + + public new void Clear() + { + if (_productManufacturers != null) + _productManufacturers.Clear(); + if (_productPictures != null) + _productPictures.Clear(); + if (_productTags != null) + _productTags.Clear(); + if (_productSpecificationAttributes != null) + _productSpecificationAttributes.Clear(); + if (_productBundleItems != null) + _productBundleItems.Clear(); + + _productIdsBundleItems.Clear(); + + base.Clear(); + } + + //public new void Collect(IEnumerable productIds) + //{ + // ProductManufacturers.Collect(productIds); + // ProductPictures.Collect(productIds); + + // base.Collect(productIds); + //} + + public LazyMultimap ProductManufacturers + { + get + { + if (_productManufacturers == null) + { + _productManufacturers = new LazyMultimap(keys => _funcProductManufacturers(keys), _productIds); + } + return _productManufacturers; + } + } + + public LazyMultimap ProductPictures + { + get + { + if (_productPictures == null) + { + _productPictures = new LazyMultimap(keys => _funcProductPictures(keys), _productIds); + } + return _productPictures; + } + } + + public LazyMultimap ProductTags + { + get + { + if (_productTags == null) + { + _productTags = new LazyMultimap(keys => _funcProductTags(keys), _productIds); + } + return _productTags; + } + } + + public LazyMultimap ProductSpecificationAttributes + { + get + { + if (_productSpecificationAttributes == null) + { + _productSpecificationAttributes = new LazyMultimap(keys => _funcProductSpecificationAttributes(keys), _productIds); + } + return _productSpecificationAttributes; + } + } + + public LazyMultimap ProductBundleItems + { + get + { + if (_productBundleItems == null) + { + _productBundleItems = new LazyMultimap(keys => _funcProductBundleItems(keys), _productIdsBundleItems); + } + return _productBundleItems; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/ISyncMappingService.cs b/src/Libraries/SmartStore.Services/DataExchange/ISyncMappingService.cs new file mode 100644 index 0000000000..eb72d07e19 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/ISyncMappingService.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange +{ + public partial interface ISyncMappingService + { + /// + /// Inserts a sync mapping entity + /// + /// Sync mapping + void InsertSyncMapping(SyncMapping mapping); + + /// + /// Inserts a range of sync mapping entities + /// + /// A sequence of sync mappings + void InsertSyncMappings(IEnumerable mappings); + + /// + /// Gets all sync mappings + /// + /// The context (external application) name. Leave null to load all records regardless of context. + /// The entity name. Leave null to load all records regardless of entity name. + /// SyncMappings + IList GetAllSyncMappings(string contextName = null, string entityName = null); + + /// + /// Gets a sync mapping record by (target) entity id, name and context name. + /// + /// Entity nd + /// Entity name + /// Context name + /// SyncMapping + SyncMapping GetSyncMappingByEntity(int entityId, string entityName, string contextName); + + /// + /// Gets a sync mapping record by (external) source key, entity name and context name. + /// + /// Source key + /// Entity name + /// Context name + /// SyncMappings + SyncMapping GetSyncMappingBySource(string sourceKey, string entityName, string contextName); + + /// + /// Deletes a sync mapping entity + /// + /// Sync mapping + void DeleteSyncMapping(SyncMapping mapping); + + /// + /// Deletes a range of sync mapping entities + /// + /// Sync mappings + void DeleteSyncMappings(IEnumerable mappings); + + /// + /// Deletes all sync mapping entities referencing the specified entity + /// + /// The entity + void DeleteSyncMappingsFor(T entity) where T : BaseEntity; + + /// + /// Deletes a range of sync mapping entities + /// + /// The context (external application) name. + /// The entity name. Leave null to delete all context specific mappings regardless of entity name. + /// SyncMappings + void DeleteSyncMappings(string contextName, string entityName = null); + + /// + /// Updates a sync mapping entity + /// + /// Sync mapping + void UpdateSyncMapping(SyncMapping mapping); + } + + + public static class ISyncMappingServiceExtensions + { + + public static SyncMapping InsertSyncMapping(this ISyncMappingService svc, T entity, string contextName, string sourceKey) where T : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotEmpty(() => contextName); + Guard.ArgumentNotEmpty(() => sourceKey); + + if (entity is SyncMapping) + { + throw Error.InvalidOperation("Cannot insert a sync mapping record for a SyncMapping entity"); + } + + if (entity.IsTransientRecord()) + { + throw Error.InvalidOperation("Cannot insert a sync mapping record for a transient (unsaved) entity"); + } + + var mapping = new SyncMapping + { + ContextName = contextName, + EntityId = entity.Id, + EntityName = typeof(T).Name, + SourceKey = sourceKey + }; + + return mapping; + } + + public static SyncMapping GetSyncMappingByEntity(this ISyncMappingService svc, T entity, string contextName) where T : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotEmpty(() => contextName); + + if (entity is SyncMapping) + { + throw Error.InvalidOperation("Cannot get a sync mapping record for a SyncMapping entity"); + } + + if (entity.IsTransientRecord()) + { + throw Error.InvalidOperation("Cannot get a sync mapping record for a transient (unsaved) entity"); + } + + return svc.GetSyncMappingByEntity(entity.Id, typeof(T).Name, contextName); + } + + /// + /// Inserts a range of sync mapping entities by specifying two equal sized sequences for entity ids and source keys. + /// + /// Context name for all mappings + /// Entity name for all mappings + /// A sequence of entity ids + /// A sequence of source keys + /// List of persisted sync mappings + /// Both sequences must contain at least one element and must be of equal size. + public static IList InsertSyncMappings(this ISyncMappingService svc, string contextName, string entityName, IEnumerable entityIds, IEnumerable sourceKeys) + { + Guard.ArgumentNotEmpty(() => contextName); + Guard.ArgumentNotEmpty(() => entityName); + Guard.ArgumentNotNull(() => entityIds); + Guard.ArgumentNotNull(() => sourceKeys); + + if (!entityIds.Any() || !sourceKeys.Any() || entityIds.Count() != sourceKeys.Count()) + { + throw Error.InvalidOperation("Both sequences must contain at least one element and must be of equal size."); + } + + var mappings = new List(); + var arrIds = entityIds.ToArray(); + var arrKeys = sourceKeys.ToArray(); + + for (int i = 0; i < arrIds.Length; i++) + { + mappings.Add(new SyncMapping + { + ContextName = contextName, + EntityName = entityName, + EntityId = arrIds[i], + SourceKey = arrKeys[i] + }); + } + + svc.InsertSyncMappings(mappings); + + return mappings; + } + + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs new file mode 100644 index 0000000000..14a0ac77e9 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMap.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace SmartStore.Services.DataExchange.Import +{ + public class ColumnMap + { + // maps source column to property + private readonly Dictionary _map = new Dictionary(StringComparer.OrdinalIgnoreCase); + + private static bool IsIndexed(string name) + { + return (name.EmptyNull().EndsWith("]") && name.EmptyNull().Contains("[")); + } + + private static string CreateSourceName(string name, string index) + { + if (index.HasValue()) + { + name += String.Concat("[", index, "]"); + } + + return name; + } + + public IReadOnlyDictionary Mappings + { + get { return _map; } + } + + public static bool ParseSourceName(string sourceName, out string nameWithoutIndex, out string index) + { + nameWithoutIndex = sourceName; + index = null; + + var result = true; + + if (sourceName.HasValue() && IsIndexed(sourceName)) + { + var x1 = sourceName.IndexOf('['); + var x2 = sourceName.IndexOf(']', x1); + + if (x1 != -1 && x2 != -1 && x2 > x1) + { + nameWithoutIndex = sourceName.Substring(0, x1); + index = sourceName.Substring(x1 + 1, x2 - x1 - 1); + } + else + { + result = false; + } + } + + return result; + } + + public void AddMapping(string sourceName, string mappedName, string defaultValue = null) + { + AddMapping(sourceName, null, mappedName, defaultValue); + } + + public void AddMapping(string sourceName, string index, string mappedName, string defaultValue = null) + { + Guard.ArgumentNotEmpty(() => sourceName); + Guard.ArgumentNotEmpty(() => mappedName); + + var key = CreateSourceName(sourceName, index); + + _map[key] = new ColumnMappingItem + { + SoureName = key, + MappedName = mappedName, + Default = defaultValue + }; + } + + /// + /// Gets a mapped column value + /// + /// The name of the column to get a mapped value for. + /// The column index, e.g. a language code (de, en etc.) + /// The mapped column value OR - if the name is unmapped - a value with the passed [] + public ColumnMappingItem GetMapping(string sourceName, string index) + { + return GetMapping(CreateSourceName(sourceName, index)); + } + + /// + /// Gets a mapped column value + /// + /// The name of the column to get a mapped value for. + /// The mapped column value OR - if the name is unmapped - the value of the passed + public ColumnMappingItem GetMapping(string sourceName) + { + ColumnMappingItem result; + + if (_map.TryGetValue(sourceName, out result)) + { + return result; + } + + return new ColumnMappingItem { SoureName = sourceName, MappedName = sourceName }; + } + } + + + [JsonObject(MemberSerialization.OptIn)] + public class ColumnMappingItem + { + private bool? _ignored; + + /// + /// The source name + /// + [JsonIgnore] + public string SoureName { get; set; } + + /// + /// The mapped name + /// + [JsonProperty] + public string MappedName { get; set; } + + /// + /// An optional default value + /// + [JsonProperty] + public string Default { get; set; } + + /// + /// Indicates whether to explicitly ignore this property + /// + public bool IgnoreProperty + { + get + { + if (_ignored == null) + { + _ignored = Default != null && Default == "[IGNOREPROPERTY]"; + } + + return _ignored.Value; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs new file mode 100644 index 0000000000..c46b90b82a --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ColumnMapping/ColumnMapConverter.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using Newtonsoft.Json; +using SmartStore.ComponentModel; + +namespace SmartStore.Services.DataExchange.Import +{ + public class ColumnMapConverter : TypeConverterBase + { + public ColumnMapConverter() + : base(typeof(object)) + { + } + + public override bool CanConvertFrom(Type type) + { + return type == typeof(string); + } + + public override bool CanConvertTo(Type type) + { + return type == typeof(string); + } + + public override object ConvertFrom(CultureInfo culture, object value) + { + if (value is string) + { + var dict = JsonConvert.DeserializeObject>((string)value); + var map = new ColumnMap(); + + foreach (var kvp in dict) + { + map.AddMapping(kvp.Key, null, kvp.Value.MappedName, kvp.Value.Default); + } + + return map; + } + + return base.ConvertFrom(culture, value); + } + + public T ConvertFrom(string value) + { + if (value.HasValue()) + return (T)ConvertFrom(CultureInfo.InvariantCulture, value); + + return default(T); + } + + public override object ConvertTo(CultureInfo culture, string format, object value, Type to) + { + if (to == typeof(string)) + { + if (value is ColumnMap) + { + return JsonConvert.SerializeObject(((ColumnMap)value).Mappings); + } + else + { + return string.Empty; + } + } + + return base.ConvertTo(culture, format, value, to); + } + + public string ConvertTo(object value) + { + return (string)ConvertTo(CultureInfo.InvariantCulture, null, value, typeof(string)); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs new file mode 100644 index 0000000000..a25235fe00 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImportTask.cs @@ -0,0 +1,34 @@ +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.DataExchange.Import +{ + // note: namespace persisted in ScheduleTask.Type + public partial class DataImportTask : ITask + { + private readonly IDataImporter _importer; + private readonly IImportProfileService _importProfileService; + + public DataImportTask( + IDataImporter importer, + IImportProfileService importProfileService) + { + _importer = importer; + _importProfileService = importProfileService; + } + + public void Execute(TaskExecutionContext ctx) + { + var profileId = ctx.ScheduleTask.Alias.ToInt(); + var profile = _importProfileService.GetImportProfileById(profileId); + + var request = new DataImportRequest(profile); + + request.ProgressValueSetter = delegate (int val, int max, string msg) + { + ctx.SetProgress(val, max, msg, true); + }; + + _importer.Import(request, ctx.CancellationToken); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs new file mode 100644 index 0000000000..aeb4b81897 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataImporter.cs @@ -0,0 +1,360 @@ +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Linq; +using SmartStore.Core; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Email; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Services.DataExchange.Csv; +using SmartStore.Services.DataExchange.Import.Internal; +using SmartStore.Services.Localization; +using SmartStore.Services.Messages; +using SmartStore.Services.Security; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Import +{ + public partial class DataImporter : IDataImporter + { + private readonly ICommonServices _services; + private readonly IImportProfileService _importProfileService; + private readonly ILanguageService _languageService; + private readonly Func _importerFactory; + private readonly Lazy _emailAccountService; + private readonly Lazy _emailSender; + private readonly Lazy _contactDataSettings; + private readonly Lazy _dataExchangeSettings; + + public DataImporter( + ICommonServices services, + IImportProfileService importProfileService, + ILanguageService languageService, + Func importerFactory, + Lazy emailAccountService, + Lazy emailSender, + Lazy contactDataSettings, + Lazy dataExchangeSettings) + { + _services = services; + _importProfileService = importProfileService; + _languageService = languageService; + _importerFactory = importerFactory; + _emailAccountService = emailAccountService; + _emailSender = emailSender; + _contactDataSettings = contactDataSettings; + _dataExchangeSettings = dataExchangeSettings; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + private bool HasPermission(DataImporterContext ctx) + { + if (ctx.Request.HasPermission) + return true; + + var customer = _services.WorkContext.CurrentCustomer; + + if (customer.SystemName == SystemCustomerNames.BackgroundTask) + return true; + + if (ctx.Request.Profile.EntityType == ImportEntityType.Product || ctx.Request.Profile.EntityType == ImportEntityType.Category) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog, customer); + + if (ctx.Request.Profile.EntityType == ImportEntityType.Customer) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageCustomers, customer); + + if (ctx.Request.Profile.EntityType == ImportEntityType.NewsLetterSubscription) + return _services.Permissions.Authorize(StandardPermissionProvider.ManageNewsletterSubscribers, customer); + + return true; + } + + private void LogResult(DataImporterContext ctx) + { + var result = ctx.ExecuteContext.Result; + var sb = new StringBuilder(); + + sb.AppendLine(); + sb.AppendFormat("Started:\t\t{0}\r\n", result.StartDateUtc.ToLocalTime()); + sb.AppendFormat("Finished:\t\t{0}\r\n", result.EndDateUtc.ToLocalTime()); + sb.AppendFormat("Duration:\t\t{0}\r\n", (result.EndDateUtc - result.StartDateUtc).ToString("g")); + sb.AppendLine(); + sb.AppendFormat("Total rows:\t\t{0}\r\n", result.TotalRecords); + sb.AppendFormat("Rows processed:\t\t{0}\r\n", result.AffectedRecords); + sb.AppendFormat("Records imported:\t{0}\r\n", result.NewRecords); + sb.AppendFormat("Records updated:\t{0}\r\n", result.ModifiedRecords); + sb.AppendLine(); + sb.AppendFormat("Warnings:\t\t{0}\r\n", result.Warnings); + sb.AppendFormat("Errors:\t\t\t{0}", result.Errors); + + ctx.Log.Information(sb.ToString()); + + foreach (var message in result.Messages) + { + if (message.MessageType == ImportMessageType.Error) + ctx.Log.Error(message.ToString(), message.FullMessage); + else if (message.MessageType == ImportMessageType.Warning) + ctx.Log.Warning(message.ToString()); + else + ctx.Log.Information(message.ToString()); + } + } + + private void SendCompletionEmail(DataImporterContext ctx) + { + var emailAccount = _emailAccountService.Value.GetDefaultEmailAccount(); + var smtpContext = new SmtpContext(emailAccount); + var message = new EmailMessage(); + + var store = _services.StoreContext.CurrentStore; + var storeInfo = "{0} ({1})".FormatInvariant(store.Name, store.Url); + var intro = _services.Localization.GetResource("Admin.DataExchange.Import.CompletedEmail.Body").FormatInvariant(storeInfo); + var body = new StringBuilder(intro); + var result = ctx.ExecuteContext.Result; + + if (result.LastError.HasValue()) + { + body.AppendFormat("

{0}

", result.LastError); + } + + body.Append("

"); + + body.AppendFormat("

{0}: {1} · {2}: {3}
", + T("Admin.Common.TotalRows"), result.TotalRecords, + T("Admin.Common.Skipped"), result.SkippedRecords); + + body.AppendFormat("
{0}: {1} · {2}: {3}
", + T("Admin.Common.NewRecords"), result.NewRecords, + T("Admin.Common.Updated"), result.ModifiedRecords); + + body.AppendFormat("
{0}: {1} · {2}: {3}
", + T("Admin.Common.Errors"), result.Errors, + T("Admin.Common.Warnings"), result.Warnings); + + body.Append("

"); + + message.From = new EmailAddress(emailAccount.Email, emailAccount.DisplayName); + + if (_contactDataSettings.Value.WebmasterEmailAddress.HasValue()) + message.To.Add(new EmailAddress(_contactDataSettings.Value.WebmasterEmailAddress)); + + if (message.To.Count == 0 && _contactDataSettings.Value.CompanyEmailAddress.HasValue()) + message.To.Add(new EmailAddress(_contactDataSettings.Value.CompanyEmailAddress)); + + if (message.To.Count == 0) + message.To.Add(new EmailAddress(emailAccount.Email, emailAccount.DisplayName)); + + message.Subject = T("Admin.DataExchange.Import.CompletedEmail.Subject").Text.FormatInvariant(ctx.Request.Profile.Name); + + message.Body = body.ToString(); + + _emailSender.Value.SendEmail(smtpContext, message); + + //Core.Infrastructure.EngineContext.Current.Resolve().InsertQueuedEmail(new QueuedEmail + //{ + // From = emailAccount.Email, + // FromName = emailAccount.DisplayName, + // To = message.To.First().Address, + // Subject = message.Subject, + // Body = message.Body, + // CreatedOnUtc = DateTime.UtcNow, + // EmailAccountId = emailAccount.Id, + // SendManually = true + //}); + //_services.DbContext.SaveChanges(); + } + + private void ImportCoreInner(DataImporterContext ctx, string filePath) + { + if (ctx.ExecuteContext.Abort == DataExchangeAbortion.Hard) + return; + + { + var logHead = new StringBuilder(); + logHead.AppendLine(); + logHead.AppendLine(new string('-', 40)); + logHead.AppendLine("SmartStore.NET:\t\tv." + SmartStoreVersion.CurrentFullVersion); + logHead.Append("Import profile:\t\t" + ctx.Request.Profile.Name); + logHead.AppendLine(ctx.Request.Profile.Id == 0 ? " (volatile)" : " (Id {0})".FormatInvariant(ctx.Request.Profile.Id)); + + logHead.AppendLine("Entity:\t\t\t" + ctx.Request.Profile.EntityType.ToString()); + logHead.AppendLine("File:\t\t\t" + Path.GetFileName(filePath)); + + var customer = _services.WorkContext.CurrentCustomer; + logHead.Append("Executed by:\t\t" + (customer.Email.HasValue() ? customer.Email : customer.SystemName)); + + ctx.Log.Information(logHead.ToString()); + } + + if (!File.Exists(filePath)) + { + throw new SmartException("File does not exist {0}.".FormatInvariant(filePath)); + } + + CsvConfiguration csvConfiguration = null; + var extension = Path.GetExtension(filePath); + + if ((new string[] { ".csv", ".txt", ".tab" }).Contains(extension, StringComparer.OrdinalIgnoreCase)) + { + var converter = new CsvConfigurationConverter(); + csvConfiguration = converter.ConvertFrom(ctx.Request.Profile.FileTypeConfiguration); + } + + if (csvConfiguration == null) + { + csvConfiguration = CsvConfiguration.ExcelFriendlyConfiguration; + } + + using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + ctx.ExecuteContext.DataTable = LightweightDataTable.FromFile( + Path.GetFileName(filePath), + stream, + stream.Length, + csvConfiguration, + ctx.Request.Profile.Skip, + ctx.Request.Profile.Take > 0 ? ctx.Request.Profile.Take : int.MaxValue + ); + + try + { + ctx.Importer.Execute(ctx.ExecuteContext); + } + catch (Exception exception) + { + ctx.ExecuteContext.Abort = DataExchangeAbortion.Hard; + ctx.ExecuteContext.Result.AddError(exception, "The importer failed: {0}.".FormatInvariant(exception.ToAllMessages())); + } + + if (ctx.ExecuteContext.IsMaxFailures) + ctx.ExecuteContext.Result.AddWarning("Import aborted. The maximum number of failures has been reached."); + + if (ctx.CancellationToken.IsCancellationRequested) + ctx.ExecuteContext.Result.AddWarning("Import aborted. A cancellation has been requested."); + } + } + + private void ImportCoreOuter(DataImporterContext ctx) + { + if (ctx.Request.Profile == null || !ctx.Request.Profile.Enabled) + return; + + var logPath = ctx.Request.Profile.GetImportLogPath(); + + FileSystemHelper.Delete(logPath); + + using (var logger = new TraceLogger(logPath)) + { + try + { + ctx.Log = logger; + + ctx.ExecuteContext.DataExchangeSettings = _dataExchangeSettings.Value; + ctx.ExecuteContext.Services = _services; + ctx.ExecuteContext.Log = logger; + ctx.ExecuteContext.Languages = _languageService.GetAllLanguages(true); + ctx.ExecuteContext.UpdateOnly = ctx.Request.Profile.UpdateOnly; + ctx.ExecuteContext.KeyFieldNames = ctx.Request.Profile.KeyFieldNames.SplitSafe(","); + ctx.ExecuteContext.ImportFolder = ctx.Request.Profile.GetImportFolder(); + ctx.ExecuteContext.ExtraData = XmlHelper.Deserialize(ctx.Request.Profile.ExtraData); + + { + var mapConverter = new ColumnMapConverter(); + ctx.ExecuteContext.ColumnMap = mapConverter.ConvertFrom(ctx.Request.Profile.ColumnMapping) ?? new ColumnMap(); + } + + var files = ctx.Request.Profile.GetImportFiles(); + + if (files.Count == 0) + throw new SmartException("No files to import."); + + if (!HasPermission(ctx)) + throw new SmartException("You do not have permission to perform the selected import."); + + ctx.Importer = _importerFactory(ctx.Request.Profile.EntityType); + + files.ForEach(x => ImportCoreInner(ctx, x)); + } + catch (Exception exception) + { + ctx.ExecuteContext.Result.AddError(exception); + } + finally + { + try + { + // database context sharing problem: if there are entities in modified state left by the provider due to SaveChanges failure, + // then all subsequent SaveChanges would fail too (e.g. IImportProfileService.UpdateImportProfile, IScheduledTaskService.UpdateTask...). + // so whatever it is, detach\dispose all what the tracker still has tracked. + + _services.DbContext.DetachAll(false); + } + catch (Exception exception) + { + ctx.ExecuteContext.Result.AddError(exception); + } + + try + { + SendCompletionEmail(ctx); + } + catch (Exception exception) + { + ctx.ExecuteContext.Result.AddError(exception); + } + + try + { + ctx.ExecuteContext.Result.EndDateUtc = DateTime.UtcNow; + + LogResult(ctx); + } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } + + try + { + ctx.Request.Profile.ResultInfo = XmlHelper.Serialize(ctx.ExecuteContext.Result.Clone()); + + _importProfileService.UpdateImportProfile(ctx.Request.Profile); + } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } + + try + { + ctx.Request.CustomData.Clear(); + ctx.Log = null; + } + catch (Exception exception) + { + logger.ErrorsAll(exception); + } + } + } + } + + public void Import(DataImportRequest request, CancellationToken cancellationToken) + { + Guard.ArgumentNotNull(() => request); + Guard.ArgumentNotNull(() => cancellationToken); + + var ctx = new DataImporterContext(request, cancellationToken, T("Admin.DataExchange.Import.ProgressInfo")); + + ImportCoreOuter(ctx); + + cancellationToken.ThrowIfCancellationRequested(); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/IDataTable.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/IDataTable.cs new file mode 100644 index 0000000000..f35c328fb6 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/IDataTable.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; + +namespace SmartStore.Services.DataExchange.Import +{ + public interface IDataColumn + { + string Name { get; } + Type Type { get; } + } + + public interface IDataRow + { + object[] Values { get; } + object this[int index] { get; set; } + object this[string name] { get; set; } + + IDataTable Table { get; } + } + + public interface IDataTable + { + bool HasColumn(string name); + int GetColumnIndex(string name); + IList Columns { get; } + IList Rows { get; } + } + + public static class IDataRowExtensions + { + public static object GetValue(this IDataRow row, int index) + { + return row[index]; + } + + public static object GetValue(this IDataRow row, string name) + { + return row[name]; + } + + public static void SetValue(this IDataRow row, int index, object value) + { + row[index] = value; + } + + public static void SetValue(this IDataRow row, string name, object value) + { + row[name] = value; + } + + public static bool TryGetValue(this IDataRow row, string name, out object value) + { + value = null; + + var index = row.Table.GetColumnIndex(name); + if (index < 0) + return false; + + value = row[index]; + return true; + } + + public static bool TrySetValue(this IDataRow row, string name, object value) + { + var index = row.Table.GetColumnIndex(name); + if (index < 0) + return false; + + row[index] = value; + return true; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/LightweightDataTable.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/LightweightDataTable.cs new file mode 100644 index 0000000000..52be0a8dfa --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/DataTable/LightweightDataTable.cs @@ -0,0 +1,406 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data; +using System.Data.Common; +using System.Dynamic; +using System.IO; +using System.Linq; +using System.Web; +using SmartStore.Services.DataExchange.Csv; +using SmartStore.Services.DataExchange.Excel; + +namespace SmartStore.Services.DataExchange.Import +{ + public class LightweightDataTable : IDataTable + { + private readonly IList _columns; + private readonly IList _rows; + private readonly IDictionary _columnIndexes; + private readonly IDictionary _alternativeColumnIndexes; + + public LightweightDataTable(IList columns, IList data) + { + Guard.ArgumentNotNull(() => columns); + Guard.ArgumentNotNull(() => data); + + if (columns.Select(x => x.Name.ToLower()).Distinct().ToArray().Length != columns.Count) + { + throw Error.Argument("columns", "The columns collection cannot contain duplicate column names."); + } + + _columns = new ReadOnlyCollection(columns); + + TrimData(data); + + var rows = data.Select(x => new LightweightDataRow(this, x)).Cast().ToList(); + _rows = new ReadOnlyCollection(rows); + + _columnIndexes = new Dictionary(StringComparer.OrdinalIgnoreCase); + _alternativeColumnIndexes = new Dictionary(StringComparer.OrdinalIgnoreCase); + + for (var i = 0; i < columns.Count; i++) + { + var name = columns[i].Name; + var alternativeName = GetAlternativeColumnNameFor(name); + + _columnIndexes[name] = i; + + if (!alternativeName.IsCaseInsensitiveEqual(name)) + _alternativeColumnIndexes[alternativeName] = i; + } + } + + private static void TrimData(IList data) + { + // When a user deletes content instead of whole rows from an excel sheet, + // our data table contains completely empty rows at the end. + // Here we get rid of them as they are absolutely useless. + for (int i = data.Count - 1; i >= 0; i--) + { + var allColumnsEmpty = data[i].All(x => x == null || x == DBNull.Value); + if (allColumnsEmpty) + { + data.RemoveAt(i); + //i--; + } + else + { + // get out here on the first occurence of a NON-empty row + break; + } + } + } + + public bool HasColumn(string name) + { + if (name.HasValue()) + { + return (_columnIndexes.ContainsKey(name) || _alternativeColumnIndexes.ContainsKey(name)); + } + + return false; + } + + public int GetColumnIndex(string name) + { + int index; + + if (name.HasValue()) + { + if (_columnIndexes.TryGetValue(name, out index)) + return index; + + if (_alternativeColumnIndexes.TryGetValue(name, out index)) + return index; + } + + return -1; + } + + public IList Columns + { + get + { + return _columns; + } + } + + public IList Rows + { + get + { + return _rows; + } + } + + public static string GetAlternativeColumnNameFor(string name) + { + if (name.IsEmpty()) + return name; + + return name + .Replace(" ", "") + .Replace("-", "") + .Replace("_", ""); + } + + public static IDataTable FromPostedFile( + HttpPostedFileBase file, + int skip = 0, + int take = int.MaxValue) + { + Guard.ArgumentNotNull(() => file); + + return FromFile(file.FileName, file.InputStream, file.ContentLength, new CsvConfiguration(), skip, take); + } + + public static IDataTable FromPostedFile( + HttpPostedFileBase file, + CsvConfiguration configuration, + int skip = 0, + int take = int.MaxValue) + { + Guard.ArgumentNotNull(() => file); + + return FromFile(file.FileName, file.InputStream, file.ContentLength, configuration, skip, take); + } + + public static IDataTable FromFile( + string fileName, + Stream stream, + long contentLength, + CsvConfiguration configuration, + int skip = 0, + int take = int.MaxValue) + { + Guard.ArgumentNotEmpty(() => fileName); + Guard.ArgumentNotNull(() => stream); + Guard.ArgumentNotNull(() => configuration); + + if (contentLength == 0) + { + throw Error.Argument("fileName", "The posted file '{0}' does not contain any data.".FormatInvariant(fileName)); + } + + IDataReader dataReader = null; + + try + { + var fileExt = System.IO.Path.GetExtension(fileName).ToLowerInvariant(); + + switch (fileExt) + { + case ".xlsx": + dataReader = new ExcelDataReader(stream, true); // TODO: let the user specify if excel file has headers + break; + default: + dataReader = new CsvDataReader(new StreamReader(stream), configuration); + break; + } + + var table = LightweightDataTable.FromDataReader(dataReader, skip, take); + + if (table.Columns.Count == 0 || table.Rows.Count == 0) + { + throw Error.InvalidOperation("The posted file '{0}' does not contain any columns or data rows.".FormatInvariant(fileName)); + } + + return table; + } + catch (Exception ex) + { + throw ex; + } + finally + { + if (dataReader != null) + { + if (!dataReader.IsClosed) + { + dataReader.Dispose(); + } + dataReader = null; + } + } + } + + public static IDataTable FromDataReader( + IDataReader reader, + int skip = 0, + int take = int.MaxValue) + { + Guard.ArgumentNotNull(() => reader); + + if (reader.IsClosed) + throw new ArgumentException("This operation is invalid when the reader is closed.", "reader"); + + var columns = new List(reader.FieldCount); + var data = new List(); + + var schema = reader.GetSchemaTable(); + + var nameCol = schema.Columns[SchemaTableColumn.ColumnName]; + var typeCol = schema.Columns[SchemaTableColumn.DataType]; + + foreach (DataRow schemaRow in schema.Rows) + { + var column = new LightweightDataColumn((string)schemaRow[nameCol], (Type)schemaRow[typeCol]); + columns.Add(column); + } + + var fieldCount = reader.FieldCount; + + take = Math.Min(take, int.MaxValue - skip); + + int i = -1; + while (reader.Read()) + { + i++; + + if (skip > i) + continue; + + if (i >= skip + take) + break; + + var values = new object[fieldCount]; + reader.GetValues(values); + data.Add(values); + } + + var table = new LightweightDataTable(columns, data); + + return table; + } + } + + internal class LightweightDataRow : DynamicObject, IDataRow + { + private readonly IDataTable _table; + private readonly object[] _values; + + public LightweightDataRow(IDataTable table, object[] values) + { + Guard.ArgumentNotNull(() => values); + + if (table.Columns.Count != values.Length) + { + throw new ArgumentOutOfRangeException( + "values", + "The number of row values must match the number of columns. Expected: {0}, actual: {1}".FormatInvariant(table.Columns.Count, values.Length)); + } + + _table = table; + _values = values; + } + + public IDataTable Table + { + get { return _table; } + } + + public object[] Values + { + get { return _values; } + } + + public object this[string name] + { + get + { + var index = _table.GetColumnIndex(name); + if (index < 0) + throw new KeyNotFoundException(); + + return _values[index]; + } + set + { + var index = _table.GetColumnIndex(name); + if (index < 0) + throw new KeyNotFoundException(); + + _values[index] = value; + } + } + + public object this[int index] + { + get + { + ValidateColumnIndex(index); + return _values[index]; + } + set + { + ValidateColumnIndex(index); + _values[index] = value; + } + } + + private void ValidateColumnIndex(int index) + { + if (index < 0 || index >= _table.Columns.Count) + { + throw new ArgumentOutOfRangeException("index", index, + "Column index must be included within [0, {0}], but specified column index was: '{1}'.".FormatInvariant(_table.Columns.Count, index)); + } + } + + public override IEnumerable GetDynamicMemberNames() + { + return _table.Columns.Select(x => x.Name); + } + + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + result = null; + + if (this.TryGetValue(binder.Name, out result)) + { + return true; + } + + return false; + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + return this.TrySetValue(binder.Name, value); + } + + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) + { + result = null; + + try + { + result = _values[(int)indexes[0]]; + return true; + } + catch + { + return false; + } + } + + public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) + { + try + { + _values[(int)indexes[0]] = value; + return true; + } + catch + { + return false; + } + } + } + + internal class LightweightDataColumn : IDataColumn + { + public LightweightDataColumn(string name, Type type) + { + Guard.ArgumentNotEmpty(() => name); + Guard.ArgumentNotNull(() => type); + + this.Name = name; + this.Type = type; + } + + public string Name + { + get; + private set; + } + + public Type Type + { + get; + private set; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/EntityImporterBase.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/EntityImporterBase.cs new file mode 100644 index 0000000000..eff63d8431 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/EntityImporterBase.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Mime; +using System.Linq; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.IO; +using SmartStore.Utilities; +using System.Linq.Expressions; +using SmartStore.Core; +using Autofac; +using SmartStore.Services.Localization; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Seo; +using SmartStore.Services.Seo; +using SmartStore.Core.Data; +using SmartStore.Services.Stores; +using SmartStore.Core.Domain.Stores; + +namespace SmartStore.Services.DataExchange.Import +{ + public abstract class EntityImporterBase : IEntityImporter + { + private const string _imageDownloadFolder = @"Content\DownloadedImages"; + + public DateTime UtcNow + { + get; + private set; + } + + public Dictionary DownloadedItems + { + get; + private set; + } + + public string ImageDownloadFolder + { + get; + private set; + } + + public string ImageFolder + { + get; + private set; + } + + public FileDownloadManagerContext DownloaderContext + { + get; + private set; + } + + public void Execute(ImportExecuteContext context) + { + Import(context); + } + + protected abstract void Import(ImportExecuteContext context); + + protected void Initialize(ImportExecuteContext context) + { + UtcNow = DateTime.UtcNow; + DownloadedItems = new Dictionary(); + ImageDownloadFolder = Path.Combine(context.ImportFolder, _imageDownloadFolder); + + var settings = context.DataExchangeSettings; + + if (settings.ImageImportFolder.HasValue()) + ImageFolder = Path.Combine(context.ImportFolder, settings.ImageImportFolder); + else + ImageFolder = context.ImportFolder; + + if (!System.IO.Directory.Exists(ImageDownloadFolder)) + System.IO.Directory.CreateDirectory(ImageDownloadFolder); + + DownloaderContext = new FileDownloadManagerContext + { + Timeout = TimeSpan.FromMinutes(settings.ImageDownloadTimeout), + Logger = context.Log, + CancellationToken = context.CancellationToken + }; + + context.Result.TotalRecords = context.DataSegmenter.TotalRows; + } + + public FileDownloadManagerItem CreateDownloadImage(string urlOrPath, string seoName, int displayOrder) + { + var item = new FileDownloadManagerItem + { + Id = displayOrder, + DisplayOrder = displayOrder, + MimeType = MimeTypes.MapNameToMimeType(urlOrPath) + }; + + if (item.MimeType.IsEmpty()) + { + item.MimeType = MediaTypeNames.Image.Jpeg; + } + + var extension = MimeTypes.MapMimeTypeToExtension(item.MimeType); + + if (extension.HasValue()) + { + if (urlOrPath.IsWebUrl()) + { + item.Url = urlOrPath; + item.FileName = "{0}-{1}".FormatInvariant(seoName, item.Id).ToValidFileName(); + + if (DownloadedItems.ContainsKey(urlOrPath)) + { + item.Path = Path.Combine(ImageDownloadFolder, DownloadedItems[urlOrPath]); + item.Success = true; + } + else + { + item.Path = Path.Combine(ImageDownloadFolder, item.FileName + extension.EnsureStartsWith(".")); + } + } + else if (Path.IsPathRooted(urlOrPath)) + { + item.Path = urlOrPath; + item.Success = true; + } + else + { + item.Path = Path.Combine(ImageFolder, urlOrPath); + item.Success = true; + } + + return item; + } + + return null; + } + + public void Succeeded(FileDownloadManagerItem item) + { + if ((item.Success ?? false) && item.Url.HasValue() && !DownloadedItems.ContainsKey(item.Url)) + { + DownloadedItems.Add(item.Url, Path.GetFileName(item.Path)); + } + } + + protected virtual int ProcessLocalizations( + ImportExecuteContext context, + IEnumerable> batch, + IDictionary>> localizableProperties) where TEntity : BaseEntity, ILocalizedEntity + { + Guard.ArgumentNotNull(() => context); + Guard.ArgumentNotNull(() => batch); + Guard.ArgumentNotNull(() => localizableProperties); + + // Perf: determine whether our localizable properties actually have + // counterparts in the source BEFORE import batch begins. This way we spare ourself + // to query over and over for values. + var localizedProps = (from kvp in localizableProperties + where context.DataSegmenter.GetColumnIndexes(kvp.Key).Length > 0 + select kvp.Key).ToArray(); + + if (localizedProps.Length == 0) + { + return 0; + } + + var localizedEntityService = context.Services.Resolve(); + + bool shouldSave = false; + + foreach (var row in batch) + { + foreach (var prop in localizedProps) + { + var lambda = localizableProperties[prop]; + foreach (var lang in context.Languages) + { + var code = lang.UniqueSeoCode; + string value; + + if (row.TryGetDataValue(prop /* ColumnName */, code, out value)) + { + localizedEntityService.SaveLocalizedValue(row.Entity, lambda, value, lang.Id); + shouldSave = true; + } + } + } + } + + if (shouldSave) + { + // commit whole batch at once + return context.Services.DbContext.SaveChanges(); + } + + return 0; + } + + protected virtual int ProcessStoreMappings( + ImportExecuteContext context, + IEnumerable> batch) where TEntity : BaseEntity, IStoreMappingSupported + { + var storeMappingService = context.Services.Resolve(); + var storeMappingRepository = context.Services.Resolve>(); + + storeMappingRepository.AutoCommitEnabled = false; + + foreach (var row in batch) + { + var storeIds = row.GetDataValue>("StoreIds"); + if (!storeIds.IsNullOrEmpty()) + { + storeMappingService.SaveStoreMappings(row.Entity, storeIds.ToArray()); + } + } + + // commit whole batch at once + return context.Services.DbContext.SaveChanges(); + } + + protected virtual int ProcessSlugs( + ImportExecuteContext context, + IEnumerable> batch, + string entityName) where TEntity : BaseEntity, ISlugSupported + { + var slugMap = new Dictionary(); + UrlRecord urlRecord = null; + + var urlRecordService = context.Services.Resolve(); + var urlRecordRepository = context.Services.Resolve>(); + var seoSettings = context.Services.Resolve(); + + Func slugLookup = ((s) => + { + return (slugMap.ContainsKey(s) ? slugMap[s] : null); + }); + + foreach (var row in batch) + { + try + { + string seName = null; + string localizedName = null; + + if (row.TryGetDataValue("SeName", out seName) || row.IsNew || row.NameChanged) + { + seName = row.Entity.ValidateSeName(seName, row.EntityDisplayName, true, urlRecordService, seoSettings, extraSlugLookup: slugLookup); + + if (row.IsNew) + { + // dont't bother validating SeName for new entities. + urlRecord = new UrlRecord + { + EntityId = row.Entity.Id, + EntityName = entityName, + Slug = seName, + LanguageId = 0, + IsActive = true, + }; + urlRecordRepository.Insert(urlRecord); + } + else + { + urlRecord = urlRecordService.SaveSlug(row.Entity, seName, 0); + } + + if (urlRecord != null) + { + // a new record was inserted to the store: keep track of it for this batch. + slugMap[seName] = urlRecord; + } + } + + // process localized SeNames + foreach (var lang in context.Languages) + { + var hasSeName = row.TryGetDataValue("SeName", lang.UniqueSeoCode, out seName); + var hasLocalizedName = row.TryGetDataValue("Name", lang.UniqueSeoCode, out localizedName); + + if (hasSeName || hasLocalizedName) + { + seName = row.Entity.ValidateSeName(seName, localizedName, false, urlRecordService, seoSettings, lang.Id, slugLookup); + urlRecord = urlRecordService.SaveSlug(row.Entity, seName, lang.Id); + if (urlRecord != null) + { + slugMap[seName] = urlRecord; + } + } + } + } + catch (Exception exception) + { + context.Result.AddWarning(exception.Message, row.GetRowInfo(), "SeName"); + } + } + + // commit whole batch at once + return context.Services.DbContext.SaveChanges(); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IDataImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IDataImporter.cs new file mode 100644 index 0000000000..8c2fbebf73 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IDataImporter.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange.Import +{ + public interface IDataImporter + { + void Import(DataImportRequest request, CancellationToken cancellationToken); + } + + + public class DataImportRequest + { + private readonly static ProgressValueSetter _voidProgressValueSetter = DataImportRequest.SetProgress; + + public DataImportRequest(ImportProfile profile) + { + Guard.ArgumentNotNull(() => profile); + + Profile = profile; + ProgressValueSetter = _voidProgressValueSetter; + + EntitiesToImport = new List(); + CustomData = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + public ImportProfile Profile { get; private set; } + + public ProgressValueSetter ProgressValueSetter { get; set; } + + public bool HasPermission { get; set; } + + public IList EntitiesToImport { get; set; } + + public IDictionary CustomData { get; private set; } + + + private static void SetProgress(int val, int max, string msg) + { + // do nothing + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs new file mode 100644 index 0000000000..bc64b63531 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IEntityImporter.cs @@ -0,0 +1,7 @@ +namespace SmartStore.Services.DataExchange.Import +{ + public partial interface IEntityImporter + { + void Execute(ImportExecuteContext context); + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs new file mode 100644 index 0000000000..6f7b7d4f8e --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/IImportProfileService.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange.Import +{ + public interface IImportProfileService + { + /// + /// Gets a new profile name + /// + /// Entity type + /// Suggestion for a new profile name + string GetNewProfileName(ImportEntityType entityType); + + /// + /// Inserts an import profile + /// + /// Name of the import file + /// Profile name + /// Entity type + /// Inserted import profile + ImportProfile InsertImportProfile(string fileName, string name, ImportEntityType entityType); + + /// + /// Updates an import profile + /// + /// Import profile + void UpdateImportProfile(ImportProfile profile); + + /// + /// Deletes an import profile + /// + /// Import profile + void DeleteImportProfile(ImportProfile profile); + + /// + /// Get queryable import profiles + /// + /// Whether to filter enabled or disabled profiles + /// Import profiles + IQueryable GetImportProfiles(bool? enabled = null); + + /// + /// Gets an import profile by identifier + /// + /// Import profile identifier + /// Import profile + ImportProfile GetImportProfileById(int id); + + /// + /// Gets an import profile by name + /// + /// Name of the import profile + /// Import profile + ImportProfile GetImportProfileByName(string name); + + /// + /// Get all importable entity properties and their localized values + /// + /// Import entity type + /// Importable entity properties + Dictionary GetImportableEntityProperties(ImportEntityType entityType); + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs new file mode 100644 index 0000000000..41129e24f8 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportDataSegmenter.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.Linq; +using SmartStore.Core; + +namespace SmartStore.Services.DataExchange.Import +{ + public class ImportDataSegmenter + { + private const int BATCHSIZE = 100; + + private readonly IDataTable _table; + private object[] _currentBatch; + private readonly IPageable _pageable; + private bool _bof; + private CultureInfo _culture; + private ColumnMap _columnMap; + + private readonly IDictionary _columnIndexes = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public ImportDataSegmenter(IDataTable table, ColumnMap map) + { + Guard.ArgumentNotNull(() => table); + Guard.ArgumentNotNull(() => map); + + _table = table; + _columnMap = map; + + _bof = true; + _pageable = new PagedList(0, BATCHSIZE, table.Rows.Count); + _culture = CultureInfo.InvariantCulture; + } + + public CultureInfo Culture + { + get + { + return _culture; + } + set + { + _culture = value ?? CultureInfo.InvariantCulture; + } + } + + public ColumnMap ColumnMap + { + get + { + return _columnMap; + } + set + { + _columnMap = value ?? new ColumnMap(); + } + } + + public int TotalRows + { + get { return _table.Rows.Count; } + } + + public int TotalColumns + { + get { return _table.Columns.Count; } + } + + public int CurrentSegment + { + get { return _bof ? 0 : _pageable.PageNumber; } + } + + public int CurrentSegmentFirstRowIndex + { + get { return _pageable.FirstItemIndex; } + } + + public int TotalSegments + { + get { return _pageable.TotalPages; } + } + + public int BatchSize + { + get { return BATCHSIZE; } + } + + /// + /// Determines whether a specific column exists in the underlying data table. + /// + /// The name of the column to find + /// + /// If true and a column with the passed does not exist, + /// this method tests for the existence of any indexed column with the same name. + /// + /// true if the column exists, false otherwise + /// + /// This method takes mapped column names into account. + /// + public bool HasColumn(string name, bool withAnyIndex = false) + { + var result = HasColumn(name, null); + + if (!result && withAnyIndex) + { + // Column does not exist, but withAnyIndex is true: + // Test for existence of any indexed column. + result = GetColumnIndexes(name).Length > 0; + } + + return result; + } + + /// + /// Determines whether the column name[index] exists in the underlying data table. + /// + /// The name of the column to find + /// The index of the column + /// true if the column exists, false otherwise + /// + /// This method takes mapped column names into account. + /// + public bool HasColumn(string name, string index) + { + return _table.HasColumn(_columnMap.GetMapping(name, index).MappedName); + } + + /// + /// Indicates whether to ignore the property that is mapped to columnName + /// + /// The name of the column + /// true ignore, false do not ignore + public bool IsIgnored(string columnName) + { + return IsIgnored(columnName, null); + } + + /// + /// Indicates whether to ignore the property that is mapped to columnName + /// + /// The name of the column + /// The index of the column + /// true ignore, false do not ignore + public bool IsIgnored(string columnName, string index) + { + var mapping = _columnMap.GetMapping(columnName, index); + + return mapping.IgnoreProperty; + } + + /// + /// Returns an array of exisiting index names for a column + /// + /// The name of the columns without index qualification + /// An array of index names + /// + /// If following columns exist in source: Attr[Color], Attr[Size] + /// This method returns: string[] { "Color", "Size" } + /// + public string[] GetColumnIndexes(string name) + { + string[] indexes; + + if (!_columnIndexes.TryGetValue(name, out indexes)) + { + var startsWith = name + "["; + + var columns1 = _columnMap.Mappings + .Where(x => x.Key.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase)) + .Select(x => x.Key); + + var columns2 = _table.Columns + .Where(x => x.Name.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase)) + .Select(x => x.Name); + + indexes = columns1.Concat(columns2) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(x => x.Substring(x.IndexOf("[", StringComparison.OrdinalIgnoreCase) + 1).TrimEnd(']')) + .ToArray(); + + _columnIndexes[name] = indexes; + } + + return indexes; + } + + public void Reset() + { + if (_pageable.PageIndex != 0 && _currentBatch != null) + { + _currentBatch = null; + } + _bof = true; + _pageable.PageIndex = 0; + } + + public bool ReadNextBatch() + { + if (_currentBatch != null) + { + _currentBatch = null; + } + + if (_bof) + { + _bof = false; + return _pageable.TotalCount > 0; + } + + if (_pageable.HasNextPage) + { + _pageable.PageIndex++; + return true; + } + + Reset(); + return false; + } + + public IEnumerable> GetCurrentBatch() where T : BaseEntity + { + if (_currentBatch == null) + { + int start = _pageable.FirstItemIndex - 1; + int end = _pageable.LastItemIndex - 1; + + _currentBatch = new ImportRow[(end - start) + 1]; + + // Determine values per row + int i = 0; + for (int r = start; r <= end; r++) + { + _currentBatch[i] = new ImportRow(this, _table.Rows[r], r); + i++; + } + } + + return _currentBatch.Cast>(); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs new file mode 100644 index 0000000000..70170c0fd3 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExecuteContext.cs @@ -0,0 +1,227 @@ +using System.Collections.Generic; +using System.Threading; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.DataExchange.Import +{ + public class ImportExecuteContext + { + private DataExchangeAbortion _abortion; + private ProgressValueSetter _progressValueSetter; + private string _progressInfo; + + private IDataTable _dataTable; + private ImportDataSegmenter _segmenter; + + public ImportExecuteContext( + CancellationToken cancellation, + ProgressValueSetter progressValueSetter, + string progressInfo) + { + _progressValueSetter = progressValueSetter; + _progressInfo = progressInfo; + + CancellationToken = cancellation; + CustomProperties = new Dictionary(); + Result = new ImportResult(); + } + + /// + /// Import settings + /// + public DataExchangeSettings DataExchangeSettings + { + get; + internal set; + } + + /// + /// The data source (CSV, Excel etc.) + /// + public IDataTable DataTable + { + get + { + return _dataTable; + } + internal set + { + _dataTable = value; + _segmenter = null; + } + } + + /// + /// Mapping information between database and data source + /// + public ColumnMap ColumnMap + { + get; + internal set; + } + + /// + /// Whether to only update existing records + /// + public bool UpdateOnly + { + get; + internal set; + } + + /// + /// Name of key fields to identify existing records for updating + /// + public string[] KeyFieldNames + { + get; + internal set; + } + + /// + /// All active languages + /// + public IList Languages + { + get; + internal set; + } + + /// + /// To log information into the import log file + /// + public ILogger Log + { + get; + internal set; + } + + /// + /// Common Services + /// + public ICommonServices Services + { + get; + internal set; + } + + /// + /// Cancellation token + /// + public CancellationToken CancellationToken + { + get; + private set; + } + + /// + /// The import folder + /// + public string ImportFolder + { + get; + internal set; + } + + /// + /// Use this dictionary for any custom data required along the import + /// + public Dictionary CustomProperties + { + get; + set; + } + + /// + /// Result of the import + /// + public ImportResult Result + { + get; + set; + } + + /// + /// Extra import configuration data + /// + public ImportExtraData ExtraData + { + get; + internal set; + } + + /// + /// Indicates whether and how to abort the import + /// + public DataExchangeAbortion Abort + { + get + { + if (CancellationToken.IsCancellationRequested || IsMaxFailures) + return DataExchangeAbortion.Hard; + + return _abortion; + } + set + { + _abortion = value; + } + } + + public bool IsMaxFailures + { + get + { + return Result.Errors > 11; + } + } + + public ImportDataSegmenter DataSegmenter + { + get + { + if (_segmenter == null) + { + if (this.DataTable == null || this.ColumnMap == null) + { + throw new SmartException("A DataTable and a ColumnMap must be specified before accessing the DataSegmenter property."); + } + _segmenter = new ImportDataSegmenter(DataTable, ColumnMap); + } + + return _segmenter; + } + } + + /// + /// Allows to set a progress message + /// + /// Progress value + /// /// Progress maximum + public void SetProgress(int value, int maximum) + { + try + { + if (_progressValueSetter != null) + _progressValueSetter.Invoke(value, maximum, _progressInfo.FormatInvariant(value, maximum)); + } + catch { } + } + + /// + /// Allows to set a message + /// + /// Message to display + public void SetProgress(string message) + { + try + { + if (_progressValueSetter != null && message.HasValue()) + _progressValueSetter.Invoke(0, 0, message); + } + catch { } + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs new file mode 100644 index 0000000000..89f576e47a --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtensions.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SmartStore.Core.Domain; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Import +{ + public static class ImportExtensions + { + /// + /// Get folder for import files + /// + /// Import profile + /// Folder path + public static string GetImportFolder(this ImportProfile profile, bool content = false, bool create = false) + { + var path = CommonHelper.MapPath(string.Concat("~/App_Data/ImportProfiles/", profile.FolderName, content ? "/Content" : "")); + + if (create && !System.IO.Directory.Exists(path)) + System.IO.Directory.CreateDirectory(path); + + return path; + } + + /// + /// Gets import files for an import profile + /// + /// Import profile + /// List of file paths + public static List GetImportFiles(this ImportProfile profile) + { + var importFolder = profile.GetImportFolder(true); + + if (System.IO.Directory.Exists(importFolder)) + { + return System.IO.Directory.EnumerateFiles(importFolder, "*", SearchOption.TopDirectoryOnly) + .OrderBy(x => x) + .ToList(); + } + + return new List(); + } + + /// + /// Get log file path for an import profile + /// + /// Import profile + /// Log file path + public static string GetImportLogPath(this ImportProfile profile) + { + return Path.Combine(profile.GetImportFolder(), "log.txt"); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtraData.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtraData.cs new file mode 100644 index 0000000000..ecbe710677 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportExtraData.cs @@ -0,0 +1,13 @@ +using System; + +namespace SmartStore.Services.DataExchange.Import +{ + [Serializable] + public class ImportExtraData + { + /// + /// Number of images per object to be imported + /// + public int? NumberOfPictures { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportMessage.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportMessage.cs new file mode 100644 index 0000000000..1061e690e7 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportMessage.cs @@ -0,0 +1,90 @@ +using System; + +namespace SmartStore.Services.DataExchange.Import +{ + + public class ImportMessage + { + public ImportMessage(string message, ImportMessageType messageType = ImportMessageType.Info) + { + Guard.ArgumentNotEmpty(() => message); + + this.Message = message; + this.MessageType = messageType; + } + + public ImportRowInfo AffectedItem + { + get; + set; + } + + public string AffectedField + { + get; + set; + } + + public ImportMessageType MessageType + { + get; + set; + } + + public string Message + { + get; + set; + } + + public string FullMessage + { + get; + set; + } + + public override string ToString() + { + var result = Message.NaIfEmpty(); + + string appendix = null; + + if (AffectedItem != null) + appendix = appendix.Grow("Pos: " + (AffectedItem.Position + 1).ToString(), ", "); + + if (AffectedField.HasValue()) + appendix = appendix.Grow("Field: " + AffectedField, ", "); + + if (appendix.HasValue()) + result = "{0} [{1}]".FormatInvariant(result, appendix); + + return result; + } + } + + public class ImportRowInfo : Tuple + { + public ImportRowInfo(int position, string entityName) + : base(position, entityName) + { + } + + public int Position + { + get { return base.Item1; } + } + + public string EntityName + { + get { return base.Item2; } + } + } + + public enum ImportMessageType + { + Info = 0, + Warning = 5, + Error = 10 + } + +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs new file mode 100644 index 0000000000..c1e54633dc --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportProfileService.cs @@ -0,0 +1,411 @@ +using System; +using System.Collections.Generic; +using System.Data.Entity.Core.Metadata.Edm; +using System.Data.Entity.Infrastructure; +using System.Diagnostics; +using System.IO; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Events; +using SmartStore.Core.Localization; +using SmartStore.Services.Catalog.Importer; +using SmartStore.Services.Customers.Importer; +using SmartStore.Services.Localization; +using SmartStore.Services.Messages.Importer; +using SmartStore.Services.Tasks; +using SmartStore.Utilities; + +namespace SmartStore.Services.DataExchange.Import +{ + public partial class ImportProfileService : IImportProfileService + { + private static object _lock = new object(); + private static Dictionary> _entityProperties = null; + + private readonly IRepository _importProfileRepository; + private readonly IEventPublisher _eventPublisher; + private readonly IScheduleTaskService _scheduleTaskService; + private readonly ILocalizationService _localizationService; + private readonly ILanguageService _languageService; + private readonly DataExchangeSettings _dataExchangeSettings; + + public ImportProfileService( + IRepository importProfileRepository, + IEventPublisher eventPublisher, + IScheduleTaskService scheduleTaskService, + ILocalizationService localizationService, + ILanguageService languageService, + DataExchangeSettings dataExchangeSettings) + { + _importProfileRepository = importProfileRepository; + _eventPublisher = eventPublisher; + _scheduleTaskService = scheduleTaskService; + _localizationService = localizationService; + _languageService = languageService; + _dataExchangeSettings = dataExchangeSettings; + } + + private string GetLocalizedPropertyName(ImportEntityType type, string property) + { + if (property.IsEmpty()) + return ""; + + string key = null; + string prefixKey = null; + + if (property.StartsWith("BillingAddress.")) + prefixKey = "Admin.Orders.Fields.BillingAddress"; + else if (property.StartsWith("ShippingAddress.")) + prefixKey = "Admin.Orders.Fields.ShippingAddress"; + + #region Get resource key + + switch (property) + { + case "Id": + key = "Admin.Common.Entity.Fields.Id"; + break; + case "LimitedToStores": + key = "Admin.Common.Store.LimitedTo"; + break; + case "DisplayOrder": + key = "Common.DisplayOrder"; + break; + case "Deleted": + key = "Admin.Common.Deleted"; + break; + case "CreatedOnUtc": + case "BillingAddress.CreatedOnUtc": + case "ShippingAddress.CreatedOnUtc": + key = "Common.CreatedOn"; + break; + case "UpdatedOnUtc": + key = "Common.UpdatedOn"; + break; + case "HasDiscountsApplied": + key = "Admin.Catalog.Products.Fields.HasDiscountsApplied"; + break; + case "DefaultViewMode": + key = "Admin.Configuration.Settings.Catalog.DefaultViewMode"; + break; + case "StoreId": + key = "Admin.Common.Store"; + break; + case "ParentGroupedProductId": + key = "Admin.Catalog.Products.Fields.AssociatedToProductName"; + break; + case "PasswordFormatId": + key = "Admin.Configuration.Settings.CustomerUser.DefaultPasswordFormat"; + break; + case "LastIpAddress": + key = "Admin.Customers.Customers.Fields.IPAddress"; + break; + default: + switch (type) + { + case ImportEntityType.Product: + key = "Admin.Catalog.Products.Fields." + property; + break; + case ImportEntityType.Category: + key = "Admin.Catalog.Categories.Fields." + property; + break; + case ImportEntityType.Customer: + if (property.StartsWith("BillingAddress.") || property.StartsWith("ShippingAddress.")) + key = "Admin.Address.Fields." + property.Substring(property.IndexOf('.') + 1); + else + key = "Admin.Customers.Customers.Fields." + property; + break; + case ImportEntityType.NewsLetterSubscription: + key = "Admin.Promotions.NewsLetterSubscriptions.Fields." + property; + break; + } + break; + } + + #endregion + + if (key.IsEmpty()) + return ""; + + var result = _localizationService.GetResource(key, 0, false, "", true); + + if (result.IsEmpty()) + { + if (key.EndsWith("Id")) + result = _localizationService.GetResource(key.Substring(0, key.Length - 2), 0, false, "", true); + else if (key.EndsWith("Utc")) + result = _localizationService.GetResource(key.Substring(0, key.Length - 3), 0, false, "", true); + } + + if (result.IsEmpty()) + { + Debug.WriteLine("Missing string resource mapping for {0} - {1}".FormatInvariant(type.ToString(), property)); + result = property.SplitPascalCase(); + } + + if (prefixKey.HasValue()) + { + result = string.Concat(_localizationService.GetResource(prefixKey, 0, false, "", true), " - ", result); + } + + return result; + } + + public string GetNewProfileName(ImportEntityType entityType) + { + var defaultNames = _localizationService.GetResource("Admin.DataExchange.Import.DefaultProfileNames").SplitSafe(";"); + + var result = defaultNames.SafeGet((int)entityType); + + if (result.IsEmpty()) + result = entityType.ToString(); + + var profileCount = _importProfileRepository.Table.Count(x => x.EntityTypeId == (int)entityType); + + result = string.Concat(result, " ", profileCount + 1); + + return result; + } + + public virtual ImportProfile InsertImportProfile(string fileName, string name, ImportEntityType entityType) + { + Guard.ArgumentNotEmpty(() => fileName); + + if (name.IsEmpty()) + name = GetNewProfileName(entityType); + + var task = new ScheduleTask + { + CronExpression = "0 */24 * * *", + Type = typeof(DataImportTask).AssemblyQualifiedNameWithoutVersion(), + Enabled = false, + StopOnError = false, + IsHidden = true + }; + + task.Name = string.Concat(name, " Task"); + + _scheduleTaskService.InsertTask(task); + + var profile = new ImportProfile + { + Name = name, + EntityType = entityType, + Enabled = true, + SchedulingTaskId = task.Id + }; + + if (Path.GetExtension(fileName).IsCaseInsensitiveEqual(".xlsx")) + profile.FileType = ImportFileType.XLSX; + else + profile.FileType = ImportFileType.CSV; + + string[] keyFieldNames = null; + + switch (entityType) + { + case ImportEntityType.Product: + keyFieldNames = ProductImporter.DefaultKeyFields; + break; + case ImportEntityType.Category: + keyFieldNames = CategoryImporter.DefaultKeyFields; + break; + case ImportEntityType.Customer: + keyFieldNames = CustomerImporter.DefaultKeyFields; + break; + case ImportEntityType.NewsLetterSubscription: + keyFieldNames = NewsLetterSubscriptionImporter.DefaultKeyFields; + break; + } + + profile.KeyFieldNames = string.Join(",", keyFieldNames); + + profile.FolderName = SeoHelper.GetSeName(name, true, false) + .ToValidPath() + .Truncate(_dataExchangeSettings.MaxFileNameLength); + + profile.FolderName = FileSystemHelper.CreateNonExistingDirectoryName(CommonHelper.MapPath("~/App_Data/ImportProfiles"), profile.FolderName); + + _importProfileRepository.Insert(profile); + + task.Alias = profile.Id.ToString(); + _scheduleTaskService.UpdateTask(task); + + _eventPublisher.EntityInserted(profile); + + return profile; + } + + public virtual void UpdateImportProfile(ImportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + _importProfileRepository.Update(profile); + + _eventPublisher.EntityUpdated(profile); + } + + public virtual void DeleteImportProfile(ImportProfile profile) + { + if (profile == null) + throw new ArgumentNullException("profile"); + + var scheduleTaskId = profile.SchedulingTaskId; + var folder = profile.GetImportFolder(); + + _importProfileRepository.Delete(profile); + + var scheduleTask = _scheduleTaskService.GetTaskById(scheduleTaskId); + _scheduleTaskService.DeleteTask(scheduleTask); + + _eventPublisher.EntityDeleted(profile); + + if (System.IO.Directory.Exists(folder)) + { + FileSystemHelper.ClearDirectory(folder, true); + } + } + + public virtual IQueryable GetImportProfiles(bool? enabled = null) + { + var query = _importProfileRepository.Table + .Expand(x => x.ScheduleTask); + + if (enabled.HasValue) + { + query = query.Where(x => x.Enabled == enabled.Value); + } + + query = query + .OrderBy(x => x.EntityTypeId) + .ThenBy(x => x.Name); + + return query; + } + + public virtual ImportProfile GetImportProfileById(int id) + { + if (id == 0) + return null; + + var profile = _importProfileRepository.Table + .Expand(x => x.ScheduleTask) + .FirstOrDefault(x => x.Id == id); + + return profile; + } + + public virtual ImportProfile GetImportProfileByName(string name) + { + if (name.IsEmpty()) + return null; + + var profile = _importProfileRepository.Table + .Expand(x => x.ScheduleTask) + .FirstOrDefault(x => x.Name == name); + + return profile; + } + + public virtual Dictionary GetImportableEntityProperties(ImportEntityType entityType) + { + if (_entityProperties == null) + { + lock (_lock) + { + if (_entityProperties == null) + { + _entityProperties = new Dictionary>(); + + var context = ((IObjectContextAdapter)_importProfileRepository.Context).ObjectContext; + var container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace); + + var allLanguages = _languageService.GetAllLanguages(true); + var allLanguageNames = allLanguages.ToDictionarySafe(x => x.UniqueSeoCode, x => LocalizationHelper.GetLanguageNativeName(x.LanguageCulture) ?? x.Name); + + var localizableProperties = new Dictionary + { + { ImportEntityType.Product, new string[] { "Name", "ShortDescription", "FullDescription", "MetaKeywords", "MetaDescription", "MetaTitle", "SeName" } }, + { ImportEntityType.Category, new string[] { "Name", "FullName", "Description", "BottomDescription", "MetaKeywords", "MetaDescription", "MetaTitle", "SeName" } }, + { ImportEntityType.Customer, new string[] { } }, + { ImportEntityType.NewsLetterSubscription, new string[] { } } + }; + + var addressSet = container.GetEntitySetByName("Addresses", true); + + var addressProperties = addressSet.ElementType.Members + .Where(x => !x.Name.IsCaseInsensitiveEqual("Id") && x.BuiltInTypeKind.HasFlag(BuiltInTypeKind.EdmProperty)) + .Select(x => x.Name) + .ToList(); + + + foreach (ImportEntityType type in Enum.GetValues(typeof(ImportEntityType))) + { + EntitySet entitySet = null; + + try + { + if (type == ImportEntityType.Category) + entitySet = container.GetEntitySetByName("Categories", true); + else + entitySet = container.GetEntitySetByName(type.ToString() + "s", true); + } + catch (Exception) + { + throw new SmartException("There is no entity set for ImportEntityType {0}. Note, the enum value must equal the entity name.".FormatInvariant(type.ToString())); + } + + var dic = entitySet.ElementType.Members + .Where(x => !x.Name.IsCaseInsensitiveEqual("Id") && x.BuiltInTypeKind.HasFlag(BuiltInTypeKind.EdmProperty)) + .Select(x => x.Name) + .ToDictionary(x => x, x => "", StringComparer.OrdinalIgnoreCase); + + // lack of abstractness? + if ((type == ImportEntityType.Product || type == ImportEntityType.Category) && !dic.ContainsKey("SeName")) + { + dic.Add("SeName", ""); + } + + // shipping and billing address + if (type == ImportEntityType.Customer) + { + foreach (var property in addressProperties) + { + dic.Add("BillingAddress." + property, ""); + dic.Add("ShippingAddress." + property, ""); + } + } + + // add localized property names + foreach (var key in dic.Keys.ToList()) + { + var localizedValue = GetLocalizedPropertyName(type, key); + + dic[key] = localizedValue.NaIfEmpty(); + + if (localizableProperties[type].Contains(key)) + { + foreach (var language in allLanguages) + { + dic.Add( + "{0}[{1}]".FormatInvariant(key, language.UniqueSeoCode.EmptyNull().ToLower()), + "{0} {1}".FormatInvariant(localizedValue.NaIfEmpty(), allLanguageNames[language.UniqueSeoCode]) + ); + } + } + } + + _entityProperties.Add(type, dic); + } + } + } + } + + return (_entityProperties.ContainsKey(entityType) ? _entityProperties[entityType] : null); + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs new file mode 100644 index 0000000000..a8a29366f7 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportResult.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; + +namespace SmartStore.Services.DataExchange.Import +{ + public class ImportResult : ICloneable + { + public ImportResult() + { + this.Messages = new List(); + Clear(); + } + + public DateTime StartDateUtc + { + get; + set; + } + + public DateTime EndDateUtc + { + get; + set; + } + + public int TotalRecords + { + get; + set; + } + + public int SkippedRecords + { + get; + set; + } + + public int NewRecords + { + get; + set; + } + + public int ModifiedRecords + { + get; + set; + } + + public int AffectedRecords + { + get { return NewRecords + ModifiedRecords; } + } + + public bool Cancelled + { + get; + set; + } + + public void Clear() + { + Messages.Clear(); + StartDateUtc = EndDateUtc = DateTime.UtcNow; + TotalRecords = 0; + SkippedRecords = 0; + NewRecords = 0; + ModifiedRecords = 0; + Cancelled = false; + } + + public ImportMessage AddInfo(string message, ImportRowInfo affectedRow = null, string affectedField = null) + { + return this.AddMessage(message, ImportMessageType.Info, affectedRow, affectedField); + } + + public ImportMessage AddWarning(string message, ImportRowInfo affectedRow = null, string affectedField = null) + { + return this.AddMessage(message, ImportMessageType.Warning, affectedRow, affectedField); + } + + public ImportMessage AddError(string message, ImportRowInfo affectedRow = null, string affectedField = null) + { + return this.AddMessage(message, ImportMessageType.Error, affectedRow, affectedField); + } + + public ImportMessage AddError(Exception exception, int? affectedBatch = null, string stage = null) + { + var prefix = new List(); + if (affectedBatch.HasValue) + { + prefix.Add("Batch: " + affectedBatch.Value); + } + if (stage.HasValue()) + { + prefix.Add("Stage: " + stage); + } + + string msg = string.Empty; + if (prefix.Any()) + { + msg = "[{0}] ".FormatCurrent(String.Join(", ", prefix)); + } + + msg += exception.ToAllMessages(); + + return this.AddMessage(msg, ImportMessageType.Error, fullMessage: exception.StackTrace); + } + + public ImportMessage AddError(Exception exception, string message) + { + return AddMessage( + message ?? exception.ToAllMessages(), + ImportMessageType.Error, + null, + null, + exception.StackTrace); + } + + public ImportMessage AddMessage(string message, ImportMessageType severity, ImportRowInfo affectedRow = null, string affectedField = null, string fullMessage = null) + { + var msg = new ImportMessage(message, severity); + + msg.AffectedItem = affectedRow; + msg.AffectedField = affectedField; + msg.FullMessage = fullMessage; + + this.Messages.Add(msg); + return msg; + } + + public IList Messages + { + get; + private set; + } + + public bool HasWarnings + { + get { return this.Messages.Any(x => x.MessageType == ImportMessageType.Warning); } + } + + public int Warnings + { + get { return Messages.Count(x => x.MessageType == ImportMessageType.Warning); } + } + + public bool HasErrors + { + get { return this.Messages.Any(x => x.MessageType == ImportMessageType.Error); } + } + + public int Errors + { + get { return Messages.Count(x => x.MessageType == ImportMessageType.Error); } + } + + public string LastError + { + get + { + var lastError = Messages.LastOrDefault(x => x.MessageType == ImportMessageType.Error); + if (lastError != null) + return lastError.Message; + + return null; + } + } + + object ICloneable.Clone() + { + return this.Clone(); + } + + public SerializableImportResult Clone() + { + var result = new SerializableImportResult(); + result.StartDateUtc = StartDateUtc; + result.EndDateUtc = EndDateUtc; + result.TotalRecords = TotalRecords; + result.SkippedRecords = SkippedRecords; + result.NewRecords = NewRecords; + result.ModifiedRecords = ModifiedRecords; + result.AffectedRecords = AffectedRecords; + result.Cancelled = Cancelled; + result.Warnings = Warnings; + result.Errors = Errors; + result.LastError = LastError; + + return result; + } + } + + + [Serializable] + public partial class SerializableImportResult + { + public DateTime StartDateUtc { get; set; } + public DateTime EndDateUtc { get; set; } + public int TotalRecords { get; set; } + public int SkippedRecords { get; set; } + public int NewRecords { get; set; } + public int ModifiedRecords { get; set; } + public int AffectedRecords { get; set; } + public bool Cancelled { get; set; } + public int Warnings { get; set; } + public int Errors { get; set; } + public string LastError { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs new file mode 100644 index 0000000000..1f213ee9e4 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/ImportRow.cs @@ -0,0 +1,331 @@ +using System; +using System.Globalization; +using System.Linq.Expressions; +using SmartStore.ComponentModel; +using SmartStore.Core; + +namespace SmartStore.Services.DataExchange.Import +{ + public class ImportRow where T : BaseEntity + { + private const string ExplicitNull = "[NULL]"; + + private bool _initialized = false; + private T _entity; + private string _entityDisplayName; + private readonly int _position; + private bool _isNew; + private bool _isDirty; + private ImportRowInfo _rowInfo; + + private readonly ImportDataSegmenter _segmenter; + private readonly IDataRow _row; + + public ImportRow(ImportDataSegmenter parent, IDataRow row, int position) + { + _segmenter = parent; + _row = row; + _position = position; + } + + public void Initialize(T entity, string entityDisplayName) + { + _entity = entity; + _entityDisplayName = entityDisplayName; + _isNew = _entity.Id == 0; + + _initialized = true; + } + + private void CheckInitialized() + { + if (_initialized) + { + throw Error.InvalidOperation("A row must be initialized before interacting with the entity or the data store"); + } + } + + private TProp GetDefaultValue(ColumnMappingItem mapping, TProp defaultValue, ImportResult result = null) + { + if (mapping != null && mapping.Default.HasValue()) + { + try + { + return mapping.Default.Convert(_segmenter.Culture); + } + catch (Exception exception) + { + if (result != null) + { + var msg = "Failed to convert default value '{0}'. Please specify a convertable default value. Column: {1}"; + result.AddWarning(msg.FormatInvariant(mapping.Default, exception.Message), this.GetRowInfo(), mapping.SoureName); + } + } + } + + return defaultValue; + } + + public bool IsTransient + { + get { return _entity.Id == 0; } + } + + public bool IsNew + { + get { return _isNew; } + } + + public bool IsDirty + { + get { return _isDirty; } + } + + public ImportDataSegmenter Segmenter + { + get { return _segmenter; } + } + + public T Entity + { + get { return _entity; } + } + + public IDataRow DataRow + { + get { return _row; } + } + + public string EntityDisplayName + { + get { return _entityDisplayName; } + } + + public bool NameChanged + { + get; + set; + } + + public int Position + { + get { return _position; } + } + + /// + /// Determines whether a specific column exists in the underlying data table + /// and contains a non-null, convertible value. + /// + /// The name of the column + /// + /// If true and a column with the passed does not exist, + /// this method seeks for any indexed column with the same name. + /// + /// true if the column exists and contains a value, false otherwise + /// + /// This method takes mapped column names into account. + /// + public bool HasDataValue(string columnName, bool withAnyIndex = false) + { + var result = HasDataValue(columnName, null); + + if (!result && withAnyIndex) + { + // Column does not have a value, but withAnyIndex is true: + // Test for values in any indexed column. + var indexes = _segmenter.GetColumnIndexes(columnName); + foreach (var idx in indexes) + { + result = HasDataValue(columnName, idx); + if (result) + break; + } + } + + return result; + } + + /// + /// Determines whether the column name[index] exists in the underlying data table + /// and contains a non-null, convertible value. + /// + /// The name of the column + /// The index of the column + /// true if the column exists and contains a value, false otherwise + /// + /// This method takes mapped column names into account. + /// + public bool HasDataValue(string columnName, string index) + { + var mapping = _segmenter.ColumnMap.GetMapping(columnName, index); + + object value; + return (_row.TryGetValue(mapping.MappedName, out value) && value != null && value != DBNull.Value); + } + + public TProp GetDataValue(string columnName, bool force = false) + { + TProp value; + TryGetDataValue(columnName, null, out value, force); + return value; + } + + public TProp GetDataValue(string columnName, string index, bool force = false) + { + TProp value; + TryGetDataValue(columnName, index, out value, force); + return value; + } + + public bool TryGetDataValue(string columnName, out TProp value, bool force = false) + { + return TryGetDataValue(columnName, null, out value, force); + } + + public bool TryGetDataValue(string columnName, string index, out TProp value, bool force = false) + { + var mapping = _segmenter.ColumnMap.GetMapping(columnName, index); + + if (!force && mapping.IgnoreProperty) + { + value = default(TProp); + return false; + } + + object rawValue; + if (_row.TryGetValue(mapping.MappedName, out rawValue) && rawValue != null && rawValue != DBNull.Value) + { + value = rawValue.ToString().IsCaseInsensitiveEqual(ExplicitNull) + ? default(TProp) + : rawValue.Convert(_segmenter.Culture); + return true; + } + + if (IsNew) + { + // only transient/new entities should fallback to possible defaults. + value = GetDefaultValue(mapping, default(TProp)); + return true; + } + + value = default(TProp); + return false; + } + + public bool SetProperty( + ImportResult result, + Expression> prop, + TProp defaultValue = default(TProp), + Func converter = null) + { + return SetProperty( + result, + null, // columnName + prop, + defaultValue, + converter); + } + + public bool SetProperty( + ImportResult result, + string columnName, + Expression> prop, + TProp defaultValue = default(TProp), + Func converter = null) + { + // TBD: (MC) do not check or validate for perf reason? + //CheckInitialized(); + + var isPropertySet = false; + var pi = prop.ExtractPropertyInfo(); + var propName = pi.Name; + var target = _entity; + + columnName = columnName ?? propName; + + try + { + object value; + var mapping = _segmenter.ColumnMap.GetMapping(columnName); + + if (mapping.IgnoreProperty) + { + // explicitly ignore this property + } + else if (_row.TryGetValue(mapping.MappedName, out value) && (value != null && value != DBNull.Value)) + { + // source contains field value. Set it. + TProp converted; + if (converter != null) + { + converted = converter(value, _segmenter.Culture); + } + else if (value.ToString().IsCaseInsensitiveEqual(ExplicitNull)) + { + // prop is "explicitly" set to null. Don't fallback to any default! + converted = default(TProp); + } + else + { + converted = value.Convert(_segmenter.Culture); + } + + var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached); + fastProp.SetValue(target, converted); + isPropertySet = true; + } + else + { + // source field value does not exist or is null/empty + if (IsNew) + { + // if entity is new and source field value is null, determine default value in this particular order: + // 2.) Default value in field mapping table + // 3.) passed default value argument + defaultValue = GetDefaultValue(mapping, defaultValue, result); + + // source does not contain field data or is empty... + if (defaultValue != null) + { + // ...but the entity is new. In this case set the default value if given. + var fastProp = FastProperty.GetProperty(target.GetUnproxiedType(), propName, PropertyCachingStrategy.EagerCached); + fastProp.SetValue(target, defaultValue); + isPropertySet = true; + } + } + } + } + catch (Exception exception) + { + result.AddWarning("Conversion failed: " + exception.Message, this.GetRowInfo(), propName); + } + + if (isPropertySet && !_isDirty) + { + _isDirty = true; + } + + return isPropertySet; + } + + public ImportRowInfo GetRowInfo() + { + if (_rowInfo == null) + { + _rowInfo = new ImportRowInfo(this.Position, this.EntityDisplayName); + } + + return _rowInfo; + } + + public override string ToString() + { + var str = "Pos: {0} - Name: {1}, IsNew: {2}, IsTransient: {3}".FormatCurrent( + Position, + EntityDisplayName.EmptyNull(), + _initialized ? IsNew.ToString() : "-", + _initialized ? IsTransient.ToString() : "-"); + return str; + } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/Import/Internal/DataImporterContext.cs b/src/Libraries/SmartStore.Services/DataExchange/Import/Internal/DataImporterContext.cs new file mode 100644 index 0000000000..41efff1883 --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/Import/Internal/DataImporterContext.cs @@ -0,0 +1,28 @@ +using System.Threading; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.DataExchange.Import.Internal +{ + internal class DataImporterContext + { + public DataImporterContext( + DataImportRequest request, + CancellationToken cancellationToken, + string progressInfo) + { + Request = request; + CancellationToken = cancellationToken; + + ExecuteContext = new ImportExecuteContext(CancellationToken, Request.ProgressValueSetter, progressInfo); + } + + public DataImportRequest Request { get; private set; } + public CancellationToken CancellationToken { get; private set; } + + public TraceLogger Log { get; set; } + + public ImportExecuteContext ExecuteContext { get; set; } + + public IEntityImporter Importer { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/DataExchange/SyncMappingService.cs b/src/Libraries/SmartStore.Services/DataExchange/SyncMappingService.cs new file mode 100644 index 0000000000..3c3a11551c --- /dev/null +++ b/src/Libraries/SmartStore.Services/DataExchange/SyncMappingService.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.DataExchange; + +namespace SmartStore.Services.DataExchange +{ + + public partial class SyncMappingService : ISyncMappingService + { + private readonly IRepository _syncMappingsRepository; + + public SyncMappingService(IRepository syncMappingsRepository) + { + this._syncMappingsRepository = syncMappingsRepository; + } + + public void InsertSyncMapping(SyncMapping mapping) + { + Guard.ArgumentNotNull(() => mapping); + + _syncMappingsRepository.Insert(mapping); + } + + public void InsertSyncMappings(IEnumerable mappings) + { + Guard.ArgumentNotNull(() => mappings); + + _syncMappingsRepository.InsertRange(mappings); + } + + public IList GetAllSyncMappings(string contextName = null, string entityName = null) + { + var query = _syncMappingsRepository.Table; + + if (entityName.HasValue()) + { + query = query.Where(x => x.EntityName == entityName); + } + + if (contextName.HasValue()) + { + query = query.Where(x => x.ContextName == contextName); + } + + return query.ToList(); + } + + public SyncMapping GetSyncMappingByEntity(int entityId, string entityName, string contextName) + { + Guard.ArgumentIsPositive(entityId, "entityId"); + Guard.ArgumentNotEmpty(() => entityName); + Guard.ArgumentNotEmpty(() => contextName); + + var query = from x in _syncMappingsRepository.Table + where + x.EntityId == entityId + && x.EntityName == entityName + && x.ContextName == contextName + select x; + + return query.FirstOrDefault(); + } + + public SyncMapping GetSyncMappingBySource(string sourceKey, string entityName, string contextName) + { + Guard.ArgumentNotEmpty(() => sourceKey); + Guard.ArgumentNotEmpty(() => entityName); + Guard.ArgumentNotEmpty(() => contextName); + + var query = from x in _syncMappingsRepository.Table + where + x.SourceKey == sourceKey + && x.EntityName == entityName + && x.ContextName == contextName + select x; + + return query.FirstOrDefault(); + } + + public void DeleteSyncMapping(SyncMapping mapping) + { + Guard.ArgumentNotNull(() => mapping); + + _syncMappingsRepository.Delete(mapping); + } + + public void DeleteSyncMappings(IEnumerable mappings) + { + Guard.ArgumentNotNull(() => mappings); + + _syncMappingsRepository.DeleteRange(mappings); + } + + public void DeleteSyncMappingsFor(T entity) where T : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + + if (entity is SyncMapping) + { + throw Error.InvalidOperation("Cannot delete a sync mapping record for a SyncMapping entity"); + } + + if (entity.IsTransientRecord()) + { + return; + } + + _syncMappingsRepository.DeleteAll(x => x.EntityId == entity.Id && x.EntityName == typeof(T).Name); + } + + public void DeleteSyncMappings(string contextName, string entityName = null) + { + Guard.ArgumentNotEmpty(() => contextName); + + if (entityName.HasValue()) + { + _syncMappingsRepository.DeleteAll(x => x.ContextName == contextName && x.EntityName == entityName); + } + else + { + _syncMappingsRepository.DeleteAll(x => x.ContextName == contextName); + } + } + + + public void UpdateSyncMapping(SyncMapping mapping) + { + Guard.ArgumentNotNull(() => mapping); + + mapping.SyncedOnUtc = DateTime.UtcNow; + _syncMappingsRepository.Update(mapping); + } + + } + +} diff --git a/src/Libraries/SmartStore.Services/Directory/CountryService.cs b/src/Libraries/SmartStore.Services/Directory/CountryService.cs index aeda79b995..40b2e16a8b 100644 --- a/src/Libraries/SmartStore.Services/Directory/CountryService.cs +++ b/src/Libraries/SmartStore.Services/Directory/CountryService.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; namespace SmartStore.Services.Directory @@ -25,26 +27,28 @@ public partial class CountryService : ICountryService private readonly IRepository _countryRepository; private readonly IEventPublisher _eventPublisher; private readonly ICacheManager _cacheManager; + private readonly IStoreContext _storeContext; + private readonly IRepository _storeMappingRepository; #endregion #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// Country repository - /// Event published public CountryService(ICacheManager cacheManager, IRepository countryRepository, - IEventPublisher eventPublisher) + IEventPublisher eventPublisher, + IStoreContext storeContext, + IRepository storeMappingRepository) { _cacheManager = cacheManager; _countryRepository = countryRepository; _eventPublisher = eventPublisher; + _storeContext = storeContext; + _storeMappingRepository = storeMappingRepository; } + public DbQuerySettings QuerySettings { get; set; } + #endregion #region Methods @@ -76,10 +80,31 @@ public virtual IList GetAllCountries(bool showHidden = false) string key = string.Format(COUNTRIES_ALL_KEY, showHidden); return _cacheManager.Get(key, () => { - var query = from c in _countryRepository.Table - orderby c.DisplayOrder, c.Name - where showHidden || c.Published - select c; + var query = _countryRepository.Table; + + if (!showHidden) + query = query.Where(c => c.Published); + + query = query.OrderBy(c => c.DisplayOrder).ThenBy(c => c.Name); + + if (!showHidden && !QuerySettings.IgnoreMultiStore) + { + var currentStoreId = _storeContext.CurrentStore.Id; + query = from c in query + join sc in _storeMappingRepository.Table + on new { c1 = c.Id, c2 = "Country" } equals new { c1 = sc.EntityId, c2 = sc.EntityName } into c_sm + from sc in c_sm.DefaultIfEmpty() + where !c.LimitedToStores || currentStoreId == sc.StoreId + select c; + + query = from c in query + group c by c.Id into cGroup + orderby cGroup.Key + select cGroup.FirstOrDefault(); + + query = query.OrderBy(c => c.DisplayOrder).ThenBy(c => c.Name); + } + var countries = query.ToList(); return countries; }); @@ -95,11 +120,9 @@ public virtual IList GetAllCountriesForBilling(bool showHidden = false) string key = string.Format(COUNTRIES_BILLING_KEY, showHidden); return _cacheManager.Get(key, () => { - var query = from c in _countryRepository.Table - orderby c.DisplayOrder, c.Name - where (showHidden || c.Published) && c.AllowsBilling - select c; - var countries = query.ToList(); + var allCountries = GetAllCountries(showHidden); + + var countries = allCountries.Where(x => x.AllowsBilling).ToList(); return countries; }); } @@ -113,12 +136,10 @@ public virtual IList GetAllCountriesForShipping(bool showHidden = false { string key = string.Format(COUNTRIES_SHIPPING_KEY, showHidden); return _cacheManager.Get(key, () => - { - var query = from c in _countryRepository.Table - orderby c.DisplayOrder, c.Name - where (showHidden || c.Published) && c.AllowsShipping - select c; - var countries = query.ToList(); + { + var allCountries = GetAllCountries(showHidden); + + var countries = allCountries.Where(x => x.AllowsShipping).ToList(); return countries; }); } @@ -160,11 +181,14 @@ public virtual Country GetCountryByTwoOrThreeLetterIsoCode(string letterIsoCode) /// Country public virtual Country GetCountryByTwoLetterIsoCode(string twoLetterIsoCode) { + if (twoLetterIsoCode.IsEmpty()) + return null; + var query = from c in _countryRepository.Table where c.TwoLetterIsoCode == twoLetterIsoCode select c; - var country = query.FirstOrDefault(); + var country = query.FirstOrDefault(); return country; } @@ -175,9 +199,13 @@ public virtual Country GetCountryByTwoLetterIsoCode(string twoLetterIsoCode) /// Country public virtual Country GetCountryByThreeLetterIsoCode(string threeLetterIsoCode) { + if (threeLetterIsoCode.IsEmpty()) + return null; + var query = from c in _countryRepository.Table where c.ThreeLetterIsoCode == threeLetterIsoCode select c; + var country = query.FirstOrDefault(); return country; } diff --git a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs index c394bd7f11..5dd60700e7 100644 --- a/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/CurrencyService.cs @@ -8,7 +8,6 @@ using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Core.Plugins; -using SmartStore.Services.Customers; using SmartStore.Services.Stores; namespace SmartStore.Services.Directory @@ -32,6 +31,8 @@ public partial class CurrencyService : ICurrencyService private readonly CurrencySettings _currencySettings; private readonly IPluginFinder _pluginFinder; private readonly IEventPublisher _eventPublisher; + private readonly IProviderManager _providerManager; + private readonly IStoreContext _storeContext; #endregion @@ -51,7 +52,9 @@ public CurrencyService(ICacheManager cacheManager, IStoreMappingService storeMappingService, CurrencySettings currencySettings, IPluginFinder pluginFinder, - IEventPublisher eventPublisher) + IEventPublisher eventPublisher, + IProviderManager providerManager, + IStoreContext storeContext) { this._cacheManager = cacheManager; this._currencyRepository = currencyRepository; @@ -59,6 +62,8 @@ public CurrencyService(ICacheManager cacheManager, this._currencySettings = currencySettings; this._pluginFinder = pluginFinder; this._eventPublisher = eventPublisher; + this._providerManager = providerManager; + this._storeContext = storeContext; } #endregion @@ -73,7 +78,11 @@ public CurrencyService(ICacheManager cacheManager, public virtual IList GetCurrencyLiveRates(string exchangeRateCurrencyCode) { var exchangeRateProvider = LoadActiveExchangeRateProvider(); - return exchangeRateProvider.GetCurrencyLiveRates(exchangeRateCurrencyCode); + if (exchangeRateProvider != null) + { + return exchangeRateProvider.Value.GetCurrencyLiveRates(exchangeRateCurrencyCode); + } + return new List(); } /// @@ -182,7 +191,6 @@ public virtual void UpdateCurrency(Currency currency) } - /// /// Converts currency /// @@ -202,16 +210,17 @@ public virtual decimal ConvertCurrency(decimal amount, decimal exchangeRate) /// Amount /// Source currency code /// Target currency code + /// Store to get the primary currencies from /// Converted value - public virtual decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode) + public virtual decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode, Store store = null) { decimal result = amount; if (sourceCurrencyCode.Id == targetCurrencyCode.Id) return result; if (result != decimal.Zero && sourceCurrencyCode.Id != targetCurrencyCode.Id) { - result = ConvertToPrimaryExchangeRateCurrency(result, sourceCurrencyCode); - result = ConvertFromPrimaryExchangeRateCurrency(result, targetCurrencyCode); + result = ConvertToPrimaryExchangeRateCurrency(result, sourceCurrencyCode, store); + result = ConvertFromPrimaryExchangeRateCurrency(result, targetCurrencyCode, store); } return result; } @@ -221,11 +230,13 @@ public virtual decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCo /// /// Amount /// Source currency code + /// Store to get the primary exchange rate currency from /// Converted value - public virtual decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode) + public virtual decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null) { decimal result = amount; - var primaryExchangeRateCurrency = GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId); + var primaryExchangeRateCurrency = (store == null ? _storeContext.CurrentStore.PrimaryExchangeRateCurrency : store.PrimaryExchangeRateCurrency); + if (result != decimal.Zero && sourceCurrencyCode.Id != primaryExchangeRateCurrency.Id) { decimal exchangeRate = sourceCurrencyCode.Rate; @@ -241,11 +252,13 @@ public virtual decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Curr /// /// Amount /// Target currency code + /// Store to get the primary exchange rate currency from /// Converted value - public virtual decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode) + public virtual decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode, Store store = null) { decimal result = amount; - var primaryExchangeRateCurrency = GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId); + var primaryExchangeRateCurrency = (store == null ? _storeContext.CurrentStore.PrimaryExchangeRateCurrency : store.PrimaryExchangeRateCurrency); + if (result != decimal.Zero && targetCurrencyCode.Id != primaryExchangeRateCurrency.Id) { decimal exchangeRate = targetCurrencyCode.Rate; @@ -261,11 +274,13 @@ public virtual decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Cu /// /// Amount /// Source currency code + /// Store to get the primary store currency from /// Converted value - public virtual decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode) + public virtual decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null) { decimal result = amount; - var primaryStoreCurrency = GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + var primaryStoreCurrency = (store == null ? _storeContext.CurrentStore.PrimaryStoreCurrency : store.PrimaryStoreCurrency); + if (result != decimal.Zero && sourceCurrencyCode.Id != primaryStoreCurrency.Id) { decimal exchangeRate = sourceCurrencyCode.Rate; @@ -282,11 +297,11 @@ public virtual decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency so /// Amount /// Target currency code /// Converted value - public virtual decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode) + public virtual decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode, Store store = null) { decimal result = amount; - var primaryStoreCurrency = GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); - result = ConvertCurrency(amount, primaryStoreCurrency, targetCurrencyCode); + var primaryStoreCurrency = (store == null ? _storeContext.CurrentStore.PrimaryStoreCurrency : store.PrimaryStoreCurrency); + result = ConvertCurrency(amount, primaryStoreCurrency, targetCurrencyCode, store); return result; } @@ -295,12 +310,9 @@ public virtual decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency /// Load active exchange rate provider /// /// Active exchange rate provider - public virtual IExchangeRateProvider LoadActiveExchangeRateProvider() + public virtual Provider LoadActiveExchangeRateProvider() { - var exchangeRateProvider = LoadExchangeRateProviderBySystemName(_currencySettings.ActiveExchangeRateProviderSystemName); - if (exchangeRateProvider == null) - exchangeRateProvider = LoadAllExchangeRateProviders().FirstOrDefault(); - return exchangeRateProvider; + return LoadExchangeRateProviderBySystemName(_currencySettings.ActiveExchangeRateProviderSystemName) ?? LoadAllExchangeRateProviders().FirstOrDefault(); } /// @@ -308,25 +320,18 @@ public virtual IExchangeRateProvider LoadActiveExchangeRateProvider() /// /// System name /// Found exchange rate provider - public virtual IExchangeRateProvider LoadExchangeRateProviderBySystemName(string systemName) + public virtual Provider LoadExchangeRateProviderBySystemName(string systemName) { - var descriptor = _pluginFinder.GetPluginDescriptorBySystemName(systemName); - if (descriptor != null) - return descriptor.Instance(); - - return null; + return _providerManager.GetProvider(systemName); } /// /// Load all exchange rate providers /// /// Exchange rate providers - public virtual IList LoadAllExchangeRateProviders() + public virtual IEnumerable> LoadAllExchangeRateProviders() { - var exchangeRateProviders = _pluginFinder.GetPlugins(); - return exchangeRateProviders - .OrderBy(tp => tp.PluginDescriptor) - .ToList(); + return _providerManager.GetAllProviders(); } #endregion } diff --git a/src/Libraries/SmartStore.Services/Directory/DeliveryTimeService.cs b/src/Libraries/SmartStore.Services/Directory/DeliveryTimeService.cs index c142ec2823..376ef8a3bf 100644 --- a/src/Libraries/SmartStore.Services/Directory/DeliveryTimeService.cs +++ b/src/Libraries/SmartStore.Services/Directory/DeliveryTimeService.cs @@ -1,14 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; -using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Directory; using SmartStore.Core.Events; using SmartStore.Core.Plugins; using SmartStore.Services.Customers; -using SmartStore.Core.Domain.Catalog; namespace SmartStore.Services.Directory { @@ -29,9 +28,9 @@ public partial class DeliveryTimeService : IDeliveryTimeService private readonly IRepository _attributeCombinationRepository; private readonly ICacheManager _cacheManager; private readonly ICustomerService _customerService; - //private readonly CurrencySettings _currencySettings; private readonly IPluginFinder _pluginFinder; private readonly IEventPublisher _eventPublisher; + private readonly CatalogSettings _catalogSettings; #endregion @@ -52,16 +51,17 @@ public DeliveryTimeService(ICacheManager cacheManager, IRepository attributeCombinationRepository, ICustomerService customerService, IPluginFinder pluginFinder, - IEventPublisher eventPublisher) + IEventPublisher eventPublisher, + CatalogSettings catalogSettings) { this._cacheManager = cacheManager; this._deliveryTimeRepository = deliveryTimeRepository; this._customerService = customerService; - //this._currencySettings = currencySettings; this._pluginFinder = pluginFinder; this._eventPublisher = eventPublisher; this._productRepository = productRepository; this._attributeCombinationRepository = attributeCombinationRepository; + this._catalogSettings = catalogSettings; } #endregion @@ -114,6 +114,25 @@ public virtual DeliveryTime GetDeliveryTimeById(int deliveryTimeId) return _deliveryTimeRepository.GetById(deliveryTimeId); } + /// + /// Gets the delivery time for a product + /// + /// The product + /// Delivery time + public virtual DeliveryTime GetDeliveryTime(Product product) + { + if (product == null) + return null; + + if ((product.ManageInventoryMethod == ManageInventoryMethod.ManageStock || product.ManageInventoryMethod == ManageInventoryMethod.ManageStockByAttributes) + && _catalogSettings.DeliveryTimeIdForEmptyStock.HasValue && product.StockQuantity <= 0) + { + return GetDeliveryTimeById(_catalogSettings.DeliveryTimeIdForEmptyStock.Value); + } + + return GetDeliveryTimeById(product.DeliveryTimeId ?? 0); + } + /// /// Gets all delivery times /// diff --git a/src/Libraries/SmartStore.Services/Directory/EcbExchangeRateProvider.cs b/src/Libraries/SmartStore.Services/Directory/EcbExchangeRateProvider.cs new file mode 100644 index 0000000000..7c43f0a2c1 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Directory/EcbExchangeRateProvider.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Xml; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; + +namespace SmartStore.Services.Directory +{ + [SystemName("CurrencyExchange.ECB")] + [FriendlyName("ECB exchange rate provider")] + [DisplayOrder(0)] + public class EcbExchangeRateProvider : IExchangeRateProvider + { + private readonly ILocalizationService _localizationService; + + public EcbExchangeRateProvider(ILocalizationService localizationService) + { + this._localizationService = localizationService; + } + + /// + /// Gets currency live rates + /// + /// Exchange rate currency code + /// Exchange rates + public IList GetCurrencyLiveRates(string exchangeRateCurrencyCode) + { + if (String.IsNullOrEmpty(exchangeRateCurrencyCode) || + exchangeRateCurrencyCode.ToLower() != "eur") + throw new SmartException(_localizationService.GetResource("Providers.ExchangeRate.EcbExchange.SetCurrencyToEURO")); + + var exchangeRates = new List(); + + var request = WebRequest.Create("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml") as HttpWebRequest; + using (WebResponse response = request.GetResponse()) + { + var document = new XmlDocument(); + document.Load(response.GetResponseStream()); + var nsmgr = new XmlNamespaceManager(document.NameTable); + nsmgr.AddNamespace("ns", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref"); + nsmgr.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01"); + + var node = document.SelectSingleNode("gesmes:Envelope/ns:Cube/ns:Cube", nsmgr); + var updateDate = DateTime.ParseExact(node.Attributes["time"].Value, "yyyy-MM-dd", null); + + var provider = new NumberFormatInfo(); + provider.NumberDecimalSeparator = "."; + provider.NumberGroupSeparator = ""; + foreach (XmlNode node2 in node.ChildNodes) + { + exchangeRates.Add(new Core.Domain.Directory.ExchangeRate() + { + CurrencyCode = node2.Attributes["currency"].Value, + Rate = decimal.Parse(node2.Attributes["rate"].Value, provider), + UpdatedOn = updateDate + } + ); + } + } + return exchangeRates; + } + + } +} diff --git a/src/Libraries/SmartStore.Services/Directory/GeoCountryLookup.cs b/src/Libraries/SmartStore.Services/Directory/GeoCountryLookup.cs index d5085401d8..482c956986 100644 --- a/src/Libraries/SmartStore.Services/Directory/GeoCountryLookup.cs +++ b/src/Libraries/SmartStore.Services/Directory/GeoCountryLookup.cs @@ -3,6 +3,9 @@ using System.IO; using System.Net; using SmartStore.Core; +using SmartStore.Core.Caching; +using MaxMind.GeoIP; +using SmDir = SmartStore.Core.Domain.Directory; namespace SmartStore.Services.Directory { @@ -11,117 +14,25 @@ namespace SmartStore.Services.Directory /// public partial class GeoCountryLookup : IGeoCountryLookup { - #region Fields - private long COUNTRY_BEGIN = 16776960; - private readonly string[] _countryCode = - { "--","AP","EU","AD","AE","AF","AG","AI","AL","AM","AN","AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB","BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO","BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD","CF","CG","CH","CI","CK","CL","CM","CN","CO","CR","CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO","DZ", - "EC","EE","EG","EH","ER","ES","ET","FI","FJ","FK","FM","FO","FR","FX","GA","GB","GD","GE","GF","GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT","GU","GW","GY","HK","HM","HN","HR","HT","HU","ID","IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO","JP","KE","KG","KH","KI","KM","KN","KP","KR","KW","KY","KZ", - "LA","LB","LC","LI","LK","LR","LS","LT","LU","LV","LY","MA","MC","MD","MG","MH","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV","MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI","NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF","PG","PH","PK","PL","PM","PN","PR","PS","PT","PW","PY","QA", - "RE","RO","RU","RW","SA","SB","SC","SD","SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH","TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW","TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE","VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA","ZM","ME","ZW","A1","A2", - "O1","AX","GG","IM","JE","BL","MF" - }; - private readonly string[] _countryName = - {"N/A","Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles","Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados","Bangladesh","Belgium", - "Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia","Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the","Central African Republic","Congo","Switzerland","Cote D'Ivoire", - "Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica","Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic","Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji","Falkland Islands (Malvinas)", - "Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana","Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala","Guam","Guinea-Bissau","Guyana", - "Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia","Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan","Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis", - "Korea, Democratic People's Republic of","Korea, Republic of","Kuwait","Cayman Islands","Kazakstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania","Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar", - "Marshall Islands","Macedonia","Mali","Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives","Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua","Netherlands", - "Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia","Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau","Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia", - "Solomon Islands","Seychelles","Sudan","Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname","Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo", - "Thailand","Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan","Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines", - "Venezuela","Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa","Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider", - "Other","Aland Islands","Guernsey","Isle of Man","Jersey","Saint Barthelemy","Saint Martin"}; - private readonly IWebHelper _webHelper; - #endregion + private readonly ICountryService _countryService; + private readonly ICacheManager _cacheManager; - #region Ctor - public GeoCountryLookup(IWebHelper webHelper) + public GeoCountryLookup(IWebHelper webHelper, ICacheManager cacheManager, ICountryService countryService) { this._webHelper = webHelper; + this._cacheManager = cacheManager; + this._countryService = countryService; } - #endregion - - #region Utilities - protected virtual long AddrToNum(IPAddress addr) - { - long ipnum = 0; - byte[] b = addr.GetAddressBytes(); - for (int i = 0; i < 4; ++i) - { - long y = b[i]; - if (y < 0) - { - y += 256; - } - ipnum += y << ((3 - i) * 8); - } - Debug.WriteLine(ipnum); - return ipnum; - } - - protected virtual long SeekCountry(long offset, long ipnum, int depth) - { - byte[] buf = new byte[6]; - long[] x = new long[2]; - if (depth < 0) - { - Debug.WriteLine("Error seeking country."); - return 0; // N/A - } - try - { - //you can download the latest GeoIP database here http://www.maxmind.com/app/free - string fileName = _webHelper.MapPath("~/App_Data/GeoIP.dat"); - using (var fileInput = new FileStream(fileName, FileMode.Open, FileAccess.Read)) - { - fileInput.Seek(6 * offset, 0); - fileInput.Read(buf, 0, 6); - } - } - catch (IOException) - { - Debug.WriteLine("IO Exception"); - return 0; // N/A - } - for (int i = 0; i < 2; i++) - { - x[i] = 0; - for (int j = 0; j < 3; j++) - { - int y = buf[i * 3 + j]; - if (y < 0) - { - y += 256; - } - x[i] += (y << (j * 8)); - } - } - - if ((ipnum & (1 << depth)) > 0) - { - if (x[1] >= COUNTRY_BEGIN) - { - return x[1] - COUNTRY_BEGIN; - } - return SeekCountry(x[1], ipnum, depth - 1); - } - else - { - if (x[0] >= COUNTRY_BEGIN) - { - return x[0] - COUNTRY_BEGIN; - } - return SeekCountry(x[0], ipnum, depth - 1); - } - } - - #endregion - - #region Methods + private MaxMind.GeoIP.LookupService GetLookupService() + { + return _cacheManager.Get("GeoCountryLookup", () => + { + var lookupService = new MaxMind.GeoIP.LookupService(_webHelper.MapPath("~/App_Data/GeoIP.dat")); + return lookupService; + }); + } public virtual string LookupCountryCode(string str) { @@ -142,10 +53,20 @@ public virtual string LookupCountryCode(string str) public virtual string LookupCountryCode(IPAddress addr) { - string code = (_countryCode[(int)SeekCountry(0, AddrToNum(addr), 31)]); - if (code == "--") - code = string.Empty; - return code; + try + { + var lookupService = GetLookupService(); + var country = lookupService.getCountry(addr); + var code = country.getCode(); + if (code == "--") + return string.Empty; + + return code; + } + catch + { + return string.Empty; + } } public virtual string LookupCountryName(string str) @@ -167,9 +88,40 @@ public virtual string LookupCountryName(string str) public virtual string LookupCountryName(IPAddress addr) { - return (_countryName[(int)SeekCountry(0, AddrToNum(addr), 31)]); + try + { + var lookupService = GetLookupService(); + var country = lookupService.getCountry(addr); + return country.getName(); + } + catch + { + return string.Empty; + } } - #endregion + public virtual bool IsEuIpAddress(string ipAddress, out SmDir.Country euCountry) + { + euCountry = null; + + if (ipAddress.IsEmpty()) + return false; + + euCountry = _cacheManager.Get("GeoCountryLookup.EuCountry.{0}".FormatInvariant(ipAddress), () => + { + var countryCode = LookupCountryCode(ipAddress); + if (countryCode.IsEmpty()) + return (SmDir.Country)null; + + var country = _countryService.GetCountryByTwoLetterIsoCode(countryCode); + return country; + }); + + if (euCountry == null) + return false; + + return euCountry.SubjectToVat; + } + } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs index 2b4fb32398..65f633fed4 100644 --- a/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs +++ b/src/Libraries/SmartStore.Services/Directory/ICurrencyService.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Directory { @@ -71,40 +73,45 @@ public partial interface ICurrencyService /// Amount /// Source currency code /// Target currency code + /// Store to get the primary currencies from /// Converted value - decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode); + decimal ConvertCurrency(decimal amount, Currency sourceCurrencyCode, Currency targetCurrencyCode, Store store = null); /// /// Converts to primary exchange rate currency /// /// Amount /// Source currency code + /// Store to get the primary exchange rate currency from /// Converted value - decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode); + decimal ConvertToPrimaryExchangeRateCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null); /// /// Converts from primary exchange rate currency /// /// Amount /// Target currency code + /// Store to get the primary exchange rate currency from /// Converted value - decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode); + decimal ConvertFromPrimaryExchangeRateCurrency(decimal amount, Currency targetCurrencyCode, Store store = null); /// /// Converts to primary store currency /// /// Amount /// Source currency code + /// Store to get the primary store currency from /// Converted value - decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode); + decimal ConvertToPrimaryStoreCurrency(decimal amount, Currency sourceCurrencyCode, Store store = null); /// /// Converts from primary store currency /// /// Amount /// Target currency code + /// Store to get the primary store currency from /// Converted value - decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode); + decimal ConvertFromPrimaryStoreCurrency(decimal amount, Currency targetCurrencyCode, Store store = null); @@ -112,19 +119,19 @@ public partial interface ICurrencyService /// Load active exchange rate provider /// /// Active exchange rate provider - IExchangeRateProvider LoadActiveExchangeRateProvider(); + Provider LoadActiveExchangeRateProvider(); /// /// Load exchange rate provider by system name /// /// System name /// Found exchange rate provider - IExchangeRateProvider LoadExchangeRateProviderBySystemName(string systemName); + Provider LoadExchangeRateProviderBySystemName(string systemName); /// /// Load all exchange rate providers /// /// Exchange rate providers - IList LoadAllExchangeRateProviders(); + IEnumerable> LoadAllExchangeRateProviders(); } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Directory/IDeliveryTimeService.cs b/src/Libraries/SmartStore.Services/Directory/IDeliveryTimeService.cs index 0f90f1f8e4..884d4ab2dd 100644 --- a/src/Libraries/SmartStore.Services/Directory/IDeliveryTimeService.cs +++ b/src/Libraries/SmartStore.Services/Directory/IDeliveryTimeService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Directory; namespace SmartStore.Services.Directory @@ -27,19 +28,29 @@ public partial interface IDeliveryTimeService /// DeliveryTime DeliveryTime GetDeliveryTimeById(int deliveryTimeId); + /// + /// Gets the delivery time for a product + /// + /// The product + /// Delivery time + DeliveryTime GetDeliveryTime(Product product); + /// /// Gets all delivery times /// - /// A value indicating whether to show hidden records /// delivery time collection IList GetAllDeliveryTimes(); /// /// Inserts a delivery time /// - /// DeliveryTime + /// DeliveryTime void InsertDeliveryTime(DeliveryTime deliveryTime); + /// + /// Updates a delivery time + /// + /// DeliveryTime void UpdateDeliveryTime(DeliveryTime deliveryTime); } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Directory/IExchangeRateProvider.cs b/src/Libraries/SmartStore.Services/Directory/IExchangeRateProvider.cs index f0daa590ab..f03624ddc3 100644 --- a/src/Libraries/SmartStore.Services/Directory/IExchangeRateProvider.cs +++ b/src/Libraries/SmartStore.Services/Directory/IExchangeRateProvider.cs @@ -7,7 +7,7 @@ namespace SmartStore.Services.Directory /// /// Exchange rate provider interface /// - public partial interface IExchangeRateProvider : IPlugin + public partial interface IExchangeRateProvider : IProvider { /// /// Gets currency live rates diff --git a/src/Libraries/SmartStore.Services/Directory/IGeoCountryLookup.cs b/src/Libraries/SmartStore.Services/Directory/IGeoCountryLookup.cs index 3facbdea3c..815a030b2c 100644 --- a/src/Libraries/SmartStore.Services/Directory/IGeoCountryLookup.cs +++ b/src/Libraries/SmartStore.Services/Directory/IGeoCountryLookup.cs @@ -1,4 +1,5 @@ using System.Net; +using SmartStore.Core.Domain.Directory; namespace SmartStore.Services.Directory { @@ -14,5 +15,15 @@ public partial interface IGeoCountryLookup string LookupCountryName(string str); string LookupCountryName(IPAddress addr); + + /// + /// Gets a value indicating whether the given IP address originates from an EU country + /// + /// IP address + /// An instance of if the IP originates from a EU country + /// + /// true if the IP address originates from an EU country, false if not + /// + bool IsEuIpAddress(string ipAddress, out Country euCountry); } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Directory/IQuantityUnitService.cs b/src/Libraries/SmartStore.Services/Directory/IQuantityUnitService.cs new file mode 100644 index 0000000000..b198394f2e --- /dev/null +++ b/src/Libraries/SmartStore.Services/Directory/IQuantityUnitService.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Directory; + +namespace SmartStore.Services.Directory +{ + /// + /// QuantityUnit service + /// + public partial interface IQuantityUnitService + { + /// + /// Checks if the delivery time is associated with + /// at least one dependant entity + /// + bool IsAssociated(int quantityUnitId); + + /// + /// Deletes measure unit + /// + /// QuantityUnit + void DeleteQuantityUnit(QuantityUnit quantityUnit); + + /// + /// Gets a measure unit + /// + /// measure unit identifier + /// QuantityUnit + QuantityUnit GetQuantityUnitById(int? quantityUnitId); + + /// + /// Gets the measure unit for a product + /// + /// The product + /// measure unit + QuantityUnit GetQuantityUnit(Product product); + + /// + /// Gets all measure units + /// + /// measure unit collection + IList GetAllQuantityUnits(); + + /// + /// Inserts a measure unit + /// + /// QuantityUnit + void InsertQuantityUnit(QuantityUnit quantityUnit); + + /// + /// Updates a measure unit + /// + /// QuantityUnit + void UpdateQuantityUnit(QuantityUnit quantityUnit); + } +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs b/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs index 95f0c91c2a..e62ff53527 100644 --- a/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs +++ b/src/Libraries/SmartStore.Services/Directory/IStateProvinceService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using SmartStore.Core.Domain.Directory; namespace SmartStore.Services.Directory @@ -14,12 +15,19 @@ public partial interface IStateProvinceService /// The state/province void DeleteStateProvince(StateProvince stateProvince); - /// - /// Gets a state/province - /// - /// The state/province identifier - /// State/province - StateProvince GetStateProvinceById(int stateProvinceId); + /// + /// Get all states/provinces + /// + /// A value indicating whether to show hidden records + /// + IQueryable GetAllStateProvinces(bool showHidden = false); + + /// + /// Gets a state/province + /// + /// The state/province identifier + /// State/province + StateProvince GetStateProvinceById(int stateProvinceId); /// /// Gets a state/province diff --git a/src/Libraries/SmartStore.Services/Directory/McExchangeRateProvider.cs b/src/Libraries/SmartStore.Services/Directory/McExchangeRateProvider.cs new file mode 100644 index 0000000000..13fa8f8ee9 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Directory/McExchangeRateProvider.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Xml; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; +using SmartStore.Core.Logging; + +namespace SmartStore.Services.Directory +{ + [SystemName("CurrencyExchange.MoneyConverter")] + [FriendlyName("Money converter exchange rate provider")] + [DisplayOrder(1)] + public class McExchangeRateProvider : IExchangeRateProvider + { + private readonly ILogger _logger; + + public McExchangeRateProvider(ILogger logger) + { + this._logger = logger; + } + + /// + /// Gets currency live rates + /// + /// Exchange rate currency code + /// Exchange rates + public IList GetCurrencyLiveRates(string exchangeRateCurrencyCode) { + var exchangeRates = new List(); + string url = string.Format("http://themoneyconverter.com/rss-feed/{0}/rss.xml", exchangeRateCurrencyCode); + + var request = WebRequest.Create(url) as HttpWebRequest; + using (var response = request.GetResponse()) { + var xmlDoc = new XmlDocument(); + xmlDoc.Load(response.GetResponseStream()); + var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable); + nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom"); + nsmgr.AddNamespace("cf", "http://www.microsoft.com/schemas/rss/core/2005"); + nsmgr.AddNamespace("cfi", "http://www.microsoft.com/schemas/rss/core/2005/internal"); + + foreach (XmlNode node in xmlDoc.DocumentElement.FirstChild.ChildNodes) { + if (node.Name == "item") { + /* + + AED/NZD + http://themoneyconverter.com/NZD/AED.aspx + http://themoneyconverter.com/NZD/AED.aspx + Fri, 20 Feb 2009 08:01:41 GMT + 2009-02-20T08:01:41Z + 2009-02-20T08:01:41Z + 1 New Zealand Dollar = 1.84499 Arab Emirates Dirham + Middle-East + 32 + 1074571199 + true + http://themoneyconverter.com/NZD/rss.xml + 2009-02-20T08:05:27.168Z + + */ + try { + var rate = new Core.Domain.Directory.ExchangeRate(); + foreach (XmlNode detailNode in node.ChildNodes) { + switch (detailNode.Name) { + case "title": + rate.CurrencyCode = detailNode.InnerText.Substring(0, 3); + break; + + case "pubDate": + rate.UpdatedOn = DateTime.Parse(detailNode.InnerText, CultureInfo.InvariantCulture); + break; + + case "description": + string description = detailNode.InnerText; + int x = description.IndexOf('='); + int y = description.IndexOf(' ', x + 2); + + // 1 2 3 4 + //01234567890123456789012345678901234567890 + // 1 New Zealand Dollar = 0.78815 Australian Dollar + // x = 21 + // y = 30 + string rateText = description.Substring(x + 1, y - x - 1).Trim(); + rate.Rate = decimal.Parse(rateText, CultureInfo.InvariantCulture); + break; + + default: + break; + } + } + + // Update the Rate in the collection if its already in there + if (rate.CurrencyCode != null) { + exchangeRates.Add(rate); + } + } + catch (Exception exc) { + _logger.Warning(string.Format("Error parsing currency rates (MC): {0}", exc.Message), exc); + } + } // if node is an item + } // foreach child node under + } + + return exchangeRates; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Directory/QuantityUnitService.cs b/src/Libraries/SmartStore.Services/Directory/QuantityUnitService.cs new file mode 100644 index 0000000000..e6cee4e066 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Directory/QuantityUnitService.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SmartStore.Core.Caching; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Events; +using SmartStore.Core.Plugins; +using SmartStore.Services.Customers; + +namespace SmartStore.Services.Directory +{ + /// + /// QuantityUnit service + /// + public partial class QuantityUnitService : IQuantityUnitService + { + #region Constants + private const string MEASUREUNITS_ALL_KEY = "SMN.quantityunits.all"; + private const string MEASUREUNITS_PATTERN_KEY = "SMN.quantityunit."; + #endregion + + #region Fields + + private readonly IRepository _quantityUnitRepository; + private readonly IRepository _productRepository; + private readonly ICacheManager _cacheManager; + private readonly IEventPublisher _eventPublisher; + private readonly CatalogSettings _catalogSettings; + + #endregion + + #region Ctor + + /// + /// Ctor + /// + /// Cache manager + /// QuantityUnit repository + /// Customer service + /// Currency settings + /// Plugin finder + /// Event published + public QuantityUnitService(ICacheManager cacheManager, + IRepository quantityUnitRepository, + IRepository productRepository, + IRepository attributeCombinationRepository, + ICustomerService customerService, + IEventPublisher eventPublisher, + CatalogSettings catalogSettings) + { + this._cacheManager = cacheManager; + this._quantityUnitRepository = quantityUnitRepository; + this._eventPublisher = eventPublisher; + this._productRepository = productRepository; + this._catalogSettings = catalogSettings; + } + + #endregion + + #region Methods + + /// + /// Deletes QuantityUnit + /// + /// QuantityUnit + public virtual void DeleteQuantityUnit(QuantityUnit quantityUnit) + { + if (quantityUnit == null) + throw new ArgumentNullException("quantityUnit"); + + if (this.IsAssociated(quantityUnit.Id)) + throw new SmartException("The quantity unit cannot be deleted. It has associated product variants"); + + _quantityUnitRepository.Delete(quantityUnit); + + _cacheManager.RemoveByPattern(MEASUREUNITS_PATTERN_KEY); + + //event notification + _eventPublisher.EntityDeleted(quantityUnit); + } + + public virtual bool IsAssociated(int quantityUnitId) + { + if (quantityUnitId == 0) + return false; + + var query = + from p in _productRepository.Table + where p.QuantityUnitId == quantityUnitId || p.ProductVariantAttributeCombinations.Any(c => c.QuantityUnitId == quantityUnitId) + select p.Id; + + return query.Count() > 0; + } + + /// + /// Gets a QuantityUnit + /// + /// QuantityUnit identifier + /// QuantityUnit + public virtual QuantityUnit GetQuantityUnitById(int? quantityUnitId) + { + if (quantityUnitId == null || quantityUnitId == 0) + { + if(_catalogSettings.ShowDefaultQuantityUnit) + { + return GetAllQuantityUnits().Where(x => x.IsDefault == true).FirstOrDefault(); + } + else + { + return null; + } + } + + return _quantityUnitRepository.GetById(quantityUnitId); + } + + /// + /// Gets the measure unit for a product + /// + /// The product + /// QuantityUnit + public virtual QuantityUnit GetQuantityUnit(Product product) + { + if (product == null) + return null; + + return GetQuantityUnitById(product.QuantityUnitId ?? 0); + } + + /// + /// Gets all measure units + /// + /// A value indicating whether to show hidden records + /// QuantityUnit collection + public virtual IList GetAllQuantityUnits() + { + string key = string.Format(MEASUREUNITS_ALL_KEY); + return _cacheManager.Get(key, () => + { + var query = _quantityUnitRepository.Table; + query = query.OrderBy(c => c.DisplayOrder); + var quantityUnits = query.ToList(); + return quantityUnits; + }); + } + + /// + /// Inserts a QuantityUnit + /// + /// QuantityUnit + public virtual void InsertQuantityUnit(QuantityUnit quantityUnit) + { + if (quantityUnit == null) + throw new ArgumentNullException("quantityUnit"); + + _quantityUnitRepository.Insert(quantityUnit); + + _cacheManager.RemoveByPattern(MEASUREUNITS_PATTERN_KEY); + + //event notification + _eventPublisher.EntityInserted(quantityUnit); + } + + /// + /// Updates the QuantityUnit + /// + /// QuantityUnit + public virtual void UpdateQuantityUnit(QuantityUnit quantityUnit) + { + if (quantityUnit == null) + throw new ArgumentNullException("quantityUnit"); + + if (quantityUnit.IsDefault == true) { + + var temp = new List(); + temp.Add(quantityUnit); + + var query = GetAllQuantityUnits() + .Where(x => x.IsDefault == true) + .Except(temp); + + foreach(var qu in query) + { + qu.IsDefault = false; + _quantityUnitRepository.Update(qu); + } + } + + _quantityUnitRepository.Update(quantityUnit); + + _cacheManager.RemoveByPattern(MEASUREUNITS_PATTERN_KEY); + + //event notification + _eventPublisher.EntityUpdated(quantityUnit); + } + + #endregion + + } +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs b/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs index 27ddf6f5a6..b631dca9e9 100644 --- a/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs +++ b/src/Libraries/SmartStore.Services/Directory/StateProvinceService.cs @@ -8,10 +8,10 @@ namespace SmartStore.Services.Directory { - /// - /// State province service - /// - public partial class StateProvinceService : IStateProvinceService + /// + /// State province service + /// + public partial class StateProvinceService : IStateProvinceService { #region Constants private const string STATEPROVINCES_ALL_KEY = "SmartStore.stateprovince.all-{0}"; @@ -46,6 +46,7 @@ public StateProvinceService(ICacheManager cacheManager, #endregion #region Methods + /// /// Deletes a state/province /// @@ -63,12 +64,22 @@ public virtual void DeleteStateProvince(StateProvince stateProvince) _eventPublisher.EntityDeleted(stateProvince); } - /// - /// Gets a state/province - /// - /// The state/province identifier - /// State/province - public virtual StateProvince GetStateProvinceById(int stateProvinceId) + public virtual IQueryable GetAllStateProvinces(bool showHidden = false) + { + var query = _stateProvinceRepository.Table; + + if (!showHidden) + query = query.Where(x => x.Published); + + return query; + } + + /// + /// Gets a state/province + /// + /// The state/province identifier + /// State/province + public virtual StateProvince GetStateProvinceById(int stateProvinceId) { if (stateProvinceId == 0) return null; diff --git a/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs b/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs index a3d52f317c..0882af90c5 100644 --- a/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs +++ b/src/Libraries/SmartStore.Services/Directory/UpdateExchangeRateTask.cs @@ -1,6 +1,5 @@ using System; using SmartStore.Core.Domain.Directory; -using SmartStore.Services.Configuration; using SmartStore.Services.Tasks; namespace SmartStore.Services.Directory @@ -11,15 +10,17 @@ namespace SmartStore.Services.Directory public partial class UpdateExchangeRateTask : ITask { private readonly ICurrencyService _currencyService; - private readonly ISettingService _settingService; private readonly CurrencySettings _currencySettings; + private readonly ICommonServices _services; - public UpdateExchangeRateTask(ICurrencyService currencyService, - ISettingService settingService, CurrencySettings currencySettings) + public UpdateExchangeRateTask( + ICurrencyService currencyService, + CurrencySettings currencySettings, + ICommonServices services) { this._currencyService = currencyService; - this._settingService = settingService; this._currencySettings = currencySettings; + this._services = services; } /// @@ -33,10 +34,11 @@ public void Execute(TaskExecutionContext ctx) long lastUpdateTimeTicks = _currencySettings.LastUpdateTime; DateTime lastUpdateTime = DateTime.FromBinary(lastUpdateTimeTicks); lastUpdateTime = DateTime.SpecifyKind(lastUpdateTime, DateTimeKind.Utc); + if (lastUpdateTime.AddHours(1) < DateTime.UtcNow) { //update rates each one hour - var exchangeRates = _currencyService.GetCurrencyLiveRates(_currencyService.GetCurrencyById(_currencySettings.PrimaryExchangeRateCurrencyId).CurrencyCode); + var exchangeRates = _currencyService.GetCurrencyLiveRates(_services.StoreContext.CurrentStore.PrimaryExchangeRateCurrency.CurrencyCode); foreach (var exchageRate in exchangeRates) { @@ -51,7 +53,7 @@ public void Execute(TaskExecutionContext ctx) //save new update time value _currencySettings.LastUpdateTime = DateTime.UtcNow.ToBinary(); - _settingService.SaveSetting(_currencySettings); + _services.Settings.SaveSetting(_currencySettings); } } } diff --git a/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs b/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs index e33b09613d..ccc62d5921 100644 --- a/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs +++ b/src/Libraries/SmartStore.Services/Discounts/DiscountExtentions.cs @@ -29,10 +29,8 @@ public static decimal GetDiscountAmount(this Discount discount, decimal amount) return result; } - - public static Discount GetPreferredDiscount(this IList discounts, - decimal amount) + public static Discount GetPreferredDiscount(this IList discounts, decimal amount) { Discount preferredDiscount = null; decimal maximumDiscountValue = decimal.Zero; @@ -48,21 +46,5 @@ public static Discount GetPreferredDiscount(this IList discounts, return preferredDiscount; } - - public static bool ContainsDiscount(this IList discounts, - Discount discount) - { - if (discounts == null) - throw new ArgumentNullException("discounts"); - - if (discount == null) - throw new ArgumentNullException("discount"); - - foreach (var dis1 in discounts) - if (discount.Id == dis1.Id) - return true; - - return false; - } } } diff --git a/src/Libraries/SmartStore.Services/Discounts/DiscountService.cs b/src/Libraries/SmartStore.Services/Discounts/DiscountService.cs index 22a4b22e8a..ffa0fa2615 100644 --- a/src/Libraries/SmartStore.Services/Discounts/DiscountService.cs +++ b/src/Libraries/SmartStore.Services/Discounts/DiscountService.cs @@ -8,9 +8,11 @@ using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Events; using SmartStore.Core.Plugins; +using SmartStore.Core.Domain.Orders; using SmartStore.Services.Customers; using SmartStore.Services.Common; using SmartStore.Services.Configuration; +using SmartStore.Services.Orders; namespace SmartStore.Services.Discounts { @@ -34,24 +36,13 @@ public partial class DiscountService : IDiscountService private readonly IGenericAttributeService _genericAttributeService; private readonly IPluginFinder _pluginFinder; private readonly IEventPublisher _eventPublisher; - private readonly ISettingService _settingService; // codehint: sm-add + private readonly ISettingService _settingService; + private readonly IProviderManager _providerManager; #endregion #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// Discount repository - /// Discount requirement repository - /// Discount usage history repository - /// Store context - /// Generic attribute service - /// Plugin finder - /// Event published - /// Setting service public DiscountService(ICacheManager cacheManager, IRepository discountRepository, IRepository discountRequirementRepository, @@ -60,7 +51,8 @@ public DiscountService(ICacheManager cacheManager, IGenericAttributeService genericAttributeService, IPluginFinder pluginFinder, IEventPublisher eventPublisher, - ISettingService settingService) + ISettingService settingService, + IProviderManager providerManager) { this._cacheManager = cacheManager; this._discountRepository = discountRepository; @@ -70,7 +62,8 @@ public DiscountService(ICacheManager cacheManager, this._genericAttributeService = genericAttributeService; this._pluginFinder = pluginFinder; this._eventPublisher = eventPublisher; - this._settingService = settingService; // codehint: sm-add + this._settingService = settingService; + this._providerManager = providerManager; } #endregion @@ -256,23 +249,18 @@ public virtual void DeleteDiscountRequirement(DiscountRequirement discountRequir /// /// System name /// Found discount requirement rule - public virtual IDiscountRequirementRule LoadDiscountRequirementRuleBySystemName(string systemName) + public virtual Provider LoadDiscountRequirementRuleBySystemName(string systemName, int storeId = 0) { - var descriptor = _pluginFinder.GetPluginDescriptorBySystemName(systemName); - if (descriptor != null) - return descriptor.Instance(); - - return null; + return _providerManager.GetProvider(systemName, storeId); } /// /// Load all discount requirement rules /// /// Discount requirement rules - public virtual IList LoadAllDiscountRequirementRules() + public virtual IEnumerable> LoadAllDiscountRequirementRules(int storeId = 0) { - var rules = _pluginFinder.GetPlugins(); - return rules.ToList(); + return _providerManager.GetAllProviders(storeId); } /// @@ -330,16 +318,18 @@ public virtual bool IsDiscountValid(Discount discount, Customer customer, string } //check date range - DateTime now = DateTime.UtcNow; + var now = DateTime.UtcNow; + var store = _storeContext.CurrentStore; + if (discount.StartDateUtc.HasValue) { - DateTime startDate = DateTime.SpecifyKind(discount.StartDateUtc.Value, DateTimeKind.Utc); + var startDate = DateTime.SpecifyKind(discount.StartDateUtc.Value, DateTimeKind.Utc); if (startDate.CompareTo(now) > 0) return false; } if (discount.EndDateUtc.HasValue) { - DateTime endDate = DateTime.SpecifyKind(discount.EndDateUtc.Value, DateTimeKind.Utc); + var endDate = DateTime.SpecifyKind(discount.EndDateUtc.Value, DateTimeKind.Utc); if (endDate.CompareTo(now) < 0) return false; } @@ -347,26 +337,37 @@ public virtual bool IsDiscountValid(Discount discount, Customer customer, string if (!CheckDiscountLimitations(discount, customer)) return false; - //discount requirements - var requirements = discount.DiscountRequirements; + // better not to apply discounts if there are gift cards in the cart cause the customer could "earn" money through that. + if (discount.DiscountType == DiscountType.AssignedToOrderTotal || discount.DiscountType == DiscountType.AssignedToOrderSubTotal) + { + var cart = customer.ShoppingCartItems + .Filter(ShoppingCartType.ShoppingCart, store.Id) + .ToList(); + + if (cart.Any(x => x.Product.IsGiftCard)) + return false; + } + + // discount requirements + var requirements = discount.DiscountRequirements; foreach (var req in requirements) { - var requirementRule = LoadDiscountRequirementRuleBySystemName(req.DiscountRequirementRuleSystemName); + var requirementRule = LoadDiscountRequirementRuleBySystemName(req.DiscountRequirementRuleSystemName, store.Id); if (requirementRule == null) continue; - if (!(_storeContext.CurrentStore.Id == 0 || - _settingService.GetSettingByKey(requirementRule.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(_storeContext.CurrentStore.Id, true))) - continue; - var request = new CheckDiscountRequirementRequest() + var request = new CheckDiscountRequirementRequest { DiscountRequirement = req, Customer = customer, - Store = _storeContext.CurrentStore + Store = store }; - if (!requirementRule.CheckRequirement(request)) + + // TODO: cache result... CheckRequirement is very often called + if (!requirementRule.Value.CheckRequirement(request)) return false; } + return true; } diff --git a/src/Libraries/SmartStore.Services/Discounts/IDiscountRequirementRule.cs b/src/Libraries/SmartStore.Services/Discounts/IDiscountRequirementRule.cs index 769881b6ab..15325d3141 100644 --- a/src/Libraries/SmartStore.Services/Discounts/IDiscountRequirementRule.cs +++ b/src/Libraries/SmartStore.Services/Discounts/IDiscountRequirementRule.cs @@ -1,12 +1,11 @@ - -using SmartStore.Core.Plugins; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Discounts { /// /// Represents a discount requirement rule /// - public partial interface IDiscountRequirementRule : IPlugin + public partial interface IDiscountRequirementRule : IProvider { /// /// Check discount requirement diff --git a/src/Libraries/SmartStore.Services/Discounts/IDiscountService.cs b/src/Libraries/SmartStore.Services/Discounts/IDiscountService.cs index 0f1b5f1af1..8302251085 100644 --- a/src/Libraries/SmartStore.Services/Discounts/IDiscountService.cs +++ b/src/Libraries/SmartStore.Services/Discounts/IDiscountService.cs @@ -1,7 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Discounts { @@ -54,13 +56,13 @@ public partial interface IDiscountService /// /// System name /// Found discount requirement rule - IDiscountRequirementRule LoadDiscountRequirementRuleBySystemName(string systemName); + Provider LoadDiscountRequirementRuleBySystemName(string systemName, int storeId = 0); /// /// Load all discount requirement rules /// /// Discount requirement rules - IList LoadAllDiscountRequirementRules(); + IEnumerable> LoadAllDiscountRequirementRules(int storeId = 0); /// diff --git a/src/Libraries/SmartStore.Services/Events/DefaultConsumerFactory.cs b/src/Libraries/SmartStore.Services/Events/DefaultConsumerFactory.cs index dd84254caa..f9c0a1e032 100644 --- a/src/Libraries/SmartStore.Services/Events/DefaultConsumerFactory.cs +++ b/src/Libraries/SmartStore.Services/Events/DefaultConsumerFactory.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using SmartStore.Core.Infrastructure; using SmartStore.Core.Events; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Events { @@ -10,10 +11,14 @@ namespace SmartStore.Services.Events public class DefaultConsumerFactory : IConsumerFactory { private readonly IEnumerable, EventConsumerMetadata>> _consumers; + private readonly ICommonServices _services; - public DefaultConsumerFactory(IEnumerable, EventConsumerMetadata>> consumers) + public DefaultConsumerFactory( + IEnumerable, EventConsumerMetadata>> consumers, + ICommonServices services) { this._consumers = consumers; + this._services = services; } public IEnumerable> GetConsumers(bool? resolveAsyncs = null) @@ -22,9 +27,14 @@ public IEnumerable> GetConsumers(bool? resolveAsyncs = null) { var isActive = consumer.Metadata.IsActive; var isAsync = consumer.Metadata.ExecuteAsync; + var pluginDescriptor = consumer.Metadata.PluginDescriptor; + if (isActive && (resolveAsyncs == null || (resolveAsyncs.Value == isAsync))) { - yield return consumer.Value; + if (pluginDescriptor == null || IsActiveForStore(pluginDescriptor, _services.StoreContext.CurrentStore.Id)) + { + yield return consumer.Value; + } } } } @@ -37,6 +47,29 @@ public bool HasAsyncConsumer return _consumers.Any(c => c.Metadata.IsActive == true && c.Metadata.ExecuteAsync == true); } } + + private bool IsActiveForStore(PluginDescriptor plugin, int storeId) + { + if (storeId == 0) + { + return true; + } + + var limitedToStoresSetting = _services.Settings.GetSettingByKey(plugin.GetSettingKey("LimitedToStores")); + if (limitedToStoresSetting.IsEmpty()) + { + return true; + } + + var limitedToStores = limitedToStoresSetting.ToIntArray(); + if (limitedToStores.Length > 0) + { + var flag = limitedToStores.Contains(storeId); + return flag; + } + + return true; + } } } diff --git a/src/Libraries/SmartStore.Services/Events/EventPublisher.cs b/src/Libraries/SmartStore.Services/Events/EventPublisher.cs index 88bfc4e8cd..fc8b33df35 100644 --- a/src/Libraries/SmartStore.Services/Events/EventPublisher.cs +++ b/src/Libraries/SmartStore.Services/Events/EventPublisher.cs @@ -43,7 +43,7 @@ public void Publish(T eventMessage) // first fire/forget all async consumers if (consumerFactory.HasAsyncConsumer) { - AsyncRunner.Run(c => + AsyncRunner.Run((c, ct) => { // for wiring up dependencies correctly var newFactory = c.Resolve>(); diff --git a/src/Libraries/SmartStore.Services/ExportImport/DataSegmenter.cs b/src/Libraries/SmartStore.Services/ExportImport/DataSegmenter.cs deleted file mode 100644 index 303f12a2c5..0000000000 --- a/src/Libraries/SmartStore.Services/ExportImport/DataSegmenter.cs +++ /dev/null @@ -1,370 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using Fasterflect; -using OfficeOpenXml; -using SmartStore.Core; -using SmartStore.Core.Data; - -namespace SmartStore.Services.ExportImport -{ - - internal class DataSegmenter : DisposableObject where T : BaseEntity - { - private const int BATCHSIZE = 100; - - private ExcelPackage _excelPackage; - private ExcelWorksheet _sheet; - private int _totalRows; - private int _totalColumns; - private readonly string[] _columns; - private readonly IDictionary _properties; - private IList> _currentBatch; - private IPageable _pageable; - private bool _bof; - - public DataSegmenter(Stream source) - { - Guard.ArgumentNotNull(() => source); - - _excelPackage = new ExcelPackage(source); - - // get the first worksheet in the workbook - _sheet = _excelPackage.Workbook.Worksheets.FirstOrDefault(); - if (_sheet == null) - { - throw Error.InvalidOperation("The excel package does not contain any worksheet."); - } - - if (_sheet.Dimension == null) - { - throw Error.InvalidOperation("The excel worksheet does not contain any data."); - } - - _totalColumns = _sheet.Dimension.End.Column; - _totalRows = _sheet.Dimension.End.Row - 1; // excluding 1st - - // Determine column names from 1st row (excel indexes start from 1) - var cols = new List(); - for (int i = 1; i <= _totalColumns; i++) - { - cols.Add(_sheet.Cells[1, i].Text); - } - - _columns = cols.ToArray(); - ValidateColumns(_columns); - _properties = new Dictionary(_columns.Length, StringComparer.InvariantCultureIgnoreCase); - - // determine corresponding Properties for given columns - var t = typeof(T); - foreach (var col in _columns) - { - var pi = t.GetProperty(col); - if (pi != null) - { - _properties[col] = new TargetProperty - { - IsSettable = pi.CanWrite && pi.GetSetMethod().IsPublic, - PropertyInfo = pi - }; - } - } - - _bof = true; - _pageable = new PagedList(0, BATCHSIZE, _totalRows); - } - - public int TotalRows - { - get { return _totalRows; } - } - - public int TotalColumns - { - get { return _totalColumns; } - } - - public int CurrentSegment - { - get { return _bof ? 0 : _pageable.PageNumber; } - } - - public int CurrentSegmentFirstRowIndex - { - get { return _pageable.FirstItemIndex; } - } - - public int TotalSegments - { - get { return _pageable.TotalPages; } - } - - public int BatchSize - { - get { return BATCHSIZE; } - } - - public void Reset() - { - if (_pageable.PageIndex != 0 && _currentBatch != null) - { - _currentBatch.Clear(); - _currentBatch = null; - } - _bof = true; - _pageable.PageIndex = 0; - } - - public bool ReadNextBatch() - { - if (_currentBatch != null) - { - _currentBatch.Clear(); - _currentBatch = null; - } - - if (_bof) - { - _bof = false; - return _pageable.TotalCount > 0; - } - - if (_pageable.HasNextPage) - { - _pageable.PageIndex++; - return true; - } - - Reset(); - return false; - } - - public ICollection> CurrentBatch - { - get - { - if (_currentBatch == null) - { - _currentBatch = new List>(); - - int start = _pageable.FirstItemIndex + 1; - int end = _pageable.LastItemIndex + 1; - - // Determine cell values per row - for (int r = start; r <= end; r++) - { - var values = new List(); - for (int c = 1; c <= _totalColumns; c++) - { - values.Add(_sheet.Cells[r, c].Value); - } - - _currentBatch.Add(new ImportRow(_columns, values.ToArray(), _properties, r - 1)); - } - } - - return _currentBatch.AsReadOnly(); - } - } - - protected override void OnDispose(bool disposing) - { - if (disposing) - { - _sheet = null; - if (_excelPackage != null) - { - _excelPackage.Dispose(); - _excelPackage = null; - } - } - } - - private void ValidateColumns(string[] columns) - { - if (columns.Any(x => x.IsEmpty())) - { - throw Error.InvalidOperation("The first row must contain the column names and therefore cannot have empty cells."); - } - - if (columns.Select(x => x.ToLower()).Distinct().ToArray().Length != columns.Length) - { - throw Error.InvalidOperation("The first row cannot contain duplicate column names."); - } - } - } - - internal class ImportRow : Dictionary where T : BaseEntity - { - private bool _initialized = false; - private T _entity; - private string _entityDisplayName; - private int _position; - private bool _isNew; - private ImportRowInfo _rowInfo; - - public ImportRow(string[] columns, object[] values, IDictionary properties, int position) - : base(columns.Length, StringComparer.InvariantCultureIgnoreCase) - { - _position = position; - - for (int i = 0; i < columns.Length; i++) - { - var col = columns[i]; - var val = values[i]; - - if (val != null && val.ToString().HasValue()) - { - if (!properties.ContainsKey(col) || properties[col].IsSettable) - { - // only add value when no correponding property exists (special field) - // or when property exists but it's publicly settable. - this[col] = val; - } - } - } - } - - public void Initialize(T entity, string entityDisplayName) - { - _entity = entity; - _entityDisplayName = entityDisplayName; - _isNew = _entity.Id == 0; - - _initialized = true; - } - - private void CheckInitialized() - { - if (_initialized) - { - throw Error.InvalidOperation("A row must be initialized before interacting with the entity or the data store"); - } - } - - public bool IsTransient - { - get { return _entity.Id == 0; } - } - - public bool IsNew - { - get { return _isNew; } - } - - public T Entity - { - get { return _entity; } - } - - public string EntityDisplayName - { - get { return _entityDisplayName; } - } - - public bool NameChanged - { - get; - set; - } - - public int Position - { - get { return _position; } - } - - public TProp GetValue(string columnName) - { - object value; - if (this.TryGetValue(columnName, out value)) - { - return value.Convert(); - } - - return default(TProp); - } - - public bool SetProperty(ImportResult result, T target, Expression> prop, TProp defaultValue = default(TProp), Func converter = null) - { - // TBD: (MC) do not check for perf reason? - //CheckInitialized(); - - var pi = prop.ExtractPropertyInfo(); - var propName = pi.Name; - - try - { - object value; - if (this.TryGetValue(propName, out value)) - { - // source contains field value. Set it. - TProp converted; - if (converter != null) - { - converted = converter(value); - } - else - { - if (value.ToString().ToUpper().Equals("NULL")) - { - // prop is set "explicitly" to null. - converted = default(TProp); - } - else - { - converted = value.Convert(); - } - } - return target.TrySetPropertyValue(propName, converted); - } - else - { - // source does not contain field data or it's empty... - if (IsTransient && defaultValue != null) - { - // ...but the entity is new. In this case - // set the default value if given. - return target.TrySetPropertyValue(propName, defaultValue); - } - } - } - catch (Exception ex) - { - result.AddWarning("Conversion failed: " + ex.Message, this.GetRowInfo(), propName); - } - - return false; - } - - public ImportRowInfo GetRowInfo() - { - if (_rowInfo == null) - { - _rowInfo = new ImportRowInfo(this.Position, this.EntityDisplayName); - } - - return _rowInfo; - } - - public override string ToString() - { - var str = "Pos: {0} - Name: {1}, IsNew: {2}, IsTransient: {3}".FormatCurrent( - Position, - EntityDisplayName.EmptyNull(), - _initialized ? IsNew.ToString() : "-", - _initialized ? IsTransient.ToString() : "-"); - return str; - } - } - - - internal class TargetProperty - { - public bool IsSettable { get; set; } - public PropertyInfo PropertyInfo { get; set; } - } -} diff --git a/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs deleted file mode 100644 index 2f48ee0290..0000000000 --- a/src/Libraries/SmartStore.Services/ExportImport/ExportManager.cs +++ /dev/null @@ -1,1680 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Text; -using System.Xml; -using SmartStore.Core; -using SmartStore.Core.Domain; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Orders; -using SmartStore.Services.Catalog; -using SmartStore.Services.Common; -using SmartStore.Services.Customers; -using SmartStore.Services.Media; -using SmartStore.Services.Messages; -using SmartStore.Services.Seo; -using OfficeOpenXml; -using OfficeOpenXml.Style; - -namespace SmartStore.Services.ExportImport -{ - /// - /// Export manager - /// - public partial class ExportManager : IExportManager - { - #region Fields - - private readonly ICategoryService _categoryService; - private readonly IManufacturerService _manufacturerService; - private readonly IProductService _productService; - private readonly IPictureService _pictureService; - private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService; - - #endregion - - #region Ctor - - public ExportManager(ICategoryService categoryService, - IManufacturerService manufacturerService, - IProductService productService, - IPictureService pictureService, - INewsLetterSubscriptionService newsLetterSubscriptionService) - { - this._categoryService = categoryService; - this._manufacturerService = manufacturerService; - this._productService = productService; - this._pictureService = pictureService; - this._newsLetterSubscriptionService = newsLetterSubscriptionService; - } - - #endregion - - #region Utilities - - protected virtual void WriteCategories(XmlWriter xmlWriter, int parentCategoryId) - { - var categories = _categoryService.GetAllCategoriesByParentCategoryId(parentCategoryId, true); - if (categories != null && categories.Count > 0) - { - foreach (var category in categories) - { - xmlWriter.WriteStartElement("Category"); - xmlWriter.WriteElementString("Id", null, category.Id.ToString()); - xmlWriter.WriteElementString("Name", null, category.Name); - xmlWriter.WriteElementString("Description", null, category.Description); - xmlWriter.WriteElementString("CategoryTemplateId", null, category.CategoryTemplateId.ToString()); - xmlWriter.WriteElementString("MetaKeywords", null, category.MetaKeywords); - xmlWriter.WriteElementString("MetaDescription", null, category.MetaDescription); - xmlWriter.WriteElementString("MetaTitle", null, category.MetaTitle); - xmlWriter.WriteElementString("SeName", null, category.GetSeName(0)); - xmlWriter.WriteElementString("ParentCategoryId", null, category.ParentCategoryId.ToString()); - xmlWriter.WriteElementString("PictureId", null, category.PictureId.ToString()); - xmlWriter.WriteElementString("PageSize", null, category.PageSize.ToString()); - xmlWriter.WriteElementString("AllowCustomersToSelectPageSize", null, category.AllowCustomersToSelectPageSize.ToString()); - xmlWriter.WriteElementString("PageSizeOptions", null, category.PageSizeOptions); - xmlWriter.WriteElementString("PriceRanges", null, category.PriceRanges); - xmlWriter.WriteElementString("ShowOnHomePage", null, category.ShowOnHomePage.ToString()); - xmlWriter.WriteElementString("Published", null, category.Published.ToString()); - xmlWriter.WriteElementString("Deleted", null, category.Deleted.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, category.DisplayOrder.ToString()); - xmlWriter.WriteElementString("CreatedOnUtc", null, category.CreatedOnUtc.ToString()); - xmlWriter.WriteElementString("UpdatedOnUtc", null, category.UpdatedOnUtc.ToString()); - - - xmlWriter.WriteStartElement("Products"); - var productCategories = _categoryService.GetProductCategoriesByCategoryId(category.Id, 0, int.MaxValue, true); - foreach (var productCategory in productCategories) - { - var product = productCategory.Product; - if (product != null && !product.Deleted) - { - xmlWriter.WriteStartElement("ProductCategory"); - xmlWriter.WriteElementString("ProductCategoryId", null, productCategory.Id.ToString()); - xmlWriter.WriteElementString("ProductId", null, productCategory.ProductId.ToString()); - xmlWriter.WriteElementString("IsFeaturedProduct", null, productCategory.IsFeaturedProduct.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productCategory.DisplayOrder.ToString()); - xmlWriter.WriteEndElement(); - } - } - xmlWriter.WriteEndElement(); - - xmlWriter.WriteStartElement("SubCategories"); - WriteCategories(xmlWriter, category.Id); - xmlWriter.WriteEndElement(); - xmlWriter.WriteEndElement(); - } - } - } - - #endregion - - #region Methods - - /// - /// Export manufacturer list to xml - /// - /// Manufacturers - /// Result in XML format - public virtual string ExportManufacturersToXml(IList manufacturers) - { - var sb = new StringBuilder(); - var stringWriter = new StringWriter(sb); - var xmlWriter = new XmlTextWriter(stringWriter); - xmlWriter.WriteStartDocument(); - xmlWriter.WriteStartElement("Manufacturers"); - xmlWriter.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); - - foreach (var manufacturer in manufacturers) - { - xmlWriter.WriteStartElement("Manufacturer"); - - xmlWriter.WriteElementString("ManufacturerId", null, manufacturer.Id.ToString()); - xmlWriter.WriteElementString("Name", null, manufacturer.Name); - xmlWriter.WriteElementString("Description", null, manufacturer.Description); - xmlWriter.WriteElementString("ManufacturerTemplateId", null, manufacturer.ManufacturerTemplateId.ToString()); - xmlWriter.WriteElementString("MetaKeywords", null, manufacturer.MetaKeywords); - xmlWriter.WriteElementString("MetaDescription", null, manufacturer.MetaDescription); - xmlWriter.WriteElementString("MetaTitle", null, manufacturer.MetaTitle); - xmlWriter.WriteElementString("SEName", null, manufacturer.GetSeName(0)); - xmlWriter.WriteElementString("PictureId", null, manufacturer.PictureId.ToString()); - xmlWriter.WriteElementString("PageSize", null, manufacturer.PageSize.ToString()); - xmlWriter.WriteElementString("AllowCustomersToSelectPageSize", null, manufacturer.AllowCustomersToSelectPageSize.ToString()); - xmlWriter.WriteElementString("PageSizeOptions", null, manufacturer.PageSizeOptions); - xmlWriter.WriteElementString("PriceRanges", null, manufacturer.PriceRanges); - xmlWriter.WriteElementString("Published", null, manufacturer.Published.ToString()); - xmlWriter.WriteElementString("Deleted", null, manufacturer.Deleted.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, manufacturer.DisplayOrder.ToString()); - xmlWriter.WriteElementString("CreatedOnUtc", null, manufacturer.CreatedOnUtc.ToString()); - xmlWriter.WriteElementString("UpdatedOnUtc", null, manufacturer.UpdatedOnUtc.ToString()); - - xmlWriter.WriteStartElement("Products"); - var productManufacturers = _manufacturerService.GetProductManufacturersByManufacturerId(manufacturer.Id, 0, int.MaxValue, true); - if (productManufacturers != null) - { - foreach (var productManufacturer in productManufacturers) - { - var product = productManufacturer.Product; - if (product != null && !product.Deleted) - { - xmlWriter.WriteStartElement("ProductManufacturer"); - xmlWriter.WriteElementString("ProductManufacturerId", null, productManufacturer.Id.ToString()); - xmlWriter.WriteElementString("ProductId", null, productManufacturer.ProductId.ToString()); - xmlWriter.WriteElementString("IsFeaturedProduct", null, productManufacturer.IsFeaturedProduct.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productManufacturer.DisplayOrder.ToString()); - xmlWriter.WriteEndElement(); - } - } - } - xmlWriter.WriteEndElement(); - - - xmlWriter.WriteEndElement(); - } - - xmlWriter.WriteEndElement(); - xmlWriter.WriteEndDocument(); - xmlWriter.Close(); - return stringWriter.ToString(); - } - - /// - /// Export category list to xml - /// - /// Result in XML format - public virtual string ExportCategoriesToXml() - { - var sb = new StringBuilder(); - var stringWriter = new StringWriter(sb); - var xmlWriter = new XmlTextWriter(stringWriter); - xmlWriter.WriteStartDocument(); - xmlWriter.WriteStartElement("Categories"); - xmlWriter.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); - WriteCategories(xmlWriter, 0); - xmlWriter.WriteEndElement(); - xmlWriter.WriteEndDocument(); - xmlWriter.Close(); - return stringWriter.ToString(); - } - - /// - /// Export product list to xml - /// - /// Products - /// Result in XML format - public virtual string ExportProductsToXml(IList products) - { - var sb = new StringBuilder(); - var stringWriter = new StringWriter(sb); - var xmlWriter = new XmlTextWriter(stringWriter); - xmlWriter.WriteStartDocument(); - xmlWriter.WriteStartElement("Products"); - xmlWriter.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); - - foreach (var product in products) - { - xmlWriter.WriteStartElement("Product"); - - xmlWriter.WriteElementString("ProductId", null, product.Id.ToString()); - xmlWriter.WriteElementString("ProductTypeId", null, product.ProductTypeId.ToString()); - xmlWriter.WriteElementString("ParentGroupedProductId", null, product.ParentGroupedProductId.ToString()); - xmlWriter.WriteElementString("VisibleIndividually", null, product.VisibleIndividually.ToString()); - xmlWriter.WriteElementString("Name", null, product.Name); - xmlWriter.WriteElementString("ShortDescription", null, product.ShortDescription); - xmlWriter.WriteElementString("FullDescription", null, product.FullDescription.RemoveInvalidXmlChars()); - xmlWriter.WriteElementString("AdminComment", null, product.AdminComment); - xmlWriter.WriteElementString("ProductTemplateId", null, product.ProductTemplateId.ToString()); - xmlWriter.WriteElementString("ShowOnHomePage", null, product.ShowOnHomePage.ToString()); - xmlWriter.WriteElementString("MetaKeywords", null, product.MetaKeywords); - xmlWriter.WriteElementString("MetaDescription", null, product.MetaDescription); - xmlWriter.WriteElementString("MetaTitle", null, product.MetaTitle); - xmlWriter.WriteElementString("SEName", null, product.GetSeName(0)); - xmlWriter.WriteElementString("AllowCustomerReviews", null, product.AllowCustomerReviews.ToString()); - xmlWriter.WriteElementString("SKU", null, product.Sku); - xmlWriter.WriteElementString("ManufacturerPartNumber", null, product.ManufacturerPartNumber); - xmlWriter.WriteElementString("Gtin", null, product.Gtin); - xmlWriter.WriteElementString("IsGiftCard", null, product.IsGiftCard.ToString()); - xmlWriter.WriteElementString("GiftCardType", null, product.GiftCardType.ToString()); - xmlWriter.WriteElementString("RequireOtherProducts", null, product.RequireOtherProducts.ToString()); - xmlWriter.WriteElementString("RequiredProductIds", null, product.RequiredProductIds); - xmlWriter.WriteElementString("AutomaticallyAddRequiredProducts", null, product.AutomaticallyAddRequiredProducts.ToString()); - xmlWriter.WriteElementString("IsDownload", null, product.IsDownload.ToString()); - xmlWriter.WriteElementString("DownloadId", null, product.DownloadId.ToString()); - xmlWriter.WriteElementString("UnlimitedDownloads", null, product.UnlimitedDownloads.ToString()); - xmlWriter.WriteElementString("MaxNumberOfDownloads", null, product.MaxNumberOfDownloads.ToString()); - if (product.DownloadExpirationDays.HasValue) - xmlWriter.WriteElementString("DownloadExpirationDays", null, product.DownloadExpirationDays.ToString()); - else - xmlWriter.WriteElementString("DownloadExpirationDays", null, string.Empty); - xmlWriter.WriteElementString("DownloadActivationType", null, product.DownloadActivationType.ToString()); - xmlWriter.WriteElementString("HasSampleDownload", null, product.HasSampleDownload.ToString()); - xmlWriter.WriteElementString("SampleDownloadId", null, product.SampleDownloadId.ToString()); - xmlWriter.WriteElementString("HasUserAgreement", null, product.HasUserAgreement.ToString()); - xmlWriter.WriteElementString("UserAgreementText", null, product.UserAgreementText); - xmlWriter.WriteElementString("IsRecurring", null, product.IsRecurring.ToString()); - xmlWriter.WriteElementString("RecurringCycleLength", null, product.RecurringCycleLength.ToString()); - xmlWriter.WriteElementString("RecurringCyclePeriodId", null, product.RecurringCyclePeriodId.ToString()); - xmlWriter.WriteElementString("RecurringTotalCycles", null, product.RecurringTotalCycles.ToString()); - xmlWriter.WriteElementString("IsShipEnabled", null, product.IsShipEnabled.ToString()); - xmlWriter.WriteElementString("IsFreeShipping", null, product.IsFreeShipping.ToString()); - xmlWriter.WriteElementString("AdditionalShippingCharge", null, product.AdditionalShippingCharge.ToString()); - xmlWriter.WriteElementString("IsTaxExempt", null, product.IsTaxExempt.ToString()); - xmlWriter.WriteElementString("TaxCategoryId", null, product.TaxCategoryId.ToString()); - xmlWriter.WriteElementString("ManageInventoryMethodId", null, product.ManageInventoryMethodId.ToString()); - xmlWriter.WriteElementString("StockQuantity", null, product.StockQuantity.ToString()); - xmlWriter.WriteElementString("DisplayStockAvailability", null, product.DisplayStockAvailability.ToString()); - xmlWriter.WriteElementString("DisplayStockQuantity", null, product.DisplayStockQuantity.ToString()); - xmlWriter.WriteElementString("MinStockQuantity", null, product.MinStockQuantity.ToString()); - xmlWriter.WriteElementString("LowStockActivityId", null, product.LowStockActivityId.ToString()); - xmlWriter.WriteElementString("NotifyAdminForQuantityBelow", null, product.NotifyAdminForQuantityBelow.ToString()); - xmlWriter.WriteElementString("BackorderModeId", null, product.BackorderModeId.ToString()); - xmlWriter.WriteElementString("AllowBackInStockSubscriptions", null, product.AllowBackInStockSubscriptions.ToString()); - xmlWriter.WriteElementString("OrderMinimumQuantity", null, product.OrderMinimumQuantity.ToString()); - xmlWriter.WriteElementString("OrderMaximumQuantity", null, product.OrderMaximumQuantity.ToString()); - xmlWriter.WriteElementString("AllowedQuantities", null, product.AllowedQuantities); - xmlWriter.WriteElementString("DisableBuyButton", null, product.DisableBuyButton.ToString()); - xmlWriter.WriteElementString("DisableWishlistButton", null, product.DisableWishlistButton.ToString()); - xmlWriter.WriteElementString("AvailableForPreOrder", null, product.AvailableForPreOrder.ToString()); - xmlWriter.WriteElementString("CallForPrice", null, product.CallForPrice.ToString()); - xmlWriter.WriteElementString("Price", null, product.Price.ToString()); - xmlWriter.WriteElementString("OldPrice", null, product.OldPrice.ToString()); - xmlWriter.WriteElementString("ProductCost", null, product.ProductCost.ToString()); - xmlWriter.WriteElementString("SpecialPrice", null, product.SpecialPrice.HasValue ? product.SpecialPrice.ToString() : ""); - xmlWriter.WriteElementString("SpecialPriceStartDateTimeUtc", null, product.SpecialPriceStartDateTimeUtc.HasValue ? product.SpecialPriceStartDateTimeUtc.ToString() : ""); - xmlWriter.WriteElementString("SpecialPriceEndDateTimeUtc", null, product.SpecialPriceEndDateTimeUtc.HasValue ? product.SpecialPriceEndDateTimeUtc.ToString() : ""); - xmlWriter.WriteElementString("CustomerEntersPrice", null, product.CustomerEntersPrice.ToString()); - xmlWriter.WriteElementString("MinimumCustomerEnteredPrice", null, product.MinimumCustomerEnteredPrice.ToString()); - xmlWriter.WriteElementString("MaximumCustomerEnteredPrice", null, product.MaximumCustomerEnteredPrice.ToString()); - xmlWriter.WriteElementString("LowestAttributeCombinationPrice", null, product.LowestAttributeCombinationPrice.HasValue ? product.LowestAttributeCombinationPrice.ToString() : ""); - xmlWriter.WriteElementString("Weight", null, product.Weight.ToString()); - xmlWriter.WriteElementString("Length", null, product.Length.ToString()); - xmlWriter.WriteElementString("Width", null, product.Width.ToString()); - xmlWriter.WriteElementString("Height", null, product.Height.ToString()); - xmlWriter.WriteElementString("Published", null, product.Published.ToString()); - xmlWriter.WriteElementString("CreatedOnUtc", null, product.CreatedOnUtc.ToString()); - xmlWriter.WriteElementString("UpdatedOnUtc", null, product.UpdatedOnUtc.ToString()); - - if (product.DeliveryTimeId.HasValue) - xmlWriter.WriteElementString("DeliveryTimeId", null, product.DeliveryTimeId.Value.ToString()); - xmlWriter.WriteElementString("BasePriceEnabled", null, product.BasePriceEnabled.ToString()); - xmlWriter.WriteElementString("BasePriceMeasureUnit", null, product.BasePriceMeasureUnit); - if (product.BasePriceAmount.HasValue) - xmlWriter.WriteElementString("BasePriceAmount", null, product.BasePriceAmount.Value.ToString()); - if (product.BasePriceBaseAmount.HasValue) - xmlWriter.WriteElementString("BasePriceBaseAmount", null, product.BasePriceBaseAmount.Value.ToString()); - - xmlWriter.WriteElementString("BundleTitleText", null, product.BundleTitleText); - xmlWriter.WriteElementString("BundlePerItemShipping", null, product.BundlePerItemShipping.ToString()); - xmlWriter.WriteElementString("BundlePerItemPricing", null, product.BundlePerItemPricing.ToString()); - xmlWriter.WriteElementString("BundlePerItemShoppingCart", null, product.BundlePerItemShoppingCart.ToString()); - - xmlWriter.WriteStartElement("ProductDiscounts"); - var discounts = product.AppliedDiscounts; - foreach (var discount in discounts) - { - xmlWriter.WriteStartElement("ProductDiscount"); - xmlWriter.WriteElementString("DiscountId", null, discount.Id.ToString()); - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - - - xmlWriter.WriteStartElement("TierPrices"); - var tierPrices = product.TierPrices; - foreach (var tierPrice in tierPrices) - { - xmlWriter.WriteStartElement("TierPrice"); - xmlWriter.WriteElementString("TierPriceId", null, tierPrice.Id.ToString()); - xmlWriter.WriteElementString("StoreId", null, tierPrice.StoreId.ToString()); - xmlWriter.WriteElementString("CustomerRoleId", null, tierPrice.CustomerRoleId.HasValue ? tierPrice.CustomerRoleId.ToString() : "0"); - xmlWriter.WriteElementString("Quantity", null, tierPrice.Quantity.ToString()); - xmlWriter.WriteElementString("Price", null, tierPrice.Price.ToString()); - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - - xmlWriter.WriteStartElement("ProductAttributes"); - var productVariantAttributes = product.ProductVariantAttributes; - foreach (var productVariantAttribute in productVariantAttributes) - { - xmlWriter.WriteStartElement("ProductVariantAttribute"); - xmlWriter.WriteElementString("ProductVariantAttributeId", null, productVariantAttribute.Id.ToString()); - xmlWriter.WriteElementString("ProductAttributeId", null, productVariantAttribute.ProductAttributeId.ToString()); - xmlWriter.WriteElementString("TextPrompt", null, productVariantAttribute.TextPrompt); - xmlWriter.WriteElementString("IsRequired", null, productVariantAttribute.IsRequired.ToString()); - xmlWriter.WriteElementString("AttributeControlTypeId", null, productVariantAttribute.AttributeControlTypeId.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productVariantAttribute.DisplayOrder.ToString()); - - xmlWriter.WriteStartElement("ProductVariantAttributeValues"); - var productVariantAttributeValues = productVariantAttribute.ProductVariantAttributeValues; - foreach (var productVariantAttributeValue in productVariantAttributeValues) - { - xmlWriter.WriteStartElement("ProductVariantAttributeValue"); - xmlWriter.WriteElementString("ProductVariantAttributeValueId", null, productVariantAttributeValue.Id.ToString()); - xmlWriter.WriteElementString("Name", null, productVariantAttributeValue.Name); - xmlWriter.WriteElementString("PriceAdjustment", null, productVariantAttributeValue.PriceAdjustment.ToString()); - xmlWriter.WriteElementString("WeightAdjustment", null, productVariantAttributeValue.WeightAdjustment.ToString()); - xmlWriter.WriteElementString("IsPreSelected", null, productVariantAttributeValue.IsPreSelected.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productVariantAttributeValue.DisplayOrder.ToString()); - xmlWriter.WriteElementString("ValueTypeId", null, productVariantAttributeValue.ValueTypeId.ToString()); - xmlWriter.WriteElementString("LinkedProductId", null, productVariantAttributeValue.LinkedProductId.ToString()); - xmlWriter.WriteElementString("Quantity", null, productVariantAttributeValue.Quantity.ToString()); - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); // ProductAttributes - - xmlWriter.WriteStartElement("ProductVariantAttributeCombinations"); - var combinations = product.ProductVariantAttributeCombinations; - foreach (var combination in combinations) - { - xmlWriter.WriteStartElement("ProductVariantAttributeCombination"); - xmlWriter.WriteElementString("ProductVariantAttributeCombinationId", null, combination.Id.ToString()); - xmlWriter.WriteElementString("AllowOutOfStockOrders", null, combination.AllowOutOfStockOrders.ToString()); - xmlWriter.WriteElementString("StockQuantity", null, combination.StockQuantity.ToString()); - xmlWriter.WriteElementString("AssignedPictureIds", null, combination.AssignedPictureIds); - xmlWriter.WriteStartElement("AttributesXml"); - xmlWriter.WriteCData(combination.AttributesXml); - xmlWriter.WriteEndElement(); // AttributesXml - xmlWriter.WriteElementString("IsActive", null, combination.IsActive.ToString()); - //xmlWriter.WriteElementString("IsDefaultCombination", null, combination.IsDefaultCombination.ToString()); - if (combination.BasePriceAmount.HasValue) - xmlWriter.WriteElementString("BasePriceAmount", null, combination.BasePriceAmount.Value.ToString()); - if (combination.BasePriceBaseAmount.HasValue) - xmlWriter.WriteElementString("BasePriceBaseAmount", null, combination.BasePriceBaseAmount.Value.ToString()); - if (combination.DeliveryTimeId.HasValue) - xmlWriter.WriteElementString("DeliveryTimeId", null, combination.DeliveryTimeId.Value.ToString()); - if (combination.Length.HasValue) - xmlWriter.WriteElementString("Length", null, combination.Length.Value.ToString()); - if (combination.Width.HasValue) - xmlWriter.WriteElementString("Width", null, combination.Width.Value.ToString()); - if (combination.Height.HasValue) - xmlWriter.WriteElementString("Height", null, combination.Height.Value.ToString()); - if (combination.Height.HasValue) - xmlWriter.WriteElementString("Height", null, combination.Height.Value.ToString()); - if (combination.Gtin.HasValue()) - xmlWriter.WriteElementString("Gtin", null, combination.Gtin); - if (combination.Sku.HasValue()) - xmlWriter.WriteElementString("Sku", null, combination.Sku); - if (combination.ManufacturerPartNumber.HasValue()) - xmlWriter.WriteElementString("ManufacturerPartNumber", null, combination.ManufacturerPartNumber); - if (combination.Price.HasValue) - xmlWriter.WriteElementString("Price", null, combination.Price.Value.ToString()); - - xmlWriter.WriteEndElement(); // ProductVariantAttributeCombination - } - xmlWriter.WriteEndElement(); // ProductVariantAttributeCombinations - - xmlWriter.WriteStartElement("ProductPictures"); - var productPictures = product.ProductPictures; - foreach (var productPicture in productPictures) - { - xmlWriter.WriteStartElement("ProductPicture"); - xmlWriter.WriteElementString("ProductPictureId", null, productPicture.Id.ToString()); - xmlWriter.WriteElementString("PictureId", null, productPicture.PictureId.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productPicture.DisplayOrder.ToString()); - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - - xmlWriter.WriteStartElement("ProductCategories"); - var productCategories = _categoryService.GetProductCategoriesByProductId(product.Id); - if (productCategories != null) - { - foreach (var productCategory in productCategories) - { - xmlWriter.WriteStartElement("ProductCategory"); - xmlWriter.WriteElementString("ProductCategoryId", null, productCategory.Id.ToString()); - xmlWriter.WriteElementString("CategoryId", null, productCategory.CategoryId.ToString()); - xmlWriter.WriteElementString("IsFeaturedProduct", null, productCategory.IsFeaturedProduct.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productCategory.DisplayOrder.ToString()); - xmlWriter.WriteEndElement(); - } - } - xmlWriter.WriteEndElement(); - - xmlWriter.WriteStartElement("ProductManufacturers"); - var productManufacturers = _manufacturerService.GetProductManufacturersByProductId(product.Id); - if (productManufacturers != null) - { - foreach (var productManufacturer in productManufacturers) - { - xmlWriter.WriteStartElement("ProductManufacturer"); - xmlWriter.WriteElementString("ProductManufacturerId", null, productManufacturer.Id.ToString()); - xmlWriter.WriteElementString("ManufacturerId", null, productManufacturer.ManufacturerId.ToString()); - xmlWriter.WriteElementString("IsFeaturedProduct", null, productManufacturer.IsFeaturedProduct.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productManufacturer.DisplayOrder.ToString()); - xmlWriter.WriteEndElement(); - } - } - xmlWriter.WriteEndElement(); - - xmlWriter.WriteStartElement("ProductSpecificationAttributes"); - var productSpecificationAttributes = product.ProductSpecificationAttributes; - foreach (var productSpecificationAttribute in productSpecificationAttributes) - { - xmlWriter.WriteStartElement("ProductSpecificationAttribute"); - xmlWriter.WriteElementString("ProductSpecificationAttributeId", null, productSpecificationAttribute.Id.ToString()); - xmlWriter.WriteElementString("SpecificationAttributeOptionId", null, productSpecificationAttribute.SpecificationAttributeOptionId.ToString()); - xmlWriter.WriteElementString("AllowFiltering", null, productSpecificationAttribute.AllowFiltering.ToString()); - xmlWriter.WriteElementString("ShowOnProductPage", null, productSpecificationAttribute.ShowOnProductPage.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, productSpecificationAttribute.DisplayOrder.ToString()); - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - - xmlWriter.WriteStartElement("ProductBundleItems"); - var bundleItems = _productService.GetBundleItems(product.Id, true); - foreach (var bundleItem in bundleItems.Select(x => x.Item)) - { - xmlWriter.WriteStartElement("ProductBundleItem"); - - xmlWriter.WriteElementString("ProductId", null, bundleItem.ProductId.ToString()); - xmlWriter.WriteElementString("BundleProductId", null, bundleItem.BundleProductId.ToString()); - xmlWriter.WriteElementString("Quantity", null, bundleItem.Quantity.ToString()); - if (bundleItem.Discount.HasValue) - xmlWriter.WriteElementString("Discount", null, bundleItem.Discount.Value.ToString()); - xmlWriter.WriteElementString("DiscountPercentage", null, bundleItem.DiscountPercentage.ToString()); - xmlWriter.WriteElementString("Name", null, bundleItem.GetLocalizedName()); - xmlWriter.WriteElementString("ShortDescription", null, bundleItem.ShortDescription); - xmlWriter.WriteElementString("FilterAttributes", null, bundleItem.FilterAttributes.ToString()); - xmlWriter.WriteElementString("HideThumbnail", null, bundleItem.HideThumbnail.ToString()); - xmlWriter.WriteElementString("Visible", null, bundleItem.Visible.ToString()); - xmlWriter.WriteElementString("Published", null, bundleItem.Published.ToString()); - xmlWriter.WriteElementString("DisplayOrder", null, bundleItem.DisplayOrder.ToString()); - xmlWriter.WriteElementString("CreatedOnUtc", null, bundleItem.CreatedOnUtc.ToString()); - xmlWriter.WriteElementString("UpdatedOnUtc", null, bundleItem.UpdatedOnUtc.ToString()); - - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - - - - xmlWriter.WriteEndElement(); - } - - xmlWriter.WriteEndElement(); - xmlWriter.WriteEndDocument(); - xmlWriter.Close(); - return stringWriter.ToString(); - } - - /// - /// Export products to XLSX - /// - /// Stream - /// Products - public virtual void ExportProductsToXlsx(Stream stream, IList products) - { - if (stream == null) - throw new ArgumentNullException("stream"); - - // ok, we can run the real code of the sample now - using (var xlPackage = new ExcelPackage(stream)) - { - // uncomment this line if you want the XML written out to the outputDir - //xlPackage.DebugMode = true; - - // get handle to the existing worksheet - var worksheet = xlPackage.Workbook.Worksheets.Add("Products"); - - // get handle to the cells range of the worksheet - var cells = worksheet.Cells; - - //Create Headers and format them - var properties = new string[] - { - "ProductTypeId", - "ParentGroupedProductId", - "VisibleIndividually", - "Name", - "ShortDescription", - "FullDescription", - "ProductTemplateId", - "ShowOnHomePage", - "MetaKeywords", - "MetaDescription", - "MetaTitle", - "SeName", - "AllowCustomerReviews", - "Published", - "SKU", - "ManufacturerPartNumber", - "Gtin", - "IsGiftCard", - "GiftCardTypeId", - "RequireOtherProducts", - "RequiredProductIds", - "AutomaticallyAddRequiredProducts", - "IsDownload", - "DownloadId", - "UnlimitedDownloads", - "MaxNumberOfDownloads", - "DownloadActivationTypeId", - "HasSampleDownload", - "SampleDownloadId", - "HasUserAgreement", - "UserAgreementText", - "IsRecurring", - "RecurringCycleLength", - "RecurringCyclePeriodId", - "RecurringTotalCycles", - "IsShipEnabled", - "IsFreeShipping", - "AdditionalShippingCharge", - "IsTaxExempt", - "TaxCategoryId", - "ManageInventoryMethodId", - "StockQuantity", - "DisplayStockAvailability", - "DisplayStockQuantity", - "MinStockQuantity", - "LowStockActivityId", - "NotifyAdminForQuantityBelow", - "BackorderModeId", - "AllowBackInStockSubscriptions", - "OrderMinimumQuantity", - "OrderMaximumQuantity", - "AllowedQuantities", - "DisableBuyButton", - "DisableWishlistButton", - "AvailableForPreOrder", - "CallForPrice", - "Price", - "OldPrice", - "ProductCost", - "SpecialPrice", - "SpecialPriceStartDateTimeUtc", - "SpecialPriceEndDateTimeUtc", - "CustomerEntersPrice", - "MinimumCustomerEnteredPrice", - "MaximumCustomerEnteredPrice", - "Weight", - "Length", - "Width", - "Height", - "CreatedOnUtc", - "CategoryIds", - "ManufacturerIds", - "Picture1", - "Picture2", - "Picture3", - "DeliveryTimeId", // codehint: sm-add (following) - "BasePriceEnabled", - "BasePriceMeasureUnit", - "BasePriceAmount", - "BasePriceBaseAmount", - "BundleTitleText", - "BundlePerItemShipping", - "BundlePerItemPricing", - "BundlePerItemShoppingCart", - "BundleItemSkus" - }; - for (int i = 0; i < properties.Length; i++) - { - cells[1, i + 1].Value = properties[i]; - cells[1, i + 1].Style.Fill.PatternType = ExcelFillStyle.Solid; - cells[1, i + 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228)); - cells[1, i + 1].Style.Font.Bold = true; - } - - - int row = 2; - foreach (var p in products) - { - int col = 1; - - cells[row, col].Value = p.ProductTypeId; - col++; - - cells[row, col].Value = p.ParentGroupedProductId; - col++; - - cells[row, col].Value = p.VisibleIndividually; - col++; - - cells[row, col].Value = p.Name; - col++; - - cells[row, col].Value = p.ShortDescription; - col++; - - cells[row, col].Value = p.FullDescription; - col++; - - cells[row, col].Value = p.ProductTemplateId; - col++; - - cells[row, col].Value = p.ShowOnHomePage; - col++; - - cells[row, col].Value = p.MetaKeywords; - col++; - - cells[row, col].Value = p.MetaDescription; - col++; - - cells[row, col].Value = p.MetaTitle; - col++; - - cells[row, col].Value = p.GetSeName(0); - col++; - - cells[row, col].Value = p.AllowCustomerReviews; - col++; - - cells[row, col].Value = p.Published; - col++; - - cells[row, col].Value = p.Sku; - col++; - - cells[row, col].Value = p.ManufacturerPartNumber; - col++; - - cells[row, col].Value = p.Gtin; - col++; - - cells[row, col].Value = p.IsGiftCard; - col++; - - cells[row, col].Value = p.GiftCardTypeId; - col++; - - cells[row, col].Value = p.RequireOtherProducts; - col++; - - cells[row, col].Value = p.RequiredProductIds; - col++; - - cells[row, col].Value = p.AutomaticallyAddRequiredProducts; - col++; - - cells[row, col].Value = p.IsDownload; - col++; - - cells[row, col].Value = p.DownloadId; - col++; - - cells[row, col].Value = p.UnlimitedDownloads; - col++; - - cells[row, col].Value = p.MaxNumberOfDownloads; - col++; - - cells[row, col].Value = p.DownloadActivationTypeId; - col++; - - cells[row, col].Value = p.HasSampleDownload; - col++; - - cells[row, col].Value = p.SampleDownloadId; - col++; - - cells[row, col].Value = p.HasUserAgreement; - col++; - - cells[row, col].Value = p.UserAgreementText; - col++; - - cells[row, col].Value = p.IsRecurring; - col++; - - cells[row, col].Value = p.RecurringCycleLength; - col++; - - cells[row, col].Value = p.RecurringCyclePeriodId; - col++; - - cells[row, col].Value = p.RecurringTotalCycles; - col++; - - cells[row, col].Value = p.IsShipEnabled; - col++; - - cells[row, col].Value = p.IsFreeShipping; - col++; - - cells[row, col].Value = p.AdditionalShippingCharge; - col++; - - cells[row, col].Value = p.IsTaxExempt; - col++; - - cells[row, col].Value = p.TaxCategoryId; - col++; - - cells[row, col].Value = p.ManageInventoryMethodId; - col++; - - cells[row, col].Value = p.StockQuantity; - col++; - - cells[row, col].Value = p.DisplayStockAvailability; - col++; - - cells[row, col].Value = p.DisplayStockQuantity; - col++; - - cells[row, col].Value = p.MinStockQuantity; - col++; - - cells[row, col].Value = p.LowStockActivityId; - col++; - - cells[row, col].Value = p.NotifyAdminForQuantityBelow; - col++; - - cells[row, col].Value = p.BackorderModeId; - col++; - - cells[row, col].Value = p.AllowBackInStockSubscriptions; - col++; - - cells[row, col].Value = p.OrderMinimumQuantity; - col++; - - cells[row, col].Value = p.OrderMaximumQuantity; - col++; - - cells[row, col].Value = p.AllowedQuantities; - col++; - - cells[row, col].Value = p.DisableBuyButton; - col++; - - cells[row, col].Value = p.DisableWishlistButton; - col++; - - cells[row, col].Value = p.AvailableForPreOrder; - col++; - - cells[row, col].Value = p.CallForPrice; - col++; - - cells[row, col].Value = p.Price; - col++; - - cells[row, col].Value = p.OldPrice; - col++; - - cells[row, col].Value = p.ProductCost; - col++; - - cells[row, col].Value = p.SpecialPrice; - col++; - - cells[row, col].Value = p.SpecialPriceStartDateTimeUtc; - col++; - - cells[row, col].Value = p.SpecialPriceEndDateTimeUtc; - col++; - - cells[row, col].Value = p.CustomerEntersPrice; - col++; - - cells[row, col].Value = p.MinimumCustomerEnteredPrice; - col++; - - cells[row, col].Value = p.MaximumCustomerEnteredPrice; - col++; - - cells[row, col].Value = p.Weight; - col++; - - cells[row, col].Value = p.Length; - col++; - - cells[row, col].Value = p.Width; - col++; - - cells[row, col].Value = p.Height; - col++; - - cells[row, col].Value = p.CreatedOnUtc.ToOADate(); - col++; - - //category identifiers - string categoryIds = null; - foreach (var pc in _categoryService.GetProductCategoriesByProductId(p.Id)) - { - categoryIds += pc.CategoryId; - categoryIds += ";"; - } - cells[row, col].Value = categoryIds; - col++; - - //manufacturer identifiers - string manufacturerIds = null; - foreach (var pm in _manufacturerService.GetProductManufacturersByProductId(p.Id)) - { - manufacturerIds += pm.ManufacturerId; - manufacturerIds += ";"; - } - cells[row, col].Value = manufacturerIds; - col++; - - //pictures (up to 3 pictures) - string picture1 = null; - string picture2 = null; - string picture3 = null; - var pictures = _pictureService.GetPicturesByProductId(p.Id, 3); - for (int i = 0; i < pictures.Count; i++) - { - string pictureLocalPath = _pictureService.GetThumbLocalPath(pictures[i]); - switch (i) - { - case 0: - picture1 = pictureLocalPath; - break; - case 1: - picture2 = pictureLocalPath; - break; - case 2: - picture3 = pictureLocalPath; - break; - } - } - cells[row, col].Value = picture1; - col++; - cells[row, col].Value = picture2; - col++; - cells[row, col].Value = picture3; - col++; - - cells[row, col].Value = p.DeliveryTimeId; - col++; - cells[row, col].Value = p.BasePriceEnabled; - col++; - cells[row, col].Value = p.BasePriceMeasureUnit; - col++; - cells[row, col].Value = p.BasePriceAmount; - col++; - cells[row, col].Value = p.BasePriceBaseAmount; - col++; - - cells[row, col].Value = p.BundleTitleText; - col++; - - cells[row, col].Value = p.BundlePerItemShipping; - col++; - - cells[row, col].Value = p.BundlePerItemPricing; - col++; - - cells[row, col].Value = p.BundlePerItemShoppingCart; - col++; - - string bundleItemSkus = ""; - - if (p.ProductType == ProductType.BundledProduct) - { - bundleItemSkus = string.Join(",", _productService.GetBundleItems(p.Id, true).Select(x => x.Item.Product.Sku)); - } - - cells[row, col].Value = bundleItemSkus; - col++; - - row++; - } - - // we had better add some document properties to the spreadsheet - - // set some core property values - //var storeName = _storeInformationSettings.StoreName; - //var storeUrl = _storeInformationSettings.StoreUrl; - //xlPackage.Workbook.Properties.Title = string.Format("{0} products", storeName); - //xlPackage.Workbook.Properties.Author = storeName; - //xlPackage.Workbook.Properties.Subject = string.Format("{0} products", storeName); - //xlPackage.Workbook.Properties.Keywords = string.Format("{0} products", storeName); - //xlPackage.Workbook.Properties.Category = "Products"; - //xlPackage.Workbook.Properties.Comments = string.Format("{0} products", storeName); - - // set some extended property values - //xlPackage.Workbook.Properties.Company = storeName; - //xlPackage.Workbook.Properties.HyperlinkBase = new Uri(storeUrl); - - // save the new spreadsheet - xlPackage.Save(); - } - - // EPPLus has serious memory leak problems. - // We enforce the garbage collector to release unused memory, - // it's not perfect, but better than nothing. - GC.Collect(); - } - - /// - /// Export order list to xml - /// - /// Orders - /// Result in XML format - public virtual string ExportOrdersToXml(IList orders) - { - var sb = new StringBuilder(); - var stringWriter = new StringWriter(sb); - var xmlWriter = new XmlTextWriter(stringWriter); - xmlWriter.WriteStartDocument(); - xmlWriter.WriteStartElement("Orders"); - xmlWriter.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); - - - foreach (var order in orders) - { - xmlWriter.WriteStartElement("Order"); - - xmlWriter.WriteElementString("OrderId", null, order.GetOrderNumber()); - xmlWriter.WriteElementString("OrderGuid", null, order.OrderGuid.ToString()); - xmlWriter.WriteElementString("StoreId", null, order.StoreId.ToString()); - xmlWriter.WriteElementString("CustomerId", null, order.CustomerId.ToString()); - xmlWriter.WriteElementString("CustomerLanguageId", null, order.CustomerLanguageId.ToString()); - xmlWriter.WriteElementString("CustomerTaxDisplayTypeId", null, order.CustomerTaxDisplayTypeId.ToString()); - xmlWriter.WriteElementString("CustomerIp", null, order.CustomerIp); - xmlWriter.WriteElementString("OrderSubtotalInclTax", null, order.OrderSubtotalInclTax.ToString()); - xmlWriter.WriteElementString("OrderSubtotalExclTax", null, order.OrderSubtotalExclTax.ToString()); - xmlWriter.WriteElementString("OrderSubTotalDiscountInclTax", null, order.OrderSubTotalDiscountInclTax.ToString()); - xmlWriter.WriteElementString("OrderSubTotalDiscountExclTax", null, order.OrderSubTotalDiscountExclTax.ToString()); - xmlWriter.WriteElementString("OrderShippingInclTax", null, order.OrderShippingInclTax.ToString()); - xmlWriter.WriteElementString("OrderShippingExclTax", null, order.OrderShippingExclTax.ToString()); - xmlWriter.WriteElementString("PaymentMethodAdditionalFeeInclTax", null, order.PaymentMethodAdditionalFeeInclTax.ToString()); - xmlWriter.WriteElementString("PaymentMethodAdditionalFeeExclTax", null, order.PaymentMethodAdditionalFeeExclTax.ToString()); - xmlWriter.WriteElementString("TaxRates", null, order.TaxRates); - xmlWriter.WriteElementString("OrderTax", null, order.OrderTax.ToString()); - xmlWriter.WriteElementString("OrderTotal", null, order.OrderTotal.ToString()); - xmlWriter.WriteElementString("RefundedAmount", null, order.RefundedAmount.ToString()); - xmlWriter.WriteElementString("OrderDiscount", null, order.OrderDiscount.ToString()); - xmlWriter.WriteElementString("CurrencyRate", null, order.CurrencyRate.ToString()); - xmlWriter.WriteElementString("CustomerCurrencyCode", null, order.CustomerCurrencyCode); - xmlWriter.WriteElementString("AffiliateId", null, order.AffiliateId.ToString()); - xmlWriter.WriteElementString("OrderStatusId", null, order.OrderStatusId.ToString()); - xmlWriter.WriteElementString("AllowStoringCreditCardNumber", null, order.AllowStoringCreditCardNumber.ToString()); - xmlWriter.WriteElementString("CardType", null, order.CardType); - xmlWriter.WriteElementString("CardName", null, order.CardName); - xmlWriter.WriteElementString("CardNumber", null, order.CardNumber); - xmlWriter.WriteElementString("MaskedCreditCardNumber", null, order.MaskedCreditCardNumber); - xmlWriter.WriteElementString("CardCvv2", null, order.CardCvv2); - xmlWriter.WriteElementString("CardExpirationMonth", null, order.CardExpirationMonth); - xmlWriter.WriteElementString("CardExpirationYear", null, order.CardExpirationYear); - - //codehint: sm-add begin - xmlWriter.WriteElementString("DirectDebitAccountHolder", null, order.DirectDebitAccountHolder); - xmlWriter.WriteElementString("DirectDebitAccountHolder", null, order.DirectDebitAccountNumber); - xmlWriter.WriteElementString("DirectDebitAccountHolder", null, order.DirectDebitBankCode); - xmlWriter.WriteElementString("DirectDebitAccountHolder", null, order.DirectDebitBankName); - xmlWriter.WriteElementString("DirectDebitAccountHolder", null, order.DirectDebitBIC); - xmlWriter.WriteElementString("DirectDebitAccountHolder", null, order.DirectDebitCountry); - xmlWriter.WriteElementString("DirectDebitAccountHolder", null, order.DirectDebitIban); - //codehint: sm-add end - - xmlWriter.WriteElementString("PaymentMethodSystemName", null, order.PaymentMethodSystemName); - xmlWriter.WriteElementString("AuthorizationTransactionId", null, order.AuthorizationTransactionId); - xmlWriter.WriteElementString("AuthorizationTransactionCode", null, order.AuthorizationTransactionCode); - xmlWriter.WriteElementString("AuthorizationTransactionResult", null, order.AuthorizationTransactionResult); - xmlWriter.WriteElementString("CaptureTransactionId", null, order.CaptureTransactionId); - xmlWriter.WriteElementString("CaptureTransactionResult", null, order.CaptureTransactionResult); - xmlWriter.WriteElementString("SubscriptionTransactionId", null, order.SubscriptionTransactionId); - xmlWriter.WriteElementString("PurchaseOrderNumber", null, order.PurchaseOrderNumber); - xmlWriter.WriteElementString("PaymentStatusId", null, order.PaymentStatusId.ToString()); - xmlWriter.WriteElementString("PaidDateUtc", null, (order.PaidDateUtc == null) ? string.Empty : order.PaidDateUtc.Value.ToString()); - xmlWriter.WriteElementString("ShippingStatusId", null, order.ShippingStatusId.ToString()); - xmlWriter.WriteElementString("ShippingMethod", null, order.ShippingMethod); - xmlWriter.WriteElementString("ShippingRateComputationMethodSystemName", null, order.ShippingRateComputationMethodSystemName); - xmlWriter.WriteElementString("VatNumber", null, order.VatNumber); - xmlWriter.WriteElementString("Deleted", null, order.Deleted.ToString()); - xmlWriter.WriteElementString("CreatedOnUtc", null, order.CreatedOnUtc.ToString()); - xmlWriter.WriteElementString("UpdatedOnUtc", null, order.UpdatedOnUtc.ToString()); - xmlWriter.WriteElementString("RewardPointsRemaining", null, order.RewardPointsRemaining.HasValue ? order.RewardPointsRemaining.Value.ToString() : ""); - - //products - var orderItems = order.OrderItems; - if (orderItems.Count > 0) - { - xmlWriter.WriteStartElement("OrderItems"); - foreach (var orderItem in orderItems) - { - xmlWriter.WriteStartElement("OrderItem"); - xmlWriter.WriteElementString("Id", null, orderItem.Id.ToString()); - xmlWriter.WriteElementString("OrderItemGuid", null, orderItem.OrderItemGuid.ToString()); - xmlWriter.WriteElementString("ProductId", null, orderItem.ProductId.ToString()); - - xmlWriter.WriteElementString("ProductName", null, orderItem.Product.Name); - xmlWriter.WriteElementString("UnitPriceInclTax", null, orderItem.UnitPriceInclTax.ToString()); - xmlWriter.WriteElementString("UnitPriceExclTax", null, orderItem.UnitPriceExclTax.ToString()); - xmlWriter.WriteElementString("PriceInclTax", null, orderItem.PriceInclTax.ToString()); - xmlWriter.WriteElementString("PriceExclTax", null, orderItem.PriceExclTax.ToString()); - xmlWriter.WriteElementString("AttributeDescription", null, orderItem.AttributeDescription); - xmlWriter.WriteElementString("AttributesXml", null, orderItem.AttributesXml); - xmlWriter.WriteElementString("Quantity", null, orderItem.Quantity.ToString()); - xmlWriter.WriteElementString("DiscountAmountInclTax", null, orderItem.DiscountAmountInclTax.ToString()); - xmlWriter.WriteElementString("DiscountAmountExclTax", null, orderItem.DiscountAmountExclTax.ToString()); - xmlWriter.WriteElementString("DownloadCount", null, orderItem.DownloadCount.ToString()); - xmlWriter.WriteElementString("IsDownloadActivated", null, orderItem.IsDownloadActivated.ToString()); - xmlWriter.WriteElementString("LicenseDownloadId", null, orderItem.LicenseDownloadId.ToString()); - xmlWriter.WriteElementString("BundleData", null, orderItem.BundleData); - xmlWriter.WriteElementString("ProductCost", null, orderItem.ProductCost.ToString()); - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - } - - //shipments - var shipments = order.Shipments.OrderBy(x => x.CreatedOnUtc).ToList(); - if (shipments.Count > 0) - { - xmlWriter.WriteStartElement("Shipments"); - foreach (var shipment in shipments) - { - xmlWriter.WriteStartElement("Shipment"); - xmlWriter.WriteElementString("ShipmentId", null, shipment.Id.ToString()); - xmlWriter.WriteElementString("TrackingNumber", null, shipment.TrackingNumber); - xmlWriter.WriteElementString("TotalWeight", null, shipment.TotalWeight.HasValue ? shipment.TotalWeight.Value.ToString() : ""); - - xmlWriter.WriteElementString("ShippedDateUtc", null, shipment.ShippedDateUtc.HasValue ? - shipment.ShippedDateUtc.ToString() : ""); - xmlWriter.WriteElementString("DeliveryDateUtc", null, shipment.DeliveryDateUtc.HasValue ? - shipment.DeliveryDateUtc.Value.ToString() : ""); - xmlWriter.WriteElementString("CreatedOnUtc", null, shipment.CreatedOnUtc.ToString()); - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - } - xmlWriter.WriteEndElement(); - } - - xmlWriter.WriteEndElement(); - xmlWriter.WriteEndDocument(); - xmlWriter.Close(); - return stringWriter.ToString(); - } - - /// - /// Export orders to XLSX - /// - /// Stream - /// Orders - public virtual void ExportOrdersToXlsx(Stream stream, IList orders) - { - if (stream == null) - throw new ArgumentNullException("stream"); - - // ok, we can run the real code of the sample now - using (var xlPackage = new ExcelPackage(stream)) - { - // uncomment this line if you want the XML written out to the outputDir - //xlPackage.DebugMode = true; - - // get handle to the existing worksheet - var worksheet = xlPackage.Workbook.Worksheets.Add("Orders"); - //Create Headers and format them - var properties = new string[] - { - //order properties - "OrderId", - "OrderGuid", - "CustomerId", - "OrderSubtotalInclTax", - "OrderSubtotalExclTax", - "OrderSubTotalDiscountInclTax", - "OrderSubTotalDiscountExclTax", - "OrderShippingInclTax", - "OrderShippingExclTax", - "PaymentMethodAdditionalFeeInclTax", - "PaymentMethodAdditionalFeeExclTax", - "TaxRates", - "OrderTax", - "OrderTotal", - "RefundedAmount", - "OrderDiscount", - "CurrencyRate", - "CustomerCurrencyCode", - "AffiliateId", - "OrderStatusId", - "PaymentMethodSystemName", - "PurchaseOrderNumber", - "PaymentStatusId", - "ShippingStatusId", - "ShippingMethod", - "ShippingRateComputationMethodSystemName", - "VatNumber", - "CreatedOnUtc", - "UpdatedOnUtc", - "RewardPointsRemaining", - //billing address - "BillingFirstName", - "BillingLastName", - "BillingEmail", - "BillingCompany", - "BillingCountry", - "BillingStateProvince", - "BillingCity", - "BillingAddress1", - "BillingAddress2", - "BillingZipPostalCode", - "BillingPhoneNumber", - "BillingFaxNumber", - //shipping address - "ShippingFirstName", - "ShippingLastName", - "ShippingEmail", - "ShippingCompany", - "ShippingCountry", - "ShippingStateProvince", - "ShippingCity", - "ShippingAddress1", - "ShippingAddress2", - "ShippingZipPostalCode", - "ShippingPhoneNumber", - "ShippingFaxNumber", - }; - for (int i = 0; i < properties.Length; i++) - { - worksheet.Cells[1, i + 1].Value = properties[i]; - worksheet.Cells[1, i + 1].Style.Fill.PatternType = ExcelFillStyle.Solid; - worksheet.Cells[1, i + 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228)); - worksheet.Cells[1, i + 1].Style.Font.Bold = true; - } - - - int row = 2; - foreach (var order in orders) - { - int col = 1; - - //order properties - worksheet.Cells[row, col].Value = order.GetOrderNumber(); - col++; - - worksheet.Cells[row, col].Value = order.OrderGuid; - col++; - - worksheet.Cells[row, col].Value = order.CustomerId; - col++; - - worksheet.Cells[row, col].Value = order.OrderSubtotalInclTax; - col++; - - worksheet.Cells[row, col].Value = order.OrderSubtotalExclTax; - col++; - - worksheet.Cells[row, col].Value = order.OrderSubTotalDiscountInclTax; - col++; - - worksheet.Cells[row, col].Value = order.OrderSubTotalDiscountExclTax; - col++; - - worksheet.Cells[row, col].Value = order.OrderShippingInclTax; - col++; - - worksheet.Cells[row, col].Value = order.OrderShippingExclTax; - col++; - - worksheet.Cells[row, col].Value = order.PaymentMethodAdditionalFeeInclTax; - col++; - - worksheet.Cells[row, col].Value = order.PaymentMethodAdditionalFeeExclTax; - col++; - - worksheet.Cells[row, col].Value = order.TaxRates; - col++; - - worksheet.Cells[row, col].Value = order.OrderTax; - col++; - - worksheet.Cells[row, col].Value = order.OrderTotal; - col++; - - worksheet.Cells[row, col].Value = order.RefundedAmount; - col++; - - worksheet.Cells[row, col].Value = order.OrderDiscount; - col++; - - worksheet.Cells[row, col].Value = order.CurrencyRate; - col++; - - worksheet.Cells[row, col].Value = order.CustomerCurrencyCode; - col++; - - worksheet.Cells[row, col].Value = order.AffiliateId; - col++; - - worksheet.Cells[row, col].Value = order.OrderStatusId; - col++; - - worksheet.Cells[row, col].Value = order.PaymentMethodSystemName; - col++; - - worksheet.Cells[row, col].Value = order.PurchaseOrderNumber; - col++; - - worksheet.Cells[row, col].Value = order.PaymentStatusId; - col++; - - worksheet.Cells[row, col].Value = order.ShippingStatusId; - col++; - - worksheet.Cells[row, col].Value = order.ShippingMethod; - col++; - - worksheet.Cells[row, col].Value = order.ShippingRateComputationMethodSystemName; - col++; - - worksheet.Cells[row, col].Value = order.VatNumber; - col++; - - worksheet.Cells[row, col].Value = order.CreatedOnUtc.ToOADate(); - col++; - - worksheet.Cells[row, col].Value = order.UpdatedOnUtc.ToOADate(); - col++; - - worksheet.Cells[row, col].Value = (order.RewardPointsRemaining.HasValue ? order.RewardPointsRemaining.Value.ToString() : ""); - col++; - - - //billing address - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.FirstName : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.LastName : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.Email : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.Company : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null && order.BillingAddress.Country != null ? order.BillingAddress.Country.Name : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null && order.BillingAddress.StateProvince != null ? order.BillingAddress.StateProvince.Name : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.City : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.Address1 : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.Address2 : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.ZipPostalCode : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.PhoneNumber : ""; - col++; - - worksheet.Cells[row, col].Value = order.BillingAddress != null ? order.BillingAddress.FaxNumber : ""; - col++; - - //shipping address - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.FirstName : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.LastName : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.Email : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.Company : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null && order.ShippingAddress.Country != null ? order.ShippingAddress.Country.Name : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null && order.ShippingAddress.StateProvince != null ? order.ShippingAddress.StateProvince.Name : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.City : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.Address1 : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.Address2 : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.ZipPostalCode : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.PhoneNumber : ""; - col++; - - worksheet.Cells[row, col].Value = order.ShippingAddress != null ? order.ShippingAddress.FaxNumber : ""; - col++; - - //next row - row++; - } - - - - - - - - - // we had better add some document properties to the spreadsheet - - // set some core property values - //var storeName = _storeInformationSettings.StoreName; - //var storeUrl = _storeInformationSettings.StoreUrl; - //xlPackage.Workbook.Properties.Title = string.Format("{0} orders", storeName); - //xlPackage.Workbook.Properties.Author = storeName; - //xlPackage.Workbook.Properties.Subject = string.Format("{0} orders", storeName); - //xlPackage.Workbook.Properties.Keywords = string.Format("{0} orders", storeName); - //xlPackage.Workbook.Properties.Category = "Orders"; - //xlPackage.Workbook.Properties.Comments = string.Format("{0} orders", storeName); - - // set some extended property values - //xlPackage.Workbook.Properties.Company = storeName; - //xlPackage.Workbook.Properties.HyperlinkBase = new Uri(storeUrl); - - // save the new spreadsheet - xlPackage.Save(); - } - } - - /// - /// Export customer list to XLSX - /// - /// Stream - /// Customers - public virtual void ExportCustomersToXlsx(Stream stream, IList customers) - { - if (stream == null) - throw new ArgumentNullException("stream"); - - // ok, we can run the real code of the sample now - using (var xlPackage = new ExcelPackage(stream)) - { - // uncomment this line if you want the XML written out to the outputDir - //xlPackage.DebugMode = true; - - // get handle to the existing worksheet - var worksheet = xlPackage.Workbook.Worksheets.Add("Customers"); - //Create Headers and format them - var properties = new string[] - { - "CustomerId", - "CustomerGuid", - "Email", - "Username", - "PasswordStr",//why can't we use 'Password' name? - "PasswordFormatId", - "PasswordSalt", - "LanguageId", - "CurrencyId", - "TaxDisplayTypeId", - "IsTaxExempt", - "VatNumber", - "VatNumberStatusId", - "TimeZoneId", - "AffiliateId", - "Active", - "IsGuest", - "IsRegistered", - "IsAdministrator", - "IsForumModerator", - "FirstName", - "LastName", - "Gender", - "Company", - "StreetAddress", - "StreetAddress2", - "ZipPostalCode", - "City", - "CountryId", - "StateProvinceId", - "Phone", - "Fax", - "AvatarPictureId", - "ForumPostCount", - "Signature", - }; - for (int i = 0; i < properties.Length; i++) - { - worksheet.Cells[1, i + 1].Value = properties[i]; - worksheet.Cells[1, i + 1].Style.Fill.PatternType = ExcelFillStyle.Solid; - worksheet.Cells[1, i + 1].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228)); - worksheet.Cells[1, i + 1].Style.Font.Bold = true; - } - - - int row = 2; - foreach (var customer in customers) - { - int col = 1; - - worksheet.Cells[row, col].Value = customer.Id; - col++; - - worksheet.Cells[row, col].Value = customer.CustomerGuid; - col++; - - worksheet.Cells[row, col].Value = customer.Email; - col++; - - worksheet.Cells[row, col].Value = customer.Username; - col++; - - worksheet.Cells[row, col].Value = customer.Password; - col++; - - worksheet.Cells[row, col].Value = customer.PasswordFormatId; - col++; - - worksheet.Cells[row, col].Value = customer.PasswordSalt; - col++; - - worksheet.Cells[row, col].Value = customer.IsTaxExempt; - col++; - - worksheet.Cells[row, col].Value = customer.AffiliateId; - col++; - - worksheet.Cells[row, col].Value = customer.Active; - col++; - - //roles - worksheet.Cells[row, col].Value = customer.IsGuest(); - col++; - - worksheet.Cells[row, col].Value = customer.IsRegistered(); - col++; - - worksheet.Cells[row, col].Value = customer.IsAdmin(); - col++; - - worksheet.Cells[row, col].Value = customer.IsForumModerator(); - col++; - - //attributes - var firstName = customer.GetAttribute(SystemCustomerAttributeNames.FirstName); - var lastName = customer.GetAttribute(SystemCustomerAttributeNames.LastName); - var gender = customer.GetAttribute(SystemCustomerAttributeNames.Gender); - var company = customer.GetAttribute(SystemCustomerAttributeNames.Company); - var streetAddress = customer.GetAttribute(SystemCustomerAttributeNames.StreetAddress); - var streetAddress2 = customer.GetAttribute(SystemCustomerAttributeNames.StreetAddress2); - var zipPostalCode = customer.GetAttribute(SystemCustomerAttributeNames.ZipPostalCode); - var city = customer.GetAttribute(SystemCustomerAttributeNames.City); - var countryId = customer.GetAttribute(SystemCustomerAttributeNames.CountryId); - var stateProvinceId = customer.GetAttribute(SystemCustomerAttributeNames.StateProvinceId); - var phone = customer.GetAttribute(SystemCustomerAttributeNames.Phone); - var fax = customer.GetAttribute(SystemCustomerAttributeNames.Fax); - var vatNumber = customer.GetAttribute(SystemCustomerAttributeNames.VatNumber); - var vatNumberStatusId = customer.GetAttribute(SystemCustomerAttributeNames.VatNumberStatusId); - var timeZoneId = customer.GetAttribute(SystemCustomerAttributeNames.TimeZoneId); - - var avatarPictureId = customer.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId); - var forumPostCount = customer.GetAttribute(SystemCustomerAttributeNames.ForumPostCount); - var signature = customer.GetAttribute(SystemCustomerAttributeNames.Signature); - - worksheet.Cells[row, col].Value = firstName; - col++; - - worksheet.Cells[row, col].Value = lastName; - col++; - - worksheet.Cells[row, col].Value = gender; - col++; - - worksheet.Cells[row, col].Value = company; - col++; - - worksheet.Cells[row, col].Value = streetAddress; - col++; - - worksheet.Cells[row, col].Value = streetAddress2; - col++; - - worksheet.Cells[row, col].Value = zipPostalCode; - col++; - - worksheet.Cells[row, col].Value = city; - col++; - - worksheet.Cells[row, col].Value = countryId; - col++; - - worksheet.Cells[row, col].Value = stateProvinceId; - col++; - - worksheet.Cells[row, col].Value = phone; - col++; - - worksheet.Cells[row, col].Value = fax; - col++; - - worksheet.Cells[row, col].Value = vatNumber; - col++; - - worksheet.Cells[row, col].Value = vatNumberStatusId; - col++; - - worksheet.Cells[row, col].Value = avatarPictureId; - col++; - - worksheet.Cells[row, col].Value = timeZoneId; - col++; - - worksheet.Cells[row, col].Value = forumPostCount; - col++; - - worksheet.Cells[row, col].Value = signature; - col++; - - row++; - } - - - - - - - - - // we had better add some document properties to the spreadsheet - - // set some core property values - //var storeName = _storeInformationSettings.StoreName; - //var storeUrl = _storeInformationSettings.StoreUrl; - //xlPackage.Workbook.Properties.Title = string.Format("{0} customers", storeName); - //xlPackage.Workbook.Properties.Author = storeName; - //xlPackage.Workbook.Properties.Subject = string.Format("{0} customers", storeName); - //xlPackage.Workbook.Properties.Keywords = string.Format("{0} customers", storeName); - //xlPackage.Workbook.Properties.Category = "Customers"; - //xlPackage.Workbook.Properties.Comments = string.Format("{0} customers", storeName); - - // set some extended property values - //xlPackage.Workbook.Properties.Company = storeName; - //xlPackage.Workbook.Properties.HyperlinkBase = new Uri(storeUrl); - - // save the new spreadsheet - xlPackage.Save(); - } - } - - /// - /// Export customer list to xml - /// - /// Customers - /// Result in XML format - public virtual string ExportCustomersToXml(IList customers) - { - var sb = new StringBuilder(); - var stringWriter = new StringWriter(sb); - var xmlWriter = new XmlTextWriter(stringWriter); - xmlWriter.WriteStartDocument(); - xmlWriter.WriteStartElement("Customers"); - xmlWriter.WriteAttributeString("Version", SmartStoreVersion.CurrentVersion); - - foreach (var customer in customers) - { - xmlWriter.WriteStartElement("Customer"); - xmlWriter.WriteElementString("CustomerId", null, customer.Id.ToString()); - xmlWriter.WriteElementString("CustomerGuid", null, customer.CustomerGuid.ToString()); - xmlWriter.WriteElementString("Email", null, customer.Email); - xmlWriter.WriteElementString("Username", null, customer.Username); - xmlWriter.WriteElementString("Password", null, customer.Password); - xmlWriter.WriteElementString("PasswordFormatId", null, customer.PasswordFormatId.ToString()); - xmlWriter.WriteElementString("PasswordSalt", null, customer.PasswordSalt); - xmlWriter.WriteElementString("IsTaxExempt", null, customer.IsTaxExempt.ToString()); - xmlWriter.WriteElementString("AffiliateId", null, customer.AffiliateId.ToString()); - xmlWriter.WriteElementString("Active", null, customer.Active.ToString()); - - - xmlWriter.WriteElementString("IsGuest", null, customer.IsGuest().ToString()); - xmlWriter.WriteElementString("IsRegistered", null, customer.IsRegistered().ToString()); - xmlWriter.WriteElementString("IsAdministrator", null, customer.IsAdmin().ToString()); - xmlWriter.WriteElementString("IsForumModerator", null, customer.IsForumModerator().ToString()); - - xmlWriter.WriteElementString("FirstName", null, customer.GetAttribute(SystemCustomerAttributeNames.FirstName)); - xmlWriter.WriteElementString("LastName", null, customer.GetAttribute(SystemCustomerAttributeNames.LastName)); - xmlWriter.WriteElementString("Gender", null, customer.GetAttribute(SystemCustomerAttributeNames.Gender)); - xmlWriter.WriteElementString("Company", null, customer.GetAttribute(SystemCustomerAttributeNames.Company)); - - xmlWriter.WriteElementString("CountryId", null, customer.GetAttribute(SystemCustomerAttributeNames.CountryId).ToString()); - xmlWriter.WriteElementString("StreetAddress", null, customer.GetAttribute(SystemCustomerAttributeNames.StreetAddress)); - xmlWriter.WriteElementString("StreetAddress2", null, customer.GetAttribute(SystemCustomerAttributeNames.StreetAddress2)); - xmlWriter.WriteElementString("ZipPostalCode", null, customer.GetAttribute(SystemCustomerAttributeNames.ZipPostalCode)); - xmlWriter.WriteElementString("City", null, customer.GetAttribute(SystemCustomerAttributeNames.City)); - xmlWriter.WriteElementString("CountryId", null, customer.GetAttribute(SystemCustomerAttributeNames.CountryId).ToString()); - xmlWriter.WriteElementString("StateProvinceId", null, customer.GetAttribute(SystemCustomerAttributeNames.StateProvinceId).ToString()); - xmlWriter.WriteElementString("Phone", null, customer.GetAttribute(SystemCustomerAttributeNames.Phone)); - xmlWriter.WriteElementString("Fax", null, customer.GetAttribute(SystemCustomerAttributeNames.Fax)); - xmlWriter.WriteElementString("VatNumber", null, customer.GetAttribute(SystemCustomerAttributeNames.VatNumber)); - xmlWriter.WriteElementString("VatNumberStatusId", null, customer.GetAttribute(SystemCustomerAttributeNames.VatNumberStatusId).ToString()); - xmlWriter.WriteElementString("TimeZoneId", null, customer.GetAttribute(SystemCustomerAttributeNames.TimeZoneId)); - - var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(customer.Email); - bool subscribedToNewsletters = newsletter != null && newsletter.Active; - xmlWriter.WriteElementString("Newsletter", null, subscribedToNewsletters.ToString()); - - xmlWriter.WriteElementString("AvatarPictureId", null, customer.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId).ToString()); - xmlWriter.WriteElementString("ForumPostCount", null, customer.GetAttribute(SystemCustomerAttributeNames.ForumPostCount).ToString()); - xmlWriter.WriteElementString("Signature", null, customer.GetAttribute(SystemCustomerAttributeNames.Signature)); - - xmlWriter.WriteEndElement(); - } - - xmlWriter.WriteEndElement(); - xmlWriter.WriteEndDocument(); - xmlWriter.Close(); - return stringWriter.ToString(); - } - - - #endregion - } -} diff --git a/src/Libraries/SmartStore.Services/ExportImport/IExportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/IExportManager.cs deleted file mode 100644 index 5f05271673..0000000000 --- a/src/Libraries/SmartStore.Services/ExportImport/IExportManager.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Domain.Orders; - -namespace SmartStore.Services.ExportImport -{ - /// - /// Export manager interface - /// - public interface IExportManager - { - /// - /// Export manufacturer list to xml - /// - /// Manufacturers - /// Result in XML format - string ExportManufacturersToXml(IList manufacturers); - - /// - /// Export category list to xml - /// - /// Result in XML format - string ExportCategoriesToXml(); - - /// - /// Export product list to xml - /// - /// Products - /// Result in XML format - string ExportProductsToXml(IList products); - - /// - /// Export products to XLSX - /// - /// Stream - /// Products - void ExportProductsToXlsx(Stream stream, IList products); - - /// - /// Export order list to xml - /// - /// Orders - /// Result in XML format - string ExportOrdersToXml(IList orders); - - /// - /// Export orders to XLSX - /// - /// Stream - /// Orders - void ExportOrdersToXlsx(Stream stream, IList orders); - - /// - /// Export customer list to XLSX - /// - /// Stream - /// Customers - void ExportCustomersToXlsx(Stream stream, IList customers); - - /// - /// Export customer list to xml - /// - /// Customers - /// Result in XML format - string ExportCustomersToXml(IList customers); - } -} diff --git a/src/Libraries/SmartStore.Services/ExportImport/IImportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/IImportManager.cs deleted file mode 100644 index b0ffb02314..0000000000 --- a/src/Libraries/SmartStore.Services/ExportImport/IImportManager.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using SmartStore.Core.Data; -using SmartStore.Core.Async; - -namespace SmartStore.Services.ExportImport -{ - /// - /// Import manager interface - /// - public interface IImportManager - { - Task ImportProductsFromExcelAsync( - Stream stream, - CancellationToken cancellationToken, - IProgress progress = null); - - /// - /// Dumps an instance to a string - /// - /// The result instance - /// The report - string CreateTextReport(ImportResult result); - } - - public static class IImportManagerExtensions - { - public static Task ImportProductsFromExcelAsync( - this IImportManager importManager, - Stream stream, - IProgress progress = null) - { - return importManager.ImportProductsFromExcelAsync(stream, CancellationToken.None, progress); - } - - public static ImportResult ImportProductsFromExcel(this IImportManager importManager, Stream stream) - { - Func> fn = () => importManager.ImportProductsFromExcelAsync(stream); - return fn.RunSync(); - } - } -} diff --git a/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs b/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs deleted file mode 100644 index 0f7d857c5d..0000000000 --- a/src/Libraries/SmartStore.Services/ExportImport/ImportManager.cs +++ /dev/null @@ -1,710 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Data; -using SmartStore.Services.Catalog; -using SmartStore.Core.Events; -using SmartStore.Services.Media; -using SmartStore.Services.Seo; -using SmartStore.Utilities; -using System.Text; -using SmartStore.Core.Domain.Seo; - -namespace SmartStore.Services.ExportImport -{ - /// - /// Import manager - /// - public partial class ImportManager : IImportManager - { - private readonly IProductService _productService; - private readonly ICategoryService _categoryService; - private readonly IManufacturerService _manufacturerService; - private readonly IPictureService _pictureService; - private readonly IUrlRecordService _urlRecordService; - private readonly SeoSettings _seoSettings; - private readonly IEventPublisher _eventPublisher; - private readonly IRepository _rsProduct; - private readonly IRepository _rsProductCategory; - private readonly IRepository _rsProductManufacturer; - private readonly IRepository _rsProductPicture; - private readonly IRepository _rsUrlRecord; - - public ImportManager( - IProductService productService, - ICategoryService categoryService, - IManufacturerService manufacturerService, - IPictureService pictureService, - IUrlRecordService urlRecordService, - SeoSettings seoSettings, - IEventPublisher eventPublisher, - IRepository rsProduct, - IRepository rsProductCategory, - IRepository rsProductManufacturer, - IRepository rsProductPicture, - IRepository rsUrlRecord) - { - this._productService = productService; - this._categoryService = categoryService; - this._manufacturerService = manufacturerService; - this._pictureService = pictureService; - this._urlRecordService = urlRecordService; - this._seoSettings = seoSettings; - this._eventPublisher = eventPublisher; - this._rsProduct = rsProduct; - this._rsProductCategory = rsProductCategory; - this._rsProductManufacturer = rsProductManufacturer; - this._rsProductPicture = rsProductPicture; - this._rsUrlRecord = rsUrlRecord; - } - - public virtual string CreateTextReport(ImportResult result) - { - var sb = new StringBuilder(); - - using (var writer = new StringWriter(sb)) - { - writer.WriteLine("SUMMARY"); - writer.WriteLine("=================================================================================="); - writer.WriteLine("Started: {0}".FormatCurrent(result.StartDateUtc.ToLocalTime())); - writer.WriteLine("Finished: {0}{1}".FormatCurrent(result.EndDateUtc.ToLocalTime(), result.Cancelled ? " (cancelled by user)" : "")); - writer.WriteLine("Duration: {0}".FormatCurrent((result.EndDateUtc - result.StartDateUtc).ToString("g"))); - - writer.WriteLine(""); - writer.WriteLine("Total rows in source: {0}".FormatCurrent(result.TotalRecords)); - writer.WriteLine("Rows processed: {0}".FormatCurrent(result.AffectedRecords)); - writer.WriteLine("Products imported: {0}".FormatCurrent(result.NewRecords)); - writer.WriteLine("Products updated: {0}".FormatCurrent(result.ModifiedRecords)); - - writer.WriteLine(""); - writer.WriteLine("Warnings: {0}".FormatCurrent(result.Messages.Count(x => x.MessageType == ImportMessageType.Warning))); - writer.WriteLine("Errors: {0}".FormatCurrent(result.Messages.Count(x => x.MessageType == ImportMessageType.Error))); - - writer.WriteLine(""); - writer.WriteLine(""); - writer.WriteLine("MESSAGES"); - writer.WriteLine("=================================================================================="); - - foreach (var message in result.Messages) - { - string msg = string.Empty; - var prefix = new List(); - if (message.AffectedItem != null) - { - prefix.Add("Pos: " + message.AffectedItem.Position + 1); - } - if (message.AffectedField.HasValue()) - { - prefix.Add("Field: " + message.AffectedField); - } - - if (prefix.Any()) - { - msg = "[{0}] ".FormatCurrent(String.Join(", ", prefix)); - } - - msg += message.Message; - - writer.WriteLine("{0}: {1}".FormatCurrent(message.MessageType.ToString().ToUpper(), msg)); - } - } - - return sb.ToString(); - } - - /// - /// Import products from XLSX file - /// - /// Stream - public virtual async Task ImportProductsFromExcelAsync( - Stream stream, - CancellationToken cancellationToken, - IProgress progress = null) - { - Guard.ArgumentNotNull(() => stream); - - var t = await Task.Run(async () => { - - var result = new ImportResult(); - int saved = 0; - - progress.Report(new ImportProgressInfo { ElapsedTime = TimeSpan.Zero }); - - using (var scope = new DbContextScope(ctx: _rsProduct.Context, autoDetectChanges: false, proxyCreation: false, validateOnSave: false)) - { - using (var segmenter = new DataSegmenter(stream)) - { - result.TotalRecords = segmenter.TotalRows; - - while (segmenter.ReadNextBatch() && !cancellationToken.IsCancellationRequested) - { - var batch = segmenter.CurrentBatch; - - // Perf: detach all entities - _rsProduct.Context.DetachAll(); - - // Update progress for calling thread - if (progress != null) - { - progress.Report(new ImportProgressInfo - { - TotalRecords = result.TotalRecords, - TotalProcessed = segmenter.CurrentSegmentFirstRowIndex - 1, - NewRecords = result.NewRecords, - ModifiedRecords = result.ModifiedRecords, - ElapsedTime = DateTime.UtcNow - result.StartDateUtc, - TotalWarnings = result.Messages.Count(x => x.MessageType == ImportMessageType.Warning), - TotalErrors = result.Messages.Count(x => x.MessageType == ImportMessageType.Error), - }); - } - - // =========================================================================== - // 1.) Import products - // =========================================================================== - try - { - saved = await ProcessProducts(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProducts"); - } - - // reduce batch to saved (valid) products. - // No need to perform import operations on errored products. - batch = batch.Where(x => x.Entity != null && !x.IsTransient).AsReadOnly(); - - // update result object - result.NewRecords += batch.Count(x => x.IsNew && !x.IsTransient); - result.ModifiedRecords += batch.Count(x => !x.IsNew && !x.IsTransient); - - // =========================================================================== - // 2.) Import SEO Slugs - // IMPORTANT: Unlike with Products AutoCommitEnabled must be TRUE, - // as Slugs are going to be validated against existing ones in DB. - // =========================================================================== - if (batch.Any(x => x.IsNew || (x.ContainsKey("SeName") || x.NameChanged))) - { - _rsProduct.Context.AutoDetectChangesEnabled = true; - await ProcessSlugs(batch, result); - _rsProduct.Context.AutoDetectChangesEnabled = false; - } - - // =========================================================================== - // 3.) Import product category mappings - // =========================================================================== - if (batch.Any(x => x.ContainsKey("CategoryIds"))) - { - try - { - await ProcessProductCategories(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProductCategories"); - } - } - - // =========================================================================== - // 4.) Import product manufacturer mappings - // =========================================================================== - if (batch.Any(x => x.ContainsKey("ManufacturerIds"))) - { - try - { - await ProcessProductManufacturers(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProductManufacturers"); - } - } - - // =========================================================================== - // 5.) Import product picture mappings - // =========================================================================== - if (batch.Any(x => x.ContainsKey("Picture1") || x.ContainsKey("Picture2") || x.ContainsKey("Picture3"))) - { - try - { - ProcessProductPictures(batch, result); - } - catch (Exception ex) - { - result.AddError(ex, segmenter.CurrentSegment, "ProcessProductPictures"); - } - } - - } - } - } - - result.EndDateUtc = DateTime.UtcNow; - - if (cancellationToken.IsCancellationRequested) - { - result.Cancelled = true; - result.AddInfo("Import task was cancelled by user"); - } - - return result; - }); - - return t; - } - - private async Task ProcessProducts(ICollection> batch, ImportResult result) - { - _rsProduct.AutoCommitEnabled = false; - - Product lastInserted = null; - Product lastUpdated = null; - - foreach (var row in batch) - { - Product product = null; - - object key; - - // try get by int ID - if (row.TryGetValue("Id", out key) && key.ToString().ToInt() > 0) - { - product = _productService.GetProductById(key.ToString().ToInt()); - } - - // try get by SKU - if (product == null && row.TryGetValue("SKU", out key)) - { - product = _productService.GetProductBySku(key.ToString()); - } - - // try get by GTIN - if (product == null && row.TryGetValue("Gtin", out key)) - { - product = _productService.GetProductByGtin(key.ToString()); - } - - if (product == null) - { - // a Name is required with new products. - if (!row.ContainsKey("Name")) - { - result.AddError("The 'Name' field is required for new products. Skipping row.", row.GetRowInfo(), "Name"); - continue; - } - product = new Product(); - } - - row.Initialize(product, row["Name"].ToString()); - - if (!row.IsNew) - { - if (!product.Name.Equals(row["Name"].ToString(), StringComparison.OrdinalIgnoreCase)) - { - // Perf: use this later for SeName updates. - row.NameChanged = true; - } - } - - row.SetProperty(result, product, (x) => x.Sku); - row.SetProperty(result, product, (x) => x.Gtin); - row.SetProperty(result, product, (x) => x.ManufacturerPartNumber); - row.SetProperty(result, product, (x) => x.ProductTypeId, (int)ProductType.SimpleProduct); - row.SetProperty(result, product, (x) => x.ParentGroupedProductId); - row.SetProperty(result, product, (x) => x.VisibleIndividually, true); - row.SetProperty(result, product, (x) => x.Name); - row.SetProperty(result, product, (x) => x.ShortDescription); - row.SetProperty(result, product, (x) => x.FullDescription); - row.SetProperty(result, product, (x) => x.ProductTemplateId); - row.SetProperty(result, product, (x) => x.ShowOnHomePage); - row.SetProperty(result, product, (x) => x.MetaKeywords); - row.SetProperty(result, product, (x) => x.MetaDescription); - row.SetProperty(result, product, (x) => x.MetaTitle); - row.SetProperty(result, product, (x) => x.AllowCustomerReviews, true); - row.SetProperty(result, product, (x) => x.Published, true); - row.SetProperty(result, product, (x) => x.IsGiftCard); - row.SetProperty(result, product, (x) => x.GiftCardTypeId); - row.SetProperty(result, product, (x) => x.RequireOtherProducts); - row.SetProperty(result, product, (x) => x.RequiredProductIds); - row.SetProperty(result, product, (x) => x.AutomaticallyAddRequiredProducts); - row.SetProperty(result, product, (x) => x.IsDownload); - row.SetProperty(result, product, (x) => x.DownloadId); - row.SetProperty(result, product, (x) => x.UnlimitedDownloads, true); - row.SetProperty(result, product, (x) => x.MaxNumberOfDownloads, 10); - row.SetProperty(result, product, (x) => x.DownloadActivationTypeId, 1); - row.SetProperty(result, product, (x) => x.HasSampleDownload); - row.SetProperty(result, product, (x) => x.SampleDownloadId, (int?)null, ZeroToNull); - row.SetProperty(result, product, (x) => x.HasUserAgreement); - row.SetProperty(result, product, (x) => x.UserAgreementText); - row.SetProperty(result, product, (x) => x.IsRecurring); - row.SetProperty(result, product, (x) => x.RecurringCycleLength, 100); - row.SetProperty(result, product, (x) => x.RecurringCyclePeriodId); - row.SetProperty(result, product, (x) => x.RecurringTotalCycles, 10); - row.SetProperty(result, product, (x) => x.IsShipEnabled, true); - row.SetProperty(result, product, (x) => x.IsFreeShipping); - row.SetProperty(result, product, (x) => x.AdditionalShippingCharge); - row.SetProperty(result, product, (x) => x.IsTaxExempt); - row.SetProperty(result, product, (x) => x.TaxCategoryId, 1); - row.SetProperty(result, product, (x) => x.ManageInventoryMethodId); - row.SetProperty(result, product, (x) => x.StockQuantity, 10000); - row.SetProperty(result, product, (x) => x.DisplayStockAvailability); - row.SetProperty(result, product, (x) => x.DisplayStockQuantity); - row.SetProperty(result, product, (x) => x.MinStockQuantity); - row.SetProperty(result, product, (x) => x.LowStockActivityId); - row.SetProperty(result, product, (x) => x.NotifyAdminForQuantityBelow, 1); - row.SetProperty(result, product, (x) => x.BackorderModeId); - row.SetProperty(result, product, (x) => x.AllowBackInStockSubscriptions); - row.SetProperty(result, product, (x) => x.OrderMinimumQuantity, 1); - row.SetProperty(result, product, (x) => x.OrderMaximumQuantity, 10000); - row.SetProperty(result, product, (x) => x.AllowedQuantities); - row.SetProperty(result, product, (x) => x.DisableBuyButton); - row.SetProperty(result, product, (x) => x.DisableWishlistButton); - row.SetProperty(result, product, (x) => x.AvailableForPreOrder); - row.SetProperty(result, product, (x) => x.CallForPrice); - row.SetProperty(result, product, (x) => x.Price); - row.SetProperty(result, product, (x) => x.OldPrice); - row.SetProperty(result, product, (x) => x.ProductCost); - row.SetProperty(result, product, (x) => x.SpecialPrice); - row.SetProperty(result, product, (x) => x.SpecialPriceStartDateTimeUtc, null, OADateToUtcDate); - row.SetProperty(result, product, (x) => x.SpecialPriceEndDateTimeUtc, null, OADateToUtcDate); - row.SetProperty(result, product, (x) => x.CustomerEntersPrice); - row.SetProperty(result, product, (x) => x.MinimumCustomerEnteredPrice); - row.SetProperty(result, product, (x) => x.MaximumCustomerEnteredPrice, 1000); - row.SetProperty(result, product, (x) => x.Weight); - row.SetProperty(result, product, (x) => x.Length); - row.SetProperty(result, product, (x) => x.Width); - row.SetProperty(result, product, (x) => x.Height); - row.SetProperty(result, product, (x) => x.DeliveryTimeId); - row.SetProperty(result, product, (x) => x.BasePriceEnabled); - row.SetProperty(result, product, (x) => x.BasePriceMeasureUnit); - row.SetProperty(result, product, (x) => x.BasePriceAmount); - row.SetProperty(result, product, (x) => x.BasePriceBaseAmount); - row.SetProperty(result, product, (x) => x.BundlePerItemPricing); - row.SetProperty(result, product, (x) => x.BundlePerItemShipping); - row.SetProperty(result, product, (x) => x.BundlePerItemShoppingCart); - row.SetProperty(result, product, (x) => x.BundleTitleText); - row.SetProperty(result, product, (x) => x.CreatedOnUtc, DateTime.UtcNow, OADateToUtcDate); - - product.UpdatedOnUtc = DateTime.UtcNow; - - if (row.IsTransient) - { - _rsProduct.Insert(product); - lastInserted = product; - } - else - { - _rsProduct.Update(product); - lastUpdated = product; - } - } - - // commit whole batch at once - var t = await _rsProduct.Context.SaveChangesAsync(); - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - if (lastUpdated != null) - _eventPublisher.EntityUpdated(lastUpdated); - - //// ensure all products got imported before processing other stuff. - //t.Wait(); - - return t; - } - - private async Task ProcessSlugs(ICollection> batch, ImportResult result) - { - _rsUrlRecord.AutoCommitEnabled = false; - - var slugMap = new Dictionary(100); - Func slugLookup = ((s) => { - if (slugMap.ContainsKey(s)) - { - return slugMap[s]; - } - return (UrlRecord)null; - }); - - var entityName = typeof(Product).Name; - - foreach (var row in batch) - { - if (row.IsNew || row.NameChanged || row.ContainsKey("SeName")) - { - try - { - string seName = row.GetValue("SeName"); - seName = row.Entity.ValidateSeName(seName, row.Entity.Name, true, _urlRecordService, _seoSettings, extraSlugLookup: slugLookup); - - UrlRecord urlRecord = null; - - if (row.IsNew) - { - // dont't bother validating SeName for new entities. - urlRecord = new UrlRecord() - { - EntityId = row.Entity.Id, - EntityName = entityName, - Slug = seName, - LanguageId = 0, - IsActive = true, - }; - _rsUrlRecord.Insert(urlRecord); - } - else - { - urlRecord = _urlRecordService.SaveSlug(row.Entity, seName, 0); - } - - if (urlRecord != null) - { - // a new record was inserted to the store: keep track of it for this batch. - slugMap[seName] = urlRecord; - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "SeName"); - } - } - } - - // commit whole batch at once - var t = await _rsUrlRecord.Context.SaveChangesAsync(); - - return t; - } - - private async Task ProcessProductCategories(ICollection> batch, ImportResult result) - { - _rsProductCategory.AutoCommitEnabled = false; - - ProductCategory lastInserted = null; - - foreach (var row in batch) - { - string categoryIds = row.GetValue("CategoryIds"); - if (categoryIds.HasValue()) - { - try - { - foreach (var id in categoryIds.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim()))) - { - if (_rsProductCategory.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.CategoryId == id).FirstOrDefault() == null) - { - // ensure that category exists - var category = _categoryService.GetCategoryById(id); - if (category != null) - { - var productCategory = new ProductCategory() - { - ProductId = row.Entity.Id, - CategoryId = category.Id, - IsFeaturedProduct = false, - DisplayOrder = 1 - }; - _rsProductCategory.Insert(productCategory); - lastInserted = productCategory; - } - } - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "CategoryIds"); - } - } - } - - // commit whole batch at once - var t = await _rsProductCategory.Context.SaveChangesAsync(); - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - - return t; - } - - private async Task ProcessProductManufacturers(ICollection> batch, ImportResult result) - { - _rsProductManufacturer.AutoCommitEnabled = false; - - ProductManufacturer lastInserted = null; - - foreach (var row in batch) - { - string manufacturerIds = row.GetValue("ManufacturerIds"); - if (manufacturerIds.HasValue()) - { - try - { - foreach (var id in manufacturerIds.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x.Trim()))) - { - if (_rsProductManufacturer.TableUntracked.Where(x => x.ProductId == row.Entity.Id && x.ManufacturerId == id).FirstOrDefault() == null) - { - // ensure that manufacturer exists - var manufacturer = _manufacturerService.GetManufacturerById(id); - if (manufacturer != null) - { - var productManufacturer = new ProductManufacturer() - { - ProductId = row.Entity.Id, - ManufacturerId = manufacturer.Id, - IsFeaturedProduct = false, - DisplayOrder = 1 - }; - _rsProductManufacturer.Insert(productManufacturer); - lastInserted = productManufacturer; - } - } - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "ManufacturerIds"); - } - } - } - - // commit whole batch at once - var t = await _rsProductManufacturer.Context.SaveChangesAsync(); - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - - return t; - } - - private void ProcessProductPictures(ICollection> batch, ImportResult result) - { - // true, cause pictures must be saved and assigned an id - // prior adding a mapping. - _rsProductPicture.AutoCommitEnabled = true; - - ProductPicture lastInserted = null; - - foreach (var row in batch) - { - var pictures = new string[] - { - row.GetValue("Picture1"), - row.GetValue("Picture2"), - row.GetValue("Picture3") - }; - - int i = 0; - try - { - for (i = 0; i < pictures.Length; i++) - { - var picture = pictures[i]; - - if (picture.IsEmpty() || !File.Exists(picture)) - continue; - - var currentPictures = _rsProductPicture.TableUntracked.Where(x => x.ProductId == row.Entity.Id); - var pictureBinary = FindEqualPicture(picture, currentPictures); - - if (pictureBinary != null && pictureBinary.Length > 0) - { - // no equal picture found in sequence - var newPicture = _pictureService.InsertPicture(pictureBinary, "image/jpeg", _pictureService.GetPictureSeName(row.EntityDisplayName), true, true); - if (newPicture != null) - { - var mapping = new ProductPicture() - { - ProductId = row.Entity.Id, - PictureId = newPicture.Id, - DisplayOrder = 1, - }; - _rsProductPicture.Insert(mapping); - lastInserted = mapping; - } - } - else - { - result.AddInfo("Found equal picture in data store. Skipping field.", row.GetRowInfo(), "Picture" + (i + 1).ToString()); - } - } - } - catch (Exception ex) - { - result.AddWarning(ex.Message, row.GetRowInfo(), "Picture" + (i + 1).ToString()); - } - - } - - // Perf: notify only about LAST insertion and update - if (lastInserted != null) - _eventPublisher.EntityInserted(lastInserted); - } - - private DateTime? OADateToUtcDate(object value) - { - double oaDate; - if (CommonHelper.TryConvert(value, out oaDate) && oaDate != 0) - { - return DateTime.FromOADate(Convert.ToDouble(oaDate)); - } - - return null; - } - - - private int? ZeroToNull(object value) - { - int result; - if (CommonHelper.TryConvert(value, out result) && result > 0) - { - return result; - } - - return (int?)null; - } - - /// - /// Finds an equal picture by comparing the binary buffer - /// - /// The picture to find a duplicate for - /// The sequence of product pictures to seek within for duplicates - /// The picture binary for path when no picture equals in the sequence, null otherwise. - private byte[] FindEqualPicture(string path, IEnumerable productPictures) - { - try - { - var myBuffer = File.ReadAllBytes(path); - - foreach (var pictureMap in productPictures.Where(x => x.Id > 0)) - { - var otherBuffer = _pictureService.LoadPictureBinary(pictureMap.Picture); - using (var myStream = new MemoryStream(myBuffer)) - { - using (var otherStream = new MemoryStream(otherBuffer)) - { - var equals = myStream.ContentsEqual(otherStream); - if (equals) - { - return null; - } - } - } - } - - return myBuffer; - } - catch - { - return null; - } - } - } -} diff --git a/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs b/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs index 575c2948c8..216894b2d2 100644 --- a/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs +++ b/src/Libraries/SmartStore.Services/Extensions/NameValueCollectionExtensions.cs @@ -13,53 +13,85 @@ namespace SmartStore { public static class NameValueCollectionExtensions { + // TODO: find place to make it public static private static string AttributeFormatedName(int productAttributeId, int attributeId, int productId = 0, int bundleItemId = 0) { if (productId == 0) - return "product_attribute_{0}_{1}".FormatWith(productAttributeId, attributeId); + return "product_attribute_{0}_{1}".FormatInvariant(productAttributeId, attributeId); else - return "product_attribute_{0}_{1}_{2}_{3}".FormatWith(productId, bundleItemId, productAttributeId, attributeId); + return "product_attribute_{0}_{1}_{2}_{3}".FormatInvariant(productId, bundleItemId, productAttributeId, attributeId); } public static void AddProductAttribute(this NameValueCollection collection, int productAttributeId, int attributeId, int valueId, int productId = 0, int bundleItemId = 0) { if (productAttributeId != 0 && attributeId != 0 && valueId != 0) { - string name = AttributeFormatedName(productAttributeId, attributeId, productId, bundleItemId); + var name = AttributeFormatedName(productAttributeId, attributeId, productId, bundleItemId); collection.Add(name, valueId.ToString()); } } /// - /// Converts attribute query data + /// Get selected attributes from query string /// - /// Name value collection - /// Attribute query data items with following structure: Product.Id, ProductAttribute.Id, Product_ProductAttribute_Mapping.Id, ProductVariantAttributeValue.Id + /// Name value collection with selected attributes + /// Query string parameters + /// Attribute query data items with following structure: + /// Product.Id, ProductAttribute.Id, Product_ProductAttribute_Mapping.Id, ProductVariantAttributeValue.Id, [BundleItem.Id] /// Product identifier to filter - public static void ConvertAttributeQueryData(this NameValueCollection collection, List> queryData, int productId = 0) + public static void GetSelectedAttributes(this NameValueCollection collection, NameValueCollection queryString, List> attributes, int productId = 0) { - if (collection == null || queryData == null || queryData.Count <= 0) - return; + Guard.NotNull(() => collection); - var enm = queryData.Where(i => i.Count > 3); + // ambiguous parameters: let other query string parameters win over the json formatted attributes parameter + if (queryString != null && queryString.Count > 0) + { + var items = queryString.AllKeys + .Where(x => x.EmptyNull().StartsWith("product_attribute_")) + .SelectMany(queryString.GetValues, (k, v) => new { key = k.EmptyNull(), value = v.TrimSafe() }); - if (productId != 0) - enm = enm.Where(i => i[0] == productId); + foreach (var item in items) + { + var ids = item.key.Replace("product_attribute_", "").SplitSafe("_"); + if (ids.Count() > 3) + { + if (productId == 0 || (productId != 0 && productId == ids[0].ToInt())) + { + collection.Add(item.key, item.value); + } + } + } + } - foreach (var itm in enm) + if (attributes != null && attributes.Count > 0) { - string name = AttributeFormatedName(itm[1], itm[2], itm[0]); + var items = attributes.Where(i => i.Count > 3); + + if (productId != 0) + items = items.Where(i => i[0] == productId); - collection.Add(name, itm[3].ToString()); + foreach (var item in items) + { + var name = AttributeFormatedName(item[1], item[2], item[0], item.Count > 4 ? item[4] : 0); + + collection.Add(name, item[3].ToString()); + } } } /// Takes selected elements from collection and creates a attribute XML string from it. /// how the name of the controls are formatted. frontend includes productId, backend does not. - public static string CreateSelectedAttributesXml(this NameValueCollection collection, int productId, IList variantAttributes, - IProductAttributeParser productAttributeParser, ILocalizationService localizationService, IDownloadService downloadService, CatalogSettings catalogSettings, - HttpRequestBase request, List warnings, bool formatWithProductId = true, int bundleItemId = 0) + public static string CreateSelectedAttributesXml(this NameValueCollection collection, + int productId, + IEnumerable variantAttributes, + IProductAttributeParser productAttributeParser, + ILocalizationService localizationService, + IDownloadService downloadService, + CatalogSettings catalogSettings, + HttpRequestBase request, List warnings, + bool formatWithProductId = true, + int bundleItemId = 0) { if (collection == null) return ""; @@ -80,7 +112,7 @@ public static string CreateSelectedAttributesXml(this NameValueCollection collec var ctrlAttributes = collection[controlId]; if (ctrlAttributes.HasValue()) { - int selectedAttributeId = int.Parse(ctrlAttributes); + var selectedAttributeId = ctrlAttributes.SplitSafe(",").SafeGet(0).ToInt(); if (selectedAttributeId > 0) selectedAttributes = productAttributeParser.AddProductAttribute(selectedAttributes, attribute, selectedAttributeId.ToString()); } @@ -94,7 +126,7 @@ public static string CreateSelectedAttributesXml(this NameValueCollection collec { foreach (var item in cblAttributes.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { - int selectedAttributeId = int.Parse(item); + var selectedAttributeId = item.SplitSafe(",").SafeGet(0).ToInt(); if (selectedAttributeId > 0) selectedAttributes = productAttributeParser.AddProductAttribute(selectedAttributes, attribute, selectedAttributeId.ToString()); } @@ -142,31 +174,33 @@ public static string CreateSelectedAttributesXml(this NameValueCollection collec var download = downloadService.GetDownloadByGuid(downloadGuid); if (download != null) { + download.IsTransient = false; + downloadService.UpdateDownload(download); selectedAttributes = productAttributeParser.AddProductAttribute(selectedAttributes, attribute, download.DownloadGuid.ToString()); } } else { - var httpPostedFile = request.Files[controlId]; - if (httpPostedFile != null && httpPostedFile.FileName.HasValue()) + var postedFile = request.Files[controlId]; + if (postedFile != null && postedFile.FileName.HasValue()) { int fileMaxSize = catalogSettings.FileUploadMaximumSizeBytes; - if (httpPostedFile.ContentLength > fileMaxSize) + if (postedFile.ContentLength > fileMaxSize) { warnings.Add(string.Format(localizationService.GetResource("ShoppingCart.MaximumUploadedFileSize"), (int)(fileMaxSize / 1024))); } else { //save an uploaded file - var download = new Download() + var download = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = false, DownloadUrl = "", - DownloadBinary = httpPostedFile.GetDownloadBits(), - ContentType = httpPostedFile.ContentType, - Filename = System.IO.Path.GetFileNameWithoutExtension(httpPostedFile.FileName), - Extension = System.IO.Path.GetExtension(httpPostedFile.FileName), + DownloadBinary = postedFile.InputStream.ToByteArray(), + ContentType = postedFile.ContentType, + Filename = System.IO.Path.GetFileNameWithoutExtension(postedFile.FileName), + Extension = System.IO.Path.GetExtension(postedFile.FileName), IsNew = true }; downloadService.InsertDownload(download); diff --git a/src/Libraries/SmartStore.Services/Filter/FilterCriteria.cs b/src/Libraries/SmartStore.Services/Filter/FilterCriteria.cs index cbe6d704bd..6bbd9756f9 100644 --- a/src/Libraries/SmartStore.Services/Filter/FilterCriteria.cs +++ b/src/Libraries/SmartStore.Services/Filter/FilterCriteria.cs @@ -1,14 +1,9 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; -using SmartStore.Core.Infrastructure; namespace SmartStore.Services.Filter { - /// codehint: sm-add [JsonObject(MemberSerialization.OptIn)] public class FilterCriteria : IComparable { @@ -38,29 +33,44 @@ public class FilterCriteria : IComparable [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public int? ID { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public int? PId { get; set; } + // Metadata public int MatchCount { get; set; } + public int DisplayOrder { get; set; } + public int DisplayOrderValues { get; set; } public bool IsInactive { get; set; } + public string NameLocalized { get; set; } + public string ValueLocalized { get; set; } + + public string SqlName + { + get + { + if (Entity.IsCaseInsensitiveEqual("Manufacturer") && !Name.Contains('.')) + return "{0}.{1}".FormatInvariant(Entity, Name); - public string SqlName { - get { - if (Entity == "Manufacturer" && !Name.Contains('.')) - return "{0}.{1}".FormatWith(Entity, Name); return Name; } } - public bool IsRange { - get { + + public bool IsRange + { + get + { return (Value.HasValue() && Value.Contains('~') && (Operator == FilterOperator.RangeGreaterEqualLessEqual || Operator == FilterOperator.RangeGreaterEqualLess)); } } - int IComparable.CompareTo(object obj) { - FilterCriteria filter = (FilterCriteria)obj; + int IComparable.CompareTo(object obj) + { + var filter = (FilterCriteria)obj; - int compare = string.Compare(this.Entity, filter.Entity, true); + var compare = string.Compare(this.Entity, filter.Entity, true); - if (compare == 0) { + if (compare == 0) + { compare = string.Compare(this.Name, filter.Name, true); if (compare == 0) @@ -68,28 +78,19 @@ int IComparable.CompareTo(object obj) { } return compare; - - - //int compare = 0; - - //if (this.Name.HasValue() && filter.Name.HasValue()) - // compare = string.Compare(this.Name, filter.Name, true); - //else - // compare = string.Compare(this.Entity, filter.Entity, true); - - //if (compare != 0) - // return compare; - - //return string.Compare(this.Value, filter.Value, true); } - public override string ToString() { - try { + + public override string ToString() + { + try + { return JsonConvert.SerializeObject(this); } - catch (Exception exc) { + catch (Exception exc) + { exc.Dump(); } return ""; } - } // class + } } diff --git a/src/Libraries/SmartStore.Services/Filter/FilterExtensions.cs b/src/Libraries/SmartStore.Services/Filter/FilterExtensions.cs index e652747031..56f0655f26 100644 --- a/src/Libraries/SmartStore.Services/Filter/FilterExtensions.cs +++ b/src/Libraries/SmartStore.Services/Filter/FilterExtensions.cs @@ -17,6 +17,7 @@ private static string FormatPrice(string value) if (value.HasValue()) { decimal d = 0; + if (StringToPrice(value, out d)) return EngineContext.Current.Resolve().FormatPrice(d, true, false); } @@ -27,7 +28,7 @@ public static string ToDescription(this FilterCriteria criteria) { var localize = EngineContext.Current.Resolve(); - if (criteria == null || criteria.Value.IsNullOrEmpty()) + if (criteria == null || criteria.Value.IsEmpty()) return localize.GetResource("Common.Unspecified"); if (criteria.Operator == FilterOperator.RangeGreaterEqualLessEqual || criteria.Operator == FilterOperator.RangeGreaterEqualLess) @@ -35,38 +36,39 @@ public static string ToDescription(this FilterCriteria criteria) string valueLeft, valueRight; criteria.Value.SplitToPair(out valueLeft, out valueRight, "~"); - if (criteria.Entity == FilterService.ShortcutPrice) - return "{0} - {1}".FormatWith(FormatPrice(valueLeft), FormatPrice(valueRight)); + if (criteria.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutPrice)) + return "{0} - {1}".FormatInvariant(FormatPrice(valueLeft), FormatPrice(valueRight)); - return "{0} - {1}".FormatWith(valueLeft, valueRight); + return "{0} - {1}".FormatInvariant(valueLeft, valueRight); } - string value = criteria.Value; + var value = (criteria.ValueLocalized.HasValue() ? criteria.ValueLocalized : criteria.Value); - if (criteria.Entity == FilterService.ShortcutPrice) + if (criteria.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutPrice)) value = FormatPrice(criteria.Value); if (criteria.Operator == FilterOperator.Unequal) - return "≠ {0}".FormatWith(value); + return "≠ {0}".FormatInvariant(value); if (criteria.Operator == FilterOperator.Greater) - return "> {0}".FormatWith(value); + return "> {0}".FormatInvariant(value); if (criteria.Operator == FilterOperator.GreaterEqual) - return "≥ {0}".FormatWith(value); + return "≥ {0}".FormatInvariant(value); if (criteria.Operator == FilterOperator.Less) - return "< {0}".FormatWith(value); + return "< {0}".FormatInvariant(value); if (criteria.Operator == FilterOperator.LessEqual) - return "≤ {0}".FormatWith(value); + return "≤ {0}".FormatInvariant(value); if (criteria.Operator == FilterOperator.Contains) - return "{0} {1}".FormatWith(localize.GetResource("Products.Filter.Contains"), value); + return "{0} {1}".FormatInvariant(localize.GetResource("Products.Filter.Contains"), value); if (criteria.Operator == FilterOperator.StartsWith) - return "{0} {1}".FormatWith(localize.GetResource("Products.Filter.StartsWith"), value); + return "{0} {1}".FormatInvariant(localize.GetResource("Products.Filter.StartsWith"), value); if (criteria.Operator == FilterOperator.EndsWith) - return "{0} {1}".FormatWith(localize.GetResource("Products.Filter.EndsWith"), value); + return "{0} {1}".FormatInvariant(localize.GetResource("Products.Filter.EndsWith"), value); return value; } - public static FilterCriteria ParsePriceString(this string priceRange) { + public static FilterCriteria ParsePriceString(this string priceRange) + { try { if (priceRange.HasValue()) @@ -119,17 +121,20 @@ public static FilterCriteria ParsePriceString(this string priceRange) { } return null; } + public static bool StringToPrice(string value, out decimal result) { result = 0; return (value.HasValue() && decimal.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out result)); } + public static bool StringToPrice(this string[] range, int index, out decimal result) { result = 0; if (range != null && index < range.Length) { - string value = range[index].Trim(); + var value = range[index].Trim(); + return StringToPrice(value, out result); } return false; @@ -137,11 +142,11 @@ public static bool StringToPrice(this string[] range, int index, out decimal res public static string GetUrl(this FilterProductContext context, FilterCriteria criteriaAdd = null, FilterCriteria criteriaRemove = null) { - string url = "{0}?pagesize={1}&viewmode={2}".FormatWith(context.Path, context.PageSize, context.ViewMode); + var url = "{0}?pagesize={1}&viewmode={2}".FormatInvariant(context.Path, context.PageSize, context.ViewMode); if (context.OrderBy.HasValue) { - url = "{0}&orderby={1}".FormatWith(url, context.OrderBy.Value); + url = "{0}&orderby={1}".FormatInvariant(url, context.OrderBy.Value); } try @@ -156,10 +161,10 @@ public static string GetUrl(this FilterProductContext context, FilterCriteria cr if (criteriaAdd != null) criterias.Add(criteriaAdd); else - criterias.RemoveAll(c => c.Entity == criteriaRemove.Entity && c.Name == criteriaRemove.Name && c.Value == criteriaRemove.Value); + criterias.RemoveAll(c => c.Entity.IsCaseInsensitiveEqual(criteriaRemove.Entity) && c.Name.IsCaseInsensitiveEqual(criteriaRemove.Name) && c.Value.IsCaseInsensitiveEqual(criteriaRemove.Value)); if (criterias.Count > 0) - url = "{0}&filter={1}".FormatWith(url, HttpUtility.UrlEncode(JsonConvert.SerializeObject(criterias))); + url = "{0}&filter={1}".FormatInvariant(url, HttpUtility.UrlEncode(JsonConvert.SerializeObject(criterias))); } } catch (Exception exc) @@ -169,21 +174,17 @@ public static string GetUrl(this FilterProductContext context, FilterCriteria cr return url; } + public static bool IsActive(this FilterProductContext context, FilterCriteria criteria) { if (criteria != null && context.Criteria != null) { - return (context.Criteria.FirstOrDefault(c => c.Entity == criteria.Entity && c.Name == criteria.Name && c.Value == criteria.Value && !c.IsInactive) != null); + var foundCriteria = context.Criteria.FirstOrDefault(c => !c.IsInactive && + c.Entity.IsCaseInsensitiveEqual(criteria.Entity) && c.Name.IsCaseInsensitiveEqual(criteria.Name) && c.Value.IsCaseInsensitiveEqual(criteria.Value)); + + return (foundCriteria != null); } return false; } - - public static bool IsShowAllText(this IEnumerable criteriaGroup) - { - if (criteriaGroup.Any(c => c.Entity == FilterService.ShortcutPrice)) - return false; - - return (criteriaGroup.Count() >= FilterService.MaxDisplayCriteria || criteriaGroup.Any(c => !c.IsInactive)); - } } } diff --git a/src/Libraries/SmartStore.Services/Filter/FilterOperator.cs b/src/Libraries/SmartStore.Services/Filter/FilterOperator.cs index 0e5dc79bf1..ed49bed2b5 100644 --- a/src/Libraries/SmartStore.Services/Filter/FilterOperator.cs +++ b/src/Libraries/SmartStore.Services/Filter/FilterOperator.cs @@ -1,13 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Newtonsoft.Json; namespace SmartStore.Services.Filter { - /// codehint: sm-add public sealed class FilterOperator { private const string _equal = "="; @@ -24,7 +19,8 @@ public sealed class FilterOperator private readonly string _name; - private FilterOperator(string name) { + private FilterOperator(string name) + { this._name = name; } @@ -40,11 +36,14 @@ private FilterOperator(string name) { public static readonly FilterOperator RangeGreaterEqualLessEqual = new FilterOperator(_rangeGreaterEqualLessEqual); public static readonly FilterOperator RangeGreaterEqualLess = new FilterOperator(_rangeGreaterEqualLess); - public override string ToString() { + public override string ToString() + { return _name ?? "="; } - public static FilterOperator Parse(string op) { - switch (op) { + public static FilterOperator Parse(string op) + { + switch (op) + { case _equal: return FilterOperator.Equal; case _unequal: @@ -57,38 +56,46 @@ public static FilterOperator Parse(string op) { return FilterOperator.Less; case _lessEqual: return FilterOperator.LessEqual; - case _contains: - return FilterOperator.Contains; - case _startWith: - return FilterOperator.StartsWith; - case _endsWith: - return FilterOperator.EndsWith; case _rangeGreaterEqualLessEqual: return FilterOperator.RangeGreaterEqualLessEqual; case _rangeGreaterEqualLess: return FilterOperator.RangeGreaterEqualLess; + default: + if (op.IsCaseInsensitiveEqual(_contains)) + return FilterOperator.Contains; + + if (op.IsCaseInsensitiveEqual(_startWith)) + return FilterOperator.StartsWith; + + if (op.IsCaseInsensitiveEqual(_endsWith)) + return FilterOperator.EndsWith; + return null; } } - } // class + } public class OperatorConverter : JsonConverter { - public override bool CanConvert(Type objectType) { + public override bool CanConvert(Type objectType) + { return objectType == typeof(FilterOperator); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { writer.WriteValue(value.ToString()); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - if (reader != null && reader.TokenType == JsonToken.String) { + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader != null && reader.TokenType == JsonToken.String) + { return FilterOperator.Parse(reader.Value as string); } return null; } - } // class + } } diff --git a/src/Libraries/SmartStore.Services/Filter/FilterService.cs b/src/Libraries/SmartStore.Services/Filter/FilterService.cs index 422769a45e..507b1f2fed 100644 --- a/src/Libraries/SmartStore.Services/Filter/FilterService.cs +++ b/src/Libraries/SmartStore.Services/Filter/FilterService.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Linq.Dynamic; using System.Text; using Newtonsoft.Json; +using SmartStore.ComponentModel; +using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Infrastructure; using SmartStore.Services.Catalog; -using System.Linq.Dynamic; -using SmartStore.Core.Data; -using System.Globalization; -using SmartStore.Core; -using SmartStore.Utilities; +using SmartStore.Services.Localization; namespace SmartStore.Services.Filter { @@ -20,39 +20,43 @@ public partial class FilterService : IFilterService private readonly IProductService _productService; private readonly ICategoryService _categoryService; - private readonly IStoreContext _storeContext; + private readonly CatalogSettings _catalogSettings; + private readonly IRepository _productRepository; + private readonly IRepository _productCategoryRepository; + private readonly ILocalizedEntityService _localizedEntityService; + private readonly ICommonServices _services; + private IQueryable _products; - private bool? _includeFeatured; - public FilterService(IProductService productService, ICategoryService categoryService, IStoreContext storeContext) + public FilterService(IProductService productService, + ICategoryService categoryService, + CatalogSettings catalogSettings, + IRepository productRepository, + IRepository productCategoryRepository, + ILocalizedEntityService localizedEntityService, + ICommonServices services) { _productService = productService; _categoryService = categoryService; - _storeContext = storeContext; + _catalogSettings = catalogSettings; + _productRepository = productRepository; + _productCategoryRepository = productCategoryRepository; + _localizedEntityService = localizedEntityService; + _services = services; } - public static int MaxDisplayCriteria { get { return 4; } } - public static string ShortcutPrice { get { return "_Price"; } } public static string ShortcutSpecAttribute { get { return "_SpecId"; } } - public bool IncludeFeatured - { - get - { - if (_includeFeatured == null) - _includeFeatured = EngineContext.Current.Resolve().IncludeFeaturedProductsInNormalLists; - return _includeFeatured ?? false; - } - } - // helper private string ValidateValue(string value, string alternativeValue) { if (value.HasValue() && !value.IsCaseInsensitiveEqual("null")) return value; + return alternativeValue; } + private string FormatParameterIndex(ref int index) { //if (curlyBracketFormatting) @@ -60,6 +64,7 @@ private string FormatParameterIndex(ref int index) return "@{0}".FormatWith(index++); } + private object FilterValueToObject(string value, string type) { if (value == null) @@ -74,15 +79,16 @@ private object FilterValueToObject(string value, string type) //if (curlyBracketFormatting) // return value.FormatWith("\"{0}\"", value.Replace("\"", "\"\"")); - Type t = Type.GetType("System.{0}".FormatWith(ValidateValue(type, _defaultType))); + Type t = Type.GetType("System.{0}".FormatInvariant(ValidateValue(type, _defaultType))); - var result = CommonHelper.GetTypeConverter(t).ConvertFromString(null, CultureInfo.InvariantCulture, value); + var result = TypeConverterFactory.GetConverter(t).ConvertFrom(CultureInfo.InvariantCulture, value); return result; } + private bool IsShortcut(FilterSql context, FilterCriteria itm, ref int index) { - if (itm.Entity == ShortcutPrice) + if (itm.Entity.IsCaseInsensitiveEqual(ShortcutPrice)) { // TODO: where clause of special price not correct. product can appear in price and in special price range. @@ -113,7 +119,7 @@ private bool IsShortcut(FilterSql context, FilterCriteria itm, ref int index) context.Values.Add(DateTime.UtcNow); } } - else if (itm.Entity == ShortcutSpecAttribute) + else if (itm.Entity.IsCaseInsensitiveEqual(ShortcutSpecAttribute)) { context.WhereClause.AppendFormat("SpecificationAttributeOptionId {0} {1}", itm.Operator == null ? "=" : itm.Operator.ToString(), FormatParameterIndex(ref index)); @@ -125,6 +131,7 @@ private bool IsShortcut(FilterSql context, FilterCriteria itm, ref int index) } return true; } + private void FilterParentheses(List criteria) { // Logical or combine all criteria with same name. @@ -152,19 +159,40 @@ from c in criteria } } } + private IQueryable AllProducts(List categoryIds) { if (_products == null) { - var searchContext = new ProductSearchContext() + var searchContext = new ProductSearchContext { - CategoryIds = categoryIds, - FeaturedProducts = IncludeFeatured, - StoreId = _storeContext.CurrentStoreIdIfMultiStoreMode, + Query = _productRepository.TableUntracked, + FeaturedProducts = (_catalogSettings.IncludeFeaturedProductsInNormalLists ? null : (bool?)false), + StoreId = _services.StoreContext.CurrentStoreIdIfMultiStoreMode, VisibleIndividuallyOnly = true }; - _products = _productService.PrepareProductSearchQuery(searchContext); + if (categoryIds != null && categoryIds.Count > 1) + { + _products = _productService.PrepareProductSearchQuery(searchContext); + + var distinctIds = ( + from p in _productRepository.TableUntracked + join pc in _productCategoryRepository.TableUntracked on p.Id equals pc.ProductId + where categoryIds.Contains(pc.CategoryId) + select p.Id).Distinct(); + + _products = + from p in _products + join x in distinctIds on p.Id equals x + select p; + } + else + { + searchContext.CategoryIds = categoryIds; + + _products = _productService.PrepareProductSearchQuery(searchContext); + } } return _products; } @@ -212,32 +240,41 @@ private List ProductFilterablePrices(FilterProductContext contex result.ForEach(c => c.IsInactive = true); return result; } + private List ProductFilterableManufacturer(FilterProductContext context, bool getAll = false) { - bool includeFeatured = IncludeFeatured; var query = ProductFilter(context); var manus = from p in query from pm in p.ProductManufacturers - where pm.IsFeaturedProduct == includeFeatured && !pm.Manufacturer.Deleted + where !pm.Manufacturer.Deleted select pm.Manufacturer; var grouped = from m in manus - orderby m.DisplayOrder group m by m.Id into grp orderby grp.Key select new FilterCriteria { MatchCount = grp.Count(), - Value = grp.FirstOrDefault().Name + Value = grp.FirstOrDefault().Name, + DisplayOrder = grp.FirstOrDefault().DisplayOrder }; - grouped = grouped.OrderByDescending(m => m.MatchCount); + if (_catalogSettings.SortFilterResultsByMatches) + { + grouped = grouped.OrderByDescending(m => m.MatchCount); + } + else + { + grouped = grouped.OrderBy(m => m.DisplayOrder); + } if (!getAll) - grouped = grouped.Take(MaxDisplayCriteria); + { + grouped = grouped.Take(_catalogSettings.MaxFilterItemsToDisplay); + } var lst = grouped.ToList(); @@ -250,19 +287,23 @@ orderby grp.Key return lst; } + private List ProductFilterableSpecAttributes(FilterProductContext context, string attributeName = null) { + List criterias = null; + var languageId = _services.WorkContext.WorkingLanguage.Id; var query = ProductFilter(context); var attributes = from p in query from sa in p.ProductSpecificationAttributes where sa.AllowFiltering - orderby sa.DisplayOrder select sa.SpecificationAttributeOption; if (attributeName.HasValue()) + { attributes = attributes.Where(a => a.SpecificationAttribute.Name == attributeName); + } var grouped = from a in attributes @@ -272,19 +313,55 @@ from a in attributes Name = g.FirstOrDefault().SpecificationAttribute.Name, Value = g.FirstOrDefault().Name, ID = g.Key.Id, - MatchCount = g.Count() + PId = g.FirstOrDefault().SpecificationAttribute.Id, + MatchCount = g.Count(), + DisplayOrder = g.FirstOrDefault().SpecificationAttribute.DisplayOrder, + DisplayOrderValues = g.FirstOrDefault().DisplayOrder }; + if (_catalogSettings.SortFilterResultsByMatches) + { + criterias = grouped + .OrderBy(a => a.DisplayOrder) + .ThenByDescending(a => a.MatchCount) + .ThenBy(a => a.DisplayOrderValues) + .ToList(); + } + else + { + criterias = grouped + .OrderBy(a => a.DisplayOrder) + .ThenBy(a => a.DisplayOrderValues) + .ToList(); + } - var lst = grouped.OrderByDescending(a => a.MatchCount).ToList(); - - lst.ForEach(c => + criterias.ForEach(c => { c.Entity = ShortcutSpecAttribute; c.IsInactive = true; + + if (c.PId.HasValue) + c.NameLocalized = _localizedEntityService.GetLocalizedValue(languageId, c.PId.Value, "SpecificationAttribute", "Name"); + + if (c.ID.HasValue) + c.ValueLocalized = _localizedEntityService.GetLocalizedValue(languageId, c.ID.Value, "SpecificationAttributeOption", "Name"); }); - return lst; + return criterias; + } + + private void AddChildCategoryIds(List result, int categoryId) + { + var ids = _categoryService.GetAllCategoriesByParentCategoryId(categoryId).Select(x => x.Id); + + foreach (var id in ids) + { + if (!result.Contains(id)) + { + result.Add(id); + AddChildCategoryIds(result, id); + } + } } public virtual List Deserialize(string jsonData) @@ -300,14 +377,49 @@ public virtual List Deserialize(string jsonData) } return new List(); } + public virtual string Serialize(List criteria) { //criteria.FindAll(c => c.Type.IsNullOrEmpty()).ForEach(c => c.Type = _defaultType); if (criteria != null && criteria.Count > 0) return JsonConvert.SerializeObject(criteria); + return ""; } + public virtual FilterProductContext CreateFilterProductContext(string filter, int categoryID, string path, int? pagesize, int? orderby, string viewmode) + { + var context = new FilterProductContext + { + Filter = filter, + ParentCategoryID = categoryID, + CategoryIds = new List { categoryID }, + Path = path, + PageSize = pagesize ?? 12, + ViewMode = viewmode, + OrderBy = orderby, + Criteria = Deserialize(filter) + }; + + if (_catalogSettings.ShowProductsFromSubcategories) + { + AddChildCategoryIds(context.CategoryIds, categoryID); + } + + int languageId = _services.WorkContext.WorkingLanguage.Id; + + foreach (var criteria in context.Criteria.Where(x => x.Entity.IsCaseInsensitiveEqual(ShortcutSpecAttribute))) + { + if (criteria.PId.HasValue) + criteria.NameLocalized = _localizedEntityService.GetLocalizedValue(languageId, criteria.PId.Value, "SpecificationAttribute", "Name"); + + if (criteria.ID.HasValue) + criteria.ValueLocalized = _localizedEntityService.GetLocalizedValue(languageId, criteria.ID.Value, "SpecificationAttributeOption", "Name"); + } + + return context; + } + public virtual bool ToWhereClause(FilterSql context) { if (context.Values == null) @@ -350,7 +462,7 @@ public virtual bool ToWhereClause(FilterSql context) context.Values.Add(FilterValueToObject(valueLeft, itm.Type)); context.Values.Add(FilterValueToObject(valueRight, itm.Type)); } - else if (itm.Value.IsNullOrEmpty()) + else if (itm.Value.IsEmpty()) { context.WhereClause.AppendFormat("ASCII({0}) Is Null", itm.SqlName); // true if null or empty (string) } @@ -380,12 +492,14 @@ public virtual bool ToWhereClause(FilterSql context) } return (context.WhereClause.Length > 0); } + public virtual bool ToWhereClause(FilterSql context, List findIn, Predicate match) { if (context.Criteria != null) context.Criteria.Clear(); // ! context.Criteria = findIn.FindAll(match); + return ToWhereClause(context); } @@ -395,27 +509,27 @@ public virtual IQueryable ProductFilter(FilterProductContext context) var query = AllProducts(context.CategoryIds); // prices - if (ToWhereClause(sql, context.Criteria, c => !c.IsInactive && c.Entity == ShortcutPrice)) + if (ToWhereClause(sql, context.Criteria, c => !c.IsInactive && c.Entity.IsCaseInsensitiveEqual(ShortcutPrice))) { query = query.Where(sql.WhereClause.ToString(), sql.Values.ToArray()); } // manufacturer - if (ToWhereClause(sql, context.Criteria, c => !c.IsInactive && c.Entity == "Manufacturer")) + if (ToWhereClause(sql, context.Criteria, c => !c.IsInactive && c.Entity.IsCaseInsensitiveEqual("Manufacturer"))) { - bool includeFeatured = IncludeFeatured; - - var pmq = ( + var pmq = from p in query from pm in p.ProductManufacturers - where (!includeFeatured || includeFeatured == pm.IsFeaturedProduct) && !pm.Manufacturer.Deleted - select pm).Where(sql.WhereClause.ToString(), sql.Values.ToArray()); + where !pm.Manufacturer.Deleted + select pm; - query = pmq.Select(pm => pm.Product); + query = pmq + .Where(sql.WhereClause.ToString(), sql.Values.ToArray()) + .Select(pm => pm.Product); } // specification attribute - if (ToWhereClause(sql, context.Criteria, c => !c.IsInactive && (c.Entity == "SpecificationAttributeOption" || c.Entity == ShortcutSpecAttribute))) + if (ToWhereClause(sql, context.Criteria, c => !c.IsInactive && (c.Entity.IsCaseInsensitiveEqual("SpecificationAttributeOption") || c.Entity.IsCaseInsensitiveEqual(ShortcutSpecAttribute)))) { //var saq = ( // from p in query @@ -425,13 +539,13 @@ from pm in p.ProductManufacturers //query = saq.Select(sa => sa.Product); int countSameNameAttributes = sql.Criteria - .Where(c => c.Entity == ShortcutSpecAttribute) + .Where(c => c.Entity.IsCaseInsensitiveEqual(ShortcutSpecAttribute)) .GroupBy(c => c.Name) .Count(); var specRepository = EngineContext.Current.Resolve>(); - var saq = specRepository.Table + var saq = specRepository.TableUntracked .Where(a => a.AllowFiltering) .Where(sql.WhereClause.ToString(), sql.Values.ToArray()) .GroupBy(a => a.ProductId) @@ -467,8 +581,7 @@ join sa in saq on p.Id equals sa.Key break; } - - // distinct (required?) + // distinct cause same products can be mapped to sub-categories... too slow //query = // from p in query // group p by p.Id into grp @@ -481,14 +594,15 @@ join sa in saq on p.Id equals sa.Key public virtual void ProductFilterable(FilterProductContext context) { - if (context.Criteria.FirstOrDefault(c => c.Entity == FilterService.ShortcutPrice) == null) + if (context.Criteria.FirstOrDefault(c => c.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutPrice)) == null) context.Criteria.AddRange(ProductFilterablePrices(context)); - if (context.Criteria.FirstOrDefault(c => c.Name == "Name" && c.Entity == "Manufacturer") == null) + if (context.Criteria.FirstOrDefault(c => c.Name.IsCaseInsensitiveEqual("Name") && c.Entity.IsCaseInsensitiveEqual("Manufacturer")) == null) context.Criteria.AddRange(ProductFilterableManufacturer(context)); context.Criteria.AddRange(ProductFilterableSpecAttributes(context)); } + public virtual void ProductFilterableMultiSelect(FilterProductContext context, string filterMultiSelect) { var criteriaMultiSelect = Deserialize(filterMultiSelect).FirstOrDefault(); @@ -496,18 +610,18 @@ public virtual void ProductFilterableMultiSelect(FilterProductContext context, s if (criteriaMultiSelect != null) { - context.Criteria.RemoveAll(c => c.Name == criteriaMultiSelect.Name && c.Entity == criteriaMultiSelect.Entity); + context.Criteria.RemoveAll(c => c.Name.IsCaseInsensitiveEqual(criteriaMultiSelect.Name) && c.Entity.IsCaseInsensitiveEqual(criteriaMultiSelect.Entity)); - if (criteriaMultiSelect.Name == "Name" && criteriaMultiSelect.Entity == "Manufacturer") + if (criteriaMultiSelect.Name.IsCaseInsensitiveEqual("Name") && criteriaMultiSelect.Entity.IsCaseInsensitiveEqual("Manufacturer")) inactive = ProductFilterableManufacturer(context, true); - else if (criteriaMultiSelect.Entity == FilterService.ShortcutPrice) + else if (criteriaMultiSelect.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutPrice)) inactive = ProductFilterablePrices(context); - else if (criteriaMultiSelect.Entity == FilterService.ShortcutSpecAttribute) + else if (criteriaMultiSelect.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutSpecAttribute)) inactive = ProductFilterableSpecAttributes(context, criteriaMultiSelect.Name); } // filters WITHOUT the multiple selectable filters - string excludedFilter = Serialize(context.Criteria); + var excludedFilter = Serialize(context.Criteria); // filters WITH the multiple selectable filters (required for highlighting selected values) context.Criteria = Deserialize(context.Filter); diff --git a/src/Libraries/SmartStore.Services/Filter/IFilterService.cs b/src/Libraries/SmartStore.Services/Filter/IFilterService.cs index 0a38d10769..f27c9ff91f 100644 --- a/src/Libraries/SmartStore.Services/Filter/IFilterService.cs +++ b/src/Libraries/SmartStore.Services/Filter/IFilterService.cs @@ -7,11 +7,11 @@ namespace SmartStore.Services.Filter { public partial interface IFilterService { - bool IncludeFeatured { get; } - List Deserialize(string jsonData); string Serialize(List criteria); + FilterProductContext CreateFilterProductContext(string filter, int categoryID, string path, int? pagesize, int? orderby, string viewmode); + bool ToWhereClause(FilterSql context); bool ToWhereClause(FilterSql context, List findIn, Predicate match); diff --git a/src/Libraries/SmartStore.Services/Forums/ForumService.cs b/src/Libraries/SmartStore.Services/Forums/ForumService.cs index 54dc1cf9b2..5871f34ab6 100644 --- a/src/Libraries/SmartStore.Services/Forums/ForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/ForumService.cs @@ -6,6 +6,7 @@ using SmartStore.Core.Data; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; using SmartStore.Services.Common; using SmartStore.Services.Customers; @@ -19,13 +20,16 @@ namespace SmartStore.Services.Forums public partial class ForumService : IForumService { #region Constants - private const string FORUMGROUP_ALL_KEY = "SmartStore.forumgroup.all"; + + private const string FORUMGROUP_ALL_KEY = "SmartStore.forumgroup.all-{0}"; private const string FORUM_ALLBYFORUMGROUPID_KEY = "SmartStore.forum.allbyforumgroupid-{0}"; private const string FORUMGROUP_PATTERN_KEY = "SmartStore.forumgroup."; private const string FORUM_PATTERN_KEY = "SmartStore.forum."; - #endregion + + #endregion #region Fields + private readonly IRepository _forumGroupRepository; private readonly IRepository _forumRepository; private readonly IRepository _forumTopicRepository; @@ -37,31 +41,14 @@ public partial class ForumService : IForumService private readonly ICacheManager _cacheManager; private readonly IGenericAttributeService _genericAttributeService; private readonly ICustomerService _customerService; - private readonly IWorkContext _workContext; private readonly IWorkflowMessageService _workflowMessageService; - private readonly IEventPublisher _eventPublisher; + private readonly IRepository _storeMappingRepository; + private readonly ICommonServices _services; #endregion #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// Forum group repository - /// Forum repository - /// Forum topic repository - /// Forum post repository - /// Private message repository - /// Forum subscription repository - /// Forum settings - /// Customer repository - /// Generic attribute service - /// Customer service - /// Work context - /// Workflow message service - /// Event published public ForumService(ICacheManager cacheManager, IRepository forumGroupRepository, IRepository forumRepository, @@ -73,27 +60,29 @@ public ForumService(ICacheManager cacheManager, IRepository customerRepository, IGenericAttributeService genericAttributeService, ICustomerService customerService, - IWorkContext workContext, IWorkflowMessageService workflowMessageService, - IEventPublisher eventPublisher - ) + IRepository storeMappingRepository, + ICommonServices services) { - this._cacheManager = cacheManager; - this._forumGroupRepository = forumGroupRepository; - this._forumRepository = forumRepository; - this._forumTopicRepository = forumTopicRepository; - this._forumPostRepository = forumPostRepository; - this._forumPrivateMessageRepository = forumPrivateMessageRepository; - this._forumSubscriptionRepository = forumSubscriptionRepository; - this._forumSettings = forumSettings; - this._customerRepository = customerRepository; - this._genericAttributeService = genericAttributeService; - this._customerService = customerService; - this._workContext = workContext; - this._workflowMessageService = workflowMessageService; - _eventPublisher = eventPublisher; + _cacheManager = cacheManager; + _forumGroupRepository = forumGroupRepository; + _forumRepository = forumRepository; + _forumTopicRepository = forumTopicRepository; + _forumPostRepository = forumPostRepository; + _forumPrivateMessageRepository = forumPrivateMessageRepository; + _forumSubscriptionRepository = forumSubscriptionRepository; + _forumSettings = forumSettings; + _customerRepository = customerRepository; + _genericAttributeService = genericAttributeService; + _customerService = customerService; + _workflowMessageService = workflowMessageService; + _storeMappingRepository = storeMappingRepository; + _services = services; } - #endregion + + public DbQuerySettings QuerySettings { get; set; } + + #endregion #region Utilities @@ -268,7 +257,7 @@ public virtual void DeleteForumGroup(ForumGroup forumGroup) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forumGroup); + _services.EventPublisher.EntityDeleted(forumGroup); } /// @@ -288,14 +277,33 @@ public virtual ForumGroup GetForumGroupById(int forumGroupId) /// Gets all forum groups /// /// Forum groups - public virtual IList GetAllForumGroups() + public virtual IList GetAllForumGroups(bool showHidden = false) { - string key = string.Format(FORUMGROUP_ALL_KEY); + string key = string.Format(FORUMGROUP_ALL_KEY, showHidden); return _cacheManager.Get(key, () => { - var query = from fg in _forumGroupRepository.Table - orderby fg.DisplayOrder - select fg; + var query = _forumGroupRepository.Table; + + if (!showHidden && !QuerySettings.IgnoreMultiStore) + { + var currentStoreId = _services.StoreContext.CurrentStore.Id; + + query = + from fg in query + join sm in _storeMappingRepository.Table on new { c1 = fg.Id, c2 = "ForumGroup" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into fg_sm + from sm in fg_sm.DefaultIfEmpty() + where !fg.LimitedToStores || currentStoreId == sm.StoreId + select fg; + + query = + from fg in query + group fg by fg.Id into fgGroup + orderby fgGroup.Key + select fgGroup.FirstOrDefault(); + } + + query = query.OrderBy(m => m.DisplayOrder); + return query.ToList(); }); } @@ -318,7 +326,7 @@ public virtual void InsertForumGroup(ForumGroup forumGroup) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forumGroup); + _services.EventPublisher.EntityInserted(forumGroup); } /// @@ -339,7 +347,7 @@ public virtual void UpdateForumGroup(ForumGroup forumGroup) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forumGroup); + _services.EventPublisher.EntityUpdated(forumGroup); } /// @@ -364,7 +372,7 @@ where queryTopicIds.Contains(fs.TopicId) { _forumSubscriptionRepository.Delete(fs); //event notification - _eventPublisher.EntityDeleted(fs); + _services.EventPublisher.EntityDeleted(fs); } //delete forum subscriptions (forum) @@ -375,7 +383,7 @@ where queryTopicIds.Contains(fs.TopicId) { _forumSubscriptionRepository.Delete(fs2); //event notification - _eventPublisher.EntityDeleted(fs2); + _services.EventPublisher.EntityDeleted(fs2); } //delete forum @@ -385,7 +393,7 @@ where queryTopicIds.Contains(fs.TopicId) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forum); + _services.EventPublisher.EntityDeleted(forum); } /// @@ -437,7 +445,7 @@ public virtual void InsertForum(Forum forum) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forum); + _services.EventPublisher.EntityInserted(forum); } /// @@ -457,7 +465,7 @@ public virtual void UpdateForum(Forum forum) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forum); + _services.EventPublisher.EntityUpdated(forum); } /// @@ -486,7 +494,7 @@ public virtual void DeleteTopic(ForumTopic forumTopic) { _forumSubscriptionRepository.Delete(fs); //event notification - _eventPublisher.EntityDeleted(fs); + _services.EventPublisher.EntityDeleted(fs); } //update stats @@ -497,7 +505,7 @@ public virtual void DeleteTopic(ForumTopic forumTopic) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forumTopic); + _services.EventPublisher.EntityDeleted(forumTopic); } /// @@ -552,32 +560,33 @@ public virtual ForumTopic GetTopicById(int forumTopicId, bool increaseViews) /// Page index /// Page size /// Forum Topics - public virtual IPagedList GetAllTopics(int forumId, - int customerId, string keywords, ForumSearchType searchType, - int limitDays, int pageIndex, int pageSize) + public virtual IPagedList GetAllTopics(int forumId, int customerId, string keywords, ForumSearchType searchType, int limitDays, int pageIndex, int pageSize) { DateTime? limitDate = null; + if (limitDays > 0) { limitDate = DateTime.UtcNow.AddDays(-limitDays); } - var query1 = from ft in _forumTopicRepository.Table - join fp in _forumPostRepository.Table on ft.Id equals fp.TopicId - where - (forumId == 0 || ft.ForumId == forumId) && - (customerId == 0 || ft.CustomerId == customerId) && - ( - // following line causes SqlCeException on SQLCE4 (comparing parameter to IS NULL in query) -works on SQL Server - // String.IsNullOrEmpty(keywords) || - ((searchType == ForumSearchType.All || searchType == ForumSearchType.TopicTitlesOnly) && ft.Subject.Contains(keywords)) || - ((searchType == ForumSearchType.All || searchType == ForumSearchType.PostTextOnly) && fp.Text.Contains(keywords))) && - (!limitDate.HasValue || limitDate.Value <= ft.LastPostTime) - select ft.Id; - - var query2 = from ft in _forumTopicRepository.Table - where query1.Contains(ft.Id) - orderby ft.TopicTypeId descending, ft.LastPostTime descending, ft.Id descending - select ft; + + var query1 = + from ft in _forumTopicRepository.Table + join fp in _forumPostRepository.Table on ft.Id equals fp.TopicId + where + (forumId == 0 || ft.ForumId == forumId) && + (customerId == 0 || ft.CustomerId == customerId) && + (!limitDate.HasValue || limitDate.Value <= ft.LastPostTime) && + ( + ((searchType == ForumSearchType.All || searchType == ForumSearchType.TopicTitlesOnly) && ft.Subject.Contains(keywords)) || + ((searchType == ForumSearchType.All || searchType == ForumSearchType.PostTextOnly) && fp.Text.Contains(keywords)) + ) + select ft.Id; + + var query2 = + from ft in _forumTopicRepository.Table + where query1.Contains(ft.Id) + orderby ft.TopicTypeId descending, ft.LastPostTime descending, ft.Id descending + select ft; var topics = new PagedList(query2, pageIndex, pageSize); return topics; @@ -591,18 +600,34 @@ where query1.Contains(ft.Id) /// Forum Topics public virtual IList GetActiveTopics(int forumId, int count) { - var query1 = from ft in _forumTopicRepository.Table - where - (forumId == 0 || ft.ForumId == forumId) && - (ft.LastPostTime.HasValue) - select ft.Id; - - var query2 = from ft in _forumTopicRepository.Table - where query1.Contains(ft.Id) - orderby ft.LastPostTime descending - select ft; - - var forumTopics = query2.Take(count).ToList(); + var query = + from ft in _forumTopicRepository.Table + where (forumId == 0 || ft.ForumId == forumId) && (ft.LastPostTime.HasValue) + select ft; + + if (!QuerySettings.IgnoreMultiStore) + { + var currentStoreId = _services.StoreContext.CurrentStore.Id; + + query = + from ft in query + join ff in _forumRepository.Table on ft.ForumId equals ff.Id + join fg in _forumGroupRepository.Table on ff.ForumGroupId equals fg.Id + join sm in _storeMappingRepository.Table on new { c1 = fg.Id, c2 = "ForumGroup" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into fg_sm + from sm in fg_sm.DefaultIfEmpty() + where !fg.LimitedToStores || currentStoreId == sm.StoreId + select ft; + + query = + from ft in query + group ft by ft.Id into ftGroup + orderby ftGroup.Key + select ftGroup.FirstOrDefault(); + } + + query = query.OrderByDescending(x => x.LastPostTime); + + var forumTopics = query.Take(count).ToList(); return forumTopics; } @@ -628,14 +653,14 @@ public virtual void InsertTopic(ForumTopic forumTopic, bool sendNotifications) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forumTopic); + _services.EventPublisher.EntityInserted(forumTopic); //send notifications if (sendNotifications) { var forum = forumTopic.Forum; var subscriptions = GetAllSubscriptions(0, forum.Id, 0, 0, int.MaxValue); - var languageId = _workContext.WorkingLanguage.Id; + var languageId = _services.WorkContext.WorkingLanguage.Id; foreach (var subscription in subscriptions) { @@ -646,8 +671,7 @@ public virtual void InsertTopic(ForumTopic forumTopic, bool sendNotifications) if (!String.IsNullOrEmpty(subscription.Customer.Email)) { - _workflowMessageService.SendNewForumTopicMessage(subscription.Customer, forumTopic, - forum, languageId); + _workflowMessageService.SendNewForumTopicMessage(subscription.Customer, forumTopic, forum, languageId); } } } @@ -670,7 +694,7 @@ public virtual void UpdateTopic(ForumTopic forumTopic) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forumTopic); + _services.EventPublisher.EntityUpdated(forumTopic); } /// @@ -685,7 +709,7 @@ public virtual ForumTopic MoveTopic(int forumTopicId, int newForumId) if (forumTopic == null) return forumTopic; - if (this.IsCustomerAllowedToMoveTopic(_workContext.CurrentCustomer, forumTopic)) + if (this.IsCustomerAllowedToMoveTopic(_services.WorkContext.CurrentCustomer, forumTopic)) { int previousForumId = forumTopic.ForumId; var newForum = GetForumById(newForumId); @@ -725,7 +749,7 @@ public virtual void DeletePost(ForumPost forumPost) //delete topic if it was the first post bool deleteTopic = false; - ForumPost firstPost = forumTopic.GetFirstPost(this); + var firstPost = forumTopic.GetFirstPost(this); if (firstPost != null && firstPost.Id == forumPost.Id) { deleteTopic = true; @@ -753,7 +777,7 @@ public virtual void DeletePost(ForumPost forumPost) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityDeleted(forumPost); + _services.EventPublisher.EntityDeleted(forumPost); } @@ -786,11 +810,9 @@ public virtual ForumPost GetPostById(int forumPostId) /// Page index /// Page size /// Posts - public virtual IPagedList GetAllPosts(int forumTopicId, - int customerId, string keywords, int pageIndex, int pageSize) + public virtual IPagedList GetAllPosts(int forumTopicId, int customerId, string keywords, int pageIndex, int pageSize) { - return GetAllPosts(forumTopicId, customerId, keywords, true, - pageIndex, pageSize); + return GetAllPosts(forumTopicId, customerId, keywords, true, pageIndex, pageSize); } /// @@ -803,8 +825,7 @@ public virtual IPagedList GetAllPosts(int forumTopicId, /// Page index /// Page size /// Forum Posts - public virtual IPagedList GetAllPosts(int forumTopicId, int customerId, - string keywords, bool ascSort, int pageIndex, int pageSize) + public virtual IPagedList GetAllPosts(int forumTopicId, int customerId, string keywords, bool ascSort, int pageIndex, int pageSize) { var query = _forumPostRepository.Table; if (forumTopicId > 0) @@ -860,20 +881,17 @@ public virtual void InsertPost(ForumPost forumPost, bool sendNotifications) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityInserted(forumPost); + _services.EventPublisher.EntityInserted(forumPost); //notifications if (sendNotifications) { var forum = forumTopic.Forum; - var subscriptions = GetAllSubscriptions(0, 0, - forumTopic.Id, 0, int.MaxValue); + var subscriptions = GetAllSubscriptions(0, 0, forumTopic.Id, 0, int.MaxValue); - var languageId = _workContext.WorkingLanguage.Id; + var languageId = _services.WorkContext.WorkingLanguage.Id; - int friendlyTopicPageIndex = CalculateTopicPageIndex(forumPost.TopicId, - _forumSettings.PostsPageSize > 0 ? _forumSettings.PostsPageSize : 10, - forumPost.Id) + 1; + int friendlyTopicPageIndex = CalculateTopicPageIndex(forumPost.TopicId, _forumSettings.PostsPageSize > 0 ? _forumSettings.PostsPageSize : 10, forumPost.Id) + 1; foreach (ForumSubscription subscription in subscriptions) { @@ -884,8 +902,7 @@ public virtual void InsertPost(ForumPost forumPost, bool sendNotifications) if (!String.IsNullOrEmpty(subscription.Customer.Email)) { - _workflowMessageService.SendNewForumPostMessage(subscription.Customer, forumPost, - forumTopic, forum, friendlyTopicPageIndex, languageId); + _workflowMessageService.SendNewForumPostMessage(subscription.Customer, forumPost, forumTopic, forum, friendlyTopicPageIndex, languageId); } } } @@ -909,7 +926,7 @@ public virtual void UpdatePost(ForumPost forumPost) _cacheManager.RemoveByPattern(FORUM_PATTERN_KEY); //event notification - _eventPublisher.EntityUpdated(forumPost); + _services.EventPublisher.EntityUpdated(forumPost); } /// @@ -926,7 +943,7 @@ public virtual void DeletePrivateMessage(PrivateMessage privateMessage) _forumPrivateMessageRepository.Delete(privateMessage); //event notification - _eventPublisher.EntityDeleted(privateMessage); + _services.EventPublisher.EntityDeleted(privateMessage); } /// @@ -1005,7 +1022,7 @@ public virtual void InsertPrivateMessage(PrivateMessage privateMessage) _forumPrivateMessageRepository.Insert(privateMessage); //event notification - _eventPublisher.EntityInserted(privateMessage); + _services.EventPublisher.EntityInserted(privateMessage); var customerTo = _customerService.GetCustomerById(privateMessage.ToCustomerId); if (customerTo == null) @@ -1019,7 +1036,7 @@ public virtual void InsertPrivateMessage(PrivateMessage privateMessage) //Email notification if (_forumSettings.NotifyAboutPrivateMessages) { - _workflowMessageService.SendPrivateMessageNotification(privateMessage, _workContext.WorkingLanguage.Id); + _workflowMessageService.SendPrivateMessageNotification(customerTo, privateMessage, _services.WorkContext.WorkingLanguage.Id); } } @@ -1036,13 +1053,13 @@ public virtual void UpdatePrivateMessage(PrivateMessage privateMessage) { _forumPrivateMessageRepository.Delete(privateMessage); //event notification - _eventPublisher.EntityDeleted(privateMessage); + _services.EventPublisher.EntityDeleted(privateMessage); } else { _forumPrivateMessageRepository.Update(privateMessage); //event notification - _eventPublisher.EntityUpdated(privateMessage); + _services.EventPublisher.EntityUpdated(privateMessage); } } @@ -1060,7 +1077,7 @@ public virtual void DeleteSubscription(ForumSubscription forumSubscription) _forumSubscriptionRepository.Delete(forumSubscription); //event notification - _eventPublisher.EntityDeleted(forumSubscription); + _services.EventPublisher.EntityDeleted(forumSubscription); } /// @@ -1092,22 +1109,23 @@ public virtual ForumSubscription GetSubscriptionById(int forumSubscriptionId) /// Page index /// Page size /// Forum subscriptions - public virtual IPagedList GetAllSubscriptions(int customerId, int forumId, - int topicId, int pageIndex, int pageSize) + public virtual IPagedList GetAllSubscriptions(int customerId, int forumId, int topicId, int pageIndex, int pageSize) { - var fsQuery = from fs in _forumSubscriptionRepository.Table - join c in _customerRepository.Table on fs.CustomerId equals c.Id - where - (customerId == 0 || fs.CustomerId == customerId) && - (forumId == 0 || fs.ForumId == forumId) && - (topicId == 0 || fs.TopicId == topicId) && - (c.Active && !c.Deleted) - select fs.SubscriptionGuid; - - var query = from fs in _forumSubscriptionRepository.Table - where fsQuery.Contains(fs.SubscriptionGuid) - orderby fs.CreatedOnUtc descending, fs.SubscriptionGuid descending - select fs; + var fsQuery = + from fs in _forumSubscriptionRepository.Table + join c in _customerRepository.Table on fs.CustomerId equals c.Id + where + (customerId == 0 || fs.CustomerId == customerId) && + (forumId == 0 || fs.ForumId == forumId) && + (topicId == 0 || fs.TopicId == topicId) && + (c.Active && !c.Deleted) + select fs.SubscriptionGuid; + + var query = + from fs in _forumSubscriptionRepository.Table + where fsQuery.Contains(fs.SubscriptionGuid) + orderby fs.CreatedOnUtc descending, fs.SubscriptionGuid descending + select fs; var forumSubscriptions = new PagedList(query, pageIndex, pageSize); return forumSubscriptions; @@ -1127,7 +1145,7 @@ public virtual void InsertSubscription(ForumSubscription forumSubscription) _forumSubscriptionRepository.Insert(forumSubscription); //event notification - _eventPublisher.EntityInserted(forumSubscription); + _services.EventPublisher.EntityInserted(forumSubscription); } /// @@ -1144,7 +1162,7 @@ public virtual void UpdateSubscription(ForumSubscription forumSubscription) _forumSubscriptionRepository.Update(forumSubscription); //event notification - _eventPublisher.EntityUpdated(forumSubscription); + _services.EventPublisher.EntityUpdated(forumSubscription); } /// @@ -1438,8 +1456,7 @@ public virtual bool IsCustomerAllowedToSubscribe(Customer customer) public virtual int CalculateTopicPageIndex(int forumTopicId, int pageSize, int postId) { int pageIndex = 0; - var forumPosts = GetAllPosts(forumTopicId, 0, - string.Empty, true, 0, int.MaxValue); + var forumPosts = GetAllPosts(forumTopicId, 0, string.Empty, true, 0, int.MaxValue); for (int i = 0; i < forumPosts.TotalCount; i++) { @@ -1454,6 +1471,7 @@ public virtual int CalculateTopicPageIndex(int forumTopicId, int pageSize, int p return pageIndex; } - #endregion + + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Forums/IForumService.cs b/src/Libraries/SmartStore.Services/Forums/IForumService.cs index a0de486d1c..46e0f2f428 100644 --- a/src/Libraries/SmartStore.Services/Forums/IForumService.cs +++ b/src/Libraries/SmartStore.Services/Forums/IForumService.cs @@ -27,7 +27,7 @@ public partial interface IForumService /// Gets all forum groups /// /// Forum groups - IList GetAllForumGroups(); + IList GetAllForumGroups(bool showHidden = false); /// /// Inserts a forum group @@ -105,9 +105,7 @@ public partial interface IForumService /// Page index /// Page size /// Forum Topics - IPagedList GetAllTopics(int forumId, - int customerId, string keywords, ForumSearchType searchType, - int limitDays, int pageIndex, int pageSize); + IPagedList GetAllTopics(int forumId, int customerId, string keywords, ForumSearchType searchType, int limitDays, int pageIndex, int pageSize); /// /// Gets active forum topics diff --git a/src/Libraries/SmartStore.Services/Hooks/SlugSupportedPostDeleteHook.cs b/src/Libraries/SmartStore.Services/Hooks/SlugSupportedPostDeleteHook.cs new file mode 100644 index 0000000000..9c7c0cbb49 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Hooks/SlugSupportedPostDeleteHook.cs @@ -0,0 +1,31 @@ +using System; +using SmartStore.Core; +using SmartStore.Core.Data.Hooks; +using SmartStore.Core.Domain.Seo; +using SmartStore.Services.Seo; + +namespace SmartStore.Services.Common +{ + public class SlugSupportedPostDeleteHook : PostDeleteHook + { + private readonly Lazy _urlRecordService; + + public SlugSupportedPostDeleteHook(Lazy urlRecordService) + { + this._urlRecordService = urlRecordService; + } + + public override void Hook(ISlugSupported entity, HookEntityMetadata metadata) + { + var baseEntity = entity as BaseEntity; + + if (baseEntity == null) + return; + + var entityType = baseEntity.GetUnproxiedType(); + + var records = _urlRecordService.Value.GetUrlRecordsFor(entityType.Name, baseEntity.Id); + records.Each(x => _urlRecordService.Value.DeleteUrlRecord(x)); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Hooks/SoftDeletablePreUpdateHook.cs b/src/Libraries/SmartStore.Services/Hooks/SoftDeletablePreUpdateHook.cs index ae87d21fa5..82e9a734cd 100644 --- a/src/Libraries/SmartStore.Services/Hooks/SoftDeletablePreUpdateHook.cs +++ b/src/Libraries/SmartStore.Services/Hooks/SoftDeletablePreUpdateHook.cs @@ -1,22 +1,22 @@ -using System; +using Autofac; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Data.Hooks; using SmartStore.Core.Domain.Security; +using SmartStore.Core.Domain.Seo; using SmartStore.Services.Security; +using SmartStore.Services.Seo; namespace SmartStore.Services.Hooks { public class SoftDeletablePreUpdateHook : PreUpdateHook { - private readonly Lazy _aclService; - private readonly Lazy _dbContext; + private readonly IComponentContext _ctx; - public SoftDeletablePreUpdateHook(Lazy aclService, Lazy dbContext) + public SoftDeletablePreUpdateHook(IComponentContext ctx) { - this._aclService = aclService; - this._dbContext = dbContext; + this._ctx = ctx; } public override void Hook(ISoftDeletable entity, HookEntityMetadata metadata) @@ -26,22 +26,48 @@ public override void Hook(ISoftDeletable entity, HookEntityMetadata metadata) if (baseEntity == null) return; - var aclEntity = baseEntity as IAclSupported; - if (aclEntity == null || !aclEntity.SubjectToAcl) + var dbContext = _ctx.Resolve(); + var modifiedProps = dbContext.GetModifiedProperties(baseEntity); + + if (!modifiedProps.ContainsKey("Deleted")) return; - var ctx = _dbContext.Value; - var modProps = ctx.GetModifiedProperties(baseEntity); - if (modProps.ContainsKey("Deleted")) + var entityType = baseEntity.GetUnproxiedType(); + + using (var scope = new DbContextScope(ctx: dbContext, autoCommit: false)) { - var shouldSetIdle = entity.Deleted; - var entityType = baseEntity.GetUnproxiedType(); + // mark orphaned ACL records as idle + var aclSupported = baseEntity as IAclSupported; + if (aclSupported != null && aclSupported.SubjectToAcl) + { + var shouldSetIdle = entity.Deleted; + var rsAclRecord = _ctx.Resolve>(); - var records = _aclService.Value.GetAclRecordsFor(entityType.Name, baseEntity.Id); - foreach (var record in records) + var aclService = _ctx.Resolve(); + var records = aclService.GetAclRecordsFor(entityType.Name, baseEntity.Id); + foreach (var record in records) + { + record.IsIdle = shouldSetIdle; + aclService.UpdateAclRecord(record); + } + } + + // Delete orphaned inactive UrlRecords. + // We keep the active ones on purpose in order to be able to fully restore a soft deletable entity once we implemented the "recycle bin" feature + var slugSupported = baseEntity as ISlugSupported; + if (slugSupported != null && entity.Deleted) { - record.IsIdle = shouldSetIdle; - _aclService.Value.UpdateAclRecord(record); + var rsUrlRecord = _ctx.Resolve>(); + + var urlRecordService = _ctx.Resolve(); + var activeRecords = urlRecordService.GetUrlRecordsFor(entityType.Name, baseEntity.Id); + foreach (var record in activeRecords) + { + if (!record.IsActive) + { + urlRecordService.DeleteUrlRecord(record); + } + } } } } diff --git a/src/Libraries/SmartStore.Services/Hooks/StoreMappingEntityPostDeleteHook.cs b/src/Libraries/SmartStore.Services/Hooks/StoreMappingEntityPostDeleteHook.cs new file mode 100644 index 0000000000..212ef2626f --- /dev/null +++ b/src/Libraries/SmartStore.Services/Hooks/StoreMappingEntityPostDeleteHook.cs @@ -0,0 +1,36 @@ +using System; +using System.Linq; +using SmartStore.Core; +using SmartStore.Core.Data.Hooks; +using SmartStore.Core.Domain.Security; +using SmartStore.Core.Domain.Stores; +using SmartStore.Services.Stores; + +namespace SmartStore.Services.Common +{ + public class StoreMappingEntityPostDeleteHook : PostDeleteHook + { + private readonly Lazy _storeMappingService; + + public StoreMappingEntityPostDeleteHook(Lazy storeMappingService) + { + _storeMappingService = storeMappingService; + } + + public override void Hook(IStoreMappingSupported entity, HookEntityMetadata metadata) + { + var baseEntity = entity as BaseEntity; + + if (baseEntity == null) + return; + + var entityType = baseEntity.GetUnproxiedType(); + + var records = _storeMappingService.Value + .GetStoreMappingsFor(entityType.Name, baseEntity.Id) + .ToList(); + + records.Each(x => _storeMappingService.Value.DeleteStoreMapping(x)); + } + } +} diff --git a/src/Libraries/SmartStore.Services/ICommonServices.cs b/src/Libraries/SmartStore.Services/ICommonServices.cs index 9d603c0b81..f9b3043bf0 100644 --- a/src/Libraries/SmartStore.Services/ICommonServices.cs +++ b/src/Libraries/SmartStore.Services/ICommonServices.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; @@ -8,12 +7,20 @@ using SmartStore.Services.Localization; using SmartStore.Core.Logging; using SmartStore.Services.Security; +using SmartStore.Services.Configuration; +using SmartStore.Services.Stores; +using Autofac; +using SmartStore.Services.Helpers; namespace SmartStore.Services -{ - +{ public interface ICommonServices { + IComponentContext Container + { + get; + } + ICacheManager Cache { get; @@ -63,6 +70,53 @@ IPermissionService Permissions { get; } + + ISettingService Settings + { + get; + } + + IStoreService StoreService + { + get; + } + + IDateTimeHelper DateTimeHelper + { + get; + } } + public static class ICommonServicesExtensions + { + public static TService Resolve(this ICommonServices services) + { + return services.Container.Resolve(); + } + + public static TService Resolve(this ICommonServices services, object serviceKey) + { + return services.Container.ResolveKeyed(serviceKey); + } + + public static TService ResolveNamed(this ICommonServices services, string serviceName) + { + return services.Container.ResolveNamed(serviceName); + } + + public static object Resolve(this ICommonServices services, Type serviceType) + { + return services.Resolve(null, serviceType); + } + + public static object Resolve(this ICommonServices services, object serviceKey, Type serviceType) + { + return services.Container.ResolveKeyed(serviceKey, serviceType); + } + + public static object ResolveNamed(this ICommonServices services, string serviceName, Type serviceType) + { + return services.Container.ResolveNamed(serviceName, serviceType); + } + } } diff --git a/src/Libraries/SmartStore.Services/Localization/ILanguageService.cs b/src/Libraries/SmartStore.Services/Localization/ILanguageService.cs index e14f2ff0f3..a717f199ca 100644 --- a/src/Libraries/SmartStore.Services/Localization/ILanguageService.cs +++ b/src/Libraries/SmartStore.Services/Localization/ILanguageService.cs @@ -41,7 +41,6 @@ public partial interface ILanguageService /// /// Culture code /// Language - /// Language GetLanguageByCulture(string culture); /// @@ -49,7 +48,6 @@ public partial interface ILanguageService /// /// SEO code /// Language - /// Language GetLanguageBySeoCode(string seoCode); /// @@ -63,5 +61,35 @@ public partial interface ILanguageService /// /// Language void UpdateLanguage(Language language); + + /// + /// Determines whether a language is active/published + /// + /// The SEO code of the language to check + /// The store id + /// true when the language is published, false otherwise + bool IsPublishedLanguage(string seoCode, int storeId = 0); + + /// + /// Determines whether a language is active/published + /// + /// The id of the language to check + /// The store id + /// true when the language is published, false otherwise + bool IsPublishedLanguage(int languageId, int storeId = 0); + + /// + /// Gets the seo code of the default (first) active language + /// + /// The store id + /// The seo code + string GetDefaultLanguageSeoCode(int storeId = 0); + + /// + /// Gets the id of the default (first) active language + /// + /// The store id + /// The language id + int GetDefaultLanguageId(int storeId = 0); } } diff --git a/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs b/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs index 808b43450f..6195301c03 100644 --- a/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs +++ b/src/Libraries/SmartStore.Services/Localization/ILocalizationService.cs @@ -1,16 +1,16 @@ using System; using System.Collections.Generic; using System.Xml; -using SmartStore.Core.Data; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Plugins; namespace SmartStore.Services.Localization { - /// - /// Localization manager interface - /// - public partial interface ILocalizationService + /// + /// Localization manager interface + /// + public partial interface ILocalizationService { void ClearCache(); @@ -27,12 +27,6 @@ public partial interface ILocalizationService /// Number of deleted string resources int DeleteLocaleStringResources(string key, bool keyIsRootKey = true); - /// - /// Deletes all string resources of a plugin - /// - /// Plugin descriptor - void DeletePluginStringResources(PluginDescriptor pluginDescriptor); - /// /// Gets a locale string resource /// @@ -123,9 +117,10 @@ LocaleStringResource GetLocaleStringResourceByName(string resourceName, int lang /// Language /// XML document /// Prefix for resource key name - /// Specifies whether resource should be inserted or updated (or both) - /// Specifies whether user touched resources should also be updated - void ImportResourcesFromXml(Language language, + /// Specifies whether resource should be inserted or updated (or both) + /// Specifies whether user touched resources should also be updated + /// The number of processed (added or updated) resource entries + int ImportResourcesFromXml(Language language, XmlDocument xmlDocument, string rootKey = null, bool sourceIsPlugin = false, @@ -137,11 +132,14 @@ void ImportResourcesFromXml(Language language, /// /// codehint: sm-add /// Descriptor of the plugin - /// Load them into list rather than into database + /// Load them into the passed list rather than into database /// Specifies whether user touched resources should also be updated /// Import only files for particular languages - void ImportPluginResourcesFromXml(PluginDescriptor pluginDescriptor, - List forceToList = null, bool updateTouchedResources = true, IList filterLanguages = null); + void ImportPluginResourcesFromXml( + PluginDescriptor pluginDescriptor, + IList targetList = null, + bool updateTouchedResources = true, + IList filterLanguages = null); /// /// Flattens all nested LocaleResource child nodes into a new document diff --git a/src/Libraries/SmartStore.Services/Localization/ILocalizedEntityService.cs b/src/Libraries/SmartStore.Services/Localization/ILocalizedEntityService.cs index 0cd20e422f..070d1fbfe5 100644 --- a/src/Libraries/SmartStore.Services/Localization/ILocalizedEntityService.cs +++ b/src/Libraries/SmartStore.Services/Localization/ILocalizedEntityService.cs @@ -24,15 +24,6 @@ public partial interface ILocalizedEntityService /// Localized property LocalizedProperty GetLocalizedPropertyById(int localizedPropertyId); - /// - /// Find localized values - /// - /// Locale key group - /// Locale key - /// Locale key - /// Found localized values - int GetEntityIdByLocalizedValue(string localeKeyGroup, string localeKey, string localeValue); - /// /// Find localized value /// @@ -71,12 +62,14 @@ public partial interface ILocalizedEntityService /// Key selector /// Locale value /// Language ID - void SaveLocalizedValue(T entity, + void SaveLocalizedValue( + T entity, Expression> keySelector, string localeValue, int languageId) where T : BaseEntity, ILocalizedEntity; - void SaveLocalizedValue(T entity, + void SaveLocalizedValue( + T entity, Expression> keySelector, TPropType localeValue, int languageId) where T : BaseEntity, ILocalizedEntity; diff --git a/src/Libraries/SmartStore.Services/Localization/LanguageService.cs b/src/Libraries/SmartStore.Services/Localization/LanguageService.cs index a6bd92091b..db75218b54 100644 --- a/src/Libraries/SmartStore.Services/Localization/LanguageService.cs +++ b/src/Libraries/SmartStore.Services/Localization/LanguageService.cs @@ -8,6 +8,8 @@ using SmartStore.Services.Configuration; using SmartStore.Core.Domain.Stores; using SmartStore.Services.Stores; +using SmartStore.Collections; +using SmartStore.Core; namespace SmartStore.Services.Localization { @@ -29,6 +31,8 @@ public partial class LanguageService : ILanguageService private readonly IRepository _languageRepository; private readonly IStoreMappingService _storeMappingService; + private readonly IStoreService _storeService; + private readonly IStoreContext _storeContext; private readonly ICacheManager _cacheManager; private readonly ISettingService _settingService; private readonly LocalizationSettings _localizationSettings; @@ -38,20 +42,14 @@ public partial class LanguageService : ILanguageService #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// Language repository - /// Setting service - /// Localization settings - /// Event published public LanguageService(ICacheManager cacheManager, IRepository languageRepository, ISettingService settingService, LocalizationSettings localizationSettings, IEventPublisher eventPublisher, - IStoreMappingService storeMappingService) + IStoreMappingService storeMappingService, + IStoreService storeService, + IStoreContext storeContext) { this._cacheManager = cacheManager; this._languageRepository = languageRepository; @@ -59,6 +57,8 @@ public LanguageService(ICacheManager cacheManager, this._localizationSettings = localizationSettings; this._eventPublisher = eventPublisher; this._storeMappingService = storeMappingService; + this._storeService = storeService; + this._storeContext = storeContext; } #endregion @@ -110,18 +110,19 @@ public virtual IList GetAllLanguages(bool showHidden = false, int stor { var query = _languageRepository.Table; if (!showHidden) - query = query.Where(l => l.Published); - query = query.OrderBy(l => l.DisplayOrder); + query = query.Where(x => x.Published); + query = query.OrderBy(x => x.DisplayOrder); return query.ToList(); }); - //store mapping + // store mapping if (storeId > 0) { languages = languages .Where(l => _storeMappingService.Authorize(l, storeId)) .ToList(); } + return languages; } @@ -164,7 +165,6 @@ public virtual Language GetLanguageById(int languageId) /// /// Culture code /// Language - /// public virtual Language GetLanguageByCulture(string culture) { if (!culture.HasValue()) @@ -226,6 +226,105 @@ public virtual void UpdateLanguage(Language language) _eventPublisher.EntityUpdated(language); } + public virtual bool IsPublishedLanguage(string seoCode, int storeId = 0) + { + if (storeId <= 0) + storeId = _storeContext.CurrentStore.Id; + + var map = this.GetStoreLanguageMap(); + if (map.ContainsKey(storeId)) + { + return map[storeId].Any(x => x.Item2 == seoCode); + } + + return false; + } + + public virtual bool IsPublishedLanguage(int languageId, int storeId = 0) + { + if (languageId <= 0) + return false; + + if (storeId <= 0) + storeId = _storeContext.CurrentStore.Id; + + var map = this.GetStoreLanguageMap(); + if (map.ContainsKey(storeId)) + { + return map[storeId].Any(x => x.Item1 == languageId); + } + + return false; + } + + public virtual string GetDefaultLanguageSeoCode(int storeId = 0) + { + if (storeId <= 0) + storeId = _storeContext.CurrentStore.Id; + + var map = this.GetStoreLanguageMap(); + if (map.ContainsKey(storeId)) + { + return map[storeId].FirstOrDefault().Item2; + } + + return null; + } + + public virtual int GetDefaultLanguageId(int storeId = 0) + { + if (storeId <= 0) + storeId = _storeContext.CurrentStore.Id; + + var map = this.GetStoreLanguageMap(); + if (map.ContainsKey(storeId)) + { + return map[storeId].FirstOrDefault().Item1; + } + + return 0; + } + + /// + /// Gets a map of active/published store languages + /// + /// A map of store languages where key is the store id and values are tuples of language ids and seo codes + protected virtual Multimap> GetStoreLanguageMap() + { + var result = _cacheManager.Get(ServiceCacheConsumer.STORE_LANGUAGE_MAP_KEY, () => + { + var map = new Multimap>(); + + var allStores = _storeService.GetAllStores(); + foreach (var store in allStores) + { + var languages = GetAllLanguages(false, store.Id); + if (!languages.Any()) + { + // language-less stores aren't allowed but could exist accidentally. Correct this. + var firstStoreLang = GetAllLanguages(true, store.Id).FirstOrDefault(); + if (firstStoreLang == null) + { + // absolute fallback + firstStoreLang = GetAllLanguages(true).FirstOrDefault(); + } + map.Add(store.Id, new Tuple(firstStoreLang.Id, firstStoreLang.UniqueSeoCode)); + } + else + { + foreach (var lang in languages) + { + map.Add(store.Id, new Tuple(lang.Id, lang.UniqueSeoCode)); + } + } + } + + return map; + }, 1440 /* 24 hrs */); + + return result; + } + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs index d0190caf5d..a55b8ab84f 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationExtentions.cs @@ -1,22 +1,19 @@ using System; using System.Linq.Expressions; using System.Reflection; +using System.Xml; +using SmartStore.ComponentModel; using SmartStore.Core; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Infrastructure; using SmartStore.Core.Plugins; -using Fasterflect; -using System.Xml; -using SmartStore.Core.Data; using SmartStore.Utilities; -using System.Collections.Concurrent; namespace SmartStore.Services.Localization { - public static class LocalizationExtentions + public static class LocalizationExtentions { - //private static readonly ConcurrentDictionary _compiledExpressions = new ConcurrentDictionary(); // --> MEM LEAK - /// /// Get localized property of an entity /// @@ -24,8 +21,7 @@ public static class LocalizationExtentions /// Entity /// Key selector /// Localized property - public static string GetLocalized(this T entity, - Expression> keySelector) + public static string GetLocalized(this T entity, Expression> keySelector) where T : BaseEntity, ILocalizedEntity { var workContext = EngineContext.Current.Resolve(); @@ -46,7 +42,7 @@ public static string GetLocalized(this T entity, bool returnDefaultValue = true, bool ensureTwoPublishedLanguages = true) where T : BaseEntity, ILocalizedEntity { - return GetLocalized(entity, keySelector, languageId, returnDefaultValue, ensureTwoPublishedLanguages); + return GetLocalized(entity, keySelector, languageId, returnDefaultValue, ensureTwoPublishedLanguages); } /// /// Get localized property of an entity @@ -97,7 +93,7 @@ public static TPropType GetLocalized(this T entity, if (ensureTwoPublishedLanguages) { var lService = EngineContext.Current.Resolve(); - var totalPublishedLanguages = lService.GetLanguagesCount(false); // codehint: sm-edit + var totalPublishedLanguages = lService.GetLanguagesCount(false); loadLocalizedValue = totalPublishedLanguages >= 2; } @@ -324,7 +320,13 @@ public static string GetLocalizedValue(this PluginDescriptor descriptor, ILocali string result = localizationService.GetResource(resourceName, languageId, false, "", true); if (String.IsNullOrEmpty(result) && returnDefaultValue) - result = descriptor.TryGetPropertyValue(propertyName) as string; + { + var fastProp = FastProperty.GetProperty(descriptor.GetType(), propertyName); + if (fastProp != null) + { + result = fastProp.GetValue(descriptor) as string; + } + } return result; } diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs b/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs index bc7a518d3b..c6ac869c27 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizationService.cs @@ -1,31 +1,30 @@ using System; +using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Xml; -using System.Xml.Linq; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Data; -using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Events; -using SmartStore.Data; using SmartStore.Core.Logging; using SmartStore.Core.Plugins; -using System.Text.RegularExpressions; -using System.Collections.Concurrent; -using System.Web.Mvc; -using System.Collections; +using SmartStore.Core.Localization; +using System.Globalization; namespace SmartStore.Services.Localization { - /// - /// Provides information about localization - /// - public partial class LocalizationService : ILocalizationService + /// + /// Provides information about localization + /// + public partial class LocalizationService : ILocalizationService { #region Constants private const string LOCALESTRINGRESOURCES_ALL_KEY = "SmartStore.lsr.all-{0}"; @@ -43,6 +42,9 @@ public partial class LocalizationService : ILocalizationService private readonly LocalizationSettings _localizationSettings; private readonly IEventPublisher _eventPublisher; + private int _notFoundLogCount = 0; + private int? _defaultLanguageId; + #endregion #region Ctor @@ -128,21 +130,6 @@ public virtual int DeleteLocaleStringResources(string key, bool keyIsRootKey = t return result; } - /// - /// Deletes all string resources of a plugin - /// - /// Plugin descriptor - public virtual void DeletePluginStringResources(PluginDescriptor pluginDescriptor) - { - if (pluginDescriptor != null && pluginDescriptor.ResourceRootKey.HasValue() && pluginDescriptor.SystemName.HasValue()) - { - DeleteLocaleStringResources(pluginDescriptor.ResourceRootKey); - - DeleteLocaleStringResources("Plugins.FriendlyName." + pluginDescriptor.SystemName, false); - DeleteLocaleStringResources("Plugins.Description." + pluginDescriptor.SystemName, false); - } - } - /// /// Gets a locale string resource /// @@ -187,6 +174,7 @@ orderby lsr.ResourceName if (localeStringResource == null && logIfNotFound) _logger.Warning(string.Format("Resource string ({0}) not found. Language ID = {1}", resourceName, languageId)); + return localeStringResource; } @@ -264,19 +252,19 @@ public virtual IDictionary> GetResourceValues(int lan { Action>> loadAllAction = (d) => { - var locales = this.GetAllResources(languageId); + var query = from l in _lsrRepository.TableUntracked + orderby l.ResourceName + where l.LanguageId == languageId + select l; + var resources = query.ToList(); - foreach (var locale in locales) + foreach (var res in resources) { - var resourceName = locale.ResourceName.ToLowerInvariant(); - //if (!d.ContainsKey(resourceName)) - //{ - //d.TryAdd(resourceName, new Tuple(locale.Id, locale.ResourceValue)); - d.AddOrUpdate( - resourceName, - (k) => new Tuple(locale.Id, locale.ResourceValue), - (k, v) => { d[k] = v; return v; }); - //} + var resourceName = res.ResourceName.ToLowerInvariant(); + d.AddOrUpdate( + resourceName, + (k) => new Tuple(res.Id, res.ResourceValue), + (k, v) => { d[k] = v; return v; }); } // perf: add a dummy item indicating that data is fully loaded @@ -285,6 +273,7 @@ public virtual IDictionary> GetResourceValues(int lan string cacheKey = string.Format(LOCALESTRINGRESOURCES_ALL_KEY, languageId); var dict = _cacheManager.Get(cacheKey, () => { + // TODO: make result cacheable in distributed cache (IDictionary) var result = new ConcurrentDictionary>(8, 2000, StringComparer.CurrentCultureIgnoreCase); if (forceAll || _localizationSettings.LoadAllLocaleRecordsOnStartup) { @@ -311,11 +300,10 @@ public virtual IDictionary> GetResourceValues(int lan /// Language identifier /// A value indicating whether to log error if locale string resource is not found /// Default value - /// A value indicating whether to empty string will be returned if a resource is not found and default value is set to empty string + /// A value indicating whether an empty string will be returned if a resource is not found and default value is set to empty string /// A string representing the requested resource string. public virtual string GetResource(string resourceKey, int languageId = 0, bool logIfNotFound = true, string defaultValue = "", bool returnEmptyIfNotFound = false) { - // codehint: sm-edit if (languageId <= 0) { if (_workContext.WorkingLanguage == null) @@ -340,7 +328,7 @@ public virtual string GetResource(string resourceKey, int languageId = 0, bool l where l.ResourceName == resourceKey && l.LanguageId == languageId select l; var res = query.FirstOrDefault(); - if (res != null) // codehint: sm-edit (null case) + if (res != null) return new Tuple(res.Id, res.ResourceValue); return null; }); @@ -352,8 +340,19 @@ public virtual string GetResource(string resourceKey, int languageId = 0, bool l if (String.IsNullOrEmpty(result)) { - if (logIfNotFound) - _logger.Warning(string.Format("Resource string ({0}) is not found. Language ID = {1}", resourceKey, languageId)); + if (logIfNotFound) + { + if (_notFoundLogCount < 50) + { + _logger.Warning(string.Format("Resource string ({0}) does not exist. Language ID = {1}", resourceKey, languageId)); + } + else if (_notFoundLogCount == 50) + { + _logger.Warning("Too many language resources do not exist (> 50). Stopped logging missing resources to prevent performance drop."); + } + + _notFoundLogCount++; + } if (!String.IsNullOrEmpty(defaultValue)) { @@ -361,10 +360,28 @@ public virtual string GetResource(string resourceKey, int languageId = 0, bool l } else { - if (!returnEmptyIfNotFound) - result = resourceKey; + // try fallback to default language + if (!_defaultLanguageId.HasValue) + { + _defaultLanguageId = _languageService.GetDefaultLanguageId(); + } + var defaultLangId = _defaultLanguageId.Value; + if (defaultLangId > 0 && defaultLangId != languageId) + { + var fallbackResult = GetResource(resourceKey, defaultLangId, false, resourceKey); + if (fallbackResult != resourceKey) + { + result = fallbackResult; + } + } + + if (!returnEmptyIfNotFound && result.IsEmpty()) + { + result = resourceKey; + } } } + return result; } @@ -402,187 +419,280 @@ public virtual string ExportResourcesToXml(Language language) return stringWriter.ToString(); } - /// - /// Import language resources from XML file - /// - /// Language - /// XML document - /// Prefix for resource key name - public virtual void ImportResourcesFromXml( - Language language, - XmlDocument xmlDocument, - string rootKey = null, - bool sourceIsPlugin = false, - ImportModeFlags mode = ImportModeFlags.Insert | ImportModeFlags.Update, - bool updateTouchedResources = false) - { - var autoCommit = _lsrRepository.AutoCommitEnabled; - var validateOnSave = _lsrRepository.Context.ValidateOnSaveEnabled; - var autoDetectChanges = _lsrRepository.Context.AutoDetectChangesEnabled; - var proxyCreation = _lsrRepository.Context.ProxyCreationEnabled; + public virtual void ImportPluginResourcesFromXml( + PluginDescriptor pluginDescriptor, + IList targetList = null, + bool updateTouchedResources = true, + IList filterLanguages = null) + { + var directory = new DirectoryInfo(Path.Combine(pluginDescriptor.OriginalAssemblyFile.Directory.FullName, "Localization")); - try - { - _lsrRepository.Context.ValidateOnSaveEnabled = false; - _lsrRepository.Context.AutoDetectChangesEnabled = false; - _lsrRepository.Context.ProxyCreationEnabled = false; + if (!directory.Exists) + return; - var toAdd = new List(); - var toUpdate = new List(); - var nodes = xmlDocument.SelectNodes(@"//Language/LocaleResource"); + if (targetList == null && updateTouchedResources) + { + DeleteLocaleStringResources(pluginDescriptor.ResourceRootKey); + } - foreach (var xel in nodes.Cast()) - { + var unprocessedLanguages = new List(); - string name = xel.GetAttribute("Name").TrimSafe(); - string value = ""; - var valueNode = xel.SelectSingleNode("Value"); - if (valueNode != null) - value = valueNode.InnerText; + var defaultLanguageId = _languageService.GetDefaultLanguageId(); + var languages = filterLanguages ?? _languageService.GetAllLanguages(true); - if (String.IsNullOrEmpty(name)) - continue; + string code = null; + foreach (var language in languages) + { + code = ImportPluginResourcesForLanguage( + language, + null, + directory, + pluginDescriptor.ResourceRootKey, + targetList, + updateTouchedResources, + false); + + if (code == null) + { + unprocessedLanguages.Add(language); + } + } - if (rootKey.HasValue()) - { - if (!xel.GetAttributeText("AppendRootKey").IsCaseInsensitiveEqual("false")) - name = "{0}.{1}".FormatWith(rootKey, name); - } + if (filterLanguages == null && unprocessedLanguages.Count > 0) + { + // There were unprocessed languages (no corresponding resource file could be found). + // In order for GetResource() to be able to gracefully fallback to the default language's resources, + // we need to import resources for the current default language.... + var processedLanguages = languages.Except(unprocessedLanguages).ToList(); + if (!processedLanguages.Any(x => x.Id == defaultLanguageId)) + { + // ...but only if no resource file could be mapped to the default language before, + // namely because in this case the following operation would be redundant. + var defaultLanguage = _languageService.GetLanguageById(_languageService.GetDefaultLanguageId()); + if (defaultLanguage != null) + { + ImportPluginResourcesForLanguage( + defaultLanguage, + "en-us", + directory, + pluginDescriptor.ResourceRootKey, + targetList, + updateTouchedResources, + true); + } + } + } + } - // do not use "Insert"/"Update" methods because they clear cache - // let's bulk insert - var resource = language.LocaleStringResources.Where(x => x.ResourceName.Equals(name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - if (resource != null) - { - if (mode.IsSet(ImportModeFlags.Update)) - { - if (updateTouchedResources || !resource.IsTouched.GetValueOrDefault()) - { - resource.ResourceValue = value; - resource.IsTouched = null; - toUpdate.Add(resource); - } - } - } - else - { - if (mode.IsSet(ImportModeFlags.Insert)) - { - toAdd.Add( - new LocaleStringResource() - { - LanguageId = language.Id, - ResourceName = name, - ResourceValue = value, - IsFromPlugin = sourceIsPlugin - }); - } - } - } + /// + /// Resolves a resource file for the specified language and processes the import + /// + /// Language + /// The culture code of the processed resource file + private string ImportPluginResourcesForLanguage( + Language language, + string fileCode, + DirectoryInfo directory, + string resourceRootKey, + IList targetList, + bool updateTouchedResources, + bool canFallBackToAnyResourceFile) + { + var fileNamePattern = "resources.{0}.xml"; - _lsrRepository.AutoCommitEnabled = true; - _lsrRepository.InsertRange(toAdd, 500); - toAdd.Clear(); + var codeCandidates = GetResourceFileCodeCandidates( + fileCode ?? language.LanguageCulture, + directory, + canFallBackToAnyResourceFile); - _lsrRepository.AutoCommitEnabled = false; - toUpdate.Each(x => - { - _lsrRepository.Update(x); - }); - - _lsrRepository.Context.SaveChanges(); - toUpdate.Clear(); + string path = null; + string code = null; - //clear cache - _cacheManager.RemoveByPattern(LOCALESTRINGRESOURCES_PATTERN_KEY); - } - catch (Exception ex) - { - throw ex; - } - finally - { - _lsrRepository.AutoCommitEnabled = autoCommit; - _lsrRepository.Context.ValidateOnSaveEnabled = validateOnSave; - _lsrRepository.Context.AutoDetectChangesEnabled = autoDetectChanges; - _lsrRepository.Context.ProxyCreationEnabled = proxyCreation; - } + foreach (var candidate in codeCandidates) + { + var pathCandidate = Path.Combine(directory.FullName, fileNamePattern.FormatInvariant(candidate)); + if (File.Exists(pathCandidate)) + { + code = candidate; + path = pathCandidate; + break; + } + } - } + if (code != null) + { + var doc = new XmlDocument(); - /// - /// Import plugin resources from xml files in plugin's localization directory. - /// - /// Descriptor of the plugin - /// Load them into list rather than into database - /// Specifies whether user touched resources should also be updated - /// Import only files for particular languages - public virtual void ImportPluginResourcesFromXml(PluginDescriptor pluginDescriptor, - List forceToList = null, bool updateTouchedResources = true, IList filterLanguages = null) - { - string pluginDir = pluginDescriptor.OriginalAssemblyFile.Directory.FullName; - string localizationDir = Path.Combine(pluginDir, "Localization"); + doc.Load(path); + doc = FlattenResourceFile(doc); - if (!System.IO.Directory.Exists(localizationDir)) - return; + if (targetList == null) + { + ImportResourcesFromXml(language, doc, resourceRootKey, true, updateTouchedResources: updateTouchedResources); + } + else + { + var nodes = doc.SelectNodes(@"//Language/LocaleResource"); + foreach (XmlNode node in nodes) + { + var valueNode = node.SelectSingleNode("Value"); + var res = new LocaleStringResource() + { + ResourceName = node.Attributes["Name"].InnerText.Trim(), + ResourceValue = (valueNode == null ? "" : valueNode.InnerText), + LanguageId = language.Id, + IsFromPlugin = true + }; - if (forceToList == null && updateTouchedResources) - DeleteLocaleStringResources(pluginDescriptor.ResourceRootKey); + if (res.ResourceName.HasValue()) + { + targetList.Add(res); + } + } + } + } - var languages = _languageService.GetAllLanguages(true); - var doc = new XmlDocument(); + return code; + } + + private IEnumerable GetResourceFileCodeCandidates(string code, DirectoryInfo directory, bool canFallBackToAnyResourceFile) + { + // exact match (de-DE) + yield return code; - foreach (var filePath in System.IO.Directory.EnumerateFiles(localizationDir, "*.xml")) + // neutral culture (de) + var ci = CultureInfo.GetCultureInfo(code); + if (ci.Parent != null && !ci.IsNeutralCulture) { - Match match = Regex.Match(Path.GetFileName(filePath), Regex.Escape("resources.") + "(.*?)" + Regex.Escape(".xml")); - string languageCode = match.Groups[1].Value; + code = ci.Parent.Name; + yield return code; + } + + var rgFileName = new Regex("^resources.(.+?).xml$", RegexOptions.Compiled | RegexOptions.IgnoreCase); - Language language = languages.Where(l => l.LanguageCulture.IsCaseInsensitiveEqual(languageCode)).FirstOrDefault(); - if (language != null) + // any other region with same language (de-*) + foreach (var fi in directory.EnumerateFiles("resources.{0}-*.xml".FormatInvariant(code), SearchOption.TopDirectoryOnly)) + { + code = rgFileName.Match(fi.Name).Groups[1].Value; + if (LocalizationHelper.IsValidCultureCode(code)) { - language = _languageService.GetLanguageById(language.Id); + yield return code; + yield break; } + } - if (languageCode.HasValue() && language != null) + if (canFallBackToAnyResourceFile) + { + foreach (var fi in directory.EnumerateFiles("resources.*.xml", SearchOption.TopDirectoryOnly)) { - if (filterLanguages != null && !filterLanguages.Exists(x => x.Id == language.Id)) + code = rgFileName.Match(fi.Name).Groups[1].Value; + if (LocalizationHelper.IsValidCultureCode(code)) { + yield return code; + yield break; + } + } + } + } + + public virtual int ImportResourcesFromXml( + Language language, + XmlDocument xmlDocument, + string rootKey = null, + bool sourceIsPlugin = false, + ImportModeFlags mode = ImportModeFlags.Insert | ImportModeFlags.Update, + bool updateTouchedResources = false) + { + using (var scope = new DbContextScope(autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false, forceNoTracking: true, hooksEnabled: false)) + { + var toAdd = new List(); + var toUpdate = new List(); + var nodes = xmlDocument.SelectNodes(@"//Language/LocaleResource"); + + var resources = language.LocaleStringResources.ToDictionarySafe(x => x.ResourceName, StringComparer.OrdinalIgnoreCase); + + LocaleStringResource resource; + + foreach (var xel in nodes.Cast()) + { + string name = xel.GetAttribute("Name").TrimSafe(); + string value = ""; + var valueNode = xel.SelectSingleNode("Value"); + if (valueNode != null) + value = valueNode.InnerText; + + if (String.IsNullOrEmpty(name)) continue; + + if (rootKey.HasValue()) + { + if (!xel.GetAttributeText("AppendRootKey").IsCaseInsensitiveEqual("false")) + name = "{0}.{1}".FormatWith(rootKey, name); } - doc.Load(filePath); + resource = null; - if (forceToList == null) + // do not use "Insert"/"Update" methods because they clear cache + // let's bulk insert + //var resource = language.LocaleStringResources.Where(x => x.ResourceName.Equals(name, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (resources.TryGetValue(name, out resource)) { - ImportResourcesFromXml(language, doc, pluginDescriptor.ResourceRootKey, true, updateTouchedResources: updateTouchedResources); + if (mode.HasFlag(ImportModeFlags.Update)) + { + if (updateTouchedResources || !resource.IsTouched.GetValueOrDefault()) + { + if (value != resource.ResourceValue) + { + resource.ResourceValue = value; + resource.IsTouched = null; + toUpdate.Add(resource); + } + } + } } else { - var nodes = doc.SelectNodes(@"//Language/LocaleResource"); - foreach (XmlNode node in nodes) + if (mode.HasFlag(ImportModeFlags.Insert)) { - var valueNode = node.SelectSingleNode("Value"); - var res = new LocaleStringResource() - { - ResourceName = node.Attributes["Name"].InnerText.Trim(), - ResourceValue = (valueNode == null ? "" : valueNode.InnerText), - LanguageId = language.Id, - IsFromPlugin = true - }; - - if (res.ResourceName.HasValue()) - forceToList.Add(res); + toAdd.Add( + new LocaleStringResource + { + LanguageId = language.Id, + ResourceName = name, + ResourceValue = value, + IsFromPlugin = sourceIsPlugin + }); } } } + + //_lsrRepository.AutoCommitEnabled = true; + + if (toAdd.Any() || toUpdate.Any()) + { + _lsrRepository.InsertRange(toAdd); + toAdd.Clear(); + + _lsrRepository.UpdateRange(toUpdate); + toUpdate.Clear(); + + int num = _lsrRepository.Context.SaveChanges(); + + // clear cache + _cacheManager.RemoveByPattern(LOCALESTRINGRESOURCES_PATTERN_KEY); + + return num; + } + + return 0; } } public virtual XmlDocument FlattenResourceFile(XmlDocument source) { - Guard.NotNull(() => source); + Guard.ArgumentNotNull(() => source); - if (!source.SelectNodes("//Children").HasItems()) + if (source.SelectNodes("//Children").Count == 0) { // the document contains absolutely NO nesting, // so don't bother parsing. @@ -615,7 +725,7 @@ public virtual XmlDocument FlattenResourceFile(XmlDocument source) foreach (var resource in resources) { - RecursivelyWriteResource(resource, writer); + RecursivelyWriteResource(resource, writer, null); } writer.WriteEndElement(); @@ -629,7 +739,7 @@ public virtual XmlDocument FlattenResourceFile(XmlDocument source) return result; } - private void RecursivelyWriteResource(LocaleStringResourceParent resource, XmlWriter writer) + private void RecursivelyWriteResource(LocaleStringResourceParent resource, XmlWriter writer, bool? parentAppendRootKey) { //The value isn't actually used, but the name is used to create a namespace. if (resource.IsPersistable) @@ -640,6 +750,20 @@ private void RecursivelyWriteResource(LocaleStringResourceParent resource, XmlWr writer.WriteString(resource.NameWithNamespace); writer.WriteEndAttribute(); + if (resource.AppendRootKey.HasValue) + { + writer.WriteStartAttribute("AppendRootKey", ""); + writer.WriteString(resource.AppendRootKey.Value ? "true" : "false"); + writer.WriteEndAttribute(); + parentAppendRootKey = resource.AppendRootKey; + } + else if (parentAppendRootKey.HasValue) + { + writer.WriteStartAttribute("AppendRootKey", ""); + writer.WriteString(parentAppendRootKey.Value ? "true" : "false"); + writer.WriteEndAttribute(); + } + writer.WriteStartElement("Value", ""); writer.WriteString(resource.ResourceValue); writer.WriteEndElement(); @@ -649,7 +773,7 @@ private void RecursivelyWriteResource(LocaleStringResourceParent resource, XmlWr foreach (var child in resource.ChildLocaleStringResources) { - RecursivelyWriteResource(child, writer); + RecursivelyWriteResource(child, writer, resource.AppendRootKey ?? parentAppendRootKey); } } @@ -688,6 +812,12 @@ public LocaleStringResourceParent(XmlNode localStringResource, string nameSpace } ResourceName = resName; + var appendRootKeyAttribute = localStringResource.Attributes["AppendRootKey"]; + if (appendRootKeyAttribute != null) + { + AppendRootKey = appendRootKeyAttribute.Value.ToBool(true); + } + if (resValueNode == null || string.IsNullOrEmpty(resValueNode.InnerText.Trim())) { IsPersistable = false; @@ -703,11 +833,15 @@ public LocaleStringResourceParent(XmlNode localStringResource, string nameSpace ChildLocaleStringResources.Add(new LocaleStringResourceParent(childResource, NameWithNamespace)); } } + public string Namespace { get; set; } + public IList ChildLocaleStringResources = new List(); public bool IsPersistable { get; set; } + public bool? AppendRootKey { get; set; } + public string NameWithNamespace { get diff --git a/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs b/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs index 8160c79380..f765e0d580 100644 --- a/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs +++ b/src/Libraries/SmartStore.Services/Localization/LocalizedEntityService.cs @@ -7,6 +7,7 @@ using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Localization; +using System.Collections.Concurrent; namespace SmartStore.Services.Localization { @@ -15,126 +16,76 @@ namespace SmartStore.Services.Localization /// public partial class LocalizedEntityService : ILocalizedEntityService { - #region Constants - - private const string LOCALIZEDPROPERTY_KEY = "SmartStore.localizedproperty.value-{0}-{1}-{2}-{3}"; - private const string LOCALIZEDPROPERTY_ENTITYID_KEY = "SmartStore.localizedproperty.entityid-{0}-{1}-{2}"; - private const string LOCALIZEDPROPERTY_PATTERN_KEY = "SmartStore.localizedproperty."; - - #endregion - - #region Fields + private const string LOCALIZEDPROPERTY_ALL_KEY = "SmartStore.localizedproperty.all"; private readonly IRepository _localizedPropertyRepository; private readonly ICacheManager _cacheManager; + private readonly LocalizationSettings _localizationSettings; - #endregion - - #region Ctor - - /// - /// Ctor - /// - /// Cache manager - /// Localized property repository - public LocalizedEntityService(ICacheManager cacheManager, - IRepository localizedPropertyRepository) + public LocalizedEntityService( + ICacheManager cacheManager, + IRepository localizedPropertyRepository, + LocalizationSettings localizationSettings) { this._cacheManager = cacheManager; this._localizedPropertyRepository = localizedPropertyRepository; + this._localizationSettings = localizationSettings; } - #endregion - - #region Methods - - /// - /// Deletes a localized property - /// - /// Localized property - public virtual void DeleteLocalizedProperty(LocalizedProperty localizedProperty) - { - if (localizedProperty == null) - throw new ArgumentNullException("localizedProperty"); - - _localizedPropertyRepository.Delete(localizedProperty); - - //cache - _cacheManager.RemoveByPattern(LOCALIZEDPROPERTY_PATTERN_KEY); - } - - /// - /// Gets a localized property - /// - /// Localized property identifier - /// Localized property - public virtual LocalizedProperty GetLocalizedPropertyById(int localizedPropertyId) - { - if (localizedPropertyId == 0) - return null; - - var localizedProperty = _localizedPropertyRepository.GetById(localizedPropertyId); - return localizedProperty; - } - - /// - /// Find localized value - /// - /// Language identifier - /// Entity identifier - /// Locale key group - /// Locale key - /// Found localized value - public virtual string GetLocalizedValue(int languageId, int entityId, string localeKeyGroup, string localeKey) - { - string key = string.Format(LOCALIZEDPROPERTY_KEY, languageId, entityId, localeKeyGroup, localeKey); - return _cacheManager.Get(key, () => - { - var query = from lp in _localizedPropertyRepository.Table - where lp.LanguageId == languageId && - lp.EntityId == entityId && - lp.LocaleKeyGroup == localeKeyGroup && - lp.LocaleKey == localeKey - select lp.LocaleValue; - var localeValue = query.FirstOrDefault(); - //little hack here. nulls aren't cacheable so set it to "" - if (localeValue == null) - localeValue = ""; - return localeValue; - }); - } - - /// - /// Find localized values - /// - /// Locale key group - /// Locale key - /// Locale key - /// Found localized values - public virtual int GetEntityIdByLocalizedValue(string localeKeyGroup, string localeKey, string localeValue) - { - string key = string.Format(LOCALIZEDPROPERTY_ENTITYID_KEY, localeKeyGroup, localeKey, localeValue); - return _cacheManager.Get(key, () => - { - var query = from lp in _localizedPropertyRepository.Table - where lp.LocaleKeyGroup == localeKeyGroup && - lp.LocaleKey == localeKey && - lp.LocaleValue == localeValue - select lp.EntityId; - var result = query.FirstOrDefault(); - return result; - }); - } + protected virtual ConcurrentDictionary GetAllProperties() + { + var result = _cacheManager.Get(LOCALIZEDPROPERTY_ALL_KEY, () => + { + if (_localizationSettings.LoadAllLocalizedPropertiesOnStartup) + { + var props = _localizedPropertyRepository.TableUntracked.ToDictionarySafe( + x => GenerateKey(x.LanguageId, x.LocaleKeyGroup, x.LocaleKey, x.EntityId), + x => x.LocaleValue.EmptyNull()); + return new ConcurrentDictionary(props); + } + else + { + return new ConcurrentDictionary(); + } + }); + + return result; + } + + public virtual string GetLocalizedValue(int languageId, int entityId, string localeKeyGroup, string localeKey) + { + var props = GetAllProperties(); + string key = GenerateKey(languageId, localeKeyGroup, localeKey, entityId); + string val = null; + + if (_localizationSettings.LoadAllLocalizedPropertiesOnStartup) + { + if (!props.TryGetValue(key, out val)) + { + return string.Empty; + } + } + else + { + val = props.GetOrAdd(key, k => { + var query = from lp in _localizedPropertyRepository.TableUntracked + where + lp.EntityId == entityId && + lp.LocaleKey == localeKey && + lp.LocaleKeyGroup == localeKeyGroup && + lp.LanguageId == languageId + select lp.LocaleValue; + + return query.FirstOrDefault().EmptyNull(); + }); + } + + return val; + } - /// - /// Gets localized properties - /// - /// Entity identifier - /// Locale key group - /// Localized properties public virtual IList GetLocalizedProperties(int entityId, string localeKeyGroup) { - if (entityId == 0 || string.IsNullOrEmpty(localeKeyGroup)) + if (localeKeyGroup.IsEmpty()) return new List(); var query = from lp in _localizedPropertyRepository.Table @@ -142,49 +93,92 @@ orderby lp.Id where lp.EntityId == entityId && lp.LocaleKeyGroup == localeKeyGroup select lp; + var props = query.ToList(); return props; } - /// - /// Inserts a localized property - /// - /// Localized property - public virtual void InsertLocalizedProperty(LocalizedProperty localizedProperty) - { - if (localizedProperty == null) - throw new ArgumentNullException("localizedProperty"); + protected virtual LocalizedProperty GetLocalizedProperty(int languageId, int entityId, string localeKeyGroup, string localeKey) + { + var query = from lp in _localizedPropertyRepository.Table + where + lp.EntityId == entityId && + lp.LocaleKey == localeKey && + lp.LocaleKeyGroup == localeKeyGroup && + lp.LanguageId == languageId + select lp; - _localizedPropertyRepository.Insert(localizedProperty); + return query.FirstOrDefault(); + } - //cache - _cacheManager.RemoveByPattern(LOCALIZEDPROPERTY_PATTERN_KEY); + public virtual void InsertLocalizedProperty(LocalizedProperty localizedProperty) + { + Guard.ArgumentNotNull(() => localizedProperty); + + try + { + // db + _localizedPropertyRepository.Insert(localizedProperty); + + // cache + var key = GenerateKey(localizedProperty); + var val = localizedProperty.LocaleValue.EmptyNull(); + GetAllProperties().AddOrUpdate( + key, + val, + (k, v) => val); + } + catch { } } - /// - /// Updates the localized property - /// - /// Localized property public virtual void UpdateLocalizedProperty(LocalizedProperty localizedProperty) { - if (localizedProperty == null) - throw new ArgumentNullException("localizedProperty"); - - _localizedPropertyRepository.Update(localizedProperty); - - //cache - _cacheManager.RemoveByPattern(LOCALIZEDPROPERTY_PATTERN_KEY); - } - - /// - /// Save localized value - /// - /// Type - /// Entity - /// Key selector - /// Locale value - /// Language ID - public virtual void SaveLocalizedValue(T entity, + Guard.ArgumentNotNull(() => localizedProperty); + + try + { + // db + _localizedPropertyRepository.Update(localizedProperty); + + // cache + var key = GenerateKey(localizedProperty); + var val = localizedProperty.LocaleValue.EmptyNull(); + GetAllProperties().AddOrUpdate( + key, + val, + (k, v) => val); + } + catch { } + } + + public virtual void DeleteLocalizedProperty(LocalizedProperty localizedProperty) + { + Guard.ArgumentNotNull(() => localizedProperty); + + try + { + // cache + var key = GenerateKey(localizedProperty); + string val = null; + GetAllProperties().TryRemove(key, out val); + + // db + _localizedPropertyRepository.Delete(localizedProperty); + } + catch { } + } + + public virtual LocalizedProperty GetLocalizedPropertyById(int localizedPropertyId) + { + if (localizedPropertyId == 0) + return null; + + var localizedProperty = _localizedPropertyRepository.GetById(localizedPropertyId); + return localizedProperty; + } + + public virtual void SaveLocalizedValue( + T entity, Expression> keySelector, string localeValue, int languageId) where T : BaseEntity, ILocalizedEntity @@ -192,16 +186,14 @@ public virtual void SaveLocalizedValue(T entity, SaveLocalizedValue(entity, keySelector, localeValue, languageId); } - public virtual void SaveLocalizedValue(T entity, + public virtual void SaveLocalizedValue( + T entity, Expression> keySelector, TPropType localeValue, int languageId) where T : BaseEntity, ILocalizedEntity { - if (entity == null) - throw new ArgumentNullException("entity"); - - if (languageId == 0) - throw new ArgumentOutOfRangeException("languageId", "Language ID should not be 0"); + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotZero(languageId, "languageId"); var member = keySelector.Body as MemberExpression; if (member == null) @@ -222,32 +214,33 @@ public virtual void SaveLocalizedValue(T entity, string localeKeyGroup = typeof(T).Name; string localeKey = propInfo.Name; - var props = GetLocalizedProperties(entity.Id, localeKeyGroup); - var prop = props.FirstOrDefault(lp => lp.LanguageId == languageId && - lp.LocaleKey.Equals(localeKey, StringComparison.InvariantCultureIgnoreCase)); //should be culture invariant + var prop = GetLocalizedProperty(languageId, entity.Id, localeKeyGroup, localeKey); string localeValueStr = localeValue.Convert(); if (prop != null) { - if (string.IsNullOrWhiteSpace(localeValueStr)) + if (localeValueStr.IsEmpty()) { - //delete + // delete DeleteLocalizedProperty(prop); } else { - //update - prop.LocaleValue = localeValueStr; - UpdateLocalizedProperty(prop); + // update + if (prop.LocaleValue != localeValueStr) + { + prop.LocaleValue = localeValueStr; + UpdateLocalizedProperty(prop); + } } } else { - if (!string.IsNullOrWhiteSpace(localeValueStr)) + if (localeValueStr.HasValue()) { - //insert - prop = new LocalizedProperty() + // insert + prop = new LocalizedProperty { EntityId = entity.Id, LanguageId = languageId, @@ -260,6 +253,14 @@ public virtual void SaveLocalizedValue(T entity, } } - #endregion + private string GenerateKey(LocalizedProperty prop) + { + return GenerateKey(prop.LanguageId, prop.LocaleKeyGroup, prop.LocaleKey, prop.EntityId); + } + + private string GenerateKey(int languageId, string localeKeyGroup, string localeKey, int entityId) + { + return "{0}.{1}.{2}.{3}".FormatInvariant(languageId, localeKeyGroup, localeKey, entityId); + } } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs b/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs index c84c5f7526..61ba8f21ad 100644 --- a/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs +++ b/src/Libraries/SmartStore.Services/Logging/CustomerActivityService.cs @@ -1,64 +1,49 @@ using System; -using System.Collections.Generic; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; -using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Logging; -using SmartStore.Data; using SmartStore.Core.Logging; namespace SmartStore.Services.Logging { - /// - /// Customer activity service - /// - public class CustomerActivityService : ICustomerActivityService + /// + /// Customer activity service + /// + public class CustomerActivityService : ICustomerActivityService { - #region Fields + #region Fields - /// - /// Cache manager - /// - private readonly ICacheManager _cacheManager; - private readonly IRepository _activityLogRepository; + private const int _deleteNumberOfEntries = 1000; + + private readonly IRepository _activityLogRepository; private readonly IRepository _activityLogTypeRepository; - private readonly IWorkContext _workContext; + private readonly IRepository _customerRepository; + private readonly IWorkContext _workContext; private readonly IDbContext _dbContext; - private readonly IDataProvider _dataProvider; - private readonly CommonSettings _commonSettings; - // codehint: sm-add + private readonly static object s_lock = new object(); private readonly static ConcurrentDictionary s_logTypes = new ConcurrentDictionary(); - #endregion - #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// Activity log repository - /// Activity log type repository - /// Work context - /// DB context> - /// WeData provider - /// Common settings - public CustomerActivityService(ICacheManager cacheManager, + #endregion + + #region Ctor + + public CustomerActivityService( IRepository activityLogRepository, IRepository activityLogTypeRepository, - IWorkContext workContext, - IDbContext dbContext, IDataProvider dataProvider, CommonSettings commonSettings) + IRepository customerRepository, + IWorkContext workContext, + IDbContext dbContext) { - this._cacheManager = cacheManager; this._activityLogRepository = activityLogRepository; this._activityLogTypeRepository = activityLogTypeRepository; + this._customerRepository = customerRepository; this._workContext = workContext; this._dbContext = dbContext; - this._dataProvider = dataProvider; - this._commonSettings = commonSettings; } #endregion @@ -218,27 +203,55 @@ public virtual void DeleteActivity(ActivityLog activityLog) _activityLogRepository.Delete(activityLog); } - /// - /// Gets all activity log items - /// - /// Log item creation from; null to load all customers - /// Log item creation to; null to load all customers - /// Customer identifier; null to load all customers - /// Activity log type identifier - /// Page index - /// Page size - /// Activity log collection - public virtual IPagedList GetAllActivities(DateTime? createdOnFrom, - DateTime? createdOnTo, int? customerId, int activityLogTypeId, - int pageIndex, int pageSize) + /// + /// Gets all activity log items + /// + /// Log item creation from; null to load all customers + /// Log item creation to; null to load all customers + /// Customer identifier; null to load all customers + /// Activity log type identifier + /// Page index + /// Page size + /// Customer email + /// Customer system name + /// Activity log collection + public virtual IPagedList GetAllActivities( + DateTime? createdOnFrom, + DateTime? createdOnTo, + int? customerId, + int activityLogTypeId, + int pageIndex, + int pageSize, + string email = null, + bool? customerSystemAccount = null) { var query = _activityLogRepository.Table; + + if (email.HasValue() || customerSystemAccount.HasValue) + { + var queryCustomers = _customerRepository.Table; + + if (email.HasValue()) + queryCustomers = queryCustomers.Where(x => x.Email == email); + + if (customerSystemAccount.HasValue) + queryCustomers = queryCustomers.Where(x => x.IsSystemAccount == customerSystemAccount.Value); + + query = + from al in _activityLogRepository.Table + join c in queryCustomers on al.CustomerId equals c.Id + select al; + } + if (createdOnFrom.HasValue) query = query.Where(al => createdOnFrom.Value <= al.CreatedOnUtc); + if (createdOnTo.HasValue) query = query.Where(al => createdOnTo.Value >= al.CreatedOnUtc); + if (activityLogTypeId > 0) query = query.Where(al => activityLogTypeId == al.ActivityLogTypeId); + if (customerId.HasValue) query = query.Where(al => customerId.Value == al.CustomerId); @@ -266,29 +279,54 @@ public virtual ActivityLog GetActivityById(int activityLogId) return activityLog; } - /// - /// Clears activity log - /// - public virtual void ClearAllActivities() - { - if (_commonSettings.UseStoredProceduresIfSupported && _dataProvider.StoredProceduresSupported) - { - //although it's not a stored procedure we use it to ensure that a database supports them - //we cannot wait until EF team has it implemented - http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/1015357-batch-cud-support + public virtual IList GetActivityByIds(int[] activityLogIds) + { + if (activityLogIds == null || activityLogIds.Length == 0) + return new List(); + var query = _activityLogRepository.Table + .Where(x => activityLogIds.Contains(x.Id)) + .OrderByDescending(x => x.CreatedOnUtc); - //do all databases support "Truncate command"? - //TODO: do not hard-code the table name - _dbContext.ExecuteSqlCommand("TRUNCATE TABLE [ActivityLog]"); - } - else - { - var activityLog = _activityLogRepository.Table.ToList(); - foreach (var activityLogItem in activityLog) - _activityLogRepository.Delete(activityLogItem); - } - } - #endregion + return query.ToList(); + } + /// + /// Clears activity log + /// + public virtual void ClearAllActivities() + { + try + { + _dbContext.ExecuteSqlCommand("TRUNCATE TABLE [ActivityLog]"); + } + catch + { + try + { + for (int i = 0; i < 100000; ++i) + { + if (_dbContext.ExecuteSqlCommand("Delete Top ({0}) From [ActivityLog]", false, null, _deleteNumberOfEntries) < _deleteNumberOfEntries) + break; + } + } + catch { } + + try + { + _dbContext.ExecuteSqlCommand("DBCC CHECKIDENT('ActivityLog', RESEED, 0)"); + } + catch + { + try + { + _dbContext.ExecuteSqlCommand("Alter Table [ActivityLog] Alter Column [Id] Identity(1,1)"); + } + catch { } + } + } + } + + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs b/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs index bdf8a33046..8387de3969 100644 --- a/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs +++ b/src/Libraries/SmartStore.Services/Logging/DefaultLogger.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Logging; using SmartStore.Core.Logging; +using SmartStore.Data; namespace SmartStore.Services.Logging { @@ -22,37 +23,26 @@ public partial class DefaultLogger : ILogger private readonly IRepository _logRepository; private readonly IWebHelper _webHelper; private readonly IDbContext _dbContext; - private readonly IDataProvider _dataProvider; + private readonly IWorkContext _workContext; + + private readonly IList _entries = new List(); #endregion #region Ctor - /// - /// Ctor - /// - /// Log repository - /// Web helper> - /// DB context> - /// WeData provider - /// Common settings - public DefaultLogger(IRepository logRepository, IWebHelper webHelper, IDbContext dbContext, IDataProvider dataProvider) + public DefaultLogger(IRepository logRepository, IWebHelper webHelper, IDbContext dbContext, IWorkContext workContext) { this._logRepository = logRepository; this._webHelper = webHelper; this._dbContext = dbContext; - this._dataProvider = dataProvider; + this._workContext = workContext; } #endregion #region Methods - /// - /// Determines whether a log level is enabled - /// - /// Log level - /// Result public virtual bool IsEnabled(LogLevel level) { switch (level) @@ -64,10 +54,6 @@ public virtual bool IsEnabled(LogLevel level) } } - /// - /// Deletes a log item - /// - /// Log item public virtual void DeleteLog(Log log) { if (log == null) @@ -76,16 +62,13 @@ public virtual void DeleteLog(Log log) _logRepository.Delete(log); } - /// - /// Clears a log - /// public virtual void ClearLog() { try { _dbContext.ExecuteSqlCommand("TRUNCATE TABLE [Log]"); } - catch (Exception) + catch { try { @@ -95,21 +78,23 @@ public virtual void ClearLog() break; } } - catch (Exception) { } + catch { } try { _dbContext.ExecuteSqlCommand("DBCC CHECKIDENT('Log', RESEED, 0)"); } - catch (Exception) + catch { try { _dbContext.ExecuteSqlCommand("Alter Table [Log] Alter Column [Id] Identity(1,1)"); } - catch (Exception) { } + catch{ } } } + + _dbContext.ShrinkDatabase(); } public virtual void ClearLog(DateTime toUtc, LogLevel logLevel) @@ -123,29 +108,20 @@ public virtual void ClearLog(DateTime toUtc, LogLevel logLevel) if (_dbContext.ExecuteSqlCommand(sqlDelete, false, null, _deleteNumberOfEntries, (int)logLevel, toUtc) < _deleteNumberOfEntries) break; } + + _dbContext.ShrinkDatabase(); } - catch (Exception) { } + catch { } } - /// - /// Gets all log items - /// - /// Log item creation from; null to load all records - /// Log item creation to; null to load all records - /// Message - /// Log level; null to load all records - /// Page index - /// Page size - /// Log item collection - public virtual IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, - string message, LogLevel? logLevel, int pageIndex, int pageSize, int minFrequency) + public virtual IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, string message, LogLevel? logLevel, int pageIndex, int pageSize, int minFrequency) { var query = _logRepository.Table; if (fromUtc.HasValue) - query = query.Where(l => fromUtc.Value <= l.CreatedOnUtc); + query = query.Where(l => fromUtc.Value <= l.CreatedOnUtc || fromUtc.Value <= l.UpdatedOnUtc); if (toUtc.HasValue) - query = query.Where(l => toUtc.Value >= l.CreatedOnUtc); + query = query.Where(l => toUtc.Value >= l.CreatedOnUtc || toUtc.Value >= l.UpdatedOnUtc); if (logLevel.HasValue) { int logLevelId = (int)logLevel.Value; @@ -153,7 +129,8 @@ public virtual IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, } if (!String.IsNullOrEmpty(message)) query = query.Where(l => l.ShortMessage.Contains(message) || l.FullMessage.Contains(message)); - query = query.OrderByDescending(l => l.CreatedOnUtc); + + query = query.OrderByDescending(l => l.UpdatedOnUtc).ThenByDescending(l => l.CreatedOnUtc); if (minFrequency > 0) query = query.Where(l => l.Frequency >= minFrequency); @@ -164,11 +141,6 @@ public virtual IPagedList GetAllLogs(DateTime? fromUtc, DateTime? toUtc, return log; } - /// - /// Gets a log item - /// - /// Log item identifier - /// Log item public virtual Log GetLogById(int logId) { if (logId == 0) @@ -178,11 +150,6 @@ public virtual Log GetLogById(int logId) return log; } - /// - /// Get log items by identifiers - /// - /// Log item identifiers - /// Log items public virtual IList GetLogByIds(int[] logIds) { if (logIds == null || logIds.Length == 0) @@ -203,111 +170,126 @@ where logIds.Contains(l.Id) return sortedLogItems; } - /// - /// Inserts a log item - /// - /// The log context - /// A log item - public virtual Log InsertLog(LogContext context) + public virtual void InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null) + { + var context = new LogContext + { + LogLevel = logLevel, + ShortMessage = shortMessage, + FullMessage = fullMessage, + Customer = customer + }; + + InsertLog(context); + } + + public virtual void InsertLog(LogContext context) { - if (context == null || (context.ShortMessage.IsNullOrEmpty() && context.FullMessage.IsNullOrEmpty())) - return null; + _entries.Add(context); + if (_entries.Count == 50) + { + Flush(); + } + } - Log log = null; + public void Flush() + { + if (_entries.Count == 0) + return; + + string ipAddress = ""; + string pageUrl = ""; + string referrerUrl = ""; + var currentCustomer = _workContext.CurrentCustomer; try { - string shortMessage = context.ShortMessage.NaIfEmpty(); - string fullMessage = context.FullMessage.EmptyNull(); - string contentHash = null; - string ipAddress = ""; - string pageUrl = ""; - string referrerUrl = ""; - - try - { - ipAddress = _webHelper.GetCurrentIpAddress(); - pageUrl = _webHelper.GetThisPageUrl(true); - referrerUrl = _webHelper.GetUrlReferrer(); - } - catch { } + ipAddress = _webHelper.GetCurrentIpAddress(); + pageUrl = _webHelper.GetThisPageUrl(true); + referrerUrl = _webHelper.GetUrlReferrer(); + } + catch { } - if (context.HashNotFullMessage || context.HashIpAddress) - { - contentHash = (shortMessage - + (context.HashNotFullMessage ? "" : fullMessage) - + (context.HashIpAddress ? ipAddress.EmptyNull() : "") - ).Hash(true, true); - } - else + using (var scope = new DbContextScope(autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) + { + foreach (var context in _entries) { - contentHash = (shortMessage + fullMessage).Hash(true, true); - } + if (context.ShortMessage.IsEmpty() && context.FullMessage.IsEmpty()) + continue; - log = _logRepository.Table.OrderByDescending(x => x.CreatedOnUtc).FirstOrDefault(x => x.ContentHash == contentHash); + Log log = null; - if (log == null) - { - log = new Log() + try + { + string shortMessage = context.ShortMessage.NaIfEmpty(); + string fullMessage = context.FullMessage.EmptyNull(); + string contentHash = null; + + if (context.HashNotFullMessage || context.HashIpAddress) + { + contentHash = (shortMessage + + (context.HashNotFullMessage ? "" : fullMessage) + + (context.HashIpAddress ? ipAddress.EmptyNull() : "") + ).Hash(Encoding.Unicode, true); + } + else + { + contentHash = (shortMessage + fullMessage).Hash(Encoding.Unicode, true); + } + + log = _logRepository.Table.OrderByDescending(x => x.CreatedOnUtc).FirstOrDefault(x => x.ContentHash == contentHash); + + if (log == null) + { + log = new Log + { + Frequency = 1, + LogLevel = context.LogLevel, + ShortMessage = shortMessage, + FullMessage = fullMessage, + IpAddress = ipAddress, + Customer = context.Customer ?? currentCustomer, + PageUrl = pageUrl, + ReferrerUrl = referrerUrl, + CreatedOnUtc = DateTime.UtcNow, + ContentHash = contentHash + }; + + _logRepository.Insert(log); + } + else + { + if (log.Frequency < 2147483647) + log.Frequency = log.Frequency + 1; + + log.LogLevel = context.LogLevel; + log.IpAddress = ipAddress; + log.Customer = context.Customer ?? currentCustomer; + log.PageUrl = pageUrl; + log.ReferrerUrl = referrerUrl; + log.UpdatedOnUtc = DateTime.UtcNow; + + _logRepository.Update(log); + } + } + catch (Exception ex) { - Frequency = 1, - LogLevel = context.LogLevel, - ShortMessage = shortMessage, - FullMessage = fullMessage, - IpAddress = ipAddress, - Customer = context.Customer, - PageUrl = pageUrl, - ReferrerUrl = referrerUrl, - CreatedOnUtc = DateTime.UtcNow, - ContentHash = contentHash - }; - - _logRepository.Insert(log); + ex.Dump(); + } } - else - { - if (log.Frequency < 2147483647) - log.Frequency = log.Frequency + 1; - - log.LogLevel = context.LogLevel; - log.IpAddress = ipAddress; - log.Customer = context.Customer; - log.PageUrl = pageUrl; - log.ReferrerUrl = referrerUrl; - log.UpdatedOnUtc = DateTime.UtcNow; - _logRepository.Update(log); + try + { + // FIRE! + _logRepository.Context.SaveChanges(); } + catch { } } - catch (Exception exc) - { - exc.Dump(); - } - - return log; - } - /// - /// Inserts a log item - /// - /// Log level - /// The short message - /// The full message - /// The customer to associate log record with - /// A log item - public virtual Log InsertLog(LogLevel logLevel, string shortMessage, string fullMessage = "", Customer customer = null) - { - var context = new LogContext() - { - LogLevel = logLevel, - ShortMessage = shortMessage, - FullMessage = fullMessage, - Customer = customer - }; - - return InsertLog(context); + _entries.Clear(); } #endregion - } + + } } diff --git a/src/Libraries/SmartStore.Services/Media/DownloadService.cs b/src/Libraries/SmartStore.Services/Media/DownloadService.cs index 71117a3bcd..b7f03930e8 100644 --- a/src/Libraries/SmartStore.Services/Media/DownloadService.cs +++ b/src/Libraries/SmartStore.Services/Media/DownloadService.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Media; @@ -23,13 +26,7 @@ public partial class DownloadService : IDownloadService #region Ctor - /// - /// Ctor - /// - /// Download repository - /// - public DownloadService(IRepository downloadRepository, - IEventPublisher eventPubisher) + public DownloadService(IRepository downloadRepository, IEventPublisher eventPubisher) { _downloadRepository = downloadRepository; _eventPubisher = eventPubisher; @@ -39,11 +36,6 @@ public DownloadService(IRepository downloadRepository, #region Methods - /// - /// Gets a download - /// - /// Download identifier - /// Download public virtual Download GetDownloadById(int downloadId) { if (downloadId == 0) @@ -53,11 +45,25 @@ public virtual Download GetDownloadById(int downloadId) return download; } - /// - /// Gets a download by GUID - /// - /// Download GUID - /// Download + public virtual IList GetDownloadsByIds(int[] downloadIds) + { + if (downloadIds == null || downloadIds.Length == 0) + return new List(); + + var query = from dl in _downloadRepository.Table + where downloadIds.Contains(dl.Id) + select dl; + + var downloads = query.ToList(); + + // sort by passed identifier sequence + var sortQuery = from i in downloadIds + join d in downloads on i equals d.Id + select d; + + return sortQuery.ToList(); + } + public virtual Download GetDownloadByGuid(Guid downloadGuid) { if (downloadGuid == Guid.Empty) @@ -70,10 +76,6 @@ public virtual Download GetDownloadByGuid(Guid downloadGuid) return order; } - /// - /// Deletes a download - /// - /// Download public virtual void DeleteDownload(Download download) { if (download == null) @@ -84,39 +86,28 @@ public virtual void DeleteDownload(Download download) _eventPubisher.EntityDeleted(download); } - /// - /// Inserts a download - /// - /// Download public virtual void InsertDownload(Download download) { if (download == null) throw new ArgumentNullException("download"); + download.UpdatedOnUtc = DateTime.UtcNow; _downloadRepository.Insert(download); _eventPubisher.EntityInserted(download); } - /// - /// Updates the download - /// - /// Download public virtual void UpdateDownload(Download download) { if (download == null) throw new ArgumentNullException("download"); + download.UpdatedOnUtc = DateTime.UtcNow; _downloadRepository.Update(download); _eventPubisher.EntityUpdated(download); } - /// - /// Gets a value indicating whether download is allowed - /// - /// Order item to check - /// True if download is allowed; otherwise, false. public virtual bool IsDownloadAllowed(OrderItem orderItem) { if (orderItem == null) @@ -182,11 +173,6 @@ public virtual bool IsDownloadAllowed(OrderItem orderItem) return false; } - /// - /// Gets a value indicating whether license download is allowed - /// - /// Order item to check - /// True if license download is allowed; otherwise, false. public virtual bool IsLicenseDownloadAllowed(OrderItem orderItem) { if (orderItem == null) diff --git a/src/Libraries/SmartStore.Services/Media/Extensions.cs b/src/Libraries/SmartStore.Services/Media/Extensions.cs deleted file mode 100644 index fcc6269049..0000000000 --- a/src/Libraries/SmartStore.Services/Media/Extensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.IO; -using System.Web; - -namespace SmartStore.Services.Media -{ - /// - /// Extensions - /// - public static class Extensions - { - /// - /// Gets the download binary array - /// - /// Posted file - /// Download binary array - public static byte[] GetDownloadBits(this HttpPostedFileBase postedFile) - { - Stream fs = postedFile.InputStream; - int size = postedFile.ContentLength; - byte[] binary = new byte[size]; - fs.Read(binary, 0, size); - return binary; - } - - /// - /// Gets the picture binary array - /// - /// Posted file - /// Picture binary array - public static byte[] GetPictureBits(this HttpPostedFileBase postedFile) - { - Stream fs = postedFile.InputStream; - int size = postedFile.ContentLength; - byte[] img = new byte[size]; - fs.Read(img, 0, size); - return img; - } - } -} diff --git a/src/Libraries/SmartStore.Services/Media/IDownloadService.cs b/src/Libraries/SmartStore.Services/Media/IDownloadService.cs index 73afed9a32..80faf7f50a 100644 --- a/src/Libraries/SmartStore.Services/Media/IDownloadService.cs +++ b/src/Libraries/SmartStore.Services/Media/IDownloadService.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using SmartStore.Core; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; @@ -16,6 +19,13 @@ public partial interface IDownloadService /// Download Download GetDownloadById(int downloadId); + /// + /// Gets downloads by identifiers + /// + /// Download identifiers + /// List of download entities + IList GetDownloadsByIds(int[] downloadIds); + /// /// Gets a download by GUID /// diff --git a/src/Libraries/SmartStore.Services/Media/IPictureService.cs b/src/Libraries/SmartStore.Services/Media/IPictureService.cs index 74b2aba0da..ce9f231349 100644 --- a/src/Libraries/SmartStore.Services/Media/IPictureService.cs +++ b/src/Libraries/SmartStore.Services/Media/IPictureService.cs @@ -5,10 +5,10 @@ namespace SmartStore.Services.Media { - /// - /// Picture service interface - /// - public partial interface IPictureService + /// + /// Picture service interface + /// + public partial interface IPictureService { /// /// Validates input picture dimensions and prevents that the image size exceeds global max size @@ -17,6 +17,24 @@ public partial interface IPictureService /// MIME type /// Picture binary or throws an exception byte[] ValidatePicture(byte[] pictureBinary); + + /// + /// Finds an equal picture by comparing the binary buffer + /// + /// The picture to find a duplicate for + /// The sequence of pictures to seek within for duplicates + /// Id of equal picture if any + /// The picture binary for path when no picture equals in the sequence, null otherwise. + byte[] FindEqualPicture(string path, IEnumerable pictures, out int equalPictureId); + + /// + /// Finds an equal picture by comparing the binary buffer + /// + /// Binary picture data + /// The sequence of pictures to seek within for duplicates + /// Id of equal picture if any + /// The picture binary for path when no picture equals in the sequence, null otherwise. + byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable pictures, out int equalPictureId); /// /// Gets the loaded picture binary depending on picture storage settings @@ -118,16 +136,24 @@ string GetPictureUrl(Picture picture, /// Pictures IList GetPicturesByProductId(int productId, int recordsToReturn = 0); - /// - /// Inserts a picture - /// - /// The picture binary - /// The picture MIME type - /// The SEO filename - /// A value indicating whether the picture is new - /// A value indicating whether to validated provided picture binary - /// Picture - Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool validateBinary = true); + /// + /// Gets pictures by picture identifier + /// + /// Picture identifier + /// Pictures + IList GetPicturesByIds(int[] pictureIds); + + /// + /// Inserts a picture + /// + /// The picture binary + /// The picture MIME type + /// The SEO filename + /// A value indicating whether the picture is new + /// A value indicating whether the picture is initially in transient state + /// A value indicating whether to validated provided picture binary + /// Picture + Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool isTransient = true, bool validateBinary = true); /// /// Updates the picture diff --git a/src/Libraries/SmartStore.Services/Media/ImageCache.cs b/src/Libraries/SmartStore.Services/Media/ImageCache.cs index 2d90833e88..23e88f2295 100644 --- a/src/Libraries/SmartStore.Services/Media/ImageCache.cs +++ b/src/Libraries/SmartStore.Services/Media/ImageCache.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Web; using ImageResizer; using SmartStore.Core; @@ -75,18 +76,23 @@ public virtual CachedImageResult GetCachedImage(int? pictureId, string seoFileNa public virtual string GetImageUrl(string imagePath, string storeLocation = null) { - if (imagePath.IsEmpty()) + if (imagePath.IsEmpty()) return null; - var cdnUrl = _storeContext.CurrentStore.ContentDeliveryNetwork; - if (cdnUrl.HasValue() && !_httpContext.IsDebuggingEnabled && !_httpContext.Request.IsLocal) + var root = storeLocation; + + if (root.IsEmpty()) { - storeLocation = cdnUrl; + var cdnUrl = _storeContext.CurrentStore.ContentDeliveryNetwork; + if (cdnUrl.HasValue() && !_httpContext.IsDebuggingEnabled && !_httpContext.Request.IsLocal) + { + root = cdnUrl; + } } - storeLocation = storeLocation.NullEmpty() ?? _webHelper.GetStoreLocation(); - storeLocation = storeLocation.TrimEnd('/', '\\'); - var url = storeLocation + "/Media/Thumbs/"; + root = root.NullEmpty() ?? _httpContext.Request.ApplicationPath; + root = root.TrimEnd('/', '\\'); + var url = root + "/Media/Thumbs/"; url = url + imagePath; return url; @@ -111,7 +117,10 @@ public virtual void DeleteCachedImages() { foreach (var file in _cacheRootDir.GetFiles()) { - file.Delete(); + if (!file.Name.IsCaseInsensitiveEqual("placeholder") && !file.Name.IsCaseInsensitiveEqual("placeholder.txt")) + { + file.Delete(); + } } foreach (var dir in _cacheRootDir.GetDirectories()) { @@ -128,11 +137,14 @@ public virtual void DeleteCachedImages() public void CacheStatistics(out long fileCount, out long totalSize) { var allFiles = _cacheRootDir.GetFiles("*.*", SearchOption.AllDirectories); - fileCount = allFiles.Count(); + var allImageFiles = allFiles.Where(x => !x.Name.IsCaseInsensitiveEqual("placeholder") && !x.Name.IsCaseInsensitiveEqual("placeholder.txt")); + + fileCount = allImageFiles.Count(); + if (fileCount == 0) totalSize = 0; else - totalSize = allFiles.Sum(x => x.Length); + totalSize = allImageFiles.Sum(x => x.Length); } #region Utils @@ -194,7 +206,7 @@ private string CreateSettingsHash(ResizeSettings settings) { return settings.MaxWidth.ToString(); } - return settings.ToString().Hash(); + return settings.ToString().Hash(Encoding.ASCII); } private bool NeedsProcessing(ResizeSettings settings) diff --git a/src/Libraries/SmartStore.Services/Media/MediaExtensions.cs b/src/Libraries/SmartStore.Services/Media/MediaExtensions.cs new file mode 100644 index 0000000000..b776fd8de7 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Media/MediaExtensions.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Infrastructure; + +namespace SmartStore.Services.Media +{ + + public static class MediaHelper + { + + public static void UpdateDownloadTransientStateFor(TEntity entity, Expression> downloadIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => downloadIdProp); + + var propName = downloadIdProp.ExtractMemberInfo().Name; + int currentDownloadId = downloadIdProp.Compile().Invoke(entity); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentDownloadId, rs, null, save); + } + + public static void UpdateDownloadTransientStateFor(TEntity entity, Expression> downloadIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => downloadIdProp); + + var propName = downloadIdProp.ExtractMemberInfo().Name; + int currentDownloadId = downloadIdProp.Compile().Invoke(entity).GetValueOrDefault(); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentDownloadId, rs, null, save); + } + + public static void UpdatePictureTransientStateFor(TEntity entity, Expression> pictureIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => pictureIdProp); + + var propName = pictureIdProp.ExtractMemberInfo().Name; + int currentPictureId = pictureIdProp.Compile().Invoke(entity); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentPictureId, rs, GetPictureDeleteAction(), save); + } + + public static void UpdatePictureTransientStateFor(TEntity entity, Expression> pictureIdProp, bool save = false) where TEntity : BaseEntity + { + Guard.ArgumentNotNull(() => entity); + Guard.ArgumentNotNull(() => pictureIdProp); + + var propName = pictureIdProp.ExtractMemberInfo().Name; + int currentPictureId = pictureIdProp.Compile().Invoke(entity).GetValueOrDefault(); + var rs = EngineContext.Current.Resolve>(); + + UpdateTransientStateForEntityInternal(entity, propName, currentPictureId, rs, GetPictureDeleteAction(), save); + } + + public static void UpdateDownloadTransientState(int? prevDownloadId, int? currentDownloadId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevDownloadId.GetValueOrDefault(), currentDownloadId.GetValueOrDefault(), rs, null, save); + } + + public static void UpdateDownloadTransientState(int prevDownloadId, int currentDownloadId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevDownloadId, currentDownloadId, rs, null, save); + } + + public static void UpdatePictureTransientState(int? prevPictureId, int? currentPictureId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevPictureId.GetValueOrDefault(), currentPictureId.GetValueOrDefault(), rs, GetPictureDeleteAction(), save); + } + + public static void UpdatePictureTransientState(int prevPictureId, int currentPictureId, bool save = false) + { + var rs = EngineContext.Current.Resolve>(); + UpdateTransientStateCore(prevPictureId, currentPictureId, rs, GetPictureDeleteAction(), save); + } + + private static Action GetPictureDeleteAction() + { + Action deleteAction = pic => + { + var svc = EngineContext.Current.Resolve(); + svc.DeletePicture((Picture)pic); + }; + + return deleteAction; + } + + internal static void UpdateTransientStateForEntityInternal( + TEntity entity, + string propName, + int currentMediaId, + IRepository rs, + Action deleteAction, + bool save) where TEntity : BaseEntity where TMedia : BaseEntity + { + bool editMode = !entity.IsTransientRecord(); + var modifiedProperties = editMode ? rs.Context.GetModifiedProperties(entity) : new Dictionary(); + + object obj = null; + int prevMediaId = 0; + if (modifiedProperties.TryGetValue(propName, out obj)) + { + prevMediaId = ((int?)obj).GetValueOrDefault(); + } + + UpdateTransientStateCore(prevMediaId, currentMediaId, rs, deleteAction, save); + } + + internal static void UpdateTransientStateCore( + int prevMediaId, + int currentMediaId, + IRepository rs, + Action deleteAction, + bool save) + where TMedia : BaseEntity + { + var autoCommit = rs.AutoCommitEnabled; + rs.AutoCommitEnabled = false; + + try + { + TMedia media = null; + bool shouldSave = false; + + bool isModified = prevMediaId != currentMediaId; + + if (currentMediaId > 0 && isModified) + { + // new entity with a media or media replaced + media = rs.GetById(currentMediaId); + if (media != null) + { + var transient = media as ITransient; + if (transient != null) + { + transient.IsTransient = false; + shouldSave = true; + } + } + } + + if (prevMediaId > 0 && isModified) + { + // ID changed, so delete old record + media = rs.GetById(prevMediaId); + if (media != null) + { + if (deleteAction == null) + { + rs.Delete(media); + } + else + { + deleteAction(media); + } + shouldSave = true; + } + } + + if (save && shouldSave) + { + rs.Context.SaveChanges(); + } + } + finally + { + rs.AutoCommitEnabled = autoCommit; + } + } + + + } + +} diff --git a/src/Libraries/SmartStore.Services/Media/PictureService.cs b/src/Libraries/SmartStore.Services/Media/PictureService.cs index a408398cd0..563993234f 100644 --- a/src/Libraries/SmartStore.Services/Media/PictureService.cs +++ b/src/Libraries/SmartStore.Services/Media/PictureService.cs @@ -1,24 +1,19 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; using System.IO; using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ImageResizer; using SmartStore.Core; -using SmartStore.Core.IO; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Media; -using SmartStore.Services.Configuration; using SmartStore.Core.Events; +using SmartStore.Core.IO; using SmartStore.Core.Logging; -using SmartStore.Services.Seo; -using ImageResizer; -using ImageResizer.Configuration; -using StackExchange.Profiling; -using System.Threading; -using System.Text; +using SmartStore.Services.Configuration; using SmartStore.Utilities; namespace SmartStore.Services.Media @@ -47,21 +42,16 @@ public partial class PictureService : IPictureService private readonly MediaSettings _mediaSettings; private readonly IImageResizerService _imageResizerService; private readonly IImageCache _imageCache; + private readonly INotifier _notifier; + + private string _mediaPath; + private string _imagesPath; #endregion #region Ctor - /// - /// Ctor - /// - /// Picture repository - /// Product picture repository - /// Setting service - /// Web helper - /// Logger - /// Event publisher - /// Media settings + public PictureService( IRepository pictureRepository, IRepository productPictureRepository, @@ -71,7 +61,8 @@ public PictureService( IEventPublisher eventPublisher, MediaSettings mediaSettings, IImageResizerService imageResizerService, - IImageCache imageCache) + IImageCache imageCache, + INotifier notifier) { this._pictureRepository = pictureRepository; this._productPictureRepository = productPictureRepository; @@ -82,6 +73,7 @@ public PictureService( this._mediaSettings = mediaSettings; this._imageResizerService = imageResizerService; this._imageCache = imageCache; + this._notifier = notifier; } #endregion @@ -96,11 +88,19 @@ public PictureService( /// MIME type protected virtual void SavePictureInFile(int pictureId, byte[] pictureBinary, string mimeType) { - string lastPart = MimeTypes.MapMimeTypeToExtension(mimeType); - string fileName = string.Format("{0}-0.{1}", pictureId.ToString("0000000"), lastPart); - File.WriteAllBytes(GetPictureLocalPath(fileName), pictureBinary); + string filePath; + SavePictureInFile(pictureId, pictureBinary, mimeType, out filePath); } + private void SavePictureInFile(int pictureId, byte[] pictureBinary, string mimeType, out string filePath) + { + filePath = null; + string lastPart = MimeTypes.MapMimeTypeToExtension(mimeType); + string fileName = string.Format("{0}-0.{1}", pictureId.ToString("0000000"), lastPart); + filePath = GetPictureLocalPath(fileName); + File.WriteAllBytes(filePath, pictureBinary); + } + /// /// Delete a picture on file system /// @@ -119,12 +119,25 @@ protected virtual void DeletePictureOnFileSystem(Picture picture) } } - /// - /// Validates input picture dimensions and prevents that the image size exceeds global max size - /// - /// Picture binary - /// MIME type - /// Picture binary or throws an exception + private string GetDefaultImageFileName(PictureType defaultPictureType = PictureType.Entity) + { + string defaultImageFileName; + switch (defaultPictureType) + { + case PictureType.Entity: + defaultImageFileName = _settingService.GetSettingByKey("Media.DefaultImageName", "default-image.jpg"); + break; + case PictureType.Avatar: + defaultImageFileName = _settingService.GetSettingByKey("Media.Customer.DefaultAvatarImageName", "default-avatar.jpg"); + break; + default: + defaultImageFileName = _settingService.GetSettingByKey("Media.DefaultImageName", "default-image.jpg"); + break; + } + + return defaultImageFileName; + } + public virtual byte[] ValidatePicture(byte[] pictureBinary) { Size originalSize = this.GetPictureSize(pictureBinary); @@ -141,46 +154,48 @@ public virtual byte[] ValidatePicture(byte[] pictureBinary) } } - private string GetDefaultImageFileName(PictureType defaultPictureType = PictureType.Entity) - { - string defaultImageFileName; - switch (defaultPictureType) - { - case PictureType.Entity: - defaultImageFileName = _settingService.GetSettingByKey("Media.DefaultImageName", "default-image.jpg"); - break; - case PictureType.Avatar: - defaultImageFileName = _settingService.GetSettingByKey("Media.Customer.DefaultAvatarImageName", "default-avatar.jpg"); - break; - default: - defaultImageFileName = _settingService.GetSettingByKey("Media.DefaultImageName", "default-image.jpg"); - break; - } - - return defaultImageFileName; - } - - #endregion - - #region Methods - - /// - /// Get picture SEO friendly name - /// - /// Name - /// Result - public virtual string GetPictureSeName(string name) + #endregion + + #region Methods + + public byte[] FindEqualPicture(string path, IEnumerable pictures, out int equalPictureId) + { + return FindEqualPicture(File.ReadAllBytes(path), pictures, out equalPictureId); + } + + public byte[] FindEqualPicture(byte[] pictureBinary, IEnumerable pictures, out int equalPictureId) + { + equalPictureId = 0; + try + { + foreach (var picture in pictures) + { + var otherPictureBinary = LoadPictureBinary(picture); + + using (var myStream = new MemoryStream(pictureBinary)) + using (var otherStream = new MemoryStream(otherPictureBinary)) + { + if (myStream.ContentsEqual(otherStream)) + { + equalPictureId = picture.Id; + return null; + } + } + } + + return pictureBinary; + } + catch + { + return null; + } + } + + public virtual string GetPictureSeName(string name) { return SeoHelper.GetSeName(name, true, false); } - /// - /// Get a picture local path - /// - /// Picture instance - /// The target picture size (longest side) - /// A value indicating whether the default picture is shown - /// public virtual string GetThumbLocalPath(Picture picture, int targetSize = 0, bool showDefaultPicture = true) { // 'GetPictureUrl' takes care of creating the thumb when not created already @@ -215,13 +230,6 @@ public virtual string GetThumbLocalPath(Picture picture, int targetSize = 0, boo } - /// - /// Gets the default picture URL - /// - /// The target picture size (longest side) - /// Default picture type - /// Store location URL; null to use determine the current store location automatically - /// Picture URL public virtual string GetDefaultPictureUrl(int targetSize = 0, PictureType defaultPictureType = PictureType.Entity, string storeLocation = null) { string defaultImageFileName = GetDefaultImageFileName(defaultPictureType); @@ -232,26 +240,15 @@ public virtual string GetDefaultPictureUrl(int targetSize = 0, PictureType defau return string.Empty; } - if (targetSize == 0) - { - string url = (!String.IsNullOrEmpty(storeLocation) - ? storeLocation - : _webHelper.GetStoreLocation()) - + "Content/Images/" + defaultImageFileName; - return url; - } - else - { - var url = this.GetProcessedImageUrl( - filePath, - 0, - Path.GetFileNameWithoutExtension(filePath), - Path.GetExtension(filePath), - targetSize, - storeLocation); + var url = this.GetProcessedImageUrl( + filePath, + 0, + Path.GetFileNameWithoutExtension(filePath), + Path.GetExtension(filePath), + targetSize, + storeLocation); - return url; - } + return url; } protected internal virtual string GetProcessedImageUrl(object source, int? pictureId, string seoFileName, string extension, int targetSize = 0, string storeLocation = null) @@ -299,7 +296,6 @@ protected internal virtual string GetProcessedImageUrl(object source, int? pictu using (var resultStream = _imageResizerService.ResizeImage(sourceStream, targetSize, targetSize, _mediaSettings.DefaultImageQuality)) { _imageCache.AddImageToCache(cachedImage, resultStream.GetBuffer()); - //File.WriteAllBytes(cachedImage.LocalPath, resultStream.GetBuffer()); } } } @@ -324,32 +320,30 @@ protected internal virtual string GetProcessedImageUrl(object source, int? pictu /// Picture binary protected virtual byte[] LoadPictureFromFile(int pictureId, string mimeType) { - string lastPart = MimeTypes.MapMimeTypeToExtension(mimeType); - string fileName = string.Format("{0}-0.{1}", pictureId.ToString("0000000"), lastPart); - var filePath = GetPictureLocalPath(fileName); - if (!File.Exists(filePath)) - { - return new byte[0]; - } - return File.ReadAllBytes(filePath); + string filePath; + return LoadPictureFromFile(pictureId, mimeType, out filePath); } - /// - /// Gets the loaded picture binary depending on picture storage settings - /// - /// Picture - /// Picture binary + private byte[] LoadPictureFromFile(int pictureId, string mimeType, out string filePath) + { + filePath = null; + + string lastPart = MimeTypes.MapMimeTypeToExtension(mimeType); + string fileName = string.Format("{0}-0.{1}", pictureId.ToString("0000000"), lastPart); + filePath = GetPictureLocalPath(fileName); + if (!File.Exists(filePath)) + { + filePath = null; + return new byte[0]; + } + return File.ReadAllBytes(filePath); + } + public virtual byte[] LoadPictureBinary(Picture picture) { return LoadPictureBinary(picture, this.StoreInDb); } - /// - /// Gets the loaded picture binary depending on picture storage settings - /// - /// Picture - /// Load from database; otherwise, from file system - /// Picture binary public virtual byte[] LoadPictureBinary(Picture picture, bool fromDb) { if (picture == null) @@ -409,15 +403,6 @@ internal Size GetPictureSize(byte[] pictureBinary) return size; } - /// - /// Get a picture URL - /// - /// Picture identifier - /// The target picture size (longest side) - /// A value indicating whether the default picture is shown - /// Store location URL; null to use determine the current store location automatically - /// Default picture type - /// Picture URL public virtual string GetPictureUrl( int pictureId, int targetSize = 0, @@ -429,15 +414,6 @@ public virtual string GetPictureUrl( return GetPictureUrl(picture, targetSize, showDefaultPicture, storeLocation, defaultPictureType); } - /// - /// Get a picture URL - /// - /// Picture instance - /// The target picture size (longest side) - /// A value indicating whether the default picture is shown - /// Store location URL; null to use determine the current store location automatically - /// Default picture type - /// Picture URL public virtual string GetPictureUrl( Picture picture, int targetSize = 0, @@ -501,15 +477,15 @@ private ResizeSettings CreateResizeSettings(int targetSize) /// Local picture path protected virtual string GetPictureLocalPath(string fileName) { - var imagesDirectoryPath = _webHelper.MapPath("~/Media/"); - var filePath = Path.Combine(imagesDirectoryPath, fileName); + var path = _mediaPath ?? (_mediaPath = _webHelper.MapPath("~/Media/")); + var filePath = Path.Combine(path, fileName); return filePath; } protected virtual string GetDefaultPictureLocalPath(string fileName) { - var dirPath = _webHelper.MapPath("~/Content/Images"); - var filePath = Path.Combine(dirPath, fileName); + var path = _imagesPath ?? (_imagesPath = _webHelper.MapPath("~/Content/Images")); + var filePath = Path.Combine(path, fileName); return filePath; } @@ -527,37 +503,27 @@ public virtual Picture GetPictureById(int pictureId) return picture; } - /// - /// Deletes a picture - /// - /// Picture public virtual void DeletePicture(Picture picture) { if (picture == null) throw new ArgumentNullException("picture"); - //delete thumbs + // delete thumbs _imageCache.DeleteCachedImages(picture); - //delete from file system + // delete from file system if (!this.StoreInDb) { DeletePictureOnFileSystem(picture); } - //delete from database + // delete from database _pictureRepository.Delete(picture); - //event notification + // event notification _eventPublisher.EntityDeleted(picture); } - /// - /// Gets a collection of pictures - /// - /// Current page - /// Items on each page - /// Paged list of pictures public virtual IPagedList GetPictures(int pageIndex, int pageSize) { var query = from p in _pictureRepository.Table @@ -567,20 +533,13 @@ orderby p.Id descending return pics; } - /// - /// Gets pictures by product identifier - /// - /// Product identifier - /// Number of records to return. 0 if you want to get all items - /// Pictures public virtual IList GetPicturesByProductId(int productId, int recordsToReturn = 0) { if (productId == 0) return new List(); - var query = from p in _pictureRepository.Table - join pp in _productPictureRepository.Table on p.Id equals pp.PictureId + join pp in _productPictureRepository.Table on p.Id equals pp.PictureId orderby pp.DisplayOrder where pp.ProductId == productId select p; @@ -592,16 +551,17 @@ orderby pp.DisplayOrder return pics; } - /// - /// Inserts a picture - /// - /// The picture binary - /// The picture MIME type - /// The SEO filename - /// A value indicating whether the picture is new - /// A value indicating whether to validated provided picture binary - /// Picture - public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool validateBinary = true) + public virtual IList GetPicturesByIds(int[] pictureIds) + { + Guard.ArgumentNotNull(() => pictureIds); + + var query = _pictureRepository.Table + .Where(x => pictureIds.Contains(x.Id)); + + return query.ToList(); + } + + public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool isTransient = true, bool validateBinary = true) { mimeType = mimeType.EmptyNull(); mimeType = mimeType.Truncate(20); @@ -618,6 +578,8 @@ public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, stri picture.MimeType = mimeType; picture.SeoFilename = seoFilename; picture.IsNew = isNew; + picture.IsTransient = isTransient; + picture.UpdatedOnUtc = DateTime.UtcNow; _pictureRepository.Insert(picture); @@ -632,16 +594,6 @@ public virtual Picture InsertPicture(byte[] pictureBinary, string mimeType, stri return picture; } - /// - /// Updates the picture - /// - /// The picture identifier - /// The picture binary - /// The picture MIME type - /// The SEO filename - /// A value indicating whether the picture is new - /// A value indicating whether to validated provided picture binary - /// Picture public virtual Picture UpdatePicture(int pictureId, byte[] pictureBinary, string mimeType, string seoFilename, bool isNew, bool validateBinary = true) { mimeType = mimeType.EmptyNull().Truncate(20); @@ -666,6 +618,7 @@ public virtual Picture UpdatePicture(int pictureId, byte[] pictureBinary, string picture.MimeType = mimeType; picture.SeoFilename = seoFilename; picture.IsNew = isNew; + picture.UpdatedOnUtc = DateTime.UtcNow; _pictureRepository.Update(picture); @@ -680,22 +633,15 @@ public virtual Picture UpdatePicture(int pictureId, byte[] pictureBinary, string return picture; } - /// - /// Updates a SEO filename of a picture - /// - /// The picture identifier - /// The SEO filename - /// Picture public virtual Picture SetSeoFilename(int pictureId, string seoFilename) { var picture = GetPictureById(pictureId); if (picture == null) throw new ArgumentException("No picture found with the specified id"); - //update if it has been changed + // update if it has been changed if (seoFilename != picture.SeoFilename) { - //update picture picture = UpdatePicture(picture.Id, LoadPictureBinary(picture), picture.MimeType, seoFilename, true, false); } return picture; @@ -705,10 +651,6 @@ public virtual Picture SetSeoFilename(int pictureId, string seoFilename) #region Properties - - /// - /// Gets or sets a value indicating whether the images should be stored in data base. - /// public virtual bool StoreInDb { get @@ -717,34 +659,139 @@ public virtual bool StoreInDb } set { - //check whether it's a new value + // check whether the value was changed if (this.StoreInDb != value) { - //save the new setting value + // save the new setting value _settingService.SetSetting("Media.Images.StoreInDB", value); - //update all picture objects - var pictures = this.GetPictures(0, int.MaxValue); - foreach (var picture in pictures) - { - var pictureBinary = LoadPictureBinary(picture, !value); - - //delete from file system - if (value) - DeletePictureOnFileSystem(picture); - - //just update a picture (all required logic is in UpdatePicture method) - UpdatePicture(picture.Id, - pictureBinary, - picture.MimeType, - picture.SeoFilename, - true, - false); - //we do not validate picture binary here to ensure that no exception ("Parameter is not valid") will be thrown when "moving" pictures - } + // move them all + MovePictures(value); } } } + + protected int MovePictures(bool toDb) + { + // long running operation, therefore some code chunks are redundant here in order to boost performance + + // a list of ALL file paths that were either deleted or created + var affectedFiles = new List(1000); + + var ctx = _pictureRepository.Context; + var failed = false; + int i = 0; + + using (var scope = new DbContextScope(ctx: ctx, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) + { + using (var tx = ctx.BeginTransaction()) + { + // we are about to process data in chunks but want to commit ALL at once when ALL chunks have been processed successfully. + try + { + int pageIndex = 0; + IPagedList pictures = null; + + do + { + if (pictures != null) + { + // detach all entities from previous page to save memory + ctx.DetachEntities(pictures); + + // breathe + pictures.Clear(); + pictures = null; + } + + // load max 500 picture entities at once + pictures = this.GetPictures(pageIndex, 500); + pageIndex++; + + foreach (var picture in pictures) + { + string filePath = null; + + if (!toDb) + { + if (picture.PictureBinary != null && picture.PictureBinary.Length > 0) + { + // save picture as file + SavePictureInFile(picture.Id, picture.PictureBinary, picture.MimeType, out filePath); + } + // remove picture binary from DB + picture.PictureBinary = new byte[0]; + } + else + { + // load picture binary from file and set in DB + var picBinary = LoadPictureFromFile(picture.Id, picture.MimeType, out filePath); + if (picBinary.Length > 0) + { + picture.PictureBinary = picBinary; + } + } + + // remember file path: we must be able to rollback IO operations on transaction failure + if (filePath.HasValue()) + { + affectedFiles.Add(filePath); + //picture.IsNew = true; + } + + // explicitly attach modified entity to context, because we disabled AutoCommit + picture.UpdatedOnUtc = DateTime.UtcNow; + _pictureRepository.Update(picture); + + i++; + } + + // save the current batch to DB + ctx.SaveChanges(); + + } while (pictures.HasNextPage); + + // FIRE! + tx.Commit(); + } + catch (Exception ex) + { + failed = true; + tx.Rollback(); + _settingService.SetSetting("Media.Images.StoreInDB", !toDb); + _notifier.Error(ex.Message); + _logger.Error(ex); + } + } + } + + if (affectedFiles.Count > 0) + { + if ((toDb && !failed) || (!toDb && failed)) + { + // FS > DB sucessful OR DB > FS failed: delete all physical files + // run a background task for the deletion of files (fire & forget) + Task.Factory.StartNew(state => + { + var files = state as string[]; + foreach (var path in files) + { + if (File.Exists(path)) + File.Delete(path); + } + }, affectedFiles.ToArray()).ConfigureAwait(false); + } + + // shrink database (only when DB > FS and success) + if (!toDb && !failed) + { + ctx.ShrinkDatabase(); + } + } + + return i; + } + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Media/TransientMediaClearTask.cs b/src/Libraries/SmartStore.Services/Media/TransientMediaClearTask.cs new file mode 100644 index 0000000000..b67c04fbe5 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Media/TransientMediaClearTask.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Media; +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.Media +{ + /// + /// Represents a task for deleting transient media from the database + /// (pictures and downloads which have been uploaded but never assigned to an entity) + /// + public partial class TransientMediaClearTask : ITask + { + private readonly IPictureService _pictureService; + private readonly IRepository _pictureRepository; + private readonly IRepository _downloadRepository; + + public TransientMediaClearTask( + IPictureService pictureService, + IRepository pictureRepository, + IRepository downloadRepository) + { + this._pictureService = pictureService; + this._pictureRepository = pictureRepository; + this._downloadRepository = downloadRepository; + } + + public void Execute(TaskExecutionContext ctx) + { + // delete all media records which are in transient state since at least 3 hours + var olderThan = DateTime.UtcNow.AddHours(-3); + + // delete Downloads + _downloadRepository.DeleteAll(x => x.IsTransient && x.UpdatedOnUtc < olderThan); + + // delete Pictures + var autoCommit = _pictureRepository.AutoCommitEnabled; + _pictureRepository.AutoCommitEnabled = false; + + try + { + using (var scope = new DbContextScope(autoDetectChanges: false, validateOnSave: false, hooksEnabled: false)) + { + var pictures = _pictureRepository.Table.Where(x => x.IsTransient && x.UpdatedOnUtc < olderThan).ToList(); + foreach (var picture in pictures) + { + _pictureService.DeletePicture(picture); + } + + _pictureRepository.Context.SaveChanges(); + + if (DataSettings.Current.IsSqlServer) + { + try + { + _pictureRepository.Context.ExecuteSqlCommand("DBCC SHRINKDATABASE(0)", true); + } + catch { } + } + } + } + finally + { + _pictureRepository.AutoCommitEnabled = autoCommit; + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/CampaignService.cs b/src/Libraries/SmartStore.Services/Messages/CampaignService.cs index 3612b15a53..0db4388dc7 100644 --- a/src/Libraries/SmartStore.Services/Messages/CampaignService.cs +++ b/src/Libraries/SmartStore.Services/Messages/CampaignService.cs @@ -190,6 +190,9 @@ public virtual void SendCampaign(Campaign campaign, EmailAccount emailAccount, s var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, _storeContext.CurrentStore); + _messageTokenProvider.AddNewsLetterSubscriptionTokens(tokens, new NewsLetterSubscription() { + Email = email + }); var customer = _customerService.GetCustomerByEmail(email); if (customer != null) diff --git a/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs b/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs index ebf71742dc..639c0391cb 100644 --- a/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs +++ b/src/Libraries/SmartStore.Services/Messages/EmailAccountService.cs @@ -2,36 +2,37 @@ using System.Collections.Generic; using System.Linq; using SmartStore.Core; +using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; namespace SmartStore.Services.Messages { - public partial class EmailAccountService:IEmailAccountService + public partial class EmailAccountService : IEmailAccountService { - private readonly IRepository _emailAccountRepository; + private const string EMAILACCOUNT_BY_ID_KEY = "SmartStore.emailaccount.id-{0}"; + private const string EMAILACCOUNT_PATTERN_KEY = "SmartStore.emailaccount."; + + private readonly IRepository _emailAccountRepository; private readonly EmailAccountSettings _emailAccountSettings; private readonly IEventPublisher _eventPublisher; + private readonly ICacheManager _cacheManager; - /// - /// Ctor - /// - /// Email account repository - /// - /// Event published - public EmailAccountService(IRepository emailAccountRepository, - EmailAccountSettings emailAccountSettings, IEventPublisher eventPublisher) + private EmailAccount _defaultEmailAccount; + + public EmailAccountService( + IRepository emailAccountRepository, + EmailAccountSettings emailAccountSettings, + IEventPublisher eventPublisher, + ICacheManager cacheManager /* request */) { - _emailAccountRepository = emailAccountRepository; - _emailAccountSettings = emailAccountSettings; - _eventPublisher = eventPublisher; + this._emailAccountRepository = emailAccountRepository; + this._emailAccountSettings = emailAccountSettings; + this._eventPublisher = eventPublisher; + this._cacheManager = cacheManager; } - /// - /// Inserts an email account - /// - /// Email account public virtual void InsertEmailAccount(EmailAccount emailAccount) { if (emailAccount == null) @@ -57,14 +58,12 @@ public virtual void InsertEmailAccount(EmailAccount emailAccount) _emailAccountRepository.Insert(emailAccount); - //event notification + _cacheManager.RemoveByPattern(EMAILACCOUNT_PATTERN_KEY); + _defaultEmailAccount = null; + _eventPublisher.EntityInserted(emailAccount); } - /// - /// Updates an email account - /// - /// Email account public virtual void UpdateEmailAccount(EmailAccount emailAccount) { if (emailAccount == null) @@ -90,14 +89,12 @@ public virtual void UpdateEmailAccount(EmailAccount emailAccount) _emailAccountRepository.Update(emailAccount); - //event notification + _cacheManager.RemoveByPattern(EMAILACCOUNT_PATTERN_KEY); + _defaultEmailAccount = null; + _eventPublisher.EntityUpdated(emailAccount); } - /// - /// Deletes an email account - /// - /// Email account public virtual void DeleteEmailAccount(EmailAccount emailAccount) { if (emailAccount == null) @@ -108,28 +105,38 @@ public virtual void DeleteEmailAccount(EmailAccount emailAccount) _emailAccountRepository.Delete(emailAccount); - //event notification + _cacheManager.RemoveByPattern(EMAILACCOUNT_PATTERN_KEY); + _defaultEmailAccount = null; + _eventPublisher.EntityDeleted(emailAccount); } - /// - /// Gets an email account by identifier - /// - /// The email account identifier - /// Email account public virtual EmailAccount GetEmailAccountById(int emailAccountId) { if (emailAccountId == 0) return null; - - var emailAccount = _emailAccountRepository.GetById(emailAccountId); - return emailAccount; + + string key = string.Format(EMAILACCOUNT_BY_ID_KEY, emailAccountId); + return _cacheManager.Get(key, () => + { + return _emailAccountRepository.GetById(emailAccountId); + }); } - /// - /// Gets all email accounts - /// - /// Email accounts list + public virtual EmailAccount GetDefaultEmailAccount() + { + if (_defaultEmailAccount == null) + { + _defaultEmailAccount = GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); + if (_defaultEmailAccount == null) + { + _defaultEmailAccount = GetAllEmailAccounts().FirstOrDefault(); + } + } + + return _defaultEmailAccount; + } + public virtual IList GetAllEmailAccounts() { var query = from ea in _emailAccountRepository.Table diff --git a/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs b/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs index ada12006c8..681cb588b6 100644 --- a/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs +++ b/src/Libraries/SmartStore.Services/Messages/EventPublisherExtensions.cs @@ -1,4 +1,5 @@ -using SmartStore.Core; +using System.Collections.Generic; +using SmartStore.Core; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Events; @@ -26,12 +27,12 @@ public static void PublishNewsletterUnsubscribe(this IEventPublisher eventPublis eventPublisher.Publish(new EmailUnsubscribedEvent(email)); } - public static void EntityTokensAdded(this IEventPublisher eventPublisher, T entity, System.Collections.Generic.IList tokens) where T : BaseEntity + public static void EntityTokensAdded(this IEventPublisher eventPublisher, T entity, IList tokens) where T : BaseEntity { eventPublisher.Publish(new EntityTokensAddedEvent(entity, tokens)); } - public static void MessageTokensAdded(this IEventPublisher eventPublisher, MessageTemplate message, System.Collections.Generic.IList tokens) + public static void MessageTokensAdded(this IEventPublisher eventPublisher, MessageTemplate message, IList tokens) { eventPublisher.Publish(new MessageTokensAddedEvent(message, tokens)); } diff --git a/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs b/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs index 5f03d721bd..6b3df6f6eb 100644 --- a/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs +++ b/src/Libraries/SmartStore.Services/Messages/IEmailAccountService.cs @@ -30,6 +30,12 @@ public partial interface IEmailAccountService /// Email account EmailAccount GetEmailAccountById(int emailAccountId); + /// + /// Gets the default email account + /// + /// Emil account + EmailAccount GetDefaultEmailAccount(); + /// /// Gets all email accounts /// diff --git a/src/Libraries/SmartStore.Services/Messages/IMessageTokenProvider.cs b/src/Libraries/SmartStore.Services/Messages/IMessageTokenProvider.cs index b70bcdd0bf..3cf3bd7563 100644 --- a/src/Libraries/SmartStore.Services/Messages/IMessageTokenProvider.cs +++ b/src/Libraries/SmartStore.Services/Messages/IMessageTokenProvider.cs @@ -3,6 +3,7 @@ using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.News; using SmartStore.Core.Domain.Orders; @@ -11,13 +12,13 @@ namespace SmartStore.Services.Messages { - public partial interface IMessageTokenProvider + public partial interface IMessageTokenProvider { void AddStoreTokens(IList tokens, Store store); - void AddOrderTokens(IList tokens, Order order, int languageId); + void AddOrderTokens(IList tokens, Order order, Language language); - void AddShipmentTokens(IList tokens, Shipment shipment, int languageId); + void AddShipmentTokens(IList tokens, Shipment shipment, Language language); void AddOrderNoteTokens(IList tokens, OrderNote orderNote); @@ -37,9 +38,9 @@ public partial interface IMessageTokenProvider void AddNewsCommentTokens(IList tokens, NewsComment newsComment); - void AddProductTokens(IList tokens, Product product, int languageId); + void AddProductTokens(IList tokens, Product product, Language language); - void AddForumTokens(IList tokens, Forum forum); + void AddForumTokens(IList tokens, Forum forum, Language language); void AddForumTopicTokens(IList tokens, ForumTopic forumTopic, int? friendlyForumTopicPageIndex = null, int? appendedPostIdentifierAnchor = null); @@ -54,13 +55,10 @@ void AddForumTopicTokens(IList tokens, ForumTopic forumTopic, string[] GetListOfAllowedTokens(); - //codehint: sm-add begin void AddBankConnectionTokens(IList tokens); void AddCompanyTokens(IList tokens); void AddContactDataTokens(IList tokens); - //codehint: sm-add end - } } diff --git a/src/Libraries/SmartStore.Services/Messages/INewsLetterSubscriptionService.cs b/src/Libraries/SmartStore.Services/Messages/INewsLetterSubscriptionService.cs index 851a4d952d..a579ff6859 100644 --- a/src/Libraries/SmartStore.Services/Messages/INewsLetterSubscriptionService.cs +++ b/src/Libraries/SmartStore.Services/Messages/INewsLetterSubscriptionService.cs @@ -1,21 +1,11 @@ using System; -using System.IO; using SmartStore.Core; using SmartStore.Core.Domain.Messages; -using SmartStore.Core.Data; namespace SmartStore.Services.Messages { - public partial interface INewsLetterSubscriptionService - { - - /// - /// Executes a bulk import of subscriber data from a CSV source - /// - /// The input file stream - /// The import result - ImportResult ImportSubscribers(Stream stream); - + public partial interface INewsLetterSubscriptionService + { /// /// Inserts a newsletter subscription /// @@ -37,12 +27,21 @@ public partial interface INewsLetterSubscriptionService /// if set to true [publish subscription events]. void DeleteNewsLetterSubscription(NewsLetterSubscription newsLetterSubscription, bool publishSubscriptionEvents = true); - /// - /// Gets a newsletter subscription by newsletter subscription identifier - /// - /// The newsletter subscription identifier - /// NewsLetter subscription - NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId); + /// + /// Adds or deletes a newsletter subscription + /// + /// true add subscription, false delete + /// Email address + /// Store identifier + /// true added subscription, false removed subscription, null did nothing + bool? AddNewsLetterSubscriptionFor(bool add, string email, int storeId); + + /// + /// Gets a newsletter subscription by newsletter subscription identifier + /// + /// The newsletter subscription identifier + /// NewsLetter subscription + NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId); /// /// Gets a newsletter subscription by newsletter subscription GUID @@ -70,4 +69,4 @@ public partial interface INewsLetterSubscriptionService /// NewsLetterSubscription entity list IPagedList GetAllNewsLetterSubscriptions(string email, int pageIndex, int pageSize, bool showHidden = false, int storeId = 0); } -} +} \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs index 2df4541e0b..12baf20719 100644 --- a/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/IQueuedEmailService.cs @@ -25,6 +25,12 @@ public partial interface IQueuedEmailService /// Queued email void DeleteQueuedEmail(QueuedEmail queuedEmail); + /// + /// Deletes all queued emails + /// + /// The count of deleted entries + int DeleteAllQueuedEmails(); + /// /// Gets a queued email by identifier /// @@ -42,19 +48,28 @@ public partial interface IQueuedEmailService /// /// Search queued emails /// - /// From Email - /// To Email - /// The start time - /// The end time - /// A value indicating whether to load only not sent emails - /// Maximum send tries - /// A value indicating whether we should sort queued email descending; otherwise, ascending. - /// Page index - /// Page size + /// An object containing the query criteria /// Email item collection - IPagedList SearchEmails(string fromEmail, - string toEmail, DateTime? startTime, DateTime? endTime, - bool loadNotSentItemsOnly, int maxSendTries, - bool loadNewest, int pageIndex, int pageSize); + IPagedList SearchEmails(SearchEmailsQuery query); + + /// + /// Sends a queued email + /// + /// Queued email + /// Whether the operation succeeded + bool SendEmail(QueuedEmail queuedEmail); + + /// + /// Gets a queued email attachment by identifier + /// + /// Queued email attachment identifier + /// Queued email attachment + QueuedEmailAttachment GetQueuedEmailAttachmentById(int id); + + /// + /// Deleted a queued email attachment + /// + /// Queued email attachment + void DeleteQueuedEmailAttachment(QueuedEmailAttachment qea); } } diff --git a/src/Libraries/SmartStore.Services/Messages/IWorkflowMessageService.cs b/src/Libraries/SmartStore.Services/Messages/IWorkflowMessageService.cs index 624834f672..5dbb25c83a 100644 --- a/src/Libraries/SmartStore.Services/Messages/IWorkflowMessageService.cs +++ b/src/Libraries/SmartStore.Services/Messages/IWorkflowMessageService.cs @@ -227,7 +227,7 @@ int SendNewForumPostMessage(Customer customer, /// Private message /// Message language identifier /// Queued email identifier - int SendPrivateMessageNotification(PrivateMessage privateMessage, int languageId); + int SendPrivateMessageNotification(Customer customer, PrivateMessage privateMessage, int languageId); #endregion diff --git a/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs new file mode 100644 index 0000000000..979051d1d6 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Messages/Importer/NewsLetterSubscriptionImporter.cs @@ -0,0 +1,154 @@ +using System; +using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Messages; +using SmartStore.Services.DataExchange.Import; + +namespace SmartStore.Services.Messages.Importer +{ + public class NewsLetterSubscriptionImporter : IEntityImporter + { + private readonly ICommonServices _services; + private readonly IRepository _subscriptionRepository; + + public NewsLetterSubscriptionImporter( + ICommonServices services, + IRepository subscriptionRepository) + { + _services = services; + _subscriptionRepository = subscriptionRepository; + } + + public static string[] SupportedKeyFields + { + get + { + return new string[] { "Email" }; + } + } + + public static string[] DefaultKeyFields + { + get + { + return new string[] { "Email" }; + } + } + + public void Execute(ImportExecuteContext context) + { + var utcNow = DateTime.UtcNow; + var currentStoreId = _services.StoreContext.CurrentStore.Id; + + using (var scope = new DbContextScope(ctx: _services.DbContext, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false)) + { + var segmenter = context.DataSegmenter; + + context.Result.TotalRecords = segmenter.TotalRows; + + while (context.Abort == DataExchangeAbortion.None && segmenter.ReadNextBatch()) + { + var batch = segmenter.GetCurrentBatch(); + + // Perf: detach all entities + _subscriptionRepository.Context.DetachEntities(false); + + context.SetProgress(segmenter.CurrentSegmentFirstRowIndex - 1, segmenter.TotalRows); + + foreach (var row in batch) + { + try + { + var active = true; + var email = row.GetDataValue("Email"); + var storeId = row.GetDataValue("StoreId"); + + if (storeId == 0) + { + storeId = currentStoreId; + } + + if (row.HasDataValue("Active") && row.TryGetDataValue("Active", out active)) + { + } + else + { + active = true; // default + } + + if (email.IsEmpty()) + { + context.Result.AddWarning("Skipped empty email address", row.GetRowInfo(), "Email"); + continue; + } + + if (email.Length > 255) + { + context.Result.AddWarning("Skipped email address '{0}'. It exceeds the maximum allowed length of 255".FormatInvariant(email), row.GetRowInfo(), "Email"); + continue; + } + + if (!email.IsEmail()) + { + context.Result.AddWarning("Skipped invalid email address '{0}'".FormatInvariant(email), row.GetRowInfo(), "Email"); + continue; + } + + NewsLetterSubscription subscription = null; + + foreach (var keyName in context.KeyFieldNames) + { + switch (keyName) + { + case "Email": + subscription = _subscriptionRepository.Table + .OrderBy(x => x.Id) + .FirstOrDefault(x => x.Email == email && x.StoreId == storeId); + break; + } + + if (subscription != null) + break; + } + + if (subscription == null) + { + if (context.UpdateOnly) + { + ++context.Result.SkippedRecords; + continue; + } + + subscription = new NewsLetterSubscription + { + Active = active, + CreatedOnUtc = utcNow, + Email = email, + NewsLetterSubscriptionGuid = Guid.NewGuid(), + StoreId = storeId + }; + + _subscriptionRepository.Insert(subscription); + context.Result.NewRecords++; + } + else + { + subscription.Active = active; + + _subscriptionRepository.Update(subscription); + context.Result.ModifiedRecords++; + } + } + catch (Exception exception) + { + context.Result.AddError(exception.ToAllMessages(), row.GetRowInfo()); + } + } // for + + _subscriptionRepository.Context.SaveChanges(); + } // while + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs b/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs index 92ae48a637..65d8fe735c 100644 --- a/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs +++ b/src/Libraries/SmartStore.Services/Messages/MessageTemplateService.cs @@ -45,7 +45,8 @@ public partial class MessageTemplateService: IMessageTemplateService /// Store mapping service /// Message template repository /// Event published - public MessageTemplateService(ICacheManager cacheManager, + public MessageTemplateService( + ICacheManager cacheManager, IRepository storeMappingRepository, ILanguageService languageService, ILocalizedEntityService localizedEntityService, @@ -209,7 +210,7 @@ public virtual MessageTemplate CopyMessageTemplate(MessageTemplate messageTempla if (messageTemplate == null) throw new ArgumentNullException("messageTemplate"); - var mtCopy = new MessageTemplate() + var mtCopy = new MessageTemplate { Name = messageTemplate.Name, BccEmailAddresses = messageTemplate.BccEmailAddresses, @@ -218,25 +219,26 @@ public virtual MessageTemplate CopyMessageTemplate(MessageTemplate messageTempla IsActive = messageTemplate.IsActive, EmailAccountId = messageTemplate.EmailAccountId, LimitedToStores = messageTemplate.LimitedToStores + // INFO: we do not copy attachments }; InsertMessageTemplate(mtCopy); var languages = _languageService.GetAllLanguages(true); - //localization + // localization foreach (var lang in languages) { var bccEmailAddresses = messageTemplate.GetLocalized(x => x.BccEmailAddresses, lang.Id, false, false); - if (!String.IsNullOrEmpty(bccEmailAddresses)) + if (bccEmailAddresses.HasValue()) _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.BccEmailAddresses, bccEmailAddresses, lang.Id); var subject = messageTemplate.GetLocalized(x => x.Subject, lang.Id, false, false); - if (!String.IsNullOrEmpty(subject)) + if (subject.HasValue()) _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.Subject, subject, lang.Id); var body = messageTemplate.GetLocalized(x => x.Body, lang.Id, false, false); - if (!String.IsNullOrEmpty(body)) + if (body.HasValue()) _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.Body, subject, lang.Id); var emailAccountId = messageTemplate.GetLocalized(x => x.EmailAccountId, lang.Id, false, false); @@ -244,7 +246,7 @@ public virtual MessageTemplate CopyMessageTemplate(MessageTemplate messageTempla _localizedEntityService.SaveLocalizedValue(mtCopy, x => x.EmailAccountId, emailAccountId, lang.Id); } - //store mapping + // store mapping var selectedStoreIds = _storeMappingService.GetStoresIdsWithAccess(messageTemplate); foreach (var id in selectedStoreIds) { diff --git a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs index 83a31b72e7..d0ff917259 100644 --- a/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs +++ b/src/Libraries/SmartStore.Services/Messages/MessageTokenProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Linq.Expressions; using System.Text; using System.Web; using SmartStore.Core; @@ -10,19 +11,23 @@ using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.News; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Stores; using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Events; using SmartStore.Core.Html; +using SmartStore.Core.Plugins; using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; using SmartStore.Services.Directory; -using SmartStore.Core.Events; using SmartStore.Services.Forums; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; @@ -30,8 +35,8 @@ using SmartStore.Services.Orders; using SmartStore.Services.Payments; using SmartStore.Services.Seo; +using SmartStore.Services.Stores; using SmartStore.Services.Topics; -using SmartStore.Core.Domain.Directory; namespace SmartStore.Services.Messages { @@ -50,42 +55,49 @@ public partial class MessageTokenProvider : IMessageTokenProvider private readonly IStoreContext _storeContext; private readonly IDownloadService _downloadService; private readonly IOrderService _orderService; - private readonly IPaymentService _paymentService; + private readonly IProviderManager _providerManager; private readonly IProductAttributeParser _productAttributeParser; - private readonly StoreInformationSettings _storeSettings; private readonly MessageTemplatesSettings _templatesSettings; private readonly EmailAccountSettings _emailAccountSettings; private readonly CatalogSettings _catalogSettings; private readonly TaxSettings _taxSettings; - private readonly IEventPublisher _eventPublisher; - private readonly CompanyInformationSettings _companyInfoSettings; private readonly BankConnectionSettings _bankConnectionSettings; private readonly ContactDataSettings _contactDataSettings; private readonly ITopicService _topicService; private readonly ShoppingCartSettings _shoppingCartSettings; private readonly IDeliveryTimeService _deliveryTimeService; + private readonly IQuantityUnitService _quantityUnitService; + private readonly IUrlRecordService _urlRecordService; + private readonly IStoreService _storeService; + private readonly IGenericAttributeService _attrService; + private readonly IPictureService _pictureService; + private readonly MediaSettings _mediaSettings; - #endregion + #endregion - #region Ctor + #region Ctor - public MessageTokenProvider(ILanguageService languageService, + public MessageTokenProvider(ILanguageService languageService, ILocalizationService localizationService, IDateTimeHelper dateTimeHelper, IEmailAccountService emailAccountService, IPriceFormatter priceFormatter, ICurrencyService currencyService, IWebHelper webHelper, IWorkContext workContext, IStoreContext storeContext, IDownloadService downloadService, ShoppingCartSettings shoppingCartSettings, - IOrderService orderService, IPaymentService paymentService, + IOrderService orderService, IProviderManager providerManager, IProductAttributeParser productAttributeParser, StoreInformationSettings storeSettings, MessageTemplatesSettings templatesSettings, EmailAccountSettings emailAccountSettings, CatalogSettings catalogSettings, TaxSettings taxSettings, IEventPublisher eventPublisher, CompanyInformationSettings companyInfoSettings, BankConnectionSettings bankConnectionSettings, ContactDataSettings contactDataSettings, ITopicService topicService, - IDeliveryTimeService deliveryTimeService) + IDeliveryTimeService deliveryTimeService, IQuantityUnitService quantityUnitService, + IUrlRecordService urlRecordService, IStoreService storeService, + IGenericAttributeService attrService, + IPictureService pictureService, + MediaSettings mediaSettings) { this._languageService = languageService; this._localizationService = localizationService; @@ -98,49 +110,105 @@ public MessageTokenProvider(ILanguageService languageService, this._storeContext = storeContext; this._downloadService = downloadService; this._orderService = orderService; - this._paymentService = paymentService; + this._providerManager = providerManager; this._productAttributeParser = productAttributeParser; - this._storeSettings = storeSettings; this._templatesSettings = templatesSettings; this._emailAccountSettings = emailAccountSettings; this._catalogSettings = catalogSettings; this._taxSettings = taxSettings; this._eventPublisher = eventPublisher; - this._companyInfoSettings = companyInfoSettings; this._bankConnectionSettings = bankConnectionSettings; this._contactDataSettings = contactDataSettings; this._topicService = topicService; this._shoppingCartSettings = shoppingCartSettings; this._deliveryTimeService = deliveryTimeService; + this._quantityUnitService = quantityUnitService; + this._urlRecordService = urlRecordService; + this._storeService = storeService; + this._attrService = attrService; + this._pictureService = pictureService; + this._mediaSettings = mediaSettings; } - #endregion + #endregion - #region Utilities + #region Utilities - /// - /// Convert a collection to a HTML table - /// - /// Order - /// Language identifier - /// HTML table of products - protected virtual string ProductListToHtmlTable(Order order, int languageId) - { - var result = ""; + protected virtual Picture GetPictureFor(Product product, string attributesXml) + { + Picture picture = null; + + if (attributesXml.HasValue()) + { + var combination = _productAttributeParser.FindProductVariantAttributeCombination(product.Id, attributesXml); + + if (combination != null) + { + var picturesIds = combination.GetAssignedPictureIds(); + if (picturesIds != null && picturesIds.Length > 0) + picture = _pictureService.GetPictureById(picturesIds[0]); + } + } + + if (picture == null) + { + picture = _pictureService.GetPicturesByProductId(product.Id, 1).FirstOrDefault(); + } + + if (picture == null && !product.VisibleIndividually && product.ParentGroupedProductId > 0) + { + picture = _pictureService.GetPicturesByProductId(product.ParentGroupedProductId, 1).FirstOrDefault(); + } + + return picture; + } + + protected virtual string ProductPictureToHtml(Picture picture, Language language, string productName, string productUrl, string storeLocation) + { + if (picture != null && _mediaSettings.MessageProductThumbPictureSize > 0) + { + var imageUrl = _pictureService.GetPictureUrl(picture, _mediaSettings.MessageProductThumbPictureSize, false, storeLocation); + if (imageUrl.HasValue()) + { + var title = _localizationService.GetResource("Media.Product.ImageLinkTitleFormat", language.Id).FormatInvariant(productName); + var alternate = _localizationService.GetResource("Media.Product.ImageAlternateTextFormat", language.Id).FormatInvariant(productName); + + var polaroid = "padding: 3px; background-color: #fff; border: 1px solid #ccc; border: 1px solid rgba(0,0,0,.2);"; + var style = "max-width: {0}px; max-height: {0}px; {1}".FormatInvariant(_mediaSettings.MessageProductThumbPictureSize, polaroid); - var language = _languageService.GetLanguageById(languageId); + var image = "\"{1}\"".FormatInvariant(imageUrl, alternate, title, style); + if (productUrl.IsEmpty()) + return image; + + return "{1}".FormatInvariant(productUrl, image); + } + } + return ""; + } + + /// + /// Convert a collection to a HTML table + /// + /// Order + /// Language identifier + /// HTML table of products + protected virtual string ProductListToHtmlTable(Order order, Language language) + { var sb = new StringBuilder(); - sb.AppendLine(""); + var storeLocation = _webHelper.GetStoreLocation(false); + + sb.AppendLine("
"); #region Products - sb.AppendLine(string.Format("", _templatesSettings.Color1)); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Name", languageId))); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Price", languageId))); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Quantity", languageId))); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Total", languageId))); + + sb.AppendLine(string.Format("", _templatesSettings.Color1)); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Name", language.Id))); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Price", language.Id))); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Quantity", language.Id))); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Total", language.Id))); sb.AppendLine(""); var table = order.OrderItems.ToList(); @@ -153,11 +221,7 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) DeliveryTime deliveryTime = null; - // merging attribute combination data required? - if (_catalogSettings.ShowProductSku || (_shoppingCartSettings.ShowDeliveryTimes && product.IsShipEnabled)) - { - product.MergeWithCombination(orderItem.AttributesXml, _productAttributeParser); - } + product.MergeWithCombination(orderItem.AttributesXml, _productAttributeParser); if (_shoppingCartSettings.ShowDeliveryTimes && product.IsShipEnabled) { @@ -165,16 +229,29 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) } sb.AppendLine(string.Format("", _templatesSettings.Color2)); - //product name - string productName = product.GetLocalized(x => x.Name, languageId); + + var productName = product.GetLocalized(x => x.Name, language.Id); + var productUrl = _productAttributeParser.GetProductUrlWithAttributes(orderItem.AttributesXml, product.Id, product.GetSeName()); - sb.AppendLine(""); @@ -228,7 +305,10 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) } sb.AppendLine(string.Format("", unitPriceStr)); - sb.AppendLine(string.Format("", orderItem.Quantity)); + var quantityUnit = _quantityUnitService.GetQuantityUnitById(product.QuantityUnitId); + + sb.AppendLine(string.Format("", + orderItem.Quantity, quantityUnit == null ? "" : quantityUnit.GetLocalized(x => x.Name))); string priceStr = string.Empty; switch (order.CustomerTaxDisplayType) @@ -250,6 +330,7 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) sb.AppendLine(""); } + #endregion #region Checkout Attributes @@ -257,8 +338,6 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) if (!String.IsNullOrEmpty(order.CheckoutAttributeDescription)) { sb.AppendLine(""); } @@ -276,6 +355,7 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) string cusTaxTotal = string.Empty; string cusDiscount = string.Empty; string cusTotal = string.Empty; + //subtotal, shipping, payment method fee switch (order.CustomerTaxDisplayType) { @@ -374,41 +454,34 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate); cusTotal = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, language); - - - //subtotal - //sb.AppendLine(string.Format("", _templatesSettings.Color3, _localizationService.GetResource("Messages.Order.SubTotal", languageId), cusSubTotal)); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.SubTotal", languageId), cusSubTotal)); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.SubTotal", language.Id), cusSubTotal)); //discount (applied to order subtotal) if (dislaySubTotalDiscount) { - //sb.AppendLine(string.Format("", _templatesSettings.Color3, _localizationService.GetResource("Messages.Order.SubTotalDiscount", languageId), cusSubTotalDiscount)); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.SubTotalDiscount", languageId), cusSubTotalDiscount)); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.SubTotalDiscount", language.Id), cusSubTotalDiscount)); } //shipping if (dislayShipping) { - //sb.AppendLine(string.Format("", _templatesSettings.Color3, _localizationService.GetResource("Messages.Order.Shipping", languageId), cusShipTotal)); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Shipping", languageId), cusShipTotal)); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Shipping", language.Id), cusShipTotal)); } //payment method fee if (displayPaymentMethodFee) { - string paymentMethodFeeTitle = _localizationService.GetResource("Messages.Order.PaymentMethodAdditionalFee", languageId); - //sb.AppendLine(string.Format("", _templatesSettings.Color3, paymentMethodFeeTitle, cusPaymentMethodAdditionalFee)); - sb.AppendLine(string.Format("", paymentMethodFeeTitle, cusPaymentMethodAdditionalFee)); + string paymentMethodFeeTitle = _localizationService.GetResource("Messages.Order.PaymentMethodAdditionalFee", language.Id); + + sb.AppendLine(string.Format("", paymentMethodFeeTitle, cusPaymentMethodAdditionalFee)); } //tax if (displayTax) { - //sb.AppendLine(string.Format("", _templatesSettings.Color3, _localizationService.GetResource("Messages.Order.Tax", languageId), cusTaxTotal)); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Tax", languageId), cusTaxTotal)); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Tax", language.Id), cusTaxTotal)); } if (displayTaxRates) { @@ -416,45 +489,50 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) { string taxRate = String.Format(_localizationService.GetResource("Messages.Order.TaxRateLine"), _priceFormatter.FormatTaxRate(item.Key)); string taxValue = _priceFormatter.FormatPrice(item.Value, true, order.CustomerCurrencyCode, false, language); - //sb.AppendLine(string.Format("", _templatesSettings.Color3, taxRate, taxValue)); - sb.AppendLine(string.Format("", taxRate, taxValue)); + + sb.AppendLine(string.Format("", taxRate, taxValue)); } } //discount if (dislayDiscount) { - //sb.AppendLine(string.Format("", _templatesSettings.Color3, _localizationService.GetResource("Messages.Order.TotalDiscount", languageId), cusDiscount)); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.TotalDiscount", languageId), cusDiscount)); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.TotalDiscount", language.Id), cusDiscount)); } //gift cards var gcuhC = order.GiftCardUsageHistory; foreach (var gcuh in gcuhC) { - string giftCardText = String.Format(_localizationService.GetResource("Messages.Order.GiftCardInfo", languageId), HttpUtility.HtmlEncode(gcuh.GiftCard.GiftCardCouponCode)); + string giftCardText = String.Format(_localizationService.GetResource("Messages.Order.GiftCardInfo", language.Id), HttpUtility.HtmlEncode(gcuh.GiftCard.GiftCardCouponCode)); string giftCardAmount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(gcuh.UsedValue, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, language); - //sb.AppendLine(string.Format("", _templatesSettings.Color3, giftCardText, giftCardAmount)); - sb.AppendLine(string.Format("", giftCardText, giftCardAmount)); + + var remaining = _currencyService.ConvertCurrency(gcuh.GiftCard.GetGiftCardRemainingAmount(), order.CurrencyRate); + var remainingFormatted = _priceFormatter.FormatPrice(remaining, true, false); + var remainingText = _localizationService.GetResource("ShoppingCart.Totals.GiftCardInfo.Remaining", language.Id).FormatInvariant(remainingFormatted); + + sb.AppendLine(string.Format("", + giftCardText, remainingText, giftCardAmount)); } //reward points if (order.RedeemedRewardPointsEntry != null) { - string rpTitle = string.Format(_localizationService.GetResource("Messages.Order.RewardPoints", languageId), -order.RedeemedRewardPointsEntry.Points); + string rpTitle = string.Format(_localizationService.GetResource("Messages.Order.RewardPoints", language.Id), -order.RedeemedRewardPointsEntry.Points); string rpAmount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(order.RedeemedRewardPointsEntry.UsedAmount, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, language); - //sb.AppendLine(string.Format("", _templatesSettings.Color3, rpTitle, rpAmount)); - sb.AppendLine(string.Format("", rpTitle, rpAmount)); + + sb.AppendLine(string.Format("", rpTitle, rpAmount)); } //total - sb.AppendLine(string.Format("", _templatesSettings.Color3, _localizationService.GetResource("Messages.Order.OrderTotal", languageId), cusTotal)); - #endregion + sb.AppendLine(string.Format("", _templatesSettings.Color3, _localizationService.GetResource("Messages.Order.OrderTotal", language.Id), cusTotal)); + + #endregion sb.AppendLine("
{0}{0}{0}{0}
{0}{0}{0}{0}
" + HttpUtility.HtmlEncode(productName)); - //add download link - if (_downloadService.IsDownloadAllowed(orderItem)) + sb.AppendLine(""); + + if (_mediaSettings.MessageProductThumbPictureSize > 0) + { + var pictureHtml = ProductPictureToHtml(GetPictureFor(product, orderItem.AttributesXml), language, productName, productUrl, storeLocation); + if (pictureHtml.HasValue()) + { + sb.AppendLine("
{0}
".FormatInvariant(pictureHtml)); + } + } + + sb.AppendLine("{1}".FormatInvariant(productUrl, HttpUtility.HtmlEncode(productName))); + + //add download link + if (_downloadService.IsDownloadAllowed(orderItem)) { //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - string downloadUrl = string.Format("{0}download/getdownload/{1}", _webHelper.GetStoreLocation(false), orderItem.OrderItemGuid); - string downloadLink = string.Format("{1}", downloadUrl, _localizationService.GetResource("Messages.Order.Product(s).Download", languageId)); + string downloadUrl = string.Format("{0}download/getdownload/{1}", storeLocation, orderItem.OrderItemGuid); + string downloadLink = string.Format("{1}", downloadUrl, _localizationService.GetResource("Messages.Order.Product(s).Download", language.Id)); sb.AppendLine("  ("); sb.AppendLine(downloadLink); sb.AppendLine(")"); @@ -187,7 +264,7 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) sb.AppendLine("
"); sb.AppendLine("
"); - sb.AppendLine("" + _localizationService.GetResource("Products.DeliveryTime") + ""); + sb.AppendLine("" + _localizationService.GetResource("Products.DeliveryTime", language.Id) + ""); sb.AppendLine(""); sb.AppendLine("" + deliveryTimeName + ""); sb.AppendLine("
"); @@ -205,7 +282,7 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) if (!String.IsNullOrEmpty(product.Sku)) { sb.AppendLine("
"); - sb.AppendLine(string.Format(_localizationService.GetResource("Messages.Order.Product(s).SKU", languageId), HttpUtility.HtmlEncode(product.Sku))); + sb.AppendLine(string.Format(_localizationService.GetResource("Messages.Order.Product(s).SKU", language.Id), HttpUtility.HtmlEncode(product.Sku))); } } sb.AppendLine("
{0}{0}{0} {1}
 "); - //codehint: sm-edit - //sb.AppendLine(order.CheckoutAttributeDescription); sb.AppendLine(HtmlUtils.ConvertPlainTextToTable(HtmlUtils.ConvertHtmlToPlainText(order.CheckoutAttributeDescription))); sb.AppendLine("
 {1} {2}
 {0} {1}
 {0} {1}
 {1} {2}
 {0} {1}
 {0} {1}
 {1} {2}
 {0} {1}
 {0} {1}
 {1} {2}
 {0} {1}
 {0} {1}
 {1} {2}
 {0} {1}
 {0} {1}
 {1} {2}
 {0} {1}
 {0} {1}
 {1} {2}
 {0} {1}
 {0} {1}
 {1} {2}
 {0} {1}
 {0}
{1}
{2}
 {1} {2}
 {0} {1}
 {0} {1}
 {1}{2}
 {1}{2}
"); - result = sb.ToString(); - return result; - } + + return sb.ToString(); + } /// /// Convert a collection to a HTML table @@ -462,17 +540,17 @@ protected virtual string ProductListToHtmlTable(Order order, int languageId) /// Shipment /// Language identifier /// HTML table of products - protected virtual string ProductListToHtmlTable(Shipment shipment, int languageId) + protected virtual string ProductListToHtmlTable(Shipment shipment, Language language) { - var result = ""; - var sb = new StringBuilder(); + sb.AppendLine(""); #region Products + sb.AppendLine(string.Format("", _templatesSettings.Color1)); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Name", languageId))); - sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Quantity", languageId))); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Name", language.Id))); + sb.AppendLine(string.Format("", _localizationService.GetResource("Messages.Order.Product(s).Quantity", language.Id))); sb.AppendLine(""); var table = shipment.ShipmentItems.ToList(); @@ -488,12 +566,15 @@ protected virtual string ProductListToHtmlTable(Shipment shipment, int languageI continue; sb.AppendLine(string.Format("", _templatesSettings.Color2)); - //product name - string productName = product.GetLocalized(x => x.Name, languageId); - sb.AppendLine(""); @@ -515,14 +596,14 @@ protected virtual string ProductListToHtmlTable(Shipment shipment, int languageI sb.AppendLine(""); } + #endregion sb.AppendLine("
{0}{0}{0}{0}
" + HttpUtility.HtmlEncode(productName)); - //attributes - if (!String.IsNullOrEmpty(orderItem.AttributeDescription)) + var productName = product.GetLocalized(x => x.Name, language.Id); + var productUrl = _productAttributeParser.GetProductUrlWithAttributes(orderItem.AttributesXml, product.Id, product.GetSeName()); + + sb.AppendLine(""); + sb.AppendLine("{1}".FormatInvariant(productUrl, HttpUtility.HtmlEncode(productName))); + + //attributes + if (!String.IsNullOrEmpty(orderItem.AttributeDescription)) { sb.AppendLine("
"); sb.AppendLine(orderItem.AttributeDescription); @@ -506,7 +587,7 @@ protected virtual string ProductListToHtmlTable(Shipment shipment, int languageI if (!String.IsNullOrEmpty(product.Sku)) { sb.AppendLine("
"); - sb.AppendLine(string.Format(_localizationService.GetResource("Messages.Order.Product(s).SKU", languageId), HttpUtility.HtmlEncode(product.Sku))); + sb.AppendLine(string.Format(_localizationService.GetResource("Messages.Order.Product(s).SKU", language.Id), HttpUtility.HtmlEncode(product.Sku))); } } sb.AppendLine("
"); - result = sb.ToString(); - return result; - } - //codehint: sm-add + return sb.ToString(); + } + protected virtual string TopicToHtml(string systemName, int languageId) { var result = ""; @@ -555,7 +636,7 @@ protected virtual string GetSupplierIdentification() sb.AppendLine(""); sb.AppendLine(""); - sb.AppendLine("\s*$/g,At={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"
"); + sb.AppendLine(""); sb.AppendLine(String.Format("{0}
", _companyInfoSettings.CompanyName )); @@ -598,7 +679,7 @@ protected virtual string GetSupplierIdentification() sb.AppendLine("
"); - sb.AppendLine(""); + sb.AppendLine(""); if (!String.IsNullOrEmpty(_storeContext.CurrentStore.Url)) { @@ -619,7 +700,7 @@ protected virtual string GetSupplierIdentification() sb.AppendLine(""); - sb.AppendLine(""); + sb.AppendLine(""); if (!String.IsNullOrEmpty(_bankConnectionSettings.Bankname)) { @@ -667,15 +748,11 @@ public virtual void AddStoreTokens(IList tokens, Store store) { tokens.Add(new Token("Store.Name", store.Name)); tokens.Add(new Token("Store.URL", store.Url, true)); - var defaultEmailAccount = _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); - if (defaultEmailAccount == null) - defaultEmailAccount = _emailAccountService.GetAllEmailAccounts().FirstOrDefault(); + var defaultEmailAccount = _emailAccountService.GetDefaultEmailAccount(); tokens.Add(new Token("Store.SupplierIdentification", GetSupplierIdentification(), true)); tokens.Add(new Token("Store.Email", defaultEmailAccount.Email)); } - //codehint: sm-add begin - public virtual void AddCompanyTokens(IList tokens) { tokens.Add(new Token("Company.CompanyName", _companyInfoSettings.CompanyName)); @@ -718,28 +795,26 @@ public virtual void AddContactDataTokens(IList tokens) tokens.Add(new Token("Contact.ContactEmailAddress", _contactDataSettings.ContactEmailAddress)); } - //codehint: sm-add end - - public virtual void AddOrderTokens(IList tokens, Order order, int languageId) + public virtual void AddOrderTokens(IList tokens, Order order, Language language) { - tokens.Add(new Token("Order.OrderNumber", order.GetOrderNumber())); + tokens.Add(new Token("Order.ID", order.Id.ToString())); + tokens.Add(new Token("Order.OrderNumber", order.GetOrderNumber())); tokens.Add(new Token("Order.CustomerFullName", string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName))); tokens.Add(new Token("Order.CustomerEmail", order.BillingAddress.Email)); - - tokens.Add(new Token("Order.BillingFirstName", order.BillingAddress.FirstName)); - tokens.Add(new Token("Order.BillingLastName", order.BillingAddress.LastName)); - tokens.Add(new Token("Order.BillingPhoneNumber", order.BillingAddress.PhoneNumber)); - tokens.Add(new Token("Order.BillingEmail", order.BillingAddress.Email)); - tokens.Add(new Token("Order.BillingFaxNumber", order.BillingAddress.FaxNumber)); - tokens.Add(new Token("Order.BillingCompany", order.BillingAddress.Company)); - tokens.Add(new Token("Order.BillingAddress1", order.BillingAddress.Address1)); - tokens.Add(new Token("Order.BillingAddress2", order.BillingAddress.Address2)); - tokens.Add(new Token("Order.BillingCity", order.BillingAddress.City)); - tokens.Add(new Token("Order.BillingStateProvince", order.BillingAddress.StateProvince != null ? order.BillingAddress.StateProvince.GetLocalized(x => x.Name) : "")); - tokens.Add(new Token("Order.BillingZipPostalCode", order.BillingAddress.ZipPostalCode)); - tokens.Add(new Token("Order.BillingCountry", order.BillingAddress.Country != null ? order.BillingAddress.Country.GetLocalized(x => x.Name) : "")); + tokens.Add(new Token("Order.BillingFirstName", order.BillingAddress.FirstName)); + tokens.Add(new Token("Order.BillingLastName", order.BillingAddress.LastName)); + tokens.Add(new Token("Order.BillingPhoneNumber", order.BillingAddress.PhoneNumber)); + tokens.Add(new Token("Order.BillingEmail", order.BillingAddress.Email)); + tokens.Add(new Token("Order.BillingFaxNumber", order.BillingAddress.FaxNumber)); + tokens.Add(new Token("Order.BillingCompany", order.BillingAddress.Company)); + tokens.Add(new Token("Order.BillingAddress1", order.BillingAddress.Address1)); + tokens.Add(new Token("Order.BillingAddress2", order.BillingAddress.Address2)); + tokens.Add(new Token("Order.BillingCity", order.BillingAddress.City)); + tokens.Add(new Token("Order.BillingStateProvince", order.BillingAddress.StateProvince != null ? order.BillingAddress.StateProvince.GetLocalized(x => x.Name) : "")); + tokens.Add(new Token("Order.BillingZipPostalCode", order.BillingAddress.ZipPostalCode)); + tokens.Add(new Token("Order.BillingCountry", order.BillingAddress.Country != null ? order.BillingAddress.Country.GetLocalized(x => x.Name) : "")); tokens.Add(new Token("Order.ShippingMethod", order.ShippingMethod)); tokens.Add(new Token("Order.ShippingFirstName", order.ShippingAddress != null ? order.ShippingAddress.FirstName : "")); @@ -755,14 +830,22 @@ public virtual void AddOrderTokens(IList tokens, Order order, int languag tokens.Add(new Token("Order.ShippingZipPostalCode", order.ShippingAddress != null ? order.ShippingAddress.ZipPostalCode : "")); tokens.Add(new Token("Order.ShippingCountry", order.ShippingAddress != null && order.ShippingAddress.Country != null ? order.ShippingAddress.Country.GetLocalized(x => x.Name) : "")); - var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(order.PaymentMethodSystemName); - var paymentMethodName = paymentMethod != null ? paymentMethod.GetLocalizedValue(_localizationService, "FriendlyName", _workContext.WorkingLanguage.Id) : order.PaymentMethodSystemName; - tokens.Add(new Token("Order.PaymentMethod", paymentMethodName)); + string paymentMethodName = null; + var paymentMethod = _providerManager.GetProvider(order.PaymentMethodSystemName); + if (paymentMethod != null) + { + paymentMethodName = GetLocalizedValue(paymentMethod.Metadata, "FriendlyName", x => x.FriendlyName); + } + if (paymentMethodName.IsEmpty()) + { + paymentMethodName = order.PaymentMethodSystemName; + } + + tokens.Add(new Token("Order.PaymentMethod", paymentMethodName)); tokens.Add(new Token("Order.VatNumber", order.VatNumber)); + tokens.Add(new Token("Order.Product(s)", ProductListToHtmlTable(order, language), true)); + tokens.Add(new Token("Order.CustomerComment", order.CustomerOrderComment, true)); - tokens.Add(new Token("Order.Product(s)", ProductListToHtmlTable(order, languageId), true)); - - var language = _languageService.GetLanguageById(languageId); if (language != null && !String.IsNullOrEmpty(language.LanguageCulture)) { DateTime createdOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, TimeZoneInfo.Utc, _dateTimeHelper.GetCustomerTimeZone(order.Customer)); @@ -773,24 +856,39 @@ public virtual void AddOrderTokens(IList tokens, Order order, int languag tokens.Add(new Token("Order.CreatedOn", order.CreatedOnUtc.ToString("D"))); } - //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - tokens.Add(new Token("Order.OrderURLForCustomer", string.Format("{0}orderdetails/{1}", _webHelper.GetStoreLocation(false), order.Id), true)); - + // TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) + tokens.Add(new Token("Order.OrderURLForCustomer", string.Format("{0}order/details/{1}", _webHelper.GetStoreLocation(false), order.Id), true)); - //Codehint: sm-add - tokens.Add(new Token("Order.Disclaimer", TopicToHtml("Disclaimer", languageId), true)); - tokens.Add(new Token("Order.ConditionsOfUse", TopicToHtml("ConditionsOfUse", languageId), true)); + tokens.Add(new Token("Order.Disclaimer", TopicToHtml("Disclaimer", language.Id), true)); + tokens.Add(new Token("Order.ConditionsOfUse", TopicToHtml("ConditionsOfUse", language.Id), true)); //event notification _eventPublisher.EntityTokensAdded(order, tokens); } - public virtual void AddShipmentTokens(IList tokens, Shipment shipment, int languageId) + private string GetLocalizedValue(ProviderMetadata metadata, string propertyName, Expression> fallback) + { + // TODO: (mc) this actually belongs to PluginMediator, but we simply cannot add a dependency to framework from here. Refactor later! + + Guard.ArgumentNotNull(() => metadata); + + string systemName = metadata.SystemName; + var languageId = _workContext.WorkingLanguage.Id; + var resourceName = metadata.ResourceKeyPattern.FormatInvariant(metadata.SystemName, propertyName); + string result = _localizationService.GetResource(resourceName, languageId, false, "", true); + + if (result.IsEmpty()) + result = fallback.Compile()(metadata); + + return result; + } + + public virtual void AddShipmentTokens(IList tokens, Shipment shipment, Language language) { tokens.Add(new Token("Shipment.ShipmentNumber", shipment.Id.ToString())); tokens.Add(new Token("Shipment.TrackingNumber", shipment.TrackingNumber)); - tokens.Add(new Token("Shipment.Product(s)", ProductListToHtmlTable(shipment, languageId), true)); - tokens.Add(new Token("Shipment.URLForCustomer", string.Format("{0}orderdetails/shipment/{1}", _webHelper.GetStoreLocation(false), shipment.Id), true)); + tokens.Add(new Token("Shipment.Product(s)", ProductListToHtmlTable(shipment, language), true)); + tokens.Add(new Token("Shipment.URLForCustomer", string.Format("{0}order/shipmentdetails/{1}", _webHelper.GetStoreLocation(false), shipment.Id), true)); //event notification _eventPublisher.EntityTokensAdded(shipment, tokens); @@ -829,14 +927,27 @@ public virtual void AddReturnRequestTokens(IList tokens, ReturnRequest re public virtual void AddGiftCardTokens(IList tokens, GiftCard giftCard) { - tokens.Add(new Token("GiftCard.SenderName", giftCard.SenderName)); + var order = (giftCard.PurchasedWithOrderItem != null ? giftCard.PurchasedWithOrderItem.Order : null); + + if (order != null) + { + var remainingAmount = _currencyService.ConvertCurrency(giftCard.GetGiftCardRemainingAmount(), order.CurrencyRate); + + tokens.Add(new Token("GiftCard.RemainingAmount", _priceFormatter.FormatPrice(remainingAmount, true, false))); + } + else + { + tokens.Add(new Token("GiftCard.RemainingAmount", "")); + } + + tokens.Add(new Token("GiftCard.SenderName", giftCard.SenderName)); tokens.Add(new Token("GiftCard.SenderEmail", giftCard.SenderEmail)); tokens.Add(new Token("GiftCard.RecipientName", giftCard.RecipientName)); tokens.Add(new Token("GiftCard.RecipientEmail", giftCard.RecipientEmail)); tokens.Add(new Token("GiftCard.Amount", _priceFormatter.FormatPrice(giftCard.Amount, true, false))); - tokens.Add(new Token("GiftCard.CouponCode", giftCard.GiftCardCouponCode)); + tokens.Add(new Token("GiftCard.CouponCode", giftCard.GiftCardCouponCode)); - var giftCardMesage = !String.IsNullOrWhiteSpace(giftCard.Message) ? + var giftCardMesage = !String.IsNullOrWhiteSpace(giftCard.Message) ? HtmlUtils.FormatText(giftCard.Message, false, true, false, false, false, false) : ""; tokens.Add(new Token("GiftCard.Message", giftCardMesage, true)); @@ -847,22 +958,22 @@ public virtual void AddGiftCardTokens(IList tokens, GiftCard giftCard) public virtual void AddCustomerTokens(IList tokens, Customer customer) { - tokens.Add(new Token("Customer.Email", customer.Email)); + tokens.Add(new Token("Customer.ID", customer.Id.ToString())); + tokens.Add(new Token("Customer.Email", customer.Email)); tokens.Add(new Token("Customer.Username", customer.Username)); tokens.Add(new Token("Customer.FullName", customer.GetFullName())); tokens.Add(new Token("Customer.VatNumber", customer.GetAttribute(SystemCustomerAttributeNames.VatNumber))); tokens.Add(new Token("Customer.VatNumberStatus", ((VatNumberStatus)customer.GetAttribute(SystemCustomerAttributeNames.VatNumberStatusId)).ToString())); - //note: we do not use SEO friendly URLS because we can get errors caused by having .(dot) in the URL (from the emauk address) //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - string passwordRecoveryUrl = string.Format("{0}passwordrecovery/confirm?token={1}&email={2}", _webHelper.GetStoreLocation(false), + string passwordRecoveryUrl = string.Format("{0}customer/passwordrecoveryconfirm?token={1}&email={2}", _webHelper.GetStoreLocation(), customer.GetAttribute(SystemCustomerAttributeNames.PasswordRecoveryToken), HttpUtility.UrlEncode(customer.Email)); - string accountActivationUrl = string.Format("{0}customer/activation?token={1}&email={2}", _webHelper.GetStoreLocation(false), + string accountActivationUrl = string.Format("{0}customer/activation?token={1}&email={2}", _webHelper.GetStoreLocation(), customer.GetAttribute(SystemCustomerAttributeNames.AccountActivationToken), HttpUtility.UrlEncode(customer.Email)); - var wishlistUrl = string.Format("{0}wishlist/{1}", _webHelper.GetStoreLocation(false), customer.CustomerGuid); + var wishlistUrl = string.Format("{0}wishlist/{1}", _webHelper.GetStoreLocation(), customer.CustomerGuid); tokens.Add(new Token("Customer.PasswordRecoveryURL", passwordRecoveryUrl, true)); tokens.Add(new Token("Customer.AccountActivationURL", accountActivationUrl, true)); tokens.Add(new Token("Wishlist.URLForCustomer", wishlistUrl, true)); @@ -875,7 +986,6 @@ public virtual void AddNewsLetterSubscriptionTokens(IList tokens, NewsLet { tokens.Add(new Token("NewsLetterSubscription.Email", subscription.Email)); - const string urlFormat = "{0}newsletter/subscriptionactivation/{1}/{2}"; var activationUrl = String.Format(urlFormat, _webHelper.GetStoreLocation(false), subscription.NewsLetterSubscriptionGuid, "true"); @@ -912,20 +1022,36 @@ public virtual void AddNewsCommentTokens(IList tokens, NewsComment newsCo _eventPublisher.EntityTokensAdded(newsComment, tokens); } - public virtual void AddProductTokens(IList tokens, Product product, int languageId) + public virtual void AddProductTokens(IList tokens, Product product, Language language) { + // TODO: add a method for getting URL (use routing because it handles all SEO friendly URLs) + var storeLocation = _webHelper.GetStoreLocation(false); + var productUrl = storeLocation + product.GetSeName(); + var productName = product.GetLocalized(x => x.Name, language.Id); + tokens.Add(new Token("Product.ID", product.Id.ToString())); tokens.Add(new Token("Product.Sku", product.Sku)); - tokens.Add(new Token("Product.Name", product.GetLocalized(x => x.Name, languageId))); - tokens.Add(new Token("Product.ShortDescription", product.GetLocalized(x => x.ShortDescription, languageId), true)); + tokens.Add(new Token("Product.Name", productName)); + tokens.Add(new Token("Product.ShortDescription", product.GetLocalized(x => x.ShortDescription, language.Id), true)); tokens.Add(new Token("Product.StockQuantity", product.StockQuantity.ToString())); - - // TODO: add a method for getting URL (use routing because it handles all SEO friendly URLs) - var productUrl = string.Format("{0}{1}", _webHelper.GetStoreLocation(false), product.GetSeName()); tokens.Add(new Token("Product.ProductURLForCustomer", productUrl, true)); - //event notification - _eventPublisher.EntityTokensAdded(product, tokens); + var currency = _workContext.WorkingCurrency; + + var additionalShippingCharge = _currencyService.ConvertFromPrimaryStoreCurrency(product.AdditionalShippingCharge, currency); + var additionalShippingChargeFormatted = _priceFormatter.FormatPrice(additionalShippingCharge, false, currency.CurrencyCode, false, language); + + tokens.Add(new Token("Product.AdditionalShippingCharge", additionalShippingChargeFormatted)); + + if (_mediaSettings.MessageProductThumbPictureSize > 0) + { + var pictureHtml = ProductPictureToHtml(GetPictureFor(product, null), language, productName, productUrl, storeLocation); + + tokens.Add(new Token("Product.Thumbnail", pictureHtml, true)); + } + + //event notification + _eventPublisher.EntityTokensAdded(product, tokens); } public virtual void AddForumTopicTokens(IList tokens, ForumTopic forumTopic, @@ -955,12 +1081,12 @@ public virtual void AddForumPostTokens(IList tokens, ForumPost forumPost) _eventPublisher.EntityTokensAdded(forumPost, tokens); } - public virtual void AddForumTokens(IList tokens, Forum forum) + public virtual void AddForumTokens(IList tokens, Forum forum, Language language) { //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - var forumUrl = string.Format("{0}boards/forum/{1}/{2}", _webHelper.GetStoreLocation(false), forum.Id, forum.GetSeName()); + var forumUrl = string.Format("{0}boards/forum/{1}/{2}", _webHelper.GetStoreLocation(false), forum.Id, forum.GetSeName(language.Id)); tokens.Add(new Token("Forums.ForumURL", forumUrl, true)); - tokens.Add(new Token("Forums.ForumName", forum.Name)); + tokens.Add(new Token("Forums.ForumName", forum.GetLocalized(x => x.Name, language.Id))); //event notification _eventPublisher.EntityTokensAdded(forum, tokens); @@ -977,7 +1103,15 @@ public virtual void AddPrivateMessageTokens(IList tokens, PrivateMessage public virtual void AddBackInStockTokens(IList tokens, BackInStockSubscription subscription) { - tokens.Add(new Token("BackInStockSubscription.ProductName", subscription.Product.Name)); + var customerLangId = subscription.Customer.GetAttribute( + SystemCustomerAttributeNames.LanguageId, + _attrService, + _storeContext.CurrentStore.Id); + + var store = _storeService.GetStoreById(subscription.StoreId); + var productLink = "{0}{1}".FormatWith(store.Url, subscription.Product.GetSeName(customerLangId, _urlRecordService, _languageService)); + + tokens.Add(new Token("BackInStockSubscription.ProductName", "{1}".FormatWith(productLink, subscription.Product.Name), true)); //event notification _eventPublisher.EntityTokensAdded(subscription, tokens); @@ -997,7 +1131,6 @@ public virtual string[] GetListOfCampaignAllowedTokens() "%NewsLetterSubscription.Email%", "%NewsLetterSubscription.ActivationUrl%", "%NewsLetterSubscription.DeactivationUrl%", - //codehint: sm-add "%Store.SupplierIdentification%", }; return allowedTokens.ToArray(); @@ -1040,6 +1173,7 @@ public virtual string[] GetListOfAllowedTokens() "%Order.ShippingCountry%", "%Order.PaymentMethod%", "%Order.VatNumber%", + "%Order.CustomerComment%", "%Order.Product(s)%", "%Order.CreatedOn%", "%Order.OrderURLForCustomer%", @@ -1050,7 +1184,9 @@ public virtual string[] GetListOfAllowedTokens() "%Product.ShortDescription%", "%Product.ProductURLForCustomer%", "%Product.StockQuantity%", - "%RecurringPayment.ID%", + "%Product.AdditionalShippingCharge%", + "%Product.Thumbnail%", + "%RecurringPayment.ID%", "%Shipment.ShipmentNumber%", "%Shipment.TrackingNumber%", "%Shipment.Product(s)%", @@ -1067,8 +1203,9 @@ public virtual string[] GetListOfAllowedTokens() "%GiftCard.SenderEmail%", "%GiftCard.RecipientName%", "%GiftCard.RecipientEmail%", - "%GiftCard.Amount%", - "%GiftCard.CouponCode%", + "%GiftCard.Amount%", + "%GiftCard.RemainingAmount%", + "%GiftCard.CouponCode%", "%GiftCard.Message%", "%Customer.Email%", "%Customer.Username%", @@ -1093,7 +1230,6 @@ public virtual string[] GetListOfAllowedTokens() "%PrivateMessage.Subject%", "%PrivateMessage.Text%", "%BackInStockSubscription.ProductName%", - //codehint: sm-add "%Order.Disclaimer%", "%Order.ConditionsOfUse%", "%Company.CompanyName%", diff --git a/src/Libraries/SmartStore.Services/Messages/NewsLetterSubscriptionService.cs b/src/Libraries/SmartStore.Services/Messages/NewsLetterSubscriptionService.cs index 74bd6a41c3..dde1d076c9 100644 --- a/src/Libraries/SmartStore.Services/Messages/NewsLetterSubscriptionService.cs +++ b/src/Libraries/SmartStore.Services/Messages/NewsLetterSubscriptionService.cs @@ -1,167 +1,25 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Messages; -using SmartStore.Data; using SmartStore.Core.Events; -using SmartStore.Services.Stores; namespace SmartStore.Services.Messages { - - public class NewsLetterSubscriptionService : INewsLetterSubscriptionService + public class NewsLetterSubscriptionService : INewsLetterSubscriptionService { private readonly IEventPublisher _eventPublisher; private readonly IDbContext _context; private readonly IRepository _subscriptionRepository; - private readonly IStoreService _storeService; public NewsLetterSubscriptionService(IDbContext context, IRepository subscriptionRepository, - IEventPublisher eventPublisher, - IStoreService storeService) + IEventPublisher eventPublisher) { _context = context; _subscriptionRepository = subscriptionRepository; _eventPublisher = eventPublisher; - _storeService = storeService; - } - - public ImportResult ImportSubscribers(Stream stream) - { - Guard.ArgumentNotNull(() => stream); - - var result = new ImportResult(); - var toAdd = new List(); - var toUpdate = new List(); - var autoCommit = _subscriptionRepository.AutoCommitEnabled; - var validateOnSave = _subscriptionRepository.Context.ValidateOnSaveEnabled; - var autoDetectChanges = _subscriptionRepository.Context.AutoDetectChangesEnabled; - var proxyCreation = _subscriptionRepository.Context.ProxyCreationEnabled; - - try - { - using (var reader = new StreamReader(stream)) - { - _subscriptionRepository.Context.ValidateOnSaveEnabled = false; - _subscriptionRepository.Context.AutoDetectChangesEnabled = false; - _subscriptionRepository.Context.ProxyCreationEnabled = false; - - while (!reader.EndOfStream) - { - string line = reader.ReadLine(); - if (line.IsEmpty()) - { - continue; - } - string[] tmp = line.Split(','); - - var email = ""; - bool isActive = true; - int storeId = 0; - - // parse - if (tmp.Length == 1) - { - // "email" only - email = tmp[0].Trim(); - } - else if (tmp.Length == 2) - { - // "email" and "active" fields specified - email = tmp[0].Trim(); - isActive = Boolean.Parse(tmp[1].Trim()); - } - else if (tmp.Length == 3) - { - email = tmp[0].Trim(); - isActive = Boolean.Parse(tmp[1].Trim()); - storeId = int.Parse(tmp[2].Trim()); - } - else - { - throw new SmartException("Wrong file format (expected comma separated entries 'Email' and optionally 'IsActive')"); - } - - result.TotalRecords++; - - if (email.Length > 255) - { - result.AddWarning("The emal address '{0}' exceeds the maximun allowed length of 255.".FormatInvariant(email)); - continue; - } - - if (!email.IsEmail()) - { - result.AddWarning("'{0}' is not a valid email address.".FormatInvariant(email)); - continue; - } - - if (storeId == 0) - { - storeId = _storeService.GetAllStores().First().Id; - } - - // import - var subscription = (from nls in _subscriptionRepository.Table - where nls.Email == email && nls.StoreId == storeId - orderby nls.Id - select nls).FirstOrDefault(); - - if (subscription != null) - { - subscription.Active = isActive; - - toUpdate.Add(subscription); - result.ModifiedRecords++; - } - else - { - subscription = new NewsLetterSubscription() - { - Active = isActive, - CreatedOnUtc = DateTime.UtcNow, - Email = email, - NewsLetterSubscriptionGuid = Guid.NewGuid(), - StoreId = storeId - }; - - toAdd.Add(subscription); - result.NewRecords++; - } - } - } - - // insert new subscribers - _subscriptionRepository.AutoCommitEnabled = true; - _subscriptionRepository.InsertRange(toAdd, 500); - toAdd.Clear(); - - // update modified subscribers - _subscriptionRepository.AutoCommitEnabled = false; - toUpdate.Each(x => - { - _subscriptionRepository.Update(x); - }); - _subscriptionRepository.Context.SaveChanges(); - toUpdate.Clear(); - } - catch (Exception ex) - { - throw ex; - } - finally - { - _subscriptionRepository.AutoCommitEnabled = autoCommit; - _subscriptionRepository.Context.ValidateOnSaveEnabled = validateOnSave; - _subscriptionRepository.Context.AutoDetectChangesEnabled = autoDetectChanges; - _subscriptionRepository.Context.ProxyCreationEnabled = proxyCreation; - } - - return result; } /// @@ -255,7 +113,8 @@ public void UpdateNewsLetterSubscription(NewsLetterSubscription newsLetterSubscr /// if set to true [publish subscription events]. public virtual void DeleteNewsLetterSubscription(NewsLetterSubscription newsLetterSubscription, bool publishSubscriptionEvents = true) { - if (newsLetterSubscription == null) throw new ArgumentNullException("newsLetterSubscription"); + if (newsLetterSubscription == null) + throw new ArgumentNullException("newsLetterSubscription"); _subscriptionRepository.Delete(newsLetterSubscription); @@ -266,12 +125,52 @@ public virtual void DeleteNewsLetterSubscription(NewsLetterSubscription newsLett _eventPublisher.EntityDeleted(newsLetterSubscription); } - /// - /// Gets a newsletter subscription by newsletter subscription identifier - /// - /// The newsletter subscription identifier - /// NewsLetter subscription - public virtual NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId) + public virtual bool? AddNewsLetterSubscriptionFor(bool add, string email, int storeId) + { + bool? result = null; + + if (email.IsEmail()) + { + var newsletter = GetNewsLetterSubscriptionByEmail(email, storeId); + if (newsletter != null) + { + if (add) + { + newsletter.Active = true; + UpdateNewsLetterSubscription(newsletter); + result = true; + } + else + { + DeleteNewsLetterSubscription(newsletter); + result = false; + } + } + else + { + if (add) + { + InsertNewsLetterSubscription(new NewsLetterSubscription + { + NewsLetterSubscriptionGuid = Guid.NewGuid(), + Email = email, + Active = true, + CreatedOnUtc = DateTime.UtcNow, + StoreId = storeId + }); + result = true; + } + } + } + return result; + } + + /// + /// Gets a newsletter subscription by newsletter subscription identifier + /// + /// The newsletter subscription identifier + /// NewsLetter subscription + public virtual NewsLetterSubscription GetNewsLetterSubscriptionById(int newsLetterSubscriptionId) { if (newsLetterSubscriptionId == 0) return null; diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs index 62c693cee1..b03c247f39 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedEmailService.cs @@ -1,33 +1,47 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; +using System.Net.Mail; +using System.IO; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Email; using SmartStore.Core.Events; +using SmartStore.Core.Logging; +using SmartStore.Services.Localization; +using SmartStore.Utilities; +using System.Web; +using SmartStore.Core.Localization; namespace SmartStore.Services.Messages { public partial class QueuedEmailService : IQueuedEmailService { private readonly IRepository _queuedEmailRepository; - private readonly IEventPublisher _eventPublisher; - - /// - /// Ctor - /// - /// Queued email repository - /// Event published - public QueuedEmailService(IRepository queuedEmailRepository, IEventPublisher eventPublisher) + private readonly IRepository _queuedEmailAttachmentRepository; + private readonly IEmailSender _emailSender; + private readonly ICommonServices _services; + + public QueuedEmailService( + IRepository queuedEmailRepository, + IRepository queuedEmailAttachmentRepository, + IEmailSender emailSender, + ICommonServices services) { - _queuedEmailRepository = queuedEmailRepository; - _eventPublisher = eventPublisher; + this._queuedEmailRepository = queuedEmailRepository; + this._queuedEmailAttachmentRepository = queuedEmailAttachmentRepository; + this._emailSender = emailSender; + this._services = services; + + T = NullLocalizer.Instance; + Logger = NullLogger.Instance; } - /// - /// Inserts a queued email - /// - /// Queued email + public Localizer T { get; set; } + public ILogger Logger { get; set; } + public virtual void InsertQueuedEmail(QueuedEmail queuedEmail) { if (queuedEmail == null) @@ -36,13 +50,9 @@ public virtual void InsertQueuedEmail(QueuedEmail queuedEmail) _queuedEmailRepository.Insert(queuedEmail); //event notification - _eventPublisher.EntityInserted(queuedEmail); + _services.EventPublisher.EntityInserted(queuedEmail); } - /// - /// Updates a queued email - /// - /// Queued email public virtual void UpdateQueuedEmail(QueuedEmail queuedEmail) { if (queuedEmail == null) @@ -51,13 +61,9 @@ public virtual void UpdateQueuedEmail(QueuedEmail queuedEmail) _queuedEmailRepository.Update(queuedEmail); //event notification - _eventPublisher.EntityUpdated(queuedEmail); + _services.EventPublisher.EntityUpdated(queuedEmail); } - /// - /// Deleted a queued email - /// - /// Queued email public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) { if (queuedEmail == null) @@ -66,14 +72,15 @@ public virtual void DeleteQueuedEmail(QueuedEmail queuedEmail) _queuedEmailRepository.Delete(queuedEmail); //event notification - _eventPublisher.EntityDeleted(queuedEmail); + _services.EventPublisher.EntityDeleted(queuedEmail); } - /// - /// Gets a queued email by identifier - /// - /// Queued email identifier - /// Queued email + public virtual int DeleteAllQueuedEmails() + { + // do not delete e-mails which are about to be sent + return _queuedEmailRepository.DeleteAll(x => x.SentOnUtc.HasValue || x.SentTries >= 3); + } + public virtual QueuedEmail GetQueuedEmailById(int queuedEmailId) { if (queuedEmailId == 0) @@ -81,14 +88,8 @@ public virtual QueuedEmail GetQueuedEmailById(int queuedEmailId) var queuedEmail = _queuedEmailRepository.GetById(queuedEmailId); return queuedEmail; - } - /// - /// Get queued emails by identifiers - /// - /// queued email identifiers - /// Queued emails public virtual IList GetQueuedEmailsByIds(int[] queuedEmailIds) { if (queuedEmailIds == null || queuedEmailIds.Length == 0) @@ -97,9 +98,12 @@ public virtual IList GetQueuedEmailsByIds(int[] queuedEmailIds) var query = from qe in _queuedEmailRepository.Table where queuedEmailIds.Contains(qe.Id) select qe; + var queuedEmails = query.ToList(); - //sort by passed identifiers + + // sort by passed identifiers var sortedQueuedEmails = new List(); + foreach (int id in queuedEmailIds) { var queuedEmail = queuedEmails.Find(x => x.Id == id); @@ -109,46 +113,195 @@ where queuedEmailIds.Contains(qe.Id) return sortedQueuedEmails; } - /// - /// Gets all queued emails - /// - /// From Email - /// To Email - /// The start time - /// The end time - /// A value indicating whether to load only not sent emails - /// Maximum send tries - /// A value indicating whether we should sort queued email descending; otherwise, ascending. - /// Page index - /// Page size - /// Email item list - public virtual IPagedList SearchEmails(string fromEmail, - string toEmail, DateTime? startTime, DateTime? endTime, - bool loadNotSentItemsOnly, int maxSendTries, - bool loadNewest, int pageIndex, int pageSize) + public virtual IPagedList SearchEmails(SearchEmailsQuery query) { - fromEmail = (fromEmail ?? String.Empty).Trim(); - toEmail = (toEmail ?? String.Empty).Trim(); + Guard.ArgumentNotNull(() => query); - var query = _queuedEmailRepository.Table; - if (!String.IsNullOrEmpty(fromEmail)) - query = query.Where(qe => qe.From.Contains(fromEmail)); - if (!String.IsNullOrEmpty(toEmail)) - query = query.Where(qe => qe.To.Contains(toEmail)); - if (startTime.HasValue) - query = query.Where(qe => qe.CreatedOnUtc >= startTime); - if (endTime.HasValue) - query = query.Where(qe => qe.CreatedOnUtc <= endTime); - if (loadNotSentItemsOnly) - query = query.Where(qe => !qe.SentOnUtc.HasValue); - query = query.Where(qe => qe.SentTries < maxSendTries); - query = query.OrderByDescending(qe => qe.Priority); - query = loadNewest ? - ((IOrderedQueryable)query).ThenByDescending(qe => qe.CreatedOnUtc) : - ((IOrderedQueryable)query).ThenBy(qe => qe.CreatedOnUtc); - - var queuedEmails = new PagedList(query, pageIndex, pageSize); + var q = _queuedEmailRepository.Table; + + if (query.Expand.HasValue()) + { + var expands = query.Expand.Split(','); + foreach (var expand in expands) + { + q = q.Expand(expand.Trim()); + } + } + + if (query.From.HasValue()) + q = q.Where(qe => qe.From.Contains(query.From.Trim())); + + if (query.To.HasValue()) + q = q.Where(qe => qe.To.Contains(query.To.Trim())); + + if (query.StartTime.HasValue) + q = q.Where(qe => qe.CreatedOnUtc >= query.StartTime); + + if (query.EndTime.HasValue) + q = q.Where(qe => qe.CreatedOnUtc <= query.EndTime); + + if (query.UnsentOnly) + q = q.Where(qe => !qe.SentOnUtc.HasValue); + + if (query.SendManually.HasValue) + q = q.Where(qe => qe.SendManually == query.SendManually.Value); + + q = q.Where(qe => qe.SentTries < query.MaxSendTries); + + q = q.OrderByDescending(qe => qe.Priority); + + q = query.OrderByLatest ? + ((IOrderedQueryable)q).ThenByDescending(qe => qe.CreatedOnUtc) : + ((IOrderedQueryable)q).ThenBy(qe => qe.CreatedOnUtc); + + var queuedEmails = new PagedList(q, query.PageIndex, query.PageSize); return queuedEmails; } - } + + public virtual bool SendEmail(QueuedEmail queuedEmail) + { + var result = false; + + try + { + var smtpContext = new SmtpContext(queuedEmail.EmailAccount); + var msg = ConvertEmail(queuedEmail); + + _emailSender.SendEmail(smtpContext, msg); + + queuedEmail.SentOnUtc = DateTime.UtcNow; + result = true; + } + catch (Exception exc) + { + Logger.Error(string.Concat(T("Admin.Common.ErrorSendingEmail"), ": ", exc.Message), exc); + } + finally + { + queuedEmail.SentTries = queuedEmail.SentTries + 1; + UpdateQueuedEmail(queuedEmail); + } + + return result; + } + + private void AddEmailAddresses(string addresses, ICollection target) + { + var arr = addresses.IsEmpty() ? null : addresses.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + if (arr != null && arr.Length > 0) + { + target.AddRange(arr.Where(x => x.Trim().HasValue()).Select(x => new EmailAddress(x))); + } + } + + internal EmailMessage ConvertEmail(QueuedEmail qe) + { + // 'internal' for testing purposes + + var msg = new EmailMessage( + new EmailAddress(qe.To, qe.ToName), + qe.Subject, + qe.Body, + new EmailAddress(qe.From, qe.FromName)); + + if (qe.ReplyTo.HasValue()) + { + msg.ReplyTo.Add(new EmailAddress(qe.ReplyTo, qe.ReplyToName)); + } + + AddEmailAddresses(qe.CC, msg.Cc); + AddEmailAddresses(qe.Bcc, msg.Bcc); + + if (qe.Attachments != null && qe.Attachments.Count > 0) + { + foreach (var qea in qe.Attachments) + { + Attachment attachment = null; + + if (qea.StorageLocation == EmailAttachmentStorageLocation.Blob) + { + var data = qea.Data; + if (data != null && data.Length > 0) + { + attachment = new Attachment(data.ToStream(), qea.Name, qea.MimeType); + } + } + else if (qea.StorageLocation == EmailAttachmentStorageLocation.Path) + { + var path = qea.Path; + if (path.HasValue()) + { + if (path[0] == '~' || path[0] == '/') + { + path = CommonHelper.MapPath(VirtualPathUtility.ToAppRelative(path), false); + } + if (File.Exists(path)) + { + attachment = new Attachment(path, qea.MimeType); + attachment.Name = qea.Name; + } + } + } + else if (qea.StorageLocation == EmailAttachmentStorageLocation.FileReference) + { + var file = qea.File; + if (file != null && file.UseDownloadUrl == false && file.DownloadBinary != null && file.DownloadBinary.Length > 0) + { + attachment = new Attachment(file.DownloadBinary.ToStream(), file.Filename + file.Extension, file.ContentType); + } + } + + if (attachment != null) + { + msg.Attachments.Add(attachment); + } + } + } + + return msg; + } + + #region Attachments + + public virtual QueuedEmailAttachment GetQueuedEmailAttachmentById(int id) + { + if (id == 0) + return null; + + var qea = _queuedEmailAttachmentRepository.GetById(id); + return qea; + } + + public virtual void DeleteQueuedEmailAttachment(QueuedEmailAttachment qea) + { + if (qea == null) + throw new ArgumentNullException("qea"); + + _queuedEmailAttachmentRepository.Delete(qea); + + _services.EventPublisher.EntityDeleted(qea); + } + + #endregion + } + + public class SearchEmailsQuery + { + public string From { get; set; } + public string To { get; set; } + public DateTime? StartTime { get; set; } + public DateTime? EndTime { get; set; } + public bool UnsentOnly { get; set; } + public int MaxSendTries { get; set; } + public bool OrderByLatest { get; set; } + public int PageIndex { get; set; } + public int PageSize { get; set; } + public bool? SendManually { get; set; } + + /// + /// Navigation properties to eager load (comma separataed) + /// + public string Expand { get; set; } + } + } diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs new file mode 100644 index 0000000000..b31f3b4ce3 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesClearTask.cs @@ -0,0 +1,31 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Messages; +using SmartStore.Data; +using SmartStore.Services.Tasks; + +namespace SmartStore.Services.Messages +{ + /// + /// Represents a task for deleting sent emails from the message queue + /// + public partial class QueuedMessagesClearTask : ITask + { + private readonly IRepository _qeRepository; + + public QueuedMessagesClearTask(IRepository qeRepository) + { + this._qeRepository = qeRepository; + } + + public void Execute(TaskExecutionContext ctx) + { + var olderThan = DateTime.UtcNow.AddDays(-14); + _qeRepository.DeleteAll(x => x.SentOnUtc.HasValue && x.CreatedOnUtc < olderThan); + + _qeRepository.Context.ShrinkDatabase(); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs index 1d8474f259..a37e7e82c4 100644 --- a/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs +++ b/src/Libraries/SmartStore.Services/Messages/QueuedMessagesSendTask.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using SmartStore.Core.Email; -using SmartStore.Core.Logging; -using SmartStore.Services.Tasks; +using SmartStore.Services.Tasks; namespace SmartStore.Services.Messages { @@ -14,73 +8,37 @@ namespace SmartStore.Services.Messages public partial class QueuedMessagesSendTask : ITask { private readonly IQueuedEmailService _queuedEmailService; - private readonly IEmailSender _emailSender; - public QueuedMessagesSendTask(IQueuedEmailService queuedEmailService, IEmailSender emailSender) + public QueuedMessagesSendTask(IQueuedEmailService queuedEmailService) { - this._queuedEmailService = queuedEmailService; - this._emailSender = emailSender; - Logger = NullLogger.Instance; + _queuedEmailService = queuedEmailService; } - public ILogger Logger - { - get; - set; - } - - /// - /// Executes a task - /// public void Execute(TaskExecutionContext ctx) { - var maxTries = 3; - var queuedEmails = _queuedEmailService.SearchEmails(null, null, null, null, true, maxTries, false, 0, 10000); - - foreach (var qe in queuedEmails) - { - var bcc = String.IsNullOrWhiteSpace(qe.Bcc) - ? null - : qe.Bcc.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - var cc = String.IsNullOrWhiteSpace(qe.CC) - ? null - : qe.CC.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - - try - { - var smtpContext = new SmtpContext(qe.EmailAccount); - - var msg = new EmailMessage( - new EmailAddress(qe.To, qe.ToName), - qe.Subject, - qe.Body, - new EmailAddress(qe.From, qe.FromName)); - - if (qe.ReplyTo.HasValue()) - { - msg.ReplyTo.Add(new EmailAddress(qe.ReplyTo, qe.ReplyToName)); - } - - if (cc != null) - msg.Cc.AddRange(cc.Where(x => x.HasValue()).Select(x => new EmailAddress(x))); - - if (bcc != null) - msg.Bcc.AddRange(bcc.Where(x => x.HasValue()).Select(x => new EmailAddress(x))); - - _emailSender.SendEmail(smtpContext, msg); - - qe.SentOnUtc = DateTime.UtcNow; - } - catch (Exception exc) - { - Logger.Error(string.Format("Error sending e-mail: {0}", exc.Message), exc); - } - finally - { - qe.SentTries = qe.SentTries + 1; - _queuedEmailService.UpdateQueuedEmail(qe); - } - } + const int pageSize = 1000; + const int maxTries = 3; + + for (int i = 0; i < 9999999; ++i) + { + var q = new SearchEmailsQuery + { + MaxSendTries = maxTries, + PageIndex = i, + PageSize = pageSize, + Expand = "Attachments", + UnsentOnly = true + }; + var queuedEmails = _queuedEmailService.SearchEmails(q); + + foreach (var queuedEmail in queuedEmails) + { + _queuedEmailService.SendEmail(queuedEmail); + } + + if (!queuedEmails.HasNextPage) + break; + } } } } diff --git a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEvent.cs b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEvent.cs new file mode 100644 index 0000000000..d9efdacd84 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEvent.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using SmartStore.Core.Domain.Messages; + +namespace SmartStore.Services.Messages +{ + /// + /// An event message, which gets published just before a new instance + /// of is persisted to the database + /// + public class QueuingEmailEvent + { + public QueuedEmail QueuedEmail + { + get; + set; + } + + public MessageTemplate MessageTemplate + { + get; + set; + } + + public EmailAccount EmailAccount + { + get; + set; + } + + public IList Tokens + { + get; + set; + } + + public int LanguageId + { + get; + set; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs new file mode 100644 index 0000000000..11eca682cc --- /dev/null +++ b/src/Libraries/SmartStore.Services/Messages/QueuingEmailEventConsumer.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Mime; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using System.Web.Security; +using SmartStore.Core; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Events; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Utilities; + +namespace SmartStore.Services.Messages +{ + public class QueuingEmailEventConsumer : IConsumer + { + private readonly PdfSettings _pdfSettings; + private readonly HttpRequestBase _httpRequest; + private readonly Lazy _fileDownloadManager; + + public QueuingEmailEventConsumer( + PdfSettings pdfSettings, + HttpRequestBase httpRequest, + Lazy fileDownloadManager) + { + this._pdfSettings = pdfSettings; + this._httpRequest = httpRequest; + this._fileDownloadManager = fileDownloadManager; + + Logger = NullLogger.Instance; + T = NullLocalizer.Instance; + } + + public ILogger Logger { get; set; } + public Localizer T { get; set; } + + public void HandleEvent(QueuingEmailEvent eventMessage) + { + var qe = eventMessage.QueuedEmail; + var tpl = eventMessage.MessageTemplate; + + var handledTemplates = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "OrderPlaced.CustomerNotification", _pdfSettings.AttachOrderPdfToOrderPlacedEmail }, + { "OrderCompleted.CustomerNotification", _pdfSettings.AttachOrderPdfToOrderCompletedEmail } + }; + + bool shouldHandle = false; + if (handledTemplates.TryGetValue(tpl.Name, out shouldHandle) && shouldHandle) + { + var orderId = eventMessage.Tokens.First(x => x.Key.IsCaseInsensitiveEqual("Order.ID")).Value.ToInt(); + try + { + var qea = CreatePdfInvoiceAttachment(orderId); + qe.Attachments.Add(qea); + } + catch (Exception ex) + { + Logger.Error(T("Admin.System.QueuedEmails.ErrorCreatingAttachment"), ex); + } + } + } + + private QueuedEmailAttachment CreatePdfInvoiceAttachment(int orderId) + { + var urlHelper = new UrlHelper(_httpRequest.RequestContext); + var path = urlHelper.Action("Print", "Order", new { id = orderId, pdf = true, area = "" }); + + var fileResponse = _fileDownloadManager.Value.DownloadFile(path, true, 5000); + + if (fileResponse == null) + { + throw new InvalidOperationException(T("Admin.System.QueuedEmails.ErrorEmptyAttachmentResult", path)); + } + + if (!fileResponse.ContentType.IsCaseInsensitiveEqual("application/pdf")) + { + throw new InvalidOperationException(T("Admin.System.QueuedEmails.ErrorNoPdfAttachment")); + } + + return new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.Blob, + Data = fileResponse.Data, + MimeType = fileResponse.ContentType, + Name = fileResponse.FileName + }; + } + + } +} diff --git a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs index c5220ee7b1..1f2746245e 100644 --- a/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs +++ b/src/Libraries/SmartStore.Services/Messages/WorkflowMessageService.cs @@ -1,20 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Web; using SmartStore.Core; using SmartStore.Core.Domain.Blogs; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.News; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Stores; -using SmartStore.Services.Customers; using SmartStore.Core.Events; +using SmartStore.Core.Localization; +using SmartStore.Services.Customers; using SmartStore.Services.Localization; +using SmartStore.Services.Media; using SmartStore.Services.Stores; namespace SmartStore.Services.Messages @@ -31,24 +35,30 @@ public partial class WorkflowMessageService : IWorkflowMessageService private readonly IMessageTokenProvider _messageTokenProvider; private readonly IStoreService _storeService; private readonly IStoreContext _storeContext; - private readonly EmailAccountSettings _emailAccountSettings; private readonly IEventPublisher _eventPublisher; private readonly IWorkContext _workContext; + private readonly HttpRequestBase _httpRequest; + private readonly IDownloadService _downloadServioce; #endregion #region Ctor - public WorkflowMessageService(IMessageTemplateService messageTemplateService, - IQueuedEmailService queuedEmailService, ILanguageService languageService, - ITokenizer tokenizer, IEmailAccountService emailAccountService, + public WorkflowMessageService( + IMessageTemplateService messageTemplateService, + IQueuedEmailService queuedEmailService, + ILanguageService languageService, + ITokenizer tokenizer, + IEmailAccountService emailAccountService, IMessageTokenProvider messageTokenProvider, IStoreService storeService, IStoreContext storeContext, EmailAccountSettings emailAccountSettings, IEventPublisher eventPublisher, - IWorkContext workContext) + IWorkContext workContext, + HttpRequestBase httpRequest, + IDownloadService downloadServioce) { this._messageTemplateService = messageTemplateService; this._queuedEmailService = queuedEmailService; @@ -58,21 +68,26 @@ public WorkflowMessageService(IMessageTemplateService messageTemplateService, this._messageTokenProvider = messageTokenProvider; this._storeService = storeService; this._storeContext = storeContext; - this._emailAccountSettings = emailAccountSettings; this._eventPublisher = eventPublisher; this._workContext = workContext; - } + this._httpRequest = httpRequest; + this._downloadServioce = downloadServioce; - #endregion + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + #endregion - #region Utilities + #region Utilities - protected int SendNotification( + protected int SendNotification( MessageTemplate messageTemplate, EmailAccount emailAccount, int languageId, - IEnumerable tokens, + IList tokens, string toEmailAddress, string toName, string replyTo = null, @@ -82,12 +97,14 @@ protected int SendNotification( var bcc = messageTemplate.GetLocalized((mt) => mt.BccEmailAddresses, languageId); var subject = messageTemplate.GetLocalized((mt) => mt.Subject, languageId); var body = messageTemplate.GetLocalized((mt) => mt.Body, languageId); - + // Replace subject and body tokens var subjectReplaced = _tokenizer.Replace(subject, tokens, false); var bodyReplaced = _tokenizer.Replace(body, tokens, true); - - var email = new QueuedEmail() + + bodyReplaced = WebHelper.MakeAllUrlsAbsolute(bodyReplaced, _httpRequest); + + var email = new QueuedEmail { Priority = 5, From = emailAccount.Email, @@ -101,20 +118,56 @@ protected int SendNotification( Subject = subjectReplaced, Body = bodyReplaced, CreatedOnUtc = DateTime.UtcNow, - EmailAccountId = emailAccount.Id + EmailAccountId = emailAccount.Id, + SendManually = messageTemplate.SendManually }; + // create attachments if any + var fileIds = (new int?[] + { + messageTemplate.GetLocalized(x => x.Attachment1FileId, languageId), + messageTemplate.GetLocalized(x => x.Attachment2FileId, languageId), + messageTemplate.GetLocalized(x => x.Attachment3FileId, languageId) + }) + .Where(x => x.HasValue) + .Select(x => x.Value) + .ToArray(); + + if (fileIds.Any()) + { + var files = _downloadServioce.GetDownloadsByIds(fileIds); + foreach (var file in files) + { + email.Attachments.Add(new QueuedEmailAttachment + { + StorageLocation = EmailAttachmentStorageLocation.FileReference, + FileId = file.Id, + Name = (file.Filename.NullEmpty() ?? file.Id.ToString()) + file.Extension.EmptyNull(), + MimeType = file.ContentType.NullEmpty() ?? "application/octet-stream" + }); + } + } + + + // publish event so that integrators can add attachments, alter the email etc. + _eventPublisher.Publish(new QueuingEmailEvent + { + EmailAccount = emailAccount, + LanguageId = languageId, + MessageTemplate = messageTemplate, + QueuedEmail = email, + Tokens = tokens + }); + _queuedEmailService.InsertQueuedEmail(email); + return email.Id; } - protected MessageTemplate GetLocalizedActiveMessageTemplate(string messageTemplateName, - int languageId, int storeId) + protected MessageTemplate GetActiveMessageTemplate(string messageTemplateName, int storeId) { - //TODO remove languageId parameter var messageTemplate = _messageTemplateService.GetMessageTemplateByName(messageTemplateName, storeId); - //no template found if (messageTemplate == null) return null; @@ -131,9 +184,7 @@ protected EmailAccount GetEmailAccountOfMessageTemplate(MessageTemplate messageT var emailAccounId = messageTemplate.GetLocalized(mt => mt.EmailAccountId, languageId); var emailAccount = _emailAccountService.GetEmailAccountById(emailAccounId); if (emailAccount == null) - emailAccount = _emailAccountService.GetEmailAccountById(_emailAccountSettings.DefaultEmailAccountId); - if (emailAccount == null) - emailAccount = _emailAccountService.GetAllEmailAccounts().FirstOrDefault(); + emailAccount = _emailAccountService.GetDefaultEmailAccount(); return emailAccount; } @@ -187,7 +238,7 @@ private string GetDisplayNameForCustomer(Customer customer) return name ?? customer.Username.EmptyNull(); } - protected int EnsureLanguageIsActive(int languageId, int storeId) + protected Language EnsureLanguageIsActive(int languageId, int storeId) { //load language by specified ID var language = _languageService.GetLanguageById(languageId); @@ -204,8 +255,9 @@ protected int EnsureLanguageIsActive(int languageId, int storeId) } if (language == null) - throw new Exception("No active language could be loaded"); - return language.Id; + throw new SmartException(T("Common.Error.NoActiveLanguage")); + + return language; } #endregion @@ -226,9 +278,9 @@ public virtual int SendCustomerRegisteredNotificationMessage(Customer customer, throw new ArgumentNullException("customer"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewCustomer.Notification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewCustomer.Notification", store.Id); if (messageTemplate == null) return 0; @@ -240,17 +292,14 @@ public virtual int SendCustomerRegisteredNotificationMessage(Customer customer, //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; // use customer email as reply address var replyTo = GetReplyToEmail(customer); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName, - replyTo.Item1, replyTo.Item2); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, replyTo.Item1, replyTo.Item2); } /// @@ -265,9 +314,9 @@ public virtual int SendCustomerWelcomeMessage(Customer customer, int languageId) throw new ArgumentNullException("customer"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.WelcomeMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.WelcomeMessage", store.Id); if (messageTemplate == null) return 0; @@ -279,12 +328,11 @@ public virtual int SendCustomerWelcomeMessage(Customer customer, int languageId) //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = customer.Email; var toName = customer.GetFullName(); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -299,9 +347,9 @@ public virtual int SendCustomerEmailValidationMessage(Customer customer, int lan throw new ArgumentNullException("customer"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.EmailValidationMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.EmailValidationMessage", store.Id); if (messageTemplate == null) return 0; @@ -313,12 +361,11 @@ public virtual int SendCustomerEmailValidationMessage(Customer customer, int lan //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = customer.Email; var toName = customer.GetFullName(); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -333,9 +380,9 @@ public virtual int SendCustomerPasswordRecoveryMessage(Customer customer, int la throw new ArgumentNullException("customer"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.PasswordRecovery", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.PasswordRecovery", store.Id); if (messageTemplate == null) return 0; @@ -347,12 +394,11 @@ public virtual int SendCustomerPasswordRecoveryMessage(Customer customer, int la //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = customer.Email; var toName = customer.GetFullName(); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } #endregion @@ -371,22 +417,22 @@ public virtual int SendOrderPlacedStoreOwnerNotification(Order order, int langua throw new ArgumentNullException("order"); var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderPlaced.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderPlaced.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddOrderTokens(tokens, order, languageId); + _messageTokenProvider.AddOrderTokens(tokens, order, language); _messageTokenProvider.AddCustomerTokens(tokens, order.Customer); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; @@ -398,10 +444,7 @@ public virtual int SendOrderPlacedStoreOwnerNotification(Order order, int langua replyToName += ", " + order.BillingAddress.Company; } - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName, - replyToEmail, replyToName); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, replyToEmail, replyToName); } /// @@ -416,31 +459,30 @@ public virtual int SendOrderPlacedCustomerNotification(Order order, int language throw new ArgumentNullException("order"); var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderPlaced.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderPlaced.CustomerNotification", store.Id); if (messageTemplate == null) return 0; //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddOrderTokens(tokens, order, languageId); + _messageTokenProvider.AddOrderTokens(tokens, order, language); _messageTokenProvider.AddCustomerTokens(tokens, order.Customer); _messageTokenProvider.AddCompanyTokens(tokens); _messageTokenProvider.AddBankConnectionTokens(tokens); _messageTokenProvider.AddContactDataTokens(tokens); - //event notification + // event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = order.BillingAddress.Email; var toName = string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -456,31 +498,30 @@ public virtual int SendShipmentSentCustomerNotification(Shipment shipment, int l var order = shipment.Order; if (order == null) - throw new Exception("Order cannot be loaded"); + throw new SmartException(T("Order.NotFound", shipment.OrderId)); var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("ShipmentSent.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("ShipmentSent.CustomerNotification", store.Id); if (messageTemplate == null) return 0; //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddShipmentTokens(tokens, shipment, languageId); - _messageTokenProvider.AddOrderTokens(tokens, shipment.Order, languageId); + _messageTokenProvider.AddShipmentTokens(tokens, shipment, language); + _messageTokenProvider.AddOrderTokens(tokens, shipment.Order, language); _messageTokenProvider.AddCustomerTokens(tokens, shipment.Order.Customer); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = order.BillingAddress.Email; var toName = string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -496,31 +537,30 @@ public virtual int SendShipmentDeliveredCustomerNotification(Shipment shipment, var order = shipment.Order; if (order == null) - throw new Exception("Order cannot be loaded"); + throw new SmartException(T("Order.NotFound", shipment.OrderId)); var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("ShipmentDelivered.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("ShipmentDelivered.CustomerNotification", store.Id); if (messageTemplate == null) return 0; //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddShipmentTokens(tokens, shipment, languageId); - _messageTokenProvider.AddOrderTokens(tokens, shipment.Order, languageId); + _messageTokenProvider.AddShipmentTokens(tokens, shipment, language); + _messageTokenProvider.AddOrderTokens(tokens, shipment.Order, language); _messageTokenProvider.AddCustomerTokens(tokens, shipment.Order.Customer); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = order.BillingAddress.Email; var toName = string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -535,16 +575,16 @@ public virtual int SendOrderCompletedCustomerNotification(Order order, int langu throw new ArgumentNullException("order"); var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderCompleted.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderCompleted.CustomerNotification", store.Id); if (messageTemplate == null) return 0; //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddOrderTokens(tokens, order, languageId); + _messageTokenProvider.AddOrderTokens(tokens, order, language); _messageTokenProvider.AddCustomerTokens(tokens, order.Customer); _messageTokenProvider.AddCompanyTokens(tokens); @@ -554,12 +594,11 @@ public virtual int SendOrderCompletedCustomerNotification(Order order, int langu //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = order.BillingAddress.Email; var toName = string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -574,27 +613,26 @@ public virtual int SendOrderCancelledCustomerNotification(Order order, int langu throw new ArgumentNullException("order"); var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("OrderCancelled.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("OrderCancelled.CustomerNotification", store.Id); if (messageTemplate == null) return 0; //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddOrderTokens(tokens, order, languageId); + _messageTokenProvider.AddOrderTokens(tokens, order, language); _messageTokenProvider.AddCustomerTokens(tokens, order.Customer); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = order.BillingAddress.Email; var toName = string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -611,9 +649,9 @@ public virtual int SendNewOrderNoteAddedCustomerNotification(OrderNote orderNote var order = orderNote.Order; var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.NewOrderNote", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.NewOrderNote", store.Id); if (messageTemplate == null) return 0; @@ -621,18 +659,17 @@ public virtual int SendNewOrderNoteAddedCustomerNotification(OrderNote orderNote var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); _messageTokenProvider.AddOrderNoteTokens(tokens, orderNote); - _messageTokenProvider.AddOrderTokens(tokens, orderNote.Order, languageId); + _messageTokenProvider.AddOrderTokens(tokens, orderNote.Order, language); _messageTokenProvider.AddCustomerTokens(tokens, orderNote.Order.Customer); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = order.BillingAddress.Email; var toName = string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -647,29 +684,27 @@ public virtual int SendRecurringPaymentCancelledStoreOwnerNotification(Recurring throw new ArgumentNullException("recurringPayment"); var store = _storeService.GetStoreById(recurringPayment.InitialOrder.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("RecurringPaymentCancelled.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("RecurringPaymentCancelled.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddOrderTokens(tokens, recurringPayment.InitialOrder, languageId); + _messageTokenProvider.AddOrderTokens(tokens, recurringPayment.InitialOrder, language); _messageTokenProvider.AddCustomerTokens(tokens, recurringPayment.InitialOrder.Customer); _messageTokenProvider.AddRecurringPaymentTokens(tokens, recurringPayment); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } #endregion @@ -682,16 +717,15 @@ public virtual int SendRecurringPaymentCancelledStoreOwnerNotification(Recurring /// Newsletter subscription /// Language identifier /// Queued email identifier - public virtual int SendNewsLetterSubscriptionActivationMessage(NewsLetterSubscription subscription, - int languageId) + public virtual int SendNewsLetterSubscriptionActivationMessage(NewsLetterSubscription subscription, int languageId) { if (subscription == null) throw new ArgumentNullException("subscription"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewsLetterSubscription.ActivationMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewsLetterSubscription.ActivationMessage", store.Id); if (messageTemplate == null) return 0; @@ -703,12 +737,11 @@ public virtual int SendNewsLetterSubscriptionActivationMessage(NewsLetterSubscri //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = subscription.Email; var toName = ""; - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -717,16 +750,15 @@ public virtual int SendNewsLetterSubscriptionActivationMessage(NewsLetterSubscri /// Newsletter subscription /// Language identifier /// Queued email identifier - public virtual int SendNewsLetterSubscriptionDeactivationMessage(NewsLetterSubscription subscription, - int languageId) + public virtual int SendNewsLetterSubscriptionDeactivationMessage(NewsLetterSubscription subscription, int languageId) { if (subscription == null) throw new ArgumentNullException("subscription"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewsLetterSubscription.DeactivationMessage", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewsLetterSubscription.DeactivationMessage", store.Id); if (messageTemplate == null) return 0; @@ -737,12 +769,11 @@ public virtual int SendNewsLetterSubscriptionDeactivationMessage(NewsLetterSubsc //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = subscription.Email; var toName = ""; - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } #endregion @@ -769,9 +800,9 @@ public virtual int SendProductEmailAFriendMessage(Customer customer, int languag throw new ArgumentNullException("product"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Service.EmailAFriend", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Service.EmailAFriend", store.Id); if (messageTemplate == null) return 0; @@ -779,19 +810,19 @@ public virtual int SendProductEmailAFriendMessage(Customer customer, int languag var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); _messageTokenProvider.AddCustomerTokens(tokens, customer); - _messageTokenProvider.AddProductTokens(tokens, product, languageId); + _messageTokenProvider.AddProductTokens(tokens, product, language); + tokens.Add(new Token("EmailAFriend.PersonalMessage", personalMessage, true)); tokens.Add(new Token("EmailAFriend.Email", customerEmail)); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = friendsEmail; var toName = ""; - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } public virtual int SendProductQuestionMessage(Customer customer, int languageId, Product product, @@ -807,16 +838,16 @@ public virtual int SendProductQuestionMessage(Customer customer, int languageId, throw new ArgumentNullException("product"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Product.AskQuestion", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Product.AskQuestion", store.Id); if (messageTemplate == null) return 0; var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); _messageTokenProvider.AddCustomerTokens(tokens, customer); - _messageTokenProvider.AddProductTokens(tokens, product, languageId); + _messageTokenProvider.AddProductTokens(tokens, product, language); tokens.Add(new Token("ProductQuestion.Message", question, true)); tokens.Add(new Token("ProductQuestion.SenderEmail", senderEmail)); @@ -826,11 +857,11 @@ public virtual int SendProductQuestionMessage(Customer customer, int languageId, //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; - return SendNotification(messageTemplate, emailAccount, languageId, tokens, toEmail, toName, senderEmail, senderName); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, senderEmail, senderName); } /// @@ -849,9 +880,9 @@ public virtual int SendWishlistEmailAFriendMessage(Customer customer, int langua throw new ArgumentNullException("customer"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Wishlist.EmailAFriend", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Wishlist.EmailAFriend", store.Id); if (messageTemplate == null) return 0; @@ -865,12 +896,11 @@ public virtual int SendWishlistEmailAFriendMessage(Customer customer, int langua //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = friendsEmail; var toName = ""; - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } #endregion @@ -890,9 +920,9 @@ public virtual int SendNewReturnRequestStoreOwnerNotification(ReturnRequest retu throw new ArgumentNullException("returnRequest"); var store = _storeService.GetStoreById(orderItem.Order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewReturnRequest.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewReturnRequest.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; @@ -905,17 +935,14 @@ public virtual int SendNewReturnRequestStoreOwnerNotification(ReturnRequest retu //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; // use customer email as reply address var replyTo = GetReplyToEmail(returnRequest.Customer); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName, - replyTo.Item1, replyTo.Item2); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, replyTo.Item1, replyTo.Item2); } /// @@ -931,9 +958,9 @@ public virtual int SendReturnRequestStatusChangedCustomerNotification(ReturnRequ throw new ArgumentNullException("returnRequest"); var store = _storeService.GetStoreById(orderItem.Order.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("ReturnRequestStatusChanged.CustomerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("ReturnRequestStatusChanged.CustomerNotification", store.Id); if (messageTemplate == null) return 0; @@ -946,12 +973,14 @@ public virtual int SendReturnRequestStatusChangedCustomerNotification(ReturnRequ //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); - var toEmail = returnRequest.Customer.Email; + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); + var toEmail = returnRequest.Customer.FindEmail(); var toName = returnRequest.Customer.GetFullName(); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + if (toEmail.IsEmpty()) + return 0; + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } #endregion @@ -966,8 +995,7 @@ public virtual int SendReturnRequestStatusChangedCustomerNotification(ReturnRequ /// Forum /// Message language identifier /// Queued email identifier - public int SendNewForumTopicMessage(Customer customer, - ForumTopic forumTopic, Forum forum, int languageId) + public int SendNewForumTopicMessage(Customer customer, ForumTopic forumTopic, Forum forum, int languageId) { if (customer == null) { @@ -975,8 +1003,9 @@ public int SendNewForumTopicMessage(Customer customer, } var store = _storeContext.CurrentStore; + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Forums.NewForumTopic", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Forums.NewForumTopic", store.Id); if (messageTemplate == null) { return 0; @@ -985,17 +1014,18 @@ public int SendNewForumTopicMessage(Customer customer, //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); + _messageTokenProvider.AddCustomerTokens(tokens, customer); _messageTokenProvider.AddForumTopicTokens(tokens, forumTopic); - _messageTokenProvider.AddForumTokens(tokens, forumTopic.Forum); + _messageTokenProvider.AddForumTokens(tokens, forumTopic.Forum, language); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = customer.Email; var toName = customer.GetFullName(); - return SendNotification(messageTemplate, emailAccount, languageId, tokens, toEmail, toName); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -1008,9 +1038,7 @@ public int SendNewForumTopicMessage(Customer customer, /// Friendly (starts with 1) forum topic page to use for URL generation /// Message language identifier /// Queued email identifier - public int SendNewForumPostMessage(Customer customer, - ForumPost forumPost, ForumTopic forumTopic, - Forum forum, int friendlyForumTopicPageIndex, int languageId) + public int SendNewForumPostMessage(Customer customer, ForumPost forumPost, ForumTopic forumTopic, Forum forum, int friendlyForumTopicPageIndex, int languageId) { if (customer == null) { @@ -1018,8 +1046,9 @@ public int SendNewForumPostMessage(Customer customer, } var store = _storeContext.CurrentStore; + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Forums.NewForumPost", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Forums.NewForumPost", store.Id); if (messageTemplate == null) { return 0; @@ -1029,18 +1058,18 @@ public int SendNewForumPostMessage(Customer customer, var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); _messageTokenProvider.AddForumPostTokens(tokens, forumPost); - _messageTokenProvider.AddForumTopicTokens(tokens, forumPost.ForumTopic, - friendlyForumTopicPageIndex, forumPost.Id); - _messageTokenProvider.AddForumTokens(tokens, forumPost.ForumTopic.Forum); + _messageTokenProvider.AddCustomerTokens(tokens, customer); + _messageTokenProvider.AddForumTopicTokens(tokens, forumPost.ForumTopic, friendlyForumTopicPageIndex, forumPost.Id); + _messageTokenProvider.AddForumTokens(tokens, forumPost.ForumTopic.Forum, language); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = customer.Email; var toName = customer.GetFullName(); - return SendNotification(messageTemplate, emailAccount, languageId, tokens, toEmail, toName); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -1049,7 +1078,7 @@ public int SendNewForumPostMessage(Customer customer, /// Private message /// Message language identifier /// Queued email identifier - public int SendPrivateMessageNotification(PrivateMessage privateMessage, int languageId) + public int SendPrivateMessageNotification(Customer customer, PrivateMessage privateMessage, int languageId) { if (privateMessage == null) { @@ -1058,7 +1087,7 @@ public int SendPrivateMessageNotification(PrivateMessage privateMessage, int lan var store = _storeService.GetStoreById(privateMessage.StoreId) ?? _storeContext.CurrentStore; - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.NewPM", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.NewPM", store.Id); if (messageTemplate == null) { return 0; @@ -1067,6 +1096,7 @@ public int SendPrivateMessageNotification(PrivateMessage privateMessage, int lan //tokens var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); + _messageTokenProvider.AddCustomerTokens(tokens, customer); _messageTokenProvider.AddPrivateMessageTokens(tokens, privateMessage); //event notification @@ -1114,9 +1144,10 @@ public virtual int SendGenericMessage(string messageTemplateName, Action @@ -1182,16 +1212,15 @@ public virtual int SendGiftCardNotification(GiftCard giftCard, int languageId) /// Product review /// Message language identifier /// Queued email identifier - public virtual int SendProductReviewNotificationMessage(ProductReview productReview, - int languageId) + public virtual int SendProductReviewNotificationMessage(ProductReview productReview, int languageId) { if (productReview == null) throw new ArgumentNullException("productReview"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Product.ProductReview", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Product.ProductReview", store.Id); if (messageTemplate == null) return 0; @@ -1203,17 +1232,14 @@ public virtual int SendProductReviewNotificationMessage(ProductReview productRev //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; // use customer email as reply address var replyTo = GetReplyToEmail(productReview.Customer); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName, - replyTo.Item1, replyTo.Item2); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, replyTo.Item1, replyTo.Item2); } /// @@ -1228,25 +1254,24 @@ public virtual int SendQuantityBelowStoreOwnerNotification(Product product, int throw new ArgumentNullException("product"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("QuantityBelow.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("QuantityBelow.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; var tokens = new List(); _messageTokenProvider.AddStoreTokens(tokens, store); - _messageTokenProvider.AddProductTokens(tokens, product, languageId); + _messageTokenProvider.AddProductTokens(tokens, product, language); //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } /// @@ -1257,16 +1282,15 @@ public virtual int SendQuantityBelowStoreOwnerNotification(Product product, int /// Received VAT address /// Message language identifier /// Queued email identifier - public virtual int SendNewVatSubmittedStoreOwnerNotification(Customer customer, - string vatName, string vatAddress, int languageId) + public virtual int SendNewVatSubmittedStoreOwnerNotification(Customer customer, string vatName, string vatAddress, int languageId) { if (customer == null) throw new ArgumentNullException("customer"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("NewVATSubmitted.StoreOwnerNotification", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("NewVATSubmitted.StoreOwnerNotification", store.Id); if (messageTemplate == null) return 0; @@ -1280,17 +1304,14 @@ public virtual int SendNewVatSubmittedStoreOwnerNotification(Customer customer, //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; // use customer email as reply address var replyTo = GetReplyToEmail(customer); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName, - replyTo.Item1, replyTo.Item2); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, replyTo.Item1, replyTo.Item2); } /// @@ -1305,9 +1326,9 @@ public virtual int SendBlogCommentNotificationMessage(BlogComment blogComment, i throw new ArgumentNullException("blogComment"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Blog.BlogComment", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Blog.BlogComment", store.Id); if (messageTemplate == null) return 0; @@ -1319,17 +1340,14 @@ public virtual int SendBlogCommentNotificationMessage(BlogComment blogComment, i //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; // use customer email as reply address var replyTo = GetReplyToEmail(blogComment.Customer); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName, - replyTo.Item1, replyTo.Item2); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, replyTo.Item1, replyTo.Item2); } /// @@ -1344,9 +1362,9 @@ public virtual int SendNewsCommentNotificationMessage(NewsComment newsComment, i throw new ArgumentNullException("newsComment"); var store = _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("News.NewsComment", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("News.NewsComment", store.Id); if (messageTemplate == null) return 0; @@ -1358,17 +1376,14 @@ public virtual int SendNewsCommentNotificationMessage(NewsComment newsComment, i //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var toEmail = emailAccount.Email; var toName = emailAccount.DisplayName; // use customer email as sender/reply address var replyTo = GetReplyToEmail(newsComment.Customer); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName, - replyTo.Item1, replyTo.Item2); + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName, replyTo.Item1, replyTo.Item2); } /// @@ -1383,9 +1398,9 @@ public virtual int SendBackInStockNotification(BackInStockSubscription subscript throw new ArgumentNullException("subscription"); var store = _storeService.GetStoreById(subscription.StoreId) ?? _storeContext.CurrentStore; - languageId = EnsureLanguageIsActive(languageId, store.Id); + var language = EnsureLanguageIsActive(languageId, store.Id); - var messageTemplate = GetLocalizedActiveMessageTemplate("Customer.BackInStock", languageId, store.Id); + var messageTemplate = GetActiveMessageTemplate("Customer.BackInStock", store.Id); if (messageTemplate == null) return 0; @@ -1398,13 +1413,12 @@ public virtual int SendBackInStockNotification(BackInStockSubscription subscript //event notification _eventPublisher.MessageTokensAdded(messageTemplate, tokens); - var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId); + var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, language.Id); var customer = subscription.Customer; var toEmail = customer.Email; var toName = customer.GetFullName(); - return SendNotification(messageTemplate, emailAccount, - languageId, tokens, - toEmail, toName); + + return SendNotification(messageTemplate, emailAccount, language.Id, tokens, toEmail, toName); } #endregion diff --git a/src/Libraries/SmartStore.Services/News/INewsService.cs b/src/Libraries/SmartStore.Services/News/INewsService.cs index 435dca7ced..d25a8d8afa 100644 --- a/src/Libraries/SmartStore.Services/News/INewsService.cs +++ b/src/Libraries/SmartStore.Services/News/INewsService.cs @@ -1,3 +1,5 @@ +using System; +using System.Linq; using SmartStore.Core; using SmartStore.Core.Domain.News; @@ -21,6 +23,13 @@ public partial interface INewsService /// News NewsItem GetNewsById(int newsId); + /// + /// Get news by identifiers + /// + /// News identifiers + /// News query + IQueryable GetNewsByIds(int[] newsIds); + /// /// Gets all news /// @@ -29,9 +38,9 @@ public partial interface INewsService /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned news /// News items - IPagedList GetAllNews(int languageId, int storeId, - int pageIndex, int pageSize, bool showHidden = false); + IPagedList GetAllNews(int languageId, int storeId, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null); /// /// Inserts a news item diff --git a/src/Libraries/SmartStore.Services/News/NewsService.cs b/src/Libraries/SmartStore.Services/News/NewsService.cs index 0668085998..743ab7f9f4 100644 --- a/src/Libraries/SmartStore.Services/News/NewsService.cs +++ b/src/Libraries/SmartStore.Services/News/NewsService.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using SmartStore.Core; -using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.News; using SmartStore.Core.Domain.Stores; @@ -18,8 +17,9 @@ public partial class NewsService : INewsService private readonly IRepository _newsItemRepository; private readonly IRepository _storeMappingRepository; - private readonly ICacheManager _cacheManager; - private readonly IEventPublisher _eventPublisher; + private readonly ICommonServices _services; + + private readonly NewsSettings _newsSettings; #endregion @@ -27,13 +27,13 @@ public partial class NewsService : INewsService public NewsService(IRepository newsItemRepository, IRepository storeMappingRepository, - ICacheManager cacheManager, - IEventPublisher eventPublisher) + ICommonServices services, + NewsSettings newsSettings) { _newsItemRepository = newsItemRepository; _storeMappingRepository = storeMappingRepository; - _cacheManager = cacheManager; - _eventPublisher = eventPublisher; + _services = services; + _newsSettings = newsSettings; this.QuerySettings = DbQuerySettings.Default; } @@ -56,7 +56,7 @@ public virtual void DeleteNews(NewsItem newsItem) _newsItemRepository.Delete(newsItem); //event notification - _eventPublisher.EntityDeleted(newsItem); + _services.EventPublisher.EntityDeleted(newsItem); } /// @@ -72,6 +72,24 @@ public virtual NewsItem GetNewsById(int newsId) return _newsItemRepository.GetById(newsId); } + /// + /// Get news by identifiers + /// + /// News identifiers + /// News query + public virtual IQueryable GetNewsByIds(int[] newsIds) + { + if (newsIds == null || newsIds.Length == 0) + return null; + + var query = + from x in _newsItemRepository.Table + where newsIds.Contains(x.Id) + select x; + + return query; + } + /// /// Gets all news /// @@ -80,13 +98,22 @@ public virtual NewsItem GetNewsById(int newsId) /// Page index /// Page size /// A value indicating whether to show hidden records + /// The maximum age of returned news /// News items - public virtual IPagedList GetAllNews(int languageId, int storeId, - int pageIndex, int pageSize, bool showHidden = false) + public virtual IPagedList GetAllNews(int languageId, int storeId, int pageIndex, int pageSize, bool showHidden = false, DateTime? maxAge = null) { var query = _newsItemRepository.Table; - if (languageId > 0) - query = query.Where(n => languageId == n.LanguageId); + + if (languageId > 0) + { + query = query.Where(n => languageId == n.LanguageId); + } + + if (maxAge.HasValue) + { + query = query.Where(n => n.CreatedOnUtc >= maxAge.Value); + } + if (!showHidden) { var utcNow = DateTime.UtcNow; @@ -94,6 +121,7 @@ public virtual IPagedList GetAllNews(int languageId, int storeId, query = query.Where(n => !n.StartDateUtc.HasValue || n.StartDateUtc <= utcNow); query = query.Where(n => !n.EndDateUtc.HasValue || n.EndDateUtc >= utcNow); } + query = query.OrderByDescending(n => n.CreatedOnUtc); //Store mapping @@ -111,6 +139,7 @@ from sm in n_sm.DefaultIfEmpty() group n by n.Id into nGroup orderby nGroup.Key select nGroup.FirstOrDefault(); + query = query.OrderByDescending(n => n.CreatedOnUtc); } @@ -130,7 +159,7 @@ public virtual void InsertNews(NewsItem news) _newsItemRepository.Insert(news); //event notification - _eventPublisher.EntityInserted(news); + _services.EventPublisher.EntityInserted(news); } /// @@ -145,7 +174,7 @@ public virtual void UpdateNews(NewsItem news) _newsItemRepository.Update(news); //event notification - _eventPublisher.EntityUpdated(news); + _services.EventPublisher.EntityUpdated(news); } /// diff --git a/src/Libraries/SmartStore.Services/Orders/AddToCartContext.cs b/src/Libraries/SmartStore.Services/Orders/AddToCartContext.cs new file mode 100644 index 0000000000..27c3f37023 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Orders/AddToCartContext.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Collections.Specialized; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; + +namespace SmartStore.Services.Orders +{ + public class AddToCartContext + { + public AddToCartContext() + { + Warnings = new List(); + CustomerEnteredPrice = decimal.Zero; + ChildItems = new List(); + } + + public List Warnings { get; set; } + + public ShoppingCartItem Item { get; set; } + public List ChildItems { get; set; } + public ProductBundleItem BundleItem { get; set; } + + public Customer Customer { get; set; } + public Product Product { get; set; } + public ShoppingCartType CartType { get; set; } + public NameValueCollection AttributeForm { get; set; } + public string Attributes { get; set; } + public decimal CustomerEnteredPrice { get; set; } + public int Quantity { get; set; } + public bool AddRequiredProducts { get; set; } + public int? StoreId { get; set; } + + public int BundleItemId + { + get + { + return (BundleItem == null ? 0 : BundleItem.Id); + } + } + } +} diff --git a/src/Libraries/SmartStore.Services/Orders/AppliedGiftCard.cs b/src/Libraries/SmartStore.Services/Orders/AppliedGiftCard.cs index ea8cdd8be8..4318b43cd6 100644 --- a/src/Libraries/SmartStore.Services/Orders/AppliedGiftCard.cs +++ b/src/Libraries/SmartStore.Services/Orders/AppliedGiftCard.cs @@ -1,6 +1,3 @@ - - - using SmartStore.Core.Domain.Orders; namespace SmartStore.Services.Orders diff --git a/src/Libraries/SmartStore.Services/Orders/AutoUpdateOrderItemContext.cs b/src/Libraries/SmartStore.Services/Orders/AutoUpdateOrderItemContext.cs new file mode 100644 index 0000000000..38528c835c --- /dev/null +++ b/src/Libraries/SmartStore.Services/Orders/AutoUpdateOrderItemContext.cs @@ -0,0 +1,104 @@ +using SmartStore.Core.Domain.Orders; +using SmartStore.Services.Catalog; +using SmartStore.Services.Localization; + +namespace SmartStore.Services.Orders +{ + public class AutoUpdateOrderItemContext + { + /// + /// [IN] Whether order item is new + /// + public bool IsNewOrderItem { get; set; } + + /// + /// [IN] Order item + /// + public OrderItem OrderItem { get; set; } + + /// + /// [IN] Whether to adjust the inventory + /// + public bool AdjustInventory { get; set; } + + /// + /// [IN] Whether to update order totals if order is in pending state + /// + public bool UpdateTotals { get; set; } + + /// + /// [IN] Whether to update reward points + /// + public bool UpdateRewardPoints { get; set; } + + /// + /// [IN] Quantity old + /// + public int QuantityOld { get; set; } + + /// + /// [IN] Quantity new + /// + public int QuantityNew { get; set; } + + /// + /// [OUT] Inventory changes + /// + public AdjustInventoryResult Inventory { get; set; } + + /// + /// [OUT] Reward points old + /// + public int RewardPointsOld { get; set; } + + /// + /// [OUT] Reward points new + /// + public int RewardPointsNew { get; set; } + + public static string InfoKey { get { return "UpdateOrderItemContextInfo"; } } + + /// + /// The value to which the quantity amount has changed + /// + public int QuantityDelta + { + get + { + return QuantityNew - QuantityOld; + } + } + + public decimal QuantityChangeFactor + { + get + { + if (QuantityOld != 0) + return (decimal)QuantityNew / (decimal)QuantityOld; + + return 1.0M; + } + } + + public string ToString(ILocalizationService localizationService) + { + if (Inventory == null && RewardPointsOld == 0 && RewardPointsNew == 0) + return ""; + + string stockOld = null; + string stockNew = null; + + if (Inventory != null && Inventory.HasClearStockQuantityResult) + { + stockOld = Inventory.StockQuantityOld.ToString(); + stockNew = Inventory.StockQuantityNew.ToString(); + } + + string result = localizationService.GetResource("Admin.Orders.OrderItem.Update.Info").FormatWith( + stockOld.NaIfEmpty(), stockNew.NaIfEmpty(), RewardPointsOld, RewardPointsNew + ); + + return result; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Orders/CancelOrderItemContext.cs b/src/Libraries/SmartStore.Services/Orders/CancelOrderItemContext.cs deleted file mode 100644 index b84168584f..0000000000 --- a/src/Libraries/SmartStore.Services/Orders/CancelOrderItemContext.cs +++ /dev/null @@ -1,59 +0,0 @@ -using SmartStore.Core.Domain.Orders; -using SmartStore.Services.Localization; - -namespace SmartStore.Services.Orders -{ - public class CancelOrderItemContext - { - /// - /// [IN] Order item - /// - public OrderItem OrderItem { get; set; } - - /// - /// [IN] Return request object - /// - public ReturnRequest ReturnRequest { get; set; } - - /// - /// [IN] Whether to adjust the inventory - /// - public bool AdjustInventory { get; set; } - - /// - /// [IN] Whether to reduce reward points - /// - public bool ReduceRewardPoints { get; set; } - - /// - /// [OUT] Inventory old - /// - public int InventoryOld { get; set; } - - /// - /// [OUT] Inventory new - /// - public int InventoryNew { get; set; } - - /// - /// [OUT] Reward points old - /// - public int RewardPointsOld { get; set; } - - /// - /// [OUT] Reward points new - /// - public int RewardPointsNew { get; set; } - - public static string InfoKey { get { return "CancelOrderItemContextInfo"; } } - - public string ToString(ILocalizationService localizationService) - { - string result = localizationService.GetResource("Admin.Orders.OrderItem.Cancel.Info").FormatWith( - InventoryOld, InventoryNew, RewardPointsOld, RewardPointsNew - ); - - return result; - } - } -} diff --git a/src/Libraries/SmartStore.Services/Orders/CheckoutAttributeService.cs b/src/Libraries/SmartStore.Services/Orders/CheckoutAttributeService.cs index 981f4f879a..7e266a98b1 100644 --- a/src/Libraries/SmartStore.Services/Orders/CheckoutAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Orders/CheckoutAttributeService.cs @@ -4,29 +4,33 @@ using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Stores; using SmartStore.Core.Events; namespace SmartStore.Services.Orders { - /// - /// Checkout attribute service - /// - public partial class CheckoutAttributeService : ICheckoutAttributeService + /// + /// Checkout attribute service + /// + public partial class CheckoutAttributeService : ICheckoutAttributeService { #region Constants - private const string CHECKOUTATTRIBUTES_ALL_KEY = "SmartStore.checkoutattribute.all-{0}"; + + private const string CHECKOUTATTRIBUTES_ALL_KEY = "SmartStore.checkoutattribute.all-{0}-{1}"; private const string CHECKOUTATTRIBUTEVALUES_ALL_KEY = "SmartStore.checkoutattributevalue.all-{0}"; private const string CHECKOUTATTRIBUTES_PATTERN_KEY = "SmartStore.checkoutattribute."; private const string CHECKOUTATTRIBUTEVALUES_PATTERN_KEY = "SmartStore.checkoutattributevalue."; private const string CHECKOUTATTRIBUTES_BY_ID_KEY = "SmartStore.checkoutattribute.id-{0}"; private const string CHECKOUTATTRIBUTEVALUES_BY_ID_KEY = "SmartStore.checkoutattributevalue.id-{0}"; + #endregion #region Fields private readonly IRepository _checkoutAttributeRepository; private readonly IRepository _checkoutAttributeValueRepository; - private readonly IEventPublisher _eventPublisher; + private readonly IRepository _storeMappingRepository; + private readonly IEventPublisher _eventPublisher; private readonly ICacheManager _cacheManager; #endregion @@ -43,25 +47,31 @@ public partial class CheckoutAttributeService : ICheckoutAttributeService public CheckoutAttributeService(ICacheManager cacheManager, IRepository checkoutAttributeRepository, IRepository checkoutAttributeValueRepository, - IEventPublisher eventPublisher) + IRepository storeMappingRepository, + IEventPublisher eventPublisher) { _cacheManager = cacheManager; _checkoutAttributeRepository = checkoutAttributeRepository; _checkoutAttributeValueRepository = checkoutAttributeValueRepository; + _storeMappingRepository = storeMappingRepository; _eventPublisher = eventPublisher; - } - #endregion + this.QuerySettings = DbQuerySettings.Default; + } - #region Methods + #endregion - #region Checkout attributes + public DbQuerySettings QuerySettings { get; set; } - /// - /// Deletes a checkout attribute - /// - /// Checkout attribute - public virtual void DeleteCheckoutAttribute(CheckoutAttribute checkoutAttribute) + #region Methods + + #region Checkout attributes + + /// + /// Deletes a checkout attribute + /// + /// Checkout attribute + public virtual void DeleteCheckoutAttribute(CheckoutAttribute checkoutAttribute) { if (checkoutAttribute == null) throw new ArgumentNullException("checkoutAttribute"); @@ -75,20 +85,56 @@ public virtual void DeleteCheckoutAttribute(CheckoutAttribute checkoutAttribute) _eventPublisher.EntityDeleted(checkoutAttribute); } - /// - /// Gets all checkout attributes - /// - /// Checkout attribute collection - public virtual IList GetAllCheckoutAttributes() + /// + /// Gets checkout attributes + /// + /// Whether to filter result by store identifier + /// A value indicating whether to show hidden records + /// Checkout attributes query + public virtual IQueryable GetCheckoutAttributes(int storeId = 0, bool showHidden = false) + { + var query = _checkoutAttributeRepository.Table; + + if (!showHidden) + query = query.Where(x => x.IsActive); + + if (storeId > 0 && !QuerySettings.IgnoreMultiStore) + { + query = + from x in query + join sm in _storeMappingRepository.Table on new { c1 = x.Id, c2 = "CheckoutAttribute" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into x_sm + from sm in x_sm.DefaultIfEmpty() + where !x.LimitedToStores || storeId == sm.StoreId + select x; + + query = + from x in query + group x by x.Id into grp + orderby grp.Key + select grp.FirstOrDefault(); + } + + query = query.OrderBy(x => x.DisplayOrder); + + return query; + } + + /// + /// Gets all checkout attributes + /// + /// Whether to filter result by store identifier + /// A value indicating whether to show hidden records + /// Checkout attribute collection + public virtual IList GetAllCheckoutAttributes(int storeId = 0, bool showHidden = false) { - return _cacheManager.Get(CHECKOUTATTRIBUTES_ALL_KEY, () => + string key = CHECKOUTATTRIBUTES_ALL_KEY.FormatInvariant(storeId, showHidden); + + return _cacheManager.Get(key, () => { - var query = from ca in _checkoutAttributeRepository.Table - orderby ca.DisplayOrder - select ca; - var checkoutAttributes = query.ToList(); - return checkoutAttributes; - }); + var query = GetCheckoutAttributes(storeId, showHidden); + + return query.ToList(); + }); } /// diff --git a/src/Libraries/SmartStore.Services/Orders/CheckoutState.cs b/src/Libraries/SmartStore.Services/Orders/CheckoutState.cs index 8fb20c239f..6c876aa266 100644 --- a/src/Libraries/SmartStore.Services/Orders/CheckoutState.cs +++ b/src/Libraries/SmartStore.Services/Orders/CheckoutState.cs @@ -1,24 +1,39 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Web.Routing; namespace SmartStore.Services.Orders { + [Serializable] public partial class CheckoutState { public CheckoutState() { - CustomProperties = new Dictionary(); + CustomProperties = new RouteValueDictionary(); } public static string CheckoutStateSessionKey { get { return "SmCheckoutState"; } } + public string PaymentSummary + { + get + { + return CustomProperties["_PaymentSummary"] as string; + } + set + { + CustomProperties["_PaymentSummary"] = value; + } + } + /// - /// Whether the one page checkout is enabled for a particular session + /// Indicated whether the page with the payment method selection was skipped during checkout. /// - public bool OnePageCkeckoutEnabled { get; set; } + public bool IsPaymentSelectionSkipped { get; set; } /// - /// Use that dictionary for any custom data required along checkout flow + /// Use this dictionary for any custom data required along checkout flow. /// - public Dictionary CustomProperties { get; set; } + public IDictionary CustomProperties { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/Orders/ICheckoutAttributeService.cs b/src/Libraries/SmartStore.Services/Orders/ICheckoutAttributeService.cs index cb34e948c4..9a520ca28b 100644 --- a/src/Libraries/SmartStore.Services/Orders/ICheckoutAttributeService.cs +++ b/src/Libraries/SmartStore.Services/Orders/ICheckoutAttributeService.cs @@ -1,12 +1,13 @@ using System.Collections.Generic; +using System.Linq; using SmartStore.Core.Domain.Orders; namespace SmartStore.Services.Orders { - /// - /// Checkout attribute service - /// - public partial interface ICheckoutAttributeService + /// + /// Checkout attribute service + /// + public partial interface ICheckoutAttributeService { #region Checkout attributes @@ -16,11 +17,21 @@ public partial interface ICheckoutAttributeService /// Checkout attribute void DeleteCheckoutAttribute(CheckoutAttribute checkoutAttribute); - /// - /// Gets all checkout attributes - /// - /// Checkout attribute collection - IList GetAllCheckoutAttributes(); + /// + /// Gets checkout attributes + /// + /// Whether to filter result by store identifier + /// A value indicating whether to show hidden records + /// Checkout attributes query + IQueryable GetCheckoutAttributes(int storeId = 0, bool showHidden = false); + + /// + /// Gets all checkout attributes + /// + /// Whether to filter result by store identifier + /// A value indicating whether to show hidden records + /// Checkout attribute collection + IList GetAllCheckoutAttributes(int storeId = 0, bool showHidden = false); /// /// Gets a checkout attribute diff --git a/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs index f017d568cd..9c3f825b03 100644 --- a/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/IOrderProcessingService.cs @@ -22,7 +22,7 @@ public partial interface IOrderProcessingService /// /// Process payment request /// Place order result - PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentRequest); + PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentRequest, Dictionary extraData); /// /// Deletes an order @@ -86,10 +86,10 @@ public partial interface IOrderProcessingService void CancelOrder(Order order, bool notifyCustomer); /// - /// Cancel an order item + /// Auto update order details /// - /// Cancel order item context - void CancelOrderItem(CancelOrderItemContext context); + /// Context parameters + void AutoUpdateOrderDetails(AutoUpdateOrderItemContext context); /// @@ -266,5 +266,14 @@ public partial interface IOrderProcessingService /// Shopping cart /// true - OK; false - minimum order total amount is not reached bool ValidateMinOrderTotalAmount(IList cart); + + /// + /// Adds a shipment to an order + /// + /// Order + /// Tracking number + /// Quantities by order item identifiers. null to use the remaining total number of products for each order item. + /// New shipment, null if no shipment was added + Shipment AddShipment(Order order, string trackingNumber, Dictionary quantities); } } diff --git a/src/Libraries/SmartStore.Services/Orders/IOrderReportService.cs b/src/Libraries/SmartStore.Services/Orders/IOrderReportService.cs index 60de1af55f..b5f278c3d5 100644 --- a/src/Libraries/SmartStore.Services/Orders/IOrderReportService.cs +++ b/src/Libraries/SmartStore.Services/Orders/IOrderReportService.cs @@ -58,15 +58,14 @@ IList BestSellersReport(int storeId, int orderBy = 1, bool showHidden = false); /// - /// Gets a list of products purchased by other customers who purchased the above + /// Gets a list of product identifiers purchased by other customers who purchased the above /// /// Store identifier /// Product identifier /// Records to return /// A value indicating whether to show hidden records /// Product collection - IList GetProductsAlsoPurchasedById(int storeId, int productId, - int recordsToReturn = 5, bool showHidden = false); + int[] GetAlsoPurchasedProductsIds(int storeId, int productId, int recordsToReturn = 5, bool showHidden = false); /// /// Gets a list of products that were never sold diff --git a/src/Libraries/SmartStore.Services/Orders/IOrderService.cs b/src/Libraries/SmartStore.Services/Orders/IOrderService.cs index 98a8d3dab0..9fca02b17f 100644 --- a/src/Libraries/SmartStore.Services/Orders/IOrderService.cs +++ b/src/Libraries/SmartStore.Services/Orders/IOrderService.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; @@ -68,6 +70,32 @@ public partial interface IOrderService /// The order void DeleteOrder(Order order); + /// + /// Get orders + /// + /// Store identifier; null to load all orders + /// Customer identifier; null to load all orders + /// Order start time; null to load all orders + /// Order end time; null to load all orders + /// Filter by order status + /// Filter by payment status + /// Filter by shipping status + /// Billing email. Leave empty to load all records. + /// Filter by order number + /// Billing name. Leave empty to load all records. + /// Order query + IQueryable GetOrders( + int storeId, + int customerId, + DateTime? startTime, + DateTime? endTime, + int[] orderStatusIds, + int[] paymentStatusIds, + int[] shippingStatusIds, + string billingEmail, + string orderNumber, + string billingName = null); + /// /// Search orders /// @@ -87,7 +115,7 @@ public partial interface IOrderService /// Order collection IPagedList SearchOrders(int storeId, int customerId, DateTime? startTime, DateTime? endTime, int[] orderStatusIds, int[] paymentStatusIds, int[] shippingStatusIds, - string billingName, string orderGuid, string orderNumber, int pageIndex, int pageSize, string billingEmail = null); + string billingEmail, string orderGuid, string orderNumber, int pageIndex, int pageSize, string billingName = null); /// /// Gets all orders by affiliate identifier @@ -136,17 +164,25 @@ IPagedList SearchOrders(int storeId, int customerId, DateTime? startTime, /// Payment method system name /// Order Order GetOrderByAuthorizationTransactionIdAndPaymentMethod(string authorizationTransactionId, string paymentMethodSystemName); - - #endregion - #region Orders items - - /// - /// Gets an order item - /// - /// Order item identifier - /// Order item - OrderItem GetOrderItemById(int orderItemId); + /// + /// Shortcut to add an order + /// + /// Order + /// Order note + /// Whether to display the note to the customer + void AddOrderNote(Order order, string note, bool displayToCustomer = false); + + #endregion + + #region Orders items + + /// + /// Gets an order item + /// + /// Order item identifier + /// Order item + OrderItem GetOrderItemById(int orderItemId); /// /// Gets an order item @@ -172,6 +208,13 @@ IList GetAllOrderItems(int? orderId, OrderStatus? os, PaymentStatus? ps, ShippingStatus? ss, bool loadDownloableProductsOnly = false); + /// + /// Get order items by order identifiers + /// + /// Order identifiers + /// Order items + Multimap GetOrderItemsByOrderIds(int[] orderIds); + /// /// Delete an order item /// @@ -245,8 +288,9 @@ IList SearchRecurringPayments(int storeId, /// Return request status; null to load all entries /// Page index /// Page size + /// Return Request Id /// Return requests - IPagedList SearchReturnRequests(int storeId, int customerId, int orderItemId, ReturnRequestStatus? rs, int pageIndex, int pageSize); + IPagedList SearchReturnRequests(int storeId, int customerId, int orderItemId, ReturnRequestStatus? rs, int pageIndex, int pageSize, int id = 0); #endregion } diff --git a/src/Libraries/SmartStore.Services/Orders/IShoppingCartService.cs b/src/Libraries/SmartStore.Services/Orders/IShoppingCartService.cs index b753abfeba..d8479eb218 100644 --- a/src/Libraries/SmartStore.Services/Orders/IShoppingCartService.cs +++ b/src/Libraries/SmartStore.Services/Orders/IShoppingCartService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; @@ -59,18 +58,25 @@ IList GetStandardWarnings(Customer customer, ShoppingCartType shoppingCa Product product, string selectedAttributes, decimal customerEnteredPrice, int quantity); - /// - /// Validates shopping cart item attributes - /// + /// + /// Validates shopping cart item attributes + /// /// The customer - /// Shopping cart type + /// Shopping cart type /// Product - /// Selected attributes + /// Selected attributes + /// The product variant attribute combination instance (reduces database roundtrips) /// Quantity /// Product bundle item - /// Warnings - IList GetShoppingCartItemAttributeWarnings(Customer customer, ShoppingCartType shoppingCartType, - Product product, string selectedAttributes, int quantity = 1, ProductBundleItem bundleItem = null); + /// Warnings + IList GetShoppingCartItemAttributeWarnings( + Customer customer, + ShoppingCartType shoppingCartType, + Product product, + string selectedAttributes, + int quantity = 1, + ProductBundleItem bundleItem = null, + ProductVariantAttributeCombination combination = null); /// /// Validates shopping cart item (gift card) @@ -143,42 +149,41 @@ OrganizedShoppingCartItem FindShoppingCartItemInTheCart(IList - /// Add a product to shopping cart - /// - /// Customer - /// Product - /// Shopping cart type + /// + /// Add product to cart + /// + /// The customer + /// The product + /// Cart type /// Store identifier - /// Selected attributes - /// The price enter by a customer - /// Quantity - /// Automatically add required products if enabled - /// Identifier fo the new shopping cart item - /// Identifier of the parent shopping cart item - /// Product bundle item - /// Warnings - IList AddToCart(Customer customer, Product product, - ShoppingCartType shoppingCartType, int storeId, string selectedAttributes, - decimal customerEnteredPrice, int quantity, bool automaticallyAddRequiredProductsIfEnabled, - out int shoppingCartItemId, int? parentItemId = null, ProductBundleItem bundleItem = null); + /// Selected attributes + /// Price entered by customer + /// Quantity + /// Whether to add required products + /// Add to cart context + /// List with warnings + List AddToCart(Customer customer, Product product, ShoppingCartType cartType, int storeId, string selectedAttributes, + decimal customerEnteredPrice, int quantity, bool automaticallyAddRequiredProductsIfEnabled, AddToCartContext ctx = null); /// - /// Adds a product to the shopping cart and also adds bundle items if the product is a bundle. + /// Add product to cart /// - /// List with warnings - /// Product - /// Collection with selected attribute data - /// Shopping cart type - /// The price enter by a customer - /// Quantity - /// Automatically add required products if enabled - /// Parent cart item if it is a bundle item - /// Bundle item object if it is a bundle item - /// Identifier of inserted (parent) shopping cart item - int AddToCart(List warnings, Product product, NameValueCollection form, ShoppingCartType cartType, decimal customerEnteredPrice, - int quantity, bool addRequiredProducts, int? parentCartItemId = null, ProductBundleItem bundleItem = null); + /// Add to cart context + void AddToCart(AddToCartContext ctx); + + /// + /// Stores the shopping card items in the database + /// + /// Add to cart context + void AddToCartStoring(AddToCartContext ctx); + + /// + /// Validates if all required attributes are selected + /// + /// Selected attributes + /// Product + /// bool + bool AreAllAttributesForCombinationSelected(string selectedAttributes, Product product); /// /// Updates the shopping cart item diff --git a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs index 095f6ecbae..0993597da4 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderProcessingService.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using SmartStore.Core; -using SmartStore.Core.Html; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; @@ -16,28 +14,29 @@ using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Events; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; using SmartStore.Services.Affiliates; using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; using SmartStore.Services.Directory; using SmartStore.Services.Discounts; -using SmartStore.Core.Events; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Messages; using SmartStore.Services.Payments; using SmartStore.Services.Security; using SmartStore.Services.Shipping; using SmartStore.Services.Tax; -using SmartStore.Services.Seo; namespace SmartStore.Services.Orders { - /// - /// Order processing service - /// - public partial class OrderProcessingService : IOrderProcessingService + /// + /// Order processing service + /// + public partial class OrderProcessingService : IOrderProcessingService { #region Fields @@ -70,8 +69,9 @@ public partial class OrderProcessingService : IOrderProcessingService private readonly IAffiliateService _affiliateService; private readonly IEventPublisher _eventPublisher; private readonly IGenericAttributeService _genericAttributeService; + private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService; - private readonly PaymentSettings _paymentSettings; + private readonly PaymentSettings _paymentSettings; private readonly RewardPointsSettings _rewardPointsSettings; private readonly OrderSettings _orderSettings; private readonly TaxSettings _taxSettings; @@ -79,48 +79,48 @@ public partial class OrderProcessingService : IOrderProcessingService private readonly CurrencySettings _currencySettings; private readonly ShoppingCartSettings _shoppingCartSettings; - #endregion + #endregion - #region Ctor + #region Ctor - /// - /// Ctor - /// - /// Order service - /// Web helper - /// Localization service - /// Language service - /// Product service - /// Payment service - /// Logger - /// Order total calculationservice - /// Price calculation service - /// Price formatter - /// Product attribute parser - /// Product attribute formatter - /// Gift card service - /// Shopping cart service - /// Checkout attribute service - /// Shipping service - /// Shipment service - /// Tax service - /// Customer service - /// Discount service - /// Encryption service - /// Work context + /// + /// Ctor + /// + /// Order service + /// Web helper + /// Localization service + /// Language service + /// Product service + /// Payment service + /// Logger + /// Order total calculationservice + /// Price calculation service + /// Price formatter + /// Product attribute parser + /// Product attribute formatter + /// Gift card service + /// Shopping cart service + /// Checkout attribute service + /// Shipping service + /// Shipment service + /// Tax service + /// Customer service + /// Discount service + /// Encryption service + /// Work context /// Store context - /// Workflow message service - /// Customer activity service - /// Currency service + /// Workflow message service + /// Customer activity service + /// Currency service /// Affiliate service - /// Event published - /// Payment settings - /// Reward points settings - /// Order settings - /// Tax settings - /// Localization settings - /// Currency settings - public OrderProcessingService(IOrderService orderService, + /// Event published + /// Payment settings + /// Reward points settings + /// Order settings + /// Tax settings + /// Localization settings + /// Currency settings + public OrderProcessingService(IOrderService orderService, IWebHelper webHelper, ILocalizationService localizationService, ILanguageService languageService, @@ -149,7 +149,8 @@ public OrderProcessingService(IOrderService orderService, IAffiliateService affiliateService, IEventPublisher eventPublisher, IGenericAttributeService genericAttributeService, - PaymentSettings paymentSettings, + INewsLetterSubscriptionService newsLetterSubscriptionService, + PaymentSettings paymentSettings, RewardPointsSettings rewardPointsSettings, OrderSettings orderSettings, TaxSettings taxSettings, @@ -186,6 +187,7 @@ public OrderProcessingService(IOrderService orderService, this._affiliateService = affiliateService; this._eventPublisher = eventPublisher; this._genericAttributeService = genericAttributeService; + this._newsLetterSubscriptionService = newsLetterSubscriptionService; this._paymentSettings = paymentSettings; this._rewardPointsSettings = rewardPointsSettings; this._orderSettings = orderSettings; @@ -193,21 +195,31 @@ public OrderProcessingService(IOrderService orderService, this._localizationSettings = localizationSettings; this._currencySettings = currencySettings; this._shoppingCartSettings = shoppingCartSettings; - } - #endregion + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } - #region Utilities + #endregion + + #region Utilities private decimal Round(decimal value) { return (_shoppingCartSettings.RoundPricesDuringCalculation ? Math.Round(value, 2) : value); } - private string T(string resKey) - { - return _localizationService.GetResource("Admin.OrderNotice." + resKey); - } + private void ProcessErrors(Order order, IList errors, string messageKey) + { + if (errors.Any()) + { + var msg = string.Concat(T(messageKey, order.GetOrderNumber()), " ", string.Join(" ", errors)); + + _orderService.AddOrderNote(order, msg); + _logger.InsertLog(LogLevel.Error, msg, msg); + } + } /// /// Award reward points @@ -230,21 +242,20 @@ protected void AwardRewardPoints(Order order, decimal? amount = null) if (order.RewardPointsWereAdded) return; - // Truncate increases the risk of inaccuracy of rounding - //int points = (int)Math.Truncate((amount ?? order.OrderTotal) / _rewardPointsSettings.PointsForPurchases_Amount * _rewardPointsSettings.PointsForPurchases_Points); - - int points = (int)Math.Round((amount ?? order.OrderTotal) / _rewardPointsSettings.PointsForPurchases_Amount * _rewardPointsSettings.PointsForPurchases_Points); + // Trucate same as Floor for positive amounts + int points = (int)Math.Truncate((amount ?? order.OrderTotal) / _rewardPointsSettings.PointsForPurchases_Amount * _rewardPointsSettings.PointsForPurchases_Points); if (points == 0) return; //add reward points - order.Customer.AddRewardPointsHistoryEntry(points, string.Format(_localizationService.GetResource("RewardPoints.Message.EarnedForOrder"), order.GetOrderNumber())); + order.Customer.AddRewardPointsHistoryEntry(points, T("RewardPoints.Message.EarnedForOrder", order.GetOrderNumber())); order.RewardPointsWereAdded = true; + _orderService.UpdateOrder(order); } /// - /// Award reward points + /// Reduce reward points /// /// Order /// The amount. OrderTotal is used if null. @@ -276,7 +287,7 @@ protected void ReduceRewardPoints(Order order, decimal? amount = null) return; //reduce reward points - order.Customer.AddRewardPointsHistoryEntry(-points, string.Format(_localizationService.GetResource("RewardPoints.Message.ReducedForOrder"), order.GetOrderNumber())); + order.Customer.AddRewardPointsHistoryEntry(-points, T("RewardPoints.Message.ReducedForOrder", order.GetOrderNumber())); if (!order.RewardPointsRemaining.HasValue) order.RewardPointsRemaining = (int)Math.Round(order.OrderTotal / _rewardPointsSettings.PointsForPurchases_Amount * _rewardPointsSettings.PointsForPurchases_Points); @@ -294,34 +305,42 @@ protected void ReduceRewardPoints(Order order, decimal? amount = null) protected void SetActivatedValueForPurchasedGiftCards(Order order, bool activate) { var giftCards = _giftCardService.GetAllGiftCards(order.Id, null, null, !activate); + foreach (var gc in giftCards) { if (activate) { //activate - bool isRecipientNotified = gc.IsRecipientNotified; + var isRecipientNotified = gc.IsRecipientNotified; + if (gc.GiftCardType == GiftCardType.Virtual) { //send email for virtual gift card - if (!String.IsNullOrEmpty(gc.RecipientEmail) && - !String.IsNullOrEmpty(gc.SenderEmail)) + if (!String.IsNullOrEmpty(gc.RecipientEmail) && !String.IsNullOrEmpty(gc.SenderEmail)) { var customerLang = _languageService.GetLanguageById(order.CustomerLanguageId); if (customerLang == null) customerLang = _languageService.GetAllLanguages().FirstOrDefault(); - int queuedEmailId = _workflowMessageService.SendGiftCardNotification(gc, customerLang.Id); - if (queuedEmailId > 0) - isRecipientNotified = true; + + var queuedEmailId = _workflowMessageService.SendGiftCardNotification(gc, customerLang.Id); + + if (queuedEmailId > 0) + { + isRecipientNotified = true; + } } } + gc.IsGiftCardActivated = true; gc.IsRecipientNotified = isRecipientNotified; + _giftCardService.UpdateGiftCard(gc); } else { //deactivate gc.IsGiftCardActivated = false; + _giftCardService.UpdateGiftCard(gc); } } @@ -346,49 +365,25 @@ protected void SetOrderStatus(Order order, OrderStatus os, bool notifyCustomer) order.OrderStatusId = (int)os; _orderService.UpdateOrder(order); - //order notes, notifications - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderStatusChanged"), os.GetLocalizedEnum(_localizationService)), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); - + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderStatusChanged", os.GetLocalizedEnum(_localizationService))); - if (prevOrderStatus != OrderStatus.Complete && - os == OrderStatus.Complete - && notifyCustomer) + if (prevOrderStatus != OrderStatus.Complete && os == OrderStatus.Complete && notifyCustomer) { //notification int orderCompletedCustomerNotificationQueuedEmailId = _workflowMessageService.SendOrderCompletedCustomerNotification(order, order.CustomerLanguageId); if (orderCompletedCustomerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("CustomerCompletedEmailQueued"), orderCompletedCustomerNotificationQueuedEmailId), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.CustomerCompletedEmailQueued", orderCompletedCustomerNotificationQueuedEmailId)); } } - if (prevOrderStatus != OrderStatus.Cancelled && - os == OrderStatus.Cancelled - && notifyCustomer) + if (prevOrderStatus != OrderStatus.Cancelled && os == OrderStatus.Cancelled && notifyCustomer) { //notification int orderCancelledCustomerNotificationQueuedEmailId = _workflowMessageService.SendOrderCancelledCustomerNotification(order, order.CustomerLanguageId); if (orderCancelledCustomerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("CustomerCancelledEmailQueued"), orderCancelledCustomerNotificationQueuedEmailId), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.CustomerCancelledEmailQueued", orderCancelledCustomerNotificationQueuedEmailId)); } } @@ -403,15 +398,13 @@ protected void SetOrderStatus(Order order, OrderStatus os, bool notifyCustomer) } //gift cards activation - if (_orderSettings.GiftCards_Activated_OrderStatusId > 0 && - _orderSettings.GiftCards_Activated_OrderStatusId == (int)order.OrderStatus) + if (_orderSettings.GiftCards_Activated_OrderStatusId > 0 && _orderSettings.GiftCards_Activated_OrderStatusId == (int)order.OrderStatus) { SetActivatedValueForPurchasedGiftCards(order, true); } //gift cards deactivation - if (_orderSettings.GiftCards_Deactivated_OrderStatusId > 0 && - _orderSettings.GiftCards_Deactivated_OrderStatusId == (int)order.OrderStatus) + if (_orderSettings.GiftCards_Deactivated_OrderStatusId > 0 && _orderSettings.GiftCards_Deactivated_OrderStatusId == (int)order.OrderStatus) { SetActivatedValueForPurchasedGiftCards(order, false); } @@ -436,8 +429,7 @@ public void CheckOrderStatus(Order order) if (order.OrderStatus == OrderStatus.Pending) { - if (order.PaymentStatus == PaymentStatus.Authorized || - order.PaymentStatus == PaymentStatus.Paid) + if (order.PaymentStatus == PaymentStatus.Authorized || order.PaymentStatus == PaymentStatus.Paid) { SetOrderStatus(order, OrderStatus.Processing, false); } @@ -445,16 +437,13 @@ public void CheckOrderStatus(Order order) if (order.OrderStatus == OrderStatus.Pending) { - if (order.ShippingStatus == ShippingStatus.PartiallyShipped || - order.ShippingStatus == ShippingStatus.Shipped || - order.ShippingStatus == ShippingStatus.Delivered) + if (order.ShippingStatus == ShippingStatus.PartiallyShipped || order.ShippingStatus == ShippingStatus.Shipped || order.ShippingStatus == ShippingStatus.Delivered) { SetOrderStatus(order, OrderStatus.Processing, false); } } - if (order.OrderStatus != OrderStatus.Cancelled && - order.OrderStatus != OrderStatus.Complete) + if (order.OrderStatus != OrderStatus.Cancelled && order.OrderStatus != OrderStatus.Complete) { if (order.PaymentStatus == PaymentStatus.Paid) { @@ -475,9 +464,11 @@ public void CheckOrderStatus(Order order) /// /// Process payment request /// Place order result - public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentRequest) + public virtual PlaceOrderResult PlaceOrder( + ProcessPaymentRequest processPaymentRequest, + Dictionary extraData) { - //think about moving functionality of processing recurring orders (after the initial order was placed) to ProcessNextRecurringPayment() method + // think about moving functionality of processing recurring orders (after the initial order was placed) to ProcessNextRecurringPayment() method if (processPaymentRequest == null) throw new ArgumentNullException("processPaymentRequest"); @@ -485,32 +476,36 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR processPaymentRequest.OrderGuid = Guid.NewGuid(); var result = new PlaceOrderResult(); + var utcNow = DateTime.UtcNow; + try { #region Order details (customer, totals) - //Recurring orders. Load initial order - Order initialOrder = _orderService.GetOrderById(processPaymentRequest.InitialOrderId); + // Recurring orders. Load initial order + var initialOrder = _orderService.GetOrderById(processPaymentRequest.InitialOrderId); if (processPaymentRequest.IsRecurringPayment) { if (initialOrder == null) - throw new ArgumentException("Initial order is not set for recurring payment"); + throw new ArgumentException(T("Order.InitialOrderDoesNotExistForRecurringPayment")); processPaymentRequest.PaymentMethodSystemName = initialOrder.PaymentMethodSystemName; } - //customer + // customer var customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId); if (customer == null) - throw new ArgumentException("Customer is not set"); + throw new ArgumentException(T("Customer.DoesNotExist")); - //affilites - int affiliateId = 0; + // affilites + var affiliateId = 0; var affiliate = _affiliateService.GetAffiliateById(customer.AffiliateId); if (affiliate != null && affiliate.Active && !affiliate.Deleted) + { affiliateId = affiliate.Id; + } - //customer currency + // customer currency string customerCurrencyCode = ""; decimal customerCurrencyRate = decimal.Zero; if (!processPaymentRequest.IsRecurringPayment) @@ -518,7 +513,9 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR var currencyTmp = _currencyService.GetCurrencyById(customer.GetAttribute(SystemCustomerAttributeNames.CurrencyId, processPaymentRequest.StoreId)); var customerCurrency = (currencyTmp != null && currencyTmp.Published) ? currencyTmp : _workContext.WorkingCurrency; customerCurrencyCode = customerCurrency.CurrencyCode; - var primaryStoreCurrency = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId); + + var primaryStoreCurrency = _storeContext.CurrentStore.PrimaryStoreCurrency; + customerCurrencyRate = customerCurrency.Rate / primaryStoreCurrency.Rate; } else @@ -527,95 +524,80 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR customerCurrencyRate = initialOrder.CurrencyRate; } - //customer language + // customer language Language customerLanguage = null; if (!processPaymentRequest.IsRecurringPayment) { - customerLanguage = _languageService.GetLanguageById(customer.GetAttribute( - SystemCustomerAttributeNames.LanguageId, processPaymentRequest.StoreId)); + customerLanguage = _languageService.GetLanguageById(customer.GetAttribute(SystemCustomerAttributeNames.LanguageId, processPaymentRequest.StoreId)); } else { customerLanguage = _languageService.GetLanguageById(initialOrder.CustomerLanguageId); } - if (customerLanguage == null || !customerLanguage.Published) - customerLanguage = _workContext.WorkingLanguage; - //check whether customer is guest + if (customerLanguage == null || !customerLanguage.Published) + { + customerLanguage = _workContext.WorkingLanguage; + } + + // check whether customer is guest if (customer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed) - throw new SmartException("Anonymous checkout is not allowed"); + throw new SmartException(T("Checkout.AnonymousNotAllowed")); var storeId = _storeContext.CurrentStore.Id; - //load and validate customer shopping cart + // load and validate customer shopping cart IList cart = null; if (!processPaymentRequest.IsRecurringPayment) { //load shopping cart - cart = customer.GetCartItems(ShoppingCartType.ShoppingCart, processPaymentRequest.StoreId); + if (processPaymentRequest.ShoppingCartItems.Count > 0) + cart = processPaymentRequest.ShoppingCartItems; + else + cart = customer.GetCartItems(ShoppingCartType.ShoppingCart, processPaymentRequest.StoreId); if (cart.Count == 0) - throw new SmartException("Cart is empty"); + throw new SmartException(T("ShoppingCart.CartIsEmpty")); - //validate the entire shopping cart - var warnings = _shoppingCartService.GetShoppingCartWarnings(cart, - customer.GetAttribute(SystemCustomerAttributeNames.CheckoutAttributes), true); + // validate the entire shopping cart + var warnings = _shoppingCartService.GetShoppingCartWarnings(cart, customer.GetAttribute(SystemCustomerAttributeNames.CheckoutAttributes), true); if (warnings.Count > 0) - { - var warningsSb = new StringBuilder(); - foreach (string warning in warnings) - { - warningsSb.Append(warning); - warningsSb.Append(";"); - } - throw new SmartException(warningsSb.ToString()); - } + throw new SmartException(string.Join(" ", warnings)); - //validate individual cart items + // validate individual cart items foreach (var sci in cart) { var sciWarnings = _shoppingCartService.GetShoppingCartItemWarnings(customer, sci.Item.ShoppingCartType, sci.Item.Product, processPaymentRequest.StoreId, sci.Item.AttributesXml, sci.Item.CustomerEnteredPrice, sci.Item.Quantity, false, childItems: sci.ChildItems); + if (sciWarnings.Count > 0) - { - var warningsSb = new StringBuilder(); - foreach (string warning in sciWarnings) - { - warningsSb.Append(warning); - warningsSb.Append(";"); - } - throw new SmartException(warningsSb.ToString()); - } + throw new SmartException(string.Join(" ", sciWarnings)); } } - //min totals validation + // min totals validation if (!processPaymentRequest.IsRecurringPayment) { - bool minOrderSubtotalAmountOk = ValidateMinOrderSubtotalAmount(cart); + var minOrderSubtotalAmountOk = ValidateMinOrderSubtotalAmount(cart); if (!minOrderSubtotalAmountOk) { - decimal minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency); - throw new SmartException(string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"), _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false))); + var minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency); + throw new SmartException(T("Checkout.MinOrderSubtotalAmount", _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false))); } - bool minOrderTotalAmountOk = ValidateMinOrderTotalAmount(cart); + + var minOrderTotalAmountOk = ValidateMinOrderTotalAmount(cart); if (!minOrderTotalAmountOk) { - decimal minOrderTotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderTotalAmount, _workContext.WorkingCurrency); - throw new SmartException(string.Format(_localizationService.GetResource("Checkout.MinOrderTotalAmount"), _priceFormatter.FormatPrice(minOrderTotalAmount, true, false))); + var minOrderTotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderTotalAmount, _workContext.WorkingCurrency); + throw new SmartException(T("Checkout.MinOrderTotalAmount", _priceFormatter.FormatPrice(minOrderTotalAmount, true, false))); } } - //tax display type + // tax display type var customerTaxDisplayType = TaxDisplayType.IncludingTax; if (!processPaymentRequest.IsRecurringPayment) { - //if (_taxSettings.AllowCustomersToSelectTaxDisplayType) - // customerTaxDisplayType = customer.TaxDisplayType; - //else - // customerTaxDisplayType = _taxSettings.TaxDisplayType; - customerTaxDisplayType = _workContext.GetTaxDisplayTypeFor(customer, processPaymentRequest.StoreId); } else @@ -623,7 +605,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR customerTaxDisplayType = initialOrder.CustomerTaxDisplayType; } - //checkout attributes + // checkout attributes string checkoutAttributeDescription, checkoutAttributesXml; if (!processPaymentRequest.IsRecurringPayment) { @@ -636,15 +618,15 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR checkoutAttributeDescription = initialOrder.CheckoutAttributeDescription; } - //applied discount (used to store discount usage history) + // applied discount (used to store discount usage history) var appliedDiscounts = new List(); - //sub total + // sub total decimal orderSubTotalInclTax, orderSubTotalExclTax; decimal orderSubTotalDiscountInclTax = 0, orderSubTotalDiscountExclTax = 0; if (!processPaymentRequest.IsRecurringPayment) { - //sub total (incl tax) + // sub total (incl tax) decimal orderSubTotalDiscountAmount1 = decimal.Zero; Discount orderSubTotalAppliedDiscount1 = null; decimal subTotalWithoutDiscountBase1 = decimal.Zero; @@ -656,11 +638,11 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR orderSubTotalInclTax = subTotalWithoutDiscountBase1; orderSubTotalDiscountInclTax = orderSubTotalDiscountAmount1; - //discount history - if (orderSubTotalAppliedDiscount1 != null && !appliedDiscounts.ContainsDiscount(orderSubTotalAppliedDiscount1)) + // discount history + if (orderSubTotalAppliedDiscount1 != null && !appliedDiscounts.Any(x => x.Id == orderSubTotalAppliedDiscount1.Id)) appliedDiscounts.Add(orderSubTotalAppliedDiscount1); - //sub total (excl tax) + // sub total (excl tax) decimal orderSubTotalDiscountAmount2 = decimal.Zero; Discount orderSubTotalAppliedDiscount2 = null; decimal subTotalWithoutDiscountBase2 = decimal.Zero; @@ -679,7 +661,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR } - //shipping info + // shipping info bool shoppingCartRequiresShipping = false; if (!processPaymentRequest.IsRecurringPayment) { @@ -695,7 +677,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR { if (!processPaymentRequest.IsRecurringPayment) { - var shippingOption = customer.GetAttribute(SystemCustomerAttributeNames.SelectedShippingOption, processPaymentRequest.StoreId); + var shippingOption = customer.GetAttribute(SystemCustomerAttributeNames.SelectedShippingOption, processPaymentRequest.StoreId); if (shippingOption != null) { shippingMethodName = shippingOption.Name; @@ -709,38 +691,40 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR } } - //shipping total + // shipping total decimal? orderShippingTotalInclTax, orderShippingTotalExclTax = null; + decimal orderShippingTaxRate = decimal.Zero; if (!processPaymentRequest.IsRecurringPayment) { - decimal taxRate = decimal.Zero; Discount shippingTotalDiscount = null; - orderShippingTotalInclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, true, out taxRate, out shippingTotalDiscount); + orderShippingTotalInclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, true, out orderShippingTaxRate, out shippingTotalDiscount); orderShippingTotalExclTax = _orderTotalCalculationService.GetShoppingCartShippingTotal(cart, false); if (!orderShippingTotalInclTax.HasValue || !orderShippingTotalExclTax.HasValue) - throw new SmartException("Shipping total couldn't be calculated"); + throw new SmartException(T("Order.CannotCalculateShippingTotal")); - if (shippingTotalDiscount != null && !appliedDiscounts.ContainsDiscount(shippingTotalDiscount)) + if (shippingTotalDiscount != null && !appliedDiscounts.Any(x => x.Id == shippingTotalDiscount.Id)) appliedDiscounts.Add(shippingTotalDiscount); } else { orderShippingTotalInclTax = initialOrder.OrderShippingInclTax; orderShippingTotalExclTax = initialOrder.OrderShippingExclTax; + orderShippingTaxRate = initialOrder.OrderShippingTaxRate; } //payment total - decimal paymentAdditionalFeeInclTax, paymentAdditionalFeeExclTax; + decimal paymentAdditionalFeeInclTax, paymentAdditionalFeeExclTax, paymentAdditionalFeeTaxRate; if (!processPaymentRequest.IsRecurringPayment) { decimal paymentAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, processPaymentRequest.PaymentMethodSystemName); - paymentAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, true, customer); + paymentAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, true, customer, out paymentAdditionalFeeTaxRate); paymentAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentAdditionalFee, false, customer); } else { paymentAdditionalFeeInclTax = initialOrder.PaymentMethodAdditionalFeeInclTax; paymentAdditionalFeeExclTax = initialOrder.PaymentMethodAdditionalFeeExclTax; + paymentAdditionalFeeTaxRate = initialOrder.PaymentMethodAdditionalFeeTaxRate; } //tax total @@ -755,7 +739,9 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR //VAT number var customerVatStatus = (VatNumberStatus)customer.GetAttribute(SystemCustomerAttributeNames.VatNumberStatusId); if (_taxSettings.EuVatEnabled && customerVatStatus == VatNumberStatus.Valid) + { vatNumber = customer.GetAttribute(SystemCustomerAttributeNames.VatNumber); + } //tax rates foreach (var kvp in taxRatesDictionary) @@ -771,6 +757,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR //VAT number vatNumber = initialOrder.VatNumber; } + processPaymentRequest.OrderTax = orderTaxTotal; //order total (and applied discounts, gift cards, reward points) decimal? orderTotal = null; @@ -782,14 +769,16 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR { Discount orderAppliedDiscount = null; orderTotal = _orderTotalCalculationService.GetShoppingCartTotal(cart, - out orderDiscountAmount, out orderAppliedDiscount, out appliedGiftCards, - out redeemedRewardPoints, out redeemedRewardPointsAmount); + out orderDiscountAmount, out orderAppliedDiscount, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount); + if (!orderTotal.HasValue) - throw new SmartException("Order total couldn't be calculated"); + throw new SmartException(T("Order.CannotCalculateOrderTotal")); - //discount history - if (orderAppliedDiscount != null && !appliedDiscounts.ContainsDiscount(orderAppliedDiscount)) - appliedDiscounts.Add(orderAppliedDiscount); + //discount history + if (orderAppliedDiscount != null && !appliedDiscounts.Any(x => x.Id == orderAppliedDiscount.Id)) + { + appliedDiscounts.Add(orderAppliedDiscount); + } } else { @@ -801,41 +790,38 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR #endregion #region Addresses & pre payment workflow - + // give payment processor the opportunity to fullfill billing address var preProcessPaymentResult = _paymentService.PreProcessPayment(processPaymentRequest); if (!preProcessPaymentResult.Success) { - foreach (var paymentError in preProcessPaymentResult.Errors) - { - result.AddError(string.Format("Payment error: {0}", paymentError)); - } - - throw new SmartException("Error while pre-processing the payment"); + result.Errors.AddRange(preProcessPaymentResult.Errors); + result.Errors.Add(T("Common.Error.PreProcessPayment")); + return result; } Address billingAddress = null; if (!processPaymentRequest.IsRecurringPayment) { if (customer.BillingAddress == null) - throw new SmartException("Billing address is not provided"); + throw new SmartException(T("Order.BillingAddressMissing")); if (!customer.BillingAddress.Email.IsEmail()) - throw new SmartException("Email is not valid"); + throw new SmartException(T("Common.Error.InvalidEmail")); billingAddress = (Address)customer.BillingAddress.Clone(); } else { if (initialOrder.BillingAddress == null) - throw new SmartException("Billing address is not available"); + throw new SmartException(T("Order.BillingAddressMissing")); billingAddress = (Address)initialOrder.BillingAddress.Clone(); } if (billingAddress.Country != null && !billingAddress.Country.AllowsBilling) - throw new SmartException(string.Format("Country '{0}' is not allowed for billing", billingAddress.Country.Name)); + throw new SmartException(T("Order.CountryNotAllowedForBilling", billingAddress.Country.Name)); Address shippingAddress = null; if (shoppingCartRequiresShipping) @@ -843,62 +829,68 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR if (!processPaymentRequest.IsRecurringPayment) { if (customer.ShippingAddress == null) - throw new SmartException("Shipping address is not provided"); + throw new SmartException(T("Order.ShippingAddressMissing")); if (!customer.ShippingAddress.Email.IsEmail()) - throw new SmartException("Email is not valid"); + throw new SmartException(T("Common.Error.InvalidEmail")); shippingAddress = (Address)customer.ShippingAddress.Clone(); } else { if (initialOrder.ShippingAddress == null) - throw new SmartException("Shipping address is not available"); + throw new SmartException(T("Order.ShippingAddressMissing")); shippingAddress = (Address)initialOrder.ShippingAddress.Clone(); } if (shippingAddress.Country != null && !shippingAddress.Country.AllowsShipping) - throw new SmartException(string.Format("Country '{0}' is not allowed for shipping", shippingAddress.Country.Name)); + throw new SmartException(T("Order.CountryNotAllowedForShipping", shippingAddress.Country.Name)); } #endregion #region Payment workflow - //skip payment workflow if order total equals zero - bool skipPaymentWorkflow = false; - if (orderTotal.Value == decimal.Zero) - skipPaymentWorkflow = true; + // skip payment workflow if order total equals zero + var skipPaymentWorkflow = false; + if (orderTotal.Value == decimal.Zero) + { + skipPaymentWorkflow = true; + } - //payment workflow - IPaymentMethod paymentMethod = null; - if (!skipPaymentWorkflow) - { - paymentMethod = _paymentService.LoadPaymentMethodBySystemName(processPaymentRequest.PaymentMethodSystemName); - if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); + // payment workflow + Provider paymentMethod = null; + if (!skipPaymentWorkflow) + { + paymentMethod = _paymentService.LoadPaymentMethodBySystemName(processPaymentRequest.PaymentMethodSystemName); + if (paymentMethod == null) + throw new SmartException(T("Payment.CouldNotLoadMethod")); - //ensure that payment method is active - if (!paymentMethod.IsPaymentMethodActive(_paymentSettings)) - throw new SmartException("Payment method is not active"); - } - else - processPaymentRequest.PaymentMethodSystemName = ""; + // ensure that payment method is active + if (!paymentMethod.IsPaymentMethodActive(_paymentSettings)) + throw new SmartException(T("Payment.MethodNotAvailable")); + } + else + { + processPaymentRequest.PaymentMethodSystemName = ""; + } - //recurring or standard shopping cart? - bool isRecurringShoppingCart = false; + // recurring or standard shopping cart? + var isRecurringShoppingCart = false; if (!processPaymentRequest.IsRecurringPayment) { isRecurringShoppingCart = cart.IsRecurring(); if (isRecurringShoppingCart) { - int recurringCycleLength = 0; + var recurringCycleLength = 0; + var recurringTotalCycles = 0; RecurringProductCyclePeriod recurringCyclePeriod; - int recurringTotalCycles = 0; string recurringCyclesError = cart.GetRecurringCycleInfo(_localizationService, out recurringCycleLength, out recurringCyclePeriod, out recurringTotalCycles); + if (!string.IsNullOrEmpty(recurringCyclesError)) throw new SmartException(recurringCyclesError); + processPaymentRequest.RecurringCycleLength = recurringCycleLength; processPaymentRequest.RecurringCyclePeriod = recurringCyclePeriod; processPaymentRequest.RecurringTotalCycles = recurringTotalCycles; @@ -909,31 +901,31 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR isRecurringShoppingCart = true; } - //process payment + // process payment ProcessPaymentResult processPaymentResult = null; - if (!skipPaymentWorkflow) + if (!skipPaymentWorkflow && !processPaymentRequest.IsMultiOrder) { if (!processPaymentRequest.IsRecurringPayment) { if (isRecurringShoppingCart) { - //recurring cart + // recurring cart var recurringPaymentType = _paymentService.GetRecurringPaymentType(processPaymentRequest.PaymentMethodSystemName); switch (recurringPaymentType) { case RecurringPaymentType.NotSupported: - throw new SmartException("Recurring payments are not supported by selected payment method"); + throw new SmartException(T("Payment.RecurringPaymentNotSupported")); case RecurringPaymentType.Manual: case RecurringPaymentType.Automatic: processPaymentResult = _paymentService.ProcessRecurringPayment(processPaymentRequest); break; default: - throw new SmartException("Not supported recurring payment type"); + throw new SmartException(T("Payment.RecurringPaymentTypeUnknown")); } } else { - //standard cart + // standard cart processPaymentResult = _paymentService.ProcessPayment(processPaymentRequest); } } @@ -941,12 +933,13 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR { if (isRecurringShoppingCart) { - //Old credit card info + // Old credit card info processPaymentRequest.CreditCardType = initialOrder.AllowStoringCreditCardNumber ? _encryptionService.DecryptText(initialOrder.CardType) : ""; processPaymentRequest.CreditCardName = initialOrder.AllowStoringCreditCardNumber ? _encryptionService.DecryptText(initialOrder.CardName) : ""; processPaymentRequest.CreditCardNumber = initialOrder.AllowStoringCreditCardNumber ? _encryptionService.DecryptText(initialOrder.CardNumber) : ""; - //MaskedCreditCardNumber + // MaskedCreditCardNumber processPaymentRequest.CreditCardCvv2 = initialOrder.AllowStoringCreditCardNumber ? _encryptionService.DecryptText(initialOrder.CardCvv2) : ""; + try { processPaymentRequest.CreditCardExpireMonth = initialOrder.AllowStoringCreditCardNumber ? Convert.ToInt32(_encryptionService.DecryptText(initialOrder.CardExpirationMonth)) : 0; @@ -958,7 +951,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR switch (recurringPaymentType) { case RecurringPaymentType.NotSupported: - throw new SmartException("Recurring payments are not supported by selected payment method"); + throw new SmartException(T("Payment.RecurringPaymentNotSupported")); case RecurringPaymentType.Manual: processPaymentResult = _paymentService.ProcessRecurringPayment(processPaymentRequest); break; @@ -967,26 +960,25 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR processPaymentResult = new ProcessPaymentResult(); break; default: - throw new SmartException("Not supported recurring payment type"); - } + throw new SmartException(T("Payment.RecurringPaymentTypeUnknown")); + } } else { - throw new SmartException("No recurring products"); + throw new SmartException(T("Order.NoRecurringProducts")); } } } else { - //payment is not required - if (processPaymentResult == null) - processPaymentResult = new ProcessPaymentResult(); + // payment is not required + if (processPaymentResult == null) + { + processPaymentResult = new ProcessPaymentResult(); + } processPaymentResult.NewPaymentStatus = PaymentStatus.Paid; } - if (processPaymentResult == null) - throw new SmartException("processPaymentResult is not available"); - #endregion if (processPaymentResult.Success) @@ -998,10 +990,12 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR #region Save order details var shippingStatus = ShippingStatus.NotYetShipped; - if (!shoppingCartRequiresShipping) - shippingStatus = ShippingStatus.ShippingNotRequired; - - var order = new Order() + if (!shoppingCartRequiresShipping) + { + shippingStatus = ShippingStatus.ShippingNotRequired; + } + + var order = new Order { StoreId = processPaymentRequest.StoreId, OrderGuid = processPaymentRequest.OrderGuid, @@ -1015,8 +1009,10 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR OrderSubTotalDiscountExclTax = orderSubTotalDiscountExclTax, OrderShippingInclTax = orderShippingTotalInclTax.Value, OrderShippingExclTax = orderShippingTotalExclTax.Value, + OrderShippingTaxRate = orderShippingTaxRate, PaymentMethodAdditionalFeeInclTax = paymentAdditionalFeeInclTax, PaymentMethodAdditionalFeeExclTax = paymentAdditionalFeeExclTax, + PaymentMethodAdditionalFeeTaxRate = paymentAdditionalFeeTaxRate, TaxRates = taxRates, OrderTax = orderTaxTotal, OrderTotal = orderTotal.Value, @@ -1036,8 +1032,6 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR CardCvv2 = processPaymentResult.AllowStoringCreditCardNumber ? _encryptionService.EncryptText(processPaymentRequest.CreditCardCvv2) : string.Empty, CardExpirationMonth = processPaymentResult.AllowStoringCreditCardNumber ? _encryptionService.EncryptText(processPaymentRequest.CreditCardExpireMonth.ToString()) : string.Empty, CardExpirationYear = processPaymentResult.AllowStoringCreditCardNumber ? _encryptionService.EncryptText(processPaymentRequest.CreditCardExpireYear.ToString()) : string.Empty, - - //codehint: sm-add begin AllowStoringDirectDebit = processPaymentResult.AllowStoringDirectDebit, DirectDebitAccountHolder = processPaymentResult.AllowStoringDirectDebit ? _encryptionService.EncryptText(processPaymentRequest.DirectDebitAccountHolder) : string.Empty, DirectDebitAccountNumber = processPaymentResult.AllowStoringDirectDebit ? _encryptionService.EncryptText(processPaymentRequest.DirectDebitAccountNumber) : string.Empty, @@ -1046,8 +1040,6 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR DirectDebitBIC = processPaymentResult.AllowStoringDirectDebit ? _encryptionService.EncryptText(processPaymentRequest.DirectDebitBic) : string.Empty, DirectDebitCountry = processPaymentResult.AllowStoringDirectDebit ? _encryptionService.EncryptText(processPaymentRequest.DirectDebitCountry) : string.Empty, DirectDebitIban = processPaymentResult.AllowStoringDirectDebit ? _encryptionService.EncryptText(processPaymentRequest.DirectDebitIban) : string.Empty, - //codehint: sm-add end - PaymentMethodSystemName = processPaymentRequest.PaymentMethodSystemName, AuthorizationTransactionId = processPaymentResult.AuthorizationTransactionId, AuthorizationTransactionCode = processPaymentResult.AuthorizationTransactionCode, @@ -1064,9 +1056,16 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR ShippingMethod = shippingMethodName, ShippingRateComputationMethodSystemName = shippingRateComputationMethodSystemName, VatNumber = vatNumber, - CreatedOnUtc = DateTime.UtcNow, - UpdatedOnUtc = DateTime.UtcNow + CreatedOnUtc = utcNow, + UpdatedOnUtc = utcNow, + CustomerOrderComment = extraData.ContainsKey("CustomerComment") ? extraData["CustomerComment"] : "" }; + + if (extraData.ContainsKey("AcceptThirdPartyEmailHandOver") && _shoppingCartSettings.ThirdPartyEmailHandOver != CheckoutThirdPartyEmailHandOver.None) + { + order.AcceptThirdPartyEmailHandOver = extraData["AcceptThirdPartyEmailHandOver"].ToBool(); + } + _orderService.InsertOrder(order); result.PlacedOrder = order; @@ -1076,11 +1075,14 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR //move shopping cart items to order products foreach (var sc in cart) { + sc.Item.Product.MergeWithCombination(sc.Item.AttributesXml); + //prices decimal taxRate = decimal.Zero; + decimal unitPriceTaxRate = decimal.Zero; decimal scUnitPrice = _priceCalculationService.GetUnitPrice(sc, true); decimal scSubTotal = _priceCalculationService.GetSubTotal(sc, true); - decimal scUnitPriceInclTax = _taxService.GetProductPrice(sc.Item.Product, scUnitPrice, true, customer, out taxRate); + decimal scUnitPriceInclTax = _taxService.GetProductPrice(sc.Item.Product, scUnitPrice, true, customer, out unitPriceTaxRate); decimal scUnitPriceExclTax = _taxService.GetProductPrice(sc.Item.Product, scUnitPrice, false, customer, out taxRate); decimal scSubTotalInclTax = _taxService.GetProductPrice(sc.Item.Product, scSubTotal, true, customer, out taxRate); decimal scSubTotalExclTax = _taxService.GetProductPrice(sc.Item.Product, scSubTotal, false, customer, out taxRate); @@ -1090,16 +1092,19 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR decimal discountAmount = _priceCalculationService.GetDiscountAmount(sc, out scDiscount); decimal discountAmountInclTax = _taxService.GetProductPrice(sc.Item.Product, discountAmount, true, customer, out taxRate); decimal discountAmountExclTax = _taxService.GetProductPrice(sc.Item.Product, discountAmount, false, customer, out taxRate); - if (scDiscount != null && !appliedDiscounts.ContainsDiscount(scDiscount)) - appliedDiscounts.Add(scDiscount); + + if (scDiscount != null && !appliedDiscounts.Any(x => x.Id == scDiscount.Id)) + { + appliedDiscounts.Add(scDiscount); + } //attributes - string attributeDescription = _productAttributeFormatter.FormatAttributes(sc.Item.Product, sc.Item.AttributesXml, customer); + var attributeDescription = _productAttributeFormatter.FormatAttributes(sc.Item.Product, sc.Item.AttributesXml, customer); var itemWeight = _shippingService.GetShoppingCartItemWeight(sc); //save order item - var orderItem = new OrderItem() + var orderItem = new OrderItem { OrderItemGuid = Guid.NewGuid(), Order = order, @@ -1108,6 +1113,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR UnitPriceExclTax = scUnitPriceExclTax, PriceInclTax = scSubTotalInclTax, PriceExclTax = scSubTotalExclTax, + TaxRate = unitPriceTaxRate, AttributeDescription = attributeDescription, AttributesXml = sc.Item.AttributesXml, Quantity = sc.Item.Quantity, @@ -1126,10 +1132,10 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR foreach (var childItem in sc.ChildItems) { - decimal bundleItemSubTotal = _taxService.GetProductPrice(childItem.Item.Product, _priceCalculationService.GetSubTotal(childItem, true), out taxRate); + var bundleItemSubTotal = _taxService.GetProductPrice(childItem.Item.Product, _priceCalculationService.GetSubTotal(childItem, true), out taxRate); - string attributesInfo = _productAttributeFormatter.FormatAttributes(childItem.Item.Product, childItem.Item.AttributesXml, order.Customer, - renderPrices: false, allowHyperlinks: false); + var attributesInfo = _productAttributeFormatter.FormatAttributes(childItem.Item.Product, childItem.Item.AttributesXml, order.Customer, + renderPrices: false, allowHyperlinks: true); childItem.BundleItemData.ToOrderData(listBundleData, bundleItemSubTotal, childItem.Item.AttributesXml, attributesInfo); } @@ -1143,15 +1149,14 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR //gift cards if (sc.Item.Product.IsGiftCard) { - string giftCardRecipientName, giftCardRecipientEmail, - giftCardSenderName, giftCardSenderEmail, giftCardMessage; + string giftCardRecipientName, giftCardRecipientEmail, giftCardSenderName, giftCardSenderEmail, giftCardMessage; + _productAttributeParser.GetGiftCardAttribute(sc.Item.AttributesXml, - out giftCardRecipientName, out giftCardRecipientEmail, - out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); + out giftCardRecipientName, out giftCardRecipientEmail, out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); for (int i = 0; i < sc.Item.Quantity; i++) { - var gc = new GiftCard() + var gc = new GiftCard { GiftCardType = sc.Item.Product.GiftCardType, PurchasedWithOrderItem = orderItem, @@ -1164,18 +1169,18 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR SenderEmail = giftCardSenderEmail, Message = giftCardMessage, IsRecipientNotified = false, - CreatedOnUtc = DateTime.UtcNow + CreatedOnUtc = utcNow }; _giftCardService.InsertGiftCard(gc); } } - //inventory _productService.AdjustInventory(sc, true); } //clear shopping cart - cart.ToList().ForEach(sci => _shoppingCartService.DeleteShoppingCartItem(sci.Item, false)); + if (!processPaymentRequest.IsMultiOrder) + cart.ToList().ForEach(sci => _shoppingCartService.DeleteShoppingCartItem(sci.Item, false)); } else { @@ -1184,7 +1189,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR foreach (var orderItem in initialOrderItems) { //save item - var newOrderItem = new OrderItem() + var newOrderItem = new OrderItem { OrderItemGuid = Guid.NewGuid(), Order = order, @@ -1193,6 +1198,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR UnitPriceExclTax = orderItem.UnitPriceExclTax, PriceInclTax = orderItem.PriceInclTax, PriceExclTax = orderItem.PriceExclTax, + TaxRate = orderItem.TaxRate, AttributeDescription = orderItem.AttributeDescription, AttributesXml = orderItem.AttributesXml, Quantity = orderItem.Quantity, @@ -1214,12 +1220,11 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR string giftCardRecipientName, giftCardRecipientEmail, giftCardSenderName, giftCardSenderEmail, giftCardMessage; _productAttributeParser.GetGiftCardAttribute(orderItem.AttributesXml, - out giftCardRecipientName, out giftCardRecipientEmail, - out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); + out giftCardRecipientName, out giftCardRecipientEmail, out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); for (int i = 0; i < orderItem.Quantity; i++) { - var gc = new GiftCard() + var gc = new GiftCard { GiftCardType = orderItem.Product.GiftCardType, PurchasedWithOrderItem = newOrderItem, @@ -1232,13 +1237,12 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR SenderEmail = giftCardSenderEmail, Message = giftCardMessage, IsRecipientNotified = false, - CreatedOnUtc = DateTime.UtcNow + CreatedOnUtc = utcNow }; _giftCardService.InsertGiftCard(gc); } } - //inventory _productService.AdjustInventory(orderItem, true, orderItem.Quantity); } } @@ -1248,11 +1252,11 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR { foreach (var discount in appliedDiscounts) { - var duh = new DiscountUsageHistory() + var duh = new DiscountUsageHistory { Discount = discount, Order = order, - CreatedOnUtc = DateTime.UtcNow + CreatedOnUtc = utcNow }; _discountService.InsertDiscountUsageHistory(duh); } @@ -1263,13 +1267,13 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR { foreach (var agc in appliedGiftCards) { - decimal amountUsed = agc.AmountCanBeUsed; - var gcuh = new GiftCardUsageHistory() + var amountUsed = agc.AmountCanBeUsed; + var gcuh = new GiftCardUsageHistory { GiftCard = agc.GiftCard, UsedWithOrder = order, UsedValue = amountUsed, - CreatedOnUtc = DateTime.UtcNow + CreatedOnUtc = utcNow }; agc.GiftCard.GiftCardUsageHistory.Add(gcuh); _giftCardService.UpdateGiftCard(agc.GiftCard); @@ -1280,9 +1284,10 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR if (redeemedRewardPointsAmount > decimal.Zero) { customer.AddRewardPointsHistoryEntry(-redeemedRewardPoints, - string.Format(_localizationService.GetResource("RewardPoints.Message.RedeemedForOrder", order.CustomerLanguageId), order.GetOrderNumber()), + _localizationService.GetResource("RewardPoints.Message.RedeemedForOrder", order.CustomerLanguageId).FormatInvariant(order.GetOrderNumber()), order, - redeemedRewardPointsAmount); + redeemedRewardPointsAmount); + _customerService.UpdateCustomer(customer); } @@ -1290,19 +1295,18 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR if (!processPaymentRequest.IsRecurringPayment && isRecurringShoppingCart) { //create recurring payment (the first payment) - var rp = new RecurringPayment() + var rp = new RecurringPayment { CycleLength = processPaymentRequest.RecurringCycleLength, CyclePeriod = processPaymentRequest.RecurringCyclePeriod, TotalCycles = processPaymentRequest.RecurringTotalCycles, - StartDateUtc = DateTime.UtcNow, + StartDateUtc = utcNow, IsActive = true, - CreatedOnUtc = DateTime.UtcNow, + CreatedOnUtc = utcNow, InitialOrder = order, }; _orderService.InsertRecurringPayment(rp); - var recurringPaymentType = _paymentService.GetRecurringPaymentType(processPaymentRequest.PaymentMethodSystemName); switch (recurringPaymentType) { @@ -1317,7 +1321,7 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR var rph = new RecurringPaymentHistory() { RecurringPayment = rp, - CreatedOnUtc = DateTime.UtcNow, + CreatedOnUtc = utcNow, OrderId = order.Id, }; rp.RecurringPaymentHistory.Add(rph); @@ -1334,50 +1338,34 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR } } - #endregion + #endregion - #region Notifications, notes and attributes - - //notes, messages - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderPlaced"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + #region Notifications, notes and attributes + + // notes, messages + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderPlaced")); //send email notifications int orderPlacedStoreOwnerNotificationQueuedEmailId = _workflowMessageService.SendOrderPlacedStoreOwnerNotification(order, _localizationSettings.DefaultAdminLanguageId); if (orderPlacedStoreOwnerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("MerchantEmailQueued"), orderPlacedStoreOwnerNotificationQueuedEmailId), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.MerchantEmailQueued", orderPlacedStoreOwnerNotificationQueuedEmailId)); } int orderPlacedCustomerNotificationQueuedEmailId = _workflowMessageService.SendOrderPlacedCustomerNotification(order, order.CustomerLanguageId); if (orderPlacedCustomerNotificationQueuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("CustomerEmailQueued"), orderPlacedCustomerNotificationQueuedEmailId), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.CustomerEmailQueued", orderPlacedCustomerNotificationQueuedEmailId)); } - //check order status + // check order status CheckOrderStatus(order); - //reset checkout data - if (!processPaymentRequest.IsRecurringPayment) + //reset checkout data + if (!processPaymentRequest.IsRecurringPayment && !processPaymentRequest.IsMultiOrder) + { _customerService.ResetCheckoutData(customer, processPaymentRequest.StoreId, clearCouponCodes: true, clearCheckoutAttributes: true); + } // check for generic attributes to be inserted automatically foreach (var customProperty in processPaymentRequest.CustomProperties.Where(x => x.Key.HasValue() && x.Value.AutoCreateGenericAttribute)) @@ -1388,29 +1376,50 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR //uncomment this line to support transactions //scope.Complete(); - //raise event + // raise event _eventPublisher.PublishOrderPlaced(order); if (!processPaymentRequest.IsRecurringPayment) { - _customerActivityService.InsertActivity( - "PublicStore.PlaceOrder", - _localizationService.GetResource("ActivityLog.PublicStore.PlaceOrder"), - order.GetOrderNumber()); + _customerActivityService.InsertActivity("PublicStore.PlaceOrder", T("ActivityLog.PublicStore.PlaceOrder", order.GetOrderNumber())); } - + //raise event if (order.PaymentStatus == PaymentStatus.Paid) { _eventPublisher.PublishOrderPaid(order); } - #endregion - } - } + + #endregion + + #region Newsletter subscription + + if (extraData.ContainsKey("SubscribeToNewsLetter") && _shoppingCartSettings.NewsLetterSubscription != CheckoutNewsLetterSubscription.None) + { + var addSubscription = extraData["SubscribeToNewsLetter"].ToBool(); + + bool? nsResult = _newsLetterSubscriptionService.AddNewsLetterSubscriptionFor(addSubscription, customer.Email, order.StoreId); + + if (nsResult.HasValue) + { + if (nsResult.Value) + _orderService.AddOrderNote(order, T("Admin.OrderNotice.NewsLetterSubscriptionAdded")); + else + _orderService.AddOrderNote(order, T("Admin.OrderNotice.NewsLetterSubscriptionRemoved")); + } + } + + #endregion + } + } else { - foreach (var paymentError in processPaymentResult.Errors) - result.AddError(string.Format("Payment error: {0}", paymentError)); + result.AddError(T("Payment.PayingFailed")); + + foreach (var paymentError in processPaymentResult.Errors) + { + result.AddError(paymentError); + } } } catch (Exception exc) @@ -1419,23 +1428,10 @@ public virtual PlaceOrderResult PlaceOrder(ProcessPaymentRequest processPaymentR result.AddError(exc.Message); } - #region Process errors - - string error = ""; - for (int i = 0; i < result.Errors.Count; i++) - { - error += string.Format("Error {0}: {1}", i + 1, result.Errors[i]); - if (i != result.Errors.Count - 1) - error += ". "; - } - if (!String.IsNullOrEmpty(error)) - { - //log it - string logError = string.Format("Error while placing order. {0}", error); - _logger.Error(logError); - } - - #endregion + if (result.Errors.Count > 0) + { + _logger.Error(string.Join(" ", result.Errors)); + } return result; } @@ -1466,14 +1462,8 @@ public virtual void DeleteOrder(Order order) _productService.AdjustInventory(orderItem, false, orderItem.Quantity); } - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderDeleted"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + //add a note + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderDeleted")); //now delete an order _orderService.DeleteOrder(order); @@ -1488,25 +1478,25 @@ public virtual void ProcessNextRecurringPayment(RecurringPayment recurringPaymen { if (recurringPayment == null) throw new ArgumentNullException("recurringPayment"); + try { if (!recurringPayment.IsActive) - throw new SmartException("Recurring payment is not active"); + throw new SmartException(T("Payment.RecurringPaymentNotActive")); var initialOrder = recurringPayment.InitialOrder; if (initialOrder == null) - throw new SmartException("Initial order could not be loaded"); + throw new SmartException(T("Order.InitialOrderDoesNotExistForRecurringPayment")); var customer = initialOrder.Customer; if (customer == null) - throw new SmartException("Customer could not be loaded"); + throw new SmartException(T("Customer.DoesNotExist")); var nextPaymentDate = recurringPayment.NextPaymentDate; if (!nextPaymentDate.HasValue) - throw new SmartException("Next payment date could not be calculated"); + throw new SmartException(T("Payment.CannotCalculateNextPaymentDate")); - //payment info - var paymentInfo = new ProcessPaymentRequest() + var paymentInfo = new ProcessPaymentRequest { StoreId = initialOrder.StoreId, CustomerId = customer.Id, @@ -1519,36 +1509,31 @@ public virtual void ProcessNextRecurringPayment(RecurringPayment recurringPaymen }; //place a new order - var result = this.PlaceOrder(paymentInfo); + var result = this.PlaceOrder(paymentInfo, new Dictionary()); + if (result.Success) { if (result.PlacedOrder == null) - throw new SmartException("Placed order could not be loaded"); + throw new SmartException(T("Order.NotFound", "".NaIfEmpty())); - var rph = new RecurringPaymentHistory() + var rph = new RecurringPaymentHistory { RecurringPayment = recurringPayment, CreatedOnUtc = DateTime.UtcNow, - OrderId = result.PlacedOrder.Id, + OrderId = result.PlacedOrder.Id }; + recurringPayment.RecurringPaymentHistory.Add(rph); _orderService.UpdateRecurringPayment(recurringPayment); } - else - { - string error = ""; - for (int i = 0; i < result.Errors.Count; i++) - { - error += string.Format("Error {0}: {1}", i, result.Errors[i]); - if (i != result.Errors.Count - 1) - error += ". "; - } - throw new SmartException(error); + else if (result.Errors.Count > 0) + { + throw new SmartException(string.Join(" ", result.Errors)); } } - catch (Exception exc) + catch (Exception exception) { - _logger.Error(string.Format("Error while processing recurring order. {0}", exc.Message), exc); + _logger.ErrorsAll(exception); throw; } } @@ -1564,69 +1549,42 @@ public virtual IList CancelRecurringPayment(RecurringPayment recurringPa var initialOrder = recurringPayment.InitialOrder; if (initialOrder == null) - return new List() { "Initial order could not be loaded" }; - + return new List { T("Order.InitialOrderDoesNotExistForRecurringPayment") }; var request = new CancelRecurringPaymentRequest(); CancelRecurringPaymentResult result = null; + try { request.Order = initialOrder; - result = _paymentService.CancelRecurringPayment(request); + + result = _paymentService.CancelRecurringPayment(request); + if (result.Success) { //update recurring payment recurringPayment.IsActive = false; _orderService.UpdateRecurringPayment(recurringPayment); - - //add a note - initialOrder.OrderNotes.Add(new OrderNote() - { - Note = T("RecurringPaymentCancelled"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(initialOrder); + _orderService.AddOrderNote(initialOrder, T("Admin.OrderNotice.RecurringPaymentCancelled")); //notify a store owner - _workflowMessageService - .SendRecurringPaymentCancelledStoreOwnerNotification(recurringPayment, - _localizationSettings.DefaultAdminLanguageId); + _workflowMessageService.SendRecurringPaymentCancelledStoreOwnerNotification(recurringPayment, _localizationSettings.DefaultAdminLanguageId); } } - catch (Exception exc) + catch (Exception exception) { - if (result == null) - result = new CancelRecurringPaymentResult(); - result.AddError(string.Format("Error: {0}. Full exception: {1}", exc.Message, exc.ToString())); + if (result == null) + { + result = new CancelRecurringPaymentResult(); + } + + result.AddError(exception.ToAllMessages()); } + ProcessErrors(initialOrder, result.Errors, "Admin.OrderNotice.RecurringPaymentCancellationError"); - //process errors - string error = ""; - for (int i = 0; i < result.Errors.Count; i++) - { - error += string.Format("Error {0}: {1}", i, result.Errors[i]); - if (i != result.Errors.Count - 1) - error += ". "; - } - if (!String.IsNullOrEmpty(error)) - { - //add a note - initialOrder.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("RecurringPaymentCancellationError"), error), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(initialOrder); - - //log it - string logError = string.Format("Error cancelling recurring payment. Order #{0}. Error: {1}", initialOrder.Id, error); - _logger.InsertLog(LogLevel.Error, logError, logError); - } - return result.Errors; + return result.Errors; } /// @@ -1680,10 +1638,10 @@ public virtual void Ship(Shipment shipment, bool notifyCustomer) var order = _orderService.GetOrderById(shipment.OrderId); if (order == null) - throw new Exception("Order cannot be loaded"); + throw new SmartException(T("Order.NotFound", shipment.OrderId)); if (shipment.ShippedDateUtc.HasValue) - throw new Exception("This shipment is already shipped"); + throw new SmartException(T("Shipment.AlreadyShipped")); shipment.ShippedDateUtc = DateTime.UtcNow; _shipmentService.UpdateShipment(shipment); @@ -1693,30 +1651,18 @@ public virtual void Ship(Shipment shipment, bool notifyCustomer) order.ShippingStatusId = (int)ShippingStatus.PartiallyShipped; else order.ShippingStatusId = (int)ShippingStatus.Shipped; - _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("ShipmentSent"), shipment.Id), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.ShipmentSent", shipment.Id)); + if (notifyCustomer) { //notify customer int queuedEmailId = _workflowMessageService.SendShipmentSentCustomerNotification(shipment, order.CustomerLanguageId); if (queuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("CustomerShippedEmailQueued"), queuedEmailId), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.CustomerShippedEmailQueued", queuedEmailId)); } } @@ -1736,40 +1682,30 @@ public virtual void Deliver(Shipment shipment, bool notifyCustomer) var order = shipment.Order; if (order == null) - throw new Exception("Order cannot be loaded"); + throw new SmartException(T("Order.NotFound", shipment.OrderId)); - if (shipment.DeliveryDateUtc.HasValue) - throw new Exception("This shipment is already delivered"); + if (shipment.DeliveryDateUtc.HasValue) + throw new SmartException(T("Shipment.AlreadyDelivered")); shipment.DeliveryDateUtc = DateTime.UtcNow; _shipmentService.UpdateShipment(shipment); - if (!order.HasItemsToAddToShipment() && !order.HasItemsToShip() && !order.HasItemsToDeliver()) - order.ShippingStatusId = (int)ShippingStatus.Delivered; - _orderService.UpdateOrder(order); + if (!order.HasItemsToAddToShipment() && !order.HasItemsToShip() && !order.HasItemsToDeliver()) + { + order.ShippingStatusId = (int)ShippingStatus.Delivered; + } - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("ShipmentDelivered"), shipment.Id), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.ShipmentDelivered", shipment.Id)); + if (notifyCustomer) { //send email notification int queuedEmailId = _workflowMessageService.SendShipmentDeliveredCustomerNotification(shipment, order.CustomerLanguageId); if (queuedEmailId > 0) { - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("CustomerDeliveredEmailQueued"), queuedEmailId), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.CustomerDeliveredEmailQueued", queuedEmailId)); } } @@ -1806,19 +1742,12 @@ public virtual void CancelOrder(Order order, bool notifyCustomer) throw new ArgumentNullException("order"); if (!CanCancelOrder(order)) - throw new SmartException("Cannot do cancel for order."); + throw new SmartException(T("Order.CannotCancel")); //Cancel order SetOrderStatus(order, OrderStatus.Cancelled, notifyCustomer); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderCancelled"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderCancelled")); //cancel recurring payments var recurringPayments = _orderService.SearchRecurringPayments(0, 0, order.Id, null); @@ -1836,79 +1765,63 @@ public virtual void CancelOrder(Order order, bool notifyCustomer) } /// - /// Cancel an order item + /// Auto update order details /// - /// Cancel order item context - public virtual void CancelOrderItem(CancelOrderItemContext context) + /// Context parameters + public virtual void AutoUpdateOrderDetails(AutoUpdateOrderItemContext context) { - if (context == null) - throw new ArgumentNullException("context"); - - OrderItem oi = context.OrderItem; - int cancelQuantity = 0; - - if (oi == null && context.ReturnRequest != null) - oi = _orderService.GetOrderItemById(context.ReturnRequest.OrderItemId); + var oi = context.OrderItem; - if (context.ReturnRequest == null) - cancelQuantity = oi.Quantity; - else - cancelQuantity = (context.ReturnRequest.Quantity > oi.Quantity ? oi.Quantity : context.ReturnRequest.Quantity); - - context.InventoryOld = context.InventoryNew = oi.Product.StockQuantity; context.RewardPointsOld = context.RewardPointsNew = oi.Order.Customer.GetRewardPointsBalance(); - if (cancelQuantity <= 0) - return; - - int newQuantity = Math.Max(oi.Quantity - cancelQuantity, 0); - - decimal reduceFactor = (decimal)newQuantity / (decimal)oi.Quantity; - - decimal priceInclTax = newQuantity * oi.UnitPriceInclTax; - decimal priceExclTax = newQuantity * oi.UnitPriceExclTax; - - decimal deltaPriceInclTax = Math.Max(oi.PriceInclTax - priceInclTax, 0); - decimal deltaPriceExclTax = Math.Max(oi.PriceExclTax - priceExclTax, 0); + if (context.UpdateTotals && oi.Order.OrderStatusId <= (int)OrderStatus.Pending) + { + decimal priceInclTax = Round(context.QuantityNew * oi.UnitPriceInclTax); + decimal priceExclTax = Round(context.QuantityNew * oi.UnitPriceExclTax); - //oi.PriceInclTax = Round(priceInclTax); - //oi.PriceExclTax = Round(priceExclTax); + decimal deltaPriceInclTax = priceInclTax - (context.IsNewOrderItem ? decimal.Zero : oi.PriceInclTax); + decimal deltaPriceExclTax = priceExclTax - (context.IsNewOrderItem ? decimal.Zero : oi.PriceExclTax); - //decimal discountInclTax = oi.DiscountAmountInclTax * reduceFactor; - //decimal discountExclTax = oi.DiscountAmountExclTax * reduceFactor; + oi.Quantity = context.QuantityNew; + oi.PriceInclTax = Round(priceInclTax); + oi.PriceExclTax = Round(priceExclTax); - //decimal deltaDiscountInclTax = Math.Max(oi.DiscountAmountInclTax - discountInclTax, 0); - //decimal deltaDiscountExclTax = Math.Max(oi.DiscountAmountExclTax - discountExclTax, 0); + decimal subtotalInclTax = oi.Order.OrderSubtotalInclTax + deltaPriceInclTax; + decimal subtotalExclTax = oi.Order.OrderSubtotalExclTax + deltaPriceExclTax; - //oi.DiscountAmountInclTax = Round(discountInclTax); - //oi.DiscountAmountExclTax = Round(discountExclTax); + oi.Order.OrderSubtotalInclTax = Round(subtotalInclTax); + oi.Order.OrderSubtotalExclTax = Round(subtotalExclTax); - //oi.Quantity = newQuantity; + decimal discountInclTax = oi.DiscountAmountInclTax * context.QuantityChangeFactor; + decimal discountExclTax = oi.DiscountAmountExclTax * context.QuantityChangeFactor; - //// update order (OrderTotal and OrderDiscout always includes tax) - //decimal subtotalInclTax = Math.Max(oi.Order.OrderSubtotalInclTax - deltaPriceInclTax, 0); - //decimal subtotalExclTax = Math.Max(oi.Order.OrderSubtotalExclTax - deltaPriceExclTax, 0); + decimal deltaDiscountInclTax = discountInclTax - oi.DiscountAmountInclTax; + decimal deltaDiscountExclTax = discountExclTax - oi.DiscountAmountExclTax; - //oi.Order.OrderSubtotalInclTax = Round(subtotalInclTax); - //oi.Order.OrderSubtotalExclTax = Round(subtotalExclTax); + oi.DiscountAmountInclTax = Round(discountInclTax); + oi.DiscountAmountExclTax = Round(discountExclTax); - //decimal total = Math.Max(oi.Order.OrderTotal - deltaPriceInclTax, 0); - //decimal tax = Math.Max(oi.Order.OrderTax - (deltaPriceInclTax - deltaPriceExclTax), 0); + decimal total = Math.Max(oi.Order.OrderTotal + deltaPriceInclTax, 0); + decimal tax = Math.Max(oi.Order.OrderTax + (deltaPriceInclTax - deltaPriceExclTax), 0); - //oi.Order.OrderTotal = Round(total); - //oi.Order.OrderTax = Round(tax); + oi.Order.OrderTotal = Round(total); + oi.Order.OrderTax = Round(tax); - //_orderService.UpdateOrder(oi.Order); + _orderService.UpdateOrder(oi.Order); + } - if (context.AdjustInventory) + if (context.AdjustInventory && context.QuantityDelta != 0) { - _productService.AdjustInventory(oi, false, cancelQuantity); - context.InventoryNew = oi.Product.StockQuantity; + context.Inventory = _productService.AdjustInventory(oi, context.QuantityDelta > 0, Math.Abs(context.QuantityDelta)); } - if (context.ReduceRewardPoints) + if (context.UpdateRewardPoints && context.QuantityDelta < 0) { - ReduceRewardPoints(oi.Order, deltaPriceInclTax); + // we reduce but we do not award points subsequently. they can be awarded once per order anyway (see Order.RewardPointsWereAdded). + // UpdateRewardPoints only visible for unpending orders (see RewardPointsSettingsValidator). + // note: reducing can of cource only work if oi.UnitPriceExclTax has not been changed! + decimal reduceAmount = Math.Abs(context.QuantityDelta) * oi.UnitPriceInclTax; + ReduceRewardPoints(oi.Order, reduceAmount); context.RewardPointsNew = oi.Order.Customer.GetRewardPointsBalance(); } } @@ -1945,14 +1858,7 @@ public virtual void MarkAsAuthorized(Order order) order.PaymentStatusId = (int)PaymentStatus.Authorized; _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderMarkedAsAuthorized"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderMarkedAsAuthorized")); //check order status CheckOrderStatus(order); @@ -1979,7 +1885,7 @@ public virtual bool CanCompleteOrder(Order order) public virtual void CompleteOrder(Order order) { if (!CanCompleteOrder(order)) - throw new SmartException("You can't mark this order as completed"); + throw new SmartException(T("Order.CannotMarkCompleted")); if (CanMarkOrderAsPaid(order)) { @@ -2007,12 +1913,10 @@ public virtual bool CanCapture(Order order) if (order == null) throw new ArgumentNullException("order"); - if (order.OrderStatus == OrderStatus.Cancelled || - order.OrderStatus == OrderStatus.Pending) + if (order.OrderStatus == OrderStatus.Cancelled || order.OrderStatus == OrderStatus.Pending) return false; - if (order.PaymentStatus == PaymentStatus.Authorized && - _paymentService.SupportCapture(order.PaymentMethodSystemName)) + if (order.PaymentStatus == PaymentStatus.Authorized && _paymentService.SupportCapture(order.PaymentMethodSystemName)) return true; return false; @@ -2029,7 +1933,7 @@ public virtual IList Capture(Order order) throw new ArgumentNullException("order"); if (!CanCapture(order)) - throw new SmartException("Cannot do capture for order."); + throw new SmartException(T("Order.CannotCapture")); var request = new CapturePaymentRequest(); CapturePaymentResult result = null; @@ -2042,24 +1946,20 @@ public virtual IList Capture(Order order) if (result.Success) { var paidDate = order.PaidDateUtc; - if (result.NewPaymentStatus == PaymentStatus.Paid) - paidDate = DateTime.UtcNow; + if (result.NewPaymentStatus == PaymentStatus.Paid) + { + paidDate = DateTime.UtcNow; + } order.CaptureTransactionId = result.CaptureTransactionId; order.CaptureTransactionResult = result.CaptureTransactionResult; order.PaymentStatus = result.NewPaymentStatus; order.PaidDateUtc = paidDate; - _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderCaptured"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderCaptured")); + CheckOrderStatus(order); //raise event @@ -2069,38 +1969,19 @@ public virtual IList Capture(Order order) } } } - catch (Exception exc) + catch (Exception exception) { - if (result == null) - result = new CapturePaymentResult(); - result.AddError(string.Format("Error: {0}. Full exception: {1}", exc.Message, exc.ToString())); - } + if (result == null) + { + result = new CapturePaymentResult(); + } + result.AddError(exception.ToAllMessages()); + } - //process errors - string error = ""; - for (int i = 0; i < result.Errors.Count; i++) - { - error += string.Format("Error {0}: {1}", i, result.Errors[i]); - if (i != result.Errors.Count - 1) - error += ". "; - } - if (!String.IsNullOrEmpty(error)) - { - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format("Unable to capture order. {0}", error), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + ProcessErrors(order, result.Errors, "Admin.OrderNotice.OrderCaptureError"); - //log it - string logError = string.Format(T("OrderCaptureError"), order.GetOrderNumber(), error); - _logger.InsertLog(LogLevel.Error, logError, logError); - } - return result.Errors; + return result.Errors; } /// @@ -2134,24 +2015,18 @@ public virtual void MarkOrderAsPaid(Order order) throw new ArgumentNullException("order"); if (!CanMarkOrderAsPaid(order)) - throw new SmartException("You can't mark this order as paid"); + throw new SmartException(T("Order.CannotMarkPaid")); order.PaymentStatusId = (int)PaymentStatus.Paid; order.PaidDateUtc = DateTime.UtcNow; - _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderMarkedAsPaid"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + _orderService.UpdateOrder(order); + + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderMarkedAsPaid")); CheckOrderStatus(order); - //raise event + // raise event if (order.PaymentStatus == PaymentStatus.Paid) { _eventPublisher.PublishOrderPaid(order); @@ -2195,7 +2070,7 @@ public virtual IList Refund(Order order) throw new ArgumentNullException("order"); if (!CanRefund(order)) - throw new SmartException("Cannot do refund for order."); + throw new SmartException(T("Order.CannotRefund")); var request = new RefundPaymentRequest(); RefundPaymentResult result = null; @@ -2204,7 +2079,9 @@ public virtual IList Refund(Order order) request.Order = order; request.AmountToRefund = order.OrderTotal; request.IsPartialRefund = false; - result = _paymentService.Refund(request); + + result = _paymentService.Refund(request); + if (result.Success) { //total amount refunded @@ -2213,53 +2090,29 @@ public virtual IList Refund(Order order) //update order info order.RefundedAmount = totalAmountRefunded; order.PaymentStatus = result.NewPaymentStatus; - _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderRefunded"), _priceFormatter.FormatPrice(request.AmountToRefund, true, false)), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderRefunded", _priceFormatter.FormatPrice(request.AmountToRefund, true, false))); + //check order status CheckOrderStatus(order); } } - catch (Exception exc) + catch (Exception exception) { - if (result == null) - result = new RefundPaymentResult(); - result.AddError(string.Format("Error: {0}. Full exception: {1}", exc.Message, exc.ToString())); - } + if (result == null) + { + result = new RefundPaymentResult(); + } - //process errors - string error = ""; - for (int i = 0; i < result.Errors.Count; i++) - { - error += string.Format("Error {0}: {1}", i, result.Errors[i]); - if (i != result.Errors.Count - 1) - error += ". "; + result.AddError(exception.ToAllMessages()); } - if (!String.IsNullOrEmpty(error)) - { - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderRefundError"), error), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); - //log it - string logError = string.Format("Error refunding order '{0}'. Error: {1}", order.GetOrderNumber(), error); - _logger.InsertLog(LogLevel.Error, logError, logError); - } - return result.Errors; + ProcessErrors(order, result.Errors, "Admin.OrderNotice.OrderRefundError"); + + return result.Errors; } /// @@ -2295,7 +2148,7 @@ public virtual void RefundOffline(Order order) throw new ArgumentNullException("order"); if (!CanRefundOffline(order)) - throw new SmartException("You can't refund this order"); + throw new SmartException(T("Order.CannotRefund")); //amout to refund decimal amountToRefund = order.OrderTotal; @@ -2306,17 +2159,11 @@ public virtual void RefundOffline(Order order) //update order info order.RefundedAmount = totalAmountRefunded; order.PaymentStatus = PaymentStatus.Refunded; - _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderMarkedAsRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderMarkedAsRefunded", _priceFormatter.FormatPrice(amountToRefund, true, false))); + //check order status CheckOrderStatus(order); } @@ -2366,10 +2213,11 @@ public virtual IList PartiallyRefund(Order order, decimal amountToRefund throw new ArgumentNullException("order"); if (!CanPartiallyRefund(order, amountToRefund)) - throw new SmartException("Cannot do partial refund for order."); + throw new SmartException(T("Order.CannotPartialRefund")); var request = new RefundPaymentRequest(); RefundPaymentResult result = null; + try { request.Order = order; @@ -2386,53 +2234,28 @@ public virtual IList PartiallyRefund(Order order, decimal amountToRefund //update order info order.RefundedAmount = totalAmountRefunded; order.PaymentStatus = result.NewPaymentStatus; - _orderService.UpdateOrder(order); - - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderPartiallyRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderPartiallyRefunded", _priceFormatter.FormatPrice(amountToRefund, true, false))); + //check order status CheckOrderStatus(order); } } - catch (Exception exc) + catch (Exception exception) { - if (result == null) - result = new RefundPaymentResult(); - result.AddError(string.Format("Error: {0}. Full exception: {1}", exc.Message, exc.ToString())); - } + if (result == null) + { + result = new RefundPaymentResult(); + } - //process errors - string error = ""; - for (int i = 0; i < result.Errors.Count; i++) - { - error += string.Format("Error {0}: {1}", i, result.Errors[i]); - if (i != result.Errors.Count - 1) - error += ". "; - } - if (!String.IsNullOrEmpty(error)) - { - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderPartiallyRefundError"), error), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + result.AddError(exception.ToAllMessages()); + } - //log it - string logError = string.Format("Error refunding order '{0}'. Error: {1}", order.GetOrderNumber(), error); - _logger.InsertLog(LogLevel.Error, logError, logError); - } - return result.Errors; + ProcessErrors(order, result.Errors, "Admin.OrderNotice.OrderPartiallyRefundError"); + + return result.Errors; } /// @@ -2478,7 +2301,7 @@ public virtual void PartiallyRefundOffline(Order order, decimal amountToRefund) throw new ArgumentNullException("order"); if (!CanPartiallyRefundOffline(order, amountToRefund)) - throw new SmartException("You can't partially refund (offline) this order"); + throw new SmartException(T("Order.CannotPartialRefund")); //total amount refunded decimal totalAmountRefunded = order.RefundedAmount + amountToRefund; @@ -2487,17 +2310,11 @@ public virtual void PartiallyRefundOffline(Order order, decimal amountToRefund) order.RefundedAmount = totalAmountRefunded; //if (order.OrderTotal == totalAmountRefunded), then set order.PaymentStatus = PaymentStatus.Refunded; order.PaymentStatus = PaymentStatus.PartiallyRefunded; - _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderMarkedAsPartiallyRefunded"), _priceFormatter.FormatPrice(amountToRefund, true, false)), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderMarkedAsPartiallyRefunded", _priceFormatter.FormatPrice(amountToRefund, true, false))); + //check order status CheckOrderStatus(order); } @@ -2539,10 +2356,11 @@ public virtual IList Void(Order order) throw new ArgumentNullException("order"); if (!CanVoid(order)) - throw new SmartException("Cannot do void for order."); + throw new SmartException(T("Order.CannotVoid")); var request = new VoidPaymentRequest(); VoidPaymentResult result = null; + try { request.Order = order; @@ -2552,51 +2370,27 @@ public virtual IList Void(Order order) { //update order info order.PaymentStatus = result.NewPaymentStatus; - _orderService.UpdateOrder(order); - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderVoided"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderVoided")); + //check order status CheckOrderStatus(order); } } - catch (Exception exc) + catch (Exception exception) { - if (result == null) - result = new VoidPaymentResult(); - result.AddError(string.Format("Error: {0}. Full exception: {1}", exc.Message, exc.ToString())); - } + if (result == null) + { + result = new VoidPaymentResult(); + } - //process errors - string error = ""; - for (int i = 0; i < result.Errors.Count; i++) - { - error += string.Format("Error {0}: {1}", i, result.Errors[i]); - if (i != result.Errors.Count - 1) - error += ". "; - } - if (!String.IsNullOrEmpty(error)) - { - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = string.Format(T("OrderVoidError"), error), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); + result.AddError(exception.ToAllMessages()); + } + + ProcessErrors(order, result.Errors, "Admin.OrderNotice.OrderVoidError"); - //log it - string logError = string.Format("Error voiding order '{0}'. Error: {1}", order.GetOrderNumber(), error); - _logger.InsertLog(LogLevel.Error, logError, logError); - } return result.Errors; } @@ -2633,20 +2427,14 @@ public virtual void VoidOffline(Order order) throw new ArgumentNullException("order"); if (!CanVoidOffline(order)) - throw new SmartException("You can't void this order"); + throw new SmartException(T("Order.CannotVoid")); - order.PaymentStatusId = (int)PaymentStatus.Voided; - _orderService.UpdateOrder(order); + order.PaymentStatusId = (int)PaymentStatus.Voided; - //add a note - order.OrderNotes.Add(new OrderNote() - { - Note = T("OrderMarkedAsVoided"), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); _orderService.UpdateOrder(order); + _orderService.AddOrderNote(order, T("Admin.OrderNotice.OrderMarkedAsVoided")); + //check orer status CheckOrderStatus(order); } @@ -2662,28 +2450,28 @@ public virtual void ReOrder(Order order) if (order == null) throw new ArgumentNullException("order"); - int parentItemId, childItemId; - foreach (var orderItem in order.OrderItems) { - bool isBundle = (orderItem.Product.ProductType == ProductType.BundledProduct); + var isBundle = (orderItem.Product.ProductType == ProductType.BundledProduct); - var warnings =_shoppingCartService.AddToCart(orderItem.Order.Customer, orderItem.Product, ShoppingCartType.ShoppingCart, orderItem.Order.StoreId, - orderItem.AttributesXml, isBundle ? decimal.Zero : orderItem.UnitPriceExclTax, orderItem.Quantity, false, out parentItemId); + var addToCartContext = new AddToCartContext(); - if (isBundle && orderItem.BundleData.HasValue() && warnings.Count <= 0) + addToCartContext.Warnings = _shoppingCartService.AddToCart(order.Customer, orderItem.Product, ShoppingCartType.ShoppingCart, order.StoreId, + orderItem.AttributesXml, isBundle ? decimal.Zero : orderItem.UnitPriceExclTax, orderItem.Quantity, false, addToCartContext); + + if (isBundle && orderItem.BundleData.HasValue() && addToCartContext.Warnings.Count == 0) { foreach (var bundleData in orderItem.GetBundleData()) { var bundleItem = _productService.GetBundleItemById(bundleData.BundleItemId); + addToCartContext.BundleItem = bundleItem; - warnings =_shoppingCartService.AddToCart(orderItem.Order.Customer, bundleItem.Product, ShoppingCartType.ShoppingCart, - orderItem.Order.StoreId, bundleData.AttributesXml, decimal.Zero, bundleData.Quantity, false, out childItemId, parentItemId, bundleItem); - - if (warnings.Count > 0) - _shoppingCartService.DeleteShoppingCartItem(parentItemId); + addToCartContext.Warnings = _shoppingCartService.AddToCart(order.Customer, bundleItem.Product, ShoppingCartType.ShoppingCart, order.StoreId, + bundleData.AttributesXml, decimal.Zero, bundleData.Quantity, false, addToCartContext); } } + + _shoppingCartService.AddToCartStoring(addToCartContext); } } @@ -2703,7 +2491,8 @@ public virtual bool IsReturnRequestAllowed(Order order) if (order.OrderStatus != OrderStatus.Complete) return false; - bool numberOfDaysReturnRequestAvailableValid = false; + var numberOfDaysReturnRequestAvailableValid = false; + if (_orderSettings.NumberOfDaysReturnRequestAvailable == 0) { numberOfDaysReturnRequestAvailableValid = true; @@ -2730,14 +2519,13 @@ public virtual bool ValidateMinOrderSubtotalAmount(IList 0 && _orderSettings.MinOrderSubtotalAmount > decimal.Zero) { - //subtotal decimal orderSubTotalDiscountAmountBase = decimal.Zero; Discount orderSubTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; + _orderTotalCalculationService.GetShoppingCartSubTotal(cart, - out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, - out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); + out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); if (subTotalWithoutDiscountBase < _orderSettings.MinOrderSubtotalAmount) return false; @@ -2759,6 +2547,7 @@ public virtual bool ValidateMinOrderTotalAmount(IList if (cart.Count > 0 && _orderSettings.MinOrderTotalAmount > decimal.Zero) { decimal? shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart); + if (shoppingCartTotalBase.HasValue && shoppingCartTotalBase.Value < _orderSettings.MinOrderTotalAmount) return false; } @@ -2766,6 +2555,80 @@ public virtual bool ValidateMinOrderTotalAmount(IList return true; } + public virtual Shipment AddShipment(Order order, string trackingNumber, Dictionary quantities) + { + Guard.ArgumentNotNull(() => order); + + Shipment shipment = null; + decimal? totalWeight = null; + + foreach (var orderItem in order.OrderItems) + { + if (!orderItem.Product.IsShipEnabled) + continue; + + //ensure that this product can be shipped (have at least one item to ship) + var maxQtyToAdd = orderItem.GetTotalNumberOfItemsCanBeAddedToShipment(); + if (maxQtyToAdd <= 0) + continue; + + var qtyToAdd = 0; + + if (quantities != null && quantities.ContainsKey(orderItem.Id)) + qtyToAdd = quantities[orderItem.Id]; + else if (quantities == null) + qtyToAdd = maxQtyToAdd; + + if (qtyToAdd <= 0) + continue; + + if (qtyToAdd > maxQtyToAdd) + qtyToAdd = maxQtyToAdd; + + var orderItemTotalWeight = orderItem.ItemWeight.HasValue ? orderItem.ItemWeight * qtyToAdd : null; + if (orderItemTotalWeight.HasValue) + { + if (!totalWeight.HasValue) + totalWeight = 0; + + totalWeight += orderItemTotalWeight.Value; + } + + if (shipment == null) + { + shipment = new Shipment + { + OrderId = order.Id, + Order = order, // otherwise order updated event would not be fired during InsertShipment + TrackingNumber = trackingNumber, + TotalWeight = null, + ShippedDateUtc = null, + DeliveryDateUtc = null, + CreatedOnUtc = DateTime.UtcNow, + }; + } + + var shipmentItem = new ShipmentItem + { + OrderItemId = orderItem.Id, + Quantity = qtyToAdd + }; + + shipment.ShipmentItems.Add(shipmentItem); + } + + if (shipment != null && shipment.ShipmentItems.Count > 0) + { + shipment.TotalWeight = totalWeight; + + _shipmentService.InsertShipment(shipment); + + return shipment; + } + + return null; + } + #endregion } } diff --git a/src/Libraries/SmartStore.Services/Orders/OrderReportService.cs b/src/Libraries/SmartStore.Services/Orders/OrderReportService.cs index 72c75822bb..f98d7292f0 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderReportService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderReportService.cs @@ -264,25 +264,15 @@ group orderItem by orderItem.ProductId into g return result; } - /// - /// Gets a list of products purchased by other customers who purchased the above - /// - /// Store identifier - /// Product identifier - /// Records to return - /// A value indicating whether to show hidden records - /// Product collection - public virtual IList GetProductsAlsoPurchasedById(int storeId, int productId, - int recordsToReturn = 5, bool showHidden = false) + public virtual int[] GetAlsoPurchasedProductsIds(int storeId, int productId, int recordsToReturn = 5, bool showHidden = false) { if (productId == 0) throw new ArgumentException("Product ID is not specified"); //this inner query should retrieve all orders that have contained the productID - var query1 = (from orderItem in _orderItemRepository.Table - join p in _productRepository.Table on orderItem.ProductId equals p.Id - where p.Id == productId - select orderItem.OrderId).Distinct(); + var query1 = from orderItem in _orderItemRepository.Table + where orderItem.ProductId == productId + select orderItem.OrderId; var query2 = from orderItem in _orderItemRepository.Table join p in _productRepository.Table on orderItem.ProductId equals p.Id @@ -304,15 +294,16 @@ group orderItem_p by orderItem_p.p.Id into g }; query3 = query3.OrderByDescending(x => x.ProductsPurchased); - if (recordsToReturn > 0) - query3 = query3.Take(recordsToReturn); + if (recordsToReturn > 0) + query3 = query3.Take(recordsToReturn); + + var report = query3.ToList(); - var report = query3.ToList(); - var products = new List(); - foreach (var reportLine in report) - products.Add(_productService.GetProductById(reportLine.ProductId)); + var ids = new List(); + foreach (var line in report) + ids.Add(line.ProductId); - return products; + return ids.ToArray(); } /// diff --git a/src/Libraries/SmartStore.Services/Orders/OrderService.cs b/src/Libraries/SmartStore.Services/Orders/OrderService.cs index c707783e9d..7ed45bb61a 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; @@ -12,10 +13,10 @@ namespace SmartStore.Services.Orders { - /// - /// Order service - /// - public partial class OrderService : IOrderService + /// + /// Order service + /// + public partial class OrderService : IOrderService { #region Fields @@ -152,7 +153,7 @@ public virtual Order GetOrderByGuid(Guid orderGuid) /// Order entity public virtual Order GetOrderByPaymentAuthorization(string paymentMethodSystemName, string authorizationTransactionId) { - if (paymentMethodSystemName.IsNullOrEmpty() || authorizationTransactionId.IsNullOrEmpty()) + if (paymentMethodSystemName.IsEmpty() || authorizationTransactionId.IsEmpty()) return null; var query = @@ -171,7 +172,7 @@ from o in _orderRepository.Table /// Order entity public virtual Order GetOrderByPaymentCapture(string paymentMethodSystemName, string captureTransactionId) { - if (paymentMethodSystemName.IsNullOrEmpty() || captureTransactionId.IsNullOrEmpty()) + if (paymentMethodSystemName.IsEmpty() || captureTransactionId.IsEmpty()) return null; var query = @@ -182,18 +183,59 @@ from o in _orderRepository.Table return query.FirstOrDefault(); } - /// - /// Deletes an order - /// - /// The order - public virtual void DeleteOrder(Order order) - { - if (order == null) - throw new ArgumentNullException("order"); + public virtual IQueryable GetOrders( + int storeId, + int customerId, + DateTime? startTime, + DateTime? endTime, + int[] orderStatusIds, + int[] paymentStatusIds, + int[] shippingStatusIds, + string billingEmail, + string orderNumber, + string billingName = null) + { + var query = _orderRepository.Table; - order.Deleted = true; - UpdateOrder(order); - } + if (storeId > 0) + query = query.Where(x => x.StoreId == storeId); + + if (customerId > 0) + query = query.Where(x => x.CustomerId == customerId); + + if (startTime.HasValue) + query = query.Where(x => startTime.Value <= x.CreatedOnUtc); + + if (endTime.HasValue) + query = query.Where(x => endTime.Value >= x.CreatedOnUtc); + + if (billingEmail.HasValue()) + query = query.Where(x => x.BillingAddress != null && !String.IsNullOrEmpty(x.BillingAddress.Email) && x.BillingAddress.Email.Contains(billingEmail)); + + if (billingName.HasValue()) + { + query = query.Where(x => x.BillingAddress != null && ( + (!String.IsNullOrEmpty(x.BillingAddress.LastName) && x.BillingAddress.LastName.Contains(billingName)) || + (!String.IsNullOrEmpty(x.BillingAddress.FirstName) && x.BillingAddress.FirstName.Contains(billingName)) + )); + } + + if (orderNumber.HasValue()) + query = query.Where(x => x.OrderNumber.ToLower().Contains(orderNumber.ToLower())); + + if (orderStatusIds != null && orderStatusIds.Count() > 0) + query = query.Where(x => orderStatusIds.Contains(x.OrderStatusId)); + + if (paymentStatusIds != null && paymentStatusIds.Count() > 0) + query = query.Where(x => paymentStatusIds.Contains(x.PaymentStatusId)); + + if (shippingStatusIds != null && shippingStatusIds.Count() > 0) + query = query.Where(x => shippingStatusIds.Contains(x.ShippingStatusId)); + + query = query.Where(x => !x.Deleted); + + return query; + } /// /// Search orders @@ -216,44 +258,17 @@ public virtual IPagedList SearchOrders(int storeId, int customerId, DateT int[] orderStatusIds, int[] paymentStatusIds, int[] shippingStatusIds, string billingEmail, string orderGuid, string orderNumber, int pageIndex, int pageSize, string billingName = null) { - var query = _orderRepository.Table; - - if (storeId > 0) - query = query.Where(o => o.StoreId == storeId); - if (customerId > 0) - query = query.Where(o => o.CustomerId == customerId); - if (startTime.HasValue) - query = query.Where(o => startTime.Value <= o.CreatedOnUtc); - if (endTime.HasValue) - query = query.Where(o => endTime.Value >= o.CreatedOnUtc); - if (!String.IsNullOrEmpty(billingEmail)) - query = query.Where(o => o.BillingAddress != null && !String.IsNullOrEmpty(o.BillingAddress.Email) && o.BillingAddress.Email.Contains(billingEmail)); - if (billingName.HasValue()) - query = query.Where(o => o.BillingAddress != null && ( - (!String.IsNullOrEmpty(o.BillingAddress.LastName) && o.BillingAddress.LastName.Contains(billingName)) || - (!String.IsNullOrEmpty(o.BillingAddress.FirstName) && o.BillingAddress.FirstName.Contains(billingName)) - )); - if (orderNumber.HasValue()) - query = query.Where(o => o.OrderNumber.ToLower().Contains(orderNumber.ToLower())); + var query = GetOrders(storeId, customerId, startTime, endTime, orderStatusIds, paymentStatusIds, shippingStatusIds, + billingEmail, orderNumber, billingName); - if (orderStatusIds != null && orderStatusIds.Count() > 0) - query = query.Where(x => orderStatusIds.Contains(x.OrderStatusId)); + query = query.OrderByDescending(x => x.CreatedOnUtc); - if (paymentStatusIds != null && paymentStatusIds.Count() > 0) - query = query.Where(x => paymentStatusIds.Contains(x.PaymentStatusId)); - - if (shippingStatusIds != null && shippingStatusIds.Count() > 0) - query = query.Where(x => shippingStatusIds.Contains(x.ShippingStatusId)); - - query = query.Where(o => !o.Deleted); - query = query.OrderByDescending(o => o.CreatedOnUtc); - - - if (!String.IsNullOrEmpty(orderGuid)) + if (orderGuid.HasValue()) { //filter by GUID. Filter in BLL because EF doesn't support casting of GUID to string var orders = query.ToList(); - orders = orders.FindAll(o => o.OrderGuid.ToString().ToLowerInvariant().Contains(orderGuid.ToLowerInvariant())); + orders = orders.FindAll(x => x.OrderGuid.ToString().ToLowerInvariant().Contains(orderGuid.ToLowerInvariant())); + return new PagedList(orders, pageIndex, pageSize); } else @@ -338,6 +353,19 @@ public virtual void UpdateOrder(Order order) _eventPublisher.PublishOrderUpdated(order); } + /// + /// Deletes an order + /// + /// The order + public virtual void DeleteOrder(Order order) + { + if (order == null) + throw new ArgumentNullException("order"); + + order.Deleted = true; + UpdateOrder(order); + } + /// /// Deletes an order note /// @@ -364,8 +392,7 @@ public virtual void DeleteOrderNote(OrderNote orderNote) /// Authorization transaction ID /// Payment method system name /// Order - public virtual Order GetOrderByAuthorizationTransactionIdAndPaymentMethod(string authorizationTransactionId, - string paymentMethodSystemName) + public virtual Order GetOrderByAuthorizationTransactionIdAndPaymentMethod(string authorizationTransactionId, string paymentMethodSystemName) { var query = _orderRepository.Table; if (!String.IsNullOrWhiteSpace(authorizationTransactionId)) @@ -378,17 +405,32 @@ public virtual Order GetOrderByAuthorizationTransactionIdAndPaymentMethod(string var order = query.FirstOrDefault(); return order; } - - #endregion - - #region Order items - /// - /// Gets an Order item - /// - /// Order item identifier - /// Order item - public virtual OrderItem GetOrderItemById(int orderItemId) + public virtual void AddOrderNote(Order order, string note, bool displayToCustomer = false) + { + if (order != null && note.HasValue()) + { + order.OrderNotes.Add(new OrderNote + { + Note = note, + DisplayToCustomer = displayToCustomer, + CreatedOnUtc = DateTime.UtcNow + }); + + UpdateOrder(order); + } + } + + #endregion + + #region Order items + + /// + /// Gets an Order item + /// + /// Order item identifier + /// Order item + public virtual OrderItem GetOrderItemById(int orderItemId) { if (orderItemId == 0) return null; @@ -462,6 +504,23 @@ join p in _productRepository.Table on orderItem.ProductId equals p.Id return orderItems; } + public virtual Multimap GetOrderItemsByOrderIds(int[] orderIds) + { + Guard.ArgumentNotNull(() => orderIds); + + var query = + from x in _orderItemRepository.TableUntracked.Expand(x => x.Product) + where orderIds.Contains(x.OrderId) + select x; + + var map = query + .OrderBy(x => x.OrderId) + .ToList() + .ToMultimap(x => x.OrderId, x => x); + + return map; + } + /// /// Delete an Order item /// @@ -629,8 +688,9 @@ public virtual ReturnRequest GetReturnRequestById(int returnRequestId) /// Return request status; null to load all entries /// Page index /// Page size + /// Return request Id /// Return requests - public virtual IPagedList SearchReturnRequests(int storeId, int customerId, int orderItemId, ReturnRequestStatus? rs, int pageIndex, int pageSize) + public virtual IPagedList SearchReturnRequests(int storeId, int customerId, int orderItemId, ReturnRequestStatus? rs, int pageIndex, int pageSize, int id = 0) { var query = _returnRequestRepository.Table; @@ -643,13 +703,16 @@ public virtual IPagedList SearchReturnRequests(int storeId, int c if (orderItemId > 0) query = query.Where(rr => rr.OrderItemId == orderItemId); + if (id != 0) + query = query.Where(rr => rr.Id == id); + if (rs.HasValue) { int returnStatusId = (int)rs.Value; query = query.Where(rr => rr.ReturnRequestStatusId == returnStatusId); } - query = query.OrderByDescending(rr => rr.CreatedOnUtc).ThenByDescending(rr=>rr.Id); + query = query.OrderByDescending(rr => rr.CreatedOnUtc).ThenByDescending(rr => rr.Id); var returnRequests = new PagedList(query, pageIndex, pageSize); return returnRequests; diff --git a/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs b/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs index d697132ba3..e154dd519d 100644 --- a/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs +++ b/src/Libraries/SmartStore.Services/Orders/OrderTotalCalculationService.cs @@ -9,6 +9,8 @@ using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Localization; +using SmartStore.Core.Plugins; using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Discounts; @@ -18,10 +20,10 @@ namespace SmartStore.Services.Orders { - /// - /// Order service - /// - public partial class OrderTotalCalculationService : IOrderTotalCalculationService + /// + /// Order service + /// + public partial class OrderTotalCalculationService : IOrderTotalCalculationService { #region Fields @@ -30,16 +32,18 @@ public partial class OrderTotalCalculationService : IOrderTotalCalculationServic private readonly IPriceCalculationService _priceCalculationService; private readonly ITaxService _taxService; private readonly IShippingService _shippingService; - private readonly IPaymentService _paymentService; + private readonly IProviderManager _providerManager; private readonly ICheckoutAttributeParser _checkoutAttributeParser; private readonly IDiscountService _discountService; private readonly IGiftCardService _giftCardService; private readonly IGenericAttributeService _genericAttributeService; + private readonly IProductAttributeParser _productAttributeParser; private readonly TaxSettings _taxSettings; private readonly RewardPointsSettings _rewardPointsSettings; private readonly ShippingSettings _shippingSettings; private readonly ShoppingCartSettings _shoppingCartSettings; private readonly CatalogSettings _catalogSettings; + #endregion #region Ctor @@ -67,11 +71,12 @@ public OrderTotalCalculationService(IWorkContext workContext, IPriceCalculationService priceCalculationService, ITaxService taxService, IShippingService shippingService, - IPaymentService paymentService, + IProviderManager providerManager, ICheckoutAttributeParser checkoutAttributeParser, IDiscountService discountService, IGiftCardService giftCardService, IGenericAttributeService genericAttributeService, + IProductAttributeParser productAttributeParser, TaxSettings taxSettings, RewardPointsSettings rewardPointsSettings, ShippingSettings shippingSettings, @@ -83,30 +88,35 @@ public OrderTotalCalculationService(IWorkContext workContext, this._priceCalculationService = priceCalculationService; this._taxService = taxService; this._shippingService = shippingService; - this._paymentService = paymentService; + this._providerManager = providerManager; this._checkoutAttributeParser = checkoutAttributeParser; this._discountService = discountService; this._giftCardService = giftCardService; this._genericAttributeService = genericAttributeService; + this._productAttributeParser = productAttributeParser; this._taxSettings = taxSettings; this._rewardPointsSettings = rewardPointsSettings; this._shippingSettings = shippingSettings; this._shoppingCartSettings = shoppingCartSettings; this._catalogSettings = catalogSettings; - } - #endregion + T = NullLocalizer.Instance; + } - #region Methods + public Localizer T { get; set; } - /// - /// Gets shopping cart subtotal - /// - /// Cart - /// Applied discount amount - /// Applied discount - /// Sub total (without discount) - /// Sub total (with discount) + #endregion + + #region Methods + + /// + /// Gets shopping cart subtotal + /// + /// Cart + /// Applied discount amount + /// Applied discount + /// Sub total (without discount) + /// Sub total (with discount) public virtual void GetShoppingCartSubTotal(IList cart, out decimal discountAmount, out Discount appliedDiscount, out decimal subTotalWithoutDiscount, out decimal subTotalWithDiscount) @@ -180,8 +190,13 @@ public virtual void GetShoppingCartSubTotal(IList car foreach (var shoppingCartItem in cart) { + if (shoppingCartItem.Item.Product == null) + continue; + decimal taxRate, sciSubTotal, sciExclTax, sciInclTax = decimal.Zero; + shoppingCartItem.Item.Product.MergeWithCombination(shoppingCartItem.Item.AttributesXml, _productAttributeParser); + if (_shoppingCartSettings.RoundPricesDuringCalculation) { // Gross > Net RoundFix @@ -341,12 +356,16 @@ public virtual decimal GetOrderSubtotalDiscount(Customer customer, var allDiscounts = _discountService.GetAllDiscounts(DiscountType.AssignedToOrderSubTotal); var allowedDiscounts = new List(); - if (allDiscounts != null) - foreach (var discount in allDiscounts) - if (_discountService.IsDiscountValid(discount, customer) && - discount.DiscountType == DiscountType.AssignedToOrderSubTotal && - !allowedDiscounts.ContainsDiscount(discount)) - allowedDiscounts.Add(discount); + if (allDiscounts != null) + { + foreach (var discount in allDiscounts) + { + if (discount.DiscountType == DiscountType.AssignedToOrderSubTotal && !allowedDiscounts.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) + { + allowedDiscounts.Add(discount); + } + } + } appliedDiscount = allowedDiscounts.GetPreferredDiscount(orderSubTotal); if (appliedDiscount != null) @@ -598,15 +617,15 @@ public virtual decimal AdjustShippingRate(decimal shippingRate, IList(); - if (allDiscounts != null) - foreach (var discount in allDiscounts) - if (_discountService.IsDiscountValid(discount, customer) && - discount.DiscountType == DiscountType.AssignedToShipping && - !allowedDiscounts.ContainsDiscount(discount)) - allowedDiscounts.Add(discount); + + if (allDiscounts != null) + { + foreach (var discount in allDiscounts) + { + if (discount.DiscountType == DiscountType.AssignedToShipping && !allowedDiscounts.Any(x => x.Id == discount.Id) && _discountService.IsDiscountValid(discount, customer)) + { + allowedDiscounts.Add(discount); + } + } + } appliedDiscount = allowedDiscounts.GetPreferredDiscount(shippingTotal); if (appliedDiscount != null) @@ -702,8 +726,7 @@ public virtual decimal GetTaxTotal(IList cart, bool u /// Tax rates /// A value indicating whether we should use payment method additional fee when calculating tax /// Tax total - public virtual decimal GetTaxTotal(IList cart, - out SortedDictionary taxRates, bool usePaymentMethodAdditionalFee = true) + public virtual decimal GetTaxTotal(IList cart, out SortedDictionary taxRates, bool usePaymentMethodAdditionalFee = true) { if (cart == null) throw new ArgumentNullException("cart"); @@ -723,10 +746,7 @@ public virtual decimal GetTaxTotal(IList cart, string paymentMethodSystemName = ""; if (customer != null) { - paymentMethodSystemName = customer.GetAttribute( - SystemCustomerAttributeNames.SelectedPaymentMethod, - _genericAttributeService, - _storeContext.CurrentStore.Id); + paymentMethodSystemName = customer.GetAttribute(SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id); } //order sub total (items + checkout attributes) @@ -736,10 +756,12 @@ public virtual decimal GetTaxTotal(IList cart, decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; SortedDictionary orderSubTotalTaxRates = null; + GetShoppingCartSubTotal(cart, false, out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase, out orderSubTotalTaxRates); + foreach (KeyValuePair kvp in orderSubTotalTaxRates) { decimal taxRate = kvp.Key; @@ -762,6 +784,7 @@ public virtual decimal GetTaxTotal(IList cart, decimal taxRate = decimal.Zero; decimal? shippingExclTax = GetShoppingCartShippingTotal(cart, false, out taxRate); decimal? shippingInclTax = GetShoppingCartShippingTotal(cart, true, out taxRate); + if (shippingExclTax.HasValue && shippingInclTax.HasValue) { shippingTax = shippingInclTax.Value - shippingExclTax.Value; @@ -785,18 +808,22 @@ public virtual decimal GetTaxTotal(IList cart, if (usePaymentMethodAdditionalFee && _taxSettings.PaymentMethodAdditionalFeeIsTaxable) { decimal taxRate = decimal.Zero; + + var provider = _providerManager.GetProvider(paymentMethodSystemName); + var paymentMethodAdditionalFee = (provider != null ? provider.Value.GetAdditionalHandlingFee(cart) : decimal.Zero); + + if (_shoppingCartSettings.RoundPricesDuringCalculation) + { + paymentMethodAdditionalFee = Math.Round(paymentMethodAdditionalFee, 2); + } - decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); decimal paymentMethodAdditionalFeeExclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer, out taxRate); decimal paymentMethodAdditionalFeeInclTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, true, customer, out taxRate); paymentMethodAdditionalFeeTax = paymentMethodAdditionalFeeInclTax - paymentMethodAdditionalFeeExclTax; - //ensure that tax is equal or greater than zero - if (paymentMethodAdditionalFeeTax < decimal.Zero) - paymentMethodAdditionalFeeTax = decimal.Zero; //tax rates - if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax > decimal.Zero) + if (taxRate > decimal.Zero && paymentMethodAdditionalFeeTax != decimal.Zero) { if (!taxRates.ContainsKey(taxRate)) taxRates.Add(taxRate, paymentMethodAdditionalFeeTax); @@ -811,12 +838,14 @@ public virtual decimal GetTaxTotal(IList cart, //summarize taxes decimal taxTotal = subTotalTaxTotal + shippingTax + paymentMethodAdditionalFeeTax; + //ensure that tax is equal or greater than zero if (taxTotal < decimal.Zero) taxTotal = decimal.Zero; //round tax if (_shoppingCartSettings.RoundPricesDuringCalculation) taxTotal = Math.Round(taxTotal, 2); + return taxTotal; } @@ -840,9 +869,9 @@ public virtual decimal GetTaxTotal(IList cart, int redeemedRewardPoints = 0; decimal redeemedRewardPointsAmount = decimal.Zero; List appliedGiftCards = null; + return GetShoppingCartTotal(cart, out discountAmount, out appliedDiscount, - out appliedGiftCards, - out redeemedRewardPoints, out redeemedRewardPointsAmount, ignoreRewardPonts, usePaymentMethodAdditionalFee); + out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount, ignoreRewardPonts, usePaymentMethodAdditionalFee); } /// @@ -870,50 +899,42 @@ public virtual decimal GetTaxTotal(IList cart, string paymentMethodSystemName = ""; if (customer != null) { - paymentMethodSystemName = customer.GetAttribute( - SystemCustomerAttributeNames.SelectedPaymentMethod, - _genericAttributeService, - _storeContext.CurrentStore.Id); + paymentMethodSystemName = customer.GetAttribute(SystemCustomerAttributeNames.SelectedPaymentMethod, _genericAttributeService, _storeContext.CurrentStore.Id); } - //subtotal without tax decimal subtotalBase = decimal.Zero; decimal orderSubTotalDiscountAmount = decimal.Zero; Discount orderSubTotalAppliedDiscount = null; decimal subTotalWithoutDiscountBase = decimal.Zero; decimal subTotalWithDiscountBase = decimal.Zero; - GetShoppingCartSubTotal(cart, false, - out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount, - out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); - //subtotal with discount - subtotalBase = subTotalWithDiscountBase; + GetShoppingCartSubTotal(cart, false, out orderSubTotalDiscountAmount, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); + //subtotal with discount + subtotalBase = subTotalWithDiscountBase; //shipping without tax decimal? shoppingCartShipping = GetShoppingCartShippingTotal(cart, false); - - //payment method additional fee without tax decimal paymentMethodAdditionalFeeWithoutTax = decimal.Zero; if (usePaymentMethodAdditionalFee && !String.IsNullOrEmpty(paymentMethodSystemName)) { - decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); - paymentMethodAdditionalFeeWithoutTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, - false, customer); - } - + var provider = _providerManager.GetProvider(paymentMethodSystemName); + var paymentMethodAdditionalFee = (provider != null ? provider.Value.GetAdditionalHandlingFee(cart) : decimal.Zero); + if (_shoppingCartSettings.RoundPricesDuringCalculation) + { + paymentMethodAdditionalFee = Math.Round(paymentMethodAdditionalFee, 2); + } + paymentMethodAdditionalFeeWithoutTax = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, false, customer); + } //tax decimal shoppingCartTax = GetTaxTotal(cart, usePaymentMethodAdditionalFee); - - - //order total decimal resultTemp = decimal.Zero; resultTemp += subtotalBase; @@ -963,25 +984,29 @@ public virtual decimal GetTaxTotal(IList cart, { //we don't apply gift cards for recurring products var giftCards = _giftCardService.GetActiveGiftCardsAppliedByCustomer(customer); - if (giftCards != null) - foreach (var gc in giftCards) - if (resultTemp > decimal.Zero) - { - decimal remainingAmount = gc.GetGiftCardRemainingAmount(); - decimal amountCanBeUsed = decimal.Zero; - if (resultTemp > remainingAmount) - amountCanBeUsed = remainingAmount; - else - amountCanBeUsed = resultTemp; - - //reduce subtotal - resultTemp -= amountCanBeUsed; - - var appliedGiftCard = new AppliedGiftCard(); - appliedGiftCard.GiftCard = gc; - appliedGiftCard.AmountCanBeUsed = amountCanBeUsed; - appliedGiftCards.Add(appliedGiftCard); - } + if (giftCards != null) + { + foreach (var gc in giftCards) + { + if (resultTemp > decimal.Zero) + { + decimal remainingAmount = gc.GetGiftCardRemainingAmount(); + decimal amountCanBeUsed = decimal.Zero; + if (resultTemp > remainingAmount) + amountCanBeUsed = remainingAmount; + else + amountCanBeUsed = resultTemp; + + //reduce subtotal + resultTemp -= amountCanBeUsed; + + var appliedGiftCard = new AppliedGiftCard(); + appliedGiftCard.GiftCard = gc; + appliedGiftCard.AmountCanBeUsed = amountCanBeUsed; + appliedGiftCards.Add(appliedGiftCard); + } + } + } } #endregion @@ -1012,6 +1037,7 @@ public virtual decimal GetTaxTotal(IList cart, { int rewardPointsBalance = customer.GetRewardPointsBalance(); decimal rewardPointsBalanceAmount = ConvertRewardPointsToAmount(rewardPointsBalance); + if (orderTotal.HasValue && orderTotal.Value > decimal.Zero) { if (orderTotal.Value > rewardPointsBalanceAmount) @@ -1035,8 +1061,7 @@ public virtual decimal GetTaxTotal(IList cart, orderTotal = Math.Round(orderTotal.Value, 2); return orderTotal; } - else - return null; + return null; } /// @@ -1060,8 +1085,7 @@ public virtual decimal GetOrderTotalDiscount(Customer customer, decimal orderTot { foreach (var discount in allDiscounts) { - if (_discountService.IsDiscountValid(discount, customer) && discount.DiscountType == DiscountType.AssignedToOrderTotal && - !allowedDiscounts.ContainsDiscount(discount)) + if (discount.DiscountType == DiscountType.AssignedToOrderTotal && !allowedDiscounts.Any(x => x.Id == discount.Id) &&_discountService.IsDiscountValid(discount, customer)) { allowedDiscounts.Add(discount); } @@ -1113,8 +1137,14 @@ public virtual int ConvertAmountToRewardPoints(decimal amount) if (amount <= 0) return 0; - if (_rewardPointsSettings.ExchangeRate > 0) - result = (int)Math.Ceiling(amount / _rewardPointsSettings.ExchangeRate); + if (_rewardPointsSettings.ExchangeRate > 0) + { + if (_rewardPointsSettings.RoundDownRewardPoints) + result = (int)Math.Floor(amount / _rewardPointsSettings.ExchangeRate); + else + result = (int)Math.Ceiling(amount / _rewardPointsSettings.ExchangeRate); + } + return result; } diff --git a/src/Libraries/SmartStore.Services/Orders/ShoppingCartExtensions.cs b/src/Libraries/SmartStore.Services/Orders/ShoppingCartExtensions.cs index c721f0968e..84dad37b83 100644 --- a/src/Libraries/SmartStore.Services/Orders/ShoppingCartExtensions.cs +++ b/src/Libraries/SmartStore.Services/Orders/ShoppingCartExtensions.cs @@ -175,7 +175,9 @@ public static IList Organize(this IList - /// Shopping cart service - /// - public partial class ShoppingCartService : IShoppingCartService + /// + /// Shopping cart service + /// + public partial class ShoppingCartService : IShoppingCartService { #region Fields @@ -71,8 +72,10 @@ public partial class ShoppingCartService : IShoppingCartService /// ACL service /// Store mapping service /// Generic attribute service - public ShoppingCartService(IRepository sciRepository, - IWorkContext workContext, IStoreContext storeContext, + public ShoppingCartService( + IRepository sciRepository, + IWorkContext workContext, + IStoreContext storeContext, ICurrencyService currencyService, IProductService productService, ILocalizationService localizationService, IProductAttributeParser productAttributeParser, @@ -110,20 +113,24 @@ public ShoppingCartService(IRepository sciRepository, this._genericAttributeService = genericAttributeService; this._downloadService = downloadService; this._catalogSettings = catalogSettings; - } - #endregion + T = NullLocalizer.Instance; + } - #region Methods + public Localizer T { get; set; } - /// - /// Delete shopping cart item - /// - /// Shopping cart item - /// A value indicating whether to reset checkout data - /// A value indicating whether to ensure that only active checkout attributes are attached to the current customer + #endregion + + #region Methods + + /// + /// Delete shopping cart item + /// + /// Shopping cart item + /// A value indicating whether to reset checkout data + /// A value indicating whether to ensure that only active checkout attributes are attached to the current customer /// A value indicating whether to delete child cart items - public virtual void DeleteShoppingCartItem(ShoppingCartItem shoppingCartItem, bool resetCheckoutData = true, + public virtual void DeleteShoppingCartItem(ShoppingCartItem shoppingCartItem, bool resetCheckoutData = true, bool ensureOnlyActiveCheckoutAttributes = false, bool deleteChildCartItems = true) { if (shoppingCartItem == null) @@ -261,25 +268,25 @@ public virtual IList GetRequiredProductWarnings(Customer customer, if (automaticallyAddRequiredProductsIfEnabled) { //pass 'false' for 'automaticallyAddRequiredProducsIfEnabled' to prevent circular references - int shoppingCartItemId; - var addToCartWarnings = AddToCart(customer, rp, shoppingCartType, storeId, "", decimal.Zero, 1, false, out shoppingCartItemId); + var addToCartWarnings = AddToCart(customer, rp, shoppingCartType, storeId, "", decimal.Zero, 1, false, null); + if (addToCartWarnings.Count > 0) { //a product wasn't atomatically added for some reasons //don't display specific errors from 'addToCartWarnings' variable //display only generic error - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.RequiredProductWarning"), rp.GetLocalized(x => x.Name))); + warnings.Add(T("ShoppingCart.RequiredProductWarning", rp.GetLocalized(x => x.Name))); } } else { - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.RequiredProductWarning"), rp.GetLocalized(x => x.Name))); + warnings.Add(T("ShoppingCart.RequiredProductWarning", rp.GetLocalized(x => x.Name))); } } else { - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.RequiredProductWarning"), rp.GetLocalized(x => x.Name))); + warnings.Add(T("ShoppingCart.RequiredProductWarning", rp.GetLocalized(x => x.Name))); } } } @@ -299,8 +306,7 @@ public virtual IList GetRequiredProductWarnings(Customer customer, /// Quantity /// Warnings public virtual IList GetStandardWarnings(Customer customer, ShoppingCartType shoppingCartType, - Product product, string selectedAttributes, decimal customerEnteredPrice, - int quantity) + Product product, string selectedAttributes, decimal customerEnteredPrice, int quantity) { if (customer == null) throw new ArgumentNullException("customer"); @@ -313,57 +319,57 @@ public virtual IList GetStandardWarnings(Customer customer, ShoppingCart //deleted? if (product.Deleted) { - warnings.Add(_localizationService.GetResource("ShoppingCart.ProductDeleted")); + warnings.Add(T("ShoppingCart.ProductDeleted")); return warnings; } // check if the product type is available for order if (product.ProductType == ProductType.GroupedProduct) { - warnings.Add(_localizationService.GetResource("ShoppingCart.ProductNotAvailableForOrder")); + warnings.Add(T("ShoppingCart.ProductNotAvailableForOrder")); } // validate bundle if (product.ProductType == ProductType.BundledProduct) { if (product.BundlePerItemPricing && customerEnteredPrice != decimal.Zero) - warnings.Add(_localizationService.GetResource("ShoppingCart.Bundle.NoCustomerEnteredPrice")); + warnings.Add(T("ShoppingCart.Bundle.NoCustomerEnteredPrice")); } //published? if (!product.Published) { - warnings.Add(_localizationService.GetResource("ShoppingCart.ProductUnpublished")); + warnings.Add(T("ShoppingCart.ProductUnpublished")); } //ACL if (!_aclService.Authorize(product, customer)) { - warnings.Add(_localizationService.GetResource("ShoppingCart.ProductUnpublished")); + warnings.Add(T("ShoppingCart.ProductUnpublished")); } //Store mapping if (!_storeMappingService.Authorize(product, _storeContext.CurrentStore.Id)) { - warnings.Add(_localizationService.GetResource("ShoppingCart.ProductUnpublished")); + warnings.Add(T("ShoppingCart.ProductUnpublished")); } //disabled "add to cart" button if (shoppingCartType == ShoppingCartType.ShoppingCart && product.DisableBuyButton) { - warnings.Add(_localizationService.GetResource("ShoppingCart.BuyingDisabled")); + warnings.Add(T("ShoppingCart.BuyingDisabled")); } //disabled "add to wishlist" button if (shoppingCartType == ShoppingCartType.Wishlist && product.DisableWishlistButton) { - warnings.Add(_localizationService.GetResource("ShoppingCart.WishlistDisabled")); + warnings.Add(T("ShoppingCart.WishlistDisabled")); } //call for price if (shoppingCartType == ShoppingCartType.ShoppingCart && product.CallForPrice) { - warnings.Add(_localizationService.GetResource("Products.CallForPrice")); + warnings.Add(T("Products.CallForPrice")); } //customer entered price @@ -372,11 +378,13 @@ public virtual IList GetStandardWarnings(Customer customer, ShoppingCart if (customerEnteredPrice < product.MinimumCustomerEnteredPrice || customerEnteredPrice > product.MaximumCustomerEnteredPrice) { - decimal minimumCustomerEnteredPrice = _currencyService.ConvertFromPrimaryStoreCurrency(product.MinimumCustomerEnteredPrice, _workContext.WorkingCurrency); - decimal maximumCustomerEnteredPrice = _currencyService.ConvertFromPrimaryStoreCurrency(product.MaximumCustomerEnteredPrice, _workContext.WorkingCurrency); - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.CustomerEnteredPrice.RangeError"), - _priceFormatter.FormatPrice(minimumCustomerEnteredPrice, false, false), - _priceFormatter.FormatPrice(maximumCustomerEnteredPrice, false, false))); + var minimumCustomerEnteredPrice = _currencyService.ConvertFromPrimaryStoreCurrency(product.MinimumCustomerEnteredPrice, _workContext.WorkingCurrency); + var maximumCustomerEnteredPrice = _currencyService.ConvertFromPrimaryStoreCurrency(product.MaximumCustomerEnteredPrice, _workContext.WorkingCurrency); + + warnings.Add(T("ShoppingCart.CustomerEnteredPrice.RangeError", + _priceFormatter.FormatPrice(minimumCustomerEnteredPrice, true, false), + _priceFormatter.FormatPrice(maximumCustomerEnteredPrice, true, false)) + ); } } @@ -384,18 +392,20 @@ public virtual IList GetStandardWarnings(Customer customer, ShoppingCart var hasQtyWarnings = false; if (quantity < product.OrderMinimumQuantity) { - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.MinimumQuantity"), product.OrderMinimumQuantity)); + warnings.Add(T("ShoppingCart.MinimumQuantity", product.OrderMinimumQuantity)); hasQtyWarnings = true; } + if (quantity > product.OrderMaximumQuantity) { - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.MaximumQuantity"), product.OrderMaximumQuantity)); + warnings.Add(T("ShoppingCart.MaximumQuantity", product.OrderMaximumQuantity)); hasQtyWarnings = true; } + var allowedQuantities = product.ParseAllowedQuatities(); if (allowedQuantities.Length > 0 && !allowedQuantities.Contains(quantity)) { - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.AllowedQuantities"), string.Join(", ", allowedQuantities))); + warnings.Add(T("ShoppingCart.AllowedQuantities", string.Join(", ", allowedQuantities))); } var validateOutOfStock = shoppingCartType == ShoppingCartType.ShoppingCart || !_shoppingCartSettings.AllowOutOfStockItemsToBeAddedToWishlist; @@ -413,29 +423,31 @@ public virtual IList GetStandardWarnings(Customer customer, ShoppingCart { if (product.StockQuantity < quantity) { - int maximumQuantityCanBeAdded = product.StockQuantity; + var maximumQuantityCanBeAdded = product.StockQuantity; + if (maximumQuantityCanBeAdded <= 0) - warnings.Add(_localizationService.GetResource("ShoppingCart.OutOfStock")); + warnings.Add(T("ShoppingCart.OutOfStock")); else - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.QuantityExceedsStock"), maximumQuantityCanBeAdded)); + warnings.Add(T("ShoppingCart.QuantityExceedsStock", maximumQuantityCanBeAdded)); } } } break; case ManageInventoryMethod.ManageStockByAttributes: { - var combination = product - .ProductVariantAttributeCombinations - .FirstOrDefault(x => _productAttributeParser.AreProductAttributesEqual(x.AttributesXml, selectedAttributes)); - if (combination != null && - !combination.AllowOutOfStockOrders && - combination.StockQuantity < quantity) + var combination = _productAttributeParser.FindProductVariantAttributeCombination(product.Id, selectedAttributes); + + if (combination != null) { - int maximumQuantityCanBeAdded = combination.StockQuantity; - if (maximumQuantityCanBeAdded <= 0) - warnings.Add(_localizationService.GetResource("ShoppingCart.OutOfStock")); - else - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.QuantityExceedsStock"), maximumQuantityCanBeAdded)); + if (!combination.AllowOutOfStockOrders && combination.StockQuantity < quantity) + { + int maximumQuantityCanBeAdded = combination.StockQuantity; + + if (maximumQuantityCanBeAdded <= 0) + warnings.Add(T("ShoppingCart.OutOfStock")); + else + warnings.Add(T("ShoppingCart.QuantityExceedsStock", maximumQuantityCanBeAdded)); + } } } break; @@ -445,14 +457,14 @@ public virtual IList GetStandardWarnings(Customer customer, ShoppingCart } //availability dates - bool availableStartDateError = false; + var availableStartDateError = false; if (product.AvailableStartDateTimeUtc.HasValue) { DateTime now = DateTime.UtcNow; DateTime availableStartDateTime = DateTime.SpecifyKind(product.AvailableStartDateTimeUtc.Value, DateTimeKind.Utc); if (availableStartDateTime.CompareTo(now) > 0) { - warnings.Add(_localizationService.GetResource("ShoppingCart.NotAvailable")); + warnings.Add(T("ShoppingCart.NotAvailable")); availableStartDateError = true; } } @@ -462,30 +474,28 @@ public virtual IList GetStandardWarnings(Customer customer, ShoppingCart DateTime availableEndDateTime = DateTime.SpecifyKind(product.AvailableEndDateTimeUtc.Value, DateTimeKind.Utc); if (availableEndDateTime.CompareTo(now) < 0) { - warnings.Add(_localizationService.GetResource("ShoppingCart.NotAvailable")); + warnings.Add(T("ShoppingCart.NotAvailable")); } } return warnings; } - /// - /// Validates shopping cart item attributes - /// - /// The customer - /// Shopping cart type - /// Product - /// Selected attributes - /// Quantity - /// Product bundle item - /// Warnings - public virtual IList GetShoppingCartItemAttributeWarnings(Customer customer, ShoppingCartType shoppingCartType, - Product product, string selectedAttributes, int quantity = 1, ProductBundleItem bundleItem = null) + public virtual IList GetShoppingCartItemAttributeWarnings( + Customer customer, + ShoppingCartType shoppingCartType, + Product product, + string selectedAttributes, + int quantity = 1, + ProductBundleItem bundleItem = null, + ProductVariantAttributeCombination combination = null) { - if (product == null) - throw new ArgumentNullException("product"); + Guard.ArgumentNotNull(() => product); var warnings = new List(); + if (product.ProductType == ProductType.BundledProduct) + return warnings; // customer cannot select anything cause bundles have no attributes + if (bundleItem != null && !bundleItem.BundleProduct.BundlePerItemPricing) return warnings; // customer cannot select anything... selectedAttribute is always empty @@ -494,18 +504,12 @@ public virtual IList GetShoppingCartItemAttributeWarnings(Customer custo foreach (var pva1 in pva1Collection) { var pv1 = pva1.Product; - if (pv1 != null) - { - if (pv1.Id != product.Id) - { - warnings.Add("Attribute error"); - } - } - else - { - warnings.Add("Attribute error"); - return warnings; - } + + if (pv1 == null || pv1.Id != product.Id) + { + warnings.Add(T("ShoppingCart.AttributeError")); + return warnings; + } } //existing product attributes @@ -532,24 +536,35 @@ public virtual IList GetShoppingCartItemAttributeWarnings(Customer custo } } - if (!found && bundleItem != null && bundleItem.FilterAttributes && !bundleItem.AttributeFilters.Exists(x => x.AttributeId == pva2.ProductAttributeId)) + if (!found && bundleItem != null && bundleItem.FilterAttributes && !bundleItem.AttributeFilters.Any(x => x.AttributeId == pva2.ProductAttributeId)) { found = true; // attribute is filtered out on bundle item level... it cannot be selected by customer } if (!found) { - if (pva2.TextPrompt.HasValue()) - warnings.Add(pva2.TextPrompt); - else - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.SelectAttribute"), pva2.ProductAttribute.GetLocalized(a => a.Name))); + warnings.Add(T("ShoppingCart.SelectAttribute", pva2.TextPrompt.HasValue() ? pva2.TextPrompt : pva2.ProductAttribute.GetLocalized(a => a.Name))); } } } + // check if there is a selected attribute combination and if it is active + if (warnings.Count == 0 && selectedAttributes.HasValue()) + { + if (combination == null) + { + combination = _productAttributeParser.FindProductVariantAttributeCombination(product.Id, selectedAttributes); + } + + if (combination != null && !combination.IsActive) + { + warnings.Add(T("ShoppingCart.NotAvailable")); + } + } + if (warnings.Count == 0) { - var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(selectedAttributes); + var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(selectedAttributes).ToList(); foreach (var pvaValue in pvaValues) { if (pvaValue.ValueType == ProductVariantAttributeValueType.ProductLinkage) @@ -562,18 +577,16 @@ public virtual IList GetShoppingCartItemAttributeWarnings(Customer custo foreach (var linkageWarning in linkageWarnings) { - string msg = _localizationService.GetResource("ShoppingCart.ProductLinkageAttributeWarning").FormatWith( + warnings.Add(T("ShoppingCart.ProductLinkageAttributeWarning", pvaValue.ProductVariantAttribute.ProductAttribute.GetLocalized(a => a.Name), pvaValue.GetLocalized(a => a.Name), - linkageWarning); - - warnings.Add(msg); + linkageWarning) + ); } } else { - string msg = _localizationService.GetResource("ShoppingCart.ProductLinkageProductNotLoading").FormatWith(pvaValue.LinkedProductId); - warnings.Add(msg); + warnings.Add(T("ShoppingCart.ProductLinkageProductNotLoading", pvaValue.LinkedProductId)); } } } @@ -582,6 +595,61 @@ public virtual IList GetShoppingCartItemAttributeWarnings(Customer custo return warnings; } + /// + /// Validates if all required attributes are selected + /// + /// Selected attributes + /// Product + /// bool + public virtual bool AreAllAttributesForCombinationSelected(string selectedAttributes, Product product) + { + Guard.ArgumentNotNull(() => product); + + var hasAttributeCombinations = _sciRepository.Context.QueryForCollection(product, (Product p) => p.ProductVariantAttributeCombinations).Any(); + if (!hasAttributeCombinations) + return true; + + //selected attributes + var pva1Collection = _productAttributeParser.ParseProductVariantAttributes(selectedAttributes); + + //existing product attributes + var pva2Collection = product.ProductVariantAttributes; + foreach (var pva2 in pva2Collection) + { + if (pva2.IsRequired) + { + bool found = false; + //selected product attributes + foreach (var pva1 in pva1Collection) + { + if (pva1.Id == pva2.Id) + { + var pvaValuesStr = _productAttributeParser.ParseValues(selectedAttributes, pva1.Id); + foreach (string str1 in pvaValuesStr) + { + if (!String.IsNullOrEmpty(str1.Trim())) + { + found = true; + break; + } + } + } + } + + if (!found) + { + return found; + } + } + else + { + return true; + } + } + + return true; + } + /// /// Validates shopping cart item (gift card) /// @@ -607,27 +675,34 @@ public virtual IList GetShoppingCartItemGiftCardWarnings(ShoppingCartTyp string giftCardMessage = string.Empty; _productAttributeParser.GetGiftCardAttribute(selectedAttributes, - out giftCardRecipientName, out giftCardRecipientEmail, - out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); + out giftCardRecipientName, out giftCardRecipientEmail, out giftCardSenderName, out giftCardSenderEmail, out giftCardMessage); - if (String.IsNullOrEmpty(giftCardRecipientName)) - warnings.Add(_localizationService.GetResource("ShoppingCart.RecipientNameError")); + if (String.IsNullOrEmpty(giftCardRecipientName)) + { + warnings.Add(T("ShoppingCart.RecipientNameError")); + } if (product.GiftCardType == GiftCardType.Virtual) { - //validate for virtual gift cards only + //validate for virtual gift cards only if (String.IsNullOrEmpty(giftCardRecipientEmail) || !giftCardRecipientEmail.IsEmail()) - warnings.Add(_localizationService.GetResource("ShoppingCart.RecipientEmailError")); + { + warnings.Add(T("ShoppingCart.RecipientEmailError")); + } } - if (String.IsNullOrEmpty(giftCardSenderName)) - warnings.Add(_localizationService.GetResource("ShoppingCart.SenderNameError")); + if (String.IsNullOrEmpty(giftCardSenderName)) + { + warnings.Add(T("ShoppingCart.SenderNameError")); + } if (product.GiftCardType == GiftCardType.Virtual) { - //validate for virtual gift cards only + //validate for virtual gift cards only if (String.IsNullOrEmpty(giftCardSenderEmail) || !giftCardSenderEmail.IsEmail()) - warnings.Add(_localizationService.GetResource("ShoppingCart.SenderEmailError")); + { + warnings.Add(T("ShoppingCart.SenderEmailError")); + } } } @@ -646,19 +721,27 @@ public virtual IList GetBundleItemWarnings(ProductBundleItem bundleItem) if (bundleItem != null) { - string name = bundleItem.GetLocalizedName(); + var name = bundleItem.GetLocalizedName(); if (!bundleItem.Published) - warnings.Add(_localizationService.GetResource("ShoppingCart.Bundle.BundleItemUnpublished").FormatWith(name)); + { + warnings.Add(T("ShoppingCart.Bundle.BundleItemUnpublished", name)); + } if (bundleItem.ProductId == 0 || bundleItem.BundleProductId == 0 || bundleItem.Product == null || bundleItem.BundleProduct == null) - warnings.Add(_localizationService.GetResource("ShoppingCart.Bundle.MissingProduct").FormatWith(name)); + { + warnings.Add(T("ShoppingCart.Bundle.MissingProduct", name)); + } if (bundleItem.Quantity <= 0) - warnings.Add(_localizationService.GetResource("ShoppingCart.Bundle.Quantity").FormatWith(name)); + { + warnings.Add(T("ShoppingCart.Bundle.Quantity", name)); + } if (bundleItem.Product.IsDownload || bundleItem.Product.IsRecurring) - warnings.Add(_localizationService.GetResource("ShoppingCart.Bundle.ProductResrictions").FormatWith(name)); + { + warnings.Add(T("ShoppingCart.Bundle.ProductResrictions", name)); + } } return warnings; @@ -758,7 +841,7 @@ public virtual IList GetShoppingCartWarnings(IList GetShoppingCartWarnings(IList GetShoppingCartWarnings(IList GetShoppingCartWarnings(IList GetShoppingCartWarnings(IList a.TextPrompt))) warnings.Add(ca2.GetLocalized(a => a.TextPrompt)); else - warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.SelectAttribute"), ca2.GetLocalized(a => a.Name))); + warnings.Add(T("ShoppingCart.SelectAttribute", ca2.GetLocalized(a => a.Name))); } } } @@ -866,7 +955,7 @@ public virtual OrganizedShoppingCartItem FindShoppingCartItemInTheCart(IList - /// Add a product to shopping cart - /// - /// Customer - /// Product - /// Shopping cart type + /// + /// Add product to cart + /// + /// The customer + /// The product + /// Cart type /// Store identifier - /// Selected attributes - /// The price enter by a customer - /// Quantity - /// Automatically add required products if enabled - /// Identifier fo the new shopping cart item - /// Identifier of the parent shopping cart item - /// Product bundle item - /// Warnings - public virtual IList AddToCart(Customer customer, Product product, - ShoppingCartType shoppingCartType, int storeId, string selectedAttributes, - decimal customerEnteredPrice, int quantity, bool automaticallyAddRequiredProductsIfEnabled, - out int shoppingCartItemId, int? parentItemId = null, ProductBundleItem bundleItem = null) - { - shoppingCartItemId = 0; + /// Selected attributes + /// Price entered by customer + /// Quantity + /// Whether to add required products + /// Add to cart context + /// List with warnings + public virtual List AddToCart(Customer customer, Product product, ShoppingCartType cartType, int storeId, string selectedAttributes, + decimal customerEnteredPrice, int quantity, bool automaticallyAddRequiredProductsIfEnabled, AddToCartContext ctx = null) + { + if (customer == null) + throw new ArgumentNullException("customer"); - if (customer == null) - throw new ArgumentNullException("customer"); + if (product == null) + throw new ArgumentNullException("product"); - if (product == null) - throw new ArgumentNullException("product"); + var warnings = new List(); + var bundleItem = (ctx == null ? null : ctx.BundleItem); - var warnings = new List(); - if (shoppingCartType == ShoppingCartType.ShoppingCart && !_permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart, customer)) - { - warnings.Add("Shopping cart is disabled"); - return warnings; - } - if (shoppingCartType == ShoppingCartType.Wishlist && !_permissionService.Authorize(StandardPermissionProvider.EnableWishlist, customer)) - { - warnings.Add("Wishlist is disabled"); - return warnings; - } + if (ctx != null && bundleItem != null && ctx.Warnings.Count > 0) + return ctx.Warnings; // warnings while adding bundle items to cart -> no need for further processing - if (quantity <= 0) - { - warnings.Add(_localizationService.GetResource("ShoppingCart.QuantityShouldPositive")); - return warnings; - } + if (cartType == ShoppingCartType.ShoppingCart && !_permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart, customer)) + { + warnings.Add(T("ShoppingCart.IsDisabled")); + return warnings; + } + if (cartType == ShoppingCartType.Wishlist && !_permissionService.Authorize(StandardPermissionProvider.EnableWishlist, customer)) + { + warnings.Add(T("Wishlist.IsDisabled")); + return warnings; + } - if (parentItemId.HasValue && (parentItemId.Value == 0 || bundleItem == null || bundleItem.Id == 0)) + if (quantity <= 0) { - warnings.Add(_localizationService.GetResource("ShoppingCart.Bundle.BundleItemNotFound").FormatWith(bundleItem.GetLocalizedName())); + warnings.Add(T("ShoppingCart.QuantityShouldPositive")); return warnings; } - //reset checkout info + //if (parentItemId.HasValue && (parentItemId.Value == 0 || bundleItem == null || bundleItem.Id == 0)) + //{ + // warnings.Add(T("ShoppingCart.Bundle.BundleItemNotFound", bundleItem.GetLocalizedName())); + // return warnings; + //} + + //reset checkout info _customerService.ResetCheckoutData(customer, storeId); - var cart = customer.GetCartItems(shoppingCartType, storeId); - OrganizedShoppingCartItem shoppingCartItem = null; + var cart = customer.GetCartItems(cartType, storeId); + OrganizedShoppingCartItem existingCartItem = null; if (bundleItem == null) { - shoppingCartItem = FindShoppingCartItemInTheCart(cart, shoppingCartType, product, selectedAttributes, customerEnteredPrice); + existingCartItem = FindShoppingCartItemInTheCart(cart, cartType, product, selectedAttributes, customerEnteredPrice); } - if (shoppingCartItem != null) - { - //update existing shopping cart item - int newQuantity = shoppingCartItem.Item.Quantity + quantity; + if (existingCartItem != null) + { + //update existing shopping cart item + int newQuantity = existingCartItem.Item.Quantity + quantity; - warnings.AddRange( - GetShoppingCartItemWarnings(customer, shoppingCartType, product, storeId, selectedAttributes, customerEnteredPrice, newQuantity, + warnings.AddRange( + GetShoppingCartItemWarnings(customer, cartType, product, storeId, selectedAttributes, customerEnteredPrice, newQuantity, automaticallyAddRequiredProductsIfEnabled, bundleItem: bundleItem) ); - if (warnings.Count == 0) - { - shoppingCartItem.Item.AttributesXml = selectedAttributes; - shoppingCartItem.Item.Quantity = newQuantity; - shoppingCartItem.Item.UpdatedOnUtc = DateTime.UtcNow; - _customerService.UpdateCustomer(customer); + if (warnings.Count == 0) + { + existingCartItem.Item.AttributesXml = selectedAttributes; + existingCartItem.Item.Quantity = newQuantity; + existingCartItem.Item.UpdatedOnUtc = DateTime.UtcNow; + _customerService.UpdateCustomer(customer); - //event notification - _eventPublisher.EntityUpdated(shoppingCartItem.Item); - } - } - else - { - //new shopping cart item - warnings.AddRange( - GetShoppingCartItemWarnings(customer, shoppingCartType, product, storeId, selectedAttributes, customerEnteredPrice, quantity, + //event notification + _eventPublisher.EntityUpdated(existingCartItem.Item); + } + } + else + { + //new shopping cart item + warnings.AddRange( + GetShoppingCartItemWarnings(customer, cartType, product, storeId, selectedAttributes, customerEnteredPrice, quantity, automaticallyAddRequiredProductsIfEnabled, bundleItem: bundleItem) ); - if (warnings.Count == 0) - { - //maximum items validation - switch (shoppingCartType) - { - case ShoppingCartType.ShoppingCart: - if (cart.Count >= _shoppingCartSettings.MaximumShoppingCartItems) - { - warnings.Add(_localizationService.GetResource("ShoppingCart.MaximumShoppingCartItems")); - return warnings; - } - break; - case ShoppingCartType.Wishlist: - if (cart.Count >= _shoppingCartSettings.MaximumWishlistItems) - { - warnings.Add(_localizationService.GetResource("ShoppingCart.MaximumWishlistItems")); - return warnings; - } - break; - default: - break; - } + if (warnings.Count == 0) + { + //maximum items validation + if (cartType == ShoppingCartType.ShoppingCart && cart.Count >= _shoppingCartSettings.MaximumShoppingCartItems) + { + warnings.Add(T("ShoppingCart.MaximumShoppingCartItems")); + return warnings; + } + else if (cartType == ShoppingCartType.Wishlist && cart.Count >= _shoppingCartSettings.MaximumWishlistItems) + { + warnings.Add(T("ShoppingCart.MaximumWishlistItems")); + return warnings; + } - DateTime now = DateTime.UtcNow; - var cartItem = new ShoppingCartItem() - { - ShoppingCartType = shoppingCartType, + var now = DateTime.UtcNow; + var cartItem = new ShoppingCartItem + { + ShoppingCartType = cartType, StoreId = storeId, - Product = product, - AttributesXml = selectedAttributes, - CustomerEnteredPrice = customerEnteredPrice, - Quantity = quantity, - CreatedOnUtc = now, - UpdatedOnUtc = now, - ParentItemId = parentItemId - }; + Product = product, + AttributesXml = selectedAttributes, + CustomerEnteredPrice = customerEnteredPrice, + Quantity = quantity, + CreatedOnUtc = now, + UpdatedOnUtc = now, + ParentItemId = null //parentItemId + }; if (bundleItem != null) + { cartItem.BundleItemId = bundleItem.Id; + } - customer.ShoppingCartItems.Add(cartItem); - _customerService.UpdateCustomer(customer); - - shoppingCartItemId = cartItem.Id; - - //event notification - _eventPublisher.EntityInserted(cartItem); - } - } + if (ctx == null) + { + customer.ShoppingCartItems.Add(cartItem); + _customerService.UpdateCustomer(customer); + _eventPublisher.EntityInserted(cartItem); + } + else + { + if (bundleItem == null) + { + Debug.Assert(ctx.Item == null, "Add to cart item already specified"); + ctx.Item = cartItem; + } + else + { + ctx.ChildItems.Add(cartItem); + } + } + } + } - return warnings; - } + return warnings; + } /// - /// Adds a product to the shopping cart and also adds bundle items if the product is a bundle. + /// Add product to cart /// - /// List with warnings - /// Product - /// Collection with selected attribute data - /// Shopping cart type - /// The price enter by a customer - /// Quantity - /// Automatically add required products if enabled - /// Parent cart item if it is a bundle item - /// Bundle item object if it is a bundle item - /// Identifier of inserted (parent) shopping cart item - public virtual int AddToCart(List warnings, Product product, NameValueCollection form, ShoppingCartType cartType, decimal customerEnteredPrice, - int quantity, bool addRequiredProducts, int? parentCartItemId = null, ProductBundleItem bundleItem = null) + /// Add to cart context + public virtual void AddToCart(AddToCartContext ctx) { - int newCartItemId; - string selectedAttributes = ""; - int bundleItemId = (bundleItem == null ? 0 : bundleItem.Id); + var customer = ctx.Customer ?? _workContext.CurrentCustomer; + int storeId = ctx.StoreId ?? _storeContext.CurrentStore.Id; + var cart = customer.GetCartItems(ctx.CartType, storeId); - var attributes = _productAttributeService.GetProductVariantAttributesByProductId(product.Id); - - selectedAttributes = form.CreateSelectedAttributesXml(product.Id, attributes, _productAttributeParser, _localizationService, _downloadService, - _catalogSettings, null, warnings, true, bundleItemId); + _customerService.ResetCheckoutData(customer, storeId); - if (product.ProductType == ProductType.BundledProduct && selectedAttributes.HasValue()) + if (ctx.AttributeForm != null) { - warnings.Add(_localizationService.GetResource("ShoppingCart.Bundle.NoAttributes")); - return 0; - } + var attributes = _productAttributeService.GetProductVariantAttributesByProductId(ctx.Product.Id); - if (product.IsGiftCard) - { - selectedAttributes = form.AddGiftCardAttribute(selectedAttributes, product.Id, _productAttributeParser, bundleItemId); + ctx.Attributes = ctx.AttributeForm.CreateSelectedAttributesXml(ctx.Product.Id, attributes, _productAttributeParser, _localizationService, + _downloadService, _catalogSettings, null, ctx.Warnings, true, ctx.BundleItemId); + + if (ctx.Product.ProductType == ProductType.BundledProduct && ctx.Attributes.HasValue()) + ctx.Warnings.Add(T("ShoppingCart.Bundle.NoAttributes")); + + if (ctx.Product.IsGiftCard) + ctx.Attributes = ctx.AttributeForm.AddGiftCardAttribute(ctx.Attributes, ctx.Product.Id, _productAttributeParser, ctx.BundleItemId); } - warnings.AddRange( - AddToCart(_workContext.CurrentCustomer, product, cartType, _storeContext.CurrentStore.Id, - selectedAttributes, customerEnteredPrice, quantity, addRequiredProducts, out newCartItemId, parentCartItemId, bundleItem) + ctx.Warnings.AddRange( + AddToCart(_workContext.CurrentCustomer, ctx.Product, ctx.CartType, storeId, ctx.Attributes, ctx.CustomerEnteredPrice, ctx.Quantity, ctx.AddRequiredProducts, ctx) ); - if (product.ProductType == ProductType.BundledProduct && warnings.Count <= 0 && newCartItemId != 0 && bundleItem == null) + if (ctx.Product.ProductType == ProductType.BundledProduct && ctx.Warnings.Count <= 0 && ctx.BundleItem == null) { - foreach (var item in _productService.GetBundleItems(product.Id).Select(x => x.Item)) + foreach (var bundleItem in _productService.GetBundleItems(ctx.Product.Id).Select(x => x.Item)) { - AddToCart(warnings, item.Product, form, cartType, decimal.Zero, item.Quantity, false, newCartItemId, item); + AddToCart(new AddToCartContext + { + BundleItem = bundleItem, + Warnings = ctx.Warnings, + Item = ctx.Item, + ChildItems = ctx.ChildItems, + Product = bundleItem.Product, + Customer = customer, + AttributeForm = ctx.AttributeForm, + CartType = ctx.CartType, + Quantity = bundleItem.Quantity, + AddRequiredProducts = ctx.AddRequiredProducts, + StoreId = storeId + }); + + if (ctx.Warnings.Count > 0) + { + ctx.ChildItems.Clear(); + break; + } } + } + + if (ctx.BundleItem == null) + { + AddToCartStoring(ctx); + } + } + + /// + /// Stores the shopping card items in the database + /// + /// Add to cart context + public virtual void AddToCartStoring(AddToCartContext ctx) + { + if (ctx.Warnings.Count == 0 && ctx.Item != null) + { + var customer = ctx.Customer ?? _workContext.CurrentCustomer; - if (warnings.Count > 0) - DeleteShoppingCartItem(newCartItemId); + customer.ShoppingCartItems.Add(ctx.Item); + _customerService.UpdateCustomer(customer); + _eventPublisher.EntityInserted(ctx.Item); + + foreach (var childItem in ctx.ChildItems) + { + childItem.ParentItemId = ctx.Item.Id; + + customer.ShoppingCartItems.Add(childItem); + _customerService.UpdateCustomer(customer); + _eventPublisher.EntityInserted(childItem); + } } - return newCartItemId; } /// @@ -1116,8 +1246,7 @@ public virtual int AddToCart(List warnings, Product product, NameValueCo /// New shopping cart item quantity /// A value indicating whether to reset checkout data /// Warnings - public virtual IList UpdateShoppingCartItem(Customer customer, int shoppingCartItemId, - int newQuantity, bool resetCheckoutData) + public virtual IList UpdateShoppingCartItem(Customer customer, int shoppingCartItemId, int newQuantity, bool resetCheckoutData) { if (customer == null) throw new ArgumentNullException("customer"); @@ -1214,20 +1343,28 @@ public virtual IList Copy(OrganizedShoppingCartItem sci, Customer custom if (sci == null) throw new ArgumentNullException("item"); - int parentItemId, childItemId; + var addToCartContext = new AddToCartContext + { + Customer = customer + }; - var warnings = AddToCart(customer, sci.Item.Product, cartType, storeId, sci.Item.AttributesXml, sci.Item.CustomerEnteredPrice, - sci.Item.Quantity, addRequiredProductsIfEnabled, out parentItemId); + addToCartContext.Warnings = AddToCart(customer, sci.Item.Product, cartType, storeId, sci.Item.AttributesXml, sci.Item.CustomerEnteredPrice, + sci.Item.Quantity, addRequiredProductsIfEnabled, addToCartContext); - if (warnings.Count == 0 && parentItemId != 0 && sci.ChildItems != null) + if (addToCartContext.Warnings.Count == 0 && sci.ChildItems != null) { foreach (var childItem in sci.ChildItems) { - AddToCart(customer, childItem.Item.Product, cartType, storeId, childItem.Item.AttributesXml, childItem.Item.CustomerEnteredPrice, - childItem.Item.Quantity, false, out childItemId, parentItemId, childItem.Item.BundleItem); + addToCartContext.BundleItem = childItem.Item.BundleItem; + + addToCartContext.Warnings = AddToCart(customer, childItem.Item.Product, cartType, storeId, childItem.Item.AttributesXml, childItem.Item.CustomerEnteredPrice, + childItem.Item.Quantity, false, addToCartContext); } } - return warnings; + + AddToCartStoring(addToCartContext); + + return addToCartContext.Warnings; } #endregion diff --git a/src/Libraries/SmartStore.Services/Payments/IPaymentMethod.cs b/src/Libraries/SmartStore.Services/Payments/IPaymentMethod.cs index 3c12cc18c0..9dc48a1b85 100644 --- a/src/Libraries/SmartStore.Services/Payments/IPaymentMethod.cs +++ b/src/Libraries/SmartStore.Services/Payments/IPaymentMethod.cs @@ -9,7 +9,7 @@ namespace SmartStore.Services.Payments /// /// Provides an interface for creating payment gateways and methods /// - public partial interface IPaymentMethod : IPlugin + public partial interface IPaymentMethod : IProvider, IUserEditable { #region Methods @@ -28,7 +28,8 @@ public partial interface IPaymentMethod : IPlugin ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest); /// - /// Post process payment (used by payment gateways that require redirecting to a third-party URL) + /// Post process payment (e.g. used by payment gateways to redirect to a third-party URL). + /// Called after an order has been placed or when customer re-post the payment. /// /// Payment info required for an order processing void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest); @@ -82,14 +83,6 @@ public partial interface IPaymentMethod : IPlugin /// Result bool CanRePostProcessPayment(Order order); - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); - /// /// Gets a route for payment info /// @@ -98,23 +91,23 @@ public partial interface IPaymentMethod : IPlugin /// Route values void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); - ///// - ///// Gets a route for the payment info handler controller action - ///// - ///// Order - ///// Result - ///// - ///// The defined route is being redirected to during the checkout process > PaymentInfo page. - ///// Implementors should return null if no redirection occurs. - ///// - RouteInfo GetPaymentInfoHandlerRoute(); - Type GetControllerType(); #endregion #region Properties + /// + /// Gets a value indicating whether the payment method is active and should be offered to customers + /// + bool IsActive { get; } + + /// + /// Gets a value indicating whether the payment method requires user input + /// before proceeding (e.g. CreditCard, DirectDebit etc.) + /// + bool RequiresInteraction { get; } + /// /// Gets a value indicating whether capture is supported /// diff --git a/src/Libraries/SmartStore.Services/Payments/IPaymentMethodFilter.cs b/src/Libraries/SmartStore.Services/Payments/IPaymentMethodFilter.cs new file mode 100644 index 0000000000..4ecd12457d --- /dev/null +++ b/src/Libraries/SmartStore.Services/Payments/IPaymentMethodFilter.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.Payments +{ + public partial interface IPaymentMethodFilter + { + /// + /// Gets a value indicating whether a payment method should be filtered out + /// + /// Payment filter request + /// true filter out method, false do not filter out method + bool IsExcluded(PaymentFilterRequest request); + + /// + /// Get URL for filter configuration + /// + /// Payment provider system name + /// URL for filter configuration + string GetConfigurationUrl(string systemName); + } + + + public partial class PaymentFilterRequest + { + /// + /// The payment method to be checked + /// + public Provider PaymentMethod { get; set; } + + /// + /// The context shopping cart + /// + public IList Cart { get; set; } + + /// + /// The context store identifier + /// + public int StoreId { get; set; } + + /// + /// The context customer + /// + public Customer Customer { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs index e0fe854039..ced73b9b10 100644 --- a/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/IPaymentService.cs @@ -1,5 +1,8 @@ using System.Collections.Generic; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Payments { @@ -11,10 +14,18 @@ public partial interface IPaymentService /// /// Load active payment methods /// - /// Filter payment methods by customer; null to load all records - /// Load records allows only in specified store; pass 0 to load all records + /// Filter payment methods by customer and apply payment method restrictions; null to load all records + /// Filter payment methods by cart amount; null to load all records + /// Filter payment methods by store identifier; pass 0 to load all records + /// Filter payment methods by payment method types + /// Provide a fallback payment method if none is active /// Payment methods - IList LoadActivePaymentMethods(int? filterByCustomerId = null, int storeId = 0); + IEnumerable> LoadActivePaymentMethods( + Customer customer = null, + IList cart = null, + int storeId = 0, + PaymentMethodType[] types = null, + bool provideFallbackMethod = true); /// /// Determines whether a payment method is active\enabled for a shop @@ -26,15 +37,46 @@ public partial interface IPaymentService /// /// System name /// Found payment provider - IPaymentMethod LoadPaymentMethodBySystemName(string systemName); + Provider LoadPaymentMethodBySystemName(string systemName, bool onlyWhenActive = false, int storeId = 0); /// /// Load all payment providers /// /// Load records allows only in specified store; pass 0 to load all records /// Payment providers - IList LoadAllPaymentMethods(int storeId = 0); + IEnumerable> LoadAllPaymentMethods(int storeId = 0); + + + /// + /// Gets all payment method extra data + /// + /// List of payment method objects + IList GetAllPaymentMethods(); + + /// + /// Gets payment method extra data by system name + /// + /// Provider system name + /// Payment method entity + PaymentMethod GetPaymentMethodBySystemName(string systemName); + + /// + /// Insert payment method extra data + /// + /// Payment method + void InsertPaymentMethod(PaymentMethod paymentMethod); + /// + /// Updates payment method extra data + /// + /// Payment method + void UpdatePaymentMethod(PaymentMethod paymentMethod); + + /// + /// Delete payment method extra data + /// + /// Payment method + void DeletePaymentMethod(PaymentMethod paymentMethod); /// @@ -167,5 +209,10 @@ public partial interface IPaymentService /// Masked credit card number string GetMaskedCreditCardNumber(string creditCardNumber); + /// + /// Gets all payment filters + /// + /// List of payment filters + IList GetAllPaymentMethodFilters(); } } diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentExtentions.cs b/src/Libraries/SmartStore.Services/Payments/PaymentExtentions.cs index 2229728ae3..d9cd258259 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentExtentions.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentExtentions.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Web.Routing; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Plugins; using SmartStore.Services.Orders; namespace SmartStore.Services.Payments { - public static class PaymentExtentions + public static class PaymentExtentions { /// /// Is payment method active? @@ -14,8 +17,7 @@ public static class PaymentExtentions /// Payment method /// Payment settings /// Result - public static bool IsPaymentMethodActive(this IPaymentMethod paymentMethod, - PaymentSettings paymentSettings) + public static bool IsPaymentMethodActive(this Provider paymentMethod, PaymentSettings paymentSettings) { if (paymentMethod == null) throw new ArgumentNullException("paymentMethod"); @@ -25,10 +27,11 @@ public static bool IsPaymentMethodActive(this IPaymentMethod paymentMethod, if (paymentSettings.ActivePaymentMethodSystemNames == null) return false; - foreach (string activeMethodSystemName in paymentSettings.ActivePaymentMethodSystemNames) - if (paymentMethod.PluginDescriptor.SystemName.Equals(activeMethodSystemName, StringComparison.InvariantCultureIgnoreCase)) - return true; - return false; + + if (!paymentMethod.Value.IsActive) + return false; + + return paymentSettings.ActivePaymentMethodSystemNames.Contains(paymentMethod.Metadata.SystemName, StringComparer.OrdinalIgnoreCase); } /// @@ -41,12 +44,15 @@ public static bool IsPaymentMethodActive(this IPaymentMethod paymentMethod, /// Is fee amount specified as percentage or fixed value? /// Result public static decimal CalculateAdditionalFee(this IPaymentMethod paymentMethod, - IOrderTotalCalculationService orderTotalCalculationService, IList cart, - decimal fee, bool usePercentage) + IOrderTotalCalculationService orderTotalCalculationService, + IList cart, + decimal fee, + bool usePercentage) { if (paymentMethod == null) throw new ArgumentNullException("paymentMethod"); - if (fee <= 0) + + if (fee == decimal.Zero) return fee; var result = decimal.Zero; @@ -63,5 +69,44 @@ public static decimal CalculateAdditionalFee(this IPaymentMethod paymentMethod, } return result; } + + public static RouteInfo GetConfigurationRoute(this IPaymentMethod method) + { + Guard.ArgumentNotNull(() => method); + + string action; + string controller; + RouteValueDictionary routeValues; + + var configurable = method as IConfigurable; + + if (configurable != null) + { + configurable.GetConfigurationRoute(out action, out controller, out routeValues); + if (action.HasValue()) + { + return new RouteInfo(action, controller, routeValues); + } + } + + return null; + } + + public static RouteInfo GetPaymentInfoRoute(this IPaymentMethod method) + { + Guard.ArgumentNotNull(() => method); + + string action; + string controller; + RouteValueDictionary routeValues; + + method.GetPaymentInfoRoute(out action, out controller, out routeValues); + if (action.HasValue()) + { + return new RouteInfo(action, controller, routeValues); + } + + return null; + } } } diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentMethodBase.cs b/src/Libraries/SmartStore.Services/Payments/PaymentMethodBase.cs index eca689b9c9..3510b71b2a 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentMethodBase.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentMethodBase.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Web.Routing; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Localization; using SmartStore.Core.Plugins; namespace SmartStore.Services.Payments @@ -11,9 +12,16 @@ namespace SmartStore.Services.Payments /// /// Base class for payment methods /// - public abstract class PaymentMethodBase : BasePlugin, IPaymentMethod + public abstract class PaymentMethodBase : IPaymentMethod { + protected PaymentMethodBase() + { + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + #region Methods /// @@ -59,7 +67,9 @@ public virtual decimal GetAdditionalHandlingFee(IList /// Capture payment result public virtual CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) { - throw Error.NotSupported(); + var result = new CapturePaymentResult(); + result.AddError(T("Common.Payment.NoCaptureSupport")); + return result; } /// @@ -69,7 +79,9 @@ public virtual CapturePaymentResult Capture(CapturePaymentRequest capturePayment /// Result public virtual RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) { - throw Error.NotSupported(); + var result = new RefundPaymentResult(); + result.AddError(T("Common.Payment.NoRefundSupport")); + return result; } /// @@ -79,7 +91,9 @@ public virtual RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequ /// Result public virtual VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) { - throw Error.NotSupported(); + var result = new VoidPaymentResult(); + result.AddError(T("Common.Payment.NoVoidSupport")); + return result; } /// @@ -89,7 +103,9 @@ public virtual VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) /// Process payment result public virtual ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) { - throw Error.NotSupported(); + var result = new ProcessPaymentResult(); + result.AddError(T("Common.Payment.NoRecurringPaymentSupport")); + return result; } /// @@ -99,7 +115,9 @@ public virtual ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentReques /// Result public virtual CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) { - throw Error.NotSupported(); + var result = new CancelRecurringPaymentResult(); + result.AddError(T("Common.Payment.NoRecurringPaymentSupport")); + return result; } /// @@ -119,16 +137,6 @@ public virtual bool CanRePostProcessPayment(Order order) /// Controller name /// Route values public abstract void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); - public RouteInfo GetConfigurationRoute() - { - string action; - string controller; - RouteValueDictionary routeValues; - - this.GetConfigurationRoute(out action, out controller, out routeValues); - - return new RouteInfo(action, controller, routeValues); - } /// /// Gets a route for payment info @@ -137,16 +145,6 @@ public RouteInfo GetConfigurationRoute() /// Controller name /// Route values public abstract void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); - public RouteInfo GetPaymentInfoRoute() - { - string action; - string controller; - RouteValueDictionary routeValues; - - this.GetPaymentInfoRoute(out action, out controller, out routeValues); - - return new RouteInfo(action, controller, routeValues); - } /// /// Gets a route for the payment info handler controller action @@ -168,6 +166,29 @@ public virtual RouteInfo GetPaymentInfoHandlerRoute() #region Properties + /// + /// Gets a value indicating whether the payment method is active and should be offered to customers + /// + public virtual bool IsActive + { + get + { + return true; + } + } + + /// + /// Gets a value indicating whether the payment method requires user input + /// before proceeding (e.g. CreditCard, DirectDebit etc.) + /// + public virtual bool RequiresInteraction + { + get + { + return false; + } + } + /// /// Gets a value indicating whether capture is supported /// diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentMethodType.cs b/src/Libraries/SmartStore.Services/Payments/PaymentMethodType.cs index 04767d9afe..cfa24c23b7 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentMethodType.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentMethodType.cs @@ -25,5 +25,9 @@ public enum PaymentMethodType : int /// All payment information is entered on the site and is available via button /// StandardAndButton = 25, + /// + /// Payment information is entered in checkout and customer is redirected to complete payment (e.g. 3D Secure) after order has been placed + /// + StandardAndRedirection = 30 } } diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentPluginBase.cs b/src/Libraries/SmartStore.Services/Payments/PaymentPluginBase.cs new file mode 100644 index 0000000000..3ab7d5b6e3 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Payments/PaymentPluginBase.cs @@ -0,0 +1,28 @@ +using SmartStore.Core.Plugins; + +namespace SmartStore.Services.Payments +{ + public abstract class PaymentPluginBase : PaymentMethodBase, IPlugin + { + /// + /// Gets or sets the plugin descriptor + /// + public virtual PluginDescriptor PluginDescriptor { get; set; } + + /// + /// Install plugin + /// + public virtual void Install() + { + PluginManager.MarkPluginAsInstalled(this.PluginDescriptor.SystemName); + } + + /// + /// Uninstall plugin + /// + public virtual void Uninstall() + { + PluginManager.MarkPluginAsUninstalled(this.PluginDescriptor.SystemName); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs index 05af1183fa..0bce57bb5e 100644 --- a/src/Libraries/SmartStore.Services/Payments/PaymentService.cs +++ b/src/Libraries/SmartStore.Services/Payments/PaymentService.cs @@ -1,27 +1,39 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Events; using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; using SmartStore.Core.Plugins; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; namespace SmartStore.Services.Payments { - /// - /// Payment service - /// - public partial class PaymentService : IPaymentService + /// + /// Payment service + /// + public partial class PaymentService : IPaymentService { - #region Fields + #region Constants + + private const string PAYMENTMETHOD_ALL_KEY = "SmartStore.paymentmethod.all"; + #endregion + + #region Fields + + private readonly static object _lock = new object(); + private static IList _paymentMethodFilterTypes = null; + + private readonly IRepository _paymentMethodRepository; private readonly PaymentSettings _paymentSettings; - private readonly IPluginFinder _pluginFinder; private readonly ShoppingCartSettings _shoppingCartSettings; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; + private readonly IProviderManager _providerManager; + private readonly ICommonServices _services; + private readonly ITypeFinder _typeFinder; #endregion @@ -34,50 +46,107 @@ public partial class PaymentService : IPaymentService /// Plugin finder /// Shopping cart settings /// Plugin service - public PaymentService(PaymentSettings paymentSettings, IPluginFinder pluginFinder, + public PaymentService( + IRepository paymentMethodRepository, + PaymentSettings paymentSettings, ShoppingCartSettings shoppingCartSettings, - ISettingService settingService, - ILocalizationService localizationService) + IProviderManager providerManager, + ICommonServices services, + ITypeFinder typeFinder) { - this._paymentSettings = paymentSettings; - this._pluginFinder = pluginFinder; - this._shoppingCartSettings = shoppingCartSettings; - this._settingService = settingService; - this._localizationService = localizationService; - } + _paymentMethodRepository = paymentMethodRepository; + _paymentSettings = paymentSettings; + _shoppingCartSettings = shoppingCartSettings; + _providerManager = providerManager; + _services = services; + _typeFinder = typeFinder; + + T = NullLocalizer.Instance; + } - #endregion + public Localizer T { get; set; } - #region Methods + #endregion - /// - /// Load active payment methods - /// - /// Filter payment methods by customer; null to load all records - /// Load records allows only in specified store; pass 0 to load all records - /// Payment methods - public virtual IList LoadActivePaymentMethods(int? filterByCustomerId = null, int storeId = 0) - { - return LoadAllPaymentMethods(storeId) - .Where(provider => _paymentSettings.ActivePaymentMethodSystemNames.Contains(provider.PluginDescriptor.SystemName, StringComparer.InvariantCultureIgnoreCase)) - .ToList(); - } + #region Methods /// - /// Determines whether a payment method is active\enabled for a shop + /// Load active payment methods /// - public virtual bool IsPaymentMethodActive(string systemName, int storeId = 0) - { - var method = LoadActivePaymentMethods() - .FirstOrDefault(x => x.PluginDescriptor.SystemName == systemName && x.PluginDescriptor.Installed); + /// Filter payment methods by customer and apply payment method restrictions; null to load all records + /// Filter payment methods by cart amount; null to load all records + /// Filter payment methods by store identifier; pass 0 to load all records + /// Filter payment methods by payment method types + /// Provide a fallback payment method if none is active + /// Payment methods + public virtual IEnumerable> LoadActivePaymentMethods( + Customer customer = null, + IList cart = null, + int storeId = 0, + PaymentMethodType[] types = null, + bool provideFallbackMethod = true) + { + IList allFilters = null; + IEnumerable> allProviders = null; - if (method != null) + var filterRequest = new PaymentFilterRequest { - if (storeId == 0 || _settingService.GetSettingByKey(method.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) + Cart = cart, + StoreId = storeId, + Customer = customer + }; + + if (types != null && types.Any()) + allProviders = LoadAllPaymentMethods(storeId).Where(x => types.Contains(x.Value.PaymentMethodType)); + else + allProviders = LoadAllPaymentMethods(storeId); + + var activeProviders = allProviders + .Where(p => + { + if (!p.Value.IsActive || !_paymentSettings.ActivePaymentMethodSystemNames.Contains(p.Metadata.SystemName, StringComparer.InvariantCultureIgnoreCase)) + return false; + + // payment method filtering + if (allFilters == null) + allFilters = GetAllPaymentMethodFilters(); + + filterRequest.PaymentMethod = p; + + if (allFilters.Any(x => x.IsExcluded(filterRequest))) + return false; + return true; + }); + + if (!activeProviders.Any() && provideFallbackMethod) + { + var fallbackMethod = allProviders.FirstOrDefault(x => x.IsPaymentMethodActive(_paymentSettings)); + + if (fallbackMethod == null) + fallbackMethod = allProviders.FirstOrDefault(); + + if (fallbackMethod != null) + { + return new Provider[] { fallbackMethod }; + } + else + { + if (DataSettings.DatabaseIsInstalled()) + throw new SmartException(T("Payment.OneActiveMethodProviderRequired")); + } } - return false; + return activeProviders; + } + + /// + /// Determines whether a payment method is active\enabled for a shop + /// + public virtual bool IsPaymentMethodActive(string systemName, int storeId = 0) + { + var method = LoadPaymentMethodBySystemName(systemName, true, storeId); + return method != null; } /// @@ -85,13 +154,14 @@ public virtual bool IsPaymentMethodActive(string systemName, int storeId = 0) /// /// System name /// Found payment provider - public virtual IPaymentMethod LoadPaymentMethodBySystemName(string systemName) + public virtual Provider LoadPaymentMethodBySystemName(string systemName, bool onlyWhenActive = false, int storeId = 0) { - var descriptor = _pluginFinder.GetPluginDescriptorBySystemName(systemName); - if (descriptor != null) - return descriptor.Instance(); - - return null; + var provider = _providerManager.GetProvider(systemName, storeId); + if (provider != null && onlyWhenActive && !provider.IsPaymentMethodActive(_paymentSettings)) + { + return null; + } + return provider; } /// @@ -99,15 +169,79 @@ public virtual IPaymentMethod LoadPaymentMethodBySystemName(string systemName) /// /// Load records allows only in specified store; pass 0 to load all records /// Payment providers - public virtual IList LoadAllPaymentMethods(int storeId = 0) + public virtual IEnumerable> LoadAllPaymentMethods(int storeId = 0) { - return _pluginFinder - .GetPlugins() - .Where(x => storeId == 0 || _settingService.GetSettingByKey(x.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) - .ToList(); + return _providerManager.GetAllProviders(storeId); } + /// + /// Gets all payment method extra data + /// + /// List of payment method objects + public virtual IList GetAllPaymentMethods() + { + var methods = _paymentMethodRepository.TableUntracked.ToList(); + return methods; + } + + /// + /// Gets payment method extra data by system name + /// + /// Provider system name + /// Payment method entity + public virtual PaymentMethod GetPaymentMethodBySystemName(string systemName) + { + if (systemName.HasValue()) + { + return _paymentMethodRepository.Table.FirstOrDefault(x => x.PaymentMethodSystemName == systemName); + } + return null; + } + + /// + /// Insert payment method extra data + /// + /// Payment method + public virtual void InsertPaymentMethod(PaymentMethod paymentMethod) + { + if (paymentMethod == null) + throw new ArgumentNullException("paymentMethod"); + + _paymentMethodRepository.Insert(paymentMethod); + + _services.EventPublisher.EntityInserted(paymentMethod); + } + + /// + /// Updates payment method extra data + /// + /// Payment method + public virtual void UpdatePaymentMethod(PaymentMethod paymentMethod) + { + if (paymentMethod == null) + throw new ArgumentNullException("paymentMethod"); + + _paymentMethodRepository.Update(paymentMethod); + + _services.EventPublisher.EntityUpdated(paymentMethod); + } + + /// + /// Delete payment method extra data + /// + /// Payment method + public virtual void DeletePaymentMethod(PaymentMethod paymentMethod) + { + if (paymentMethod == null) + throw new ArgumentNullException("paymentMethod"); + + _paymentMethodRepository.Delete(paymentMethod); + + _services.EventPublisher.EntityDeleted(paymentMethod); + } + + /// /// Pre process a payment /// @@ -124,9 +258,9 @@ public virtual PreProcessPaymentResult PreProcessPayment(ProcessPaymentRequest p { var paymentMethod = LoadPaymentMethodBySystemName(processPaymentRequest.PaymentMethodSystemName); if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); + throw new SmartException(T("Payment.CouldNotLoadMethod")); - return paymentMethod.PreProcessPayment(processPaymentRequest); + return paymentMethod.Value.PreProcessPayment(processPaymentRequest); } } @@ -153,27 +287,31 @@ public virtual ProcessPaymentResult ProcessPayment(ProcessPaymentRequest process processPaymentRequest.CreditCardNumber = processPaymentRequest.CreditCardNumber.Replace(" ", ""); processPaymentRequest.CreditCardNumber = processPaymentRequest.CreditCardNumber.Replace("-", ""); } - var paymentMethod = LoadPaymentMethodBySystemName(processPaymentRequest.PaymentMethodSystemName); - if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); - return paymentMethod.ProcessPayment(processPaymentRequest); + + var paymentMethod = LoadPaymentMethodBySystemName(processPaymentRequest.PaymentMethodSystemName); + + if (paymentMethod == null) + throw new SmartException(T("Payment.CouldNotLoadMethod")); + + return paymentMethod.Value.ProcessPayment(processPaymentRequest); } } /// - /// Post process payment (used by payment gateways that require redirecting to a third-party URL) + /// Post process payment (e.g. used by payment gateways to redirect to a third-party URL). + /// Called after an order has been placed or when customer re-post the payment. /// /// Payment info required for an order processing public virtual void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest) { - //already paid or order.OrderTotal == decimal.Zero - if (postProcessPaymentRequest.Order.PaymentStatus == PaymentStatus.Paid) - return; + if (postProcessPaymentRequest.Order.PaymentMethodSystemName.HasValue()) + { + var paymentMethod = LoadPaymentMethodBySystemName(postProcessPaymentRequest.Order.PaymentMethodSystemName); + if (paymentMethod == null) + throw new SmartException(T("Payment.CouldNotLoadMethod")); - var paymentMethod = LoadPaymentMethodBySystemName(postProcessPaymentRequest.Order.PaymentMethodSystemName); - if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); - paymentMethod.PostProcessPayment(postProcessPaymentRequest); + paymentMethod.Value.PostProcessPayment(postProcessPaymentRequest); + } } /// @@ -193,7 +331,7 @@ public virtual bool CanRePostProcessPayment(Order order) if (paymentMethod == null) return false; //Payment method couldn't be loaded (for example, was uninstalled) - if (paymentMethod.PaymentMethodType != PaymentMethodType.Redirection) + if (paymentMethod.Value.PaymentMethodType != PaymentMethodType.Redirection && paymentMethod.Value.PaymentMethodType != PaymentMethodType.StandardAndRedirection) return false; //this option is available only for redirection payment methods if (order.Deleted) @@ -205,7 +343,7 @@ public virtual bool CanRePostProcessPayment(Order order) if (order.PaymentStatus != PaymentStatus.Pending) return false; //payment status should be Pending - return paymentMethod.CanRePostProcessPayment(order); + return paymentMethod.Value.CanRePostProcessPayment(order); } @@ -219,15 +357,14 @@ public virtual bool CanRePostProcessPayment(Order order) public virtual decimal GetAdditionalHandlingFee(IList cart, string paymentMethodSystemName) { var paymentMethod = LoadPaymentMethodBySystemName(paymentMethodSystemName); - if (paymentMethod == null) - return decimal.Zero; - - decimal result = paymentMethod.GetAdditionalHandlingFee(cart); - if (result < decimal.Zero) - result = decimal.Zero; - if (_shoppingCartSettings.RoundPricesDuringCalculation) - result = Math.Round(result, 2); - return result; + var paymentMethodAdditionalFee = (paymentMethod != null ? paymentMethod.Value.GetAdditionalHandlingFee(cart) : decimal.Zero); + + if (_shoppingCartSettings.RoundPricesDuringCalculation) + { + paymentMethodAdditionalFee = Math.Round(paymentMethodAdditionalFee, 2); + } + + return paymentMethodAdditionalFee; } @@ -242,7 +379,7 @@ public virtual bool SupportCapture(string paymentMethodSystemName) var paymentMethod = LoadPaymentMethodBySystemName(paymentMethodSystemName); if (paymentMethod == null) return false; - return paymentMethod.SupportCapture; + return paymentMethod.Value.SupportCapture; } /// @@ -254,16 +391,16 @@ public virtual CapturePaymentResult Capture(CapturePaymentRequest capturePayment { var paymentMethod = LoadPaymentMethodBySystemName(capturePaymentRequest.Order.PaymentMethodSystemName); if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); + throw new SmartException(T("Payment.CouldNotLoadMethod")); try { - return paymentMethod.Capture(capturePaymentRequest); + return paymentMethod.Value.Capture(capturePaymentRequest); } catch (NotSupportedException) { var result = new CapturePaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoCaptureSupport")); + result.AddError(T("Common.Payment.NoCaptureSupport")); return result; } catch @@ -284,7 +421,7 @@ public virtual bool SupportPartiallyRefund(string paymentMethodSystemName) var paymentMethod = LoadPaymentMethodBySystemName(paymentMethodSystemName); if (paymentMethod == null) return false; - return paymentMethod.SupportPartiallyRefund; + return paymentMethod.Value.SupportPartiallyRefund; } /// @@ -297,7 +434,7 @@ public virtual bool SupportRefund(string paymentMethodSystemName) var paymentMethod = LoadPaymentMethodBySystemName(paymentMethodSystemName); if (paymentMethod == null) return false; - return paymentMethod.SupportRefund; + return paymentMethod.Value.SupportRefund; } /// @@ -309,16 +446,16 @@ public virtual RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequ { var paymentMethod = LoadPaymentMethodBySystemName(refundPaymentRequest.Order.PaymentMethodSystemName); if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); + throw new SmartException(T("Payment.CouldNotLoadMethod")); try { - return paymentMethod.Refund(refundPaymentRequest); + return paymentMethod.Value.Refund(refundPaymentRequest); } catch (NotSupportedException) { var result = new RefundPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRefundSupport")); + result.AddError(T("Common.Payment.NoRefundSupport")); return result; } catch @@ -339,7 +476,7 @@ public virtual bool SupportVoid(string paymentMethodSystemName) var paymentMethod = LoadPaymentMethodBySystemName(paymentMethodSystemName); if (paymentMethod == null) return false; - return paymentMethod.SupportVoid; + return paymentMethod.Value.SupportVoid; } /// @@ -351,16 +488,16 @@ public virtual VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) { var paymentMethod = LoadPaymentMethodBySystemName(voidPaymentRequest.Order.PaymentMethodSystemName); if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); + throw new SmartException(T("Payment.CouldNotLoadMethod")); try { - return paymentMethod.Void(voidPaymentRequest); + return paymentMethod.Value.Void(voidPaymentRequest); } catch (NotSupportedException) { var result = new VoidPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoVoidSupport")); + result.AddError(T("Common.Payment.NoVoidSupport")); return result; } catch @@ -381,7 +518,8 @@ public virtual RecurringPaymentType GetRecurringPaymentType(string paymentMethod var paymentMethod = LoadPaymentMethodBySystemName(paymentMethodSystemName); if (paymentMethod == null) return RecurringPaymentType.NotSupported; - return paymentMethod.RecurringPaymentType; + + return paymentMethod.Value.RecurringPaymentType; } /// @@ -403,16 +541,16 @@ public virtual ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentReques { var paymentMethod = LoadPaymentMethodBySystemName(processPaymentRequest.PaymentMethodSystemName); if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); + throw new SmartException(T("Payment.CouldNotLoadMethod")); try { - return paymentMethod.ProcessRecurringPayment(processPaymentRequest); + return paymentMethod.Value.ProcessRecurringPayment(processPaymentRequest); } catch (NotSupportedException) { var result = new ProcessPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); + result.AddError(T("Common.Payment.NoRecurringPaymentSupport")); return result; } catch @@ -434,16 +572,16 @@ public virtual CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurri var paymentMethod = LoadPaymentMethodBySystemName(cancelPaymentRequest.Order.PaymentMethodSystemName); if (paymentMethod == null) - throw new SmartException("Payment method couldn't be loaded"); + throw new SmartException(T("Payment.CouldNotLoadMethod")); try { - return paymentMethod.CancelRecurringPayment(cancelPaymentRequest); + return paymentMethod.Value.CancelRecurringPayment(cancelPaymentRequest); } catch (NotSupportedException) { var result = new CancelRecurringPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); + result.AddError(T("Common.Payment.NoRecurringPaymentSupport")); return result; } catch @@ -464,7 +602,8 @@ public virtual PaymentMethodType GetPaymentMethodType(string paymentMethodSystem var paymentMethod = LoadPaymentMethodBySystemName(paymentMethodSystemName); if (paymentMethod == null) return PaymentMethodType.Unknown; - return paymentMethod.PaymentMethodType; + + return paymentMethod.Value.PaymentMethodType; } /// @@ -489,6 +628,27 @@ public virtual string GetMaskedCreditCardNumber(string creditCardNumber) return maskedChars + last4; } - #endregion - } + public virtual IList GetAllPaymentMethodFilters() + { + if (_paymentMethodFilterTypes == null) + { + lock (_lock) + { + if (_paymentMethodFilterTypes == null) + { + _paymentMethodFilterTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true) + .ToList(); + } + } + } + + var paymentMethodFilters = _paymentMethodFilterTypes + .Select(x => EngineContext.Current.ContainerManager.ResolveUnregistered(x) as IPaymentMethodFilter) + .ToList(); + + return paymentMethodFilters; + } + + #endregion + } } diff --git a/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs b/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs index aefd8c76b3..f14a6cc6aa 100644 --- a/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs +++ b/src/Libraries/SmartStore.Services/Payments/PostProcessPaymentRequest.cs @@ -11,5 +11,15 @@ public partial class PostProcessPaymentRequest /// Gets or sets an order. Used when order is already saved (payment gateways that redirect a customer to a third-party URL) /// public Order Order { get; set; } + + /// + /// Whether the customer clicked the button to re-post the payment process + /// + public bool IsRePostProcessPayment { get; set; } + + /// + /// URL to a payment provider to fulfill the payment. The .NET core will redirect to it. + /// + public string RedirectUrl { get; set; } } } diff --git a/src/Libraries/SmartStore.Services/Payments/ProcessPaymentRequest.cs b/src/Libraries/SmartStore.Services/Payments/ProcessPaymentRequest.cs index d4c42f0926..a3ba77cb5b 100644 --- a/src/Libraries/SmartStore.Services/Payments/ProcessPaymentRequest.cs +++ b/src/Libraries/SmartStore.Services/Payments/ProcessPaymentRequest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Orders; namespace SmartStore.Services.Payments { @@ -12,7 +13,9 @@ public partial class ProcessPaymentRequest { public ProcessPaymentRequest() { - this.CustomProperties = new Dictionary(); + CustomProperties = new Dictionary(); + IsMultiOrder = false; + ShoppingCartItems = new List(); } /// @@ -35,11 +38,21 @@ public ProcessPaymentRequest() /// public decimal OrderTotal { get; set; } + /// + /// Gets or sets an order tax total + /// + public decimal OrderTax { get; set; } + /// /// Gets or sets a payment method identifier /// public string PaymentMethodSystemName { get; set; } + /// + /// Gets or sets a payment method identifier + /// + public bool IsMultiOrder { get; set; } + /// /// Use that dictionary for any payment method or checkout flow specific data /// @@ -109,7 +122,6 @@ public ProcessPaymentRequest() public string DirectDebitBic { get; set; } public bool IsShippingMethodSet { get; set; } - public bool RequiresPaymentWorkflow { get; set; } #endregion @@ -140,6 +152,8 @@ public ProcessPaymentRequest() /// public int RecurringTotalCycles { get; set; } + public IList ShoppingCartItems { get; set; } + #endregion } diff --git a/src/Libraries/SmartStore.Services/Pdf/Content/IPdfContent.cs b/src/Libraries/SmartStore.Services/Pdf/Content/IPdfContent.cs new file mode 100644 index 0000000000..9a1319426c --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/Content/IPdfContent.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SmartStore.Services.Pdf +{ + public interface IPdfContent + { + PdfContentKind Kind { get; } + + string Process(string flag); + + void WriteArguments(string flag, StringBuilder builder); + + void Teardown(); + } + + public enum PdfContentKind + { + Html, + Url + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/Content/PdfHtmlContent.cs b/src/Libraries/SmartStore.Services/Pdf/Content/PdfHtmlContent.cs new file mode 100644 index 0000000000..4a4cd59928 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/Content/PdfHtmlContent.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using SmartStore.Core; + +namespace SmartStore.Services.Pdf +{ + public class PdfHtmlContent : IPdfContent + { + private string _html; + private string _originalHtml; + private bool _processed; + private string _tempFilePath; + private PdfContentKind _kind = PdfContentKind.Html; + + public PdfHtmlContent(string html) + { + Guard.ArgumentNotEmpty(() => html); + + _originalHtml = html; + _html = html; + } + + public PdfContentKind Kind + { + get { return _kind; } + } + + public string Process(string flag) + { + if (!_processed) + { + if (HttpContext.Current != null && HttpContext.Current.Request != null) + { + _html = WebHelper.MakeAllUrlsAbsolute(_html, new HttpRequestWrapper(HttpContext.Current.Request)); + if (!flag.IsCaseInsensitiveEqual("page")) + { + CreateTempFile(); + } + } + _processed = true; + } + + return _tempFilePath ?? _html; + } + + private void CreateTempFile() + { + // TODO: (mc) This is a very weak mechanism to determine if html is partial. Find a better way! + bool isPartial = !_html.Trim().StartsWith("\r\n\r\n{0}\r\n", html); + } + + public void WriteArguments(string flag, StringBuilder builder) + { + // noop + } + + public void Teardown() + { + if (_tempFilePath != null && File.Exists(_tempFilePath)) + { + try + { + File.Delete(_tempFilePath); + } + catch { } + } + + _kind = PdfContentKind.Html; + _html = _originalHtml; + _tempFilePath = null; + _processed = false; + } + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/Content/PdfUrlContent.cs b/src/Libraries/SmartStore.Services/Pdf/Content/PdfUrlContent.cs new file mode 100644 index 0000000000..c456b5e172 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/Content/PdfUrlContent.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Security; +using SmartStore.Core; + +namespace SmartStore.Services.Pdf +{ + public class PdfUrlContent : IPdfContent + { + private readonly string _url; + + public PdfUrlContent(string url) + { + Guard.ArgumentNotEmpty(() => url); + _url = url; + + this.SendAuthCookie = false; + this.Post = new Dictionary(); + this.Cookies = new Dictionary(); + } + + #region Options + + /// + /// Send FormsAuthentication cookie to authorize + /// + public bool SendAuthCookie { get; set; } + + /// + /// HTTP Authentication username. + /// + public string UserName { get; set; } + + /// + /// HTTP Authentication password. + /// + public string Password { get; set; } + + /// + /// Sets cookies. + /// + public IDictionary Post { get; set; } + + /// + /// Sets post values. + /// + public IDictionary Cookies { get; set; } + + #endregion + + public PdfContentKind Kind + { + get { return PdfContentKind.Url; } + } + + protected virtual string GetAbsoluteUrl() + { + if (HttpContext.Current != null && HttpContext.Current.Request != null) + { + return WebHelper.GetAbsoluteUrl(_url, new HttpRequestWrapper(HttpContext.Current.Request)); + } + + return _url; + } + + public string Process(string flag) + { + return GetAbsoluteUrl(); + } + + public void WriteArguments(string flag, StringBuilder builder) + { + if (UserName.HasValue()) + { + builder.AppendFormat(CultureInfo.InvariantCulture, " --username {0}", UserName); + } + + if (Password.HasValue()) + { + builder.AppendFormat(CultureInfo.InvariantCulture, " --password {0}", Password); + } + + if (Post != null && Post.Count > 0) + { + CreateRepeatableFlags("--post", Post, builder); + } + + if (Cookies != null && Cookies.Count > 0) + { + CreateRepeatableFlags("--cookie", Cookies, builder); + } + + // Send FormsAuthentication Cookie + var ctx = HttpContext.Current; + if (SendAuthCookie && ctx != null && ctx.Request != null && ctx.Request.Cookies != null) + { + var authCookieName = FormsAuthentication.FormsCookieName; + if (Cookies == null || !Cookies.ContainsKey(authCookieName)) + { + HttpCookie authCookie = null; + if (ctx.Request.Cookies.AllKeys.Contains(authCookieName)) + { + authCookie = ctx.Request.Cookies[authCookieName]; + } + if (authCookie != null) + { + var authCookieValue = authCookie.Value; + builder.AppendFormat(CultureInfo.InvariantCulture, " {0} {1} {2}", "--cookie", authCookieName, authCookieValue); + } + } + } + } + + private void CreateRepeatableFlags(string flagName, IDictionary dict, StringBuilder sb) + { + foreach (var kvp in dict) + { + sb.AppendFormat(CultureInfo.InvariantCulture, " {0} {1} {2}", flagName, kvp.Key, kvp.Value.EmptyNull()); + } + } + + public void Teardown() + { + // noop + } + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/IPdfConverter.cs b/src/Libraries/SmartStore.Services/Pdf/IPdfConverter.cs new file mode 100644 index 0000000000..69bcad9872 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/IPdfConverter.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SmartStore.Services.Pdf +{ + public interface IPdfConverter + { + /// + /// Converts html content to PDF + /// + /// The settings to be used for the conversion process + /// The PDF binary data + byte[] Convert(PdfConvertSettings settings); + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/Options/IPdfOptions.cs b/src/Libraries/SmartStore.Services/Pdf/Options/IPdfOptions.cs new file mode 100644 index 0000000000..468a73ae6e --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/Options/IPdfOptions.cs @@ -0,0 +1,16 @@ +using System; +using System.Text; + +namespace SmartStore.Services.Pdf +{ + public interface IPdfOptions + { + /// + /// Processes the options by converting them to native arguments + /// + /// The section flag + /// The builder + /// Possible flags are: page | header | footer | cover | toc + void Process(string flag, StringBuilder builder); + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/Options/PdfHeaderFooterOptions.cs b/src/Libraries/SmartStore.Services/Pdf/Options/PdfHeaderFooterOptions.cs new file mode 100644 index 0000000000..2456fd4743 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/Options/PdfHeaderFooterOptions.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace SmartStore.Services.Pdf +{ + public class PdfHeaderFooterOptions : IPdfOptions + { + + public PdfHeaderFooterOptions() + { + Spacing = 5; + FontSize = 10; + } + + /// + /// Spacing between footer and content in mm (default 0) + /// + public float? Spacing { get; set; } + + /// + /// Display line below the header / above the footer + /// + public bool ShowLine { get; set; } + + /// + /// Set font name (default Arial) + /// + public string FontName { get; set; } + + /// + /// Set font size (default 12) + /// + public float? FontSize { get; set; } + + /// + /// Left aligned text + /// + public string TextLeft { get; set; } + + /// + /// Centered text + /// + public string TextCenter { get; set; } + + /// + /// Right aligned text + /// + public string TextRight { get; set; } + + public bool HasText + { + get { return TextLeft.HasValue() || TextCenter.HasValue() || TextRight.HasValue(); } + } + + public void Process(string flag, StringBuilder builder) + { + if (Spacing.HasValue) + { + builder.AppendFormat(CultureInfo.InvariantCulture, " --{0}-spacing {1}", flag, Spacing.Value); + } + + if (ShowLine) + { + builder.AppendFormat(" --{0}-line", flag); + } + + if (HasText) + { + if (FontName.HasValue()) + { + builder.AppendFormat(CultureInfo.InvariantCulture, " --{0}-font-name \"{1}\"", flag, FontName); + } + if (FontSize.HasValue) + { + builder.AppendFormat(CultureInfo.InvariantCulture, " --{0}-font-size {1}", flag, FontSize.Value); + } + } + + if (TextLeft.HasValue()) + { + builder.AppendFormat(CultureInfo.CurrentCulture, " --{0}-left \"{1}\"", flag, TextLeft); + } + if (TextCenter.HasValue()) + { + builder.AppendFormat(CultureInfo.CurrentCulture, " --{0}-center \"{1}\"", flag, TextCenter); + } + if (TextRight.HasValue()) + { + builder.AppendFormat(CultureInfo.CurrentCulture, " --{0}-right \"{1}\"", flag, TextRight); + } + } + + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/Options/PdfPageOptions.cs b/src/Libraries/SmartStore.Services/Pdf/Options/PdfPageOptions.cs new file mode 100644 index 0000000000..2db0049016 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/Options/PdfPageOptions.cs @@ -0,0 +1,72 @@ +using System; +using System.Globalization; +using System.Text; + +namespace SmartStore.Services.Pdf +{ + public class PdfPageOptions : IPdfOptions + { + + public PdfPageOptions() + { + this.Zoom = 1f; + this.UsePrintMediaType = true; + } + + /// + /// Get or set zoom factor + /// + public float Zoom { get; set; } + + /// + /// Indicates whether the page background should be disabled. + /// + public bool BackgroundDisabled { get; set; } + + /// + /// Use print media-type instead of screen + /// + public bool UsePrintMediaType { get; set; } + + /// + /// Specifies a user style sheet to load with every page + /// + public string UserStylesheetUrl { get; set; } + + /// + /// Custom page pdf tool options + /// + public string CustomFlags { get; set; } + + + + public virtual void Process(string flag, StringBuilder builder) + { + if (UserStylesheetUrl.HasValue()) + { + builder.AppendFormat(CultureInfo.InvariantCulture, " --user-style-sheet \"{0}\"", UserStylesheetUrl); + } + + if (UsePrintMediaType) + { + builder.Append(" --print-media-type"); + } + + if (BackgroundDisabled) + { + builder.Append(" --no-background"); + } + + if (Zoom != 1 /*&& flag.IsCaseInsensitiveEqual("page")*/) + { + builder.AppendFormat(" --zoom {0}", Zoom); + } + + if (CustomFlags.HasValue()) + { + builder.AppendFormat(" {0}", CustomFlags); + } + } + + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/Options/PdfTocOptions.cs b/src/Libraries/SmartStore.Services/Pdf/Options/PdfTocOptions.cs new file mode 100644 index 0000000000..89692ca7e6 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/Options/PdfTocOptions.cs @@ -0,0 +1,78 @@ +using System; +using System.Globalization; +using System.Text; + +namespace SmartStore.Services.Pdf +{ + public class PdfTocOptions : PdfPageOptions + { + public PdfTocOptions() + : base() + { + } + + /// + /// TOC creation enabled + /// + public bool Enabled { get; set; } + + /// + /// The header text of the toc (default Table of Contents) + /// + public string TocHeaderText { get; set; } + + /// + /// Do not use dotted lines in the toc + /// + public bool DisableDottedLines { get; set; } + + /// + /// Do not link from toc to sections + /// + public bool DisableTocLinks { get; set; } + + /// + /// For each level of headings in the toc indent by this length (default 1em) + /// + public string TocLevelIndendation { get; set; } + + /// + /// For each level of headings in the toc the font is scaled by this factor (default 0.8) + /// + public float? TocTextSizeShrink { get; set; } + + + public override void Process(string flag, StringBuilder builder) + { + builder.Append(" toc"); + + if (TocHeaderText.HasValue()) + { + builder.AppendFormat(" --toc-header-text \"{0}\"", TocHeaderText.Replace("\"", "\\\"")); + } + + if (DisableDottedLines) + { + builder.Append(" --disable-dotted-lines"); + } + + if (DisableTocLinks) + { + builder.Append(" --disable-toc-links"); + } + + if (TocLevelIndendation.HasValue()) + { + builder.AppendFormat(" --toc-level-indentation {0}", TocLevelIndendation); + } + + if (TocTextSizeShrink.HasValue) + { + builder.AppendFormat(" --toc-text-size-shrink {0}", TocTextSizeShrink.Value); + } + + base.Process(flag, builder); + } + + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/PdfConvertSettings.cs b/src/Libraries/SmartStore.Services/Pdf/PdfConvertSettings.cs new file mode 100644 index 0000000000..a1f32ace0f --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/PdfConvertSettings.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.Security; + +namespace SmartStore.Services.Pdf +{ + public class PdfConvertSettings + { + public PdfConvertSettings() + { + this.Margins = new PdfPageMargins(); + this.Orientation = PdfPagePrientation.Default; + this.Size = PdfPageSize.Default; + this.PageOptions = new PdfPageOptions(); + this.HeaderOptions = new PdfHeaderFooterOptions(); + this.FooterOptions = new PdfHeaderFooterOptions(); + this.CoverOptions = new PdfPageOptions(); + this.TocOptions = new PdfTocOptions(); + } + + /// + /// The title of the generated pdf file (The title of the first document is used if not specified) + /// + public string Title { get; set; } + + /// + /// Get or set option to generate grayscale PDF + /// + public bool Grayscale { get; set; } + + /// + /// Get or set option to generate low quality PDF (shrink the result document space) + /// + public bool LowQuality { get; set; } + + /// + /// Get or set PDF page margins (in mm) + /// + public PdfPageMargins Margins { get; set; } + + /// + /// Get or set PDF page orientation + /// + public PdfPagePrientation Orientation { get; set; } + + /// + /// Get or set PDF page width (in mm) + /// + public float? PageWidth { get; set; } + + /// + /// Get or set PDF page height (in mm) + /// + public float? PageHeight { get; set; } + + /// + /// Get or set PDF page orientation + /// + public PdfPageSize Size { get; set; } + + /// + /// Custom global pdf tool options + /// + public string CustomFlags { get; set; } + + + + /// + /// Cover content + /// + public IPdfContent Cover { get; set; } + + /// + /// Cover content options + /// + public PdfPageOptions CoverOptions { get; set; } + + /// + /// Toc (table of contents) options + /// + public PdfTocOptions TocOptions { get; set; } + + /// + /// Page content (required) + /// + public IPdfContent Page { get; set; } + + /// + /// Page content options + /// + public PdfPageOptions PageOptions { get; set; } + + /// + /// Footer content + /// + public IPdfContent Footer { get; set; } + + /// + /// Footer content options + /// + public PdfHeaderFooterOptions FooterOptions { get; set; } + + /// + /// Header content + /// + public IPdfContent Header { get; set; } + + /// + /// Header content options + /// + public PdfHeaderFooterOptions HeaderOptions { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/PdfPageMargins.cs b/src/Libraries/SmartStore.Services/Pdf/PdfPageMargins.cs new file mode 100644 index 0000000000..a33aec6bbe --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/PdfPageMargins.cs @@ -0,0 +1,17 @@ +using System; + +namespace SmartStore.Services.Pdf +{ + public class PdfPageMargins + { + public PdfPageMargins() + { + Left = 20; + } + + public float? Bottom { get; set; } + public float? Left { get; set; } + public float? Right { get; set; } + public float? Top { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/PdfPagePrientation.cs b/src/Libraries/SmartStore.Services/Pdf/PdfPagePrientation.cs new file mode 100644 index 0000000000..6c46162167 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/PdfPagePrientation.cs @@ -0,0 +1,11 @@ +using System; + +namespace SmartStore.Services.Pdf +{ + public enum PdfPagePrientation + { + Default, + Landscape, + Portrait + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/PdfPageSize.cs b/src/Libraries/SmartStore.Services/Pdf/PdfPageSize.cs new file mode 100644 index 0000000000..c6865b5b0e --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/PdfPageSize.cs @@ -0,0 +1,12 @@ +using System; + +namespace SmartStore.Services.Pdf +{ + public enum PdfPageSize + { + Default, + A4, + A3, + Letter + } +} diff --git a/src/Libraries/SmartStore.Services/Pdf/WkHtmlToPdfConverter.cs b/src/Libraries/SmartStore.Services/Pdf/WkHtmlToPdfConverter.cs new file mode 100644 index 0000000000..4694512828 --- /dev/null +++ b/src/Libraries/SmartStore.Services/Pdf/WkHtmlToPdfConverter.cs @@ -0,0 +1,161 @@ +using System; +using System.Globalization; +using System.Text; +using NReco.PdfGenerator; +using SmartStore.Core.Logging; +using SmartStore.Utilities; + +namespace SmartStore.Services.Pdf +{ + public class WkHtmlToPdfConverter : IPdfConverter + { + public WkHtmlToPdfConverter() + { + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + + + public byte[] Convert(PdfConvertSettings settings) + { + Guard.ArgumentNotNull(() => settings); + if (settings.Page == null) + { + throw Error.InvalidOperation("The 'Page' property of the 'settings' argument cannot be null."); + } + + try + { + var converter = CreateWkConverter(settings); + + var input = settings.Page.Process("page"); + + if (settings.Page.Kind == PdfContentKind.Url) + { + return converter.GeneratePdfFromFile(input, null); + } + else + { + return converter.GeneratePdf(input, null); + } + } + catch (Exception ex) + { + Logger.Error("Html to Pdf conversion error", ex); + throw; + } + finally + { + TeardownContent(settings.Cover); + TeardownContent(settings.Footer); + TeardownContent(settings.Header); + TeardownContent(settings.Page); + } + } + + private void TeardownContent(IPdfContent content) + { + if (content != null) + content.Teardown(); + } + + internal HtmlToPdfConverter CreateWkConverter(PdfConvertSettings settings) + { + // Global options + var converter = new HtmlToPdfConverter + { + Grayscale = settings.Grayscale, + LowQuality = settings.LowQuality, + Orientation = (PageOrientation)(int)settings.Orientation, + PageHeight = settings.PageHeight, + PageWidth = settings.PageWidth, + Size = (PageSize)(int)settings.Size, + PdfToolPath = FileSystemHelper.TempDir("wkhtmltopdf") + }; + + if (settings.Margins != null) + { + converter.Margins.Bottom = settings.Margins.Bottom; + converter.Margins.Left = settings.Margins.Left; + converter.Margins.Right = settings.Margins.Right; + converter.Margins.Top = settings.Margins.Top; + } + + var sb = new StringBuilder(settings.CustomFlags); + + // doc title + if (settings.Title.HasValue()) + { + sb.AppendFormat(CultureInfo.CurrentCulture, " --title \"{0}\"", settings.Title); + } + + // Cover content & options + if (settings.Cover != null) + { + var path = settings.Cover.Process("cover"); + if (path.HasValue()) + { + sb.AppendFormat(" cover \"{0}\" ", path); + settings.Cover.WriteArguments("cover", sb); + if (settings.CoverOptions != null) + { + settings.CoverOptions.Process("cover", sb); + } + } + } + + // Toc options + if (settings.TocOptions != null && settings.TocOptions.Enabled) + { + settings.TocOptions.Process("toc", sb); + } + + // apply cover & toc + converter.CustomWkHtmlArgs = sb.ToString().Trim().NullEmpty(); + sb.Clear(); + + // Page options + if (settings.PageOptions != null) + { + settings.PageOptions.Process("page", sb); + } + + // Header content & options + if (settings.Header != null) + { + var path = settings.Header.Process("header"); + if (path.HasValue()) + { + sb.AppendFormat(" --header-html \"{0}\"", path); + settings.Header.WriteArguments("header", sb); + } + } + if (settings.HeaderOptions != null && (settings.Header != null || settings.HeaderOptions.HasText)) + { + settings.HeaderOptions.Process("header", sb); + } + + // Footer content & options + if (settings.Footer != null) + { + var path = settings.Footer.Process("footer"); + if (path.HasValue()) + { + sb.AppendFormat(" --footer-html \"{0}\"", path); + settings.Footer.WriteArguments("footer", sb); + } + } + if (settings.FooterOptions != null && (settings.Footer != null || settings.FooterOptions.HasText)) + { + settings.FooterOptions.Process("footer", sb); + } + + // apply settings + converter.CustomWkHtmlPageArgs = sb.ToString().Trim().NullEmpty(); + + return converter; + } + + } +} diff --git a/src/Libraries/SmartStore.Services/Properties/Settings.Designer.cs b/src/Libraries/SmartStore.Services/Properties/Settings.Designer.cs index 55c9eb47fe..0d4d638b36 100644 --- a/src/Libraries/SmartStore.Services/Properties/Settings.Designer.cs +++ b/src/Libraries/SmartStore.Services/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.17929 +// Laufzeitversion:4.0.30319.34209 // // Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn // der Code erneut generiert wird. @@ -12,7 +12,7 @@ namespace SmartStore.Services.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/src/Libraries/SmartStore.Services/Security/AclService.cs b/src/Libraries/SmartStore.Services/Security/AclService.cs index 62057fe3b6..f1ea323ff2 100644 --- a/src/Libraries/SmartStore.Services/Security/AclService.cs +++ b/src/Libraries/SmartStore.Services/Security/AclService.cs @@ -60,8 +60,7 @@ public bool HasActiveAcl { if (!_hasActiveAcl.HasValue) { - var query = _aclRecordRepository.Where(x => !x.IsIdle); - _hasActiveAcl = query.Any(); + _hasActiveAcl = _aclRecordRepository.TableUntracked.Any(x => !x.IsIdle); } return _hasActiveAcl.Value; } @@ -159,7 +158,7 @@ public virtual void InsertAclRecord(T entity, int customerRoleId) where T : B int entityId = entity.Id; string entityName = typeof(T).Name; - var aclRecord = new AclRecord() + var aclRecord = new AclRecord { EntityId = entityId, EntityName = entityName, @@ -180,7 +179,6 @@ public virtual void UpdateAclRecord(AclRecord aclRecord) _aclRecordRepository.Update(aclRecord); - //cache _cacheManager.RemoveByPattern(ACLRECORD_PATTERN_KEY); } diff --git a/src/Libraries/SmartStore.Services/Security/PermissionService.cs b/src/Libraries/SmartStore.Services/Security/PermissionService.cs index a105e18520..a3ada9721a 100644 --- a/src/Libraries/SmartStore.Services/Security/PermissionService.cs +++ b/src/Libraries/SmartStore.Services/Security/PermissionService.cs @@ -10,10 +10,10 @@ namespace SmartStore.Services.Security { - /// - /// Permission service - /// - public partial class PermissionService : IPermissionService + /// + /// Permission service + /// + public partial class PermissionService : IPermissionService { #region Constants /// @@ -141,9 +141,11 @@ orderby pr.Id /// Permissions public virtual IList GetAllPermissionRecords() { - var query = from pr in _permissionRecordRepository.Table - orderby pr.Name - select pr; + var query = + from pr in _permissionRecordRepository.Table + orderby pr.Category, pr.Name + select pr; + var permissions = query.ToList(); return permissions; } @@ -182,70 +184,59 @@ public virtual void UpdatePermissionRecord(PermissionRecord permission) /// Permission provider public virtual void InstallPermissions(IPermissionProvider permissionProvider) { - using (var scope = new DbContextScope(_permissionRecordRepository.Context, autoDetectChanges: false)) + using (var scope = new DbContextScope(_permissionRecordRepository.Context, autoDetectChanges: false, autoCommit: false)) { - try + //install new permissions + var permissions = permissionProvider.GetPermissions(); + foreach (var permission in permissions) { - _permissionRecordRepository.AutoCommitEnabled = false; - _customerRoleRepository.AutoCommitEnabled = false; - - //install new permissions - var permissions = permissionProvider.GetPermissions(); - foreach (var permission in permissions) + var permission1 = GetPermissionRecordBySystemName(permission.SystemName); + if (permission1 == null) { - var permission1 = GetPermissionRecordBySystemName(permission.SystemName); - if (permission1 == null) + //new permission (install it) + permission1 = new PermissionRecord() { - //new permission (install it) - permission1 = new PermissionRecord() - { - Name = permission.Name, - SystemName = permission.SystemName, - Category = permission.Category, - }; - - // default customer role mappings - var defaultPermissions = permissionProvider.GetDefaultPermissions(); - foreach (var defaultPermission in defaultPermissions) + Name = permission.Name, + SystemName = permission.SystemName, + Category = permission.Category, + }; + + // default customer role mappings + var defaultPermissions = permissionProvider.GetDefaultPermissions(); + foreach (var defaultPermission in defaultPermissions) + { + var customerRole = _customerService.GetCustomerRoleBySystemName(defaultPermission.CustomerRoleSystemName); + if (customerRole == null) { - var customerRole = _customerService.GetCustomerRoleBySystemName(defaultPermission.CustomerRoleSystemName); - if (customerRole == null) + //new role (save it) + customerRole = new CustomerRole { - //new role (save it) - customerRole = new CustomerRole() - { - Name = defaultPermission.CustomerRoleSystemName, - Active = true, - SystemName = defaultPermission.CustomerRoleSystemName - }; - _customerService.InsertCustomerRole(customerRole); - } - - - var defaultMappingProvided = (from p in defaultPermission.PermissionRecords - where p.SystemName == permission1.SystemName - select p).Any(); - var mappingExists = (from p in customerRole.PermissionRecords - where p.SystemName == permission1.SystemName - select p).Any(); - if (defaultMappingProvided && !mappingExists) - { - permission1.CustomerRoles.Add(customerRole); - } + Name = defaultPermission.CustomerRoleSystemName, + Active = true, + SystemName = defaultPermission.CustomerRoleSystemName + }; + _customerService.InsertCustomerRole(customerRole); } - //save new permission - InsertPermissionRecord(permission1); + + var defaultMappingProvided = (from p in defaultPermission.PermissionRecords + where p.SystemName == permission1.SystemName + select p).Any(); + var mappingExists = (from p in customerRole.PermissionRecords + where p.SystemName == permission1.SystemName + select p).Any(); + if (defaultMappingProvided && !mappingExists) + { + permission1.CustomerRoles.Add(customerRole); + } } - } - scope.Commit(); - } - finally - { - _permissionRecordRepository.AutoCommitEnabled = true; - _customerRoleRepository.AutoCommitEnabled = true; + //save new permission + InsertPermissionRecord(permission1); + } } + + scope.Commit(); } } diff --git a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs index 58b4d8634c..4f1032077a 100644 --- a/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs +++ b/src/Libraries/SmartStore.Services/Security/StandardPermissionProvider.cs @@ -34,11 +34,10 @@ public partial class StandardPermissionProvider : IPermissionProvider public static readonly PermissionRecord ManageTaxSettings = new PermissionRecord { Name = "Admin area. Manage Tax Settings", SystemName = "ManageTaxSettings", Category = "Configuration" }; public static readonly PermissionRecord ManageShippingSettings = new PermissionRecord { Name = "Admin area. Manage Shipping Settings", SystemName = "ManageShippingSettings", Category = "Configuration" }; public static readonly PermissionRecord ManageCurrencies = new PermissionRecord { Name = "Admin area. Manage Currencies", SystemName = "ManageCurrencies", Category = "Configuration" }; - //codehint: sm-add begin public static readonly PermissionRecord ManageDeliveryTimes = new PermissionRecord { Name = "Admin area. Manage Delivery Times", SystemName = "ManageDeliveryTimes", Category = "Configuration" }; + public static readonly PermissionRecord ManageQuantityUnits = new PermissionRecord { Name = "Admin area. Manage Quantity Units", SystemName = "ManageQuantityUnits", Category = "Configuration" }; public static readonly PermissionRecord ManageContentSlider = new PermissionRecord { Name = "Admin area. Manage Content Slider", SystemName = "ManageContentSlider", Category = "Configuration" }; public static readonly PermissionRecord ManageThemes = new PermissionRecord { Name = "Admin area. Manage Themes", SystemName = "ManageThemes", Category = "Configuration" }; - //codehint: sm-add end public static readonly PermissionRecord ManageMeasures = new PermissionRecord { Name = "Admin area. Manage Measures", SystemName = "ManageMeasures", Category = "Configuration" }; public static readonly PermissionRecord ManageActivityLog = new PermissionRecord { Name = "Admin area. Manage Activity Log", SystemName = "ManageActivityLog", Category = "Configuration" }; public static readonly PermissionRecord ManageAcl = new PermissionRecord { Name = "Admin area. Manage ACL", SystemName = "ManageACL", Category = "Configuration" }; @@ -50,10 +49,12 @@ public partial class StandardPermissionProvider : IPermissionProvider public static readonly PermissionRecord ManageMaintenance = new PermissionRecord { Name = "Admin area. Manage Maintenance", SystemName = "ManageMaintenance", Category = "Configuration" }; public static readonly PermissionRecord UploadPictures = new PermissionRecord { Name = "Admin area. Upload Pictures", SystemName = "UploadPictures", Category = "Configuration" }; public static readonly PermissionRecord ManageScheduleTasks = new PermissionRecord { Name = "Admin area. Manage Schedule Tasks", SystemName = "ManageScheduleTasks", Category = "Configuration" }; + public static readonly PermissionRecord ManageExports = new PermissionRecord { Name = "Admin area. Manage Exports", SystemName = "ManageExports", Category = "Configuration" }; + public static readonly PermissionRecord ManageImports = new PermissionRecord { Name = "Admin area. Manage Imports", SystemName = "ManageImports", Category = "Configuration" }; + public static readonly PermissionRecord ManageUrlRecords = new PermissionRecord { Name = "Admin area. Manage Url Records", SystemName = "ManageUrlRecords", Category = "Configuration" }; - - //public store permissions - public static readonly PermissionRecord DisplayPrices = new PermissionRecord { Name = "Public store. Display Prices", SystemName = "DisplayPrices", Category = "PublicStore" }; + //public store permissions + public static readonly PermissionRecord DisplayPrices = new PermissionRecord { Name = "Public store. Display Prices", SystemName = "DisplayPrices", Category = "PublicStore" }; public static readonly PermissionRecord EnableShoppingCart = new PermissionRecord { Name = "Public store. Enable shopping cart", SystemName = "EnableShoppingCart", Category = "PublicStore" }; public static readonly PermissionRecord EnableWishlist = new PermissionRecord { Name = "Public store. Enable wishlist", SystemName = "EnableWishlist", Category = "PublicStore" }; public static readonly PermissionRecord PublicStoreAllowNavigation = new PermissionRecord { Name = "Public store. Allow navigation", SystemName = "PublicStoreAllowNavigation", Category = "PublicStore" }; @@ -90,9 +91,9 @@ public virtual IEnumerable GetPermissions() ManageTaxSettings, ManageShippingSettings, ManageCurrencies, - ManageDeliveryTimes, //codehint: sm-add - ManageContentSlider, //codehint: sm-add - ManageThemes, //codehint: sm-add + ManageDeliveryTimes, + ManageContentSlider, + ManageThemes, ManageMeasures, ManageActivityLog, ManageAcl, @@ -104,7 +105,10 @@ public virtual IEnumerable GetPermissions() ManageMaintenance, UploadPictures, ManageScheduleTasks, - DisplayPrices, + ManageExports, + ManageImports, + ManageUrlRecords, + DisplayPrices, EnableShoppingCart, EnableWishlist, PublicStoreAllowNavigation, @@ -147,9 +151,9 @@ public virtual IEnumerable GetDefaultPermissions() ManageTaxSettings, ManageShippingSettings, ManageCurrencies, - ManageDeliveryTimes, //codehint: sm-add - ManageContentSlider, //codehint: sm-add - ManageThemes, //codehint: sm-add + ManageDeliveryTimes, + ManageContentSlider, + ManageThemes, ManageMeasures, ManageActivityLog, ManageAcl, @@ -161,6 +165,9 @@ public virtual IEnumerable GetDefaultPermissions() ManageMaintenance, UploadPictures, ManageScheduleTasks, + ManageExports, + ManageImports, + ManageUrlRecords, DisplayPrices, EnableShoppingCart, EnableWishlist, diff --git a/src/Libraries/SmartStore.Services/Seo/BaseSitemapGenerator.cs b/src/Libraries/SmartStore.Services/Seo/BaseSitemapGenerator.cs index 3d3893c55f..e4ae0b24f7 100644 --- a/src/Libraries/SmartStore.Services/Seo/BaseSitemapGenerator.cs +++ b/src/Libraries/SmartStore.Services/Seo/BaseSitemapGenerator.cs @@ -1,87 +1,78 @@ using System; using System.IO; using System.Text; +using System.Web.Mvc; using System.Xml; using SmartStore.Core; +using SmartStore.Core.Data; namespace SmartStore.Services.Seo { - /// - /// Represents a base sitemap generator - /// - public abstract partial class BaseSitemapGenerator - { - #region Fields - - private const string DateFormat = @"yyyy-MM-dd"; - private XmlTextWriter _writer; - - #endregion - - #region Utilities - - /// - /// Method that is overridden, that handles creation of child urls. - /// Use the method WriteUrlLocation() within this method. - /// - protected abstract void GenerateUrlNodes(); - - /// - /// Writes the url location to the writer. - /// - /// Url of indexed location (don't put root url information in). - /// Update frequency - always, hourly, daily, weekly, yearly, never. - /// Date last updated. - protected void WriteUrlLocation(string url, UpdateFrequency updateFrequency, DateTime lastUpdated) - { - _writer.WriteStartElement("url"); - string loc = XmlHelper.XmlEncode(url); - _writer.WriteElementString("loc", loc); - _writer.WriteElementString("changefreq", updateFrequency.ToString().ToLowerInvariant()); - _writer.WriteElementString("lastmod", lastUpdated.ToString(DateFormat)); - _writer.WriteEndElement(); - } - - #endregion - - #region Methods - - /// - /// This will build an xml sitemap for better index with search engines. - /// See http://en.wikipedia.org/wiki/Sitemaps for more information. - /// - /// Sitemap.xml as string - public string Generate() - { - using (var stream = new MemoryStream()) - { - Generate(stream); - return Encoding.UTF8.GetString(stream.ToArray()); - } - } - - /// - /// This will build an xml sitemap for better index with search engines. - /// See http://en.wikipedia.org/wiki/Sitemaps for more information. - /// - /// Stream of sitemap. - public void Generate(Stream stream) - { - _writer = new XmlTextWriter(stream, Encoding.UTF8); - _writer.Formatting = Formatting.Indented; - _writer.WriteStartDocument(); - _writer.WriteStartElement("urlset"); - _writer.WriteAttributeString("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"); - _writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); - _writer.WriteAttributeString("xsi:schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"); - - GenerateUrlNodes(); - - _writer.WriteEndElement(); - _writer.Close(); - } - - #endregion - - } + /// + /// Represents a base sitemap generator + /// + public abstract partial class BaseSitemapGenerator : ISitemapGenerator + { + #region Fields + + private const string DateFormat = @"yyyy-MM-dd"; + private XmlTextWriter _writer; + + #endregion + + #region Utilities + + protected abstract void GenerateUrlNodes(UrlHelper urlHelper); + + protected void WriteUrlLocation(string url, UpdateFrequency updateFrequency, DateTime lastUpdated) + { + if (url.IsEmpty()) + return; + + string loc = XmlHelper.XmlEncode(url); + if (url.IsEmpty()) + return; + + _writer.WriteStartElement("url"); + _writer.WriteElementString("loc", loc); + //_writer.WriteElementString("changefreq", updateFrequency.ToString().ToLowerInvariant()); + _writer.WriteElementString("lastmod", lastUpdated.ToString(DateFormat)); + _writer.WriteEndElement(); + } + + #endregion + + #region Methods + + public string Generate(UrlHelper urlHelper) + { + using (var stream = new MemoryStream()) + { + Generate(urlHelper, stream); + return Encoding.UTF8.GetString(stream.ToArray()); + } + } + + public void Generate(UrlHelper urlHelper, Stream stream) + { + using (var scope = new DbContextScope(autoDetectChanges: false, forceNoTracking: true)) + { + _writer = new XmlTextWriter(stream, Encoding.UTF8); + _writer.Formatting = Formatting.Indented; + _writer.WriteStartDocument(); + _writer.WriteStartElement("urlset"); + _writer.WriteAttributeString("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"); + _writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + _writer.WriteAttributeString("xsi:schemaLocation", "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"); + + GenerateUrlNodes(urlHelper); + + _writer.WriteEndElement(); + _writer.Close(); + } + } + + #endregion + + } } diff --git a/src/Libraries/SmartStore.Services/Seo/ISitemapGenerator.cs b/src/Libraries/SmartStore.Services/Seo/ISitemapGenerator.cs index 904a3f795c..1073d291f4 100644 --- a/src/Libraries/SmartStore.Services/Seo/ISitemapGenerator.cs +++ b/src/Libraries/SmartStore.Services/Seo/ISitemapGenerator.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Web.Mvc; namespace SmartStore.Services.Seo { @@ -11,15 +12,17 @@ public partial interface ISitemapGenerator /// This will build an xml sitemap for better index with search engines. /// See http://en.wikipedia.org/wiki/Sitemaps for more information. /// + /// URL helper /// Sitemap.xml as string - string Generate(); + string Generate(UrlHelper urlHelper); /// /// This will build an xml sitemap for better index with search engines. /// See http://en.wikipedia.org/wiki/Sitemaps for more information. /// + /// URL helper /// Stream of sitemap. - void Generate(Stream stream); + void Generate(UrlHelper urlHelper, Stream stream); } } diff --git a/src/Libraries/SmartStore.Services/Seo/IUrlRecordService.cs b/src/Libraries/SmartStore.Services/Seo/IUrlRecordService.cs index 4f6f5f00ae..d3bfa5a04d 100644 --- a/src/Libraries/SmartStore.Services/Seo/IUrlRecordService.cs +++ b/src/Libraries/SmartStore.Services/Seo/IUrlRecordService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; using SmartStore.Core; using SmartStore.Core.Domain.Seo; @@ -23,6 +24,13 @@ public partial interface IUrlRecordService /// URL record UrlRecord GetUrlRecordById(int urlRecordId); + /// + /// Gets URL records by identifiers + /// + /// + /// List of URL records + IList GetUrlRecordsByIds(int[] urlRecordIds); + /// /// Inserts an URL record /// @@ -45,11 +53,24 @@ public partial interface IUrlRecordService /// /// Gets all URL records /// - /// Slug /// Page index /// Page size + /// Slug + /// Entity name + /// Entity identifier + /// Whether to load only active records + /// Language identifier /// Customer collection - IPagedList GetAllUrlRecords(string slug, int pageIndex, int pageSize); + IPagedList GetAllUrlRecords(int pageIndex, int pageSize, string slug, string entityName, int? entityId, int? languageId, bool? isActive); + + /// + /// Gets all URL records for the specified entity + /// + /// Type + /// Entity + /// Specifies whether only active URL records should be returned + /// List of URL records + IList GetUrlRecordsFor(string entityName, int entityId, bool activeOnly = false); /// /// Find slug @@ -80,5 +101,20 @@ public partial interface IUrlRecordService /// Name of a property /// Url record UrlRecord SaveSlug(T entity, Expression> nameProperty) where T : BaseEntity, ISlugSupported; + + /// + /// Get number of slugs per entity + /// + /// URL record identifier + /// Dictionary of slugs per entity count + Dictionary CountSlugsPerEntity(int[] urlRecordIds); + + /// + /// Get number of slugs per entity + /// + /// Entity name + /// Entity identifier + /// Number of slugs per entity + int CountSlugsPerEntity(string entityName, int entityId); } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs b/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs index f1d12d4bf5..29c29d13ef 100644 --- a/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs +++ b/src/Libraries/SmartStore.Services/Seo/SeoExtensions.cs @@ -1,17 +1,15 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using SmartStore.Core; using SmartStore.Core.Domain.Blogs; using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Forums; using SmartStore.Core.Domain.News; using SmartStore.Core.Domain.Seo; using SmartStore.Core.Infrastructure; using SmartStore.Services.Localization; using SmartStore.Utilities; +using SmartStore.Core.Localization; namespace SmartStore.Services.Seo { @@ -79,32 +77,6 @@ public static string GetSeName(this NewsItem newsItem) #region Forum - /// - /// Gets ForumGroup SE (search engine) name - /// - /// ForumGroup - /// ForumGroup SE (search engine) name - public static string GetSeName(this ForumGroup forumGroup) - { - if (forumGroup == null) - throw new ArgumentNullException("forumGroup"); - string seName = GetSeName(forumGroup.Name); - return seName; - } - - /// - /// Gets Forum SE (search engine) name - /// - /// Forum - /// Forum SE (search engine) name - public static string GetSeName(this Forum forum) - { - if (forum == null) - throw new ArgumentNullException("forum"); - string seName = GetSeName(forum.Name); - return seName; - } - /// /// Gets ForumTopic SE (search engine) name /// @@ -189,20 +161,20 @@ public static string GetSeName(this T entity, if (languageId > 0) { - //ensure that we have at least two published languages + // ensure that we have at least two published languages bool loadLocalizedValue = true; if (ensureTwoPublishedLanguages) { var totalPublishedLanguages = languageService.GetLanguagesCount(false); loadLocalizedValue = totalPublishedLanguages >= 2; } - //localized value + // localized value if (loadLocalizedValue) { result = urlRecordService.GetActiveSlug(entity.Id, entityName, languageId); } } - //set default value if required + // set default value if required if (String.IsNullOrEmpty(result) && returnDefaultValue) { result = urlRecordService.GetActiveSlug(entity.Id, entityName, 0); @@ -247,31 +219,40 @@ public static string ValidateSeName(this T entity, if (entity == null) throw new ArgumentNullException("entity"); - //use name if sename is not specified + // use name if sename is not specified if (String.IsNullOrWhiteSpace(seName) && !String.IsNullOrWhiteSpace(name)) seName = name; - //validation + // validation seName = GetSeName(seName, seoSettings); - //max length + // max length seName = seName.Truncate(400); if (String.IsNullOrWhiteSpace(seName)) { if (ensureNotEmpty) { - //use entity identifier as sename if empty + // use entity identifier as sename if empty seName = entity.Id.ToString(); } else { - //return. no need for further processing + // return. no need for further processing return seName; } } - //ensure this sename is not reserved yet + // validate and alter SeName if it could be interpreted as SEO code + if (LocalizationHelper.IsValidCultureCode(seName)) + { + if (seName.Length == 2) + { + seName = seName + "-0"; + } + } + + // ensure this sename is not reserved yet string entityName = typeof(T).Name; int i = 2; var tempSeName = seName; @@ -280,14 +261,14 @@ public static string ValidateSeName(this T entity, while (true) { - //check whether such slug already exists (and that is not the current product) + // check whether such slug already exists (and that it's not the current entity) var urlRecord = urlRecordService.GetBySlug(tempSeName) ?? extraSlugLookup(tempSeName); var reserved1 = urlRecord != null && !(urlRecord.EntityId == entity.Id && urlRecord.EntityName.Equals(entityName, StringComparison.InvariantCultureIgnoreCase)); - if (!reserved1 && urlRecord != null && languageId.HasValue) // codehint: sm-add + if (!reserved1 && urlRecord != null && languageId.HasValue) reserved1 = (urlRecord.LanguageId != languageId.Value); - //and it's not in the list of reserved slugs + // and it's not in the list of reserved slugs var reserved2 = seoSettings.ReservedUrlRecordSlugs.Contains(tempSeName, StringComparer.InvariantCultureIgnoreCase); if (!reserved1 && !reserved2) break; @@ -323,7 +304,8 @@ public static string GetSeName(string name, SeoSettings seoSettings) return SeoHelper.GetSeName( name, seoSettings == null ? false : seoSettings.ConvertNonWesternChars, - seoSettings == null ? false : seoSettings.AllowUnicodeCharsInUrls); + seoSettings == null ? false : seoSettings.AllowUnicodeCharsInUrls, + seoSettings == null ? null : seoSettings.SeoNameCharConversion); } #endregion diff --git a/src/Libraries/SmartStore.Services/Seo/SitemapGenerator.cs b/src/Libraries/SmartStore.Services/Seo/SitemapGenerator.cs index e57d1cee52..497555026d 100644 --- a/src/Libraries/SmartStore.Services/Seo/SitemapGenerator.cs +++ b/src/Libraries/SmartStore.Services/Seo/SitemapGenerator.cs @@ -1,17 +1,20 @@ using System; using System.Linq; +using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Services.Catalog; using SmartStore.Services.Topics; +using SmartStore.Services.Seo; +using SmartStore.Core.Domain.Security; namespace SmartStore.Services.Seo { /// /// Represents a sitemap generator /// - public partial class SitemapGenerator : BaseSitemapGenerator, ISitemapGenerator + public partial class SitemapGenerator : BaseSitemapGenerator { private readonly IStoreContext _storeContext; private readonly ICategoryService _categoryService; @@ -20,10 +23,17 @@ public partial class SitemapGenerator : BaseSitemapGenerator, ISitemapGenerator private readonly ITopicService _topicService; private readonly CommonSettings _commonSettings; private readonly IWebHelper _webHelper; + private readonly SecuritySettings _securitySettings; - public SitemapGenerator(IStoreContext storeContext, ICategoryService categoryService, - IProductService productService, IManufacturerService manufacturerService, - ITopicService topicService, CommonSettings commonSettings, IWebHelper webHelper) + public SitemapGenerator( + IStoreContext storeContext, + ICategoryService categoryService, + IProductService productService, + IManufacturerService manufacturerService, + ITopicService topicService, + CommonSettings commonSettings, + IWebHelper webHelper, + SecuritySettings securitySettings) { this._storeContext = storeContext; this._categoryService = categoryService; @@ -32,97 +42,94 @@ public SitemapGenerator(IStoreContext storeContext, ICategoryService categorySer this._topicService = topicService; this._commonSettings = commonSettings; this._webHelper = webHelper; + this._securitySettings = securitySettings; } - /// - /// Method that is overridden, that handles creation of child urls. - /// Use the method WriteUrlLocation() within this method. - /// - protected override void GenerateUrlNodes() + protected override void GenerateUrlNodes(UrlHelper urlHelper) { if (_commonSettings.SitemapIncludeCategories) { - WriteCategories(0); + WriteCategories(urlHelper, 0); } if (_commonSettings.SitemapIncludeManufacturers) { - WriteManufacturers(); + WriteManufacturers(urlHelper); } if (_commonSettings.SitemapIncludeProducts) { - WriteProducts(); + WriteProducts(urlHelper); } if (_commonSettings.SitemapIncludeTopics) { - WriteTopics(); + WriteTopics(urlHelper); } } - private void WriteCategories(int parentCategoryId) + private void WriteCategories(UrlHelper urlHelper, int parentCategoryId) { - string location = _webHelper.GetStoreLocation(false); - var categories = _categoryService.GetAllCategories(showHidden: false); + var protocol = _securitySettings.ForceSslForAllPages ? "https" : "http"; foreach (var category in categories) { - //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - var url = string.Format("{0}{1}", location, category.GetSeName()); + var url = urlHelper.RouteUrl("Category", new { SeName = category.GetSeName() }, protocol); var updateFrequency = UpdateFrequency.Weekly; var updateTime = category.UpdatedOnUtc; WriteUrlLocation(url, updateFrequency, updateTime); } } - private void WriteManufacturers() + private void WriteManufacturers(UrlHelper urlHelper) { - string location = _webHelper.GetStoreLocation(false); - var manufacturers = _manufacturerService.GetAllManufacturers(false); + var protocol = _securitySettings.ForceSslForAllPages ? "https" : "http"; foreach (var manufacturer in manufacturers) { - //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - var url = string.Format("{0}{1}", location, manufacturer.GetSeName()); + var url = urlHelper.RouteUrl("Manufacturer", new { SeName = manufacturer.GetSeName() }, protocol); var updateFrequency = UpdateFrequency.Weekly; var updateTime = manufacturer.UpdatedOnUtc; WriteUrlLocation(url, updateFrequency, updateTime); } } - private void WriteProducts() + private void WriteProducts(UrlHelper urlHelper) { - string location = _webHelper.GetStoreLocation(false); - - var ctx = new ProductSearchContext() + var protocol = _securitySettings.ForceSslForAllPages ? "https" : "http"; + + var ctx = new ProductSearchContext { OrderBy = ProductSortingEnum.CreatedOn, - PageSize = int.MaxValue, + PageSize = 500, StoreId = _storeContext.CurrentStoreIdIfMultiStoreMode, VisibleIndividuallyOnly = true }; - var products = _productService.SearchProducts(ctx); - foreach (var product in products) - { - //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - var url = string.Format("{0}{1}", location, product.GetSeName()); - var updateFrequency = UpdateFrequency.Weekly; - var updateTime = product.UpdatedOnUtc; - WriteUrlLocation(url, updateFrequency, updateTime); - } + for (ctx.PageIndex = 0; ctx.PageIndex < 9999999; ++ctx.PageIndex) + { + var products = _productService.SearchProducts(ctx); + + foreach (var product in products) + { + var url = urlHelper.RouteUrl("Product", new { SeName = product.GetSeName() }, protocol); + var updateFrequency = UpdateFrequency.Weekly; + var updateTime = product.UpdatedOnUtc; + WriteUrlLocation(url, updateFrequency, updateTime); + } + + if (!products.HasNextPage) + break; + } } - private void WriteTopics() + private void WriteTopics(UrlHelper urlHelper) { - string location = _webHelper.GetStoreLocation(false); - - var topics = _topicService.GetAllTopics(_storeContext.CurrentStore.Id).ToList().FindAll(t => t.IncludeInSitemap); + var topics = _topicService.GetAllTopics(_storeContext.CurrentStore.Id).ToList().FindAll(t => t.IncludeInSitemap && !t.RenderAsWidget); + var protocol = _securitySettings.ForceSslForAllPages ? "https" : "http"; foreach (var topic in topics) { - //TODO add a method for getting URL (use routing because it handles all SEO friendly URLs) - var url = string.Format("{0}t/{1}", location, topic.SystemName.ToLowerInvariant()); + var url = urlHelper.RouteUrl("Topic", new { SystemName = topic.SystemName }, protocol); var updateFrequency = UpdateFrequency.Weekly; var updateTime = DateTime.UtcNow; WriteUrlLocation(url, updateFrequency, updateTime); diff --git a/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs b/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs index a330e3616c..38fe4a7bda 100644 --- a/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs +++ b/src/Libraries/SmartStore.Services/Seo/UrlRecordService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using SmartStore.Core; @@ -15,8 +16,10 @@ public partial class UrlRecordService : IUrlRecordService { #region Constants - private const string URLRECORD_ACTIVE_BY_ID_NAME_LANGUAGE_KEY = "SmartStore.urlrecord.active.id-name-language-{0}-{1}-{2}"; - private const string URLRECORD_PATTERN_KEY = "SmartStore.urlrecord."; + // {0} = id, {1} = name, {2} = language + private const string URLRECORD_KEY = "SmartStore.urlrecord.{0}-{1}-{2}"; + private const string URLRECORD_ALL_ACTIVESLUGS_KEY = "SmartStore.urlrecord.all-active-slugs"; + private const string URLRECORD_PATTERN_KEY = "SmartStore.urlrecord."; #endregion @@ -24,31 +27,23 @@ public partial class UrlRecordService : IUrlRecordService private readonly IRepository _urlRecordRepository; private readonly ICacheManager _cacheManager; + private readonly SeoSettings _seoSettings; #endregion #region Ctor - /// - /// Ctor - /// - /// Cache manager - /// URL record repository - public UrlRecordService(ICacheManager cacheManager, - IRepository urlRecordRepository) + public UrlRecordService(ICacheManager cacheManager, IRepository urlRecordRepository, SeoSettings seoSettings) { this._cacheManager = cacheManager; this._urlRecordRepository = urlRecordRepository; + this._seoSettings = seoSettings; } #endregion #region Methods - /// - /// Deletes an URL record - /// - /// URL record public virtual void DeleteUrlRecord(UrlRecord urlRecord) { if (urlRecord == null) @@ -56,15 +51,9 @@ public virtual void DeleteUrlRecord(UrlRecord urlRecord) _urlRecordRepository.Delete(urlRecord); - //cache _cacheManager.RemoveByPattern(URLRECORD_PATTERN_KEY); } - /// - /// Gets an URL record - /// - /// URL record identifier - /// URL record public virtual UrlRecord GetUrlRecordById(int urlRecordId) { if (urlRecordId == 0) @@ -74,10 +63,18 @@ public virtual UrlRecord GetUrlRecordById(int urlRecordId) return urlRecord; } - /// - /// Inserts an URL record - /// - /// URL record + public virtual IList GetUrlRecordsByIds(int[] urlRecordIds) + { + if (urlRecordIds == null || urlRecordIds.Length == 0) + return new List(); + + var urlRecords = _urlRecordRepository.Table + .Where(x => urlRecordIds.Contains(x.Id)) + .ToList(); + + return urlRecords; + } + public virtual void InsertUrlRecord(UrlRecord urlRecord) { if (urlRecord == null) @@ -89,10 +86,6 @@ public virtual void InsertUrlRecord(UrlRecord urlRecord) _cacheManager.RemoveByPattern(URLRECORD_PATTERN_KEY); } - /// - /// Updates the URL record - /// - /// URL record public virtual void UpdateUrlRecord(UrlRecord urlRecord) { if (urlRecord == null) @@ -104,75 +97,107 @@ public virtual void UpdateUrlRecord(UrlRecord urlRecord) _cacheManager.RemoveByPattern(URLRECORD_PATTERN_KEY); } - /// - /// Find URL record - /// - /// Slug - /// Found URL record - public virtual UrlRecord GetBySlug(string slug) + public virtual IPagedList GetAllUrlRecords(int pageIndex, int pageSize, string slug, string entityName, int? entityId, int? languageId, bool? isActive) { - if (String.IsNullOrEmpty(slug)) - return null; + var query = _urlRecordRepository.Table; - var query = from ur in _urlRecordRepository.Table - where ur.Slug == slug - select ur; - var urlRecord = query.FirstOrDefault(); - return urlRecord; - } + if (slug.HasValue()) + query = query.Where(x => x.Slug.Contains(slug)); - /// - /// Gets all URL records - /// - /// Slug - /// Page index - /// Page size - /// Customer collection - public virtual IPagedList GetAllUrlRecords(string slug, int pageIndex, int pageSize) - { - var query = _urlRecordRepository.Table; - if (!String.IsNullOrWhiteSpace(slug)) - query = query.Where(ur => ur.Slug.Contains(slug)); - query = query.OrderBy(ur => ur.Slug); + if (entityName.HasValue()) + query = query.Where(x => x.EntityName == entityName); + + if (entityId.HasValue) + query = query.Where(x => x.EntityId == entityId.Value); + + if (isActive.HasValue) + query = query.Where(x => x.IsActive == isActive.Value); - var urlRecords = new PagedList(query, pageIndex, pageSize); - return urlRecords; + if (languageId.HasValue) + query = query.Where(x => x.LanguageId == languageId); + + query = query.OrderBy(x => x.Slug); + + var urlRecords = new PagedList(query, pageIndex, pageSize); + return urlRecords; } - /// - /// Find slug - /// - /// Entity identifier - /// Entity name - /// Language identifier - /// Found slug + public virtual IList GetUrlRecordsFor(string entityName, int entityId, bool activeOnly = false) + { + Guard.ArgumentNotEmpty(() => entityName); + + var query = from ur in _urlRecordRepository.Table + where ur.EntityId == entityId && + ur.EntityName == entityName + select ur; + + if (activeOnly) + { + query = query.Where(ur => ur.IsActive); + } + + return query.ToList(); + } + + public virtual UrlRecord GetBySlug(string slug) + { + // INFO: (mc) Caching unnecessary here. This is not a 'bottleneck' function. + if (String.IsNullOrEmpty(slug)) + return null; + + var query = from ur in _urlRecordRepository.Table + where ur.Slug == slug + select ur; + var urlRecord = query.FirstOrDefault(); + return urlRecord; + } + public virtual string GetActiveSlug(int entityId, string entityName, int languageId) - { - string key = string.Format(URLRECORD_ACTIVE_BY_ID_NAME_LANGUAGE_KEY, entityId, entityName, languageId); - return _cacheManager.Get(key, () => - { - var query = from ur in _urlRecordRepository.Table - where ur.EntityId == entityId && - ur.EntityName == entityName && - ur.LanguageId == languageId && - ur.IsActive - orderby ur.Id descending - select ur.Slug; - var slug = query.FirstOrDefault(); - //little hack here. nulls aren't cacheable so set it to "" - if (slug == null) - slug = ""; - return slug; - }); + { + string slug = null; + + if (_seoSettings.LoadAllUrlAliasesOnStartup) + { + var allActiveSlugs = _cacheManager.Get(URLRECORD_ALL_ACTIVESLUGS_KEY, () => + { + var query = from x in _urlRecordRepository.TableUntracked + where x.IsActive + orderby x.Id descending + select x; + + var result = query.ToDictionarySafe( + x => GenerateKey(x.EntityId, x.EntityName, x.LanguageId), + x => x.Slug, + StringComparer.OrdinalIgnoreCase); + + return result; + }); + + var key = GenerateKey(entityId, entityName, languageId); + if (!allActiveSlugs.TryGetValue(key, out slug)) + { + return string.Empty; + } + } + else + { + string cacheKey = string.Format(URLRECORD_KEY, entityId, entityName, languageId); + slug = _cacheManager.Get(cacheKey, () => + { + var query = from ur in _urlRecordRepository.Table + where ur.EntityId == entityId && + ur.EntityName == entityName && + ur.LanguageId == languageId && + ur.IsActive + orderby ur.Id descending + select ur.Slug; + return query.FirstOrDefault() ?? string.Empty; + }); + } + + return slug; } - /// - /// Save slug - /// - /// Type - /// Entity - /// Slug - /// Language ID public virtual UrlRecord SaveSlug(T entity, string slug, int languageId) where T : BaseEntity, ISlugSupported { if (entity == null) @@ -193,18 +218,18 @@ orderby ur.Id descending var activeUrlRecord = allUrlRecords.FirstOrDefault(x => x.IsActive); if (activeUrlRecord == null && !string.IsNullOrWhiteSpace(slug)) { - //find in non-active records with the specified slug + // find in non-active records with the specified slug var nonActiveRecordWithSpecifiedSlug = allUrlRecords.FirstOrDefault(x => x.Slug.Equals(slug, StringComparison.InvariantCultureIgnoreCase) && !x.IsActive); if (nonActiveRecordWithSpecifiedSlug != null) { - //mark non-active record as active + // mark non-active record as active nonActiveRecordWithSpecifiedSlug.IsActive = true; UpdateUrlRecord(nonActiveRecordWithSpecifiedSlug); } else { - //new record - var urlRecord = new UrlRecord() + // new record + var urlRecord = new UrlRecord { EntityId = entity.Id, EntityName = entityName, @@ -219,27 +244,27 @@ orderby ur.Id descending if (activeUrlRecord != null && string.IsNullOrWhiteSpace(slug)) { - //disable the previous active URL record + // disable the previous active URL record activeUrlRecord.IsActive = false; UpdateUrlRecord(activeUrlRecord); } if (activeUrlRecord != null && !string.IsNullOrWhiteSpace(slug)) { - //is it the same slug as in active URL record? + // is it the same slug as in active URL record? if (activeUrlRecord.Slug.Equals(slug, StringComparison.InvariantCultureIgnoreCase)) { - //yes. do nothing - //P.S. wrote this way for more source code readability + // yes. do nothing + // P.S. wrote this way for more source code readability } else { - //find in non-active records with the specified slug + // find in non-active records with the specified slug var nonActiveRecordWithSpecifiedSlug = allUrlRecords .FirstOrDefault(x => x.Slug.Equals(slug, StringComparison.InvariantCultureIgnoreCase) && !x.IsActive); if (nonActiveRecordWithSpecifiedSlug != null) { - //mark non-active record as active + // mark non-active record as active nonActiveRecordWithSpecifiedSlug.IsActive = true; UpdateUrlRecord(nonActiveRecordWithSpecifiedSlug); @@ -264,10 +289,10 @@ orderby ur.Id descending } else { - //insert new record - //we do not update the existing record because we should track all previously entered slugs - //to ensure that URLs will work fine - var urlRecord = new UrlRecord() + // insert new record + // we do not update the existing record because we should track all previously entered slugs + // to ensure that URLs will work fine + var urlRecord = new UrlRecord { EntityId = entity.Id, EntityName = entityName, @@ -278,7 +303,7 @@ orderby ur.Id descending InsertUrlRecord(urlRecord); result = urlRecord; - //disable the previous active URL record + // disable the previous active URL record activeUrlRecord.IsActive = false; UpdateUrlRecord(activeUrlRecord); } @@ -290,13 +315,6 @@ orderby ur.Id descending return result; } - /// - /// Save slug - /// - /// Type - /// Entity - /// Name of a property - /// Url record public virtual UrlRecord SaveSlug(T entity, Expression> nameProperty) where T : BaseEntity, ISlugSupported { string name = nameProperty.Compile().Invoke(entity); @@ -307,6 +325,41 @@ public virtual UrlRecord SaveSlug(T entity, Expression> nameP return SaveSlug(entity, existingSeName, 0); } + private string GenerateKey(int entityId, string entityName, int languageId) + { + return "{0}.{1}.{2}".FormatInvariant(entityId, entityName, languageId); + } + + public virtual Dictionary CountSlugsPerEntity(int[] urlRecordIds) + { + if (urlRecordIds == null || urlRecordIds.Length == 0) + return new Dictionary(); + + var query = + from x in _urlRecordRepository.TableUntracked + where urlRecordIds.Contains(x.Id) + select new + { + Id = x.Id, + Count = _urlRecordRepository.TableUntracked.Where(y => y.EntityName == x.EntityName && y.EntityId == x.EntityId).Count() + }; + + var result = query + .ToList() + .ToDictionary(x => x.Id, x => x.Count); + + return result; + } + + public virtual int CountSlugsPerEntity(string entityName, int entityId) + { + var count = _urlRecordRepository.Table + .Where(x => x.EntityName == entityName && x.EntityId == entityId) + .Count(); + + return count; + } + #endregion } } \ No newline at end of file diff --git a/src/Libraries/SmartStore.Services/ServiceCacheConsumer.cs b/src/Libraries/SmartStore.Services/ServiceCacheConsumer.cs new file mode 100644 index 0000000000..e3fd3f18b8 --- /dev/null +++ b/src/Libraries/SmartStore.Services/ServiceCacheConsumer.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SmartStore.Core.Caching; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Events; +using SmartStore.Services.Tasks; +using SmartStore.Services.Stores; + +namespace SmartStore.Services +{ + public class ServiceCacheConsumer : + IConsumer>, + IConsumer>, + IConsumer>, + IConsumer>, + IConsumer> + { + public const string STORE_LANGUAGE_MAP_KEY = "sm.svc.storelangmap"; + + private readonly ICacheManager _cacheManager; + + public ServiceCacheConsumer(Func cache) + { + this._cacheManager = cache("static"); + } + + public void HandleEvent(EntityInserted eventMessage) + { + _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); + } + + public void HandleEvent(EntityDeleted eventMessage) + { + _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); + } + + public void HandleEvent(EntityInserted eventMessage) + { + _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); + } + + public void HandleEvent(EntityUpdated eventMessage) + { + _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); + } + + public void HandleEvent(EntityDeleted eventMessage) + { + _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); + } + } +} diff --git a/src/Libraries/SmartStore.Services/Shipping/GetShippingOptionRequest.cs b/src/Libraries/SmartStore.Services/Shipping/GetShippingOptionRequest.cs index 1962f97177..3439b6fd4f 100644 --- a/src/Libraries/SmartStore.Services/Shipping/GetShippingOptionRequest.cs +++ b/src/Libraries/SmartStore.Services/Shipping/GetShippingOptionRequest.cs @@ -16,6 +16,11 @@ public GetShippingOptionRequest() this.Items = new List(); } + /// + /// The context store identifier + /// + public int StoreId { get; set; } + /// /// Gets or sets a customer /// diff --git a/src/Libraries/SmartStore.Services/Shipping/IShipmentService.cs b/src/Libraries/SmartStore.Services/Shipping/IShipmentService.cs index ac79efe3dc..0a544651ad 100644 --- a/src/Libraries/SmartStore.Services/Shipping/IShipmentService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/IShipmentService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Domain.Shipping; @@ -29,12 +30,19 @@ IPagedList GetAllShipments(string trackingNumber, DateTime? createdFro int pageIndex, int pageSize); /// - /// Get shipment by identifiers + /// Get shipments by identifiers /// /// Shipment identifiers /// Shipments IList GetShipmentsByIds(int[] shipmentIds); + /// + /// Get shipments by order identifiers + /// + /// Order identifiers + /// Shipments + Multimap GetShipmentsByOrderIds(int[] orderIds); + /// /// Gets a shipment /// diff --git a/src/Libraries/SmartStore.Services/Shipping/IShippingMethodFilter.cs b/src/Libraries/SmartStore.Services/Shipping/IShippingMethodFilter.cs new file mode 100644 index 0000000000..2fbed519bc --- /dev/null +++ b/src/Libraries/SmartStore.Services/Shipping/IShippingMethodFilter.cs @@ -0,0 +1,35 @@ +using SmartStore.Core.Domain.Shipping; + +namespace SmartStore.Services.Shipping +{ + public partial interface IShippingMethodFilter + { + /// + /// Gets a value indicating whether a shipping method should be filtered out + /// + /// Shipping filter request + /// true filter out method, false do not filter out method + bool IsExcluded(ShippingFilterRequest request); + + /// + /// Get URL for filter configuration + /// + /// Shipping method identifier + /// URL for filter configuration + string GetConfigurationUrl(int shippingMethodId); + } + + + public partial class ShippingFilterRequest + { + /// + /// The shipping method to be checked + /// + public ShippingMethod ShippingMethod { get; set; } + + /// + /// Shipping method request + /// + public GetShippingOptionRequest Option { get; set; } + } +} diff --git a/src/Libraries/SmartStore.Services/Shipping/IShippingRateComputationMethod.cs b/src/Libraries/SmartStore.Services/Shipping/IShippingRateComputationMethod.cs index c416c74bb9..fd13e71b4c 100644 --- a/src/Libraries/SmartStore.Services/Shipping/IShippingRateComputationMethod.cs +++ b/src/Libraries/SmartStore.Services/Shipping/IShippingRateComputationMethod.cs @@ -7,7 +7,7 @@ namespace SmartStore.Services.Shipping /// /// Provides an interface of shipping rate computation method /// - public partial interface IShippingRateComputationMethod : IPlugin + public partial interface IShippingRateComputationMethod : IProvider, IUserEditable { /// /// Gets a shipping rate computation method type @@ -33,12 +33,9 @@ public partial interface IShippingRateComputationMethod : IPlugin /// IShipmentTracker ShipmentTracker { get; } - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues); + /// + /// Gets a value indicating whether the shipping rate computation method is active and should be offered to customers + /// + bool IsActive { get; } } } diff --git a/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs index 593ba86229..9018fab4b6 100644 --- a/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/IShippingService.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Shipping { @@ -15,21 +17,21 @@ public partial interface IShippingService /// /// Load records allows only in specified store; pass 0 to load all records /// Shipping rate computation methods - IList LoadActiveShippingRateComputationMethods(int storeId = 0); + IEnumerable> LoadActiveShippingRateComputationMethods(int storeId = 0); /// /// Load shipping rate computation method by system name /// /// System name /// Found Shipping rate computation method - IShippingRateComputationMethod LoadShippingRateComputationMethodBySystemName(string systemName); + Provider LoadShippingRateComputationMethodBySystemName(string systemName, int storeId = 0); /// /// Load all shipping rate computation methods /// /// Load records allows only in specified store; pass 0 to load all records /// Shipping rate computation methods - IList LoadAllShippingRateComputationMethods(int storeId = 0); + IEnumerable> LoadAllShippingRateComputationMethods(int storeId = 0); @@ -51,9 +53,9 @@ public partial interface IShippingService /// /// Gets all shipping methods /// - /// The country indentifier to filter by + /// Shipping option request to filter out shipping methods. null to load all shipping methods. /// Shipping method collection - IList GetAllShippingMethods(int? filterByCountryId = null); + IList GetAllShippingMethods(GetShippingOptionRequest request = null); /// /// Inserts a shipping method @@ -95,8 +97,9 @@ public partial interface IShippingService /// /// Shopping cart /// Shipping address + /// Store identifier /// Shipment package - GetShippingOptionRequest CreateShippingOptionRequest(IList cart, Address shippingAddress); + GetShippingOptionRequest CreateShippingOptionRequest(IList cart, Address shippingAddress, int storeId); /// /// Gets available shipping options @@ -108,5 +111,11 @@ public partial interface IShippingService /// Shipping options GetShippingOptionResponse GetShippingOptions(IList cart, Address shippingAddress, string allowedShippingRateComputationMethodSystemName = "", int storeId = 0); + + /// + /// Gets all shipping method filters + /// + /// List of shipping method filters + IList GetAllShippingMethodFilters(); } } diff --git a/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs b/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs index 8b29b8be75..3a8c261164 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShipmentService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using SmartStore.Collections; using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Orders; @@ -41,7 +42,7 @@ public ShipmentService(IRepository shipmentRepository, this._shipmentRepository = shipmentRepository; this._siRepository = siRepository; this._orderRepository = orderRepository; - _eventPublisher = eventPublisher; + this._eventPublisher = eventPublisher; } #endregion @@ -83,7 +84,7 @@ public virtual void DeleteShipment(Shipment shipment) public virtual IPagedList GetAllShipments(string trackingNumber, DateTime? createdFrom, DateTime? createdTo, int pageIndex, int pageSize) { - var query = _shipmentRepository.Table; + var query = _shipmentRepository.Table.Expand(x => x.Order); if (!String.IsNullOrEmpty(trackingNumber)) query = query.Where(s => s.TrackingNumber.Contains(trackingNumber)); if (createdFrom.HasValue) @@ -107,7 +108,7 @@ public virtual IList GetShipmentsByIds(int[] shipmentIds) if (shipmentIds == null || shipmentIds.Length == 0) return new List(); - var query = from o in _shipmentRepository.Table + var query = from o in _shipmentRepository.Table.Expand(x => x.Order) where shipmentIds.Contains(o.Id) select o; var shipments = query.ToList(); @@ -122,6 +123,24 @@ where shipmentIds.Contains(o.Id) return sortedOrders; } + public virtual Multimap GetShipmentsByOrderIds(int[] orderIds) + { + Guard.ArgumentNotNull(() => orderIds); + + var query = + from x in _shipmentRepository.TableUntracked.Expand(x => x.ShipmentItems) + where orderIds.Contains(x.OrderId) + select x; + + var map = query + .OrderBy(x => x.OrderId) + .ThenBy(x => x.CreatedOnUtc) + .ToList() + .ToMultimap(x => x.OrderId, x => x); + + return map; + } + /// /// Gets a shipment /// @@ -220,7 +239,20 @@ public virtual void InsertShipmentItem(ShipmentItem shipmentItem) //event notifications _eventPublisher.EntityInserted(shipmentItem); - _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + + if (shipmentItem.Shipment != null && shipmentItem.Shipment.Order != null) + { + _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + } + else + { + var shipment = _shipmentRepository.Table + .Expand(x => x.Order) + .FirstOrDefault(x => x.Id == shipmentItem.ShipmentId); + + if (shipment != null) + _eventPublisher.PublishOrderUpdated(shipment.Order); + } } /// @@ -236,7 +268,20 @@ public virtual void UpdateShipmentItem(ShipmentItem shipmentItem) //event notifications _eventPublisher.EntityUpdated(shipmentItem); - _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + + if (shipmentItem.Shipment != null && shipmentItem.Shipment.Order != null) + { + _eventPublisher.PublishOrderUpdated(shipmentItem.Shipment.Order); + } + else + { + var shipment = _shipmentRepository.Table + .Expand(x => x.Order) + .FirstOrDefault(x => x.Id == shipmentItem.ShipmentId); + + if (shipment != null) + _eventPublisher.PublishOrderUpdated(shipment.Order); + } } #endregion diff --git a/src/Libraries/SmartStore.Services/Shipping/ShippingExtentions.cs b/src/Libraries/SmartStore.Services/Shipping/ShippingExtentions.cs index e960642e1c..fedfbe3891 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShippingExtentions.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShippingExtentions.cs @@ -1,13 +1,13 @@ using System; using System.Linq; using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Plugins; namespace SmartStore.Services.Shipping { public static class ShippingExtentions { - public static bool IsShippingRateComputationMethodActive(this IShippingRateComputationMethod srcm, - ShippingSettings shippingSettings) + public static bool IsShippingRateComputationMethodActive(this Provider srcm, ShippingSettings shippingSettings) { if (srcm == null) throw new ArgumentNullException("srcm"); @@ -17,14 +17,14 @@ public static bool IsShippingRateComputationMethodActive(this IShippingRateCompu if (shippingSettings.ActiveShippingRateComputationMethodSystemNames == null) return false; - foreach (string activeMethodSystemName in shippingSettings.ActiveShippingRateComputationMethodSystemNames) - if (srcm.PluginDescriptor.SystemName.Equals(activeMethodSystemName, StringComparison.InvariantCultureIgnoreCase)) - return true; - return false; + + if (!srcm.Value.IsActive) + return false; + + return shippingSettings.ActiveShippingRateComputationMethodSystemNames.Contains(srcm.Metadata.SystemName, StringComparer.OrdinalIgnoreCase); } - public static bool CountryRestrictionExists(this ShippingMethod shippingMethod, - int countryId) + public static bool CountryRestrictionExists(this ShippingMethod shippingMethod, int countryId) { if (shippingMethod == null) throw new ArgumentNullException("shippingMethod"); diff --git a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs index 5c5e67ad77..4f6db7fa9c 100644 --- a/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs +++ b/src/Libraries/SmartStore.Services/Shipping/ShippingService.cs @@ -1,41 +1,43 @@ using System; using System.Collections.Generic; using System.Linq; -using SmartStore.Core.Caching; using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Events; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; using SmartStore.Core.Plugins; using SmartStore.Services.Catalog; -using SmartStore.Services.Localization; -using SmartStore.Core.Logging; -using SmartStore.Services.Orders; using SmartStore.Services.Common; using SmartStore.Services.Configuration; -using SmartStore.Core.Domain.Catalog; +using SmartStore.Services.Orders; namespace SmartStore.Services.Shipping { - public partial class ShippingService : IShippingService + public partial class ShippingService : IShippingService { - #region Fields + #region Fields - private readonly IRepository _shippingMethodRepository; - private readonly ICacheManager _cacheManager; + private readonly static object _lock = new object(); + private static IList _shippingMethodFilterTypes = null; + + private readonly IRepository _shippingMethodRepository; private readonly ILogger _logger; private readonly IProductAttributeParser _productAttributeParser; private readonly IProductService _productService; private readonly ICheckoutAttributeParser _checkoutAttributeParser; private readonly IGenericAttributeService _genericAttributeService; - private readonly ILocalizationService _localizationService; private readonly ShippingSettings _shippingSettings; - private readonly IPluginFinder _pluginFinder; private readonly IEventPublisher _eventPublisher; private readonly ShoppingCartSettings _shoppingCartSettings; private readonly ISettingService _settingService; + private readonly IProviderManager _providerManager; + private readonly ITypeFinder _typeFinder; #endregion @@ -57,51 +59,79 @@ public partial class ShippingService : IShippingService /// Event published /// Shopping cart settings /// Setting service - public ShippingService(ICacheManager cacheManager, + public ShippingService( IRepository shippingMethodRepository, ILogger logger, IProductAttributeParser productAttributeParser, IProductService productService, ICheckoutAttributeParser checkoutAttributeParser, IGenericAttributeService genericAttributeService, - ILocalizationService localizationService, ShippingSettings shippingSettings, - IPluginFinder pluginFinder, IEventPublisher eventPublisher, ShoppingCartSettings shoppingCartSettings, - ISettingService settingService) + ISettingService settingService, + IProviderManager providerManager, + ITypeFinder typeFinder) { - this._cacheManager = cacheManager; this._shippingMethodRepository = shippingMethodRepository; this._logger = logger; this._productAttributeParser = productAttributeParser; this._productService = productService; this._checkoutAttributeParser = checkoutAttributeParser; this._genericAttributeService = genericAttributeService; - this._localizationService = localizationService; this._shippingSettings = shippingSettings; - this._pluginFinder = pluginFinder; this._eventPublisher = eventPublisher; this._shoppingCartSettings = shoppingCartSettings; - this._settingService = settingService; // codehint: sm-add + this._settingService = settingService; + this._providerManager = providerManager; + this._typeFinder = typeFinder; + + T = NullLocalizer.Instance; } - #endregion - - #region Methods + public Localizer T { get; set; } - #region Shipping rate computation methods + #endregion - /// - /// Load active shipping rate computation methods - /// + #region Methods + + #region Shipping rate computation methods + + /// + /// Load active shipping rate computation methods + /// /// Load records allows only in specified store; pass 0 to load all records - /// Shipping rate computation methods - public virtual IList LoadActiveShippingRateComputationMethods(int storeId = 0) + /// Shipping rate computation methods + public virtual IEnumerable> LoadActiveShippingRateComputationMethods(int storeId = 0) { - return LoadAllShippingRateComputationMethods(storeId) - .Where(provider => _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Contains(provider.PluginDescriptor.SystemName, StringComparer.InvariantCultureIgnoreCase)) - .ToList(); + var allMethods = LoadAllShippingRateComputationMethods(storeId); + + var activeMethods = allMethods + .Where(p => p.Value.IsActive && _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Contains(p.Metadata.SystemName, StringComparer.InvariantCultureIgnoreCase)); + + if (!activeMethods.Any()) + { + var fallbackMethod = allMethods.FirstOrDefault(x => x.IsShippingRateComputationMethodActive(_shippingSettings)); + + if (fallbackMethod == null) + fallbackMethod = allMethods.FirstOrDefault(); + + if (fallbackMethod != null) + { + _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Clear(); + _shippingSettings.ActiveShippingRateComputationMethodSystemNames.Add(fallbackMethod.Metadata.SystemName); + _settingService.SaveSetting(_shippingSettings); + + return new Provider[] { fallbackMethod }; + } + else + { + if (DataSettings.DatabaseIsInstalled()) + throw new SmartException(T("Shipping.OneActiveMethodProviderRequired")); + } + } + + return activeMethods; } /// @@ -109,13 +139,9 @@ public virtual IList LoadActiveShippingRateCompu /// /// System name /// Found Shipping rate computation method - public virtual IShippingRateComputationMethod LoadShippingRateComputationMethodBySystemName(string systemName) + public virtual Provider LoadShippingRateComputationMethodBySystemName(string systemName, int storeId = 0) { - var descriptor = _pluginFinder.GetPluginDescriptorBySystemName(systemName); - if (descriptor != null) - return descriptor.Instance(); - - return null; + return _providerManager.GetProvider(systemName, storeId); } /// @@ -123,12 +149,9 @@ public virtual IShippingRateComputationMethod LoadShippingRateComputationMethodB /// /// Load records allows only in specified store; pass 0 to load all records /// Shipping rate computation methods - public virtual IList LoadAllShippingRateComputationMethods(int storeId = 0) + public virtual IEnumerable> LoadAllShippingRateComputationMethods(int storeId = 0) { - return _pluginFinder - .GetPlugins() - .Where(x => storeId == 0 || _settingService.GetSettingByKey(x.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) - .ToList(); + return _providerManager.GetAllProviders(storeId); } #endregion @@ -163,37 +186,37 @@ public virtual ShippingMethod GetShippingMethodById(int shippingMethodId) return _shippingMethodRepository.GetById(shippingMethodId); } - - /// - /// Gets all shipping methods - /// - /// The country indentifier to filter by - /// Shipping method collection - public virtual IList GetAllShippingMethods(int? filterByCountryId = null) + + public virtual IList GetAllShippingMethods(GetShippingOptionRequest request = null) { - if (filterByCountryId.HasValue && filterByCountryId.Value > 0) - { - var query1 = from sm in _shippingMethodRepository.Table - where - sm.RestrictedCountries.Select(c => c.Id).Contains(filterByCountryId.Value) - select sm.Id; - - var query2 = from sm in _shippingMethodRepository.Table - where !query1.Contains(sm.Id) - orderby sm.DisplayOrder - select sm; - - var shippingMethods = query2.ToList(); - return shippingMethods; - } - else - { - var query = from sm in _shippingMethodRepository.Table - orderby sm.DisplayOrder - select sm; - var shippingMethods = query.ToList(); - return shippingMethods; - } + var query = + from sm in _shippingMethodRepository.Table + orderby sm.DisplayOrder + select sm; + + var allMethods = query.ToList(); + + if (request == null) + return allMethods; + + IList allFilters = null; + var filterRequest = new ShippingFilterRequest { Option = request }; + + var activeShippingMethods = allMethods.Where(s => + { + // shipping method filtering + if (allFilters == null) + allFilters = GetAllShippingMethodFilters(); + + filterRequest.ShippingMethod = s; + + if (allFilters.Any(x => x.IsExcluded(filterRequest))) + return false; + + return true; + }); + + return activeShippingMethods.ToList(); } /// @@ -248,7 +271,7 @@ public virtual decimal GetShoppingCartItemWeight(OrganizedShoppingCartItem shopp if (!String.IsNullOrEmpty(shoppingCartItem.Item.AttributesXml)) { - var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml); + var pvaValues = _productAttributeParser.ParseProductVariantAttributeValues(shoppingCartItem.Item.AttributesXml).ToList(); foreach (var pvaValue in pvaValues) { @@ -294,11 +317,11 @@ public virtual decimal GetShoppingCartTotalWeight(IList(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); @@ -309,6 +332,7 @@ public virtual decimal GetShoppingCartTotalWeight(IList /// Shopping cart /// Shipping address + /// Store identifier /// Shipment package - public virtual GetShippingOptionRequest CreateShippingOptionRequest(IList cart, - Address shippingAddress) + public virtual GetShippingOptionRequest CreateShippingOptionRequest(IList cart, Address shippingAddress, int storeId) { var request = new GetShippingOptionRequest(); + request.StoreId = storeId; request.Customer = cart.GetCustomer(); - request.Items = new List(); - foreach (var sc in cart) - if (sc.Item.IsShipEnabled) - request.Items.Add(sc); request.ShippingAddress = shippingAddress; request.CountryFrom = null; request.StateProvinceFrom = null; request.ZipPostalCodeFrom = string.Empty; + + request.Items = new List(); + + foreach (var sc in cart) + { + if (sc.Item.IsShipEnabled) + request.Items.Add(sc); + } + return request; } @@ -343,8 +373,8 @@ public virtual GetShippingOptionRequest CreateShippingOptionRequest(IListFilter by shipping rate computation method identifier; null to load shipping options of all shipping rate computation methods /// Load records allows only in specified store; pass 0 to load all records /// Shipping options - public virtual GetShippingOptionResponse GetShippingOptions(IList cart, - Address shippingAddress, string allowedShippingRateComputationMethodSystemName = "", int storeId = 0) + public virtual GetShippingOptionResponse GetShippingOptions(IList cart, Address shippingAddress, + string allowedShippingRateComputationMethodSystemName = "", int storeId = 0) { if (cart == null) throw new ArgumentNullException("cart"); @@ -352,26 +382,30 @@ public virtual GetShippingOptionResponse GetShippingOptions(IList String.IsNullOrWhiteSpace(allowedShippingRateComputationMethodSystemName) || - allowedShippingRateComputationMethodSystemName.Equals(srcm.PluginDescriptor.SystemName, StringComparison.InvariantCultureIgnoreCase)) + allowedShippingRateComputationMethodSystemName.Equals(srcm.Metadata.SystemName, StringComparison.InvariantCultureIgnoreCase)) .ToList(); + if (shippingRateComputationMethods.Count == 0) - throw new SmartException("Shipping rate computation method could not be loaded"); + throw new SmartException(T("Shipping.CouldNotLoadMethod")); //get shipping options foreach (var srcm in shippingRateComputationMethods) { - var getShippingOptionResponse = srcm.GetShippingOptions(getShippingOptionRequest); + var getShippingOptionResponse = srcm.Value.GetShippingOptions(getShippingOptionRequest); foreach (var so2 in getShippingOptionResponse.ShippingOptions) { //system name - so2.ShippingRateComputationMethodSystemName = srcm.PluginDescriptor.SystemName; + so2.ShippingRateComputationMethodSystemName = srcm.Metadata.SystemName; + //round if (_shoppingCartSettings.RoundPricesDuringCalculation) so2.Rate = Math.Round(so2.Rate, 2); + result.ShippingOptions.Add(so2); } @@ -381,7 +415,7 @@ public virtual GetShippingOptionResponse GetShippingOptions(IList 0 && result.Errors.Count > 0) result.Errors.Clear(); } - - //no shipping options loaded - if (result.ShippingOptions.Count == 0 && result.Errors.Count == 0) - result.Errors.Add(_localizationService.GetResource("Checkout.ShippingOptionCouldNotBeLoaded")); + + //no shipping options loaded + if (result.ShippingOptions.Count == 0 && result.Errors.Count == 0) + { + result.Errors.Add(T("Checkout.ShippingOptionCouldNotBeLoaded")); + } return result; } + public virtual IList GetAllShippingMethodFilters() + { + if (_shippingMethodFilterTypes == null) + { + lock (_lock) + { + if (_shippingMethodFilterTypes == null) + { + _shippingMethodFilterTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true) + .ToList(); + } + } + } + + var shippingMethodFilters = _shippingMethodFilterTypes + .Select(x => EngineContext.Current.ContainerManager.ResolveUnregistered(x) as IShippingMethodFilter) + .ToList(); + + return shippingMethodFilters; + } + #endregion #endregion diff --git a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj index 10ea9b6fe1..1edfe58738 100644 --- a/src/Libraries/SmartStore.Services/SmartStore.Services.csproj +++ b/src/Libraries/SmartStore.Services/SmartStore.Services.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,7 +10,7 @@ Properties SmartStore.Services SmartStore.Services - v4.5 + v4.5.1 512 @@ -62,80 +62,102 @@ MinimumRecommendedRules.ruleset - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True - - False - ..\..\packages\EPPlus.3.1.3.3\lib\net35\EPPlus.dll + + ..\..\packages\CronExpressionDescriptor.1.17.0\lib\net45\CronExpressionDescriptor.dll - + False - ..\..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll - + False - ..\..\packages\ImageResizer.3.4.2\lib\ImageResizer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - + False - ..\..\packages\ImageResizer.Plugins.PrettyGifs.3.4.2\lib\ImageResizer.Plugins.PrettyGifs.dll + ..\..\packages\EPPlus.4.0.3\lib\net20\EPPlus.dll - - False - ..\..\packages\iTextSharp.5.5.0\lib\itextsharp.dll + + ..\..\packages\ImageResizer.4.0.4\lib\net45\ImageResizer.dll + True + + + ..\..\packages\ImageResizer.Plugins.PrettyGifs.4.0.4\lib\net45\ImageResizer.Plugins.PrettyGifs.dll + True + + + ..\..\packages\LumenWorksCsvReader.3.9\lib\net20\LumenWorks.Framework.IO.dll + True + + + ..\..\packages\MaxMind.GeoIP.2.1.17\lib\net35\MaxMind.GeoIP.dll True ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - False - ..\..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + + ..\..\packages\ncrontab.2.0.0\lib\net20\NCrontab.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True - + False - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll + ..\..\packages\NReco.PdfGenerator.1.1.5.0\lib\net20\NReco.PdfGenerator.dll + + ..\..\packages\System.Linq.Dynamic.1.0.0\lib\net40\System.Linq.Dynamic.dll + + False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - + False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + ..\..\packages\UAParser.2.0.0.0\lib\net40-Client\UAParser.dll + True + @@ -144,6 +166,89 @@ Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -180,7 +285,6 @@ - @@ -201,9 +305,8 @@ - + - @@ -213,13 +316,9 @@ - - - - @@ -233,7 +332,6 @@ - @@ -267,8 +365,6 @@ - - @@ -287,12 +383,9 @@ - - - @@ -314,7 +407,7 @@ - + @@ -341,6 +434,7 @@ + @@ -360,6 +454,15 @@ + + + + + + + + + @@ -388,7 +491,9 @@ + + @@ -404,15 +509,20 @@ + + + + + - - - + + + @@ -493,8 +603,13 @@ Nop_Services_EuropaCheckVatService_checkVatService + + + + + +
+ + + + + http://ec.europa.eu/taxation_customs/vies/services/checkVatService + + + http://ec.europa.eu/taxation_customs/vies/services/checkVatService + + + - + @@ -27,8 +29,14 @@ - + - + + + + + + + diff --git a/src/Libraries/SmartStore.Services/packages.config b/src/Libraries/SmartStore.Services/packages.config index cab20a0610..d078b22719 100644 --- a/src/Libraries/SmartStore.Services/packages.config +++ b/src/Libraries/SmartStore.Services/packages.config @@ -1,15 +1,20 @@  - - - - - - - - - + + + + + + + + + + + - + + + + \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/Content/smartstore.web.api.css b/src/Plugins/Api.WebApi/Content/smartstore.web.api.css deleted file mode 100644 index e00e76c4a1..0000000000 --- a/src/Plugins/Api.WebApi/Content/smartstore.web.api.css +++ /dev/null @@ -1,5 +0,0 @@ - -#apiuser-grid .t-last { - padding-top: 3px; - padding-bottom: 0px; -} diff --git a/src/Plugins/Api.WebApi/Controllers/Api/HomeController.cs b/src/Plugins/Api.WebApi/Controllers/Api/HomeController.cs deleted file mode 100644 index da7fbe306e..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/Api/HomeController.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SmartStore.Web.Framework.WebApi.Security; -using System.Web.Http; - -namespace SmartStore.Plugin.Api.WebApi.Controllers.Api -{ - [WebApiAuthenticate] - public class HomeController : ApiController - { - } -} diff --git a/src/Plugins/Api.WebApi/Controllers/Api/PaymentsController.cs b/src/Plugins/Api.WebApi/Controllers/Api/PaymentsController.cs deleted file mode 100644 index 4c8f51d2cf..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/Api/PaymentsController.cs +++ /dev/null @@ -1,36 +0,0 @@ -using SmartStore.Core.Plugins; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework.WebApi; -using SmartStore.Web.Framework.WebApi.OData; -using SmartStore.Web.Framework.WebApi.Security; -using System.Linq; -using System.Web.Http; -using System; - -namespace SmartStore.Plugin.Api.WebApi.Controllers.Api -{ - [WebApiAuthenticate(Permission = "ManagePaymentMethods")] - public class PaymentsController : ApiController - { - private readonly Lazy _pluginFinder; - - public PaymentsController(Lazy pluginFinder) - { - _pluginFinder = pluginFinder; - } - - [WebApiQueryable(PagingOptional = true)] - public IQueryable GetMethods() - { - if (!ModelState.IsValid) - throw this.ExceptionInvalidModelState(); - - var query = _pluginFinder.Value - .GetPlugins(false) - .Select(x => x.PluginDescriptor) - .AsQueryable(); - - return query; - } - } -} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/CustomersController.cs b/src/Plugins/Api.WebApi/Controllers/OData/CustomersController.cs deleted file mode 100644 index e385c7f004..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/OData/CustomersController.cs +++ /dev/null @@ -1,101 +0,0 @@ -using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Orders; -using SmartStore.Services.Customers; -using SmartStore.Web.Framework.WebApi; -using SmartStore.Web.Framework.WebApi.OData; -using SmartStore.Web.Framework.WebApi.Security; -using System.Collections.Generic; -using System.Linq; -using System.Web.Http; - -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData -{ - [WebApiAuthenticate(Permission = "ManageCustomers")] - public class CustomersController : WebApiEntityController - { - protected override IQueryable GetEntitySet() - { - var query = - from x in this.Repository.Table - where !x.Deleted - select x; - - return query; - } - protected override void Insert(Customer entity) - { - Service.InsertCustomer(entity); - } - protected override void Update(Customer entity) - { - Service.UpdateCustomer(entity); - } - protected override void Delete(Customer entity) - { - Service.DeleteCustomer(entity); - } - - [WebApiQueryable] - public SingleResult GetCustomer(int key) - { - return GetSingleResult(key); - } - - // navigation properties - - public Address GetBillingAddress(int key) - { - return GetExpandedProperty
(key, x => x.BillingAddress); - } - - public Address GetShippingAddress(int key) - { - return GetExpandedProperty
(key, x => x.ShippingAddress); - } - - //public Language GetLanguage(int key) - //{ - // return GetExpandedProperty(key, x => x.Language); - //} - - //public Currency GetCurrency(int key) - //{ - // return GetExpandedProperty(key, x => x.Currency); - //} - - [WebApiQueryable] - public IQueryable GetOrders(int key) - { - var entity = GetExpandedEntity>(key, x => x.Orders); - - return entity.Orders.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetReturnRequests(int key) - { - var entity = GetExpandedEntity>(key, x => x.ReturnRequests); - - return entity.ReturnRequests.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable
GetAddresses(int key) - { - var entity = GetExpandedEntity>(key, x => x.Addresses); - - return entity.Addresses.AsQueryable(); - } - - // actions - - //[HttpGet, Queryable] - //public IQueryable GetGenericAttributes(int key) - //{ - // var query = GenericAttributes(key, "Customer"); - - // return query; - //} - } -} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/OrdersController.cs b/src/Plugins/Api.WebApi/Controllers/OData/OrdersController.cs deleted file mode 100644 index c4f49782d7..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/OData/OrdersController.cs +++ /dev/null @@ -1,175 +0,0 @@ -using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Domain.Shipping; -using SmartStore.Services.Orders; -using SmartStore.Web.Framework.WebApi; -using SmartStore.Web.Framework.WebApi.OData; -using SmartStore.Web.Framework.WebApi.Security; -using System.Collections.Generic; -using System.Linq; -using System.Web.Http; -using System.Web.Http.OData; -using System; - -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData -{ - [WebApiAuthenticate(Permission = "ManageOrders")] - public class OrdersController : WebApiEntityController - { - private readonly Lazy _orderProcessingService; - - public OrdersController(Lazy orderProcessingService) - { - _orderProcessingService = orderProcessingService; - } - - protected override IQueryable GetEntitySet() - { - var query = - from x in this.Repository.Table - where !x.Deleted - select x; - - return query; - } - protected override void Insert(Order entity) - { - Service.InsertOrder(entity); - } - protected override void Update(Order entity) - { - Service.UpdateOrder(entity); - } - protected override void Delete(Order entity) - { - Service.DeleteOrder(entity); - } - - [WebApiQueryable] - public SingleResult GetOrder(int key) - { - return GetSingleResult(key); - } - - // navigation properties - - public Customer GetCustomer(int key) - { - return GetExpandedProperty(key, x => x.Customer); - } - - public Address GetBillingAddress(int key) - { - return GetExpandedProperty
(key, x => x.BillingAddress); - } - - public Address GetShippingAddress(int key) - { - return GetExpandedProperty
(key, x => x.ShippingAddress); - } - - [WebApiQueryable] - public IQueryable GetOrderNotes(int key) - { - var entity = GetExpandedEntity>(key, x => x.OrderNotes); - //var entity = GetEntityByKeyNotNull(key); // if ProxyCreationEnabled = true - - return entity.OrderNotes.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetShipments(int key) - { - var entity = GetExpandedEntity>(key, x => x.Shipments); - - return entity.Shipments.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetOrderItems(int key) - { - var entity = GetExpandedEntity>(key, x => x.OrderItems); - - return entity.OrderItems.AsQueryable(); - } - - // actions - - [HttpPost] - public Order PaymentPending(int key) - { - var entity = GetEntityByKeyNotNull(key); - - this.ProcessEntity(() => - { - entity.PaymentStatus = PaymentStatus.Pending; - Service.UpdateOrder(entity); - return null; - }); - - return entity; - } - - [HttpPost] - public Order PaymentPaid(int key, ODataActionParameters parameters) - { - var entity = GetEntityByKeyNotNull(key); - - this.ProcessEntity(() => - { - string paymentMethodName = parameters.GetValue("PaymentMethodName"); - - if (paymentMethodName != null) - { - entity.PaymentMethodSystemName = paymentMethodName; - Service.UpdateOrder(entity); - } - - _orderProcessingService.Value.MarkOrderAsPaid(entity); - return null; - }); - return entity; - } - - [HttpPost] - public Order PaymentRefund(int key, ODataActionParameters parameters) - { - var entity = GetEntityByKeyNotNull(key); - - this.ProcessEntity(() => - { - bool online = parameters.GetValue("Online"); - - if (online) - { - var errors = _orderProcessingService.Value.Refund(entity); - - if (errors.Count > 0) - return errors[0]; - } - else - { - _orderProcessingService.Value.RefundOffline(entity); - } - return null; - }); - return entity; - } - - [HttpPost] - public Order Cancel(int key) - { - var entity = GetEntityByKeyNotNull(key); - - this.ProcessEntity(() => - { - _orderProcessingService.Value.CancelOrder(entity, true); - - return null; - }); - return entity; - } - } -} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ProductBundleItemsController.cs b/src/Plugins/Api.WebApi/Controllers/OData/ProductBundleItemsController.cs deleted file mode 100644 index b59b8f845a..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/OData/ProductBundleItemsController.cs +++ /dev/null @@ -1,44 +0,0 @@ -using SmartStore.Core.Domain.Catalog; -using SmartStore.Services.Catalog; -using SmartStore.Web.Framework.WebApi; -using SmartStore.Web.Framework.WebApi.OData; -using SmartStore.Web.Framework.WebApi.Security; -using System.Web.Http; - -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData -{ - [WebApiAuthenticate(Permission = "ManageCatalog")] - public class ProductBundleItemsController : WebApiEntityController - { - protected override void Insert(ProductBundleItem entity) - { - Service.InsertBundleItem(entity); - } - protected override void Update(ProductBundleItem entity) - { - Service.UpdateBundleItem(entity); - } - protected override void Delete(ProductBundleItem entity) - { - Service.DeleteBundleItem(entity); - } - - [WebApiQueryable] - public SingleResult GetProductBundleItem(int key) - { - return GetSingleResult(key); - } - - // navigation properties - - public Product GetProduct(int key) - { - return GetExpandedProperty(key, x => x.Product); - } - - public Product GetBundleProduct(int key) - { - return GetExpandedProperty(key, x => x.BundleProduct); - } - } -} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ProductsController.cs b/src/Plugins/Api.WebApi/Controllers/OData/ProductsController.cs deleted file mode 100644 index aa42bd3afc..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/OData/ProductsController.cs +++ /dev/null @@ -1,361 +0,0 @@ -using System; -using System.Linq; -using System.Web.Http; -using System.Collections.Generic; -using SmartStore.Core; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Media; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Services.Catalog; -using SmartStore.Services.Seo; -using SmartStore.Web.Framework.WebApi; -using SmartStore.Web.Framework.WebApi.OData; -using SmartStore.Web.Framework.WebApi.Security; -using System.Web.Http.OData; -using SmartStore.Plugin.Api.WebApi.Services; - -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData -{ - [WebApiAuthenticate(Permission = "ManageCatalog")] - public class ProductsController : WebApiEntityController - { - private readonly Lazy _workContext; - private readonly Lazy _priceCalculationService; - private readonly Lazy _urlRecordService; - private readonly Lazy _productAttributeService; - - public ProductsController( - Lazy workContext, - Lazy priceCalculationService, - Lazy urlRecordService, - Lazy productAttributeService) - { - _workContext = workContext; - _priceCalculationService = priceCalculationService; - _urlRecordService = urlRecordService; - _productAttributeService = productAttributeService; - } - - protected override IQueryable GetEntitySet() - { - var query = - from x in this.Repository.Table - where !x.Deleted - select x; - - return query; - } - protected override void Insert(Product entity) - { - Service.InsertProduct(entity); - - this.ProcessEntity(() => - { - _urlRecordService.Value.SaveSlug(entity, x => x.Name); - return null; - }); - } - protected override void Update(Product entity) - { - Service.UpdateProduct(entity); - - this.ProcessEntity(() => - { - _urlRecordService.Value.SaveSlug(entity, x => x.Name); - return null; - }); - } - protected override void Delete(Product entity) - { - Service.DeleteProduct(entity); - } - - [WebApiQueryable] - public SingleResult GetProduct(int key) - { - return GetSingleResult(key); - } - - // navigation properties - - public DeliveryTime GetDeliveryTime(int key) - { - return GetExpandedProperty(key, x => x.DeliveryTime); - } - - public Download GetSampleDownload(int key) - { - return GetExpandedProperty(key, x => x.SampleDownload); - } - - [WebApiQueryable] - public IQueryable GetProductCategories(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductCategories); - - return entity.ProductCategories.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetProductManufacturers(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductManufacturers); - - return entity.ProductManufacturers.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetProductPictures(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductPictures); - - return entity.ProductPictures.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetProductSpecificationAttributes(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductSpecificationAttributes); - - return entity.ProductSpecificationAttributes.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetProductTags(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductTags); - - return entity.ProductTags.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetTierPrices(int key) - { - var entity = GetExpandedEntity>(key, x => x.TierPrices); - - return entity.TierPrices.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetAppliedDiscounts(int key) - { - var entity = GetExpandedEntity>(key, x => x.AppliedDiscounts); - - return entity.AppliedDiscounts.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetProductVariantAttributes(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductVariantAttributes); - - return entity.ProductVariantAttributes.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetProductVariantAttributeCombinations(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductVariantAttributeCombinations); - - return entity.ProductVariantAttributeCombinations.AsQueryable(); - } - - [WebApiQueryable] - public IQueryable GetProductBundleItems(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductBundleItems); - - return entity.ProductBundleItems.AsQueryable(); - } - - // actions - - private decimal? CalculatePrice(int key, bool lowestPrice) - { - string requiredProperties = "TierPrices, AppliedDiscounts, ProductBundleItems"; - var entity = GetExpandedEntity(key, requiredProperties); - decimal? result = null; - - this.ProcessEntity(() => - { - if (lowestPrice) - { - if (entity.ProductType == ProductType.GroupedProduct) - { - var searchContext = new ProductSearchContext() - { - Query = this.GetExpandedEntitySet(requiredProperties), - ParentGroupedProductId = entity.Id, - PageSize = int.MaxValue, - VisibleIndividuallyOnly = false - }; - - Product lowestPriceProduct; - var associatedProducts = Service.PrepareProductSearchQuery(searchContext); - - result = _priceCalculationService.Value.GetLowestPrice(entity, associatedProducts, out lowestPriceProduct); - } - else - { - bool displayFromMessage; - result = _priceCalculationService.Value.GetLowestPrice(entity, out displayFromMessage); - } - } - else - { - result = _priceCalculationService.Value.GetFinalPrice(entity, null, _workContext.Value.CurrentCustomer, decimal.Zero, true, 1); - } - return null; - }); - return result; - } - - [HttpPost] - public decimal? FinalPrice(int key) - { - return CalculatePrice(key, false); - } - - [HttpPost] - public decimal? LowestPrice(int key) - { - return CalculatePrice(key, true); - } - - [HttpPost, WebApiQueryable(PagingOptional = true)] - public IQueryable CreateAttributeCombinations(int key) - { - var entity = GetEntityByKeyNotNull(key); - - this.ProcessEntity(() => - { - _productAttributeService.Value.CreateAllProductVariantAttributeCombinations(entity); - return null; - }); - - return entity.ProductVariantAttributeCombinations.AsQueryable(); - } - - [HttpPost, WebApiQueryable(PagingOptional = true)] - public IQueryable ManageAttributes(int key, ODataActionParameters parameters) - { - var entity = GetExpandedEntity>(key, x => x.ProductVariantAttributes); - var result = new List(); - - this.ProcessEntity(() => - { - bool synchronize = parameters.GetValue("Synchronize"); - var data = (parameters["Attributes"] as IEnumerable).Where(x => x.Name.HasValue()).ToList(); - - var allAttributes = _productAttributeService.Value.GetAllProductAttributes(); - - foreach (var srcAttr in data) - { - var productAttribute = allAttributes.FirstOrDefault(x => x.Name.IsCaseInsensitiveEqual(srcAttr.Name)); - - if (productAttribute == null) - { - productAttribute = new ProductAttribute() { Name = srcAttr.Name }; - _productAttributeService.Value.InsertProductAttribute(productAttribute); - } - - var attribute = entity.ProductVariantAttributes.FirstOrDefault(x => x.ProductAttribute.Name.IsCaseInsensitiveEqual(srcAttr.Name)); - - if (attribute == null) - { - attribute = new ProductVariantAttribute() - { - ProductId = entity.Id, - ProductAttributeId = productAttribute.Id, - AttributeControlTypeId = srcAttr.ControlTypeId, - DisplayOrder = entity.ProductVariantAttributes.OrderByDescending(x => x.DisplayOrder).Select(x => x.DisplayOrder).FirstOrDefault() + 1, - IsRequired = srcAttr.IsRequired - }; - - entity.ProductVariantAttributes.Add(attribute); - Service.UpdateProduct(entity); - } - else if (synchronize) - { - if (srcAttr.Values.Count <= 0) - { - _productAttributeService.Value.DeleteProductVariantAttribute(attribute); - } - else - { - attribute.AttributeControlTypeId = srcAttr.ControlTypeId; - attribute.IsRequired = srcAttr.IsRequired; - - Service.UpdateProduct(entity); - } - } - - int maxDisplayOrder = attribute.ProductVariantAttributeValues.OrderByDescending(x => x.DisplayOrder).Select(x => x.DisplayOrder).FirstOrDefault(); - - foreach (var srcVal in srcAttr.Values.Where(x => x.Name.HasValue())) - { - var value = attribute.ProductVariantAttributeValues.FirstOrDefault(x => x.Name.IsCaseInsensitiveEqual(srcVal.Name)); - - if (value == null) - { - value = new ProductVariantAttributeValue() - { - ProductVariantAttributeId = attribute.Id, - Name = srcVal.Name, - Alias = srcVal.Alias, - ColorSquaresRgb = srcVal.ColorSquaresRgb, - PriceAdjustment = srcVal.PriceAdjustment, - WeightAdjustment = srcVal.WeightAdjustment, - IsPreSelected = srcVal.IsPreSelected, - DisplayOrder = ++maxDisplayOrder - }; - - attribute.ProductVariantAttributeValues.Add(value); - Service.UpdateProduct(entity); - } - else if (synchronize) - { - value.Alias = srcVal.Alias; - value.ColorSquaresRgb = srcVal.ColorSquaresRgb; - value.PriceAdjustment = srcVal.PriceAdjustment; - value.WeightAdjustment = srcVal.WeightAdjustment; - value.IsPreSelected = srcVal.IsPreSelected; - - Service.UpdateProduct(entity); - } - } - - if (synchronize) - { - foreach (var dstVal in attribute.ProductVariantAttributeValues.ToList()) - { - if (!srcAttr.Values.Exists(x => x.Name.IsCaseInsensitiveEqual(dstVal.Name))) - _productAttributeService.Value.DeleteProductVariantAttributeValue(dstVal); - } - } - } - return null; - }); - - return entity.ProductVariantAttributes.AsQueryable(); - } - - - //[HttpGet, WebApiQueryable] - //public IQueryable GetRelatedProducts(int key) - //{ - // if (!ModelState.IsValid) - // throw this.ExceptionInvalidModelState(); - - // var repository = EngineContext.Current.Resolve>(); - - // var query = - // from x in repository.Table - // where x.ProductId1 == key - // select x; - - // return query; - //} - } -} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/SpecificationAttributeOptionsController.cs b/src/Plugins/Api.WebApi/Controllers/OData/SpecificationAttributeOptionsController.cs deleted file mode 100644 index 4e9d719b78..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/OData/SpecificationAttributeOptionsController.cs +++ /dev/null @@ -1,49 +0,0 @@ -using SmartStore.Core.Domain.Catalog; -using SmartStore.Services.Catalog; -using SmartStore.Web.Framework.WebApi; -using SmartStore.Web.Framework.WebApi.OData; -using SmartStore.Web.Framework.WebApi.Security; -using System.Collections.Generic; -using System.Linq; -using System.Web.Http; - -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData -{ - [WebApiAuthenticate(Permission = "ManageCatalog")] - public class SpecificationAttributeOptionsController : WebApiEntityController - { - protected override void Insert(SpecificationAttributeOption entity) - { - Service.InsertSpecificationAttributeOption(entity); - } - protected override void Update(SpecificationAttributeOption entity) - { - Service.UpdateSpecificationAttributeOption(entity); - } - protected override void Delete(SpecificationAttributeOption entity) - { - Service.DeleteSpecificationAttributeOption(entity); - } - - [WebApiQueryable] - public SingleResult GetSpecificationAttributeOption(int key) - { - return GetSingleResult(key); - } - - // navigation properties - - public SpecificationAttribute GetSpecificationAttribute(int key) - { - return GetExpandedProperty(key, x => x.SpecificationAttribute); - } - - [WebApiQueryable] - public IQueryable GetProductSpecificationAttributes(int key) - { - var entity = GetExpandedEntity>(key, x => x.ProductSpecificationAttributes); - - return entity.ProductSpecificationAttributes.AsQueryable(); - } - } -} diff --git a/src/Plugins/Api.WebApi/Controllers/WebApiController.cs b/src/Plugins/Api.WebApi/Controllers/WebApiController.cs deleted file mode 100644 index fbb3c9046e..0000000000 --- a/src/Plugins/Api.WebApi/Controllers/WebApiController.cs +++ /dev/null @@ -1,130 +0,0 @@ -using SmartStore.Core.Domain.Common; -using SmartStore.Plugin.Api.WebApi.Models; -using SmartStore.Plugin.Api.WebApi.Security; -using SmartStore.Plugin.Api.WebApi.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Security; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Web.Framework.WebApi; -using System; -using System.Web.Mvc; -using Telerik.Web.Mvc; - -namespace SmartStore.Plugin.Api.WebApi.Controllers -{ - public class WebApiController : PluginControllerBase - { - private readonly IPermissionService _permissionService; - private readonly WebApiSettings _webApiSettings; - private readonly ISettingService _settingService; - private readonly IWebApiPluginService _webApiPluginService; - private readonly AdminAreaSettings _adminAreaSettings; - private readonly ILocalizationService _localizationService; - - public WebApiController( - IPermissionService permissionService, - WebApiSettings settings, - ISettingService settingService, - IWebApiPluginService webApiPluginService, - AdminAreaSettings adminAreaSettings, - ILocalizationService localizationService) - { - _permissionService = permissionService; - _webApiSettings = settings; - _settingService = settingService; - _webApiPluginService = webApiPluginService; - _adminAreaSettings = adminAreaSettings; - _localizationService = localizationService; - } - - private bool HasPermission(bool notify = true) - { - bool hasPermission = _permissionService.Authorize(WebApiPermissionProvider.ManageWebApi); - - if (notify && !hasPermission) - NotifyError(_localizationService.GetResource("Admin.AccessDenied.Description")); - - return hasPermission; - } - private void AddButtonText() - { - ViewData["ButtonTextEnable"] = _localizationService.GetResource("Plugins.Api.WebApi.Activate"); - ViewData["ButtonTextDisable"] = _localizationService.GetResource("Plugins.Api.WebApi.Deactivate"); - ViewData["ButtonTextRemoveKeys"] = _localizationService.GetResource("Plugins.Api.WebApi.RemoveKeys"); - ViewData["ButtonTextCreateKeys"] = _localizationService.GetResource("Plugins.Api.WebApi.CreateKeys"); - } - - public ActionResult Configure() - { - if (!HasPermission(false)) - return AccessDeniedPartialView(); - - var model = new WebApiConfigModel(); - model.Copy(_webApiSettings, true); - - var odataUri = new Uri(Request.Url, - WebApiGlobal.MostRecentOdataPath.StartsWith("/") ? WebApiGlobal.MostRecentOdataPath : "/" + WebApiGlobal.MostRecentOdataPath - ); - - model.ApiOdataUrl = odataUri.AbsoluteUri.EnsureEndsWith("/"); - model.ApiOdataMetadataUrl = model.ApiOdataUrl + "$metadata"; - - model.GridPageSize = _adminAreaSettings.GridPageSize; - - AddButtonText(); - - return View(model); - } - - [HttpPost, ActionName("Configure")] - [FormValueRequired("savegeneralsettings")] - public ActionResult SaveGeneralSettings(WebApiConfigModel model) - { - if (!HasPermission(false) || !ModelState.IsValid) - return Configure(); - - model.Copy(_webApiSettings, false); - _settingService.SaveSetting(_webApiSettings); - - WebApiCaching.Remove(WebApiControllingCacheData.Key); - - return Configure(); - } - - [HttpPost, GridAction(EnableCustomBinding = true)] - public ActionResult GridUserData(GridCommand command) - { - var model = _webApiPluginService.GetGridModel(command.Page - 1, command.PageSize); - - AddButtonText(); - - return new JsonResult { Data = model }; - } - - [HttpPost] - public void ApiButtonCreateKeys(int customerId) - { - _webApiPluginService.CreateKeys(customerId); - } - - [HttpPost] - public void ApiButtonRemoveKeys(int customerId) - { - _webApiPluginService.RemoveKeys(customerId); - } - - [HttpPost] - public void ApiButtonEnable(int customerId) - { - _webApiPluginService.EnableOrDisableUser(customerId, true); - } - - [HttpPost] - public void ApiButtonDisable(int customerId) - { - _webApiPluginService.EnableOrDisableUser(customerId, false); - } - - } -} diff --git a/src/Plugins/Api.WebApi/DependencyRegistrar.cs b/src/Plugins/Api.WebApi/DependencyRegistrar.cs deleted file mode 100644 index 1eb0f0c860..0000000000 --- a/src/Plugins/Api.WebApi/DependencyRegistrar.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Autofac; -using Autofac.Integration.Mvc; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Plugin.Api.WebApi.Services; - -namespace SmartStore.Plugin.Api.WebApi -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/Api.WebApi/Description.txt b/src/Plugins/Api.WebApi/Description.txt deleted file mode 100644 index db309f19e4..0000000000 --- a/src/Plugins/Api.WebApi/Description.txt +++ /dev/null @@ -1,9 +0,0 @@ -Group: Api -FriendlyName: SmartStore.NET Web Api -SystemName: Api.WebApi -Version: 1.23 -MinAppVersion: 2.0.0 -Author: SmartStore AG -DisplayOrder: 1 -FileName: SmartStore.Plugin.Api.WebApi.dll -ResourceRootKey: Plugins.Api.WebApi \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/Docs/Developer-Guide.md b/src/Plugins/Api.WebApi/Docs/Developer-Guide.md deleted file mode 100644 index 900bc6f0d1..0000000000 --- a/src/Plugins/Api.WebApi/Docs/Developer-Guide.md +++ /dev/null @@ -1,492 +0,0 @@ -# Introduction -The SmartStore.Net Web API allows direct access to the data of an online store. It is build on the most recent technologies Microsoft offers for web based data consuming, the ASP.NET Web API and the OData provider. This documentation gives you an overview of how to build an API client, also known as API consumer. It uses C# code but you can build your consumer in any common programming language. As OData is a standardized protocol there are a lot of [frameworks and toolkits][4] available for various platforms. - -The ASP.NET Web API is a framework for building web APIs on top of the .NET framework. It uses HTTP as an application protocol (rather than a transport protocol) to return data based on the client requests. The Web API is able to return the data appropriately based on the media type specified with the request. By default it provides JSON and XML based responses. - -The [Open Data Protocol (OData)][5] is a standardized web protocol that provides an uniform way to expose, structure, query and manipulate data using REST practices. OData also provides an uniform way to represent metadata about the data, allowing clients to know more about the type system, relationships and structure of the data. - -# Prerequisites -The SmartStore.Net Web API requires configuration by the storekeeper to go into action. First of all he must install the Web API plugin in the backend of SmartStore.Net. The plugin technology gives him the opportunity to activate or deactivate the entire Web API at any time without any influence on the online store. - -Next step is to configure the API on the plugin's configuration page. The main thing here is to provide individual members access to the API and the data of the online store. Therefore the storekeeper can create a public and a secret key for each registered member. Only a registered member with both keys has access to the API. To exclude a member from the API the storekeeper can either delete the keys of the member (permanent exclusion) or disable them (temporary exclusion). Roles and rights of a member are taken into consideration when accessing data via the API. - -The consumer must transmit the public key through a custom HTTP header field. It identifies the member who is accessing the API. The secret key on the other hand should never ever be send over the wire! It is secret to the storekeeper and the member who is accessing the Web API. It is only used for encryption as described in the following chapters. - -# The SmartStore.Net Web API in detail -You can consume API services through HTTP calls in a RESTful manner by using HTTP methods GET, POST (insert), PUT (update), PATCH (partially update) and DELETE. OData options (like $filter, $top, $select etc.) and API specific options (like SmNetFulfillCountry) can be transfered through query strings. The web API offers two services. The OData service (path `/odata/v1/`) provides all entity related data and the API service (path `/api/v1/`) provides all remaining resources. - -Paging is required if you want to query multiple records. You can do that with OData $skip and $top. The maximum value for $top is returned in SmartStore-Net-Api-MaxTop header field. - -A request body needs to be UTF8 encoded. - -The OData metadata document ------- -The metadata document describes the entity data model (EDM) of the OData service, using an XML language called the Conceptual Schema Definition Language (CSDL). The metadata document shows the structure of the data in the OData service and can be used to generate client code. It is the recommended overview for the consumer to indicate where to find a particular resource. To get the metadata document, send a - - GET http://localhost:1260/odata/v1/$metadata - -Request HTTP header fields ------- -**User-Agent** (optional): Short description of the API consumer. Example: `My shopping data consumer v.1.0` - -**Accept** (required): The wanted response format. Example for JSON: `application/json, text/javascript, */*`. Example for XML: `application/atom+xml,application/atomsvc+xml,application/xml` - -**Accept-Charset** (required): Always UTF-8. - -**Content-Type** and **Content-Length** (conditional): Necessary for the methods POST, PUT, and PATCH, if new data is send via the HTTP body. Example: `application/json; charset=utf-8` - -**Content-MD5** (optional): For methods POST, PUT, and PATCH. Authentication provides the error `ContentMd5NotMatching` if the hash does not match the one calculated by the server. This header field has no safety relevance, because the content carried out using the HMAC signature. Example: `lgifXydL3FhffpTIilkwOw==` - -**SmartStore-Net-Api-Date** (required): Date and time of the request as coordinated universal time (UTC). Use ISO-8601 format including milliseconds. Example: `2013-11-09T11:42:48.4715986Z` - -**SmartStore-Net-Api-PublicKey** (required): The public key of a member. Example: `0c6b33651708eb09c8a8d6036b79d739` - -**Authorization** (required): The authorization schema and the HMAC signature, separated by a space. The schema is SmNetHmac plus its version. Example: `SmNetHmac1 +yvONYvJmQl19omu1uE3HVlQ7afd7Qqkk8DrNrfUbe8=` - -Example of a complete request header: - - User-Agent: My shopping data consumer v.1.0 - Accept: application/json, text/javascript, */* - Accept-Charset: UTF-8 - SmartStore-Net-Api-PublicKey: 0c6b33651708eb09c8a8d6036b79d739 - SmartStore-Net-Api-Date: 2013-11-09T11:42:48.4715986Z - Content-Type: application/json; charset=utf-8 - Content-MD5: lgifXydL3FhffpTIilkwOw== - Authorization: SmNetHmac1 +yvONYvJmQl19omu1uE3HVlQ7afd7Qqkk8DrNrfUbe8= - - -Response HTTP header fields ------- -**SmartStore-Net-Api-Version**: The highest API version supported by the server (unsigned integer) and the version of the installed API plugin (floating-point value). The API version is only increased when there is a fundamental break in API development without the ability of downward compatibility. The plugin version is typically increased when the API has been extended, for example when new ressouces were added. -Example: `1 1.0` - -**SmartStore-Net-Api-Date**: The current server date and time in ISO-8601 UTC. Example: `2013-11-11T14:35:33.7772907Z` - -**SmartStore-Net-Api-MaxTop**: The maximum value for OData $top option. Required for client driven paging. - -**SmartStore-Net-Api-HmacResultDesc**: Short description of the result of the HMAC authentication. Only returned if the authentication failed. Example: `InvalidTimestamp` - -**SmartStore-Net-Api-HmacResultId**: Unsigned ID that represents the result of the HMAC authentication. Only returned if the authentication failed. Example: `5` - -**WWW-Authenticate**: The name of the authentication method that failed. Note that CORS requests can lead to multiple of this header fields. The SmartStore.Net Web API returns `SmNetHmac1` if its authentication failed. - -List with HmacResultId and HmacResultDesc: - -- 0 Success -- 1 FailedForUnknownReason -- 2 ApiUnavailable -- 3 InvalidAuthorizationHeader -- 4 InvalidSignature -- 5 InvalidTimestamp -- 6 TimestampOutOfPeriod -- 7 TimestampOlderThanLastRequest -- 8 MissingMessageRepresentationParameter -- 9 ContentMd5NotMatching -- 10 UserUnknown -- 11 UserDisabled -- 12 UserInvalid -- 13 UserHasNoPermission - -Frequent HTTP response status codes ------- -**200 OK**: Standard response for successful HTTP requests. - -**201 Created**: The request has been fulfilled and resulted in a new resource being created. - -**204 No Content**: The server successfully processed the request, but is not returning any content. Usually used as a response to a successful delete request. - -**400 BadRequest**: There is something wrong with the request, for instance an invalid or missing parameter. - -**401 Unauthorized**: Authentication failed or the user is not authorized (in case of UserHasNoPermission). There is no content returned because no access can be granted to the client. - -**403 Forbidden**: The resource cannot be accessed through the API, for example for security reasons. - -**404 Not found**: The requested ressource cannot be found. - -**406 Not Acceptable**: The requested resource is only capable of generating content not acceptable according to the accept headers sent in the request. Typically generated by OData provider. - -**422 Unprocessable entity**: The request is ok but its processing failed due to sematic issues or unprocessable instructions. For example putting the payment status of an order to an unknown value. - -**500 Internal Server Error**: A generic error message, given when no more specific message is suitable. - -**501 Not implemented**: Accessing the ressource through the API is not implemented (yet). - -Query options ------- -[OData query options][2] allows to manipulate the querying of data like sorting, filtering, paging etc. They are send in the query string of the request URL. A more detailed overview can be found [here][3]. - -Custom query options should lighten the work with the SmartStore.Net Web API, especially when you work with entity relationships. - -**SmNetFulfill{property_name}**: Entities are often in multiple relationships with other entities. In most cases an ID has to be set to create or to change such a relation. But mostly this ID is unknown to you. To reduce the amount of API round trips this option can set an entity relation indirectly. Example: You want to add a german address but you don't know the ID of the german country entity which is required for inserting an address. Rather than calling the API again to get the ID you can add the query option SmNetFulfillCountry=DE and the API resolves the relationship automatically. The API can fulfill the following properties: - -- Country: The two or three letter ISO country code. Example: SmNetFulfillCountry=USA -- StateProvince: The abbreviation of a state province. Example for California: SmNetFulfillStateProvince=CA -- Language: The culture of a language. Example for German: SmNetFulfillLanguage=de-DE -- Currency: The ISO code of a currency. Example for Euro: SmNetFulfillCurrency=EUR - -# HMAC authentication -The SmartStore.Net Web API uses the HMAC authentication method to protect data from unauthorized access. - -HMAC (hash-based message authentication code) is a sessionless authentication method, where the integrity of a resource request is guaranteed through a this request representing code (called message representation) and a cryptological hash function. The procedure is considered to be very safe. It is used for example by Amazon to protect their S3 Web services. - -SmartStore.Net uses SHA-256 as hash function, which is why this authentication procedure is often called HMAC-SHA256. - -The consumer must transmit a timestamp with each request which may not differ too far from the server time, otherwise the authentication will fail. The storekeeper can configure this time window in the plugin configuration. The default value is 15 minutes. To prevent replay attacks the timestamp must be younger than the one of a previous request. - - -Message representation ------- -The message representation is a concatenation of various informations separated by newline characters. All values are required but can be empty (in case of Content-MD5). It must be build as follows: - - HTTP method\n - Content-MD5\n - Response content type (accept header)\n - Canonicalized URI\n - ISO-8601 UTC timestamp\n - Public key - -**HTTP method**: In lower case. Example: `post` - -**Content-MD5**: The base64 encoded MD5 hash of the HTTP body, so `base64(md5Hash(content))`. For GET requests this fied is empty. The value should be equal to the optional Content-MD5 request header field. For example the MD5 hash for the content - - {"OrderId":152,"Note":"Hello world!","DisplayToCustomer":false,"CreatedOnUtc":"2013-11-09T11:15:00"} - -is `lgifXydL3FhffpTIilkwOw==`. - -**Response content type**: The value of the accept header field. In lower case. Example: `application/json, text/javascript, */*` - -**Canonicalized URI**: The complete URI of the requested resource (including query string). In lower case. Example: `http://localhost:1260/odata/v1/ordernotes` - -**ISO-8601 UTC timestamp**: Current UTC date and time including milliseconds. Must be equal to the request header field SmartStore-Net-Api-Date. Example: `2013-11-09T11:37:21.1918793Z`. The API accepts milliseconds with 7 and 3 digits. Can be created in C# as follows: `string timestamp = DateTime.UtcNow.ToString("o");` - -**Public key**: The public key of the user. In lower case. Example: `0c6b33651708eb09c8a8d6036b79d739` - -A complete message representation might look like this: - - post - lgifXydL3FhffpTIilkwOw== - application/json, text/javascript, */* - http://localhost:1260/odata/v1/ordernotes - 2013-11-09T11:42:48.4715986Z - 0c6b33651708eb09c8a8d6036b79d739 - -HMAC signature ------- -The signature is the computed hash of the message representation by using SHA-256 and the user's secret key. Always UTF8 encode the secret key and the message representation while calculating the hash. Example of creating the HMAC signature: - - public string CreateSignature(string secretKey, string messageRepresentation) - { - if (string.IsNullOrWhiteSpace(secretKey) || string.IsNullOrWhiteSpace(messageRepresentation)) - return ""; - - string signature; - var secretBytes = Encoding.UTF8.GetBytes(secretKey); - var valueBytes = Encoding.UTF8.GetBytes(messageRepresentation); - - using (var hmac = new HMACSHA256(secretBytes)) - { - var hash = hmac.ComputeHash(valueBytes); - signature = Convert.ToBase64String(hash); - } - return signature; - } - -The signature is transmitted as a base64 encoded string together with the schema using authorization header field. -For above message representation and the secret key `3025c89ebaab20b71e0e42744239bf50` the authorization header field is - - Authorization: SmNetHmac1 +yvONYvJmQl19omu1uE3HVlQ7afd7Qqkk8DrNrfUbe8= - -# Code examples -See also [this tutorial][1] for more information about using the ASP.NET web API client libraries. - -Making a GET request ------- -Let us read orders created after a particular date. For security reasons query results needs to be paged, so we have to specify the $top option (and optionally $skip). - - string publicKey = "0c6b33651708eb09c8a8d6036b79d739"; - string secretKey = "3025c89ebaab20b71e0e42744239bf50"; - string method = "get"; - string accept = "application/json, text/javascript, */*"; - string timestamp = DateTime.UtcNow.ToString("o"); // 2013-11-11T10:15:54.1731069Z - string url = "http://localhost:1260/odata/v1/Orders?$top=10&$filter=CreatedOnUtc gt datetime'2013-02-20T00:00:00'"; - -First we create the message representation. - - string messageRepresentation = string.Join("\n", - get.ToLower(), - "", - accept.ToLower(), - url.ToLower(), - timestamp, - publicKey.ToLower() - ); - -It looks like: - - get - - application/json, text/javascript, */* - http://localhost:1260/odata/v1/orders?$top=10&$filter=createdonutc gt datetime'2013-02-20t00:00:00' - 2013-11-11T10:15:54.1731069Z - 0c6b33651708eb09c8a8d6036b79d739 - -Now we can calculate the HMAC signature by using our secret key. - - string signature = CreateSignature(secretKey, messageRepresentation); // hWce6V2KA0kkB0GBbIK0GSw5QAcS3+vj+m+WN/8k9EE= - -We have all informations to setup the request, so we create a web request object and pass the required headers. - - var request = (HttpWebRequest)WebRequest.Create(url); - request.Method = method; - request.UserAgent = "My shopping data consumer v.1.0"; - request.Accept = accept; - request.Headers.Add("Accept-Charset", "UTF-8"); - request.Headers.Add("SmartStore-Net-Api-PublicKey", publicKey); - request.Headers.Add("SmartStore-Net-Api-Date", timestamp); - request.Headers.Add("Authorization", "SmNetHmac1 " + signature); - -The complete header looks like: - - User-Agent: My shopping data consumer v.1.0 - Accept: application/json, text/javascript, */* - Accept-Charset: UTF-8 - SmartStore-Net-Api-PublicKey: 0c6b33651708eb09c8a8d6036b79d739 - SmartStore-Net-Api-Date: 2013-11-11T10:15:54.1731069Z - Authorization: SmNetHmac1 hWce6V2KA0kkB0GBbIK0GSw5QAcS3+vj+m+WN/8k9EE= - -Making a POST request ------- -Posting means inserting data via API. This example shows how to add a new order note "Hello world!" to the order with ID 152. Here is the function to create the MD5 hash of the request body: - - public string CreateContentMd5Hash(byte[] content) - { - string result = ""; - if (content != null && content.Length > 0) - { - using (var md5 = MD5.Create()) - { - byte[] hash = md5.ComputeHash(content); - result = Convert.ToBase64String(hash); - } - } - return result; - } - -All other variables have not changed. - - string content = "{\"OrderId\":152,\"Note\":\"Hello world!\",\"DisplayToCustomer\":false,\"CreatedOnUtc\":\"2013-11-09T11:15:00\"}"; - - byte[] data = Encoding.UTF8.GetBytes(content); - string contentMd5Hash = CreateContentMd5Hash(data); - - string method = "post"; - string timestamp = DateTime.UtcNow.ToString("o"); // 2013-11-11T19:44:04.9378268Z - string url = "http://localhost:1260/odata/v1/OrderNotes"; - -We add the same header fields as in the previous example and additionally: - - request.ContentLength = data.Length; - request.ContentType = "application/json; charset=utf-8"; - request.Headers.Add("Content-MD5", contentMd5Hash); // optional - -And we write the content into the request stream. - - using (var stream = request.GetRequestStream()) - { - stream.Write(data, 0, data.Length); - } - -The message representation is: - - post - lgifXydL3FhffpTIilkwOw== - application/json, text/javascript, */* - http://localhost:1260/odata/v1/ordernotes - 2013-11-11T19:44:04.9378268Z - 0c6b33651708eb09c8a8d6036b79d739 - -The header looks like: - - User-Agent: My shopping data consumer v.1.0 - Accept: application/json, text/javascript, */* - Accept-Charset: UTF-8 - SmartStore-Net-Api-PublicKey: 0c6b33651708eb09c8a8d6036b79d739 - SmartStore-Net-Api-Date: 2013-11-11T19:44:04.9378268Z - Content-Type: application/json; charset=utf-8 - Content-Length: 100 - Content-MD5: lgifXydL3FhffpTIilkwOw== - Authorization: SmNetHmac1 ejKxxtHNJYHCtBglZPg+cbSs3YTrA50pkfTHtVb1PMo= - -As a general rule POST, PUT and PATCH are returning the added or changed record. For example: - - { - "odata.metadata":"http://localhost:1260/odata/v1/$metadata#OrderNotes/@Element","OrderId":152,"Note":"Hello world!","DisplayToCustomer":false,"CreatedOnUtc":"2013-11-09T11:15:00","Id":692 - } - -Processing the response ------- -Example of reading the response into a string: - - HttpWebResponse webResponse = null; - string response; - - try - { - webResponse = request.GetResponse() as HttpWebResponse; - using (var reader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8)) - { - response = reader.ReadToEnd(); - } - } - catch (WebException wexc) { /* ... */ } - catch (Exception exc) { /* ... */ } - finally - { - if (webResponse != null) - { - webResponse.Close(); - webResponse.Dispose(); - } - } - -JSON data can be easily parsed into dynamic or strongly typed objects using [Json.NET][6]. This example deserialize a JSON string into a list of customers. - - public class Customer - { - public string Id { get; set; } - public string CustomerGuid { get; set; } - public string Email { get; set; } - // more properties... - } - - JObject json = JObject.Parse(response); - string metadata = (string)json["odata.metadata"]; - - if (!string.IsNullOrWhiteSpace(metadata) && metadata.EndsWith("#Customers")) - { - List customers = json["value"].Select(x => x.ToObject()).ToList(); - } - -Dynamic JSON parsing might look like this: - - dynamic dynamicJson = JObject.Parse(response); - - foreach (dynamic customer in dynamicJson.value) - { - string str = string.Format("{0} {1} {2}", customer.Id, customer.CustomerGuid, customer.Email); - Debug.WriteLine(str); - } - - -# Working with the product entity - -#### Getting a product with name *SmartStore eBay SmartSeller* - - GET http://localhost:1260/odata/v1/Products?$top=1&$filter=Name eq 'SmartStore eBay SmartSeller' - -#### Get child products of group product with ID 210 - - GET http://localhost:1260/odata/v1/Products?$top=120&$filter=ParentGroupedProductId eq 210 - -#### Get final price of product with ID 211 - - POST http://localhost:1260/odata/v1/Products(211)/FinalPrice - -Note the post method. There is a second action `LowestPrice` which serves the lowest possible price for a product. - -#### Managing product attributes - -You can use the following endpoints: `ProductAttributes` (types of attributes), `ProductVariantAttributes` (attribute types mapped to a product), `ProductVariantAttributeValues` (attribute values assigned to product) and optionally `ProductVariantAttributeCombinations` (additional information for particular attribute combinations). Because managing attributes that way can lead to some extra work, there is an action method `ManageAttributes` that wraps up the most important steps. - - POST http://localhost:1260/odata/v1/Products(211)/ManageAttributes - {"Synchronize":true,"Attributes":[ - {"Name":"Color","IsRequired":false,"Values":[ - {"Name":"Red"},{"Name":"Green","IsPreSelected":true},{"Name":"Blue"} - ]}, - {"Name":"Size","Values":[ - {"Name":"Large"},{"Name":"X-Large","IsPreSelected":true} - ]} - ]} - -That request configurates a product with the ID 211 with two attributes `Color` and `Size` and its values `Red, Green, Blue` and `Large, X-Large`. The action parameter `Attributes` is of type `ManageAttributeType`. See the OData metadata document for a complete list of available properties. If `Synchronize` is set to `false` only missing attributes and attribute values are inserted. If set to `true` existing records are also updated and values that are not included in the request body are removed from the database. If you pass an empty value array the attribute and all its values are removed from the product. - -The following method creates all possible attribute combinations for a product with the ID 211 - - POST http://localhost:1260/odata/v1/Products(211)/CreateAttributeCombinations - -As a first step this action always deletes all existing attribute combinations (for a product). - - -# More examples - -#### Get installed payment methods - - GET http://localhost:1260/api/v1/Payments/Methods?$filter=Installed eq true - -Note that payment methods in SmartStore.Net are plugins and not entities, so we must use the `/api/v1/` service here. - -#### Get return requests for customer with ID 1 - - GET http://localhost:1260/odata/v1/Customers(1)/ReturnRequests?$top=25&$inlinecount=allpages - -Note the inlinecount option which tells OData to return an odata.count value with total count of matching entities in the response. - -#### Mark order with ID 145 as payed - - POST http://localhost:1260/odata/v1/Orders(145)/PaymentPaid - {"PaymentMethodName":"Payments.Sofortueberweisung"} - -This request is called OData action because it is initiating further data processing on the server. -Note the second line which are optional OData action parameters. They are send in the request body, not in the query string. This example additionally set the system name of the payment method to `Payments.Sofortueberweisung` with which order 145 was balanced. - -Other actions that would change the payment status are `PaymentPending` and `PaymentRefund`. `PaymentRefund` supports the action parameter `Online`. *True* would call the related payment gateway to refund the payment. Use the action `Cancel` to cancel an order. - -#### Get shipping address for order 145 - - GET http://localhost:1260/odata/v1/Orders(145)/ShippingAddress - -This request is called OData navigation. Use `BillingAddress` if you want the billing address of an order to be returned. - -#### Partially update address with ID 1 - - PATCH http://localhost:1260/odata/v1/Addresses(1)?SmNetFulfillCountry=US&SmNetFulfillStateProvince=NY - {"City":"New York","Address1":"21 West 52nd Street","ZipPostalCode":"10021","FirstName":"John","LastName":"Doe"} - -The example uses SmNetFulfillCountry and SmNetFulfillStateProvince options to update the country (USA) and province (New York). That avoids extra querying of country and province records and passing its IDs in the request body. -Note that you cannot use a path `/Orders(145)/ShippingAddress` to update an address because `ShippingAddress` is a navigation property and updates are not supported here. - -#### Get email address of customer with ID 1 - - GET http://localhost:1260/odata/v1/Customers(1)/Email - -#### Get ID of store with name *my nice store* - - GET http://localhost:1260/odata/v1/Stores?$top=1&$filter=Name eq 'my nice store'&$select=Id - -Note the select option which tells OData just to return the Id property. - -#### Getting localized property values - - GET http://localhost:1260/odata/v1/LocalizedPropertys?$top=120&$filter=LocaleKeyGroup eq 'Product' and EntityId eq 224 and Language/LanguageCulture eq 'en-US' - -That's where OData filter enter the equation. That request filters all english property values for a product with the ID 224. LocaleKeyGroup is typically the entity name (Product, Category, Manufacturer, ProductBundleItem, DeliveryTime etc.). -The result looks like - - { - "odata.metadata":"http://localhost:1260/odata/v1/$metadata#LocalizedPropertys","value":[ - { - "EntityId":224,"LanguageId":1,"LocaleKeyGroup":"Product","LocaleKey":"Name","LocaleValue":"My name for the product","Id":111 - },{ - "EntityId":224,"LanguageId":1,"LocaleKeyGroup":"Product","LocaleKey":"FullDescription","LocaleValue":"

Hello world! My product description goes here...

","Id":113 - }] - } - -LocaleKey is the context property name (here name and full description of the product entity). LocaleValue offers the localized value. - -
-[1]: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client -[2]: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options -[3]: http://www.odata.org/documentation/odata-v2-documentation/uri-conventions/#4_Query_String_Options -[4]: http://msopentech.com/odataorg/libraries/ -[5]: http://msopentech.com/odataorg/introduction/ -[6]: https://json.codeplex.com/ \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/Extensions/MiscExtensions.cs b/src/Plugins/Api.WebApi/Extensions/MiscExtensions.cs deleted file mode 100644 index 82f1acdeeb..0000000000 --- a/src/Plugins/Api.WebApi/Extensions/MiscExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Text; -using System.Web.Mvc; - -namespace SmartStore.Plugin.Api.WebApi.Extensions -{ - public static class MiscExtensions - { - public static string ApiGridButtons(this HtmlHelper helper) - { - var sb = new StringBuilder(); - - sb.Append("
\">"); - - sb.AppendFormat("", - helper.ViewData["ButtonTextRemoveKeys"]); - - sb.AppendFormat("", - helper.ViewData["ButtonTextCreateKeys"]); - - sb.AppendFormat("", - helper.ViewData["ButtonTextEnable"]); - - sb.AppendFormat("", - helper.ViewData["ButtonTextDisable"]); - - sb.Append("
"); - - return sb.ToString(); - } - } -} diff --git a/src/Plugins/Api.WebApi/Localization/resources.de-de.xml b/src/Plugins/Api.WebApi/Localization/resources.de-de.xml deleted file mode 100644 index 0159961db4..0000000000 --- a/src/Plugins/Api.WebApi/Localization/resources.de-de.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - Web-API - - - - -
  • Nur registrierte Kunden (siehe Liste unten) mit einem öffentlichen und einem geheimen Schlüssel zur API haben Zugriff.
  • -
  • Sie können den Zugriff für einen Kunden durch Löschen der Schlüssel endgültig oder durch Deaktivieren zeitweise unterbinden.
  • -
  • Die Rechte der jeweiligen Kundengruppe gelten auch bei Zugriffen über die API.
  • -]]> -
    -
    - - OData API URL - - - Die URL der OData Web API. - - - OData Metadaten URL - - - Die URL der OData Metadaten. Sie beschreiben das gesamte Entitäten-Daten-Modell (EDM), auf dem die Web API basiert. - - - Anfragezeitfenster (Minuten) - - - Aus Sicherheitsgründen darf die Zeit, zu der die Anfrage an die API gesendet wurde, nicht zu weit von der aktuellen Server-Zeit abweichen. Mit dieser Einstellung legen Sie dieses Zeitfenster in Minuten fest. - - - Unauthorisierte Zugriffe speichern - - - Jeder unauthorisierte Zugriff wird in der Ereignisliste gespeichert. - - - Öffentlicher Schlüssel - - - Geheimer Schlüssel - - - Letzter Zugriff - - - Für API zugelassen - - - Zulassen - - - Nicht zulassen - - - Schlüssel löschen - - - Schlüssel erstellen - -
    \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/Localization/resources.en-us.xml b/src/Plugins/Api.WebApi/Localization/resources.en-us.xml deleted file mode 100644 index 4b7f67b5bf..0000000000 --- a/src/Plugins/Api.WebApi/Localization/resources.en-us.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - Web-API - - - - -
  • Only registered customers (see list below) with a public and a secret key for the API have access to it.
  • -
  • You can remove the access for a customer permanently by deleting the keys or temporary by deactivating them.
  • -
  • The rights of the respective customer group are valid for the API too.
  • -]]> -
    -
    - - OData API URL - - - URL of the OData Web API. - - - OData metadata URL - - - URL of the OData metadata. It describes the complete entity data model (EDM) the Web API is based on. - - - Request time window (minutes) - - - For security reasons should the time at which the request was sent to the API differ not too far from the current server time. With this setting, you set this time window in minutes. - - - Log unauthorized accesses - - - Each unauthorized access will be saved in the log list. - - - Public key - - - Secret key - - - Last access - - - API enabled - - - Activate - - - Deactivate - - - Delete keys - - - Generate keys - -
    \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/Models/WebApiConfigModel.cs b/src/Plugins/Api.WebApi/Models/WebApiConfigModel.cs deleted file mode 100644 index 4b661e3d06..0000000000 --- a/src/Plugins/Api.WebApi/Models/WebApiConfigModel.cs +++ /dev/null @@ -1,37 +0,0 @@ -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; -using SmartStore.Web.Framework.WebApi; - -namespace SmartStore.Plugin.Api.WebApi.Models -{ - public class WebApiConfigModel : ModelBase - { - [SmartResourceDisplayName("Plugins.Api.WebApi.ApiOdataUrl")] - public string ApiOdataUrl { get; set; } - - [SmartResourceDisplayName("Plugins.Api.WebApi.ApiOdataMetadataUrl")] - public string ApiOdataMetadataUrl { get; set; } - - [SmartResourceDisplayName("Plugins.Api.WebApi.ValidMinutePeriod")] - public int ValidMinutePeriod { get; set; } - - [SmartResourceDisplayName("Plugins.Api.WebApi.LogUnauthorized")] - public bool LogUnauthorized { get; set; } - - public int GridPageSize { get; set; } - - public void Copy(WebApiSettings settings, bool fromSettings) - { - if (fromSettings) - { - ValidMinutePeriod = settings.ValidMinutePeriod; - LogUnauthorized = settings.LogUnauthorized; - } - else - { - settings.ValidMinutePeriod = ValidMinutePeriod; - settings.LogUnauthorized = LogUnauthorized; - } - } - } -} diff --git a/src/Plugins/Api.WebApi/Properties/AssemblyInfo.cs b/src/Plugins/Api.WebApi/Properties/AssemblyInfo.cs deleted file mode 100644 index f4e34c3a83..0000000000 --- a/src/Plugins/Api.WebApi/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Api.WebApi")] diff --git a/src/Plugins/Api.WebApi/RouteProvider.cs b/src/Plugins/Api.WebApi/RouteProvider.cs deleted file mode 100644 index c07be74448..0000000000 --- a/src/Plugins/Api.WebApi/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Api.WebApi -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Api.WebApi.Action", - "Plugins/WebApi/{action}", - new { controller = "WebApi" }, - new[] { "SmartStore.Plugin.Api.WebApi.Controllers" } - ) - .DataTokens["area"] = "Api.WebApi"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Api.WebApi/SmartStore.Plugin.Api.WebApi.csproj b/src/Plugins/Api.WebApi/SmartStore.Plugin.Api.WebApi.csproj deleted file mode 100644 index f87e344d5f..0000000000 --- a/src/Plugins/Api.WebApi/SmartStore.Plugin.Api.WebApi.csproj +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - False - - - False - - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - Debug - AnyCPU - {D8947A85-F0D7-4FF5-8E77-ED4EE18447C8} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Api.WebApi - SmartStore.Plugin.Api.WebApi - v4.5 - 512 - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Api.WebApi\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Api.WebApi\ - TRACE - prompt - 4 - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - ..\..\packages\Autofac.WebApi.3.1.0\lib\net40\Autofac.Integration.WebApi.dll - - - ..\..\packages\AutoMapper.3.1.1\lib\net40\AutoMapper.dll - - - ..\..\packages\AutoMapper.3.1.1\lib\net40\AutoMapper.Net4.dll - - - False - ..\..\packages\Microsoft.Data.Edm.5.6.1\lib\net40\Microsoft.Data.Edm.dll - - - False - ..\..\packages\Microsoft.Data.OData.5.6.1\lib\net40\Microsoft.Data.OData.dll - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebApi.Client.5.1.2\lib\net45\System.Net.Http.Formatting.dll - - - - - - False - ..\..\packages\System.Spatial.5.6.1\lib\net40\System.Spatial.dll - - - - - ..\..\packages\Microsoft.AspNet.Cors.5.1.2\lib\net45\System.Web.Cors.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.WebApi.Core.5.1.2\lib\net45\System.Web.Http.dll - - - ..\..\packages\Microsoft.AspNet.WebApi.Cors.5.1.1\lib\net45\System.Web.Http.Cors.dll - - - ..\..\packages\Microsoft.AspNet.WebApi.OData.5.1.2\lib\net45\System.Web.Http.OData.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - False - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Always - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - Always - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541ad-f659-47da-8763-16f36c5cd2f4} - SmartStore.Services - - - {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} - SmartStore.Data - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - Designer - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/Views/Web.config b/src/Plugins/Api.WebApi/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Api.WebApi/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Api.WebApi/Views/WebApi/Configure.cshtml b/src/Plugins/Api.WebApi/Views/WebApi/Configure.cshtml deleted file mode 100644 index 827e5a2d46..0000000000 --- a/src/Plugins/Api.WebApi/Views/WebApi/Configure.cshtml +++ /dev/null @@ -1,111 +0,0 @@ -@model WebApiConfigModel -@using SmartStore.Plugin.Api.WebApi; -@using SmartStore.Plugin.Api.WebApi.Models; -@using SmartStore.Web.Framework; -@using SmartStore.Web.Framework.Plugins; -@using SmartStore.Plugin.Api.WebApi.Extensions; -@using SmartStore.Web.Framework.UI; -@using Telerik.Web.Mvc.UI; - -@{ - Layout = ""; - - Html.AddCssFileParts(true, Url.Content("~/Plugins/Api.WebApi/Content/smartstore.web.api.css")); - Html.AddScriptParts(true, Url.Content("~/Plugins/Api.WebApi/Scripts/smartstore.web.api.js")); -} - -
    - @Html.Raw(@T("Plugins.Api.WebApi.AdminInstruction")) -
    - - - - - -
    - - @(Html.Telerik().Grid() - .Name("apiuser-grid") - .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) - .Columns(c => - { - c.Bound(x => x.Id).Width(50); - c.Bound(x => x.Username); - c.Bound(x => x.Email) - .Template(x => Html.ActionLink(x.Email, "Edit", "Customer", new { id = x.Id, area = "admin" }, new { })) - .ClientTemplate("\"><#= Email #>"); - c.Bound(x => x.AdminComment); - c.Bound(x => x.PublicKey); - c.Bound(x => x.SecretKey); - c.Bound(x => x.Enabled).Width(110).Centered() - .Template(x => @Html.SymbolForBool(x.Enabled)) - .ClientTemplate(@Html.SymbolForBool("Enabled")); - c.Bound(x => x.LastRequest); - c.Template(x => @Html.ApiGridButtons()) - .ClientTemplate(@Html.ApiGridButtons()); - }) - .DataBinding(dataBinding => - { - dataBinding.Ajax().Select("GridUserData", "WebApi", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Api.WebApi.Controllers" }, { "area", "Api.WebApi" } }); - }) - .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) - .EnableCustomBinding(true) - ) - -
    - -

     

    - -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.ApiOdataUrl) - - @Model.ApiOdataUrl -
    - @Html.SmartLabelFor(model => model.ApiOdataMetadataUrl) - - @Model.ApiOdataMetadataUrl -
    - @Html.SmartLabelFor(model => model.ValidMinutePeriod) - - @Html.EditorFor(model => model.ValidMinutePeriod) - @Html.ValidationMessageFor(model => model.ValidMinutePeriod) -
    - @Html.SmartLabelFor(model => model.LogUnauthorized) - - @Html.EditorFor(model => model.LogUnauthorized) - @Html.ValidationMessageFor(model => model.LogUnauthorized) -
      - -
    -} - - diff --git a/src/Plugins/Api.WebApi/WebApiPlugin.cs b/src/Plugins/Api.WebApi/WebApiPlugin.cs deleted file mode 100644 index e27ce0cb45..0000000000 --- a/src/Plugins/Api.WebApi/WebApiPlugin.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Services.Common; -using SmartStore.Services.Localization; -using SmartStore.Services.Security; -using SmartStore.Services.Configuration; -using SmartStore.Web.Framework.WebApi; -using SmartStore.Plugin.Api.WebApi.Security; - -namespace SmartStore.Plugin.Api.WebApi -{ - public class WebApiPlugin : BasePlugin, IMiscPlugin - { - private readonly IPermissionService _permissionService; - private readonly ILocalizationService _localizationService; - private readonly ISettingService _settingService; - - public WebApiPlugin(IPermissionService permissionService, ILocalizationService localizationService, ISettingService settingService) - { - _permissionService = permissionService; - _localizationService = localizationService; - _settingService = settingService; - } - - - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "WebApi"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Api.WebApi.Controllers" }, { "area", "Api.WebApi" } }; - } - - public override void Install() - { - _permissionService.InstallPermissions(new WebApiPermissionProvider()); - - var apiSettings = new WebApiSettings() - { - LogUnauthorized = true, - ValidMinutePeriod = WebApiGlobal.DefaultTimePeriodMinutes - }; - - _settingService.SaveSetting(apiSettings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - - WebApiCaching.Remove(WebApiControllingCacheData.Key); - WebApiCaching.Remove(WebApiUserCacheData.Key); - } - - public override void Uninstall() - { - WebApiCaching.Remove(WebApiControllingCacheData.Key); - WebApiCaching.Remove(WebApiUserCacheData.Key); - - _settingService.DeleteSetting(); - - _permissionService.UninstallPermissions(new WebApiPermissionProvider()); - - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Api.WebApi", false); - - base.Uninstall(); - } - - } -} diff --git a/src/Plugins/Api.WebApi/changelog.md b/src/Plugins/Api.WebApi/changelog.md deleted file mode 100644 index 9ad0d41873..0000000000 --- a/src/Plugins/Api.WebApi/changelog.md +++ /dev/null @@ -1,19 +0,0 @@ -#Release Notes# - -##Web Api 1.23## - -###New Features### -* #431 Add support for localized properties (part 1) - -##Web Api 1.22## - -###New Features### -* #393 Implement OData actions for simpler working with product attributes -> added ProductsController.ManageAttributes and ProductsController.CreateAttributeCombinations. - -##Web Api 1.21## - -###Improvements### -* #384 Inserting sluged recources like products require an URL record - -###Bugfixes### -* PUT implementation was uncomplete \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/packages.config b/src/Plugins/Api.WebApi/packages.config deleted file mode 100644 index c220328f76..0000000000 --- a/src/Plugins/Api.WebApi/packages.config +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/web.config b/src/Plugins/Api.WebApi/web.config deleted file mode 100644 index 6527ceade2..0000000000 --- a/src/Plugins/Api.WebApi/web.config +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/AdminMenu.cs b/src/Plugins/Developer.DevTools/AdminMenu.cs deleted file mode 100644 index 9dde46e81e..0000000000 --- a/src/Plugins/Developer.DevTools/AdminMenu.cs +++ /dev/null @@ -1,25 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; -//using System.Web.Routing; -//using System.Web.Mvc; -//using SmartStore.Web.Framework.UI; -//using SmartStore.Collections; - -//namespace SmartStore.Plugin.Developer.DevTools -//{ -// public class AdminMenu : IMenuProvider -// { -// public void BuildMenu(TreeNode pluginsNode) -// { -// var menuItem = new MenuItem().ToBuilder() -// .Text("DevTools Plugin") -// .Action("Index", "DevToolsAdmin", new { area = "Developer.DevTools" }) -// .ToItem(); - -// pluginsNode.Append(menuItem); -// } - -// } -//} diff --git a/src/Plugins/Developer.DevTools/Controllers/DevToolsController.cs b/src/Plugins/Developer.DevTools/Controllers/DevToolsController.cs deleted file mode 100644 index 962e8d61cf..0000000000 --- a/src/Plugins/Developer.DevTools/Controllers/DevToolsController.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Stores; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Web.Framework.Settings; - -namespace SmartStore.Plugin.Developer.DevTools.Controllers -{ - public class DevToolsController : PluginControllerBase - { - private readonly IWorkContext _workContext; - private readonly IStoreContext _storeContext; - private readonly IStoreService _storeService; - private readonly ISettingService _settingService; - - public DevToolsController( - IWorkContext workContext, - IStoreContext storeContext, - IStoreService storeService, - ISettingService settingService) - { - _workContext = workContext; - _storeContext = storeContext; - _storeService = storeService; - _settingService = settingService; - } - - [ChildActionOnly] - public ActionResult Configure() - { - return View(); - } - - [HttpPost] - [ChildActionOnly] - public ActionResult Configure(ProfilerSettings model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - // load settings for a chosen store scope - var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - - storeDependingSettingHelper.UpdateSettings(model /*settings*/, form, storeScope, _settingService); - _settingService.ClearCache(); - - return Configure(); - } - - [AllowAnonymous] - public ActionResult MiniProfiler() - { - return View(); - } - - } -} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/DependencyRegistrar.cs b/src/Plugins/Developer.DevTools/DependencyRegistrar.cs deleted file mode 100644 index 34406f2fc1..0000000000 --- a/src/Plugins/Developer.DevTools/DependencyRegistrar.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Web.Mvc; -using System.Reflection; -using Autofac; -using Autofac.Core; -using Autofac.Integration.Mvc; -using SmartStore.Core.Plugins; -using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Plugin.Developer.DevTools.Filters; -using SmartStore.Plugin.Developer.DevTools.Services; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.Developer.DevTools -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().InstancePerRequest(); - - if (isActiveModule) - { - // intercept ALL public store controller actions - builder.RegisterType().AsActionFilterFor(); - - //// intercept CatalogController's Product action - //builder.RegisterType().AsResultFilterFor(x => x.Product(default(int), default(string))).InstancePerRequest(); - //builder.RegisterType().AsActionFilterFor().InstancePerRequest(); - //// intercept CheckoutController's Index action (to hijack the checkout or payment workflow) - //builder.RegisterType().AsActionFilterFor(x => x.Index()).InstancePerRequest(); - } - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/Developer.DevTools/Description.txt b/src/Plugins/Developer.DevTools/Description.txt deleted file mode 100644 index 56a2ed3f55..0000000000 --- a/src/Plugins/Developer.DevTools/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: SmartStore.NET Developer Tools (MiniProfiler and other goodies) -SystemName: Developer.DevTools -Version: 1.0 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Developer.DevTools.dll -ResourceRootKey: Plugins.Developer.DevTools \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/ProfilerHttpModule.cs b/src/Plugins/Developer.DevTools/ProfilerHttpModule.cs deleted file mode 100644 index d465e9e20a..0000000000 --- a/src/Plugins/Developer.DevTools/ProfilerHttpModule.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using Microsoft.Web.Infrastructure.DynamicModuleHelper; -using SmartStore.Core.Plugins; -using StackExchange.Profiling; - -namespace SmartStore.Plugin.Developer.DevTools -{ - - public class ProfilerStarter : IPreApplicationStart - { - public void Start() - { - DynamicModuleUtility.RegisterModule(typeof(ProfilerHttpModule)); - } - } - - public class ProfilerHttpModule : IHttpModule - { - public void Init(HttpApplication context) - { - context.BeginRequest += OnBeginRequest; - context.EndRequest += OnEndRequest; - } - - public static void OnBeginRequest(object sender, EventArgs e) - { - MiniProfiler.Start(); - } - - public static void OnEndRequest(object sender, EventArgs e) - { - MiniProfiler.Stop(); - } - - public void Dispose() - { - // nothing to dispose - } - } - -} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/Properties/AssemblyInfo.cs b/src/Plugins/Developer.DevTools/Properties/AssemblyInfo.cs deleted file mode 100644 index 383ac1e294..0000000000 --- a/src/Plugins/Developer.DevTools/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Tax.Free")] diff --git a/src/Plugins/Developer.DevTools/RouteProvider.cs b/src/Plugins/Developer.DevTools/RouteProvider.cs deleted file mode 100644 index 7496a06fdc..0000000000 --- a/src/Plugins/Developer.DevTools/RouteProvider.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Developer.DevTools -{ - - public class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Developer.DevTools", - "Plugin/DevTools/{action}/{id}", - new { controller = "DevTools", action = "Configure", id = UrlParameter.Optional }, - new[] { "SmartStore.Plugin.Developer.DevTools.Controllers" } - ) - .DataTokens["area"] = "Developer.DevTools"; - - //routes.MapRoute("Developer.DevTools.MyCheckout", - // "MyCheckout/{action}", - // new { controller = "MyCheckout", action = "MyBillingAddress" }, - // new[] { "SmartStore.Plugin.Developer.DevTools.Controllers" } - //) - //.DataTokens["area"] = "Developer.DevTools"; - } - public int Priority - { - get - { - return 0; - } - } - } - -} diff --git a/src/Plugins/Developer.DevTools/Services/IProfilerService.cs b/src/Plugins/Developer.DevTools/Services/IProfilerService.cs deleted file mode 100644 index bb215297d5..0000000000 --- a/src/Plugins/Developer.DevTools/Services/IProfilerService.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace SmartStore.Plugin.Developer.DevTools.Services -{ - public interface IProfilerService - { - void StepStart(string key, string message, bool isVerbose = false); - void StepStop(string key); - } -} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/Settings/ProfilerSettings.cs b/src/Plugins/Developer.DevTools/Settings/ProfilerSettings.cs deleted file mode 100644 index 8964edd570..0000000000 --- a/src/Plugins/Developer.DevTools/Settings/ProfilerSettings.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Developer.DevTools -{ - public class ProfilerSettings : ISettings - { - public bool EnableMiniProfilerInPublicStore { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/SmartStore.Plugin.Developer.DevTools.csproj b/src/Plugins/Developer.DevTools/SmartStore.Plugin.Developer.DevTools.csproj deleted file mode 100644 index 010ca3e084..0000000000 --- a/src/Plugins/Developer.DevTools/SmartStore.Plugin.Developer.DevTools.csproj +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {542B9C12-E2A1-49BB-9134-0E3484F9D669} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Developer.DevTools - SmartStore.Plugin.Developer.DevTools - v4.5 - 512 - - ..\..\ - true - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Developer.DevTools\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Developer.DevTools\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - ..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.dll - - - ..\..\packages\EntityFramework.6.0.0\lib\net45\EntityFramework.SqlServer.dll - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - ..\..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - True - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} - SmartStore.Data - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - PreserveNewest - - - Designer - PreserveNewest - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - bin\ - - - - - - - Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Aktivieren Sie die Wiederherstellung von NuGet-Paketen, um die fehlende Datei herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}". - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/Views/DevTools/Configure.cshtml b/src/Plugins/Developer.DevTools/Views/DevTools/Configure.cshtml deleted file mode 100644 index f5a309670d..0000000000 --- a/src/Plugins/Developer.DevTools/Views/DevTools/Configure.cshtml +++ /dev/null @@ -1,30 +0,0 @@ -@model SmartStore.Plugin.Developer.DevTools.ProfilerSettings -@using SmartStore.Web.Framework; - -@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) - -@using (Html.BeginForm()) -{ - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.EnableMiniProfilerInPublicStore) - - @Html.SettingEditorFor(model => model.EnableMiniProfilerInPublicStore) - @Html.ValidationMessageFor(model => model.EnableMiniProfilerInPublicStore) -
    -   - - -
    -} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/Views/Web.config b/src/Plugins/Developer.DevTools/Views/Web.config deleted file mode 100644 index d6ec073c8e..0000000000 --- a/src/Plugins/Developer.DevTools/Views/Web.config +++ /dev/null @@ -1,65 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Developer.DevTools/Web.config b/src/Plugins/Developer.DevTools/Web.config deleted file mode 100644 index fd1aee3249..0000000000 --- a/src/Plugins/Developer.DevTools/Web.config +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Developer.DevTools/packages.config b/src/Plugins/Developer.DevTools/packages.config deleted file mode 100644 index 6719710455..0000000000 --- a/src/Plugins/Developer.DevTools/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Controllers/DiscountRulesCustomerRolesController.cs b/src/Plugins/DiscountRules.CustomerRoles/Controllers/DiscountRulesCustomerRolesController.cs deleted file mode 100644 index 5d3ecfd508..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Controllers/DiscountRulesCustomerRolesController.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Linq; -using System.Web.Mvc; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Plugin.DiscountRules.CustomerRoles.Models; -using SmartStore.Services.Customers; -using SmartStore.Services.Discounts; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.DiscountRules.CustomerRoles.Controllers -{ - - public class DiscountRulesCustomerRolesController : PluginControllerBase - { - private readonly IDiscountService _discountService; - private readonly ICustomerService _customerService; - private readonly ILocalizationService _localize; - - public DiscountRulesCustomerRolesController(IDiscountService discountService, - ICustomerService customerService, ILocalizationService localize) - { - this._discountService = discountService; - this._customerService = customerService; - this._localize = localize; - } - - public ActionResult Configure(int discountId, int? discountRequirementId) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - //throw new ArgumentException("Discount could not be loaded"); - throw new ArgumentException(_localize.GetResource("Plugins.DiscountRequirement.MustBeAssignedToCustomerRole.ConfigureDiscountNotLoaded")); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - { - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - if (discountRequirement == null) - //return Content("Failed to load requirement."); - return Content(_localize.GetResource("Plugins.DiscountRequirement.MustBeAssignedToCustomerRole.ConfigureRequirementFailed")); - } - - var model = new RequirementModel(); - model.RequirementId = discountRequirementId.HasValue ? discountRequirementId.Value : 0; - model.DiscountId = discountId; - //countries - //model.AvailableCustomerRoles.Add(new SelectListItem() { Text = "Select customer role", Value = "0" }); - model.AvailableCustomerRoles.Add(new SelectListItem() { Text = _localize.GetResource("Plugins.DiscountRequirement.MustBeAssignedToCustomerRole.ConfigureSelectCustomerRole"), Value = "0" }); - foreach (var cr in _customerService.GetAllCustomerRoles(true)) - { - model.AvailableCustomerRoles.Add(new SelectListItem() { Text = cr.Name, Value = cr.Id.ToString(), Selected = discountRequirement != null && cr.Id == discountRequirement.RestrictedToCustomerRoleId }); - if (discountRequirement != null && cr.Id == discountRequirement.RestrictedToCustomerRoleId) - { - model.CustomerRoleId = cr.Id; - } - } - //add a prefix - ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("DiscountRulesCustomerRoles{0}", discountRequirementId.HasValue ? discountRequirementId.Value.ToString() : "0"); - - return View(model); - } - - [HttpPost] - public ActionResult Configure(int discountId, int? discountRequirementId, int customerRoleId) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - - if (discountRequirement != null) - { - //update existing rule - discountRequirement.RestrictedToCustomerRoleId = customerRoleId; - _discountService.UpdateDiscount(discount); - } - else - { - //save new rule - discountRequirement = new DiscountRequirement() - { - DiscountRequirementRuleSystemName = "DiscountRequirement.MustBeAssignedToCustomerRole", - RestrictedToCustomerRoleId = customerRoleId, - }; - discount.DiscountRequirements.Add(discountRequirement); - _discountService.UpdateDiscount(discount); - } - return Json(new { Result = true, NewRequirementId = discountRequirement.Id }, JsonRequestBehavior.AllowGet); - } - - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/CustomerRoleDiscountRequirementRule.cs b/src/Plugins/DiscountRules.CustomerRoles/CustomerRoleDiscountRequirementRule.cs deleted file mode 100644 index a5079e0abb..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/CustomerRoleDiscountRequirementRule.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Linq; -using SmartStore.Core; -using SmartStore.Core.Plugins; -using SmartStore.Services.Discounts; -using SmartStore.Services.Localization; -using SmartStore.Services.Configuration; - - -namespace SmartStore.Plugin.DiscountRules.CustomerRoles -{ - public partial class CustomerRoleDiscountRequirementRule : BasePlugin, IDiscountRequirementRule - { - /// - /// Check discount requirement - /// - /// Object that contains all information required to check the requirement (Current customer, discount, etc) - /// true - requirement is met; otherwise, false - /// - - private readonly ILocalizationService _localizationService; - private readonly ISettingService _settingService; - - public CustomerRoleDiscountRequirementRule(ILocalizationService _localizationService, ISettingService _settingService) - { - - this._localizationService = _localizationService; - this._settingService = _settingService; - } - - public bool CheckRequirement(CheckDiscountRequirementRequest request) - { - if (request == null) - throw new ArgumentNullException("request"); - - if (request.DiscountRequirement == null) - throw new SmartException("Discount requirement is not set"); - - if (request.Customer == null) - return false; - - if (!request.DiscountRequirement.RestrictedToCustomerRoleId.HasValue) - return false; - - foreach (var customerRole in request.Customer.CustomerRoles.Where(cr => cr.Active).ToList()) - if (request.DiscountRequirement.RestrictedToCustomerRoleId == customerRole.Id) - return true; - - return false; - } - - /// - /// Get URL for rule configuration - /// - /// Discount identifier - /// Discount requirement identifier (if editing) - /// URL - public string GetConfigurationUrl(int discountId, int? discountRequirementId) - { - //configured in RouteProvider.cs - string result = "Plugins/DiscountRulesCustomerRoles/Configure/?discountId=" + discountId; - if (discountRequirementId.HasValue) - result += string.Format("&discountRequirementId={0}", discountRequirementId.Value); - return result; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.DiscountRequirement.MustBeAssignedToCustomerRole", false); - _settingService.DeleteSettings("DiscountRequirement.MustBeAssignedToCustomerRole"); - - base.Uninstall(); - } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Description.txt b/src/Plugins/DiscountRules.CustomerRoles/Description.txt deleted file mode 100644 index 0447d72b93..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Must be assigned to customer role -SystemName: DiscountRequirement.MustBeAssignedToCustomerRole -Version: 1.3 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.DiscountRules.CustomerRoles.dll -ResourceRootKey: Plugins.DiscountRequirement.MustBeAssignedToCustomerRole diff --git a/src/Plugins/DiscountRules.CustomerRoles/Localization/resources.de-de.xml b/src/Plugins/DiscountRules.CustomerRoles/Localization/resources.de-de.xml deleted file mode 100644 index 88718207a9..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Localization/resources.de-de.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - Der Kunde muss einer Kundengruppe zugeordnet sein - - - Rabatt konnte nicht geladen werden - - - Anforderung konnte nicht geladen werden - - - Wählen Sie eine Kundengruppe - - - Benötigte Kundengruppe - - - Der Rabatt wird angewendet, wenn der Kunde zur gewählten Kundengruppe gehört. - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Localization/resources.en-us.xml b/src/Plugins/DiscountRules.CustomerRoles/Localization/resources.en-us.xml deleted file mode 100644 index 5be78a4ce5..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Localization/resources.en-us.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - Must be assigned to customer role - - - Discount could not be loaded - - - Failed to load requirement - - - Select a customer role - - - Required customer role - - - Discount will be applied if customer is in the selected customer role. - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Models/RequirementModel.cs b/src/Plugins/DiscountRules.CustomerRoles/Models/RequirementModel.cs deleted file mode 100644 index d46ea5d311..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Models/RequirementModel.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; - -namespace SmartStore.Plugin.DiscountRules.CustomerRoles.Models -{ - public class RequirementModel - { - public RequirementModel() - { - AvailableCustomerRoles = new List(); - } - - [SmartResourceDisplayName("Plugins.DiscountRequirement.MustBeAssignedToCustomerRole.Fields.CustomerRole")] - public int CustomerRoleId { get; set; } - - public int DiscountId { get; set; } - - public int RequirementId { get; set; } - - public IList AvailableCustomerRoles { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Properties/AssemblyInfo.cs b/src/Plugins/DiscountRules.CustomerRoles/Properties/AssemblyInfo.cs deleted file mode 100644 index 397d670d98..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.DiscountRules.CustomerRoles")] diff --git a/src/Plugins/DiscountRules.CustomerRoles/RouteProvider.cs b/src/Plugins/DiscountRules.CustomerRoles/RouteProvider.cs deleted file mode 100644 index 67e26ba3fa..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.DiscountRules.CustomerRoles -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.DiscountRules.CustomerRoles.Configure", - "Plugins/DiscountRulesCustomerRoles/Configure", - new { controller = "DiscountRulesCustomerRoles", action = "Configure" }, - new[] { "SmartStore.Plugin.DiscountRules.CustomerRoles.Controllers" } - ) - .DataTokens["area"] = "DiscountRules.CustomerRoles"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/DiscountRules.CustomerRoles/SmartStore.Plugin.DiscountRules.CustomerRoles.csproj b/src/Plugins/DiscountRules.CustomerRoles/SmartStore.Plugin.DiscountRules.CustomerRoles.csproj deleted file mode 100644 index 05201be423..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/SmartStore.Plugin.DiscountRules.CustomerRoles.csproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {D28CAD64-4C88-48CB-8AA4-10B7D050BE56} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.DiscountRules.CustomerRoles - SmartStore.Plugin.DiscountRules.CustomerRoles - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.CustomerRoles\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.CustomerRoles\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Views/DiscountRulesCustomerRoles/Configure.cshtml b/src/Plugins/DiscountRules.CustomerRoles/Views/DiscountRulesCustomerRoles/Configure.cshtml deleted file mode 100644 index c09bf47332..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Views/DiscountRulesCustomerRoles/Configure.cshtml +++ /dev/null @@ -1,49 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.DiscountRules.CustomerRoles.Models.RequirementModel -@using SmartStore.Web.Framework; - - - - - - - - -
    - @Html.SmartLabelFor(model => model.CustomerRoleId) - -
    - @Html.DropDownListFor(model => model.CustomerRoleId, Model.AvailableCustomerRoles) - -
    - -
    \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Views/Web.config b/src/Plugins/DiscountRules.CustomerRoles/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.CustomerRoles/packages.config b/src/Plugins/DiscountRules.CustomerRoles/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/web.config b/src/Plugins/DiscountRules.CustomerRoles/web.config deleted file mode 100644 index 8caecad85c..0000000000 --- a/src/Plugins/DiscountRules.CustomerRoles/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Controllers/DiscountRulesHadSpentAmountController.cs b/src/Plugins/DiscountRules.HadSpentAmount/Controllers/DiscountRulesHadSpentAmountController.cs deleted file mode 100644 index 312b48971b..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Controllers/DiscountRulesHadSpentAmountController.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Linq; -using System.Web.Mvc; -using Newtonsoft.Json; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Plugin.DiscountRules.HadSpentAmount.Models; -using SmartStore.Services.Discounts; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.DiscountRules.HadSpentAmount.Controllers -{ - - public class DiscountRulesHadSpentAmountController : PluginControllerBase - { - private readonly IDiscountService _discountService; - - public DiscountRulesHadSpentAmountController(IDiscountService discountService) - { - this._discountService = discountService; - } - - public ActionResult Configure(int discountId, int? discountRequirementId) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - { - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - if (discountRequirement == null) - return Content("Failed to load requirement."); - } - - // parse settings from ExtraData - string extraData = null; - if (discountRequirement != null) - { - extraData = discountRequirement.ExtraData; - } - var settings = HadSpentAmountDiscountRequirementRule.DeserializeSettings(extraData); - - var model = new RequirementModel(); - model.RequirementId = discountRequirementId.HasValue ? discountRequirementId.Value : 0; - model.DiscountId = discountId; - model.SpentAmount = discountRequirement != null ? discountRequirement.SpentAmount : decimal.Zero; - model.LimitToCurrentBasketSubTotal = settings.LimitToCurrentBasketSubTotal; - model.BasketSubTotalIncludesDiscounts = settings.BasketSubTotalIncludesDiscounts; - - //add a prefix - ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("DiscountRulesHadSpentAmount{0}", discountRequirementId.HasValue ? discountRequirementId.Value.ToString() : "0"); - - return View(model); - } - - [HttpPost] - public ActionResult Configure(int discountId, int? discountRequirementId, decimal spentAmount, string settings) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - - if (discountRequirement != null) - { - //update existing rule - discountRequirement.SpentAmount = spentAmount; - discountRequirement.ExtraData = settings; - - _discountService.UpdateDiscount(discount); - } - else - { - //save new rule - discountRequirement = new DiscountRequirement() - { - DiscountRequirementRuleSystemName = "DiscountRequirement.HadSpentAmount", - ExtraData = settings, - SpentAmount = spentAmount - }; - discount.DiscountRequirements.Add(discountRequirement); - _discountService.UpdateDiscount(discount); - } - return Json(new { Result = true, NewRequirementId = discountRequirement.Id }, JsonRequestBehavior.AllowGet); - } - - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Description.txt b/src/Plugins/DiscountRules.HadSpentAmount/Description.txt deleted file mode 100644 index 137af57841..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Customer had spent x.xx amount -SystemName: DiscountRequirement.HadSpentAmount -Version: 1.13 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.DiscountRules.HadSpentAmount.dll -ResourceRootKey: Plugins.DiscountRules.HadSpentAmount \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/HadSpentAmountDiscountRequirementRule.cs b/src/Plugins/DiscountRules.HadSpentAmount/HadSpentAmountDiscountRequirementRule.cs deleted file mode 100644 index a2e5286fa6..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/HadSpentAmountDiscountRequirementRule.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Linq; -using Newtonsoft.Json; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Plugins; -using SmartStore.Services.Catalog; -using SmartStore.Services.Customers; -using SmartStore.Services.Discounts; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Tax; - -namespace SmartStore.Plugin.DiscountRules.HadSpentAmount -{ - public partial class HadSpentAmountDiscountRequirementRule : BasePlugin, IDiscountRequirementRule - { - private readonly ILocalizationService _localizationService; - private readonly IOrderService _orderService; - private readonly IPriceCalculationService _priceCalculationService; - private readonly ITaxService _taxService; - - public HadSpentAmountDiscountRequirementRule( - ILocalizationService localizationService, - IOrderService orderService, - IPriceCalculationService priceCalculationService, - ITaxService taxService) - { - this._localizationService = localizationService; - this._orderService = orderService; - this._priceCalculationService = priceCalculationService; - this._taxService = taxService; - } - - /// - /// Check discount requirement - /// - /// Object that contains all information required to check the requirement (Current customer, discount, etc) - /// true - requirement is met; otherwise, false - public bool CheckRequirement(CheckDiscountRequirementRequest request) - { - if (request == null) - throw new ArgumentNullException("request"); - - if (request.DiscountRequirement == null) - throw new SmartException("Discount requirement is not set"); - - if (request.DiscountRequirement.SpentAmount == decimal.Zero) - return true; - - if (request.Customer == null) - return false; - - var settings = DeserializeSettings(request.DiscountRequirement.ExtraData); - - if (settings.LimitToCurrentBasketSubTotal) - { - return CheckCurrentSubTotalRequirement(request, settings.BasketSubTotalIncludesDiscounts); - } - else - { - return CheckTotalHistoryRequirement(request); - } - } - - private bool CheckTotalHistoryRequirement(CheckDiscountRequirementRequest request) - { - if (request.Customer.IsGuest()) - return false; - - var orders = _orderService.SearchOrders( - request.Store.Id, - request.Customer.Id, - null, - null, - new int[] { (int)OrderStatus.Complete }, - null, - null, - null, - null, - null, - 0, - int.MaxValue); - - decimal spentAmount = orders.Sum(o => o.OrderTotal); - return spentAmount >= request.DiscountRequirement.SpentAmount; - } - - private bool CheckCurrentSubTotalRequirement(CheckDiscountRequirementRequest request, bool includingDiscount = true) - { - var cartItems = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id); - - decimal spentAmount = decimal.Zero; - decimal taxRate = decimal.Zero; - foreach (var sci in cartItems) - { - // stackoverflow! - //spentAmount += sci.Item.Quantity * _taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, includingDiscount), out taxRate); - spentAmount += sci.Item.Quantity * _taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, false), out taxRate); - } - - return spentAmount >= request.DiscountRequirement.SpentAmount; - } - - /// - /// Get URL for rule configuration - /// - /// Discount identifier - /// Discount requirement identifier (if editing) - /// URL - public string GetConfigurationUrl(int discountId, int? discountRequirementId) - { - //configured in RouteProvider.cs - string result = "Plugins/DiscountRulesHadSpentAmount/Configure/?discountId=" + discountId; - if (discountRequirementId.HasValue) - result += string.Format("&discountRequirementId={0}", discountRequirementId.Value); - return result; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - base.Install(); - } - - public override void Uninstall() - { - // locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.DiscountRequirement.HadSpentAmount", false); - - base.Uninstall(); - } - - internal static RequirementSettings DeserializeSettings(string expression) - { - var settings = new RequirementSettings(); - if (expression.HasValue()) - { - try - { - settings = JsonConvert.DeserializeObject(expression); - } - catch { } - } - - return settings; - } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Localization/resources.de-de.xml b/src/Plugins/DiscountRules.HadSpentAmount/Localization/resources.de-de.xml deleted file mode 100644 index ef1925b184..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Localization/resources.de-de.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - Kunde hat Betrag x ausgegeben - - - Betrag - - - Der Rabatt wird angewendet, wenn der Kunde den angegebenen Betrag ausgegeben hat. - - - - Bezogen auf Warenkorb-Zwischensumme - - - Legt fest, ob sich der angegebene Betrag auf die Zwischensumme im aktuellen Warenkorb oder - wenn inaktiv - auf die Summe aller zuvor vom Kunden getätigten Bestellungen bezieht. - - - Positions-Rabatte berücksichtigen - - - Wenn aktiv, ist der Vergleichswert die Warenkorbsumme abzüglich aller Positions-Rabatte. - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Localization/resources.en-us.xml b/src/Plugins/DiscountRules.HadSpentAmount/Localization/resources.en-us.xml deleted file mode 100644 index a554eb66b8..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Localization/resources.en-us.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - Customer had spent x amount - - - Amount spent - - - Discount will be applied if customer has spent/purchased x.xx amount. - - - - Limit to basket subtotal - - - Specifies whether the amount refers to the current basket subtotal or - when unselected - to the sum of all previously incurred orders. - - - Include discounts - - - When selected the specified amount is compared with the basket subtotal excluding all cart item discounts. - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Models/RequirementModel.cs b/src/Plugins/DiscountRules.HadSpentAmount/Models/RequirementModel.cs deleted file mode 100644 index 9404652a2c..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Models/RequirementModel.cs +++ /dev/null @@ -1,20 +0,0 @@ -using SmartStore.Web.Framework; - -namespace SmartStore.Plugin.DiscountRules.HadSpentAmount.Models -{ - public class RequirementModel - { - [SmartResourceDisplayName("Plugins.DiscountRules.HadSpentAmount.Fields.Amount")] - public decimal SpentAmount { get; set; } - - [SmartResourceDisplayName("Plugins.DiscountRules.HadSpentAmount.Fields.LimitToCurrentBasketSubTotal")] - public bool LimitToCurrentBasketSubTotal { get; set; } - - [SmartResourceDisplayName("Plugins.DiscountRules.HadSpentAmount.Fields.BasketSubTotalIncludesDiscounts")] - public bool BasketSubTotalIncludesDiscounts { get; set; } - - public int DiscountId { get; set; } - - public int RequirementId { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Properties/AssemblyInfo.cs b/src/Plugins/DiscountRules.HadSpentAmount/Properties/AssemblyInfo.cs deleted file mode 100644 index a4d27b988d..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.DiscountRules.HadSpentAmount")] diff --git a/src/Plugins/DiscountRules.HadSpentAmount/RequirementSettings.cs b/src/Plugins/DiscountRules.HadSpentAmount/RequirementSettings.cs deleted file mode 100644 index c9266e0383..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/RequirementSettings.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.DiscountRules.HadSpentAmount -{ - - public class RequirementSettings - { - public RequirementSettings() - { - BasketSubTotalIncludesDiscounts = true; - } - public bool LimitToCurrentBasketSubTotal { get; set; } - public bool BasketSubTotalIncludesDiscounts { get; set; } - } - -} diff --git a/src/Plugins/DiscountRules.HadSpentAmount/RouteProvider.cs b/src/Plugins/DiscountRules.HadSpentAmount/RouteProvider.cs deleted file mode 100644 index 8804f72039..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.DiscountRules.HadSpentAmount -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.DiscountRules.HadSpentAmount.Configure", - "Plugins/DiscountRulesHadSpentAmount/Configure", - new { controller = "DiscountRulesHadSpentAmount", action = "Configure" }, - new[] { "SmartStore.Plugin.DiscountRules.HadSpentAmount.Controllers" } - ) - .DataTokens["area"] = "DiscountRules.HadSpentAmount"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/DiscountRules.HadSpentAmount/SmartStore.Plugin.DiscountRules.HadSpentAmount.csproj b/src/Plugins/DiscountRules.HadSpentAmount/SmartStore.Plugin.DiscountRules.HadSpentAmount.csproj deleted file mode 100644 index 1b8d0a0cd5..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/SmartStore.Plugin.DiscountRules.HadSpentAmount.csproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {C4FFB99C-8A99-47E2-B863-3586AE2CF9C9} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.DiscountRules.HadSpentAmount - SmartStore.Plugin.DiscountRules.HadSpentAmount - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.HadSpentAmount\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.HadSpentAmount\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - False - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Views/DiscountRulesHadSpentAmount/Configure.cshtml b/src/Plugins/DiscountRules.HadSpentAmount/Views/DiscountRulesHadSpentAmount/Configure.cshtml deleted file mode 100644 index d95a60177e..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Views/DiscountRulesHadSpentAmount/Configure.cshtml +++ /dev/null @@ -1,100 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.DiscountRules.HadSpentAmount.Models.RequirementModel -@using SmartStore.Web.Framework; - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.SpentAmount) - - @Html.EditorFor(model => model.SpentAmount) - @Html.ValidationMessageFor(model => model.SpentAmount) -
    - @Html.SmartLabelFor(model => model.LimitToCurrentBasketSubTotal) - - @Html.EditorFor(model => model.LimitToCurrentBasketSubTotal) - @Html.ValidationMessageFor(model => model.LimitToCurrentBasketSubTotal) -
    - @Html.SmartLabelFor(model => model.BasketSubTotalIncludesDiscounts) - - @Html.EditorFor(model => model.BasketSubTotalIncludesDiscounts) - @Html.ValidationMessageFor(model => model.BasketSubTotalIncludesDiscounts) -
      - -
    \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Views/Web.config b/src/Plugins/DiscountRules.HadSpentAmount/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.HadSpentAmount/packages.config b/src/Plugins/DiscountRules.HadSpentAmount/packages.config deleted file mode 100644 index 6a24b4891d..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/web.config b/src/Plugins/DiscountRules.HadSpentAmount/web.config deleted file mode 100644 index 8caecad85c..0000000000 --- a/src/Plugins/DiscountRules.HadSpentAmount/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.HasAllProducts/Controllers/DiscountRulesHasAllProductsController.cs b/src/Plugins/DiscountRules.HasAllProducts/Controllers/DiscountRulesHasAllProductsController.cs deleted file mode 100644 index a93c7b9411..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Controllers/DiscountRulesHasAllProductsController.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Linq; -using System.Web.Mvc; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Plugin.DiscountRules.HasAllProducts.Models; -using SmartStore.Services.Customers; -using SmartStore.Services.Discounts; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.DiscountRules.HasAllProducts.Controllers -{ - - public class DiscountRulesHasAllProductsController : PluginControllerBase - { - private readonly IDiscountService _discountService; - - public DiscountRulesHasAllProductsController(IDiscountService discountService, - ICustomerService customerService) - { - this._discountService = discountService; - } - - public ActionResult Configure(int discountId, int? discountRequirementId) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - { - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - if (discountRequirement == null) - return Content("Failed to load requirement."); - } - - var model = new RequirementModel(); - model.RequirementId = discountRequirementId.HasValue ? discountRequirementId.Value : 0; - model.DiscountId = discountId; - model.Products = discountRequirement != null ? discountRequirement.RestrictedProductIds : ""; - - //add a prefix - ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("DiscountRulesHasAllProducts{0}", discountRequirementId.HasValue ? discountRequirementId.Value.ToString() : "0"); - - return View(model); - } - - [HttpPost] - public ActionResult Configure(int discountId, int? discountRequirementId, string productIds) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - - if (discountRequirement != null) - { - //update existing rule - discountRequirement.RestrictedProductIds = productIds; - _discountService.UpdateDiscount(discount); - } - else - { - //save new rule - discountRequirement = new DiscountRequirement() - { - DiscountRequirementRuleSystemName = "DiscountRequirement.HasAllProducts", - RestrictedProductIds = productIds, - }; - discount.DiscountRequirements.Add(discountRequirement); - _discountService.UpdateDiscount(discount); - } - return Json(new { Result = true, NewRequirementId = discountRequirement.Id }, JsonRequestBehavior.AllowGet); - } - - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Description.txt b/src/Plugins/DiscountRules.HasAllProducts/Description.txt deleted file mode 100644 index 87e578e9e0..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Customer has all of these products in the cart -SystemName: DiscountRequirement.HasAllProducts -Version: 1.3 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.DiscountRules.HasAllProducts.dll -ResourceRootKey: Plugins.DiscountRules.HasAllProducts \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/HasAllProductsDiscountRequirementRule.cs b/src/Plugins/DiscountRules.HasAllProducts/HasAllProductsDiscountRequirementRule.cs deleted file mode 100644 index 5396c6d8f4..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/HasAllProductsDiscountRequirementRule.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Linq; -using SmartStore.Core; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Plugins; -using SmartStore.Services.Discounts; -using SmartStore.Services.Localization; -using SmartStore.Services.Customers; - -namespace SmartStore.Plugin.DiscountRules.HasAllProducts -{ - public partial class HasAllProductsDiscountRequirementRule : BasePlugin, IDiscountRequirementRule - { - private readonly ILocalizationService _localizationService; - - public HasAllProductsDiscountRequirementRule(ILocalizationService localizationService) - { - _localizationService = localizationService; - } - - /// - /// Check discount requirement - /// - /// Object that contains all information required to check the requirement (Current customer, discount, etc) - /// true - requirement is met; otherwise, false - public bool CheckRequirement(CheckDiscountRequirementRequest request) - { - if (request == null) - throw new ArgumentNullException("request"); - - if (request.DiscountRequirement == null) - throw new SmartException("Discount requirement is not set"); - - if (String.IsNullOrWhiteSpace(request.DiscountRequirement.RestrictedProductIds)) - return true; - - if (request.Customer == null) - return false; - - //we support three ways of specifying products: - //1. The comma-separated list of product identifiers (e.g. 77, 123, 156). - //2. The comma-separated list of product identifiers with quantities. - // {Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 - //3. The comma-separated list of product identifiers with quantity range. - // {Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 - var restrictedProducts = request.DiscountRequirement.RestrictedProductIds - .Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.Trim()) - .ToList(); - if (restrictedProducts.Count == 0) - return false; - - //cart - var cart = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id); - - bool allFound = true; - foreach (var restrictedProduct in restrictedProducts) - { - if (String.IsNullOrWhiteSpace(restrictedProduct)) - continue; - - bool found1 = false; - foreach (var sci in cart) - { - if (restrictedProduct.Contains(":")) - { - if (restrictedProduct.Contains("-")) - { - //the third way (the quantity rage specified) - //{Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 - int restrictedProductId = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) - //parsing error; exit; - return false; - int quantityMin = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[0], out quantityMin)) - //parsing error; exit; - return false; - int quantityMax = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[1], out quantityMax)) - //parsing error; exit; - return false; - - if (sci.Item.ProductId == restrictedProductId && quantityMin <= sci.Item.Quantity && sci.Item.Quantity <= quantityMax) - { - found1 = true; - break; - } - } - else - { - //the second way (the quantity specified) - //{Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 - int restrictedProductId = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) - //parsing error; exit; - return false; - int quantity = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1], out quantity)) - //parsing error; exit; - return false; - - if (sci.Item.ProductId == restrictedProductId && sci.Item.Quantity == quantity) - { - found1 = true; - break; - } - } - } - else - { - //the first way (the quantity is not specified) - int restrictedProductId = int.Parse(restrictedProduct); - if (sci.Item.ProductId == restrictedProductId) - { - found1 = true; - break; - } - } - } - - if (!found1) - { - allFound = false; - break; - } - } - - if (allFound) - return true; - - return false; - } - - /// - /// Get URL for rule configuration - /// - /// Discount identifier - /// Discount requirement identifier (if editing) - /// URL - public string GetConfigurationUrl(int discountId, int? discountRequirementId) - { - //configured in RouteProvider.cs - string result = "Plugins/DiscountRulesHasAllProducts/Configure/?discountId=" + discountId; - if (discountRequirementId.HasValue) - result += string.Format("&discountRequirementId={0}", discountRequirementId.Value); - return result; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - base.Install(); - } - - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.DiscountRequirement.HasAllProducts", false); - base.Uninstall(); - } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Localization/resources.de-de.xml b/src/Plugins/DiscountRules.HasAllProducts/Localization/resources.de-de.xml deleted file mode 100644 index f35cc08f04..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Localization/resources.de-de.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Der Kunde hat folgende Produkte in seinem Warenkorb - - - Produkte - - - Kommagetrennte Liste von Produkt-IDs (z.B. 77, 123, 156). Die ID eines Produkts findet sich in seiner Detailansicht. Man kann die Liste außerdem um Mengenangaben ({Produkt-ID}:{Menge} z.B.: 77:1, 123:2, 156:3) oder um einen Mengenbereich ergänzen ({Produkt-ID}:{Minimale Menge}-{Maximale Menge} z.B.: 77:1-3, 123:2-5, 156:3-8). - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Localization/resources.en-us.xml b/src/Plugins/DiscountRules.HasAllProducts/Localization/resources.en-us.xml deleted file mode 100644 index 9d357c6a7f..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Localization/resources.en-us.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Customer has all of these products in the cart - - - Restricted products - - - The comma-separated list of product identifiers (e.g. 77, 123, 156). You can find a product ID on its details page. You can also specify the comma-separated list of product identifiers with quantities ({Product ID}:{Quantity}. for example, 77:1, 123:2, 156:3). And you can also specify the comma-separated list of product identifiers with quantity range ({Product ID}:{Min quantity}-{Max quantity}. for example, 77:1-3, 123:2-5, 156:3-8). - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Models/RequirementModel.cs b/src/Plugins/DiscountRules.HasAllProducts/Models/RequirementModel.cs deleted file mode 100644 index 62f4eae608..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Models/RequirementModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using SmartStore.Web.Framework; - -namespace SmartStore.Plugin.DiscountRules.HasAllProducts.Models -{ - public class RequirementModel - { - [SmartResourceDisplayName("Plugins.DiscountRules.HasAllProducts.Fields.Products")] - public string Products { get; set; } - - public int DiscountId { get; set; } - - public int RequirementId { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Notes.txt b/src/Plugins/DiscountRules.HasAllProducts/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Properties/AssemblyInfo.cs b/src/Plugins/DiscountRules.HasAllProducts/Properties/AssemblyInfo.cs deleted file mode 100644 index 5dd1b20aef..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.DiscountRules.HasAllProducts")] diff --git a/src/Plugins/DiscountRules.HasAllProducts/RouteProvider.cs b/src/Plugins/DiscountRules.HasAllProducts/RouteProvider.cs deleted file mode 100644 index dd1594ac95..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.DiscountRules.HasAllProducts -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.DiscountRules.HasAllProducts.Configure", - "Plugins/DiscountRulesHasAllProducts/Configure", - new { controller = "DiscountRulesHasAllProducts", action = "Configure" }, - new[] { "SmartStore.Plugin.DiscountRules.HasAllProducts.Controllers" } - ) - .DataTokens["area"] = "DiscountRules.HasAllProducts"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/DiscountRules.HasAllProducts/SmartStore.Plugin.DiscountRules.HasAllProducts.csproj b/src/Plugins/DiscountRules.HasAllProducts/SmartStore.Plugin.DiscountRules.HasAllProducts.csproj deleted file mode 100644 index 5f1efa867e..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/SmartStore.Plugin.DiscountRules.HasAllProducts.csproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {36261AB6-2FD4-4BDA-A941-AF4CC18C21E5} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.DiscountRules.HasAllProducts - SmartStore.Plugin.DiscountRules.HasAllProducts - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.HasAllProducts\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.HasAllProducts\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Views/DiscountRulesHasAllProducts/Configure.cshtml b/src/Plugins/DiscountRules.HasAllProducts/Views/DiscountRulesHasAllProducts/Configure.cshtml deleted file mode 100644 index 16de285d2a..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Views/DiscountRulesHasAllProducts/Configure.cshtml +++ /dev/null @@ -1,49 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.DiscountRules.HasAllProducts.Models.RequirementModel -@using SmartStore.Web.Framework; - - - - - - - - -
    - @Html.SmartLabelFor(model => model.Products) - -
    - @Html.EditorFor(model => model.Products) - -
    - -
    \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/Views/Web.config b/src/Plugins/DiscountRules.HasAllProducts/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.HasAllProducts/packages.config b/src/Plugins/DiscountRules.HasAllProducts/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasAllProducts/web.config b/src/Plugins/DiscountRules.HasAllProducts/web.config deleted file mode 100644 index 8caecad85c..0000000000 --- a/src/Plugins/DiscountRules.HasAllProducts/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.HasOneProduct/Controllers/DiscountRulesHasOneProductController.cs b/src/Plugins/DiscountRules.HasOneProduct/Controllers/DiscountRulesHasOneProductController.cs deleted file mode 100644 index 43e38568e1..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Controllers/DiscountRulesHasOneProductController.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Linq; -using System.Web.Mvc; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Plugin.DiscountRules.HasOneProduct.Models; -using SmartStore.Services.Customers; -using SmartStore.Services.Discounts; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.DiscountRules.HasOneProduct.Controllers -{ - - public class DiscountRulesHasOneProductController : PluginControllerBase - { - private readonly IDiscountService _discountService; - - public DiscountRulesHasOneProductController(IDiscountService discountService, - ICustomerService customerService) - { - this._discountService = discountService; - } - - public ActionResult Configure(int discountId, int? discountRequirementId) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - { - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - if (discountRequirement == null) - return Content("Failed to load requirement."); - } - - var model = new RequirementModel(); - model.RequirementId = discountRequirementId.HasValue ? discountRequirementId.Value : 0; - model.DiscountId = discountId; - model.Products = discountRequirement != null ? discountRequirement.RestrictedProductIds : ""; - - //add a prefix - ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("DiscountRulesHasOneProduct{0}", discountRequirementId.HasValue ? discountRequirementId.Value.ToString() : "0"); - - return View(model); - } - - [HttpPost] - public ActionResult Configure(int discountId, int? discountRequirementId, string productIds) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - - if (discountRequirement != null) - { - //update existing rule - discountRequirement.RestrictedProductIds = productIds; - _discountService.UpdateDiscount(discount); - } - else - { - //save new rule - discountRequirement = new DiscountRequirement() - { - DiscountRequirementRuleSystemName = "DiscountRequirement.HasOneProduct", - RestrictedProductIds = productIds, - }; - discount.DiscountRequirements.Add(discountRequirement); - _discountService.UpdateDiscount(discount); - } - return Json(new { Result = true, NewRequirementId = discountRequirement.Id }, JsonRequestBehavior.AllowGet); - } - - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Description.txt b/src/Plugins/DiscountRules.HasOneProduct/Description.txt deleted file mode 100644 index 48aa227741..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Customer has one of these products in the cart -SystemName: DiscountRequirement.HasOneProduct -Version: 1.3 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.DiscountRules.HasOneProduct.dll -ResourceRootKey: Plugins.DiscountRules.HasOneProduct \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/HasOneProductDiscountRequirementRule.cs b/src/Plugins/DiscountRules.HasOneProduct/HasOneProductDiscountRequirementRule.cs deleted file mode 100644 index 463ecd012b..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/HasOneProductDiscountRequirementRule.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Linq; -using SmartStore.Core; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Plugins; -using SmartStore.Services.Discounts; -using SmartStore.Services.Localization; -using SmartStore.Services.Customers; - -namespace SmartStore.Plugin.DiscountRules.HasOneProduct -{ - public partial class HasOneProductDiscountRequirementRule : BasePlugin, IDiscountRequirementRule - { - private readonly ILocalizationService _localizationService; - - public HasOneProductDiscountRequirementRule(ILocalizationService localizationService) - { - _localizationService = localizationService; - } - - /// - /// Check discount requirement - /// - /// Object that contains all information required to check the requirement (Current customer, discount, etc) - /// true - requirement is met; otherwise, false - public bool CheckRequirement(CheckDiscountRequirementRequest request) - { - if (request == null) - throw new ArgumentNullException("request"); - - if (request.DiscountRequirement == null) - throw new SmartException("Discount requirement is not set"); - - if (String.IsNullOrWhiteSpace(request.DiscountRequirement.RestrictedProductIds)) - return true; - - if (request.Customer == null) - return false; - - //we support three ways of specifying products: - //1. The comma-separated list of product identifiers (e.g. 77, 123, 156). - //2. The comma-separated list of product identifiers with quantities. - // {Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 - //3. The comma-separated list of product identifiers with quantity range. - // {Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 - var restrictedProducts = request.DiscountRequirement.RestrictedProductIds - .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.Trim()) - .ToList(); - if (restrictedProducts.Count == 0) - return false; - - //cart - var cart = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id); - - bool found = false; - foreach (var restrictedProduct in restrictedProducts) - { - if (String.IsNullOrWhiteSpace(restrictedProduct)) - continue; - - foreach (var sci in cart) - { - if (restrictedProduct.Contains(":")) - { - if (restrictedProduct.Contains("-")) - { - //the third way (the quantity rage specified) - //{Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 - int restrictedProductId = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) - //parsing error; exit; - return false; - int quantityMin = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[0], out quantityMin)) - //parsing error; exit; - return false; - int quantityMax = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[1], out quantityMax)) - //parsing error; exit; - return false; - - if (sci.Item.ProductId == restrictedProductId && quantityMin <= sci.Item.Quantity && sci.Item.Quantity <= quantityMax) - { - found = true; - break; - } - } - else - { - //the second way (the quantity specified) - //{Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 - int restrictedProductId = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) - //parsing error; exit; - return false; - int quantity = 0; - if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1], out quantity)) - //parsing error; exit; - return false; - - if (sci.Item.ProductId == restrictedProductId && sci.Item.Quantity == quantity) - { - found = true; - break; - } - } - } - else - { - //the first way (the quantity is not specified) - int restrictedProductId = int.Parse(restrictedProduct); - if (sci.Item.ProductId == restrictedProductId) - { - found = true; - break; - } - } - } - - if (found) - { - break; - } - } - - if (found) - return true; - - return false; - } - - /// - /// Get URL for rule configuration - /// - /// Discount identifier - /// Discount requirement identifier (if editing) - /// URL - public string GetConfigurationUrl(int discountId, int? discountRequirementId) - { - //configured in RouteProvider.cs - string result = "Plugins/DiscountRulesHasOneProduct/Configure/?discountId=" + discountId; - if (discountRequirementId.HasValue) - result += string.Format("&discountRequirementId={0}", discountRequirementId.Value); - return result; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - base.Install(); - } - - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.DiscountRequirement.HasOneProduct", false); - base.Uninstall(); - } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Localization/resources.de-de.xml b/src/Plugins/DiscountRules.HasOneProduct/Localization/resources.de-de.xml deleted file mode 100644 index 6eb6e307a4..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Localization/resources.de-de.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Der Kunde hat einen der folgenden Produkte in seinem Warenkorb - - - Produkte - - - Kommagetrennte Liste von Produkt-IDs (z.B. 77, 123, 156). Die ID eines Produkts findet sich in seiner Detailansicht. Man kann die Liste außerdem um Mengenangaben ({Produkt-ID}:{Menge} z.B.: 77:1, 123:2, 156:3) oder um einen Mengenbereich ergänzen ({Produkt-ID}:{Minimale Menge}-{Maximale Menge} z.B.: 77:1-3, 123:2-5, 156:3-8). - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Localization/resources.en-us.xml b/src/Plugins/DiscountRules.HasOneProduct/Localization/resources.en-us.xml deleted file mode 100644 index 8721a5c3ef..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Localization/resources.en-us.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Customer has one of these products in the cart - - - Restricted products - - - The comma-separated list of product identifiers (e.g. 77, 123, 156). You can find a product ID on its details page. You can also specify the comma-separated list of product identifiers with quantities ({Product ID}:{Quantity}. for example, 77:1, 123:2, 156:3). And you can also specify the comma-separated list of product identifiers with quantity range ({Product ID}:{Min quantity}-{Max quantity}. for example, 77:1-3, 123:2-5, 156:3-8). - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Models/RequirementModel.cs b/src/Plugins/DiscountRules.HasOneProduct/Models/RequirementModel.cs deleted file mode 100644 index 2522adea6d..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Models/RequirementModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using SmartStore.Web.Framework; - -namespace SmartStore.Plugin.DiscountRules.HasOneProduct.Models -{ - public class RequirementModel - { - [SmartResourceDisplayName("Plugins.DiscountRules.HasOneProduct.Fields.Products")] - public string Products { get; set; } - - public int DiscountId { get; set; } - - public int RequirementId { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Notes.txt b/src/Plugins/DiscountRules.HasOneProduct/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Properties/AssemblyInfo.cs b/src/Plugins/DiscountRules.HasOneProduct/Properties/AssemblyInfo.cs deleted file mode 100644 index 1e72711102..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.DiscountRules.HasOneProduct")] diff --git a/src/Plugins/DiscountRules.HasOneProduct/RouteProvider.cs b/src/Plugins/DiscountRules.HasOneProduct/RouteProvider.cs deleted file mode 100644 index 9aa9e535d3..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.DiscountRules.HasOneProduct -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.DiscountRules.HasOneProduct.Configure", - "Plugins/DiscountRulesHasOneProduct/Configure", - new { controller = "DiscountRulesHasOneProduct", action = "Configure" }, - new[] { "SmartStore.Plugin.DiscountRules.HasOneProduct.Controllers" } - ) - .DataTokens["area"] = "DiscountRules.HasOneProduct"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/DiscountRules.HasOneProduct/SmartStore.Plugin.DiscountRules.HasOneProduct.csproj b/src/Plugins/DiscountRules.HasOneProduct/SmartStore.Plugin.DiscountRules.HasOneProduct.csproj deleted file mode 100644 index 90c4db4aca..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/SmartStore.Plugin.DiscountRules.HasOneProduct.csproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {5B956174-04FA-4E95-AA00-3736630FEEFB} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.DiscountRules.HasOneProduct - SmartStore.Plugin.DiscountRules.HasOneProduct - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.HasOneProduct\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.HasOneProduct\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Views/DiscountRulesHasOneProduct/Configure.cshtml b/src/Plugins/DiscountRules.HasOneProduct/Views/DiscountRulesHasOneProduct/Configure.cshtml deleted file mode 100644 index cc9d2acde5..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Views/DiscountRulesHasOneProduct/Configure.cshtml +++ /dev/null @@ -1,49 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.DiscountRules.HasOneProduct.Models.RequirementModel -@using SmartStore.Web.Framework; - - - - - - - - -
    - @Html.SmartLabelFor(model => model.Products) - -
    - @Html.EditorFor(model => model.Products) - -
    - -
    \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/Views/Web.config b/src/Plugins/DiscountRules.HasOneProduct/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.HasOneProduct/packages.config b/src/Plugins/DiscountRules.HasOneProduct/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HasOneProduct/web.config b/src/Plugins/DiscountRules.HasOneProduct/web.config deleted file mode 100644 index 8caecad85c..0000000000 --- a/src/Plugins/DiscountRules.HasOneProduct/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.Store/Controllers/DiscountRulesStoreController.cs b/src/Plugins/DiscountRules.Store/Controllers/DiscountRulesStoreController.cs deleted file mode 100644 index cc034658a6..0000000000 --- a/src/Plugins/DiscountRules.Store/Controllers/DiscountRulesStoreController.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Linq; -using System.Web.Mvc; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Plugin.DiscountRules.Store.Models; -using SmartStore.Services.Discounts; -using SmartStore.Services.Localization; -using SmartStore.Services.Stores; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.DiscountRules.Store.Controllers -{ - public class DiscountRulesStoreController : PluginControllerBase - { - private readonly ILocalizationService _localizationService; - private readonly IDiscountService _discountService; - private readonly IStoreService _storeService; - - public DiscountRulesStoreController(ILocalizationService localizationService, - IDiscountService discountService, IStoreService storeService) - { - this._localizationService = localizationService; - this._discountService = discountService; - this._storeService = storeService; - } - - public ActionResult Configure(int discountId, int? discountRequirementId) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - { - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - if (discountRequirement == null) - return Content("Failed to load requirement."); - } - - var model = new RequirementModel(); - model.RequirementId = discountRequirementId.HasValue ? discountRequirementId.Value : 0; - model.DiscountId = discountId; - - if (discountRequirement != null) - model.StoreId = discountRequirement.RestrictedToStoreId ?? 0; - - //stores - model.AvailableStores.Add(new SelectListItem() { Text = _localizationService.GetResource("Plugins.DiscountRules.Store.Fields.SelectStore"), Value = "0" }); - foreach (var s in _storeService.GetAllStores()) - model.AvailableStores.Add(new SelectListItem() { Text = s.Name, Value = s.Id.ToString(), Selected = discountRequirement != null && s.Id == model.StoreId }); - - //add a prefix - ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("DiscountRulesStore{0}", discountRequirementId.HasValue ? discountRequirementId.Value.ToString() : "0"); - - return View(model); - } - - [HttpPost] - public ActionResult Configure(int discountId, int? discountRequirementId, int storeId) - { - var discount = _discountService.GetDiscountById(discountId); - if (discount == null) - throw new ArgumentException("Discount could not be loaded"); - - DiscountRequirement discountRequirement = null; - if (discountRequirementId.HasValue) - discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); - - if (discountRequirement != null) - { - discountRequirement.RestrictedToStoreId = storeId; - _discountService.UpdateDiscount(discount); - } - else - { - //save new rule - discountRequirement = new DiscountRequirement() - { - DiscountRequirementRuleSystemName = "DiscountRequirement.Store", - RestrictedToStoreId = storeId - }; - discount.DiscountRequirements.Add(discountRequirement); - _discountService.UpdateDiscount(discount); - } - return Json(new { Result = true, NewRequirementId = discountRequirement.Id }, JsonRequestBehavior.AllowGet); - } - - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Description.txt b/src/Plugins/DiscountRules.Store/Description.txt deleted file mode 100644 index 7a160543b2..0000000000 --- a/src/Plugins/DiscountRules.Store/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Restricted to store -SystemName: DiscountRequirement.Store -Version: 1.2 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.DiscountRules.Store.dll -ResourceRootKey: Plugins.DiscountRules.Store \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Localization/resources.de-de.xml b/src/Plugins/DiscountRules.Store/Localization/resources.de-de.xml deleted file mode 100644 index 4408b4f014..0000000000 --- a/src/Plugins/DiscountRules.Store/Localization/resources.de-de.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - Auf bestimmten Shop begrenzt - - - Shop auswählen - - - Shop - - - Wählen Sie den Shop für diesen Rabatt. - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Localization/resources.en-us.xml b/src/Plugins/DiscountRules.Store/Localization/resources.en-us.xml deleted file mode 100644 index c438bbcb78..0000000000 --- a/src/Plugins/DiscountRules.Store/Localization/resources.en-us.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - Restricted to store - - - Select store - - - Store - - - Select the store in which this discount will be valid. - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Models/RequirementModel.cs b/src/Plugins/DiscountRules.Store/Models/RequirementModel.cs deleted file mode 100644 index 08be2fa657..0000000000 --- a/src/Plugins/DiscountRules.Store/Models/RequirementModel.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; - -namespace SmartStore.Plugin.DiscountRules.Store.Models -{ - public class RequirementModel - { - public RequirementModel() - { - AvailableStores = new List(); - } - - [SmartResourceDisplayName("Plugins.DiscountRules.Store.Fields.Store")] - public int StoreId { get; set; } - - public int DiscountId { get; set; } - - public int RequirementId { get; set; } - - public IList AvailableStores { get; set; } - } - -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Notes.txt b/src/Plugins/DiscountRules.Store/Notes.txt deleted file mode 100644 index aa687d831a..0000000000 --- a/src/Plugins/DiscountRules.Store/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\Nop.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Properties/AssemblyInfo.cs b/src/Plugins/DiscountRules.Store/Properties/AssemblyInfo.cs deleted file mode 100644 index 0010147251..0000000000 --- a/src/Plugins/DiscountRules.Store/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.DiscountRules.Store")] diff --git a/src/Plugins/DiscountRules.Store/RouteProvider.cs b/src/Plugins/DiscountRules.Store/RouteProvider.cs deleted file mode 100644 index 33249da090..0000000000 --- a/src/Plugins/DiscountRules.Store/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.DiscountRules.Store -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.DiscountRules.Store.Configure", - "Plugins/DiscountRulesStore/Configure", - new { controller = "DiscountRulesStore", action = "Configure" }, - new[] { "SmartStore.Plugin.DiscountRules.Store.Controllers" } - ) - .DataTokens["area"] = "DiscountRules.Store"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/DiscountRules.Store/SmartStore.Plugin.DiscountRules.Store.csproj b/src/Plugins/DiscountRules.Store/SmartStore.Plugin.DiscountRules.Store.csproj deleted file mode 100644 index 67b8339860..0000000000 --- a/src/Plugins/DiscountRules.Store/SmartStore.Plugin.DiscountRules.Store.csproj +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {36261AB6-2FD4-4BDA-A941-AF4CC18C21E6} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.DiscountRules.Store - SmartStore.Plugin.DiscountRules.Store - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.Store\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\DiscountRules.Store\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/StoreDiscountRequirementRule.cs b/src/Plugins/DiscountRules.Store/StoreDiscountRequirementRule.cs deleted file mode 100644 index 5b09a28f5b..0000000000 --- a/src/Plugins/DiscountRules.Store/StoreDiscountRequirementRule.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using SmartStore.Core.Plugins; -using SmartStore.Services.Discounts; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.DiscountRules.Store -{ - public partial class StoreDiscountRequirementRule : BasePlugin, IDiscountRequirementRule - { - private readonly ILocalizationService _localizationService; - - public StoreDiscountRequirementRule(ILocalizationService localizationService) - { - this._localizationService = localizationService; - } - - /// - /// Check discount requirement - /// - /// Object that contains all information required to check the requirement (Current customer, discount, etc) - /// true - requirement is met; otherwise, false - public bool CheckRequirement(CheckDiscountRequirementRequest request) - { - if (request == null) - throw new ArgumentNullException("request"); - - if (request.DiscountRequirement == null) - throw new SmartException("Discount requirement is not set"); - - if (request.Customer == null) - return false; - - var storeId = request.DiscountRequirement.RestrictedToStoreId ?? 0; - - if (storeId == 0) - return false; - - bool result = request.Store.Id == storeId; - return result; - } - - /// - /// Get URL for rule configuration - /// - /// Discount identifier - /// Discount requirement identifier (if editing) - /// URL - public string GetConfigurationUrl(int discountId, int? discountRequirementId) - { - //configured in RouteProvider.cs - string result = "Plugins/DiscountRulesStore/Configure/?discountId=" + discountId; - if (discountRequirementId.HasValue) - result += string.Format("&discountRequirementId={0}", discountRequirementId.Value); - return result; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - base.Install(); - } - - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.DiscountRequirement.Store", false); - base.Uninstall(); - } - } -} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Views/DiscountRulesStore/Configure.cshtml b/src/Plugins/DiscountRules.Store/Views/DiscountRulesStore/Configure.cshtml deleted file mode 100644 index bb8a14fafc..0000000000 --- a/src/Plugins/DiscountRules.Store/Views/DiscountRulesStore/Configure.cshtml +++ /dev/null @@ -1,49 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.DiscountRules.Store.Models.RequirementModel -@using SmartStore.Web.Framework; - - - - - - - - -
    - @Html.SmartLabelFor(model => model.StoreId) - -
    - @Html.DropDownListFor(model => model.StoreId, Model.AvailableStores) - -
    - -
    \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/Views/Web.config b/src/Plugins/DiscountRules.Store/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/DiscountRules.Store/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/DiscountRules.Store/packages.config b/src/Plugins/DiscountRules.Store/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/DiscountRules.Store/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/DiscountRules.Store/web.config b/src/Plugins/DiscountRules.Store/web.config deleted file mode 100644 index 8caecad85c..0000000000 --- a/src/Plugins/DiscountRules.Store/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/ExchangeRate.EcbExchange/Description.txt b/src/Plugins/ExchangeRate.EcbExchange/Description.txt deleted file mode 100644 index 50dd568350..0000000000 --- a/src/Plugins/ExchangeRate.EcbExchange/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: ECB exchange rate provider -SystemName: CurrencyExchange.ECB -Version: 1.2 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.ExchangeRate.EcbExchange.dll -ResourceRootKey: Plugins.ExchangeRate.EcbExchange \ No newline at end of file diff --git a/src/Plugins/ExchangeRate.EcbExchange/EcbExchangeRateProvider.cs b/src/Plugins/ExchangeRate.EcbExchange/EcbExchangeRateProvider.cs deleted file mode 100644 index 429b08fbf2..0000000000 --- a/src/Plugins/ExchangeRate.EcbExchange/EcbExchangeRateProvider.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Net; -using System.Xml; -using SmartStore.Core; -using SmartStore.Core.Plugins; -using SmartStore.Core.Domain.Localization; -using SmartStore.Services.Directory; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.ExchangeRate.EcbExchange -{ - public class EcbExchangeRateProvider : BasePlugin, IExchangeRateProvider - { - private readonly ILocalizationService _localizationService; - - public EcbExchangeRateProvider(ILocalizationService localizationService) - { - this._localizationService = localizationService; - } - - /// - /// Gets currency live rates - /// - /// Exchange rate currency code - /// Exchange rates - public IList GetCurrencyLiveRates(string exchangeRateCurrencyCode) - { - if (String.IsNullOrEmpty(exchangeRateCurrencyCode) || - exchangeRateCurrencyCode.ToLower() != "eur") - throw new SmartException(_localizationService.GetResource("Plugins.ExchangeRate.EcbExchange.SetCurrencyToEURO")); - - var exchangeRates = new List(); - - var request = WebRequest.Create("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml") as HttpWebRequest; - using (WebResponse response = request.GetResponse()) - { - var document = new XmlDocument(); - document.Load(response.GetResponseStream()); - var nsmgr = new XmlNamespaceManager(document.NameTable); - nsmgr.AddNamespace("ns", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref"); - nsmgr.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01"); - - var node = document.SelectSingleNode("gesmes:Envelope/ns:Cube/ns:Cube", nsmgr); - var updateDate = DateTime.ParseExact(node.Attributes["time"].Value, "yyyy-MM-dd", null); - - var provider = new NumberFormatInfo(); - provider.NumberDecimalSeparator = "."; - provider.NumberGroupSeparator = ""; - foreach (XmlNode node2 in node.ChildNodes) - { - exchangeRates.Add(new Core.Domain.Directory.ExchangeRate() - { - CurrencyCode = node2.Attributes["currency"].Value, - Rate = decimal.Parse(node2.Attributes["rate"].Value, provider), - UpdatedOn = updateDate - } - ); - } - } - return exchangeRates; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - base.Install(); - } - - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.CurrencyExchange.ECB", false); - base.Uninstall(); - } - } -} diff --git a/src/Plugins/ExchangeRate.EcbExchange/Localization/resources.de-de.xml b/src/Plugins/ExchangeRate.EcbExchange/Localization/resources.de-de.xml deleted file mode 100644 index 25dea1faf3..0000000000 --- a/src/Plugins/ExchangeRate.EcbExchange/Localization/resources.de-de.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - EZB-Wechselkursdienst - - - Der EZB-Wechselkursdienst kann nur genutzt werden, wenn der Wechselkurs-Währungscode auf EUR gesetzt ist. - - \ No newline at end of file diff --git a/src/Plugins/ExchangeRate.EcbExchange/Localization/resources.en-us.xml b/src/Plugins/ExchangeRate.EcbExchange/Localization/resources.en-us.xml deleted file mode 100644 index 842fbcf35c..0000000000 --- a/src/Plugins/ExchangeRate.EcbExchange/Localization/resources.en-us.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - ECB exchange rate provider - - - You can use ECB (European central bank) exchange rate provider only when exchange rate currency code is set to EURO - - \ No newline at end of file diff --git a/src/Plugins/ExchangeRate.EcbExchange/Notes.txt b/src/Plugins/ExchangeRate.EcbExchange/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/ExchangeRate.EcbExchange/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/ExchangeRate.EcbExchange/Properties/AssemblyInfo.cs b/src/Plugins/ExchangeRate.EcbExchange/Properties/AssemblyInfo.cs deleted file mode 100644 index ead572f89d..0000000000 --- a/src/Plugins/ExchangeRate.EcbExchange/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.ExchangeRate.EcbExchange")] diff --git a/src/Plugins/ExchangeRate.EcbExchange/SmartStore.Plugin.ExchangeRate.EcbExchange.csproj b/src/Plugins/ExchangeRate.EcbExchange/SmartStore.Plugin.ExchangeRate.EcbExchange.csproj deleted file mode 100644 index 745ce0a6d1..0000000000 --- a/src/Plugins/ExchangeRate.EcbExchange/SmartStore.Plugin.ExchangeRate.EcbExchange.csproj +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {6DF00C56-EC49-4AB8-8B29-404E3694026C} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.ExchangeRate.EcbExchange - SmartStore.Plugin.ExchangeRate.EcbExchange - v4.5 - 512 - - - - - - - - - - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\CurrencyExchange.ECB\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\CurrencyExchange.ECB\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/ExchangeRate.EcbExchange/icon.png b/src/Plugins/ExchangeRate.EcbExchange/icon.png deleted file mode 100644 index bf81be6945..0000000000 Binary files a/src/Plugins/ExchangeRate.EcbExchange/icon.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.Facebook/Content/Images/oauth/facebook-logo-large.jpg b/src/Plugins/ExternalAuth.Facebook/Content/Images/oauth/facebook-logo-large.jpg deleted file mode 100644 index b56acf4743..0000000000 Binary files a/src/Plugins/ExternalAuth.Facebook/Content/Images/oauth/facebook-logo-large.jpg and /dev/null differ diff --git a/src/Plugins/ExternalAuth.Facebook/Content/Images/oauth/facebook-logo.jpg b/src/Plugins/ExternalAuth.Facebook/Content/Images/oauth/facebook-logo.jpg deleted file mode 100644 index 39f10e2475..0000000000 Binary files a/src/Plugins/ExternalAuth.Facebook/Content/Images/oauth/facebook-logo.jpg and /dev/null differ diff --git a/src/Plugins/ExternalAuth.Facebook/Content/facebookstyles.css b/src/Plugins/ExternalAuth.Facebook/Content/facebookstyles.css deleted file mode 100644 index 9b9724bba6..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Content/facebookstyles.css +++ /dev/null @@ -1,49 +0,0 @@ -.foo{} -/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~* - - FACEBOOK - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.oauth-login-facebook -{ - display: inline; - float: left; - margin-right: 20px; -} - -.facebook_large_btn { - width: 100px; - height: 40px; -/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */ - _width: 102px; - _height: 42px; - - border: 1px solid #DDD; - margin: 3px; - float: left; -} - -.facebook_small_btn { - width: 24px; - height: 24px; -/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */ - _width: 26px; - _height: 26px; - - border: 1px solid #DDD; - margin: 3px; - float: left; -} - -a.facebook_large_btn:focus { - outline: none; -} - -a.facebook_large_btn:focus { - -moz-outline-style: none; -} - -.facebook_selected { - border: 4px solid #DDD; -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Controllers/ExternalAuthFacebookController.cs b/src/Plugins/ExternalAuth.Facebook/Controllers/ExternalAuthFacebookController.cs deleted file mode 100644 index 12eefc9d4a..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Controllers/ExternalAuthFacebookController.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Domain.Customers; -using SmartStore.Plugin.ExternalAuth.Facebook.Core; -using SmartStore.Plugin.ExternalAuth.Facebook.Models; -using SmartStore.Services.Authentication.External; -using SmartStore.Services.Configuration; -using SmartStore.Services.Security; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.ExternalAuth.Facebook.Controllers -{ - //[UnitOfWork] - public class ExternalAuthFacebookController : PluginControllerBase - { - private readonly ISettingService _settingService; - private readonly FacebookExternalAuthSettings _facebookExternalAuthSettings; - private readonly IOAuthProviderFacebookAuthorizer _oAuthProviderFacebookAuthorizer; - private readonly IOpenAuthenticationService _openAuthenticationService; - private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; - private readonly IStoreContext _storeContext; - private readonly IPermissionService _permissionService; - - public ExternalAuthFacebookController(ISettingService settingService, - FacebookExternalAuthSettings facebookExternalAuthSettings, - IOAuthProviderFacebookAuthorizer oAuthProviderFacebookAuthorizer, - IOpenAuthenticationService openAuthenticationService, - ExternalAuthenticationSettings externalAuthenticationSettings, - IStoreContext storeContext, - IPermissionService permissionService) - { - this._settingService = settingService; - this._facebookExternalAuthSettings = facebookExternalAuthSettings; - this._oAuthProviderFacebookAuthorizer = oAuthProviderFacebookAuthorizer; - this._openAuthenticationService = openAuthenticationService; - this._externalAuthenticationSettings = externalAuthenticationSettings; - this._storeContext = storeContext; - this._permissionService = permissionService; - } - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) - return Content("Access denied"); - - var model = new ConfigurationModel(); - model.ClientKeyIdentifier = _facebookExternalAuthSettings.ClientKeyIdentifier; - model.ClientSecret = _facebookExternalAuthSettings.ClientSecret; - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure(ConfigurationModel model) - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods)) - return Content("Access denied"); - - if (!ModelState.IsValid) - return Configure(); - - //save settings - _facebookExternalAuthSettings.ClientKeyIdentifier = model.ClientKeyIdentifier; - _facebookExternalAuthSettings.ClientSecret = model.ClientSecret; - _settingService.SaveSetting(_facebookExternalAuthSettings); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PublicInfo() - { - return View(); - } - - [NonAction] - private ActionResult LoginInternal(string returnUrl, bool verifyResponse) - { - var processor = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName("ExternalAuth.Facebook"); - if (processor == null || - !processor.IsMethodActive(_externalAuthenticationSettings) || - !processor.PluginDescriptor.Installed || - !(_storeContext.CurrentStore.Id == 0 || - _settingService.GetSettingByKey(processor.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(_storeContext.CurrentStore.Id, true))) - throw new SmartException("Facebook module cannot be loaded"); - - var viewModel = new LoginModel(); - TryUpdateModel(viewModel); - - var result = _oAuthProviderFacebookAuthorizer.Authorize(returnUrl, verifyResponse); - switch (result.AuthenticationStatus) - { - case OpenAuthenticationStatus.Error: - { - if (!result.Success) - foreach (var error in result.Errors) - NotifyError(error); - - return new RedirectResult(Url.LogOn(returnUrl)); - } - case OpenAuthenticationStatus.AssociateOnLogon: - { - return new RedirectResult(Url.LogOn(returnUrl)); - } - case OpenAuthenticationStatus.AutoRegisteredEmailValidation: - { - //result - return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.EmailValidation }); - } - case OpenAuthenticationStatus.AutoRegisteredAdminApproval: - { - return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.AdminApproval }); - } - case OpenAuthenticationStatus.AutoRegisteredStandard: - { - return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.Standard }); - } - default: - break; - } - - if (result.Result != null) return result.Result; - return HttpContext.Request.IsAuthenticated ? new RedirectResult(!string.IsNullOrEmpty(returnUrl) ? returnUrl : "~/") : new RedirectResult(Url.LogOn(returnUrl)); - } - - public ActionResult Login(string returnUrl) - { - return LoginInternal(returnUrl, false); - } - - public ActionResult LoginCallback(string returnUrl) - { - return LoginInternal(returnUrl, true); - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Core/Provider.cs b/src/Plugins/ExternalAuth.Facebook/Core/Provider.cs deleted file mode 100644 index 924c392f8f..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Core/Provider.cs +++ /dev/null @@ -1,14 +0,0 @@ - -namespace SmartStore.Plugin.ExternalAuth.Facebook.Core -{ - public static class Provider - { - public static string SystemName - { - get - { - return "ExternalAuth.Facebook"; - } - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/DependencyRegistrar.cs b/src/Plugins/ExternalAuth.Facebook/DependencyRegistrar.cs deleted file mode 100644 index 7234403ceb..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/DependencyRegistrar.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Autofac; -using Autofac.Integration.Mvc; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Plugin.ExternalAuth.Facebook.Core; - -namespace SmartStore.Plugin.ExternalAuth.Facebook -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/ExternalAuth.Facebook/Description.txt b/src/Plugins/ExternalAuth.Facebook/Description.txt deleted file mode 100644 index 8623a47e9f..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Facebook -SystemName: ExternalAuth.Facebook -Version: 1.5 -MinAppVersion: 2.0.0 -DisplayOrder: 5 -FileName: SmartStore.Plugin.ExternalAuth.Facebook.dll -ResourceRootKey: Plugins.ExternalAuth.Facebook \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Localization/resources.de-de.xml b/src/Plugins/ExternalAuth.Facebook/Localization/resources.de-de.xml deleted file mode 100644 index 3c91062c90..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Localization/resources.de-de.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - Facebook - - - - -
  • Die Facebook Zugangsdaten (s.u.) erhalten Sie, indem Sie bei Facebook unter Entwickler eine Anwendung mit der Option Facebook-Anmeldung erstellen.
  • -
  • Aktivieren Sie in den Kundeneinstellungen die automatische Registrierung, falls extern autorisierte Besucher automatisch registriert werden sollen.
  • -]]> -
    -
    - - Loggen Sie sich mit Ihrem Facebook-Account ein - - - Benutzer-Schlüssel-Identifikator (App ID) - - - Geben Sie hier Ihren Benutzer-Schlüssel-Identifikator (App ID) an. - - - Benutzer-Sicherheitsschlüssel (App Secret) - - - Geben Sie hier Ihren Benutzer-Sicherheitsschlüssel (App Secret) an. - -
    \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Localization/resources.en-us.xml b/src/Plugins/ExternalAuth.Facebook/Localization/resources.en-us.xml deleted file mode 100644 index 0d64d9ecdf..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Localization/resources.en-us.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - Facebook - - - - -
  • Create an application with the facebook login option in the developer area at facebook to get the facebook access data (see below).
  • -
  • Activate auto registration in the customer settings if you want externally authorized visitors to be registered automatically.
  • -]]> -
    -
    - - Login using Facebook account - - - Client key identifier (App ID) - - - Enter your client key identifier (App ID) here. - - - Client secret (App Secret) - - - Enter your client secret (App Secret) here. - -
    \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Models/ConfigurationModel.cs b/src/Plugins/ExternalAuth.Facebook/Models/ConfigurationModel.cs deleted file mode 100644 index 54e75def8e..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Models/ConfigurationModel.cs +++ /dev/null @@ -1,13 +0,0 @@ -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.ExternalAuth.Facebook.Models -{ - public class ConfigurationModel : ModelBase - { - [SmartResourceDisplayName("Plugins.ExternalAuth.Facebook.ClientKeyIdentifier")] - public string ClientKeyIdentifier { get; set; } - [SmartResourceDisplayName("Plugins.ExternalAuth.Facebook.ClientSecret")] - public string ClientSecret { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Models/LoginModel.cs b/src/Plugins/ExternalAuth.Facebook/Models/LoginModel.cs deleted file mode 100644 index fe6c310b7c..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Models/LoginModel.cs +++ /dev/null @@ -1,10 +0,0 @@ - -namespace SmartStore.Plugin.ExternalAuth.Facebook.Models -{ - public class LoginModel - { - public string ExternalIdentifier { get; set; } - public string KnownProvider { get; set; } - public string ReturnUrl { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Notes.txt b/src/Plugins/ExternalAuth.Facebook/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Properties/AssemblyInfo.cs b/src/Plugins/ExternalAuth.Facebook/Properties/AssemblyInfo.cs deleted file mode 100644 index 3ab03912fe..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.ExternalAuth.Facebook")] diff --git a/src/Plugins/ExternalAuth.Facebook/RouteProvider.cs b/src/Plugins/ExternalAuth.Facebook/RouteProvider.cs deleted file mode 100644 index 57c2914fa2..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.ExternalAuth.Facebook -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("ExternalAuth.Facebook", - "Plugins/ExternalAuthFacebook/{action}", - new { controller = "ExternalAuthFacebook", action = "Login" }, - new[] { "SmartStore.Plugin.ExternalAuth.Facebook.Controllers" } - ) - .DataTokens["area"] = "ExternalAuth.Facebook"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/ExternalAuth.Facebook/SmartStore.Plugin.ExternalAuth.Facebook.csproj b/src/Plugins/ExternalAuth.Facebook/SmartStore.Plugin.ExternalAuth.Facebook.csproj deleted file mode 100644 index e6ebe70d60..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/SmartStore.Plugin.ExternalAuth.Facebook.csproj +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {446FED73-BCA1-4D8F-BC13-EA1507C7EF29} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.ExternalAuth.Facebook - SmartStore.Plugin.ExternalAuth.Facebook - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\ExternalAuth.Facebook\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\ExternalAuth.Facebook\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - False - ..\..\packages\DotNetOpenAuth.AspNet.4.3.4.13329\lib\net45-full\DotNetOpenAuth.AspNet.dll - True - - - False - ..\..\packages\DotNetOpenAuth.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.Core.dll - True - - - False - ..\..\packages\DotNetOpenAuth.OAuth.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OAuth.dll - True - - - False - ..\..\packages\DotNetOpenAuth.OAuth.Consumer.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OAuth.Consumer.dll - True - - - False - ..\..\packages\DotNetOpenAuth.OpenId.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OpenId.dll - True - - - False - ..\..\packages\DotNetOpenAuth.OpenId.RelyingParty.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OpenId.RelyingParty.dll - True - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - False - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll - - - - - - - False - ..\..\packages\Microsoft.Net.Http.2.2.19\lib\net45\System.Net.Http.Extensions.dll - - - False - ..\..\packages\Microsoft.Net.Http.2.2.19\lib\net45\System.Net.Http.Primitives.dll - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - Always - - - Always - - - Always - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Views/ExternalAuthFacebook/Configure.cshtml b/src/Plugins/ExternalAuth.Facebook/Views/ExternalAuthFacebook/Configure.cshtml deleted file mode 100644 index b1f9a32c17..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Views/ExternalAuthFacebook/Configure.cshtml +++ /dev/null @@ -1,47 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.ExternalAuth.Facebook.Models.ConfigurationModel -@using SmartStore.Web.Framework; -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - -
    -
    - - @Html.Raw(T("Plugins.ExternalAuth.Facebook.AdminInstruction")) -
    -
    - @Html.SmartLabelFor(model => model.ClientKeyIdentifier) - - @Html.EditorFor(model => model.ClientKeyIdentifier) - @Html.ValidationMessageFor(model => model.ClientKeyIdentifier) -
    - @Html.SmartLabelFor(model => model.ClientSecret) - - @Html.EditorFor(model => model.ClientSecret) - @Html.ValidationMessageFor(model => model.ClientSecret) -
    -   - - -
    - -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Views/ExternalAuthFacebook/PublicInfo.cshtml b/src/Plugins/ExternalAuth.Facebook/Views/ExternalAuthFacebook/PublicInfo.cshtml deleted file mode 100644 index bf8cc3194d..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Views/ExternalAuthFacebook/PublicInfo.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@using SmartStore.Web.Framework.UI -@{ - Layout = ""; - - Html.AddCssFileParts(true, "~/Plugins/ExternalAuth.Facebook/Content/facebookstyles.css"); -} - diff --git a/src/Plugins/ExternalAuth.Facebook/Views/Web.config b/src/Plugins/ExternalAuth.Facebook/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/ExternalAuth.Facebook/packages.config b/src/Plugins/ExternalAuth.Facebook/packages.config deleted file mode 100644 index 70db21597f..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/packages.config +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/web.config b/src/Plugins/ExternalAuth.Facebook/web.config deleted file mode 100644 index 0162400634..0000000000 --- a/src/Plugins/ExternalAuth.Facebook/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/aol.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/aol.gif deleted file mode 100644 index decc4f1236..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/aol.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/facebook.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/facebook.gif deleted file mode 100644 index b997b358f7..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/facebook.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/google.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/google.gif deleted file mode 100644 index 1b6cd07bd8..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/google.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/mailru.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/mailru.gif deleted file mode 100644 index 62fe79ede6..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/mailru.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/myopenid.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/myopenid.gif deleted file mode 100644 index 4885a6dd97..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/myopenid.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/openid.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/openid.gif deleted file mode 100644 index c718b0e6f3..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/openid.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/rambler.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/rambler.gif deleted file mode 100644 index f311e6fec6..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/rambler.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/verisign.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/verisign.gif deleted file mode 100644 index faa6aaafbd..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/verisign.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/vkontakte.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/vkontakte.gif deleted file mode 100644 index afb5c338c6..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/vkontakte.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/yahoo.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/yahoo.gif deleted file mode 100644 index 42adbfa57f..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/yahoo.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/yandex.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/yandex.gif deleted file mode 100644 index ffb3672341..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.large/yandex.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico deleted file mode 100644 index f599e0b96d..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico.gif deleted file mode 100644 index 7ba24cc9f2..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico.png deleted file mode 100644 index d8984a2cfa..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/aol.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico deleted file mode 100644 index 1b9730b01c..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico.gif deleted file mode 100644 index 7e9be595a2..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico.png deleted file mode 100644 index 4a53a1a539..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/blogger.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico deleted file mode 100644 index 2b80f49183..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico.gif deleted file mode 100644 index 8a57d79ada..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico.png deleted file mode 100644 index a0086c32d2..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/claimid.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico deleted file mode 100644 index a97a2e5953..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico.gif deleted file mode 100644 index 05e27f470b..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico.png deleted file mode 100644 index 6fd06059ee..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/clickpass.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico deleted file mode 100644 index de63d7f3f5..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico.gif deleted file mode 100644 index 848ff1eb61..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico.png deleted file mode 100644 index 800bce7e4f..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/facebook.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico deleted file mode 100644 index 11f6e07f68..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico.gif deleted file mode 100644 index 5967b2c172..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico.png deleted file mode 100644 index cdb4a24963..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/flickr.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico deleted file mode 100644 index ee7c943abf..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico.gif deleted file mode 100644 index 3b6b9be6b1..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico.png deleted file mode 100644 index 31dd03db95..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico deleted file mode 100644 index ee7c943abf..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico.gif deleted file mode 100644 index 3b6b9be6b1..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico.png deleted file mode 100644 index 820c1ea219..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/google_profile.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico deleted file mode 100644 index 7db6e67f8b..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico.gif deleted file mode 100644 index 51192da6a2..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico.png deleted file mode 100644 index 1f43d33e61..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/launchpad.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico deleted file mode 100644 index 7f267aa3c5..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico.gif deleted file mode 100644 index b25477a358..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico.png deleted file mode 100644 index a8800badca..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/linkedin.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico deleted file mode 100644 index f3d21ec5e8..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico.gif deleted file mode 100644 index 8897eb25fd..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico.png deleted file mode 100644 index ff703a2827..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/livejournal.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico deleted file mode 100644 index 0694727ea2..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico.gif deleted file mode 100644 index 2f449a5f76..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico.png deleted file mode 100644 index 49b21cda2e..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/mailru.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico deleted file mode 100644 index ceb06e6a3f..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico.gif deleted file mode 100644 index 5f0af22e49..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico.png deleted file mode 100644 index 9b96dc250a..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/myopenid.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico deleted file mode 100644 index 982b4433b9..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico.gif deleted file mode 100644 index d925305c09..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico.png deleted file mode 100644 index 6040e923a2..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/openid.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico deleted file mode 100644 index 6b9f787080..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico.gif deleted file mode 100644 index 2d5064bbbf..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico.png deleted file mode 100644 index 39efc92760..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/rambler.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico deleted file mode 100644 index fa1083c116..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico.gif deleted file mode 100644 index 290c894f15..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico.png deleted file mode 100644 index 9019c1fd4b..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/technorati.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico deleted file mode 100644 index 92336ff012..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico.gif deleted file mode 100644 index a6a018e328..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico.png deleted file mode 100644 index c3227e7c8c..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/twitter.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico deleted file mode 100644 index 3953af9319..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico.gif deleted file mode 100644 index 6a770720f5..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico.png deleted file mode 100644 index 04869b2ae1..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/verisign.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico deleted file mode 100644 index bbd9a0d50f..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico.gif deleted file mode 100644 index 0a16de3dc9..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico.png deleted file mode 100644 index 30e486ee24..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vidoop.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico deleted file mode 100644 index c1e4428bdb..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico.gif deleted file mode 100644 index c360eb1ced..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico.png deleted file mode 100644 index 06f19b2bfc..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/vkontakte.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico deleted file mode 100644 index 4744dae8a5..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico.gif deleted file mode 100644 index a6eba9afa7..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico.png deleted file mode 100644 index 38fab9f097..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/winliveid.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico deleted file mode 100644 index 31b7d2c2b7..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico.gif deleted file mode 100644 index b4f3beb469..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico.png deleted file mode 100644 index 7242e38370..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/wordpress.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico deleted file mode 100644 index d7761e5a9f..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico.gif deleted file mode 100644 index 32d27c1976..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico.png deleted file mode 100644 index 1475eca0c5..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yahoo.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico deleted file mode 100644 index e78219755c..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico.gif deleted file mode 100644 index 6b1e30e3c1..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico.png deleted file mode 100644 index e09f1d995b..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images.small/yandex.ico.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-inputicon.gif b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-inputicon.gif deleted file mode 100644 index cde836c893..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-inputicon.gif and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-providers-en.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-providers-en.png deleted file mode 100644 index f5fd7288cb..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-providers-en.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-providers-ru.png b/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-providers-ru.png deleted file mode 100644 index a1750caf3a..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/openid-providers-ru.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/Content/openidstyles.css b/src/Plugins/ExternalAuth.OpenId/Content/openidstyles.css deleted file mode 100644 index 42402748c3..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Content/openidstyles.css +++ /dev/null @@ -1,73 +0,0 @@ -.foo{} -/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~* - - OPEN ID - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ - -.oauth-login-openid -{ -} - -#openid_form { - -} - -#openid_form legend { - -} - -#openid_choice { - display: none; -} - -#openid_input_area { - clear: both; - padding:10px 10px 10px 0; -} - -#openid_btns, #openid_btns br { - clear: both; -} - -#openid_highlight { - padding: 3px; - background-color: #FFFCC9; - float: left; -} - -.openid_large_btn { - width: 100px; - height: 60px; -/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */ - _width: 102px; - _height: 62px; - - border: 1px solid #DDD; - margin: 3px; - float: left; -} - -.openid_small_btn { - width: 24px; - height: 24px; -/* fix for IE 6 only: http://en.wikipedia.org/wiki/CSS_filter#Underscore_hack */ - _width: 26px; - _height: 26px; - - border: 1px solid #DDD; - margin: 3px; - float: left; -} - -a.openid_large_btn:focus { - outline: none; -} - -a.openid_large_btn:focus { - -moz-outline-style: none; -} - -.openid_selected { - border: 4px solid #DDD; -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Controllers/ExternalAuthOpenIdController.cs b/src/Plugins/ExternalAuth.OpenId/Controllers/ExternalAuthOpenIdController.cs deleted file mode 100644 index a48c0e6aa3..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Controllers/ExternalAuthOpenIdController.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Domain.Customers; -using SmartStore.Plugin.ExternalAuth.OpenId.Core; -using SmartStore.Plugin.ExternalAuth.OpenId.Models; -using SmartStore.Services.Authentication.External; -using SmartStore.Services.Configuration; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Controllers -{ - //[UnitOfWork] - public class ExternalAuthOpenIdController : PluginControllerBase - { - private readonly IOpenIdProviderAuthorizer _openIdProviderAuthorizer; - private readonly IOpenAuthenticationService _openAuthenticationService; - private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; - private readonly IStoreContext _storeContext; - private readonly ISettingService _settingService; // codehint: sm-add - - public ExternalAuthOpenIdController(IOpenIdProviderAuthorizer openIdProviderAuthorizer, - IOpenAuthenticationService openAuthenticationService, - ExternalAuthenticationSettings externalAuthenticationSettings, - IStoreContext storeContext, - ISettingService settingService) - { - this._openIdProviderAuthorizer = openIdProviderAuthorizer; - this._openAuthenticationService = openAuthenticationService; - this._externalAuthenticationSettings = externalAuthenticationSettings; - this._storeContext = storeContext; - this._settingService = settingService; // codehint: sm-add - } - - [ChildActionOnly] - public ActionResult PublicInfo() - { - return View(); - } - - public ActionResult Login(string returnUrl) - { - var processor = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName("ExternalAuth.OpenId"); - if (processor == null || - !processor.IsMethodActive(_externalAuthenticationSettings) || - !processor.PluginDescriptor.Installed || - !(_storeContext.CurrentStore.Id == 0 || - _settingService.GetSettingByKey(processor.PluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(_storeContext.CurrentStore.Id, true))) - throw new SmartException("OpenID module cannot be loaded"); - - if (!_openIdProviderAuthorizer.IsOpenIdCallback) - { - var viewModel = new LoginModel(); - TryUpdateModel(viewModel); - _openIdProviderAuthorizer.EnternalIdentifier = viewModel.ExternalIdentifier; - } - - var result = _openIdProviderAuthorizer.Authorize(returnUrl); - switch (result.AuthenticationStatus) - { - case OpenAuthenticationStatus.Error: - { - if (!result.Success) - foreach (var error in result.Errors) - NotifyError(error); - - return new RedirectResult(Url.LogOn(returnUrl)); - } - case OpenAuthenticationStatus.AssociateOnLogon: - { - return new RedirectResult(Url.LogOn(returnUrl)); - } - case OpenAuthenticationStatus.AutoRegisteredEmailValidation: - { - //result - return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.EmailValidation }); - } - case OpenAuthenticationStatus.AutoRegisteredAdminApproval: - { - return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.AdminApproval }); - } - case OpenAuthenticationStatus.AutoRegisteredStandard: - { - return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.Standard }); - } - default: - break; - } - - if (result.Result != null) return result.Result; - return HttpContext.Request.IsAuthenticated ? new RedirectResult(!string.IsNullOrEmpty(returnUrl) ? returnUrl : "~/") : new RedirectResult(Url.LogOn(returnUrl)); - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/Claims.cs b/src/Plugins/ExternalAuth.OpenId/Core/Claims.cs deleted file mode 100644 index 1e05020003..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/Claims.cs +++ /dev/null @@ -1,42 +0,0 @@ -//Contributor: Nicholas Mayne - - -using DotNetOpenAuth.OpenId.Extensions.AttributeExchange; -using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; -using DotNetOpenAuth.OpenId.Messages; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public static class Claims - { - public static IOpenIdMessageExtension CreateClaimsRequest() - { - var claimsRequest = new ClaimsRequest(); - - //claimsRequest.BirthDate = DemandLevel.Require; - //claimsRequest.Country = DemandLevel.Require; - claimsRequest.Email = DemandLevel.Require; - claimsRequest.FullName = DemandLevel.Require; - //claimsRequest.Gender = DemandLevel.Require; - //claimsRequest.Language = DemandLevel.Require; - //claimsRequest.Nickname = DemandLevel.Require; - //claimsRequest.PostalCode = DemandLevel.Require; - //claimsRequest.TimeZone = DemandLevel.Require; - - return claimsRequest; - } - - public static FetchRequest CreateFetchRequest() - { - var fetchRequest = new FetchRequest(); - - fetchRequest.Attributes.AddRequired(WellKnownAttributes.Contact.Email); - fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.First); - fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.Last); - fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.FullName); - fetchRequest.Attributes.AddRequired(WellKnownAttributes.Name.Alias); - - return fetchRequest; - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/IOpenIdProviderAuthorizer.cs b/src/Plugins/ExternalAuth.OpenId/Core/IOpenIdProviderAuthorizer.cs deleted file mode 100644 index d02abea401..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/IOpenIdProviderAuthorizer.cs +++ /dev/null @@ -1,13 +0,0 @@ -//Contributor: Nicholas Mayne - - -using SmartStore.Services.Authentication.External; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public interface IOpenIdProviderAuthorizer : IExternalProviderAuthorizer - { - string EnternalIdentifier { get; set; } // mayne - refactor this out - bool IsOpenIdCallback { get; } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/IOpenIdRelyingPartyService.cs b/src/Plugins/ExternalAuth.OpenId/Core/IOpenIdRelyingPartyService.cs deleted file mode 100644 index e95c17eda5..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/IOpenIdRelyingPartyService.cs +++ /dev/null @@ -1,14 +0,0 @@ -//Contributor: Nicholas Mayne - - -using DotNetOpenAuth.OpenId.RelyingParty; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public interface IOpenIdRelyingPartyService - { - IAuthenticationResponse Response { get; } - IAuthenticationRequest CreateRequest(OpenIdIdentifier openIdIdentifier); - bool HasResponse { get; } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdAuthenticationParameters.cs b/src/Plugins/ExternalAuth.OpenId/Core/OpenIdAuthenticationParameters.cs deleted file mode 100644 index a7ae0deabb..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdAuthenticationParameters.cs +++ /dev/null @@ -1,50 +0,0 @@ -//Contributor: Nicholas Mayne - - -using System; -using System.Collections.Generic; -using DotNetOpenAuth.OpenId.Extensions.AttributeExchange; -using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; -using DotNetOpenAuth.OpenId.RelyingParty; -using SmartStore.Services.Authentication.External; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - [Serializable] - public sealed class OpenIdAuthenticationParameters : OpenAuthenticationParameters - { - private readonly IList _claims; - - public OpenIdAuthenticationParameters() { } - - public OpenIdAuthenticationParameters(IAuthenticationResponse authenticationResponse) - { - ExternalIdentifier = authenticationResponse.ClaimedIdentifier; - ExternalDisplayIdentifier = authenticationResponse.FriendlyIdentifierForDisplay; - - _claims = new List(); - var claimsResponseTranslator = new OpenIdClaimsResponseClaimsTranslator(); - var claims1 = claimsResponseTranslator.Translate(authenticationResponse.GetExtension()); - if (claims1 != null) - UserClaims.Add(claims1); - - var fetchResponseTranslator = new OpenIdFetchResponseClaimsTranslator(); - var claims2 = fetchResponseTranslator.Translate(authenticationResponse.GetExtension()); - if (claims2 != null) - UserClaims.Add(claims2); - } - - public override IList UserClaims - { - get - { - return _claims; - } - } - - public override string ProviderSystemName - { - get { return Provider.SystemName; } - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdClaimsResponseClaimsTranslator.cs b/src/Plugins/ExternalAuth.OpenId/Core/OpenIdClaimsResponseClaimsTranslator.cs deleted file mode 100644 index 458c6b59f9..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdClaimsResponseClaimsTranslator.cs +++ /dev/null @@ -1,65 +0,0 @@ -//Contributor: Nicholas Mayne - - -using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; -using SmartStore.Services.Authentication.External; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public class OpenIdClaimsResponseClaimsTranslator : IClaimsTranslator - { - public UserClaims Translate(ClaimsResponse response) - { - if (response == null) - return null; - - var claims = new UserClaims(); - - claims.BirthDate = new BirthDateClaims(); - if (response.BirthDate.HasValue) - { - claims.BirthDate.DayOfMonth = response.BirthDate.Value.Day; - claims.BirthDate.Month = response.BirthDate.Value.Month; - claims.BirthDate.WholeBirthDate = response.BirthDate; - claims.BirthDate.Year = response.BirthDate.Value.Year; - } - claims.BirthDate.Raw = response.BirthDateRaw; - - claims.Contact = new ContactClaims(); - claims.Contact.Email = response.Email; - - claims.Contact.Address = new AddressClaims(); - claims.Contact.Address.Country = response.Country; - claims.Contact.Address.PostalCode = response.PostalCode; - - claims.Preferences = new PreferenceClaims(); - if (response.Culture != null) - claims.Preferences.Language = response.Culture.IetfLanguageTag; - - claims.Preferences.PrimaryLanguage = response.Language; - claims.Preferences.TimeZone = response.TimeZone; - - claims.Name = new NameClaims(); - claims.Name.FullName = response.FullName; - claims.Name.Nickname = response.Nickname; - - claims.Person = new PersonClaims(); - if (response.Gender.HasValue) - claims.Person.Gender = response.Gender.Value.ToString(); - - claims.IsSignedByProvider = response.IsSignedByProvider; - - claims.Contact.MailAddress = new AddressClaims(); - if (response.MailAddress != null) - { - claims.Contact.MailAddress.SingleLineAddress = response.MailAddress.Address; - claims.Contact.MailAddress.DisplayName = response.MailAddress.DisplayName; - claims.Contact.MailAddress.Host = response.MailAddress.Host; - claims.Contact.MailAddress.User = response.MailAddress.User; - } - - claims.Version = response.Version; - return claims; - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdFetchResponseClaimsTranslator.cs b/src/Plugins/ExternalAuth.OpenId/Core/OpenIdFetchResponseClaimsTranslator.cs deleted file mode 100644 index b31fc0cb69..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdFetchResponseClaimsTranslator.cs +++ /dev/null @@ -1,110 +0,0 @@ -//Contributor: Nicholas Mayne - - -using System; -using DotNetOpenAuth.OpenId.Extensions.AttributeExchange; -using SmartStore.Services.Authentication.External; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public class OpenIdFetchResponseClaimsTranslator : IClaimsTranslator - { - public UserClaims Translate(FetchResponse response) - { - if (response == null) - return null; - - var claims = new UserClaims(); - claims.BirthDate = new BirthDateClaims(); - int dayOfMonth; - if (int.TryParse(response.GetAttributeValue(WellKnownAttributes.BirthDate.DayOfMonth), out dayOfMonth)) - claims.BirthDate.DayOfMonth = dayOfMonth; - int month; - if (int.TryParse(response.GetAttributeValue(WellKnownAttributes.BirthDate.Month), out month)) - claims.BirthDate.Month = month; - DateTime wholeBirthDate; - if (DateTime.TryParse(response.GetAttributeValue(WellKnownAttributes.BirthDate.WholeBirthDate), out wholeBirthDate)) - claims.BirthDate.WholeBirthDate = wholeBirthDate; - int year; - if (int.TryParse(response.GetAttributeValue(WellKnownAttributes.BirthDate.Year), out year)) - claims.BirthDate.Year = year; - - claims.Company = new CompanyClaims(); - claims.Company.CompanyName = response.GetAttributeValue(WellKnownAttributes.Company.CompanyName); - claims.Company.JobTitle = response.GetAttributeValue(WellKnownAttributes.Company.JobTitle); - - claims.Contact = new ContactClaims(); - claims.Contact.Email = response.GetAttributeValue(WellKnownAttributes.Contact.Email); - - claims.Contact.Address = new AddressClaims(); - claims.Contact.Address.City = response.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.City); - claims.Contact.Address.Country = response.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.Country); - claims.Contact.Address.PostalCode = response.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.PostalCode); - claims.Contact.Address.State = response.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.State); - claims.Contact.Address.StreetAddressLine1 = response.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.StreetAddressLine1); - claims.Contact.Address.StreetAddressLine2 = response.GetAttributeValue(WellKnownAttributes.Contact.HomeAddress.StreetAddressLine2); - - claims.Contact.IM = new InstantMessagingClaims(); - claims.Contact.IM.AOL = response.GetAttributeValue(WellKnownAttributes.Contact.IM.AOL); - claims.Contact.IM.ICQ = response.GetAttributeValue(WellKnownAttributes.Contact.IM.ICQ); - claims.Contact.IM.Jabber = response.GetAttributeValue(WellKnownAttributes.Contact.IM.Jabber); - claims.Contact.IM.MSN = response.GetAttributeValue(WellKnownAttributes.Contact.IM.MSN); - claims.Contact.IM.Skype = response.GetAttributeValue(WellKnownAttributes.Contact.IM.Skype); - claims.Contact.IM.Yahoo = response.GetAttributeValue(WellKnownAttributes.Contact.IM.Yahoo); - - claims.Contact.Phone = new TelephoneClaims(); - claims.Contact.Phone.Fax = response.GetAttributeValue(WellKnownAttributes.Contact.Phone.Fax); - claims.Contact.Phone.Home = response.GetAttributeValue(WellKnownAttributes.Contact.Phone.Home); - claims.Contact.Phone.Mobile = response.GetAttributeValue(WellKnownAttributes.Contact.Phone.Mobile); - claims.Contact.Phone.Preferred = response.GetAttributeValue(WellKnownAttributes.Contact.Phone.Preferred); - claims.Contact.Phone.Work = response.GetAttributeValue(WellKnownAttributes.Contact.Phone.Work); - - claims.Contact.Web = new WebClaims(); - claims.Contact.Web.Amazon = response.GetAttributeValue(WellKnownAttributes.Contact.Web.Amazon); - claims.Contact.Web.Blog = response.GetAttributeValue(WellKnownAttributes.Contact.Web.Blog); - claims.Contact.Web.Delicious = response.GetAttributeValue(WellKnownAttributes.Contact.Web.Delicious); - claims.Contact.Web.Flickr = response.GetAttributeValue(WellKnownAttributes.Contact.Web.Flickr); - claims.Contact.Web.Homepage = response.GetAttributeValue(WellKnownAttributes.Contact.Web.Homepage); - claims.Contact.Web.LinkedIn = response.GetAttributeValue(WellKnownAttributes.Contact.Web.LinkedIn); - - claims.Contact.WorkAddress = new AddressClaims(); - claims.Contact.WorkAddress.City = response.GetAttributeValue(WellKnownAttributes.Contact.WorkAddress.City); - claims.Contact.WorkAddress.Country = response.GetAttributeValue(WellKnownAttributes.Contact.WorkAddress.Country); - claims.Contact.WorkAddress.PostalCode = response.GetAttributeValue(WellKnownAttributes.Contact.WorkAddress.PostalCode); - claims.Contact.WorkAddress.State = response.GetAttributeValue(WellKnownAttributes.Contact.WorkAddress.State); - claims.Contact.WorkAddress.StreetAddressLine1 = response.GetAttributeValue(WellKnownAttributes.Contact.WorkAddress.StreetAddressLine1); - claims.Contact.WorkAddress.StreetAddressLine2 = response.GetAttributeValue(WellKnownAttributes.Contact.WorkAddress.StreetAddressLine2); - - claims.Media = new MediaClaims(); - claims.Media.AudioGreeting = response.GetAttributeValue(WellKnownAttributes.Media.AudioGreeting); - claims.Media.SpokenName = response.GetAttributeValue(WellKnownAttributes.Media.SpokenName); - claims.Media.VideoGreeting = response.GetAttributeValue(WellKnownAttributes.Media.VideoGreeting); - - claims.Media.Images = new ImageClaims(); - claims.Media.Images.Aspect11 = response.GetAttributeValue(WellKnownAttributes.Media.Images.Aspect11); - claims.Media.Images.Aspect34 = response.GetAttributeValue(WellKnownAttributes.Media.Images.Aspect34); - claims.Media.Images.Aspect43 = response.GetAttributeValue(WellKnownAttributes.Media.Images.Aspect43); - claims.Media.Images.Default = response.GetAttributeValue(WellKnownAttributes.Media.Images.Default); - claims.Media.Images.FavIcon = response.GetAttributeValue(WellKnownAttributes.Media.Images.FavIcon); - - claims.Name = new NameClaims(); - claims.Name.Alias = response.GetAttributeValue(WellKnownAttributes.Name.Alias); - claims.Name.First = response.GetAttributeValue(WellKnownAttributes.Name.First); - claims.Name.FullName = response.GetAttributeValue(WellKnownAttributes.Name.FullName); - claims.Name.Last = response.GetAttributeValue(WellKnownAttributes.Name.Last); - claims.Name.Middle = response.GetAttributeValue(WellKnownAttributes.Name.Middle); - claims.Name.Prefix = response.GetAttributeValue(WellKnownAttributes.Name.Prefix); - claims.Name.Suffix = response.GetAttributeValue(WellKnownAttributes.Name.Suffix); - - claims.Person = new PersonClaims(); - claims.Person.Biography = response.GetAttributeValue(WellKnownAttributes.Person.Biography); - claims.Person.Gender = response.GetAttributeValue(WellKnownAttributes.Person.Gender); - - claims.Preferences = new PreferenceClaims(); - claims.Preferences.Language = response.GetAttributeValue(WellKnownAttributes.Preferences.Language); - claims.Preferences.TimeZone = response.GetAttributeValue(WellKnownAttributes.Preferences.TimeZone); - - return claims; - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdIdentifier.cs b/src/Plugins/ExternalAuth.OpenId/Core/OpenIdIdentifier.cs deleted file mode 100644 index fe0c65ca55..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdIdentifier.cs +++ /dev/null @@ -1,38 +0,0 @@ -//Contributor: Nicholas Mayne - - -using DotNetOpenAuth.OpenId; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public sealed class OpenIdIdentifier - { - public OpenIdIdentifier(string externalIdentifier) - { - Identifier id; - if (Identifier.TryParse(externalIdentifier, out id)) - { - Identifier = id; - } - } - - public Identifier Identifier - { - get; - private set; - } - - public bool IsValid - { - get - { - return Identifier != null; - } - } - - public override string ToString() - { - return Identifier != null ? Identifier.ToString() : string.Empty; - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdProviderAuthorizer.cs b/src/Plugins/ExternalAuth.OpenId/Core/OpenIdProviderAuthorizer.cs deleted file mode 100644 index 5eaed7d379..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdProviderAuthorizer.cs +++ /dev/null @@ -1,122 +0,0 @@ -//Contributor: Nicholas Mayne - -using System; -using System.Web.Mvc; -using DotNetOpenAuth.Messaging; -using DotNetOpenAuth.OpenId.RelyingParty; -using SmartStore.Services.Authentication.External; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public class OpenIdProviderAuthorizer : IOpenIdProviderAuthorizer - { - private readonly IOpenIdRelyingPartyService _openIdRelyingPartyService; - private readonly IExternalAuthorizer _authorizer; - - public OpenIdProviderAuthorizer(IOpenIdRelyingPartyService openIdRelyingPartyService, - IExternalAuthorizer authorizer) - { - _openIdRelyingPartyService = openIdRelyingPartyService; - _authorizer = authorizer; - } - - /// - /// Authorize response - /// - /// Return URL - /// true - Verify response;false - request authentication;null - determine automatically - /// Authorize state - public AuthorizeState Authorize(string returnUrl, bool? verifyResponse = null) - { - if (verifyResponse.HasValue ? verifyResponse.Value : IsOpenIdCallback) - return VerifyAuthentication(returnUrl); - - return RequestAuthentication(returnUrl); - } - - private AuthorizeState VerifyAuthentication(string returnUrl) - { - switch (_openIdRelyingPartyService.Response.Status) - { - case AuthenticationStatus.Authenticated: - var parameters = new OpenIdAuthenticationParameters(_openIdRelyingPartyService.Response); - return new AuthorizeState(returnUrl, _authorizer.Authorize(parameters)); - case AuthenticationStatus.Canceled: - { - var result = new AuthorizeState(returnUrl, OpenAuthenticationStatus.AssociateOnLogon); - return result; - } - case AuthenticationStatus.Failed: - { - var result = new AuthorizeState(returnUrl, OpenAuthenticationStatus.Error); - result.AddError(_openIdRelyingPartyService.Response.Exception.Message); - return result; - } - } - return new AuthorizeState(returnUrl, OpenAuthenticationStatus.Unknown); - } - - private AuthorizeState RequestAuthentication(string returnUrl) - { - var identifier = new OpenIdIdentifier(EnternalIdentifier); - if (!identifier.IsValid) - { - var result = new AuthorizeState(returnUrl, OpenAuthenticationStatus.Error); - result.AddError("Invalid Open ID identifier"); - return result; - } - - try - { - var request = _openIdRelyingPartyService.CreateRequest(identifier); - - request.AddExtension(Claims.CreateClaimsRequest()); - request.AddExtension(Claims.CreateFetchRequest()); - - return new AuthorizeState(returnUrl, OpenAuthenticationStatus.RequiresRedirect) - { - Result = request.RedirectingResponse.AsActionResult2() - }; - } - catch (ProtocolException ex) - { - var result = new AuthorizeState(returnUrl, OpenAuthenticationStatus.Error); - result.AddError("Unable to authenticate: " + ex.Message); - return result; - } - } - - public string EnternalIdentifier { get; set; } - - public bool IsOpenIdCallback - { - get { return _openIdRelyingPartyService.HasResponse; } - } - } - - internal static class Extensions - { - public static ActionResult AsActionResult2(this OutgoingWebResponse response) - { - Guard.ArgumentNotNull(() => response); - return new OutgoingWebResponseActionResult2(response); - } - } - - internal class OutgoingWebResponseActionResult2 : ActionResult - { - private readonly OutgoingWebResponse _response; - - public OutgoingWebResponseActionResult2(OutgoingWebResponse response) - { - _response = response; - } - - public override void ExecuteResult(ControllerContext context) - { - _response.Respond(context.HttpContext); - context.HttpContext.Response.Flush(); - - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdRelyingPartyService.cs b/src/Plugins/ExternalAuth.OpenId/Core/OpenIdRelyingPartyService.cs deleted file mode 100644 index d344db15d1..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/OpenIdRelyingPartyService.cs +++ /dev/null @@ -1,38 +0,0 @@ -//Contributor: Nicholas Mayne - -using DotNetOpenAuth.OpenId.RelyingParty; - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public class OpenIdRelyingPartyService : IOpenIdRelyingPartyService - { - private static readonly OpenIdRelyingParty _relyingParty = new OpenIdRelyingParty(); - - private IAuthenticationResponse _response; - - public IAuthenticationResponse Response - { - get - { - if (_response == null) - { - _response = _relyingParty.GetResponse(); - } - return _response; - } - } - - public IAuthenticationRequest CreateRequest(OpenIdIdentifier openIdIdentifier) - { - return _relyingParty.CreateRequest(openIdIdentifier.Identifier); - } - - public bool HasResponse - { - get - { - return Response != null; - } - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Core/Provider.cs b/src/Plugins/ExternalAuth.OpenId/Core/Provider.cs deleted file mode 100644 index bcf36fcabe..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Core/Provider.cs +++ /dev/null @@ -1,15 +0,0 @@ - - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Core -{ - public static class Provider - { - public static string SystemName - { - get - { - return "ExternalAuth.OpenId"; - } - } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/DependencyRegistrar.cs b/src/Plugins/ExternalAuth.OpenId/DependencyRegistrar.cs deleted file mode 100644 index e9e51182ca..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/DependencyRegistrar.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Autofac; -using Autofac.Integration.Mvc; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Plugin.ExternalAuth.OpenId.Core; - -namespace SmartStore.Plugin.ExternalAuth.OpenId -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/ExternalAuth.OpenId/Description.txt b/src/Plugins/ExternalAuth.OpenId/Description.txt deleted file mode 100644 index 19636449b0..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: OpenID -SystemName: ExternalAuth.OpenId -Version: 1.5 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.ExternalAuth.OpenId.dll -ResourceRootKey: Plugins.ExternalAuth.OpenId \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Localization/resources.de-de.xml b/src/Plugins/ExternalAuth.OpenId/Localization/resources.de-de.xml deleted file mode 100644 index 777fa0932a..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Localization/resources.de-de.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - OpenID - - - Loggen Sie sich mit Ihrem OpenID-Account ein - - - Bitte wählen Sie den Anbieter Ihres Accounts - - - Geben Sie Ihre OpenID an - - - Einloggen - - \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Localization/resources.en-us.xml b/src/Plugins/ExternalAuth.OpenId/Localization/resources.en-us.xml deleted file mode 100644 index 9be4f843f9..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Localization/resources.en-us.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - OpenID - - - Login using OpenID account - - - Please click your account provider - - - Enter manually your OpenID - - - Sign In - - \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Models/LoginModel.cs b/src/Plugins/ExternalAuth.OpenId/Models/LoginModel.cs deleted file mode 100644 index 80bc6019a6..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Models/LoginModel.cs +++ /dev/null @@ -1,10 +0,0 @@ - -namespace SmartStore.Plugin.ExternalAuth.OpenId.Models -{ - public class LoginModel - { - public string ExternalIdentifier { get; set; } - public string KnownProvider { get; set; } - public string ReturnUrl { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Notes.txt b/src/Plugins/ExternalAuth.OpenId/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/OpenIdExternalAuthMethod.cs b/src/Plugins/ExternalAuth.OpenId/OpenIdExternalAuthMethod.cs deleted file mode 100644 index e3541597fe..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/OpenIdExternalAuthMethod.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Services.Authentication.External; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.ExternalAuth.OpenId -{ - /// - /// OpenId externalAuth processor - /// - public class OpenIdExternalAuthMethod : BasePlugin, IExternalAuthenticationMethod - { - - private readonly ILocalizationService _localizationService; - - public OpenIdExternalAuthMethod(ILocalizationService localizationService) - { - _localizationService = localizationService; - } - - #region Methods - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - //configuration is not required - actionName = null; - controllerName = null; - routeValues = null; - } - - /// - /// Gets a route for displaying plugin in public store - /// - /// Action name - /// Controller name - /// Route values - public void GetPublicInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PublicInfo"; - controllerName = "ExternalAuthOpenId"; - routeValues = new RouteValueDictionary( new { Namespaces = "SmartStore.Plugin.ExternalAuth.OpenId.Controllers", area = "ExternalAuth.OpenId" } ); - } - - /// - /// Install plugin - /// - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.ExternalAuth.OpenId", false); - - base.Uninstall(); - } - - #endregion - - } -} diff --git a/src/Plugins/ExternalAuth.OpenId/Properties/AssemblyInfo.cs b/src/Plugins/ExternalAuth.OpenId/Properties/AssemblyInfo.cs deleted file mode 100644 index 769160619e..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.ExternalAuth.OpenId")] diff --git a/src/Plugins/ExternalAuth.OpenId/RouteProvider.cs b/src/Plugins/ExternalAuth.OpenId/RouteProvider.cs deleted file mode 100644 index 10bf39d650..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.ExternalAuth.OpenId -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("ExternalAuth.OpenId", - "Plugins/ExternalAuthOpenId/{action}", - new { controller = "ExternalAuthOpenId", action = "Login" }, - new[] { "SmartStore.Plugin.ExternalAuth.OpenId.Controllers" } - ) - .DataTokens["area"] = "ExternalAuth.OpenId"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/ExternalAuth.OpenId/Scripts/openid-en.js b/src/Plugins/ExternalAuth.OpenId/Scripts/openid-en.js deleted file mode 100644 index 2b68c66537..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Scripts/openid-en.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - Simple OpenID Plugin - http://code.google.com/p/openid-selector/ - - This code is licensed under the New BSD License. -*/ - -var providers_large = { - google : { - name : 'Google', - url : 'https://www.google.com/accounts/o8/id' - }, - yahoo : { - name : 'Yahoo', - url : 'http://me.yahoo.com/' - }, - aol : { - name : 'AOL', - label : 'Enter your AOL screenname.', - url : 'http://openid.aol.com/{username}' - }, - myopenid : { - name : 'MyOpenID', - label : 'Enter your MyOpenID username.', - url : 'http://{username}.myopenid.com/' - }, - openid : { - name : 'OpenID', - label : 'Enter your OpenID.', - url : null - } -}; - -var providers_small = { - livejournal : { - name : 'LiveJournal', - label : 'Enter your Livejournal username.', - url : 'http://{username}.livejournal.com/' - }, - /* flickr: { - name: 'Flickr', - label: 'Enter your Flickr username.', - url: 'http://flickr.com/{username}/' - }, */ - /* technorati: { - name: 'Technorati', - label: 'Enter your Technorati username.', - url: 'http://technorati.com/people/technorati/{username}/' - }, */ - wordpress : { - name : 'Wordpress', - label : 'Enter your Wordpress.com username.', - url : 'http://{username}.wordpress.com/' - }, - blogger : { - name : 'Blogger', - label : 'Your Blogger account', - url : 'http://{username}.blogspot.com/' - }, - verisign : { - name : 'Verisign', - label : 'Your Verisign username', - url : 'http://{username}.pip.verisignlabs.com/' - }, - /* vidoop: { - name: 'Vidoop', - label: 'Your Vidoop username', - url: 'http://{username}.myvidoop.com/' - }, */ - /* launchpad: { - name: 'Launchpad', - label: 'Your Launchpad username', - url: 'https://launchpad.net/~{username}' - }, */ - claimid : { - name : 'ClaimID', - label : 'Your ClaimID username', - url : 'http://claimid.com/{username}' - }, - clickpass : { - name : 'ClickPass', - label : 'Enter your ClickPass username', - url : 'http://clickpass.com/public/{username}' - }, - google_profile : { - name : 'Google Profile', - label : 'Enter your Google Profile username', - url : 'http://www.google.com/profiles/{username}' - } -}; - -openid.locale = 'en'; -openid.sprite = 'en'; // reused in german& japan localization -openid.demo_text = 'In client demo mode. Normally would have submitted OpenID:'; -openid.signin_text = 'Sign-In'; -openid.image_title = 'log in with {provider}'; diff --git a/src/Plugins/ExternalAuth.OpenId/Scripts/openid-jquery-1.3b1.js b/src/Plugins/ExternalAuth.OpenId/Scripts/openid-jquery-1.3b1.js deleted file mode 100644 index 4713617e97..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Scripts/openid-jquery-1.3b1.js +++ /dev/null @@ -1,209 +0,0 @@ -/* - Simple OpenID Plugin - http://code.google.com/p/openid-selector/ - - This code is licensed under the New BSD License. - Customized -*/ - -var providers; -var openid; -(function ($) { -openid = { - version : '1.3-beta1', // version constant - demo : false, - demo_text : null, - cookie_expires : 6 * 30, // 6 months. - cookie_name : 'openid_provider', - cookie_path : '/', - - img_path : '', - locale : null, // is set in openid-.js - sprite : null, // usually equals to locale, is set in - // openid-.js - signin_text : 'Sign In', // text on submit button on the form - all_small : false, // output large providers w/ small icons - no_sprite : false, // don't use sprite image - image_title : '{provider}', // for image title - - input_id : null, - provider_url : null, - provider_id : null, - - /** - * Class constructor - * - * @return {Void} - */ - init : function(input_id, store_root) { - providers = $.extend({}, providers_large, providers_small); - var openid_btns = $('#openid_btns'); - this.input_id = input_id; - this.img_path = store_root + 'Plugins/ExternalAuth.OpenId/Content/Images/openid-selector/images/'; - $('#openid_choice').show(); - $('#openid_input_area').empty(); - var i = 0; - // add box for each provider - for (id in providers_large) { - box = this.getBoxHTML(id, providers_large[id], (this.all_small ? 'small' : 'large'), i++); - openid_btns.append(box); - } - if (providers_small) { - openid_btns.append('
    '); - for (id in providers_small) { - box = this.getBoxHTML(id, providers_small[id], 'small', i++); - openid_btns.append(box); - } - } - $('#openid_form').submit(this.submit); - var box_id = this.readCookie(); - if (box_id) { - this.signin(box_id, true); - } - }, - - /** - * @return {String} - */ - getBoxHTML : function(box_id, provider, box_size, index) { - if (this.no_sprite) { - var image_ext = box_size == 'small' ? '.ico.gif' : '.gif'; - return ''; - } - var x = box_size == 'small' ? -index * 24 : -index * 100; - var y = box_size == 'small' ? -60 : 0; - return ''; - }, - - /** - * Provider image click - * - * @return {Void} - */ - signin : function(box_id, onload) { - var provider = providers[box_id]; - if (!provider) { - return; - } - this.highlight(box_id); - this.setCookie(box_id); - this.provider_id = box_id; - this.provider_url = provider['url']; - // prompt user for input? - if (provider['label']) { - this.useInputBox(provider); - } else { - $('#openid_input_area').empty(); - if (!onload) { - $('#openid_form').submit(); - } - } - }, - - /** - * Sign-in button click - * - * @return {Boolean} - */ - submit : function() { - var url = openid.provider_url; - if (url) { - url = url.replace('{username}', $('#openid_username').val()); - openid.setOpenIdUrl(url); - } - if (openid.demo) { - alert(openid.demo_text + "\r\n" + document.getElementById(openid.input_id).value); - return false; - } - if (url.indexOf("javascript:") == 0) { - url = url.substr("javascript:".length); - eval(url); - return false; - } - return true; - }, - - /** - * @return {Void} - */ - setOpenIdUrl : function(url) { - var hidden = document.getElementById(this.input_id); - if (hidden != null) { - hidden.value = url; - } else { - $('#openid_form').append(''); - } - }, - - /** - * @return {Void} - */ - highlight : function(box_id) { - // remove previous highlight. - var highlight = $('#openid_highlight'); - if (highlight) { - highlight.replaceWith($('#openid_highlight a')[0]); - } - // add new highlight. - $('.' + box_id).wrap('
    '); - }, - - setCookie : function(value) { - var date = new Date(); - date.setTime(date.getTime() + (this.cookie_expires * 24 * 60 * 60 * 1000)); - var expires = "; expires=" + date.toGMTString(); - document.cookie = this.cookie_name + "=" + value + expires + "; path=" + this.cookie_path; - }, - - readCookie : function() { - var nameEQ = this.cookie_name + "="; - var ca = document.cookie.split(';'); - for ( var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == ' ') - c = c.substring(1, c.length); - if (c.indexOf(nameEQ) == 0) - return c.substring(nameEQ.length, c.length); - } - return null; - }, - - /** - * @return {Void} - */ - useInputBox : function(provider) { - var input_area = $('#openid_input_area'); - var html = ''; - var id = 'openid_username'; - var value = ''; - var label = provider['label']; - var style = ''; - if (label) { - html = '

    ' + label + '

    '; - } - if (provider['name'] == 'OpenID') { - id = this.input_id; - value = 'http://'; - style = 'background: #FFF url(' + this.img_path + 'openid-inputicon.gif) no-repeat scroll 0 50%; padding-left:18px;'; - } - html += '
    ' - + '
    ' -// + ''; - input_area.empty(); - input_area.append(html); - $('#' + id).focus(); - }, - - setDemoMode : function(demoMode) { - this.demo = demoMode; - }, - - setSignInText : function(signintext){ - this.signin_text = signintext; - } -}; -})(jQuery); diff --git a/src/Plugins/ExternalAuth.OpenId/SmartStore.Plugin.ExternalAuth.OpenId.csproj b/src/Plugins/ExternalAuth.OpenId/SmartStore.Plugin.ExternalAuth.OpenId.csproj deleted file mode 100644 index bbcf46edc3..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/SmartStore.Plugin.ExternalAuth.OpenId.csproj +++ /dev/null @@ -1,522 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {A10220DE-A72B-4FDB-A1F8-E5C111657088} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.ExternalAuth.OpenId - SmartStore.Plugin.ExternalAuth.OpenId - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\ExternalAuth.OpenId\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\ExternalAuth.OpenId\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - False - ..\..\packages\DotNetOpenAuth.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.Core.dll - True - - - False - ..\..\packages\DotNetOpenAuth.OpenId.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OpenId.dll - True - - - False - ..\..\packages\DotNetOpenAuth.OpenId.RelyingParty.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OpenId.RelyingParty.dll - True - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - - False - ..\..\packages\Microsoft.Net.Http.2.2.19\lib\net45\System.Net.Http.Extensions.dll - True - - - False - ..\..\packages\Microsoft.Net.Http.2.2.19\lib\net45\System.Net.Http.Primitives.dll - True - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - Designer - - - Designer - PreserveNewest - - - PreserveNewest - - - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - Always - - - Always - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/Views/ExternalAuthOpenId/PublicInfo.cshtml b/src/Plugins/ExternalAuth.OpenId/Views/ExternalAuthOpenId/PublicInfo.cshtml deleted file mode 100644 index 5316233917..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Views/ExternalAuthOpenId/PublicInfo.cshtml +++ /dev/null @@ -1,53 +0,0 @@ -@using SmartStore.Core.Infrastructure -@using SmartStore.Core.Infrastructure.DependencyManagement -@using SmartStore.Web.Framework.UI -@{ - Layout = ""; - - - Html.AddCssFileParts(true, "~/Plugins/ExternalAuth.OpenId/Content/openidstyles.css"); - - Html.AddScriptParts(true, - "~/Plugins/ExternalAuth.OpenId/Scripts/openid-jquery-1.3b1.js", - "~/Plugins/ExternalAuth.OpenId/Scripts/openid-en.js"); - - var storeLocation = EngineContext.Current.Resolve().GetStoreLocation(); -} - -@using (Html.BeginRouteForm("ExternalAuth.OpenId", new { ReturnUrl = HttpContext.Current.Request.QueryString["ReturnUrl"], action = "Login" }, FormMethod.Post, new { id = "openid_form" })) -{ - - -} - diff --git a/src/Plugins/ExternalAuth.OpenId/Views/Web.config b/src/Plugins/ExternalAuth.OpenId/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/ExternalAuth.OpenId/icon.png b/src/Plugins/ExternalAuth.OpenId/icon.png deleted file mode 100644 index 2ee4df21ca..0000000000 Binary files a/src/Plugins/ExternalAuth.OpenId/icon.png and /dev/null differ diff --git a/src/Plugins/ExternalAuth.OpenId/packages.config b/src/Plugins/ExternalAuth.OpenId/packages.config deleted file mode 100644 index 6617b15446..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/packages.config +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.OpenId/web.config b/src/Plugins/ExternalAuth.OpenId/web.config deleted file mode 100644 index 0162400634..0000000000 --- a/src/Plugins/ExternalAuth.OpenId/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Feed.Froogle/Content/smartstore.feed.froogle.css b/src/Plugins/Feed.Froogle/Content/smartstore.feed.froogle.css deleted file mode 100644 index 3c4b0af7b7..0000000000 --- a/src/Plugins/Feed.Froogle/Content/smartstore.feed.froogle.css +++ /dev/null @@ -1,10 +0,0 @@ -.config-logo { - width: 274px; - height: 31px; -} -.edit-taxonomy { - min-width: 460px; -} -.google-product-search { - margin-bottom: 8px !important; -} \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Controllers/FeedFroogleController.cs b/src/Plugins/Feed.Froogle/Controllers/FeedFroogleController.cs deleted file mode 100644 index c801bb8b58..0000000000 --- a/src/Plugins/Feed.Froogle/Controllers/FeedFroogleController.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Web.Mvc; -using SmartStore.Plugin.Feed.Froogle.Models; -using SmartStore.Plugin.Feed.Froogle.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Security; -using SmartStore.Web.Framework.Controllers; -using Telerik.Web.Mvc; - -namespace SmartStore.Plugin.Feed.Froogle.Controllers -{ - public class FeedFroogleController : PluginControllerBase - { - private readonly IGoogleFeedService _googleService; - private readonly ISettingService _settingService; - private readonly IPermissionService _permissionService; - - public FeedFroogleController( - IGoogleFeedService googleService, - ISettingService settingService, - IPermissionService permissionService) - { - _googleService = googleService; - _settingService = settingService; - _permissionService = permissionService; - } - - private ActionResult RedirectToConfig() - { - return RedirectToAction("ConfigureMiscPlugin", "Plugin", new { systemName = _googleService.Helper.SystemName, area = "Admin" }); - } - - public ActionResult Configure() - { - var model = new FeedFroogleModel(); - model.Copy(_googleService.Settings, true); - - if (TempData["GenerateFeedRunning"] != null) - model.IsRunning = (bool)TempData["GenerateFeedRunning"]; - - _googleService.SetupModel(model); - - return View( model); - } - - [HttpPost] - [FormValueRequired("save")] - public ActionResult Configure(FeedFroogleModel model) - { - if (!ModelState.IsValid) - return Configure(); - - model.Copy(_googleService.Settings, false); - _settingService.SaveSetting(_googleService.Settings); - - _googleService.Helper.UpdateScheduleTask(model.TaskEnabled, model.GenerateStaticFileEachMinutes * 60); - - NotifySuccess(_googleService.Helper.GetResource("ConfigSaveNote"), true); - - _googleService.SetupModel(model); - - return View(model); - } - - public ActionResult GenerateFeed() - { - if (!_permissionService.Authorize(StandardPermissionProvider.ManageScheduleTasks)) - return AccessDeniedView(); - - if (_googleService.Helper.RunScheduleTask()) - TempData["GenerateFeedRunning"] = true; - - return RedirectToConfig(); - } - - [HttpPost] - public ActionResult GenerateFeedProgress() - { - string message = _googleService.Helper.GetProgressInfo(true); - return Json(new { message = message }, JsonRequestBehavior.DenyGet); - } - - public ActionResult DeleteFiles() - { - _googleService.Helper.DeleteFeedFiles(); - - return RedirectToConfig(); - } - - [HttpPost] - public ActionResult GoogleProductEdit(int pk, string name, string value) - { - _googleService.UpdateInsert(pk, name, value); - - return this.Content(""); - } - - [HttpPost, GridAction(EnableCustomBinding = true)] - public ActionResult GoogleProductList(GridCommand command, string searchProductName, string touched) - { - return new JsonResult - { - Data = _googleService.GetGridModel(command, searchProductName, touched) - }; - } - } -} diff --git a/src/Plugins/Feed.Froogle/Data/GoogleProductRecordMap.cs b/src/Plugins/Feed.Froogle/Data/GoogleProductRecordMap.cs deleted file mode 100644 index 489fb99e6f..0000000000 --- a/src/Plugins/Feed.Froogle/Data/GoogleProductRecordMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Data.Entity.ModelConfiguration; -using SmartStore.Plugin.Feed.Froogle.Domain; - -namespace SmartStore.Plugin.Feed.Froogle.Data -{ - public partial class GoogleProductRecordMap : EntityTypeConfiguration - { - public GoogleProductRecordMap() - { - this.ToTable("GoogleProduct"); - this.HasKey(x => x.Id); - } - } -} \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Data/Migrations/Configuration.cs b/src/Plugins/Feed.Froogle/Data/Migrations/Configuration.cs deleted file mode 100644 index 11974f40e2..0000000000 --- a/src/Plugins/Feed.Froogle/Data/Migrations/Configuration.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace SmartStore.Plugin.Feed.Froogle.Data.Migrations -{ - using System; - using System.Data.Entity; - using System.Data.Entity.Migrations; - using System.Linq; - - internal sealed class Configuration : DbMigrationsConfiguration - { - public Configuration() - { - AutomaticMigrationsEnabled = false; - MigrationsDirectory = @"Data\Migrations"; - ContextKey = "SmartStore.FeedGoogle"; - } - - protected override void Seed(GoogleProductObjectContext context) - { - // This method will be called after migrating to the latest version. - - // You can use the DbSet.AddOrUpdate() helper extension method - // to avoid creating duplicate seed data. E.g. - // - // context.People.AddOrUpdate( - // p => p.FullName, - // new Person { FullName = "Andrew Peters" }, - // new Person { FullName = "Brice Lambson" }, - // new Person { FullName = "Rowan Miller" } - // ); - // - } - } -} diff --git a/src/Plugins/Feed.Froogle/DependencyRegistrar.cs b/src/Plugins/Feed.Froogle/DependencyRegistrar.cs deleted file mode 100644 index a7126c1809..0000000000 --- a/src/Plugins/Feed.Froogle/DependencyRegistrar.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Autofac; -using Autofac.Core; -using Autofac.Integration.Mvc; -using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Data; -using SmartStore.Plugin.Feed.Froogle.Data; -using SmartStore.Plugin.Feed.Froogle.Domain; -using SmartStore.Plugin.Feed.Froogle.Services; - -namespace SmartStore.Plugin.Feed.Froogle -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().InstancePerRequest(); - - //register named context - builder.Register(c => new GoogleProductObjectContext(DataSettings.Current.DataConnectionString)) - .Named(GoogleProductObjectContext.ALIASKEY) - .InstancePerRequest(); - - builder.Register(c => new GoogleProductObjectContext(DataSettings.Current.DataConnectionString)) - .InstancePerRequest(); - - //override required repository with our custom context - builder.RegisterType>() - .As>() - .WithParameter(ResolvedParameter.ForNamed(GoogleProductObjectContext.ALIASKEY)) - .InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/Feed.Froogle/Description.txt b/src/Plugins/Feed.Froogle/Description.txt deleted file mode 100644 index a3e4ef8e71..0000000000 --- a/src/Plugins/Feed.Froogle/Description.txt +++ /dev/null @@ -1,8 +0,0 @@ -FriendlyName: Google Merchant Center (GMC) -SystemName: PromotionFeed.Froogle -Version: 2.22 -MinAppVersion: 2.0.0 -Author: SmartStore AG -DisplayOrder: 1 -FileName: SmartStore.Plugin.Feed.Froogle.dll -ResourceRootKey: Plugins.Feed.Froogle \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Domain/GoogleProductRecord.cs b/src/Plugins/Feed.Froogle/Domain/GoogleProductRecord.cs deleted file mode 100644 index 5fbf16c7a2..0000000000 --- a/src/Plugins/Feed.Froogle/Domain/GoogleProductRecord.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using SmartStore.Core; - -namespace SmartStore.Plugin.Feed.Froogle.Domain -{ - /// - /// Represents a Google product record - /// - public partial class GoogleProductRecord : BaseEntity - { - public int ProductId { get; set; } - - public string Taxonomy { get; set; } - public string Gender { get; set; } - public string AgeGroup { get; set; } - public string Color { get; set; } - public string Size { get; set; } - public string Material { get; set; } - public string Pattern { get; set; } - public string ItemGroupId { get; set; } - - public bool IsTouched { get; set; } - public DateTime CreatedOnUtc { get; set; } - public DateTime UpdatedOnUtc { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Extensions/MiscExtensions.cs b/src/Plugins/Feed.Froogle/Extensions/MiscExtensions.cs deleted file mode 100644 index 313a4d91f4..0000000000 --- a/src/Plugins/Feed.Froogle/Extensions/MiscExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Web.Mvc; - -namespace SmartStore.Plugin.Feed.Froogle -{ - public static class MiscExtensions - { - public static string XEditableLink(this HtmlHelper hlp, string fieldName, string type) - { - string displayText = null; - - if (fieldName == "Gender" || fieldName == "AgeGroup") - displayText = "<#= {0}Localize #>".FormatWith(fieldName); - else - displayText = "<#= {0} #>".FormatWith(fieldName); - - string skeleton = - "\" class=\"edit-link-{1}\"" + - " data-pk=\"<#= ProductId #>\" data-name=\"{0}\" data-value=\"<#= {0} #>\" data-inputclass=\"edit-{1}\" data-type=\"{2}\">" + - "{3}"; - - return skeleton.FormatWith(fieldName, fieldName.ToLower(), type, displayText); - } - } -} diff --git a/src/Plugins/Feed.Froogle/Files/taxonomy.de-DE.txt b/src/Plugins/Feed.Froogle/Files/taxonomy.de-DE.txt deleted file mode 100644 index c21aaa3e62..0000000000 --- a/src/Plugins/Feed.Froogle/Files/taxonomy.de-DE.txt +++ /dev/null @@ -1,6168 +0,0 @@ -Baby & Kleinkind -Baby & Kleinkind > Baby baden -Baby & Kleinkind > Baby baden > Babybadewannen -Baby & Kleinkind > Baby baden > Shampoo-Schutzschilder -Baby & Kleinkind > Babygesundheit -Baby & Kleinkind > Babygesundheit > Baby-Gesundheits- & Pflege-Sets -Baby & Kleinkind > Babygesundheit > Nasensauger -Baby & Kleinkind > Babygesundheit > Reinigungstücher für Schnuller -Baby & Kleinkind > Babygesundheit > Schnuller & Beißringe -Baby & Kleinkind > Babygesundheit > Schnullerclips & -ketten -Baby & Kleinkind > Babysicherheit -Baby & Kleinkind > Babysicherheit > Baby- & Haustierschutzgitter -Baby & Kleinkind > Babysicherheit > Baby-Schutzleisten -Baby & Kleinkind > Babysicherheit > Babyfone -Baby & Kleinkind > Babysicherheit > Babysicherheitsgurte & -leinen -Baby & Kleinkind > Babysicherheit > Babysicherungen & Schutzvorrichtungen -Baby & Kleinkind > Babysicherheit > Zubehör für Baby- & Haustierschutzgitter -Baby & Kleinkind > Babyspielwaren -Baby & Kleinkind > Babyspielwaren > ABC-Lernspielzeuge -Baby & Kleinkind > Babyspielwaren > Baby-Activity-Spielzeug -Baby & Kleinkind > Babyspielwaren > Baby-Mobile-Zubehör -Baby & Kleinkind > Babyspielwaren > Baby-Mobiles -Baby & Kleinkind > Babyspielwaren > Babylauflernhilfen -Baby & Kleinkind > Babyspielwaren > Babyrasseln -Baby & Kleinkind > Babyspielwaren > Babyschaukeln & Türhopser -Baby & Kleinkind > Babyspielwaren > Babywippen -Baby & Kleinkind > Babyspielwaren > Lauf- & Spielgitter -Baby & Kleinkind > Babyspielwaren > Schnuller und Beruhigung -Baby & Kleinkind > Babyspielwaren > Sortier-, Stapel- & Steckspielzeug -Baby & Kleinkind > Babyspielwaren > Spiel- & Krabbeldecken -Baby & Kleinkind > Babyspielwaren > Zieh- & Schiebespielzeug -Baby & Kleinkind > Babytransport -Baby & Kleinkind > Babytransport > Baby- & Kleinkindautositze -Baby & Kleinkind > Babytransport > Babytragen -Baby & Kleinkind > Babytransport > Kinderwagen -Baby & Kleinkind > Babytransportzubehör -Baby & Kleinkind > Babytransportzubehör > Einkaufswagen- & Hochstuhlbezüge -Baby & Kleinkind > Babytransportzubehör > Zubehör für Baby- & Kleinkindautositze -Baby & Kleinkind > Babytransportzubehör > Zubehör für Babytragen -Baby & Kleinkind > Babytransportzubehör > Zubehör für Kinderwagen -Baby & Kleinkind > Geschenksets für Babys und Kleinkinder -Baby & Kleinkind > Stillen & Füttern -Baby & Kleinkind > Stillen & Füttern > Baby-Spucktücher -Baby & Kleinkind > Stillen & Füttern > Babyflaschen -Baby & Kleinkind > Stillen & Füttern > Babypflege-Timer -Baby & Kleinkind > Stillen & Füttern > Flaschenwärmer & Sterilisatoren -Baby & Kleinkind > Stillen & Füttern > Lerntassen -Baby & Kleinkind > Stillen & Füttern > Lätzchen -Baby & Kleinkind > Stillen & Füttern > Milchpumpen -Baby & Kleinkind > Stillen & Füttern > Muttermilchbehälter -Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder -Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Baby-Snacks -Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Babymüsli -Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Babynahrung -Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Babysäfte -Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Milchnahrung -Baby & Kleinkind > Stillen & Füttern > Sauger für Babyflaschen -Baby & Kleinkind > Stillen & Füttern > Stilleinlagen -Baby & Kleinkind > Stillen & Füttern > Stillhütchen -Baby & Kleinkind > Stillen & Füttern > Stillkissen -Baby & Kleinkind > Stillen & Füttern > Stilltücher -Baby & Kleinkind > Töpfchentraining -Baby & Kleinkind > Töpfchentraining > Töpfchen -Baby & Kleinkind > Töpfchentraining > Töpfchentrainingsets -Baby & Kleinkind > Wickelbedarf -Baby & Kleinkind > Wickelbedarf > Baby-Reinigungstücher -Baby & Kleinkind > Wickelbedarf > Behandlung von Windeldermatitis -Baby & Kleinkind > Wickelbedarf > Behälter & Warmhalter für Baby-Reinigungstücher -Baby & Kleinkind > Wickelbedarf > Wickelauflagen -Baby & Kleinkind > Wickelbedarf > Windel-Organizer -Baby & Kleinkind > Wickelbedarf > Windelbeutel -Baby & Kleinkind > Wickelbedarf > Windeleimer -Baby & Kleinkind > Wickelbedarf > Windeleimerzubehör -Baby & Kleinkind > Wickelbedarf > Windeleinlagen -Baby & Kleinkind > Wickelbedarf > Windeln -Baby & Kleinkind > Wickelbedarf > Windelsets -Baby & Kleinkind > Wickeldecken -Bekleidung & Accessoires -Bekleidung & Accessoires > Bekleidung -Bekleidung & Accessoires > Bekleidung > Anzüge -Bekleidung & Accessoires > Bekleidung > Anzüge > Hosenanzüge -Bekleidung & Accessoires > Bekleidung > Anzüge > Kostüme -Bekleidung & Accessoires > Bekleidung > Anzüge > Smokings -Bekleidung & Accessoires > Bekleidung > Anzüge > Westen & Sakkos -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby- & Kleinkind-Kombis -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby- & Kleinkind-Oberbekleidung -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby- & Kleinkindsocken -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby-Bodies -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby-Schlafkleidung & -Schlafsäcke -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Babyüberhosen -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Bademode für Babys & Kleinkinder -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Kleider für Babys & Kleinkinder -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Kleinkindunterwäsche -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Oberteile für Babys & Kleinkinder -Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Unterteile für Babys & Kleinkinder -Bekleidung & Accessoires > Bekleidung > Bademode -Bekleidung & Accessoires > Bekleidung > Bademode > Badeshorts -Bekleidung & Accessoires > Bekleidung > Bademode > Badeslips -Bekleidung & Accessoires > Bekleidung > Bademode > Bikini Oberteile -Bekleidung & Accessoires > Bekleidung > Bademode > Bikini Unterteile -Bekleidung & Accessoires > Bekleidung > Bademode > Bikinis -Bekleidung & Accessoires > Bekleidung > Bademode > Einteiler-Badeanzüge -Bekleidung & Accessoires > Bekleidung > Bademode > Strandkleider -Bekleidung & Accessoires > Bekleidung > Bademode > Tankinis -Bekleidung & Accessoires > Bekleidung > Brautmoden -Bekleidung & Accessoires > Bekleidung > Brautmoden > Brautjungfernkleider -Bekleidung & Accessoires > Bekleidung > Brautmoden > Brautkleider -Bekleidung & Accessoires > Bekleidung > Einteiler -Bekleidung & Accessoires > Bekleidung > Einteiler > Latzhosen -Bekleidung & Accessoires > Bekleidung > Einteiler > Overalls -Bekleidung & Accessoires > Bekleidung > Einteiler > Turn- & Gymnastikanzüge -Bekleidung & Accessoires > Bekleidung > Hosen -Bekleidung & Accessoires > Bekleidung > Hosen > Anzughosen -Bekleidung & Accessoires > Bekleidung > Hosen > Cargo-Hosen -Bekleidung & Accessoires > Bekleidung > Hosen > Cordhosen -Bekleidung & Accessoires > Bekleidung > Hosen > Jeans -Bekleidung & Accessoires > Bekleidung > Hosen > Khakihosen -Bekleidung & Accessoires > Bekleidung > Hosen > Leder- & Wildlederhosen -Bekleidung & Accessoires > Bekleidung > Hosen > Leggings -Bekleidung & Accessoires > Bekleidung > Hosen > Leinenhosen -Bekleidung & Accessoires > Bekleidung > Kleider -Bekleidung & Accessoires > Bekleidung > Kleider > Abend- & Ballkleider -Bekleidung & Accessoires > Bekleidung > Kleider > Alltagskleider -Bekleidung & Accessoires > Bekleidung > Kleider > Cocktail- & Partykleider -Bekleidung & Accessoires > Bekleidung > Kleider > Kleines Schwarzes -Bekleidung & Accessoires > Bekleidung > Kombinationen -Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear -Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Bademäntel -Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Loungewear -Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Nachthemden -Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Schlafanzüge -Bekleidung & Accessoires > Bekleidung > Röcke -Bekleidung & Accessoires > Bekleidung > Shirts & Tops -Bekleidung & Accessoires > Bekleidung > Shirts & Tops > Fantrikots -Bekleidung & Accessoires > Bekleidung > Shirts & Tops > Hemden & Blusen -Bekleidung & Accessoires > Bekleidung > Shirts & Tops > Leibchen -Bekleidung & Accessoires > Bekleidung > Shirts & Tops > Poloshirts -Bekleidung & Accessoires > Bekleidung > Shirts & Tops > Sweater & Strickjacken -Bekleidung & Accessoires > Bekleidung > Shirts & Tops > Sweatshirts -Bekleidung & Accessoires > Bekleidung > Shirts & Tops > T-Shirts -Bekleidung & Accessoires > Bekleidung > Shorts -Bekleidung & Accessoires > Bekleidung > Shorts > Bermudashorts -Bekleidung & Accessoires > Bekleidung > Shorts > Cargo-Shorts -Bekleidung & Accessoires > Bekleidung > Shorts > Hot Pants -Bekleidung & Accessoires > Bekleidung > Skorts -Bekleidung & Accessoires > Bekleidung > Sportbekleidung -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > American Football-Hosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Boxshorts -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Gymnastik- & Ballettanzüge -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung > Ghillie-Anzüge -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung > Jagd- & taktische Hosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung > Jagd- & taktische Westen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Kampfsporthosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Lange Unterhosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung > Motorrad-Kombis -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung > Motorradhosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung > Motorradjacken -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Paintballbekleidung -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradhosen (kurz) -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradhosen (lang) -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradtrikots -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradträgerhosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Radsport-Zeitfahranzüge -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Saunaanzüge -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Schneehosen und - anzüge -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sport-Tanktops -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sporthosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sporthosen (kurz) -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportjacken -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportjacken > Windbreakers -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportkleider -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportröcke -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportshirts -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportunterkleidung -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportunterkleidung > Kompressionshose (kurz) -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportunterkleidung > Sport-BHs -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportunterkleidung > Sportunterwäsche -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Sportunterkleidung > Suspensorien -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Tanzkleidung -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Tanzkleidung > Tanz-Leggings -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Tanzkleidung > Tanz-Oberteile -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Tanzkleidung > Tanzhosen -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Tanzkleidung > Tanzkleider -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Tanzkleidung > Tanzröcke -Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Trainingsanzüge -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Dirndl -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Hakama-Hosen -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimono-Oberbekleidung -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimono-Oberbekleidung > Haori-Jacken -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimono-Oberbekleidung > Kimono-Mäntel -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos > Furisode-Kimonos -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos > Hochzeitskimonos -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos > Informelle Kimonos -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos > Iromuji-Kimonos -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos > Komon-Kimonos -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos > Tomesode- & Houmongi-Kimonos -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Religiöse Festkleidung -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Trachten Lederhosen -Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Yukata -Bekleidung & Accessoires > Bekleidung > Uniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Arbeitshosen -Bekleidung & Accessoires > Bekleidung > Uniformen > Fliegeruniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Militäruniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Schuluniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sicherheitsdienst-Bekleidung -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > American Football-Uniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Baseballuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Basketballuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Cheerleading-Uniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Fußballuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Hockeyuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Kampfsportuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Kricketuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Ringeruniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Schiedsrichteruniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Softballuniformen -Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe -Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe > Hosen für Köche -Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe > Hüte für Köche -Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe > Kochjacken -Bekleidung & Accessoires > Bekleidung > Uniformen > Ärztekittel -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > BH-Einlagen -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > BH-Träger & -Erweiterungen -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > BH-Träger-Pads -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > Brustaufkleber & -Concealer -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Büstenhalter -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Büstenhalter > Still-BHs -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous-Accessoires -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous-Accessoires > Strumpfbänder -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous-Accessoires > Strumpfhalter -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Hochzeitsdessous -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Petticoats & Rüschenhöschen -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Shapewear -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Socken -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Strumpfhosen -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Unterhemden -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Unterhosen -Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Unterwäsche -Bekleidung & Accessoires > Bekleidung > Überbekleidung -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Chaps -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Anoraks -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Boleros -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Capes & Ponchos -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > College Jacken -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Daunenjacken -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Fleecejacken -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Jeansjacken -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Leder- & Wildlederjacken -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Overcoats -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Pelzmäntel -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Sakkos -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Trenchcoats -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken > Tweedjacken -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Regenbekleidung -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Regenbekleidung > Regenanzüge -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Regenbekleidung > Regenhosen -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Regenbekleidung > Regenmäntel -Bekleidung & Accessoires > Bekleidung > Überbekleidung > Westen -Bekleidung & Accessoires > Bekleidungsaccessoires -Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung -Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung > Kimono-Unterkleidung -Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung > Obi-Accessoires -Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung > Obis -Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung > Tabi-Socken -Bekleidung & Accessoires > Bekleidungsaccessoires > Ansteckbuttons -Bekleidung & Accessoires > Bekleidungsaccessoires > Arm- & Beinstulpen -Bekleidung & Accessoires > Bekleidungsaccessoires > Arm- & Beinstulpen > Armstulpen -Bekleidung & Accessoires > Bekleidungsaccessoires > Arm- & Beinstulpen > Beinstulpen -Bekleidung & Accessoires > Bekleidungsaccessoires > Bandanas & Stofftücher -Bekleidung & Accessoires > Bekleidungsaccessoires > Braut-Accessoires -Bekleidung & Accessoires > Bekleidungsaccessoires > Braut-Accessoires > Brautschleier -Bekleidung & Accessoires > Bekleidungsaccessoires > Einstecktücher -Bekleidung & Accessoires > Bekleidungsaccessoires > Fächer -Bekleidung & Accessoires > Bekleidungsaccessoires > Gürtel -Bekleidung & Accessoires > Bekleidungsaccessoires > Gürtelschnallen -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Diademe -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haargabeln -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haargummis -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarklammern -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarkränze -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarkämme -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarnadeln & -clips -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarnetze -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarverlängerungen -Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Stirnbänder -Bekleidung & Accessoires > Bekleidungsaccessoires > Halswärmer -Bekleidung & Accessoires > Bekleidungsaccessoires > Handschuhe & Fausthandschuhe -Bekleidung & Accessoires > Bekleidungsaccessoires > Handschuhe & Fausthandschuhe > Abendhandschuhe -Bekleidung & Accessoires > Bekleidungsaccessoires > Handschuhe & Fausthandschuhe > Fausthandschuhe -Bekleidung & Accessoires > Bekleidungsaccessoires > Handschuhe & Fausthandschuhe > Handschuhe -Bekleidung & Accessoires > Bekleidungsaccessoires > Handschuhe & Fausthandschuhe > Ski- & Snowboardhandschuhe -Bekleidung & Accessoires > Bekleidungsaccessoires > Hosenträger -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Barette -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Cowboyhüte -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Filzhüte -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Kappen -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Kappen > Ballonmützen -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Kappen > Baseballmützen -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Melonen (Hut) -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Mützen -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Schirmhüte -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Sonnenhüte -Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte > Sonnenvisiere -Bekleidung & Accessoires > Bekleidungsaccessoires > Knopfnieten -Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher -Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher > Fascinators -Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher > Kopfschmuck -Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher > Turbane -Bekleidung & Accessoires > Bekleidungsaccessoires > Kragenstäbchen -Bekleidung & Accessoires > Bekleidungsaccessoires > Krawatten -Bekleidung & Accessoires > Bekleidungsaccessoires > Krawatten > Ascotkrawatte -Bekleidung & Accessoires > Bekleidungsaccessoires > Krawatten > Bolotie -Bekleidung & Accessoires > Bekleidungsaccessoires > Krawatten > Fliegen -Bekleidung & Accessoires > Bekleidungsaccessoires > Krawatten > Schlipse -Bekleidung & Accessoires > Bekleidungsaccessoires > Krawattennadeln -Bekleidung & Accessoires > Bekleidungsaccessoires > Leis -Bekleidung & Accessoires > Bekleidungsaccessoires > Manschettenknöpfe -Bekleidung & Accessoires > Bekleidungsaccessoires > Muffe -Bekleidung & Accessoires > Bekleidungsaccessoires > Ohrenschützer -Bekleidung & Accessoires > Bekleidungsaccessoires > Schals & Halstücher -Bekleidung & Accessoires > Bekleidungsaccessoires > Schleier -Bekleidung & Accessoires > Bekleidungsaccessoires > Schweißbänder -Bekleidung & Accessoires > Bekleidungsaccessoires > Sonnenbrillen -Bekleidung & Accessoires > Bekleidungsaccessoires > Sturmhauben -Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung -Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Baby- & Kleinkindhandschuhe -Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Babyschutzbekleidung -Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Gürtel für Babys & Kleinkinder -Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Kopfbedeckungen für Babys & Kleinkinder -Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires -Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Brieftaschenketten -Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Scheckheftetuis -Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Schlüsselanhänger -Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Tragebänder -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Ausweistaschen -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Geldbeutel & Geldklammern -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen > Clutches & Taschen für besondere Anlässe -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen > Henkeltaschen -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen > Hobo-Handtaschen -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen > Schultertaschen -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen > Tragetaschen -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen > Umhängetaschen -Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Visitenkartenetuis -Bekleidung & Accessoires > Kostüme & Accessoires -Bekleidung & Accessoires > Kostüme & Accessoires > Accessoires für Perücken -Bekleidung & Accessoires > Kostüme & Accessoires > Accessoires für Perücken > Kappen für Perücken -Bekleidung & Accessoires > Kostüme & Accessoires > Accessoires für Perücken > Kleber für Perücken -Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires -Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Glatzen -Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Kostümaccessoire-Sets -Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Kostümhüte -Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Plastikschmuck -Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Umhänge für Kostüme -Bekleidung & Accessoires > Kostüme & Accessoires > Kostüme & Verkleidungen -Bekleidung & Accessoires > Kostüme & Accessoires > Kostümschuhe -Bekleidung & Accessoires > Kostüme & Accessoires > Masken -Bekleidung & Accessoires > Kostüme & Accessoires > Perücken -Bekleidung & Accessoires > Schmuck -Bekleidung & Accessoires > Schmuck > Armbanduhren -Bekleidung & Accessoires > Schmuck > Armbanduhren > Analoguhren -Bekleidung & Accessoires > Schmuck > Armbanduhren > Digitaluhren -Bekleidung & Accessoires > Schmuck > Armbänder -Bekleidung & Accessoires > Schmuck > Broschen & Anstecknadeln -Bekleidung & Accessoires > Schmuck > Charms & Anhänger -Bekleidung & Accessoires > Schmuck > Edelsteine -Bekleidung & Accessoires > Schmuck > Edelsteine > Diamanten -Bekleidung & Accessoires > Schmuck > Fußkettchen -Bekleidung & Accessoires > Schmuck > Halsketten -Bekleidung & Accessoires > Schmuck > Körperschmuck -Bekleidung & Accessoires > Schmuck > Ohrringe -Bekleidung & Accessoires > Schmuck > Ringe -Bekleidung & Accessoires > Schmuck > Schmucksets -Bekleidung & Accessoires > Schmuck > Uhrenaccessoires -Bekleidung & Accessoires > Schmuck > Uhrenaccessoires > Aufkleber für Uhren -Bekleidung & Accessoires > Schmuck > Uhrenaccessoires > Uhrenarmbänder -Bekleidung & Accessoires > Schmuck > Uhrenaccessoires > Uhrenbeweger -Bekleidung & Accessoires > Schuh-Accessoires -Bekleidung & Accessoires > Schuh-Accessoires > Gamaschen -Bekleidung & Accessoires > Schuh-Accessoires > Schnürsenkel -Bekleidung & Accessoires > Schuh-Accessoires > Sporen -Bekleidung & Accessoires > Schuh-Accessoires > Stiefelsocken -Bekleidung & Accessoires > Schuh-Accessoires > Überschuhe -Bekleidung & Accessoires > Schuhe -Bekleidung & Accessoires > Schuhe > Abendschuhe & Anzugschuhe -Bekleidung & Accessoires > Schuhe > Abendschuhe & Anzugschuhe > Brautschuhe -Bekleidung & Accessoires > Schuhe > Abendschuhe & Anzugschuhe > Pumps -Bekleidung & Accessoires > Schuhe > Abendschuhe & Anzugschuhe > Pumps > Klassische Pumps -Bekleidung & Accessoires > Schuhe > Abendschuhe & Anzugschuhe > Pumps > Spectator-Pumps -Bekleidung & Accessoires > Schuhe > Abendschuhe & Anzugschuhe > Pumps > d'Orsay Pumps -Bekleidung & Accessoires > Schuhe > Abendschuhe & Anzugschuhe > Schnürschuhe -Bekleidung & Accessoires > Schuhe > Clogs & Pantoletten -Bekleidung & Accessoires > Schuhe > Espadrilles -Bekleidung & Accessoires > Schuhe > Flache Schuhe -Bekleidung & Accessoires > Schuhe > Hausschuhe -Bekleidung & Accessoires > Schuhe > Loafers -Bekleidung & Accessoires > Schuhe > Mokassins -Bekleidung & Accessoires > Schuhe > Outdoor Schuhe -Bekleidung & Accessoires > Schuhe > Outdoor Schuhe > Angel- & Jagdschuhe -Bekleidung & Accessoires > Schuhe > Outdoor Schuhe > Gartenschuhe -Bekleidung & Accessoires > Schuhe > Outdoor Schuhe > Kletterschuhe -Bekleidung & Accessoires > Schuhe > Outdoor Schuhe > Leistungsruderschuhe -Bekleidung & Accessoires > Schuhe > Outdoor Schuhe > Wanderschuhe -Bekleidung & Accessoires > Schuhe > Outdoor Schuhe > Wassersportschuhe -Bekleidung & Accessoires > Schuhe > Sandalen -Bekleidung & Accessoires > Schuhe > Sandalen > Flipflops -Bekleidung & Accessoires > Schuhe > Sandalen > Outdoor Sandalen/vorne geschlossen -Bekleidung & Accessoires > Schuhe > Sandalen > Schlupfsandalen -Bekleidung & Accessoires > Schuhe > Schuhe für Babys & Kleinkinder -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sneakers -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sneakers > Fitness-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sneakers > Laufschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sneakers > Sneakers & Freizeitschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sneakers > Walking-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Ballet- & Tanzschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Basketball-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Bowlingschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Boxschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Cheerleading-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Fahrradschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Gewichtheberschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Golfschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Hallenfussballschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Hallenschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Hallenschuhe > Badmintonschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Hallenschuhe > Handballschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Hallenschuhe > Volleyball-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Ringerschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Skateboard-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Tennis-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Sportschuhe > Tischtennis-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Stollen- & Nockenschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Stollen- & Nockenschuhe > American Football-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Stollen- & Nockenschuhe > Baseball- & Softballschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Stollen- & Nockenschuhe > Fußballschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Stollen- & Nockenschuhe > Lacrosse-Stollenschuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Stollen- & Nockenschuhe > Rugby-Schuhe -Bekleidung & Accessoires > Schuhe > Sportschuhe & Sneakers > Stollen- & Nockenschuhe > Spikes -Bekleidung & Accessoires > Schuhe > Stiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Arbeits- & Sicherheitsstiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Gefütterte Stiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Gummistiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Motorradstiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Reitstiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Schneestiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Stiefeletten -Bekleidung & Accessoires > Schuhe > Stiefel > Western-Stiefel -Bekleidung & Accessoires > Schuhe > Stiefel > Wüsten- & Chukka-Boots -Bürobedarf -Bürobedarf > Ablage & Organisation -Bürobedarf > Ablage & Organisation > Adressbücher -Bürobedarf > Ablage & Organisation > Akten- & Schreibmappen -Bürobedarf > Ablage & Organisation > Aktenaufbewahrungsboxen -Bürobedarf > Ablage & Organisation > Aktenhüllen und Klemmhefter -Bürobedarf > Ablage & Organisation > Bindesysteme -Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordner -Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör -Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör > Einbandringe -Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör > Klarsichthüllen -Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör > Registerblätter -Bürobedarf > Ablage & Organisation > Bindesysteme > Bindegeräte -Bürobedarf > Ablage & Organisation > Bindesysteme > Binderücken -Bürobedarf > Ablage & Organisation > CD-/DVD-Ordnungssysteme -Bürobedarf > Ablage & Organisation > CD-/DVD-Ordnungssysteme > CD- & DVD-Verpackungen -Bürobedarf > Ablage & Organisation > CD-/DVD-Ordnungssysteme > CD/DVD-Hüllen -Bürobedarf > Ablage & Organisation > CD-/DVD-Ordnungssysteme > CD/DVD-Taschen & -Sonnenblendentaschen -Bürobedarf > Ablage & Organisation > Federmappen -Bürobedarf > Ablage & Organisation > Geldkassetten -Bürobedarf > Ablage & Organisation > Kalender, Organizer & Zeitplaner -Bürobedarf > Ablage & Organisation > Karteikästen -Bürobedarf > Ablage & Organisation > Kartenhüllen -Bürobedarf > Ablage & Organisation > Laminieren -Bürobedarf > Ablage & Organisation > Laminieren > Laminierfolie, Schutzhüllen -Bürobedarf > Ablage & Organisation > Laminieren > Laminiergeräte -Bürobedarf > Ablage & Organisation > Postkartenorganizer -Bürobedarf > Ablage & Organisation > Postsortiersysteme -Bürobedarf > Ablage & Organisation > Register- & Hängemappen -Bürobedarf > Ablage & Organisation > Rezeptkästen -Bürobedarf > Ablage & Organisation > Schreibtischorganizer -Bürobedarf > Ablage & Organisation > Schreibtischorganizer > Ablagekästen -Bürobedarf > Ablage & Organisation > Staufächer und -schränke -Bürobedarf > Ablage & Organisation > Visitenkarten-Ständer -Bürobedarf > Ablage & Organisation > Visitenkartenbücher -Bürobedarf > Bücherzubehör -Bürobedarf > Bücherzubehör > Bucheinbände -Bürobedarf > Bücherzubehör > Buchständer & -stützen -Bürobedarf > Bücherzubehör > Leselampen -Bürobedarf > Bücherzubehör > Lesezeichen -Bürobedarf > Büroarbeitsmittel -Bürobedarf > Büroarbeitsmittel > Bleistiftspitzer -Bürobedarf > Büroarbeitsmittel > Heftgeräte -Bürobedarf > Büroarbeitsmittel > Heftklammernzieher -Bürobedarf > Büroarbeitsmittel > Klemmbretter -Bürobedarf > Büroarbeitsmittel > Lineale -Bürobedarf > Büroarbeitsmittel > Lupen -Bürobedarf > Büroarbeitsmittel > Scheren -Bürobedarf > Büroarbeitsmittel > Schreibgeräte -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Bleistifte -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Bleistifte > Schreibbleistifte -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Bleistifte > Zeichenbleistifte & Buntstifte -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Füller- & Bleistift-Sets -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Multifunktions-Schreibgeräte -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Schreibstifte, Kugelschreiber & Füller -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Markierstifte & Textmarker -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Pastellkreiden -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Tafelkreide -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Wachsmalstifte -Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Zeichenkohle -Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör -Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör > Bleistiftminen -Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör > Füllertinte & -patronen -Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör > Kugelschreiberminen -Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör > Marker-Nachfülltinte -Bürobedarf > Büroarbeitsmittel > Stempel -Bürobedarf > Büroarbeitsmittel > Stempel > Bürostempel -Bürobedarf > Büroarbeitsmittel > Stempel > Motivstempel -Bürobedarf > Büroarbeitsmittel > Tischglocken -Bürobedarf > Bürogeräte -Bürobedarf > Bürogeräte > Aktenvernichter -Bürobedarf > Bürogeräte > Diktiergeräte & Geräte zur Transkription -Bürobedarf > Bürogeräte > Elektronische Wörterbücher & Übersetzungsgeräte -Bürobedarf > Bürogeräte > Etikettendrucker -Bürobedarf > Bürogeräte > Frankiermaschinen -Bürobedarf > Bürogeräte > Schreibmaschinen -Bürobedarf > Bürogeräte > Stempeluhren -Bürobedarf > Bürogeräte > Taschenrechner -Bürobedarf > Büromatten & Stuhlunterlagen -Bürobedarf > Büromatten & Stuhlunterlagen > Arbeitsplatzmatten -Bürobedarf > Büromatten & Stuhlunterlagen > Büromatten -Bürobedarf > Büromatten & Stuhlunterlagen > Stuhlunterlagen -Bürobedarf > Bürowagen -Bürobedarf > Bürowagen > Aktenwagen -Bürobedarf > Bürowagen > Bücherwagen -Bürobedarf > Bürowagen > Medienwagen -Bürobedarf > Bürowagen > Mehrzweckwagen -Bürobedarf > Bürowagen > Postwagen -Bürobedarf > Impulsschweißgeräte -Bürobedarf > Namensschilder -Bürobedarf > Papierbearbeitung -Bürobedarf > Papierbearbeitung > Bastelmesser -Bürobedarf > Papierbearbeitung > Blattwender -Bürobedarf > Papierbearbeitung > Briefbeschwerer -Bürobedarf > Papierbearbeitung > Locher -Bürobedarf > Papierbearbeitung > Locher > Bürolocher -Bürobedarf > Papierbearbeitung > Locher > Dekolocher -Bürobedarf > Papierbearbeitung > Papierfalzmaschinen -Bürobedarf > Papierbearbeitung > Papierrüttler -Bürobedarf > Papierbearbeitung > Papierschneider -Bürobedarf > Papierbearbeitung > Papierschneiderzubehör -Bürobedarf > Papierbearbeitung > Papierschneiderzubehör > Papierschneidetische -Bürobedarf > Papierbearbeitung > Schneidematten -Bürobedarf > Papierbearbeitung > Schreibunterlagen -Bürobedarf > Präsentationsbedarf -Bürobedarf > Präsentationsbedarf > Ausstellungstafeln -Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Hartschaumstoffplatten -Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Pinnwände -Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Plakatkartons -Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Trägerplatten -Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Zubehör für Ausstellungstafeln -Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Zubehör für Ausstellungstafeln > Dekorative Elemente für Ausstellungstafeln -Bürobedarf > Präsentationsbedarf > Dokumentenkameras -Bürobedarf > Präsentationsbedarf > Flipchart-Blöcke -Bürobedarf > Präsentationsbedarf > Flipcharts -Bürobedarf > Präsentationsbedarf > Folien -Bürobedarf > Präsentationsbedarf > Laserpointer -Bürobedarf > Präsentationsbedarf > Lesepulte -Bürobedarf > Präsentationsbedarf > Präsentationsfernbedienungen -Bürobedarf > Präsentationsbedarf > Schreibtafeln -Bürobedarf > Präsentationsbedarf > Whiteboards -Bürobedarf > Schreibwaren -Bürobedarf > Schreibwaren > Büroklammern & Papierklammern -Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder -Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Adressaufkleber -Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Klebebänder für Etikettiergeräte -Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Label Clips -Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Trennblätter -Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Versandanhänger -Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Versandaufkleber & -etiketten -Bürobedarf > Schreibwaren > Gummibänder -Bürobedarf > Schreibwaren > Heftklammern -Bürobedarf > Schreibwaren > Klebstoffe -Bürobedarf > Schreibwaren > Klebstoffe > Büroklebeband -Bürobedarf > Schreibwaren > Korrektur -Bürobedarf > Schreibwaren > Korrektur > Korrekturflüssigkeiten, Korrekturstifte & Korrekturbänder -Bürobedarf > Schreibwaren > Korrektur > Radiergummis -Bürobedarf > Schreibwaren > Musterklammern -Bürobedarf > Schreibwaren > Papierprodukte -Bürobedarf > Schreibwaren > Papierprodukte > Blanko-Ausweise -Bürobedarf > Schreibwaren > Papierprodukte > Briefpapier -Bürobedarf > Schreibwaren > Papierprodukte > Briefumschläge -Bürobedarf > Schreibwaren > Papierprodukte > Drucker- & Kopierpapier -Bürobedarf > Schreibwaren > Papierprodukte > Drucker- & Kopierpapier > Fotodruckerpapier -Bürobedarf > Schreibwaren > Papierprodukte > Feinkarton -Bürobedarf > Schreibwaren > Papierprodukte > Geschäftsformulare & -belege -Bürobedarf > Schreibwaren > Papierprodukte > Haftnotizen -Bürobedarf > Schreibwaren > Papierprodukte > Karteikarten -Bürobedarf > Schreibwaren > Papierprodukte > Kassenrollen -Bürobedarf > Schreibwaren > Papierprodukte > Notizbücher & Notizblöcke -Bürobedarf > Schreibwaren > Papierprodukte > Papier für Hefter -Bürobedarf > Schreibwaren > Papierprodukte > Postkarten -Bürobedarf > Schreibwaren > Papierprodukte > Scheckformulare -Bürobedarf > Schreibwaren > Papierprodukte > Visitenkarten -Bürobedarf > Schreibwaren > Reißzwecken & Pins -Bürobedarf > Schreibwaren > Stempelkissen & Tinten -Bürobedarf > Versandbedarf -Bürobedarf > Versandbedarf > Briefwaagen -Bürobedarf > Versandbedarf > Packband -Bürobedarf > Versandbedarf > Verpackungsmaterialien -Bürobedarf > Versandbedarf > Versandschachteln -Elektronik -Elektronik > 3D-Drucker -Elektronik > Audio -Elektronik > Audio > Audiokomponenten -Elektronik > Audio > Audiokomponenten > AV-Receiver -Elektronik > Audio > Audiokomponenten > Audiomixer -Elektronik > Audio > Audiokomponenten > Audiotransmitter -Elektronik > Audio > Audiokomponenten > Audiotransmitter > Bluetooth-Sender -Elektronik > Audio > Audiokomponenten > Audiotransmitter > FM-Transmitter -Elektronik > Audio > Audiokomponenten > Audioverstärker -Elektronik > Audio > Audiokomponenten > Audioverstärker > Kopfhörerverstärker -Elektronik > Audio > Audiokomponenten > Audioverstärker > Stereoverstärker -Elektronik > Audio > Audiokomponenten > Channel Strips -Elektronik > Audio > Audiokomponenten > DI-Boxen -Elektronik > Audio > Audiokomponenten > Kopfhörer -Elektronik > Audio > Audiokomponenten > Lautsprecher -Elektronik > Audio > Audiokomponenten > Lautsprecher > Computerlautsprecher -Elektronik > Audio > Audiokomponenten > Lautsprecher > Studiomonitore -Elektronik > Audio > Audiokomponenten > Lautsprecher > Subwoofer -Elektronik > Audio > Audiokomponenten > Mikrofone -Elektronik > Audio > Audiokomponenten > Mikrofone > Videokamera-Mikrofone -Elektronik > Audio > Audiokomponenten > Signalprozessoren -Elektronik > Audio > Audiokomponenten > Signalprozessoren > Effektprozessoren -Elektronik > Audio > Audiokomponenten > Signalprozessoren > Equalizer -Elektronik > Audio > Audiokomponenten > Signalprozessoren > Frequenzweichen -Elektronik > Audio > Audiokomponenten > Signalprozessoren > Mikrofonvorverstärker -Elektronik > Audio > Audiokomponenten > Signalprozessoren > Noise Gates & Kompressoren -Elektronik > Audio > Audiokomponenten > Signalprozessoren > Phono-Vorverstärker -Elektronik > Audio > Audiokomponenten > Signalprozessoren > Steuerungssysteme für PA-Anlagen -Elektronik > Audio > Audioplayer & -rekorder -Elektronik > Audio > Audioplayer & -rekorder > CD-Player & -Rekorder -Elektronik > Audio > Audioplayer & -rekorder > Diktiergeräte -Elektronik > Audio > Audioplayer & -rekorder > Ghettoblaster -Elektronik > Audio > Audioplayer & -rekorder > Heimkinosysteme -Elektronik > Audio > Audioplayer & -rekorder > Jukeboxen -Elektronik > Audio > Audioplayer & -rekorder > Karaokesysteme -Elektronik > Audio > Audioplayer & -rekorder > Kassettenspieler & -Rekorder -Elektronik > Audio > Audioplayer & -rekorder > MP3-Player -Elektronik > Audio > Audioplayer & -rekorder > Mehrspurrekorder -Elektronik > Audio > Audioplayer & -rekorder > MiniDisc-Player -Elektronik > Audio > Audioplayer & -rekorder > Plattenspieler -Elektronik > Audio > Audioplayer & -rekorder > Plattenspieler > DJ-Plattenspieler -Elektronik > Audio > Audioplayer & -rekorder > Radios -Elektronik > Audio > Audioplayer & -rekorder > Radios > Satellitenradios -Elektronik > Audio > Audioplayer & -rekorder > Radios > WLAN-Radios -Elektronik > Audio > Audioplayer & -rekorder > Stereoanlagen -Elektronik > Audio > Audiozubehör -Elektronik > Audio > Audiozubehör > Kopfhörerzubehör -Elektronik > Audio > Audiozubehör > Kopfhörerzubehör > In-Ear-Ohrhörer Polster -Elektronik > Audio > Audiozubehör > Kopfhörerzubehör > Kopfhörer-Polster -Elektronik > Audio > Audiozubehör > Lautsprecherzubehör -Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Bespannstoff für Lautsprecher -Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Lautsprecherständer -Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Taschen für Lautsprecherständer -Elektronik > Audio > Audiozubehör > Mikrofonzubehör -Elektronik > Audio > Audiozubehör > Mikrofonzubehör > Mikrofon-Windschutz -Elektronik > Audio > Audiozubehör > Mikrofonzubehör > Mikrofonständer -Elektronik > Audio > Audiozubehör > Plattenspielerzubehör -Elektronik > Audio > Audiozubehör > Plattenspielerzubehör > Plattenspieler-Tonabnehmer & -Nadeln -Elektronik > Audio > Audiozubehör > Satellitenradio-Zubehör -Elektronik > Audio > Audiozubehör > Zubehör für Karaoke-Systeme -Elektronik > Audio > Audiozubehör > Zubehör für Karaoke-Systeme > Karaoke-Speicherchips -Elektronik > Audio > Audiozubehör > Zubehör für MP3-Player -Elektronik > Audio > Audiozubehör > Zubehör für MP3-Player > MP3-Player-Taschen -Elektronik > Audio > Audiozubehör > Zubehör für MP3-Player > Zubehör für MP3-Player & Mobiltelefone -Elektronik > Audio > Beschallungsanlagen -Elektronik > Audio > Bühnenausstattung -Elektronik > Audio > Bühnenausstattung > Drahtlossender -Elektronik > Audio > DJ- & Spezialaudiogeräte -Elektronik > Audio > DJ- & Spezialaudiogeräte > DJ CD-Player -Elektronik > Audio > DJ- & Spezialaudiogeräte > DJ Systeme -Elektronik > Audio > DJ- & Spezialaudiogeräte > Zubehör für DJ-Anlagen -Elektronik > Computer -Elektronik > Computer > Barebone-Computer -Elektronik > Computer > Computerkomponenten -Elektronik > Computer > Computerkomponenten > Ausgabegeräte -Elektronik > Computer > Computerkomponenten > Blade-Server-Gehäuse -Elektronik > Computer > Computerkomponenten > Computer-Starter-Kits -Elektronik > Computer > Computerkomponenten > Computernetzteile -Elektronik > Computer > Computerkomponenten > Computerregale & -Befestigungssysteme -Elektronik > Computer > Computerkomponenten > Eingabegeräte -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Computer Mäuse & Trackballs -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Computertastaturen -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Digitale Stifte -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Fingerabdruck-Lesegeräte -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Gamecontroller -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Grafiktabletts -Elektronik > Computer > Computerkomponenten > Eingabegeräte > KVM-Switches -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Smartcard-Leser -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Speicherkartenlesegerät -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Strichcode-Scanner -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Tastatur- & Maussets -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Touchpads -Elektronik > Computer > Computerkomponenten > Eingabegeräte > Ziffernblöcke -Elektronik > Computer > Computerkomponenten > I/O-Karten -Elektronik > Computer > Computerkomponenten > I/O-Karten > FireWire-Karten -Elektronik > Computer > Computerkomponenten > I/O-Karten > Grafikkarten -Elektronik > Computer > Computerkomponenten > I/O-Karten > Parallele Karten -Elektronik > Computer > Computerkomponenten > I/O-Karten > Serielle Karten -Elektronik > Computer > Computerkomponenten > I/O-Karten > Soundkarten -Elektronik > Computer > Computerkomponenten > I/O-Karten > TV-Karten und -Adapter -Elektronik > Computer > Computerkomponenten > I/O-Karten > USB-Karten -Elektronik > Computer > Computerkomponenten > Kühlung von Computersystemen -Elektronik > Computer > Computerkomponenten > Laptopteile -Elektronik > Computer > Computerkomponenten > Laptopteile > Laptop-Ersatzbildschirme -Elektronik > Computer > Computerkomponenten > Laptopteile > Laptop-Ersatzkabel -Elektronik > Computer > Computerkomponenten > Laptopteile > Laptop-Ersatztastaturen -Elektronik > Computer > Computerkomponenten > Laptopteile > Laptop-Scharniere -Elektronik > Computer > Computerkomponenten > Laptopteile > Laptopgehäuse -Elektronik > Computer > Computerkomponenten > Motherboards -Elektronik > Computer > Computerkomponenten > PC-Gehäuse -Elektronik > Computer > Computerkomponenten > Prozessoren -Elektronik > Computer > Computerkomponenten > Speichergeräte -Elektronik > Computer > Computerkomponenten > Speichergeräte > Bandlaufwerke -Elektronik > Computer > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer -Elektronik > Computer > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer > CD-/DVD-Brenner -Elektronik > Computer > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer > Festplatten-Duplizierer -Elektronik > Computer > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer > USB-Laufwerk-Duplizierer -Elektronik > Computer > Computerkomponenten > Speichergeräte > Disk-Arrays -Elektronik > Computer > Computerkomponenten > Speichergeräte > Diskettenlaufwerke -Elektronik > Computer > Computerkomponenten > Speichergeräte > Festplatten -Elektronik > Computer > Computerkomponenten > Speichergeräte > Festplatten > Solid-State-Laufwerke -Elektronik > Computer > Computerkomponenten > Speichergeräte > Festplatten > XBox 360 Festplatten -Elektronik > Computer > Computerkomponenten > Speichergeräte > Netzwerkspeichersysteme -Elektronik > Computer > Computerkomponenten > Speichergeräte > Netzwerkspeichersysteme > NAS-Server -Elektronik > Computer > Computerkomponenten > Speichergeräte > Netzwerkspeichersysteme > Speichernetzwerke -Elektronik > Computer > Computerkomponenten > Speichergeräte > Optische Laufwerke -Elektronik > Computer > Computerkomponenten > Speichergeräte > Optische Laufwerke > CD-Laufwerke -Elektronik > Computer > Computerkomponenten > Speichergeräte > Optische Laufwerke > DVD-Laufwerke -Elektronik > Computer > Computerkomponenten > Speichergeräte > Optische Laufwerke > MO-Disketten -Elektronik > Computer > Computerkomponenten > Speichergeräte > Speicherlaufwerkzubehör -Elektronik > Computer > Computerkomponenten > Speichergeräte > Speicherlaufwerkzubehör > Externe Festplatten -Elektronik > Computer > Computerkomponenten > Speichergeräte > Speicherlaufwerkzubehör > Festplatten-Caddies -Elektronik > Computer > Computerkomponenten > Speichergeräte > Speicherlaufwerkzubehör > Festplatten-Dockingstationen -Elektronik > Computer > Computerkomponenten > Speichergeräte > Speicherlaufwerkzubehör > Festplatten-Transporttaschen -Elektronik > Computer > Computerkomponenten > Speichergeräte > Speicherlaufwerkzubehör > Festplattenhalterungen -Elektronik > Computer > Computerkomponenten > Speichergeräte > USB-Massenspeicher -Elektronik > Computer > Computerkomponenten > USB- & FireWire-Hubs -Elektronik > Computer > Computerkomponenten > Zubehör für Eingabegeräte -Elektronik > Computer > Computerkomponenten > Zubehör für Eingabegeräte > Grafiktablett-Zubehör -Elektronik > Computer > Computerkomponenten > Zubehör für Eingabegeräte > Halterung für Strichcodeleser -Elektronik > Computer > Computerkomponenten > Zubehör für Eingabegeräte > Zubehör für Gamecontroller -Elektronik > Computer > Computerkomponenten > Zubehör für Eingabegeräte > Zubehör für Gamecontroller > Joysticks & Tasten -Elektronik > Computer > Computerserver -Elektronik > Computer > Computerzubehör -Elektronik > Computer > Computerzubehör > Ersatzspitzen für Stylus Pens -Elektronik > Computer > Computerzubehör > Keyboard- und Mausauflagen -Elektronik > Computer > Computerzubehör > Laptopzubehör -Elektronik > Computer > Computerzubehör > Laptopzubehör > Laptop-Dockingstationen -Elektronik > Computer > Computerzubehör > Monitorständer -Elektronik > Computer > Computerzubehör > Mousepads -Elektronik > Computer > Computerzubehör > Stylus Pens -Elektronik > Computer > Computerzubehör > Tablet-Computer-Zubehör -Elektronik > Computer > Computerzubehör > Tablet-Computer-Zubehör > Tablet-Computer-Ersatzteile -Elektronik > Computer > Computerzubehör > Tablet-Computer-Zubehör > Tablet-Computer-Ersatzteile > Digitalisierer -Elektronik > Computer > Computerzubehör > Tablet-Computer-Zubehör > Tablet-PC-Halter -Elektronik > Computer > Computerzubehör > Tastatur- & Maus-Handballenauflage -Elektronik > Computer > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer -Elektronik > Computer > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > PDA-Zubehör -Elektronik > Computer > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > PDA-Zubehör > PDA-Taschen -Elektronik > Computer > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > Zubehör für E-Book-Reader -Elektronik > Computer > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > Zubehör für E-Book-Reader > E-Book-Reader-Taschen -Elektronik > Computer > Desktop-Computer -Elektronik > Computer > E-Book-Reader & Handheld-Computer -Elektronik > Computer > E-Book-Reader & Handheld-Computer > Datenerfassungsterminals -Elektronik > Computer > E-Book-Reader & Handheld-Computer > E-Book-Reader -Elektronik > Computer > E-Book-Reader & Handheld-Computer > PDAs -Elektronik > Computer > Interaktive Kioske -Elektronik > Computer > Laptops -Elektronik > Computer > Laptops > Netbooks -Elektronik > Computer > Tablet-PCs -Elektronik > Drucken, Kopieren, Scannen & Faxen -Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker & Kopierer -Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker & Kopierer > Drucker -Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker & Kopierer > Drucker > Fotodrucker -Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker & Kopierer > Drucker > Laserdrucker -Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker & Kopierer > Drucker > Matrixdrucker -Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker & Kopierer > Drucker > Tintenstrahldrucker -Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker & Kopierer > Kopierer -Elektronik > Drucken, Kopieren, Scannen & Faxen > Faxgeräte -Elektronik > Drucken, Kopieren, Scannen & Faxen > Scanner -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Duplexeinheiten -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Papierfächer -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial > Drucker-Farbbänder -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial > Druckerfilter -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial > Druckköpfe -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial > Toner & Tintenpatronen -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial > Toner- & Inkjet-Kartuschen -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial > Toner- & Inkjet-Kartuschen > Druckertrommelsets -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Drucker-Verbrauchsmaterial > Toner- & Inkjet-Kartuschen > Ölwalzen -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Druckerspeicher -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Druckertische -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Druckerzubehör > Druckerwartungssets -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Kopiererzubehör -Elektronik > Drucker-, Kopierer-, Scanner- & Faxzubehör > Scannerzubehör -Elektronik > Elektrische Instrumente Seefahrt -Elektronik > Elektrische Instrumente Seefahrt > Fischfinder -Elektronik > Elektrische Instrumente Seefahrt > Schiffsradar -Elektronik > Elektrische Instrumente Seefahrt > Seefunkgeräte -Elektronik > Elektrische Instrumente Seefahrt > Seekartenplotter & GPS -Elektronik > Elektromotoren -Elektronik > Elektronische Bauelemente -Elektronik > Elektronische Bauelemente > Decoder & Encoder für Schaltkreise -Elektronik > Elektronische Bauelemente > Elektronische Filter -Elektronik > Elektronische Bauelemente > Halbleiter -Elektronik > Elektronische Bauelemente > Halbleiter > Dioden -Elektronik > Elektronische Bauelemente > Halbleiter > Integrierte Schaltkreise & Chips -Elektronik > Elektronische Bauelemente > Halbleiter > Integrierte Schaltkreise & Chips > Operationsverstärker -Elektronik > Elektronische Bauelemente > Halbleiter > Integrierte Schaltkreise & Chips > Spannungsregler (ICs) -Elektronik > Elektronische Bauelemente > Halbleiter > Mikrocontroller -Elektronik > Elektronische Bauelemente > Halbleiter > Transistoren -Elektronik > Elektronische Bauelemente > Leiterplatten -Elektronik > Elektronische Bauelemente > Leiterplatten > Entwicklungsboard -Elektronik > Elektronische Bauelemente > Optoelektronik -Elektronik > Elektronische Bauelemente > Optoelektronik > Laserdioden -Elektronik > Elektronische Bauelemente > Passive elektronische Bauelemente -Elektronik > Elektronische Bauelemente > Passive elektronische Bauelemente > Induktoren -Elektronik > Elektronische Bauelemente > Passive elektronische Bauelemente > Kondensatoren -Elektronik > Elektronische Bauelemente > Passive elektronische Bauelemente > Oszillatoren -Elektronik > Elektronische Bauelemente > Passive elektronische Bauelemente > Widerstände -Elektronik > Elektronische Bauelemente > Passive elektronische Bauelemente > Widerstände > Potentiometer -Elektronik > Elektronische Bauelemente > Platinenentwicklung -Elektronik > Elektronische Bauelemente > Platinenentwicklung > Steckplatinen -Elektronik > Elektronisches Zubehör -Elektronik > Elektronisches Zubehör > Adapter -Elektronik > Elektronisches Zubehör > Adapter > Audio/Video-Adapter -Elektronik > Elektronisches Zubehör > Adapter > Speicheradapter -Elektronik > Elektronisches Zubehör > Adapter > Storage Adapter -Elektronik > Elektronisches Zubehör > Adapter > USB-Adapter -Elektronik > Elektronisches Zubehör > Antennen -Elektronik > Elektronisches Zubehör > Antennen > Funkantennen -Elektronik > Elektronisches Zubehör > Antennen > Kommunikationsantennen -Elektronik > Elektronisches Zubehör > Antennen > TV-Antennen -Elektronik > Elektronisches Zubehör > Antennenzubehör -Elektronik > Elektronisches Zubehör > Antennenzubehör > Antennenhalterungen & -befestigungen -Elektronik > Elektronisches Zubehör > Antennenzubehör > Dreheinrichtungen -Elektronik > Elektronisches Zubehör > Antennenzubehör > Satelliten-LNBs -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Blickschutzfilter -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Display-Schutzfolien -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber > Aufkleber für Spielkonsolen -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber > Handy-Aufkleber -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber > Laptop-Sticker & -Aufkleber -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber > MP3-Player-Sticker & -Aufkleber -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber > Sticker für Computertastaturen -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber > Tablet-Computer-Sticker & -Aufkleber -Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Tastaturschutz -Elektronik > Elektronisches Zubehör > Elektronikreiniger -Elektronik > Elektronisches Zubehör > Elektronikreiniger > Audio- & Videoreiniger -Elektronik > Elektronisches Zubehör > Elektronikreiniger > Bildschirmreiniger -Elektronik > Elektronisches Zubehör > Elektronikreiniger > Kamerareiniger -Elektronik > Elektronisches Zubehör > Fernbedienungen -Elektronik > Elektronisches Zubehör > Kabel -Elektronik > Elektronisches Zubehör > Kabel > Audio- & Videokabel -Elektronik > Elektronisches Zubehör > Kabel > Audio- & Videokabel > DVI-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Audio- & Videokabel > HDMI-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Audio- & Videokabel > Lautsprecherkabel -Elektronik > Elektronisches Zubehör > Kabel > Audio- & Videokabel > SCART-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Cinch-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Datenübertragungskabel -Elektronik > Elektronisches Zubehör > Kabel > Datenübertragungskabel > Firewire-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Datenübertragungskabel > USB-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Datenübertragungskabel > iOS-Kabel -Elektronik > Elektronisches Zubehör > Kabel > KVM-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Koaxialkabel -Elektronik > Elektronisches Zubehör > Kabel > Netzwerkkabel -Elektronik > Elektronisches Zubehör > Kabel > Netzwerkkabel > Ethernet-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Netzwerkkabel > Serial-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Optische Kabel -Elektronik > Elektronisches Zubehör > Kabel > Speicherkabel -Elektronik > Elektronisches Zubehör > Kabel > Speicherkabel > IDE-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Speicherkabel > SAS-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Speicherkabel > SATA-Kabel -Elektronik > Elektronisches Zubehör > Kabel > Speicherkabel > SCSI-Kabel -Elektronik > Elektronisches Zubehör > Kabel > System- & Netzkabel -Elektronik > Elektronisches Zubehör > Kabel > Telefonkabel -Elektronik > Elektronisches Zubehör > Kabel-Management -Elektronik > Elektronisches Zubehör > Kabel-Management > Aderhülsen & Kabelmuffen -Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelbinder -Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelschellen -Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelträger -Elektronik > Elektronisches Zubehör > Kabel-Management > Schalttafeln -Elektronik > Elektronisches Zubehör > Leere Medien -Elektronik > Elektronisches Zubehör > Leere Medien > Blu-ray Rohlinge -Elektronik > Elektronisches Zubehör > Leere Medien > CD Rohlinge -Elektronik > Elektronisches Zubehör > Leere Medien > Computerbänder -Elektronik > Elektronisches Zubehör > Leere Medien > Computerdisks -Elektronik > Elektronisches Zubehör > Leere Medien > Computerdisks > Disketten -Elektronik > Elektronisches Zubehör > Leere Medien > DVD Rohlinge -Elektronik > Elektronisches Zubehör > Leere Medien > MiniDiscs -Elektronik > Elektronisches Zubehör > Leere Medien > Unbespielte Kassetten -Elektronik > Elektronisches Zubehör > Leere Medien > Unbespielte Kassetten > Mikrokassetten -Elektronik > Elektronisches Zubehör > Leere Medien > Unbespielte Videokassetten -Elektronik > Elektronisches Zubehör > Signalverstärker -Elektronik > Elektronisches Zubehör > Speicher -Elektronik > Elektronisches Zubehör > Speicher > Cache-Speicher -Elektronik > Elektronisches Zubehör > Speicher > Flash-Speicher -Elektronik > Elektronisches Zubehör > Speicher > Flash-Speicher > Flash-Speicherkarten -Elektronik > Elektronisches Zubehör > Speicher > RAM -Elektronik > Elektronisches Zubehör > Speicher > ROM -Elektronik > Elektronisches Zubehör > Speicher > Videospeicher -Elektronik > Elektronisches Zubehör > Speicherkartenzubehör -Elektronik > Elektronisches Zubehör > Speicherkartenzubehör > Speicherkartenetuis -Elektronik > Elektronisches Zubehör > Stromversorgung -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Akkus & Batterien für schnurlose Telefone -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Batterien für E-Book-Lesegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Batterien für Tablet-Computer -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Handy-Akkus -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Kameraakkus & -batterien -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Laptopakkus -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Mehrzweckbatterien -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > PDA-Batterien -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > USV-Batterien -Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Videokameraakkus & -batterien -Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör -Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör > Akkuladegeräte für Kameras -Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör > Batterieladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Brennstoffzellen -Elektronik > Elektronisches Zubehör > Stromversorgung > Ladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Ladegeräte > E-Book-Reader Ladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Ladegeräte > MP3-Player-Ladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Ladegeräte > Mobiltelefonladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Ladegeräte > PDA-Ladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Ladegeräte > Solar-Ladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Ladegeräte > Tablet-Computer-Ladegeräte -Elektronik > Elektronisches Zubehör > Stromversorgung > Leistungsregler -Elektronik > Elektronisches Zubehör > Stromversorgung > Netzadapter -Elektronik > Elektronisches Zubehör > Stromversorgung > Netzadapter > Laptop-Netzadapter -Elektronik > Elektronisches Zubehör > Stromversorgung > Netzadapter > Reiseadapter -Elektronik > Elektronisches Zubehör > Stromversorgung > Netzadapter > Schaltnetzteile -Elektronik > Elektronisches Zubehör > Stromversorgung > Netzadapter > Wechselrichter -Elektronik > Elektronisches Zubehör > Stromversorgung > Netzteilzubehör -Elektronik > Elektronisches Zubehör > Stromversorgung > Power-Injektoren & -Splitter -Elektronik > Elektronisches Zubehör > Stromversorgung > Spannungsstabilisator -Elektronik > Elektronisches Zubehör > Stromversorgung > Spannungswandler -Elektronik > Elektronisches Zubehör > Stromversorgung > Steckdosenleisten & Überspannungsschutz -Elektronik > Elektronisches Zubehör > Stromversorgung > Stromkasten -Elektronik > Elektronisches Zubehör > Stromversorgung > Unterbrechungsfreie Stromversorgung -Elektronik > Elektronisches Zubehör > Stromversorgung > Zubehör für Unterbrechungsfreie Stromversorgung -Elektronik > Elektronisches Zubehör > Stromversorgung > Überspannungsschutzgeräte -Elektronik > GPS -Elektronik > GPS > Auto-GPS-Systeme -Elektronik > GPS > Flugnavigation -Elektronik > GPS > Sport-GPS-Geräte -Elektronik > GPS-Tracker -Elektronik > GPS-Zubehör -Elektronik > GPS-Zubehör > GPS-Halterungen -Elektronik > GPS-Zubehör > GPS-Taschen -Elektronik > Geräte zur Mauterhebung -Elektronik > Kommunikationsgeräte -Elektronik > Kommunikationsgeräte > Anrufbeantworter -Elektronik > Kommunikationsgeräte > Anrufbeantworter > Telefonwarteschleifensysteme -Elektronik > Kommunikationsgeräte > Anruferkennung -Elektronik > Kommunikationsgeräte > Funkgeräte -Elektronik > Kommunikationsgeräte > Funkgeräte > CB-Funkgeräte -Elektronik > Kommunikationsgeräte > Funkgeräte > Funkscanner -Elektronik > Kommunikationsgeräte > Funkgeräte > Funksprechgeräte -Elektronik > Kommunikationsgeräte > Funkzubehör -Elektronik > Kommunikationsgeräte > Headsets -Elektronik > Kommunikationsgeräte > Pager -Elektronik > Kommunikationsgeräte > Sprechanlagen -Elektronik > Kommunikationsgeräte > Sprechanlagen-Zubehör -Elektronik > Kommunikationsgeräte > Telefone -Elektronik > Kommunikationsgeräte > Telefone > Konferenztelefone -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefone -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefone > Handyuhren -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefone > Multifunktionstelefone -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefone > Smartphones -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Ersatzteile für Mobiltelefone -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Ersatzteile für Mobiltelefone > Digitalisierer für Mobiltelefone -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Handy-SIM-Karten -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Handycharms & -anhänger -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Mobiltelefonhalterungen & -ständer -Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Mobiltelefontaschen -Elektronik > Kommunikationsgeräte > Telefone > Satellitentelefone -Elektronik > Kommunikationsgeräte > Telefone > Schnurlostelefone -Elektronik > Kommunikationsgeräte > Telefone > Schnurtelefone -Elektronik > Kommunikationsgeräte > Telefone > Telefonzubehör -Elektronik > Kommunikationsgeräte > Telefone > Telefonzubehör > Telefonkarten -Elektronik > Kommunikationsgeräte > Videokonferenzsysteme -Elektronik > Komponenten -Elektronik > Komponenten > Automatisierungskomponenten -Elektronik > Komponenten > Automatisierungskomponenten > Antriebssysteme mit variabler Frequenz & einstellbarer Drehzahl -Elektronik > Komponenten > Automatisierungskomponenten > Speicherprogrammierbare Steuerungen -Elektronik > Komponenten > Beschleunigungssensoren -Elektronik > Komponenten > Modulatoren -Elektronik > Komponenten > Modulatoren > HF-Modulatoren -Elektronik > Komponenten > Splitter -Elektronik > Komponenten > Splitter > HF-Splitter -Elektronik > Komponenten > Splitter > UHF-Splitter -Elektronik > Komponenten > Transformatoren -Elektronik > Komponenten > Transformatoren > Baluns -Elektronik > Komponenten > Verbinder -Elektronik > Komponenten > Verbinder > Keystone-Module -Elektronik > Komponenten > Verbinder > RCA-Klinkenstecker -Elektronik > Komponenten > Wandler -Elektronik > Komponenten > Wandler > Signalwandler -Elektronik > Netzwerktechnik -Elektronik > Netzwerktechnik > Bridges & Router -Elektronik > Netzwerktechnik > Bridges & Router > Netzwerk-Bridges -Elektronik > Netzwerktechnik > Bridges & Router > Netzwerk-Bridges > WLAN-Bridges -Elektronik > Netzwerktechnik > Bridges & Router > VoIP-Gateways & -Router -Elektronik > Netzwerktechnik > Bridges & Router > Wireless Access Points -Elektronik > Netzwerktechnik > Bridges & Router > Wireless Router -Elektronik > Netzwerktechnik > Druckerserver -Elektronik > Netzwerktechnik > Hubs & Schalter -Elektronik > Netzwerktechnik > Konzentratoren & Multiplexer -Elektronik > Netzwerktechnik > Modems -Elektronik > Netzwerktechnik > Modemzubehör -Elektronik > Netzwerktechnik > Netzwerkkarten -Elektronik > Netzwerktechnik > Netzwerkkarten > Xbox 360-Netzwerkkarten -Elektronik > Netzwerktechnik > Netzwerksicherheitssysteme & Firewalls -Elektronik > Netzwerktechnik > Powerline-Netzwerkadapter -Elektronik > Netzwerktechnik > Repeater & Sende/-Empfangsgeräte -Elektronik > Plug & Play-TV-Spiele -Elektronik > Spielautomatenbedarf -Elektronik > Spielautomatenbedarf > Flipper -Elektronik > Spielautomatenbedarf > Flipper-Zubehör -Elektronik > Spielautomatenbedarf > Skee-Ball-Maschinen -Elektronik > Spielautomatenbedarf > Spielautomaten -Elektronik > Spielautomatenbedarf > Zubehör für Spielautomaten -Elektronik > Video -Elektronik > Video > Computermonitore -Elektronik > Video > Fernseher -Elektronik > Video > Fernseher > Flachbildschirmfernseher -Elektronik > Video > Fernseher > Projektions-TV-Geräte -Elektronik > Video > Fernseher > Röhrenfernsehgeräte -Elektronik > Video > Fernseher > Tragbare TV-Geräte -Elektronik > Video > Projektoren -Elektronik > Video > Projektoren > Diaprojektoren -Elektronik > Video > Projektoren > Multimedia-Projektoren -Elektronik > Video > Projektoren > Overhead-Projektoren -Elektronik > Video > Satelliten- & Kabelfernsehen -Elektronik > Video > Satelliten- & Kabelfernsehen > Kabelfernsehen-Receiver -Elektronik > Video > Satelliten- & Kabelfernsehen > Satelliten-Receiver -Elektronik > Video > Video-Multiplexer -Elektronik > Video > Videoabspielgeräte & -rekorder -Elektronik > Video > Videoabspielgeräte & -rekorder > DVD- & Blu-ray-Player -Elektronik > Video > Videoabspielgeräte & -rekorder > DVD-Rekorder -Elektronik > Video > Videoabspielgeräte & -rekorder > DVD-Rekorder > Blu-ray-Rekorder -Elektronik > Video > Videoabspielgeräte & -rekorder > DVD-Rekorder > HD-DVD-Rekorder -Elektronik > Video > Videoabspielgeräte & -rekorder > Digitale Videorekorder -Elektronik > Video > Videoabspielgeräte & -rekorder > Home-Mediaplayer -Elektronik > Video > Videoabspielgeräte & -rekorder > Videorekorder -Elektronik > Video > Videobearbeitungshardware & Videoproduktionsausrüstung -Elektronik > Video > Videoserver -Elektronik > Video > Videotransmitter -Elektronik > Video > Videotransmitter > Videosender -Elektronik > Video > Videozubehör -Elektronik > Video > Videozubehör > 3D-Brillen -Elektronik > Video > Videozubehör > Computerbildschirmzubehör -Elektronik > Video > Videozubehör > Computerbildschirmzubehör > Farbkalibrierung -Elektronik > Video > Videozubehör > Projektorzubehör -Elektronik > Video > Videozubehör > Projektorzubehör > Projektionsleinwände -Elektronik > Video > Videozubehör > Projektorzubehör > Projektorersatzleuchten -Elektronik > Video > Videozubehör > Projektorzubehör > Projektorhalterungen -Elektronik > Video > Videozubehör > Projektorzubehör > Rockvorhänge für Leinwände -Elektronik > Video > Videozubehör > Projektorzubehör > Ständer für Projektionsflächen -Elektronik > Video > Videozubehör > Spulgeräte -Elektronik > Video > Videozubehör > TV-Zubehör -Elektronik > Video > Videozubehör > TV-Zubehör > Ersatzlampen für Fernseher -Elektronik > Video > Videozubehör > TV-Zubehör > TV- & Monitorhalterungen -Elektronik > Video > Videozubehör > TV-Zubehör > TV-Konverter & Receiver -Elektronik > Videospielkonsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Dreamcast-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > GameCube-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Jaguar-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Neo Geo-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Nintendo 64-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Nintendo Entertainment System-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > PC Engine-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > PlayStation 2-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > PlayStation 3-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > PlayStation-Originalkonsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Sega Genesis-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Sega Master System-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Super Nintendo-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Wii U -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Wii-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Xbox 360-Konsolen -Elektronik > Videospielkonsolen > Heim-Spielkonsolen > Xbox-Originalkonsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Atari Lynx-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Game Gear-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Gameboy-Konsolen (alle) -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Gameboy-Konsolen (alle) > Game Boy Advance-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Gameboy-Konsolen (alle) > Gameboy-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > LeapFrog -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > N-Gage-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Neo Geo Pocket-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Nintendo 3DS -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Nintendo DS-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > PlayStation Portable-Konsolen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > PlayStation Vita -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > Retrogen -Elektronik > Videospielkonsolen > Tragbare Spielkonsolen > WonderSwan -Elektronik > Zubehör für Videospielkonsolen -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Dreamcast-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > GameCube-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Jaguar-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Neo Geo-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Nintendo 64-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Nintendo Entertainment System-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > PC Engine-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > PlayStation-Zubehör (alle) -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > PlayStation-Zubehör (alle) > PlayStation 2-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > PlayStation-Zubehör (alle) > PlayStation 3-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > PlayStation-Zubehör (alle) > PlayStation-Originalzubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Sega Genesis-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Sega Master System-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Super Nintendo-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Wii U-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Wii-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Xbox-Zubehör (komplett) -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Xbox-Zubehör (komplett) > Xbox 360-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen > Xbox-Zubehör (komplett) > Xbox-Originalzubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Atari Lynx-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Game Gear-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Gameboy-Zubehör (komplett) -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Gameboy-Zubehör (komplett) > Game Boy Advance-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Gameboy-Zubehör (komplett) > Game Boy-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > N-Gage-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Neo Geo Pocket-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Nintendo 3DS-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Nintendo DS-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > PlayStation Vita-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > Playstation Portable-Zubehör -Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen > WonderSwan-Zubehör -Fahrzeuge & Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Adapterkassetten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-CD-Wechsler -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-Empfänger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-Empfänger > Car-Hifi-Satellitenradios -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-Endstufen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-Equalizer & -Frequenzweichen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-Kassettenspieler -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-Lautsprecher -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Auto-Hifi-Subwoofer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi > Freisprechanlagen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi- & -Videokabel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Hifi-Überspannungsschutz -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Multimedia -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Multimedia > Auto-DVD-Player -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Auto-Hifi & -Multimedia > Auto-Multimedia > Auto-Monitore -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Flugzeugteile & -Zubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Abschlepphaken für Kfz -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Einstiegsleisten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Ersatzteile für Pkw-Anhänger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Fahrzeugkühlergrills -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Fußrasten für Motorräder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Hardtops -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Karosseriebausätze -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kennzeichen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Anhängerkupplung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Diffusoren -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Autogepäckträger für Angelruten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Autogepäckträger für Kanus & Kajaks -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Autogepäckträger für Motorräder & Motorroller -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Autogepäckträger für Skier & Snowboards -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Autogepäckträger für Surfbretter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Autogewehrhalter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Fahrradträger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Gepäckträger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträger > Grundgestelle für Autogepäckträger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträgerzubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträgerzubehör > Fahrradträgerzubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträgerzubehör > Fahrradträgerzubehör > Adapter für Fahrradgabelhalter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträgerzubehör > Fahrradträgerzubehör > Befestigungsriemen für Fahrräder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Gepäckträgerzubehör > Fahrradträgerzubehör > Fahrradrahmenhalter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Ladenetze -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Türen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Kfz-Warnflaggen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Ladeflächen für Pickups -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Ladeflächenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Ladeflächenteile > Gestänge für Lkw-Betten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Motorradkotflügel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Motorradlenker- & Griffe -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Motorradsitze -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Motorradverkleidungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Schalthebel für Motorräder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Schiebedächer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Spoiler -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Stoßstangen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Stoßstangenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Teile für Kfz-Türen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Verdecke -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Winden -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Außenteile > Windenzubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Armaturenbrett-Zubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Autofußmatten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Autositzauflagen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Autositze -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Dachhimmel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Elektrisch verstellbare Sitze -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Elektrische Kfz-Sicherungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Fahrzeugteppiche -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Getränkehalter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Kfz-Armstützen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Kfz-Rückenlehnen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Sonnenblenden -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Innenausstattung > Zigarettenanzünderstecker -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Autoalarmanlagen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Autokameras -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Fernbediente schlüssellose Systeme -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Freilaufnaben -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Kindersicherungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Lenkradschlösser -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Motorrad-Schlösser & -Alarmanlagen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Wegfahrsperren -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Zentralverriegelungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Schließsysteme > Zubehör für Auto-Alarmanlagen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Sicherheitsausrüstung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Sicherheitsausrüstung > Einparkhilfen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Achsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Antriebswellen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Antriebswellenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Differentiale -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Getriebe -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Getrieberäder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Getriebeteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Kipphebel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Kipphebelteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Kipphebelteile > Ventildeckel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Kugellager -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Kupplungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Pleuelstangen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Antriebsteile > Verteilergetriebeteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Aufhängungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Aufhängungsteile > Stoßdämpfer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Brems- & Kupplungshebel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff > Abgasrückführungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff > Auspuffe & Auspuffteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff > Auspuffkrümmer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff > Auspufftöpfe & Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff > Katalysatoren -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff > Sauerstoffsensoren & Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Batterien -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Batterien > Hybridbatterien -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Fahrtrichtungsanzeiger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Glühbirnen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Innenbeleuchtung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Nebelscheinwerfer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Rück- & Bremslichter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Rückfahrlichter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Scheinwerfer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Seitenleuchten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Kfz-Standlichter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung > Scheinwerferabdeckungen für Fahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Bremsen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Bremsen > Bremsenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Bremsen > Feststellbremsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Bremsen > Teile für Kfz-Handbremsen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Keilriemen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Klimatisierung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Klimatisierung > Kfz-Enteisungszubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Klimatisierung > Kfz-Gebläseteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Klimatisierung > Kfz-Heizungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Klimatisierung > Kfz-Klimaanlageteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Klimatisierung > Kfz-Temperaturregler -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Anlasser -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Anlasserteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Generatorenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Heizsysteme -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Heizsystemteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Kolben -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Kolbenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Kolbenteile > Kfz-Kolbenbolzen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Kolbenteile > Kfz-Kolbenringe -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Kompressorteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Kurbelwellen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Kurbelwellenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Lichtmaschinen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Lichtmaschinenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Motordichtsätze -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Motorsteuerungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Motorsteuerungsteile > Steuerketten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Nockenwellen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Nockenwellenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Schwungräder & -Schwungradteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Vakuumpumpenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Verdichter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Verdichterteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Vergaser -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Vergaserteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Zylinderköpfe & -teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Zündungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Zündungsteile > Kfz-Verteilerteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Zündungsteile > Teile für Hochspannungskondensatorzündungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Zündungsteile > Zündkerzen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile > Kfz-Zündungsteile > Zündspulen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Autofelgen & -räder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Felgen & Räder für ATV & UTV -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Felgen & Räder für ATV & UTV > Felgen & Räder für Quads/ATVs -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Felgen & Räder für ATV & UTV > Felgen & Räder für UTV-Fahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Motorradfelgen & -räder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Radteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Autoreifen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Motorradreifen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Reifen für ATV & UTV -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Reifen für ATV & UTV > ATV-Reifen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Reifen für ATV & UTV > Reifen für UTV-Fahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifenzubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifenzubehör > Schneeketten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Spiegel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Spiegel > Anhänger- & Wohnwagenspiegel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Spiegel > Fahrzeug-Außenspiegel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Spiegel > Kfz-Rückspiegel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Ventile & -teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Benzinpumpen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Einspritzdüsen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Einspritzteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Kraftstoffleitungen & Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Kraftstoffpumpenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Kraftstoffsiebe & -filter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Lachgaseinspritzsysteme -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Luftmassenmesser -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Treibstofftanks -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen > Treibstofftankteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Achsschenkelbolzen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Lenkradkontrolltasten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Lenkradkontrolltasten > Frontscheinwerferregelungselemente -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Lenkradkontrolltasten > Kfz-Lichtdimmer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Lenkradkontrolltasten > Tempomat-Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Lenkradkontrolltasten > Wischergeschwindigkeitssteuerung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Lenkräder -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Lenkungsteile > Servolenkungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Luftansaugungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Luftansaugungsteile > Kfz-Luftpumpen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Luftansaugungsteile > Kompressorenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Luftansaugungsteile > Luftfilter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Luftansaugungsteile > Luftverteiler -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Pedale für Kfz -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Scheibenwischer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Teile für Kfz-Batterien -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Teile für Kfz-Fenster -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Teile für Kfz-Fenster > Fenster- & Windschutzscheibenglas -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Teile für Kfz-Fenster > Teile für elektrische Fensterheber -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Ölkreislauf -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Ölkreislauf > Ölfilter -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Ölkreislauf > Ölpumpen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Ölkreislauf > Ölpumpenteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Ölkreislauf > Ölwannen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Aufladegeräte für Fahrzeugbatterien -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugdiagnosegeräte -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeuglack -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Autowaschbürsten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Autowaschmittel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Fahrzeug-Glasreiniger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Fahrzeug-Polsterreiniger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Fahrzeug-Sprühreiniger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Fahrzeug-Teppichreiniger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Reifenreinigungs- & Glanzmittel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Wachse, Polituren & Schutzmittel für Fahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Antennenbälle -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Autofolien -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Autoscheibenfolien -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Autositzbezüge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Fahrzeug-Embleme -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kennzeichenrahmen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Aufkleber -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Fahnen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Kennzeichenabdeckungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Lufterfrischer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Magneten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Rückenlehnentaschen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Benzin- & Ölzusätze -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Bremsflüssigkeit -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Flüssigkeit für Servolenkungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Flüssigkeit für hydraulische Kupplungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Frostschutzmittel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Getriebeöl -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Kfz-Schmierstoffe -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Kühlsystemadditive -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Motorenöl -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Motorreiniger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Tankreiniger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Wischwasser -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Reifenbedarf -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Reifenbedarf > Radkappen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Reifenbedarf > Radventilkappen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Reifenbedarf > Reifenabdeckungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Reifenbedarf > Reifendrucksensoren & -messer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Reifenbedarf > Reifenstifte -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Starthilfe -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Windschutzscheibenreparatursets -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Überbrückungskabel -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Überwachungstechnik -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Überwachungstechnik > Benzinuhren -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Überwachungstechnik > Geschwindigkeitsanzeiger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Überwachungstechnik > Kfz-Bordcomputer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Überwachungstechnik > Kilometerzähler -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Überwachungstechnik > Motorsteuergerätteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Überwachungstechnik > Tachometer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorrad-Genickschutz -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorrad-Nierengurte -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorrad: Brust- und Rückenprotektoren -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorrad: Ellbogen- und Handgelenkschützer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorrad: Knie- & Schienbeinschützer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorradbrillen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorradhandschuhe -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorradhelme -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorradhelmersatzteile & -zubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorrad-Schutzausrüstung > Motorradhelmersatzteile & -zubehör > Motorradhelm-Visiere -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Motorradzubehör > Motorradtaschen & -koffer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Anker -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Ankerketten -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Ankerleinen & -seile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Ankerwinden -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Bootshaken -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Bootsleitern -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Klampen & Klemmen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Stufentritte -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Beleuchtung für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Benzinuhren für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Kraftstoffleitungen & Teile für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Kraftstoffpumpen & Teile für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Kraftstofftanks & Teile für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Segelbootteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugantriebe & -motoren -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugauspuffteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugauspuffteile > Schalldämpfer & Teile für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugauspuffteile > Wasserfahrzeugkrümmer -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Motorlager für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Motorschlösser für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeug Laufrad -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeug-Zündungsteile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugkolben & Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeuglichtmaschinen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugmotorsteuerung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugpropeller -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugvergaser & Teile -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugpflege -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugpflege > Wasserfahrzeugabdeckungen -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugpflege > Wasserfahrzeugpolituren -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugpflege > Wasserfahrzeugreiniger -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugsteuerung -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugsteuerung > Steuerkabel für Wasserfahrzeuge -Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugsteuerung > Steuerräder für Wasserfahrzeuge -Für Erwachsene -Für Erwachsene > Erotik -Für Erwachsene > Erotik > Erotikbücher -Für Erwachsene > Erotik > Erotikbücher > Erotik-Comics -Für Erwachsene > Erotik > Erotische DVDs & Videos -Für Erwachsene > Erotik > Erotische Kleidung -Für Erwachsene > Erotik > Erotische Lebensmittel & Esswaren -Für Erwachsene > Erotik > Erotische Spiele -Für Erwachsene > Erotik > Erotische Zeitschriften -Für Erwachsene > Erotik > Pole Dance-Tanzstangenkits -Für Erwachsene > Erotik > Sexspielzeug -Gesundheit & Schönheit -Gesundheit & Schönheit > Gesundheitspflege -Gesundheit & Schönheit > Gesundheitspflege > Akupunktur -Gesundheit & Schönheit > Gesundheitspflege > Akupunktur > Akupunkturmodelle -Gesundheit & Schönheit > Gesundheitspflege > Akupunktur > Akupunkturnadeln -Gesundheit & Schönheit > Gesundheitspflege > Arthritisbehandlung -Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin -Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin > Inhalatoren -Gesundheit & Schönheit > Gesundheitspflege > Behälter für Verhütungsmittel -Gesundheit & Schönheit > Gesundheitspflege > Bettpfannen -Gesundheit & Schönheit > Gesundheitspflege > Blutgruppentests -Gesundheit & Schönheit > Gesundheitspflege > CPAP-Ausrüstung -Gesundheit & Schönheit > Gesundheitspflege > CPAP-Ausrüstung > CPAP-Geräte -Gesundheit & Schönheit > Gesundheitspflege > CPAP-Ausrüstung > CPAP-Masken -Gesundheit & Schönheit > Gesundheitspflege > Diabetikerbedarf -Gesundheit & Schönheit > Gesundheitspflege > Drogentests -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Antiseptika & Reinigung -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Augenwaschbedarf -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Behandlung von Ausschlägen -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Erste-Hilfe-Koffer -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Medizinisches Klebeband & Verbandsmaterial -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Schutzhüllen für Gipsverbände -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Warm & Kalt Therapie -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Warm & Kalt Therapie > Eisanwendungen -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Warm & Kalt Therapie > Wärmflaschen & Heizkissen -Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Wärmecremes -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Diätpräparate -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Energie-Gel & -Nahrung -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Ergänzung zur künstlichen Ernährung -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Mahlzeitenersatz-Getränke -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Proteinpulver -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Pürierte Lebensmittel -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Sportriegel -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Traditionelle chinesische Tonika -Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Vitamine & Nahrungsergänzungsmittel -Gesundheit & Schönheit > Gesundheitspflege > HIV-Tests -Gesundheit & Schönheit > Gesundheitspflege > Hausnotrufgeräte -Gesundheit & Schönheit > Gesundheitspflege > Hörgeräte -Gesundheit & Schönheit > Gesundheitspflege > Hörhilfen -Gesundheit & Schönheit > Gesundheitspflege > Inkontinenzartikel -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Alkoholmessgeräte -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Blutdruckmessgeräte -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Blutzuckermessgeräte -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Cholesterinmessgeräte -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Fieberthermometer -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Fruchtbarkeitscomputer -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Herzfrequenzmessgeräte -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Körperfettanalyse -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Personenwaagen -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Pränatale Herzfrequenzmesser -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Pulsoximeter -Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Schrittzähler -Gesundheit & Schönheit > Gesundheitspflege > Medizinisches Gleitgel -Gesundheit & Schönheit > Gesundheitspflege > Notfall-Armband -Gesundheit & Schönheit > Gesundheitspflege > Orthopädische Hilfsmittel -Gesundheit & Schönheit > Gesundheitspflege > Orthopädische Hilfsmittel > Handtrainer -Gesundheit & Schönheit > Gesundheitspflege > Rauchabgewöhnung -Gesundheit & Schönheit > Gesundheitspflege > Schwangerschaftstests -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Behindertengerechte Möbel & Vorrichtungen -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Behindertengerechte Möbel & Vorrichtungen > Duschbänke & -sitze -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Behindertenzubehör -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen > Gehstöcke -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen > Krücken -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen > Rollatoren -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfenzubehör -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Elektromobile -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Rollstühle -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Rollstühle > Elektrorollstühle -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Rollstühle > Standardrollstühle -Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Treppenlifte -Gesundheit & Schönheit > Gesundheitspflege > Stützen & Bandagen -Gesundheit & Schönheit > Gesundheitspflege > Verhütungsmittel -Gesundheit & Schönheit > Gesundheitspflege > Verhütungsmittel > Kondome -Gesundheit & Schönheit > Gesundheitspflege > Verhütungsmittel > Spermizide -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung > Blutzucker-Kontrolllösung -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung > Blutzuckerteststreifen -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung > Stechhilfen -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Verhütungscomputerzubehör -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Badezimmerwaagen -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Blutdrucküberwachungsgeräte -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Blutdrucküberwachungsgeräte > Blutdruckmanschetten -Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Herzfrequenzmesser -Gesundheit & Schönheit > Körperpflege -Gesundheit & Schönheit > Körperpflege > Augenpflege -Gesundheit & Schönheit > Körperpflege > Augenpflege > Augentropfen -Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillen -Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillengläser -Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillenzubehör -Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillenzubehör > Brillenetuis & -ständer -Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsen -Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege -Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege > Kontaktlinsenbehälter -Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege > Kontaktlinsenpflegemittel -Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege > Pflegekits für Kontaktlinsen -Gesundheit & Schönheit > Körperpflege > Augenpflege > Sonnenbrillengläser -Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel -Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Damen-Deodorant -Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Intim-Waschlotionen -Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Slipeinlagen & Binden -Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Tampons -Gesundheit & Schönheit > Körperpflege > Deodorants & Antitranspirante -Gesundheit & Schönheit > Körperpflege > Einlaufsets & -zubehör -Gesundheit & Schönheit > Körperpflege > Fußpflege -Gesundheit & Schönheit > Körperpflege > Fußpflege > Antipilzmittel -Gesundheit & Schönheit > Körperpflege > Fußpflege > Einlegesohlen & Einlagen -Gesundheit & Schönheit > Körperpflege > Fußpflege > Fußgeruchskiller -Gesundheit & Schönheit > Körperpflege > Fußpflege > Hühneraugen- & Hornhautprodukte -Gesundheit & Schönheit > Körperpflege > Fußpflege > Zehenpflege -Gesundheit & Schönheit > Körperpflege > Fußpflege > Zehenspreizer -Gesundheit & Schönheit > Körperpflege > Gleitmittel -Gesundheit & Schönheit > Körperpflege > Haarkosmetik -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haar-Decoloration -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarfärbemittel -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarscheren -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Haarglätter -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Haartrockner -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Kämme & Bürsten -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Lockenstäbe -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Lockenwickler -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarverdichter -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Mittel für Dauerwellen & Haarglättung, chemische Haarglättung -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Mittel gegen Haarverlust -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Shampoo & Spülung -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Styling-Gel, Haarspray & Haarschaum -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Trockenhauben -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarcolorationen -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte > Haareisenzubehör -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte > Haartrocknerzubehör -Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte > Lockenwicklerklammern & -nadeln -Gesundheit & Schönheit > Körperpflege > Kosmetika -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Bade- & Naturschwämme -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Badebürsten -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Duschhauben -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Feuchttücher -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Flüssigseifen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Handdesinfektionsmittel -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Schaumbäder & Badesalze -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Seife -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Seife in Pulverform -Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Waschlotion -Gesundheit & Schönheit > Körperpflege > Kosmetika > Düfte -Gesundheit & Schönheit > Körperpflege > Kosmetika > Geschenkkörbe Bad & Körperpflege -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Aknebehandlung -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Anti-Aging-Hautpflegeprodukte -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Bräunungsprodukte -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Bräunungsprodukte > Selbstbräuner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Bräunungsprodukte > Selbstbräuner & Selbstbräuner-Entferner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Bräunungsprodukte > Sonnenöle & -lotionen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Gesichtsmasken -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Gesichtspeeling -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Gesichtsreiniger -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Gesichtsreinigungscremes -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Insektenschutzmittel -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Körperpuder -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Körperöle -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lippenpflege -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lotion & Feuchtigkeitscremes -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lotion & Feuchtigkeitscremes > Feuchtigkeitsspendende Gesichtscremes -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lotion & Feuchtigkeitscremes > Fußlotion -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lotion & Feuchtigkeitscremes > Handlotionen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lotion & Feuchtigkeitscremes > Körperlotion -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Make-up-Entferner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Porenreinigungspflaster -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Reinigungswasser & Adstringentien -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Sonnencreme -Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Vaseline -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Bimssteine -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Fußfeilen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Gesichtsbürsten -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Gesichtssaunas -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Hautpflegeroller -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Mitesser-Entferner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Applikatoren für künstliche Wimpern -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Augenbrauenschablonen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Ersatzkissen für Wimpernzangen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Kleber für doppelte Augenlider -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Kleber für künstliche Wimpern -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Make-up-Pinsel -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Make-up-Schwämme -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Make-up-Spiegel -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Pudertücher -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Wimpernformer -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Maniküre-Sets -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelfeilen & Sandblattfeilen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelfräser -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelhautscheren -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelhautschieber -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelknipser -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelpolierer -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nageltrockner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Zehenspreizer für Pediküre -Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Pinzetten -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen-Make-up -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen-Make-up > Augenbrauenstifte -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen-Make-up > Behandlungen für Wimpernwachstum -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen-Make-up > Kajalstifte -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen-Make-up > Künstliche Wimpern -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen-Make-up > Lidschatten -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen-Make-up > Mascara -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Kostüm- & Bühnen-Make-up -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Körper-Make-up -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Körper-Make-up > Bodypainting-Farbe -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Körper-Make-up > Glitter für Körper und Haar -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lipgloss -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lipliner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lippen- & Wangentönung -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lippenstift -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Makeup-Sets -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Spray zum Fixieren von Make-up -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Grundierungen & Concealer -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Highlighter & Luminizer -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Puder -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Rouge & Bronzepuder -Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Temporäre Tattoos -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Künstliche Nägel -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagelhautcremes & -Lotionen -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagelkleber -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagelkunst-Zubehör -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagellacke -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagellackentferner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagellackverdünner -Gesundheit & Schönheit > Körperpflege > Kosmetika > Reiniger für Kosmetikwerkzeuge -Gesundheit & Schönheit > Körperpflege > Massage & Entspannung -Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagegeräte -Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagestühle -Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagetische -Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massageöle -Gesundheit & Schönheit > Körperpflege > Mundpflege -Gesundheit & Schönheit > Körperpflege > Mundpflege > Ersatzdüsen für Mundduschen -Gesundheit & Schönheit > Körperpflege > Mundpflege > Gebissreiniger -Gesundheit & Schönheit > Körperpflege > Mundpflege > Interdentalreiniger -Gesundheit & Schönheit > Körperpflege > Mundpflege > Mittel gegen Zahnschmerzen -Gesundheit & Schönheit > Körperpflege > Mundpflege > Mundduschen -Gesundheit & Schönheit > Körperpflege > Mundpflege > Mundschutz -Gesundheit & Schönheit > Körperpflege > Mundpflege > Mundspray -Gesundheit & Schönheit > Körperpflege > Mundpflege > Mundwasser -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnaufhellung -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürsten -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör > Ersatzköpfe für Zahnbürsten -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör > Zahnbürstendesinfektionsmittel -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör > Zahnbürstenhüllen -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnersatz -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnfleischstimulierende Geräte -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnpasta -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnpastapressen & -spender -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnprothesehaftmittel -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnseide -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnstocher -Gesundheit & Schönheit > Körperpflege > Mundpflege > Zungenreiniger -Gesundheit & Schönheit > Körperpflege > Ohrenpflege -Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrenreinigungssets -Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrenstöpsel -Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrentrockner -Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrentropfen -Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrkerzen -Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrspritzen -Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrstöpselspender -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Alaunstifte -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haar- & Bartschneider -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Elektrolysegeräte -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Enthaarungsmittel -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Epilatoren -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Laserhaarentfernung -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Waxing-Kits -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierapparate -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasiercreme -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierer & Rasierklingen -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierpinsel -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasiersets -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierwasser -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Zubehör für Haarschneidegeräte & Trimmer -Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Zubehör für elektrische Rasierer -Gesundheit & Schönheit > Körperpflege > Rückenpflege -Gesundheit & Schönheit > Körperpflege > Rückenpflege > Stützkissen für Rücken- & Lendenbereich -Gesundheit & Schönheit > Körperpflege > Schlafhilfen -Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Hilfsmittel gegen Schnarchen und Schlaf-Apnoe -Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Reisekissen -Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Schlafmasken -Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Soundmaschinen -Gesundheit & Schönheit > Körperpflege > Sonnenbänke -Gesundheit & Schönheit > Körperpflege > Tanningzelt -Gesundheit & Schönheit > Körperpflege > Warzenentferner -Gesundheit & Schönheit > Körperpflege > Wattebällchen -Gesundheit & Schönheit > Körperpflege > Wattestäbchen -Gesundheit & Schönheit > Schmuckreinigung & -pflege -Gesundheit & Schönheit > Schmuckreinigung & -pflege > Schmuckreiniger -Gesundheit & Schönheit > Schmuckreinigung & -pflege > Schmuckständer & -kästen -Heim & Garten -Heim & Garten > Badzubehör -Heim & Garten > Badzubehör > Badematten & Badteppiche -Heim & Garten > Badzubehör > Badewannen- & Duschablagen -Heim & Garten > Badzubehör > Badewannenkissen -Heim & Garten > Badzubehör > Badezimmer-Zubehörsets -Heim & Garten > Badzubehör > Badzubehörhalterungen -Heim & Garten > Badzubehör > Duschvorhangringe -Heim & Garten > Badzubehör > Duschvorhänge -Heim & Garten > Badzubehör > Garderobenhaken -Heim & Garten > Badzubehör > Handtuchhalter -Heim & Garten > Badzubehör > Händetrockner -Heim & Garten > Badzubehör > Kosmetiktuchhalter -Heim & Garten > Badzubehör > Medizinschränke -Heim & Garten > Badzubehör > Seifen- & Lotionsspender -Heim & Garten > Badzubehör > Seifenablagen -Heim & Garten > Badzubehör > Toilettenbürsten -Heim & Garten > Badzubehör > Toilettenbürstenköpfe -Heim & Garten > Badzubehör > Toilettenpapierhalter -Heim & Garten > Badzubehör > Zahnbürstenhalter -Heim & Garten > Badzubehör > Zubehör für Händetrockner -Heim & Garten > Beleuchtung -Heim & Garten > Beleuchtung > Außenbeleuchtung -Heim & Garten > Beleuchtung > Außenbeleuchtung > Gartenlaternen & -fackeln -Heim & Garten > Beleuchtung > Außenbeleuchtung > Gartenstrahler -Heim & Garten > Beleuchtung > Außenbeleuchtung > Terrassenbeleuchtung -Heim & Garten > Beleuchtung > Außenbeleuchtung > Wegbeleuchtung -Heim & Garten > Beleuchtung > Bilderbeleuchtung -Heim & Garten > Beleuchtung > Flutlichter -Heim & Garten > Beleuchtung > Lampen -Heim & Garten > Beleuchtung > Lampen > Standleuchten -Heim & Garten > Beleuchtung > Lampen > Tischlampen -Heim & Garten > Beleuchtung > Leuchten -Heim & Garten > Beleuchtung > Leuchten > Deckenleuchten -Heim & Garten > Beleuchtung > Leuchten > Kronleuchter -Heim & Garten > Beleuchtung > Leuchten > Unterbauleuchten -Heim & Garten > Beleuchtung > Leuchten > Wandleuchten, Wandbeleuchtung -Heim & Garten > Beleuchtung > Leuchten > Wandleuchten, Wandbeleuchtung > Wandleuchten -Heim & Garten > Beleuchtung > Leuchtmittel -Heim & Garten > Beleuchtung > Leuchtmittel > Glühlampen -Heim & Garten > Beleuchtung > Leuchtmittel > Kompaktleuchtstofflampen -Heim & Garten > Beleuchtung > Leuchtmittel > LED-Leuchtmittel -Heim & Garten > Beleuchtung > Leuchtmittel > Leuchtstoffröhren -Heim & Garten > Beleuchtung > Lichtschienen -Heim & Garten > Beleuchtung > Lichtschienen > Leuchten für Lichtschienensysteme -Heim & Garten > Beleuchtung > Lichtschienen > Schienen für Lichtschienensysteme -Heim & Garten > Beleuchtung > Lichtschienen > Zubehör für Lichtschienensysteme -Heim & Garten > Beleuchtung > Lichtschläuche & Lichterketten -Heim & Garten > Beleuchtung > Nachtlichter -Heim & Garten > Beleuchtung > Notbeleuchtung -Heim & Garten > Beleuchtungszubehör -Heim & Garten > Beleuchtungszubehör > Beleuchtungszeitschaltuhren -Heim & Garten > Beleuchtungszubehör > Lampenschirme -Heim & Garten > Beleuchtungszubehör > Laternenhalterungen -Heim & Garten > Beleuchtungszubehör > Laternensockel -Heim & Garten > Bett- und Haushaltswäsche -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Bettbezüge -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Bettdecken -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Bettlaken -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Bettvolants -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Decken -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Decken > Heizdecken -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Decken > Überwürfe -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Kissen- & Zierkissenbezüge -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Kopfkissen -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Kopfkissen > Seitenschläferkissen -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Matratzenschoner -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Matratzenschoner > Matratzenauflagen -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Matratzenschoner > Matratzenbezüge -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Schlafunterlagen -Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Steppdecken -Heim & Garten > Bett- und Haushaltswäsche > Handtücher -Heim & Garten > Bett- und Haushaltswäsche > Handtücher > Badhandtücher & Waschlappen -Heim & Garten > Bett- und Haushaltswäsche > Handtücher > Geschirrtücher -Heim & Garten > Bett- und Haushaltswäsche > Handtücher > Strandtücher -Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche -Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Stoffservietten -Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischläufer -Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischsets -Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischtücher -Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischvorhänge -Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Zierdecken -Heim & Garten > Bett- und Haushaltswäsche > Tischwäschezubehör -Heim & Garten > Bett- und Haushaltswäsche > Tischwäschezubehör > Klemmen & Gewichte für Tischdecken -Heim & Garten > Dekoration -Heim & Garten > Dekoration > Bilderrahmen -Heim & Garten > Dekoration > Bilderrahmen > Digitale Bilderrahmen -Heim & Garten > Dekoration > Bilderrahmen > Posterrahmen -Heim & Garten > Dekoration > Briefkasten-Zubehör -Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkasten-Befestigungsbügel -Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkasten-Standanlagen -Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastenanlagen -Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastenaufsätze -Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastenfahnen -Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastentüren -Heim & Garten > Dekoration > Briefkästen -Heim & Garten > Dekoration > Briefschlitze -Heim & Garten > Dekoration > Brunnen & Teiche -Heim & Garten > Dekoration > Brunnen & Teiche > Brunnen -Heim & Garten > Dekoration > Brunnen & Teiche > Brunnen > Außenbrunnen -Heim & Garten > Dekoration > Brunnen & Teiche > Brunnen > Zimmerbrunnen -Heim & Garten > Dekoration > Brunnen & Teiche > Brunnen- & Teichzubehör -Heim & Garten > Dekoration > Brunnen & Teiche > Teiche -Heim & Garten > Dekoration > Buchstützen -Heim & Garten > Dekoration > Dekorative Flaschen -Heim & Garten > Dekoration > Dekorative Gefäße -Heim & Garten > Dekoration > Dekorative Klingeln -Heim & Garten > Dekoration > Dekorteller -Heim & Garten > Dekoration > Dufttarts -Heim & Garten > Dekoration > Ecosphere-Kugeln -Heim & Garten > Dekoration > Fensterdrapierung -Heim & Garten > Dekoration > Fensterdrapierung > Buntglasscheiben -Heim & Garten > Dekoration > Fensterdrapierung > Fensterfolie -Heim & Garten > Dekoration > Fensterdrapierung > Fliegengitter -Heim & Garten > Dekoration > Fensterdrapierung > Jalousien & Rollos -Heim & Garten > Dekoration > Fensterdrapierung > Volants -Heim & Garten > Dekoration > Fensterdrapierung > Vorhänge & Gardinen -Heim & Garten > Dekoration > Fensterschmuckmagnete -Heim & Garten > Dekoration > Festtags-Dekoartikel -Heim & Garten > Dekoration > Festtags-Dekoartikel > Adventskalender -Heim & Garten > Dekoration > Festtags-Dekoartikel > Haken für Weihnachtssocken -Heim & Garten > Dekoration > Festtags-Dekoartikel > Krippen -Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsbaumdecken -Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsbaumschmuck -Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsbaumständer -Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsschmuck-Aufbewahrung -Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsschmuck-Displays -Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtssocken -Heim & Garten > Dekoration > Figuren zur Dekoration -Heim & Garten > Dekoration > Flaggen & Windsäcke -Heim & Garten > Dekoration > Flammenlose Kerzen -Heim & Garten > Dekoration > Futterspender -Heim & Garten > Dekoration > Futterspender > Eichhörnchenfutterspender -Heim & Garten > Dekoration > Futterspender > Schmetterlingsfutterspender -Heim & Garten > Dekoration > Futterspender > Vogelfutterspender -Heim & Garten > Dekoration > Fußmatten -Heim & Garten > Dekoration > Garderoben -Heim & Garten > Dekoration > Garten- & Trittsteine -Heim & Garten > Dekoration > Gartenschmuck -Heim & Garten > Dekoration > Gartenschmuck > Gartenkugeln -Heim & Garten > Dekoration > Gartenskulpturen -Heim & Garten > Dekoration > Glasfensterbilder -Heim & Garten > Dekoration > Globen -Heim & Garten > Dekoration > Hausnummern & Buchstaben -Heim & Garten > Dekoration > Hausnummernschilder -Heim & Garten > Dekoration > Kerzen -Heim & Garten > Dekoration > Kerzen > Chanukkah-Kerzen -Heim & Garten > Dekoration > Kerzen > Hochzeitskerzen -Heim & Garten > Dekoration > Kerzenständer -Heim & Garten > Dekoration > Kerzenständer > Chanukkia -Heim & Garten > Dekoration > Kreuzblumen -Heim & Garten > Dekoration > Kränze & Girlanden -Heim & Garten > Dekoration > Körbe -Heim & Garten > Dekoration > Kühlschrankmagnete -Heim & Garten > Dekoration > Künstliche Pflanzen -Heim & Garten > Dekoration > Künstliche Pflanzen > Kunstfloristik -Heim & Garten > Dekoration > Künstliche Pflanzen > Künstliche Blumen -Heim & Garten > Dekoration > Künstliche Pflanzen > Künstliche Bäume -Heim & Garten > Dekoration > Künstliche Pflanzen > Künstliche Formschnittpflanzen -Heim & Garten > Dekoration > Lebensmittel-Attrappen -Heim & Garten > Dekoration > Niederschlags-Messgeräte -Heim & Garten > Dekoration > Quadratische Sitzkissen -Heim & Garten > Dekoration > Raumdüfte -Heim & Garten > Dekoration > Raumdüfte > Duftöle -Heim & Garten > Dekoration > Raumdüfte > Lufterfrischer -Heim & Garten > Dekoration > Raumdüfte > Potpourri -Heim & Garten > Dekoration > Raumdüfte > Räuchermittel -Heim & Garten > Dekoration > Raumdüfte > Räuchermittelhalter -Heim & Garten > Dekoration > Regenketten -Heim & Garten > Dekoration > Rückenstützkissen -Heim & Garten > Dekoration > Schalen -Heim & Garten > Dekoration > Schaukästen -Heim & Garten > Dekoration > Schneekugeln -Heim & Garten > Dekoration > Schonbezüge -Heim & Garten > Dekoration > Serviettenringe -Heim & Garten > Dekoration > Sitzpolster -Heim & Garten > Dekoration > Sonnenuhren -Heim & Garten > Dekoration > Sparschweine & -Dosen -Heim & Garten > Dekoration > Spaßschilder -Heim & Garten > Dekoration > Spiegel -Heim & Garten > Dekoration > Spieluhren -Heim & Garten > Dekoration > Tabletts -Heim & Garten > Dekoration > Tafeln -Heim & Garten > Dekoration > Teppiche -Heim & Garten > Dekoration > Teppiche > Heizteppiche -Heim & Garten > Dekoration > Tiki-Fackeln & Öllampen -Heim & Garten > Dekoration > Traumfänger -Heim & Garten > Dekoration > Trockenblumen -Heim & Garten > Dekoration > Truhen -Heim & Garten > Dekoration > Uhren -Heim & Garten > Dekoration > Uhren > Standuhren -Heim & Garten > Dekoration > Uhren > Tisch- und Regaluhren -Heim & Garten > Dekoration > Uhren > Wanduhren -Heim & Garten > Dekoration > Uhren > Wanduhren > Kuckucksuhren -Heim & Garten > Dekoration > Uhren > Wecker -Heim & Garten > Dekoration > Uhren > Wecker > Radiowecker -Heim & Garten > Dekoration > Uhren > Wecker > Reisewecker -Heim & Garten > Dekoration > Vasen -Heim & Garten > Dekoration > Vogelhäuschen -Heim & Garten > Dekoration > Vogeltränken -Heim & Garten > Dekoration > Wachs- & Ölwärmer -Heim & Garten > Dekoration > Wandapplikationen -Heim & Garten > Dekoration > Wandregale & Simse -Heim & Garten > Dekoration > Wetterfahnen & Dachdekoration -Heim & Garten > Dekoration > Windräder -Heim & Garten > Dekoration > Windspiele -Heim & Garten > Dekoration > Zierkissen -Heim & Garten > Dekoration > Zubehör für Fahnen und Windsäcke -Heim & Garten > Dekoration > Zubehör für Fahnen und Windsäcke > Beleuchtung für Fahnen- und Windsackstangen -Heim & Garten > Dekoration > Zubehör für Fahnen und Windsäcke > Stangen für Fahnen und Windsäcke -Heim & Garten > Dekoration > Zubehör für Vogelhäuschen -Heim & Garten > Dekoration > Zubehör zur Fensterdekoration -Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Ersatzteile für Vorhänge & Jalousien -Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Gardinen- & Vorhangringe -Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Gardinen- & Vorhangstangen -Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Gardinenhalter & -quasten -Heim & Garten > Feuer- & Gasschutz -Heim & Garten > Feuer- & Gasschutz > Feuerlöscher -Heim & Garten > Feuer- & Gasschutz > Feuerlöschkästen -Heim & Garten > Feuer- & Gasschutz > Feuermelder -Heim & Garten > Feuer- & Gasschutz > Feuermelder-Steuerungen -Heim & Garten > Feuer- & Gasschutz > Hitzemelder -Heim & Garten > Feuer- & Gasschutz > Kohlenmonoxiddetektoren -Heim & Garten > Feuer- & Gasschutz > Radondetektoren -Heim & Garten > Feuer- & Gasschutz > Rauchmelder -Heim & Garten > Feuer- & Gasschutz > Sprinkleranlagen -Heim & Garten > Haushaltsbedarf -Heim & Garten > Haushaltsbedarf > Abfallbehälter -Heim & Garten > Haushaltsbedarf > Abfallbehälter > Mülltonnen & Abfalleimer -Heim & Garten > Haushaltsbedarf > Abfallbehälter > Recycling-Behälter -Heim & Garten > Haushaltsbedarf > Abfallbehälter > Sondermüllbehälter -Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör -Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälter-Auszugsrahmen -Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälterdeckel -Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälterrollen -Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälterwagen -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrung & Ordnungssysteme für Geschenkpapier -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungsbehälter -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungsbeutel -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale > Kleiderständer -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale > Mehrzweckhaken -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale > Schirmständer -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Fotoaufbewahrung -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Fotoaufbewahrung > Fotoalben -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Fotoaufbewahrung > Fotoboxen -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Haushalts-Ordnungshelfer -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Hutschachteln -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Kleiderbügel -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Schuhregale & -schränke -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleinaufbewahrung / sonstige Aufbewahrung -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleinaufbewahrung / sonstige Aufbewahrung > Herrendiener -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleinaufbewahrung / sonstige Aufbewahrung > Kommoden-Organizer -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleinaufbewahrung / sonstige Aufbewahrung > Ladestationen -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Pillendosen -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Schubladensysteme -Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Tischbesteckkommoden -Heim & Garten > Haushaltsbedarf > Auskleidung für Schubladen & Regale -Heim & Garten > Haushaltsbedarf > Haushaltsthermometer -Heim & Garten > Haushaltsbedarf > Hygienepapiere -Heim & Garten > Haushaltsbedarf > Hygienepapiere > Küchenrollen & Papierhandtücher -Heim & Garten > Haushaltsbedarf > Hygienepapiere > Papierservietten -Heim & Garten > Haushaltsbedarf > Hygienepapiere > Papiertaschentücher -Heim & Garten > Haushaltsbedarf > Hygienepapiere > Toilettenpapier -Heim & Garten > Haushaltsbedarf > Luftentfeuchter -Heim & Garten > Haushaltsbedarf > Möbelgleiter -Heim & Garten > Haushaltsbedarf > Müllbeutel -Heim & Garten > Haushaltsbedarf > Müllpressezubehör -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Abzieher -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Besen -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Besen- & Bodenwischerstiele -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Eimer -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Ersatz-Wischmops -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Gewebe- & Polsterschutz -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Allzweckreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Backofenreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Edelstahlreiniger & -polituren -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Geschirrspülmittel & -seifen -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Glas- & Oberflächenreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Haushaltsdesinfektion -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Klarspüler -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Lederpflege- & Färbemittel -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Möbelreiniger & -Politur -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Reiniger für Hartholzböden -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Spülmaschinenreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Steinreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Teppichreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Textil- & Polsterreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Tiergeruchs- & Fleckenentferner -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Toilettenreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Wannen- & Kachelreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Waschmaschinenreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Kehrschaufeln -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Reinigungshandschuhe -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Scheuerbürsten -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Scheuerbürsten > Bürsten für Babyflaschen -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Schwämme & Topfreiniger -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Staubwedel & -Tücher -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Staubwedel-Ersatzköpfe -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Teppichkehrer -Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Wischmops & Bodenwischer -Heim & Garten > Haushaltsbedarf > Schuhpflege -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhabstreifer -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhanzieher -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhbeutel -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhbürsten -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpflege- & Färbemittel -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpflegesets -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpolierer -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpolituren & -wachse -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhspanner -Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhtrockner -Heim & Garten > Haushaltsbedarf > Schuhpflege > Stiefelknechte -Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung -Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Fallen -Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Fliegenklatschen -Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Insektenschutz -Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Insektenschutz > Mittel gegen Haushaltsinsekten -Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Insektenschutz > Tierabwehr -Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Schädlingsbekämpfungsmittel -Heim & Garten > Haushaltsbedarf > Teppichunterlagen -Heim & Garten > Haushaltsbedarf > Wäschepflege -Heim & Garten > Haushaltsbedarf > Wäschepflege > Bleichmittel -Heim & Garten > Haushaltsbedarf > Wäschepflege > Bügelbretter -Heim & Garten > Haushaltsbedarf > Wäschepflege > Bügelbrettunterlagen & -bezüge -Heim & Garten > Haushaltsbedarf > Wäschepflege > Fleckenentferner für Stoffe -Heim & Garten > Haushaltsbedarf > Wäschepflege > Fusselrasierer -Heim & Garten > Haushaltsbedarf > Wäschepflege > Fusselrollen -Heim & Garten > Haushaltsbedarf > Wäschepflege > Mittel gegen Falten & statische Aufladung -Heim & Garten > Haushaltsbedarf > Wäschepflege > Schweißabsorbierungspads -Heim & Garten > Haushaltsbedarf > Wäschepflege > Textilerfrischer -Heim & Garten > Haushaltsbedarf > Wäschepflege > Trockenreinigungsbedarf -Heim & Garten > Haushaltsbedarf > Wäschepflege > Waschbälle -Heim & Garten > Haushaltsbedarf > Wäschepflege > Waschpulver -Heim & Garten > Haushaltsbedarf > Wäschepflege > Weichspüler & Trocknertücher -Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäscheklammern -Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäschekörbe -Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäscheständer -Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäschestärke -Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäschesäcke & Waschkörbe -Heim & Garten > Haushaltsgeräte -Heim & Garten > Haushaltsgeräte > Bohner- & Poliermaschinen -Heim & Garten > Haushaltsgeräte > Dampf-Tapetenlöser -Heim & Garten > Haushaltsgeräte > Futontrockner -Heim & Garten > Haushaltsgeräte > Garagenparksensoren -Heim & Garten > Haushaltsgeräte > Garagentoröffner -Heim & Garten > Haushaltsgeräte > Garagenöffner -Heim & Garten > Haushaltsgeräte > Heim- & Gebäudeautomatisierung -Heim & Garten > Haushaltsgeräte > Heißwasserboiler -Heim & Garten > Haushaltsgeräte > Heißwasserboiler > Tauchsieder -Heim & Garten > Haushaltsgeräte > Klimatisierung -Heim & Garten > Haushaltsgeräte > Klimatisierung > Fog-Anlagen für den Außenbereich -Heim & Garten > Haushaltsgeräte > Klimatisierung > Kanalheizer -Heim & Garten > Haushaltsgeräte > Klimatisierung > Klimaanlagen -Heim & Garten > Haushaltsgeräte > Klimatisierung > Kotatsu -Heim & Garten > Haushaltsgeräte > Klimatisierung > Luftbefeuchter -Heim & Garten > Haushaltsgeräte > Klimatisierung > Luftreiniger -Heim & Garten > Haushaltsgeräte > Klimatisierung > Radiatoren -Heim & Garten > Haushaltsgeräte > Klimatisierung > Raumheizgeräte -Heim & Garten > Haushaltsgeräte > Klimatisierung > Raumtrocknungsgeräte -Heim & Garten > Haushaltsgeräte > Klimatisierung > Terrassenstrahler -Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren -Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Deckenventilatoren -Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Handventilatoren -Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Lüftungsventilatoren -Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Tisch- & Standventilatoren -Heim & Garten > Haushaltsgeräte > Klimatisierung > Verdunstungskühler -Heim & Garten > Haushaltsgeräte > Klimatisierung > Öfen & Kessel -Heim & Garten > Haushaltsgeräte > Nähmaschinen -Heim & Garten > Haushaltsgeräte > Nähmaschinen > Overlock-Nähmaschinen -Heim & Garten > Haushaltsgeräte > Staubsauger -Heim & Garten > Haushaltsgeräte > Teppich- & Dampfreinigungsgeräte -Heim & Garten > Haushaltsgeräte > Waschen & Trocknen -Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Bügeleisen -Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Dampfglätter für Bekleidung -Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Dampfpressen -Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Waschmaschinen -Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Waschtrockner -Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Wäschetrockner -Heim & Garten > Haushaltsgeräte-Zubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Abgasrohre -Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Boiler -Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Boilerwannen -Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Heizelemente -Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Heizungslüftung -Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Opferanoden -Heim & Garten > Haushaltsgeräte-Zubehör > Entfeuchterzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Entfeuchterzubehör > Entfeuchterfilter -Heim & Garten > Haushaltsgeräte-Zubehör > Heizkessel- & Boilerzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Heizkörperzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Heizkörperzubehör > Heizkörperreflexionsfolie -Heim & Garten > Haushaltsgeräte-Zubehör > Heizpilz-Zubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Heizpilz-Zubehör > Heizpilz-Abdeckungen -Heim & Garten > Haushaltsgeräte-Zubehör > Klimaanlagen-Zubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Klimaanlagen-Zubehör > Abdeckungen für Klimaanlagen -Heim & Garten > Haushaltsgeräte-Zubehör > Klimaanlagen-Zubehör > Klimaanlagenfilter -Heim & Garten > Haushaltsgeräte-Zubehör > Luftbefeuchter-Zubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Luftbefeuchter-Zubehör > Luftbefeuchterfilter -Heim & Garten > Haushaltsgeräte-Zubehör > Luftreinigerzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Luftreinigerzubehör > Luftreinigerfilter -Heim & Garten > Haushaltsgeräte-Zubehör > Nähmaschinenzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Nähmaschinenzubehör > Nähmaschinenfüße -Heim & Garten > Haushaltsgeräte-Zubehör > Nähmaschinenzubehör > Nähmaschinengehäuse & -abdeckungen -Heim & Garten > Haushaltsgeräte-Zubehör > Nähmaschinenzubehör > Nähmaschinennadeln -Heim & Garten > Haushaltsgeräte-Zubehör > Nähmaschinenzubehör > Spulen & Spulenhalter -Heim & Garten > Haushaltsgeräte-Zubehör > Staubsaugerzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Staubsaugerzubehör > Staubsauger-Antriebsriemen -Heim & Garten > Haushaltsgeräte-Zubehör > Staubsaugerzubehör > Staubsaugeraufsätze -Heim & Garten > Haushaltsgeräte-Zubehör > Staubsaugerzubehör > Staubsaugerbeutel -Heim & Garten > Haushaltsgeräte-Zubehör > Staubsaugerzubehör > Staubsaugerfilter -Heim & Garten > Haushaltsgeräte-Zubehör > Staubsaugerzubehör > Staubsaugerschläuche -Heim & Garten > Haushaltsgeräte-Zubehör > Teppich- und Dampfreinigerzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Ventilatorenzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Bügeleisenzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Waschmaschinenzubehör -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Waschmaschinenzubehör > Sockel für Waschmaschinen & Trockner -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Waschmaschinenzubehör > Waschmaschinenschläuche -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Waschmaschinenzubehör > Waschmaschinenventile -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Zubehör für Dampfmaschinen -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Zubehör für Dampfpressen -Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Zubehör für Wäschetrockner -Heim & Garten > Haussicherheit -Heim & Garten > Haussicherheit > Bewegungsmelder -Heim & Garten > Haussicherheit > Hausalarmsysteme -Heim & Garten > Haussicherheit > Safes & Tresore -Heim & Garten > Haussicherheit > Sensoren für Sicherheitssysteme -Heim & Garten > Haussicherheit > Sicherheitsleuchten -Heim & Garten > Haussicherheit > Tracking-Geräte -Heim & Garten > Haussicherheit > Überwachungskamera-Attrappen -Heim & Garten > Haussicherheit > Überwachungsmonitore & -rekorder -Heim & Garten > Holzöfen -Heim & Garten > Kamine -Heim & Garten > Kamine > Außenkamine -Heim & Garten > Kamine > Innenkamine -Heim & Garten > Küche & Esszimmer -Heim & Garten > Küche & Esszimmer > Bar-Utensilien -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Absinth-Fontänen -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Bierzapfhähne -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Dekanter -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Eiskübel -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Flaschenstöpsel & -verschlüsse -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Folienschneider -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Getränkeshaker & Zubehör -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Getränkeshaker & Zubehör > Bar-Eispickel -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Getränkeshaker & Zubehör > Cocktailshaker -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Getränkeshaker & Zubehör > Flaschenöffner -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Getränkeshaker & Zubehör > Getränkezubehörsets -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Glasuntersetzer & Bierdeckel -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Korkenzieher -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Untersetzerhalter -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Weindekantierer -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Weinglasanhänger -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Weinkübel & -kühler -Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Whisky-Steine -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Brotdosen & Tragetaschen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Feldflaschen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Flachmänner -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkedeckel -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkehüllen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkehüllen > Dosen- und Flaschenhüllen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkehüllen > Getränkebehälterhüllen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Isolierbehälter -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Kühlboxen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Kühltaschen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Picknickkörbe -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Thermosflaschen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Wasserflaschen -Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Weinflaschentaschen -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör > Sauerstoffabsorber -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör > Spender für Frischhaltefolie -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör > Verschlussstreifen & Verschlussclips -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Brotkästen & -taschen -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Frischhaltebeutel -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Honiggläser -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Kecksdosen & -behälter -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelabdeckhauben -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelbehälter -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Alufolien -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Frischhaltefolien -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Pergamentpapier -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Wachspapier -Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Nascheimer -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Auflaufförmchen & Souffléförmchen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Back- & Plätzchenbleche -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Backzubehörsets -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Brotbackformen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Bräter -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Grillbleche mit Fettpfannen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Kuchen- & Quichebackformen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Kuchenbackformen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Muffin- & Cupcakebackformen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Pizzableche -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Pizzasteine -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Spezialbackformen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör > Backgewichte -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör > Backmatten & -formen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör > Brätereinsätze -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör > Papierbackförmchen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr & Backformen (Kombisets) -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Auflaufformen & Kasserollen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Grillpfannen & -aufsätze -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Grillpressen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Kochgeschirrsets -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Paellapfannen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Pfannen für Crêpes und Pfannkuchen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Rum- & Einmachtöpfe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Sautépfannen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Schmortöpfe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Schnellkochtöpfe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Schnellkochtöpfe > Elektrische Schnellkochtöpfe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Stiel- & Bratpfannen -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Stieltöpfe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Suppentöpfe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Tajines -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Wasserbadtopf -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Wasserkessel -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Woks -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Dampfkörbe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Schnellkochtopfzubehör -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Topf- & Pfannendeckel -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Topf- & Pfannengriffe -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Wokzubehör -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Wokzubehör > Wokbürsten -Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Wokzubehör > Wokringe -Heim & Garten > Küche & Esszimmer > Küchengeräte -Heim & Garten > Küche & Esszimmer > Küchengeräte > Abfallzerkleinerer -Heim & Garten > Küche & Esszimmer > Küchengeräte > Abzugshauben -Heim & Garten > Küche & Esszimmer > Küchengeräte > Allesschneider -Heim & Garten > Küche & Esszimmer > Küchengeräte > Allesschneider > Aufschnittmaschine -Heim & Garten > Küche & Esszimmer > Küchengeräte > Außengrills -Heim & Garten > Küche & Esszimmer > Küchengeräte > Außengrills > Gasgrills -Heim & Garten > Küche & Esszimmer > Küchengeräte > Außengrills > Holzkohlegrills -Heim & Garten > Küche & Esszimmer > Küchengeräte > Backöfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Backöfen > Durchlauföfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Backöfen > Etagenöfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Backöfen > Wandöfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Brotbackautomaten -Heim & Garten > Küche & Esszimmer > Küchengeräte > Campingkocher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Crêpe-Geräte -Heim & Garten > Küche & Esszimmer > Küchengeräte > Dörrautomaten -Heim & Garten > Küche & Esszimmer > Küchengeräte > Eis-Shaver -Heim & Garten > Küche & Esszimmer > Küchengeräte > Eismaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Elektrische Pfannen & Woks -Heim & Garten > Küche & Esszimmer > Küchengeräte > Elektrogrills & -bratplatten -Heim & Garten > Küche & Esszimmer > Küchengeräte > Elektrogrills & -bratplatten > Elektrische Grillpfannen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Elektrogrills & -bratplatten > Elektrogrills -Heim & Garten > Küche & Esszimmer > Küchengeräte > Entsafter -Heim & Garten > Küche & Esszimmer > Küchengeräte > Entsafter > Handentsafter -Heim & Garten > Küche & Esszimmer > Küchengeräte > Fonduesets -Heim & Garten > Küche & Esszimmer > Küchengeräte > Fritteusen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Gasgrillplatten -Heim & Garten > Küche & Esszimmer > Küchengeräte > Gefrierschränke & -truhen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Geschirrspüler -Heim & Garten > Küche & Esszimmer > Küchengeräte > Getränkewärmer -Heim & Garten > Küche & Esszimmer > Küchengeräte > Heißgetränkebereiter -Heim & Garten > Küche & Esszimmer > Küchengeräte > Joghurtmaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Espressokannen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Espressomaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Filterkaffeemaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > French Presses -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Perkolatoren & Kaffeebrüher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Vakuumbereiter -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochfelder -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochplatten -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Dampfgarer -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Eierkocher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Langsamkocher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Reiskocher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Thermokocher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Öfen zum Vakuumgaren -Heim & Garten > Küche & Esszimmer > Küchengeräte > Küchenherde -Heim & Garten > Küche & Esszimmer > Küchengeräte > Kühlschränke -Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittel-Räucheröfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittelmühlen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittelmühlen > Fleischwölfe -Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittelmühlen > Getreidemühlen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittelmühlen > Gewürzmühlen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittelmühlen > Kaffeemühlen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Messerschärfer -Heim & Garten > Küche & Esszimmer > Küchengeräte > Mikrowellenherde -Heim & Garten > Küche & Esszimmer > Küchengeräte > Milchaufschäumer -Heim & Garten > Küche & Esszimmer > Küchengeräte > Mochi-Maschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Müllpressen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Nudelmaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Popcornmaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Roaster Ovens & Mini-Backöfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Rühr- & Küchenmaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Rührgeräte -Heim & Garten > Küche & Esszimmer > Küchengeräte > Shlushmaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Sojamilchbereiter -Heim & Garten > Küche & Esszimmer > Küchengeräte > Speiseeismaschinen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer -Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer > Speisewärmelampen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer > Warmhaltebehälter -Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer > Warmhaltetische -Heim & Garten > Küche & Esszimmer > Küchengeräte > Standmixer & Pürierstäbe -Heim & Garten > Küche & Esszimmer > Küchengeräte > Teekocher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Temperiermaschinen für Schokolade -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Brezelbackautomat -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Donutmaker -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Muffin- & Cupcake-Maker -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Pizzaöfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Pizzelle-Eisen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Quesadilla- & Tortilla-Maker -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Sandwichtoaster -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Toaster -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Toastöfen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Waffeleisen -Heim & Garten > Küche & Esszimmer > Küchengeräte > Trinkwasserspender -Heim & Garten > Küche & Esszimmer > Küchengeräte > Vakuumierer -Heim & Garten > Küche & Esszimmer > Küchengeräte > Wasserfilter -Heim & Garten > Küche & Esszimmer > Küchengeräte > Wasserkocher -Heim & Garten > Küche & Esszimmer > Küchengeräte > Wassersprudler -Heim & Garten > Küche & Esszimmer > Küchengeräte > Weinkühlschränke -Heim & Garten > Küche & Esszimmer > Küchengeräte > Zuckerwattemaschinen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Abkühlgitter -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Abtropf- & Küchensiebe -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Allespicker & Spieße -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Ausstechförmchen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Backpinsel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Backschaufeln -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Bonbon- & Pralinenformen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Bratenspritzen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Bratschläuche -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dampfgarbeutel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dessertformen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dosenpressen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dosenöffner -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dressing-Shaker -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Eiswürfelformen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Elektromesser -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Elektromesserzubehör -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Elektromesserzubehör > Elektromesser-Ersatzklingen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Essig- & Ölspender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Flambierbrenner -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Fleischgabeln -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Fleischklopfer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Fleischpistolen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Geschirrständer & Abtropfflächen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Getränkespender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kartoffelpressen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Keksmaschine -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kellen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Knoblauchpressen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kochthermometer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kuchenverzierungsbedarf -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kurzzeitmesser & Eieruhren -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenformen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenmesser -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Aufbewahrungssysteme für Getränkepads -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Besteckkästen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Gewürzregale & -ständer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Halter für Küchenutensilien -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Konservenregal -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Küchenkarusselle -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Küchenrollenhalter & -spender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Küchenschranksysteme -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Messerblöcke & -halter -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Serviettenhalter & -spender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Topfregale -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Trinkgefäßhalter -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Trinkhalmhalter & -spender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Zahnstocherbehälter & -spender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Zuckertütenhalter -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber > Grillschaber -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber > Teigschaber -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber > Teigspatel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenscheren -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschneidegeräte -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschneidegeräte > Brotschneidemaschinen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschneidegeräte > Eierschneider -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschneidegeräte > Gemüsehobel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschneidegeräte > Käsehobel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenthermometer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenutensilien-Sets -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenwaagen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenzangen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Löffelablagen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Mehlsiebe -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Messbecher & Dosierlöffel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Mörser & Stößel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Nahrungsmittelspender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pastaförmchen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pfannenwender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pizzaschneider -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pizzaschneider-Zubehör -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer > Eiscremeportionierer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer > Eisportionierer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer > Kugelausstecher -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Reiben -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Rührschüsseln -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Salatschleudern -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Saucenspender -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schaumlöffel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schneebesen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schneidebretter -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schneidemaschinen für Lebensmittel -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schäler -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schürzen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker > Hummer- & Krebszangen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker > Nussknacker -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker > Nussknacker > Dekorative Nussknacker -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spülbeckenkörbe -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spülbeckenmatten -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Stampfer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Stieleisformen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Sushi-Matten -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teesiebe -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigmischer -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollenzubehör -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollenzubehör > Abstandsringe für Teigrollen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollenzubehör > Teigrollenhüllen & -überzüge -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigräder -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigtücher -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Topfhandschuhe & Topflappen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Tortenheber -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Würfelschneider & Zerkleinerungsgeräte -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Ziseliermesser -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Zitruspressen -Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Zuckerspender -Heim & Garten > Küche & Esszimmer > Tafelgeschirr -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr > Geschirrsets -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr > Schüsseln -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr > Teller -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Kaffee- & Teekannen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Kaffee- & Teeservices -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Salz- & Pfefferstreuer -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck > Bowlenschüsseluntersatz -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck > Terrinendeckel -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck > Terrinenuntersatz -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Bowleschüsseln -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Butterdosen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Eierbecher -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Karaffen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Kuchenplatten -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Saucièren -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Servierplatten -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Serviertabletts -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Terrinen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Tortenständer -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Zuckerdosen & Milchkännchen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Besteck-Sets -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Essstäbchen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Essstäbchenzubehör -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Essstäbchenzubehör > Essstäbchenaufsätze -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Essstäbchenzubehör > Essstäbchenbank -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Gabeln -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Löffel -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Tafelmesser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Topfuntersetzer -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Biergläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Biergläser > Krüge & Bierhumpen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Biergläser > Pilsgläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Biergläser > Pint-Gläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- & Teebecher -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- und Teetassen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- und Teetassen > Kaffeetassen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- und Teetassen > Teetassen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- und Teeuntertassen -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Schnapsgläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Stielgläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Stielgläser > Kognakschwenker -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Stielgläser > Margarita-Gläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Stielgläser > Martini-Gläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Stielgläser > Sektgläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Stielgläser > Weingläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Trinkbehältersets -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Trinkgläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Trinkgläser > Highball-Gläser -Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Trinkgläser > Tumbler -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Anzündkamine -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Außengrillabdeckungen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Außengrillroste & -auflagen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Außengrillspieße & -körbe -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Grillbrenner -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Grillbretter -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Grillwagen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Holzkohle -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Räucherchips & -Pellets -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Backofenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Backofenzubehör > Backofeninnenverkleidungen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Backofenzubehör > Backofenschutz -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Backofenzubehör > Ofenroste -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Dörrautomatenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Dörrautomatenzubehör > Dörrautomatenbleche -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Dörrautomatenzubehör > Dörrautomatentabletts -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Eis-Shaver-Zubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Entsafterzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fonduesetzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fonduesetzubehör > Fonduegabeln -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fonduesetzubehör > Fonduetopfständer -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fritteusenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fritteusenzubehör > Fritteusenkörbe -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Gasherdzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Gasherdzubehör > Gasherdaufsätze -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Herdzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Herdzubehör > Herdabdeckungen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Herdzubehör > Herdauffangwannen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Küchenabfallzerkleinerer-Zubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Kühlschrankzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Mikrowellenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Mikrowellenzubehör > Mikrowellen Trim-Kits -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Mikrowellenzubehör > Mikrowellen-Schublade -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Mixerzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Mixerzubehör > Mixbecher -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Mixerzubehör > Mixerdeckel -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Nudelmaschinenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör > Knethaken für Rührgeräte -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör > Rührbesen für Rührgeräte -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör > Rührgeräteaufsätze -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör > Rührgeräteaufsätze > Entsafteraufsätze -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör > Rührgeräteaufsätze > Fleischwolfaufsätze -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör > Rührgeräteaufsätze > Nudelmaschinenaufsätze -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Rührgerätezubehör > Schüsseln für Rührgeräte -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Speiseeismaschinenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Speiseeismaschinenzubehör > Gefrierschüsseln für Speiseeismaschinen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Spülmaschinenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Spülmaschinenzubehör > Spülmaschineneinsätze für Gläser -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Toasterzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Vakuumiererzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Vakuumiererzubehör > Vakuumierer-Beutel -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Wasserspenderzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Wasserspenderzubehör > Flaschen für Wasserspender -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zerkleinererzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Brotbackautomaten -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Campingöfen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Eismaschinen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Gefriertruhen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Joghurtmaschinen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Aufschäumer -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Espressokocherteile -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeefilter -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeefilterkörbe -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeekannen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeekannenwarmhalter -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Siebträger -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Wasserfilter für Kaffeemaschinen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Lebensmittelmühlen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Lebensmittelmühlen > Fleischwolfzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Lebensmittelmühlen > Kaffeemühlenzubehör -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Lebensmittelmühlen > Zubehör für Gewürzmühlen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Popcornmaschinen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Warmhaltetheken -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Warmhaltetheken > Behälter für Warmhaltetheken -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Warmhaltetheken > Deckel für Warmhaltebehälter -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Zuckerwattemaschinen -Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für elektrische Töpfe & Woks -Heim & Garten > Notfallvorsorge -Heim & Garten > Notfallvorsorge > Erdbebenmelder -Heim & Garten > Notfallvorsorge > Möbelanker -Heim & Garten > Notfallvorsorge > Notfallwerkzeuge -Heim & Garten > Notfallvorsorge > Notvorräte -Heim & Garten > Pflanzen -Heim & Garten > Pflanzen > Blumen -Heim & Garten > Pflanzen > Bäume -Heim & Garten > Pflanzen > Grünpflanzen, Büsche & Sträucher -Heim & Garten > Pflanzen > Grünpflanzen, Büsche & Sträucher > Gartenpflanzen -Heim & Garten > Pflanzen > Grünpflanzen, Büsche & Sträucher > Zimmerpflanzen -Heim & Garten > Pflanzen > Saatgut -Heim & Garten > Pflanzen > Wasserpflanzen -Heim & Garten > Pool & Spa -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Badeinseln & Schwimmliegen -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Badeinseln & Schwimmliegen > Baby-Luftmatratzen & Baby-Schwimmringe -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Badespielzeug -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Mechanische & Chemische Poolreiniger -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Pool- & Whirlpool-Filter -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolabdeckungen -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolbürsten -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolleitern -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolreinigungsgeräte -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolskimmer -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolsysteme -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Schläuche für Poolreiniger -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Schwimmflügel -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Sprungbretter -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Swimmingpoolheizungen -Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Wasserrutschen -Heim & Garten > Pool & Spa > Pools -Heim & Garten > Pool & Spa > Saunen -Heim & Garten > Pool & Spa > Spa-Becken -Heim & Garten > Rasen & Garten -Heim & Garten > Rasen & Garten > Bewässerungssysteme -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gartenschlauchsprühköpfe -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gartenschlauchzubehör & -ventile -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gartenschläuche -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gießkannen -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinkler & Köpfe -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinkler & Köpfe > Sprinkler -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinkler & Köpfe > Sprinklerköpfe -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinklersysteme -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinklersysteme > Sprinklerventile -Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinklersysteme > Steuerelemente für Sprinkleranlagen -Heim & Garten > Rasen & Garten > Garten & Balkon -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Bögen, Gitter, Laubengänge & Pergolen -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Gartenbrücken -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Dächer für Pavillions -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Gewichte für Sonnendächer -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Rahmen für Pavillons -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Seitenwand-Sets für Pavillons -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Stangen für Sonnendächer -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillons & Gartenlauben -Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Schuppen & Lagerung -Heim & Garten > Rasen & Garten > Garten & Balkon > Hollywoodschaukeln -Heim & Garten > Rasen & Garten > Garten & Balkon > Hängematten -Heim & Garten > Rasen & Garten > Garten & Balkon > Hängemattenzubehör -Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken -Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken > Picknickdecken -Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken > Poncholiner -Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken > Strandmatten -Heim & Garten > Rasen & Garten > Garten & Balkon > Sonnenschirm- und Markisenzubehör -Heim & Garten > Rasen & Garten > Garten & Balkon > Sonnenschirm- und Markisenzubehör > Beleuchtung für Sonnenschirme -Heim & Garten > Rasen & Garten > Garten & Balkon > Sonnenschirm- und Markisenzubehör > Sonnenschirmschutzhüllen -Heim & Garten > Rasen & Garten > Garten & Balkon > Sonnenschirm- und Markisenzubehör > Sonnenschirmstoff -Heim & Garten > Rasen & Garten > Garten & Balkon > Sonnenschirm- und Markisenzubehör > Sonnenschirmständer -Heim & Garten > Rasen & Garten > Garten & Balkon > Sonnenschirme -Heim & Garten > Rasen & Garten > Gartenbau -Heim & Garten > Rasen & Garten > Gartenbau > Blumentöpfe & Pflanzgefäße -Heim & Garten > Rasen & Garten > Gartenbau > Dünger -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Astsägen -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Baumscheren -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Gartenbauutensilien -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Gartenbauutensilien > Gartenhacken -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Gartensicheln -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Geräte zum Pflanzen von Knollen -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Hacken & Spitzhacken -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Haumesser -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Macheten -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Mistgabeln -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Pflanzkellen -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Rasen- & Gartenspritzgeräte -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Rasenkantentrimmer -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Rasenlüfter -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Rechen -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Schaufeln & Spaten -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Schubkarren -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Schubkarrenteile -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Strahlstöcke -Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Streugeräte -Heim & Garten > Rasen & Garten > Gartenbau > Gewächshäuser -Heim & Garten > Rasen & Garten > Gartenbau > Herbizide -Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren -Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren > Kompost -Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren > Komposter -Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren > Kompostlüfter -Heim & Garten > Rasen & Garten > Gartenbau > Krankheitsbekämpfung -Heim & Garten > Rasen & Garten > Gartenbau > Mulch -Heim & Garten > Rasen & Garten > Gartenbau > Pflanzenständer -Heim & Garten > Rasen & Garten > Gartenbau > Pflanzenstützen -Heim & Garten > Rasen & Garten > Gartenbau > Pflanzenstützstäbe & -gitter -Heim & Garten > Rasen & Garten > Gartenbau > Regenfässer -Heim & Garten > Rasen & Garten > Gartenbau > Sand & Gartenerde -Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies -Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies-Zubehör -Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies-Zubehör > Erdanker & -nägel -Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies-Zubehör > Unkrautvlies - Gewebeband -Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit -Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit > Gartentaschen -Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit > Kniekissen -Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit > Umtopftische -Heim & Garten > Rasen & Garten > Gartenmaschinen -Heim & Garten > Rasen & Garten > Gartenmaschinen > Bodenbearbeitungsmaschinen -Heim & Garten > Rasen & Garten > Gartenmaschinen > Elektrische Heckenscheren -Heim & Garten > Rasen & Garten > Gartenmaschinen > Elektrische Kombi-Ausstattung -Heim & Garten > Rasen & Garten > Gartenmaschinen > Elektrische Kombi-Gartenmaschinen -Heim & Garten > Rasen & Garten > Gartenmaschinen > Hochdruckreiniger -Heim & Garten > Rasen & Garten > Gartenmaschinen > Kettensägen -Heim & Garten > Rasen & Garten > Gartenmaschinen > Laubbläser -Heim & Garten > Rasen & Garten > Gartenmaschinen > Laubsauger -Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher -Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Aufsitzrasenmäher -Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Handrasenmäher -Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Mähroboter -Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Quad-Anhänger -Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasentrimmer & Freischneider -Heim & Garten > Rasen & Garten > Gartenmaschinen > Schneefräsen -Heim & Garten > Rasen & Garten > Gartenmaschinen > Traktoren -Heim & Garten > Rasen & Garten > Schnee- und Eisbeseitigung -Heim & Garten > Rasen & Garten > Schnee- und Eisbeseitigung > Eiskratzer -Heim & Garten > Rasen & Garten > Schnee- und Eisbeseitigung > Schneeschaufeln -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Batterien für elektrische Kombi-Gartenmaschinen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Batterien für elektrische Kombi-Gartenmaschinen > Batterien für Heckenschneider -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Batterien für elektrische Kombi-Gartenmaschinen > Batterien für Unkrauttrimmer -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Batterien für elektrische Kombi-Gartenmaschinen > Rasenmäherbatterien -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Heckenscheren-Zubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Heckenscheren-Zubehör > Heckenscheren-Aufsätze -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Hochdruckreiniger-Zubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Kettensägenzubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Kettensägenzubehör > Kettensägenketten -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Kettensägenzubehör > Kettensägenschwerter -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Laubbläser-Zubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Laubbläser-Zubehör > Laubbläser-Erweiterungen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasentrimmer-Zubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasentrimmer-Zubehör > Rasentrimmer-Aufsätze -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Schneefräsenzubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Traktorteile & Zubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Unkrauttrimmer-Zubehör -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Unkrauttrimmer-Zubehör > Abdeckungen für Unkrauttrimmer-Kabelrollen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Unkrauttrimmer-Zubehör > Messer & Kabelrollen für Unkrauttrimmer -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Unkrauttrimmer-Zubehör > Unkrauttrimmer-Aufsätze -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Grasauffangbehälter -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenkehrmaschinen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenmäher-Keilriemen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenmäher-Reifen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenmäher-Riemenscheiben -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenmäher-Räder -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenmäher-Zusatzteile -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenmäherabdeckungen -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Rasenmähermesser -Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Zubehör für Rasenmäher > Wiesenmäher-Zusatzteile -Heim & Garten > Rauchzubehör -Heim & Garten > Rauchzubehör > Aschenbecher -Heim & Garten > Rauchzubehör > Feuerzeuge -Heim & Garten > Rauchzubehör > Humidore -Heim & Garten > Rauchzubehör > Humidorzubehör -Heim & Garten > Rauchzubehör > Streichhölzer -Heim & Garten > Rauchzubehör > Zigarettenkisten -Heim & Garten > Rauchzubehör > Zigarrenkisten -Heim & Garten > Rauchzubehör > Zigarrenschneider -Heim & Garten > Schutzhüllen für Sonnenschirme -Heim & Garten > Sonnen- & Regenschirme -Heim & Garten > Zubehör für Kamine & Holzöfen -Heim & Garten > Zubehör für Kamine & Holzöfen > Blasebälge -Heim & Garten > Zubehör für Kamine & Holzöfen > Feuerholz & Brennstoffe -Heim & Garten > Zubehör für Kamine & Holzöfen > Feuerholz-Aufbewahrung -Heim & Garten > Zubehör für Kamine & Holzöfen > Holzofenventilatoren & -gebläse -Heim & Garten > Zubehör für Kamine & Holzöfen > Kamin- & Holzofenroste -Heim & Garten > Zubehör für Kamine & Holzöfen > Kaminbodenplatten -Heim & Garten > Zubehör für Kamine & Holzöfen > Kaminböcke -Heim & Garten > Zubehör für Kamine & Holzöfen > Kamingitter -Heim & Garten > Zubehör für Kamine & Holzöfen > Kaminreflektoren -Heim & Garten > Zubehör für Kamine & Holzöfen > Kaminwerkzeug -Heim & Garten > Zubehör für Kamine & Holzöfen > Zubehör für Feuerholz-Aufbewahrung -Heimwerkerbedarf -Heimwerkerbedarf > Baumaterialien -Heimwerkerbedarf > Baumaterialien > Arbeitsplatten -Heimwerkerbedarf > Baumaterialien > Arbeitsplatten > Granitarbeitsplatten -Heimwerkerbedarf > Baumaterialien > Arbeitsplatten > Hartholzarbeitsplatten -Heimwerkerbedarf > Baumaterialien > Arbeitsplatten > Keramik- & Porzellanarbeitsplatten -Heimwerkerbedarf > Baumaterialien > Arbeitsplatten > Kunststoffbeschichtete Arbeitsplatten -Heimwerkerbedarf > Baumaterialien > Arbeitsplatten > Marmorarbeitsplatten -Heimwerkerbedarf > Baumaterialien > Arbeitsplatten > Schichtstoffarbeitsplatten -Heimwerkerbedarf > Baumaterialien > Bauholz -Heimwerkerbedarf > Baumaterialien > Fenster -Heimwerkerbedarf > Baumaterialien > Fensterläden -Heimwerkerbedarf > Baumaterialien > Fliesen -Heimwerkerbedarf > Baumaterialien > Fliesen > Fliesenböden -Heimwerkerbedarf > Baumaterialien > Fliesen > Geflieste Arbeitsplatten -Heimwerkerbedarf > Baumaterialien > Fußböden -Heimwerkerbedarf > Baumaterialien > Fußböden > Granitböden -Heimwerkerbedarf > Baumaterialien > Fußböden > Hartholzböden -Heimwerkerbedarf > Baumaterialien > Fußböden > Kautschukbeläge -Heimwerkerbedarf > Baumaterialien > Fußböden > Keramik- & Porzellanböden -Heimwerkerbedarf > Baumaterialien > Fußböden > Künstlicher Torf -Heimwerkerbedarf > Baumaterialien > Fußböden > Laminatböden -Heimwerkerbedarf > Baumaterialien > Fußböden > Marmorböden -Heimwerkerbedarf > Baumaterialien > Fußböden > Vinylböden -Heimwerkerbedarf > Baumaterialien > Glas -Heimwerkerbedarf > Baumaterialien > Leisten -Heimwerkerbedarf > Baumaterialien > Luken -Heimwerkerbedarf > Baumaterialien > Mauersteine, Steine & Beton -Heimwerkerbedarf > Baumaterialien > Schalldämpfende Materialien -Heimwerkerbedarf > Baumaterialien > Teppichböden -Heimwerkerbedarf > Baumaterialien > Treppen -Heimwerkerbedarf > Baumaterialien > Türen -Heimwerkerbedarf > Baumaterialien > Türen > Garagentore -Heimwerkerbedarf > Baumaterialien > Türen > Haustüren -Heimwerkerbedarf > Baumaterialien > Türen > Haustüren > Fliegengittertüren -Heimwerkerbedarf > Baumaterialien > Türen > Sonstige Türen -Heimwerkerbedarf > Baumaterialien > Türen > Sonstige Türen > Haustiertüren -Heimwerkerbedarf > Baumaterialien > Wandverkleidung -Heimwerkerbedarf > Bauzubehör -Heimwerkerbedarf > Bauzubehör > Abdeckfolien -Heimwerkerbedarf > Bauzubehör > Betonformen -Heimwerkerbedarf > Bauzubehör > Bindegarne -Heimwerkerbedarf > Bauzubehör > Draht -Heimwerkerbedarf > Bauzubehör > Dübel -Heimwerkerbedarf > Bauzubehör > Filter & Siebe -Heimwerkerbedarf > Bauzubehör > Flaschenzüge -Heimwerkerbedarf > Bauzubehör > Gasschläuche -Heimwerkerbedarf > Bauzubehör > Halterungen -Heimwerkerbedarf > Bauzubehör > Holzdübel & -stäbe -Heimwerkerbedarf > Bauzubehör > Holzplättchen -Heimwerkerbedarf > Bauzubehör > Ketten -Heimwerkerbedarf > Bauzubehör > Klebebänder -Heimwerkerbedarf > Bauzubehör > Klebebänder > Abdeckband -Heimwerkerbedarf > Bauzubehör > Klebebänder > Folienklebeband -Heimwerkerbedarf > Bauzubehör > Klebebänder > Gafferband -Heimwerkerbedarf > Bauzubehör > Klebebänder > Gewebeband -Heimwerkerbedarf > Bauzubehör > Klebebänder > Heizungsband -Heimwerkerbedarf > Bauzubehör > Klebebänder > Isolierband -Heimwerkerbedarf > Bauzubehör > Klebebänder > Klebe- & Gitterband für Gipskartonplatten -Heimwerkerbedarf > Bauzubehör > Klebebänder > Kupferband -Heimwerkerbedarf > Bauzubehör > Klebebänder > Teflonband -Heimwerkerbedarf > Bauzubehör > Luftdurchlässe & Abzugsrohre -Heimwerkerbedarf > Bauzubehör > Luftschläuche -Heimwerkerbedarf > Bauzubehör > Lötmetall & Flussmittel -Heimwerkerbedarf > Bauzubehör > Nieten -Heimwerkerbedarf > Bauzubehör > Nägel -Heimwerkerbedarf > Bauzubehör > Planen -Heimwerkerbedarf > Bauzubehör > Riegel -Heimwerkerbedarf > Bauzubehör > Scharniere -Heimwerkerbedarf > Bauzubehör > Schmiermittel -Heimwerkerbedarf > Bauzubehör > Schmierschläuche -Heimwerkerbedarf > Bauzubehör > Schrankbauteile -Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schrankbeschläge -Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schrankknäufe & -griffe -Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schrankscharniere -Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schrankschlösser -Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schranktüren -Heimwerkerbedarf > Bauzubehör > Schrauben -Heimwerkerbedarf > Bauzubehör > Schrauben & Muttern -Heimwerkerbedarf > Bauzubehör > Schrauben > Gipskartonschrauben -Heimwerkerbedarf > Bauzubehör > Schrauben > Holzschrauben -Heimwerkerbedarf > Bauzubehör > Schrauben > Metallschrauben -Heimwerkerbedarf > Bauzubehör > Schraubverbinder -Heimwerkerbedarf > Bauzubehör > Seile -Heimwerkerbedarf > Bauzubehör > Spanngummis -Heimwerkerbedarf > Bauzubehör > Spanngurte -Heimwerkerbedarf > Bauzubehör > Spulen -Heimwerkerbedarf > Bauzubehör > Steuerungen -Heimwerkerbedarf > Bauzubehör > Steuerungen > Heizungs- & Klimaanlagen Steuerungen -Heimwerkerbedarf > Bauzubehör > Steuerungen > Schalt- & Bedienungstafeln -Heimwerkerbedarf > Bauzubehör > Steuerungen > Thermostate -Heimwerkerbedarf > Bauzubehör > Türbeschläge & -klingeln -Heimwerkerbedarf > Bauzubehör > Türbeschläge & -klingeln > Schlossfallen -Heimwerkerbedarf > Bauzubehör > Türbeschläge & -klingeln > Türklingeln -Heimwerkerbedarf > Bauzubehör > Türbeschläge & -klingeln > Türklopfer -Heimwerkerbedarf > Bauzubehör > Türbeschläge & -klingeln > Türknäufe & -klinken -Heimwerkerbedarf > Bauzubehör > Türbeschläge & -klingeln > Türschließer -Heimwerkerbedarf > Bauzubehör > Türbeschläge & -klingeln > Türstopper -Heimwerkerbedarf > Bauzubehör > Unterlegscheiben -Heimwerkerbedarf > Bauzubehör > Warnklebeband -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Dienst- & Werkzeuggürtel -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Gartenschlauchhalterungen -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkbänke -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugetuis -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugkästen -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugschränke -Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugtaschen -Heimwerkerbedarf > Bauzubehör > Zugschalterketten und -kordeln -Heimwerkerbedarf > Bedachung -Heimwerkerbedarf > Bedachung > Dachrinnen -Heimwerkerbedarf > Bedachung > Kehlbleche -Heimwerkerbedarf > Bedachung > Zubehör für Dachrinnen -Heimwerkerbedarf > Chemikalien -Heimwerkerbedarf > Chemikalien > Abflussreiniger -Heimwerkerbedarf > Chemikalien > Ammonium -Heimwerkerbedarf > Chemikalien > Beton- & Mauerreiniger -Heimwerkerbedarf > Chemikalien > Enteiser -Heimwerkerbedarf > Chemikalien > Holzterrassen- & -zaunreiniger -Heimwerkerbedarf > Chemikalien > Kaminreiniger -Heimwerkerbedarf > Chemikalien > Reiniger für Abwassertanks & Senkgruben -Heimwerkerbedarf > Chemikalien > Säureneutralisierer -Heimwerkerbedarf > Elektrikbedarf -Heimwerkerbedarf > Elektrikbedarf > Anschlussdosen & Halterungen -Heimwerkerbedarf > Elektrikbedarf > Drahtbindemaschinen -Heimwerkerbedarf > Elektrikbedarf > Drahtspulen -Heimwerkerbedarf > Elektrikbedarf > Elektronische Leitungen -Heimwerkerbedarf > Elektrikbedarf > Elektroschalter -Heimwerkerbedarf > Elektrikbedarf > Elektroschalter > Lichtschalter -Heimwerkerbedarf > Elektrikbedarf > Laderegler -Heimwerkerbedarf > Elektrikbedarf > Relais -Heimwerkerbedarf > Elektrikbedarf > Schrumpfschläuche -Heimwerkerbedarf > Elektrikbedarf > Steckdosen -Heimwerkerbedarf > Elektrikbedarf > Steckdosenabdeckungen -Heimwerkerbedarf > Elektrikbedarf > Verlängerungskabel -Heimwerkerbedarf > Elektrikbedarf > Verlängerungskabelzubehör -Heimwerkerbedarf > Elektrikbedarf > Verlängerungskabelzubehör > Kabeltrommeln für Verlängerungskabel -Heimwerkerbedarf > Elektrikbedarf > Verlängerungskabelzubehör > Verlängerungskabelstecker -Heimwerkerbedarf > Elektrikbedarf > Verteilerkästen -Heimwerkerbedarf > Elektrikbedarf > Vorschaltgeräte & Starter -Heimwerkerbedarf > Elektrikbedarf > Wandplatten -Heimwerkerbedarf > Elektrikbedarf > Zeitschaltuhren -Heimwerkerbedarf > Elektrikbedarf > Überbrückungsschalter -Heimwerkerbedarf > Erneuerbare Energie -Heimwerkerbedarf > Erneuerbare Energie > Solarenergie -Heimwerkerbedarf > Erneuerbare Energie > Solarenergie > Solarenergie-Kits -Heimwerkerbedarf > Erneuerbare Energie > Solarenergie > Solarpaneele -Heimwerkerbedarf > Erneuerbare Energie > Windkraft -Heimwerkerbedarf > Erneuerbare Energie > Windkraft > Windturbinen -Heimwerkerbedarf > Generatoren -Heimwerkerbedarf > Hauseinzäunung -Heimwerkerbedarf > Hauseinzäunung > Tore -Heimwerkerbedarf > Hauseinzäunung > Zaunlatten -Heimwerkerbedarf > Hauseinzäunung > Zaunpfosten -Heimwerkerbedarf > Hauseinzäunung > Zäune -Heimwerkerbedarf > Hauseinzäunung > Zäune > Drahtzaun -Heimwerkerbedarf > Hauseinzäunung > Zäune > Drahtzaun > Maschendraht -Heimwerkerbedarf > Hauseinzäunung > Zäune > Drahtzaun > Stacheldraht -Heimwerkerbedarf > Isolierung -Heimwerkerbedarf > Isolierung > Fenster- & Türisolierung -Heimwerkerbedarf > Isolierung > Gebäudeisolierung -Heimwerkerbedarf > Isolierung > Rohrisolierung -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Beschichtungen -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Dichtungsmittel -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Fugendichtmittel -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Fugenmassen -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime > Glitzerkleber -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime > Gummikleber -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime > Heißklebesticks -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime > Holzleim -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime > Klebestifte -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime > Sekundenkleber -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Leime > Weißleim -Heimwerkerbedarf > Leime, Beschichtungen & Dichtungsmittel > Zement -Heimwerkerbedarf > Möbelbau -Heimwerkerbedarf > Sanitärinstallationen -Heimwerkerbedarf > Sanitärinstallationen > Abflusszubehör -Heimwerkerbedarf > Sanitärinstallationen > Abflusszubehör > Abflussauskleidung bzw. -Abdichtung -Heimwerkerbedarf > Sanitärinstallationen > Abflusszubehör > Abflussgitter -Heimwerkerbedarf > Sanitärinstallationen > Abflusszubehör > Abflussreinigungswerkzeug -Heimwerkerbedarf > Sanitärinstallationen > Abflusszubehör > Kanal- & Abflussstäbe -Heimwerkerbedarf > Sanitärinstallationen > Abflusszubehör > Sanitärabläufe -Heimwerkerbedarf > Sanitärinstallationen > Brunnenbedarf -Heimwerkerbedarf > Sanitärinstallationen > Druckminderer -Heimwerkerbedarf > Sanitärinstallationen > Düsen -Heimwerkerbedarf > Sanitärinstallationen > Installationsrohre -Heimwerkerbedarf > Sanitärinstallationen > Installationsrohre > Rohrnippel -Heimwerkerbedarf > Sanitärinstallationen > Installationsrohre > Stahlrohre -Heimwerkerbedarf > Sanitärinstallationen > Installationsrohre > Steckverbindungsrohre -Heimwerkerbedarf > Sanitärinstallationen > Kraftstoffleitungen & Zubehör -Heimwerkerbedarf > Sanitärinstallationen > Kugelhähne & Verschlüsse -Heimwerkerbedarf > Sanitärinstallationen > Pumpen -Heimwerkerbedarf > Sanitärinstallationen > Reparatursätze -Heimwerkerbedarf > Sanitärinstallationen > Reparatursätze > Rohr-Reparatursätze -Heimwerkerbedarf > Sanitärinstallationen > Rohrreiniger -Heimwerkerbedarf > Sanitärinstallationen > Rohrverbindungsstücke -Heimwerkerbedarf > Sanitärinstallationen > Rohrverbindungsstücke > Flansche -Heimwerkerbedarf > Sanitärinstallationen > Rohrverbindungsstücke > Rohranschlüsse & Reduzierstücke -Heimwerkerbedarf > Sanitärinstallationen > Rohrverbindungsstücke > Rohrkappen & -verschlüsse -Heimwerkerbedarf > Sanitärinstallationen > Rohrverbindungsstücke > Rohrschellen -Heimwerkerbedarf > Sanitärinstallationen > Rohrverbindungsstücke > Rohrverbinder -Heimwerkerbedarf > Sanitärinstallationen > Rohrverbindungsstücke > Sanitärdichtungen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärarmaturen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärarmaturen > Gashähne -Heimwerkerbedarf > Sanitärinstallationen > Sanitärarmaturen > Schlauchhähne -Heimwerkerbedarf > Sanitärinstallationen > Sanitärarmaturen > Wasserhähne -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Badarmaturen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Badarmaturen > Wasserhähne zum Vorspülen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Badewannen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Brauseeckventile -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschgriffe -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschkabinen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschkabinen & -türen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschköpfe -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschpaneele -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschschläuche -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschvorhangstangen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschwannen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Duschwände -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Stangenhalterungen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschen > Wasserfilter für Duschen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Halterungsplatten -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets > Bidets -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets > Toiletten -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets > Urinale -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör > Spülkastenabdeckungen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör > Spülkästen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör > Toilettendeckel -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör > Toilettensitze -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör > Toilettenverkleidung -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör > WC-Papiersitze -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten- und Bidetzubehör > WC-Spülkastengriffe -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken & Spülen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken & Spülen > Badezimmerwaschbecken -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken & Spülen > Küchenspülen & Spülbecken -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken- & Spülenzubehör -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken- & Spülenzubehör > Waschbeckenfüße -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Zubehör für Armaturen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Zubehör für Badewannen -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Zubehör für Badewannen > Badewanneneinläufe -Heimwerkerbedarf > Sanitärinstallationen > Sanitärkeramik & Armaturen > Zubehör für Badewannen > Badewannenverkleidungen -Heimwerkerbedarf > Sanitärinstallationen > Schläuche -Heimwerkerbedarf > Sanitärinstallationen > Siphons & Siebe -Heimwerkerbedarf > Sanitärinstallationen > Siphons & Siebe > Ablaufgarnituren für Badewannen -Heimwerkerbedarf > Sanitärinstallationen > Siphons & Siebe > Ablaufgarnituren für Duschen -Heimwerkerbedarf > Sanitärinstallationen > Siphons & Siebe > Flaschensiphons -Heimwerkerbedarf > Sanitärinstallationen > Sperrventile -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserdestillationsgeräte -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserenthärter -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserenthärtungszubehör -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserenthärtungszubehör > Salz zur Wasserenthärtung -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserleitungsfilter -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserleitungsfilter > Wasserfilter für Kühlschränke -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserspender -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserspender > Trinkbrunnen -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Wasserspender > Wasserkühler -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Zubehör für Wasserfilter -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Zubehör für Wasserfilter > Wasserfiltergehäuse -Heimwerkerbedarf > Sanitärinstallationen > Trinkwasserspender & Filter > Zubehör für Wasserfilter > Wasserfilterkartuschen -Heimwerkerbedarf > Sanitärinstallationen > Ventile -Heimwerkerbedarf > Sanitärinstallationen > Ventile > Kugelhähne -Heimwerkerbedarf > Sanitärinstallationen > Wasserschaltuhren -Heimwerkerbedarf > Sanitärinstallationen > Wasserstandsregler -Heimwerkerbedarf > Sanitärinstallationen > Wärmefühler -Heimwerkerbedarf > Schlösser & Schlossereibedarf -Heimwerkerbedarf > Schlösser & Schlossereibedarf > Kartenschließsysteme -Heimwerkerbedarf > Schlösser & Schlossereibedarf > Riegelschlösser -Heimwerkerbedarf > Schlösser & Schlossereibedarf > Taschenschiebetür-Schlösser -Heimwerkerbedarf > Schlösser & Schlossereibedarf > Vorhängeschlösser -Heimwerkerbedarf > Schlösser & Schlossereibedarf > Zylinderschlösser -Heimwerkerbedarf > Schlüsselrohlinge -Heimwerkerbedarf > Taschenlampen -Heimwerkerbedarf > Vorratsbehälter -Heimwerkerbedarf > Vorratsbehälter > Nahrungsmittelbehälter -Heimwerkerbedarf > Vorratsbehälter > Wassertanks -Heimwerkerbedarf > Vorratsbehälter > Öltanks -Heimwerkerbedarf > Wandfarben & Tapeten -Heimwerkerbedarf > Wandfarben & Tapeten > Abbeizmittel -Heimwerkerbedarf > Wandfarben & Tapeten > Anstrichfarben -Heimwerkerbedarf > Wandfarben & Tapeten > Farbe -Heimwerkerbedarf > Wandfarben & Tapeten > Farbenbindemittel -Heimwerkerbedarf > Wandfarben & Tapeten > Farbstoffe -Heimwerkerbedarf > Wandfarben & Tapeten > Grundierungen -Heimwerkerbedarf > Wandfarben & Tapeten > Lacke -Heimwerkerbedarf > Wandfarben & Tapeten > Lösungsmittel -Heimwerkerbedarf > Wandfarben & Tapeten > Tapeten -Heimwerkerbedarf > Werkstatthocker -Heimwerkerbedarf > Werkzeuge -Heimwerkerbedarf > Werkzeuge > Ahlen -Heimwerkerbedarf > Werkzeuge > Ambosse -Heimwerkerbedarf > Werkzeuge > Arbeitslampen -Heimwerkerbedarf > Werkzeuge > Arbeitslampen > Stirnlampen -Heimwerkerbedarf > Werkzeuge > Arbeitsscheinwerfer -Heimwerkerbedarf > Werkzeuge > Aufzüge & Hebeeinrichtungen -Heimwerkerbedarf > Werkzeuge > Aufzüge & Hebeeinrichtungen > Bauaufzüge -Heimwerkerbedarf > Werkzeuge > Aufzüge & Hebeeinrichtungen > Hubwagen -Heimwerkerbedarf > Werkzeuge > Aufzüge & Hebeeinrichtungen > Kettenzüge -Heimwerkerbedarf > Werkzeuge > Aufzüge & Hebeeinrichtungen > Pneumatische Hebevorrichtungen -Heimwerkerbedarf > Werkzeuge > Aufzüge & Hebeeinrichtungen > Seilzüge -Heimwerkerbedarf > Werkzeuge > Aufzüge & Hebeeinrichtungen > Wagenheber -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Betonmischer -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Fugenkellen -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Fugenschwamm -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Glättkellen -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Glättmaschinen -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Kantenwerkzeug -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Maurerkellen -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Maurerschnüre -Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Maurerwerkzeuge -Heimwerkerbedarf > Werkzeuge > Betonbesen -Heimwerkerbedarf > Werkzeuge > Biegewerkzeuge -Heimwerkerbedarf > Werkzeuge > Bodenverdichter -Heimwerkerbedarf > Werkzeuge > Bohrmaschinen -Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Druckluftbohrer -Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Elektrische Handbohrmaschinen -Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Schneckenbohrer -Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Stemmmaschinen -Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Ständerbohrmaschinen -Heimwerkerbedarf > Werkzeuge > Brecheisen -Heimwerkerbedarf > Werkzeuge > Bürsten -Heimwerkerbedarf > Werkzeuge > Bürsten > Airbrushpistolen -Heimwerkerbedarf > Werkzeuge > Bürsten > Kaminbürste -Heimwerkerbedarf > Werkzeuge > Bürsten > Malerpinsel -Heimwerkerbedarf > Werkzeuge > Bürsten > Rohrbürsten -Heimwerkerbedarf > Werkzeuge > Drehmaschinen -Heimwerkerbedarf > Werkzeuge > Druckluftpistolen -Heimwerkerbedarf > Werkzeuge > Einziehhilfen -Heimwerkerbedarf > Werkzeuge > Elektrohobel -Heimwerkerbedarf > Werkzeuge > Entgrater -Heimwerkerbedarf > Werkzeuge > Fettpistolen -Heimwerkerbedarf > Werkzeuge > Formeinsätze -Heimwerkerbedarf > Werkzeuge > Gewindeschneidmaschinen -Heimwerkerbedarf > Werkzeuge > Glühbirnenwechsler -Heimwerkerbedarf > Werkzeuge > Griffe -Heimwerkerbedarf > Werkzeuge > Handwerkzeuge für Drähte und Kabel -Heimwerkerbedarf > Werkzeuge > Handwerkzeuge für Drähte und Kabel > Abisolierzangen -Heimwerkerbedarf > Werkzeuge > Handwerkzeuge für Drähte und Kabel > Drahtschneider -Heimwerkerbedarf > Werkzeuge > Handwerkzeuge für Drähte und Kabel > Kabelklemmzangen -Heimwerkerbedarf > Werkzeuge > Handwerkzeuge für Drähte und Kabel > Kabelschneider -Heimwerkerbedarf > Werkzeuge > Handwerkzeuge für Drähte und Kabel > Seitenschneider -Heimwerkerbedarf > Werkzeuge > Heißluftpistole -Heimwerkerbedarf > Werkzeuge > Hobel -Heimwerkerbedarf > Werkzeuge > Holzspalter -Heimwerkerbedarf > Werkzeuge > Hämmern -Heimwerkerbedarf > Werkzeuge > Hämmern > Drucklufthammer -Heimwerkerbedarf > Werkzeuge > Hämmern > Elektrohammer -Heimwerkerbedarf > Werkzeuge > Hämmern > Hammer -Heimwerkerbedarf > Werkzeuge > Hämmern > Hammer > Holzhammer & Gummihammer -Heimwerkerbedarf > Werkzeuge > Hämmern > Hammer > Vorschlaghammer -Heimwerkerbedarf > Werkzeuge > Hämmern > Presslufthammer -Heimwerkerbedarf > Werkzeuge > Industriescheren -Heimwerkerbedarf > Werkzeuge > Industrievibratoren -Heimwerkerbedarf > Werkzeuge > Kittmesser & -spachtel -Heimwerkerbedarf > Werkzeuge > Klebepistolen -Heimwerkerbedarf > Werkzeuge > Kompressoren -Heimwerkerbedarf > Werkzeuge > Kompressoren > Gaskompressoren -Heimwerkerbedarf > Werkzeuge > Kompressoren > Luftkompressoren -Heimwerkerbedarf > Werkzeuge > Kontrollspiegel -Heimwerkerbedarf > Werkzeuge > Lasthebemagnete -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Arbeitsplattformen -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Gerüste -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Leitern -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Leitern > Aluminiumleitern -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Leitern > Holzleitern -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Leiterwagen -Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Tritthocker -Heimwerkerbedarf > Werkzeuge > Locheisen -Heimwerkerbedarf > Werkzeuge > Lochschaufeln -Heimwerkerbedarf > Werkzeuge > Lötkolben -Heimwerkerbedarf > Werkzeuge > Malerwerkzeug -Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbrollen -Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbschaber -Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbspritzpistolen -Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbwannen -Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Kantenmaler -Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Malschwämme -Heimwerkerbedarf > Werkzeuge > Markierwerkzeuge -Heimwerkerbedarf > Werkzeuge > Markierwerkzeuge > Markiereisen -Heimwerkerbedarf > Werkzeuge > Markierwerkzeuge > Markiermesser -Heimwerkerbedarf > Werkzeuge > Markierwerkzeuge > Schlagschnüre -Heimwerkerbedarf > Werkzeuge > Markierwerkzeuge > Zimmermannsbleistifte -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Balkensucher -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Barometer -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Diagnostische Wärmekamera -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Drucksensoren & Wandler -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Durchflussmesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Entfernungsmesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Feuchtigkeitsmesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Gasdetektoren -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Geigerzähler -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Haarlineale -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Hygrometer -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Höhenmesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Kabelprüfgeräte -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Kabelsuchgeräte -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Kluppen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Lautstärkemesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Lecksucher -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Maßbänder -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messerführungen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messinstrumente -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messräder -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messschieber -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Metallsuchgeräte & Spannungsdetektoren -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Multimeter -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Raumluftmessgeräte -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen > Laser-Wasserwaagen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen > Schaugläser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen > Wasserwaagen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Rohrsuchgeräte -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Schwingungsmesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Seismographen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Sonden & Suchgeräte -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Stahlbewehrungssucher -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Stangenzirkel -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Theodolite -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Thermometer -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Thermometer > Infrarotthermometer -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > UV-Lichtmesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Waagen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Wetterstationen -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Winkel -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Winkelmesser -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Zollstöcke -Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > pH-Meter -Heimwerkerbedarf > Werkzeuge > Multifunktionales Elektrowerkzeug -Heimwerkerbedarf > Werkzeuge > Mühlen -Heimwerkerbedarf > Werkzeuge > Müll- & Papierkrallen -Heimwerkerbedarf > Werkzeuge > Müll- & Papierkrallen > Greifzangen -Heimwerkerbedarf > Werkzeuge > Nageleisen -Heimwerkerbedarf > Werkzeuge > Nagler & Tacker -Heimwerkerbedarf > Werkzeuge > Nietwerkzeuge -Heimwerkerbedarf > Werkzeuge > Nietwerkzeuge > Nietpistolen -Heimwerkerbedarf > Werkzeuge > Nietwerkzeuge > Nietzangen -Heimwerkerbedarf > Werkzeuge > Oberfräsen -Heimwerkerbedarf > Werkzeuge > Reibahlen -Heimwerkerbedarf > Werkzeuge > Rollwagen & Sackkarren -Heimwerkerbedarf > Werkzeuge > Sandstrahler -Heimwerkerbedarf > Werkzeuge > Saugglocken -Heimwerkerbedarf > Werkzeuge > Schlagschrauber -Heimwerkerbedarf > Werkzeuge > Schleifblöcke -Heimwerkerbedarf > Werkzeuge > Schleifer & Poliermaschinen -Heimwerkerbedarf > Werkzeuge > Schleifmaschinen -Heimwerkerbedarf > Werkzeuge > Schneidegeräte -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Betonstahlschneider -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Bolzenschneider -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Cutter -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Fliesen-, Ziegel- & Schindelschneider -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Glasschneider -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Nibbelmaschinen -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Rohrschneider -Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Zwickzange -Heimwerkerbedarf > Werkzeuge > Schnitzwerkzeuge -Heimwerkerbedarf > Werkzeuge > Schnitzwerkzeuge > Hohleisen -Heimwerkerbedarf > Werkzeuge > Schnitzwerkzeuge > Hohlmeißel -Heimwerkerbedarf > Werkzeuge > Schnitzwerkzeuge > Holzschnitzmesser -Heimwerkerbedarf > Werkzeuge > Schnitzwerkzeuge > Meißel -Heimwerkerbedarf > Werkzeuge > Schraubendreher -Heimwerkerbedarf > Werkzeuge > Schraubendreher > Elektrische Schraubenzieher -Heimwerkerbedarf > Werkzeuge > Schraubendreher > Handschraubenzieher -Heimwerkerbedarf > Werkzeuge > Schraubenschlüssel -Heimwerkerbedarf > Werkzeuge > Schraubenschlüssel > Innensechskantschlüssel -Heimwerkerbedarf > Werkzeuge > Schraubenschlüssel > Knarren -Heimwerkerbedarf > Werkzeuge > Schweißwerkzeuge -Heimwerkerbedarf > Werkzeuge > Schwingschleifer -Heimwerkerbedarf > Werkzeuge > Schärfgeräte -Heimwerkerbedarf > Werkzeuge > Schärfgeräte > Schleifsteine -Heimwerkerbedarf > Werkzeuge > Schärfgeräte > Schärfgeräte für Kettensägen -Heimwerkerbedarf > Werkzeuge > Steckschlüssel -Heimwerkerbedarf > Werkzeuge > Stemmwerkzeuge -Heimwerkerbedarf > Werkzeuge > Stemmwerkzeuge > Fugenpistolen -Heimwerkerbedarf > Werkzeuge > Stemmwerkzeuge > Kalfateisen -Heimwerkerbedarf > Werkzeuge > Stemmwerkzeuge > Kalfathammer -Heimwerkerbedarf > Werkzeuge > Stoßmaschinen -Heimwerkerbedarf > Werkzeuge > Sägeböcke -Heimwerkerbedarf > Werkzeuge > Sägen -Heimwerkerbedarf > Werkzeuge > Sägen > Bandsägen -Heimwerkerbedarf > Werkzeuge > Sägen > Bügelsägen -Heimwerkerbedarf > Werkzeuge > Sägen > Dekupiersägen -Heimwerkerbedarf > Werkzeuge > Sägen > Fliesensägen -Heimwerkerbedarf > Werkzeuge > Sägen > Gehrungssägen -Heimwerkerbedarf > Werkzeuge > Sägen > Handkreissägen -Heimwerkerbedarf > Werkzeuge > Sägen > Handsägen -Heimwerkerbedarf > Werkzeuge > Sägen > Stichsägen -Heimwerkerbedarf > Werkzeuge > Sägen > Säbelsägen -Heimwerkerbedarf > Werkzeuge > Sägen > Tischkreissägen -Heimwerkerbedarf > Werkzeuge > Sägen > Trennsägen -Heimwerkerbedarf > Werkzeuge > Tischlerbänke -Heimwerkerbedarf > Werkzeuge > Wasseranschluss-Nachschleifwerkzeuge -Heimwerkerbedarf > Werkzeuge > Werkzeugfeilen -Heimwerkerbedarf > Werkzeuge > Werkzeugmesser -Heimwerkerbedarf > Werkzeuge > Werkzeugmesser > Rigipsmesser -Heimwerkerbedarf > Werkzeuge > Werkzeugschlüssel -Heimwerkerbedarf > Werkzeuge > Werkzeugschlüssel > Absperrhahn Schlüssel -Heimwerkerbedarf > Werkzeuge > Werkzeugschlüssel > Heizkörperschlüssel -Heimwerkerbedarf > Werkzeuge > Werkzeugschlüssel > Schachtdeckelheber -Heimwerkerbedarf > Werkzeuge > Werkzeugsets -Heimwerkerbedarf > Werkzeuge > Werkzeugsets > Elektrowerkzeug-Combo-Sets -Heimwerkerbedarf > Werkzeuge > Werkzeugsets > Handwerkzeugsets -Heimwerkerbedarf > Werkzeuge > Werkzeugspanner -Heimwerkerbedarf > Werkzeuge > Werkzeugspanner > Schraubzwingen -Heimwerkerbedarf > Werkzeuge > Zangen -Heimwerkerbedarf > Werkzeuge > Äxte -Heimwerkerbedarf > Werkzeuge > Ölfilterabfluss -Heimwerkerbedarf > Werkzeugzubehör -Heimwerkerbedarf > Werkzeugzubehör > Airbrushzubehör -Heimwerkerbedarf > Werkzeugzubehör > Anstreichzubehör -Heimwerkerbedarf > Werkzeugzubehör > Anstreichzubehör > Anstreichrollenzubehör -Heimwerkerbedarf > Werkzeugzubehör > Axtzubehör -Heimwerkerbedarf > Werkzeugzubehör > Axtzubehör > Axtköpfe -Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör -Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrer -Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrerschleifgeräte -Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrerverlängerungen -Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Lochsägen -Heimwerkerbedarf > Werkzeugzubehör > Drehmaschinenzubehör -Heimwerkerbedarf > Werkzeugzubehör > Elektrowerkzeug-Akkus -Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör -Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör > Drucklufthammerzubehör -Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör > Hammerkeile -Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör > Hammerköpfe -Heimwerkerbedarf > Werkzeugzubehör > Klammern -Heimwerkerbedarf > Werkzeugzubehör > Ladegeräte für Elektrowerkzeuge -Heimwerkerbedarf > Werkzeugzubehör > Magnetisierer & Entmagnetisierer -Heimwerkerbedarf > Werkzeugzubehör > Sandstrahlerzubehör -Heimwerkerbedarf > Werkzeugzubehör > Sandstrahlerzubehör > Sandstrahlkabinen -Heimwerkerbedarf > Werkzeugzubehör > Schleifzubehör -Heimwerkerbedarf > Werkzeugzubehör > Schleifzubehör > Schleifpapier & Schleifschwämme -Heimwerkerbedarf > Werkzeugzubehör > Schraubendreherzubehör -Heimwerkerbedarf > Werkzeugzubehör > Schraubendreherzubehör > Schraubendrehereinsätze -Heimwerkerbedarf > Werkzeugzubehör > Spannvorrichtungen -Heimwerkerbedarf > Werkzeugzubehör > Steckschlüsseleinsätze -Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör -Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Bandsägenzubehör -Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Handkreissägen-Zubehör -Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Kreissägenzubehör -Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Laubsägenzubehör -Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Tischsägenzubehör -Heimwerkerbedarf > Werkzeugzubehör > Werkzeuggriffe -Heimwerkerbedarf > Werkzeugzubehör > Werkzeuggriffe > Axtgriffe -Heimwerkerbedarf > Werkzeugzubehör > Werkzeuggriffe > Hammerstiele -Heimwerkerbedarf > Werkzeugzubehör > Werkzeugklingen & -blätter -Heimwerkerbedarf > Werkzeugzubehör > Werkzeugklingen & -blätter > Sägeblätter -Heimwerkerbedarf > Werkzeugzubehör > Werkzeugklingen & -blätter > Teppichmesserklingen -Heimwerkerbedarf > Werkzeugzubehör > Werkzeugständer -Heimwerkerbedarf > Werkzeugzubehör > Werkzeugständer > Sägeständer -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Generatoren -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Generatoren > Generator-Ersatzteile -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Generatoren > Generatorabdeckungen -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Lötkolben -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Lötkolben > Lötkolbenspitzen -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Lötkolben > Lötkolbenständer -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber > Multimeter-Zubehör -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber > Zubehör für Gasdetektoren -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber > Zubehör für Metallsuchgeräte & Spannungsdetektoren -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Oberfräsen -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Oberfräsen > Oberfräsenteile -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Oberfräsen > Oberfräsentische -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Stoßmaschinen -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Stoßmaschinen > Stoßmaschinenwerkzeuge -Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Taschenlampen -Kameras & Optik -Kameras & Optik > Fotografie -Kameras & Optik > Fotografie > Aufbewahrung für Negative & Kontaktbögen -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Belichtungsmesser -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Blitzdiffusoren -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Blitzdiffusoren > Kamera-Blitzdiffusoren -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Blitzreflektoren -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Hintergründe -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Lichtfilter & Filterfolien -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Lichtsteuerung -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Softboxen -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Studioausstattung -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Studioscheinwerfer & -blitzgeräte -Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Zubehör für Belichtungsmesser -Kameras & Optik > Fotografie > Dunkelkammer -Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung -Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Dunkelkammerbecken -Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Entwicklungsschalen, Wascher & Trockner -Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Entwicklungstanks & -spiralen -Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Reprostative -Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Retuschierbedarf & -zubehör -Kameras & Optik > Fotografie > Dunkelkammer > Dunkelkammerleuchten -Kameras & Optik > Fotografie > Dunkelkammer > Fotochemikalien -Kameras & Optik > Fotografie > Dunkelkammer > Fotochemikalien > Farbfotokits -Kameras & Optik > Fotografie > Dunkelkammer > Fotochemikalien > Fixierer -Kameras & Optik > Fotografie > Dunkelkammer > Fotochemikalien > Fotoentwickler -Kameras & Optik > Fotografie > Dunkelkammer > Fotochemikalien > Fototoner -Kameras & Optik > Fotografie > Dunkelkammer > Fotochemikalien > Stoppbäder -Kameras & Optik > Fotografie > Dunkelkammer > Fotopapier -Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör -Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Dunkelkammer-Timer -Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Dunkelkammerstaffeleien -Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Fokussierhilfen -Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Fotovergrößerer -Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Lichtmesser -Kameras & Optik > Kamera- & Optisches Zubehör -Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Optische Linsen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Optische Linsen > Kameraobjektive -Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Optische Linsen > Objektive für Überwachungskameras -Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Optische Linsen > Videokamera-Objektive -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen > Objektiv- & Filteradapter -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen > Objektivabdeckungen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen > Objektivfilter -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen > Objektivfilter > Makrofilter -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen > Objektivtaschen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen > Streulichtblenden -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör & Zubehör für optische Linsen > Telekonverter -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Blitzhaltesysteme -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Fototasche -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Fototasche > Kamerataschen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Fototasche > Videokamerataschen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamera-Blitzgeräte -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamera-Blitzlichtzubehör -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamera-Fernbedienungen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamerafilme -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kameragriffe -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kameragurte -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamerahalterungen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Unterwasser-Kamerahüllen -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Unterwasser-Kamerahüllen > Unterwassergehäuse für Kameras -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Unterwasser-Kamerahüllen > Unterwassergehäuse für Videokameras -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Videokameraleuchten -Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Überwachungskamera-Zubehör -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Fernglas- & Fernrohrzubehör -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Optisches Zubehör für Nachtsichtsysteme -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Taschen & Koffer für optische Instrumente -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Wärmebildzubehör -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Messsucher -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Spektive -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Spektive > Spektivokulare -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Teleskope -Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Zielfernrohre -Kameras & Optik > Kamera- & Optisches Zubehör > Stative -Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative -Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Schellen & Halterungen für Stative -Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Stativaufbewahrung -Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Stativköpfe -Kameras & Optik > Kameras -Kameras & Optik > Kameras > Analogkameras -Kameras & Optik > Kameras > Analogkameras > Sofortbildkameras -Kameras & Optik > Kameras > Digitalkameras -Kameras & Optik > Kameras > Digitalkameras > Digitale Kompaktkameras -Kameras & Optik > Kameras > Digitalkameras > Digitale Spiegelreflexkameras -Kameras & Optik > Kameras > Digitalkameras > Spiegellose Systemkameras -Kameras & Optik > Kameras > Einwegkameras -Kameras & Optik > Kameras > Videokameras -Kameras & Optik > Kameras > Webcams -Kameras & Optik > Kameras > Wildkameras -Kameras & Optik > Kameras > Überwachungskameras -Kameras & Optik > Kameras > Überwachungskameras > Versteckte Kameras -Kameras & Optik > Optische Geräte -Kameras & Optik > Optische Geräte > Ferngläser -Kameras & Optik > Optische Geräte > Ferngläser > Operngläser -Kameras & Optik > Optische Geräte > Fernrohre -Kameras & Optik > Optische Geräte > Fernrohre > Spektive -Kameras & Optik > Optische Geräte > Fernrohre > Teleskope -Kameras & Optik > Optische Geräte > Monokulare -Kameras & Optik > Optische Geräte > Optische Entfernungsmesser -Kunst & Unterhaltung -Kunst & Unterhaltung > Hobby & Kunst -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Figuren, Skulpturen & Statuen -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Fotografien -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Fotografien > Stock-Fotografie -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Gemälde -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Kartonschablonen -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Mixed-Media-Kunst -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Poster & Nachdrucke -Kunst & Unterhaltung > Hobby & Kunst > Bildende Kunst > Zeichnungen & Illustrationen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrungsmöglichkeiten für Handwerk & Hobby -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrungsmöglichkeiten für Handwerk & Hobby > Behälter für Strick- & Häkelnadeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrungsmöglichkeiten für Handwerk & Hobby > Nähkörbe -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrungsmöglichkeiten für Handwerk & Hobby > Ordnungsboxen für Garn -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Bastelmagnete -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Bier & Wein selbst herstellen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Bier & Wein selbst herstellen > Bierbrauen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Bier & Wein selbst herstellen > Weinherstellung -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Blumenstecken -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Blumenstecken > Blumenklebeband -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Blumenstecken > Vasenfüller & Streudeko -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Dekorative Aufkleber -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Druckgrafik -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Druckgrafik > Siebdruck -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Druckgrafik > Siebdruck > Handroller -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Druckgrafik > Siebdruck > Siebdruck-Rakel -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Formen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Glashandwerk -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Glitzer -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Holzbearbeitung -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > JoJos aus Stoff -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Jonglieren -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kerzen- & Seifenherstellung -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kerzen- & Seifenherstellung > Dochtaufhänger -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kerzen- & Seifenherstellung > Dochte -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kränze und Gebinde -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kränze und Gebinde > Rahmen zur Kranzbindung -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Lederhandwerk -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Leinwände & Keilrahmen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Leuchtkästen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Magnetband -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Modellbau -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Modellbau > Modellbausätze -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Modellbau > Modelleisenbahn & Eisenbahnsets -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Modellbau > Modelleisenbahnzubehör -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Modellbau > Modellraketen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Moosgummi & Styropor -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Mosaike -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Mosaike > Mosaikbausätze -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Fasernweberei-Muster -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Fasernweberei-Muster > Kreuzstich- und Stickmuster -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Fasernweberei-Muster > Nähmuster -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Fasernweberei-Muster > Strick- & Häkelmuster -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Filzen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Filzen > Filzformen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Filzen > Filznadeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Filzen > Filzpolster & -matten -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Faden- & Garnführer -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Faden- & Garnspulen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Faden- & Garnwickler -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Fadenabschneider -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Fingerhüte -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Flicksets -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Herstellungs-Sets für Jo-Jos -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Herstellungs-Sets für Pompons & Schleifen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Kardierer -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Maschenmarkierer & -zähler -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Nadeleinfädler -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Nadelkissen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Nahttrenner -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Nähnadeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Schablonen für Stoff-Zuschneidemaschinen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Schneiderpuppen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Sicherheitsnadeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Spanndrähte -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Spannmatten -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Stecknadeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Stoff-Zuschneidemaschinen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Stoffscheren -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Textilkleber -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Textilkleber > Schmucksteinkleber -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Textilkleber > Textilklebeband -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Textilkunst-Messgeräte -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Textilkunst-Rahmen, -Reifen & -Spannvorrichtungen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Textilmarker -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Geräte & Zubehör für Textilkunst > Webmaschinen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Gobelinstickerei -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Gobelinstickerei > Gobelinstickerei-Sets -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Gobelinstickerei > Leinwand für Gobelinstickerei -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Häkeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Häkeln > Häkelgarne -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Häkeln > Häkelnadeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Kreuzstich -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Quilten -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Spinnen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Spinnen > Handspindeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Spinnen > Spinnräder -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Spinnen > Spinnzubehör -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Spitze & Borten -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Stricken -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Stricken > Stricknadeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Aufnäher -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Druckknöpfe -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Elastikbund -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Füllmaterial -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Garne -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Klettverschlüsse -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Knöpfe -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Plastiksegeltuch -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Reißverschlüsse -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Rohwolle -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Stoffe -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Textilaufnäher- und aufbügler -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Textilfarben -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Textilfärbemittel -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Vlieseline -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Textilkunst-Verbrauchsmaterialien > Zwirn -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Weben -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Weben > Haken für Locker-Hooking -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Weben > Webschlagkämme -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Nähen, Häkeln, Stricken & Sticken > Weben > Webschützen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Pailletten -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Aquarellpapier -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Bastelpapier -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Origami-Papier -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Pauspapier -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Pergament -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Skizzenblöcke -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Tonpapier & Karton -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papier > Transferpapier -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Kartenbastelsets -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Prägen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Prägen > Prägemappen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Prägen > Prägemaschinen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Prägen > Prägepuder -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Prägen > Prägestempel -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Prägen > Prägestifte -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Prägen > Werkzeuge zum Prägen mit Hitze -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Papierkunst > Rill- und Perforiergeräte für Papier -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Pfeifenreiniger -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schablonenkunst -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schablonenkunst > Schablonen & Matrizen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schablonenkunst > Schablonendruckmaschinen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schmuckherstellung -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schmuckherstellung > Perlen -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schmuckherstellung > Schmuck- & Perlenband -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schmuckherstellung > Schmuck- & Perlendraht -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Schmuckherstellung > Schmuck-Basisteile -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Scrapbooking -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Sets für die Räucherwerkherstellung -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Stempeln -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Stempeln > Lederstempel & Sets -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Stempeln > Metallstempel & Sets -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Strass -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Töpferei & Bildhauerei -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Töpferei & Bildhauerei > Modellierton & Modelliermasse -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Uhrreparatursätze -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Vordrucke -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Vorlagen für Perlenarbeiten -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zauberbedarf -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Künstlerpinsel -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Malerei -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Malerei > Farbpaletten -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Malerei > Künstlerfarben -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Malerei > Malgründe -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Malerei > Palettenmesser -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Skizzieren -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Skizzieren > Zeichenzirkel -Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zeichnen & Malerei > Zeichen- & Malsets -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Akkordeons & Konzertinas -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Euphonien -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Flügelhörner -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Kornette -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Mellophone -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Posaunen -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Sousaphone -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Trompeten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Tubas -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Waldhörner -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Dudelsäcke -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > Audio-Sampler -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > MIDI-Controller -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > Musik-Keyboards -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > Synthesizer -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Blechflöten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Blockflöten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Fagotte -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Flöten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Flöten > Schwegelpfeifen -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Kinderflöten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Klarinetten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Maultrommeln -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Melodicas -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Mundharmonikas -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Oboen -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Okarinas -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Panflöten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Saxophone -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Zugpfeife -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Klaviere -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Bratschen -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Cellos -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Gitarren -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Gitarren > Akustikgitarren -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Gitarren > Bassgitarren -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Gitarren > Elektrische Gitarren -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Harfen -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Kontrabässe -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Violinen -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Basstrommeln -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Becken -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Elektronische Schlagzeuge -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Glockenspiele & Xylophone -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Gongs -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Finger- & Handzimbeln -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handglocken -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handschellen & -glocken -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Holzblöcke -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Kasagnetten -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Kuhglocken -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Rasseln -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Scraper -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburine -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins > Beckentrommel -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins > Bongos -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins > Cajons -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins > Congas -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins > Sprechtrommeln -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins > Tablas -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburins > Tympanons -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Triangeln -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Vibraslaps -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Hi-Hats -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Schlagzeuge -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Snaredrums -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Tom-Toms -Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Übungspads -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Autogramme -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Briefmarken -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Maßstabsmodelle -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Modellbau-Zubehör -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Münzen & Währungen -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Retro-Werbung -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten > Sport-Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten > Sport-Sammelkarten > American Football-Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten > Sport-Sammelkarten > Baseball-Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten > Sport-Sammelkarten > Basketball-Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten > Sport-Sammelkarten > Fußball-Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten > Sport-Sammelkarten > Hockey-Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten > Sport-Sammelkarten > Rennsport-Sammelkarten -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > American Football-Fanartikel -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Baseball- & Softball-Fanartikel -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Basketball-Fanartikel -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Fußball-Fanartikel -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Hockey-Fanartikel -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Rennsport-Fanartikel -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Tennis-Fanzubehör -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > American Football-Artikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Baseball- & Softballartikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Basketballartikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Fußballartikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Hockeyartikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Rennsportartikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Tennisartikel mit Autogramm -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Steine & Fossilien -Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Stempelsiegel -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör > Keyboardständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör > Keyboardtaschen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör > Sustain-Pedale -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Klavierzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Klavierzubehör > Klavierbänke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Notenständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Dämpfer für Schlagzeug & Becken -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Elektronische Schlagzeugmodule -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware > Beater -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware > Fußmaschinen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware > Schlagzeughalterungen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeugfelle -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeughocker -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeugkoffer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeugstockzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeugstockzubehör > Taschen für Schlagzeugstöcke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Stimmschlüssel -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Ständer für Perkussionsinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Trommelschlägel -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Trommelstöcke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Handperkussionsinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Handperkussionsinstrumente > Ständer für Handperkussionsinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Handperkussionsinstrumente > Taschen für Handperkussionsinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Stimmgeräte -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente > Beleuchtung für Instrumentenständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente > Notenklemmen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente > Taschen für Instrumentenständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Verstärker -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärker für Musikinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkergehäuse -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Bürsten, Reinigungsspiralen & Putzstöcke für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Klappenöl für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Pflegesets für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Poliertücher für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Reinigungs- & Desinfektionsmittel für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Schutzvorrichtungen für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Ersatzteile für Blechblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Euphoniumzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Euphoniumzubehör > Dämpfer für Euphonien -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Euphoniumzubehör > Euphoniummundstücke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Euphoniumzubehör > Euphoniumständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Euphoniumzubehör > Koffer & Transporttaschen für Euphonien -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Posaunenzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Posaunenzubehör > Dämpfer für Posaunen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Posaunenzubehör > Koffer & Transporttaschen für Posaunen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Posaunenzubehör > Posaunenmarschgabeln -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Posaunenzubehör > Posaunenmundstücke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Posaunenzubehör > Posaunenständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Trompeten- & Hornzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Trompeten- & Hornzubehör > Dämpfer für Trompeten & Hörner -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Trompeten- & Hornzubehör > Koffer & Transporttaschen für Trompeten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Trompeten- & Hornzubehör > Trompeten- & Hornmarschgabeln -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Trompeten- & Hornzubehör > Trompeten- & Hornmundstücke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Trompeten- & Hornzubehör > Trompeten- & Hornständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Tubazubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Tubazubehör > Dämpfer für Tubas -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Tubazubehör > Koffer & Transporttaschen für Tubas -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Tubazubehör > Tubamundstücke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Tubazubehör > Tubaständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Waldhornzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Waldhornzubehör > Dämpfer für Waldhörner -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Waldhornzubehör > Koffer & Transporttaschen für Waldhörner -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Waldhornzubehör > Waldhornmundstücke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Waldhornzubehör > Waldhornständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Blätteretui für Holzblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottblattmesser -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottblätter -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottpflege & -reinigung -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottpflege & -reinigung > Fagottreinigungstücher -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottriemen & -stützen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottteile > Fagott-S-Bögen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottteile > Kleinere Fagottzubehörteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Koffer & Transporttaschen für Fagotte -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenhalter & -ständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenmarschgabeln -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung > Flötenpflegesets -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung > Flötenreinigungsstab -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung > Flötenreinigungstücher -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenteile > Flötenkopfstücke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenteile > Kleinere Flötenzubehörteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Koffer & Transporttaschen für Flöten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Blattschrauben & Kappen für Klarinetten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenblätter -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenhalter/-ständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenmarschgabeln -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung > Klarinettenklappenschutz -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung > Klarinettenpflegesets -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung > Klarinettenreinigungstücher -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenriemen & -stützen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Klarinettenbirnen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Klarinettenmundstücke -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Klarinettentrichter -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Kleinere Klarinettenzubehörteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Koffer & Transporttaschen für Klarinetten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Korkfett für Holzblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Mundharmonikazubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Mundharmonikazubehör > Mundharmonika-Etuis -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Mundharmonikazubehör > Mundharmonikahalter -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Koffer & Transporttaschen für Oboen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenblätter -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenhalter & -ständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenpflege & -reinigung -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenpflege & -reinigung > Oboenpflegesets -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenpflege & -reinigung > Oboenreinigungstücher -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenriemen & -stützen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenteile > Kleinere Oboenzubehörteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Poliertücher für Holzblasinstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Blattschrauben & Kappen für Saxophone -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Koffer & Transporttaschen für Saxophone -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Rohrblätter für Saxophone -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonhalter & -ständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonmarschgabeln -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung > Saxophonklappenschutz -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung > Saxophonpflegesets -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung > Saxophonreinigungstücher -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonriemen/-stützen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile > Kleinere Saxophonzubehörteile -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile > Mundstücke für Saxophone -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile > Saxophonhälse -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Cellozubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Cellozubehör > Cellobögen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Cellozubehör > Cellokoffer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Cellozubehör > Cellosaiten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Cellozubehör > Dämpfer für Cellos -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarren-Slides -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenbefeuchter -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenkoffer & -taschen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenplektren -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrensaiten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenstimmgeräte -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenständer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Kapodaster -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Stegstifte für Gitarren -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Tonabnehmer für Akustikgitarren -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Tonabnehmer für E-Gitarren -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Harfenzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Harfenzubehör > Harfenkoffer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Harfenzubehör > Harfensaiten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Kontrabasszubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Kontrabasszubehör > Dämpfer für Kontrabässe -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Kontrabasszubehör > Kontrabassbögen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Kontrabasszubehör > Kontrabasskoffer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Kontrabasszubehör > Kontrabasssaiten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung > Bogenharz -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung > Politur für Saiteninstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung > Reinigungstücher für Saiteninstrumente -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violazubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violazubehör > Dämpfer für Violas -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violazubehör > Violabögen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violazubehör > Violakoffer -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violazubehör > Violasaiten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Dämpfer für Violinen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Kinnhalter für Violinen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Saitenhalter für Violinen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Schulterstützen für Violinen & Bratschen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Stimmwirbel für Violinen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Tonabnehmer für Violinen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Violinbögen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Violinenkoffer & -taschen -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Violinensaiten -Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Violinenzubehör > Violinenstege -Kunst & Unterhaltung > Party & Feiern -Kunst & Unterhaltung > Party & Feiern > Partyzubehör -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Antwortkarten -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Antwortkarten > Antwortkarten für die Hochzeit -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Ballon-Sets -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Banner -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Briefsiegel -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Cocktaildekorationen -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Einladungskarten -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Einladungskarten > Geburtstagseinladungen -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Einladungskarten > Hochzeitseinladungen -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Eventprogramme -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Geburtstagskerzen -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Getränkekühler -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Kartons & andere Behältnisse für Hochzeitskarten -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Konfetti -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Luftballons -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Luftschlangen -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Luftschlangenspray -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyartikel -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyartikel > Kleine Geschenke für Hochzeitsgäste -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyhüte -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyspiele -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Piñatas -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Platzkarten -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Platzkartenhalter -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkhalme & Rührer -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkspiele -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkspiele > Bierpong -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkspiele > Bierpong > Bierpong-Tische -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Tröten, Luftrüssel & Krachmacher -Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Wunderkerzen -Kunst & Unterhaltung > Party & Feiern > Schenken -Kunst & Unterhaltung > Party & Feiern > Schenken > Anstecksträußchen -Kunst & Unterhaltung > Party & Feiern > Schenken > Befestigungsnadeln für Anstecksträußchen -Kunst & Unterhaltung > Party & Feiern > Schenken > Frische Schnittblumen -Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkgutscheine -Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen -Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Geschenkboxen & -dosen -Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Geschenkpapier -Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Geschenktaschen -Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Schleifen & Bänder -Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Seidenpapier -Kunst & Unterhaltung > Party & Feiern > Schenken > Grußkarten -Kunst & Unterhaltung > Party & Feiern > Trophäen & Preise -Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte -Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Diskokugeln -Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Lichteffektbeleuchtung -Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Lichtmischpulte -Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Nebelmaschinen -Medien -Medien > Bücher -Medien > Bücher > Belletristik -Medien > Bücher > Belletristik > Comics -Medien > Bücher > Belletristik > Horrorromane -Medien > Bücher > Belletristik > Kinderbücher -Medien > Bücher > Belletristik > Kriminalromane -Medien > Bücher > Belletristik > Liebesromane -Medien > Bücher > Belletristik > Literatur -Medien > Bücher > Belletristik > Science Fiction- & Fantasy-Romane -Medien > Bücher > Sachliteratur -Medien > Bücher > Sachliteratur > Architekturbücher -Medien > Bücher > Sachliteratur > Biografien -Medien > Bücher > Sachliteratur > Business- & Wirtschaftsbücher -Medien > Bücher > Sachliteratur > Bücher zu Bildung & Erziehung -Medien > Bücher > Sachliteratur > Bücher zu Bildung & Erziehung > Fremdsprachenbücher -Medien > Bücher > Sachliteratur > Bücher zu Bildung & Erziehung > Lernhilfen -Medien > Bücher > Sachliteratur > Bücher zu Handwerk, Hobby & Beschäftigung -Medien > Bücher > Sachliteratur > Bücher zu Körper, Geist & Seele -Medien > Bücher > Sachliteratur > Bücher zum Verkehrswesen -Medien > Bücher > Sachliteratur > Bücher über wahre Kriminalfälle -Medien > Bücher > Sachliteratur > Computerbücher -Medien > Bücher > Sachliteratur > Familienratgeber -Medien > Bücher > Sachliteratur > Fotografiebücher -Medien > Bücher > Sachliteratur > Gartenbücher -Medien > Bücher > Sachliteratur > Geschichtsbücher -Medien > Bücher > Sachliteratur > Gesundheits- & Fitnessbücher -Medien > Bücher > Sachliteratur > Haustierratgeber -Medien > Bücher > Sachliteratur > Heimwerkerbücher -Medien > Bücher > Sachliteratur > Humorvolle Bücher -Medien > Bücher > Sachliteratur > Kochbücher -Medien > Bücher > Sachliteratur > Kunstbücher -Medien > Bücher > Sachliteratur > Literaturwissenschaften -Medien > Bücher > Sachliteratur > Malbücher -Medien > Bücher > Sachliteratur > Mathematikbücher -Medien > Bücher > Sachliteratur > Medizinische Bücher -Medien > Bücher > Sachliteratur > Musikbücher -Medien > Bücher > Sachliteratur > Nachschlagewerke -Medien > Bücher > Sachliteratur > Performance-Kunst-Bücher -Medien > Bücher > Sachliteratur > Philosophiebücher -Medien > Bücher > Sachliteratur > Poesie -Medien > Bücher > Sachliteratur > Politikwissenschaftliche Bücher -Medien > Bücher > Sachliteratur > Psychologiebücher -Medien > Bücher > Sachliteratur > Rechtsbücher -Medien > Bücher > Sachliteratur > Reiseliteratur -Medien > Bücher > Sachliteratur > Religionsbücher -Medien > Bücher > Sachliteratur > Rätselbücher -Medien > Bücher > Sachliteratur > Sachliteratur für Jugendliche -Medien > Bücher > Sachliteratur > Schauspiel -Medien > Bücher > Sachliteratur > Selbsthilfebücher -Medien > Bücher > Sachliteratur > Sozialwissenschaftliche Bücher -Medien > Bücher > Sachliteratur > Spielbücher -Medien > Bücher > Sachliteratur > Sportbücher -Medien > Bücher > Sachliteratur > Sprach- & Linguistikbücher -Medien > Bücher > Sachliteratur > Technologiebücher -Medien > Bücher > Sachliteratur > Tier- & Naturbücher -Medien > Bücher > Sachliteratur > Wissenschaftsbücher -Medien > DVDs & Videos -Medien > Musik -Medien > Notenblätter -Medien > Produkthandbücher & Gebrauchsanleitungen -Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Elektrogeräte -Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Elektrowerkzeuge -Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Haushaltsgeräte -Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Küchengeräte -Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Modelle und Spielzeuge -Medien > Produkthandbücher & Gebrauchsanleitungen > KFZ-Handbücher -Medien > Produkthandbücher & Gebrauchsanleitungen > Sport- & Freizeithandbücher -Medien > Zeitschriften & Zeitungen -Möbel -Möbel > Baby- & Kleinkindmöbel -Möbel > Baby- & Kleinkindmöbel > Gitter- & Kinderbettzubehör -Möbel > Baby- & Kleinkindmöbel > Gitter- & Kinderbettzubehör > Bettnestchen & Randschutz für Gitterbetten -Möbel > Baby- & Kleinkindmöbel > Gitter- & Kinderbettzubehör > Umbausätze für Gitterbetten -Möbel > Baby- & Kleinkindmöbel > Gitterbetten & Kleinkinderbetten -Möbel > Baby- & Kleinkindmöbel > Hochstühle und Sitzerhöhungen -Möbel > Baby- & Kleinkindmöbel > Möbelgarnituren für Babies und Kleinkinder -Möbel > Baby- & Kleinkindmöbel > Spielmöbel -Möbel > Baby- & Kleinkindmöbel > Wickeltische -Möbel > Baby- & Kleinkindmöbel > Wiegen & Stubenwagen -Möbel > Baby- & Kleinkindmöbel > Wiegen- & Stubenwagenzubehör -Möbel > Baby- & Kleinkindmöbel > Wiegen- & Stubenwagenzubehör > Untergestelle für Wiegen -Möbel > Baby- & Kleinkindmöbel > Zubehör für Hochstühle und Sitzerhöhungen -Möbel > Betten & Zubehör -Möbel > Betten & Zubehör > Betten -Möbel > Betten & Zubehör > Betten > Ausziehbetten -Möbel > Betten & Zubehör > Betten > Etagenbetten -Möbel > Betten & Zubehör > Betten > Schlafcouch -Möbel > Betten & Zubehör > Betten > Schrankbetten -Möbel > Betten & Zubehör > Bettrahmen -Möbel > Betten & Zubehör > Bettzubehör -Möbel > Betten & Zubehör > Bettzubehör > Wasserbettzubehör -Möbel > Betten & Zubehör > Kopf- & Fußenden -Möbel > Betten & Zubehör > Matratzen -Möbel > Betten & Zubehör > Matratzen > Wasserbetten -Möbel > Betten & Zubehör > Matratzen-Untergestelle -Möbel > Büromöbel -Möbel > Büromöbel > Arbeitsplätze im Großraumbüro -Möbel > Büromöbel > Arbeitstische -Möbel > Büromöbel > Arbeitstische > Konferenztische -Möbel > Büromöbel > Arbeitstische > Verstellbare Zeichentische -Möbel > Büromöbel > Bürostuhl-Zubehör -Möbel > Büromöbel > Bürostühle -Möbel > Büromöbel > Bürostühle > Kniestühle -Möbel > Büromöbel > Schreibtische -Möbel > Büromöbel > Sekretäre -Möbel > Büromöbel > Zubehör für Arbeitsplätze im Großraumbüro -Möbel > Futonauflagen -Möbel > Futonrahmen -Möbel > Futons -Möbel > Gartenmöbel -Möbel > Gartenmöbel > Aufbewahrungsbehälter für draußen -Möbel > Gartenmöbel > Gartenbetten -Möbel > Gartenmöbel > Gartenhocker -Möbel > Gartenmöbel > Gartenmöbelgarnituren -Möbel > Gartenmöbel > Gartensitzmöbel -Möbel > Gartenmöbel > Gartensitzmöbel > Gartenbänke -Möbel > Gartenmöbel > Gartensitzmöbel > Gartensofas -Möbel > Gartenmöbel > Gartensitzmöbel > Gartenstühle -Möbel > Gartenmöbel > Gartensitzmöbel > Sonnenliegen -Möbel > Gartenmöbel > Gartentische -Möbel > Gartenmöbelzubehör -Möbel > Gartenmöbelzubehör > Abdeckungen für Gartenmöbel -Möbel > Kücheninseln & Küchenwagen -Möbel > Kücheninseln & Küchenwagen > Kücheninseln -Möbel > Kücheninseln & Küchenwagen > Küchenwagen -Möbel > Möbelgarnituren -Möbel > Möbelgarnituren > Küchen- & Esszimmergarnituren -Möbel > Möbelgarnituren > Schlafzimmergarnituren -Möbel > Möbelgarnituren > Wohnzimmergarnituren -Möbel > Polsterhocker -Möbel > Polsterhocker > Fußhocker -Möbel > Polsterhocker > Hocker mit Stauraum -Möbel > Polsterhocker > Konvertierbare Hocker -Möbel > Raumteiler -Möbel > Raumteilerzubehör -Möbel > Regalsysteme -Möbel > Regalsysteme > Bücherregale & Bücherschränke -Möbel > Regalzubehör -Möbel > Regalzubehör > Ersatzregale -Möbel > Schränke -Möbel > Schränke > Aktenschränke -Möbel > Schränke > Anrichten -Möbel > Schränke > Aufbewahrungstruhen -Möbel > Schränke > Aufbewahrungstruhen > Aussteuertruhen -Möbel > Schränke > Aufbewahrungstruhen > Spielzeugtruhen -Möbel > Schränke > Buffets & Sideboards -Möbel > Schränke > Geschirrschränke -Möbel > Schränke > Kleiderschränke -Möbel > Schränke > Kommoden -Möbel > Schränke > Mediaaufbewahrung -Möbel > Schränke > Mediaaufbewahrung > Mediaschränke -Möbel > Schränke > Mediaaufbewahrung > TV- & Mediamöbel -Möbel > Schränke > Spirituosenschränke -Möbel > Schränke > Wasch- und Schminktische -Möbel > Schränke > Wasch- und Schminktische > Badezimmerwaschtische -Möbel > Schränke > Wasch- und Schminktische > Schminktische -Möbel > Schränke > Weinregale -Möbel > Schränke > Zeitschriftenständer -Möbel > Sitzbänke -Möbel > Sitzbänke > Küchen- & Eckbänke -Möbel > Sitzbänke > Schminktischhocker -Möbel > Sitzbänke > Truhen- & Flurbänke -Möbel > Sofa-Zubehör -Möbel > Sofa-Zubehör > Sitzverstärkung für Stühle & Sofas -Möbel > Sofas -Möbel > Sofas > Loveseats -Möbel > Sofas > Modulsofas -Möbel > Sofas > Schlafsofas -Möbel > Stuhlzubehör -Möbel > Stühle -Möbel > Stühle > Barhocker -Möbel > Stühle > Elektrische Massagesessel -Möbel > Stühle > Hängesessel -Möbel > Stühle > Klappstühle & Holzhocker -Möbel > Stühle > Küchen- und Esszimmerstühle -Möbel > Stühle > Liegemöbel -Möbel > Stühle > Multimediasessel -Möbel > Stühle > Schaukelstühle -Möbel > Stühle > Sessel -Möbel > Stühle > Sessel > Armsessel -Möbel > Stühle > Sessel > Recliner-Sessel -Möbel > Stühle > Sessel > Schlafsessel -Möbel > Stühle > Sessel ohne Armlehnen -Möbel > Stühle > Sitzsäcke -Möbel > TV- & HiFi-Möbel -Möbel > Tische -Möbel > Tische > Kinderspieltische -Möbel > Tische > Klapptische -Möbel > Tische > Küchen- & Esszimmertische -Möbel > Tische > Küchen- & Esszimmertische > Bartische & Stehtische -Möbel > Tische > Nachttische -Möbel > Tische > Nähmaschinentische -Möbel > Tische > Poker- & Spieltische -Möbel > Tische > Ziertische -Möbel > Tische > Ziertische > Beistelltische -Möbel > Tische > Ziertische > Couchtische -Möbel > Tische > Ziertische > Konsolentische -Möbel > Tischzubehör -Möbel > Tischzubehör > Tischbeine -Möbel > Tischzubehör > Tischplatten -Nahrungsmittel, Getränke & Tabak -Nahrungsmittel, Getränke & Tabak > Getränke -Nahrungsmittel, Getränke & Tabak > Getränke > Alkopops -Nahrungsmittel, Getränke & Tabak > Getränke > Bier -Nahrungsmittel, Getränke & Tabak > Getränke > Bier > Alkoholfreies Bier -Nahrungsmittel, Getränke & Tabak > Getränke > Buttermilch -Nahrungsmittel, Getränke & Tabak > Getränke > Cidre -Nahrungsmittel, Getränke & Tabak > Getränke > Cocktail-Premix -Nahrungsmittel, Getränke & Tabak > Getränke > Eierlikör -Nahrungsmittel, Getränke & Tabak > Getränke > Essighaltige Getränke -Nahrungsmittel, Getränke & Tabak > Getränke > Getränke mit Fruchtgeschmack -Nahrungsmittel, Getränke & Tabak > Getränke > Kaffee -Nahrungsmittel, Getränke & Tabak > Getränke > Kaffee > Gemahlener & ungemahlener Kaffee -Nahrungsmittel, Getränke & Tabak > Getränke > Kaffee > Instantkaffee -Nahrungsmittel, Getränke & Tabak > Getränke > Kaffee > Kaffeegetränke in Flaschen -Nahrungsmittel, Getränke & Tabak > Getränke > Kaffee > Kaffeekapseln -Nahrungsmittel, Getränke & Tabak > Getränke > Kakao -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Gin -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Liköre -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Rum -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Schnäpse -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Tequila -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Weinbrand -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Weinbrand > Cognac -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Whiskey -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Whiskey > Amerikanischer Whiskey -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Whiskey > Irischer Whiskey -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Whiskey > Schottischer Whisky -Nahrungsmittel, Getränke & Tabak > Getränke > Liköre & Spirituosen > Wodka -Nahrungsmittel, Getränke & Tabak > Getränke > Limonaden -Nahrungsmittel, Getränke & Tabak > Getränke > Magenbitter -Nahrungsmittel, Getränke & Tabak > Getränke > Milch -Nahrungsmittel, Getränke & Tabak > Getränke > Milch > Trockenmilch -Nahrungsmittel, Getränke & Tabak > Getränke > Mischgetränke -Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch -Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch > Hafermilch -Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch > Hanfmilch -Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch > Kokosmilch -Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch > Mandelmilch -Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch > Reismilch -Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch > Sojamilch -Nahrungsmittel, Getränke & Tabak > Getränke > Saft -Nahrungsmittel, Getränke & Tabak > Getränke > Sportgetränke & Energy Drinks -Nahrungsmittel, Getränke & Tabak > Getränke > Tees & Aufgüsse -Nahrungsmittel, Getränke & Tabak > Getränke > Tees & Aufgüsse > Teebeutel & Lose Teeblätter -Nahrungsmittel, Getränke & Tabak > Getränke > Tees & Aufgüsse > Teegetränke in Flaschen -Nahrungsmittel, Getränke & Tabak > Getränke > Tees & Aufgüsse > Teepulver -Nahrungsmittel, Getränke & Tabak > Getränke > Wasser -Nahrungsmittel, Getränke & Tabak > Getränke > Wasser > Aromatisiertes Wasser -Nahrungsmittel, Getränke & Tabak > Getränke > Wasser > Mineralwasser -Nahrungsmittel, Getränke & Tabak > Getränke > Wasser > Tonic Water -Nahrungsmittel, Getränke & Tabak > Getränke > Wasser > Wasser in Flaschen -Nahrungsmittel, Getränke & Tabak > Getränke > Wein -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Alkoholfreie Weine -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Blush-Roséwein -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Dessertwein -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Dessertwein > Portwein -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Dessertwein > Sherry -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Dessertwein > Wermut -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Met -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Reiswein -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Roséwein -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Rotwein -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Sangria -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Sekt -Nahrungsmittel, Getränke & Tabak > Getränke > Wein > Weißwein -Nahrungsmittel, Getränke & Tabak > Lebensmittel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Bagels -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Brot & Brötchen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Coffee Cake -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Cupcakes -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Dessert-Platten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Donuts -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Eistüten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Feingebäck -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Fudge -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Kuchen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Muffins -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Pasteten & Torten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Plätzchen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Tacoschalen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Tortillas & Wraps -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Delikatessen Präsentkörbe -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Apfelbutter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Frischkäse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Gemüsedip -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Guacamole -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Hummus -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Käseaufstrich -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Marmeladen & Gelees -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Nussbutter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Nussbutter > Erdnussbutter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Nussbutter > Haselnussbutter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Nussbutter > Mandelbutter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Salsa-Saucen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Tapenade -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertigvorspeisen & -beilagen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertigvorspeisen & -beilagen > Feinkost-Sandwiches -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertigvorspeisen & -beilagen > Fertigbeilagen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertigvorspeisen & -beilagen > Fertighauptgerichte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertigvorspeisen & -beilagen > Frühstückssandwiches -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertigvorspeisen & -beilagen > Pizza -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertigvorspeisen & -beilagen > Waffeln, Pfannkuchen & French Toast -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Hors d'Oeuvre-Tabletts -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Pfannengerichte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Sushi -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Tiefkühlgerichte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Eier -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fisch & Meeresfrüchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fisch & Meeresfrüchte > Fisch- & Meeresfrüchtekonserven -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fisch & Meeresfrüchte > Frische(r) & tiefgefrorene(r) Fisch/Meeresfrüchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Fleisch- & Wurstwaren -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Fleischkonserven -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Frikadellen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Frisches & Tiefgefrorenes Fleisch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Würstchen & Hotdogs -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backaromen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backaromen > Mandelextrakt -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backaromen > Vanilleextrakt -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backfett & Schmalz -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Backmischungen für Brot & Muffins -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Backmischungen für Brot & Muffins > Backmischungen für Muffins -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Backmischungen für Brot & Muffins > Brotmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Backmischungen für Kuchen und Brownies -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Backmischungen für Waffeln und Pfannkuchen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Brezel-Backmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Brotpudding-Backmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen > Plätzchenmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backpulver -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backsoda -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Blockschokoloade -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Bohnenpasten & -saucen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Essbare Backdekoration -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Essbare Backdekoration > Essbare Backwaren-Deko -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Essbare Backdekoration > Farbzucker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Essbare Backdekoration > Streusel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Essbare Backdekoration > Zuckerperlen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Fertigbackmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Geschmacksneutrale Gelatine -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Gezuckerte Kondensmilch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Hefe -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Kochwein -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Kokosraspeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Kuchenfüllung -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Künstliche Süßstoffe -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Lebensmittelfarben -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Maissirup -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Maisstärke -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Marshmallows -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Mehl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Melasse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Paniermehl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Raspeln, Flocken & Tröpfchen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Chili-Öl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Erdnussöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Hanföl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Kochspray -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Kokosöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Maisöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Olivenöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Pflanzenöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Rapsöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Reisöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Sesamöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Sojabohnenöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle > Walnussöl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Starterkulturen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Stärkemehl & Paniermischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig > Brot- & Gebäckteig -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig > Brot- & Gebäckteig > Pizzateig -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig > Pastetenteig -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig > Plätzchen- und Brownieteig -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Tomatenmark -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Ungesüßte Kondensmilch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Zucker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Zuckerguss & Glasur -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Zuckerwatte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Amarant -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Buchweizen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Couscous -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Frühstücksflocken & Müsli -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Gerste -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Haferflocken, Grütze & Grieß -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Hirse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Maismehl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Quinoa -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Reis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Roggen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Weizen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Butter & Margarine -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Hüttenkäse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Joghurt -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Käse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Sahne -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Sauerrahm -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Schlagsahne -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Brotnüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Cashewnüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Dika-Nüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Erdnüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Esskastanien -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Gemischte Nüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Geröstete Sojabohnen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Haselnüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Kolanüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Kürbiskerne -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Macadamia-Nüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Mamoncillo -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Mandeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Nüsse mit Schokoladenüberzug -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Paradiesnüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Paranuss -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Pekanuss -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Pinienkerne -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Pistazien -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Sesamkörner -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Sonnenblumenkerne -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen > Walnüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Dosenbohnen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Dosenfrüchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Alfalfasprossen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Arakachas -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Artischocken -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Auberginen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blumenkohl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Bohnen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Bohnensprossen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Borretsch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Brokkoli -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Chinesischer Brokkoli -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Choi Sum -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Erbsen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Farnspitzen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Fenchelknollen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Flaschenkürbis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Gartenkürbis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Gartensalat -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Gobo-Wurzel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Grünkohl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Gurken -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Ingwer -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kaktusblätter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kartoffeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kichererbsen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Knoblauch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kohl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kohlrabi -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kohlrüben -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Lotoswurzel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Mais -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Mangold -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Maniok -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Möhren -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Okra -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Pak Choi -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Palmkohl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Paprikaschoten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Pastinaken -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Petersilienwurzeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Pilze -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Porree -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Radieschen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rauke -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rettich -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rhabarber -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rosenkohl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rutenkohl -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rüben -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rübenblätter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Salatmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Schalotten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Sellerie -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Sellerieknollen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Spanische Artischocken -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Spargel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Speisekürbisse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Spinat -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Steckrüben -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Süßkartoffeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tamarillos -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tannias -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tarowurzeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tomaten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Topinambur -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wasserkastanien -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wasserkresse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wasserspinat -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wegwarte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wegwarte > Chicorée -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wegwarte > Krausblättrige Endivien -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wegwarte > Radicchio -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wegwarte > Winterendivie -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Weizengras -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Yambohnen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Yams -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Yu Choy -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Zuckerrohr -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Zwiebeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Ananas -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Aprikosen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Atemoyas -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Avocados -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Bananen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Beeren -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Berg-Papayas -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Birnen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Brasilianische Guaven -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Breiäpfel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Brotfrucht -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Cherimoyas -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Datteln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Feigen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Granatäpfel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Grapefruits -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Große Sapoten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Guaven -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Homli-Früchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kaktusfeigen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kirschen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kiwis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kokosnüsse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Korinthen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kumquats -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Limequats -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Limetten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Longan -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Loquats -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Lychees -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Madroaa-Früchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Mandarinen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Mangos -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Mangostanfrüchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Melonen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Melonen > Bittermelonen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Melonen > Horngurken -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Nektarinen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Orangen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Papayas -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Passionsfrüchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Persimonen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Pfirsiche -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Pflaumen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Physalis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Pitahayas -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Plumcots -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Quitten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Rambutans -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Sapoten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Stachelannonen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Sternfrüchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Tamarinden -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Tangelos -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Trauben -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zimtäpfel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitronen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Äpfel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Fruchtsoßen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Fruchtsoßen > Apfelsoße -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Fruchtsoßen > Preiselbeersoße -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Gemüsekonserven -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Getrocknete Bohnen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Getrocknete Früchte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Getrocknetes Gemüse -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Pasta & Nudeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Suppen & Brühen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Suppen & Brühen > Brühwürfel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Suppen & Brühen > Dosensuppen & -brühen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Suppen & Brühen > Fertigsuppen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Kaugummi -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Bonbons -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Candy Corn -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Dauerlutscher -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Frucht- & Weingummi -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Fruchtgummis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Früchte mit Schokoladenüberzug -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Geleebohnen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Karamellbonbons -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Kaubonbons -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Lakritze -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Marshmallow-Bonbons -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Minzbonbons -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Nougat -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Peanut Butter Cups -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Peppermint-Patties -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Pralinen-Sortiments -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Schokoladenriegel & Miniriegel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Schokoladentrüffel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Schokoriegel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Süßigkeiten mit Krokant -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Süßwaren aus Karamell -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Taffy -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Kaugummi > Süßigkeiten & Schokolade > Zuckerstangen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Eishörnchen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Frozen Yogurt -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Fruchteis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Gefrorene Desserts ohne Milchanteil -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Sorbet -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Speiseeis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Stieleis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Fleischalternativen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Käsealternativen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Seitan -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Tempeh -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Tofu -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Brezeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Chips -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Chips > Bagel-Chips -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Chips > Kartoffelchips -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Chips > Mais- & Tortilla-Chips -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Chips > Pita-Chips -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Croûtons -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Dessertküchlein -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Fruchtsnacks -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Getreide- & Müsliriegel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Grissini -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Austerncracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Crackermischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Einfache Cracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Fladenbrotcracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Graham-Cracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Käsecracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Matzecracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Salzcracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker > Sandwich-Cracker -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Käse-Flips -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Popcorn -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Pudding & Gelatine-Snacks -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Reiskuchen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Reiswaffeln -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Salatgarnituren -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Schweineschwarten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Sesamsticks -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Studentenfutter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Trockenfleisch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Trockenfleisch > Beef Jerky -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Trockenfleisch > Pork Jerky -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Trockenfleisch > Turkey Jerky -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Anis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Basilikum -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Bocksbart -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Bohnenkraut -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Chilipulver -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Dill -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Estragon -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Fenchelblätter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Knoblauchpulver -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Koriander -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Kreuzkümmel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Loorbeerblätter -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Majoran -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Minze -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Oregano -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Paprikapulver -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Petersilie -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Rosmarin -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Salbei -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Sauerampfer -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Schnittlauch -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Thymian -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Vanilleschoten -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Zimt -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Zitronengras -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze > Zwiebelpulver -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Mononatriumglutamat -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Pfeffer -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Salz -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Würzmischungen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Barbecue-Sauce -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Bratensoße -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Chilisauce -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Chutney -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Cocktailsaucen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Currysauce -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Dessertsaucen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Dessertsaucen > Aufschlagmittel -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Dessertsaucen > Eissaucen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Dessertsaucen > Fruchttopping -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Essig -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Fischsauce -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Honig -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Kaffeeweißer -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Ketchup -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Marinaden -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Mayonnaise -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Meerrettichsaucen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Oliven & Kapern -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Pastasoßen -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Pickles & Relishes -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Pizzasoße -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Salatdressing -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sataysauce -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sauce tartare -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Senf -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sirup -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sirup > Agavensirup -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sirup > Ahornsirup -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sirup > Aromatisierter Sirup -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sirup > Sirup für Schneeballeis -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sojasauce -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Steaksauce -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Tahini -Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Worcestershiresauce -Nahrungsmittel, Getränke & Tabak > Tabakprodukte -Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Kautabak -Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Rauchlose Zigaretten -Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Tabak -Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Zigaretten -Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Zigarren -Religion & Feierlichkeiten -Religion & Feierlichkeiten > Artikel für Gedenkzeremonien -Religion & Feierlichkeiten > Artikel für Gedenkzeremonien > Urnen -Religion & Feierlichkeiten > Artikel für Hochzeitszeremonien -Religion & Feierlichkeiten > Artikel für Hochzeitszeremonien > Körbe für Blumenmädchen -Religion & Feierlichkeiten > Artikel für Hochzeitszeremonien > Ringkissen -Religion & Feierlichkeiten > Religiöse Artikel -Religion & Feierlichkeiten > Religiöse Artikel > Altare -Religion & Feierlichkeiten > Religiöse Artikel > Gebetsketten -Religion & Feierlichkeiten > Religiöse Artikel > Religiöse Schleier -Software -Software > Computersoftware -Software > Computersoftware > Antiviren- & Sicherheitssoftware -Software > Computersoftware > Betriebssysteme -Software > Computersoftware > Büroanwendungssoftware -Software > Computersoftware > Compiler & Programmierungstools -Software > Computersoftware > Computer-Dienstprogramme & -Wartung -Software > Computersoftware > Handheld- & PDA-Software -Software > Computersoftware > Lernsoftware -Software > Computersoftware > Netzwerksoftware -Software > Computersoftware > Referenzsoftware -Software > Computersoftware > Referenzsoftware > GPS-Karten & -Software -Software > Computersoftware > Referenzsoftware > Wörterbuch- & Übersetzungssoftware -Software > Computersoftware > Software für Multimedia & Design -Software > Computersoftware > Software für Multimedia & Design > Animationsbearbeitungssoftware -Software > Computersoftware > Software für Multimedia & Design > Graphic-Design-Software -Software > Computersoftware > Software für Multimedia & Design > Home-Publishing-Software -Software > Computersoftware > Software für Multimedia & Design > Software für Musikkomposition -Software > Computersoftware > Software für Multimedia & Design > Software zur Erstellung von 3D-Modellen -Software > Computersoftware > Software für Multimedia & Design > Software zur Innenraumgestaltung -Software > Computersoftware > Software für Multimedia & Design > Software zur Medienwiedergabe -Software > Computersoftware > Software für Multimedia & Design > Tonbearbeitungssoftware -Software > Computersoftware > Software für Multimedia & Design > Videobearbeitungssoftware -Software > Computersoftware > Software für Multimedia & Design > Web-Design-Software -Software > Computersoftware > Steuer- & Buchhaltungssoftware -Software > Computersoftware > Unternehmens- & Produktivitätssoftware -Software > Computersoftware > Wiederherstellungsdatenträger -Software > Digital-Content-Software -Software > Digital-Content-Software > Clipart -Software > Digital-Content-Software > Computer-Icons -Software > Digital-Content-Software > Desktop-Hintergrundbilder -Software > Digital-Content-Software > Dokumentvorlagen -Software > Digital-Content-Software > Fonts -Software > Digital-Content-Software > Virtuelles Geld -Software > PC- & Videospiele -Software > PC- & Videospiele > Atari 2600-Spiele -Software > PC- & Videospiele > Atari 5200-Spiele -Software > PC- & Videospiele > Atari Lynx-Spiele -Software > PC- & Videospiele > ColecoVision-Spiele -Software > PC- & Videospiele > Computerspiele -Software > PC- & Videospiele > Computerspiele > Mac-Spiele -Software > PC- & Videospiele > Computerspiele > PC-Spiele -Software > PC- & Videospiele > Dreamcast-Spiele -Software > PC- & Videospiele > Game Boy-Spiele (gesamt) -Software > PC- & Videospiele > Game Boy-Spiele (gesamt) > Game Boy Advance-Spiele -Software > PC- & Videospiele > Game Boy-Spiele (gesamt) > Gameboy-Spiele -Software > PC- & Videospiele > Game Gear-Spiele -Software > PC- & Videospiele > GameCube-Spiele -Software > PC- & Videospiele > Intellivision-Spiele -Software > PC- & Videospiele > Jaguar-Spiele -Software > PC- & Videospiele > LeapFrog-Spiele -Software > PC- & Videospiele > N-Gage-Spiele -Software > PC- & Videospiele > Neo Geo Pocket-Spiele -Software > PC- & Videospiele > Neo Geo-Spiele -Software > PC- & Videospiele > Nintendo 64-Spiele -Software > PC- & Videospiele > Nintendo DS-Spiele -Software > PC- & Videospiele > Nintendo Entertainment System-Spiele -Software > PC- & Videospiele > PC Engine-Spiele -Software > PC- & Videospiele > PlayStation Portable-Spiele -Software > PC- & Videospiele > PlayStation Vita-Spiele -Software > PC- & Videospiele > PlayStation-Spiele (gesamt) -Software > PC- & Videospiele > PlayStation-Spiele (gesamt) > PlayStation (Original)-Spiele -Software > PC- & Videospiele > PlayStation-Spiele (gesamt) > PlayStation 2-Spiele -Software > PC- & Videospiele > PlayStation-Spiele (gesamt) > PlayStation 3-Spiele -Software > PC- & Videospiele > Sega Genesis-Spiele -Software > PC- & Videospiele > Sega Master System-Spiele -Software > PC- & Videospiele > Super Nintendo-Spiele -Software > PC- & Videospiele > Wii U-Spiele -Software > PC- & Videospiele > Wii-Spiele -Software > PC- & Videospiele > Xbox-Spiele (gesamt) -Software > PC- & Videospiele > Xbox-Spiele (gesamt) > Xbox (Original)-Spiele -Software > PC- & Videospiele > Xbox-Spiele (gesamt) > Xbox 360-Spiele -Spielzeuge & Spiele -Spielzeuge & Spiele > Puzzles & Geduldspiele -Spielzeuge & Spiele > Puzzles & Geduldspiele > Holzsteckpuzzle -Spielzeuge & Spiele > Puzzles & Geduldspiele > Mechanische Geduldspiele -Spielzeuge & Spiele > Puzzles & Geduldspiele > Mechanische Geduldspiele > Entwirrspiele -Spielzeuge & Spiele > Puzzles & Geduldspiele > Mechanische Geduldspiele > Geschicklichkeitsspiele -Spielzeuge & Spiele > Puzzles & Geduldspiele > Mechanische Geduldspiele > Zusammensetzspiele -Spielzeuge & Spiele > Puzzles & Geduldspiele > Puzzle-Zubehör -Spielzeuge & Spiele > Puzzles & Geduldspiele > Puzzles -Spielzeuge & Spiele > Spiel-Timer -Spielzeuge & Spiele > Spiele -Spielzeuge & Spiele > Spiele > Battle Tops -Spielzeuge & Spiele > Spiele > Bingo-Spiele -Spielzeuge & Spiele > Spiele > Blackjack- & Würfelspiel-Sets -Spielzeuge & Spiele > Spiele > Brettspiele -Spielzeuge & Spiele > Spiele > Brettspiele > Backgammon-Spiele -Spielzeuge & Spiele > Spiele > Brettspiele > Damespiele -Spielzeuge & Spiele > Spiele > Brettspiele > Parcheesi -Spielzeuge & Spiele > Spiele > Brettspiele > Schachspiele -Spielzeuge & Spiele > Spiele > Kampfkreiselzubehör -Spielzeuge & Spiele > Spiele > Kartenspiele -Spielzeuge & Spiele > Spiele > Kartenspiele > Sammelkartenspiele -Spielzeuge & Spiele > Spiele > Kartenspiele > Traditionelle Spielkarten -Spielzeuge & Spiele > Spiele > Kartenspielzubehör -Spielzeuge & Spiele > Spiele > Legespiele -Spielzeuge & Spiele > Spiele > Legespiele > Dominospiele -Spielzeuge & Spiele > Spiele > Legespiele > Mah-Jongg -Spielzeuge & Spiele > Spiele > Pokerchip-Zubehör -Spielzeuge & Spiele > Spiele > Pokerchip-Zubehör > Behälter für Pokerchips -Spielzeuge & Spiele > Spiele > Pokerchips & -sets -Spielzeuge & Spiele > Spiele > Rouletterad & Zubehör -Spielzeuge & Spiele > Spiele > Stapelspiele -Spielzeuge & Spiele > Spiele > Tragbare elektronische Spiele -Spielzeuge & Spiele > Spiele > Würfelsets & -spiele -Spielzeuge & Spiele > Spiele > Würfelsets & -spiele > Würfel & Würfelsets -Spielzeuge & Spiele > Spiele > Würfelsets & -spiele > Würfelspiele -Spielzeuge & Spiele > Spielzeug für draußen -Spielzeuge & Spiele > Spielzeug für draußen > Hüpfburg-Zubehör -Spielzeuge & Spiele > Spielzeug für draußen > Hüpfburgen -Spielzeuge & Spiele > Spielzeug für draußen > Rutschen -Spielzeuge & Spiele > Spielzeug für draußen > Sandkästen -Spielzeuge & Spiele > Spielzeug für draußen > Schaukeln & Rutschen -Spielzeuge & Spiele > Spielzeug für draußen > Schaukeln & Spielplatzgeräte -Spielzeuge & Spiele > Spielzeug für draußen > Spielfallschirme -Spielzeuge & Spiele > Spielzeug für draußen > Spielhäuser -Spielzeuge & Spiele > Spielzeug für draußen > Spielzelte & -tunnel -Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte -Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte > Wasserparks -Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte > Wasserrutschen für den Garten -Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte > Wassersprenger für Kinder -Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte > Wassertische -Spielzeuge & Spiele > Spielzeug für draußen > Wippen -Spielzeuge & Spiele > Spielzeug für draußen > Zubehör für Schaukeln & Spielplatzgeräte -Spielzeuge & Spiele > Spielzeuge -Spielzeuge & Spiele > Spielzeuge > Aufziehspielzeug -Spielzeuge & Spiele > Spielzeuge > Bad-Spielzeug -Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug -Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Baukästen -Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Holzbausteine -Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Murmelbahnen -Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Schaumstoffbausteine -Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Steckbausteine -Spielzeuge & Spiele > Spielzeuge > Bällebad-Zubehör -Spielzeuge & Spiele > Spielzeuge > Bällebad-Zubehör > Bälle für Bällebad -Spielzeuge & Spiele > Spielzeuge > Bürospielzeug -Spielzeuge & Spiele > Spielzeuge > Bürospielzeug > Magnetspielzeug -Spielzeuge & Spiele > Spielzeuge > Elektronisches Spielzeug -Spielzeuge & Spiele > Spielzeuge > Elektronisches Spielzeug > Roboter -Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug -Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Elektrische Kinderfahrzeuge -Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Hand- & Bollerwagen -Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Schiebe- & Pedalfahrzeuge -Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Steckenpferde -Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Wipp- & Schaukelspielzeug -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Autos -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Boote -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Boote > Ferngesteuerte U-Boote -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Figuren -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Flugzeuge -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Hubschrauber -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Motorräder -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Panzer -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Roboter -Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Zeppeline -Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug -Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Drachen -Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Luft- & Wasserraketen -Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Spielzeug-Fallschirme -Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Spielzeug-Segelflugzeuge -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Ball- und Becherspiele -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Flummis -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Hampelmänner -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Jo-Jos -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Kreisel -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Murmeln -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Paddleball-Spiele -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Seifenblasen -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Seifenblasen-Spielzeug -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Spiele mit Bändern -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Springspirale -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Teile und Zubehör für Jo-Jos -Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Teile und Zubehör für Jo-Jos > JoJo-Handschuhe -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Berufespielzeug & Rollenspiele -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Elektronisches Rollenspielzeug -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Gartengeräte für Kinder -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Haushaltsspielzeug -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Spielgeld & Banken -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Spielwerkzeug -Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Spielzeugküchen & Spielzeuglebensmittel -Spielzeuge & Spiele > Spielzeuge > Kugelbäder -Spielzeuge & Spiele > Spielzeuge > Lernspielzeug -Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Ameisenfarmen -Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Insektensammlung -Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Lesespiele -Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Schieberechner -Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Wissenschafts-Sets -Spielzeuge & Spiele > Spielzeuge > Musikspielzeuge -Spielzeuge & Spiele > Spielzeuge > Musikspielzeuge > Spielzeuginstrumente -Spielzeuge & Spiele > Spielzeuge > Optische Spielzeuge -Spielzeuge & Spiele > Spielzeuge > Optische Spielzeuge > Kaleidoskope -Spielzeuge & Spiele > Spielzeuge > Optische Spielzeuge > Prismen -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Action- & Spielzeugfiguren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Action- & Spielzeugfiguren > Action-Figuren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Action- & Spielzeugfiguren > Spielzeugsoldaten -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Action- & Spielzeugfiguren > Tierfiguren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Action- & Spielzeugfiguren > Tierfiguren > Dinosaurierfiguren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Action- & Spielzeugfiguren > Tierfiguren > Pferde- & Ponyfiguren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Marionetten -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Papier- & Magnetpuppen -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppen -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppenhaus-Zubehör -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppenhäuser -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppentheater -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Spielzeugsets -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Stofftiere -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Wackelfiguren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Zubehör für Puppen & Actionfiguren -Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Zubehör für Puppen & Puppentheater -Spielzeuge & Spiele > Spielzeuge > Spielfahrzeug-Zubehör -Spielzeuge & Spiele > Spielzeuge > Spielfahrzeug-Zubehör > Kinderfahrzeugteile & Zubehör -Spielzeuge & Spiele > Spielzeuge > Spielfahrzeug-Zubehör > Zubehör für Schiebefahrzeuge mit Pedalen -Spielzeuge & Spiele > Spielzeuge > Spielfahrzeug-Zubehör > Zubehör für elektrisches Spielfahrzeug -Spielzeuge & Spiele > Spielzeuge > Spielfahrzeug-Zubehör > Zubehör für elektrisches Spielfahrzeug > Ladegeräte für elektrisches Spielfahrzeug -Spielzeuge & Spiele > Spielzeuge > Spielzeuge zum Malen & Zeichnen -Spielzeuge & Spiele > Spielzeuge > Spielzeuge zum Malen & Zeichnen > Bastelsets -Spielzeuge & Spiele > Spielzeuge > Spielzeuge zum Malen & Zeichnen > Zeichentafeln -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Rennbahnen -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeug-LKWs & -Baumaschinen -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugautos -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugboote -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugflugzeuge -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeughubschrauber -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugmotorräder -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugraumschiffe -Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Züge & Eisenbahnsets -Spielzeuge & Spiele > Spielzeuge > Spielzeugwaffen -Spielzeuge & Spiele > Spielzeuge > Spielzeugwaffen > Wasserpistolen -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > American Football für Kinder -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > American Football für Kinder > Fußbälle aus Schaumstoff -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Baseball für Kinder -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Basketball für Kinder -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Bowling für Kinder -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Bumerangs -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Fitness-Spielzeug -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Fitness-Spielzeug > Hula-Hoop-Reifen -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Footbags -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Frisbees -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Golf für Kinder -Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Hockey für Kinder -Spielzeuge & Spiele > Spielzeuge > Strand- & Sandspielzeug -Spielzeuge & Spiele > Spielzeuge > Strand- & Sandspielzeug > Sandeimer -Spielzeuge & Spiele > Spielzeuge > Strand- & Sandspielzeug > Strandbälle -Spielzeuge & Spiele > Spielzeuge > Zubehör für Spielzeugfahrzeuge -Spielzeuge & Spiele > Spielzeuge > Zubehör für Spielzeugfahrzeuge > Autorennbahn-Zubehör -Spielzeuge & Spiele > Spielzeuge > Zubehör für Spielzeugfahrzeuge > Zubehör für Spielzeugeisenbahn -Spielzeuge & Spiele > Spielzeuge > Zubehör für ferngesteuerte Fahrzeuge -Spielzeuge & Spiele > Spielzeuge > Zubehör für fliegendes Spielzeug -Spielzeuge & Spiele > Spielzeuge > Zubehör für fliegendes Spielzeug > Zubehör für Drachen -Spielzeuge & Spiele > Spielzeuge > Zubehör für fliegendes Spielzeug > Zubehör für Drachen > Wickelspulen für Drachen -Sportartikel -Sportartikel > Kampfsport -Sportartikel > Kampfsport > Box- & Trainingssackzubehör -Sportartikel > Kampfsport > Boxen -Sportartikel > Kampfsport > Boxen > Boxhandschuhe -Sportartikel > Kampfsport > Boxen > Boxringe -Sportartikel > Kampfsport > Boxen > Boxringelemente -Sportartikel > Kampfsport > Boxen > Boxsackzubehör -Sportartikel > Kampfsport > Boxschutzbekleidung -Sportartikel > Kampfsport > Boxsäcke -Sportartikel > Kampfsport > Fechten -Sportartikel > Kampfsport > Fechten > Fechtschutzbekleidung -Sportartikel > Kampfsport > Fechten > Fechtschutzbekleidung > Fechthandschuhe -Sportartikel > Kampfsport > Fechten > Fechtschutzbekleidung > Fechtmasken -Sportartikel > Kampfsport > Kampfkunst -Sportartikel > Kampfsport > Kampfkunst > Kampfsportgürtel -Sportartikel > Kampfsport > Ringen -Sportartikel > Kampfsport > Ringen > Ringermatten -Sportartikel > Kampfsport > Ringen > Schutzbekleidung für Ringer -Sportartikel > Kampfsport > Training-Dummys -Sportartikel > Luftsport -Sportartikel > Luftsport > Drachenfliegen -Sportartikel > Luftsport > Drachenfliegen > Hängegleiter -Sportartikel > Luftsport > Fallschirme -Sportartikel > Luftsport > Fluganzüge -Sportartikel > Mannschaftssportarten -Sportartikel > Mannschaftssportarten > American Football -Sportartikel > Mannschaftssportarten > American Football > American Football-Handschuhe -Sportartikel > Mannschaftssportarten > American Football > American Football-Kicking Tees -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Girdle Shorts -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Helme -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Facemasks -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Helmpolster -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Helmvisiere -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Kinnriemen -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Nackenschutz -Sportartikel > Mannschaftssportarten > American Football > American Football-Schutzbekleidung > American Football-Schulterpads -Sportartikel > Mannschaftssportarten > American Football > American Football-Torstangen -Sportartikel > Mannschaftssportarten > American Football > American Football-Trainingsausrüstung -Sportartikel > Mannschaftssportarten > American Football > Football-Bälle -Sportartikel > Mannschaftssportarten > Ballpumpen -Sportartikel > Mannschaftssportarten > Balltaschen -Sportartikel > Mannschaftssportarten > Baseball -Sportartikel > Mannschaftssportarten > Baseball > Baseball- & Softballhandschuhe -Sportartikel > Mannschaftssportarten > Baseball > Baseball- & Softballhandschuhe > Baseballhandschuhe -Sportartikel > Mannschaftssportarten > Baseball > Baseball- & Softballhandschuhe > Softballhandschuhe -Sportartikel > Mannschaftssportarten > Baseball > Baseball-Bases -Sportartikel > Mannschaftssportarten > Baseball > Baseball-Bälle -Sportartikel > Mannschaftssportarten > Baseball > Baseball-Schutzbekleidung -Sportartikel > Mannschaftssportarten > Baseball > Baseball-Schutzbekleidung > Baseballhelme -Sportartikel > Mannschaftssportarten > Baseball > Baseballnetze -Sportartikel > Mannschaftssportarten > Baseball > Baseballschläger -Sportartikel > Mannschaftssportarten > Baseball > Schlaghandschuhe -Sportartikel > Mannschaftssportarten > Baseball > Wurfmaschinen -Sportartikel > Mannschaftssportarten > Basketball -Sportartikel > Mannschaftssportarten > Basketball > Basketballkorbteile & -zubehör -Sportartikel > Mannschaftssportarten > Basketball > Basketballkorbteile & -zubehör > Basketball-Korbbretter -Sportartikel > Mannschaftssportarten > Basketball > Basketballkorbteile & -zubehör > Basketballnetze -Sportartikel > Mannschaftssportarten > Basketball > Basketballkorbteile & -zubehör > Basketballpfosten -Sportartikel > Mannschaftssportarten > Basketball > Basketballkorbteile & -zubehör > Basketballringe -Sportartikel > Mannschaftssportarten > Basketball > Basketballkorbteile & -zubehör > Schutzverkleidung für Basketballkorb -Sportartikel > Mannschaftssportarten > Basketball > Basketballkörbe -Sportartikel > Mannschaftssportarten > Basketball > Basketbälle -Sportartikel > Mannschaftssportarten > Beachvolleyball -Sportartikel > Mannschaftssportarten > Beachvolleyball > Beachvolleyball-Bälle -Sportartikel > Mannschaftssportarten > Beachvolleyball > Beachvolleyball-Netze -Sportartikel > Mannschaftssportarten > Broomball -Sportartikel > Mannschaftssportarten > Broomball > Broomballschläger -Sportartikel > Mannschaftssportarten > Cheerleading -Sportartikel > Mannschaftssportarten > Cheerleading > Cheerleading-Megaphone -Sportartikel > Mannschaftssportarten > Cheerleading > Pom-Poms -Sportartikel > Mannschaftssportarten > Cricket -Sportartikel > Mannschaftssportarten > Cricket > Cricketbälle -Sportartikel > Mannschaftssportarten > Cricket > Crickethandschuhe -Sportartikel > Mannschaftssportarten > Cricket > Crickethelme -Sportartikel > Mannschaftssportarten > Cricket > Cricketschläger -Sportartikel > Mannschaftssportarten > Curling -Sportartikel > Mannschaftssportarten > Feldhockey -Sportartikel > Mannschaftssportarten > Feldhockey > Feldhockeybälle -Sportartikel > Mannschaftssportarten > Feldhockey > Feldhockeyhandschuhe -Sportartikel > Mannschaftssportarten > Feldhockey > Feldhockeyschläger -Sportartikel > Mannschaftssportarten > Feldhockey > Feldhockeytore -Sportartikel > Mannschaftssportarten > Fußball -Sportartikel > Mannschaftssportarten > Fußball > Eckfahnen -Sportartikel > Mannschaftssportarten > Fußball > Fußball-Kapitänsbinden -Sportartikel > Mannschaftssportarten > Fußball > Fußballschienbeinschützer -Sportartikel > Mannschaftssportarten > Fußball > Fußballtore & -netze -Sportartikel > Mannschaftssportarten > Fußball > Fußbälle -Sportartikel > Mannschaftssportarten > Fußball > Fußbälle > Futsal-Bälle -Sportartikel > Mannschaftssportarten > Fußball > Torwarthandschuhe -Sportartikel > Mannschaftssportarten > Fußball > Zubehör für Fußballtore -Sportartikel > Mannschaftssportarten > Handball -Sportartikel > Mannschaftssportarten > Hockey -Sportartikel > Mannschaftssportarten > Hockey > Hockey-Schutzausrüstung -Sportartikel > Mannschaftssportarten > Hockey > Hockey-Schutzausrüstung > Hockey-Körperpolster -Sportartikel > Mannschaftssportarten > Hockey > Hockey-Schutzausrüstung > Hockeyhandschuhe -Sportartikel > Mannschaftssportarten > Hockey > Hockey-Schutzausrüstung > Hockeyhandschuhe > Eishockeyhandschuhe -Sportartikel > Mannschaftssportarten > Hockey > Hockey-Schutzausrüstung > Hockeyhelme -Sportartikel > Mannschaftssportarten > Hockey > Hockey-Schutzausrüstung > Hockeyhelme > Eishockeyhelme -Sportartikel > Mannschaftssportarten > Hockey > Hockey-Schutzausrüstung > Hockeyhosen -Sportartikel > Mannschaftssportarten > Hockey > Hockeybälle & Pucks -Sportartikel > Mannschaftssportarten > Hockey > Hockeybälle & Pucks > Hockeypucks -Sportartikel > Mannschaftssportarten > Hockey > Hockeybälle & Pucks > Rollhockeybälle -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschlitten -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschläger -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschläger > Eishockeyschläger -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschläger > Hockeyschlager für Street- und Rollhockey -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschlägerpflege -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschlägerteile -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschlägerteile > Hockeyschlägerkellen -Sportartikel > Mannschaftssportarten > Hockey > Hockeyschlägerteile > Hockeyschlägerschäfte -Sportartikel > Mannschaftssportarten > Hockey > Hockeytore -Sportartikel > Mannschaftssportarten > Hockey > Hockeytore > Eishockeytore -Sportartikel > Mannschaftssportarten > Lacrosse -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Bälle -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schläger -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schlägerteile -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schlägerteile > Lacrosse-Schlägerköpfe -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schlägerteile > Lacrosse-Schlägernetze & Strings -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schlägerteile > Lacrosse-Schlägerschäfte -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schutzbekleidung -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schutzbekleidung > Lacrosse-Armschutz -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schutzbekleidung > Lacrosse-Augenschutz -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schutzbekleidung > Lacrosse-Handschuhe -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schutzbekleidung > Lacrosse-Helme -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Schutzbekleidung > Lacrosse-Schulterschutz -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Tore -Sportartikel > Mannschaftssportarten > Lacrosse > Lacrosse-Trainingsausrüstung -Sportartikel > Mannschaftssportarten > Rounders -Sportartikel > Mannschaftssportarten > Rounders > Rounders-Handschuhe -Sportartikel > Mannschaftssportarten > Rounders > Rounders-Schläger -Sportartikel > Mannschaftssportarten > Rugby -Sportartikel > Mannschaftssportarten > Rugby > Rugby-Bälle -Sportartikel > Mannschaftssportarten > Rugby > Rugby-Handschuhe -Sportartikel > Mannschaftssportarten > Rugby > Rugby-Helme -Sportartikel > Mannschaftssportarten > Rugby > Rugby-Tore -Sportartikel > Mannschaftssportarten > Rugby > Rugby-Trainingsausrüstung -Sportartikel > Mannschaftssportarten > Schiedsrichterausrüstung -Sportartikel > Mannschaftssportarten > Schiedsrichterausrüstung > Linienrichterfahnen -Sportartikel > Mannschaftssportarten > Schiedsrichterausrüstung > Schiedsrichterpfeifen -Sportartikel > Mannschaftssportarten > Schiedsrichterausrüstung > Strafkarten -Sportartikel > Mannschaftssportarten > Softball -Sportartikel > Mannschaftssportarten > Softball > Softball-Bälle -Sportartikel > Mannschaftssportarten > Softball > Softball-Schutzbekleidung -Sportartikel > Mannschaftssportarten > Softball > Softballschläger -Sportartikel > Mannschaftssportarten > Volleyball -Sportartikel > Mannschaftssportarten > Volleyball > Volleyball-Bälle -Sportartikel > Mannschaftssportarten > Volleyball > Volleyballnetze -Sportartikel > Mannschaftssportarten > Volleyball > Volleyballtaschen -Sportartikel > Mannschaftssportarten > Zubehör zum Aufpumpen von Bällen -Sportartikel > Mannschaftssportarten > Zubehör zum Aufpumpen von Bällen > Ballpumpenaufsätze -Sportartikel > Outdoor-Aktivitäten -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelblei -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelhaken -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelkästen & Angeltaschen -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelleinen & -wirbel -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelrollen -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelruten -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Fallen für den Angelsport -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Fischernetze -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Gaffs -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Harpunen für den Angelsport -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Karabiner und Drehringe für den Angelsport -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Kunstköder -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Kunstköder > Kunstfliegen -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbefestigung -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbefestigung > Angelschnur -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbefestigung > Pop-Up-Kugeln -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbehälter -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Lebendköder -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Schwimmer -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Wathosen für Angler & Jäger -Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Werkzeug zum Entfernen des Angelhakens -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Camping-Töpfe & -Geschirr -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campinghilfsmittel -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campinghilfsmittel > Messer & Klingen -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campinghilfsmittel > Messer & Klingen > Jagdmesser -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campinghilfsmittel > Multifunktionswerkzeuge & -messer -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campingleuchten & -laternen -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campingmöbel -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campingmöbel > Feldbetten -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campingmöbel > Luftmatratzen -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Campingmöbel > Luftmatratzenzubehör -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Gefriergetrocknete Lebensmittel -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Isomatten -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Jugendherbergs-Schlafsack -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Kompressionssäcke -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Mobile Toiletten -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Moskitonetze -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Navigationskompasse -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Notfalldecken -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Schlafsäcke -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Steigeisen -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Taschenwärmer -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Tragbare Wasserfilter & Wasserreiniger -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Trekkingstöcke -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Urinellas & Tragbare Urinale -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Zelte -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Zeltzubehör -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Zeltzubehör > Vorzelte -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Zeltzubehör > Zeltstangen & -Heringe -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Zeltzubehör > Zeltunterlagen -Sportartikel > Outdoor-Aktivitäten > Camping & Wandern & Rucksacktouren > Zubehör für Trekkingstöcke -Sportartikel > Outdoor-Aktivitäten > Discgolf -Sportartikel > Outdoor-Aktivitäten > Discgolf > Discgolf-Fangkörbe -Sportartikel > Outdoor-Aktivitäten > Discgolf > Discgolf-Scheiben -Sportartikel > Outdoor-Aktivitäten > Discgolf > Discgolf-Taschen -Sportartikel > Outdoor-Aktivitäten > Geocaching -Sportartikel > Outdoor-Aktivitäten > Geocaching > Cachebehälter -Sportartikel > Outdoor-Aktivitäten > Geocaching > Geocaching-Logbücher -Sportartikel > Outdoor-Aktivitäten > Geocaching > Geocaching-Trackables -Sportartikel > Outdoor-Aktivitäten > Golf -Sportartikel > Outdoor-Aktivitäten > Golf > Golf-Sets -Sportartikel > Outdoor-Aktivitäten > Golf > Golf-Tees -Sportartikel > Outdoor-Aktivitäten > Golf > Golf-Trainingshilfen -Sportartikel > Outdoor-Aktivitäten > Golf > Golfballmarkierungen -Sportartikel > Outdoor-Aktivitäten > Golf > Golfbälle -Sportartikel > Outdoor-Aktivitäten > Golf > Golffahnen -Sportartikel > Outdoor-Aktivitäten > Golf > Golfhandschuhe -Sportartikel > Outdoor-Aktivitäten > Golf > Golfhandtücher -Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger -Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger-Teile & Zubehör -Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger-Teile & Zubehör > Golfschläger-Schutzhüllen -Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger-Teile & Zubehör > Golfschlägergriffe -Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschen -Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschenzubehör -Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschenzubehör > Golftaschenhüllen -Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschenzubehör > Golftaschentrolleys -Sportartikel > Outdoor-Aktivitäten > Golf > Pitchgabeln -Sportartikel > Outdoor-Aktivitäten > Jagen -Sportartikel > Outdoor-Aktivitäten > Jagen > Hochsitze -Sportartikel > Outdoor-Aktivitäten > Jagen > Jagdansitze & Tarnung -Sportartikel > Outdoor-Aktivitäten > Jagen > Jagdhund-Ausrüstung -Sportartikel > Outdoor-Aktivitäten > Jagen > Jagdköder -Sportartikel > Outdoor-Aktivitäten > Jagen > Jagdzelte -Sportartikel > Outdoor-Aktivitäten > Jagen > Lockinstrumente -Sportartikel > Outdoor-Aktivitäten > Jagen > Lockmittel für Wild -Sportartikel > Outdoor-Aktivitäten > Jagen > Tierfallen -Sportartikel > Outdoor-Aktivitäten > Jagen > Wildfutterautomaten -Sportartikel > Outdoor-Aktivitäten > Kitebuggying -Sportartikel > Outdoor-Aktivitäten > Kitebuggying > Kitebuggys -Sportartikel > Outdoor-Aktivitäten > Kitebuggying-Zubehör -Sportartikel > Outdoor-Aktivitäten > Klettern -Sportartikel > Outdoor-Aktivitäten > Klettern > Eisklettern -Sportartikel > Outdoor-Aktivitäten > Klettern > Eisklettern > Eiskletterausrüstung -Sportartikel > Outdoor-Aktivitäten > Klettern > Eisklettern > Eisschrauben -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Bouldermatten -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Chalk -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Chalkbags -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Expresssets -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Gurtbänder -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Karabiner -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Klettergurte -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Kletterhelme -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Kletterschutzausrüstung -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Kletterseile -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Kletterwandgriffe -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Seilsäcke -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Sicherungsgeräte -Sportartikel > Outdoor-Aktivitäten > Klettern > Felsklettern & Indoor-Klettern > Steigklemmen & Abseilausrüstung -Sportartikel > Outdoor-Aktivitäten > Laufsport -Sportartikel > Outdoor-Aktivitäten > Leichtathletik -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Diskusscheiben -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Hochsprunglatten -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Hochsprungmatten -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Hürden -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Kugelstoß-Kugeln -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Speere -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Stabhochsprungmatten -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Stabhochsprungstäbe -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Staffelstäbe -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Startpistolen -Sportartikel > Outdoor-Aktivitäten > Leichtathletik > Wurfhämmer -Sportartikel > Outdoor-Aktivitäten > Motorsport -Sportartikel > Outdoor-Aktivitäten > Motorsport > Rennsport -Sportartikel > Outdoor-Aktivitäten > Radsport -Sportartikel > Outdoor-Aktivitäten > Radsport > Dreiradzubehör -Sportartikel > Outdoor-Aktivitäten > Radsport > Dreiräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Dreiräder > Liegedreiräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Einradzubehör -Sportartikel > Outdoor-Aktivitäten > Radsport > Einräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Cleat-Zubehör -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Cleat-Zubehör > Cleat-Platten -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Cleat-Zubehör > Cleat-Schrauben -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Cleat-Zubehör > Cleat-Schutzhüllen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Fahrradhandschuhe -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Fahrradhelme -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Fahrradhelmschutz -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Fahrradüberschuhe -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradausrüstung > Schuhplatten -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremsen-Sets -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremshebel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremsrotoren -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremssättel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradgabeln -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradgriffe & Lenkergriffbänder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkerverlängerungen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkervorbau -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkkopfteile -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkkopfteile > Fahrradlenkkopf-Abstandsringe -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkkopfteile > Fahrradlenkkopf-Halterungen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkköpfe -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkstangen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradrahmen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradreifen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradfelgen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradfußrasten -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradnaben -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradspeichen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Speichennippel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradsattelstützen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradsattelstützenklemmen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradgangschaltungen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradkassetten -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradketten -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradkettenkränze -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradkurbeln -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradpedale -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradschalthebel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Tretlagergehäuse -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschläuche -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradsättel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Kleinere Fahrradzubehörteile -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Kleinere Fahrradzubehörteile > Fahrradhalterungen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Kleinere Fahrradzubehörteile > Fahrradklemmstücke -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Dämpferpumpen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrrad-Fußriemen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradabdeckungen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradanhänger -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradcomputer -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradgepäckträger -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradklingeln & -hupen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradkörbe -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradlichter & -reflektoren -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradpumpen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradsattelbezüge & -polster -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradschlösser -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradschutzbleche -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradspeichenreflektoren -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradspiegel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradständer & Fahrradparksysteme -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradtaschen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradtaschen & -koffer -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradwerkzeug, Reinigungsmittel & Schmiermittel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradwerkzeug, Reinigungsmittel & Schmiermittel > Fahrradschmiermittel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradwerkzeug, Reinigungsmittel & Schmiermittel > Fahrradspeichen-Spannschlüssel -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Flaschenhalter für Fahrradrahmen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Kinderfahrradsitze -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Stützräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Surfbretthalterungen für Fahrräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Trainingsrollen -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Zubehör für Fahrradcomputer -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder > Cruiser -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder > Elektrofahrräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder > Liegeräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder > Mountainbikes -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder > Rennräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder > Trekkingräder -Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder > Triathlonräder -Sportartikel > Outdoor-Aktivitäten > Rasenspiele -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Bean Bag -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Boccia -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Hufeisenwerfen -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Krocket -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Leitergolf -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Rasen-Dart -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Rasenbowling -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Rasenbowling > Rasenbowling-Kugeln -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Rasenbowling > Rasenbowling-Zielkugeln -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Ringwurfspiel -Sportartikel > Outdoor-Aktivitäten > Rasenspiele > Washer Pitching -Sportartikel > Outdoor-Aktivitäten > Reflektierende Fitnessbekleidung -Sportartikel > Outdoor-Aktivitäten > Reflektierende Fitnessbekleidung > Reflektierende Gürtel -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Hufglocken & Gamaschen -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Hufglocken & Gamaschen > Hufglocken -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Hufglocken & Gamaschen > Pferdegamaschen -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Abreitdecken & Weidedecken -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Leckerli für Pferde -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Pferdefutter -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Pferdehaarpflege -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Pferdehaarpflege > Pferdeschermaschinen -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Vitamine & Futterergänzungsmittel für Pferde -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Gerten -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Reithandschuhe -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Reithelme -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Reithosen -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Pferdegeschirr -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Sattelgurte -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Sättel -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Trensen -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Zaumzeug -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Zügel -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Pferdesattel & -zaumzeug -Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Pferdesattel & -zaumzeug > Sattelauflagen -Sportartikel > Outdoor-Aktivitäten > Roller -Sportartikel > Outdoor-Aktivitäten > Roller > Motorroller -Sportartikel > Outdoor-Aktivitäten > Roller > Tretroller -Sportartikel > Outdoor-Aktivitäten > Schießspiele -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Battlepacks -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Gewehrteile -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Gewehrteile > Paintball-Gewehrläufe -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Gewehrteile > Paintball-Hopper -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Granaten -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Granatwerfer -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Markierer -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Pressluftflaschen -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Schutzausrüstung -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Schutzausrüstung > Paintball-Handschuhe -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Schutzausrüstung > Paintball-Protektoren -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Schutzausrüstung > Paintball-Schutzbrillen & -Masken -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintball-Schutzausrüstung > Paintball-Westen -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Paintball > Paintballs -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Softair -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Softair > Softair-Schutzausrüstung -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Softair > Softairkugeln -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Softair > Softairwaffen -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Softair > Softairwaffen-Teile & -Zubehör -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Softair > Softairwaffen-Teile & -Zubehör > Batterien für Softairwaffen -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Tontaubenschießen -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Tontaubenschießen > Tontauben -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Tontaubenschießen > Tontauben-Wurfmaschinen -Sportartikel > Outdoor-Aktivitäten > Schießspiele > Zielscheiben -Sportartikel > Outdoor-Aktivitäten > Schutzkleidung für Jagd- und Schießsport -Sportartikel > Outdoor-Aktivitäten > Schutzkleidung für Jagd- und Schießsport > Handschuhe für Jagd- und Schießsport -Sportartikel > Outdoor-Aktivitäten > Schutzkleidung für Jagd- und Schießsport > Jacken für Jagd- und Schießsport -Sportartikel > Outdoor-Aktivitäten > Shuffleboard -Sportartikel > Outdoor-Aktivitäten > Shuffleboard > Shuffleboard-Cues -Sportartikel > Outdoor-Aktivitäten > Shuffleboard > Shuffleboard-Disks -Sportartikel > Outdoor-Aktivitäten > Skateboarding -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skate-Rails -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skate-Rampen -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Schutzausrüstung -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Schutzausrüstung > Handschuhe für Skateboarder -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Schutzausrüstung > Skateboard-Helme -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Schutzausrüstung > Skateboard-Protektoren -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Achsen -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Decks -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Kugellager -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Rollen -Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboards -Sportartikel > Outdoor-Aktivitäten > Skaten -Sportartikel > Outdoor-Aktivitäten > Skaten > Eiskunstlaufstiefel -Sportartikel > Outdoor-Aktivitäten > Skaten > Inline-Skates -Sportartikel > Outdoor-Aktivitäten > Skaten > Kufenschoner -Sportartikel > Outdoor-Aktivitäten > Skaten > Rollerskates -Sportartikel > Outdoor-Aktivitäten > Skaten > Schlittschuhe -Sportartikel > Outdoor-Aktivitäten > Skaten > Schlittschuhe > Eishockeyschlittschuhe -Sportartikel > Outdoor-Aktivitäten > Skaten > Schlittschuhe > Eiskunstlaufschuhe -Sportartikel > Outdoor-Aktivitäten > Skaten > Schlittschuhkufen -Sportartikel > Outdoor-Aktivitäten > Skaten > Schlittschuhschleifer -Sportartikel > Outdoor-Aktivitäten > Skaten > Schnürhilfen -Sportartikel > Outdoor-Aktivitäten > Skaten > Skate-Helme & -Protektoren -Sportartikel > Outdoor-Aktivitäten > Skaten > Skate-Zubehörteile -Sportartikel > Outdoor-Aktivitäten > Stadionsitze und Polster -Sportartikel > Outdoor-Aktivitäten > Tetherball -Sportartikel > Outdoor-Aktivitäten > Trinksystem-Zubehör -Sportartikel > Outdoor-Aktivitäten > Trinksystemrucksäcke & -taschen -Sportartikel > Sportarten & Spiele für drinnen -Sportartikel > Sportarten & Spiele für drinnen > Air-Hockey -Sportartikel > Sportarten & Spiele für drinnen > Air-Hockey > Air-Hockey-Pucks -Sportartikel > Sportarten & Spiele für drinnen > Air-Hockey > Air-Hockey-Schläger -Sportartikel > Sportarten & Spiele für drinnen > Air-Hockey > Air-Hockey-Tische -Sportartikel > Sportarten & Spiele für drinnen > Air-Hockey > Air-Hockey-Tischzubehör -Sportartikel > Sportarten & Spiele für drinnen > Billard -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billarddreiecke -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardhandschuhe -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardkugeln -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardqueues & Queuebrücken -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardtisch-Beleuchtung -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardtisch-Teile & Zubehör -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardtisch-Teile & Zubehör > Ballfangtaschen -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardtisch-Teile & Zubehör > Billardtisch-Bürsten -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardtisch-Teile & Zubehör > Billardtücher -Sportartikel > Sportarten & Spiele für drinnen > Billard > Billardtische -Sportartikel > Sportarten & Spiele für drinnen > Billard > Queuezubehör -Sportartikel > Sportarten & Spiele für drinnen > Billard > Queuezubehör > Queueständer -Sportartikel > Sportarten & Spiele für drinnen > Bowling -Sportartikel > Sportarten & Spiele für drinnen > Bowling > Bowling-Handgelenkstützen -Sportartikel > Sportarten & Spiele für drinnen > Bowling > Bowlinghandschuhe -Sportartikel > Sportarten & Spiele für drinnen > Bowling > Bowlingkegel -Sportartikel > Sportarten & Spiele für drinnen > Bowling > Bowlingkugeln -Sportartikel > Sportarten & Spiele für drinnen > Bowling > Bowlingtaschen -Sportartikel > Sportarten & Spiele für drinnen > Darts -Sportartikel > Sportarten & Spiele für drinnen > Darts > Dart-Rückwände -Sportartikel > Sportarten & Spiele für drinnen > Darts > Dartpfeile & -Sets -Sportartikel > Sportarten & Spiele für drinnen > Darts > Dartscheiben -Sportartikel > Sportarten & Spiele für drinnen > Darts > Dartteile -Sportartikel > Sportarten & Spiele für drinnen > Darts > Dartteile > Dartflights -Sportartikel > Sportarten & Spiele für drinnen > Darts > Dartteile > Dartschäfte -Sportartikel > Sportarten & Spiele für drinnen > Darts > Dartteile > Dartspitzen -Sportartikel > Sportarten & Spiele für drinnen > Jakkolo -Sportartikel > Sportarten & Spiele für drinnen > Jakkolo > Jakkolo-Pulver -Sportartikel > Sportarten & Spiele für drinnen > Jakkolo > Jakkolo-Spielsteine -Sportartikel > Sportarten & Spiele für drinnen > Jakkolo > Shuffleboard-Tische -Sportartikel > Sportarten & Spiele für drinnen > Multispieltische -Sportartikel > Sportarten & Spiele für drinnen > Tischfußball -Sportartikel > Sportarten & Spiele für drinnen > Tischfußball > Tischfußball-Bälle -Sportartikel > Sportarten & Spiele für drinnen > Tischfußball > Tischfußball-Tische -Sportartikel > Sportarten & Spiele für drinnen > Tischfußball > Zubehör für Tischfußballtische -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis > Tischtennis-Roboter -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis > Tischtennisbälle -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis > Tischtennisnetze und -pfosten -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis > Tischtennisplatten -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis > Tischtennisschläger -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis > Zubehör für Tischtennis-Roboter -Sportartikel > Sportarten & Spiele für drinnen > Tischtennis > Zubehör für Tischtennisschläger -Sportartikel > Sportarten mit Schläger -Sportartikel > Sportarten mit Schläger > Badminton -Sportartikel > Sportarten mit Schläger > Badminton > Badmintonnetze -Sportartikel > Sportarten mit Schläger > Badminton > Badmintonschläger -Sportartikel > Sportarten mit Schläger > Badminton > Federbälle -Sportartikel > Sportarten mit Schläger > Bälle für Paddle-Tennis -Sportartikel > Sportarten mit Schläger > Paddle-Tennis -Sportartikel > Sportarten mit Schläger > Pickleball -Sportartikel > Sportarten mit Schläger > Platform-Tennis -Sportartikel > Sportarten mit Schläger > Racquetball -Sportartikel > Sportarten mit Schläger > Racquetball > Racquetball-Bälle -Sportartikel > Sportarten mit Schläger > Racquetball > Racquetball-Schläger -Sportartikel > Sportarten mit Schläger > Racquetball > Racquetball-Schutzausrüstung -Sportartikel > Sportarten mit Schläger > Racquetball > Racquetball-Schutzausrüstung > Squash- & Racquetball-Schutzbrillen -Sportartikel > Sportarten mit Schläger > Squash -Sportartikel > Sportarten mit Schläger > Squash > Squash-Bälle -Sportartikel > Sportarten mit Schläger > Squash > Squash-Schläger -Sportartikel > Sportarten mit Schläger > Squash > Squash-Schutzausrüstung -Sportartikel > Sportarten mit Schläger > Tennis -Sportartikel > Sportarten mit Schläger > Tennis > Tennisballdosen -Sportartikel > Sportarten mit Schläger > Tennis > Tennisballkörbe -Sportartikel > Sportarten mit Schläger > Tennis > Tennisballwurfmaschinen -Sportartikel > Sportarten mit Schläger > Tennis > Tennisbälle -Sportartikel > Sportarten mit Schläger > Tennis > Tennisnetze -Sportartikel > Sportarten mit Schläger > Tennis > Tennisschläger -Sportartikel > Sportarten mit Schläger > Tennis > Tennisschlägerzubehör -Sportartikel > Sportarten mit Schläger > Tennis > Tennisschlägerzubehör > Griffbänder -Sportartikel > Sportarten mit Schläger > Tennis > Tennisschlägerzubehör > Tennissaiten -Sportartikel > Sportarten mit Schläger > Tennis > Tennisschlägerzubehör > Tennistaschen -Sportartikel > Sportarten mit Schläger > Tennis > Tennisschlägerzubehör > Vibrationsdämpfer -Sportartikel > Sportarten mit Schläger > Tennis > Tennisschlägerzubehör > Ösenbänder für Tennisschläger -Sportartikel > Sportübungen & Fitness -Sportartikel > Sportübungen & Fitness > Bauchtrainer -Sportartikel > Sportübungen & Fitness > Fitnessbänder -Sportartikel > Sportübungen & Fitness > Gewichthebergürtel -Sportartikel > Sportübungen & Fitness > Gewichtheberhandschuhe & Handgelenkschoner -Sportartikel > Sportübungen & Fitness > Gewichtswesten & -manschetten -Sportartikel > Sportübungen & Fitness > Gymnastikbälle -Sportartikel > Sportübungen & Fitness > Gymnastikmatten -Sportartikel > Sportübungen & Fitness > Gymnastikmatten > Matten für Heimtrainer -Sportartikel > Sportübungen & Fitness > Hantelbänke -Sportartikel > Sportübungen & Fitness > Hanteln -Sportartikel > Sportübungen & Fitness > Hantelstangen -Sportartikel > Sportübungen & Fitness > Hantelzubehör -Sportartikel > Sportübungen & Fitness > Kardiogeräte -Sportartikel > Sportübungen & Fitness > Kardiogeräte > Crosstrainer -Sportartikel > Sportübungen & Fitness > Kardiogeräte > Heimtrainer -Sportartikel > Sportübungen & Fitness > Kardiogeräte > Laufbänder -Sportartikel > Sportübungen & Fitness > Kardiogeräte > Rudergeräte -Sportartikel > Sportübungen & Fitness > Kardiogeräte > Stepper -Sportartikel > Sportübungen & Fitness > Krafttrainingsgeräte -Sportartikel > Sportübungen & Fitness > Medizinbälle -Sportartikel > Sportübungen & Fitness > Reaction Balls -Sportartikel > Sportübungen & Fitness > Schaumroller -Sportartikel > Sportübungen & Fitness > Schaumroller-Zubehör -Sportartikel > Sportübungen & Fitness > Schaumroller-Zubehör > Aufbewahrungstaschen für Schaumroller -Sportartikel > Sportübungen & Fitness > Springseile -Sportartikel > Sportübungen & Fitness > Stoppuhren -Sportartikel > Sportübungen & Fitness > Yoga & Pilates -Sportartikel > Sportübungen & Fitness > Yoga & Pilates > Beutel für Yogamatten -Sportartikel > Sportübungen & Fitness > Yoga & Pilates > Pilates-Geräte -Sportartikel > Sportübungen & Fitness > Yoga & Pilates > Yoga- & Pilatesblöcke -Sportartikel > Sportübungen & Fitness > Yoga & Pilates > Yoga- & Pilatesmatten -Sportartikel > Sportübungen & Fitness > Yoga- & Pilateszubehör -Sportartikel > Sportübungen & Fitness > Yoga- & Pilateszubehör > Yoga- & Pilatestücher -Sportartikel > Sportübungen & Fitness > Zubehör für Kardiogeräte -Sportartikel > Sportübungen & Fitness > Zubehör für Krafttrainingsgeräte -Sportartikel > Springen -Sportartikel > Springen > Bungee-Jumping -Sportartikel > Springen > Springstöcke -Sportartikel > Springen > Sprungstelzen -Sportartikel > Springen > Trampoline -Sportartikel > Springen > Trampolinzubehör -Sportartikel > Springen > Trampolinzubehör > Trampolin-Sicherheitspolster -Sportartikel > Springen > Trampolinzubehör > Trampolin-Verankerungssets -Sportartikel > Springen > Trampolinzubehör > Trampolinfedern -Sportartikel > Springen > Trampolinzubehör > Trampolinleitern -Sportartikel > Springen > Trampolinzubehör > Trampolinnetze -Sportartikel > Springen > Trampolinzubehör > Trampolinsprungtücher -Sportartikel > Tanzen -Sportartikel > Tanzen > Ballettstangen -Sportartikel > Turnen -Sportartikel > Turnen > Schutzausrüstung -Sportartikel > Turnen > Schwebebalken -Sportartikel > Turnen > Sprungpferde -Sportartikel > Turnen > Turnmatten -Sportartikel > Turnen > Turnpferde -Sportartikel > Turnen > Turnringe -Sportartikel > Turnen > Turnsprungbretter -Sportartikel > Turnen > Turnstangen -Sportartikel > Wassersport -Sportartikel > Wassersport > Ablagen für Wasserfahrzeuge -Sportartikel > Wassersport > Bootssport -Sportartikel > Wassersport > Bootssport > Handschuhe für den Bootssport -Sportartikel > Wassersport > Bootssport > Kajaksport -Sportartikel > Wassersport > Bootssport > Kajaksport > Kajak-Zubehör -Sportartikel > Wassersport > Bootssport > Kajaksport > Kajak-Zubehör > Spritzdecken -Sportartikel > Wassersport > Bootssport > Kajaksport > Kajaks -Sportartikel > Wassersport > Bootssport > Kanusport -Sportartikel > Wassersport > Bootssport > Kanusport > Kanu-Zubehör -Sportartikel > Wassersport > Bootssport > Kanusport > Kanus -Sportartikel > Wassersport > Bootssport > Raftingboote -Sportartikel > Wassersport > Bootssport > Rudern -Sportartikel > Wassersport > Bootssport > Rudern > Ruderboote -Sportartikel > Wassersport > Bootssport > Rudern > Sitzauflagen -Sportartikel > Wassersport > Bootssport > Segel- & Yachtsport -Sportartikel > Wassersport > Bootssport > Tretboote -Sportartikel > Wassersport > Kitesurfen -Sportartikel > Wassersport > Kitesurfen > Kiteboard-Taschen -Sportartikel > Wassersport > Kitesurfen > Kiteboards -Sportartikel > Wassersport > Kitesurfen > Kiteboardteile -Sportartikel > Wassersport > Kitesurfen > Kitesurfing-Kites -Sportartikel > Wassersport > Kitesurfen > Kitesurfing-Trapeze -Sportartikel > Wassersport > Neoprenanzüge -Sportartikel > Wassersport > Neoprenanzüge > Neopren-Oberteile -Sportartikel > Wassersport > Neoprenanzüge > Neopren-Unterteile -Sportartikel > Wassersport > Neoprenanzüge > Zubehör für Neoprenanzüge -Sportartikel > Wassersport > Paddel & Ruder -Sportartikel > Wassersport > Rafting -Sportartikel > Wassersport > Rafting > Raftinghelme -Sportartikel > Wassersport > Rafting > Rafts -Sportartikel > Wassersport > Rettungswesten -Sportartikel > Wassersport > Schwimmen -Sportartikel > Wassersport > Schwimmen > Badekappen -Sportartikel > Wassersport > Schwimmen > Gegenstromanlagen -Sportartikel > Wassersport > Schwimmen > Handpaddel -Sportartikel > Wassersport > Schwimmen > Nasenklammern -Sportartikel > Wassersport > Schwimmen > Pull Buoys -Sportartikel > Wassersport > Schwimmen > Schwimmbretter -Sportartikel > Wassersport > Schwimmen > Schwimmbrillen & -masken -Sportartikel > Wassersport > Schwimmen > Schwimmflossen -Sportartikel > Wassersport > Schwimmen > Schwimmflossen > Monoflossen -Sportartikel > Wassersport > Schwimmen > Schwimmflossen > Trainingsflossen -Sportartikel > Wassersport > Schwimmen > Schwimmgewichte -Sportartikel > Wassersport > Schwimmen > Schwimmgürtel -Sportartikel > Wassersport > Schwimmen > Schwimmhandschuhe -Sportartikel > Wassersport > Schwimmen > Zubehör für Schwimmbrillen & -masken -Sportartikel > Wassersport > Schwimmwestenzubehör -Sportartikel > Wassersport > Seilgebundene Wassersportarten -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Handschuhe für Wassersport mit Zugseil -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Kneeboarding -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Kneeboarding > Kneeboards -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Parasailing -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Tubes & Towables -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wakeboarding -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wakeboarding > Wakeboard-Bindungen -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wakeboarding > Wakeboards -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wasserski -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wasserski > Hydrofoils -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wasserski > Wasserski-Bindungen -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wasserski > Wasserski-Koffer & -Taschen -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Wasserski > Wasserskier -Sportartikel > Wassersport > Seilgebundene Wassersportarten > Zugseile -Sportartikel > Wassersport > Surfen -Sportartikel > Wassersport > Surfen > Bodyboards -Sportartikel > Wassersport > Surfen > Fußschlaufen & Trapeztampen -Sportartikel > Wassersport > Surfen > Handschuhe für Surfer -Sportartikel > Wassersport > Surfen > Paddelboards -Sportartikel > Wassersport > Surfen > Skimboards -Sportartikel > Wassersport > Surfen > Surfboard-Taschen -Sportartikel > Wassersport > Surfen > Surfboard-Wachs -Sportartikel > Wassersport > Surfen > Surfbretter -Sportartikel > Wassersport > Surfen > Surfbrettfinnen -Sportartikel > Wassersport > Surfen > Surfpads -Sportartikel > Wassersport > Tauchen & Schnorcheln -Sportartikel > Wassersport > Tauchen & Schnorcheln > Atemregler -Sportartikel > Wassersport > Tauchen & Schnorcheln > Bleigürtel -Sportartikel > Wassersport > Tauchen & Schnorcheln > Handschuhe für Taucher & Schnorchler -Sportartikel > Wassersport > Tauchen & Schnorcheln > Schnorchel -Sportartikel > Wassersport > Tauchen & Schnorcheln > Tarierwesten -Sportartikel > Wassersport > Tauchen & Schnorcheln > Tauch- & Schnorchelflossen -Sportartikel > Wassersport > Tauchen & Schnorcheln > Tauch- & Schnorchelmasken -Sportartikel > Wassersport > Tauchen & Schnorcheln > Tauchcomputer -Sportartikel > Wassersport > Tauchen & Schnorcheln > Tauchermesser & -scheren -Sportartikel > Wassersport > Tauchen & Schnorcheln > Trockenanzüge -Sportartikel > Wassersport > Tubing -Sportartikel > Wassersport > UV-Schutz-Shirts -Sportartikel > Wassersport > Wasserball -Sportartikel > Wassersport > Wasserball > Wasserballkappen -Sportartikel > Wassersport > Wasserball > Wasserballtore -Sportartikel > Wassersport > Wasserball > Wasserbälle -Sportartikel > Wassersport > Windsurfen -Sportartikel > Wassersport > Windsurfen > Windsurf-Ausrüstung -Sportartikel > Wassersport > Windsurfen > Windsurf-Ausrüstung > Windsurf-Finnen -Sportartikel > Wassersport > Windsurfen > Windsurf-Ausrüstung > Windsurfmasten -Sportartikel > Wassersport > Windsurfen > Windsurf-Ausrüstung > Windsurfsegel -Sportartikel > Wassersport > Windsurfen > Windsurfbretter -Sportartikel > Wintersport -Sportartikel > Wintersport > Bobs -Sportartikel > Wintersport > Rodeln -Sportartikel > Wintersport > Schlitten -Sportartikel > Wintersport > Schlitten > Rodelschlitten -Sportartikel > Wintersport > Schlitten > Rodelschlitten > Rennschlitten -Sportartikel > Wintersport > Schlitten > Rodelschlitten > Schneerutscher -Sportartikel > Wintersport > Schlitten > Rodelschlitten > Toboggans -Sportartikel > Wintersport > Schlitten > Rodelschläuche -Sportartikel > Wintersport > Schneemobilsport -Sportartikel > Wintersport > Schneeschuhe & Zubehör -Sportartikel > Wintersport > Schneeschuhe & Zubehör > Schneeschuhbinder -Sportartikel > Wintersport > Schneeschuhe & Zubehör > Schneeschuhe -Sportartikel > Wintersport > Skisport -Sportartikel > Wintersport > Skisport > Ski- & Snowboard-Brillen -Sportartikel > Wintersport > Skisport > Ski- & Snowboard-Brillengläser -Sportartikel > Wintersport > Skisport > Ski- & Snowboardhelme -Sportartikel > Wintersport > Skisport > Skibindungen -Sportartikel > Wintersport > Skisport > Skibindungen > Skibindungen Alpin -Sportartikel > Wintersport > Skisport > Skibindungen > Skibindungen Langlauf -Sportartikel > Wintersport > Skisport > Skier -Sportartikel > Wintersport > Skisport > Skier > Alpinskier -Sportartikel > Wintersport > Skisport > Skier > Langlaufskier -Sportartikel > Wintersport > Skisport > Skier- & Snowboard-Ablagen -Sportartikel > Wintersport > Skisport > Skier- & Snowboard-Taschen -Sportartikel > Wintersport > Skisport > Skier- & Snowboard-Taschen > Skitaschen -Sportartikel > Wintersport > Skisport > Skier- & Snowboard-Taschen > Snowboardtaschen -Sportartikel > Wintersport > Skisport > Skischuhe -Sportartikel > Wintersport > Skisport > Skischuhe > Skischuhe Alpin -Sportartikel > Wintersport > Skisport > Skischuhe > Skischuhe Langlauf -Sportartikel > Wintersport > Skisport > Skistöcke -Sportartikel > Wintersport > Snowboarden -Sportartikel > Wintersport > Snowboarden > Snowboard-Bindungen -Sportartikel > Wintersport > Snowboarden > Snowboards -Sportartikel > Wintersport > Snowboarden > Snowboardstiefel -Sportartikel > Wintersport > Snowboarden > Zubehör Snowboard-Bindungen -Taschen & Gepäck -Taschen & Gepäck > Bauchtaschen -Taschen & Gepäck > Business-Taschen -Taschen & Gepäck > Business-Taschen > Aktentaschen -Taschen & Gepäck > Business-Taschen > Kleidertaschen -Taschen & Gepäck > Business-Taschen > Taschen & Etuis für elektronische Geräte -Taschen & Gepäck > Business-Taschen > Taschen & Etuis für elektronische Geräte > Computerschutzhüllen -Taschen & Gepäck > Business-Taschen > Taschen & Etuis für elektronische Geräte > Laptoptaschen & -Etuis -Taschen & Gepäck > Business-Taschen > Taschen & Etuis für elektronische Geräte > Taschen & Etuis für Tablets -Taschen & Gepäck > Einkaufstaschen -Taschen & Gepäck > Gepäckzubehör -Taschen & Gepäck > Gepäckzubehör > Gepäck-Organizer -Taschen & Gepäck > Gepäckzubehör > Gepäckanhänger -Taschen & Gepäck > Gepäckzubehör > Koffergurte -Taschen & Gepäck > Gepäckzubehör > Reisebehälter -Taschen & Gepäck > Gepäckzubehör > Reisedokumententaschen -Taschen & Gepäck > Koffer -Taschen & Gepäck > Koffer > Handgepäck -Taschen & Gepäck > Kosmetikkoffer -Taschen & Gepäck > Kulturtaschen -Taschen & Gepäck > Kurier- & Schultertaschen -Taschen & Gepäck > Rucksackzubehör -Taschen & Gepäck > Rucksackzubehör > Rucksack-Schutzhüllen -Taschen & Gepäck > Rucksäcke -Taschen & Gepäck > Seesäcke -Taschen & Gepäck > Wickeltaschen -Tiere & Tierbedarf -Tiere & Tierbedarf > Haustierbedarf -Tiere & Tierbedarf > Haustierbedarf > Aquaristik -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquarien -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumbeleuchtung -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumdekoration -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumdekoration > Künstliche Aquariumpflanzen -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumfilter -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumpumpen -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumständer -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Bodengrund für Aquarien -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Fischfutter -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Fischfutterautomaten -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Heizvorrichtungen für Aquarien -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Wasseraufbereitungsgeräte -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Wasserpflanzendünger -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Wasserpumpen für Aquarien -Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Überlaufkästen -Tiere & Tierbedarf > Haustierbedarf > Augentropfen für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Begrenzungssysteme -Tiere & Tierbedarf > Haustierbedarf > Bodenschutz & Unterlagen -Tiere & Tierbedarf > Haustierbedarf > Bügel für Haustierbekleidung -Tiere & Tierbedarf > Haustierbedarf > Erkennungsmarken -Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere > Glukosemessgeräte für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere > Schrittzähler für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere > Thermometer für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere > Tierwaagen -Tiere & Tierbedarf > Haustierbedarf > Floh- & Zeckenschutzmittel -Tiere & Tierbedarf > Haustierbedarf > Floh- & Zeckenschutzmittel > Mittel gegen Hundeflöhe/-zecken -Tiere & Tierbedarf > Haustierbedarf > Floh- & Zeckenschutzmittel > Mittel gegen Katzenflöhe/-zecken -Tiere & Tierbedarf > Haustierbedarf > Futternäpfe, Futter- & Wasserspender -Tiere & Tierbedarf > Haustierbedarf > Futternäpfe, Futter- & Wasserspender > Futternäpfe, Futter- & Wasserspender für Kleintiere -Tiere & Tierbedarf > Haustierbedarf > Futternäpfe, Futter- & Wasserspender > Hundeschüsseln, Futter- & Wasserspender -Tiere & Tierbedarf > Haustierbedarf > Futternäpfe, Futter- & Wasserspender > Katzenschüsseln, Futter- & Wasserspender -Tiere & Tierbedarf > Haustierbedarf > Glocken & Anhänger -Tiere & Tierbedarf > Haustierbedarf > Halsbänder & Geschirre -Tiere & Tierbedarf > Haustierbedarf > Halsbänder & Geschirre > Hundehalsbänder & Hundegeschirre -Tiere & Tierbedarf > Haustierbedarf > Halsbänder & Geschirre > Katzenhalsbänder & Katzengeschirre -Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel -Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Kämme & Bürsten zur Fellpflege -Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Nagellack für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Nagelpflege für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Shampoos & Spülungen zur Fellpflege -Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Tierhaarschneider -Tiere & Tierbedarf > Haustierbedarf > Haustiersportbedarf -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundebekleidung -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundebetten -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundefutter -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundehütten -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundespielzeug -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundewindeln -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundezwinger & -ausläufe -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Leckerbissen für Hunde -Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Zubehör für Hundezwinger & -ausläufe -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenbekleidung -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenbetten -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenfutter -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenmöbel -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenspielzeug -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenstreu -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzentoiletten -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Leckerbissen für Katzen -Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Vorleger für Katzentoiletten -Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör -Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Decken & Streu für Kleintiere -Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Futter für Kleintiere -Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Lebensräume & Gehege für Kleintiere -Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Leckerli für Kleintiere -Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Zubehör für Lebensräume von Kleintieren -Tiere & Tierbedarf > Haustierbedarf > Leinen -Tiere & Tierbedarf > Haustierbedarf > Leinen > Hundeleinen -Tiere & Tierbedarf > Haustierbedarf > Leinen > Katzenleinen -Tiere & Tierbedarf > Haustierbedarf > Lockmittel für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Maulkörbe -Tiere & Tierbedarf > Haustierbedarf > Medizinische Halsbänder für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Medizinisches Klebeband & Verbandsmaterial für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Mundpflege für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Mundpflege für Haustiere > Mundspray für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Mundpflege für Haustiere > Zahnbürsten für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Mundpflege für Haustiere > Zahnpasta für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Napfunterlagen -Tiere & Tierbedarf > Haustierbedarf > Pet-Stroller -Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf -Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Bodengrund für Reptilien & Amphibien -Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Heizung & Beleuchtung für Terrarien -Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Reptilien- & Amphibienfutter -Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Terrarien -Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Zubehör für Terrarien -Tiere & Tierbedarf > Haustierbedarf > Sonnenschutz für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Spielgehege für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Tierfutterbehälter -Tiere & Tierbedarf > Haustierbedarf > Tierfutterportionierer -Tiere & Tierbedarf > Haustierbedarf > Tiermedikamente -Tiere & Tierbedarf > Haustierbedarf > Transportboxen und -taschen für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Transportboxen und -taschen für Haustiere > Tragetaschen für Kleintiere -Tiere & Tierbedarf > Haustierbedarf > Transportboxen und -taschen für Haustiere > Transportboxen und -taschen für Hunde -Tiere & Tierbedarf > Haustierbedarf > Transportboxen und -taschen für Haustiere > Transportboxen und -taschen für Katzen -Tiere & Tierbedarf > Haustierbedarf > Treppen & Rampen für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Verlängerungsleinen -Tiere & Tierbedarf > Haustierbedarf > Vitamine & Nahrungsergänzungsmittel für Haustiere -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Snacks für Vögel -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Spielvorrichtungen für Vögel -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelfutter -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelkäfige & -ständer -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelkäfigzubehör -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelkäfigzubehör > Futter- und Wasserspender für Vogelkäfige -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelleitern & -sitzstangen -Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelspielzeug -Tiere & Tierbedarf > Lebende Tiere -Wirtschaft & Industrie -Wirtschaft & Industrie > Arbeitsschutzausrüstung -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Chemikalienschutzanzüge -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Feuerschutzkleidung -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Feuerwehr-Atemschutzmasken -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Gasmasken -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Halteseile -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Kugelsichere Westen -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzbrillen -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzhandschuhe -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzhelme -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Sicherheitsschürzen -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Signalkleidung -Wirtschaft & Industrie > Arbeitsschutzausrüstung > Staubmasken -Wirtschaft & Industrie > Aufbewahrungszubehör für industrielle Zwecke -Wirtschaft & Industrie > Baugewerbe -Wirtschaft & Industrie > Baugewerbe > Vermessung -Wirtschaft & Industrie > Bergbau & Steinbruch -Wirtschaft & Industrie > Beschilderung -Wirtschaft & Industrie > Beschilderung > Einzelhandelsschilder -Wirtschaft & Industrie > Beschilderung > Elektronische Schilder -Wirtschaft & Industrie > Beschilderung > Elektronische Schilder > LED-Schilder -Wirtschaft & Industrie > Beschilderung > Elektronische Schilder > Neonschilder -Wirtschaft & Industrie > Beschilderung > Geöffnet- und Geschlossen-Schilder -Wirtschaft & Industrie > Beschilderung > Hinweisschilder -Wirtschaft & Industrie > Beschilderung > Notfall- & Notausgangsschilder -Wirtschaft & Industrie > Beschilderung > Parkplatzschilder -Wirtschaft & Industrie > Beschilderung > Sicherheitsschilder -Wirtschaft & Industrie > Beschilderung > Tragbare Schilder -Wirtschaft & Industrie > Beschilderung > Verkehrsschilder -Wirtschaft & Industrie > Beschilderung > Warnschilder -Wirtschaft & Industrie > Beschilderung > Wegweiser -Wirtschaft & Industrie > Beschilderung > Öffnungszeiten-Schilder -Wirtschaft & Industrie > Einzelhandel -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldscheinprüfgeräte -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldtaschen -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldwechsler -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldzählmaschinen für Münzen und Scheine -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Münzrollenpapier & Geldscheinbanderolen -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Registrierkassen & Kassenzubehör -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Registrierkassen & Kassenzubehör > Kassenschubladen -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Registrierkassen & Kassenzubehör > Kreditkartenleser -Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Registrierkassen & Kassenzubehör > Unterschriftenpads -Wirtschaft & Industrie > Einzelhandel > Plastiktüten -Wirtschaft & Industrie > Einzelhandel > Preisauszeichnungsgeräte -Wirtschaft & Industrie > Einzelhandel > Präsentationsständer für Bekleidung -Wirtschaft & Industrie > Einzelhandel > Schaufensterpuppen -Wirtschaft & Industrie > Einzelhandel > Schaufensterpuppenteile -Wirtschaft & Industrie > Einzelhandel > Vitrinen -Wirtschaft & Industrie > Film & Fernsehen -Wirtschaft & Industrie > Finanzwesen & Versicherung -Wirtschaft & Industrie > Finanzwesen & Versicherung > Bullion -Wirtschaft & Industrie > Forst- & Holzwirtschaft -Wirtschaft & Industrie > Friseur- & Kosmetikgewerbe -Wirtschaft & Industrie > Friseur- & Kosmetikgewerbe > Pediküresessel -Wirtschaft & Industrie > Friseur- & Kosmetikgewerbe > Salonstühle -Wirtschaft & Industrie > Gewerbliche Lagerung -Wirtschaft & Industrie > Gewerbliche Lagerung > Frachtcontainer -Wirtschaft & Industrie > Gewerbliche Lagerung > Industrieregale -Wirtschaft & Industrie > Gewerbliche Lagerung > Industrieschränke -Wirtschaft & Industrie > Herstellung -Wirtschaft & Industrie > Hotels & Gaststätten -Wirtschaft & Industrie > Landwirtschaft -Wirtschaft & Industrie > Landwirtschaft > Viehhaltung -Wirtschaft & Industrie > Landwirtschaft > Viehhaltung > Hühnerställe -Wirtschaft & Industrie > Landwirtschaft > Viehhaltung > Viehfutterspender -Wirtschaft & Industrie > Materialbeförderung -Wirtschaft & Industrie > Materialbeförderung > Förderanlagen -Wirtschaft & Industrie > Materialbeförderung > Gabelstapler -Wirtschaft & Industrie > Medizinischer Bereich -Wirtschaft & Industrie > Medizinischer Bereich > Krankenhaus-Vorhänge -Wirtschaft & Industrie > Medizinischer Bereich > Krankenhausbekleidung -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Bettwäsche -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Automatisierte externe Defibrillatoren -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Medizinische Zangen -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Otoskope & Ophthalmoskope -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Patientenlifter -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Reflexhämmer -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Skalpelle -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Stethoskope -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Vitaldatenmonitore -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Zubehör für Vitaldatenmonitore -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Chiropraktische Tische -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Krankenhaus- und Pflegebetten -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medikamentenaufbewahrung -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medikamentenaufbewahrung > Betäubungsmittelschränke -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medizinische Wagen -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medizinische Wagen > Infusionsständer & -wagen -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medizinische Wagen > Reanimationswagen -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > OP-Tische -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Untersuchungsstühle -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Untersuchungsstühle > Gynäkologische Stühle -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Untersuchungsstühle > Optometrische Stühle -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Untersuchungsstühle > Zahnarztstühle -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Schulungsgeräte -Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Schulungsgeräte > HLW-Puppen -Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf -Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Einweghandschuhe -Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Fingerlinge -Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Medizinische Masken -Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Zungenspatel -Wirtschaft & Industrie > Medizinischer Bereich > OP-Bekleidung -Wirtschaft & Industrie > Medizinischer Bereich > OP-Hauben -Wirtschaft & Industrie > Medizinischer Bereich > OP-Kittel -Wirtschaft & Industrie > Nahrungsmittelservice -Wirtschaft & Industrie > Nahrungsmittelservice > Backwarenbehälter -Wirtschaft & Industrie > Nahrungsmittelservice > Einweg-Serviergeschirr -Wirtschaft & Industrie > Nahrungsmittelservice > Einweg-Serviergeschirr > Einwegtabletts -Wirtschaft & Industrie > Nahrungsmittelservice > Einwegbehälter -Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr -Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegbecher -Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegbesteck -Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegschüsseln -Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegteller -Wirtschaft & Industrie > Nahrungsmittelservice > Eisbehälter -Wirtschaft & Industrie > Nahrungsmittelservice > Gemüseschleudern -Wirtschaft & Industrie > Nahrungsmittelservice > Hot-Dog-Grills -Wirtschaft & Industrie > Nahrungsmittelservice > Kippbare Industrietöpfe -Wirtschaft & Industrie > Nahrungsmittelservice > Lebensmittelkörbe -Wirtschaft & Industrie > Nahrungsmittelservice > Servierwagen -Wirtschaft & Industrie > Nahrungsmittelservice > Spender für Einmalbesteck -Wirtschaft & Industrie > Nahrungsmittelservice > Spülwannen -Wirtschaft & Industrie > Nahrungsmittelservice > Takeaway-Behälter -Wirtschaft & Industrie > Nahrungsmittelservice > Teller- & Speisenwärmer -Wirtschaft & Industrie > Nahrungsmittelservice > Verkaufsautomaten -Wirtschaft & Industrie > Piercing & Tätowieren -Wirtschaft & Industrie > Piercing & Tätowieren > Piercingbedarf -Wirtschaft & Industrie > Piercing & Tätowieren > Piercingbedarf > Piercingnadeln -Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf -Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tattoo-Abdeckungen -Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tätowierfarben -Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tätowiermaschinen -Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tätowiernadeln -Wirtschaft & Industrie > Schwermaschinen -Wirtschaft & Industrie > Schwermaschinen > Häcksler -Wirtschaft & Industrie > Sicherheitssektor -Wirtschaft & Industrie > Sicherheitssektor > Metalldetektoren -Wirtschaft & Industrie > Sicherheitssektor > Schellen -Wirtschaft & Industrie > Sicherheitssektor > Schellen > Fußgelenkschellen -Wirtschaft & Industrie > Sicherheitssektor > Schellen > Fußschellen -Wirtschaft & Industrie > Sicherheitssektor > Schellen > Handschellen -Wirtschaft & Industrie > Sicherheitssektor > Schlagstöcke -Wirtschaft & Industrie > Werbung & Marketing -Wirtschaft & Industrie > Werbung & Marketing > Broschüren -Wirtschaft & Industrie > Werbung & Marketing > Messestand-Displays -Wirtschaft & Industrie > Werbung & Marketing > Messetheken -Wirtschaft & Industrie > Wissenschaft & Labor -Wirtschaft & Industrie > Wissenschaft & Labor > Biochemikalien -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Autoklaven -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Labor-Heizplatten -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Labormixer -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Laboröfen -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskope -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Ersatzlampen für Mikroskope -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Mikroskop-Objektivlinsen -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Mikroskopkameras -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Mikroskopokulare & Adapter -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Objektträger -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikrotome -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Spektrometer -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Spektrometer > Spektralfotometer -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Trockeneismaschinen -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Zentrifugen -Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Zubehör für Spektrometer -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Bechergläse -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Laborkolben -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Messzylinder -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Petrischalen -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Pipetten -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Reagenzglasständer -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Reagenzgläser -Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Spritzflaschen -Wirtschaft & Industrie > Wissenschaft & Labor > Laborchemikalien -Wirtschaft & Industrie > Wissenschaft & Labor > Sezierinstrumente -Wirtschaft & Industrie > Zahnmedizin -Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente -Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente > Zahnmedizinische Ausstattung -Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente > Zahnmedizinische Spiegel -Wirtschaft & Industrie > Zahnmedizin > Zahnzement diff --git a/src/Plugins/Feed.Froogle/Files/taxonomy.en-US.txt b/src/Plugins/Feed.Froogle/Files/taxonomy.en-US.txt deleted file mode 100644 index f7004f5fca..0000000000 --- a/src/Plugins/Feed.Froogle/Files/taxonomy.en-US.txt +++ /dev/null @@ -1,6217 +0,0 @@ - -Animals & Pet Supplies -Animals & Pet Supplies > Live Animals -Animals & Pet Supplies > Pet Supplies -Animals & Pet Supplies > Pet Supplies > Bird Supplies -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories > Bird Cage Food & Water Dishes -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cages & Stands -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Food -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Gyms & Playstands -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Ladders & Perches -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Toys -Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Treats -Animals & Pet Supplies > Pet Supplies > Cat Supplies -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Apparel -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Beds -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Furniture -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Box Mats -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Boxes -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Toys -Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Treats -Animals & Pet Supplies > Pet Supplies > Dog Supplies -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Apparel -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Beds -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Diaper Pads & Liners -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Houses -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennel & Run Accessories -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennels & Runs -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Toys -Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Treats -Animals & Pet Supplies > Pet Supplies > Fish Supplies -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Air Pumps -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Decor -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Decor > Artificial Aquarium Plants -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Filters -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Gravel & Substrates -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Heating -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Lighting -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Overflow Boxes -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Stands -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Water Pumps -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Water Treatments -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquariums -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquatic Plant Fertilizers -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Feeders -Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Food -Animals & Pet Supplies > Pet Supplies > Pet Agility Equipment -Animals & Pet Supplies > Pet Supplies > Pet Apparel Hangers -Animals & Pet Supplies > Pet Supplies > Pet Attractant -Animals & Pet Supplies > Pet Supplies > Pet Bells & Charms -Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors -Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Glucose Meters -Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Pedometers -Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Scales -Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Thermometers -Animals & Pet Supplies > Pet Supplies > Pet Bowl Mats -Animals & Pet Supplies > Pet Supplies > Pet Bowls, Feeders & Waterers -Animals & Pet Supplies > Pet Supplies > Pet Bowls, Feeders & Waterers > Cat Bowls, Feeders & Waterers -Animals & Pet Supplies > Pet Supplies > Pet Bowls, Feeders & Waterers > Dog Bowls, Feeders & Waterers -Animals & Pet Supplies > Pet Supplies > Pet Bowls, Feeders & Waterers > Small Animal Bowls, Feeders & Waterers -Animals & Pet Supplies > Pet Supplies > Pet Carriers & Crates -Animals & Pet Supplies > Pet Supplies > Pet Carriers & Crates > Cat Carriers & Crates -Animals & Pet Supplies > Pet Supplies > Pet Carriers & Crates > Dog Carriers & Crates -Animals & Pet Supplies > Pet Supplies > Pet Carriers & Crates > Small Animal Carriers -Animals & Pet Supplies > Pet Supplies > Pet Collars & Harnesses -Animals & Pet Supplies > Pet Supplies > Pet Collars & Harnesses > Cat Collars & Harnesses -Animals & Pet Supplies > Pet Supplies > Pet Collars & Harnesses > Dog Collars & Harnesses -Animals & Pet Supplies > Pet Supplies > Pet Containment Systems -Animals & Pet Supplies > Pet Supplies > Pet Eye Drops & Lubricants -Animals & Pet Supplies > Pet Supplies > Pet Flea & Tick Control -Animals & Pet Supplies > Pet Supplies > Pet Flea & Tick Control > Cat Flea & Tick Control -Animals & Pet Supplies > Pet Supplies > Pet Flea & Tick Control > Dog Flea & Tick Control -Animals & Pet Supplies > Pet Supplies > Pet Food Containers -Animals & Pet Supplies > Pet Supplies > Pet Food Scoops -Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies -Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Combs & Brushes -Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Hair Clippers & Trimmers -Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Polish -Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Tools -Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Shampoo & Conditioner -Animals & Pet Supplies > Pet Supplies > Pet ID Tags -Animals & Pet Supplies > Pet Supplies > Pet Leash Extensions -Animals & Pet Supplies > Pet Supplies > Pet Leashes -Animals & Pet Supplies > Pet Supplies > Pet Leashes > Cat Leashes -Animals & Pet Supplies > Pet Supplies > Pet Leashes > Dog Leashes -Animals & Pet Supplies > Pet Supplies > Pet Medical Collars -Animals & Pet Supplies > Pet Supplies > Pet Medical Tape & Bandages -Animals & Pet Supplies > Pet Supplies > Pet Medicine -Animals & Pet Supplies > Pet Supplies > Pet Muzzles -Animals & Pet Supplies > Pet Supplies > Pet Oral Care -Animals & Pet Supplies > Pet Supplies > Pet Oral Care > Pet Breath Spray -Animals & Pet Supplies > Pet Supplies > Pet Oral Care > Pet Toothbrushes -Animals & Pet Supplies > Pet Supplies > Pet Oral Care > Pet Toothpaste -Animals & Pet Supplies > Pet Supplies > Pet Playpens -Animals & Pet Supplies > Pet Supplies > Pet Steps & Ramps -Animals & Pet Supplies > Pet Supplies > Pet Strollers -Animals & Pet Supplies > Pet Supplies > Pet Sunscreen -Animals & Pet Supplies > Pet Supplies > Pet Training Pads -Animals & Pet Supplies > Pet Supplies > Pet Vitamins & Supplements -Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies -Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Food -Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Accessories -Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Heating & Lighting -Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitats -Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Substrates -Animals & Pet Supplies > Pet Supplies > Small Animal Supplies -Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Bedding -Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Food -Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitat Accessories -Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitats & Cages -Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Treats -Apparel & Accessories -Apparel & Accessories > Clothing -Apparel & Accessories > Clothing > Activewear -Apparel & Accessories > Clothing > Activewear > Active Dresses -Apparel & Accessories > Clothing > Activewear > Active Jackets -Apparel & Accessories > Clothing > Activewear > Active Jackets > Windbreakers -Apparel & Accessories > Clothing > Activewear > Active Leotards -Apparel & Accessories > Clothing > Activewear > Active Pants -Apparel & Accessories > Clothing > Activewear > Active Shirts -Apparel & Accessories > Clothing > Activewear > Active Shorts -Apparel & Accessories > Clothing > Activewear > Active Skirts -Apparel & Accessories > Clothing > Activewear > Active Tanks -Apparel & Accessories > Clothing > Activewear > Active Undergarments -Apparel & Accessories > Clothing > Activewear > Active Undergarments > Active Underwear -Apparel & Accessories > Clothing > Activewear > Active Undergarments > Compression Undergarment Shorts -Apparel & Accessories > Clothing > Activewear > Active Undergarments > Jock Straps -Apparel & Accessories > Clothing > Activewear > Active Undergarments > Sports Bras -Apparel & Accessories > Clothing > Activewear > Activewear Sets -Apparel & Accessories > Clothing > Activewear > Bicycle Activewear -Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Bibs -Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Jerseys -Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Shorts -Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Skinsuits -Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Tights -Apparel & Accessories > Clothing > Activewear > Boxing Shorts -Apparel & Accessories > Clothing > Activewear > Dancewear -Apparel & Accessories > Clothing > Activewear > Dancewear > Dance Dresses -Apparel & Accessories > Clothing > Activewear > Dancewear > Dance Pants -Apparel & Accessories > Clothing > Activewear > Dancewear > Dance Skirts -Apparel & Accessories > Clothing > Activewear > Dancewear > Dance Tights -Apparel & Accessories > Clothing > Activewear > Dancewear > Dance Tops -Apparel & Accessories > Clothing > Activewear > Football Pants -Apparel & Accessories > Clothing > Activewear > Hunting Clothing -Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Ghillie Suits -Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Tactical Pants -Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Tactical Vests -Apparel & Accessories > Clothing > Activewear > Long Johns -Apparel & Accessories > Clothing > Activewear > Martial Arts Shorts -Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing -Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Jackets -Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Pants -Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Suits -Apparel & Accessories > Clothing > Activewear > Paintball Clothing -Apparel & Accessories > Clothing > Activewear > Sauna Suits -Apparel & Accessories > Clothing > Activewear > Snow Pants & Suits -Apparel & Accessories > Clothing > Baby & Toddler Clothing -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Bottoms -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Diaper Covers -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Dresses -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outerwear -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outfits -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Socks & Tights -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Swimwear -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Tops -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby Onesies -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby Sleepwear & Swaddlers -Apparel & Accessories > Clothing > Baby & Toddler Clothing > Toddler Underwear -Apparel & Accessories > Clothing > Dresses -Apparel & Accessories > Clothing > Dresses > Cocktail Dresses -Apparel & Accessories > Clothing > Dresses > Day Dresses -Apparel & Accessories > Clothing > Dresses > Formal Gowns -Apparel & Accessories > Clothing > Dresses > Little Black Dresses -Apparel & Accessories > Clothing > One-Pieces -Apparel & Accessories > Clothing > One-Pieces > Jumpsuits & Rompers -Apparel & Accessories > Clothing > One-Pieces > Leotards & Unitards -Apparel & Accessories > Clothing > One-Pieces > Overalls -Apparel & Accessories > Clothing > Outerwear -Apparel & Accessories > Clothing > Outerwear > Chaps -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Anorak Jackets -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Blazers -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Boleros -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Capes & Ponchos -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Denim Jackets -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Down & Snow Jackets -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Fleece Jackets -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Fur Coats -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Leather & Suede Jackets -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Overcoats -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Trench Coats -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Tweed Jackets -Apparel & Accessories > Clothing > Outerwear > Coats & Jackets > Varsity Jackets -Apparel & Accessories > Clothing > Outerwear > Rain Gear -Apparel & Accessories > Clothing > Outerwear > Rain Gear > Rain Pants -Apparel & Accessories > Clothing > Outerwear > Rain Gear > Rain Suits -Apparel & Accessories > Clothing > Outerwear > Rain Gear > Raincoats -Apparel & Accessories > Clothing > Outerwear > Vests -Apparel & Accessories > Clothing > Outfit Sets -Apparel & Accessories > Clothing > Pants -Apparel & Accessories > Clothing > Pants > Cargo Pants -Apparel & Accessories > Clothing > Pants > Corduroy & Velvet Pants -Apparel & Accessories > Clothing > Pants > Dress Pants -Apparel & Accessories > Clothing > Pants > Jeans -Apparel & Accessories > Clothing > Pants > Khaki & Chino Pants -Apparel & Accessories > Clothing > Pants > Leather & Suede Pants -Apparel & Accessories > Clothing > Pants > Leggings -Apparel & Accessories > Clothing > Pants > Linen Pants -Apparel & Accessories > Clothing > Shirts & Tops -Apparel & Accessories > Clothing > Shirts & Tops > Camisoles & Tank Tops -Apparel & Accessories > Clothing > Shirts & Tops > Polo Shirts -Apparel & Accessories > Clothing > Shirts & Tops > Shirts & Blouses -Apparel & Accessories > Clothing > Shirts & Tops > Sports Fan Jerseys -Apparel & Accessories > Clothing > Shirts & Tops > Sweaters & Cardigans -Apparel & Accessories > Clothing > Shirts & Tops > Sweatshirts -Apparel & Accessories > Clothing > Shirts & Tops > T-Shirts -Apparel & Accessories > Clothing > Shorts -Apparel & Accessories > Clothing > Shorts > Bermuda Shorts -Apparel & Accessories > Clothing > Shorts > Cargo Shorts -Apparel & Accessories > Clothing > Shorts > Short Shorts -Apparel & Accessories > Clothing > Skirts -Apparel & Accessories > Clothing > Skorts -Apparel & Accessories > Clothing > Sleepwear & Loungewear -Apparel & Accessories > Clothing > Sleepwear & Loungewear > Loungewear -Apparel & Accessories > Clothing > Sleepwear & Loungewear > Nightgowns -Apparel & Accessories > Clothing > Sleepwear & Loungewear > Pajamas -Apparel & Accessories > Clothing > Sleepwear & Loungewear > Robes -Apparel & Accessories > Clothing > Suits -Apparel & Accessories > Clothing > Suits > Pant Suits -Apparel & Accessories > Clothing > Suits > Skirt Suits -Apparel & Accessories > Clothing > Suits > Suit Separates -Apparel & Accessories > Clothing > Suits > Tuxedos -Apparel & Accessories > Clothing > Swimwear -Apparel & Accessories > Clothing > Swimwear > Bikinis -Apparel & Accessories > Clothing > Swimwear > Cover-Ups -Apparel & Accessories > Clothing > Swimwear > One-Piece Swimsuits -Apparel & Accessories > Clothing > Swimwear > Swim Briefs -Apparel & Accessories > Clothing > Swimwear > Swim Shorts -Apparel & Accessories > Clothing > Swimwear > Swimsuit Bottoms -Apparel & Accessories > Clothing > Swimwear > Swimsuit Tops -Apparel & Accessories > Clothing > Swimwear > Tankinis & Extra Coverage Swimwear -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Dirndls -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Hakama Trousers -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimono Outerwear -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimono Outerwear > Haori Jackets -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimono Outerwear > Kimono Coats -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos > Bridal Kimonos -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos > Casual Kimonos -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos > Furisode Kimonos -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos > Iromuji Kimonos -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos > Komon Kimonos -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos > Tomesode & Houmongi Kimonos -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Religious Ceremonial Clothing -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Traditional Leather Pants -Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Yukata -Apparel & Accessories > Clothing > Underwear & Socks -Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories -Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Strap Pads -Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Straps & Extenders -Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Enhancing Inserts -Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Petals & Concealers -Apparel & Accessories > Clothing > Underwear & Socks > Bras -Apparel & Accessories > Clothing > Underwear & Socks > Bras > Nursing Bras -Apparel & Accessories > Clothing > Underwear & Socks > Bridal Intimates -Apparel & Accessories > Clothing > Underwear & Socks > Hosiery -Apparel & Accessories > Clothing > Underwear & Socks > Lingerie -Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories -Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garter Belts -Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garters -Apparel & Accessories > Clothing > Underwear & Socks > Petticoats & Pettipants -Apparel & Accessories > Clothing > Underwear & Socks > Shapewear -Apparel & Accessories > Clothing > Underwear & Socks > Socks -Apparel & Accessories > Clothing > Underwear & Socks > Undershirts -Apparel & Accessories > Clothing > Underwear & Socks > Underwear -Apparel & Accessories > Clothing > Underwear & Socks > Underwear Slips -Apparel & Accessories > Clothing > Uniforms -Apparel & Accessories > Clothing > Uniforms > Contractor Pants & Coveralls -Apparel & Accessories > Clothing > Uniforms > Flight Suits -Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms -Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Hats -Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Jackets -Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Pants -Apparel & Accessories > Clothing > Uniforms > Military Uniforms -Apparel & Accessories > Clothing > Uniforms > School Uniforms -Apparel & Accessories > Clothing > Uniforms > Security Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Baseball Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Basketball Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cheerleading Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cricket Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Football Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Hockey Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Martial Arts Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Officiating Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Soccer Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Softball Uniforms -Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Wrestling Uniforms -Apparel & Accessories > Clothing > Uniforms > White Coats -Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses -Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Bridal Party Dresses -Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Wedding Dresses -Apparel & Accessories > Clothing Accessories -Apparel & Accessories > Clothing Accessories > Arm & Leg Warmers -Apparel & Accessories > Clothing Accessories > Arm & Leg Warmers > Arm Warmers -Apparel & Accessories > Clothing Accessories > Arm & Leg Warmers > Leg Warmers -Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories -Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Belts -Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Gloves & Mittens -Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Hats -Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby Protective Wear -Apparel & Accessories > Clothing Accessories > Balaclavas -Apparel & Accessories > Clothing Accessories > Bandanas & Headties -Apparel & Accessories > Clothing Accessories > Belt Buckles -Apparel & Accessories > Clothing Accessories > Belts -Apparel & Accessories > Clothing Accessories > Bridal Accessories -Apparel & Accessories > Clothing Accessories > Bridal Accessories > Bridal Veils -Apparel & Accessories > Clothing Accessories > Button Studs -Apparel & Accessories > Clothing Accessories > Collar Stays -Apparel & Accessories > Clothing Accessories > Cufflinks -Apparel & Accessories > Clothing Accessories > Earmuffs -Apparel & Accessories > Clothing Accessories > Folding Fans -Apparel & Accessories > Clothing Accessories > Gloves & Mittens -Apparel & Accessories > Clothing Accessories > Gloves & Mittens > Formal Gloves -Apparel & Accessories > Clothing Accessories > Gloves & Mittens > Gloves -Apparel & Accessories > Clothing Accessories > Gloves & Mittens > Mittens -Apparel & Accessories > Clothing Accessories > Gloves & Mittens > Ski & Snowboard Gloves -Apparel & Accessories > Clothing Accessories > Hair Accessories -Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Claws -Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Combs -Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Extensions -Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Forks & Sticks -Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Nets -Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins & Clips -Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Wreaths -Apparel & Accessories > Clothing Accessories > Hair Accessories > Headbands -Apparel & Accessories > Clothing Accessories > Hair Accessories > Ponytail Holders -Apparel & Accessories > Clothing Accessories > Hair Accessories > Tiaras -Apparel & Accessories > Clothing Accessories > Hand Muffs -Apparel & Accessories > Clothing Accessories > Handkerchiefs -Apparel & Accessories > Clothing Accessories > Hats -Apparel & Accessories > Clothing Accessories > Hats > Beanies -Apparel & Accessories > Clothing Accessories > Hats > Berets -Apparel & Accessories > Clothing Accessories > Hats > Bowler & Derby Hats -Apparel & Accessories > Clothing Accessories > Hats > Caps -Apparel & Accessories > Clothing Accessories > Hats > Caps > Baseball Caps -Apparel & Accessories > Clothing Accessories > Hats > Caps > Newsboy Caps -Apparel & Accessories > Clothing Accessories > Hats > Cowboys Hats -Apparel & Accessories > Clothing Accessories > Hats > Fedoras -Apparel & Accessories > Clothing Accessories > Hats > Sun Hats -Apparel & Accessories > Clothing Accessories > Hats > Umbrella Hats -Apparel & Accessories > Clothing Accessories > Hats > Visors -Apparel & Accessories > Clothing Accessories > Headwear -Apparel & Accessories > Clothing Accessories > Headwear > Fascinators -Apparel & Accessories > Clothing Accessories > Headwear > Headdresses -Apparel & Accessories > Clothing Accessories > Headwear > Turbans -Apparel & Accessories > Clothing Accessories > Leis -Apparel & Accessories > Clothing Accessories > Neck Gaiters -Apparel & Accessories > Clothing Accessories > Neckties -Apparel & Accessories > Clothing Accessories > Neckties > Ascot Ties -Apparel & Accessories > Clothing Accessories > Neckties > Bolo Ties -Apparel & Accessories > Clothing Accessories > Neckties > Bow Ties -Apparel & Accessories > Clothing Accessories > Neckties > Ties -Apparel & Accessories > Clothing Accessories > Pinback Buttons -Apparel & Accessories > Clothing Accessories > Scarves & Shawls -Apparel & Accessories > Clothing Accessories > Sunglasses -Apparel & Accessories > Clothing Accessories > Suspenders -Apparel & Accessories > Clothing Accessories > Tie Clips -Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories -Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Kimono Underclothes -Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Obi Accessories -Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Obis -Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Tabi Socks -Apparel & Accessories > Clothing Accessories > Veils -Apparel & Accessories > Clothing Accessories > Wristbands -Apparel & Accessories > Costumes & Accessories -Apparel & Accessories > Costumes & Accessories > Costume Accessories -Apparel & Accessories > Costumes & Accessories > Costume Accessories > Bald Caps -Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Accessory Sets -Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Capes -Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Hats -Apparel & Accessories > Costumes & Accessories > Costume Accessories > Pretend Jewelry -Apparel & Accessories > Costumes & Accessories > Costume Shoes -Apparel & Accessories > Costumes & Accessories > Costumes -Apparel & Accessories > Costumes & Accessories > Masks -Apparel & Accessories > Costumes & Accessories > Wig Accessories -Apparel & Accessories > Costumes & Accessories > Wig Accessories > Wig Caps -Apparel & Accessories > Costumes & Accessories > Wig Accessories > Wig Glue -Apparel & Accessories > Costumes & Accessories > Wigs -Apparel & Accessories > Handbag & Wallet Accessories -Apparel & Accessories > Handbag & Wallet Accessories > Checkbook Covers -Apparel & Accessories > Handbag & Wallet Accessories > Keychains -Apparel & Accessories > Handbag & Wallet Accessories > Lanyards -Apparel & Accessories > Handbag & Wallet Accessories > Wallet Chains -Apparel & Accessories > Handbags, Wallets & Cases -Apparel & Accessories > Handbags, Wallets & Cases > Badge & Pass Holders -Apparel & Accessories > Handbags, Wallets & Cases > Business Card Cases -Apparel & Accessories > Handbags, Wallets & Cases > Handbags -Apparel & Accessories > Handbags, Wallets & Cases > Handbags > Clutches & Special Occasion Bags -Apparel & Accessories > Handbags, Wallets & Cases > Handbags > Cross-Body Handbags -Apparel & Accessories > Handbags, Wallets & Cases > Handbags > Hobo Handbags -Apparel & Accessories > Handbags, Wallets & Cases > Handbags > Satchels -Apparel & Accessories > Handbags, Wallets & Cases > Handbags > Shoulder Bags -Apparel & Accessories > Handbags, Wallets & Cases > Handbags > Tote Handbags -Apparel & Accessories > Handbags, Wallets & Cases > Handbags > Wristlets -Apparel & Accessories > Handbags, Wallets & Cases > Wallets & Money Clips -Apparel & Accessories > Jewelry -Apparel & Accessories > Jewelry > Anklets -Apparel & Accessories > Jewelry > Body Jewelry -Apparel & Accessories > Jewelry > Bracelets -Apparel & Accessories > Jewelry > Brooches & Lapel Pins -Apparel & Accessories > Jewelry > Charms & Pendants -Apparel & Accessories > Jewelry > Earrings -Apparel & Accessories > Jewelry > Jewelry Sets -Apparel & Accessories > Jewelry > Loose Stones -Apparel & Accessories > Jewelry > Loose Stones > Diamonds -Apparel & Accessories > Jewelry > Necklaces -Apparel & Accessories > Jewelry > Rings -Apparel & Accessories > Jewelry > Watch Accessories -Apparel & Accessories > Jewelry > Watch Accessories > Watch Bands -Apparel & Accessories > Jewelry > Watch Accessories > Watch Stickers & Decals -Apparel & Accessories > Jewelry > Watch Accessories > Watch Winders -Apparel & Accessories > Jewelry > Watches -Apparel & Accessories > Jewelry > Watches > Analog Watches -Apparel & Accessories > Jewelry > Watches > Digital Watches -Apparel & Accessories > Shoe Accessories -Apparel & Accessories > Shoe Accessories > Boot Liners -Apparel & Accessories > Shoe Accessories > Gaiters -Apparel & Accessories > Shoe Accessories > Shoe Covers -Apparel & Accessories > Shoe Accessories > Shoelaces -Apparel & Accessories > Shoe Accessories > Spurs -Apparel & Accessories > Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Ballet & Dance Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Basketball Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Bowling Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Boxing Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Cheerleading Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Cycling Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Golf Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Indoor Court Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Indoor Court Shoes > Badminton Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Indoor Court Shoes > Handball Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Indoor Court Shoes > Volleyball Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Indoor Soccer Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Skateboarding Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Table Tennis Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Tennis Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Weightlifting Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Athletic Shoes > Wrestling Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Cleats -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Cleats > Baseball & Softball Cleats -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Cleats > Football Cleats -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Cleats > Lacrosse Cleats -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Cleats > Rugby Boots -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Cleats > Soccer Cleats -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Cleats > Track Spikes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Sneakers -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Sneakers > Cross Training Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Sneakers > Fashion Sneakers -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Sneakers > Running Shoes -Apparel & Accessories > Shoes > Athletic Shoes & Sneakers > Sneakers > Walking Shoes -Apparel & Accessories > Shoes > Baby & Toddler Shoes -Apparel & Accessories > Shoes > Boots -Apparel & Accessories > Shoes > Boots > Cowboy Boots -Apparel & Accessories > Shoes > Boots > Desert & Chukka Boots -Apparel & Accessories > Shoes > Boots > Dress Boots -Apparel & Accessories > Shoes > Boots > Motorcycle Boots -Apparel & Accessories > Shoes > Boots > Rain Boots -Apparel & Accessories > Shoes > Boots > Riding Boots -Apparel & Accessories > Shoes > Boots > Shearling & Fur Trimmed Boots -Apparel & Accessories > Shoes > Boots > Snow Boots -Apparel & Accessories > Shoes > Boots > Work & Safety Boots -Apparel & Accessories > Shoes > Clogs & Mules -Apparel & Accessories > Shoes > Dress Shoes -Apparel & Accessories > Shoes > Dress Shoes > Formal Shoes -Apparel & Accessories > Shoes > Dress Shoes > Oxford Shoes -Apparel & Accessories > Shoes > Dress Shoes > Pumps -Apparel & Accessories > Shoes > Dress Shoes > Pumps > Basic Pumps -Apparel & Accessories > Shoes > Dress Shoes > Pumps > D'orsay & Two-Piece Pumps -Apparel & Accessories > Shoes > Dress Shoes > Pumps > Spectator Pumps -Apparel & Accessories > Shoes > Espadrilles -Apparel & Accessories > Shoes > Flats -Apparel & Accessories > Shoes > Loafers & Slip-Ons -Apparel & Accessories > Shoes > Moccasins -Apparel & Accessories > Shoes > Outdoor Shoes -Apparel & Accessories > Shoes > Outdoor Shoes > Climbing Shoes -Apparel & Accessories > Shoes > Outdoor Shoes > Fishing & Hunting Shoes -Apparel & Accessories > Shoes > Outdoor Shoes > Gardening Shoes -Apparel & Accessories > Shoes > Outdoor Shoes > Hiking Boots & Shoes -Apparel & Accessories > Shoes > Outdoor Shoes > Performance Boating Shoes -Apparel & Accessories > Shoes > Outdoor Shoes > Water Shoes -Apparel & Accessories > Shoes > Sandals -Apparel & Accessories > Shoes > Sandals > Fisherman Sandals -Apparel & Accessories > Shoes > Sandals > Slide Sandals -Apparel & Accessories > Shoes > Sandals > Thongs & Flip-Flops -Apparel & Accessories > Shoes > Slippers -Arts & Entertainment -Arts & Entertainment > Hobbies & Creative Arts -Arts & Entertainment > Hobbies & Creative Arts > Artwork -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Cardboard Cutouts -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Drawings & Illustrations -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Mixed Media Art -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Paintings -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Photographs -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Photographs > Stock Photographs -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Posters -Arts & Entertainment > Hobbies & Creative Arts > Artwork > Sculptures & Statues -Arts & Entertainment > Hobbies & Creative Arts > Collectibles -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Autographs -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Knives -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Swords -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Sword Stands & Displays -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Postage Stamps -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Rocks & Fossils -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Model Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Models -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Seal Stamps -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Auto Racing Autographed Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Baseball & Softball Autographed Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Basketball Autographed Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Football Autographed Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Hockey Autographed Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Soccer Autographed Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Tennis Autographed Sports Paraphernalia -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Auto Racing Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Baseball & Softball Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Basketball Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Football Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Hockey Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Soccer Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Tennis Fan Accessories -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards > Sports Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards > Sports Trading Cards > Auto Racing Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards > Sports Trading Cards > Baseball Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards > Sports Trading Cards > Basketball Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards > Sports Trading Cards > Football Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards > Sports Trading Cards > Hockey Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Trading Cards > Sports Trading Cards > Soccer Trading Cards -Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Vintage Advertisements -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Construction Paper -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Origami Paper -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Scratchboard Paper -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Sketch Pads -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Tracing Paper -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Transfer Paper -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Vellum -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Art Paper > Watercolor Paper -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Beading Patterns -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Candle & Soap Making -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Candle & Soap Making > Wick Tabs -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Candle & Soap Making > Wicks -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Canvas & Boards -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft & Hobby Storage -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft & Hobby Storage > Knitting Needle & Crochet Hook Cases -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft & Hobby Storage > Sewing Organizers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft & Hobby Storage > Yarn Organizers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft Blanks -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft Foam & Styrofoam -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft Magnets -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft Molds -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Craft Pipe Cleaners -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Decorative Stickers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Art Brushes -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Drafting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Drafting > Drafting Compasses -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Drawing & Painting Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Painting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Painting > Art Paint -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Painting > Paint Mediums -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Painting > Palette Knives -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Drawing & Painting > Painting > Palettes -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fabric Yo-Yos -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Crocheting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Crocheting > Crochet Hooks -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Crocheting > Crochet Thread -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Cross-Stitch & Embroidery -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Felting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Felting > Felting Molds -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Felting > Felting Needles -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Felting > Felting Pads & Mats -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Fibercraft Patterns -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Fibercraft Patterns > Cross-Stitch & Embroidery Patterns -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Fibercraft Patterns > Knitting & Crocheting Patterns -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Fibercraft Patterns > Sewing Patterns -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Hand Spinning -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Hand Spinning > Hand Spindles -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Hand Spinning > Spinning Wheel Accessories -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Hand Spinning > Spinning Wheels -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Knitting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Knitting > Knitting Needles -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Lace, Trims & Trimmings -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Needlepoint -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Needlepoint > Needlepoint Canvas -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Needlepoint > Needlepoint Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Quilting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Elastic -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Fabric -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Fabric Patches -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Hook & Loop Fasteners -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Interfacing -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Plastic Canvas -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Sewing Buttons -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Sewing Labels -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Sewing Snaps -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Stuffing & Filling Material -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Textile Dyes -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Textile Paints -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Thread -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Unspun Fiber -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Yarn -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Materials > Zippers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Blocking Mats -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Blocking Wires -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Bow & Pom-Pom Makers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Dressforms -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Adhesives -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Adhesives > Fabric Glue -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Adhesives > Fusible Fabric Tape -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Cutter Dies -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Cutters -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Marking Tools -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Repair Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fabric Scissors & Shears -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Fiber Cards -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Looms -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Needle Threaders -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Pin Cushions -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Safety Pins -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Seam Rippers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Sewing Needles -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Stitch Markers & Counters -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Straight Pins -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Textile Art Frames, Hoops & Stretchers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Textile Art Gauges & Rulers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Thimbles -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Thread & Yarn Cutters -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Thread & Yarn Guides -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Thread & Yarn Spools -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Thread & Yarn Winders -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Textile Art Tools & Accessories > Yo-Yo Makers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Weaving -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Weaving > Locker Hooks -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Weaving > Weaving Beaters -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Fibercraft & Textile Arts > Weaving > Weaving Shuttles -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Flower Arranging -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Flower Arranging > Floral Tape -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Flower Arranging > Vase Fillers & Table Scatters -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Glass Crafts -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Glitter -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Homebrewing -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Homebrewing > Beer Brewing -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Homebrewing > Wine Making -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Incense Making Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Jewelry Making -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Jewelry Making > Beads -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Jewelry Making > Jewelry & Beading Cord -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Jewelry Making > Jewelry & Beading Wire -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Jewelry Making > Jewelry Findings -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Juggling -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Leather Crafts -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Light Boxes -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Magic & Novelties -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Magnetic Tape -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Model Making -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Model Making > Model Rocketry -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Model Making > Model Train Accessories -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Model Making > Model Trains & Train Sets -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Model Making > Scale Model Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Mosaic Making -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Mosaic Making > Mosaic Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Card Making Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Embossing -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Embossing > Embossers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Embossing > Embossing Dies -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Embossing > Embossing Folders -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Embossing > Embossing Heat Tools -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Embossing > Embossing Pens -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Embossing > Embossing Powder -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Paper Crafts > Paper Creasers & Scorers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Pottery & Sculpting -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Pottery & Sculpting > Modeling Clay & Dough -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Printmaking -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Printmaking > Screen Printing -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Printmaking > Screen Printing > Brayer Rollers -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Printmaking > Screen Printing > Screen Printing Squeegees -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Rhinestones -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Scrapbooking -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Sequins -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Stamping -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Stamping > Leather Stamps & Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Stamping > Metal Stamps & Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Stenciling -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Stenciling > Stencil Machines -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Stenciling > Stencils & Dies -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Watch Repair Kits -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Woodworking -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Wreath Making -Arts & Entertainment > Hobbies & Creative Arts > Crafts & Hobbies > Wreath Making > Wreath Frames -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Brushes, Snakes & Cleaning Rods -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Care Kits -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Cleaners & Sanitizers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Guards -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Lubricants -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Polishing Cloths -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Brass Instrument Replacement Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Euphonium Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Euphonium Accessories > Euphonium Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Euphonium Accessories > Euphonium Mouthpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Euphonium Accessories > Euphonium Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Euphonium Accessories > Euphonium Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > French Horn Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > French Horn Accessories > French Horn Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > French Horn Accessories > French Horn Mouthpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > French Horn Accessories > French Horn Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > French Horn Accessories > French Horn Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trombone Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trombone Accessories > Trombone Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trombone Accessories > Trombone Lyres -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trombone Accessories > Trombone Mouthpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trombone Accessories > Trombone Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trombone Accessories > Trombone Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trumpet & Cornet Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trumpet & Cornet Accessories > Trumpet & Cornet Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trumpet & Cornet Accessories > Trumpet & Cornet Lyres -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trumpet & Cornet Accessories > Trumpet & Cornet Mouthpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trumpet & Cornet Accessories > Trumpet & Cornet Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Trumpet & Cornet Accessories > Trumpet & Cornet Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Tuba Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Tuba Accessories > Tuba Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Tuba Accessories > Tuba Mouthpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Tuba Accessories > Tuba Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Brass Instrument Accessories > Tuba Accessories > Tuba Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Electronic Tuners -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Music Stand Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Music Stand Accessories > Music Stand Bags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Music Stand Accessories > Music Stand Lights -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Music Stand Accessories > Sheet Music Clips -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Music Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Musical Instrument Amplifier Cabinets -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Musical Instrument Amplifier Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Musical Instrument Amplifiers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Musical Keyboard Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Musical Keyboard Accessories > Musical Keyboard Bags & Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Musical Keyboard Accessories > Musical Keyboard Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Musical Keyboard Accessories > Sustain Pedals -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Cymbal & Drum Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Cymbal & Drum Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Heads -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Keys -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Kit Hardware -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Kit Hardware > Bass Drum Beaters -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Kit Hardware > Drum Kit Mounting Hardware -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Kit Hardware > Drum Pedals -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Stick Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Stick Accessories > Drum Stick Bags & Holders -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drum Sticks -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Drumming Thrones -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Electronic Drum Modules -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Hand Percussion Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Bags & Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Stands & Mounts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Percussion Mallets -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Percussion Accessories > Percussion Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Piano Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Piano Accessories > Piano Benches -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Cello Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Cello Accessories > Cello Bows -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Cello Accessories > Cello Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Cello Accessories > Cello Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Cello Accessories > Cello Strings -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Acoustic Guitar Pickups -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Capos -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Electric Guitar Pickups -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Bridge Pins -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Cases & Gig Bags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Humidifiers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Picks -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Slides -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Strings -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Guitar Accessories > Guitar Tuning Machines -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Harp Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Harp Accessories > Harp Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Harp Accessories > Harp Strings -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > String Instrument Care & Cleaning -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > String Instrument Care & Cleaning > Bow Rosin -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Cleaning Cloths -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Polish -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Upright Bass Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Upright Bass Accessories > Upright Bass Bows -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Upright Bass Accessories > Upright Bass Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Upright Bass Accessories > Upright Bass Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Upright Bass Accessories > Upright Bass Strings -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Viola Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Viola Accessories > Viola Bows -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Viola Accessories > Viola Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Viola Accessories > Viola Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Viola Accessories > Viola Strings -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin & Viola Chinrests -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin & Viola Shoulder Rests -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Bows -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Bridges -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Mutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Pickups -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Strings -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Tailpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > String Instrument Accessories > Violin Accessories > Violin Tuning Pegs -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning > Bassoon Swabs -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Bocals -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Small Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Reeds -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Straps & Supports -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Care Kits -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Pad Savers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Swabs -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Ligatures & Caps -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Lyres -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Barrels -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Bells -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Mouthpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Small Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Pegs & Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Reeds -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Straps & Supports -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Care Kits -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Cleaning Rods -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Swabs -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Lyres -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Headjoints -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Small Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Pegs & Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Harmonica Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Holders -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Care Kits -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Swabs -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts > Oboe Small Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Pegs & Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Reeds -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Straps & Supports -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Care Kits -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Pad Savers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Swabs -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Cases & Gigbags -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Ligatures & Caps -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Lyres -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Mouthpieces -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Necks -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Small Parts -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Pegs & Stands -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Reeds -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Straps & Supports -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Woodwind Cork Grease -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Woodwind Polishing Cloths -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Woodwind Reed Cases -Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument Accessories > Woodwind Instrument Accessories > Woodwind Reed Knives -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Accordions & Concertinas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Bagpipes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Cornets -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Euphoniums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Flugel Horns -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > French Horns -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Mellophones -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Sousaphones -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Trombones -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Trumpets -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass > Tubas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Audio Samplers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > MIDI Controllers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Musical Keyboards -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Sound Synthesizers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Bass Drums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Cymbals -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Drum Kits -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Electronic Drums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Glockenspiels & Xylophones -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Gongs -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Claves & Castanets -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Finger & Hand Cymbals -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Bells -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Bells & Chimes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Bongos -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Cajons -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Congas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Frame Drums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Goblet Drums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Tablas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Talking Drums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Blocks -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Cowbells -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Scrapers & Ratchets -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Shakers -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Triangles -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Tambourines -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Vibraslaps -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hi-Hats -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Practice Pads -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Snare Drums -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Tom-Toms -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Pianos -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Cellos -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Guitars -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Guitars > Acoustic Guitars -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Guitars > Bass Guitars -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Guitars > Electric Guitars -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Harps -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Upright Basses -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violins -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Bassoons -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Clarinets -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutes > Fifes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutophones -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Harmonicas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Jew's Harps -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Melodicas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Musical Pipes -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Oboes & English Horns -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Ocarinas -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Recorders -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Saxophones -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Tin Whistles -Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Train Whistles -Arts & Entertainment > Party & Celebration -Arts & Entertainment > Party & Celebration > Gift Giving -Arts & Entertainment > Party & Celebration > Gift Giving > Corsage & Boutonnière Pins -Arts & Entertainment > Party & Celebration > Gift Giving > Corsages & Boutonnières -Arts & Entertainment > Party & Celebration > Gift Giving > Fresh Cut Flowers -Arts & Entertainment > Party & Celebration > Gift Giving > Gift Cards & Certificates -Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping -Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Bows & Ribbons -Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Bags -Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Boxes & Tins -Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Tissue Paper -Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Wrapping Paper -Arts & Entertainment > Party & Celebration > Gift Giving > Greeting & Note Cards -Arts & Entertainment > Party & Celebration > Party Supplies -Arts & Entertainment > Party & Celebration > Party Supplies > Balloon Kits -Arts & Entertainment > Party & Celebration > Party Supplies > Balloons -Arts & Entertainment > Party & Celebration > Party Supplies > Banners -Arts & Entertainment > Party & Celebration > Party Supplies > Beverage Tubs -Arts & Entertainment > Party & Celebration > Party Supplies > Birthday Candles -Arts & Entertainment > Party & Celebration > Party Supplies > Cocktail Decorations -Arts & Entertainment > Party & Celebration > Party Supplies > Confetti -Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games -Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong -Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong > Beer Pong Tables -Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Straws & Stirrers -Arts & Entertainment > Party & Celebration > Party Supplies > Envelope Seals -Arts & Entertainment > Party & Celebration > Party Supplies > Event Programs -Arts & Entertainment > Party & Celebration > Party Supplies > Invitations -Arts & Entertainment > Party & Celebration > Party Supplies > Invitations > Birthday Invitations -Arts & Entertainment > Party & Celebration > Party Supplies > Invitations > Wedding Invitations -Arts & Entertainment > Party & Celebration > Party Supplies > Noisemakers & Party Blowers -Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors -Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors > Wedding Favors -Arts & Entertainment > Party & Celebration > Party Supplies > Party Games -Arts & Entertainment > Party & Celebration > Party Supplies > Party Hats -Arts & Entertainment > Party & Celebration > Party Supplies > Piñatas -Arts & Entertainment > Party & Celebration > Party Supplies > Place Card Holders -Arts & Entertainment > Party & Celebration > Party Supplies > Place Cards -Arts & Entertainment > Party & Celebration > Party Supplies > Response Cards -Arts & Entertainment > Party & Celebration > Party Supplies > Response Cards > Wedding Response Cards -Arts & Entertainment > Party & Celebration > Party Supplies > Sparklers -Arts & Entertainment > Party & Celebration > Party Supplies > Spray String -Arts & Entertainment > Party & Celebration > Party Supplies > Streamers -Arts & Entertainment > Party & Celebration > Party Supplies > Wedding Card Boxes & Holders -Arts & Entertainment > Party & Celebration > Special Effects -Arts & Entertainment > Party & Celebration > Special Effects > Disco Balls -Arts & Entertainment > Party & Celebration > Special Effects > Fog Machines -Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Controllers -Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Lighting -Arts & Entertainment > Party & Celebration > Trophies & Awards -Baby & Toddler -Baby & Toddler > Baby & Toddler Gift Sets -Baby & Toddler > Baby Bathing -Baby & Toddler > Baby Bathing > Baby Bathtubs & Bath Seats -Baby & Toddler > Baby Bathing > Shower Visors -Baby & Toddler > Baby Health -Baby & Toddler > Baby Health > Baby Health & Grooming Kits -Baby & Toddler > Baby Health > Nasal Aspirators -Baby & Toddler > Baby Health > Pacifier Clips & Holders -Baby & Toddler > Baby Health > Pacifier Wipes -Baby & Toddler > Baby Health > Pacifiers & Teethers -Baby & Toddler > Baby Safety -Baby & Toddler > Baby Safety > Baby & Pet Gate Accessories -Baby & Toddler > Baby Safety > Baby & Pet Gates -Baby & Toddler > Baby Safety > Baby Monitors -Baby & Toddler > Baby Safety > Baby Safety Harnesses & Leashes -Baby & Toddler > Baby Safety > Baby Safety Locks & Guards -Baby & Toddler > Baby Safety > Baby Safety Rails -Baby & Toddler > Baby Toys -Baby & Toddler > Baby Toys > Alphabet Toys -Baby & Toddler > Baby Toys > Baby Activity Toys -Baby & Toddler > Baby Toys > Baby Bouncers & Rockers -Baby & Toddler > Baby Toys > Baby Jumpers & Swings -Baby & Toddler > Baby Toys > Baby Mobile Accessories -Baby & Toddler > Baby Toys > Baby Mobiles -Baby & Toddler > Baby Toys > Baby Soothers -Baby & Toddler > Baby Toys > Baby Walkers & Entertainers -Baby & Toddler > Baby Toys > Play Mats & Gyms -Baby & Toddler > Baby Toys > Play Yards -Baby & Toddler > Baby Toys > Push & Pull Toys -Baby & Toddler > Baby Toys > Rattles -Baby & Toddler > Baby Toys > Sorting & Stacking Toys -Baby & Toddler > Baby Transport -Baby & Toddler > Baby Transport > Baby & Toddler Car Seats -Baby & Toddler > Baby Transport > Baby Carriers -Baby & Toddler > Baby Transport > Baby Strollers -Baby & Toddler > Baby Transport Accessories -Baby & Toddler > Baby Transport Accessories > Baby & Toddler Car Seat Accessories -Baby & Toddler > Baby Transport Accessories > Baby Carrier Accessories -Baby & Toddler > Baby Transport Accessories > Baby Stroller Accessories -Baby & Toddler > Baby Transport Accessories > Shopping Cart & High Chair Covers -Baby & Toddler > Diapering -Baby & Toddler > Diapering > Baby Wipe Dispensers & Warmers -Baby & Toddler > Diapering > Baby Wipes -Baby & Toddler > Diapering > Changing Mats & Trays -Baby & Toddler > Diapering > Diaper Kits -Baby & Toddler > Diapering > Diaper Liners -Baby & Toddler > Diapering > Diaper Organizers -Baby & Toddler > Diapering > Diaper Pail Accessories -Baby & Toddler > Diapering > Diaper Pails -Baby & Toddler > Diapering > Diaper Rash Treatments -Baby & Toddler > Diapering > Diaper Wet Bags -Baby & Toddler > Diapering > Diapers -Baby & Toddler > Nursing & Feeding -Baby & Toddler > Nursing & Feeding > Baby & Toddler Food -Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Cereal -Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Food -Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Formula -Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Juice -Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Snacks -Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples -Baby & Toddler > Nursing & Feeding > Baby Bottles -Baby & Toddler > Nursing & Feeding > Baby Care Timers -Baby & Toddler > Nursing & Feeding > Bibs -Baby & Toddler > Nursing & Feeding > Bottle Warmers & Sterilizers -Baby & Toddler > Nursing & Feeding > Breast Milk Storage Containers -Baby & Toddler > Nursing & Feeding > Breast Pumps -Baby & Toddler > Nursing & Feeding > Burp Cloths -Baby & Toddler > Nursing & Feeding > Nipple Shields -Baby & Toddler > Nursing & Feeding > Nursing Covers -Baby & Toddler > Nursing & Feeding > Nursing Pads -Baby & Toddler > Nursing & Feeding > Nursing Pillows -Baby & Toddler > Nursing & Feeding > Sippy Cups -Baby & Toddler > Potty Training -Baby & Toddler > Potty Training > Potty Seats -Baby & Toddler > Potty Training > Potty Training Kits -Baby & Toddler > Swaddling Blankets -Business & Industrial -Business & Industrial > Advertising & Marketing -Business & Industrial > Advertising & Marketing > Brochures -Business & Industrial > Advertising & Marketing > Trade Show Counters -Business & Industrial > Advertising & Marketing > Trade Show Displays -Business & Industrial > Agriculture -Business & Industrial > Agriculture > Animal Husbandry -Business & Industrial > Agriculture > Animal Husbandry > Chicken Coops -Business & Industrial > Agriculture > Animal Husbandry > Livestock Feeders -Business & Industrial > Construction -Business & Industrial > Construction > Surveying -Business & Industrial > Dentistry -Business & Industrial > Dentistry > Dental Cement -Business & Industrial > Dentistry > Dental Tools -Business & Industrial > Dentistry > Dental Tools > Dental Mirrors -Business & Industrial > Dentistry > Dental Tools > Dental Tool Sets -Business & Industrial > Film & Television -Business & Industrial > Finance & Insurance -Business & Industrial > Finance & Insurance > Bullion -Business & Industrial > Food Service -Business & Industrial > Food Service > Bakery Boxes -Business & Industrial > Food Service > Bus Tubs -Business & Industrial > Food Service > Concession Food Containers -Business & Industrial > Food Service > Disposable Cutlery Dispensers -Business & Industrial > Food Service > Disposable Serveware -Business & Industrial > Food Service > Disposable Serveware > Disposable Serving Trays -Business & Industrial > Food Service > Disposable Tableware -Business & Industrial > Food Service > Disposable Tableware > Disposable Bowls -Business & Industrial > Food Service > Disposable Tableware > Disposable Cups -Business & Industrial > Food Service > Disposable Tableware > Disposable Cutlery -Business & Industrial > Food Service > Disposable Tableware > Disposable Plates -Business & Industrial > Food Service > Food Service Baskets -Business & Industrial > Food Service > Food Service Carts -Business & Industrial > Food Service > Food Washers & Dryers -Business & Industrial > Food Service > Hot Dog Rollers -Business & Industrial > Food Service > Ice Bins -Business & Industrial > Food Service > Plate & Dish Warmers -Business & Industrial > Food Service > Take-Out Containers -Business & Industrial > Food Service > Tilt Skillets -Business & Industrial > Food Service > Vending Machines -Business & Industrial > Forestry & Logging -Business & Industrial > Hairdressing & Cosmetology -Business & Industrial > Hairdressing & Cosmetology > Pedicure Chairs -Business & Industrial > Hairdressing & Cosmetology > Salon Chairs -Business & Industrial > Heavy Machinery -Business & Industrial > Heavy Machinery > Chippers -Business & Industrial > Hotel & Hospitality -Business & Industrial > Industrial Storage -Business & Industrial > Industrial Storage > Industrial Cabinets -Business & Industrial > Industrial Storage > Industrial Shelving -Business & Industrial > Industrial Storage > Shipping Containers -Business & Industrial > Industrial Storage Accessories -Business & Industrial > Law Enforcement -Business & Industrial > Law Enforcement > Batons -Business & Industrial > Law Enforcement > Cuffs -Business & Industrial > Law Enforcement > Cuffs > Ankle Cuffs -Business & Industrial > Law Enforcement > Cuffs > Handcuffs -Business & Industrial > Law Enforcement > Cuffs > Leg Cuffs -Business & Industrial > Law Enforcement > Metal Detectors -Business & Industrial > Manufacturing -Business & Industrial > Material Handling -Business & Industrial > Material Handling > Conveyors -Business & Industrial > Material Handling > Fork Lifts -Business & Industrial > Medical -Business & Industrial > Medical > Hospital Curtains -Business & Industrial > Medical > Hospital Gowns -Business & Industrial > Medical > Medical Bedding -Business & Industrial > Medical > Medical Equipment -Business & Industrial > Medical > Medical Equipment > Automated External Defibrillators -Business & Industrial > Medical > Medical Equipment > Medical Forceps -Business & Industrial > Medical > Medical Equipment > Otoscopes & Ophthalmoscopes -Business & Industrial > Medical > Medical Equipment > Patient Lifts -Business & Industrial > Medical > Medical Equipment > Reflex Hammers -Business & Industrial > Medical > Medical Equipment > Scalpels -Business & Industrial > Medical > Medical Equipment > Stethoscopes -Business & Industrial > Medical > Medical Equipment > Vital Signs Monitor Accessories -Business & Industrial > Medical > Medical Equipment > Vital Signs Monitors -Business & Industrial > Medical > Medical Furniture -Business & Industrial > Medical > Medical Furniture > Chiropractic Tables -Business & Industrial > Medical > Medical Furniture > Examination Chairs -Business & Industrial > Medical > Medical Furniture > Examination Chairs > Dental Chairs -Business & Industrial > Medical > Medical Furniture > Examination Chairs > Gynecological Chairs -Business & Industrial > Medical > Medical Furniture > Examination Chairs > Optometry Chairs -Business & Industrial > Medical > Medical Furniture > Homecare & Hospital Beds -Business & Industrial > Medical > Medical Furniture > Medical Cabinets -Business & Industrial > Medical > Medical Furniture > Medical Cabinets > Narcotics Boxes -Business & Industrial > Medical > Medical Furniture > Medical Carts -Business & Industrial > Medical > Medical Furniture > Medical Carts > Crash Carts -Business & Industrial > Medical > Medical Furniture > Medical Carts > IV Poles & Carts -Business & Industrial > Medical > Medical Furniture > Surgical Tables -Business & Industrial > Medical > Medical Supplies -Business & Industrial > Medical > Medical Supplies > Disposable Gloves -Business & Industrial > Medical > Medical Supplies > Finger Cots -Business & Industrial > Medical > Medical Supplies > Medical Masks -Business & Industrial > Medical > Medical Supplies > Tongue Depressors -Business & Industrial > Medical > Medical Teaching Equipment -Business & Industrial > Medical > Medical Teaching Equipment > CPR Mannequins -Business & Industrial > Medical > Scrub Caps -Business & Industrial > Medical > Scrubs -Business & Industrial > Medical > Surgical Gowns -Business & Industrial > Mining & Quarrying -Business & Industrial > Piercing & Tattooing -Business & Industrial > Piercing & Tattooing > Piercing Supplies -Business & Industrial > Piercing & Tattooing > Piercing Supplies > Piercing Needles -Business & Industrial > Piercing & Tattooing > Tattooing Supplies -Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattoo Cover-Ups -Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Inks -Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Machines -Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Needles -Business & Industrial > Retail -Business & Industrial > Retail > Clothing Display Racks -Business & Industrial > Retail > Mannequin Parts -Business & Industrial > Retail > Mannequins -Business & Industrial > Retail > Money Handling -Business & Industrial > Retail > Money Handling > Banknote Verifiers -Business & Industrial > Retail > Money Handling > Cash Registers & POS Equipment -Business & Industrial > Retail > Money Handling > Cash Registers & POS Equipment > Cash Drawers -Business & Industrial > Retail > Money Handling > Cash Registers & POS Equipment > Credit Card Readers -Business & Industrial > Retail > Money Handling > Cash Registers & POS Equipment > Signature Capture Pads -Business & Industrial > Retail > Money Handling > Coin & Bill Counters -Business & Industrial > Retail > Money Handling > Money Changers -Business & Industrial > Retail > Money Handling > Money Deposit Bags -Business & Industrial > Retail > Money Handling > Paper Coin Wrappers & Bill Straps -Business & Industrial > Retail > Plastic Bags -Business & Industrial > Retail > Pricing Guns -Business & Industrial > Retail > Retail Display Cases -Business & Industrial > Science & Laboratory -Business & Industrial > Science & Laboratory > Biochemicals -Business & Industrial > Science & Laboratory > Dissection Kits -Business & Industrial > Science & Laboratory > Laboratory Chemicals -Business & Industrial > Science & Laboratory > Laboratory Equipment -Business & Industrial > Science & Laboratory > Laboratory Equipment > Autoclaves -Business & Industrial > Science & Laboratory > Laboratory Equipment > Centrifuges -Business & Industrial > Science & Laboratory > Laboratory Equipment > Dry Ice Makers -Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Blenders -Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Hot Plates -Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Ovens -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Cameras -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Eyepieces & Adapters -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Objective Lenses -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Replacement Bulbs -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Slides -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscopes -Business & Industrial > Science & Laboratory > Laboratory Equipment > Microtomes -Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometer Accessories -Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometers -Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometers > Spectrophotometers -Business & Industrial > Science & Laboratory > Laboratory Supplies -Business & Industrial > Science & Laboratory > Laboratory Supplies > Beakers -Business & Industrial > Science & Laboratory > Laboratory Supplies > Graduated Cylinders -Business & Industrial > Science & Laboratory > Laboratory Supplies > Laboratory Flasks -Business & Industrial > Science & Laboratory > Laboratory Supplies > Petri Dishes -Business & Industrial > Science & Laboratory > Laboratory Supplies > Pipettes -Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tube Racks -Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tubes -Business & Industrial > Science & Laboratory > Laboratory Supplies > Wash Bottles -Business & Industrial > Signage -Business & Industrial > Signage > Business Hour Signs -Business & Industrial > Signage > Electronic Signs -Business & Industrial > Signage > Electronic Signs > LED Signs -Business & Industrial > Signage > Electronic Signs > Neon Signs -Business & Industrial > Signage > Emergency & Exit Signs -Business & Industrial > Signage > Facility Identification Signs -Business & Industrial > Signage > Open & Closed Signs -Business & Industrial > Signage > Parking Signs & Permits -Business & Industrial > Signage > Policy Signs -Business & Industrial > Signage > Retail & Sale Signs -Business & Industrial > Signage > Road & Traffic Signs -Business & Industrial > Signage > Safety & Warning Signs -Business & Industrial > Signage > Security Signs -Business & Industrial > Signage > Sidewalk & Yard Signs -Business & Industrial > Work Safety Protective Gear -Business & Industrial > Work Safety Protective Gear > Bullet Proof Vests -Business & Industrial > Work Safety Protective Gear > Dust Masks -Business & Industrial > Work Safety Protective Gear > Fire Repellent Clothing -Business & Industrial > Work Safety Protective Gear > Fireman's Masks -Business & Industrial > Work Safety Protective Gear > Gas Masks & Respirators -Business & Industrial > Work Safety Protective Gear > Hardhats -Business & Industrial > Work Safety Protective Gear > Hazardous Material Suits -Business & Industrial > Work Safety Protective Gear > High-Visibility Clothing -Business & Industrial > Work Safety Protective Gear > Protective Aprons -Business & Industrial > Work Safety Protective Gear > Protective Eyewear -Business & Industrial > Work Safety Protective Gear > Safety Gloves -Business & Industrial > Work Safety Protective Gear > Safety Tethers -Cameras & Optics -Cameras & Optics > Camera & Optic Accessories -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories > Lens & Filter Adapters -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories > Lens Bags -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories > Lens Caps -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories > Lens Converters -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories > Lens Filters -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories > Lens Filters > Close-Up Filters -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lens Accessories > Lens Hoods -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lenses -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lenses > Camera Lenses -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lenses > Surveillance Camera Lenses -Cameras & Optics > Camera & Optic Accessories > Camera & Optic Lenses > Video Camera Lenses -Cameras & Optics > Camera & Optic Accessories > Camera Accessories -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Bags -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Bags > Still Camera Bags -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Bags > Video Camera Bags -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Film -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Flash Accessories -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Flashes -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Handles -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Mounts -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Remote Controls -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Camera Straps -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Flash Brackets -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Surveillance Camera Accessories -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Underwater Camera Housings -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Underwater Camera Housings > Underwater Still Camera Housings -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Underwater Camera Housings > Underwater Video Camera Housings -Cameras & Optics > Camera & Optic Accessories > Camera Accessories > Video Camera Lights -Cameras & Optics > Camera & Optic Accessories > Optic Accessories -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Binocular & Monocular Accessories -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Night Vision Optic Accessories -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Optics Bags & Cases -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Rangefinder Accessories -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Spotting Scope Accessories -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Spotting Scope Accessories > Scope Eyepieces -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Telescope Accessories -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Thermal Optic Accessories -Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Weapon Scope Accessories -Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories -Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Cases -Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Heads -Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Collars & Mounts -Cameras & Optics > Camera & Optic Accessories > Tripods & Monopods -Cameras & Optics > Cameras -Cameras & Optics > Cameras > Digital Cameras -Cameras & Optics > Cameras > Digital Cameras > Digital Point & Shoot Cameras -Cameras & Optics > Cameras > Digital Cameras > Digital SLRs -Cameras & Optics > Cameras > Digital Cameras > Mirrorless System Digital Cameras -Cameras & Optics > Cameras > Disposable Cameras -Cameras & Optics > Cameras > Film Cameras -Cameras & Optics > Cameras > Film Cameras > Instant Cameras -Cameras & Optics > Cameras > Surveillance Cameras -Cameras & Optics > Cameras > Surveillance Cameras > Hidden Cameras -Cameras & Optics > Cameras > Trail Cameras -Cameras & Optics > Cameras > Video Cameras -Cameras & Optics > Cameras > Webcams -Cameras & Optics > Optics -Cameras & Optics > Optics > Binoculars -Cameras & Optics > Optics > Binoculars > Opera Glasses -Cameras & Optics > Optics > Monoculars -Cameras & Optics > Optics > Rangefinders -Cameras & Optics > Optics > Scopes -Cameras & Optics > Optics > Scopes > Spotting Scopes -Cameras & Optics > Optics > Scopes > Telescopes -Cameras & Optics > Optics > Scopes > Weapon Scopes & Sights -Cameras & Optics > Photography -Cameras & Optics > Photography > Darkroom -Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment -Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Copystands -Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Darkroom Sinks -Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Developing Tanks & Reels -Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Print Trays, Washers & Dryers -Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Retouching Equipment & Supplies -Cameras & Optics > Photography > Darkroom > Enlarging Equipment -Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Easels -Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Timers -Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Focusing Aids -Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Analyzers -Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Enlargers -Cameras & Optics > Photography > Darkroom > Photographic Chemicals -Cameras & Optics > Photography > Darkroom > Photographic Chemicals > Photographic Color Kits -Cameras & Optics > Photography > Darkroom > Photographic Chemicals > Photographic Developer -Cameras & Optics > Photography > Darkroom > Photographic Chemicals > Photographic Fixers -Cameras & Optics > Photography > Darkroom > Photographic Chemicals > Photographic Toners -Cameras & Optics > Photography > Darkroom > Photographic Chemicals > Stop Baths -Cameras & Optics > Photography > Darkroom > Photographic Paper -Cameras & Optics > Photography > Darkroom > Safelights -Cameras & Optics > Photography > Lighting & Studio -Cameras & Optics > Photography > Lighting & Studio > Backgrounds -Cameras & Optics > Photography > Lighting & Studio > Flash Diffusers -Cameras & Optics > Photography > Lighting & Studio > Flash Diffusers > Camera Flash Diffusers -Cameras & Optics > Photography > Lighting & Studio > Flash Reflectors -Cameras & Optics > Photography > Lighting & Studio > Light Controls -Cameras & Optics > Photography > Lighting & Studio > Light Meter Accessories -Cameras & Optics > Photography > Lighting & Studio > Light Meters -Cameras & Optics > Photography > Lighting & Studio > Lighting Filters & Gels -Cameras & Optics > Photography > Lighting & Studio > Softboxes -Cameras & Optics > Photography > Lighting & Studio > Studio Lights & Flashes -Cameras & Optics > Photography > Lighting & Studio > Studio Mountings -Cameras & Optics > Photography > Photo Negative & Slide Storage -Electronics -Electronics > 3D Printers -Electronics > Arcade Equipment -Electronics > Arcade Equipment > Pinball Machine Accessories -Electronics > Arcade Equipment > Pinball Machines -Electronics > Arcade Equipment > Skee-Ball Machines -Electronics > Arcade Equipment > Video Game Arcade Cabinet Accessories -Electronics > Arcade Equipment > Video Game Arcade Cabinets -Electronics > Audio -Electronics > Audio > Audio Accessories -Electronics > Audio > Audio Accessories > Headphone Accessories -Electronics > Audio > Audio Accessories > Headphone Accessories > Headphone Cushions -Electronics > Audio > Audio Accessories > Headphone Accessories > Headphone Ear Tips -Electronics > Audio > Audio Accessories > Karaoke System Accessories -Electronics > Audio > Audio Accessories > Karaoke System Accessories > Karaoke Chips -Electronics > Audio > Audio Accessories > MP3 Player Accessories -Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player & Mobile Phone Accessory Sets -Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player Cases -Electronics > Audio > Audio Accessories > Microphone Accessories -Electronics > Audio > Audio Accessories > Microphone Accessories > Microphone Stands -Electronics > Audio > Audio Accessories > Microphone Accessories > Microphone Windscreens -Electronics > Audio > Audio Accessories > Satellite Radio Accessories -Electronics > Audio > Audio Accessories > Speaker Accessories -Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Grill Fabric -Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stand Bags -Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stands -Electronics > Audio > Audio Accessories > Turntable Accessories -Electronics > Audio > Audio Accessories > Turntable Accessories > Turntable Cartridges & Needles -Electronics > Audio > Audio Components -Electronics > Audio > Audio Components > Audio & Video Receivers -Electronics > Audio > Audio Components > Audio Amplifiers -Electronics > Audio > Audio Components > Audio Amplifiers > Headphone Amplifiers -Electronics > Audio > Audio Components > Audio Amplifiers > Power Amplifiers -Electronics > Audio > Audio Components > Audio Mixers -Electronics > Audio > Audio Components > Audio Transmitters -Electronics > Audio > Audio Components > Audio Transmitters > Bluetooth Transmitters -Electronics > Audio > Audio Components > Audio Transmitters > FM Transmitters -Electronics > Audio > Audio Components > Channel Strips -Electronics > Audio > Audio Components > Direct Boxes -Electronics > Audio > Audio Components > Headphones -Electronics > Audio > Audio Components > Microphones -Electronics > Audio > Audio Components > Microphones > Video Camera Microphones -Electronics > Audio > Audio Components > Signal Processors -Electronics > Audio > Audio Components > Signal Processors > Crossovers -Electronics > Audio > Audio Components > Signal Processors > Effects Processors -Electronics > Audio > Audio Components > Signal Processors > Equalizers -Electronics > Audio > Audio Components > Signal Processors > Microphone Preamps -Electronics > Audio > Audio Components > Signal Processors > Noise Gates & Compressors -Electronics > Audio > Audio Components > Signal Processors > Phono Preamps -Electronics > Audio > Audio Components > Signal Processors > Public Address Management Systems -Electronics > Audio > Audio Components > Speakers -Electronics > Audio > Audio Components > Speakers > Computer Speakers -Electronics > Audio > Audio Components > Speakers > Studio Monitors -Electronics > Audio > Audio Components > Speakers > Subwoofers -Electronics > Audio > Audio Players & Recorders -Electronics > Audio > Audio Players & Recorders > Boomboxes -Electronics > Audio > Audio Players & Recorders > CD Players & Recorders -Electronics > Audio > Audio Players & Recorders > Cassette Players & Recorders -Electronics > Audio > Audio Players & Recorders > Home Theater Systems -Electronics > Audio > Audio Players & Recorders > Jukeboxes -Electronics > Audio > Audio Players & Recorders > Karaoke Systems -Electronics > Audio > Audio Players & Recorders > MP3 Players -Electronics > Audio > Audio Players & Recorders > MiniDisc Players & Recorders -Electronics > Audio > Audio Players & Recorders > Multitrack Recorders -Electronics > Audio > Audio Players & Recorders > Radios -Electronics > Audio > Audio Players & Recorders > Radios > Internet Radios -Electronics > Audio > Audio Players & Recorders > Radios > Satellite Radios -Electronics > Audio > Audio Players & Recorders > Stereo Systems -Electronics > Audio > Audio Players & Recorders > Turntables & Record Players -Electronics > Audio > Audio Players & Recorders > Turntables & Record Players > DJ Turntables -Electronics > Audio > Audio Players & Recorders > Voice Recorders -Electronics > Audio > DJ & Specialty Audio -Electronics > Audio > DJ & Specialty Audio > DJ CD Players -Electronics > Audio > DJ & Specialty Audio > DJ Equipment Accessories -Electronics > Audio > DJ & Specialty Audio > DJ Systems -Electronics > Audio > Public Address Systems -Electronics > Audio > Stage Equipment -Electronics > Audio > Stage Equipment > Wireless Transmitters -Electronics > Circuit Components -Electronics > Circuit Components > Circuit Decoders & Encoders -Electronics > Circuit Components > Circuit Prototyping -Electronics > Circuit Components > Circuit Prototyping > Breadboards -Electronics > Circuit Components > Electronic Filters -Electronics > Circuit Components > Optoelectronics -Electronics > Circuit Components > Optoelectronics > Laser Diodes -Electronics > Circuit Components > Passive Circuit Components -Electronics > Circuit Components > Passive Circuit Components > Capacitors -Electronics > Circuit Components > Passive Circuit Components > Electronic Oscillators -Electronics > Circuit Components > Passive Circuit Components > Inductors -Electronics > Circuit Components > Passive Circuit Components > Resistors -Electronics > Circuit Components > Passive Circuit Components > Resistors > Potentiometers -Electronics > Circuit Components > Printed Circuit Boards -Electronics > Circuit Components > Printed Circuit Boards > Development Boards -Electronics > Circuit Components > Semiconductors -Electronics > Circuit Components > Semiconductors > Diodes -Electronics > Circuit Components > Semiconductors > Integrated Circuits & Chips -Electronics > Circuit Components > Semiconductors > Integrated Circuits & Chips > Op Amps -Electronics > Circuit Components > Semiconductors > Integrated Circuits & Chips > Voltage Regulator ICs -Electronics > Circuit Components > Semiconductors > Microcontrollers -Electronics > Circuit Components > Semiconductors > Transistors -Electronics > Communications -Electronics > Communications > Answering Machines -Electronics > Communications > Answering Machines > On Hold Systems -Electronics > Communications > Caller IDs -Electronics > Communications > Communication Radio Accessories -Electronics > Communications > Communication Radios -Electronics > Communications > Communication Radios > CB Radios -Electronics > Communications > Communication Radios > Radio Scanners -Electronics > Communications > Communication Radios > Two-Way Radios -Electronics > Communications > Headsets -Electronics > Communications > Intercom Accessories -Electronics > Communications > Intercoms -Electronics > Communications > Pagers -Electronics > Communications > Telephony -Electronics > Communications > Telephony > Conference Phones -Electronics > Communications > Telephony > Corded Phones -Electronics > Communications > Telephony > Cordless Phones -Electronics > Communications > Telephony > Mobile Phone Accessories -Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Cases -Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Charms & Straps -Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Replacement Parts -Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Replacement Parts > Mobile Phone Digitizers -Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone SIM Cards -Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Stands -Electronics > Communications > Telephony > Mobile Phones -Electronics > Communications > Telephony > Mobile Phones > Feature Phones -Electronics > Communications > Telephony > Mobile Phones > Smartphones -Electronics > Communications > Telephony > Mobile Phones > Watch Phones -Electronics > Communications > Telephony > Satellite Phones -Electronics > Communications > Telephony > Telephone Accessories -Electronics > Communications > Telephony > Telephone Accessories > Phone Cards -Electronics > Communications > Video Conferencing -Electronics > Components -Electronics > Components > Accelerometers -Electronics > Components > Automation Control Components -Electronics > Components > Automation Control Components > Programmable Logic Controllers -Electronics > Components > Automation Control Components > Variable Frequency & Adjustable Speed Drives -Electronics > Components > Connectors -Electronics > Components > Connectors > Keystone Jacks -Electronics > Components > Connectors > RCA Jacks -Electronics > Components > Converters -Electronics > Components > Converters > Scan Converters -Electronics > Components > Modulators -Electronics > Components > Modulators > RF Modulators -Electronics > Components > Splitters -Electronics > Components > Splitters > RF Splitters -Electronics > Components > Splitters > UHF Splitters -Electronics > Components > Transformers -Electronics > Components > Transformers > Baluns -Electronics > Computers -Electronics > Computers > Barebone Computers -Electronics > Computers > Computer Accessories -Electronics > Computers > Computer Accessories > Computer Risers & Stands -Electronics > Computers > Computer Accessories > Handheld Device Accessories -Electronics > Computers > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories -Electronics > Computers > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories > E-Book Reader Cases -Electronics > Computers > Computer Accessories > Handheld Device Accessories > PDA Accessories -Electronics > Computers > Computer Accessories > Handheld Device Accessories > PDA Accessories > PDA Cases -Electronics > Computers > Computer Accessories > Keyboard & Mouse Wrist Rests -Electronics > Computers > Computer Accessories > Keyboard Trays & Platforms -Electronics > Computers > Computer Accessories > Laptop Accessories -Electronics > Computers > Computer Accessories > Laptop Accessories > Laptop Docking Stations -Electronics > Computers > Computer Accessories > Mouse Pads -Electronics > Computers > Computer Accessories > Stylus Pen Nibs & Refills -Electronics > Computers > Computer Accessories > Stylus Pens -Electronics > Computers > Computer Accessories > Tablet Computer Accessories -Electronics > Computers > Computer Accessories > Tablet Computer Accessories > Tablet Computer Replacement Parts -Electronics > Computers > Computer Accessories > Tablet Computer Accessories > Tablet Computer Replacement Parts > Tablet Computer Digitizers -Electronics > Computers > Computer Accessories > Tablet Computer Accessories > Tablet Computer Stands -Electronics > Computers > Computer Components -Electronics > Computers > Computer Components > Blade Server Enclosures -Electronics > Computers > Computer Components > Computer Cases -Electronics > Computers > Computer Components > Computer Power Supplies -Electronics > Computers > Computer Components > Computer Processors -Electronics > Computers > Computer Components > Computer Racks & Mounts -Electronics > Computers > Computer Components > Computer Starter Kits -Electronics > Computers > Computer Components > Computer System Cooling -Electronics > Computers > Computer Components > I/O Cards & Adapters -Electronics > Computers > Computer Components > I/O Cards & Adapters > Audio Cards & Adapters -Electronics > Computers > Computer Components > I/O Cards & Adapters > FireWire Cards -Electronics > Computers > Computer Components > I/O Cards & Adapters > Parallel Cards & Adapters -Electronics > Computers > Computer Components > I/O Cards & Adapters > Serial Cards & Adapters -Electronics > Computers > Computer Components > I/O Cards & Adapters > TV Tuner Cards & Adapters -Electronics > Computers > Computer Components > I/O Cards & Adapters > USB Cards -Electronics > Computers > Computer Components > I/O Cards & Adapters > Video Cards & Adapters -Electronics > Computers > Computer Components > Input Device Accessories -Electronics > Computers > Computer Components > Input Device Accessories > Barcode Scanner Stands -Electronics > Computers > Computer Components > Input Device Accessories > Game Controller Accessories -Electronics > Computers > Computer Components > Input Device Accessories > Game Controller Accessories > Game Controller Thumbsticks & Buttons -Electronics > Computers > Computer Components > Input Device Accessories > Graphics Tablet Accessories -Electronics > Computers > Computer Components > Input Devices -Electronics > Computers > Computer Components > Input Devices > Barcode Scanners -Electronics > Computers > Computer Components > Input Devices > Computer Keyboards -Electronics > Computers > Computer Components > Input Devices > Digital Note Taking Pens -Electronics > Computers > Computer Components > Input Devices > Fingerprint Readers -Electronics > Computers > Computer Components > Input Devices > Game Controllers -Electronics > Computers > Computer Components > Input Devices > Graphics Tablets -Electronics > Computers > Computer Components > Input Devices > KVM Switches -Electronics > Computers > Computer Components > Input Devices > Keyboard & Mouse Sets -Electronics > Computers > Computer Components > Input Devices > Memory Card Readers -Electronics > Computers > Computer Components > Input Devices > Mice & Trackballs -Electronics > Computers > Computer Components > Input Devices > Numeric Keypads -Electronics > Computers > Computer Components > Input Devices > Smart Card Readers -Electronics > Computers > Computer Components > Input Devices > Touchpads -Electronics > Computers > Computer Components > Laptop Parts -Electronics > Computers > Computer Components > Laptop Parts > Laptop Hinges -Electronics > Computers > Computer Components > Laptop Parts > Laptop Replacement Cables -Electronics > Computers > Computer Components > Laptop Parts > Laptop Replacement Keyboards -Electronics > Computers > Computer Components > Laptop Parts > Laptop Replacement Screens -Electronics > Computers > Computer Components > Laptop Parts > Laptop Shells -Electronics > Computers > Computer Components > Motherboards -Electronics > Computers > Computer Components > Output Devices -Electronics > Computers > Computer Components > Storage Devices -Electronics > Computers > Computer Components > Storage Devices > Disk Arrays -Electronics > Computers > Computer Components > Storage Devices > Disk Duplicators -Electronics > Computers > Computer Components > Storage Devices > Disk Duplicators > CD/DVD Duplicators -Electronics > Computers > Computer Components > Storage Devices > Disk Duplicators > Hard Drive Duplicators -Electronics > Computers > Computer Components > Storage Devices > Disk Duplicators > USB Drive Duplicators -Electronics > Computers > Computer Components > Storage Devices > Floppy Drives -Electronics > Computers > Computer Components > Storage Devices > Hard Drives -Electronics > Computers > Computer Components > Storage Devices > Hard Drives > Solid State Drives -Electronics > Computers > Computer Components > Storage Devices > Hard Drives > XBox 360 Hard Drives -Electronics > Computers > Computer Components > Storage Devices > Network Storage Systems -Electronics > Computers > Computer Components > Storage Devices > Network Storage Systems > Network Storage Servers -Electronics > Computers > Computer Components > Storage Devices > Network Storage Systems > Storage Area Networks -Electronics > Computers > Computer Components > Storage Devices > Optical Drives -Electronics > Computers > Computer Components > Storage Devices > Optical Drives > CD Drives -Electronics > Computers > Computer Components > Storage Devices > Optical Drives > DVD Drives -Electronics > Computers > Computer Components > Storage Devices > Optical Drives > MO Drives -Electronics > Computers > Computer Components > Storage Devices > Storage Drive Accessories -Electronics > Computers > Computer Components > Storage Devices > Storage Drive Accessories > Hard Drive Caddies -Electronics > Computers > Computer Components > Storage Devices > Storage Drive Accessories > Hard Drive Carrying Cases -Electronics > Computers > Computer Components > Storage Devices > Storage Drive Accessories > Hard Drive Docks -Electronics > Computers > Computer Components > Storage Devices > Storage Drive Accessories > Hard Drive Enclosures -Electronics > Computers > Computer Components > Storage Devices > Storage Drive Accessories > Hard Drive Mounts -Electronics > Computers > Computer Components > Storage Devices > Tape Drives -Electronics > Computers > Computer Components > Storage Devices > USB Flash Drives -Electronics > Computers > Computer Components > USB & FireWire Hubs -Electronics > Computers > Computer Servers -Electronics > Computers > Desktop Computers -Electronics > Computers > Handheld Devices -Electronics > Computers > Handheld Devices > Data Collection Terminals -Electronics > Computers > Handheld Devices > E-Book Readers -Electronics > Computers > Handheld Devices > PDAs -Electronics > Computers > Interactive Kiosks -Electronics > Computers > Laptops -Electronics > Computers > Laptops > Netbooks -Electronics > Computers > Tablet Computers -Electronics > Electrical Motors -Electronics > Electronics Accessories -Electronics > Electronics Accessories > Adapters -Electronics > Electronics Accessories > Adapters > Audio & Video Adapters -Electronics > Electronics Accessories > Adapters > Memory Adapters -Electronics > Electronics Accessories > Adapters > Storage Adapters -Electronics > Electronics Accessories > Adapters > USB Adapters -Electronics > Electronics Accessories > Antenna Accessories -Electronics > Electronics Accessories > Antenna Accessories > Antenna Mounts & Brackets -Electronics > Electronics Accessories > Antenna Accessories > Antenna Rotators -Electronics > Electronics Accessories > Antenna Accessories > Satellite LNBs -Electronics > Electronics Accessories > Antennas -Electronics > Electronics Accessories > Antennas > Communication Antennas -Electronics > Electronics Accessories > Antennas > Radio Antennas -Electronics > Electronics Accessories > Antennas > TV Antennas -Electronics > Electronics Accessories > Blank Media -Electronics > Electronics Accessories > Blank Media > Blank Audio Tapes -Electronics > Electronics Accessories > Blank Media > Blank Audio Tapes > Micro Cassettes -Electronics > Electronics Accessories > Blank Media > Blank Blu-ray Discs -Electronics > Electronics Accessories > Blank Media > Blank CDs -Electronics > Electronics Accessories > Blank Media > Blank DVDs -Electronics > Electronics Accessories > Blank Media > Blank Video Tapes -Electronics > Electronics Accessories > Blank Media > Computer Disks -Electronics > Electronics Accessories > Blank Media > Computer Disks > Floppy Disks -Electronics > Electronics Accessories > Blank Media > Computer Tapes -Electronics > Electronics Accessories > Blank Media > MiniDiscs -Electronics > Electronics Accessories > Cable Management -Electronics > Electronics Accessories > Cable Management > Cable Clips -Electronics > Electronics Accessories > Cable Management > Cable Trays -Electronics > Electronics Accessories > Cable Management > Patch Panels -Electronics > Electronics Accessories > Cable Management > Wire & Cable Sleeves -Electronics > Electronics Accessories > Cable Management > Wire & Cable Ties -Electronics > Electronics Accessories > Cables -Electronics > Electronics Accessories > Cables > Audio & Video Cables -Electronics > Electronics Accessories > Cables > Audio & Video Cables > DVI Cables -Electronics > Electronics Accessories > Cables > Audio & Video Cables > HDMI Cables -Electronics > Electronics Accessories > Cables > Audio & Video Cables > SCART Cables -Electronics > Electronics Accessories > Cables > Audio & Video Cables > Speaker Cables -Electronics > Electronics Accessories > Cables > Coaxial Cables -Electronics > Electronics Accessories > Cables > Data Transfer Cables -Electronics > Electronics Accessories > Cables > Data Transfer Cables > FireWire Cables -Electronics > Electronics Accessories > Cables > Data Transfer Cables > USB Cables -Electronics > Electronics Accessories > Cables > Data Transfer Cables > iOS Cables -Electronics > Electronics Accessories > Cables > KVM Cables -Electronics > Electronics Accessories > Cables > Network Cables -Electronics > Electronics Accessories > Cables > Network Cables > Ethernet Cables -Electronics > Electronics Accessories > Cables > Network Cables > Serial Cables -Electronics > Electronics Accessories > Cables > Optical Cables -Electronics > Electronics Accessories > Cables > RCA Cables -Electronics > Electronics Accessories > Cables > Storage Cables -Electronics > Electronics Accessories > Cables > Storage Cables > IDE Cables -Electronics > Electronics Accessories > Cables > Storage Cables > SAS Cables -Electronics > Electronics Accessories > Cables > Storage Cables > SATA Cables -Electronics > Electronics Accessories > Cables > Storage Cables > SCSI Cables -Electronics > Electronics Accessories > Cables > System & Power Cables -Electronics > Electronics Accessories > Cables > Telephone Cables -Electronics > Electronics Accessories > Electronics Cleaners -Electronics > Electronics Accessories > Electronics Cleaners > Audio & Video Cleaners -Electronics > Electronics Accessories > Electronics Cleaners > Camera Cleaners -Electronics > Electronics Accessories > Electronics Cleaners > Screen Cleaners -Electronics > Electronics Accessories > Electronics Films & Shields -Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals -Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals > Computer Keyboard Stickers -Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals > Game Console Stickers & Decals -Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals > Laptop Stickers & Decals -Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals > MP3 Player Stickers & Decals -Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals > Mobile Phone Stickers & Decals -Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals > Tablet Computer Stickers & Decals -Electronics > Electronics Accessories > Electronics Films & Shields > Keyboard Protectors -Electronics > Electronics Accessories > Electronics Films & Shields > Privacy Filters -Electronics > Electronics Accessories > Electronics Films & Shields > Screen Protectors -Electronics > Electronics Accessories > Memory -Electronics > Electronics Accessories > Memory > Cache Memory -Electronics > Electronics Accessories > Memory > Flash Memory -Electronics > Electronics Accessories > Memory > Flash Memory > Flash Memory Cards -Electronics > Electronics Accessories > Memory > RAM -Electronics > Electronics Accessories > Memory > ROM -Electronics > Electronics Accessories > Memory > Video Memory -Electronics > Electronics Accessories > Memory Accessories -Electronics > Electronics Accessories > Memory Accessories > Memory Cases -Electronics > Electronics Accessories > Power -Electronics > Electronics Accessories > Power > Batteries -Electronics > Electronics Accessories > Power > Batteries > Camera Batteries -Electronics > Electronics Accessories > Power > Batteries > Cordless Phone Batteries -Electronics > Electronics Accessories > Power > Batteries > E-Book Reader Batteries -Electronics > Electronics Accessories > Power > Batteries > General Purpose Batteries -Electronics > Electronics Accessories > Power > Batteries > Laptop Batteries -Electronics > Electronics Accessories > Power > Batteries > Mobile Phone Batteries -Electronics > Electronics Accessories > Power > Batteries > PDA Batteries -Electronics > Electronics Accessories > Power > Batteries > Tablet Computer Batteries -Electronics > Electronics Accessories > Power > Batteries > UPS Batteries -Electronics > Electronics Accessories > Power > Batteries > Video Camera Batteries -Electronics > Electronics Accessories > Power > Battery Accessories -Electronics > Electronics Accessories > Power > Battery Accessories > Camera Battery Chargers -Electronics > Electronics Accessories > Power > Battery Accessories > General Purpose Battery Chargers -Electronics > Electronics Accessories > Power > Chargers -Electronics > Electronics Accessories > Power > Chargers > E-Book Reader Chargers -Electronics > Electronics Accessories > Power > Chargers > MP3 Player Chargers -Electronics > Electronics Accessories > Power > Chargers > Mobile Phone Chargers -Electronics > Electronics Accessories > Power > Chargers > PDA Chargers -Electronics > Electronics Accessories > Power > Chargers > Solar Chargers -Electronics > Electronics Accessories > Power > Chargers > Tablet Computer Chargers -Electronics > Electronics Accessories > Power > Fuel Cells -Electronics > Electronics Accessories > Power > Power Adapter Accessories -Electronics > Electronics Accessories > Power > Power Adapters -Electronics > Electronics Accessories > Power > Power Adapters > Laptop Power Adapters -Electronics > Electronics Accessories > Power > Power Adapters > Power Converters -Electronics > Electronics Accessories > Power > Power Adapters > Power Inverters -Electronics > Electronics Accessories > Power > Power Adapters > Travel Adapters -Electronics > Electronics Accessories > Power > Power Conditioners -Electronics > Electronics Accessories > Power > Power Control Units -Electronics > Electronics Accessories > Power > Power Enclosures -Electronics > Electronics Accessories > Power > Power Injectors & Splitters -Electronics > Electronics Accessories > Power > Power Strips & Surge Suppressors -Electronics > Electronics Accessories > Power > Surge Protection Devices -Electronics > Electronics Accessories > Power > UPS -Electronics > Electronics Accessories > Power > UPS Accessories -Electronics > Electronics Accessories > Power > Voltage Converters -Electronics > Electronics Accessories > Remote Controls -Electronics > Electronics Accessories > Signal Boosters -Electronics > GPS -Electronics > GPS > Automotive GPS -Electronics > GPS > Aviation GPS -Electronics > GPS > Sport GPS -Electronics > GPS Accessories -Electronics > GPS Accessories > GPS Cases -Electronics > GPS Accessories > GPS Mounts -Electronics > GPS Trackers -Electronics > Marine Electronics -Electronics > Marine Electronics > Fish Finders -Electronics > Marine Electronics > Marine Chartplotters & GPS -Electronics > Marine Electronics > Marine Radar -Electronics > Marine Electronics > Marine Radios -Electronics > Networking -Electronics > Networking > Bridges & Routers -Electronics > Networking > Bridges & Routers > Network Bridges -Electronics > Networking > Bridges & Routers > Network Bridges > Wireless Bridges -Electronics > Networking > Bridges & Routers > VoIP Gateways & Routers -Electronics > Networking > Bridges & Routers > Wireless Access Points -Electronics > Networking > Bridges & Routers > Wireless Routers -Electronics > Networking > Concentrators & Multiplexers -Electronics > Networking > Hubs & Switches -Electronics > Networking > Modem Accessories -Electronics > Networking > Modems -Electronics > Networking > Network Cards & Adapters -Electronics > Networking > Network Cards & Adapters > XBox 360 Network Cards -Electronics > Networking > Network Security & Firewall Devices -Electronics > Networking > Power Line Network Adapters -Electronics > Networking > Print Servers -Electronics > Networking > Repeaters & Transceivers -Electronics > Plug & Play TV Games -Electronics > Print, Copy, Scan & Fax -Electronics > Print, Copy, Scan & Fax > Fax Machines -Electronics > Print, Copy, Scan & Fax > Printers & Copiers -Electronics > Print, Copy, Scan & Fax > Printers & Copiers > Copiers -Electronics > Print, Copy, Scan & Fax > Printers & Copiers > Printers -Electronics > Print, Copy, Scan & Fax > Printers & Copiers > Printers > Dot Matrix Printers -Electronics > Print, Copy, Scan & Fax > Printers & Copiers > Printers > Inkjet Printers -Electronics > Print, Copy, Scan & Fax > Printers & Copiers > Printers > Laser Printers -Electronics > Print, Copy, Scan & Fax > Printers & Copiers > Printers > Photo Printers -Electronics > Print, Copy, Scan & Fax > Scanners -Electronics > Print, Copy, Scan & Fax Accessories -Electronics > Print, Copy, Scan & Fax Accessories > Copier Accessories -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables > Printer Filters -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables > Printer Ribbons -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables > Printheads -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables > Toner & Inkjet Cartridge Refills -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables > Toner & Inkjet Cartridges -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables > Toner & Inkjet Cartridges > Oil Rollers -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Consumables > Toner & Inkjet Cartridges > Printer Drum Kits -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Duplexers -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Maintenance Kits -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Memory -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Stands -Electronics > Print, Copy, Scan & Fax Accessories > Printer Accessories > Printer Trays -Electronics > Print, Copy, Scan & Fax Accessories > Scanner Accessories -Electronics > Toll Collection Devices -Electronics > Video -Electronics > Video > Computer Monitors -Electronics > Video > Projectors -Electronics > Video > Projectors > Multimedia Projectors -Electronics > Video > Projectors > Overhead Projectors -Electronics > Video > Projectors > Slide Projectors -Electronics > Video > Satellite & Cable TV -Electronics > Video > Satellite & Cable TV > Cable TV Receivers -Electronics > Video > Satellite & Cable TV > Satellite Receivers -Electronics > Video > Televisions -Electronics > Video > Televisions > CRT Televisions -Electronics > Video > Televisions > Flat Panel Televisions -Electronics > Video > Televisions > Portable Televisions -Electronics > Video > Televisions > Projection Televisions -Electronics > Video > Video Accessories -Electronics > Video > Video Accessories > 3D Glasses -Electronics > Video > Video Accessories > Computer Monitor Accessories -Electronics > Video > Video Accessories > Computer Monitor Accessories > Color Calibrators -Electronics > Video > Video Accessories > Projector Accessories -Electronics > Video > Video Accessories > Projector Accessories > Projection & Tripod Skirts -Electronics > Video > Video Accessories > Projector Accessories > Projection Screen Stands -Electronics > Video > Video Accessories > Projector Accessories > Projection Screens -Electronics > Video > Video Accessories > Projector Accessories > Projector Mounts -Electronics > Video > Video Accessories > Projector Accessories > Projector Replacement Lamps -Electronics > Video > Video Accessories > Rewinders -Electronics > Video > Video Accessories > Television Accessories -Electronics > Video > Video Accessories > Television Accessories > TV & Monitor Mounts -Electronics > Video > Video Accessories > Television Accessories > TV Replacement Lamps -Electronics > Video > Video Accessories > Television Accessories > TV Scan Converters -Electronics > Video > Video Editing Hardware & Production Equipment -Electronics > Video > Video Multiplexers -Electronics > Video > Video Players & Recorders -Electronics > Video > Video Players & Recorders > DVD & Blu-ray Players -Electronics > Video > Video Players & Recorders > DVD Recorders -Electronics > Video > Video Players & Recorders > DVD Recorders > Blu-Ray Recorders -Electronics > Video > Video Players & Recorders > DVD Recorders > HD-DVD Recorders -Electronics > Video > Video Players & Recorders > Digital Video Recorders -Electronics > Video > Video Players & Recorders > Home Media Players -Electronics > Video > Video Players & Recorders > VCRs -Electronics > Video > Video Servers -Electronics > Video > Video Transmitters -Electronics > Video > Video Transmitters > Video Senders -Electronics > Video Game Console Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > All PlayStation Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > All PlayStation Accessories > PlayStation (original) Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > All PlayStation Accessories > PlayStation 2 Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > All PlayStation Accessories > PlayStation 3 Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > All XBox Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > All XBox Accessories > XBox (original) Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > All XBox Accessories > XBox 360 Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Dreamcast Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > GameCube Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Jaguar Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Neo Geo Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Nintendo 64 Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Nintendo Entertainment System Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Sega Genesis Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Sega Master System Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Super Nintendo Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Turbografx 16 Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Wii Accessories -Electronics > Video Game Console Accessories > Home Game Console Accessories > Wii U Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > All Game Boy Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > All Game Boy Accessories > Game Boy Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > All Game Boy Accessories > Game Boy Advance Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > Atari Lynx Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > Game Gear Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > N-Gage Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > Neo Geo Pocket Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > Nintendo 3DS Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > Nintendo DS Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > PlayStation Portable Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > PlayStation Vita Accessories -Electronics > Video Game Console Accessories > Portable Game Console Accessories > WonderSwan Accessories -Electronics > Video Game Consoles -Electronics > Video Game Consoles > Home Game Consoles -Electronics > Video Game Consoles > Home Game Consoles > Dreamcast Consoles -Electronics > Video Game Consoles > Home Game Consoles > GameCube Consoles -Electronics > Video Game Consoles > Home Game Consoles > Jaguar Consoles -Electronics > Video Game Consoles > Home Game Consoles > Neo Geo Consoles -Electronics > Video Game Consoles > Home Game Consoles > Nintendo 64 Consoles -Electronics > Video Game Consoles > Home Game Consoles > Nintendo Entertainment System Consoles -Electronics > Video Game Consoles > Home Game Consoles > PlayStation (original) Consoles -Electronics > Video Game Consoles > Home Game Consoles > PlayStation 2 Consoles -Electronics > Video Game Consoles > Home Game Consoles > PlayStation 3 Consoles -Electronics > Video Game Consoles > Home Game Consoles > Sega Genesis Consoles -Electronics > Video Game Consoles > Home Game Consoles > Sega Master System Consoles -Electronics > Video Game Consoles > Home Game Consoles > Super Nintendo Consoles -Electronics > Video Game Consoles > Home Game Consoles > Turbografx 16 Consoles -Electronics > Video Game Consoles > Home Game Consoles > Wii Consoles -Electronics > Video Game Consoles > Home Game Consoles > Wii U Consoles -Electronics > Video Game Consoles > Home Game Consoles > XBox (original) Consoles -Electronics > Video Game Consoles > Home Game Consoles > XBox 360 Consoles -Electronics > Video Game Consoles > Portable Game Consoles -Electronics > Video Game Consoles > Portable Game Consoles > All Game Boy Consoles -Electronics > Video Game Consoles > Portable Game Consoles > All Game Boy Consoles > Game Boy Advance Consoles -Electronics > Video Game Consoles > Portable Game Consoles > All Game Boy Consoles > Game Boy Consoles -Electronics > Video Game Consoles > Portable Game Consoles > Atari Lynx Consoles -Electronics > Video Game Consoles > Portable Game Consoles > Game Gear Consoles -Electronics > Video Game Consoles > Portable Game Consoles > LeapFrog Consoles -Electronics > Video Game Consoles > Portable Game Consoles > N-Gage Consoles -Electronics > Video Game Consoles > Portable Game Consoles > Neo Geo Pocket Consoles -Electronics > Video Game Consoles > Portable Game Consoles > Nintendo 3DS -Electronics > Video Game Consoles > Portable Game Consoles > Nintendo DS Consoles -Electronics > Video Game Consoles > Portable Game Consoles > PlayStation Portable Consoles -Electronics > Video Game Consoles > Portable Game Consoles > PlayStation Vita -Electronics > Video Game Consoles > Portable Game Consoles > Retrogen -Electronics > Video Game Consoles > Portable Game Consoles > WonderSwan -Food, Beverages & Tobacco -Food, Beverages & Tobacco > Beverages -Food, Beverages & Tobacco > Beverages > Beer -Food, Beverages & Tobacco > Beverages > Beer > Non-Alcoholic Beer -Food, Beverages & Tobacco > Beverages > Bitters -Food, Beverages & Tobacco > Beverages > Buttermilk -Food, Beverages & Tobacco > Beverages > Cocktail Mixes -Food, Beverages & Tobacco > Beverages > Coffee -Food, Beverages & Tobacco > Beverages > Coffee > Bottled Coffee Drinks -Food, Beverages & Tobacco > Beverages > Coffee > Coffee Pods -Food, Beverages & Tobacco > Beverages > Coffee > Ground & Whole Bean Coffee -Food, Beverages & Tobacco > Beverages > Coffee > Instant Coffee -Food, Beverages & Tobacco > Beverages > Eggnog -Food, Beverages & Tobacco > Beverages > Flavored Malt Beverages -Food, Beverages & Tobacco > Beverages > Fruit Flavored Drinks -Food, Beverages & Tobacco > Beverages > Hard Cider -Food, Beverages & Tobacco > Beverages > Hot Chocolate -Food, Beverages & Tobacco > Beverages > Juice -Food, Beverages & Tobacco > Beverages > Liquor & Spirits -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Brandy -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Brandy > Cognac -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Gin -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Liqueurs -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Rum -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Schnapps -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Tequila -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Vodka -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Whiskey -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Whiskey > American Whiskey -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Whiskey > Irish Whiskey -Food, Beverages & Tobacco > Beverages > Liquor & Spirits > Whiskey > Scotch Whiskey -Food, Beverages & Tobacco > Beverages > Milk -Food, Beverages & Tobacco > Beverages > Milk > Powdered Milk -Food, Beverages & Tobacco > Beverages > Non-Dairy Milk -Food, Beverages & Tobacco > Beverages > Non-Dairy Milk > Almond Milk -Food, Beverages & Tobacco > Beverages > Non-Dairy Milk > Coconut Milk -Food, Beverages & Tobacco > Beverages > Non-Dairy Milk > Hemp Milk -Food, Beverages & Tobacco > Beverages > Non-Dairy Milk > Oat Milk -Food, Beverages & Tobacco > Beverages > Non-Dairy Milk > Rice Milk -Food, Beverages & Tobacco > Beverages > Non-Dairy Milk > Soy Milk -Food, Beverages & Tobacco > Beverages > Powdered Beverage Mixes -Food, Beverages & Tobacco > Beverages > Soda -Food, Beverages & Tobacco > Beverages > Sports & Energy Drinks -Food, Beverages & Tobacco > Beverages > Tea & Infusions -Food, Beverages & Tobacco > Beverages > Tea & Infusions > Bottled Tea Drinks -Food, Beverages & Tobacco > Beverages > Tea & Infusions > Powdered Tea -Food, Beverages & Tobacco > Beverages > Tea & Infusions > Tea Bags & Loose Tea Leaves -Food, Beverages & Tobacco > Beverages > Vinegar Drinks -Food, Beverages & Tobacco > Beverages > Water -Food, Beverages & Tobacco > Beverages > Water > Bottled Water -Food, Beverages & Tobacco > Beverages > Water > Carbonated Water -Food, Beverages & Tobacco > Beverages > Water > Flavored Water -Food, Beverages & Tobacco > Beverages > Water > Tonic Water -Food, Beverages & Tobacco > Beverages > Wine -Food, Beverages & Tobacco > Beverages > Wine > Blush Wine -Food, Beverages & Tobacco > Beverages > Wine > Dessert Wine -Food, Beverages & Tobacco > Beverages > Wine > Dessert Wine > Port -Food, Beverages & Tobacco > Beverages > Wine > Dessert Wine > Sherry -Food, Beverages & Tobacco > Beverages > Wine > Dessert Wine > Vermouth -Food, Beverages & Tobacco > Beverages > Wine > Mead -Food, Beverages & Tobacco > Beverages > Wine > Non-Alcoholic Wine -Food, Beverages & Tobacco > Beverages > Wine > Red Wine -Food, Beverages & Tobacco > Beverages > Wine > Rice Wine -Food, Beverages & Tobacco > Beverages > Wine > Rosé Wine -Food, Beverages & Tobacco > Beverages > Wine > Sangria -Food, Beverages & Tobacco > Beverages > Wine > Sparkling Wine -Food, Beverages & Tobacco > Beverages > Wine > White Wine -Food, Beverages & Tobacco > Food Items -Food, Beverages & Tobacco > Food Items > Bakery -Food, Beverages & Tobacco > Food Items > Bakery > Bagels -Food, Beverages & Tobacco > Food Items > Bakery > Bakery Assortments -Food, Beverages & Tobacco > Food Items > Bakery > Breads & Buns -Food, Beverages & Tobacco > Food Items > Bakery > Cakes & Dessert Bars -Food, Beverages & Tobacco > Food Items > Bakery > Coffee Cakes -Food, Beverages & Tobacco > Food Items > Bakery > Cookies -Food, Beverages & Tobacco > Food Items > Bakery > Cupcakes -Food, Beverages & Tobacco > Food Items > Bakery > Donuts -Food, Beverages & Tobacco > Food Items > Bakery > Fudge -Food, Beverages & Tobacco > Food Items > Bakery > Ice Cream Cones -Food, Beverages & Tobacco > Food Items > Bakery > Muffins -Food, Beverages & Tobacco > Food Items > Bakery > Pastries & Scones -Food, Beverages & Tobacco > Food Items > Bakery > Pies & Tarts -Food, Beverages & Tobacco > Food Items > Bakery > Taco Shells & Tostadas -Food, Beverages & Tobacco > Food Items > Bakery > Tortillas & Wraps -Food, Beverages & Tobacco > Food Items > Candy & Gum -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Candy Bars & Pieces -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Candy Brittle -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Candy Canes -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Candy Corn -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Caramels -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Chocolate Assortments -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Chocolate Bars -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Chocolate Covered Fruit -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Chocolate Truffles -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Fruit Chews -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Gumdrops -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Gummy Candies -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Hard Candies -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Jelly Beans -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Licorice -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Lollipops & Suckers -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Marshmallow Candies -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Mints -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Nougat -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Peanut Butter Cups -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Peppermint Patties -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Taffy -Food, Beverages & Tobacco > Food Items > Candy & Gum > Candy & Chocolate > Toffee -Food, Beverages & Tobacco > Food Items > Candy & Gum > Chewing Gum -Food, Beverages & Tobacco > Food Items > Condiments & Sauces -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Barbecue Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Chutney -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Cocktail Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Coffee Creamer -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Curry Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Fruit Toppings -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Ice Cream Syrup -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Whipped Topping -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Fish Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Gravy -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Honey -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Horseradish Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Hot Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Ketchup -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Marinade -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mayonnaise -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mustard -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Olives & Capers -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pasta Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pickles & Relishes -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pizza Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Salad Dressing -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Satay Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Soy Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Steak Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup > Agave Syrup -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup > Flavored Syrup -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup > Pancake & Maple Syrup -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup > Snow Cone Syrup -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tahini -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tartar Sauce -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Vinegar -Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Worcestershire Sauce -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Artificial Sweeteners -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chips -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chocolate -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Extracts -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Extracts > Almond Extract -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Extracts > Vanilla Extract -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Kits -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Bread & Muffin Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Bread & Muffin Mixes > Bread Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Bread & Muffin Mixes > Muffin Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Bread Pudding Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Cake & Brownie Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Cookie Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Pretzel Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes > Waffle & Pancake Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Powder -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Soda -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Batter & Coating Mixes -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bean Paste -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bread Crumbs -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Condensed Milk -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Canola Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Chili Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Coconut Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Cooking Spray -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Corn Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Hemp Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Olive Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Peanut Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Rice Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Sesame Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Soybean Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Vegetable Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oil > Walnut Oil -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Starch -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Wine -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Corn Syrup -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Bread & Pastry Dough -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Bread & Pastry Dough > Pizza Dough -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Cookie & Brownie Dough -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Pie Crusts -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations > Colored Sugar -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations > Edible Baking Decoration Kits -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations > Sprinkles -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations > Sugar Pearls -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Evaporated Milk -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Floss Sugar -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Flour -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Food Coloring -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Frosting & Icing -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Marshmallows -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Molasses -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Pie Fillings -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Shortening & Lard -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Shredded Coconut -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Starter Cultures -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Sugar -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Tomato Paste -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Unflavored Gelatin -Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Yeast -Food, Beverages & Tobacco > Food Items > Dairy Products -Food, Beverages & Tobacco > Food Items > Dairy Products > Butter & Margarine -Food, Beverages & Tobacco > Food Items > Dairy Products > Cheese -Food, Beverages & Tobacco > Food Items > Dairy Products > Cottage Cheese -Food, Beverages & Tobacco > Food Items > Dairy Products > Cream -Food, Beverages & Tobacco > Food Items > Dairy Products > Sour Cream -Food, Beverages & Tobacco > Food Items > Dairy Products > Whipped Cream -Food, Beverages & Tobacco > Food Items > Dairy Products > Yogurt -Food, Beverages & Tobacco > Food Items > Dips & Spreads -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Apple Butter -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cheese Spread -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cream Cheese -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Guacamole -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Hummus -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Jams & Jellies -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Nut Butters -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Nut Butters > Almond Butter -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Nut Butters > Hazelnut Butter -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Nut Butters > Peanut Butter -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Salsa -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Tapenade -Food, Beverages & Tobacco > Food Items > Dips & Spreads > Vegetable Dip -Food, Beverages & Tobacco > Food Items > Food Gift Baskets -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Frozen Yogurt -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Cream -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Nondairy Frozen Desserts -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Popsicles -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Sherbet -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Sorbet -Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Sundae Cones -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Jarred Vegetables -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Prepared Beans -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned Fruits -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Fruits -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Vegetables -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dry Beans -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Apples -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Apricots -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Atemoyas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Avocados -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Babacos -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Bananas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Berries -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Breadfruit -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cactus Pears -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cherimoyas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cherries -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Coconuts -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Currants -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Dates -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Feijoas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Figs -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Grapefruits -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Grapes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Guavas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Homli Fruits -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Kiwifruit -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Kumquats -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Lemons -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Limequats -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Limes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Longan -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Loquats -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Lychees -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Madroño -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mamey -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mangoes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mangosteens -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Melons -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Melons > Bitter Melons -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Melons > Kiwanos -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Nectarines -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Oranges -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Papayas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Passion Fruit -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Peaches -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pears -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Persimmons -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Physalis -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pineapples -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pitahayas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Plumcots -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Plums -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pomegranates -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Quince -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Rambutans -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapodillo -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapote -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Soursops -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Starfruits -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sugar Apples -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Tamarindo -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Tangelos -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Tangerines -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Alfafa Sprouts -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Arracachas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Artichokes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Arugula -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Asparagus -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Bean Sprouts -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beans -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beet Greens -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beets -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Bok Choy -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Borage -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Broccoli -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Brussel Sprouts -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cabbage -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cactus Leaves -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cardoon -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Carrots -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cauliflower -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery Roots -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Chard -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Chick Peas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Chicory -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Chicory > Belgian Endives -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Chicory > Endives -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Chicory > Escarole -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Chicory > Radicchio -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Choy Sum -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Corn -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cucumbers -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Eggplants -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fennel Bulbs -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fiddlehead Ferns -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Choy -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Lan -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Garlic -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Ginger Root -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gobo Root -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gourds -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Horseradish Root -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Jicama -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Kale -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Kohlrabi -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Leeks -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Lettuce -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Lotus Roots -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Malangas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Mushrooms -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Okra -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > On Choy -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Onions -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsley Roots -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsnips -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peppers -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Potatoes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Pumpkins -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Radishes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Rhubarb -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Rutabagas -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Salad Mixes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Shallots -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Spinach -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Squashes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sugar Cane -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sunchokes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sweet Potatoes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tamarillos -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Taro Root -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tomatoes -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Turnips -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tuscan Cabbage -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Water Chestnuts -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Watercress -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Wheatgrass -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yu Choy -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yuca Root -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Ñame -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fruit Sauce -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fruit Sauce > Apple Sauce -Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fruit Sauce > Cranberry Sauce -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Amaranth -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Barley -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Buckwheat -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Cereal & Granola -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Cornmeal -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Couscous -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Millet -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Oats, Grits & Hot Cereal -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Quinoa -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rice -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rye -Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Wheat -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Canned Meats -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Fresh & Frozen Meats -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Lunch & Deli Meats -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Meat Patties -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Sausages & Hot Dogs -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Canned Seafood -Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Fresh & Frozen Seafood -Food, Beverages & Tobacco > Food Items > Nuts & Seeds -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Almonds -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Brazil Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Cashews -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Chestnuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Chocolate Covered Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Hazelnuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Kola Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Macadamia Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Mamoncillo Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Maya Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Mixed Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Ogbono Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Paradise Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Peanuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Pecans -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Pine Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Pistachios -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Pumpkin Seeds -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Sesame Seeds -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Soy Nuts -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Sunflower Seeds -Food, Beverages & Tobacco > Food Items > Nuts & Seeds > Walnuts -Food, Beverages & Tobacco > Food Items > Pasta & Noodles -Food, Beverages & Tobacco > Food Items > Prepared Foods -Food, Beverages & Tobacco > Food Items > Prepared Foods > Appetizers & Hors d'Oeuvres -Food, Beverages & Tobacco > Food Items > Prepared Foods > Frozen Dinners -Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Entrées & Sides -Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Entrées & Sides > Breakfast Sandwiches -Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Entrées & Sides > Pizza -Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Entrées & Sides > Prepared Entrées -Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Entrées & Sides > Prepared Sandwiches -Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Entrées & Sides > Prepared Side Dishes -Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Entrées & Sides > Waffles, Pancakes & French Toast -Food, Beverages & Tobacco > Food Items > Prepared Foods > Skillet Dinners -Food, Beverages & Tobacco > Food Items > Prepared Foods > Sushi -Food, Beverages & Tobacco > Food Items > Seasonings & Spices -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Anise -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Basil -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Bay Leaves -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Chili Powder -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Chives -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Cilantro -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Cinnamon -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Cumin -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Dill -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Fennel Seeds -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Garlic Powder -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Lemon Grass -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Marjoram -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Mint -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Onion Powder -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Oregano -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Paprika -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Parsley -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Rosemary -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Sage -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Salsify -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Savory -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Sorrel -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Tarragon -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Thyme -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices > Vanilla Beans -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > MSG -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Pepper -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Salt -Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Seasoning & Spice Blends -Food, Beverages & Tobacco > Food Items > Snack Foods -Food, Beverages & Tobacco > Food Items > Snack Foods > Breadsticks -Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars -Food, Beverages & Tobacco > Food Items > Snack Foods > Cheese Puffs -Food, Beverages & Tobacco > Food Items > Snack Foods > Chips -Food, Beverages & Tobacco > Food Items > Snack Foods > Chips > Bagel Chips -Food, Beverages & Tobacco > Food Items > Snack Foods > Chips > Corn & Tortilla Chips -Food, Beverages & Tobacco > Food Items > Snack Foods > Chips > Pita Chips -Food, Beverages & Tobacco > Food Items > Snack Foods > Chips > Potato Chips -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Cheese Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Cracker Assortments -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Flatbread Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Graham Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Matzo Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Oyster Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Saltine Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Sandwich Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers > Water Crackers -Food, Beverages & Tobacco > Food Items > Snack Foods > Croutons -Food, Beverages & Tobacco > Food Items > Snack Foods > Fruit Snacks -Food, Beverages & Tobacco > Food Items > Snack Foods > Jerky -Food, Beverages & Tobacco > Food Items > Snack Foods > Jerky > Beef Jerky -Food, Beverages & Tobacco > Food Items > Snack Foods > Jerky > Pork Jerky -Food, Beverages & Tobacco > Food Items > Snack Foods > Jerky > Turkey Jerky -Food, Beverages & Tobacco > Food Items > Snack Foods > Popcorn -Food, Beverages & Tobacco > Food Items > Snack Foods > Pork Rinds -Food, Beverages & Tobacco > Food Items > Snack Foods > Pretzels -Food, Beverages & Tobacco > Food Items > Snack Foods > Pudding & Gelatin Snacks -Food, Beverages & Tobacco > Food Items > Snack Foods > Puffed Rice Cakes -Food, Beverages & Tobacco > Food Items > Snack Foods > Salad Toppings -Food, Beverages & Tobacco > Food Items > Snack Foods > Sesame Sticks -Food, Beverages & Tobacco > Food Items > Snack Foods > Snack Cakes -Food, Beverages & Tobacco > Food Items > Snack Foods > Sticky Rice Cakes -Food, Beverages & Tobacco > Food Items > Snack Foods > Trail & Snack Mixes -Food, Beverages & Tobacco > Food Items > Soups & Broths -Food, Beverages & Tobacco > Food Items > Soups & Broths > Bouillon Cubes -Food, Beverages & Tobacco > Food Items > Soups & Broths > Canned Soups & Broths -Food, Beverages & Tobacco > Food Items > Soups & Broths > Dried Soups -Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products -Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Cheese Alternatives -Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Meat Alternatives -Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Seitan -Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tempeh -Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tofu -Food, Beverages & Tobacco > Tobacco Products -Food, Beverages & Tobacco > Tobacco Products > Chewing Tobacco -Food, Beverages & Tobacco > Tobacco Products > Cigarettes -Food, Beverages & Tobacco > Tobacco Products > Cigars -Food, Beverages & Tobacco > Tobacco Products > Electronic Cigarettes -Food, Beverages & Tobacco > Tobacco Products > Loose Tobacco -Furniture -Furniture > Baby & Toddler Furniture -Furniture > Baby & Toddler Furniture > Baby & Toddler Furniture Sets -Furniture > Baby & Toddler Furniture > Bassinet & Cradle Accessories -Furniture > Baby & Toddler Furniture > Bassinet & Cradle Accessories > Bassinet Stands -Furniture > Baby & Toddler Furniture > Bassinets & Cradles -Furniture > Baby & Toddler Furniture > Changing Tables -Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories -Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Bumpers & Liners -Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Conversion Kits -Furniture > Baby & Toddler Furniture > Cribs & Toddler Beds -Furniture > Baby & Toddler Furniture > High Chair & Booster Seat Accessories -Furniture > Baby & Toddler Furniture > High Chairs & Boosters -Furniture > Baby & Toddler Furniture > Playroom Furniture -Furniture > Beds & Accessories -Furniture > Beds & Accessories > Bed Accessories -Furniture > Beds & Accessories > Bed Accessories > Waterbed Accessories -Furniture > Beds & Accessories > Bed Frames -Furniture > Beds & Accessories > Beds -Furniture > Beds & Accessories > Beds > Bunk Beds -Furniture > Beds & Accessories > Beds > Day Beds -Furniture > Beds & Accessories > Beds > Murphy Beds -Furniture > Beds & Accessories > Beds > Trundle Beds -Furniture > Beds & Accessories > Headboards & Footboards -Furniture > Beds & Accessories > Mattress Foundations -Furniture > Beds & Accessories > Mattresses -Furniture > Beds & Accessories > Mattresses > Waterbeds -Furniture > Benches -Furniture > Benches > Kitchen & Dining Benches -Furniture > Benches > Storage & Entryway Benches -Furniture > Benches > Vanity Benches -Furniture > Cabinets & Storage -Furniture > Cabinets & Storage > Armoires & Wardrobes -Furniture > Cabinets & Storage > Buffets & Sideboards -Furniture > Cabinets & Storage > China Cabinets & Hutches -Furniture > Cabinets & Storage > Dressers -Furniture > Cabinets & Storage > File Cabinets -Furniture > Cabinets & Storage > Magazine Racks -Furniture > Cabinets & Storage > Media Storage -Furniture > Cabinets & Storage > Media Storage > Media Cabinets -Furniture > Cabinets & Storage > Media Storage > Media Racks & Towers -Furniture > Cabinets & Storage > Pantries -Furniture > Cabinets & Storage > Storage Chests -Furniture > Cabinets & Storage > Storage Chests > Hope Chests -Furniture > Cabinets & Storage > Storage Chests > Toy Chests -Furniture > Cabinets & Storage > Vanities -Furniture > Cabinets & Storage > Vanities > Bathroom Vanities -Furniture > Cabinets & Storage > Vanities > Bedroom Vanities -Furniture > Cabinets & Storage > Wine & Liquor Cabinets -Furniture > Cabinets & Storage > Wine Racks -Furniture > Carts & Islands -Furniture > Carts & Islands > Kitchen & Dining Carts -Furniture > Carts & Islands > Kitchen Islands -Furniture > Chair Accessories -Furniture > Chairs -Furniture > Chairs > Arm Chairs, Recliners & Sleeper Chairs -Furniture > Chairs > Arm Chairs, Recliners & Sleeper Chairs > Arm Chairs -Furniture > Chairs > Arm Chairs, Recliners & Sleeper Chairs > Recliners -Furniture > Chairs > Arm Chairs, Recliners & Sleeper Chairs > Sleeper Chairs -Furniture > Chairs > Bar Stools -Furniture > Chairs > Bean Bag Chairs -Furniture > Chairs > Chaises -Furniture > Chairs > Electric Massaging Chairs -Furniture > Chairs > Folding Chairs & Stools -Furniture > Chairs > Gaming Chairs -Furniture > Chairs > Hanging Chairs -Furniture > Chairs > Kitchen & Dining Room Chairs -Furniture > Chairs > Rocking Chairs -Furniture > Chairs > Slipper Chairs -Furniture > Entertainment Centers & TV Stands -Furniture > Furniture Sets -Furniture > Furniture Sets > Bedroom Furniture Sets -Furniture > Furniture Sets > Kitchen & Dining Furniture Sets -Furniture > Furniture Sets > Living Room Furniture Sets -Furniture > Futon Frames -Furniture > Futon Pads -Furniture > Futons -Furniture > Office Furniture -Furniture > Office Furniture > Desk Hutches -Furniture > Office Furniture > Desks -Furniture > Office Furniture > Office Chair Accessories -Furniture > Office Furniture > Office Chairs -Furniture > Office Furniture > Office Chairs > Kneeling Chairs -Furniture > Office Furniture > Workspace Tables -Furniture > Office Furniture > Workspace Tables > Art & Drafting Tables -Furniture > Office Furniture > Workspace Tables > Conference Room Tables -Furniture > Office Furniture > Workstation & Cubicle Accessories -Furniture > Office Furniture > Workstations & Cubicles -Furniture > Ottomans -Furniture > Ottomans > Convertible Ottomans -Furniture > Ottomans > Glider Ottomans -Furniture > Ottomans > Storage Ottomans -Furniture > Outdoor Furniture -Furniture > Outdoor Furniture > Outdoor Beds -Furniture > Outdoor Furniture > Outdoor Furniture Sets -Furniture > Outdoor Furniture > Outdoor Ottomans -Furniture > Outdoor Furniture > Outdoor Seating -Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Benches -Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Chairs -Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Sofas -Furniture > Outdoor Furniture > Outdoor Seating > Sunloungers -Furniture > Outdoor Furniture > Outdoor Storage Boxes -Furniture > Outdoor Furniture > Outdoor Tables -Furniture > Outdoor Furniture Accessories -Furniture > Outdoor Furniture Accessories > Outdoor Furniture Covers -Furniture > Room Divider Accessories -Furniture > Room Dividers -Furniture > Shelving -Furniture > Shelving > Bookcases & Standing Shelves -Furniture > Shelving Accessories -Furniture > Shelving Accessories > Replacement Shelves -Furniture > Sofa Accessories -Furniture > Sofa Accessories > Chair & Sofa Supports -Furniture > Sofas -Furniture > Sofas > Loveseats -Furniture > Sofas > Sectional Sofas -Furniture > Sofas > Sofabeds -Furniture > Table Accessories -Furniture > Table Accessories > Table Legs -Furniture > Table Accessories > Table Tops -Furniture > Tables -Furniture > Tables > Accent Tables -Furniture > Tables > Accent Tables > Coffee Tables -Furniture > Tables > Accent Tables > End Tables -Furniture > Tables > Accent Tables > Sofa Tables -Furniture > Tables > Activity Tables -Furniture > Tables > Folding Tables -Furniture > Tables > Kitchen & Dining Room Tables -Furniture > Tables > Kitchen & Dining Room Tables > Hightop Tables -Furniture > Tables > Nightstands -Furniture > Tables > Poker & Game Tables -Furniture > Tables > Sewing Machine Tables -Hardware -Hardware > Adhesives, Coatings & Sealants -Hardware > Adhesives, Coatings & Sealants > Caulk -Hardware > Adhesives, Coatings & Sealants > Cements -Hardware > Adhesives, Coatings & Sealants > Coatings -Hardware > Adhesives, Coatings & Sealants > Glues -Hardware > Adhesives, Coatings & Sealants > Glues > Glitter Glue -Hardware > Adhesives, Coatings & Sealants > Glues > Glue Gun Sticks -Hardware > Adhesives, Coatings & Sealants > Glues > Glue Sticks -Hardware > Adhesives, Coatings & Sealants > Glues > Rubber Cement -Hardware > Adhesives, Coatings & Sealants > Glues > Super Glue -Hardware > Adhesives, Coatings & Sealants > Glues > White Glue -Hardware > Adhesives, Coatings & Sealants > Glues > Wood Glue -Hardware > Adhesives, Coatings & Sealants > Joint Compounds -Hardware > Adhesives, Coatings & Sealants > Sealants -Hardware > Building Materials -Hardware > Building Materials > Bricks, Stones & Concrete -Hardware > Building Materials > Carpets -Hardware > Building Materials > Countertops -Hardware > Building Materials > Countertops > Ceramic & Porcelain Countertops -Hardware > Building Materials > Countertops > Granite Countertops -Hardware > Building Materials > Countertops > Hardwood Countertops -Hardware > Building Materials > Countertops > Laminate Countertops -Hardware > Building Materials > Countertops > Marble Countertops -Hardware > Building Materials > Countertops > Vinyl Countertops -Hardware > Building Materials > Doors -Hardware > Building Materials > Doors > Garage Doors -Hardware > Building Materials > Doors > Home Doors -Hardware > Building Materials > Doors > Home Doors > Screen Doors -Hardware > Building Materials > Doors > Utility Doors -Hardware > Building Materials > Doors > Utility Doors > Pet Doors -Hardware > Building Materials > Flooring -Hardware > Building Materials > Flooring > Artificial Turf -Hardware > Building Materials > Flooring > Ceramic & Porcelain Flooring -Hardware > Building Materials > Flooring > Granite Flooring -Hardware > Building Materials > Flooring > Hardwood Flooring -Hardware > Building Materials > Flooring > Laminate Flooring -Hardware > Building Materials > Flooring > Marble Flooring -Hardware > Building Materials > Flooring > Rubber Flooring -Hardware > Building Materials > Flooring > Vinyl Flooring -Hardware > Building Materials > Glass -Hardware > Building Materials > Hatches -Hardware > Building Materials > Lumber -Hardware > Building Materials > Molding -Hardware > Building Materials > Shutters -Hardware > Building Materials > Sound Dampening Materials -Hardware > Building Materials > Staircases -Hardware > Building Materials > Tile -Hardware > Building Materials > Tile > Tile Countertops -Hardware > Building Materials > Tile > Tile Flooring -Hardware > Building Materials > Wall Paneling -Hardware > Building Materials > Windows -Hardware > Cabinetry -Hardware > Chemicals -Hardware > Chemicals > Acid Neutralizers -Hardware > Chemicals > Ammonia -Hardware > Chemicals > Chimney Cleaners -Hardware > Chemicals > Concrete & Masonry Cleaners -Hardware > Chemicals > De-icers -Hardware > Chemicals > Deck & Fence Cleaners -Hardware > Chemicals > Drain Cleaners -Hardware > Chemicals > Septic Tank & Cesspool Cleaners -Hardware > Electrical Supplies -Hardware > Electrical Supplies > Ballasts & Starters -Hardware > Electrical Supplies > Bypass Switches -Hardware > Electrical Supplies > Charge Controllers -Hardware > Electrical Supplies > Circuit Breaker Panels -Hardware > Electrical Supplies > Electrical Plug Caps -Hardware > Electrical Supplies > Electrical Switches -Hardware > Electrical Supplies > Electrical Switches > Light Switches -Hardware > Electrical Supplies > Electrical Timers -Hardware > Electrical Supplies > Electrical Wires -Hardware > Electrical Supplies > Extension Cord Accessories -Hardware > Electrical Supplies > Extension Cord Accessories > Extension Cord Connectors -Hardware > Electrical Supplies > Extension Cord Accessories > Extension Cord Reels & Winders -Hardware > Electrical Supplies > Extension Cords -Hardware > Electrical Supplies > Heat-Shrink Tubing -Hardware > Electrical Supplies > Mount Boxes & Brackets -Hardware > Electrical Supplies > Relays -Hardware > Electrical Supplies > Wall Plates -Hardware > Electrical Supplies > Wall Sockets -Hardware > Electrical Supplies > Wire Binding Spools -Hardware > Electrical Supplies > Wire Caps & Nuts -Hardware > Generators -Hardware > Hardware Accessories -Hardware > Hardware Accessories > Brackets -Hardware > Hardware Accessories > Bungee Cords -Hardware > Hardware Accessories > Cabinet Hardware -Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Backplates -Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Catches -Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Doors -Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Knobs & Handles -Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Locks -Hardware > Hardware Accessories > Chains -Hardware > Hardware Accessories > Coils -Hardware > Hardware Accessories > Concrete Molds -Hardware > Hardware Accessories > Controls -Hardware > Hardware Accessories > Controls > Control Panels -Hardware > Hardware Accessories > Controls > HVAC Controls -Hardware > Hardware Accessories > Controls > Thermostats -Hardware > Hardware Accessories > Door Hardware -Hardware > Hardware Accessories > Door Hardware > Door Bells & Chimes -Hardware > Hardware Accessories > Door Hardware > Door Closers -Hardware > Hardware Accessories > Door Hardware > Door Knobs & Handles -Hardware > Hardware Accessories > Door Hardware > Door Knockers -Hardware > Hardware Accessories > Door Hardware > Door Stops -Hardware > Hardware Accessories > Door Hardware > Door Strikes -Hardware > Hardware Accessories > Dowel Pins & Rods -Hardware > Hardware Accessories > Drop Cloths -Hardware > Hardware Accessories > Drywall Anchors -Hardware > Hardware Accessories > Filters & Screens -Hardware > Hardware Accessories > Flagging & Caution Tape -Hardware > Hardware Accessories > Gas Hoses -Hardware > Hardware Accessories > Hardware Tape -Hardware > Hardware Accessories > Hardware Tape > Copper Tape -Hardware > Hardware Accessories > Hardware Tape > Drywall Tape -Hardware > Hardware Accessories > Hardware Tape > Duct Tape -Hardware > Hardware Accessories > Hardware Tape > Electrical Tape -Hardware > Hardware Accessories > Hardware Tape > Foil Tape -Hardware > Hardware Accessories > Hardware Tape > Gaffers Tape -Hardware > Hardware Accessories > Hardware Tape > Heat Tape -Hardware > Hardware Accessories > Hardware Tape > Masking Tape -Hardware > Hardware Accessories > Hardware Tape > Teflon Tape -Hardware > Hardware Accessories > Hinges -Hardware > Hardware Accessories > Latches -Hardware > Hardware Accessories > Lubricants -Hardware > Hardware Accessories > Lubrication Hoses -Hardware > Hardware Accessories > Nails -Hardware > Hardware Accessories > Nuts & Bolts -Hardware > Hardware Accessories > Pneumatic Hoses -Hardware > Hardware Accessories > Pull Chains -Hardware > Hardware Accessories > Pulleys -Hardware > Hardware Accessories > Rivets -Hardware > Hardware Accessories > Rope -Hardware > Hardware Accessories > Screw Posts -Hardware > Hardware Accessories > Screws -Hardware > Hardware Accessories > Screws > Drywall Screws -Hardware > Hardware Accessories > Screws > Metal Screws -Hardware > Hardware Accessories > Screws > Wood Screws -Hardware > Hardware Accessories > Solder & Flux -Hardware > Hardware Accessories > Tarps -Hardware > Hardware Accessories > Tie Down Straps -Hardware > Hardware Accessories > Tool Storage & Organization -Hardware > Hardware Accessories > Tool Storage & Organization > Garden Hose Storage -Hardware > Hardware Accessories > Tool Storage & Organization > Tool & Duty Belts -Hardware > Hardware Accessories > Tool Storage & Organization > Tool Bags -Hardware > Hardware Accessories > Tool Storage & Organization > Tool Boxes -Hardware > Hardware Accessories > Tool Storage & Organization > Tool Cabinets & Chests -Hardware > Hardware Accessories > Tool Storage & Organization > Tool Sheaths -Hardware > Hardware Accessories > Tool Storage & Organization > Work Benches -Hardware > Hardware Accessories > Twine -Hardware > Hardware Accessories > Utility Wire -Hardware > Hardware Accessories > Vents & Flues -Hardware > Hardware Accessories > Washers -Hardware > Hardware Accessories > Wood Biscuits -Hardware > Hardware Torches -Hardware > Home Fencing -Hardware > Home Fencing > Fence Pickets -Hardware > Home Fencing > Fences -Hardware > Home Fencing > Fences > Wire Fencing -Hardware > Home Fencing > Fences > Wire Fencing > Barbed & Razor Wire -Hardware > Home Fencing > Fences > Wire Fencing > Chain Link Fencing -Hardware > Home Fencing > Fencing Posts -Hardware > Home Fencing > Gates -Hardware > Insulation -Hardware > Insulation > Building Insulation -Hardware > Insulation > Pipe Insulation -Hardware > Insulation > Window & Door Insulation -Hardware > Key Blanks -Hardware > Locks & Locksmithing -Hardware > Locks & Locksmithing > Cylinder Locks -Hardware > Locks & Locksmithing > Deadbolt Locks -Hardware > Locks & Locksmithing > Key Card Entry Systems -Hardware > Locks & Locksmithing > Padlocks -Hardware > Locks & Locksmithing > Pocket Door Locks -Hardware > Painting & Wall Covering Supplies -Hardware > Painting & Wall Covering Supplies > Finishes -Hardware > Painting & Wall Covering Supplies > Paint -Hardware > Painting & Wall Covering Supplies > Paint Binders -Hardware > Painting & Wall Covering Supplies > Paint Strippers -Hardware > Painting & Wall Covering Supplies > Primers -Hardware > Painting & Wall Covering Supplies > Solvents -Hardware > Painting & Wall Covering Supplies > Stains -Hardware > Painting & Wall Covering Supplies > Varnishes -Hardware > Painting & Wall Covering Supplies > Wallpaper -Hardware > Plumbing -Hardware > Plumbing > Ballcocks & Flappers -Hardware > Plumbing > Drain Accessories -Hardware > Plumbing > Drain Accessories > Drain Frames -Hardware > Plumbing > Drain Accessories > Drain Liners -Hardware > Plumbing > Drain Accessories > Drain Openers -Hardware > Plumbing > Drain Accessories > Drain Rods -Hardware > Plumbing > Drain Accessories > Plumbing Wastes -Hardware > Plumbing > Fuel Lines & Accessories -Hardware > Plumbing > Hoses -Hardware > Plumbing > Nozzles -Hardware > Plumbing > Plumbing Fittings -Hardware > Plumbing > Plumbing Fittings > Flanges -Hardware > Plumbing > Plumbing Fittings > Pipe Adaptors & Bushings -Hardware > Plumbing > Plumbing Fittings > Pipe Caps & Plugs -Hardware > Plumbing > Plumbing Fittings > Pipe Clamps -Hardware > Plumbing > Plumbing Fittings > Pipe Connectors -Hardware > Plumbing > Plumbing Fittings > Plumbing Gaskets -Hardware > Plumbing > Plumbing Fixtures -Hardware > Plumbing > Plumbing Fixtures > Bathtub Accessories -Hardware > Plumbing > Plumbing Fixtures > Bathtub Accessories > Bathtub Skirts -Hardware > Plumbing > Plumbing Fixtures > Bathtub Accessories > Bathtub Spouts -Hardware > Plumbing > Plumbing Fixtures > Bathtubs -Hardware > Plumbing > Plumbing Fixtures > Faucet Accessories -Hardware > Plumbing > Plumbing Fixtures > Faucets -Hardware > Plumbing > Plumbing Fixtures > Faucets > Pre-Rinse Faucets -Hardware > Plumbing > Plumbing Fixtures > Fixture Plates -Hardware > Plumbing > Plumbing Fixtures > Shower -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Arm Diverters -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Arm Mounts -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Bars -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Bases -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Columns -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Doors & Enclosures -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Heads -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Hoses -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Rods -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Stalls & Kits -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Walls & Surrounds -Hardware > Plumbing > Plumbing Fixtures > Shower > Shower Water Filters -Hardware > Plumbing > Plumbing Fixtures > Sink Accessories -Hardware > Plumbing > Plumbing Fixtures > Sink Accessories > Sink Legs -Hardware > Plumbing > Plumbing Fixtures > Sinks -Hardware > Plumbing > Plumbing Fixtures > Sinks > Bathroom Sinks -Hardware > Plumbing > Plumbing Fixtures > Sinks > Kitchen & Utility Sinks -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories > Toilet & Bidet Seats -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories > Toilet Seat Covers -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories > Toilet Seat Lid Covers -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories > Toilet Tank Covers -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories > Toilet Tank Levers -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories > Toilet Tanks -Hardware > Plumbing > Plumbing Fixtures > Toilet & Bidet Accessories > Toilet Trim -Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets -Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Bidets -Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Toilets -Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Urinals -Hardware > Plumbing > Plumbing Pipes -Hardware > Plumbing > Plumbing Pipes > Piping Nipples -Hardware > Plumbing > Plumbing Pipes > Push-Fit Pipes -Hardware > Plumbing > Plumbing Pipes > Steel Pipes -Hardware > Plumbing > Plumbing Pumps -Hardware > Plumbing > Plumbing Regulators -Hardware > Plumbing > Plumbing Stoppers -Hardware > Plumbing > Plumbing Taps -Hardware > Plumbing > Plumbing Taps > Gas Taps -Hardware > Plumbing > Plumbing Taps > Hose Bibbs -Hardware > Plumbing > Plumbing Taps > Water Taps -Hardware > Plumbing > Plumbing Valves -Hardware > Plumbing > Plumbing Valves > Ball Valves -Hardware > Plumbing > Repair Kits -Hardware > Plumbing > Repair Kits > Tube Repair Kits -Hardware > Plumbing > Thermocouples -Hardware > Plumbing > Traps & Strainers -Hardware > Plumbing > Traps & Strainers > Bath Traps -Hardware > Plumbing > Traps & Strainers > Bottle Traps -Hardware > Plumbing > Traps & Strainers > Shower Traps -Hardware > Plumbing > Tube Cleaners -Hardware > Plumbing > Water Dispensing & Filtration -Hardware > Plumbing > Water Dispensing & Filtration > In-Line Water Filters -Hardware > Plumbing > Water Dispensing & Filtration > In-Line Water Filters > Refrigerator Water Filters -Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers -Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Drinking Fountains -Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Water Chillers -Hardware > Plumbing > Water Dispensing & Filtration > Water Distillers -Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories -Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Cartridges -Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Housings -Hardware > Plumbing > Water Dispensing & Filtration > Water Softener Accessories -Hardware > Plumbing > Water Dispensing & Filtration > Water Softener Accessories > Water Softener Salt -Hardware > Plumbing > Water Dispensing & Filtration > Water Softeners -Hardware > Plumbing > Water Levelers -Hardware > Plumbing > Water Timers -Hardware > Plumbing > Well Supplies -Hardware > Renewable Energy -Hardware > Renewable Energy > Solar Energy -Hardware > Renewable Energy > Solar Energy > Solar Energy Kits -Hardware > Renewable Energy > Solar Energy > Solar Panels -Hardware > Renewable Energy > Wind Power -Hardware > Renewable Energy > Wind Power > Wind Turbines -Hardware > Roofing -Hardware > Roofing > Gutter Accessories -Hardware > Roofing > Gutters -Hardware > Roofing > Roof Flashings -Hardware > Shop Stools -Hardware > Storage Tanks -Hardware > Storage Tanks > Food Tanks -Hardware > Storage Tanks > Oil Tanks -Hardware > Storage Tanks > Water Tanks -Hardware > Tool Accessories -Hardware > Tool Accessories > Air Brush Accessories -Hardware > Tool Accessories > Axe Accessories -Hardware > Tool Accessories > Axe Accessories > Axe Heads -Hardware > Tool Accessories > Drill Accessories -Hardware > Tool Accessories > Drill Accessories > Drill Bit Extensions -Hardware > Tool Accessories > Drill Accessories > Drill Bit Sharpeners -Hardware > Tool Accessories > Drill Accessories > Drill Bits -Hardware > Tool Accessories > Drill Accessories > Hole Saws -Hardware > Tool Accessories > Driver Accessories -Hardware > Tool Accessories > Flashlight Accessories -Hardware > Tool Accessories > Generator Accessories -Hardware > Tool Accessories > Generator Accessories > Generator Covers -Hardware > Tool Accessories > Generator Accessories > Generator Replacement Parts -Hardware > Tool Accessories > Hammer Accessories -Hardware > Tool Accessories > Hammer Accessories > Air Hammer Accessories -Hardware > Tool Accessories > Hammer Accessories > Hammer Heads -Hardware > Tool Accessories > Hammer Accessories > Hammer Wedges -Hardware > Tool Accessories > Industrial Staples -Hardware > Tool Accessories > Jigs -Hardware > Tool Accessories > Magnetizers & Demagnetizers -Hardware > Tool Accessories > Measuring Tool & Sensor Accessories -Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Gas Detector Accessories -Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Metal & Voltage Detector Accessories -Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Multimeter Accessories -Hardware > Tool Accessories > Paint Tool Accessories -Hardware > Tool Accessories > Paint Tool Accessories > Paint Roller Accessories -Hardware > Tool Accessories > Power Tool Batteries -Hardware > Tool Accessories > Power Tool Chargers -Hardware > Tool Accessories > Router Accessories -Hardware > Tool Accessories > Router Accessories > Router Bits -Hardware > Tool Accessories > Router Accessories > Router Tables -Hardware > Tool Accessories > Sandblasting Accessories -Hardware > Tool Accessories > Sandblasting Accessories > Sandblasting Cabinets -Hardware > Tool Accessories > Sanding Accessories -Hardware > Tool Accessories > Sanding Accessories > Sandpaper & Sanding Sponges -Hardware > Tool Accessories > Saw Accessories -Hardware > Tool Accessories > Saw Accessories > Band Saw Accessories -Hardware > Tool Accessories > Saw Accessories > Handheld Circular Saw Accessories -Hardware > Tool Accessories > Saw Accessories > Jigsaw Accessories -Hardware > Tool Accessories > Saw Accessories > Miter Saw Accessories -Hardware > Tool Accessories > Saw Accessories > Table Saw Accessories -Hardware > Tool Accessories > Screwdriver Accessories -Hardware > Tool Accessories > Screwdriver Accessories > Screwdriver Tips -Hardware > Tool Accessories > Shaper Accessories -Hardware > Tool Accessories > Shaper Accessories > Shaper Cutters -Hardware > Tool Accessories > Soldering Iron Accessories -Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Stands -Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Tips -Hardware > Tool Accessories > Tool Blades -Hardware > Tool Accessories > Tool Blades > Saw Blades -Hardware > Tool Accessories > Tool Blades > Utility Knife Blades -Hardware > Tool Accessories > Tool Handles -Hardware > Tool Accessories > Tool Handles > Axe Handles -Hardware > Tool Accessories > Tool Handles > Hammer Handles -Hardware > Tool Accessories > Tool Sockets -Hardware > Tool Accessories > Tool Stands -Hardware > Tool Accessories > Tool Stands > Saw Stands -Hardware > Tools -Hardware > Tools > Anvils -Hardware > Tools > Awls -Hardware > Tools > Axes -Hardware > Tools > Benders -Hardware > Tools > Blowguns -Hardware > Tools > Brushes -Hardware > Tools > Brushes > Airbrushes -Hardware > Tools > Brushes > Chimney Brushes -Hardware > Tools > Brushes > Paint Brushes -Hardware > Tools > Brushes > Pipe Brushes -Hardware > Tools > Carpentry Jointers -Hardware > Tools > Carving Tools -Hardware > Tools > Carving Tools > Carving Spoons -Hardware > Tools > Carving Tools > Chisels -Hardware > Tools > Carving Tools > Gouges -Hardware > Tools > Carving Tools > Wood Carving Knives -Hardware > Tools > Caulking Tools -Hardware > Tools > Caulking Tools > Caulking Guns -Hardware > Tools > Caulking Tools > Caulking Irons -Hardware > Tools > Caulking Tools > Caulking Mallets -Hardware > Tools > Compactors -Hardware > Tools > Compressors -Hardware > Tools > Compressors > Air Compressors -Hardware > Tools > Compressors > Gas Compressors -Hardware > Tools > Concrete Brooms -Hardware > Tools > Crowbars -Hardware > Tools > Cutters -Hardware > Tools > Cutters > Bolt Cutters -Hardware > Tools > Cutters > Glass Cutters -Hardware > Tools > Cutters > Nibblers -Hardware > Tools > Cutters > Nippers -Hardware > Tools > Cutters > Pipe Cutters -Hardware > Tools > Cutters > Rebar Cutters -Hardware > Tools > Cutters > Tile & Shingle Cutters -Hardware > Tools > Cutters > Utility Knives -Hardware > Tools > Deburrers -Hardware > Tools > Die Sets -Hardware > Tools > Dollies & Hand Trucks -Hardware > Tools > Drills -Hardware > Tools > Drills > Augers -Hardware > Tools > Drills > Drill Presses -Hardware > Tools > Drills > Handheld Power Drills -Hardware > Tools > Drills > Mortisers -Hardware > Tools > Drills > Pneumatic Drills -Hardware > Tools > Electrician Fish Tape -Hardware > Tools > Flashlights -Hardware > Tools > Flashlights > Headlamps -Hardware > Tools > Glue Guns -Hardware > Tools > Grease Guns -Hardware > Tools > Grinders -Hardware > Tools > Grips -Hardware > Tools > Hammering -Hardware > Tools > Hammering > Air Hammers -Hardware > Tools > Hammering > Automatic Hammers -Hardware > Tools > Hammering > Hammers -Hardware > Tools > Hammering > Hammers > Mallets -Hardware > Tools > Hammering > Hammers > Sledgehammers -Hardware > Tools > Hammering > Jackhammers -Hardware > Tools > Hardware Shears -Hardware > Tools > Heat Guns -Hardware > Tools > Hoisting -Hardware > Tools > Hoisting > Air Casters -Hardware > Tools > Hoisting > Buckhoists -Hardware > Tools > Hoisting > Chainhoists -Hardware > Tools > Hoisting > Jack Lifts -Hardware > Tools > Hoisting > Pallet Jacks -Hardware > Tools > Hoisting > Wire Hoists -Hardware > Tools > Impact Wrenches & Drivers -Hardware > Tools > Industrial Vibrators -Hardware > Tools > Inspection Mirrors -Hardware > Tools > Ladders & Scaffolding -Hardware > Tools > Ladders & Scaffolding > Ladder Carts -Hardware > Tools > Ladders & Scaffolding > Ladders -Hardware > Tools > Ladders & Scaffolding > Ladders > Aluminum Ladders -Hardware > Tools > Ladders & Scaffolding > Ladders > Wooden Ladders -Hardware > Tools > Ladders & Scaffolding > Scaffolding -Hardware > Tools > Ladders & Scaffolding > Step Stools -Hardware > Tools > Ladders & Scaffolding > Work Platforms -Hardware > Tools > Lathes -Hardware > Tools > Lifting Magnets -Hardware > Tools > Light Bulb Changers -Hardware > Tools > Log Splitters -Hardware > Tools > Marking Tools -Hardware > Tools > Marking Tools > Carpenter Crayons & Pencils -Hardware > Tools > Marking Tools > Chalk Lines -Hardware > Tools > Marking Tools > Marking Chisels -Hardware > Tools > Marking Tools > Marking Knives -Hardware > Tools > Masonry Tools -Hardware > Tools > Masonry Tools > Brick Tools -Hardware > Tools > Masonry Tools > Cement Mixers -Hardware > Tools > Masonry Tools > Construction Lines -Hardware > Tools > Masonry Tools > Edgers -Hardware > Tools > Masonry Tools > Floats -Hardware > Tools > Masonry Tools > Grout Sponges -Hardware > Tools > Masonry Tools > Masonry Jointers -Hardware > Tools > Masonry Tools > Masonry Trowels -Hardware > Tools > Masonry Tools > Power Trowels -Hardware > Tools > Measuring Tools & Sensors -Hardware > Tools > Measuring Tools & Sensors > Air Quality Meters -Hardware > Tools > Measuring Tools & Sensors > Altimeters -Hardware > Tools > Measuring Tools & Sensors > Barometers -Hardware > Tools > Measuring Tools & Sensors > Cable Testers -Hardware > Tools > Measuring Tools & Sensors > Calipers -Hardware > Tools > Measuring Tools & Sensors > Cruising Rods -Hardware > Tools > Measuring Tools & Sensors > Diagnostic Thermal Cameras -Hardware > Tools > Measuring Tools & Sensors > Distance Meters -Hardware > Tools > Measuring Tools & Sensors > Dividers -Hardware > Tools > Measuring Tools & Sensors > Flow Meters & Controllers -Hardware > Tools > Measuring Tools & Sensors > Gas Detectors -Hardware > Tools > Measuring Tools & Sensors > Gauges -Hardware > Tools > Measuring Tools & Sensors > Geiger Counters -Hardware > Tools > Measuring Tools & Sensors > Hygrometers -Hardware > Tools > Measuring Tools & Sensors > Knife Guides -Hardware > Tools > Measuring Tools & Sensors > Leak Detectors -Hardware > Tools > Measuring Tools & Sensors > Levels -Hardware > Tools > Measuring Tools & Sensors > Levels > Bubble Levels -Hardware > Tools > Measuring Tools & Sensors > Levels > Laser Levels -Hardware > Tools > Measuring Tools & Sensors > Levels > Sight Levels -Hardware > Tools > Measuring Tools & Sensors > Measuring Wheels -Hardware > Tools > Measuring Tools & Sensors > Metal & Voltage Detectors -Hardware > Tools > Measuring Tools & Sensors > Moisture Meters -Hardware > Tools > Measuring Tools & Sensors > Multimeters -Hardware > Tools > Measuring Tools & Sensors > Pipe Locators -Hardware > Tools > Measuring Tools & Sensors > Pressure Sensors & Transducers -Hardware > Tools > Measuring Tools & Sensors > Probes & Finders -Hardware > Tools > Measuring Tools & Sensors > Protractors -Hardware > Tools > Measuring Tools & Sensors > Rebar Locators -Hardware > Tools > Measuring Tools & Sensors > Rulers -Hardware > Tools > Measuring Tools & Sensors > Scales -Hardware > Tools > Measuring Tools & Sensors > Seismometer -Hardware > Tools > Measuring Tools & Sensors > Sound Meters -Hardware > Tools > Measuring Tools & Sensors > Squares -Hardware > Tools > Measuring Tools & Sensors > Straight Edges -Hardware > Tools > Measuring Tools & Sensors > Stud Sensors -Hardware > Tools > Measuring Tools & Sensors > Tape Measures -Hardware > Tools > Measuring Tools & Sensors > Theodolites -Hardware > Tools > Measuring Tools & Sensors > Thermometers -Hardware > Tools > Measuring Tools & Sensors > Thermometers > Infrared Thermometers -Hardware > Tools > Measuring Tools & Sensors > UV Light Meters -Hardware > Tools > Measuring Tools & Sensors > Vibration Meters -Hardware > Tools > Measuring Tools & Sensors > Weather Forecasters & Stations -Hardware > Tools > Measuring Tools & Sensors > Wire Locators -Hardware > Tools > Measuring Tools & Sensors > pH Meters -Hardware > Tools > Milling Machines -Hardware > Tools > Multifunction Power Tools -Hardware > Tools > Nail Pullers -Hardware > Tools > Nailers & Staplers -Hardware > Tools > Oil Filter Drains -Hardware > Tools > Paint Tools -Hardware > Tools > Paint Tools > Paint Edgers -Hardware > Tools > Paint Tools > Paint Rollers -Hardware > Tools > Paint Tools > Paint Sponges -Hardware > Tools > Paint Tools > Paint Sprayers -Hardware > Tools > Paint Tools > Paint Stripper -Hardware > Tools > Paint Tools > Paint Trays -Hardware > Tools > Pickup Tools -Hardware > Tools > Pickup Tools > Utility Tweezers -Hardware > Tools > Planers -Hardware > Tools > Planes -Hardware > Tools > Pliers -Hardware > Tools > Plungers -Hardware > Tools > Polishers & Buffers -Hardware > Tools > Post Hole Diggers -Hardware > Tools > Punches -Hardware > Tools > Putty Knives & Scrapers -Hardware > Tools > Reamers -Hardware > Tools > Riveting Tools -Hardware > Tools > Riveting Tools > Rivet Guns -Hardware > Tools > Riveting Tools > Rivet Pliers -Hardware > Tools > Routing Tools -Hardware > Tools > Sandblasters -Hardware > Tools > Sanders -Hardware > Tools > Sanding Blocks -Hardware > Tools > Saw Horses -Hardware > Tools > Saws -Hardware > Tools > Saws > Band Saws -Hardware > Tools > Saws > Cut-Off Saws -Hardware > Tools > Saws > Hacksaws -Hardware > Tools > Saws > Hand Saws -Hardware > Tools > Saws > Handheld Circular Saws -Hardware > Tools > Saws > Jig Saws -Hardware > Tools > Saws > Masonry & Tile Saws -Hardware > Tools > Saws > Miter Saws -Hardware > Tools > Saws > Reciprocating Saws -Hardware > Tools > Saws > Scroll Saws -Hardware > Tools > Saws > Table Saws -Hardware > Tools > Screwdrivers -Hardware > Tools > Screwdrivers > Manual Screwdrivers -Hardware > Tools > Screwdrivers > Power Screwdrivers -Hardware > Tools > Shapers -Hardware > Tools > Sharpeners -Hardware > Tools > Sharpeners > Chainsaw Sharpeners -Hardware > Tools > Sharpeners > Sharpening Stones -Hardware > Tools > Socket Drivers -Hardware > Tools > Soldering Irons -Hardware > Tools > Tap Reseaters -Hardware > Tools > Threading Machines -Hardware > Tools > Tool Clamps -Hardware > Tools > Tool Clamps > Vise Clamps -Hardware > Tools > Tool Files -Hardware > Tools > Tool Keys -Hardware > Tools > Tool Keys > Manhole Keys -Hardware > Tools > Tool Keys > Radiator Keys -Hardware > Tools > Tool Keys > Stopcock Keys -Hardware > Tools > Tool Knives -Hardware > Tools > Tool Knives > Sheetrock Knives -Hardware > Tools > Tool Sets -Hardware > Tools > Tool Sets > Hand Tool Sets -Hardware > Tools > Tool Sets > Power Tool Combo Sets -Hardware > Tools > Welding Tools -Hardware > Tools > Wire & Cable Hand Tools -Hardware > Tools > Wire & Cable Hand Tools > Cable Slitters -Hardware > Tools > Wire & Cable Hand Tools > Snippers -Hardware > Tools > Wire & Cable Hand Tools > Wire Crimpers -Hardware > Tools > Wire & Cable Hand Tools > Wire Cutters -Hardware > Tools > Wire & Cable Hand Tools > Wire Strippers -Hardware > Tools > Work Lights -Hardware > Tools > Wrenches -Hardware > Tools > Wrenches > Hex Keys -Hardware > Tools > Wrenches > Socket Wrenches -Health & Beauty -Health & Beauty > Health Care -Health & Beauty > Health Care > Acupuncture -Health & Beauty > Health Care > Acupuncture > Acupuncture Models -Health & Beauty > Health Care > Acupuncture > Acupuncture Needles -Health & Beauty > Health Care > Arthritis Care -Health & Beauty > Health Care > Bed Pans -Health & Beauty > Health Care > Biometric Monitor Accessories -Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories -Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Control Solution -Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Test Strips -Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Lancing Devices -Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories -Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories > Blood Pressure Monitor Cuffs -Health & Beauty > Health Care > Biometric Monitor Accessories > Body Weight Scale Accessories -Health & Beauty > Health Care > Biometric Monitor Accessories > Fertility Monitor Accessories -Health & Beauty > Health Care > Biometric Monitor Accessories > Heart Rate Monitor Accessories -Health & Beauty > Health Care > Biometric Monitors -Health & Beauty > Health Care > Biometric Monitors > Blood Glucose Meters -Health & Beauty > Health Care > Biometric Monitors > Blood Pressure Monitors -Health & Beauty > Health Care > Biometric Monitors > Body Fat Analyzers -Health & Beauty > Health Care > Biometric Monitors > Body Weight Scales -Health & Beauty > Health Care > Biometric Monitors > Breathalyzers -Health & Beauty > Health Care > Biometric Monitors > Cholesterol Analyzers -Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors -Health & Beauty > Health Care > Biometric Monitors > Heart Rate Monitors -Health & Beauty > Health Care > Biometric Monitors > Medical Thermometers -Health & Beauty > Health Care > Biometric Monitors > Pedometers -Health & Beauty > Health Care > Biometric Monitors > Prenatal Heart Monitors -Health & Beauty > Health Care > Biometric Monitors > Pulse Oximeters -Health & Beauty > Health Care > Blood Typing Test Kits -Health & Beauty > Health Care > CPAP Equipment -Health & Beauty > Health Care > CPAP Equipment > CPAP Machines -Health & Beauty > Health Care > CPAP Equipment > CPAP Masks -Health & Beauty > Health Care > Contraceptive Cases -Health & Beauty > Health Care > Contraceptives -Health & Beauty > Health Care > Contraceptives > Condoms -Health & Beauty > Health Care > Contraceptives > Spermicides -Health & Beauty > Health Care > Diabetes Care -Health & Beauty > Health Care > Drug Tests -Health & Beauty > Health Care > First Aid -Health & Beauty > Health Care > First Aid > Antiseptics & Cleaning Supplies -Health & Beauty > Health Care > First Aid > Cast & Bandage Protectors -Health & Beauty > Health Care > First Aid > Eye Wash Supplies -Health & Beauty > Health Care > First Aid > First Aid Kits -Health & Beauty > Health Care > First Aid > Heat Rubs -Health & Beauty > Health Care > First Aid > Hot & Cold Therapies -Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Heating Pads -Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Ice Packs -Health & Beauty > Health Care > First Aid > Medical Tape & Bandages -Health & Beauty > Health Care > First Aid > Rash & Anti-Itch Treatments -Health & Beauty > Health Care > Fitness & Nutrition -Health & Beauty > Health Care > Fitness & Nutrition > Diet Pills -Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Bars -Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Drinks & Shakes -Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Gels & Chews -Health & Beauty > Health Care > Fitness & Nutrition > Nutritional Food Purées -Health & Beauty > Health Care > Fitness & Nutrition > Protein Powder -Health & Beauty > Health Care > Fitness & Nutrition > Traditional Chinese Tonics -Health & Beauty > Health Care > Fitness & Nutrition > Tube Feeding Supplements -Health & Beauty > Health Care > Fitness & Nutrition > Vitamins & Supplements -Health & Beauty > Health Care > HIV Tests -Health & Beauty > Health Care > Hearing Aids -Health & Beauty > Health Care > Hearing Enhancers -Health & Beauty > Health Care > Incontinence Aids -Health & Beauty > Health Care > Medical Alarm Systems -Health & Beauty > Health Care > Medical Identification Tags & Jewelry -Health & Beauty > Health Care > Medicine & Drugs -Health & Beauty > Health Care > Medicine & Drugs > OTC Drugs -Health & Beauty > Health Care > Medicine & Drugs > OTC Drugs > Allergies & Sinus -Health & Beauty > Health Care > Medicine & Drugs > OTC Drugs > Cough, Cold & Flu -Health & Beauty > Health Care > Medicine & Drugs > OTC Drugs > Gastrointestinal Treatments -Health & Beauty > Health Care > Medicine & Drugs > OTC Drugs > Pain Relievers -Health & Beauty > Health Care > Medicine & Drugs > OTC Drugs > Sleeping Medication -Health & Beauty > Health Care > Mobility & Accessibility -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Mobility Scooters -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Stair Lifts -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Wheelchairs -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Wheelchairs > Manual Wheelchairs -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Wheelchairs > Powered Wheelchairs -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment Accessories -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures -Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures > Shower Benches & Seats -Health & Beauty > Health Care > Mobility & Accessibility > Walking Aid Accessories -Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids -Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Canes & Walking Sticks -Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Crutches -Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Walkers -Health & Beauty > Health Care > Physical Therapy Equipment -Health & Beauty > Health Care > Physical Therapy Equipment > Hand Exercisers -Health & Beauty > Health Care > Pregnancy Tests -Health & Beauty > Health Care > Respiratory Care -Health & Beauty > Health Care > Respiratory Care > Nebulizers -Health & Beauty > Health Care > Smoking Cessation -Health & Beauty > Health Care > Supports & Braces -Health & Beauty > Health Care > Surgical Lubricants -Health & Beauty > Jewelry Cleaning & Care -Health & Beauty > Jewelry Cleaning & Care > Jewelry Cleaners -Health & Beauty > Jewelry Cleaning & Care > Jewelry Holders -Health & Beauty > Personal Care -Health & Beauty > Personal Care > Back Care -Health & Beauty > Personal Care > Back Care > Back & Lumbar Support Cushions -Health & Beauty > Personal Care > Cosmetics -Health & Beauty > Personal Care > Cosmetics > Bath & Body -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bar Soap -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Additives -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Brushes -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Sponges & Loofahs -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Body Wash -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Hand Sanitizers & Wipes -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Liquid Hand Soap -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Powdered Hand Soap -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Shower Caps -Health & Beauty > Personal Care > Cosmetics > Bath & Body > Wet Wipes -Health & Beauty > Personal Care > Cosmetics > Bath & Body Gift Sets -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tool Cleaners -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Double Eyelid Glue & Tape -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyebrow Stencils -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curler Refills -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curlers -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Face Mirrors -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Facial Blotting Paper -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Adhesive -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Applicators -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Brushes -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Sponges -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Pushers -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Scissors -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Manicure Tool Sets -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Buffers -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Clippers -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Drills -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Dryers -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Files & Emery Boards -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Pedicure Toe Seperators -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Facial Saunas -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Foot Files -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Pumice Stones -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Extractors -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Rollers -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Cleansing Brushes & Systems -Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Tweezers -Health & Beauty > Personal Care > Cosmetics > Makeup -Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup -Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body & Hair Glitter -Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body Paint & Foundation -Health & Beauty > Personal Care > Cosmetics > Makeup > Costume & Stage Makeup -Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup -Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eye Shadow & Primer -Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyebrow Enhancers -Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyelash Growth Treatments -Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyeliner -Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > False Eyelashes -Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Mascara -Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup -Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Blushes & Bronzers -Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Face Powder -Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Foundations & Concealers -Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Highlighters & Luminizers -Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup -Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip & Cheek Stains -Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Gloss -Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Liner -Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lipstick -Health & Beauty > Personal Care > Cosmetics > Makeup > Makeup Finishing Sprays -Health & Beauty > Personal Care > Cosmetics > Makeup > Makeup Sets -Health & Beauty > Personal Care > Cosmetics > Makeup > Temporary Tattoos -Health & Beauty > Personal Care > Cosmetics > Nail Care -Health & Beauty > Personal Care > Cosmetics > Nail Care > Cuticle Cream & Oil -Health & Beauty > Personal Care > Cosmetics > Nail Care > False Nails -Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Art Kits & Accessories -Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Glue -Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Removers -Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Thinners -Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polishes -Health & Beauty > Personal Care > Cosmetics > Perfume & Cologne -Health & Beauty > Personal Care > Cosmetics > Skin Care -Health & Beauty > Personal Care > Cosmetics > Skin Care > Acne Treatments & Kits -Health & Beauty > Personal Care > Cosmetics > Skin Care > Anti-Aging Skin Care Kits -Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Oil -Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Powder -Health & Beauty > Personal Care > Cosmetics > Skin Care > Compressed Skin Care Mask Sheets -Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansers -Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansing Kits -Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Pore Strips -Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments -Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer -Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer > Body Lotion -Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer > Face Lotion -Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer > Foot Lotion -Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer > Hand Lotion -Health & Beauty > Personal Care > Cosmetics > Skin Care > Makeup Removers -Health & Beauty > Personal Care > Cosmetics > Skin Care > Petroleum Jelly -Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Care Masks & Peels -Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Insect Repellent -Health & Beauty > Personal Care > Cosmetics > Skin Care > Sunscreen -Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products -Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Self Tanner -Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Self Tanner Applicators & Removers -Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Tanning Oil & Lotion -Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents -Health & Beauty > Personal Care > Cotton Balls -Health & Beauty > Personal Care > Cotton Swabs -Health & Beauty > Personal Care > Deodorant & Anti-Perspirant -Health & Beauty > Personal Care > Ear Care -Health & Beauty > Personal Care > Ear Care > Ear Candles -Health & Beauty > Personal Care > Ear Care > Ear Drops -Health & Beauty > Personal Care > Ear Care > Ear Dryers -Health & Beauty > Personal Care > Ear Care > Ear Syringes -Health & Beauty > Personal Care > Ear Care > Ear Wax Removal Kits -Health & Beauty > Personal Care > Ear Care > Earplug Dispensers -Health & Beauty > Personal Care > Ear Care > Earplugs -Health & Beauty > Personal Care > Enema Kits & Supplies -Health & Beauty > Personal Care > Feminine Sanitary Supplies -Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Deodorant -Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Douches & Washes -Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Pads & Protectors -Health & Beauty > Personal Care > Feminine Sanitary Supplies > Tampons -Health & Beauty > Personal Care > Foot Care -Health & Beauty > Personal Care > Foot Care > Antifungal Treatments -Health & Beauty > Personal Care > Foot Care > Bunion Care -Health & Beauty > Personal Care > Foot Care > Corn & Callus Care -Health & Beauty > Personal Care > Foot Care > Foot Odor Removers -Health & Beauty > Personal Care > Foot Care > Insoles & Inserts -Health & Beauty > Personal Care > Foot Care > Toe Spacers -Health & Beauty > Personal Care > Hair Care -Health & Beauty > Personal Care > Hair Care > Hair Color -Health & Beauty > Personal Care > Hair Care > Hair Color Removers -Health & Beauty > Personal Care > Hair Care > Hair Coloring Accessories -Health & Beauty > Personal Care > Hair Care > Hair Loss Concealers -Health & Beauty > Personal Care > Hair Care > Hair Loss Treatments -Health & Beauty > Personal Care > Hair Care > Hair Permanents & Straighteners -Health & Beauty > Personal Care > Hair Care > Hair Shears -Health & Beauty > Personal Care > Hair Care > Hair Steamers & Heat Caps -Health & Beauty > Personal Care > Hair Care > Hair Styling Products -Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories -Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Curler Clips & Pins -Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Dryer Accessories -Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Iron Accessories -Health & Beauty > Personal Care > Hair Care > Hair Styling Tools -Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Combs & Brushes -Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Curling Irons -Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Curlers -Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Dryers -Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Straighteners -Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner -Health & Beauty > Personal Care > Massage & Relaxation -Health & Beauty > Personal Care > Massage & Relaxation > Massage Chairs -Health & Beauty > Personal Care > Massage & Relaxation > Massage Oil -Health & Beauty > Personal Care > Massage & Relaxation > Massage Tables -Health & Beauty > Personal Care > Massage & Relaxation > Massagers -Health & Beauty > Personal Care > Oral Care -Health & Beauty > Personal Care > Oral Care > Breath Spray -Health & Beauty > Personal Care > Oral Care > Dental Floss -Health & Beauty > Personal Care > Oral Care > Dental Water Jet Replacement Tips -Health & Beauty > Personal Care > Oral Care > Dental Water Jets -Health & Beauty > Personal Care > Oral Care > Denture Adhesives -Health & Beauty > Personal Care > Oral Care > Denture Cleaners -Health & Beauty > Personal Care > Oral Care > Dentures -Health & Beauty > Personal Care > Oral Care > Gum Stimulators -Health & Beauty > Personal Care > Oral Care > Mouthguards -Health & Beauty > Personal Care > Oral Care > Mouthwash -Health & Beauty > Personal Care > Oral Care > Oral Pain Relievers -Health & Beauty > Personal Care > Oral Care > Power Flossers -Health & Beauty > Personal Care > Oral Care > Teeth Whitening -Health & Beauty > Personal Care > Oral Care > Tongue Scrapers -Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories -Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Covers -Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Replacement Heads -Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Sanitizers -Health & Beauty > Personal Care > Oral Care > Toothbrushes -Health & Beauty > Personal Care > Oral Care > Toothpaste -Health & Beauty > Personal Care > Oral Care > Toothpaste Squeezers & Dispensers -Health & Beauty > Personal Care > Oral Care > Toothpicks -Health & Beauty > Personal Care > Personal Lubricants -Health & Beauty > Personal Care > Shaving & Grooming -Health & Beauty > Personal Care > Shaving & Grooming > Aftershave -Health & Beauty > Personal Care > Shaving & Grooming > Electric Razor Accessories -Health & Beauty > Personal Care > Shaving & Grooming > Electric Razors -Health & Beauty > Personal Care > Shaving & Grooming > Hair Clipper & Trimmer Accessories -Health & Beauty > Personal Care > Shaving & Grooming > Hair Clippers & Trimmers -Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal -Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Depilatories -Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Electrolysis Devices -Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Epilators -Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Laser Hair Removal Devices -Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Waxing Kits -Health & Beauty > Personal Care > Shaving & Grooming > Razors & Razor Blades -Health & Beauty > Personal Care > Shaving & Grooming > Shaving Brushes -Health & Beauty > Personal Care > Shaving & Grooming > Shaving Cream -Health & Beauty > Personal Care > Shaving & Grooming > Shaving Kits -Health & Beauty > Personal Care > Shaving & Grooming > Styptic Pencils -Health & Beauty > Personal Care > Sleeping Aids -Health & Beauty > Personal Care > Sleeping Aids > Sleep Masks -Health & Beauty > Personal Care > Sleeping Aids > Snoring & Sleep Apnea Aids -Health & Beauty > Personal Care > Sleeping Aids > Travel Pillows -Health & Beauty > Personal Care > Sleeping Aids > White Noise Machines -Health & Beauty > Personal Care > Spray Tanning Tents -Health & Beauty > Personal Care > Tanning Beds -Health & Beauty > Personal Care > Vision Care -Health & Beauty > Personal Care > Vision Care > Contact Lens Care -Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Care Kits -Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Cases -Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Solution -Health & Beauty > Personal Care > Vision Care > Contact Lenses -Health & Beauty > Personal Care > Vision Care > Eye Drops & Lubricants -Health & Beauty > Personal Care > Vision Care > Eyeglass Accessories -Health & Beauty > Personal Care > Vision Care > Eyeglass Accessories > Eyeglass Cases & Holders -Health & Beauty > Personal Care > Vision Care > Eyeglass Lenses -Health & Beauty > Personal Care > Vision Care > Eyeglasses -Health & Beauty > Personal Care > Vision Care > Sunglass Lenses -Health & Beauty > Personal Care > Wart Removers -Home & Garden -Home & Garden > Bathroom Accessories -Home & Garden > Bathroom Accessories > Bath Caddies -Home & Garden > Bathroom Accessories > Bath Mats & Rugs -Home & Garden > Bathroom Accessories > Bath Pillows -Home & Garden > Bathroom Accessories > Bathroom Accessory Mounts -Home & Garden > Bathroom Accessories > Bathroom Accessory Sets -Home & Garden > Bathroom Accessories > Facial Tissue Holders -Home & Garden > Bathroom Accessories > Hand Dryer Accessories -Home & Garden > Bathroom Accessories > Hand Dryers -Home & Garden > Bathroom Accessories > Medicine Cabinets -Home & Garden > Bathroom Accessories > Robe Hooks -Home & Garden > Bathroom Accessories > Shower Curtain Rings -Home & Garden > Bathroom Accessories > Shower Curtains -Home & Garden > Bathroom Accessories > Soap & Lotion Dispensers -Home & Garden > Bathroom Accessories > Soap Dishes & Holders -Home & Garden > Bathroom Accessories > Toilet Brush Replacement Heads -Home & Garden > Bathroom Accessories > Toilet Brushes -Home & Garden > Bathroom Accessories > Toilet Paper Holders -Home & Garden > Bathroom Accessories > Toothbrush Holders -Home & Garden > Bathroom Accessories > Towel Racks & Holders -Home & Garden > Decor -Home & Garden > Decor > Address Signs -Home & Garden > Decor > Artificial Flora -Home & Garden > Decor > Artificial Flora > Artificial Flowers -Home & Garden > Decor > Artificial Flora > Artificial Plants -Home & Garden > Decor > Artificial Flora > Artificial Topiaries -Home & Garden > Decor > Artificial Flora > Artificial Trees -Home & Garden > Decor > Artificial Food -Home & Garden > Decor > Backrest Pillows -Home & Garden > Decor > Backyard Feeders -Home & Garden > Decor > Backyard Feeders > Bird Feeders -Home & Garden > Decor > Backyard Feeders > Butterfly Feeders -Home & Garden > Decor > Backyard Feeders > Squirrel Feeders -Home & Garden > Decor > Baskets -Home & Garden > Decor > Bird Baths -Home & Garden > Decor > Bird Feeder Accessories -Home & Garden > Decor > Birdhouses -Home & Garden > Decor > Bookends -Home & Garden > Decor > Candle & Oil Warmers -Home & Garden > Decor > Candle Holders -Home & Garden > Decor > Candle Holders > Menorahs -Home & Garden > Decor > Candles -Home & Garden > Decor > Candles > Hanukkah Candles -Home & Garden > Decor > Candles > Unity Candles -Home & Garden > Decor > Chair & Sofa Cushions -Home & Garden > Decor > Clocks -Home & Garden > Decor > Clocks > Alarm Clocks -Home & Garden > Decor > Clocks > Alarm Clocks > Clock Radios -Home & Garden > Decor > Clocks > Alarm Clocks > Portable Alarm Clocks -Home & Garden > Decor > Clocks > Desk & Shelf Clocks -Home & Garden > Decor > Clocks > Floor & Grandfather Clocks -Home & Garden > Decor > Clocks > Wall Clocks -Home & Garden > Decor > Clocks > Wall Clocks > Cuckoo Clocks -Home & Garden > Decor > Coat & Hat Racks -Home & Garden > Decor > Decorative Bells -Home & Garden > Decor > Decorative Bottles -Home & Garden > Decor > Decorative Bowls -Home & Garden > Decor > Decorative Jars -Home & Garden > Decor > Decorative Plaques -Home & Garden > Decor > Decorative Plates -Home & Garden > Decor > Decorative Trays -Home & Garden > Decor > Door Mats -Home & Garden > Decor > Dreamcatchers -Home & Garden > Decor > Dried Flowers -Home & Garden > Decor > Ecospheres -Home & Garden > Decor > Figurines -Home & Garden > Decor > Finials -Home & Garden > Decor > Flag & Windsock Accessories -Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Pole Lights -Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Poles -Home & Garden > Decor > Flags & Windsocks -Home & Garden > Decor > Flameless Candles -Home & Garden > Decor > Fountains & Ponds -Home & Garden > Decor > Fountains & Ponds > Fountain & Pond Accessories -Home & Garden > Decor > Fountains & Ponds > Fountains -Home & Garden > Decor > Fountains & Ponds > Fountains > Indoor Fountains -Home & Garden > Decor > Fountains & Ponds > Fountains > Outdoor Fountains -Home & Garden > Decor > Fountains & Ponds > Ponds -Home & Garden > Decor > Garden & Stepping Stones -Home & Garden > Decor > Garden Sculptures -Home & Garden > Decor > Home Fragrances -Home & Garden > Decor > Home Fragrances > Air Fresheners -Home & Garden > Decor > Home Fragrances > Fragrance Oil -Home & Garden > Decor > Home Fragrances > Incense -Home & Garden > Decor > Home Fragrances > Incense Holders -Home & Garden > Decor > Home Fragrances > Potpourri -Home & Garden > Decor > House Numbers & Letters -Home & Garden > Decor > Lawn Ornaments -Home & Garden > Decor > Lawn Ornaments > Gazing Globes -Home & Garden > Decor > Mail Slots -Home & Garden > Decor > Mailbox Accessories -Home & Garden > Decor > Mailbox Accessories > Mailbox Covers -Home & Garden > Decor > Mailbox Accessories > Mailbox Enclosures -Home & Garden > Decor > Mailbox Accessories > Mailbox Flags -Home & Garden > Decor > Mailbox Accessories > Mailbox Mounting Brackets -Home & Garden > Decor > Mailbox Accessories > Mailbox Posts -Home & Garden > Decor > Mailbox Accessories > Mailbox Replacement Doors -Home & Garden > Decor > Mailboxes -Home & Garden > Decor > Mirrors -Home & Garden > Decor > Music Boxes -Home & Garden > Decor > Napkin Rings -Home & Garden > Decor > Novelty Signs -Home & Garden > Decor > Ottoman Cushions -Home & Garden > Decor > Picture Frames -Home & Garden > Decor > Picture Frames > Digital Picture Frames -Home & Garden > Decor > Picture Frames > Poster Frames -Home & Garden > Decor > Piggy Banks & Money Jars -Home & Garden > Decor > Rain Chains -Home & Garden > Decor > Rain Gauges -Home & Garden > Decor > Refrigerator Magnets -Home & Garden > Decor > Rugs -Home & Garden > Decor > Rugs > Electric Rugs -Home & Garden > Decor > Seasonal & Holiday Decorations -Home & Garden > Decor > Seasonal & Holiday Decorations > Advent Calendars -Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Skirts -Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Stands -Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornament Displays -Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornaments -Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stocking Hangers -Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stockings -Home & Garden > Decor > Seasonal & Holiday Decorations > Nativity Sets -Home & Garden > Decor > Seasonal & Holiday Decorations > Ornament Storage Containers -Home & Garden > Decor > Shadow Boxes -Home & Garden > Decor > Slipcovers -Home & Garden > Decor > Snow Globes -Home & Garden > Decor > Suncatchers -Home & Garden > Decor > Sundials -Home & Garden > Decor > Throw Pillows -Home & Garden > Decor > Tiki Torches & Oil Lamps -Home & Garden > Decor > Trunks -Home & Garden > Decor > Vases -Home & Garden > Decor > Wall & Window Decals -Home & Garden > Decor > Wall Shelves & Ledges -Home & Garden > Decor > Wax Tarts -Home & Garden > Decor > Weather Vanes & Roof Decor -Home & Garden > Decor > Wind Chimes -Home & Garden > Decor > Wind Wheels & Spinners -Home & Garden > Decor > Window Magnets -Home & Garden > Decor > Window Treatment Accessories -Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rings -Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rods -Home & Garden > Decor > Window Treatment Accessories > Curtain Holdbacks & Tassels -Home & Garden > Decor > Window Treatment Accessories > Window Treatment Replacement Parts -Home & Garden > Decor > Window Treatments -Home & Garden > Decor > Window Treatments > Curtains & Drapes -Home & Garden > Decor > Window Treatments > Stained Glass Panels -Home & Garden > Decor > Window Treatments > Window Blinds & Shades -Home & Garden > Decor > Window Treatments > Window Films -Home & Garden > Decor > Window Treatments > Window Screens -Home & Garden > Decor > Window Treatments > Window Valances & Cornices -Home & Garden > Decor > World Globes -Home & Garden > Decor > Wreaths & Garlands -Home & Garden > Emergency Preparedness -Home & Garden > Emergency Preparedness > Earthquake Alarms -Home & Garden > Emergency Preparedness > Emergency Food -Home & Garden > Emergency Preparedness > Emergency Tools & Kits -Home & Garden > Emergency Preparedness > Furniture Anchors -Home & Garden > Fire & Gas Safety -Home & Garden > Fire & Gas Safety > Carbon Monoxide Detectors -Home & Garden > Fire & Gas Safety > Fire Alarm Control Panels -Home & Garden > Fire & Gas Safety > Fire Alarms -Home & Garden > Fire & Gas Safety > Fire Extinguisher Cabinets -Home & Garden > Fire & Gas Safety > Fire Extinguishers -Home & Garden > Fire & Gas Safety > Fire Sprinklers -Home & Garden > Fire & Gas Safety > Heat Detectors -Home & Garden > Fire & Gas Safety > Radon Detectors -Home & Garden > Fire & Gas Safety > Smoke Detectors -Home & Garden > Fireplace & Wood Stove Accessories -Home & Garden > Fireplace & Wood Stove Accessories > Bellows -Home & Garden > Fireplace & Wood Stove Accessories > Fireplace & Wood Stove Grates -Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Andirons -Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Reflectors -Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Screens -Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Tools -Home & Garden > Fireplace & Wood Stove Accessories > Firewood & Fuel -Home & Garden > Fireplace & Wood Stove Accessories > Hearth Pads -Home & Garden > Fireplace & Wood Stove Accessories > Log Rack & Carrier Accessories -Home & Garden > Fireplace & Wood Stove Accessories > Log Racks & Carriers -Home & Garden > Fireplace & Wood Stove Accessories > Wood Stove Fans & Blowers -Home & Garden > Fireplaces -Home & Garden > Fireplaces > Indoor Fireplaces -Home & Garden > Fireplaces > Outdoor Fireplaces -Home & Garden > Home Security -Home & Garden > Home Security > Dummy Surveillance Cameras -Home & Garden > Home Security > Home Alarm Systems -Home & Garden > Home Security > Motion Sensors -Home & Garden > Home Security > Security Lights -Home & Garden > Home Security > Security Monitors & Recorders -Home & Garden > Home Security > Security Safes -Home & Garden > Home Security > Security System Sensors -Home & Garden > Home Security > Tracking Devices -Home & Garden > Household Appliance Accessories -Home & Garden > Household Appliance Accessories > Air Conditioner Accessories -Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Covers -Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Filters -Home & Garden > Household Appliance Accessories > Air Purifier Accessories -Home & Garden > Household Appliance Accessories > Air Purifier Accessories > Air Purifier Filters -Home & Garden > Household Appliance Accessories > Carpet & Steam Cleaner Accessories -Home & Garden > Household Appliance Accessories > Dehumidifier Accessories -Home & Garden > Household Appliance Accessories > Dehumidifier Accessories > Dehumidifier Filters -Home & Garden > Household Appliance Accessories > Fan Accessories -Home & Garden > Household Appliance Accessories > Furnace & Boiler Accessories -Home & Garden > Household Appliance Accessories > Heating Radiator Accessories -Home & Garden > Household Appliance Accessories > Heating Radiator Accessories > Heating Radiator Reflectors -Home & Garden > Household Appliance Accessories > Humidifier Accessories -Home & Garden > Household Appliance Accessories > Humidifier Accessories > Humidifier Filters -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Dryer Accessories -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Garment Steamer Accessories -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Iron Accessories -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Steam Press Accessories -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Washing Machine Accessories -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Washing Machine Accessories > Washing Machine & Dryer Pedestals -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Washing Machine Accessories > Washing Machine Hoses -Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Washing Machine Accessories > Washing Machine Valves -Home & Garden > Household Appliance Accessories > Patio Heater Accessories -Home & Garden > Household Appliance Accessories > Patio Heater Accessories > Patio Heater Covers -Home & Garden > Household Appliance Accessories > Sewing Machine Accessories -Home & Garden > Household Appliance Accessories > Sewing Machine Accessories > Bobbins & Bobbin Cases -Home & Garden > Household Appliance Accessories > Sewing Machine Accessories > Sewing Machine Cases & Covers -Home & Garden > Household Appliance Accessories > Sewing Machine Accessories > Sewing Machine Feet -Home & Garden > Household Appliance Accessories > Sewing Machine Accessories > Sewing Machine Needles -Home & Garden > Household Appliance Accessories > Vacuum Accessories -Home & Garden > Household Appliance Accessories > Vacuum Accessories > Vacuum Attachments -Home & Garden > Household Appliance Accessories > Vacuum Accessories > Vacuum Bags -Home & Garden > Household Appliance Accessories > Vacuum Accessories > Vacuum Belts -Home & Garden > Household Appliance Accessories > Vacuum Accessories > Vacuum Filters -Home & Garden > Household Appliance Accessories > Vacuum Accessories > Vacuum Hoses -Home & Garden > Household Appliance Accessories > Water Heater Accessories -Home & Garden > Household Appliance Accessories > Water Heater Accessories > Anode Rods -Home & Garden > Household Appliance Accessories > Water Heater Accessories > Hot Water Cylinders -Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Elements -Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Pans -Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Stacks -Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Vents -Home & Garden > Household Appliances -Home & Garden > Household Appliances > Carpet & Steam Cleaners -Home & Garden > Household Appliances > Climate Control Appliances -Home & Garden > Household Appliances > Climate Control Appliances > Air Conditioners -Home & Garden > Household Appliances > Climate Control Appliances > Air Purifiers -Home & Garden > Household Appliances > Climate Control Appliances > Dehumidifiers -Home & Garden > Household Appliances > Climate Control Appliances > Duct Heaters -Home & Garden > Household Appliances > Climate Control Appliances > Evaporative Coolers -Home & Garden > Household Appliances > Climate Control Appliances > Fans -Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ceiling Fans -Home & Garden > Household Appliances > Climate Control Appliances > Fans > Desk & Pedestal Fans -Home & Garden > Household Appliances > Climate Control Appliances > Fans > Personal Handheld Fans -Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ventilation Fans -Home & Garden > Household Appliances > Climate Control Appliances > Furnaces & Boilers -Home & Garden > Household Appliances > Climate Control Appliances > Heating Radiators -Home & Garden > Household Appliances > Climate Control Appliances > Humidifiers -Home & Garden > Household Appliances > Climate Control Appliances > Kotatsu -Home & Garden > Household Appliances > Climate Control Appliances > Outdoor Misting Systems -Home & Garden > Household Appliances > Climate Control Appliances > Patio Heaters -Home & Garden > Household Appliances > Climate Control Appliances > Space Heaters -Home & Garden > Household Appliances > Floor Polishers & Buffers -Home & Garden > Household Appliances > Futon Dryers -Home & Garden > Household Appliances > Garage Door Openers -Home & Garden > Household Appliances > Garage Door Remotes -Home & Garden > Household Appliances > Garage Parking Sensors -Home & Garden > Household Appliances > Home Automation -Home & Garden > Household Appliances > Laundry Appliances -Home & Garden > Household Appliances > Laundry Appliances > Dryers -Home & Garden > Household Appliances > Laundry Appliances > Garment Steamers -Home & Garden > Household Appliances > Laundry Appliances > Irons -Home & Garden > Household Appliances > Laundry Appliances > Laundry Combo Units -Home & Garden > Household Appliances > Laundry Appliances > Steam Presses -Home & Garden > Household Appliances > Laundry Appliances > Washing Machines -Home & Garden > Household Appliances > Sewing Machines -Home & Garden > Household Appliances > Sewing Machines > Sergers -Home & Garden > Household Appliances > Vacuums -Home & Garden > Household Appliances > Wallpaper Steamers -Home & Garden > Household Appliances > Water Heaters -Home & Garden > Household Appliances > Water Heaters > Immersion Heaters -Home & Garden > Household Supplies -Home & Garden > Household Supplies > Drawer & Shelf Liners -Home & Garden > Household Supplies > Furniture Floor Protectors -Home & Garden > Household Supplies > Garbage Bags -Home & Garden > Household Supplies > Household Cleaning Supplies -Home & Garden > Household Supplies > Household Cleaning Supplies > Broom & Mop Handles -Home & Garden > Household Supplies > Household Cleaning Supplies > Brooms -Home & Garden > Household Supplies > Household Cleaning Supplies > Buckets -Home & Garden > Household Supplies > Household Cleaning Supplies > Carpet Sweepers -Home & Garden > Household Supplies > Household Cleaning Supplies > Cleaning Gloves -Home & Garden > Household Supplies > Household Cleaning Supplies > Duster Refills -Home & Garden > Household Supplies > Household Cleaning Supplies > Dusters -Home & Garden > Household Supplies > Household Cleaning Supplies > Dustpans -Home & Garden > Household Supplies > Household Cleaning Supplies > Fabric & Upholstery Protectors -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > All-Purpose Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Carpet Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dish Detergent & Soap -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dishwasher Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Fabric & Upholstery Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Furniture Cleaners & Polish -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Hardwood Floor Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Household Disinfectants -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Leather Care & Dyes -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Oven & Grill Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Pet Odor & Stain Removers -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Rinse Aids -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Stainless Steel Cleaners & Polishes -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Stone Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Toilet Bowl Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Tub & Tile Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Washing Machine Cleaners -Home & Garden > Household Supplies > Household Cleaning Supplies > Mop Heads & Refills -Home & Garden > Household Supplies > Household Cleaning Supplies > Mops -Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brushes -Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brushes > Baby Bottle Brushes -Home & Garden > Household Supplies > Household Cleaning Supplies > Sponges & Scouring Pads -Home & Garden > Household Supplies > Household Cleaning Supplies > Squeegees -Home & Garden > Household Supplies > Household Paper Products -Home & Garden > Household Supplies > Household Paper Products > Facial Tissues -Home & Garden > Household Supplies > Household Paper Products > Paper Napkins -Home & Garden > Household Supplies > Household Paper Products > Paper Towels -Home & Garden > Household Supplies > Household Paper Products > Toilet Paper -Home & Garden > Household Supplies > Household Thermometers -Home & Garden > Household Supplies > Laundry Supplies -Home & Garden > Household Supplies > Laundry Supplies > Bleach -Home & Garden > Household Supplies > Laundry Supplies > Clothespins -Home & Garden > Household Supplies > Laundry Supplies > Dry Cleaning Kits -Home & Garden > Household Supplies > Laundry Supplies > Drying Racks & Hangers -Home & Garden > Household Supplies > Laundry Supplies > Fabric Refreshers -Home & Garden > Household Supplies > Laundry Supplies > Fabric Shavers -Home & Garden > Household Supplies > Laundry Supplies > Fabric Softeners & Dryer Sheets -Home & Garden > Household Supplies > Laundry Supplies > Fabric Stain Removers -Home & Garden > Household Supplies > Laundry Supplies > Fabric Starch -Home & Garden > Household Supplies > Laundry Supplies > Garment Shields -Home & Garden > Household Supplies > Laundry Supplies > Ironing Board Pads & Covers -Home & Garden > Household Supplies > Laundry Supplies > Ironing Boards -Home & Garden > Household Supplies > Laundry Supplies > Laundry Balls -Home & Garden > Household Supplies > Laundry Supplies > Laundry Baskets -Home & Garden > Household Supplies > Laundry Supplies > Laundry Detergent -Home & Garden > Household Supplies > Laundry Supplies > Lint Rollers -Home & Garden > Household Supplies > Laundry Supplies > Washing Bags & Baskets -Home & Garden > Household Supplies > Laundry Supplies > Wrinkle Releasers & Static Sprays -Home & Garden > Household Supplies > Moisture Absorbers -Home & Garden > Household Supplies > Pest Control -Home & Garden > Household Supplies > Pest Control > Fly Swatters -Home & Garden > Household Supplies > Pest Control > Pest Control Traps -Home & Garden > Household Supplies > Pest Control > Pesticides -Home & Garden > Household Supplies > Pest Control > Repellents -Home & Garden > Household Supplies > Pest Control > Repellents > Animal & Pet Repellents -Home & Garden > Household Supplies > Pest Control > Repellents > Household Insect Repellents -Home & Garden > Household Supplies > Rug Pads -Home & Garden > Household Supplies > Shoe Care & Tools -Home & Garden > Household Supplies > Shoe Care & Tools > Boot Pulls -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Bags -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Brushes -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Care Kits -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Dryers -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Horns -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishers -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishes & Waxes -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Scrapers -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Treatments & Dyes -Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Trees & Shapers -Home & Garden > Household Supplies > Storage & Organization -Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage -Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hangers -Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hat Boxes -Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Shoe Racks & Organizers -Home & Garden > Household Supplies > Storage & Organization > Flatware Chests -Home & Garden > Household Supplies > Storage & Organization > Gift Wrap Storage & Organization -Home & Garden > Household Supplies > Storage & Organization > Household Storage Bags -Home & Garden > Household Supplies > Storage & Organization > Household Storage Caddies -Home & Garden > Household Supplies > Storage & Organization > Household Storage Containers -Home & Garden > Household Supplies > Storage & Organization > Household Storage Drawers -Home & Garden > Household Supplies > Storage & Organization > Photo Storage -Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Albums -Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Storage Boxes -Home & Garden > Household Supplies > Storage & Organization > Pillboxes -Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks -Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Garment Racks -Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Umbrella Stands & Racks -Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Utility Hooks -Home & Garden > Household Supplies > Storage & Organization > Valets -Home & Garden > Household Supplies > Storage & Organization > Valets > Charging Valets -Home & Garden > Household Supplies > Storage & Organization > Valets > Clothes Valets -Home & Garden > Household Supplies > Storage & Organization > Valets > Dresser Valets -Home & Garden > Household Supplies > Trash Compactor Accessories -Home & Garden > Household Supplies > Waste Containment -Home & Garden > Household Supplies > Waste Containment > Hazardous Waste Containers -Home & Garden > Household Supplies > Waste Containment > Recycling Containers -Home & Garden > Household Supplies > Waste Containment > Trash Cans & Wastebaskets -Home & Garden > Household Supplies > Waste Containment Accessories -Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Carts -Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Frames -Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Lids -Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Wheels -Home & Garden > Kitchen & Dining -Home & Garden > Kitchen & Dining > Barware -Home & Garden > Kitchen & Dining > Barware > Absinthe Fountains -Home & Garden > Kitchen & Dining > Barware > Beer Dispensers & Taps -Home & Garden > Kitchen & Dining > Barware > Bottle Stoppers & Savers -Home & Garden > Kitchen & Dining > Barware > Coaster Holders -Home & Garden > Kitchen & Dining > Barware > Coasters -Home & Garden > Kitchen & Dining > Barware > Corkscrews -Home & Garden > Kitchen & Dining > Barware > Decanters -Home & Garden > Kitchen & Dining > Barware > Drink Shakers & Tools -Home & Garden > Kitchen & Dining > Barware > Drink Shakers & Tools > Bar Ice Picks -Home & Garden > Kitchen & Dining > Barware > Drink Shakers & Tools > Bottle Openers -Home & Garden > Kitchen & Dining > Barware > Drink Shakers & Tools > Drink Shakers -Home & Garden > Kitchen & Dining > Barware > Drink Shakers & Tools > Drink Tool Sets -Home & Garden > Kitchen & Dining > Barware > Foil Cutters -Home & Garden > Kitchen & Dining > Barware > Ice Buckets -Home & Garden > Kitchen & Dining > Barware > Whiskey Stones -Home & Garden > Kitchen & Dining > Barware > Wine Aerators -Home & Garden > Kitchen & Dining > Barware > Wine Buckets & Chillers -Home & Garden > Kitchen & Dining > Barware > Wine Glass Charms -Home & Garden > Kitchen & Dining > Cookware & Bakeware -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bakeware Sets -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Baking & Cookie Sheets -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Baking & Specialty Molds -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bread Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Broiling Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Cake Pans & Molds -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Muffin & Cupcake Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pie & Quiche Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Stones -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Ramekins & Souffle Dishes -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Roasting Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Cups -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Mats & Liners -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Weights -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Roasting Pan Racks -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware & Bakeware Combo Sets -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Casserole Dishes -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Cookware Sets -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Crêpe & Blini Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Double Boilers -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Dutch Ovens -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Fermentation & Pickling Crocks -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Griddles & Grill Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Grill Presses -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Paella Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Pressure Cookers -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Pressure Cookers > Electric Pressure Cookers -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Saucepans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Sauté Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Skillets & Frying Pans -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stock Pots -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stovetop Kettles -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Tajines -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Woks -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Handles -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Lids -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pressure Cooker Accessories -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Steamer Baskets -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Brushes -Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Rings -Home & Garden > Kitchen & Dining > Food & Beverage Carriers -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Airpots -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Canteens -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Coolers -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Lids -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Can & Bottle Sleeves -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Cup Sleeves -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Flasks -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Insulated Bags -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Lunch Boxes & Totes -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Picnic Baskets -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Thermoses -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Water Bottles -Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Wine Carrier Bags -Home & Garden > Kitchen & Dining > Food Storage -Home & Garden > Kitchen & Dining > Food Storage > Bowl Covers -Home & Garden > Kitchen & Dining > Food Storage > Bread Boxes & Bags -Home & Garden > Kitchen & Dining > Food Storage > Candy Buckets -Home & Garden > Kitchen & Dining > Food Storage > Cookie Jars -Home & Garden > Kitchen & Dining > Food Storage > Food Storage Bags -Home & Garden > Kitchen & Dining > Food Storage > Food Storage Containers -Home & Garden > Kitchen & Dining > Food Storage > Food Wraps -Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Foil -Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Parchment Paper -Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Plastic Wrap -Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Wax Paper -Home & Garden > Kitchen & Dining > Food Storage > Honey Jars -Home & Garden > Kitchen & Dining > Food Storage Accessories -Home & Garden > Kitchen & Dining > Food Storage Accessories > Food Wrap Dispensers -Home & Garden > Kitchen & Dining > Food Storage Accessories > Oxygen Absorbers -Home & Garden > Kitchen & Dining > Food Storage Accessories > Twist Ties & Bag Clips -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Blender Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Blender Accessories > Blender Jars -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Blender Accessories > Blender Lids -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Breadmaker Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanter Warmers -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanters -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filter Baskets -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filters -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Maker Water Filters -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Frothing Pitchers -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Portafilters -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Stovetop Espresso Pot Parts -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cooktop Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cooktop Accessories > Cooktop Burner Grates -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cotton Candy Machine Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Deep Fryer Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Deep Fryer Accessories > Fryer Baskets -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Dishwasher Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Dishwasher Accessories > Dishwasher Glass Racks -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Electric Skillet & Wok Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Forks -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Pot Stands -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Sheets -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Trays -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Grinder Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Grinder Accessories > Coffee Grinder Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Grinder Accessories > Meat Grinder Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Grinder Accessories > Spice Grinder Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories > Food Mixer Attachments -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories > Food Mixer Attachments > Juicer Attachments -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories > Food Mixer Attachments > Meat Grinder Attachments -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories > Food Mixer Attachments > Pasta Maker Attachments -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories > Food Mixer Beaters -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories > Food Mixer Bowls -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer Accessories > Food Mixer Hooks -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Processor Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Freezer Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Garbage Disposal Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories > Ice Cream Maker Freezer Bowls -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Crusher & Shaver Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Maker Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Juicer Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Microwave Oven Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Microwave Oven Accessories > Microwave Drawers -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Microwave Oven Accessories > Microwave Trim Kits -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Briquettes -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Chimneys -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Burners -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Carts -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Covers -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Racks & Toppers -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Spits & Baskets -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grilling Planks -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Smoking Chips & Pellets -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Oven Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Oven Accessories > Oven Liners -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Oven Accessories > Oven Rack Guards -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Oven Accessories > Oven Racks -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Pasta Maker Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Popcorn Maker Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Portable Cooking Stove Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Range Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Range Accessories > Range Burner Covers -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Range Accessories > Range Drip Pans -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Refrigerator Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pan Covers -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pans -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Toaster Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories > Vacuum Sealer Bags -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories > Water Cooler Bottles -Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Yogurt Maker Accessories -Home & Garden > Kitchen & Dining > Kitchen Appliances -Home & Garden > Kitchen & Dining > Kitchen Appliances > Beverage Warmers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Blenders -Home & Garden > Kitchen & Dining > Kitchen Appliances > Breadmakers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Chocolate Tempering Machines -Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines -Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Drip Coffee Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Electric & Stovetop Espresso Pots -Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Espresso Machines -Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > French Presses -Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Percolators -Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Vacuum Coffee Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Cooktops -Home & Garden > Kitchen & Dining > Kitchen Appliances > Cotton Candy Machines -Home & Garden > Kitchen & Dining > Kitchen Appliances > Crêpe Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Deep Fryers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Dishwashers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Griddles & Grills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Griddles & Grills > Electric Griddles -Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Griddles & Grills > Electric Grills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Kettles -Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Skillets & Woks -Home & Garden > Kitchen & Dining > Kitchen Appliances > Fondue Sets -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Egg Cookers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Food Steamers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Rice Cookers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Slow Cookers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Thermal Cookers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Water Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Dehydrators -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills > Coffee Grinders -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills > Grain Mills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills > Meat Grinders -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills > Spice Grinders -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Mixers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Processors -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Slicers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Slicers > Deli Slicers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Smokers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Chafing Dishes -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Food Heat Lamps -Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Steam Tables -Home & Garden > Kitchen & Dining > Kitchen Appliances > Freezers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Garbage Disposals -Home & Garden > Kitchen & Dining > Kitchen Appliances > Gas Griddles -Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Drink Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Plates -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Cream Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Crushers & Shavers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Juicers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Juicers > Hand Juicers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Knife Sharpeners -Home & Garden > Kitchen & Dining > Kitchen Appliances > Microwave Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Milk Frothers & Steamers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Mochi Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Outdoor Grills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Outdoor Grills > Charcoal Grills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Outdoor Grills > Gas Grills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ovens > Conveyor Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ovens > Deck Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ovens > Wall Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Pasta Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Popcorn Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Portable Cooking Stoves -Home & Garden > Kitchen & Dining > Kitchen Appliances > Range Hoods -Home & Garden > Kitchen & Dining > Kitchen Appliances > Ranges -Home & Garden > Kitchen & Dining > Kitchen Appliances > Refrigerators -Home & Garden > Kitchen & Dining > Kitchen Appliances > Roaster Ovens & Rotisseries -Home & Garden > Kitchen & Dining > Kitchen Appliances > Slush Machines -Home & Garden > Kitchen & Dining > Kitchen Appliances > Soda Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Soy Milk Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Tea Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Donut Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Muffin & Cupcake Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizza Makers & Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizzelle Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pretzel Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Sandwich Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Toaster Ovens -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Toasters -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Tortilla & Flatbread Makers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Waffle Irons -Home & Garden > Kitchen & Dining > Kitchen Appliances > Trash Compactors -Home & Garden > Kitchen & Dining > Kitchen Appliances > Vacuum Sealers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Coolers -Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Filters -Home & Garden > Kitchen & Dining > Kitchen Appliances > Wine Fridges -Home & Garden > Kitchen & Dining > Kitchen Appliances > Yogurt Makers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Aprons -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Baking Peels -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basters -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basting Brushes -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Beverage Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Decorating Supplies -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Servers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Crushers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Openers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Candy & Chocolate Molds -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Carving Forks -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Channel Knives -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Citrus Reamers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Colanders & Strainers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Condiment Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Cutters -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Presses -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometer Accessories -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Timers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Torches -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooling Racks -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cutting Boards -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dicers & Choppers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dish Racks & Drain Boards -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dough Wheels -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories > Electric Knife Replacement Blades -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knives -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Flour Sifters -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Lobster & Crab Crackers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers > Decorative Nutcrackers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Cutters & Wedgers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Graters & Zesters -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Peelers & Corers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Steaming Bags -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Sticks & Skewers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Garlic Presses -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Gelatin Molds -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ice Cube Trays -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ice Pop Molds -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Jerky Guns -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Knives -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Molds -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Can Organizers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Drinkware Racks -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Cabinet Organizers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Storage Carousels -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Utensil Holders -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Knife Blocks & Holders -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Napkin Holders & Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Paper Towel Holders & Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Pot Racks -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Single Serve Beverage Organizers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Spice Organizers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Straw Holders & Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Sugar Caddies -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Toothpick Holders & Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Utensil & Flatware Trays -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scales -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bench Scrapers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bowl Scrapers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Grill Scrapers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Shears -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers > Bread Slicers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers > Cheese Slicers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers > Egg Slicers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers > Mandoline Slicers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Utensil Sets -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ladles -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mashers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Measuring Cups & Spoons -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Meat Tenderizers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mixing Bowls -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mortars & Pestles -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oil & Vinegar Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Bags -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Mitts & Pot Holders -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pasta Molds & Stamps -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Blenders -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Cloths -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutter Accessories -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutters -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ricers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Covers & Sleeves -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Rings -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pins -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Dressing Mixers & Shakers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Spinners -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Cream Scoops -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Scoops -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Melon Ballers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Caddies -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Mats & Grids -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Slotted Spoons -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spatulas -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spoon Rests -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sugar Dispensers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sushi Mats -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tea Strainers -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tongs -Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Whisks -Home & Garden > Kitchen & Dining > Tableware -Home & Garden > Kitchen & Dining > Tableware > Coffee & Tea Sets -Home & Garden > Kitchen & Dining > Tableware > Coffee Servers & Tea Pots -Home & Garden > Kitchen & Dining > Tableware > Dinnerware -Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Bowls -Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Dinnerware Sets -Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Plates -Home & Garden > Kitchen & Dining > Tableware > Drinkware -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Beer Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Beer Glasses > Pilsner Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Beer Glasses > Pint Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Beer Glasses > Tankards & Beer Steins -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Cups -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Cups > Coffee Cups -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Cups > Tea Cups -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Saucers -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Drinkware Sets -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Mugs -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Shot Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware > Brandy Snifters -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware > Champagne Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware > Margarita Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware > Martini Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware > Wine Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Tumblers -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Tumblers > Highball Glasses -Home & Garden > Kitchen & Dining > Tableware > Drinkware > Tumblers > Lowball Glasses -Home & Garden > Kitchen & Dining > Tableware > Flatware -Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopstick Accessories -Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopstick Accessories > Chopstick Connectors -Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopstick Accessories > Chopstick Rests -Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopsticks -Home & Garden > Kitchen & Dining > Tableware > Flatware > Flatware Sets -Home & Garden > Kitchen & Dining > Tableware > Flatware > Forks -Home & Garden > Kitchen & Dining > Tableware > Flatware > Spoons -Home & Garden > Kitchen & Dining > Tableware > Flatware > Table Knives -Home & Garden > Kitchen & Dining > Tableware > Salt & Pepper Shakers -Home & Garden > Kitchen & Dining > Tableware > Serveware -Home & Garden > Kitchen & Dining > Tableware > Serveware > Butter Dishes -Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Boards -Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Stands -Home & Garden > Kitchen & Dining > Tableware > Serveware > Egg Cups -Home & Garden > Kitchen & Dining > Tableware > Serveware > Gravy Boats -Home & Garden > Kitchen & Dining > Tableware > Serveware > Punch Bowls -Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Pitchers & Carafes -Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Platters -Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Trays -Home & Garden > Kitchen & Dining > Tableware > Serveware > Sugar Bowls & Creamers -Home & Garden > Kitchen & Dining > Tableware > Serveware > Tureens -Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories -Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Punch Bowl Stands -Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Lids -Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Stands -Home & Garden > Kitchen & Dining > Tableware > Trivets -Home & Garden > Lawn & Garden -Home & Garden > Lawn & Garden > Gardening -Home & Garden > Lawn & Garden > Gardening > Composting -Home & Garden > Lawn & Garden > Gardening > Composting > Compost -Home & Garden > Lawn & Garden > Gardening > Composting > Compost Aerators -Home & Garden > Lawn & Garden > Gardening > Composting > Composters -Home & Garden > Lawn & Garden > Gardening > Disease Control -Home & Garden > Lawn & Garden > Gardening > Fertilizers -Home & Garden > Lawn & Garden > Gardening > Gardening Accessories -Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Kneeling Cushions -Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Totes -Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Potting Benches -Home & Garden > Lawn & Garden > Gardening > Gardening Tools -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Brush Axes -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Bulb Planting Tools -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Cultivating Tools -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Cultivating Tools > Garden Hoes -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Digging Bars -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Forks -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Sickles -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Trowels -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Grass Edgers -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn & Garden Sprayers -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn Aerators -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Machetes -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Mattocks & Pickaxes -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Saws -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Shears -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Rakes -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Shovels & Spades -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Spreaders -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Wheelbarrow Parts -Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Wheelbarrows -Home & Garden > Lawn & Garden > Gardening > Greenhouses -Home & Garden > Lawn & Garden > Gardening > Herbicides -Home & Garden > Lawn & Garden > Gardening > Landscape Fabric -Home & Garden > Lawn & Garden > Gardening > Lanscape Fabric Accessories -Home & Garden > Lawn & Garden > Gardening > Lanscape Fabric Accessories > Landscape Fabric Staples & Pins -Home & Garden > Lawn & Garden > Gardening > Lanscape Fabric Accessories > Landscape Fabric Tape -Home & Garden > Lawn & Garden > Gardening > Mulch -Home & Garden > Lawn & Garden > Gardening > Plant Cages -Home & Garden > Lawn & Garden > Gardening > Plant Stakes & Supports -Home & Garden > Lawn & Garden > Gardening > Plant Stands -Home & Garden > Lawn & Garden > Gardening > Pots & Planters -Home & Garden > Lawn & Garden > Gardening > Rain Barrels -Home & Garden > Lawn & Garden > Gardening > Sands & Soils -Home & Garden > Lawn & Garden > Outdoor Living -Home & Garden > Lawn & Garden > Outdoor Living > Hammock Accessories -Home & Garden > Lawn & Garden > Outdoor Living > Hammocks -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Beach Mats -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Picnic Blankets -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Poncho Liners -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopies & Gazebos -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Enclosure Kits -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Frames -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Tops -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Poles -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Weights -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Arches, Trellises, Arbors & Pergolas -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Bridges -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Sheds & Storage -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella & Sunshade Fabric -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Bases -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Covers -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Lights -Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrellas & Sunshades -Home & Garden > Lawn & Garden > Outdoor Living > Porch Swings -Home & Garden > Lawn & Garden > Outdoor Power Equipment -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Chainsaws -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Hedge Trimmers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Riding Mowers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Robotic Mowers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Tow-Behind Mowers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Walk-Behind Mowers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Vacuums -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Leaf Blowers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Heads -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Sets -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Power Tillers & Cultivators -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Pressure Washers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Snow Blowers -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Tractors -Home & Garden > Lawn & Garden > Outdoor Power Equipment > Weed Trimmers -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Bars -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Chains -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Grass Edger Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Grass Edger Accessories > Grass Edger Attachments -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Hedge Trimmer Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Hedge Trimmer Accessories > Hedge Trimmer Attachments -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Brush Mower Attachments -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Attachments -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Bags -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Belts -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Blades -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Covers -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Pulleys & Idlers -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Tires -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Wheels -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Sweepers -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories > Leaf Blower Extension Tubes -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Outdoor Power Equipment Batteries -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Outdoor Power Equipment Batteries > Hedge Trimmer Batteries -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Outdoor Power Equipment Batteries > Lawn Mower Batteries -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Outdoor Power Equipment Batteries > Weed Trimmer Batteries -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Pressure Washer Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Snow Blower Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Attachments -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Blades & Spools -Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Spool Covers -Home & Garden > Lawn & Garden > Snow Removal -Home & Garden > Lawn & Garden > Snow Removal > Ice Scrapers -Home & Garden > Lawn & Garden > Snow Removal > Snow Shovels -Home & Garden > Lawn & Garden > Watering & Irrigation -Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hose Fittings & Valves -Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hose Spray Nozzles -Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hoses -Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories -Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories > Sprinkler Controls -Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories > Sprinkler Valves -Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinklers & Sprinkler Heads -Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinklers & Sprinkler Heads > Sprinkler Heads -Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinklers & Sprinkler Heads > Sprinklers -Home & Garden > Lawn & Garden > Watering & Irrigation > Watering Cans -Home & Garden > Lighting -Home & Garden > Lighting > Emergency Lighting -Home & Garden > Lighting > Flood & Spot Lights -Home & Garden > Lighting > Lamps -Home & Garden > Lighting > Lamps > Floor Lamps -Home & Garden > Lighting > Lamps > Table Lamps -Home & Garden > Lighting > Landscape Lighting -Home & Garden > Lighting > Landscape Lighting > Deck Lights -Home & Garden > Lighting > Landscape Lighting > Landscape Lanterns & Torches -Home & Garden > Lighting > Landscape Lighting > Landscape Pathway Lighting -Home & Garden > Lighting > Landscape Lighting > Landscape Well Lights -Home & Garden > Lighting > Light Bulbs -Home & Garden > Lighting > Light Bulbs > Compact Fluorescent Lamps -Home & Garden > Lighting > Light Bulbs > Fluorescent Tubes -Home & Garden > Lighting > Light Bulbs > Incandescent Light Bulbs -Home & Garden > Lighting > Light Bulbs > LED Light Bulbs -Home & Garden > Lighting > Light Ropes & Strings -Home & Garden > Lighting > Lighting Fixtures -Home & Garden > Lighting > Lighting Fixtures > Ceiling Light Fixtures -Home & Garden > Lighting > Lighting Fixtures > Chandeliers -Home & Garden > Lighting > Lighting Fixtures > Under Cabinet Light Fixtures -Home & Garden > Lighting > Lighting Fixtures > Wall Light Fixtures -Home & Garden > Lighting > Lighting Fixtures > Wall Light Fixtures > Wall Sconces -Home & Garden > Lighting > Night Lights -Home & Garden > Lighting > Picture Lights -Home & Garden > Lighting > Track Lighting -Home & Garden > Lighting > Track Lighting > Track Lighting Accessories -Home & Garden > Lighting > Track Lighting > Track Lighting Fixtures -Home & Garden > Lighting > Track Lighting > Track Lighting Rails -Home & Garden > Lighting Accessories -Home & Garden > Lighting Accessories > Lamp Post Bases -Home & Garden > Lighting Accessories > Lamp Post Mounts -Home & Garden > Lighting Accessories > Lamp Shades -Home & Garden > Lighting Accessories > Lighting Timers -Home & Garden > Linens & Bedding -Home & Garden > Linens & Bedding > Bedding -Home & Garden > Linens & Bedding > Bedding > Bed Sheets -Home & Garden > Linens & Bedding > Bedding > Bedskirts -Home & Garden > Linens & Bedding > Bedding > Blankets -Home & Garden > Linens & Bedding > Bedding > Blankets > Electric Blankets -Home & Garden > Linens & Bedding > Bedding > Blankets > Throw Blankets -Home & Garden > Linens & Bedding > Bedding > Comforters & Comforter Sets -Home & Garden > Linens & Bedding > Bedding > Duvet Covers -Home & Garden > Linens & Bedding > Bedding > Mattress Protectors -Home & Garden > Linens & Bedding > Bedding > Mattress Protectors > Mattress Encasements -Home & Garden > Linens & Bedding > Bedding > Mattress Protectors > Mattress Pads -Home & Garden > Linens & Bedding > Bedding > Nap Mats -Home & Garden > Linens & Bedding > Bedding > Pillowcases & Shams -Home & Garden > Linens & Bedding > Bedding > Pillows -Home & Garden > Linens & Bedding > Bedding > Pillows > Body Pillows -Home & Garden > Linens & Bedding > Bedding > Quilts & Quilt Sets -Home & Garden > Linens & Bedding > Table Linen Accessories -Home & Garden > Linens & Bedding > Table Linen Accessories > Tablecloth Clips & Weights -Home & Garden > Linens & Bedding > Table Linens -Home & Garden > Linens & Bedding > Table Linens > Cloth Napkins -Home & Garden > Linens & Bedding > Table Linens > Doilies -Home & Garden > Linens & Bedding > Table Linens > Placemats -Home & Garden > Linens & Bedding > Table Linens > Table Runners -Home & Garden > Linens & Bedding > Table Linens > Table Skirts -Home & Garden > Linens & Bedding > Table Linens > Tablecloths -Home & Garden > Linens & Bedding > Towels -Home & Garden > Linens & Bedding > Towels > Bath Towels & Washcloths -Home & Garden > Linens & Bedding > Towels > Beach Towels -Home & Garden > Linens & Bedding > Towels > Kitchen Towels -Home & Garden > Parasols & Rain Umbrellas -Home & Garden > Plants -Home & Garden > Plants > Aquatic Plants -Home & Garden > Plants > Flowers -Home & Garden > Plants > Indoor & Outdoor Plants -Home & Garden > Plants > Indoor & Outdoor Plants > Indoor Plants -Home & Garden > Plants > Indoor & Outdoor Plants > Outdoor Plants -Home & Garden > Plants > Seeds -Home & Garden > Plants > Trees -Home & Garden > Pool & Spa -Home & Garden > Pool & Spa > Pool & Spa Accessories -Home & Garden > Pool & Spa > Pool & Spa Accessories > Child Swimming Aids -Home & Garden > Pool & Spa > Pool & Spa Accessories > Diving Boards -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool & Spa Filters -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Brushes -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cleaner Hoses -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cleaners & Chemicals -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Covers -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Deck Kits -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Floats & Loungers -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Floats & Loungers > Baby Floats -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Heaters -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Ladders -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Skimmers -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Sweeps & Vacuums -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Toys -Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Water Slides -Home & Garden > Pool & Spa > Saunas -Home & Garden > Pool & Spa > Spas -Home & Garden > Pool & Spa > Swimming Pools -Home & Garden > Smoking Accessories -Home & Garden > Smoking Accessories > Ashtrays -Home & Garden > Smoking Accessories > Cigar Cases -Home & Garden > Smoking Accessories > Cigar Cutters & Punches -Home & Garden > Smoking Accessories > Cigarette Cases -Home & Garden > Smoking Accessories > Humidor Accessories -Home & Garden > Smoking Accessories > Humidors -Home & Garden > Smoking Accessories > Lighters -Home & Garden > Smoking Accessories > Matches -Home & Garden > Umbrella Sleeves & Cases -Home & Garden > Wood Stoves -Luggage & Bags -Luggage & Bags > Backpack Accessories -Luggage & Bags > Backpack Accessories > Backpack Covers -Luggage & Bags > Backpacks -Luggage & Bags > Business Bags -Luggage & Bags > Business Bags > Briefcases -Luggage & Bags > Business Bags > Electronics Bags & Cases -Luggage & Bags > Business Bags > Electronics Bags & Cases > Computer Skins & Sleeves -Luggage & Bags > Business Bags > Electronics Bags & Cases > Laptop Bags & Cases -Luggage & Bags > Business Bags > Electronics Bags & Cases > Tablet Computer Bags & Cases -Luggage & Bags > Business Bags > Garment Bags -Luggage & Bags > Cosmetic & Toiletry Bags -Luggage & Bags > Diaper Bags -Luggage & Bags > Duffel Bags -Luggage & Bags > Fanny Packs -Luggage & Bags > Luggage Accessories -Luggage & Bags > Luggage Accessories > Luggage Straps -Luggage & Bags > Luggage Accessories > Luggage Tags -Luggage & Bags > Luggage Accessories > Packing Organizers -Luggage & Bags > Luggage Accessories > Travel Bottles & Containers -Luggage & Bags > Luggage Accessories > Travel Pouches -Luggage & Bags > Messenger Bags -Luggage & Bags > Shopping Totes -Luggage & Bags > Suitcases -Luggage & Bags > Suitcases > Carry-On Luggage -Luggage & Bags > Train Cases -Mature -Mature > Erotic -Mature > Erotic > Erotic Books -Mature > Erotic > Erotic Books > Erotic Comics -Mature > Erotic > Erotic Clothing -Mature > Erotic > Erotic DVDs & Videos -Mature > Erotic > Erotic Food & Edibles -Mature > Erotic > Erotic Games -Mature > Erotic > Erotic Magazines -Mature > Erotic > Pole Dancing Kits -Mature > Erotic > Sex Toys -Mature > Weapons -Mature > Weapons > Brass Knuckles -Mature > Weapons > Clubs -Mature > Weapons > Combat Knives -Mature > Weapons > Gun Accessories -Mature > Weapons > Gun Accessories > Ammunition -Mature > Weapons > Gun Accessories > Ammunition Belts -Mature > Weapons > Gun Accessories > Ammunition Boxes -Mature > Weapons > Gun Accessories > Gun Bags & Cases -Mature > Weapons > Gun Accessories > Gun Grips -Mature > Weapons > Gun Accessories > Gun Holsters -Mature > Weapons > Gun Accessories > Gun Lights -Mature > Weapons > Gun Accessories > Gun Rails -Mature > Weapons > Guns -Mature > Weapons > Mace & Pepper Spray -Mature > Weapons > Nunchucks -Mature > Weapons > Spears -Mature > Weapons > Staff & Stick Weapons -Mature > Weapons > Stun Guns & Tasers -Mature > Weapons > Swords -Mature > Weapons > Throwing Stars -Mature > Weapons > Whips -Media -Media > Books -Media > Books > Fiction -Media > Books > Fiction > Children's Books -Media > Books > Fiction > Comics -Media > Books > Fiction > Horror Novels -Media > Books > Fiction > Literature -Media > Books > Fiction > Mystery Novels -Media > Books > Fiction > Romance Novels -Media > Books > Fiction > Science Fiction & Fantasy Novels -Media > Books > Non-Fiction -Media > Books > Non-Fiction > Animal & Nature Books -Media > Books > Non-Fiction > Architecture Books -Media > Books > Non-Fiction > Art Books -Media > Books > Non-Fiction > Biographies -Media > Books > Non-Fiction > Body, Mind & Spirit Books -Media > Books > Non-Fiction > Business & Economics Books -Media > Books > Non-Fiction > Coloring Books -Media > Books > Non-Fiction > Computer Books -Media > Books > Non-Fiction > Cooking Books -Media > Books > Non-Fiction > Craft, Hobby & Activity Books -Media > Books > Non-Fiction > Drama Books -Media > Books > Non-Fiction > Education Books -Media > Books > Non-Fiction > Education Books > Foreign Language Books -Media > Books > Non-Fiction > Education Books > Study Aids -Media > Books > Non-Fiction > Family Relationship Books -Media > Books > Non-Fiction > Game Books -Media > Books > Non-Fiction > Gardening Books -Media > Books > Non-Fiction > Health & Fitness Books -Media > Books > Non-Fiction > History Books -Media > Books > Non-Fiction > Home Improvement Books -Media > Books > Non-Fiction > Humor Books -Media > Books > Non-Fiction > Juvenile Non-Fiction -Media > Books > Non-Fiction > Language Arts Books -Media > Books > Non-Fiction > Law Books -Media > Books > Non-Fiction > Literary Books -Media > Books > Non-Fiction > Math Books -Media > Books > Non-Fiction > Medical Books -Media > Books > Non-Fiction > Music Books -Media > Books > Non-Fiction > Performing Arts Books -Media > Books > Non-Fiction > Pet Books -Media > Books > Non-Fiction > Philosophy Books -Media > Books > Non-Fiction > Photography Books -Media > Books > Non-Fiction > Poetry -Media > Books > Non-Fiction > Political Science Books -Media > Books > Non-Fiction > Psychology Books -Media > Books > Non-Fiction > Puzzle Books -Media > Books > Non-Fiction > Reference Books -Media > Books > Non-Fiction > Religion Books -Media > Books > Non-Fiction > Science Books -Media > Books > Non-Fiction > Self Help Books -Media > Books > Non-Fiction > Social Science Books -Media > Books > Non-Fiction > Sports Books -Media > Books > Non-Fiction > Technology Books -Media > Books > Non-Fiction > Transportation Books -Media > Books > Non-Fiction > Travel Books -Media > Books > Non-Fiction > True Crime Books -Media > DVDs & Videos -Media > Magazines & Newspapers -Media > Music -Media > Product Manuals -Media > Product Manuals > Electronics Manuals -Media > Product Manuals > Household Appliance Manuals -Media > Product Manuals > Kitchen Appliance Manuals -Media > Product Manuals > Model & Toys Manuals -Media > Product Manuals > Power Tool & Equipment Manuals -Media > Product Manuals > Sports & Recreation Manuals -Media > Product Manuals > Vehicle Service Manuals -Media > Sheet Music -Office Supplies -Office Supplies > Book Accessories -Office Supplies > Book Accessories > Book Covers -Office Supplies > Book Accessories > Book Lights -Office Supplies > Book Accessories > Book Stands & Rests -Office Supplies > Book Accessories > Bookmarks -Office Supplies > Filing & Organization -Office Supplies > Filing & Organization > Address Books -Office Supplies > Filing & Organization > Binding Supplies -Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories -Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Binder Rings -Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Index Dividers -Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Sheet Protectors -Office Supplies > Filing & Organization > Binding Supplies > Binders -Office Supplies > Filing & Organization > Binding Supplies > Binding Combs & Spines -Office Supplies > Filing & Organization > Binding Supplies > Binding Machines -Office Supplies > Filing & Organization > Business Card Books -Office Supplies > Filing & Organization > Business Card Stands -Office Supplies > Filing & Organization > CD/DVD Organizers -Office Supplies > Filing & Organization > CD/DVD Organizers > CD/DVD Pouches & Visors -Office Supplies > Filing & Organization > CD/DVD Organizers > CD/DVD Sleeves -Office Supplies > Filing & Organization > CD/DVD Organizers > Jewel Cases -Office Supplies > Filing & Organization > Calendars, Organizers & Planners -Office Supplies > Filing & Organization > Card Files -Office Supplies > Filing & Organization > Card Sleeves -Office Supplies > Filing & Organization > Cash Boxes -Office Supplies > Filing & Organization > Desk Organizers -Office Supplies > Filing & Organization > Desk Organizers > Desk Trays -Office Supplies > Filing & Organization > File Boxes -Office Supplies > Filing & Organization > File Folders -Office Supplies > Filing & Organization > Folders & Report Covers -Office Supplies > Filing & Organization > Greeting Card Organizers -Office Supplies > Filing & Organization > Laminating -Office Supplies > Filing & Organization > Laminating > Laminating Film, Pouches & Sheets -Office Supplies > Filing & Organization > Laminating > Laminators -Office Supplies > Filing & Organization > Mail Sorters -Office Supplies > Filing & Organization > Pen & Pencil Cases -Office Supplies > Filing & Organization > Portfolios & Padfolios -Office Supplies > Filing & Organization > Recipe Card Boxes -Office Supplies > Filing & Organization > Storage Lockers & Cabinets -Office Supplies > General Supplies -Office Supplies > General Supplies > Adhesives -Office Supplies > General Supplies > Adhesives > Office Tape -Office Supplies > General Supplies > Brass Fasteners -Office Supplies > General Supplies > Correction -Office Supplies > General Supplies > Correction > Correction Fluids, Pens & Tapes -Office Supplies > General Supplies > Correction > Erasers -Office Supplies > General Supplies > Labels & Tags -Office Supplies > General Supplies > Labels & Tags > Address Labels -Office Supplies > General Supplies > Labels & Tags > Folder Tabs -Office Supplies > General Supplies > Labels & Tags > Label Clips -Office Supplies > General Supplies > Labels & Tags > Label Maker Tape -Office Supplies > General Supplies > Labels & Tags > Shipping Labels -Office Supplies > General Supplies > Labels & Tags > Shipping Tags -Office Supplies > General Supplies > Paper Clips & Clamps -Office Supplies > General Supplies > Paper Products -Office Supplies > General Supplies > Paper Products > Binder Paper -Office Supplies > General Supplies > Paper Products > Blank ID Cards -Office Supplies > General Supplies > Paper Products > Business Cards -Office Supplies > General Supplies > Paper Products > Business Forms & Receipts -Office Supplies > General Supplies > Paper Products > Checks -Office Supplies > General Supplies > Paper Products > Cover Paper -Office Supplies > General Supplies > Paper Products > Envelopes -Office Supplies > General Supplies > Paper Products > Index Cards -Office Supplies > General Supplies > Paper Products > Notebooks & Notepads -Office Supplies > General Supplies > Paper Products > Post Cards -Office Supplies > General Supplies > Paper Products > Printer & Copier Paper -Office Supplies > General Supplies > Paper Products > Printer & Copier Paper > Photo Printer Paper -Office Supplies > General Supplies > Paper Products > Receipt Paper Rolls -Office Supplies > General Supplies > Paper Products > Stationery -Office Supplies > General Supplies > Paper Products > Sticky Notes -Office Supplies > General Supplies > Rubber Bands -Office Supplies > General Supplies > Stamp Pads & Inks -Office Supplies > General Supplies > Staples -Office Supplies > General Supplies > Tacks & Pushpins -Office Supplies > Impulse Sealers -Office Supplies > Name Plates -Office Supplies > Office & Chair Mats -Office Supplies > Office & Chair Mats > Anti-Fatigue Mats -Office Supplies > Office & Chair Mats > Chair Mats -Office Supplies > Office & Chair Mats > Office Mats -Office Supplies > Office Carts -Office Supplies > Office Carts > AV Carts -Office Supplies > Office Carts > Book Carts -Office Supplies > Office Carts > File Carts -Office Supplies > Office Carts > Mail Carts -Office Supplies > Office Carts > Utility Carts -Office Supplies > Office Equipment -Office Supplies > Office Equipment > Calculators -Office Supplies > Office Equipment > Electronic Dictionaries & Translators -Office Supplies > Office Equipment > Label Makers -Office Supplies > Office Equipment > Office Shredders -Office Supplies > Office Equipment > Postage Meters -Office Supplies > Office Equipment > Time & Attendance Clocks -Office Supplies > Office Equipment > Transcribers & Dictation Systems -Office Supplies > Office Equipment > Typewriters -Office Supplies > Office Instruments -Office Supplies > Office Instruments > Call Bells -Office Supplies > Office Instruments > Clipboards -Office Supplies > Office Instruments > Magnifiers -Office Supplies > Office Instruments > Office Rulers -Office Supplies > Office Instruments > Pencil Sharpeners -Office Supplies > Office Instruments > Rubber Stamps -Office Supplies > Office Instruments > Rubber Stamps > Decorative Rubber Stamps -Office Supplies > Office Instruments > Rubber Stamps > Office Rubber Stamps -Office Supplies > Office Instruments > Scissors -Office Supplies > Office Instruments > Staple Removers -Office Supplies > Office Instruments > Staplers -Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories -Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Marker & Highlighter Ink Refills -Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Pen Ink & Refills -Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Pen Replacement Tips -Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Pencil Lead & Refills -Office Supplies > Office Instruments > Writing & Drawing Instruments -Office Supplies > Office Instruments > Writing & Drawing Instruments > Art Charcoals -Office Supplies > Office Instruments > Writing & Drawing Instruments > Chalk -Office Supplies > Office Instruments > Writing & Drawing Instruments > Crayons -Office Supplies > Office Instruments > Writing & Drawing Instruments > Markers & Highlighters -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pastels -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Multifunction Writing Instruments -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pen & Pencil Sets -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Art Pencils -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Writing Pencils -Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pens -Office Supplies > Paper Handling -Office Supplies > Paper Handling > Craft Knives -Office Supplies > Paper Handling > Cutting Mats -Office Supplies > Paper Handling > Fingertip Grips -Office Supplies > Paper Handling > Hole Punches -Office Supplies > Paper Handling > Hole Punches > Decorative Hole Punches -Office Supplies > Paper Handling > Hole Punches > Office Hole Punches -Office Supplies > Paper Handling > Paper Cutter Accessories -Office Supplies > Paper Handling > Paper Cutter Accessories > Paper Cutter Stands -Office Supplies > Paper Handling > Paper Cutters -Office Supplies > Paper Handling > Paper Folding Machines -Office Supplies > Paper Handling > Paper Joggers -Office Supplies > Paper Handling > Paperweights -Office Supplies > Paper Handling > Pencil Boards -Office Supplies > Presentation Supplies -Office Supplies > Presentation Supplies > Chalkboards -Office Supplies > Presentation Supplies > Display Boards -Office Supplies > Presentation Supplies > Display Boards > Bulletin Board Accessories -Office Supplies > Presentation Supplies > Display Boards > Bulletin Board Accessories > Bulletin Board Trim -Office Supplies > Presentation Supplies > Display Boards > Bulletin Boards -Office Supplies > Presentation Supplies > Display Boards > Foam Boards -Office Supplies > Presentation Supplies > Display Boards > Mounting Boards -Office Supplies > Presentation Supplies > Display Boards > Poster Boards -Office Supplies > Presentation Supplies > Document Cameras -Office Supplies > Presentation Supplies > Easel Pads -Office Supplies > Presentation Supplies > Easels -Office Supplies > Presentation Supplies > Laser Pointers -Office Supplies > Presentation Supplies > Lecterns -Office Supplies > Presentation Supplies > Transparencies -Office Supplies > Presentation Supplies > Whiteboards -Office Supplies > Presentation Supplies > Wireless Presenters -Office Supplies > Shipping Supplies -Office Supplies > Shipping Supplies > Packing Materials -Office Supplies > Shipping Supplies > Packing Tape -Office Supplies > Shipping Supplies > Postal Scales -Office Supplies > Shipping Supplies > Shipping Boxes -Religious & Ceremonial -Religious & Ceremonial > Memorial Ceremony Supplies -Religious & Ceremonial > Memorial Ceremony Supplies > Memorial Urns -Religious & Ceremonial > Religious Items -Religious & Ceremonial > Religious Items > Prayer Beads -Religious & Ceremonial > Religious Items > Religious Altars -Religious & Ceremonial > Religious Items > Religious Veils -Religious & Ceremonial > Wedding Ceremony Supplies -Religious & Ceremonial > Wedding Ceremony Supplies > Flower Girl Baskets -Religious & Ceremonial > Wedding Ceremony Supplies > Ring Pillows -Software -Software > Computer Software -Software > Computer Software > Antivirus & Security Software -Software > Computer Software > Business & Productivity Software -Software > Computer Software > Compilers & Programming Tools -Software > Computer Software > Computer Utilities & Maintenance -Software > Computer Software > Educational Software -Software > Computer Software > Financial, Tax & Accounting Software -Software > Computer Software > Handheld & PDA Software -Software > Computer Software > Multimedia & Design Software -Software > Computer Software > Multimedia & Design Software > 3D Modeling Software -Software > Computer Software > Multimedia & Design Software > Animation Editing Software -Software > Computer Software > Multimedia & Design Software > Graphic Design & Illustration Software -Software > Computer Software > Multimedia & Design Software > Home & Interior Design Software -Software > Computer Software > Multimedia & Design Software > Home Publishing Software -Software > Computer Software > Multimedia & Design Software > Media Viewing Software -Software > Computer Software > Multimedia & Design Software > Music Composition Software -Software > Computer Software > Multimedia & Design Software > Sound Editing Software -Software > Computer Software > Multimedia & Design Software > Video Editing Software -Software > Computer Software > Multimedia & Design Software > Web Design Software -Software > Computer Software > Network Software -Software > Computer Software > Office Application Software -Software > Computer Software > Operating Systems -Software > Computer Software > Reference Software -Software > Computer Software > Reference Software > Dictionary & Translation Software -Software > Computer Software > Reference Software > GPS Map Data & Software -Software > Computer Software > Restore Disks -Software > Digital Goods & Currency -Software > Digital Goods & Currency > Clip Art -Software > Digital Goods & Currency > Computer Icons -Software > Digital Goods & Currency > Desktop Wallpaper -Software > Digital Goods & Currency > Document Templates -Software > Digital Goods & Currency > Fonts -Software > Digital Goods & Currency > Virtual Currency -Software > Video Game Software -Software > Video Game Software > All Game Boy Games -Software > Video Game Software > All Game Boy Games > Game Boy Advance Games -Software > Video Game Software > All Game Boy Games > Game Boy Games -Software > Video Game Software > All PlayStation Games -Software > Video Game Software > All PlayStation Games > PlayStation (original) Games -Software > Video Game Software > All PlayStation Games > PlayStation 2 Games -Software > Video Game Software > All PlayStation Games > PlayStation 3 Games -Software > Video Game Software > All XBox Games -Software > Video Game Software > All XBox Games > XBox (original) Games -Software > Video Game Software > All XBox Games > XBox 360 Games -Software > Video Game Software > Atari 2600 Games -Software > Video Game Software > Atari 5200 Games -Software > Video Game Software > Atari Lynx Games -Software > Video Game Software > ColecoVision Games -Software > Video Game Software > Computer Games -Software > Video Game Software > Computer Games > Mac Games -Software > Video Game Software > Computer Games > PC Games -Software > Video Game Software > Dreamcast Games -Software > Video Game Software > Game Gear Games -Software > Video Game Software > GameCube Games -Software > Video Game Software > Intellivision Games -Software > Video Game Software > Jaguar Games -Software > Video Game Software > LeapFrog Games -Software > Video Game Software > N-Gage Games -Software > Video Game Software > Neo Geo Games -Software > Video Game Software > Neo Geo Pocket Games -Software > Video Game Software > Nintendo 64 Games -Software > Video Game Software > Nintendo DS Games -Software > Video Game Software > Nintendo Entertainment System Games -Software > Video Game Software > PlayStation Portable Games -Software > Video Game Software > PlayStation Vita Games -Software > Video Game Software > Sega Genesis Games -Software > Video Game Software > Sega Master System Games -Software > Video Game Software > Super Nintendo Games -Software > Video Game Software > Turbografx 16 Games -Software > Video Game Software > Wii Games -Software > Video Game Software > Wii U Games -Sporting Goods -Sporting Goods > Air Sports -Sporting Goods > Air Sports > Air Suits -Sporting Goods > Air Sports > Hang Gliding -Sporting Goods > Air Sports > Hang Gliding > Hang Gliders -Sporting Goods > Air Sports > Parachutes -Sporting Goods > Combat Sports -Sporting Goods > Combat Sports > Boxing -Sporting Goods > Combat Sports > Boxing & Martial Arts Protective Gear -Sporting Goods > Combat Sports > Boxing > Boxing Gloves & Mitts -Sporting Goods > Combat Sports > Boxing > Boxing Ring Parts -Sporting Goods > Combat Sports > Boxing > Boxing Rings -Sporting Goods > Combat Sports > Boxing > Punching Bag Accessories -Sporting Goods > Combat Sports > Fencing -Sporting Goods > Combat Sports > Fencing > Fencing Protective Gear -Sporting Goods > Combat Sports > Fencing > Fencing Protective Gear > Fencing Gloves -Sporting Goods > Combat Sports > Fencing > Fencing Protective Gear > Fencing Masks -Sporting Goods > Combat Sports > Fencing > Fencing Weapons -Sporting Goods > Combat Sports > Grappling Dummies -Sporting Goods > Combat Sports > Martial Arts -Sporting Goods > Combat Sports > Martial Arts > Martial Arts Belts -Sporting Goods > Combat Sports > Martial Arts > Martial Arts Weapons -Sporting Goods > Combat Sports > Punching & Training Bag Accessories -Sporting Goods > Combat Sports > Punching & Training Bags -Sporting Goods > Combat Sports > Wrestling -Sporting Goods > Combat Sports > Wrestling > Wrestling Mats -Sporting Goods > Combat Sports > Wrestling > Wrestling Protective Gear -Sporting Goods > Dancing -Sporting Goods > Dancing > Ballet Bars -Sporting Goods > Exercise & Fitness -Sporting Goods > Exercise & Fitness > Abdominal Equipment -Sporting Goods > Exercise & Fitness > Cardio Machine Accessories -Sporting Goods > Exercise & Fitness > Cardio Machines -Sporting Goods > Exercise & Fitness > Cardio Machines > Elliptical Trainers -Sporting Goods > Exercise & Fitness > Cardio Machines > Exercise Bikes -Sporting Goods > Exercise & Fitness > Cardio Machines > Rowing Machines -Sporting Goods > Exercise & Fitness > Cardio Machines > Stair Climbers -Sporting Goods > Exercise & Fitness > Cardio Machines > Treadmills -Sporting Goods > Exercise & Fitness > Exercise Balls -Sporting Goods > Exercise & Fitness > Exercise Bands -Sporting Goods > Exercise & Fitness > Foam Roller Accessories -Sporting Goods > Exercise & Fitness > Foam Roller Accessories > Foam Roller Storage Bags -Sporting Goods > Exercise & Fitness > Foam Rollers -Sporting Goods > Exercise & Fitness > Free Weight Accessories -Sporting Goods > Exercise & Fitness > Free Weight Bars -Sporting Goods > Exercise & Fitness > Free Weights -Sporting Goods > Exercise & Fitness > Gym Mats -Sporting Goods > Exercise & Fitness > Gym Mats > Exercise Equipment Mats -Sporting Goods > Exercise & Fitness > Jump Ropes -Sporting Goods > Exercise & Fitness > Medicine Balls -Sporting Goods > Exercise & Fitness > Reaction Balls -Sporting Goods > Exercise & Fitness > Stopwatches -Sporting Goods > Exercise & Fitness > Weight Benches -Sporting Goods > Exercise & Fitness > Weight Lifting Belts -Sporting Goods > Exercise & Fitness > Weight Lifting Gloves & Hand Supports -Sporting Goods > Exercise & Fitness > Weight Lifting Machine Accessories -Sporting Goods > Exercise & Fitness > Weight Lifting Machines -Sporting Goods > Exercise & Fitness > Weighted Clothing -Sporting Goods > Exercise & Fitness > Yoga & Pilates -Sporting Goods > Exercise & Fitness > Yoga & Pilates > Pilates Machines -Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Blocks -Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Mats -Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga Mat Bags & Straps -Sporting Goods > Exercise & Fitness > Yoga & Pilates Accessories -Sporting Goods > Exercise & Fitness > Yoga & Pilates Accessories > Yoga & Pilates Towels -Sporting Goods > Gymnastics -Sporting Goods > Gymnastics > Balance Beams -Sporting Goods > Gymnastics > Gymnastics Bars -Sporting Goods > Gymnastics > Gymnastics Mats -Sporting Goods > Gymnastics > Gymnastics Protective Gear -Sporting Goods > Gymnastics > Gymnastics Rings -Sporting Goods > Gymnastics > Pommel Horses -Sporting Goods > Gymnastics > Springboards -Sporting Goods > Gymnastics > Vaulting Horses -Sporting Goods > Indoor Games -Sporting Goods > Indoor Games > Air Hockey -Sporting Goods > Indoor Games > Air Hockey > Air Hockey Pucks -Sporting Goods > Indoor Games > Air Hockey > Air Hockey Strikers -Sporting Goods > Indoor Games > Air Hockey > Air Hockey Table Parts -Sporting Goods > Indoor Games > Air Hockey > Air Hockey Tables -Sporting Goods > Indoor Games > Billiards -Sporting Goods > Indoor Games > Billiards > Billiard Ball Racks -Sporting Goods > Indoor Games > Billiards > Billiard Balls -Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories -Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories > Billiard Cue Racks -Sporting Goods > Indoor Games > Billiards > Billiard Cues & Bridges -Sporting Goods > Indoor Games > Billiards > Billiard Gloves -Sporting Goods > Indoor Games > Billiards > Billiard Table Lights -Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories -Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Cloth -Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Pockets -Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Table Brushes -Sporting Goods > Indoor Games > Billiards > Billiard Tables -Sporting Goods > Indoor Games > Bowling -Sporting Goods > Indoor Games > Bowling > Bowling Ball Bags -Sporting Goods > Indoor Games > Bowling > Bowling Balls -Sporting Goods > Indoor Games > Bowling > Bowling Gloves -Sporting Goods > Indoor Games > Bowling > Bowling Pins -Sporting Goods > Indoor Games > Bowling > Bowling Wrist Supports -Sporting Goods > Indoor Games > Darts -Sporting Goods > Indoor Games > Darts > Dart Backboards -Sporting Goods > Indoor Games > Darts > Dart Parts -Sporting Goods > Indoor Games > Darts > Dart Parts > Dart Flights -Sporting Goods > Indoor Games > Darts > Dart Parts > Dart Shafts -Sporting Goods > Indoor Games > Darts > Dart Parts > Dart Tips -Sporting Goods > Indoor Games > Darts > Dartboards -Sporting Goods > Indoor Games > Darts > Single Darts -Sporting Goods > Indoor Games > Foosball -Sporting Goods > Indoor Games > Foosball > Foosball Balls -Sporting Goods > Indoor Games > Foosball > Foosball Table Parts -Sporting Goods > Indoor Games > Foosball > Foosball Tables -Sporting Goods > Indoor Games > Multi-Game Tables -Sporting Goods > Indoor Games > Ping Pong -Sporting Goods > Indoor Games > Ping Pong > Ping Pong Balls -Sporting Goods > Indoor Games > Ping Pong > Ping Pong Nets & Posts -Sporting Goods > Indoor Games > Ping Pong > Ping Pong Paddle Accessories -Sporting Goods > Indoor Games > Ping Pong > Ping Pong Paddles -Sporting Goods > Indoor Games > Ping Pong > Ping Pong Robot Accessories -Sporting Goods > Indoor Games > Ping Pong > Ping Pong Robots -Sporting Goods > Indoor Games > Ping Pong > Ping Pong Tables -Sporting Goods > Indoor Games > Table Shuffleboard -Sporting Goods > Indoor Games > Table Shuffleboard > Shuffleboard Tables -Sporting Goods > Indoor Games > Table Shuffleboard > Table Shuffleboard Powder -Sporting Goods > Indoor Games > Table Shuffleboard > Table Shuffleboard Pucks -Sporting Goods > Jumping -Sporting Goods > Jumping > Bungee Jumping -Sporting Goods > Jumping > Jumping Stilts -Sporting Goods > Jumping > Pogo Sticks -Sporting Goods > Jumping > Trampoline Accessories -Sporting Goods > Jumping > Trampoline Accessories > Trampoline Anchors -Sporting Goods > Jumping > Trampoline Accessories > Trampoline Ladders -Sporting Goods > Jumping > Trampoline Accessories > Trampoline Mats -Sporting Goods > Jumping > Trampoline Accessories > Trampoline Nets -Sporting Goods > Jumping > Trampoline Accessories > Trampoline Safety Pads -Sporting Goods > Jumping > Trampoline Accessories > Trampoline Springs -Sporting Goods > Jumping > Trampolines -Sporting Goods > Outdoor Recreation -Sporting Goods > Outdoor Recreation > Archery -Sporting Goods > Outdoor Recreation > Archery > Archery Armguards -Sporting Goods > Outdoor Recreation > Archery > Archery Bow Cases -Sporting Goods > Outdoor Recreation > Archery > Archery Targets -Sporting Goods > Outdoor Recreation > Archery > Arrow Parts & Accessories -Sporting Goods > Outdoor Recreation > Archery > Arrows -Sporting Goods > Outdoor Recreation > Archery > Compound Bows -Sporting Goods > Outdoor Recreation > Archery > Crossbows -Sporting Goods > Outdoor Recreation > Archery > Quivers -Sporting Goods > Outdoor Recreation > Archery > Recurve & Longbows -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camp Furniture -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camp Furniture > Air Mattress Accessories -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camp Furniture > Air Mattresses -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camp Furniture > Cots -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camping Cookware & Dinnerware -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camping Lights & Lanterns -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camping Tools -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camping Tools > Knives & Blades -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camping Tools > Knives & Blades > Hunting & Survival Knives -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Camping Tools > Multifunction Tools & Knives -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Chemical Hand Warmers -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Compression Sacks -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Crampons -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Emergency Blankets -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Freeze-Dried Food -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Hiking Pole Accessories -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Hiking Poles -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Mosquito Nets -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Navigational Compasses -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Portable Toilets -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Portable Urination Devices -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Portable Water Filters & Purifiers -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Sleeping Bag Liners -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Sleeping Bags -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Sleeping Pads -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Tent Accessories -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Tent Accessories > Tent Footprints -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Tent Accessories > Tent Poles & Stakes -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Tent Accessories > Tent Vestibules -Sporting Goods > Outdoor Recreation > Camping, Backpacking & Hiking > Tents -Sporting Goods > Outdoor Recreation > Climbing -Sporting Goods > Outdoor Recreation > Climbing > Ice Climbing -Sporting Goods > Outdoor Recreation > Climbing > Ice Climbing > Ice Climbing Tools -Sporting Goods > Outdoor Recreation > Climbing > Ice Climbing > Ice Screws -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Ascenders & Descenders -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Belay Devices -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Carabiners -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Chalk -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Chalk Bags -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Harnesses -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Helmets -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Protection Devices -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Rope -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Rope Bags -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Climbing Webbing -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Crash Pads -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Indoor Climbing Holds -Sporting Goods > Outdoor Recreation > Climbing > Rock Climbing > Quickdraws -Sporting Goods > Outdoor Recreation > Cycling -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Bags & Panniers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Baskets -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Bells & Horns -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Cages -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Child Seats -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Computer Accessories -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Computers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Covers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Fenders -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Front & Rear Racks -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Lights & Reflectors -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Locks -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Mirrors -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Pumps -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Saddle Pads & Seat Covers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Shock Pumps -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Spoke Beads -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Stands & Storage -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Surfboard Racks -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Toe Straps & Clips -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Tools, Cleaners & Lubricants -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Tools, Cleaners & Lubricants > Bicycle Lubrication -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Tools, Cleaners & Lubricants > Bicycle Spoke Wrenches -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Trailers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Trainers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Training Wheels -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Transport Bags & Cases -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Cleat Accessories -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Cleat Accessories > Bicycle Cleat Bolts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Cleat Accessories > Bicycle Cleat Covers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Cleat Accessories > Bicycle Cleat Shims & Wedges -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Cleats -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Gloves -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Helmet Covers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Helmets -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Gear > Bicycle Shoe Covers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Calipers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Levers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Rotors -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Sets -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Bottom Brackets -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Cassettes -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Chainrings -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Chains -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Cranks -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Derailleurs -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Pedals -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Shifters -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Forks -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Frames -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Grips & Handlebar Tape -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Handlebar Extensions -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Handlebars -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts > Bicycle Headset Bearings -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts > Bicycle Headset Spacers -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headsets -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Saddles -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Seatpost Clamps -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Seatposts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Small Parts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Small Parts > Bicycle Accessory Mounts & Brackets -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Small Parts > Bicycle Seatpost Shims -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Stems -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tires -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tubes -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Foot Pegs -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Hubs -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Spokes -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Nipples -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Rims -Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheels -Sporting Goods > Outdoor Recreation > Cycling > Bicycles -Sporting Goods > Outdoor Recreation > Cycling > Bicycles > Cruisers -Sporting Goods > Outdoor Recreation > Cycling > Bicycles > Electric Bicycles -Sporting Goods > Outdoor Recreation > Cycling > Bicycles > Hybrid Bicycles -Sporting Goods > Outdoor Recreation > Cycling > Bicycles > Mountain Bicycles -Sporting Goods > Outdoor Recreation > Cycling > Bicycles > Recumbent Bicycles -Sporting Goods > Outdoor Recreation > Cycling > Bicycles > Road Bicycles -Sporting Goods > Outdoor Recreation > Cycling > Bicycles > Triathlon Bicycles -Sporting Goods > Outdoor Recreation > Cycling > Tricycle Accessories -Sporting Goods > Outdoor Recreation > Cycling > Tricycles -Sporting Goods > Outdoor Recreation > Cycling > Tricycles > Recumbent Tricycles -Sporting Goods > Outdoor Recreation > Cycling > Unicycle Accessories -Sporting Goods > Outdoor Recreation > Cycling > Unicycles -Sporting Goods > Outdoor Recreation > Deck Shuffleboard -Sporting Goods > Outdoor Recreation > Deck Shuffleboard > Deck Shuffleboard Cues -Sporting Goods > Outdoor Recreation > Deck Shuffleboard > Deck Shuffleboard Pucks -Sporting Goods > Outdoor Recreation > Disc Golf -Sporting Goods > Outdoor Recreation > Disc Golf > Disc Golf Bags -Sporting Goods > Outdoor Recreation > Disc Golf > Disc Golf Baskets -Sporting Goods > Outdoor Recreation > Disc Golf > Disc Golf Discs -Sporting Goods > Outdoor Recreation > Equestrian -Sporting Goods > Outdoor Recreation > Equestrian > Horse Boots & Leg Wraps -Sporting Goods > Outdoor Recreation > Equestrian > Horse Boots & Leg Wraps > Bell Boots -Sporting Goods > Outdoor Recreation > Equestrian > Horse Boots & Leg Wraps > Splint Boots -Sporting Goods > Outdoor Recreation > Equestrian > Horse Supplies -Sporting Goods > Outdoor Recreation > Equestrian > Horse Supplies > Horse Blankets & Sheets -Sporting Goods > Outdoor Recreation > Equestrian > Horse Supplies > Horse Feed -Sporting Goods > Outdoor Recreation > Equestrian > Horse Supplies > Horse Grooming -Sporting Goods > Outdoor Recreation > Equestrian > Horse Supplies > Horse Grooming > Horse Clippers & Trimmers -Sporting Goods > Outdoor Recreation > Equestrian > Horse Supplies > Horse Treats -Sporting Goods > Outdoor Recreation > Equestrian > Horse Supplies > Horse Vitamins & Supplements -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Bridles -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Cinches -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Bits -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Harnesses -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Reins -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Saddles -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories -Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Racks -Sporting Goods > Outdoor Recreation > Equestrian > Riding Gear -Sporting Goods > Outdoor Recreation > Equestrian > Riding Gear > Equestrian Gloves -Sporting Goods > Outdoor Recreation > Equestrian > Riding Gear > Equestrian Helmets -Sporting Goods > Outdoor Recreation > Equestrian > Riding Gear > Riding Crops -Sporting Goods > Outdoor Recreation > Equestrian > Riding Gear > Riding Pants -Sporting Goods > Outdoor Recreation > Fishing -Sporting Goods > Outdoor Recreation > Fishing > Fishing & Hunting Waders -Sporting Goods > Outdoor Recreation > Fishing > Fishing Bait & Chum Containers -Sporting Goods > Outdoor Recreation > Fishing > Fishing Floats -Sporting Goods > Outdoor Recreation > Fishing > Fishing Gaffs -Sporting Goods > Outdoor Recreation > Fishing > Fishing Hook Removal Tools -Sporting Goods > Outdoor Recreation > Fishing > Fishing Hooks -Sporting Goods > Outdoor Recreation > Fishing > Fishing Lines & Leaders -Sporting Goods > Outdoor Recreation > Fishing > Fishing Lures -Sporting Goods > Outdoor Recreation > Fishing > Fishing Lures > Fishing Flies -Sporting Goods > Outdoor Recreation > Fishing > Fishing Nets -Sporting Goods > Outdoor Recreation > Fishing > Fishing Reels -Sporting Goods > Outdoor Recreation > Fishing > Fishing Rods -Sporting Goods > Outdoor Recreation > Fishing > Fishing Sinkers -Sporting Goods > Outdoor Recreation > Fishing > Fishing Snaps & Swivels -Sporting Goods > Outdoor Recreation > Fishing > Fishing Spears -Sporting Goods > Outdoor Recreation > Fishing > Fishing Traps -Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials -Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials > Fishing Beads -Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials > Fishing Yarn -Sporting Goods > Outdoor Recreation > Fishing > Live Bait -Sporting Goods > Outdoor Recreation > Fishing > Tackle Bags & Boxes -Sporting Goods > Outdoor Recreation > Geocaching -Sporting Goods > Outdoor Recreation > Geocaching > Geocaches -Sporting Goods > Outdoor Recreation > Geocaching > Geocaching Log Sheets -Sporting Goods > Outdoor Recreation > Geocaching > Geocaching Trackables -Sporting Goods > Outdoor Recreation > Golf -Sporting Goods > Outdoor Recreation > Golf > Divot Tools -Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories -Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories > Golf Bag Carts -Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories > Golf Bag Covers & Cases -Sporting Goods > Outdoor Recreation > Golf > Golf Bags -Sporting Goods > Outdoor Recreation > Golf > Golf Ball Markers -Sporting Goods > Outdoor Recreation > Golf > Golf Balls -Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories -Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Grips -Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Head Covers -Sporting Goods > Outdoor Recreation > Golf > Golf Clubs -Sporting Goods > Outdoor Recreation > Golf > Golf Flags -Sporting Goods > Outdoor Recreation > Golf > Golf Gloves -Sporting Goods > Outdoor Recreation > Golf > Golf Kits -Sporting Goods > Outdoor Recreation > Golf > Golf Tees -Sporting Goods > Outdoor Recreation > Golf > Golf Towels -Sporting Goods > Outdoor Recreation > Golf > Golf Training Aids -Sporting Goods > Outdoor Recreation > Hunting -Sporting Goods > Outdoor Recreation > Hunting & Shooting Protective Gear -Sporting Goods > Outdoor Recreation > Hunting & Shooting Protective Gear > Hunting & Shooting Gloves -Sporting Goods > Outdoor Recreation > Hunting & Shooting Protective Gear > Hunting & Shooting Jackets -Sporting Goods > Outdoor Recreation > Hunting > Animal Traps -Sporting Goods > Outdoor Recreation > Hunting > Game Feeders -Sporting Goods > Outdoor Recreation > Hunting > Hunting Blinds & Screens -Sporting Goods > Outdoor Recreation > Hunting > Hunting Calls -Sporting Goods > Outdoor Recreation > Hunting > Hunting Decoys -Sporting Goods > Outdoor Recreation > Hunting > Hunting Dog Equipment -Sporting Goods > Outdoor Recreation > Hunting > Hunting Shelters -Sporting Goods > Outdoor Recreation > Hunting > Tree Stands -Sporting Goods > Outdoor Recreation > Hunting > Wildlife Attractant -Sporting Goods > Outdoor Recreation > Hydration System Accessories -Sporting Goods > Outdoor Recreation > Hydration Systems -Sporting Goods > Outdoor Recreation > Kite Buggying -Sporting Goods > Outdoor Recreation > Kite Buggying > Kite Buggies -Sporting Goods > Outdoor Recreation > Kite Buggying Accessories -Sporting Goods > Outdoor Recreation > Lawn Games -Sporting Goods > Outdoor Recreation > Lawn Games > Bean Bag Toss -Sporting Goods > Outdoor Recreation > Lawn Games > Bocce -Sporting Goods > Outdoor Recreation > Lawn Games > Croquet -Sporting Goods > Outdoor Recreation > Lawn Games > Horseshoe Toss -Sporting Goods > Outdoor Recreation > Lawn Games > Ladder Golf -Sporting Goods > Outdoor Recreation > Lawn Games > Lawn Bowling -Sporting Goods > Outdoor Recreation > Lawn Games > Lawn Bowling > Lawn Bowling Bowls -Sporting Goods > Outdoor Recreation > Lawn Games > Lawn Bowling > Lawn Bowling Jacks -Sporting Goods > Outdoor Recreation > Lawn Games > Lawn Darts -Sporting Goods > Outdoor Recreation > Lawn Games > Ring Toss -Sporting Goods > Outdoor Recreation > Lawn Games > Washer Pitching -Sporting Goods > Outdoor Recreation > Motorsports -Sporting Goods > Outdoor Recreation > Motorsports > Auto Racing -Sporting Goods > Outdoor Recreation > Reflective Fitness Clothing -Sporting Goods > Outdoor Recreation > Reflective Fitness Clothing > Reflective Belts -Sporting Goods > Outdoor Recreation > Riding Scooters -Sporting Goods > Outdoor Recreation > Riding Scooters > Kick Scooters -Sporting Goods > Outdoor Recreation > Riding Scooters > Powered Scooters -Sporting Goods > Outdoor Recreation > Running -Sporting Goods > Outdoor Recreation > Shooting Games -Sporting Goods > Outdoor Recreation > Shooting Games > Airsoft -Sporting Goods > Outdoor Recreation > Shooting Games > Airsoft > Airsoft Gun Parts & Accessories -Sporting Goods > Outdoor Recreation > Shooting Games > Airsoft > Airsoft Gun Parts & Accessories > Airsoft Gun Batteries -Sporting Goods > Outdoor Recreation > Shooting Games > Airsoft > Airsoft Guns -Sporting Goods > Outdoor Recreation > Shooting Games > Airsoft > Airsoft Pellets -Sporting Goods > Outdoor Recreation > Shooting Games > Airsoft > Airsoft Protective Gear -Sporting Goods > Outdoor Recreation > Shooting Games > Clay Pigeon Shooting -Sporting Goods > Outdoor Recreation > Shooting Games > Clay Pigeon Shooting > Clay Pigeon Throwers -Sporting Goods > Outdoor Recreation > Shooting Games > Clay Pigeon Shooting > Clay Pigeons -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Air Tanks -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Grenade Launchers -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Grenades -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Gun Parts -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Gun Parts > Paintball Gun Barrels -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Gun Parts > Paintball Hoppers -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Guns -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Harnesses & Packs -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Protective Gear -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Protective Gear > Paintball Gloves -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Protective Gear > Paintball Goggles & Masks -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Protective Gear > Paintball Pads -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintball Protective Gear > Paintball Vests -Sporting Goods > Outdoor Recreation > Shooting Games > Paintball > Paintballs -Sporting Goods > Outdoor Recreation > Shooting Games > Shooting Targets -Sporting Goods > Outdoor Recreation > Skateboarding -Sporting Goods > Outdoor Recreation > Skateboarding > Skate Rails -Sporting Goods > Outdoor Recreation > Skateboarding > Skate Ramps -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Bearings -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Decks -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Trucks -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Wheels -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Protective Gear -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Protective Gear > Skateboard Helmets -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Protective Gear > Skateboard Pads -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Protective Gear > Skateboarding Gloves -Sporting Goods > Outdoor Recreation > Skateboarding > Skateboards -Sporting Goods > Outdoor Recreation > Skating -Sporting Goods > Outdoor Recreation > Skating > Figure Skate Boots -Sporting Goods > Outdoor Recreation > Skating > Ice Skate Blades -Sporting Goods > Outdoor Recreation > Skating > Ice Skate Sharpeners -Sporting Goods > Outdoor Recreation > Skating > Ice Skates -Sporting Goods > Outdoor Recreation > Skating > Ice Skates > Figure Skates -Sporting Goods > Outdoor Recreation > Skating > Ice Skates > Ice Hockey Skates -Sporting Goods > Outdoor Recreation > Skating > Inline Skates -Sporting Goods > Outdoor Recreation > Skating > Lace Tighteners -Sporting Goods > Outdoor Recreation > Skating > Roller Skates -Sporting Goods > Outdoor Recreation > Skating > Skate Blade Guards -Sporting Goods > Outdoor Recreation > Skating > Skate Parts -Sporting Goods > Outdoor Recreation > Skating > Skating Helmets & Pads -Sporting Goods > Outdoor Recreation > Stadium Seats & Cushions -Sporting Goods > Outdoor Recreation > Tetherball -Sporting Goods > Outdoor Recreation > Track & Field -Sporting Goods > Outdoor Recreation > Track & Field > Discuses -Sporting Goods > Outdoor Recreation > Track & Field > High Jump Bars -Sporting Goods > Outdoor Recreation > Track & Field > High Jump Pits -Sporting Goods > Outdoor Recreation > Track & Field > Hurdles -Sporting Goods > Outdoor Recreation > Track & Field > Javelins -Sporting Goods > Outdoor Recreation > Track & Field > Pole Vault Pits -Sporting Goods > Outdoor Recreation > Track & Field > Relay Batons -Sporting Goods > Outdoor Recreation > Track & Field > Shot Puts -Sporting Goods > Outdoor Recreation > Track & Field > Starter Pistols -Sporting Goods > Outdoor Recreation > Track & Field > Throwing Hammers -Sporting Goods > Outdoor Recreation > Track & Field > Vaulting Poles -Sporting Goods > Racquet Sports -Sporting Goods > Racquet Sports > Badminton -Sporting Goods > Racquet Sports > Badminton > Badminton Nets -Sporting Goods > Racquet Sports > Badminton > Badminton Rackets -Sporting Goods > Racquet Sports > Badminton > Shuttlecocks -Sporting Goods > Racquet Sports > Paddle Ball Sets -Sporting Goods > Racquet Sports > Paddle Tennis -Sporting Goods > Racquet Sports > Pickleball -Sporting Goods > Racquet Sports > Platform Tennis -Sporting Goods > Racquet Sports > Racquetball -Sporting Goods > Racquet Sports > Racquetball > Racquetball Protective Gear -Sporting Goods > Racquet Sports > Racquetball > Racquetball Protective Gear > Squash & Racquetball Goggles -Sporting Goods > Racquet Sports > Racquetball > Racquetball Rackets -Sporting Goods > Racquet Sports > Racquetball > Racquetballs -Sporting Goods > Racquet Sports > Squash -Sporting Goods > Racquet Sports > Squash > Squash Balls -Sporting Goods > Racquet Sports > Squash > Squash Protective Gear -Sporting Goods > Racquet Sports > Squash > Squash Rackets -Sporting Goods > Racquet Sports > Tennis -Sporting Goods > Racquet Sports > Tennis > Tennis Ball Hoppers -Sporting Goods > Racquet Sports > Tennis > Tennis Ball Machines -Sporting Goods > Racquet Sports > Tennis > Tennis Ball Savers -Sporting Goods > Racquet Sports > Tennis > Tennis Balls -Sporting Goods > Racquet Sports > Tennis > Tennis Nets -Sporting Goods > Racquet Sports > Tennis > Tennis Racket Accessories -Sporting Goods > Racquet Sports > Tennis > Tennis Racket Accessories > Racket Grip Tape -Sporting Goods > Racquet Sports > Tennis > Tennis Racket Accessories > Racket Vibration Dampeners -Sporting Goods > Racquet Sports > Tennis > Tennis Racket Accessories > Tennis Racket Bags -Sporting Goods > Racquet Sports > Tennis > Tennis Racket Accessories > Tennis Racket Grommets -Sporting Goods > Racquet Sports > Tennis > Tennis Racket Accessories > Tennis Racket String -Sporting Goods > Racquet Sports > Tennis > Tennis Rackets -Sporting Goods > Team Sports -Sporting Goods > Team Sports > Ball Carrying Bags -Sporting Goods > Team Sports > Ball Pump Accessories -Sporting Goods > Team Sports > Ball Pump Accessories > Ball Pump Needles -Sporting Goods > Team Sports > Ball Pumps -Sporting Goods > Team Sports > Baseball -Sporting Goods > Team Sports > Baseball > Baseball & Softball Gloves -Sporting Goods > Team Sports > Baseball > Baseball & Softball Gloves > Baseball Gloves & Mitts -Sporting Goods > Team Sports > Baseball > Baseball & Softball Gloves > Softball Gloves & Mitts -Sporting Goods > Team Sports > Baseball > Baseball Bats -Sporting Goods > Team Sports > Baseball > Baseball Diamond Bases -Sporting Goods > Team Sports > Baseball > Baseball Protective Gear -Sporting Goods > Team Sports > Baseball > Baseball Protective Gear > Batting Helmets -Sporting Goods > Team Sports > Baseball > Baseball Screens -Sporting Goods > Team Sports > Baseball > Baseballs -Sporting Goods > Team Sports > Baseball > Batting Gloves -Sporting Goods > Team Sports > Baseball > Pitching Machines -Sporting Goods > Team Sports > Basketball -Sporting Goods > Team Sports > Basketball > Basketball Hoop Parts & Accessories -Sporting Goods > Team Sports > Basketball > Basketball Hoop Parts & Accessories > Basketball Backboards -Sporting Goods > Team Sports > Basketball > Basketball Hoop Parts & Accessories > Basketball Hoop Padding -Sporting Goods > Team Sports > Basketball > Basketball Hoop Parts & Accessories > Basketball Nets -Sporting Goods > Team Sports > Basketball > Basketball Hoop Parts & Accessories > Basketball Poles -Sporting Goods > Team Sports > Basketball > Basketball Hoop Parts & Accessories > Basketball Rims -Sporting Goods > Team Sports > Basketball > Basketball Hoops -Sporting Goods > Team Sports > Basketball > Basketballs -Sporting Goods > Team Sports > Beach Volleyball -Sporting Goods > Team Sports > Beach Volleyball > Beach Volleyball Balls -Sporting Goods > Team Sports > Beach Volleyball > Beach Volleyball Nets -Sporting Goods > Team Sports > Broomball -Sporting Goods > Team Sports > Broomball > Broomball Sticks -Sporting Goods > Team Sports > Cheerleading -Sporting Goods > Team Sports > Cheerleading > Cheerleading Megaphones -Sporting Goods > Team Sports > Cheerleading > Pom-Poms -Sporting Goods > Team Sports > Cricket -Sporting Goods > Team Sports > Cricket > Cricket Balls -Sporting Goods > Team Sports > Cricket > Cricket Bats -Sporting Goods > Team Sports > Cricket > Cricket Gloves -Sporting Goods > Team Sports > Cricket > Cricket Helmets -Sporting Goods > Team Sports > Curling -Sporting Goods > Team Sports > Field Hockey -Sporting Goods > Team Sports > Field Hockey > Field Hockey Balls -Sporting Goods > Team Sports > Field Hockey > Field Hockey Gloves -Sporting Goods > Team Sports > Field Hockey > Field Hockey Goals -Sporting Goods > Team Sports > Field Hockey > Field Hockey Sticks -Sporting Goods > Team Sports > Football -Sporting Goods > Team Sports > Football > Football Gloves -Sporting Goods > Team Sports > Football > Football Goal Posts -Sporting Goods > Team Sports > Football > Football Kicking Tees -Sporting Goods > Team Sports > Football > Football Protective Gear -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Girdles -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Helmet Accessories -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Helmet Accessories > Football Chin Straps -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Helmet Accessories > Football Face Masks -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Helmet Accessories > Football Helmet Padding -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Helmet Accessories > Football Helmet Visors -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Helmets -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Neck Rolls -Sporting Goods > Team Sports > Football > Football Protective Gear > Football Shoulder Pads -Sporting Goods > Team Sports > Football > Football Training Equipment -Sporting Goods > Team Sports > Football > Footballs -Sporting Goods > Team Sports > Hockey -Sporting Goods > Team Sports > Hockey > Hockey Balls & Pucks -Sporting Goods > Team Sports > Hockey > Hockey Balls & Pucks > Ice Hockey Pucks -Sporting Goods > Team Sports > Hockey > Hockey Balls & Pucks > Roller Hockey Balls -Sporting Goods > Team Sports > Hockey > Hockey Goals -Sporting Goods > Team Sports > Hockey > Hockey Goals > Ice Hockey Goals -Sporting Goods > Team Sports > Hockey > Hockey Protective Gear -Sporting Goods > Team Sports > Hockey > Hockey Protective Gear > Hockey Body Pads -Sporting Goods > Team Sports > Hockey > Hockey Protective Gear > Hockey Gloves -Sporting Goods > Team Sports > Hockey > Hockey Protective Gear > Hockey Gloves > Ice Hockey Gloves -Sporting Goods > Team Sports > Hockey > Hockey Protective Gear > Hockey Helmets -Sporting Goods > Team Sports > Hockey > Hockey Protective Gear > Hockey Helmets > Ice Hockey Helmets -Sporting Goods > Team Sports > Hockey > Hockey Protective Gear > Hockey Pants -Sporting Goods > Team Sports > Hockey > Hockey Sledges -Sporting Goods > Team Sports > Hockey > Hockey Stick Care -Sporting Goods > Team Sports > Hockey > Hockey Stick Parts -Sporting Goods > Team Sports > Hockey > Hockey Stick Parts > Hockey Shafts -Sporting Goods > Team Sports > Hockey > Hockey Stick Parts > Hockey Stick Blades -Sporting Goods > Team Sports > Hockey > Hockey Sticks -Sporting Goods > Team Sports > Hockey > Hockey Sticks > Ice Hockey Sticks -Sporting Goods > Team Sports > Hockey > Hockey Sticks > Roller & Street Hockey Sticks -Sporting Goods > Team Sports > Indoor Volleyball -Sporting Goods > Team Sports > Indoor Volleyball > Indoor Volleyball Balls -Sporting Goods > Team Sports > Indoor Volleyball > Indoor Volleyball Nets -Sporting Goods > Team Sports > Indoor Volleyball > Volleyball Bags -Sporting Goods > Team Sports > Lacrosse -Sporting Goods > Team Sports > Lacrosse > Lacrosse Balls -Sporting Goods > Team Sports > Lacrosse > Lacrosse Goals -Sporting Goods > Team Sports > Lacrosse > Lacrosse Protective Gear -Sporting Goods > Team Sports > Lacrosse > Lacrosse Protective Gear > Lacrosse Arm Guards -Sporting Goods > Team Sports > Lacrosse > Lacrosse Protective Gear > Lacrosse Gloves -Sporting Goods > Team Sports > Lacrosse > Lacrosse Protective Gear > Lacrosse Helmets -Sporting Goods > Team Sports > Lacrosse > Lacrosse Protective Gear > Lacrosse Masks & Goggles -Sporting Goods > Team Sports > Lacrosse > Lacrosse Protective Gear > Lacrosse Shoulder Pads -Sporting Goods > Team Sports > Lacrosse > Lacrosse Stick Parts -Sporting Goods > Team Sports > Lacrosse > Lacrosse Stick Parts > Lacrosse Mesh & String -Sporting Goods > Team Sports > Lacrosse > Lacrosse Stick Parts > Lacrosse Stick Heads -Sporting Goods > Team Sports > Lacrosse > Lacrosse Stick Parts > Lacrosse Stick Shafts -Sporting Goods > Team Sports > Lacrosse > Lacrosse Sticks -Sporting Goods > Team Sports > Lacrosse > Lacrosse Training Equipment -Sporting Goods > Team Sports > Referee Accessories -Sporting Goods > Team Sports > Referee Accessories > Linesman Flags -Sporting Goods > Team Sports > Referee Accessories > Penalty Cards -Sporting Goods > Team Sports > Referee Accessories > Referee Whistles -Sporting Goods > Team Sports > Rounders -Sporting Goods > Team Sports > Rounders > Rounders Bats -Sporting Goods > Team Sports > Rounders > Rounders Gloves -Sporting Goods > Team Sports > Rugby -Sporting Goods > Team Sports > Rugby > Rugby Balls -Sporting Goods > Team Sports > Rugby > Rugby Gloves -Sporting Goods > Team Sports > Rugby > Rugby Helmets -Sporting Goods > Team Sports > Rugby > Rugby Posts -Sporting Goods > Team Sports > Rugby > Rugby Training Equipment -Sporting Goods > Team Sports > Soccer -Sporting Goods > Team Sports > Soccer > Soccer Balls -Sporting Goods > Team Sports > Soccer > Soccer Balls > Futsal Balls -Sporting Goods > Team Sports > Soccer > Soccer Captain Armbands -Sporting Goods > Team Sports > Soccer > Soccer Corner Flags -Sporting Goods > Team Sports > Soccer > Soccer Gloves -Sporting Goods > Team Sports > Soccer > Soccer Goal Accessories -Sporting Goods > Team Sports > Soccer > Soccer Goals -Sporting Goods > Team Sports > Soccer > Soccer Shin Guards -Sporting Goods > Team Sports > Softball -Sporting Goods > Team Sports > Softball > Softball Bats -Sporting Goods > Team Sports > Softball > Softball Protective Gear -Sporting Goods > Team Sports > Softball > Softballs -Sporting Goods > Team Sports > Team Handball -Sporting Goods > Water Sports -Sporting Goods > Water Sports > Boating -Sporting Goods > Water Sports > Boating > Boating Gloves -Sporting Goods > Water Sports > Boating > Canoeing -Sporting Goods > Water Sports > Boating > Canoeing > Canoeing Accessories -Sporting Goods > Water Sports > Boating > Canoeing > Canoes -Sporting Goods > Water Sports > Boating > Kayaking -Sporting Goods > Water Sports > Boating > Kayaking > Kayaking Accessories -Sporting Goods > Water Sports > Boating > Kayaking > Kayaking Accessories > Spray Skirts -Sporting Goods > Water Sports > Boating > Kayaking > Kayaks -Sporting Goods > Water Sports > Boating > Pedal Boats -Sporting Goods > Water Sports > Boating > Rafts -Sporting Goods > Water Sports > Boating > Rowing -Sporting Goods > Water Sports > Boating > Rowing > Rowing Boats -Sporting Goods > Water Sports > Boating > Rowing > Rowing Seat Pads -Sporting Goods > Water Sports > Boating > Sailing & Yachting -Sporting Goods > Water Sports > Kitesurfing -Sporting Goods > Water Sports > Kitesurfing > Kiteboard Cases -Sporting Goods > Water Sports > Kitesurfing > Kiteboard Parts -Sporting Goods > Water Sports > Kitesurfing > Kiteboards -Sporting Goods > Water Sports > Kitesurfing > Kitesurfing Harnesses -Sporting Goods > Water Sports > Kitesurfing > Kitesurfing Kites -Sporting Goods > Water Sports > Life Jacket Accessories -Sporting Goods > Water Sports > Life Jackets -Sporting Goods > Water Sports > Paddles & Oars -Sporting Goods > Water Sports > Rash Guards -Sporting Goods > Water Sports > Scuba Diving & Snorkeling -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Buoyancy Compensators -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Dive Computers -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Diving & Snorkeling Fins -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Diving & Snorkeling Masks -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Diving Belts -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Diving Knives & Shears -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Drysuits -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Regulators -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Scuba Diving & Snorkeling Gloves -Sporting Goods > Water Sports > Scuba Diving & Snorkeling > Snorkels -Sporting Goods > Water Sports > Surfing -Sporting Goods > Water Sports > Surfing > Bodyboards -Sporting Goods > Water Sports > Surfing > Paddleboards -Sporting Goods > Water Sports > Surfing > Skimboards -Sporting Goods > Water Sports > Surfing > Surfboard Cases & Bags -Sporting Goods > Water Sports > Surfing > Surfboard Fins -Sporting Goods > Water Sports > Surfing > Surfboard Leashes -Sporting Goods > Water Sports > Surfing > Surfboard Wax -Sporting Goods > Water Sports > Surfing > Surfboards -Sporting Goods > Water Sports > Surfing > Surfing Gloves -Sporting Goods > Water Sports > Surfing > Surfing Tail Pads -Sporting Goods > Water Sports > Swimming -Sporting Goods > Water Sports > Swimming > Hand Paddles -Sporting Goods > Water Sports > Swimming > Kickboards -Sporting Goods > Water Sports > Swimming > Pull Buoys -Sporting Goods > Water Sports > Swimming > Swim Belts -Sporting Goods > Water Sports > Swimming > Swim Caps -Sporting Goods > Water Sports > Swimming > Swim Gloves -Sporting Goods > Water Sports > Swimming > Swim Goggle & Mask Accessories -Sporting Goods > Water Sports > Swimming > Swim Goggles & Masks -Sporting Goods > Water Sports > Swimming > Swim Weights -Sporting Goods > Water Sports > Swimming > Swimming Fins -Sporting Goods > Water Sports > Swimming > Swimming Fins > Monofins -Sporting Goods > Water Sports > Swimming > Swimming Fins > Training Fins -Sporting Goods > Water Sports > Swimming > Swimming Machines -Sporting Goods > Water Sports > Swimming > Swimming Nose Clips -Sporting Goods > Water Sports > Towed Water Sports -Sporting Goods > Water Sports > Towed Water Sports > Kneeboarding -Sporting Goods > Water Sports > Towed Water Sports > Kneeboarding > Kneeboards -Sporting Goods > Water Sports > Towed Water Sports > Parasailing -Sporting Goods > Water Sports > Towed Water Sports > Tow Cables -Sporting Goods > Water Sports > Towed Water Sports > Towable Rafts & Tubes -Sporting Goods > Water Sports > Towed Water Sports > Towed Water Sport Gloves -Sporting Goods > Water Sports > Towed Water Sports > Wakeboarding -Sporting Goods > Water Sports > Towed Water Sports > Wakeboarding > Wakeboard Bindings -Sporting Goods > Water Sports > Towed Water Sports > Wakeboarding > Wakeboards -Sporting Goods > Water Sports > Towed Water Sports > Water Skiing -Sporting Goods > Water Sports > Towed Water Sports > Water Skiing > Sit-Down Hydrofoils -Sporting Goods > Water Sports > Towed Water Sports > Water Skiing > Water Ski Bindings -Sporting Goods > Water Sports > Towed Water Sports > Water Skiing > Water Skiing Cases & Bags -Sporting Goods > Water Sports > Towed Water Sports > Water Skiing > Water Skis -Sporting Goods > Water Sports > Water Polo -Sporting Goods > Water Sports > Water Polo > Water Polo Balls -Sporting Goods > Water Sports > Water Polo > Water Polo Caps -Sporting Goods > Water Sports > Water Polo > Water Polo Goals -Sporting Goods > Water Sports > Water Tubing -Sporting Goods > Water Sports > Watercraft Storage Racks -Sporting Goods > Water Sports > Wetsuits -Sporting Goods > Water Sports > Wetsuits > Wetsuit Accessories -Sporting Goods > Water Sports > Wetsuits > Wetsuit Bottoms -Sporting Goods > Water Sports > Wetsuits > Wetsuit Tops -Sporting Goods > Water Sports > Whitewater Rafting -Sporting Goods > Water Sports > Whitewater Rafting > Whitewater Rafting Helmets -Sporting Goods > Water Sports > Whitewater Rafting > Whitewater Rafts -Sporting Goods > Water Sports > Windsurfing -Sporting Goods > Water Sports > Windsurfing > Windsurfing Board Parts -Sporting Goods > Water Sports > Windsurfing > Windsurfing Board Parts > Windsurfing Board Fins -Sporting Goods > Water Sports > Windsurfing > Windsurfing Board Parts > Windsurfing Board Masts -Sporting Goods > Water Sports > Windsurfing > Windsurfing Board Parts > Windsurfing Sails -Sporting Goods > Water Sports > Windsurfing > Windsurfing Boards -Sporting Goods > Winter Sports -Sporting Goods > Winter Sports > Bobsledding -Sporting Goods > Winter Sports > Luge -Sporting Goods > Winter Sports > Skiing -Sporting Goods > Winter Sports > Skiing > Ski & Snowboard Bags -Sporting Goods > Winter Sports > Skiing > Ski & Snowboard Bags > Ski Bags -Sporting Goods > Winter Sports > Skiing > Ski & Snowboard Bags > Snowboard Bags -Sporting Goods > Winter Sports > Skiing > Ski & Snowboard Goggle Lenses -Sporting Goods > Winter Sports > Skiing > Ski & Snowboard Goggles -Sporting Goods > Winter Sports > Skiing > Ski & Snowboard Helmets -Sporting Goods > Winter Sports > Skiing > Ski & Snowboard Storage Racks -Sporting Goods > Winter Sports > Skiing > Ski Bindings -Sporting Goods > Winter Sports > Skiing > Ski Bindings > Cross-Country Ski Bindings -Sporting Goods > Winter Sports > Skiing > Ski Bindings > Downhill Ski Bindings -Sporting Goods > Winter Sports > Skiing > Ski Boots -Sporting Goods > Winter Sports > Skiing > Ski Boots > Cross-Country Ski Boots -Sporting Goods > Winter Sports > Skiing > Ski Boots > Downhill Ski Boots -Sporting Goods > Winter Sports > Skiing > Ski Poles -Sporting Goods > Winter Sports > Skiing > Skis -Sporting Goods > Winter Sports > Skiing > Skis > Cross-Country Skis -Sporting Goods > Winter Sports > Skiing > Skis > Downhill Skis -Sporting Goods > Winter Sports > Sledding -Sporting Goods > Winter Sports > Sledding > Sleds -Sporting Goods > Winter Sports > Sledding > Sleds > Runner Sleds -Sporting Goods > Winter Sports > Sledding > Sleds > Saucer Sleds -Sporting Goods > Winter Sports > Sledding > Sleds > Toboggans -Sporting Goods > Winter Sports > Sledding > Snow Tubes -Sporting Goods > Winter Sports > Snowboarding -Sporting Goods > Winter Sports > Snowboarding > Snowboard Binding Parts -Sporting Goods > Winter Sports > Snowboarding > Snowboard Bindings -Sporting Goods > Winter Sports > Snowboarding > Snowboard Boots -Sporting Goods > Winter Sports > Snowboarding > Snowboards -Sporting Goods > Winter Sports > Snowmobiling -Sporting Goods > Winter Sports > Snowshoeing -Sporting Goods > Winter Sports > Snowshoeing > Snowshoe Bindings -Sporting Goods > Winter Sports > Snowshoeing > Snowshoes -Toys & Games -Toys & Games > Game Timers -Toys & Games > Games -Toys & Games > Games > Battle Top Accessories -Toys & Games > Games > Battle Tops -Toys & Games > Games > Bingo Sets -Toys & Games > Games > Blackjack & Craps Sets -Toys & Games > Games > Board Games -Toys & Games > Games > Board Games > Backgammon Sets -Toys & Games > Games > Board Games > Checkers Sets -Toys & Games > Games > Board Games > Chess Sets -Toys & Games > Games > Board Games > Parcheesi -Toys & Games > Games > Card Game Accessories -Toys & Games > Games > Card Games -Toys & Games > Games > Card Games > Trading Card Games -Toys & Games > Games > Card Games > Traditional Playing Cards -Toys & Games > Games > Dice Sets & Games -Toys & Games > Games > Dice Sets & Games > Dice & Dice Sets -Toys & Games > Games > Dice Sets & Games > Dice Games -Toys & Games > Games > Poker Chip Accessories -Toys & Games > Games > Poker Chip Accessories > Poker Chip Carriers & Trays -Toys & Games > Games > Poker Chips & Sets -Toys & Games > Games > Portable Electronic Games -Toys & Games > Games > Roulette Wheels & Sets -Toys & Games > Games > Stacking Games -Toys & Games > Games > Tile Games -Toys & Games > Games > Tile Games > Dominoes -Toys & Games > Games > Tile Games > Mahjong -Toys & Games > Outdoor Play Equipment -Toys & Games > Outdoor Play Equipment > Bounce House Accessories -Toys & Games > Outdoor Play Equipment > Bounce Houses -Toys & Games > Outdoor Play Equipment > Play Parachutes -Toys & Games > Outdoor Play Equipment > Play Tents & Tunnels -Toys & Games > Outdoor Play Equipment > Playhouses -Toys & Games > Outdoor Play Equipment > Sandboxes -Toys & Games > Outdoor Play Equipment > See Saws -Toys & Games > Outdoor Play Equipment > Slides -Toys & Games > Outdoor Play Equipment > Swing Set & Playset Accessories -Toys & Games > Outdoor Play Equipment > Swing Sets & Playsets -Toys & Games > Outdoor Play Equipment > Swings & Gliders -Toys & Games > Outdoor Play Equipment > Water Play Equipment -Toys & Games > Outdoor Play Equipment > Water Play Equipment > Lawn Water Slides -Toys & Games > Outdoor Play Equipment > Water Play Equipment > Play Sprinkers -Toys & Games > Outdoor Play Equipment > Water Play Equipment > Water Parks -Toys & Games > Outdoor Play Equipment > Water Play Equipment > Water Tables -Toys & Games > Puzzles -Toys & Games > Puzzles > Jigsaw Puzzle Accessories -Toys & Games > Puzzles > Jigsaw Puzzles -Toys & Games > Puzzles > Mechanical Puzzles -Toys & Games > Puzzles > Mechanical Puzzles > Assembly & Disassembly Puzzles -Toys & Games > Puzzles > Mechanical Puzzles > Dexterity Puzzles -Toys & Games > Puzzles > Mechanical Puzzles > Tavern Puzzles -Toys & Games > Puzzles > Wooden & Pegged Puzzles -Toys & Games > Toys -Toys & Games > Toys > Activity Toys -Toys & Games > Toys > Activity Toys > Ball & Cup Games -Toys & Games > Toys > Activity Toys > Bouncy Balls -Toys & Games > Toys > Activity Toys > Bubble Blowing Solution -Toys & Games > Toys > Activity Toys > Bubble Blowing Toys -Toys & Games > Toys > Activity Toys > Coiled Spring Toys -Toys & Games > Toys > Activity Toys > Marbles -Toys & Games > Toys > Activity Toys > Paddle Ball Toys -Toys & Games > Toys > Activity Toys > Ribbon & Streamer Toys -Toys & Games > Toys > Activity Toys > Spinning Tops -Toys & Games > Toys > Activity Toys > Toy Jacks -Toys & Games > Toys > Activity Toys > Yo-Yo Parts & Accessories -Toys & Games > Toys > Activity Toys > Yo-Yo Parts & Accessories > Yo-Yo Gloves -Toys & Games > Toys > Activity Toys > Yo-Yos -Toys & Games > Toys > Art & Drawing Toys -Toys & Games > Toys > Art & Drawing Toys > Toy Craft Kits -Toys & Games > Toys > Art & Drawing Toys > Toy Drawing Tablets -Toys & Games > Toys > Ball Pit Accessories -Toys & Games > Toys > Ball Pit Accessories > Ball Pit Balls -Toys & Games > Toys > Ball Pits -Toys & Games > Toys > Bath Toys -Toys & Games > Toys > Beach & Sand Toys -Toys & Games > Toys > Beach & Sand Toys > Beach Balls -Toys & Games > Toys > Beach & Sand Toys > Sand Pails -Toys & Games > Toys > Building Toys -Toys & Games > Toys > Building Toys > Construction Set Toys -Toys & Games > Toys > Building Toys > Foam Blocks -Toys & Games > Toys > Building Toys > Interlocking Blocks -Toys & Games > Toys > Building Toys > Marble Track Sets -Toys & Games > Toys > Building Toys > Wooden Blocks -Toys & Games > Toys > Dolls, Playsets & Toy Figures -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures > Action Figures -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures > Animal Figures -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures > Animal Figures > Dinosaur Figures -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures > Animal Figures > Horse & Pony Figures -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures > Army Men -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Bobblehead Figures -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Doll & Action Figure Accessories -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dollhouse Accessories -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dollhouses -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dolls -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Paper & Magnetic Dolls -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppet & Puppet Theater Accessories -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppet Theaters -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppets & Marionettes -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Stuffed Animals -Toys & Games > Toys > Dolls, Playsets & Toy Figures > Toy Playsets -Toys & Games > Toys > Educational Toys -Toys & Games > Toys > Educational Toys > Ant Farms -Toys & Games > Toys > Educational Toys > Bug Collecting Kits -Toys & Games > Toys > Educational Toys > Reading Toys -Toys & Games > Toys > Educational Toys > Science Sets -Toys & Games > Toys > Educational Toys > Toy Abacuses -Toys & Games > Toys > Electronic Toys -Toys & Games > Toys > Electronic Toys > Robotic Toys -Toys & Games > Toys > Executive Toys -Toys & Games > Toys > Executive Toys > Magnet Toys -Toys & Games > Toys > Flying Toy Accessories -Toys & Games > Toys > Flying Toy Accessories > Kite Accessories -Toys & Games > Toys > Flying Toy Accessories > Kite Accessories > Kite Line Reels & Winders -Toys & Games > Toys > Flying Toys -Toys & Games > Toys > Flying Toys > Air & Water Rockets -Toys & Games > Toys > Flying Toys > Kites -Toys & Games > Toys > Flying Toys > Toy Gliders -Toys & Games > Toys > Flying Toys > Toy Parachutes -Toys & Games > Toys > Musical Toys -Toys & Games > Toys > Musical Toys > Toy Instruments -Toys & Games > Toys > Play Vehicle Accessories -Toys & Games > Toys > Play Vehicle Accessories > Toy Race Car & Track Accessories -Toys & Games > Toys > Play Vehicle Accessories > Toy Train Accessories -Toys & Games > Toys > Play Vehicles -Toys & Games > Toys > Play Vehicles > Toy Airplanes -Toys & Games > Toys > Play Vehicles > Toy Boats -Toys & Games > Toys > Play Vehicles > Toy Cars -Toys & Games > Toys > Play Vehicles > Toy Helicopters -Toys & Games > Toys > Play Vehicles > Toy Motorcycles -Toys & Games > Toys > Play Vehicles > Toy Race Car & Track Sets -Toys & Games > Toys > Play Vehicles > Toy Spaceships -Toys & Games > Toys > Play Vehicles > Toy Trains & Train Sets -Toys & Games > Toys > Play Vehicles > Toy Trucks & Construction Vehicles -Toys & Games > Toys > Pretend Play -Toys & Games > Toys > Pretend Play > Play Money & Banking -Toys & Games > Toys > Pretend Play > Pretend Electronics -Toys & Games > Toys > Pretend Play > Pretend Housekeeping -Toys & Games > Toys > Pretend Play > Pretend Lawn & Garden -Toys & Games > Toys > Pretend Play > Pretend Professions & Role Playing -Toys & Games > Toys > Pretend Play > Toy Kitchens & Play Food -Toys & Games > Toys > Pretend Play > Toy Tools -Toys & Games > Toys > Remote Control Toy Accessories -Toys & Games > Toys > Remote Control Toys -Toys & Games > Toys > Remote Control Toys > Remote Control Airships & Blimps -Toys & Games > Toys > Remote Control Toys > Remote Control Boats & Watercraft -Toys & Games > Toys > Remote Control Toys > Remote Control Boats & Watercraft > Remote Control Submarines -Toys & Games > Toys > Remote Control Toys > Remote Control Cars & Trucks -Toys & Games > Toys > Remote Control Toys > Remote Control Figures -Toys & Games > Toys > Remote Control Toys > Remote Control Helicopters -Toys & Games > Toys > Remote Control Toys > Remote Control Motorcycles -Toys & Games > Toys > Remote Control Toys > Remote Control Planes -Toys & Games > Toys > Remote Control Toys > Remote Control Robots -Toys & Games > Toys > Remote Control Toys > Remote Control Tanks -Toys & Games > Toys > Riding Toy Accessories -Toys & Games > Toys > Riding Toy Accessories > Electric Riding Vehicle Accessories -Toys & Games > Toys > Riding Toy Accessories > Electric Riding Vehicle Accessories > Electric Riding Vehicle Chargers -Toys & Games > Toys > Riding Toy Accessories > Push & Pedal Riding Vehicle Accessories -Toys & Games > Toys > Riding Toy Accessories > Wagon Parts & Accessories -Toys & Games > Toys > Riding Toys -Toys & Games > Toys > Riding Toys > Electric Riding Vehicles -Toys & Games > Toys > Riding Toys > Hobby Horses -Toys & Games > Toys > Riding Toys > Push & Pedal Riding Vehicles -Toys & Games > Toys > Riding Toys > Rocking & Spring Riding Toys -Toys & Games > Toys > Riding Toys > Wagons -Toys & Games > Toys > Sports Toys -Toys & Games > Toys > Sports Toys > Boomerangs -Toys & Games > Toys > Sports Toys > Fitness Toys -Toys & Games > Toys > Sports Toys > Fitness Toys > Hula Hoops -Toys & Games > Toys > Sports Toys > Flying Discs -Toys & Games > Toys > Sports Toys > Footbags -Toys & Games > Toys > Sports Toys > Toy Baseball -Toys & Games > Toys > Sports Toys > Toy Basketball -Toys & Games > Toys > Sports Toys > Toy Bowling -Toys & Games > Toys > Sports Toys > Toy Football -Toys & Games > Toys > Sports Toys > Toy Football > Foam Footballs -Toys & Games > Toys > Sports Toys > Toy Golf -Toys & Games > Toys > Sports Toys > Toy Hockey -Toys & Games > Toys > Toy Weapons -Toys & Games > Toys > Toy Weapons > Water Guns -Toys & Games > Toys > Visual Toys -Toys & Games > Toys > Visual Toys > Kaleidoscopes -Toys & Games > Toys > Visual Toys > Prisms -Toys & Games > Toys > Wind-Up Toys -Vehicles & Parts -Vehicles & Parts > Vehicle Parts & Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Aircraft Parts & Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio & Video Cables -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Amplifiers -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Audio Receivers -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Audio Receivers > Car Satellite Radios -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car CD Changers -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Cassette Players -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Equalizers & Crossovers -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Speakerphones -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Speakers -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Car Subwoofers -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Audio > Cassette Adapters -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Surge Protection -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Video -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Video > Car DVD Players -Vehicles & Parts > Vehicle Parts & Accessories > Car Audio & Video > Car Video > Car Video Monitors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Jump Starters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Jumper Cables -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Tire Care -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Tire Care > Hubcaps -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Tire Care > Tire Covers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Tire Care > Tire Markers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Tire Care > Tire Pressure Sensors & Gauges -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Tire Care > Tire Valve Caps -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Battery Chargers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Car Wash Brushes -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Car Wash Solutions -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Tire Wash & Shine -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Vehicle Aerosol Cleaners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Vehicle Carpet Cleaners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Vehicle Glass Cleaners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Vehicle Upholstery Cleaners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Cleaning > Vehicle Waxes, Polishes & Protectants -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Covers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Antenna Balls -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Bumper Stickers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Car Seat Covers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Car Seat Organizers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > License Plate Covers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > License Plate Frames -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Vehicle Air Fresheners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Vehicle Decals -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Vehicle Display Flags -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Vehicle Emblems & Hood Ornaments -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Vehicle Magnets -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Decor > Vehicle Window Films -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Diagnostic Scanners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Antifreeze -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Brake Fluid -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Cooling System Additives -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Engine Degreasers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Fuel System Cleaners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Hydraulic Clutch Fluid -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Motor Oil -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Power Steering Fluid -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Transmission Fluid -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Vehicle Greases -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Vehicle Performance Additives -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Fluids > Windshield Fluid -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Vehicle Paint -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Care > Windshield Repair Kits -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Bumper Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Bumpers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Hardtops -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > License Plates -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Body Kits -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Cargo Nets -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Rack Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Rack Accessories > Vehicle Bicycle Rack Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Rack Accessories > Vehicle Bicycle Rack Accessories > Bicycle Fork Mount Adapters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Rack Accessories > Vehicle Bicycle Rack Accessories > Bicycle Frame Adapters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Rack Accessories > Vehicle Bicycle Rack Accessories > Bicycle Wheel Straps -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Base Rack Systems -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Bicycle Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Canoe & Kayak Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Cargo Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Fishing Pole Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Gun Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Motorcycle & Scooter Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Ski & Snowboard Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Carrying Racks > Vehicle Water Sport Board Racks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Diffusers & Splitters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Door Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Doors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Grilles -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Hitches -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Running Boards -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Tow Hooks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Trailer Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motor Vehicle Warning Whips -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motorcycle Fairings -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motorcycle Fenders -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motorcycle Foot Pegs -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motorcycle Handlebars & Grips -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motorcycle Seats -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Motorcycle Shift Levers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Soft Tops -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Spoilers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Sunroofs -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Truck Bed Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Truck Bed Parts > Truck Bed Bars -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Truck Beds -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Winch Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Exterior > Winches -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Automotive Fuses -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Car Seat Cushions -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Car Seats -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Cigar Lighter Receptacles -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Cup Holders -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Dashboard Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Headliners -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Power Seats -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Sun Shields -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Vehicle Armrests -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Vehicle Backrests -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Vehicle Carpets -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Interior > Vehicle Floor Mats -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring > Engine Control Unit Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring > Fuel Meters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring > Motor Vehicle Trip Computers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring > Odometers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring > Radar Detectors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring > Speedometers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Monitoring > Tachometers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Air Intake Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Air Intake Parts > Vehicle Air Filters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Air Intake Parts > Vehicle Air Manifolds -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Air Intake Parts > Vehicle Air Pump Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Air Intake Parts > Vehicle Air Pumps -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Brake & Clutch Levers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Batteries -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Batteries > Hybrid Batteries -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Belts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Braking -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Braking > Parking Brake Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Braking > Vehicle Brake Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Braking > Vehicle Manual Brake Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control > Vehicle Air Conditioner Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control > Vehicle Blower Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control > Vehicle Defroster Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control > Vehicle Heater Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control > Vehicle Temperature Controllers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Alternator Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Alternators -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Camshaft Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Camshafts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Carburetor Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Carburetors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Compressor Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Compressors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Crankshaft Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Crankshafts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Cylinder Heads & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Engine Gaskets -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Engine Timing Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Engine Timing Parts > Vehicle Engine Timing Belts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Flywheels & Flywheel Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Generator Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Ignition Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Ignition Parts > Capacitor Discharge Ignition Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Ignition Parts > Distributor Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Ignition Parts > Ignition Coils -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Ignition Parts > Spark Plugs -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Piston Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Piston Parts > Gudgeon Pins -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Piston Parts > Piston Rings -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Pistons -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Radiator Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Radiators -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Starter Motor Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Starter Motors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Super Charger Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts > Vehicle Vacuum Pump Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust > Catalytic Converters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust > Exhaust Gas Recirculation Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust > Exhaust Manifolds -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust > Mufflers & Muffler Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust > Oxygen Sensors & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust > Tailpipes & Tailpipe Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Injection Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Injectors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Lines & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Pump Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Pumps -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Screens & Filters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Tank Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Fuel Tanks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Nitrous Systems -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems > Vehicle Flow Meters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Exterior Vehicle Light Covers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Fog Lights -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Headlights -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Interior Lighting -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Light Bulbs -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Parking Lights -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Reverse Lights -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Side Marker Lights -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Tail & Brake Lights -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting > Vehicle Turn Signal Lights -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Mirrors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Mirrors > Vehicle Rear-View Mirrors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Mirrors > Vehicle Side-View Mirrors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Mirrors > Vehicle Towing Mirrors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Pedals -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Valves & Valve Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > ATV & UTV Rims & Wheels -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > ATV & UTV Rims & Wheels > ATV Rims & Wheels -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > ATV & UTV Rims & Wheels > UTV Rims & Wheels -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Automotive Rims & Wheels -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Motorcycle Rims & Wheels -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > ATV & UTV Tires -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > ATV & UTV Tires > ATV Tires -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > ATV & UTV Tires > UTV Tires -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Automotive Tires -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Motorcycle Tires -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Wheel Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Tire Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Tire Accessories > Tire Chains -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Window Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Window Parts > Power Window Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Window Parts > Window & Windshield Glass -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Oil Circulation -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Oil Circulation > Oil Filters -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Oil Circulation > Oil Pump Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Oil Circulation > Oil Pumps -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Oil Circulation > Oil Sumps -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > King Pins -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > Power Steering Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > Steering Wheel Controls -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > Steering Wheel Controls > Cruise Control Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > Steering Wheel Controls > Headlight Control Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > Steering Wheel Controls > Vehicle Light Dimmers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > Steering Wheel Controls > Wiper Speed Control Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Steering Parts > Steering Wheels -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Suspension Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Suspension Parts > Shock Absorbers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Axle Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Ball Bearings -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Clutch Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Connecting Rods -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Differentials -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Driveshaft Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Driveshafts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Gearbox Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Gearboxes -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Rocker Arm Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Rocker Arm Parts > Rocker Covers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Rocker Arms -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Transfer Case Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Transmission Parts > Transmission Gears -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Vehicle Battery Parts -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Windshield Wipers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Safety Equipment -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Safety Equipment > Vehicle Parking Sensors -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Car Alarm Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Car Alarm Systems -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Child Safety Locks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Immobilizers -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Locking Hubs -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Motor Vehicle Security Cameras -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Motorcycle Alarms & Locks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Power Door Locks -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Remote Keyless Systems -Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Security & Locking Systems > Steering Wheel Locks -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Bags & Panniers -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Chest & Back Protectors -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Elbow & Wrist Guards -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Gloves -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Goggles -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Helmet Parts & Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Helmet Parts & Accessories > Motorcycle Helmet Visors -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Helmets -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Kidney Belts -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Knee & Shin Guards -Vehicles & Parts > Vehicle Parts & Accessories > Motorcycle Accessories > Motorcycle Protective Gear > Motorcycle Neck Braces -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Chains -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Lines & Ropes -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Windlasses -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchors -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Boat Hooks -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Boat Ladders -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Dock Cleats -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Dock Steps -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Sailboat Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care > Watercraft Cleaners -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care > Watercraft Covers -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care > Watercraft Polishes -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Alternators -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Carburetors & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Engine Controls -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Ignition Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Impellers -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Motor Locks -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Motor Mounts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Pistons & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Propellers -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engines & Motors -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts > Watercraft Manifolds -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts > Watercraft Mufflers & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Lines & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Meters -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Pumps & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Tanks & Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Lighting -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts > Watercraft Steering Cables -Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts > Watercraft Steering Wheels diff --git a/src/Plugins/Feed.Froogle/FroogleFeedPlugin.cs b/src/Plugins/Feed.Froogle/FroogleFeedPlugin.cs deleted file mode 100644 index 6f28b6f27e..0000000000 --- a/src/Plugins/Feed.Froogle/FroogleFeedPlugin.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Data.Entity.Migrations; -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Feed.Froogle.Data; -using SmartStore.Plugin.Feed.Froogle.Data.Migrations; -using SmartStore.Plugin.Feed.Froogle.Services; -using SmartStore.Services.Common; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.Feed.Froogle -{ - public class FroogleFeedPlugin : BasePlugin, IMiscPlugin - { - private readonly IGoogleFeedService _googleService; - private readonly ISettingService _settingService; - private readonly GoogleProductObjectContext _objectContext; - private readonly ILocalizationService _localizationService; - - public FroogleFeedPlugin( - IGoogleFeedService googleService, - ISettingService settingService, - GoogleProductObjectContext objectContext, - ILocalizationService localizationService) - { - _googleService = googleService; - _settingService = settingService; - _objectContext = objectContext; - _localizationService = localizationService; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "FeedFroogle"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Feed.Froogle.Controllers" }, { "area", "PromotionFeed.Froogle" } }; - } - - /// - /// Install plugin - /// - public override void Install() - { - var settings = new FroogleSettings(); - settings.CurrencyId = _googleService.Helper.CurrencyID; - - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - _googleService.Helper.InsertScheduleTask(); - - base.Install(); - } - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - _googleService.Helper.DeleteFeedFiles(); - _googleService.Helper.DeleteScheduleTask(); - - _settingService.DeleteSetting(); - - _localizationService.DeletePluginStringResources(this.PluginDescriptor); - - var migrator = new DbMigrator(new Configuration()); - migrator.Update(DbMigrator.InitialDatabase); - - base.Uninstall(); - } - } -} diff --git a/src/Plugins/Feed.Froogle/FroogleSettings.cs b/src/Plugins/Feed.Froogle/FroogleSettings.cs deleted file mode 100644 index 7c36cc2b56..0000000000 --- a/src/Plugins/Feed.Froogle/FroogleSettings.cs +++ /dev/null @@ -1,39 +0,0 @@ -using SmartStore.Core.Configuration; -using SmartStore.Utilities; -using SmartStore.Web.Framework.Plugins; - -namespace SmartStore.Plugin.Feed.Froogle -{ - public class FroogleSettings : PromotionFeedSettings, ISettings - { - public FroogleSettings() - { - ProductPictureSize = 125; - StaticFileName = "google_merchant_center_{0}.xml".FormatWith(CommonHelper.GenerateRandomDigitCode(10)); - Condition = "new"; - OnlineOnly = true; - AdditionalImages = true; - SpecialPrice = true; - } - - public string DefaultGoogleCategory { get; set; } - public string Condition { get; set; } - public bool SpecialPrice { get; set; } - public string Gender { get; set; } - public string AgeGroup { get; set; } - public string Color { get; set; } - public string Size { get; set; } - public string Material { get; set; } - public string Pattern { get; set; } - public bool OnlineOnly { get; set; } - public int ExpirationDays { get; set; } - public bool ExportShipping { get; set; } - public bool ExportBasePrice { get; set; } - - public string AppendDescriptionText1 { get; set; } - public string AppendDescriptionText2 { get; set; } - public string AppendDescriptionText3 { get; set; } - public string AppendDescriptionText4 { get; set; } - public string AppendDescriptionText5 { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Localization/resources.de-de.xml b/src/Plugins/Feed.Froogle/Localization/resources.de-de.xml deleted file mode 100644 index 5216d661e0..0000000000 --- a/src/Plugins/Feed.Froogle/Localization/resources.de-de.xml +++ /dev/null @@ -1,298 +0,0 @@ - - - - -
  • Für die Produktidentifizierung muss entweder die GTIN (z.B. als UPC, EAN etc.) oder der Hersteller samt Hersteller-Artikelnummer (MPN) hinterlegt sein. Google empfiehlt die Angabe aller drei Informationen.
  • -
  • Standard Steuer- und Versanddaten sind in den Einstellungen Ihres Google-Merchant-Center-Kontos zu hinterlegen.
  • -
  • Mehr Informationen zu benötigten Feldern finden Sie im Artikel Produkt-Feed-Spezifikationen.
  • -]]> -
    -
    - - - hier.]]> - - - - Standard-Google-Kategorie fehlt - - - Währung - - - Standardwährung fürs Erstellen des Feeds. - - - Standard-Google-Kategorie - - - Wird verwendet, falls auf Produktebene keine Kategorie angegeben ist. - - - Allgemein - - - Produktspezifische Daten - - - Feed erstellen - - - Thumbnail-Größe Produktbild - - - Die Standardgröße (in Pixel) für das Produkt-Thumbnail. - - - Produkt - - - Google-Kategorie - - - Geschlecht - - - Altersgruppe - - - Farbe - - - Größe - - - Material - - - Muster - - - Feed automatisch erstellen - - - Aktivieren Sie diese Option, falls die Feed-Datei automatisch erstellt werden soll. - - - Zeitspanne (in Minuten) - - - Die Zeitspanne nach der die Feed-Datei automatisch erstellt werden soll. - - - Einstellungen wurden erfolgreich gespeichert. Starten Sie die Anwendung bitte neu, falls "Feed automatisch erstellen" geändert wurde. - - - Artikelbeschreibung - - - Legen Sie fest, welche Informationen zur Beschreibung des Artikel wie verwendet werden sollen. - - - Automatisch - - - Kurzbeschreibung - - - Detailbeschreibung - - - Produktname + Kurzbeschreibung - - - Produktname + Detailbeschreibung - - - Hersteller + Produktname + Kurzbeschreibung - - - Hersteller + Produktname + Detailbeschreibung - - - Anzuhängender Text 1 - 5 - - - Einer der fünf Textbausteine wird an die Artikelbeschreibung angehängt, falls Kurz- und Langbeschreibung leer sind. - - - Zusätzliche Bilder - - - Aktivieren Sie diese Option, falls Sie mehr als ein Produktbild exportieren möchten. Bis zu 10 sind möglich. - - - Zustand - - - Zustand des Artikels. - - - Neu - - - Gebraucht - - - Erneuert - - - Verfügbarkeit - - - Verfügbarkeit des Artikels. - - - Vorrätig - - - Bestellbar - - - Vergriffen - - - Vorbestellt - - - Aktionspreis exportieren - - - Aktivieren Sie diese Option, falls Sie den Aktionspreis inkl. Aktionszeitraum exportieren möchten. - - - Hersteller\Marke - - - Dieser Wert wird verwendet, wenn für ein Produkt kein Hersteller bzw. Marke hinterlegt ist. - - - Eigene Artikelnummer - - - Aktivieren Sie diese Option, falls die eigene Artikelnummer als Hersteller-Artikelnummer (MPN) exportiert werden soll, sofern diese fehlt. - - - Geschlecht - - - Angabe ist für bestimmte Artikel z.B. Bekleidung erforderlich. - - - Herren - - - Damen - - - Unisex - - - Altersgruppe - - - Angabe ist für bestimmte Artikel z.B. Bekleidung erforderlich. - - - Erwachsene - - - Kinder - - - Farbe - - - Angabe ist für bestimmte Artikel z.B. Bekleidung erforderlich. - - - Größe - - - Angabe ist für bestimmte Artikel z.B. Bekleidung erforderlich. - - - Material - - - Material aus dem das Produkt besteht. Angabe ist z.B. bei Bekleidung sinnvoll. - - - Muster - - - Muster oder grafische Druckdesign eines Produkts. Angabe ist z.B. bei Bekleidung sinnvoll. - - - Nur online zu kaufen - - - Aktivieren Sie diese Option, wenn Produkte nur online erworben werden können. Aktivieren Sie diese Option nihct, falls Produkte auch in Ihrem Ladengeschäft erhältlich sind. - - - HTML entfernen - - - Aktivieren Sie diese Option, falls für den Export alle HTML-Auszeichnungen aus der Artikelbeschreibung entfernt werden sollen. - - - Leer - - - Produktname - - - Produktnamen durchsuchen. - - - Bearbeitet - - - Sucht nach Datensätzen, die bearbeitet oder noch nicht bearbeitet wurden. - - - Bearbeitet - - - Noch nicht bearbeitet - - - Shop - - - Wählen Sie den Shop, für den der Feed erstellt werden soll. - - - Verfällt in Tagen - - - Anzahl der Tage, nach dem die Artikel verfallen bzw. nicht mehr angezeigt werden sollen. Der Wert 0 bewirkt, dass kein Verfallsdatum exportiert wird. - - - Der Wert muss zwischen 1 und 29 Tagen liegen. - - - Versanddaten exportieren - - - Aktivieren Sie diese Option, wenn Sie z.B. das Gewicht des Produkt exportieren möchten. - - - Grundpreis exportieren - - - Aktivieren Sie diese Option, wenn Sie denGrundpreis des Produkt exportieren möchten. - - - Netto- in Bruttopreise umrechnen - - - Legt fest, dass Netto- in Bruttopreise umgerechnet werden sollen. - - - Sprache - - - Legt die Sprache fest, in der sprachabhängige Werte (z.B. der Produktname) exportiert werden sollen. - -
    \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Localization/resources.en-us.xml b/src/Plugins/Feed.Froogle/Localization/resources.en-us.xml deleted file mode 100644 index fcf379d586..0000000000 --- a/src/Plugins/Feed.Froogle/Localization/resources.en-us.xml +++ /dev/null @@ -1,298 +0,0 @@ - - - - -
  • Either the GTIN (such as UPC, EAN, etc.) or manufacturer and manufacturer part number (MPN) are required for product identification. Google recommends that all three pieces of information be specified.
  • -
  • Specify default tax and shipping values in your Google Merchant Center account settings.
  • -
  • In order to get more info about required fields look at the following article Product feed specification.
  • -]]> -
    -
    - - - here.]]> - - - - Default Google category is not set - - - Currency - - - The default currency that will be used to generate the feed. - - - Default Google category - - - Will be used if there is no category specified on produkt level. - - - General - - - Product specific data - - - Generate feed - - - Product thumbnail image size - - - The default size (pixels) for product thumbnail image. - - - Product - - - Google Category - - - Gender - - - Age group - - - Color - - - Size - - - Material - - - Pattern - - - Automatically generate feed - - - Check if you want the feed to be automatically generated. - - - A task period (minutes) - - - Specify a task period in minutes (generation of a new feed file). - - - Settings successfully saved. Please restart the application if "Automatically generate feed" has been changed. - - - Product description - - - Specify what information to use for the description of the product. - - - Automatic - - - Short description - - - Long description - - - Product name + short description - - - Product name + long description - - - Manufacturer + Product name + short description - - - Manufacturer + Product name + long description - - - Text 1 - 5 to be appended - - - One of the five text elements will be appended to the product description if long and short description are empty. - - - Additional images - - - Check if you want to export more than one image. Up to 10 are possible. - - - Condition - - - Condition of the product. - - - New - - - Used - - - Refurbished - - - Availability - - - Availability of the product. - - - In stock - - - Available for order - - - Out of stock - - - Preorder - - - Export special price - - - Activate this option if you want to export special price and special price period. - - - Manufacturer\Brand - - - This value is used if there's no manufacturer\brand for a product. - - - Own SKU - - - Check to export SKU as manufacturer part number (MPN) if it is missing. - - - Gender - - - Required for particular products, for example clothes. - - - Male - - - Female - - - Unisex - - - Age group - - - Required for particular products, for example clothes. - - - Adults - - - Kids - - - Color - - - Required for particular products, for example clothes. - - - Size - - - Required for particular products, for example clothes. - - - Material - - - The material or fabric that a product is made out of. Usefull for clothes for instance. - - - Muster - - - The pattern or graphic print featured on a product. Usefull for clothes for instance. - - - Only online available - - - Check if products can only be purchased online. - - - Remove HTML - - - Check if you want to remove all HTML from the product description for the export. - - - Empty - - - Product name - - - Search product names. - - - Edited - - - Searches for records which have or have not been edited yet. - - - Edited - - - Not edited yet - - - Store - - - Select the store that will be used to generate the feed. - - - Expires in days - - - Number of days after products should expire or no longer appear. A value of 0 causes that no expiry date will be exported. - - - The value must be between 1 and 29 days. - - - Export shipping data - - - Activate this option if you want to export the weight of the product. - - - Export base price - - - Activate this option if you want to export the base price of the product. - - - Convert net into gross prices - - - Determines to convert net into gross prices. - - - Language - - - Determines which language to use to export language dependent values (for instance the product name). - -
    \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Models/FeedFroogleModel.cs b/src/Plugins/Feed.Froogle/Models/FeedFroogleModel.cs deleted file mode 100644 index 0512baa29f..0000000000 --- a/src/Plugins/Feed.Froogle/Models/FeedFroogleModel.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; -using Newtonsoft.Json; -using SmartStore.Web.Framework.Plugins; -using SmartStore.Core.Domain.Catalog; - -namespace SmartStore.Plugin.Feed.Froogle.Models -{ - public class FeedFroogleModel : PromotionFeedConfigModel - { - public string GridEditUrl { get; set; } - public int GridPageSize { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.ProductPictureSize")] - public int ProductPictureSize { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Currency")] - public int CurrencyId { get; set; } - public List AvailableCurrencies { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.DefaultGoogleCategory")] - public string DefaultGoogleCategory { get; set; } - - public string[] AvailableGoogleCategories { get; set; } - public string AvailableGoogleCategoriesAsJson - { - get - { - if (AvailableGoogleCategories != null && AvailableGoogleCategories.Length > 0) - return JsonConvert.SerializeObject(AvailableGoogleCategories); - return ""; - } - } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.TaskEnabled")] - public bool TaskEnabled { get; set; } - [SmartResourceDisplayName("Plugins.Feed.Froogle.GenerateStaticFileEachMinutes")] - public int GenerateStaticFileEachMinutes { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.BuildDescription")] - public string BuildDescription { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.AppendDescriptionText")] - public string AppendDescriptionText1 { get; set; } - public string AppendDescriptionText2 { get; set; } - public string AppendDescriptionText3 { get; set; } - public string AppendDescriptionText4 { get; set; } - public string AppendDescriptionText5 { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.AdditionalImages")] - public bool AdditionalImages { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Condition")] - public string Condition { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Availability")] - public string Availability { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.SpecialPrice")] - public bool SpecialPrice { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Brand")] - public string Brand { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.UseOwnProductNo")] - public bool UseOwnProductNo { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Gender")] - public string Gender { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.AgeGroup")] - public string AgeGroup { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Color")] - public string Color { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Size")] - public string Size { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Material")] - public string Material { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Pattern")] - public string Pattern { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.OnlineOnly")] - public bool OnlineOnly { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.DescriptionToPlainText")] - public bool DescriptionToPlainText { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.SearchProductName")] - public string SearchProductName { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.SearchIsTouched")] - public string SearchIsTouched { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Store")] - public int StoreId { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.ExpirationDays")] - public int ExpirationDays { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.ExportShipping")] - public bool ExportShipping { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.ExportBasePrice")] - public bool ExportBasePrice { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.ConvertNetToGrossPrices")] - public bool ConvertNetToGrossPrices { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.LanguageId")] - public int LanguageId { get; set; } - - public void Copy(FroogleSettings settings, bool fromSettings) - { - if (fromSettings) - { - AppendDescriptionText1 = settings.AppendDescriptionText1; - AppendDescriptionText2 = settings.AppendDescriptionText2; - AppendDescriptionText3 = settings.AppendDescriptionText3; - AppendDescriptionText4 = settings.AppendDescriptionText4; - AppendDescriptionText5 = settings.AppendDescriptionText5; - ProductPictureSize = settings.ProductPictureSize; - CurrencyId = settings.CurrencyId; - DefaultGoogleCategory = settings.DefaultGoogleCategory; - BuildDescription = settings.BuildDescription; - AdditionalImages = settings.AdditionalImages; - Condition = settings.Condition; - Availability = settings.Availability; - SpecialPrice = settings.SpecialPrice; - Brand = settings.Brand; - UseOwnProductNo = settings.UseOwnProductNo; - Gender = settings.Gender; - AgeGroup = settings.AgeGroup; - Color = settings.Color; - Size = settings.Size; - Material = settings.Material; - Pattern = settings.Pattern; - OnlineOnly = settings.OnlineOnly; - DescriptionToPlainText = settings.DescriptionToPlainText; - StoreId = settings.StoreId; - ExpirationDays = settings.ExpirationDays; - ExportShipping = settings.ExportShipping; - ExportBasePrice = settings.ExportBasePrice; - ConvertNetToGrossPrices = settings.ConvertNetToGrossPrices; - LanguageId = settings.LanguageId; - } - else - { - settings.AppendDescriptionText1 = AppendDescriptionText1; - settings.AppendDescriptionText2 = AppendDescriptionText2; - settings.AppendDescriptionText3 = AppendDescriptionText3; - settings.AppendDescriptionText4 = AppendDescriptionText4; - settings.AppendDescriptionText5 = AppendDescriptionText5; - settings.ProductPictureSize = ProductPictureSize; - settings.CurrencyId = CurrencyId; - settings.DefaultGoogleCategory = DefaultGoogleCategory; - settings.BuildDescription = BuildDescription; - settings.AdditionalImages = AdditionalImages; - settings.Condition = Condition; - settings.Availability = Availability; - settings.SpecialPrice = SpecialPrice; - settings.Brand = Brand; - settings.UseOwnProductNo = UseOwnProductNo; - settings.Gender = Gender; - settings.AgeGroup = AgeGroup; - settings.Color = Color; - settings.Size = Size; - settings.Material = Material; - settings.Pattern = Pattern; - settings.OnlineOnly = OnlineOnly; - settings.DescriptionToPlainText = DescriptionToPlainText; - settings.StoreId = StoreId; - settings.ExpirationDays = ExpirationDays; - settings.ExportShipping = ExportShipping; - settings.ExportBasePrice = ExportBasePrice; - settings.ConvertNetToGrossPrices = ConvertNetToGrossPrices; - settings.LanguageId = LanguageId; - } - } - } - - - public class GoogleProductModel : ModelBase - { - public int TotalCount { get; set; } - - //this attribute is required to disable editing - [ScaffoldColumn(false)] - public int ProductId { get { return Id; } } - public int Id { get; set; } - - //this attribute is required to disable editing - [ReadOnly(true)] - [ScaffoldColumn(false)] - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.ProductName")] - public string Name { get; set; } - - public string SKU { get; set; } - public int ProductTypeId { get; set; } - public ProductType ProductType { get { return (ProductType)ProductTypeId; } } - public string ProductTypeName { get; set; } - public string ProductTypeLabelHint - { - get - { - switch (ProductType) - { - case ProductType.SimpleProduct: - return "smnet-hide"; - case ProductType.GroupedProduct: - return "success"; - case ProductType.BundledProduct: - return "info"; - default: - return ""; - } - } - } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.GoogleCategory")] - public string Taxonomy { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Gender")] - public string Gender { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.AgeGroup")] - public string AgeGroup { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Color")] - public string Color { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Size")] - public string Size { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Material")] - public string Material { get; set; } - - [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.Pattern")] - public string Pattern { get; set; } - - public string GenderLocalize { get; set; } - public string AgeGroupLocalize { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Properties/AssemblyInfo.cs b/src/Plugins/Feed.Froogle/Properties/AssemblyInfo.cs deleted file mode 100644 index af68ffa75d..0000000000 --- a/src/Plugins/Feed.Froogle/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Feed.Froogle")] diff --git a/src/Plugins/Feed.Froogle/RouteProvider.cs b/src/Plugins/Feed.Froogle/RouteProvider.cs deleted file mode 100644 index 42935b9e76..0000000000 --- a/src/Plugins/Feed.Froogle/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Feed.Froogle -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Feed.Froogle", - "Plugins/FeedFroogle/{action}", - new { controller = "FeedFroogle", action = "Configure" }, - new[] { "SmartStore.Plugin.Feed.Froogle.Controllers" } - ) - .DataTokens["area"] = "PromotionFeed.Froogle"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Feed.Froogle/Services/GoogleFeedService.cs b/src/Plugins/Feed.Froogle/Services/GoogleFeedService.cs deleted file mode 100644 index 73368864a1..0000000000 --- a/src/Plugins/Feed.Froogle/Services/GoogleFeedService.cs +++ /dev/null @@ -1,726 +0,0 @@ -using Autofac; -using Telerik.Web.Mvc; -using System; -using System.IO; -using System.Linq; -using System.Text; -using System.Xml; -using System.Web; -using System.Web.Mvc; -using System.Collections.Generic; -using System.Globalization; -using SmartStore.Web.Framework.Plugins; -using SmartStore.Plugin.Feed.Froogle.Domain; -using SmartStore.Plugin.Feed.Froogle.Models; -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Logging; -using SmartStore.Services.Catalog; -using SmartStore.Services.Directory; -using SmartStore.Services.Tasks; -using SmartStore.Services.Localization; -using SmartStore.Core.Infrastructure; -using SmartStore.Data; -using SmartStore.Core.Domain.Common; - -namespace SmartStore.Plugin.Feed.Froogle.Services -{ - public partial class GoogleFeedService : IGoogleFeedService - { - private const string _googleNamespace = "http://base.google.com/ns/1.0"; - - private readonly FeedPluginHelper _helper; - private readonly IRepository _gpRepository; - private readonly IProductService _productService; - private readonly IManufacturerService _manufacturerService; - private readonly IMeasureService _measureService; - private readonly MeasureSettings _measureSettings; - private readonly IDbContext _dbContext; - private readonly AdminAreaSettings _adminAreaSettings; - - public GoogleFeedService( - IRepository gpRepository, - IProductService productService, - IManufacturerService manufacturerService, - FroogleSettings settings, - IMeasureService measureService, - MeasureSettings measureSettings, - IDbContext dbContext, - AdminAreaSettings adminAreaSettings, - IComponentContext ctx) - { - _gpRepository = gpRepository; - _productService = productService; - _manufacturerService = manufacturerService; - Settings = settings; - _measureService = measureService; - _measureSettings = measureSettings; - _dbContext = dbContext; - _adminAreaSettings = adminAreaSettings; - - _helper = new FeedPluginHelper(ctx, "PromotionFeed.Froogle", "SmartStore.Plugin.Feed.Froogle", () => - { - return Settings as PromotionFeedSettings; - }); - } - - public FroogleSettings Settings { get; set; } - public FeedPluginHelper Helper { get { return _helper; } } - - private GoogleProductRecord GetByProductId(int productId) - { - if (productId == 0) - return null; - - var query = - from gp in _gpRepository.Table - where gp.ProductId == productId - select gp; - - var record = query.FirstOrDefault(); - return record; - } - private bool SpecialPrice(Product product, out string specialPriceDate) - { - specialPriceDate = ""; - - try - { - if (Settings.SpecialPrice && product.SpecialPrice.HasValue && product.SpecialPriceStartDateTimeUtc.HasValue && product.SpecialPriceEndDateTimeUtc.HasValue) - { - if (!(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) - { - string dateFormat = "yyyy-MM-ddTHH:mmZ"; - string startDate = product.SpecialPriceStartDateTimeUtc.Value.ToString(dateFormat); - string endDate = product.SpecialPriceEndDateTimeUtc.Value.ToString(dateFormat); - - specialPriceDate = "{0}/{1}".FormatWith(startDate, endDate); - } - } - } - catch (Exception exc) - { - exc.Dump(); - } - return specialPriceDate.HasValue(); - } - private string ProductCategory(GoogleProductRecord googleProduct) - { - string productCategory = ""; - - if (googleProduct != null) - productCategory = googleProduct.Taxonomy; - - if (productCategory.IsNullOrEmpty()) - productCategory = Settings.DefaultGoogleCategory; - - return productCategory; - } - private string Condition() - { - if (Settings.Condition.IsCaseInsensitiveEqual(PluginHelper.NotSpecified)) - return ""; - - if (Settings.Condition.IsNullOrEmpty()) - return "new"; - - return Settings.Condition; - } - private string Availability(Product product) - { - if (Settings.Availability.IsCaseInsensitiveEqual(PluginHelper.NotSpecified)) - return ""; - - if (Settings.Availability.IsNullOrEmpty()) - { - if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock && product.StockQuantity <= 0) - { - switch (product.BackorderMode) - { - case BackorderMode.NoBackorders: - return "out of stock"; - case BackorderMode.AllowQtyBelow0: - case BackorderMode.AllowQtyBelow0AndNotifyCustomer: - return "available for order"; - } - } - return "in stock"; - } - return Settings.Availability; - } - private string Gender(GoogleProductRecord googleProduct) - { - if (Settings.Gender.IsCaseInsensitiveEqual(PluginHelper.NotSpecified)) - return ""; - - if (googleProduct != null && googleProduct.Gender.HasValue()) - return googleProduct.Gender; - - return Settings.Gender; - } - private string AgeGroup(GoogleProductRecord googleProduct) - { - if (Settings.AgeGroup.IsCaseInsensitiveEqual(PluginHelper.NotSpecified)) - return ""; - - if (googleProduct != null && googleProduct.AgeGroup.HasValue()) - return googleProduct.AgeGroup; - - return Settings.AgeGroup; - } - private string Color(GoogleProductRecord googleProduct) - { - if (googleProduct != null && googleProduct.Color.HasValue()) - return googleProduct.Color; - - return Settings.Color; - } - private string Size(GoogleProductRecord googleProduct) - { - if (googleProduct != null && googleProduct.Size.HasValue()) - return googleProduct.Size; - - return Settings.Size; - } - private string Material(GoogleProductRecord googleProduct) - { - if (googleProduct != null && googleProduct.Material.HasValue()) - return googleProduct.Material; - - return Settings.Material; - } - private string Pattern(GoogleProductRecord googleProduct) - { - if (googleProduct != null && googleProduct.Pattern.HasValue()) - return googleProduct.Pattern; - - return Settings.Pattern; - } - private string ItemGroupId(GoogleProductRecord googleProduct) - { - if (googleProduct != null && googleProduct.ItemGroupId.HasValue()) - return googleProduct.ItemGroupId; - - return ""; - } - private bool BasePriceSupported(int baseAmount, string unit) - { - if (baseAmount == 1 || baseAmount == 10 || baseAmount == 100) - return true; - - if (baseAmount == 75 && unit == "cl") - return true; - - if ((baseAmount == 50 || baseAmount == 1000) && unit == "kg") - return true; - - return false; - } - private string BasePriceUnits(string value) - { - const string defaultValue = "kg"; - - if (value.IsNullOrEmpty()) - return defaultValue; - - // TODO: Product.BasePriceMeasureUnit should be localized - switch (value.ToLower()) - { - case "mg": - case "milligramm": - case "milligram": - return "mg"; - case "g": - case "gramm": - case "gram": - return "g"; - case "kg": - case "kilogramm": - case "kilogram": - return "kg"; - - case "ml": - case "milliliter": - case "millilitre": - return "ml"; - case "cl": - case "zentiliter": - case "centilitre": - return "cl"; - case "l": - case "liter": - case "litre": - return "l"; - case "cbm": - case "kubikmeter": - case "cubic metre": - return "cbm"; - - case "cm": - case "zentimeter": - case "centimetre": - return "cm"; - case "m": - case "meter": - return "m"; - - case "qm": - case "quadratmeter": - case "square metre": - return "sqm"; - - default: - return defaultValue; - } - } - private string WriteItem(XmlWriter writer, Store store, Product product, Currency currency, string measureWeightSystemKey) - { - var manu = _manufacturerService.GetProductManufacturersByProductId(product.Id).FirstOrDefault(); - var mainImageUrl = Helper.GetMainProductImageUrl(store, product); - var googleProduct = GetByProductId(product.Id); - var category = ProductCategory(googleProduct); - - if (category.IsNullOrEmpty()) - return Helper.GetResource("MissingDefaultCategory"); - - string manuName = (manu != null ? manu.Manufacturer.GetLocalized(x => x.Name, Settings.LanguageId, true, false) : null); - string productName = product.GetLocalized(x => x.Name, Settings.LanguageId, true, false); - string shortDescription = product.GetLocalized(x => x.ShortDescription, Settings.LanguageId, true, false); - string fullDescription = product.GetLocalized(x => x.FullDescription, Settings.LanguageId, true, false); - - var brand = (manuName ?? Settings.Brand); - var mpn = Helper.GetManufacturerPartNumber(product); - - bool identifierExists = product.Gtin.HasValue() || brand.HasValue() || mpn.HasValue(); - - writer.WriteElementString("g", "id", _googleNamespace, product.Id.ToString()); - - writer.WriteStartElement("title"); - writer.WriteCData(productName.Truncate(70)); - writer.WriteEndElement(); - - var description = Helper.BuildProductDescription(productName, shortDescription, fullDescription, manuName, d => - { - if (fullDescription.IsNullOrEmpty() && shortDescription.IsNullOrEmpty()) - { - var rnd = new Random(); - - switch (rnd.Next(1, 5)) - { - case 1: return d.Grow(Settings.AppendDescriptionText1, " "); - case 2: return d.Grow(Settings.AppendDescriptionText2, " "); - case 3: return d.Grow(Settings.AppendDescriptionText3, " "); - case 4: return d.Grow(Settings.AppendDescriptionText4, " "); - case 5: return d.Grow(Settings.AppendDescriptionText5, " "); - } - } - return d; - }); - - writer.WriteStartElement("description"); - writer.WriteCData(description.RemoveInvalidXmlChars()); - writer.WriteEndElement(); - - writer.WriteStartElement("g", "google_product_category", _googleNamespace); - writer.WriteCData(category); - writer.WriteFullEndElement(); - - string productType = Helper.GetCategoryPath(product); - if (productType.HasValue()) - { - writer.WriteStartElement("g", "product_type", _googleNamespace); - writer.WriteCData(productType); - writer.WriteFullEndElement(); - } - - writer.WriteElementString("link", Helper.GetProductDetailUrl(store, product)); - writer.WriteElementString("g", "image_link", _googleNamespace, mainImageUrl); - - foreach (string additionalImageUrl in Helper.GetAdditionalProductImages(store, product, mainImageUrl)) - { - writer.WriteElementString("g", "additional_image_link", _googleNamespace, additionalImageUrl); - } - - writer.WriteElementString("g", "condition", _googleNamespace, Condition()); - writer.WriteElementString("g", "availability", _googleNamespace, Availability(product)); - - decimal price = Helper.GetProductPrice(product, currency); - string specialPriceDate; - - if (SpecialPrice(product, out specialPriceDate)) - { - writer.WriteElementString("g", "sale_price", _googleNamespace, price.FormatInvariant() + " " + currency.CurrencyCode); - writer.WriteElementString("g", "sale_price_effective_date", _googleNamespace, specialPriceDate); - - // get regular price ignoring any special price - decimal specialPrice = product.SpecialPrice.Value; - product.SpecialPrice = null; - price = Helper.GetProductPrice(product, currency); - product.SpecialPrice = specialPrice; - - _dbContext.SetToUnchanged(product); - } - - writer.WriteElementString("g", "price", _googleNamespace, price.FormatInvariant() + " " + currency.CurrencyCode); - - writer.WriteCData("gtin", product.Gtin, "g", _googleNamespace); - writer.WriteCData("brand", brand, "g", _googleNamespace); - writer.WriteCData("mpn", mpn, "g", _googleNamespace); - - writer.WriteCData("gender", Gender(googleProduct), "g", _googleNamespace); - writer.WriteCData("age_group", AgeGroup(googleProduct), "g", _googleNamespace); - writer.WriteCData("color", Color(googleProduct), "g", _googleNamespace); - writer.WriteCData("size", Size(googleProduct), "g", _googleNamespace); - writer.WriteCData("material", Material(googleProduct), "g", _googleNamespace); - writer.WriteCData("pattern", Pattern(googleProduct), "g", _googleNamespace); - writer.WriteCData("item_group_id", ItemGroupId(googleProduct), "g", _googleNamespace); - - writer.WriteElementString("g", "online_only", _googleNamespace, Settings.OnlineOnly ? "y" : "n"); - writer.WriteElementString("g", "identifier_exists", _googleNamespace, identifierExists ? "TRUE" : "FALSE"); - - if (Settings.ExpirationDays > 0) - { - writer.WriteElementString("g", "expiration_date", _googleNamespace, DateTime.UtcNow.AddDays(Settings.ExpirationDays).ToString("yyyy-MM-dd")); - } - - if (Settings.ExportShipping) - { - string weightInfo, weight = product.Weight.FormatInvariant(); - - if (measureWeightSystemKey.IsCaseInsensitiveEqual("gram")) - weightInfo = weight + " g"; - else if (measureWeightSystemKey.IsCaseInsensitiveEqual("lb")) - weightInfo = weight + " lb"; - else if (measureWeightSystemKey.IsCaseInsensitiveEqual("ounce")) - weightInfo = weight + " oz"; - else - weightInfo = weight + " kg"; - - writer.WriteElementString("g", "shipping_weight", _googleNamespace, weightInfo); - } - - if (Settings.ExportBasePrice && product.BasePriceHasValue) - { - string measureUnit = BasePriceUnits(product.BasePriceMeasureUnit); - - if (BasePriceSupported(product.BasePriceBaseAmount ?? 0, measureUnit)) - { - string basePriceMeasure = "{0} {1}".FormatWith((product.BasePriceAmount ?? decimal.Zero).FormatInvariant(), measureUnit); - string basePriceBaseMeasure = "{0} {1}".FormatWith(product.BasePriceBaseAmount, measureUnit); - - writer.WriteElementString("g", "unit_pricing_measure", _googleNamespace, basePriceMeasure); - writer.WriteElementString("g", "unit_pricing_base_measure", _googleNamespace, basePriceBaseMeasure); - } - } - - return null; - } - - public string[] GetTaxonomyList() - { - try - { - string fileDir = Path.Combine(Helper.Plugin.OriginalAssemblyFile.Directory.FullName, "Files"); - string fileName = "taxonomy.{0}.txt".FormatWith(Helper.Language.LanguageCulture ?? "de-DE"); - string path = Path.Combine(fileDir, fileName); - - if (!File.Exists(path)) - path = Path.Combine(fileDir, "taxonomy.en-US.txt"); - - string[] lines = File.ReadAllLines(path, Encoding.UTF8); - - return lines; - } - catch (Exception exc) - { - exc.Dump(); - } - return new string[] { }; - } - public void UpdateInsert(int pk, string name, string value) - { - if (pk == 0 || name.IsNullOrEmpty()) - return; - - var product = GetByProductId(pk); - bool insert = (product == null); - var utcNow = DateTime.UtcNow; - - if (insert) - { - product = new GoogleProductRecord() - { - ProductId = pk, - CreatedOnUtc = utcNow, - UpdatedOnUtc = utcNow - }; - } - else - { - product.UpdatedOnUtc = utcNow; - } - - switch(name) - { - case "Taxonomy": - product.Taxonomy = value; - break; - case "Gender": - product.Gender = value; - break; - case "AgeGroup": - product.AgeGroup = value; - break; - case "Color": - product.Color = value; - break; - case "Size": - product.Size = value; - break; - case "Material": - product.Material = value; - break; - case "Pattern": - product.Pattern = value; - break; - } - - product.IsTouched = product.Taxonomy.HasValue() || product.Gender.HasValue() || product.AgeGroup.HasValue() || product.Color.HasValue() || - product.Size.HasValue() || product.Material.HasValue() || product.Pattern.HasValue() || product.ItemGroupId.HasValue(); - - if (insert) - { - _gpRepository.Insert(product); - } - else - { - _gpRepository.Update(product); - } - } - public GridModel GetGridModel(GridCommand command, string searchProductName = null, string touched = null) - { - var model = new GridModel(); - var textInfo = CultureInfo.InvariantCulture.TextInfo; - - // there's no way to share a context instance across repositories which makes GoogleProductObjectContext pretty useless here. - // so let's fallback to good ole sql... by the way, fastest possible paged data query ever. - - var whereClause = new StringBuilder("(NOT ([t2].[Deleted] = 1)) AND ([t2].[VisibleIndividually] = 1)"); - - if (searchProductName.HasValue()) - { - whereClause.AppendFormat(" AND ([t2].[Name] LIKE '%{0}%')", searchProductName.Replace("'", "''")); - } - - if (touched.HasValue()) - { - if (touched.IsCaseInsensitiveEqual("touched")) - whereClause.Append(" AND ([t2].[IsTouched] = 1)"); - else - whereClause.Append(" AND ([t2].[IsTouched] = 0 OR [t2].[IsTouched] IS NULL)"); - } - - string sql = -"SELECT [TotalCount], [t3].[Id], [t3].[Name], [t3].[SKU], [t3].[ProductTypeId], [t3].[value] AS [Taxonomy], [t3].[value2] AS [Gender], [t3].[value3] AS [AgeGroup], [t3].[value4] AS [Color], [t3].[value5] AS [Size], [t3].[value6] AS [Material], [t3].[value7] AS [Pattern]" + -" FROM (" + -" SELECT COUNT(id) OVER() [TotalCount], ROW_NUMBER() OVER (ORDER BY [t2].[Name]) AS [ROW_NUMBER], [t2].[Id], [t2].[Name], [t2].[SKU], [t2].[ProductTypeId], [t2].[value], [t2].[value2], [t2].[value3], [t2].[value4], [t2].[value5], [t2].[value6], [t2].[value7]" + -" FROM (" + -" SELECT [t0].[Id], [t0].[Name], [t0].[SKU], [t0].[ProductTypeId], [t1].[Taxonomy] AS [value], [t1].[Gender] AS [value2], [t1].[AgeGroup] AS [value3], [t1].[Color] AS [value4], [t1].[Size] AS [value5], [t1].[Material] AS [value6], [t1].[Pattern] AS [value7], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched]" + -" FROM [Product] AS [t0]" + -" LEFT OUTER JOIN [GoogleProduct] AS [t1] ON [t0].[Id] = [t1].[ProductId]" + -" ) AS [t2]" + -" WHERE " + whereClause.ToString() + -" ) AS [t3]" + -" WHERE [t3].[ROW_NUMBER] BETWEEN {0} + 1 AND {0} + {1}" + -" ORDER BY [t3].[ROW_NUMBER]"; - - - var data = _gpRepository.Context.SqlQuery(sql, (command.Page - 1) * command.PageSize, command.PageSize).ToList(); - - data.ForEach(x => - { - if (x.ProductType != ProductType.SimpleProduct) - { - string key = "Admin.Catalog.Products.ProductType.{0}.Label".FormatWith(x.ProductType.ToString()); - x.ProductTypeName = Helper.GetResource(key); - } - - if (x.Gender.HasValue()) - x.GenderLocalize = Helper.GetResource("Gender" + textInfo.ToTitleCase(x.Gender)); - - if (x.AgeGroup.HasValue()) - x.AgeGroupLocalize = Helper.GetResource("AgeGroup" + textInfo.ToTitleCase(x.AgeGroup)); - }); - - model.Data = data; - model.Total = (data.Count > 0 ? data.First().TotalCount : 0); - - return model; - - #region old code - - //var searchContext = new ProductSearchContext() - //{ - // Keywords = searchProductName, - // PageIndex = command.Page - 1, - // PageSize = command.PageSize, - // VisibleIndividuallyOnly = true, - // ShowHidden = true - //}; - - //var products = _productService.SearchProducts(searchContext); - - //var data = products.Select(x => - //{ - // var gModel = new GoogleProductModel() - // { - // ProductId = x.Id, - // Name = x.Name - // }; - - // var googleProduct = GetByProductId(x.Id); - - // if (googleProduct != null) - // { - // gModel.Taxonomy = googleProduct.Taxonomy; - // gModel.Gender = googleProduct.Gender; - // gModel.AgeGroup = googleProduct.AgeGroup; - // gModel.Color = googleProduct.Color; - // gModel.Size = googleProduct.Size; - // gModel.Material = googleProduct.Material; - // gModel.Pattern = googleProduct.Pattern; - - // if (gModel.Gender.HasValue()) - // gModel.GenderLocalize = Helper.GetResource("Gender" + CultureInfo.InvariantCulture.TextInfo.ToTitleCase(gModel.Gender)); - - // if (gModel.AgeGroup.HasValue()) - // gModel.AgeGroupLocalize = Helper.GetResource("AgeGroup" + CultureInfo.InvariantCulture.TextInfo.ToTitleCase(gModel.AgeGroup)); - // } - - // return gModel; - //}) - //.ToList(); - - //var model = new GridModel() - //{ - // Data = data, - // Total = products.TotalCount - //}; - - //return model; - - #endregion old code - } - private void CreateFeed(FeedFileCreationContext fileCreation, TaskExecutionContext taskContext) - { - var xmlSettings = new XmlWriterSettings - { - Encoding = Encoding.UTF8, - CheckCharacters = false - }; - - using (var writer = XmlWriter.Create(fileCreation.Stream, xmlSettings)) - { - try - { - fileCreation.Logger.Information("Log file - Google Merchant Center feed."); - - var searchContext = new ProductSearchContext() - { - OrderBy = ProductSortingEnum.CreatedOn, - PageSize = int.MaxValue, - StoreId = fileCreation.Store.Id, - VisibleIndividuallyOnly = true - }; - - string breakingError = null; - var qualifiedProducts = new List(); - var currency = Helper.GetUsedCurrency(Settings.CurrencyId); - var products = _productService.SearchProducts(searchContext); - var measureWeightSystemKey = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).SystemKeyword; - - if (fileCreation.TotalRecords == 0) - fileCreation.TotalRecords = products.Count * fileCreation.StoreCount; - - writer.WriteStartDocument(); - writer.WriteStartElement("rss"); - writer.WriteAttributeString("version", "2.0"); - writer.WriteAttributeString("xmlns", "g", null, _googleNamespace); - writer.WriteStartElement("channel"); - writer.WriteElementString("title", "{0} - Feed for Google Merchant Center".FormatWith(fileCreation.Store.Name)); - writer.WriteElementString("link", "http://base.google.com/base/"); - writer.WriteElementString("description", "Information about products"); - - foreach (var product in products) - { - fileCreation.Report(); - - Helper.GetQualifiedProductsByProduct(product, fileCreation.Store, qualifiedProducts); - - foreach (var qualifiedProduct in qualifiedProducts) - { - writer.WriteStartElement("item"); - - try - { - breakingError = WriteItem(writer, fileCreation.Store, qualifiedProduct, currency, measureWeightSystemKey); - } - catch (Exception exc) - { - fileCreation.Logger.Error(exc.Message, exc); - } - - writer.WriteEndElement(); // item - } - - if (breakingError.HasValue()) - { - fileCreation.Logger.Error(breakingError); - break; - } - if (taskContext.CancellationToken.IsCancellationRequested) - { - fileCreation.Logger.Warning("A cancellation has been requested"); - break; - } - } - - writer.WriteEndElement(); // channel - writer.WriteEndElement(); // rss - writer.WriteEndDocument(); - - if (breakingError.HasValue()) - throw new SmartException(breakingError); - } - catch (Exception exc) - { - fileCreation.Logger.Error(exc.Message, exc); - } - } - } - public void CreateFeed(TaskExecutionContext context) - { - Helper.StartCreatingFeeds(fileCreation => - { - CreateFeed(fileCreation, context); - return true; - }); - } - public void SetupModel(FeedFroogleModel model) - { - Helper.SetupConfigModel(model, "FeedFroogle"); - - model.GenerateStaticFileEachMinutes = Helper.ScheduleTask.Seconds / 60; - model.TaskEnabled = Helper.ScheduleTask.Enabled; - - model.AvailableCurrencies = Helper.AvailableCurrencies(); - model.AvailableGoogleCategories = GetTaxonomyList(); - - var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext); - model.GridEditUrl = urlHelper.Action("GoogleProductEdit", "FeedFroogle", new { Namespaces = "SmartStore.Plugin.Feed.Froogle.Controllers", area = "" }); - model.GridPageSize = _adminAreaSettings.GridPageSize; - } - } -} diff --git a/src/Plugins/Feed.Froogle/Services/IGoogleFeedService.cs b/src/Plugins/Feed.Froogle/Services/IGoogleFeedService.cs deleted file mode 100644 index 39a6f62291..0000000000 --- a/src/Plugins/Feed.Froogle/Services/IGoogleFeedService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using SmartStore.Plugin.Feed.Froogle.Models; -using SmartStore.Services.Tasks; -using SmartStore.Web.Framework.Plugins; -using Telerik.Web.Mvc; - -namespace SmartStore.Plugin.Feed.Froogle.Services -{ - public partial interface IGoogleFeedService - { - FroogleSettings Settings { get; set; } - FeedPluginHelper Helper { get; } - - string[] GetTaxonomyList(); - - void UpdateInsert(int pk, string name, string value); - - GridModel GetGridModel(GridCommand command, string searchProductName = null, string touched = null); - - void CreateFeed(TaskExecutionContext context); - - void SetupModel(FeedFroogleModel model); - } -} diff --git a/src/Plugins/Feed.Froogle/SmartStore.Plugin.Feed.Froogle.csproj b/src/Plugins/Feed.Froogle/SmartStore.Plugin.Feed.Froogle.csproj deleted file mode 100644 index d538720bcf..0000000000 --- a/src/Plugins/Feed.Froogle/SmartStore.Plugin.Feed.Froogle.csproj +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {965A02F0-FC84-4AC4-91E4-79EADFC1CA9D} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Feed.Froogle - SmartStore.Plugin.Feed.Froogle - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\PromotionFeed.Froogle\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\PromotionFeed.Froogle\ - TRACE - prompt - 4 - false - - - true - ..\..\Presentation\SmartStore.Web\bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - - - ..\..\packages\FluentValidation.5.0.0.1\lib\Net40\FluentValidation.dll - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - 201403112356126_Initial.cs - - - - 201408020941244_IsTouched.cs - - - - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} - SmartStore.Data - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - 201403112356126_Initial.cs - - - PreserveNewest - - - 201408020941244_IsTouched.cs - - - - - Always - - - Always - - - PreserveNewest - - - Always - - - Always - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - Designer - - - PreserveNewest - - - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/StaticFileGenerationTask.cs b/src/Plugins/Feed.Froogle/StaticFileGenerationTask.cs deleted file mode 100644 index 56e241fde8..0000000000 --- a/src/Plugins/Feed.Froogle/StaticFileGenerationTask.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Autofac; -using SmartStore.Plugin.Feed.Froogle.Services; -using SmartStore.Services.Tasks; - -namespace SmartStore.Plugin.Feed.Froogle -{ - public class StaticFileGenerationTask : ITask - { - public void Execute(TaskExecutionContext context) - { - var scope = context.LifetimeScope as ILifetimeScope; - var googleService = scope.Resolve(); - - googleService.CreateFeed(context); - } - } -} \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Validators/ConfigurationValidator.cs b/src/Plugins/Feed.Froogle/Validators/ConfigurationValidator.cs deleted file mode 100644 index b7fa9095b3..0000000000 --- a/src/Plugins/Feed.Froogle/Validators/ConfigurationValidator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using FluentValidation; -using SmartStore.Plugin.Feed.Froogle.Models; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.Feed.Froogle.Validators -{ - public class ConfigurationValidator : AbstractValidator - { - public ConfigurationValidator(ILocalizationService localize) - { - RuleFor(x => x.ExpirationDays).InclusiveBetween(1, 29) - .WithMessage(localize.GetResource("Plugins.Feed.Froogle.ExpirationDays.Validate")); - } - } -} diff --git a/src/Plugins/Feed.Froogle/Views/FeedFroogle/Configure.cshtml b/src/Plugins/Feed.Froogle/Views/FeedFroogle/Configure.cshtml deleted file mode 100644 index 8e3c39a2d8..0000000000 --- a/src/Plugins/Feed.Froogle/Views/FeedFroogle/Configure.cshtml +++ /dev/null @@ -1,606 +0,0 @@ -@model FeedFroogleModel -@using SmartStore.Plugin.Feed.Froogle; -@using SmartStore.Plugin.Feed.Froogle.Models; -@using SmartStore.Web.Framework; -@using SmartStore.Web.Framework.Plugins; -@using Telerik.Web.Mvc.UI; -@using SmartStore.Web.Framework.UI; - -@{ - Layout = ""; - - Html.AddCssFileParts(true, - "~/Content/x-editable/bootstrap-editable.css", - "~/Plugins/PromotionFeed.Froogle/Content/smartstore.feed.froogle.css"); - - Html.AppendScriptParts(true, - "~/Content/bootstrap/js/bootstrap-typeahead.js", - "~/Content/x-editable/bootstrap-editable.js"); -} - - - - - -@(Html.SmartStore().TabStrip().Name("googlebase-configure").Items(x => { - x.Add().Text(T("Plugins.Feed.Froogle.General").Text).Content(@TabGeneral()).Selected(true); - x.Add().Text(T("Plugins.Feed.Froogle.ProductData").Text).Content(@TabProductData()); -})) - -@helper TabGeneral() { - - -
    - - - - - @if (Model.GeneratedFiles.Count > 0 && !Model.IsRunning) - { - - - - - } - else if (Model.IsRunning) - { - - - - - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    - - @Html.Raw(@T("Plugins.Feed.Froogle.AdminInstruction")) -
    -
    - @Html.SmartLabelFor(m => m.GeneratedFiles) - - @foreach (var group in Model.GeneratedFiles.GroupBy(x => x.StoreId)) - { - var firstFile = group.First(); -

    - @(firstFile.StoreName): - @foreach (var file in group) - { -
    @file.FileUrl - } -
    @T("Admin.Configuration.ActivityLog"), - @T("Common.UpdatedOn"): @(firstFile.LastWriteTime) -

    - } -
      - - @Model.ProcessInfo -
      - @if (Model.IsRunning) - { - -  @T("Admin.Common.Update") - - } - else - { - -  @T("Plugins.Feed.Froogle.Generate") - - - if (Model.GeneratedFiles.Count > 0) - { - -  @T("Admin.Common.Delete") - - } - } -
    -
    -
    - @Html.SmartLabelFor(m => m.DefaultGoogleCategory) - - -
    - @Html.SmartLabelFor(m => m.ProductPictureSize) - - @Html.EditorFor(m => m.ProductPictureSize) - @Html.ValidationMessageFor(m => m.ProductPictureSize) -
    - @Html.SmartLabelFor(m => m.AdditionalImages) - - @Html.EditorFor(m => m.AdditionalImages) - @Html.ValidationMessageFor(m => m.AdditionalImages) -
    -
    -
    - @Html.SmartLabelFor(model => model.StoreId) - - @Html.DropDownListFor(model => model.StoreId, Model.AvailableStores) - @Html.ValidationMessageFor(model => model.StoreId) -
    - @Html.SmartLabelFor(model => model.LanguageId) - - @Html.DropDownListFor(model => model.LanguageId, Model.AvailableLanguages) - @Html.ValidationMessageFor(model => model.LanguageId) -
    - @Html.SmartLabelFor(m => m.BuildDescription) - - @Html.DropDownList("BuildDescription", new List { - new SelectListItem { Text = Model.Helper.GetResource("Automatic"), Value = "" }, - new SelectListItem { Text = Model.Helper.GetResource("Common.Unspecified"), Value = PluginHelper.NotSpecified }, - new SelectListItem { Text = Model.Helper.GetResource("DescShort"), Value = "short" }, - new SelectListItem { Text = Model.Helper.GetResource("DescLong"), Value = "long" }, - new SelectListItem { Text = Model.Helper.GetResource("DescTitleAndShort"), Value = "titleAndShort" }, - new SelectListItem { Text = Model.Helper.GetResource("DescTitleAndLong"), Value = "titleAndLong" }, - new SelectListItem { Text = Model.Helper.GetResource("DescManuAndTitleAndShort"), Value = "manuAndTitleAndShort" }, - new SelectListItem { Text = Model.Helper.GetResource("DescManuAndTitleAndLong"), Value = "manuAndTitleAndLong" } - }) - @Html.ValidationMessageFor(m => m.BuildDescription) -
    - @Html.SmartLabelFor(m => m.DescriptionToPlainText) - - @Html.EditorFor(m => m.DescriptionToPlainText) - @Html.ValidationMessageFor(m => m.DescriptionToPlainText) -
    - @Html.SmartLabelFor(m => m.AppendDescriptionText1) - - @Html.EditorFor(m => m.AppendDescriptionText1) - @Html.ValidationMessageFor(m => m.AppendDescriptionText1) -
    -   - - @Html.EditorFor(m => m.AppendDescriptionText2) - @Html.ValidationMessageFor(m => m.AppendDescriptionText2) -
    -   - - @Html.EditorFor(m => m.AppendDescriptionText3) - @Html.ValidationMessageFor(m => m.AppendDescriptionText3) -
    -   - - @Html.EditorFor(m => m.AppendDescriptionText4) - @Html.ValidationMessageFor(m => m.AppendDescriptionText4) -
    -   - - @Html.EditorFor(m => m.AppendDescriptionText5) - @Html.ValidationMessageFor(m => m.AppendDescriptionText5) -
    -
    -
    - @Html.SmartLabelFor(m => m.Condition) - - @Html.DropDownList("Condition", new List { - new SelectListItem { Text = Model.Helper.GetResource("Automatic"), Value = "" }, - new SelectListItem { Text = Model.Helper.GetResource("Common.Unspecified"), Value = PluginHelper.NotSpecified }, - new SelectListItem { Text = Model.Helper.GetResource("ConditionNew"), Value = "new" }, - new SelectListItem { Text = Model.Helper.GetResource("ConditionUsed"), Value = "used" }, - new SelectListItem { Text = Model.Helper.GetResource("ConditionRefurbished"), Value = "refurbished" } - }) - @Html.ValidationMessageFor(m => m.Condition) -
    - @Html.SmartLabelFor(m => m.Availability) - - @Html.DropDownList("Availability", new List { - new SelectListItem { Text = Model.Helper.GetResource("Automatic"), Value = "" }, - new SelectListItem { Text = Model.Helper.GetResource("Common.Unspecified"), Value = PluginHelper.NotSpecified }, - new SelectListItem { Text = Model.Helper.GetResource("AvailabilityInStock"), Value = "in stock" }, - new SelectListItem { Text = Model.Helper.GetResource("AvailabilityAvailableForOrder"), Value = "available for order" }, - new SelectListItem { Text = Model.Helper.GetResource("AvailabilityOutOfStock"), Value = "out of stock" }, - new SelectListItem { Text = Model.Helper.GetResource("AvailabilityPreorder"), Value = "preorder" } - }) - @Html.ValidationMessageFor(m => m.Availability) -
    - @Html.SmartLabelFor(m => m.Gender) - - @Html.DropDownList("Gender", new List { - new SelectListItem { Text = Model.Helper.GetResource("Automatic"), Value = "" }, - new SelectListItem { Text = Model.Helper.GetResource("Common.Unspecified"), Value = PluginHelper.NotSpecified }, - new SelectListItem { Text = Model.Helper.GetResource("GenderMale"), Value = "male" }, - new SelectListItem { Text = Model.Helper.GetResource("GenderFemale"), Value = "female" }, - new SelectListItem { Text = Model.Helper.GetResource("GenderUnisex"), Value = "unisex" } - }) - @Html.ValidationMessageFor(m => m.Gender) -
    - @Html.SmartLabelFor(m => m.AgeGroup) - - @Html.DropDownList("AgeGroup", new List { - new SelectListItem { Text = Model.Helper.GetResource("Automatic"), Value = "" }, - new SelectListItem { Text = Model.Helper.GetResource("Common.Unspecified"), Value = PluginHelper.NotSpecified }, - new SelectListItem { Text = Model.Helper.GetResource("AgeGroupAdult"), Value = "adult" }, - new SelectListItem { Text = Model.Helper.GetResource("AgeGroupKids"), Value = "kids" } - }) - @Html.ValidationMessageFor(m => m.AgeGroup) -
    - @Html.SmartLabelFor(m => m.Brand) - - @Html.EditorFor(m => m.Brand) - @Html.ValidationMessageFor(m => m.Brand) -
    - @Html.SmartLabelFor(m => m.Color) - - @Html.EditorFor(m => m.Color) - @Html.ValidationMessageFor(m => m.Color) -
    - @Html.SmartLabelFor(m => m.Size) - - @Html.EditorFor(m => m.Size) - @Html.ValidationMessageFor(m => m.Size) -
    - @Html.SmartLabelFor(m => m.Material) - - @Html.EditorFor(m => m.Material) - @Html.ValidationMessageFor(m => m.Material) -
    - @Html.SmartLabelFor(m => m.Pattern) - - @Html.EditorFor(m => m.Pattern) - @Html.ValidationMessageFor(m => m.Pattern) -
    -
    -
    - @Html.SmartLabelFor(m => m.CurrencyId) - - @Html.DropDownListFor(m => m.CurrencyId, Model.AvailableCurrencies) - @Html.ValidationMessageFor(m => m.CurrencyId) -
    - @Html.SmartLabelFor(m => m.ExpirationDays) - - @Html.EditorFor(m => m.ExpirationDays) - @Html.ValidationMessageFor(m => m.ExpirationDays) -
    - @Html.SmartLabelFor(m => m.SpecialPrice) - - @Html.EditorFor(m => m.SpecialPrice) - @Html.ValidationMessageFor(m => m.SpecialPrice) -
    - @Html.SmartLabelFor(m => m.ExportShipping) - - @Html.EditorFor(m => m.ExportShipping) - @Html.ValidationMessageFor(m => m.ExportShipping) -
    - @Html.SmartLabelFor(m => m.ExportBasePrice) - - @Html.EditorFor(m => m.ExportBasePrice) - @Html.ValidationMessageFor(m => m.ExportBasePrice) -
    - @Html.SmartLabelFor(m => m.UseOwnProductNo) - - @Html.EditorFor(m => m.UseOwnProductNo) - @Html.ValidationMessageFor(m => m.UseOwnProductNo) -
    - @Html.SmartLabelFor(m => m.OnlineOnly) - - @Html.EditorFor(m => m.OnlineOnly) - @Html.ValidationMessageFor(m => m.OnlineOnly) -
    - @Html.SmartLabelFor(m => m.ConvertNetToGrossPrices) - - @Html.EditorFor(m => m.ConvertNetToGrossPrices) - @Html.ValidationMessageFor(m => m.ConvertNetToGrossPrices) -
    - @Html.SmartLabelFor(m => m.TaskEnabled) - - @Html.EditorFor(m => m.TaskEnabled) - @Html.ValidationMessageFor(m => m.TaskEnabled) -
    - @Html.SmartLabelFor(m => m.GenerateStaticFileEachMinutes) - - @Html.EditorFor(m => m.GenerateStaticFileEachMinutes) - @Html.ValidationMessageFor(m => m.GenerateStaticFileEachMinutes) -
      - -
    -
    -} - -@helper TabProductData() { - - - - - - - - - - -
    - @Html.Raw(@T("Plugins.Feed.Froogle.GridEditNote")) -

     

    -
    - - - - - - - - - - - - - - - - -
    - @(Html.Telerik().Grid() - .Name("froogleproducts-grid") - .DataKeys(keys => { - keys.Add(x => x.ProductId).RouteKey("ProductId"); - }) - .Columns(c => { - c.Bound(x => x.ProductId).ReadOnly().Visible(false); - c.Bound(x => x.Name) - .ReadOnly().Visible(true).Width(420) - .Template(x => @Html.LabeledProductName(x.ProductId, x.Name, x.ProductTypeName, x.ProductTypeLabelHint)) - .ClientTemplate(@Html.LabeledProductName("ProductId", "Name")); - c.Bound(x => x.SKU).ReadOnly().Visible(true); - c.Bound(x => x.Taxonomy).ClientTemplate(Html.XEditableLink("Taxonomy", "typeahead")); - c.Bound(x => x.Gender).ClientTemplate(Html.XEditableLink("Gender", "select2")).Width(100); - c.Bound(x => x.AgeGroup).ClientTemplate(Html.XEditableLink("AgeGroup", "select2")).Width(100); - c.Bound(x => x.Color).ClientTemplate(Html.XEditableLink("Color", "text")); - c.Bound(x => x.Size).ClientTemplate(Html.XEditableLink("Size", "text")); - c.Bound(x => x.Material).ClientTemplate(Html.XEditableLink("Material", "text")); - c.Bound(x => x.Pattern).ClientTemplate(Html.XEditableLink("Pattern", "text")); - }) - .ClientEvents(e => { - e.OnDataBound("OnGridDataBound"); - e.OnDataBinding("OnGridDataBinding"); - }) - .DataBinding(dataBinding => { - dataBinding.Ajax() - .Select("GoogleProductList", "FeedFroogle", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Feed.Froogle.Controllers" }, { "area", "" } }); - }) - .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) - .EnableCustomBinding(true) - ) -
    - - -} diff --git a/src/Plugins/Feed.Froogle/Views/Web.config b/src/Plugins/Feed.Froogle/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Feed.Froogle/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Feed.Froogle/packages.config b/src/Plugins/Feed.Froogle/packages.config deleted file mode 100644 index 72f86e8f4b..0000000000 --- a/src/Plugins/Feed.Froogle/packages.config +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/web.config b/src/Plugins/Feed.Froogle/web.config deleted file mode 100644 index e57025ca4e..0000000000 --- a/src/Plugins/Feed.Froogle/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.CashOnDelivery/CashOnDeliveryPaymentProcessor.cs b/src/Plugins/Payments.CashOnDelivery/CashOnDeliveryPaymentProcessor.cs deleted file mode 100644 index cce8ea7862..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/CashOnDeliveryPaymentProcessor.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Payments.CashOnDelivery.Controllers; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; - -namespace SmartStore.Plugin.Payments.CashOnDelivery -{ - /// - /// CashOnDelivery payment processor - /// - public class CashOnDeliveryPaymentProcessor : PaymentMethodBase - { - #region Fields - - private readonly CashOnDeliveryPaymentSettings _cashOnDeliveryPaymentSettings; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; - private readonly IOrderTotalCalculationService _orderTotalCalculationService; - - #endregion - - #region Ctor - - public CashOnDeliveryPaymentProcessor(CashOnDeliveryPaymentSettings cashOnDeliveryPaymentSettings, - ISettingService settingService, - IOrderTotalCalculationService orderTotalCalculationService, - ILocalizationService localizationService) - { - this._cashOnDeliveryPaymentSettings = cashOnDeliveryPaymentSettings; - this._settingService = settingService; - this._orderTotalCalculationService = orderTotalCalculationService; - this._localizationService = localizationService; - } - - #endregion - - #region Methods - - /// - /// Process a payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.NewPaymentStatus = PaymentStatus.Pending; - return result; - } - - /// - /// Gets additional handling fee - /// - /// Shoping cart - /// Additional handling fee - public override decimal GetAdditionalHandlingFee(IList cart) - { - var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, - _cashOnDeliveryPaymentSettings.AdditionalFee, _cashOnDeliveryPaymentSettings.AdditionalFeePercentage); - return result; - } - - /// - /// Captures payment - /// - /// Capture payment request - /// Capture payment result - public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) - { - var result = new CapturePaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoCaptureSupport")); - return result; - } - - /// - /// Refunds a payment - /// - /// Request - /// Result - public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) - { - var result = new RefundPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRefundSupport")); - return result; - } - - /// - /// Voids a payment - /// - /// Request - /// Result - public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) - { - var result = new VoidPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoVoidSupport")); - return result; - } - - /// - /// Process recurring payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Cancels a recurring payment - /// - /// Request - /// Result - public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) - { - var result = new CancelRecurringPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods) - /// - /// Order - /// Result - public override bool CanRePostProcessPayment(Order order) - { - if (order == null) - throw new ArgumentNullException("order"); - - //it's not a redirection payment method. So we always return false - return false; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "PaymentCashOnDelivery"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.CashOnDelivery.Controllers" }, { "area", "Payments.CashOnDelivery" } }; - } - - /// - /// Gets a route for payment info - /// - /// Action name - /// Controller name - /// Route values - public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PaymentInfo"; - controllerName = "PaymentCashOnDelivery"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.CashOnDelivery.Controllers" }, { "area", "Payments.CashOnDelivery" } }; - } - - public override Type GetControllerType() - { - return typeof(PaymentCashOnDeliveryController); - } - - public override void Install() - { - var settings = new CashOnDeliveryPaymentSettings() - { - DescriptionText = "@Plugins.Payment.CashOnDelivery.PaymentInfoDescription" - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //settings - _settingService.DeleteSetting(); - - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Payments.CashOnDelivery", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - /// - /// Gets a payment method type - /// - public override PaymentMethodType PaymentMethodType - { - get - { - return PaymentMethodType.Standard; - } - } - - #endregion - - } -} diff --git a/src/Plugins/Payments.CashOnDelivery/CashOnDeliveryPaymentSettings.cs b/src/Plugins/Payments.CashOnDelivery/CashOnDeliveryPaymentSettings.cs deleted file mode 100644 index 1749fce6e3..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/CashOnDeliveryPaymentSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Payments.CashOnDelivery -{ - public class CashOnDeliveryPaymentSettings : ISettings - { - public string DescriptionText { get; set; } - public decimal AdditionalFee { get; set; } - public bool AdditionalFeePercentage { get; set; } - } -} diff --git a/src/Plugins/Payments.CashOnDelivery/Controllers/PaymentCashOnDeliveryController.cs b/src/Plugins/Payments.CashOnDelivery/Controllers/PaymentCashOnDeliveryController.cs deleted file mode 100644 index f3da484ea5..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Controllers/PaymentCashOnDeliveryController.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Plugin.Payments.CashOnDelivery.Models; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.Payments.CashOnDelivery.Controllers -{ - public class PaymentCashOnDeliveryController : PaymentControllerBase - { - private readonly ISettingService _settingService; - private readonly CashOnDeliveryPaymentSettings _cashOnDeliveryPaymentSettings; - private readonly ILocalizationService _localizationService; - - public PaymentCashOnDeliveryController(ISettingService settingService, - CashOnDeliveryPaymentSettings cashOnDeliveryPaymentSettings, - ILocalizationService localizationService) - { - this._settingService = settingService; - this._cashOnDeliveryPaymentSettings = cashOnDeliveryPaymentSettings; - _localizationService = localizationService; - } - - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - var model = new ConfigurationModel(); - model.DescriptionText = _cashOnDeliveryPaymentSettings.DescriptionText; - model.AdditionalFee = _cashOnDeliveryPaymentSettings.AdditionalFee; - model.AdditionalFeePercentage = _cashOnDeliveryPaymentSettings.AdditionalFeePercentage; - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - [ValidateInput(false)] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //save settings - _cashOnDeliveryPaymentSettings.DescriptionText = model.DescriptionText; - _cashOnDeliveryPaymentSettings.AdditionalFee = model.AdditionalFee; - _cashOnDeliveryPaymentSettings.AdditionalFeePercentage = model.AdditionalFeePercentage; - _settingService.SaveSetting(_cashOnDeliveryPaymentSettings); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PaymentInfo() - { - var model = new PaymentInfoModel(); - string desc = _cashOnDeliveryPaymentSettings.DescriptionText; - - if (desc.StartsWith("@")) - { - model.DescriptionText = _localizationService.GetResource(desc.Substring(1)); - } - else - { - model.DescriptionText = _cashOnDeliveryPaymentSettings.DescriptionText; - } - - return View(model); - } - - [NonAction] - public override IList ValidatePaymentForm(FormCollection form) - { - var warnings = new List(); - return warnings; - } - - [NonAction] - public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) - { - var paymentInfo = new ProcessPaymentRequest(); - return paymentInfo; - } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Description.txt b/src/Plugins/Payments.CashOnDelivery/Description.txt deleted file mode 100644 index fc15454c5d..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Cash On Delivery (COD) -SystemName: Payments.CashOnDelivery -Version: 1.4 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Payments.CashOnDelivery.dll -ResourceRootKey: Plugins.Payment.CashOnDelivery \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Localization/resources.de-de.xml b/src/Plugins/Payments.CashOnDelivery/Localization/resources.de-de.xml deleted file mode 100644 index 0a252eb36a..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Localization/resources.de-de.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Nachnahme - - - - - - - - Beschreibung - - - Geben Sie hier die Beschreibung an, die dem Kunden im Bestellprozess angezeigt wird. - - - Zusätzliche Gebühr - - - Bestimmt die Gebühr die dem Kunden für die Nutzung dieser Zahlart berechnet wird. - - - Zusätzliche Gebühren (prozentual) - - - Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. - - - - Sobald Ihre Bestellung abgeschloßen ist, werden Sie persönlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu bestätigen. -

    P.S. Dieser Text kann im Admin-Bereich editiert werden.

    - ]]> -
    -
    -
    \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Localization/resources.en-us.xml b/src/Plugins/Payments.CashOnDelivery/Localization/resources.en-us.xml deleted file mode 100644 index f56ca15459..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Localization/resources.en-us.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Cash on delivery - - - - - - - - Description - - - Enter info that will be shown to customers during checkout. - - - Additional fee - - - Determines the additional fee. - - - Additional fee. Use percentage - - - Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. - - - - In cases where an order is placed, an authorized representative will contact you, personally or over telephone, to confirm the order.
    After the order is confirmed, it will be processed.
    Orders once confirmed, cannot be cancelled.

    P.S. You can edit this text from admin panel.

    - ]]> -
    -
    - -
    \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Models/ConfigurationModel.cs b/src/Plugins/Payments.CashOnDelivery/Models/ConfigurationModel.cs deleted file mode 100644 index f42ab82dd2..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Models/ConfigurationModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.CashOnDelivery.Models -{ - public class ConfigurationModel : ModelBase - { - [AllowHtml] - [SmartResourceDisplayName("Plugins.Payment.CashOnDelivery.DescriptionText")] - public string DescriptionText { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.CashOnDelivery.AdditionalFee")] - public decimal AdditionalFee { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.CashOnDelivery.AdditionalFeePercentage")] - public bool AdditionalFeePercentage { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Models/PaymentInfoModel.cs b/src/Plugins/Payments.CashOnDelivery/Models/PaymentInfoModel.cs deleted file mode 100644 index b446e1a789..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Models/PaymentInfoModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.CashOnDelivery.Models -{ - public class PaymentInfoModel : ModelBase - { - public string DescriptionText { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Notes.txt b/src/Plugins/Payments.CashOnDelivery/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Properties/AssemblyInfo.cs b/src/Plugins/Payments.CashOnDelivery/Properties/AssemblyInfo.cs deleted file mode 100644 index 6d79d8c2d4..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Payments.CashOnDelivery")] diff --git a/src/Plugins/Payments.CashOnDelivery/RouteProvider.cs b/src/Plugins/Payments.CashOnDelivery/RouteProvider.cs deleted file mode 100644 index a112eb4573..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/RouteProvider.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Payments.CashOnDelivery -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Payments.CashOnDelivery.Configure", - "Plugins/PaymentCashOnDelivery/Configure", - new { controller = "PaymentCashOnDelivery", action = "Configure" }, - new[] { "SmartStore.Plugin.Payments.CashOnDelivery.Controllers" } - ) - .DataTokens["area"] = "Payments.CashOnDelivery"; - - routes.MapRoute("Plugin.Payments.CashOnDelivery.PaymentInfo", - "Plugins/PaymentCashOnDelivery/PaymentInfo", - new { controller = "PaymentCashOnDelivery", action = "PaymentInfo" }, - new[] { "SmartStore.Plugin.Payments.CashOnDelivery.Controllers" } - ) - .DataTokens["area"] = "Payments.CashOnDelivery"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Payments.CashOnDelivery/SmartStore.Plugin.Payments.CashOnDelivery.csproj b/src/Plugins/Payments.CashOnDelivery/SmartStore.Plugin.Payments.CashOnDelivery.csproj deleted file mode 100644 index 1babd74475..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/SmartStore.Plugin.Payments.CashOnDelivery.csproj +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {3D61DE73-5B82-40BD-A980-EA54533179C4} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Payments.CashOnDelivery - SmartStore.Plugin.Payments.CashOnDelivery - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Payments.CashOnDelivery\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Payments.CashOnDelivery\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - Always - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Views/PaymentCashOnDelivery/Configure.cshtml b/src/Plugins/Payments.CashOnDelivery/Views/PaymentCashOnDelivery/Configure.cshtml deleted file mode 100644 index df8a6bee88..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Views/PaymentCashOnDelivery/Configure.cshtml +++ /dev/null @@ -1,46 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.CashOnDelivery.Models.ConfigurationModel -@using SmartStore.Web.Framework; -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.DescriptionText) - - @Html.TextAreaFor(model => model.DescriptionText, new { style = "Width: 550px; Height: 350px;" }) - @Html.ValidationMessageFor(model => model.DescriptionText) -
    - @Html.SmartLabelFor(model => model.AdditionalFee) - - @Html.EditorFor(model => model.AdditionalFee) - @Html.ValidationMessageFor(model => model.AdditionalFee) -
    - @Html.SmartLabelFor(model => model.AdditionalFeePercentage) - - @Html.EditorFor(model => model.AdditionalFeePercentage) - @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) -
      - -
    - -} \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/Views/PaymentCashOnDelivery/PaymentInfo.cshtml b/src/Plugins/Payments.CashOnDelivery/Views/PaymentCashOnDelivery/PaymentInfo.cshtml deleted file mode 100644 index fd70e21641..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Views/PaymentCashOnDelivery/PaymentInfo.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.CashOnDelivery.Models.PaymentInfoModel -@using SmartStore.Web.Framework; - - - - -
    - @Html.Raw(Model.DescriptionText) -
    diff --git a/src/Plugins/Payments.CashOnDelivery/Views/Web.config b/src/Plugins/Payments.CashOnDelivery/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.CashOnDelivery/packages.config b/src/Plugins/Payments.CashOnDelivery/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.CashOnDelivery/web.config b/src/Plugins/Payments.CashOnDelivery/web.config deleted file mode 100644 index 8caecad85c..0000000000 --- a/src/Plugins/Payments.CashOnDelivery/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.DirectDebit/Controllers/PaymentDirectDebitController.cs b/src/Plugins/Payments.DirectDebit/Controllers/PaymentDirectDebitController.cs deleted file mode 100644 index 0014e68dbf..0000000000 --- a/src/Plugins/Payments.DirectDebit/Controllers/PaymentDirectDebitController.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Plugin.Payments.DirectDebit.Models; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.Payments.DirectDebit.Controllers -{ - public class PaymentDirectDebitController : PaymentControllerBase - { - private readonly ISettingService _settingService; - private readonly DirectDebitPaymentSettings _directDebitPaymentSettings; - private readonly ILocalizationService _localizationService; - - public PaymentDirectDebitController(ISettingService settingService, - DirectDebitPaymentSettings directDebitPaymentSettings, - ILocalizationService localizationService) - { - this._settingService = settingService; - this._directDebitPaymentSettings = directDebitPaymentSettings; - this._localizationService = localizationService; - } - - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - var model = new ConfigurationModel(); - model.DescriptionText = _directDebitPaymentSettings.DescriptionText; - model.AdditionalFee = _directDebitPaymentSettings.AdditionalFee; - model.AdditionalFeePercentage = _directDebitPaymentSettings.AdditionalFeePercentage; - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - [ValidateInput(false)] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //save settings - _directDebitPaymentSettings.DescriptionText = model.DescriptionText; - _directDebitPaymentSettings.AdditionalFee = model.AdditionalFee; - _directDebitPaymentSettings.AdditionalFeePercentage = model.AdditionalFeePercentage; - _settingService.SaveSetting(_directDebitPaymentSettings); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PaymentInfo() - { - var model = new PaymentInfoModel(); - string desc = _directDebitPaymentSettings.DescriptionText; - - if( desc.StartsWith("@") ) - { - model.DescriptionText = _localizationService.GetResource(desc.Substring(1)); - } - else { - model.DescriptionText = _directDebitPaymentSettings.DescriptionText; - } - - return View(model); - } - - [NonAction] - public override IList ValidatePaymentForm(FormCollection form) - { - var warnings = new List(); - return warnings; - } - - [NonAction] - public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) - { - var paymentInfo = new ProcessPaymentRequest(); - paymentInfo.DirectDebitAccountHolder = form["DirectDebitAccountHolder"]; - paymentInfo.DirectDebitAccountNumber = form["DirectDebitAccountNumber"]; - paymentInfo.DirectDebitBankCode = form["DirectDebitBankCode"]; - paymentInfo.DirectDebitBankName = form["DirectDebitBankName"]; - paymentInfo.DirectDebitBic = form["DirectDebitBic"]; - paymentInfo.DirectDebitCountry = form["DirectDebitCountry"]; - paymentInfo.DirectDebitIban = form["DirectDebitIban"]; - return paymentInfo; - } - - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Description.txt b/src/Plugins/Payments.DirectDebit/Description.txt deleted file mode 100644 index a65615ddd4..0000000000 --- a/src/Plugins/Payments.DirectDebit/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Direct Debit -SystemName: Payments.DirectDebit -Version: 1.5 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Payments.DirectDebit.dll -ResourceRootKey: Plugins.Payments.DirectDebit \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/DirectDebitPaymentProcessor.cs b/src/Plugins/Payments.DirectDebit/DirectDebitPaymentProcessor.cs deleted file mode 100644 index 9517581c55..0000000000 --- a/src/Plugins/Payments.DirectDebit/DirectDebitPaymentProcessor.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Payments.DirectDebit.Controllers; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; - -namespace SmartStore.Plugin.Payments.DirectDebit -{ - /// - /// DirectDebit payment processor - /// - public class DirectDebitPaymentProcessor : PaymentMethodBase - { - #region Fields - - private readonly DirectDebitPaymentSettings _directDebitPaymentSettings; - private readonly ISettingService _settingService; - private readonly IOrderTotalCalculationService _orderTotalCalculationService; - private readonly ILocalizationService _localizationService; - - #endregion - - #region Ctor - - public DirectDebitPaymentProcessor(DirectDebitPaymentSettings directDebitPaymentSettings, - ISettingService settingService, - IOrderTotalCalculationService orderTotalCalculationService, - ILocalizationService localizationService) - { - this._directDebitPaymentSettings = directDebitPaymentSettings; - this._settingService = settingService; - this._orderTotalCalculationService = orderTotalCalculationService; - this._localizationService = localizationService; - } - - #endregion - - #region Methods - - /// - /// Process a payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.AllowStoringDirectDebit = true; - result.NewPaymentStatus = PaymentStatus.Pending; - return result; - } - - /// - /// Gets additional handling fee - /// - /// Shoping cart - /// Additional handling fee - public override decimal GetAdditionalHandlingFee(IList cart) - { - var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, - _directDebitPaymentSettings.AdditionalFee, _directDebitPaymentSettings.AdditionalFeePercentage); - return result; - } - - /// - /// Captures payment - /// - /// Capture payment request - /// Capture payment result - public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) - { - var result = new CapturePaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoCaptureSupport")); - return result; - } - - /// - /// Refunds a payment - /// - /// Request - /// Result - public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) - { - var result = new RefundPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRefundSupport")); - return result; - } - - /// - /// Voids a payment - /// - /// Request - /// Result - public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) - { - var result = new VoidPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoVoidSupport")); - return result; - } - - /// - /// Process recurring payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.AllowStoringDirectDebit = true; - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Cancels a recurring payment - /// - /// Request - /// Result - public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) - { - var result = new CancelRecurringPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods) - /// - /// Order - /// Result - public override bool CanRePostProcessPayment(Order order) - { - if (order == null) - throw new ArgumentNullException("order"); - - //it's not a redirection payment method. So we always return false - return false; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "PaymentDirectDebit"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.DirectDebit.Controllers" }, { "area", "Payments.DirectDebit" } }; - } - - /// - /// Gets a route for payment info - /// - /// Action name - /// Controller name - /// Route values - public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PaymentInfo"; - controllerName = "PaymentDirectDebit"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.DirectDebit.Controllers" }, { "area", "Payments.DirectDebit" } }; - } - - public override Type GetControllerType() - { - return typeof(PaymentDirectDebitController); - } - - public override void Install() - { - var settings = new DirectDebitPaymentSettings() - { - DescriptionText = "@Plugins.Payments.DirectDebit.PaymentInfoDescription" - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //settings - _settingService.DeleteSetting(); - - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Payments.DirectDebit", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - /// - /// Gets a payment method type - /// - public override PaymentMethodType PaymentMethodType - { - get - { - return PaymentMethodType.Standard; - } - } - - #endregion - - } -} diff --git a/src/Plugins/Payments.DirectDebit/DirectDebitPaymentSettings.cs b/src/Plugins/Payments.DirectDebit/DirectDebitPaymentSettings.cs deleted file mode 100644 index a4dbbcd60b..0000000000 --- a/src/Plugins/Payments.DirectDebit/DirectDebitPaymentSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Payments.DirectDebit -{ - public class DirectDebitPaymentSettings : ISettings - { - public string DescriptionText { get; set; } - public decimal AdditionalFee { get; set; } - public bool AdditionalFeePercentage { get; set; } - } -} diff --git a/src/Plugins/Payments.DirectDebit/Localization/resources.de-de.xml b/src/Plugins/Payments.DirectDebit/Localization/resources.de-de.xml deleted file mode 100644 index 312776bbee..0000000000 --- a/src/Plugins/Payments.DirectDebit/Localization/resources.de-de.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - Lastschrifteinzug (ELV) - - - - - - - - Beschreibung - - - Geben Sie hier die Beschreibung an, die dem Kunden im Bestellprozess angezeigt wird. - - - Zusätzliche Gebühr - - - Bestimmt die Gebühr die dem Kunden für die Nutzung dieser Zahlart berechnet wird. - - - Zusätzliche Gebühren (prozentual) - - - Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. - - - - Name Kontoinhaber - - - Name des Kontoinhabers - - - Kontonummer - - - Kontonummer - - - BLZ - - - Bankleitzahl - - - Land - - - Land der Bankverbindung. - - - Name der Bank - - - Name der Bank. - - - IBAN - - - International Bank Account Number - - - BIC - - - Bank Interchange Code - - - IBAN eingeben - - - Nein - - - Ja - - - Geben Sie bitte den Namen des Kontoinhabers ein. - - - Geben Sie bitte Ihre Kontonummer ein. - - - Geben Sie bitte die Bankleitzahl (BLZ) ein. - - - Geben Sie bitte die IBAN (International Bank Account Number) ein. - - - Geben Sie bitte die BIC (Bank Interchange Code) ein. - - - - - Sobald Ihre Bestellung abgeschloßen ist, werden Sie persönlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu bestätigen. -

    P.S. Dieser Text kann im Admin-Bereich editiert werden.

    - ]]> -
    -
    -
    \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Localization/resources.en-us.xml b/src/Plugins/Payments.DirectDebit/Localization/resources.en-us.xml deleted file mode 100644 index c86a4cea11..0000000000 --- a/src/Plugins/Payments.DirectDebit/Localization/resources.en-us.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - Direct Debit - - - - - - - - Description - - - Enter info that will be shown to customers during checkout. - - - Additional fee - - - Determines the additional fee. - - - Additional fee. Use percentage - - - Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. - - - - Account holder name - - - Holder name of the bank account - - - Account number - - - Account number - - - Bank code - - - Bank code number - - - Country - - - Country of your bank account. - - - Bank name - - - Name of your bank. - - - IBAN - - - International Bank Account Number - - - BIC - - - Bank Interchange Code - - - - Enter IBAN - - - No - - - Yes - - - Please enter the name of the account holder. - - - Please enter your account number. - - - Please enter the bank code. - - - Please enter the IBAN (International Bank Account Number). - - - Please enter the BIC (Bank Interchange Code). - - - - - In cases where an order is placed, an authorized representative will contact you, personally or over telephone, to confirm the order.
    After the order is confirmed, it will be processed.
    Orders once confirmed, cannot be cancelled.

    P.S. You can edit this text from admin panel.

    - ]]> -
    -
    - -
    \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Models/ConfigurationModel.cs b/src/Plugins/Payments.DirectDebit/Models/ConfigurationModel.cs deleted file mode 100644 index 031f60cc6c..0000000000 --- a/src/Plugins/Payments.DirectDebit/Models/ConfigurationModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.DirectDebit.Models -{ - public class ConfigurationModel : ModelBase - { - [AllowHtml] - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DescriptionText")] - public string DescriptionText { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.AdditionalFee")] - public decimal AdditionalFee { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.AdditionalFeePercentage")] - public bool AdditionalFeePercentage { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Models/PaymentInfoModel.cs b/src/Plugins/Payments.DirectDebit/Models/PaymentInfoModel.cs deleted file mode 100644 index aaa7c017d2..0000000000 --- a/src/Plugins/Payments.DirectDebit/Models/PaymentInfoModel.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.DirectDebit.Models -{ - public class PaymentInfoModel : ModelBase - { - public string DescriptionText { get; set; } - - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.EnterIBAN")] - public string EnterIBAN { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitAccountHolder")] - public string DirectDebitAccountHolder { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitAccountNumber")] - public string DirectDebitAccountNumber { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitBankCode")] - public string DirectDebitBankCode { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitCountry")] - public string DirectDebitCountry { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitBankName")] - public string DirectDebitBankName { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitIban")] - public string DirectDebitIban { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitBic")] - public string DirectDebitBic { get; set; } - - public List Countries { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Notes.txt b/src/Plugins/Payments.DirectDebit/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Payments.DirectDebit/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Properties/AssemblyInfo.cs b/src/Plugins/Payments.DirectDebit/Properties/AssemblyInfo.cs deleted file mode 100644 index b8edd34a88..0000000000 --- a/src/Plugins/Payments.DirectDebit/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Payments.DirectDebit")] diff --git a/src/Plugins/Payments.DirectDebit/RouteProvider.cs b/src/Plugins/Payments.DirectDebit/RouteProvider.cs deleted file mode 100644 index 3a483d7373..0000000000 --- a/src/Plugins/Payments.DirectDebit/RouteProvider.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Payments.DirectDebit -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Payments.DirectDebit.Configure", - "Plugins/PaymentDirectDebit/Configure", - new { controller = "PaymentDirectDebit", action = "Configure" }, - new[] { "SmartStore.Plugin.Payments.DirectDebit.Controllers" } - ) - .DataTokens["area"] = "Payments.DirectDebit"; - - routes.MapRoute("Plugin.Payments.DirectDebit.PaymentInfo", - "Plugins/PaymentDirectDebit/PaymentInfo", - new { controller = "PaymentDirectDebit", action = "PaymentInfo" }, - new[] { "SmartStore.Plugin.Payments.DirectDebit.Controllers" } - ) - .DataTokens["area"] = "Payments.DirectDebit"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Payments.DirectDebit/SmartStore.Plugin.Payments.DirectDebit.csproj b/src/Plugins/Payments.DirectDebit/SmartStore.Plugin.Payments.DirectDebit.csproj deleted file mode 100644 index 1a6be93f4a..0000000000 --- a/src/Plugins/Payments.DirectDebit/SmartStore.Plugin.Payments.DirectDebit.csproj +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {AF706567-352D-4FFC-BBAC-913E8DFA22D6} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Payments.DirectDebit - SmartStore.Plugin.Payments.DirectDebit - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Payments.DirectDebit\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Payments.DirectDebit\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Views/PaymentDirectDebit/Configure.cshtml b/src/Plugins/Payments.DirectDebit/Views/PaymentDirectDebit/Configure.cshtml deleted file mode 100644 index 8fcf58d972..0000000000 --- a/src/Plugins/Payments.DirectDebit/Views/PaymentDirectDebit/Configure.cshtml +++ /dev/null @@ -1,46 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.DirectDebit.Models.ConfigurationModel -@using SmartStore.Web.Framework; -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.DescriptionText) - - @Html.TextAreaFor(model => model.DescriptionText, new { style = "Width: 550px; Height: 350px;" }) - @Html.ValidationMessageFor(model => model.DescriptionText) -
    - @Html.SmartLabelFor(model => model.AdditionalFee) - - @Html.EditorFor(model => model.AdditionalFee) - @Html.ValidationMessageFor(model => model.AdditionalFee) -
    - @Html.SmartLabelFor(model => model.AdditionalFeePercentage) - - @Html.EditorFor(model => model.AdditionalFeePercentage) - @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) -
      - -
    - -} \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Views/PaymentDirectDebit/PaymentInfo.cshtml b/src/Plugins/Payments.DirectDebit/Views/PaymentDirectDebit/PaymentInfo.cshtml deleted file mode 100644 index 9baf7ef1cb..0000000000 --- a/src/Plugins/Payments.DirectDebit/Views/PaymentDirectDebit/PaymentInfo.cshtml +++ /dev/null @@ -1,91 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.DirectDebit.Models.PaymentInfoModel -@using SmartStore.Web.Framework; - -
    - @Html.Raw(Model.DescriptionText) -
    - -
    -
    - @Html.LabelFor(model => model.EnterIBAN, new { @class = "control-label" }) -
    - - - - -
    -
    - -
    - @Html.LabelFor(model => model.DirectDebitAccountHolder, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.DirectDebitAccountHolder, new { autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.DirectDebitAccountHolder) -
    -
    - -
    -
    - @Html.LabelFor(model => model.DirectDebitAccountNumber, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.DirectDebitAccountNumber, new { autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.DirectDebitAccountNumber) -
    -
    -
    - @Html.LabelFor(model => model.DirectDebitBankCode, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.DirectDebitBankCode, new { autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.DirectDebitBankCode) -
    -
    -
    - @Html.LabelFor(model => model.DirectDebitCountry, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.DirectDebitCountry, new { autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.DirectDebitCountry) -
    -
    -
    - -
    -
    - @Html.LabelFor(model => model.DirectDebitIban, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.DirectDebitIban, new { autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.DirectDebitIban) -
    -
    -
    - @Html.LabelFor(model => model.DirectDebitBic, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.DirectDebitBic, new { autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.DirectDebitBic) -
    -
    -
    - -
    - @Html.LabelFor(model => model.DirectDebitBankName, new { @class = "control-label" }) -
    - @Html.TextBoxFor(model => model.DirectDebitBankName, new { autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.DirectDebitBankName) -
    -
    -
    - - \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/Views/Web.config b/src/Plugins/Payments.DirectDebit/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Payments.DirectDebit/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.DirectDebit/packages.config b/src/Plugins/Payments.DirectDebit/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/Payments.DirectDebit/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.DirectDebit/web.config b/src/Plugins/Payments.DirectDebit/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Payments.DirectDebit/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.Invoice/Controllers/PaymentInvoiceController.cs b/src/Plugins/Payments.Invoice/Controllers/PaymentInvoiceController.cs deleted file mode 100644 index a0e2e3a177..0000000000 --- a/src/Plugins/Payments.Invoice/Controllers/PaymentInvoiceController.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Plugin.Payments.Invoice.Models; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.Payments.Invoice.Controllers -{ - public class PaymentInvoiceController : PaymentControllerBase - { - private readonly ISettingService _settingService; - private readonly InvoicePaymentSettings _invoicePaymentSettings; - private readonly ILocalizationService _localizationService; - - public PaymentInvoiceController(ISettingService settingService, - InvoicePaymentSettings invoicePaymentSettings, - ILocalizationService localizationService) - { - this._settingService = settingService; - this._invoicePaymentSettings = invoicePaymentSettings; - _localizationService = localizationService; - } - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - var model = new ConfigurationModel(); - model.DescriptionText = _invoicePaymentSettings.DescriptionText; - model.AdditionalFee = _invoicePaymentSettings.AdditionalFee; - model.AdditionalFeePercentage = _invoicePaymentSettings.AdditionalFeePercentage; - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - [ValidateInput(false)] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //save settings - _invoicePaymentSettings.DescriptionText = model.DescriptionText; - _invoicePaymentSettings.AdditionalFee = model.AdditionalFee; - _invoicePaymentSettings.AdditionalFeePercentage = model.AdditionalFeePercentage; - _settingService.SaveSetting(_invoicePaymentSettings); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PaymentInfo() - { - var model = new PaymentInfoModel(); - - string desc = _invoicePaymentSettings.DescriptionText; - - if( desc.StartsWith("@") ) - { - model.DescriptionText = _localizationService.GetResource(desc.Substring(1)); - } - else { - model.DescriptionText = _invoicePaymentSettings.DescriptionText; - } - - return View(model); - } - - [NonAction] - public override IList ValidatePaymentForm(FormCollection form) - { - var warnings = new List(); - return warnings; - } - - [NonAction] - public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) - { - var paymentInfo = new ProcessPaymentRequest(); - return paymentInfo; - } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Description.txt b/src/Plugins/Payments.Invoice/Description.txt deleted file mode 100644 index f4e64cb380..0000000000 --- a/src/Plugins/Payments.Invoice/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Invoice -SystemName: Payments.Invoice -Version: 1.4 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Payments.Invoice.dll -ResourceRootKey: Plugins.Payment.Invoice \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/InvoicePaymentProcessor.cs b/src/Plugins/Payments.Invoice/InvoicePaymentProcessor.cs deleted file mode 100644 index ff4d935f4f..0000000000 --- a/src/Plugins/Payments.Invoice/InvoicePaymentProcessor.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Payments.Invoice.Controllers; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; - -namespace SmartStore.Plugin.Payments.Invoice -{ - /// - /// Invoice payment processor - /// - public class InvoicePaymentProcessor : PaymentMethodBase - { - #region Fields - - private readonly InvoicePaymentSettings _invoicePaymentSettings; - private readonly ISettingService _settingService; - private readonly IOrderTotalCalculationService _orderTotalCalculationService; - private readonly ILocalizationService _localizationService; - - #endregion - - #region Ctor - - public InvoicePaymentProcessor(InvoicePaymentSettings invoicePaymentSettings, - ISettingService settingService, - IOrderTotalCalculationService orderTotalCalculationService, - ILocalizationService localizationService) - { - this._invoicePaymentSettings = invoicePaymentSettings; - this._settingService = settingService; - this._orderTotalCalculationService = orderTotalCalculationService; - this._localizationService = localizationService; - } - - #endregion - - #region Methods - - /// - /// Process a payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.NewPaymentStatus = PaymentStatus.Pending; - return result; - } - - /// - /// Gets additional handling fee - /// - /// Shoping cart - /// Additional handling fee - public override decimal GetAdditionalHandlingFee(IList cart) - { - var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, - _invoicePaymentSettings.AdditionalFee, _invoicePaymentSettings.AdditionalFeePercentage); - return result; - } - - /// - /// Captures payment - /// - /// Capture payment request - /// Capture payment result - public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) - { - var result = new CapturePaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoCaptureSupport")); - return result; - } - - /// - /// Refunds a payment - /// - /// Request - /// Result - public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) - { - var result = new RefundPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRefundSupport")); - return result; - } - - /// - /// Voids a payment - /// - /// Request - /// Result - public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) - { - var result = new VoidPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoVoidSupport")); - return result; - } - - /// - /// Process recurring payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Cancels a recurring payment - /// - /// Request - /// Result - public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) - { - var result = new CancelRecurringPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods) - /// - /// Order - /// Result - public override bool CanRePostProcessPayment(Order order) - { - if (order == null) - throw new ArgumentNullException("order"); - - //it's not a redirection payment method. So we always return false - return false; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "PaymentInvoice"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.Invoice.Controllers" }, { "area", "Payments.Invoice" } }; - } - - /// - /// Gets a route for payment info - /// - /// Action name - /// Controller name - /// Route values - public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PaymentInfo"; - controllerName = "PaymentInvoice"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.Invoice.Controllers" }, { "area", "Payments.Invoice" } }; - } - - public override Type GetControllerType() - { - return typeof(PaymentInvoiceController); - } - - public override void Install() - { - var settings = new InvoicePaymentSettings() - { - DescriptionText = "@Plugins.Payment.Invoice.PaymentInfoDescription" - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //settings - _settingService.DeleteSetting(); - - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Payments.Invoice", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - /// - /// Gets a payment method type - /// - public override PaymentMethodType PaymentMethodType - { - get - { - return PaymentMethodType.Standard; - } - } - - #endregion - - } -} diff --git a/src/Plugins/Payments.Invoice/InvoicePaymentSettings.cs b/src/Plugins/Payments.Invoice/InvoicePaymentSettings.cs deleted file mode 100644 index d131013067..0000000000 --- a/src/Plugins/Payments.Invoice/InvoicePaymentSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Payments.Invoice -{ - public class InvoicePaymentSettings : ISettings - { - public string DescriptionText { get; set; } - public decimal AdditionalFee { get; set; } - public bool AdditionalFeePercentage { get; set; } - } -} diff --git a/src/Plugins/Payments.Invoice/Localization/resources.de-de.xml b/src/Plugins/Payments.Invoice/Localization/resources.de-de.xml deleted file mode 100644 index ded5809437..0000000000 --- a/src/Plugins/Payments.Invoice/Localization/resources.de-de.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Rechnung - - - - - - - - Beschreibung - - - Geben Sie hier die Beschreibung an, die dem Kunden im Bestellprozess angezeigt wird. - - - Zusätzliche Gebühr - - - Bestimmt die Gebühr, die dem Kunden für die Nutzung dieser Zahlart berechnet wird. - - - Zusätzliche Gebühren (prozentual) - - - Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. - - - - Sobald Ihre Bestellung abgeschloßen ist, werden Sie persönlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu bestätigen. -

    P.S. Dieser Text kann im Admin-Bereich editiert werden.

    - ]]> -
    -
    -
    \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Localization/resources.en-us.xml b/src/Plugins/Payments.Invoice/Localization/resources.en-us.xml deleted file mode 100644 index 709e228397..0000000000 --- a/src/Plugins/Payments.Invoice/Localization/resources.en-us.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Invoice - - - - - - - - Description - - - Enter info that will be shown to customers during checkout. - - - Additional fee - - - Determines the additional fee. - - - Additional fee. Use percentage - - - Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. - - - - In cases where an order is placed, an authorized representative will contact you, personally or over telephone, to confirm the order.
    After the order is confirmed, it will be processed.
    Orders once confirmed, cannot be cancelled.

    P.S. You can edit this text from admin panel.

    - ]]> -
    -
    - -
    \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Models/ConfigurationModel.cs b/src/Plugins/Payments.Invoice/Models/ConfigurationModel.cs deleted file mode 100644 index 73fc4cf380..0000000000 --- a/src/Plugins/Payments.Invoice/Models/ConfigurationModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.Invoice.Models -{ - public class ConfigurationModel : ModelBase - { - [AllowHtml] - [SmartResourceDisplayName("Plugins.Payment.Invoice.DescriptionText")] - public string DescriptionText { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.Invoice.AdditionalFee")] - public decimal AdditionalFee { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.Invoice.AdditionalFeePercentage")] - public bool AdditionalFeePercentage { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Models/PaymentInfoModel.cs b/src/Plugins/Payments.Invoice/Models/PaymentInfoModel.cs deleted file mode 100644 index b72fba9467..0000000000 --- a/src/Plugins/Payments.Invoice/Models/PaymentInfoModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.Invoice.Models -{ - public class PaymentInfoModel : ModelBase - { - public string DescriptionText { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Notes.txt b/src/Plugins/Payments.Invoice/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Payments.Invoice/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Properties/AssemblyInfo.cs b/src/Plugins/Payments.Invoice/Properties/AssemblyInfo.cs deleted file mode 100644 index ce15eca395..0000000000 --- a/src/Plugins/Payments.Invoice/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Payments.Invoice")] diff --git a/src/Plugins/Payments.Invoice/RouteProvider.cs b/src/Plugins/Payments.Invoice/RouteProvider.cs deleted file mode 100644 index d31bc14b97..0000000000 --- a/src/Plugins/Payments.Invoice/RouteProvider.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Payments.Invoice -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Payments.Invoice.Configure", - "Plugins/PaymentInvoice/Configure", - new { controller = "PaymentInvoice", action = "Configure" }, - new[] { "SmartStore.Plugin.Payments.Invoice.Controllers" } - ) - .DataTokens["area"] = "Payments.Invoice"; - - routes.MapRoute("Plugin.Payments.Invoice.PaymentInfo", - "Plugins/PaymentInvoice/PaymentInfo", - new { controller = "PaymentInvoice", action = "PaymentInfo" }, - new[] { "SmartStore.Plugin.Payments.Invoice.Controllers" } - ) - .DataTokens["area"] = "Payments.Invoice"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Payments.Invoice/SmartStore.Plugin.Payments.Invoice.csproj b/src/Plugins/Payments.Invoice/SmartStore.Plugin.Payments.Invoice.csproj deleted file mode 100644 index 6b3b89f13b..0000000000 --- a/src/Plugins/Payments.Invoice/SmartStore.Plugin.Payments.Invoice.csproj +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {A1B992C8-91DC-482E-9D3C-F56E474ED45B} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Payments.Invoice - SmartStore.Plugin.Payments.Invoice - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Payments.Invoice\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Payments.Invoice\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Views/PaymentInvoice/Configure.cshtml b/src/Plugins/Payments.Invoice/Views/PaymentInvoice/Configure.cshtml deleted file mode 100644 index fe1c9a44d9..0000000000 --- a/src/Plugins/Payments.Invoice/Views/PaymentInvoice/Configure.cshtml +++ /dev/null @@ -1,46 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.Invoice.Models.ConfigurationModel -@using SmartStore.Web.Framework; -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.DescriptionText) - - @Html.TextAreaFor(model => model.DescriptionText, new { style = "Width: 550px; Height: 350px;" }) - @Html.ValidationMessageFor(model => model.DescriptionText) -
    - @Html.SmartLabelFor(model => model.AdditionalFee) - - @Html.EditorFor(model => model.AdditionalFee) - @Html.ValidationMessageFor(model => model.AdditionalFee) -
    - @Html.SmartLabelFor(model => model.AdditionalFeePercentage) - - @Html.EditorFor(model => model.AdditionalFeePercentage) - @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) -
      - -
    - -} \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/Views/PaymentInvoice/PaymentInfo.cshtml b/src/Plugins/Payments.Invoice/Views/PaymentInvoice/PaymentInfo.cshtml deleted file mode 100644 index ea5967c164..0000000000 --- a/src/Plugins/Payments.Invoice/Views/PaymentInvoice/PaymentInfo.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.Invoice.Models.PaymentInfoModel -@using SmartStore.Web.Framework; - - - - -
    - @Html.Raw(Model.DescriptionText) -
    diff --git a/src/Plugins/Payments.Invoice/Views/Web.config b/src/Plugins/Payments.Invoice/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Payments.Invoice/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.Invoice/packages.config b/src/Plugins/Payments.Invoice/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/Payments.Invoice/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.Invoice/web.config b/src/Plugins/Payments.Invoice/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Payments.Invoice/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.Manual/Controllers/PaymentManualController.cs b/src/Plugins/Payments.Manual/Controllers/PaymentManualController.cs deleted file mode 100644 index e4e543f1a6..0000000000 --- a/src/Plugins/Payments.Manual/Controllers/PaymentManualController.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web.Mvc; -using SmartStore.Plugin.Payments.Manual.Models; -using SmartStore.Plugin.Payments.Manual.Validators; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.Payments.Manual.Controllers -{ - public class PaymentManualController : PaymentControllerBase - { - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; - private readonly ManualPaymentSettings _manualPaymentSettings; - - public PaymentManualController(ISettingService settingService, - ILocalizationService localizationService, ManualPaymentSettings manualPaymentSettings) - { - this._settingService = settingService; - this._localizationService = localizationService; - this._manualPaymentSettings = manualPaymentSettings; - } - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - var model = new ConfigurationModel(); - model.TransactMode = Convert.ToInt32(_manualPaymentSettings.TransactMode); - model.AdditionalFee = _manualPaymentSettings.AdditionalFee; - model.AdditionalFeePercentage = _manualPaymentSettings.AdditionalFeePercentage; - model.TransactModeValues = _manualPaymentSettings.TransactMode.ToSelectList(); - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //save settings - _manualPaymentSettings.TransactMode = (TransactMode)model.TransactMode; - _manualPaymentSettings.AdditionalFee = model.AdditionalFee; - _manualPaymentSettings.AdditionalFeePercentage = model.AdditionalFeePercentage; - _settingService.SaveSetting(_manualPaymentSettings); - - model.TransactModeValues = _manualPaymentSettings.TransactMode.ToSelectList(); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PaymentInfo() - { - var model = new PaymentInfoModel(); - - //CC types - model.CreditCardTypes.Add(new SelectListItem() - { - Text = "Visa", - Value = "Visa", - }); - model.CreditCardTypes.Add(new SelectListItem() - { - Text = "Master card", - Value = "MasterCard", - }); - model.CreditCardTypes.Add(new SelectListItem() - { - Text = "Discover", - Value = "Discover", - }); - model.CreditCardTypes.Add(new SelectListItem() - { - Text = "Amex", - Value = "Amex", - }); - - //years - for (int i = 0; i < 15; i++) - { - string year = Convert.ToString(DateTime.Now.Year + i); - model.ExpireYears.Add(new SelectListItem() - { - Text = year, - Value = year, - }); - } - - //months - for (int i = 1; i <= 12; i++) - { - string text = (i < 10) ? "0" + i.ToString() : i.ToString(); - model.ExpireMonths.Add(new SelectListItem() - { - Text = text, - Value = i.ToString(), - }); - } - - //set postback values - var form = this.Request.Form; - model.CardholderName = form["CardholderName"]; - model.CardNumber = form["CardNumber"]; - model.CardCode = form["CardCode"]; - var selectedCcType = model.CreditCardTypes.Where(x => x.Value.Equals(form["CreditCardType"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - if (selectedCcType != null) - selectedCcType.Selected = true; - var selectedMonth = model.ExpireMonths.Where(x => x.Value.Equals(form["ExpireMonth"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - if (selectedMonth != null) - selectedMonth.Selected = true; - var selectedYear = model.ExpireYears.Where(x => x.Value.Equals(form["ExpireYear"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); - if (selectedYear != null) - selectedYear.Selected = true; - - return View(model); - } - - [NonAction] - public override IList ValidatePaymentForm(FormCollection form) - { - var warnings = new List(); - - //validate - var validator = new PaymentInfoValidator(_localizationService); - var model = new PaymentInfoModel() - { - CardholderName = form["CardholderName"], - CardNumber = form["CardNumber"], - CardCode = form["CardCode"], - }; - var validationResult = validator.Validate(model); - if (!validationResult.IsValid) - foreach (var error in validationResult.Errors) - warnings.Add(error.ErrorMessage); - return warnings; - } - - [NonAction] - public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) - { - var paymentInfo = new ProcessPaymentRequest(); - paymentInfo.CreditCardType = form["CreditCardType"]; - paymentInfo.CreditCardName = form["CardholderName"]; - paymentInfo.CreditCardNumber = form["CardNumber"]; - paymentInfo.CreditCardExpireMonth = int.Parse(form["ExpireMonth"]); - paymentInfo.CreditCardExpireYear = int.Parse(form["ExpireYear"]); - paymentInfo.CreditCardCvv2 = form["CardCode"]; - return paymentInfo; - } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Description.txt b/src/Plugins/Payments.Manual/Description.txt deleted file mode 100644 index 3c3972b337..0000000000 --- a/src/Plugins/Payments.Manual/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Credit Card -SystemName: Payments.Manual -Version: 1.51 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Payments.Manual.dll -ResourceRootKey: Plugins.Payments.Manual \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Localization/resources.de-de.xml b/src/Plugins/Payments.Manual/Localization/resources.de-de.xml deleted file mode 100644 index 4d6ec894cf..0000000000 --- a/src/Plugins/Payments.Manual/Localization/resources.de-de.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - Kreditkarte - - - - - - - - Zusätzliche Gebühr - - - Geben Sie hier die zusätzliche Gebühr an, die Ihren Kunden für die Nutzung dieser Zahlart berechnet werden soll. - - - Zusätzliche Gebühr prozentual berechnen - - - Bestimmt ob die zusätzliche Gebühr prozentual zum Gesamtwert der Bestellung berechnet werden soll. Wenn die Option nicht aktiv ist, wird ein fester Wert berechnet. - - - Markiere die Zahlung nach dem Abschluß der Bestellung als - - - Bestimmen Sie den Transaktionsmodus. - - \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Localization/resources.en-us.xml b/src/Plugins/Payments.Manual/Localization/resources.en-us.xml deleted file mode 100644 index 60a0d1e98a..0000000000 --- a/src/Plugins/Payments.Manual/Localization/resources.en-us.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - Credit card - - - - - - - - Additional fee - - - Enter additional fee to charge your customers. - - - Additional fee. Use percentage - - - Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. - - - After checkout mark payment as - - - Specify transaction mode. - - \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/ManualPaymentProcessor.cs b/src/Plugins/Payments.Manual/ManualPaymentProcessor.cs deleted file mode 100644 index 2ab7724885..0000000000 --- a/src/Plugins/Payments.Manual/ManualPaymentProcessor.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Domain.Discounts; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Payments.Manual.Controllers; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; - -namespace SmartStore.Plugin.Payments.Manual -{ - /// - /// Manual payment processor - /// - public class ManualPaymentProcessor : PaymentMethodBase - { - #region Fields - - private readonly ManualPaymentSettings _manualPaymentSettings; - private readonly ISettingService _settingService; - private readonly IOrderTotalCalculationService _orderTotalCalculationService; - private readonly ILocalizationService _localizationService; - - #endregion - - #region Ctor - - public ManualPaymentProcessor(ManualPaymentSettings manualPaymentSettings, - ISettingService settingService, - IOrderTotalCalculationService orderTotalCalculationService, - ILocalizationService localizationService) - { - this._manualPaymentSettings = manualPaymentSettings; - this._settingService = settingService; - this._orderTotalCalculationService = orderTotalCalculationService; - _localizationService = localizationService; - } - - #endregion - - #region Methods - - /// - /// Process a payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - - result.AllowStoringCreditCardNumber = true; - switch (_manualPaymentSettings.TransactMode) - { - case TransactMode.Pending: - result.NewPaymentStatus = PaymentStatus.Pending; - break; - case TransactMode.Authorize: - result.NewPaymentStatus = PaymentStatus.Authorized; - break; - case TransactMode.AuthorizeAndCapture: - result.NewPaymentStatus = PaymentStatus.Paid; - break; - default: - { - result.AddError(_localizationService.GetResource("Common.Payment.TranactionTypeNotSupported")); - return result; - } - } - - return result; - } - - /// - /// Gets additional handling fee - /// - /// Additional handling fee - public override decimal GetAdditionalHandlingFee(IList cart) - { - var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, - _manualPaymentSettings.AdditionalFee, _manualPaymentSettings.AdditionalFeePercentage); - - return result; - } - - /// - /// Process recurring payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - - result.AllowStoringCreditCardNumber = true; - switch (_manualPaymentSettings.TransactMode) - { - case TransactMode.Pending: - result.NewPaymentStatus = PaymentStatus.Pending; - break; - case TransactMode.Authorize: - result.NewPaymentStatus = PaymentStatus.Authorized; - break; - case TransactMode.AuthorizeAndCapture: - result.NewPaymentStatus = PaymentStatus.Paid; - break; - default: - { - result.AddError(_localizationService.GetResource("Common.Payment.TranactionTypeNotSupported")); - return result; - } - } - - return result; - } - - /// - /// Cancels a recurring payment - /// - /// Request - /// Result - public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) - { - //always success - return new CancelRecurringPaymentResult(); - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "PaymentManual"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.Manual.Controllers" }, { "area", "Payments.Manual" } }; - } - - /// - /// Gets a route for payment info - /// - /// Action name - /// Controller name - /// Route values - public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PaymentInfo"; - controllerName = "PaymentManual"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.Manual.Controllers" }, { "area", "Payments.Manual" } }; - } - - public override Type GetControllerType() - { - return typeof(PaymentManualController); - } - - public override void Install() - { - //settings - var settings = new ManualPaymentSettings() - { - TransactMode = TransactMode.Pending - }; - _settingService.SaveSetting(settings); - - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //settings - _settingService.DeleteSetting(); - - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Payments.Manual", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - /// - /// Gets a recurring payment type of payment method - /// - public override RecurringPaymentType RecurringPaymentType - { - get - { - return RecurringPaymentType.Manual; - } - } - - /// - /// Gets a payment method type - /// - public override PaymentMethodType PaymentMethodType - { - get - { - return PaymentMethodType.Standard; - } - } - - #endregion - - } -} diff --git a/src/Plugins/Payments.Manual/ManualPaymentSettings.cs b/src/Plugins/Payments.Manual/ManualPaymentSettings.cs deleted file mode 100644 index 47af16aa95..0000000000 --- a/src/Plugins/Payments.Manual/ManualPaymentSettings.cs +++ /dev/null @@ -1,17 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Payments.Manual -{ - public class ManualPaymentSettings : ISettings - { - public TransactMode TransactMode { get; set; } - /// - /// Gets or sets a value indicating whether to "additional fee" is specified as percentage. true - percentage, false - fixed value. - /// - public bool AdditionalFeePercentage { get; set; } - /// - /// Additional fee - /// - public decimal AdditionalFee { get; set; } - } -} diff --git a/src/Plugins/Payments.Manual/Models/ConfigurationModel.cs b/src/Plugins/Payments.Manual/Models/ConfigurationModel.cs deleted file mode 100644 index f05c1e8ae1..0000000000 --- a/src/Plugins/Payments.Manual/Models/ConfigurationModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.Manual.Models -{ - public class ConfigurationModel : ModelBase - { - [SmartResourceDisplayName("Plugins.Payments.Manual.Fields.AdditionalFeePercentage")] - public bool AdditionalFeePercentage { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.Manual.Fields.AdditionalFee")] - public decimal AdditionalFee { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.Manual.Fields.TransactMode")] - public int TransactMode { get; set; } - public SelectList TransactModeValues { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Models/PaymentInfoModel.cs b/src/Plugins/Payments.Manual/Models/PaymentInfoModel.cs deleted file mode 100644 index 4171cd35da..0000000000 --- a/src/Plugins/Payments.Manual/Models/PaymentInfoModel.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.Manual.Models -{ - public class PaymentInfoModel : ModelBase - { - public PaymentInfoModel() - { - CreditCardTypes = new List(); - ExpireMonths = new List(); - ExpireYears = new List(); - } - - [SmartResourceDisplayName("Payment.SelectCreditCard")] - [AllowHtml] - public string CreditCardType { get; set; } - [SmartResourceDisplayName("Payment.SelectCreditCard")] - public IList CreditCardTypes { get; set; } - - [SmartResourceDisplayName("Payment.CardholderName")] - [AllowHtml] - public string CardholderName { get; set; } - - [SmartResourceDisplayName("Payment.CardNumber")] - [AllowHtml] - public string CardNumber { get; set; } - - [SmartResourceDisplayName("Payment.ExpirationDate")] - [AllowHtml] - public string ExpireMonth { get; set; } - [SmartResourceDisplayName("Payment.ExpirationDate")] - [AllowHtml] - public string ExpireYear { get; set; } - public IList ExpireMonths { get; set; } - public IList ExpireYears { get; set; } - - [SmartResourceDisplayName("Payment.CardCode")] - [AllowHtml] - public string CardCode { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Notes.txt b/src/Plugins/Payments.Manual/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Payments.Manual/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Properties/AssemblyInfo.cs b/src/Plugins/Payments.Manual/Properties/AssemblyInfo.cs deleted file mode 100644 index 885fef84f2..0000000000 --- a/src/Plugins/Payments.Manual/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Payments.Manual")] diff --git a/src/Plugins/Payments.Manual/RouteProvider.cs b/src/Plugins/Payments.Manual/RouteProvider.cs deleted file mode 100644 index 028ec62c16..0000000000 --- a/src/Plugins/Payments.Manual/RouteProvider.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Payments.Manual -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Payments.Manual.Configure", - "Plugins/PaymentManual/Configure", - new { controller = "PaymentManual", action = "Configure" }, - new[] { "SmartStore.Plugin.Payments.Manual.Controllers" } - ) - .DataTokens["area"] = "Payments.Manual"; - - routes.MapRoute("Plugin.Payments.Manual.PaymentInfo", - "Plugins/PaymentManual/PaymentInfo", - new { controller = "PaymentManual", action = "PaymentInfo" }, - new[] { "SmartStore.Plugin.Payments.Manual.Controllers" } - ) - .DataTokens["area"] = "Payments.Manual"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Payments.Manual/SmartStore.Plugin.Payments.Manual.csproj b/src/Plugins/Payments.Manual/SmartStore.Plugin.Payments.Manual.csproj deleted file mode 100644 index a0fb1f9602..0000000000 --- a/src/Plugins/Payments.Manual/SmartStore.Plugin.Payments.Manual.csproj +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {9A7B9344-6AD0-4828-876D-0BF14C177148} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Payments.Manual - SmartStore.Plugin.Payments.Manual - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Payments.Manual\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Payments.Manual\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\FluentValidation.5.0.0.1\lib\Net40\FluentValidation.dll - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - PreserveNewest - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/TransactMode.cs b/src/Plugins/Payments.Manual/TransactMode.cs deleted file mode 100644 index 0fde0e7292..0000000000 --- a/src/Plugins/Payments.Manual/TransactMode.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace SmartStore.Plugin.Payments.Manual -{ - /// - /// Represents manual payment processor transaction mode - /// - public enum TransactMode : int - { - /// - /// Pending - /// - Pending = 0, - /// - /// Authorize - /// - Authorize = 1, - /// - /// Authorize and capture - /// - AuthorizeAndCapture= 2 - } -} diff --git a/src/Plugins/Payments.Manual/Validators/PaymentInfoValidator.cs b/src/Plugins/Payments.Manual/Validators/PaymentInfoValidator.cs deleted file mode 100644 index 4703731496..0000000000 --- a/src/Plugins/Payments.Manual/Validators/PaymentInfoValidator.cs +++ /dev/null @@ -1,23 +0,0 @@ -using FluentValidation; -using SmartStore.Plugin.Payments.Manual.Models; -using SmartStore.Services.Localization; -using SmartStore.Web.Framework.Validators; - -namespace SmartStore.Plugin.Payments.Manual.Validators -{ - public class PaymentInfoValidator : AbstractValidator - { - public PaymentInfoValidator(ILocalizationService localizationService) - { - //useful links: - //http://fluentvalidation.codeplex.com/wikipage?title=Custom&referringTitle=Documentation&ANCHOR#CustomValidator - //http://benjii.me/2010/11/credit-card-validator-attribute-for-asp-net-mvc-3/ - - //RuleFor(x => x.CardNumber).NotEmpty().WithMessage(localizationService.GetResource("Payment.CardNumber.Required")); - //RuleFor(x => x.CardCode).NotEmpty().WithMessage(localizationService.GetResource("Payment.CardCode.Required")); - - RuleFor(x => x.CardholderName).NotEmpty().WithMessage(localizationService.GetResource("Payment.CardholderName.Required")); - RuleFor(x => x.CardNumber).IsCreditCard().WithMessage(localizationService.GetResource("Payment.CardNumber.Wrong")); - RuleFor(x => x.CardCode).Matches(@"^[0-9]{3,4}$").WithMessage(localizationService.GetResource("Payment.CardCode.Wrong")); - }} -} \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Views/PaymentManual/Configure.cshtml b/src/Plugins/Payments.Manual/Views/PaymentManual/Configure.cshtml deleted file mode 100644 index c65a6a4795..0000000000 --- a/src/Plugins/Payments.Manual/Views/PaymentManual/Configure.cshtml +++ /dev/null @@ -1,45 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.Manual.Models.ConfigurationModel -@using SmartStore.Web.Framework; -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.TransactMode) - - @Html.DropDownList("TransactMode", Model.TransactModeValues) -
    - @Html.SmartLabelFor(model => model.AdditionalFee) - - @Html.EditorFor(model => model.AdditionalFee) - @Html.ValidationMessageFor(model => model.AdditionalFee) -
    - @Html.SmartLabelFor(model => model.AdditionalFeePercentage) - - @Html.EditorFor(model => model.AdditionalFeePercentage) - @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) -
      - -
    - -} \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/Views/PaymentManual/PaymentInfo.Mobile.cshtml b/src/Plugins/Payments.Manual/Views/PaymentManual/PaymentInfo.Mobile.cshtml deleted file mode 100644 index b91a3e4788..0000000000 --- a/src/Plugins/Payments.Manual/Views/PaymentManual/PaymentInfo.Mobile.cshtml +++ /dev/null @@ -1,24 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.Manual.Models.PaymentInfoModel -@using SmartStore.Web.Framework; -@Html.SmartLabelFor(model => model.CreditCardTypes, false) -@Html.DropDownListFor(model => model.CreditCardType, Model.CreditCardTypes) -@Html.SmartLabelFor(model => model.CardholderName, false) -@Html.TextBoxFor(model => model.CardholderName, new { autocomplete = "off" }) -@Html.ValidationMessageFor(model => model.CardholderName) -@Html.SmartLabelFor(model => model.CardNumber, false) -@Html.TextBoxFor(model => model.CardNumber, new { autocomplete = "off", maxlength = 22 }) -@Html.ValidationMessageFor(model => model.CardNumber) -@Html.SmartLabelFor(model => model.ExpireMonth, false) -
    -
    - @Html.DropDownListFor(model => model.ExpireMonth, Model.ExpireMonths) - / - @Html.DropDownListFor(model => model.ExpireYear, Model.ExpireYears) -
    -
    -@Html.SmartLabelFor(model => model.CardCode, false) -@Html.TextBoxFor(model => model.CardCode, new { style = "Width: 60px;", autocomplete = "off", maxlength = 4 }) -@Html.ValidationMessageFor(model => model.CardCode) diff --git a/src/Plugins/Payments.Manual/Views/PaymentManual/PaymentInfo.cshtml b/src/Plugins/Payments.Manual/Views/PaymentManual/PaymentInfo.cshtml deleted file mode 100644 index 9232fcf2a3..0000000000 --- a/src/Plugins/Payments.Manual/Views/PaymentManual/PaymentInfo.cshtml +++ /dev/null @@ -1,43 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.Manual.Models.PaymentInfoModel -@using SmartStore.Web.Framework; - -
    -
    - @Html.LabelFor(model => model.CreditCardTypes, new { @class="control-label required" }) -
    - @Html.DropDownListFor(model => model.CreditCardType, Model.CreditCardTypes, new { @class = "dropdownlists", style = "min-width: 180px;" }) -
    -
    -
    - @Html.LabelFor(model => model.CardholderName, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.CardholderName, new { style = "Width: 165px;", autocomplete = "off" }) - @Html.ValidationMessageFor(model => model.CardholderName) -
    -
    -
    - @Html.LabelFor(model => model.CardNumber, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.CardNumber, new { style = "Width: 165px;", autocomplete = "off", maxlength = 22 }) - @Html.ValidationMessageFor(model => model.CardNumber) -
    -
    -
    - @Html.LabelFor(model => model.ExpireMonth, new { @class="control-label required" }) -
    - @Html.DropDownListFor(model => model.ExpireMonth, Model.ExpireMonths, new { @class = "dropdownlists", style = "min-width: 83px;" }) - / - @Html.DropDownListFor(model => model.ExpireYear, Model.ExpireYears, new { @class = "dropdownlists", style = "min-width: 83px;" }) -
    -
    -
    - @Html.LabelFor(model => model.CardCode, new { @class="control-label required" }) -
    - @Html.TextBoxFor(model => model.CardCode, new { style = "Width: 60px;", autocomplete = "off", maxlength = 4 }) - @Html.ValidationMessageFor(model => model.CardCode) -
    -
    -
    diff --git a/src/Plugins/Payments.Manual/Views/Web.config b/src/Plugins/Payments.Manual/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Payments.Manual/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.Manual/packages.config b/src/Plugins/Payments.Manual/packages.config deleted file mode 100644 index dbb54d0ded..0000000000 --- a/src/Plugins/Payments.Manual/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.Manual/web.config b/src/Plugins/Payments.Manual/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Payments.Manual/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.PayInStore/Controllers/PaymentPayInStoreController.cs b/src/Plugins/Payments.PayInStore/Controllers/PaymentPayInStoreController.cs deleted file mode 100644 index 255660b1fc..0000000000 --- a/src/Plugins/Payments.PayInStore/Controllers/PaymentPayInStoreController.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Plugin.Payments.PayInStore.Models; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.Payments.PayInStore.Controllers -{ - public class PaymentPayInStoreController : PaymentControllerBase - { - private readonly ISettingService _settingService; - private readonly PayInStorePaymentSettings _payInStorePaymentSettings; - private readonly ILocalizationService _localizationService; - - public PaymentPayInStoreController(ISettingService settingService, - PayInStorePaymentSettings payInStorePaymentSettings, - ILocalizationService localizationService) - { - this._settingService = settingService; - this._payInStorePaymentSettings = payInStorePaymentSettings; - this._localizationService = localizationService; - } - - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - var model = new ConfigurationModel(); - model.DescriptionText = _payInStorePaymentSettings.DescriptionText; - model.AdditionalFee = _payInStorePaymentSettings.AdditionalFee; - model.AdditionalFeePercentage = _payInStorePaymentSettings.AdditionalFeePercentage; - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - [ValidateInput(false)] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //save settings - _payInStorePaymentSettings.DescriptionText = model.DescriptionText; - _payInStorePaymentSettings.AdditionalFee = model.AdditionalFee; - _payInStorePaymentSettings.AdditionalFeePercentage = model.AdditionalFeePercentage; - _settingService.SaveSetting(_payInStorePaymentSettings); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PaymentInfo() - { - var model = new PaymentInfoModel(); - - string desc = _payInStorePaymentSettings.DescriptionText; - - if (desc.StartsWith("@")) - { - model.DescriptionText = _localizationService.GetResource(desc.Substring(1)); - } - else - { - model.DescriptionText = _payInStorePaymentSettings.DescriptionText; - } - - return View(model); - } - - [NonAction] - public override IList ValidatePaymentForm(FormCollection form) - { - var warnings = new List(); - return warnings; - } - - [NonAction] - public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) - { - var paymentInfo = new ProcessPaymentRequest(); - return paymentInfo; - } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Description.txt b/src/Plugins/Payments.PayInStore/Description.txt deleted file mode 100644 index 2d3edf1a75..0000000000 --- a/src/Plugins/Payments.PayInStore/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Pay In Store -SystemName: Payments.PayInStore -Version: 1.4 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Payments.PayInStore.dll -ResourceRootKey: Plugins.Payment.PayInStore \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Localization/resources.de-de.xml b/src/Plugins/Payments.PayInStore/Localization/resources.de-de.xml deleted file mode 100644 index 39040b8257..0000000000 --- a/src/Plugins/Payments.PayInStore/Localization/resources.de-de.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Barzahlung - - - - - - - - Beschreibung - - - Geben Sie hier die Beschreibung an, die dem Kunden im Bestellprozess angezeigt wird. - - - Zusätzliche Gebühr - - - Bestimmt die Gebühr die dem Kunden für die Nutzung dieser Zahlart berechnet wird. - - - Zusätzliche Gebühren (prozentual) - - - Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. - - - - Reservieren Sie Produkte und zahlen Sie an der Kasse in unserem Ladenlokal.
    Und Hier finden Sie uns: Dortmund, Westenhellweg 88,...

    -

    P.S. Dieser Text kann im Admin-Bereich editiert werden.

    - ]]> -
    -
    -
    \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Localization/resources.en-us.xml b/src/Plugins/Payments.PayInStore/Localization/resources.en-us.xml deleted file mode 100644 index 443e8eee24..0000000000 --- a/src/Plugins/Payments.PayInStore/Localization/resources.en-us.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Pay in store - - - - - - - - Description - - - Enter info that will be shown to customers during checkout. - - - Additional fee - - - Determines the additional fee. - - - Additional fee. Use percentage - - - Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. - - - - Reserve items at your local store, and pay in store when you pick up your order.
    Our store location: USA, New York,...

    P.S. You can edit this text from admin panel.

    - ]]> -
    -
    - -
    \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Models/ConfigurationModel.cs b/src/Plugins/Payments.PayInStore/Models/ConfigurationModel.cs deleted file mode 100644 index b80e685bbf..0000000000 --- a/src/Plugins/Payments.PayInStore/Models/ConfigurationModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.PayInStore.Models -{ - public class ConfigurationModel : ModelBase - { - [AllowHtml] - [SmartResourceDisplayName("Plugins.Payment.PayInStore.DescriptionText")] - public string DescriptionText { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.PayInStore.AdditionalFee")] - public decimal AdditionalFee { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.PayInStore.AdditionalFeePercentage")] - public bool AdditionalFeePercentage { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Models/PaymentInfoModel.cs b/src/Plugins/Payments.PayInStore/Models/PaymentInfoModel.cs deleted file mode 100644 index 6606ec4563..0000000000 --- a/src/Plugins/Payments.PayInStore/Models/PaymentInfoModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.PayInStore.Models -{ - public class PaymentInfoModel : ModelBase - { - public string DescriptionText { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Notes.txt b/src/Plugins/Payments.PayInStore/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Payments.PayInStore/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/PayInStorePaymentProcessor.cs b/src/Plugins/Payments.PayInStore/PayInStorePaymentProcessor.cs deleted file mode 100644 index 2204481008..0000000000 --- a/src/Plugins/Payments.PayInStore/PayInStorePaymentProcessor.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Payments.PayInStore.Controllers; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; - -namespace SmartStore.Plugin.Payments.PayInStore -{ - /// - /// PayInStore payment processor - /// - public class PayInStorePaymentProcessor : PaymentMethodBase - { - #region Fields - private readonly PayInStorePaymentSettings _payInStorePaymentSettings; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; - private readonly IOrderTotalCalculationService _orderTotalCalculationService; - #endregion - - #region Ctor - - public PayInStorePaymentProcessor(PayInStorePaymentSettings payInStorePaymentSettings, - ISettingService settingService, - ILocalizationService localizationService, - IOrderTotalCalculationService orderTotalCalculationService) - { - this._payInStorePaymentSettings = payInStorePaymentSettings; - this._settingService = settingService; - this._localizationService = localizationService; - this._orderTotalCalculationService = orderTotalCalculationService; - } - - #endregion - - #region Methods - - /// - /// Process a payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.NewPaymentStatus = PaymentStatus.Pending; - return result; - } - - /// - /// Gets additional handling fee - /// - /// Shoping cart - /// Additional handling fee - public override decimal GetAdditionalHandlingFee(IList cart) - { - var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, _payInStorePaymentSettings.AdditionalFee, _payInStorePaymentSettings.AdditionalFeePercentage); - return result; - } - - /// - /// Captures payment - /// - /// Capture payment request - /// Capture payment result - public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) - { - var result = new CapturePaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoCaptureSupport")); - return result; - } - - /// - /// Refunds a payment - /// - /// Request - /// Result - public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) - { - var result = new RefundPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRefundSupport")); - return result; - } - - /// - /// Voids a payment - /// - /// Request - /// Result - public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) - { - var result = new VoidPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoVoidSupport")); - return result; - } - - /// - /// Process recurring payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Cancels a recurring payment - /// - /// Request - /// Result - public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) - { - var result = new CancelRecurringPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods) - /// - /// Order - /// Result - public override bool CanRePostProcessPayment(Order order) - { - if (order == null) - throw new ArgumentNullException("order"); - - //it's not a redirection payment method. So we always return false - return false; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "PaymentPayInStore"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.PayInStore.Controllers" }, { "area", "Payments.PayInStore" } }; - } - - /// - /// Gets a route for payment info - /// - /// Action name - /// Controller name - /// Route values - public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PaymentInfo"; - controllerName = "PaymentPayInStore"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.PayInStore.Controllers" }, { "area", "Payments.PayInStore" } }; - } - - public override Type GetControllerType() - { - return typeof(PaymentPayInStoreController); - } - - public override void Install() - { - var settings = new PayInStorePaymentSettings() - { - DescriptionText = "@Plugins.Payment.PayInStore.PaymentInfoDescription" - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //settings - _settingService.DeleteSetting(); - - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Payments.PayInStore", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - /// - /// Gets a payment method type - /// - public override PaymentMethodType PaymentMethodType - { - get - { - return PaymentMethodType.Standard; - } - } - - #endregion - - } -} diff --git a/src/Plugins/Payments.PayInStore/PayInStorePaymentSettings.cs b/src/Plugins/Payments.PayInStore/PayInStorePaymentSettings.cs deleted file mode 100644 index b523b166aa..0000000000 --- a/src/Plugins/Payments.PayInStore/PayInStorePaymentSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Payments.PayInStore -{ - public class PayInStorePaymentSettings : ISettings - { - public string DescriptionText { get; set; } - public decimal AdditionalFee { get; set; } - public bool AdditionalFeePercentage { get; set; } - } -} diff --git a/src/Plugins/Payments.PayInStore/Properties/AssemblyInfo.cs b/src/Plugins/Payments.PayInStore/Properties/AssemblyInfo.cs deleted file mode 100644 index f79777245c..0000000000 --- a/src/Plugins/Payments.PayInStore/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Payments.PayInStore")] \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/RouteProvider.cs b/src/Plugins/Payments.PayInStore/RouteProvider.cs deleted file mode 100644 index 65b301c0cf..0000000000 --- a/src/Plugins/Payments.PayInStore/RouteProvider.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Payments.PayInStore -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Payments.PayInStore.Configure", - "Plugins/PaymentPayInStore/Configure", - new { controller = "PaymentPayInStore", action = "Configure" }, - new[] { "SmartStore.Plugin.Payments.PayInStore.Controllers" } - ) - .DataTokens["area"] = "Payments.PayInStore"; - - routes.MapRoute("Plugin.Payments.PayInStore.PaymentInfo", - "Plugins/PaymentPayInStore/PaymentInfo", - new { controller = "PaymentPayInStore", action = "PaymentInfo" }, - new[] { "SmartStore.Plugin.Payments.PayInStore.Controllers" } - ) - .DataTokens["area"] = "Payments.PayInStore"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Payments.PayInStore/SmartStore.Plugin.Payments.PayInStore.csproj b/src/Plugins/Payments.PayInStore/SmartStore.Plugin.Payments.PayInStore.csproj deleted file mode 100644 index 581ff84e4b..0000000000 --- a/src/Plugins/Payments.PayInStore/SmartStore.Plugin.Payments.PayInStore.csproj +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {A284F47B-9DAF-4475-BB79-7A418EECC01D} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Payments.PayInStore - SmartStore.Plugin.Payments.PayInStore - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Payments.PayInStore\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Payments.PayInStore\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Views/PaymentPayInStore/Configure.cshtml b/src/Plugins/Payments.PayInStore/Views/PaymentPayInStore/Configure.cshtml deleted file mode 100644 index 894ad4d435..0000000000 --- a/src/Plugins/Payments.PayInStore/Views/PaymentPayInStore/Configure.cshtml +++ /dev/null @@ -1,47 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.PayInStore.Models.ConfigurationModel -@using SmartStore.Web.Framework; -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.DescriptionText) - - @Html.TextAreaFor(model => Model.DescriptionText, new { style = "Width: 550px; Height: 350px;" }) - @Html.ValidationMessageFor(model => model.DescriptionText) -
    - @Html.SmartLabelFor(model => model.AdditionalFee) - - @Html.EditorFor(model => model.AdditionalFee) - @Html.ValidationMessageFor(model => model.AdditionalFee) -
    - @Html.SmartLabelFor(model => model.AdditionalFeePercentage) - - @Html.EditorFor(model => model.AdditionalFeePercentage) - @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) -
    -   - - -
    -} \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/Views/PaymentPayInStore/PaymentInfo.cshtml b/src/Plugins/Payments.PayInStore/Views/PaymentPayInStore/PaymentInfo.cshtml deleted file mode 100644 index a084e3fcb4..0000000000 --- a/src/Plugins/Payments.PayInStore/Views/PaymentPayInStore/PaymentInfo.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.PayInStore.Models.PaymentInfoModel -@using SmartStore.Web.Framework; - - - - -
    - @Html.Raw(Model.DescriptionText) -
    diff --git a/src/Plugins/Payments.PayInStore/Views/Web.config b/src/Plugins/Payments.PayInStore/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Payments.PayInStore/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.PayInStore/packages.config b/src/Plugins/Payments.PayInStore/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/Payments.PayInStore/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.PayInStore/web.config b/src/Plugins/Payments.PayInStore/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Payments.PayInStore/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.PayPalStandard/Content/images/logo200x53.png b/src/Plugins/Payments.PayPalStandard/Content/images/logo200x53.png deleted file mode 100644 index a23fcb7a0b..0000000000 Binary files a/src/Plugins/Payments.PayPalStandard/Content/images/logo200x53.png and /dev/null differ diff --git a/src/Plugins/Payments.PayPalStandard/Controllers/PaymentPayPalStandardController.cs b/src/Plugins/Payments.PayPalStandard/Controllers/PaymentPayPalStandardController.cs deleted file mode 100644 index baea80dabc..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Controllers/PaymentPayPalStandardController.cs +++ /dev/null @@ -1,451 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using System.Linq; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Plugin.Payments.PayPalStandard.Models; -using SmartStore.Services.Configuration; -using SmartStore.Core.Logging; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Plugin.Payments.PayPalStandard.Services; -using SmartStore.Services.Localization; -using Autofac; - -namespace SmartStore.Plugin.Payments.PayPalStandard.Controllers -{ - public class PaymentPayPalStandardController : PaymentControllerBase - { - private readonly ISettingService _settingService; - private readonly IPaymentService _paymentService; - private readonly IOrderService _orderService; - private readonly IOrderProcessingService _orderProcessingService; - private readonly IStoreContext _storeContext; - private readonly IWorkContext _workContext; - private readonly IWebHelper _webHelper; - private readonly PayPalStandardPaymentSettings _paypalStandardPaymentSettings; - private readonly PaymentSettings _paymentSettings; - private readonly ILocalizationService _localizationService; - private readonly IPayPalStandardService _payPalStandardService; - - public PaymentPayPalStandardController(ISettingService settingService, - IPaymentService paymentService, IOrderService orderService, - IOrderProcessingService orderProcessingService, - IStoreContext storeContext, - IWorkContext workContext, - IWebHelper webHelper, - PayPalStandardPaymentSettings paypalStandardPaymentSettings, - PaymentSettings paymentSettings, - ILocalizationService localizationService, - IPayPalStandardService payPalStandardService) - { - this._settingService = settingService; - this._paymentService = paymentService; - this._orderService = orderService; - this._orderProcessingService = orderProcessingService; - this._storeContext = storeContext; - this._workContext = workContext; - this._webHelper = webHelper; - this._paypalStandardPaymentSettings = paypalStandardPaymentSettings; - this._paymentSettings = paymentSettings; - this._localizationService = localizationService; - this._payPalStandardService = payPalStandardService; - } - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - var model = new ConfigurationModel(); - model.UseSandbox = _paypalStandardPaymentSettings.UseSandbox; - model.BusinessEmail = _paypalStandardPaymentSettings.BusinessEmail; - model.PdtToken = _paypalStandardPaymentSettings.PdtToken; - model.PdtValidateOrderTotal = _paypalStandardPaymentSettings.PdtValidateOrderTotal; - model.AdditionalFee = _paypalStandardPaymentSettings.AdditionalFee; - model.AdditionalFeePercentage = _paypalStandardPaymentSettings.AdditionalFeePercentage; - model.PassProductNamesAndTotals = _paypalStandardPaymentSettings.PassProductNamesAndTotals; - model.EnableIpn = _paypalStandardPaymentSettings.EnableIpn; - model.IpnUrl = _paypalStandardPaymentSettings.IpnUrl; - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //save settings - _paypalStandardPaymentSettings.UseSandbox = model.UseSandbox; - _paypalStandardPaymentSettings.BusinessEmail = model.BusinessEmail; - _paypalStandardPaymentSettings.PdtToken = model.PdtToken; - _paypalStandardPaymentSettings.PdtValidateOrderTotal = model.PdtValidateOrderTotal; - _paypalStandardPaymentSettings.AdditionalFee = model.AdditionalFee; - _paypalStandardPaymentSettings.AdditionalFeePercentage = model.AdditionalFeePercentage; - _paypalStandardPaymentSettings.PassProductNamesAndTotals = model.PassProductNamesAndTotals; - _paypalStandardPaymentSettings.EnableIpn = model.EnableIpn; - _paypalStandardPaymentSettings.IpnUrl = model.IpnUrl; - _settingService.SaveSetting(_paypalStandardPaymentSettings); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PaymentInfo() - { - return View(); - } - - [NonAction] - public override IList ValidatePaymentForm(FormCollection form) - { - var warnings = new List(); - return warnings; - } - - [NonAction] - public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) - { - var paymentInfo = new ProcessPaymentRequest(); - return paymentInfo; - } - - [ValidateInput(false)] - public ActionResult PDTHandler(FormCollection form) - { - string tx = _webHelper.QueryString("tx"); - Dictionary values; - string response; - - var processor = _paymentService.LoadPaymentMethodBySystemName("Payments.PayPalStandard") as PayPalStandardPaymentProcessor; - if (processor == null || !processor.IsPaymentMethodActive(_paymentSettings) || !processor.PluginDescriptor.Installed) - throw new SmartException(_localizationService.GetResource("Plugins.Payments.PayPalStandard.NoModuleLoading")); - - if (processor.GetPDTDetails(tx, out values, out response)) - { - string orderNumber = string.Empty; - values.TryGetValue("custom", out orderNumber); - Guid orderNumberGuid = Guid.Empty; - try - { - orderNumberGuid = new Guid(orderNumber); - } - catch { } - Order order = _orderService.GetOrderByGuid(orderNumberGuid); - if (order != null) - { - decimal total = decimal.Zero; - try - { - total = decimal.Parse(values["mc_gross"], new CultureInfo("en-US")); - } - catch (Exception exc) - { - Logger.Error(_localizationService.GetResource("Plugins.Payments.PayPalStandard.FailedGetGross"), exc); - } - - string payer_status = string.Empty; - values.TryGetValue("payer_status", out payer_status); - string payment_status = string.Empty; - values.TryGetValue("payment_status", out payment_status); - string pending_reason = string.Empty; - values.TryGetValue("pending_reason", out pending_reason); - string mc_currency = string.Empty; - values.TryGetValue("mc_currency", out mc_currency); - string txn_id = string.Empty; - values.TryGetValue("txn_id", out txn_id); - string payment_type = string.Empty; - values.TryGetValue("payment_type", out payment_type); - string payer_id = string.Empty; - values.TryGetValue("payer_id", out payer_id); - string receiver_id = string.Empty; - values.TryGetValue("receiver_id", out receiver_id); - string invoice = string.Empty; - values.TryGetValue("invoice", out invoice); - string payment_fee = string.Empty; - values.TryGetValue("payment_fee", out payment_fee); - - string paymentNote = _localizationService.GetResource("Plugins.Payments.PayPalStandard.PaymentNote").FormatWith( - total, mc_currency, payer_status, payment_status, pending_reason, txn_id, payment_type, payer_id, receiver_id, invoice, payment_fee); - - //order note - order.OrderNotes.Add(new OrderNote() - { - Note = paymentNote, - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); - - //validate order total - if (_paypalStandardPaymentSettings.PdtValidateOrderTotal && !Math.Round(total, 2).Equals(Math.Round(order.OrderTotal, 2))) - { - Logger.Error(_localizationService.GetResource("Plugins.Payments.PayPalStandard.UnequalTotalOrder").FormatWith(total, order.OrderTotal)); - - return RedirectToAction("Index", "Home", new { area = "" }); - } - - //mark order as paid - if (_orderProcessingService.CanMarkOrderAsPaid(order)) - { - order.AuthorizationTransactionId = txn_id; - _orderService.UpdateOrder(order); - - _orderProcessingService.MarkOrderAsPaid(order); - } - } - - return RedirectToRoute("CheckoutCompleted"); - } - else - { - string orderNumber = string.Empty; - values.TryGetValue("custom", out orderNumber); - Guid orderNumberGuid = Guid.Empty; - try - { - orderNumberGuid = new Guid(orderNumber); - } - catch { } - Order order = _orderService.GetOrderByGuid(orderNumberGuid); - if (order != null) - { - //order note - order.OrderNotes.Add(new OrderNote() - { - Note = "{0} {1}".FormatWith(_localizationService.GetResource("Plugins.Payments.PayPalStandard.PdtFailed"), response), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); - } - return RedirectToAction("Index", "Home", new { area = "" }); - } - } - - [ValidateInput(false)] - public ActionResult IPNHandler() - { - Debug.WriteLine("PayPal Standard IPN: {0}".FormatWith(Request.ContentLength)); - - byte[] param = Request.BinaryRead(Request.ContentLength); - string strRequest = Encoding.ASCII.GetString(param); - Dictionary values; - - var processor = _paymentService.LoadPaymentMethodBySystemName("Payments.PayPalStandard") as PayPalStandardPaymentProcessor; - if (processor == null || !processor.IsPaymentMethodActive(_paymentSettings) || !processor.PluginDescriptor.Installed) - throw new SmartException(_localizationService.GetResource("Plugins.Payments.PayPalStandard.NoModuleLoading")); - - if (processor.VerifyIPN(strRequest, out values)) - { - #region values - decimal total = decimal.Zero; - try - { - total = decimal.Parse(values["mc_gross"], new CultureInfo("en-US")); - } - catch { } - - string payer_status = string.Empty; - values.TryGetValue("payer_status", out payer_status); - string payment_status = string.Empty; - values.TryGetValue("payment_status", out payment_status); - string pending_reason = string.Empty; - values.TryGetValue("pending_reason", out pending_reason); - string mc_currency = string.Empty; - values.TryGetValue("mc_currency", out mc_currency); - string txn_id = string.Empty; - values.TryGetValue("txn_id", out txn_id); - string txn_type = string.Empty; - values.TryGetValue("txn_type", out txn_type); - string rp_invoice_id = string.Empty; - values.TryGetValue("rp_invoice_id", out rp_invoice_id); - string payment_type = string.Empty; - values.TryGetValue("payment_type", out payment_type); - string payer_id = string.Empty; - values.TryGetValue("payer_id", out payer_id); - string receiver_id = string.Empty; - values.TryGetValue("receiver_id", out receiver_id); - string invoice = string.Empty; - values.TryGetValue("invoice", out invoice); - string payment_fee = string.Empty; - values.TryGetValue("payment_fee", out payment_fee); - - #endregion - - var sb = new StringBuilder(); - sb.AppendLine("PayPal IPN:"); - foreach (KeyValuePair kvp in values) - { - sb.AppendLine(kvp.Key + ": " + kvp.Value); - } - - var newPaymentStatus = _payPalStandardService.GetPaymentStatus(payment_status, pending_reason); - sb.AppendLine("{0}: {1}".FormatWith(_localizationService.GetResource("Plugins.Payments.PayPalStandard.NewPaymentStatus"), newPaymentStatus)); - - switch (txn_type) - { - case "recurring_payment_profile_created": - //do nothing here - break; - case "recurring_payment": - #region Recurring payment - { - Guid orderNumberGuid = Guid.Empty; - try - { - orderNumberGuid = new Guid(rp_invoice_id); - } - catch { } - - var initialOrder = _orderService.GetOrderByGuid(orderNumberGuid); - if (initialOrder != null) - { - var recurringPayments = _orderService.SearchRecurringPayments(0, 0, initialOrder.Id, null); - foreach (var rp in recurringPayments) - { - switch (newPaymentStatus) - { - case PaymentStatus.Authorized: - case PaymentStatus.Paid: { - var recurringPaymentHistory = rp.RecurringPaymentHistory; - if (recurringPaymentHistory.Count == 0) - { - //first payment - var rph = new RecurringPaymentHistory() - { - RecurringPaymentId = rp.Id, - OrderId = initialOrder.Id, - CreatedOnUtc = DateTime.UtcNow - }; - rp.RecurringPaymentHistory.Add(rph); - _orderService.UpdateRecurringPayment(rp); - } - else - { - //next payments - _orderProcessingService.ProcessNextRecurringPayment(rp); - } - } - break; - } - } - - //this.OrderService.InsertOrderNote(newOrder.OrderId, sb.ToString(), DateTime.UtcNow); - Logger.Information(_localizationService.GetResource("Plugins.Payments.PayPalStandard.IpnLogInfo"), new SmartException(sb.ToString())); - } - else - { - Logger.Error(_localizationService.GetResource("Plugins.Payments.PayPalStandard.IpnOrderNotFound"), new SmartException(sb.ToString())); - } - } - #endregion - break; - default: - #region Standard payment - { - string orderNumber = string.Empty; - values.TryGetValue("custom", out orderNumber); - Guid orderNumberGuid = Guid.Empty; - try - { - orderNumberGuid = new Guid(orderNumber); - } - catch { } - - var order = _orderService.GetOrderByGuid(orderNumberGuid); - if (order != null) - { - //order note - order.OrderNotes.Add(new OrderNote() - { - Note = sb.ToString(), - DisplayToCustomer = false, - CreatedOnUtc = DateTime.UtcNow - }); - _orderService.UpdateOrder(order); - - switch (newPaymentStatus) - { - case PaymentStatus.Pending: - { - } - break; - case PaymentStatus.Authorized: { - if (_orderProcessingService.CanMarkOrderAsAuthorized(order)) - { - _orderProcessingService.MarkAsAuthorized(order); - } - } - break; - case PaymentStatus.Paid: - { - if (_orderProcessingService.CanMarkOrderAsPaid(order)) - { - - order.AuthorizationTransactionId = txn_id; - _orderService.UpdateOrder(order); - - _orderProcessingService.MarkOrderAsPaid(order); - } - } - break; - case PaymentStatus.Refunded: { - if (_orderProcessingService.CanRefundOffline(order)) - { - _orderProcessingService.RefundOffline(order); - } - } - break; - case PaymentStatus.Voided: { - if (_orderProcessingService.CanVoidOffline(order)) - { - _orderProcessingService.VoidOffline(order); - } - } - break; - default: - break; - } - } - else - { - Logger.Error(_localizationService.GetResource("Plugins.Payments.PayPalStandard.IpnOrderNotFound"), new SmartException(sb.ToString())); - } - } - #endregion - break; - } - } - else - { - Logger.Error(_localizationService.GetResource("Plugins.Payments.PayPalStandard.IpnFailed"), new SmartException(strRequest)); - } - - //nothing should be rendered to visitor - return Content(""); - } - - public ActionResult CancelOrder(FormCollection form) - { - var order = _orderService.SearchOrders(_storeContext.CurrentStore.Id, _workContext.CurrentCustomer.Id, null, null, null, null, null, null, null, null, 0, 1) - .FirstOrDefault(); - - if (order != null) - { - return RedirectToRoute("OrderDetails", new { orderId = order.Id }); - } - - return RedirectToAction("Index", "Home", new { area = "Payments.PayPalStandard" }); - } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/DependencyRegistrar.cs b/src/Plugins/Payments.PayPalStandard/DependencyRegistrar.cs deleted file mode 100644 index b276173cd2..0000000000 --- a/src/Plugins/Payments.PayPalStandard/DependencyRegistrar.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Autofac; -using Autofac.Integration.Mvc; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Plugin.Payments.PayPalStandard.Services; - -namespace SmartStore.Plugin.Payments.PayPalStandard -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/Payments.PayPalStandard/Description.txt b/src/Plugins/Payments.PayPalStandard/Description.txt deleted file mode 100644 index a3dde554fb..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: PayPal Standard -SystemName: Payments.PayPalStandard -Version: 2.02 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Payments.PayPalStandard.dll -ResourceRootKey: Plugins.Payments.PayPalStandard \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/Localization/resources.de-de.xml b/src/Plugins/Payments.PayPalStandard/Localization/resources.de-de.xml deleted file mode 100644 index 3677d65064..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Localization/resources.de-de.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - PayPal Standard - - - - Stellen Sie bitte sicher, dass PayPal die Primärwährung Ihres Shops unterstützt, falls Sie dieses Gateway benutzen!

    -

    Sie müssen PDT (Payment Data Transfer) und die automatische Rückleitung in Ihrem PayPal-Profil aktivieren, um PDT nutzen zu können. -Ferner benötigen Sie einen PDT-Identitäts-Token, der für jede PDT-Kommunikation mit PayPal erforderlich ist. -Folgen Sie den Schritten, um Ihr Konto für PDT zu konfigurieren:

    -
      -
    1. Loggen Sie sich in Ihr PayPal-Konto ein.
    2. -
    3. Klicken Sie auf den Register Mein Profil.
    4. -
    5. Klicken Sie unter Verkäufer/Händler auf Website-Einstellungen.
    6. -
    7. Aktivieren Sie Automatische Rückleitung.
    8. -
    9. Als Rückleitungs-URL geben Sie bitte die Seite Ihres Shops ein, die die Transaktions-ID von PayPal nach einer Kundenzahlung empfängt (http://www.yourStore.com/Plugins/PaymentPayPalStandard/PDTHandler).
    10. -
    11. Aktivieren Sie Übertragung der Zahlungsdaten.
    12. -
    13. Klicken Sie auf Speichern.
    14. -
    15. Klicken Sie unter Verkäufer/Händler auf Website-Einstellungen.
    16. -
    17. Scrollen Sie runter zu Übertragung der Zahlungsdaten, um den PDT-Identitäts-Token einzusehen.
    18. -
    -

    Es gibt zwei Wege, um IPN-Nachrichten (Instant Payment Notification) zu empfangen (optional):

    -
      -
    1. Unten IPN aktivieren abhaken. Die URL zu Ihrem IPN-Handler wird dann über die Anfrage übermittelt.
    2. -
    3. - Ihr PayPal-Konto für diesen Service konfigurieren. Schritte hierzu: -
        -
      1. In Ihr Premier- oder Business-Konto einloggen.
      2. -
      3. Auf den Register Mein Profil klicken.
      4. -
      5. Sofortige Zahlungsbestätigung klicken.
      6. -
      7. Einstellungen für sofortige Zahlungsbestätigungen wählen klicken.
      8. -
      9. Bei Benachrichtigungs-URL die URL Ihres IPN-Handlers (http://www.yourStore.com/Plugins/PaymentPayPalStandard/IPNHandler) eingeben.
      10. -
      11. Speichern klicken. Danach sollten Sie eine Nachricht über die erfolgreiche Aktivierung von IPN erhalten.
      12. -
      -
    4. -
    ]]> -
    -
    - - Nach Bestätigung der Bestellung werden Sie direkt zu PayPal weitergeleitet. Halten Sie bitte Ihre Daten für das Online-Banking bereit. - - - Sandbox benutzen - - - Abhaken, um die Sandbox (Testumgebung) zu aktivieren. - - - Business E-Mail - - - PayPal Business E-Mail festlegen. - - - PDT-Identitäts-Token - - - PDT-Identitäts-Token festlegen. - - - Gesamtbetrag überprüfen - - - Aktivieren Sie diese Option, falls der durch PayPal übermittelte Gesamtbetrag überprüft werden soll. - - - Zusätzliche Gebühren - - - Zusätzliche Gebühren, die dem Kunden berechnet werden sollen. - - - Zusätzliche Gebühren (prozentual) - - - Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. - - - Produktbezeichnung und Gesamtbetrag an PayPal übermitteln - - - Aktivieren Sie diese Option, falls die Produktbezeichnung und der Gesamtbetrag an PayPal übermitteln werden sollen. - - - IPN aktivieren - - - Aktivieren Sie diese Option, falls IPN (Instant Payment Notification) aktiviert werden soll. - - - Leer lassen, falls die URL des Standard-IPN-Handlers verwendet werden soll. - - - IPN-Handler (URL) - - - URL zum IPN-Handler festlegen. - - - PayPal Standard Modul konnte nicht geladen werden. - - - PayPal Standard PDT. Fehler beim Abruf von mc_gross. - - - PayPal Standard PDT. Der übermittelte Gesamtbetrag {0} entspricht nicht dem des Shops {1}. - - - PayPal Standard PDT ist fehlgeschlagen. - - - Neuer Zahlungsstatus - - - PayPal Standard IPN. Wiederkehrende Information. - - - PayPal Standard IPN. Bestellung konnte nicht gefunden werden. - - - PayPal Standard IPN. Benachrichtigung konnte nicht abgerufen werden. - - - Unvollständige Zugangsdaten für die PayPal API. Bitte geben Sie die erforderlichen Zugangsdaten im Konfigurationsbereich ein. - - - Versandgebühren - - - Zahlungsgebühren - - - Umsatzsteuer - - - - - - -
    \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/Localization/resources.en-us.xml b/src/Plugins/Payments.PayPalStandard/Localization/resources.en-us.xml deleted file mode 100644 index b6347b5919..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Localization/resources.en-us.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - PayPal Standard - - - - If you're using this gateway ensure that your primary store currency is supported by Paypal.

    -

    To use PDT (Payment Data Transfer), you must activate PDT and Auto Return in your PayPal account profile. -You must also acquire a PDT identity token, which is used in all PDT communication -you send to PayPal. Follow these steps to configure your account for PDT:

    -
      -
    1. Log in to your PayPal account.
    2. -
    3. Click the Profile subtab.
    4. -
    5. Click Website Payment Preferences in the Seller Preferences column.
    6. -
    7. Under Auto Return for Website Payments, click the On radio button.
    8. -
    9. For the Return URL, enter the URL on your site that will receive the transaction ID posted by PayPal after a customer payment (http://www.yourStore.com/Plugins/PaymentPayPalStandard/PDTHandler).
    10. -
    11. Under Payment Data Transfer, click the On radio button.
    12. -
    13. Click Save.
    14. -
    15. Click Website Payment Preferences in the Seller Preferences column.
    16. -
    17. Scroll down to Payment Data Transfer of the page to view your PDT identity token.
    18. -
    -

    Two ways to be able to receive IPN (Instant Payment Notification) messages (optional):

    -
      -
    1. Check Enable IPN below. It will include in the request the url of you IPN handler.
    2. -
    3. - The second way is to configure your paypal account to activate this service; follow these steps: -
        -
      1. Log in to your Premier or Business account.
      2. -
      3. Click the Profile subtab.
      4. -
      5. Click Instant Payment Notification in the Selling Preferences column.
      6. -
      7. Click the Edit IPN Settings button to update your settings.
      8. -
      9. Select Receive IPN messages (Enabled) and enter the URL of your IPN handler (http://www.yourStore.com/Plugins/PaymentPayPalStandard/IPNHandler).
      10. -
      11. Click Save, and you should get a message that you have successfully activated IPN.
      12. -
      -
    4. -
    ]]> -
    -
    - - After confirmation of the order, you will be redirected straight to PayPal. Please provide your data for online banking. - - - Use Sandbox - - - Check to enable Sandbox (testing environment). - - - Business Email - - - Specify your PayPal business email. - - - PDT Identity Token - - - Specify PDT identity token - - - Validate order total - - - Check if the PDT handler should validate PayPal's order totals. - - - Additional fee - - - Enter additional fee to charge your customers. - - - Additional fee. Use percentage - - - Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. - - - Pass product names and order totals to PayPal - - - Check if product names and order totals should be passed to PayPal. - - - Enable IPN - - - Check if IPN (Instant Payment Notification) is enabled. - - - Leave blank to use the default IPN handler URL. - - - IPN Handler - - - Specify IPN Handler. - - - PayPal Standard module cannot be loaded. - - - PayPal Standard PDT. Error getting mc_gross. - - - PayPal Standard PDT. Returned order total {0} doesn't equal order total {1}. - - - PayPal Standard PDT failed. - - - New payment status - - - PayPal Standard IPN. Recurring info. - - - PayPal Standard IPN. Order cannot be found. - - - PayPal Standard IPN. Failed to retrieve notification. - - - Incomplete credentials for the PayPal API. Please enter the required data in the configuration area. - - - Shipping fee - - - Payment method fee - - - Sales tax - - - - - - -
    \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/Models/ConfigurationModel.cs b/src/Plugins/Payments.PayPalStandard/Models/ConfigurationModel.cs deleted file mode 100644 index 539894acd6..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Models/ConfigurationModel.cs +++ /dev/null @@ -1,35 +0,0 @@ -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.PayPalStandard.Models -{ - public class ConfigurationModel : ModelBase - { - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.UseSandbox")] - public bool UseSandbox { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.BusinessEmail")] - public string BusinessEmail { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.PDTToken")] - public string PdtToken { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.PDTValidateOrderTotal")] - public bool PdtValidateOrderTotal { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.AdditionalFee")] - public decimal AdditionalFee { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.AdditionalFeePercentage")] - public bool AdditionalFeePercentage { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.PassProductNamesAndTotals")] - public bool PassProductNamesAndTotals { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.EnableIpn")] - public bool EnableIpn { get; set; } - - [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.IpnUrl")] - public string IpnUrl { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/Notes.txt b/src/Plugins/Payments.PayPalStandard/Notes.txt deleted file mode 100644 index caf8a89383..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Notes.txt +++ /dev/null @@ -1,13 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources - -// codehint: sm-add -Testing with PayPal sandbox: -- The store must be accessible through one of the default ports 80 or 443 for IPN. \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentProcessor.cs b/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentProcessor.cs deleted file mode 100644 index 012b56a8e4..0000000000 --- a/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentProcessor.cs +++ /dev/null @@ -1,496 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Net; -using System.Text; -using System.Linq; -using System.Web; -using System.Web.Routing; -using Autofac; -using SmartStore.Core; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Domain.Shipping; -using SmartStore.Plugin.Payments.PayPalStandard.Controllers; -using SmartStore.Plugin.Payments.PayPalStandard.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Directory; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; -using SmartStore.Services.Tax; - -namespace SmartStore.Plugin.Payments.PayPalStandard -{ - /// - /// PayPalStandard payment processor - /// - public class PayPalStandardPaymentProcessor : PaymentMethodBase - { - #region Fields - - private readonly PayPalStandardPaymentSettings _paypalStandardPaymentSettings; - private readonly ISettingService _settingService; - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; - private readonly IWebHelper _webHelper; - private readonly ICheckoutAttributeParser _checkoutAttributeParser; - private readonly ITaxService _taxService; - private readonly IOrderTotalCalculationService _orderTotalCalculationService; - private readonly HttpContextBase _httpContext; - private readonly ILocalizationService _localizationService; - private readonly IPayPalStandardService _payPalStandardService; - - #endregion - - #region Ctor - - public PayPalStandardPaymentProcessor(PayPalStandardPaymentSettings paypalStandardPaymentSettings, - ISettingService settingService, ICurrencyService currencyService, - CurrencySettings currencySettings, IWebHelper webHelper, - ICheckoutAttributeParser checkoutAttributeParser, ITaxService taxService, - IOrderTotalCalculationService orderTotalCalculationService, HttpContextBase httpContext, - ILocalizationService localizationService, - IPayPalStandardService payPalStandardService) - { - this._paypalStandardPaymentSettings = paypalStandardPaymentSettings; - this._settingService = settingService; - this._currencyService = currencyService; - this._currencySettings = currencySettings; - this._webHelper = webHelper; - this._checkoutAttributeParser = checkoutAttributeParser; - this._taxService = taxService; - this._orderTotalCalculationService = orderTotalCalculationService; - this._httpContext = httpContext; - this._localizationService = localizationService; - this._payPalStandardService = payPalStandardService; - } - - #endregion - - #region Utilities - - /// - /// Gets Paypal URL - /// - /// - private string GetPaypalUrl() - { - //return _paypalStandardPaymentSettings.UseSandbox ? "https://www.sandbox.paypal.com/us/cgi-bin/webscr" : - // "https://www.paypal.com/us/cgi-bin/webscr"; - - // codehint: sm-edit (url that paypal actually publish) - return _paypalStandardPaymentSettings.UseSandbox ? - "https://www.sandbox.paypal.com/cgi-bin/webscr" : - "https://www.paypal.com/cgi-bin/webscr"; - } - - /// - /// Gets PDT details - /// - /// TX - /// Values - /// Response - /// Result - public bool GetPDTDetails(string tx, out Dictionary values, out string response) - { - var req = (HttpWebRequest)WebRequest.Create(GetPaypalUrl()); - req.Method = "POST"; - req.ContentType = "application/x-www-form-urlencoded"; - - string formContent = string.Format("cmd=_notify-synch&at={0}&tx={1}", _paypalStandardPaymentSettings.PdtToken, tx); - req.ContentLength = formContent.Length; - - using (var sw = new StreamWriter(req.GetRequestStream(), Encoding.ASCII)) - sw.Write(formContent); - - response = null; - using (var sr = new StreamReader(req.GetResponse().GetResponseStream())) - response = HttpUtility.UrlDecode(sr.ReadToEnd()); - - values = new Dictionary(StringComparer.OrdinalIgnoreCase); - bool firstLine = true, success = false; - foreach (string l in response.Split('\n')) - { - string line = l.Trim(); - if (firstLine) - { - success = line.Equals("SUCCESS", StringComparison.OrdinalIgnoreCase); - firstLine = false; - } - else - { - int equalPox = line.IndexOf('='); - if (equalPox >= 0) - values.Add(line.Substring(0, equalPox), line.Substring(equalPox + 1)); - } - } - - return success; - } - - /// - /// Verifies IPN - /// - /// Form string - /// Values - /// Result - public bool VerifyIPN(string formString, out Dictionary values) - { - var req = (HttpWebRequest)WebRequest.Create(GetPaypalUrl()); - req.Method = "POST"; - req.ContentType = "application/x-www-form-urlencoded"; - - string formContent = string.Format("{0}&cmd=_notify-validate", formString); - req.ContentLength = formContent.Length; - - using (var sw = new StreamWriter(req.GetRequestStream(), Encoding.ASCII)) - { - sw.Write(formContent); - } - - string response = null; - using (var sr = new StreamReader(req.GetResponse().GetResponseStream())) - { - response = HttpUtility.UrlDecode(sr.ReadToEnd()); - } - bool success = response.Trim().Equals("VERIFIED", StringComparison.OrdinalIgnoreCase); - - values = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (string l in formString.Split('&')) - { - string line = HttpUtility.UrlDecode(l).Trim(); // codehint: sm-edit - int equalPox = line.IndexOf('='); - if (equalPox >= 0) - values.Add(line.Substring(0, equalPox), line.Substring(equalPox + 1)); - } - - return success; - } - - #endregion - - #region Methods - - /// - /// Process a payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.NewPaymentStatus = PaymentStatus.Pending; - - // codehint: sm-add - if (_paypalStandardPaymentSettings.BusinessEmail.IsNullOrEmpty() || _paypalStandardPaymentSettings.PdtToken.IsNullOrEmpty()) - { - result.AddError(_localizationService.GetResource("Plugins.Payments.PayPalStandard.InvalidCredentials")); - } - - return result; - } - - /// - /// Post process payment (used by payment gateways that require redirecting to a third-party URL) - /// - /// Payment info required for an order processing - public override void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest) - { - var builder = new StringBuilder(); - builder.Append(GetPaypalUrl()); - - string orderNumber = postProcessPaymentRequest.Order.GetOrderNumber(); - string cmd = (_paypalStandardPaymentSettings.PassProductNamesAndTotals ? "_cart" : "_xclick"); - - builder.AppendFormat("?cmd={0}&business={1}", cmd, HttpUtility.UrlEncode(_paypalStandardPaymentSettings.BusinessEmail)); - - if (_paypalStandardPaymentSettings.PassProductNamesAndTotals) - { - builder.AppendFormat("&upload=1"); - - int index = 0; - decimal cartTotal = decimal.Zero; - //var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); - - var lineItems = _payPalStandardService.GetLineItems(postProcessPaymentRequest, out cartTotal); - - _payPalStandardService.AdjustLineItemAmounts(lineItems, postProcessPaymentRequest); - - foreach (var item in lineItems.OrderBy(x => (int)x.Type)) - { - ++index; - builder.AppendFormat("&item_name_" + index + "={0}", HttpUtility.UrlEncode(item.Name)); - builder.AppendFormat("&amount_" + index + "={0}", item.AmountRounded.ToString("0.00", CultureInfo.InvariantCulture)); - builder.AppendFormat("&quantity_" + index + "={0}", item.Quantity); - } - - #region old code - - //var cartItems = postProcessPaymentRequest.Order.OrderItems; - //int x = 1; - //foreach (var item in cartItems) - //{ - // var unitPriceExclTax = item.UnitPriceExclTax; - // var priceExclTax = item.PriceExclTax; - // //round - // var unitPriceExclTaxRounded = Math.Round(unitPriceExclTax, 2); - - // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(item.Product.Name)); - // builder.AppendFormat("&amount_" + x + "={0}", unitPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); - // builder.AppendFormat("&quantity_" + x + "={0}", item.Quantity); - // x++; - // cartTotal += priceExclTax; - //} - - ////the checkout attributes that have a dollar value and send them to Paypal as items to be paid for - //foreach (var val in caValues) - //{ - // var attPrice = _taxService.GetCheckoutAttributePrice(val, false, postProcessPaymentRequest.Order.Customer); - // //round - // var attPriceRounded = Math.Round(attPrice, 2); - // if (attPrice > decimal.Zero) //if it has a price - // { - // var ca = val.CheckoutAttribute; - // if (ca != null) - // { - // var attName = ca.Name; //set the name - // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(attName)); //name - // builder.AppendFormat("&amount_" + x + "={0}", attPriceRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount - // builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity - // x++; - // cartTotal += attPrice; - // } - // } - //} - - ////order totals - - ////shipping - //var orderShippingExclTax = postProcessPaymentRequest.Order.OrderShippingExclTax; - //var orderShippingExclTaxRounded = Math.Round(orderShippingExclTax, 2); - //if (orderShippingExclTax > decimal.Zero) - //{ - // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(_localizationService.GetResource("Plugins.Payments.PayPalStandard.ShippingFee"))); - // builder.AppendFormat("&amount_" + x + "={0}", orderShippingExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); - // builder.AppendFormat("&quantity_" + x + "={0}", 1); - // x++; - // cartTotal += orderShippingExclTax; - //} - - ////payment method additional fee - //var paymentMethodAdditionalFeeExclTax = postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax; - //var paymentMethodAdditionalFeeExclTaxRounded = Math.Round(paymentMethodAdditionalFeeExclTax, 2); - //if (paymentMethodAdditionalFeeExclTax > decimal.Zero) - //{ - // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(_localizationService.GetResource("Plugins.Payments.PayPalStandard.PaymentMethodFee"))); - // builder.AppendFormat("&amount_" + x + "={0}", paymentMethodAdditionalFeeExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); - // builder.AppendFormat("&quantity_" + x + "={0}", 1); - // x++; - // cartTotal += paymentMethodAdditionalFeeExclTax; - //} - - ////tax - //var orderTax = postProcessPaymentRequest.Order.OrderTax; - //var orderTaxRounded = Math.Round(orderTax, 2); - //if (orderTax > decimal.Zero) - //{ - // //builder.AppendFormat("&tax_1={0}", orderTax.ToString("0.00", CultureInfo.InvariantCulture)); - - // //add tax as item - // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(_localizationService.GetResource("Plugins.Payments.PayPalStandard.SalesTax"))); - // builder.AppendFormat("&amount_" + x + "={0}", orderTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount - // builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity - - // cartTotal += orderTax; - // x++; - //} - - #endregion - - if (cartTotal > postProcessPaymentRequest.Order.OrderTotal) - { - /* Take the difference between what the order total is and what it should be and use that as the "discount". - * The difference equals the amount of the gift card and/or reward points used. - */ - decimal discountTotal = cartTotal - postProcessPaymentRequest.Order.OrderTotal; - discountTotal = Math.Round(discountTotal, 2); - //gift card or rewared point amount applied to cart in SmartStore.NET - shows in Paypal as "discount" - builder.AppendFormat("&discount_amount_cart={0}", discountTotal.ToString("0.00", CultureInfo.InvariantCulture)); - } - } - else - { - //pass order total - string totalItemName = "{0} {1}".FormatWith(_localizationService.GetResource("Checkout.OrderNumber"), orderNumber); - builder.AppendFormat("&item_name={0}", HttpUtility.UrlEncode(totalItemName)); - var orderTotal = Math.Round(postProcessPaymentRequest.Order.OrderTotal, 2); - builder.AppendFormat("&amount={0}", orderTotal.ToString("0.00", CultureInfo.InvariantCulture)); - } - - builder.AppendFormat("&custom={0}", postProcessPaymentRequest.Order.OrderGuid); - builder.AppendFormat("&charset={0}", "utf-8"); - builder.Append(string.Format("&no_note=1¤cy_code={0}", HttpUtility.UrlEncode(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode))); - builder.AppendFormat("&invoice={0}", HttpUtility.UrlEncode(orderNumber)); - builder.AppendFormat("&rm=2", new object[0]); - - if (postProcessPaymentRequest.Order.ShippingStatus != ShippingStatus.ShippingNotRequired) - builder.AppendFormat("&no_shipping=2", new object[0]); - else - builder.AppendFormat("&no_shipping=1", new object[0]); - - string returnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/PDTHandler"; - string cancelReturnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/CancelOrder"; - builder.AppendFormat("&return={0}&cancel_return={1}", HttpUtility.UrlEncode(returnUrl), HttpUtility.UrlEncode(cancelReturnUrl)); - - //Instant Payment Notification (server to server message) - if (_paypalStandardPaymentSettings.EnableIpn) - { - string ipnUrl; - if (String.IsNullOrWhiteSpace(_paypalStandardPaymentSettings.IpnUrl)) - ipnUrl = _webHelper.GetStoreLocation(false) + "Plugins/PaymentPayPalStandard/IPNHandler"; - else - ipnUrl = _paypalStandardPaymentSettings.IpnUrl; - builder.AppendFormat("¬ify_url={0}", ipnUrl); - } - - //address - builder.AppendFormat("&address_override=1"); - builder.AppendFormat("&first_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.FirstName)); - builder.AppendFormat("&last_name={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.LastName)); - builder.AppendFormat("&address1={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Address1)); - builder.AppendFormat("&address2={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Address2)); - builder.AppendFormat("&city={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.City)); - //if (!String.IsNullOrEmpty(postProcessPaymentRequest.Order.BillingAddress.PhoneNumber)) - //{ - // //strip out all non-digit characters from phone number; - // string billingPhoneNumber = System.Text.RegularExpressions.Regex.Replace(postProcessPaymentRequest.Order.BillingAddress.PhoneNumber, @"\D", string.Empty); - // if (billingPhoneNumber.Length >= 10) - // { - // builder.AppendFormat("&night_phone_a={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(0, 3))); - // builder.AppendFormat("&night_phone_b={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(3, 3))); - // builder.AppendFormat("&night_phone_c={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(6, 4))); - // } - //} - if (postProcessPaymentRequest.Order.BillingAddress.StateProvince != null) - builder.AppendFormat("&state={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.StateProvince.Abbreviation)); - else - builder.AppendFormat("&state={0}", ""); - - if (postProcessPaymentRequest.Order.BillingAddress.Country != null) - builder.AppendFormat("&country={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Country.TwoLetterIsoCode)); - else - builder.AppendFormat("&country={0}", ""); - - builder.AppendFormat("&zip={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.ZipPostalCode)); - builder.AppendFormat("&email={0}", HttpUtility.UrlEncode(postProcessPaymentRequest.Order.BillingAddress.Email)); - - _httpContext.Response.Redirect(builder.ToString()); - } - - /// - /// Gets additional handling fee - /// - /// Shoping cart - /// Additional handling fee - public override decimal GetAdditionalHandlingFee(IList cart) - { - var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, - _paypalStandardPaymentSettings.AdditionalFee, _paypalStandardPaymentSettings.AdditionalFeePercentage); - return result; - } - - /// - /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods) - /// - /// Order - /// Result - public override bool CanRePostProcessPayment(Order order) - { - if (order == null) - throw new ArgumentNullException("order"); - - if (order.PaymentStatus == PaymentStatus.Pending && (DateTime.UtcNow - order.CreatedOnUtc).TotalSeconds > 5) - { - return true; - } - return true; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "PaymentPayPalStandard"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.PayPalStandard.Controllers" }, { "area", "Payments.PayPalStandard" } }; - } - - /// - /// Gets a route for payment info - /// - /// Action name - /// Controller name - /// Route values - public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PaymentInfo"; - controllerName = "PaymentPayPalStandard"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.PayPalStandard.Controllers" }, { "area", "Payments.PayPalStandard" } }; - } - - public override Type GetControllerType() - { - return typeof(PaymentPayPalStandardController); - } - - public override void Install() - { - //settings - var settings = new PayPalStandardPaymentSettings() - { - //UseSandbox = true, - //BusinessEmail = "test@test.com", - //PdtToken = "PDT token...", - PdtValidateOrderTotal = true, - EnableIpn = true, - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //settings - _settingService.DeleteSetting(); - - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Payments.PayPalStandard", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - public override PaymentMethodType PaymentMethodType - { - get - { - return PaymentMethodType.Redirection; - } - } - - #endregion - } -} diff --git a/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentSettings.cs b/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentSettings.cs deleted file mode 100644 index 1e319a6d51..0000000000 --- a/src/Plugins/Payments.PayPalStandard/PayPalStandardPaymentSettings.cs +++ /dev/null @@ -1,23 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Payments.PayPalStandard -{ - public class PayPalStandardPaymentSettings : ISettings - { - public bool UseSandbox { get; set; } - public string BusinessEmail { get; set; } - public string PdtToken { get; set; } - /// - /// Gets or sets a value indicating whether to "additional fee" is specified as percentage. true - percentage, false - fixed value. - /// - public bool AdditionalFeePercentage { get; set; } - /// - /// Additional fee - /// - public decimal AdditionalFee { get; set; } - public bool PassProductNamesAndTotals { get; set; } - public bool PdtValidateOrderTotal { get; set; } - public bool EnableIpn { get; set; } - public string IpnUrl { get; set; } - } -} diff --git a/src/Plugins/Payments.PayPalStandard/Properties/AssemblyInfo.cs b/src/Plugins/Payments.PayPalStandard/Properties/AssemblyInfo.cs deleted file mode 100644 index 0c4b7605cc..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Payments.PayPalStandard")] diff --git a/src/Plugins/Payments.PayPalStandard/RouteProvider.cs b/src/Plugins/Payments.PayPalStandard/RouteProvider.cs deleted file mode 100644 index f7a9eedc28..0000000000 --- a/src/Plugins/Payments.PayPalStandard/RouteProvider.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Payments.PayPalStandard -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Payments.PayPalStandard.Configure", - "Plugins/PaymentPayPalStandard/Configure", - new { controller = "PaymentPayPalStandard", action = "Configure" }, - new[] { "SmartStore.Plugin.Payments.PayPalStandard.Controllers" } - ) - .DataTokens["area"] = "Payments.PayPalStandard"; - - routes.MapRoute("Plugin.Payments.PayPalStandard.PaymentInfo", - "Plugins/PaymentPayPalStandard/PaymentInfo", - new { controller = "PaymentPayPalStandard", action = "PaymentInfo" }, - new[] { "SmartStore.Plugin.Payments.PayPalStandard.Controllers" } - ) - .DataTokens["area"] = "Payments.PayPalStandard"; - - routes.MapRoute("Plugin.Payments.PayPalStandard.PDTHandler", - "Plugins/PaymentPayPalStandard/PDTHandler", - new { controller = "PaymentPayPalStandard", action = "PDTHandler" }, - new[] { "SmartStore.Plugin.Payments.PayPalStandard.Controllers" } - ) - .DataTokens["area"] = "Payments.PayPalStandard"; - - routes.MapRoute("Plugin.Payments.PayPalStandard.IPNHandler", - "Plugins/PaymentPayPalStandard/IPNHandler", - new { controller = "PaymentPayPalStandard", action = "IPNHandler" }, - new[] { "SmartStore.Plugin.Payments.PayPalStandard.Controllers" } - ) - .DataTokens["area"] = "Payments.PayPalStandard"; - - routes.MapRoute("Plugin.Payments.PayPalStandard.CancelOrder", - "Plugins/PaymentPayPalStandard/CancelOrder", - new { controller = "PaymentPayPalStandard", action = "CancelOrder" }, - new[] { "SmartStore.Plugin.Payments.PayPalStandard.Controllers" } - ) - .DataTokens["area"] = "Payments.PayPalStandard"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Payments.PayPalStandard/Services/IPayPalStandardService.cs b/src/Plugins/Payments.PayPalStandard/Services/IPayPalStandardService.cs deleted file mode 100644 index 8dd98c5fc7..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Services/IPayPalStandardService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Services.Payments; - -namespace SmartStore.Plugin.Payments.PayPalStandard.Services -{ - public partial interface IPayPalStandardService - { - /// - /// Gets a payment status - /// - /// PayPal payment status - /// PayPal pending reason - /// Payment status - PaymentStatus GetPaymentStatus(string paymentStatus, string pendingReason); - - /// - /// Get all PayPal line items - /// - /// Post process paymenmt request object - /// Receives the calculated cart total amount - /// All items for PayPal Standard API - List GetLineItems(PostProcessPaymentRequest postProcessPaymentRequest, out decimal cartTotal); - - /// - /// Adjusts the line amount for cart items to avoid rounding differences - /// - /// PayPal line items - /// Post process paymenmt request object - void AdjustLineItemAmounts(List paypalItems, PostProcessPaymentRequest postProcessPaymentRequest); - } -} diff --git a/src/Plugins/Payments.PayPalStandard/Services/PayPalStandardCore.cs b/src/Plugins/Payments.PayPalStandard/Services/PayPalStandardCore.cs deleted file mode 100644 index 3ab090588e..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Services/PayPalStandardCore.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Globalization; - -namespace SmartStore.Plugin.Payments.PayPalStandard.Services -{ - public class PayPalLineItem : ICloneable - { - public PayPalItemType Type { get; set; } - public string Name { get; set; } - public int Quantity { get; set; } - public decimal Amount { get; set; } - - public decimal AmountRounded - { - get - { - return Math.Round(Amount, 2); - } - } - - public PayPalLineItem Clone() - { - var item = new PayPalLineItem() - { - Type = this.Type, - Name = this.Name, - Quantity = this.Quantity, - Amount = this.Amount - }; - return item; - } - - object ICloneable.Clone() - { - return this.Clone(); - } - } - - - public enum PayPalItemType : int - { - CartItem = 0, - CheckoutAttribute, - Shipping, - PaymentFee, - Tax - } -} diff --git a/src/Plugins/Payments.PayPalStandard/Services/PayPalStandardService.cs b/src/Plugins/Payments.PayPalStandard/Services/PayPalStandardService.cs deleted file mode 100644 index fd841fef7b..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Services/PayPalStandardService.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System; -using System.Linq; -using System.Diagnostics; -using System.Collections.Generic; -using SmartStore.Core.Logging; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Services.Payments; -using SmartStore.Services.Localization; -using SmartStore.Services.Tax; -using SmartStore.Core.Localization; - -namespace SmartStore.Plugin.Payments.PayPalStandard.Services -{ - public class PayPalStandardService : IPayPalStandardService - { - private readonly ITaxService _taxService; - - public PayPalStandardService( - ITaxService taxService) - { - _taxService = taxService; - - T = NullLocalizer.Instance; - Logger = NullLogger.Instance; - } - - public Localizer T { get; set; } - public ILogger Logger { get; set; } - - /// - /// Splits the difference of two value into a portion value (for each item) and a rest value - /// - /// The difference value - /// Number of lines\items to split the difference - /// Portion value - /// Rest value - private void SplitDifference(decimal difference, int numberOfLines, out decimal portion, out decimal rest) - { - portion = rest = decimal.Zero; - - if (numberOfLines == 0) - numberOfLines = 1; - - int intDifference = (int)(difference * 100); - int intPortion = (int)Math.Truncate((double)intDifference / (double)numberOfLines); - int intRest = intDifference % numberOfLines; - - portion = Math.Round(((decimal)intPortion) / 100, 2); - rest = Math.Round(((decimal)intRest) / 100, 2); - - Debug.Assert(difference == ((numberOfLines * portion) + rest)); - } - - /// - /// Gets a payment status - /// - /// PayPal payment status - /// PayPal pending reason - /// Payment status - public PaymentStatus GetPaymentStatus(string paymentStatus, string pendingReason) - { - var result = PaymentStatus.Pending; - - if (paymentStatus == null) - paymentStatus = string.Empty; - - if (pendingReason == null) - pendingReason = string.Empty; - - switch (paymentStatus.ToLowerInvariant()) - { - case "pending": - switch (pendingReason.ToLowerInvariant()) - { - case "authorization": - result = PaymentStatus.Authorized; - break; - default: - result = PaymentStatus.Pending; - break; - } - break; - case "processed": - case "completed": - case "canceled_reversal": - result = PaymentStatus.Paid; - break; - case "denied": - case "expired": - case "failed": - case "voided": - result = PaymentStatus.Voided; - break; - case "refunded": - case "reversed": - result = PaymentStatus.Refunded; - break; - default: - break; - } - return result; - } - - /// - /// Get all PayPal line items - /// - /// Post process paymenmt request object - /// List with checkout attribute values - /// Receives the calculated cart total amount - /// All items for PayPal Standard API - public List GetLineItems(PostProcessPaymentRequest postProcessPaymentRequest, out decimal cartTotal) - { - cartTotal = decimal.Zero; - - var order = postProcessPaymentRequest.Order; - var lst = new List(); - - // order items - foreach (var orderItem in order.OrderItems) - { - var item = new PayPalLineItem() - { - Type = PayPalItemType.CartItem, - Name = orderItem.Product.GetLocalized(x => x.Name), - Quantity = orderItem.Quantity, - Amount = orderItem.UnitPriceExclTax - }; - lst.Add(item); - - cartTotal += orderItem.PriceExclTax; - } - - // checkout attributes.... are included in order total - //foreach (var caValue in checkoutAttributeValues) - //{ - // var attributePrice = _taxService.GetCheckoutAttributePrice(caValue, false, order.Customer); - - // if (attributePrice > decimal.Zero && caValue.CheckoutAttribute != null) - // { - // var item = new PayPalLineItem() - // { - // Type = PayPalItemType.CheckoutAttribute, - // Name = caValue.CheckoutAttribute.GetLocalized(x => x.Name), - // Quantity = 1, - // Amount = attributePrice - // }; - // lst.Add(item); - - // cartTotal += attributePrice; - // } - //} - - // shipping - if (order.OrderShippingExclTax > decimal.Zero) - { - var item = new PayPalLineItem() - { - Type = PayPalItemType.Shipping, - Name = T("Plugins.Payments.PayPalStandard.ShippingFee").Text, - Quantity = 1, - Amount = order.OrderShippingExclTax - }; - lst.Add(item); - - cartTotal += order.OrderShippingExclTax; - } - - // payment fee - if (order.PaymentMethodAdditionalFeeExclTax > decimal.Zero) - { - var item = new PayPalLineItem() - { - Type = PayPalItemType.PaymentFee, - Name = T("Plugins.Payments.PayPalStandard.PaymentMethodFee").Text, - Quantity = 1, - Amount = order.PaymentMethodAdditionalFeeExclTax - }; - lst.Add(item); - - cartTotal += order.PaymentMethodAdditionalFeeExclTax; - } - - // tax - if (order.OrderTax > decimal.Zero) - { - var item = new PayPalLineItem() - { - Type = PayPalItemType.Tax, - Name = T("Plugins.Payments.PayPalStandard.SalesTax").Text, - Quantity = 1, - Amount = order.OrderTax - }; - lst.Add(item); - - cartTotal += order.OrderTax; - } - - return lst; - } - - /// - /// Manually adjusts the net prices for cart items to avoid rounding differences with the PayPal API. - /// - /// PayPal line items - /// Post process paymenmt request object - /// - /// In detail: We add what we have thrown away in the checkout when we rounded prices to two decimal places. - /// It's a workaround. Better solution would be to store the thrown away decimal places for each OrderItem in the database. - /// More details: http://magento.xonu.de/magento-extensions/empfehlungen/magento-paypal-rounding-error-fix/ - /// - public void AdjustLineItemAmounts(List paypalItems, PostProcessPaymentRequest postProcessPaymentRequest) - { - try - { - var cartItems = paypalItems.Where(x => x.Type == PayPalItemType.CartItem); - - if (cartItems.Count() <= 0) - return; - - decimal totalSmartStore = Math.Round(postProcessPaymentRequest.Order.OrderSubtotalExclTax, 2); - decimal totalPayPal = decimal.Zero; - decimal delta, portion, rest; - - // calculate what PayPal calculates - cartItems.Each(x => totalPayPal += (x.AmountRounded * x.Quantity)); - totalPayPal = Math.Round(totalPayPal, 2, MidpointRounding.AwayFromZero); - - // calculate difference - delta = Math.Round(totalSmartStore - totalPayPal, 2); - if (delta == decimal.Zero) - return; - - // prepare lines... only lines with quantity = 1 are adjustable. if there is no one, create one. - if (!cartItems.Any(x => x.Quantity == 1)) - { - var item = cartItems.First(x => x.Quantity > 1); - item.Quantity -= 1; - var newItem = item.Clone(); - newItem.Quantity = 1; - paypalItems.Insert(paypalItems.IndexOf(item) + 1, newItem); - } - - var cartItemsOneQuantity = paypalItems.Where(x => x.Type == PayPalItemType.CartItem && x.Quantity == 1); - Debug.Assert(cartItemsOneQuantity.Count() > 0); - - SplitDifference(delta, cartItemsOneQuantity.Count(), out portion, out rest); - - if (portion != decimal.Zero) - { - cartItems - .Where(x => x.Quantity == 1) - .Each(x => x.Amount = x.Amount + portion); - } - - if (rest != decimal.Zero) - { - var restItem = cartItems.First(x => x.Quantity == 1); - restItem.Amount = restItem.Amount + rest; - } - - //"SM: {0}, PP: {1}, delta: {2} (portion: {3}, rest: {4})".FormatWith(totalSmartStore, totalPayPal, delta, portion, rest).Dump(); - } - catch (Exception exc) - { - Logger.Error(exc.Message, exc); - } - } - } -} diff --git a/src/Plugins/Payments.PayPalStandard/SmartStore.Plugin.Payments.PayPalStandard.csproj b/src/Plugins/Payments.PayPalStandard/SmartStore.Plugin.Payments.PayPalStandard.csproj deleted file mode 100644 index 8ef81fab04..0000000000 --- a/src/Plugins/Payments.PayPalStandard/SmartStore.Plugin.Payments.PayPalStandard.csproj +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {83235353-0D04-4028-82B2-81116E7361DA} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Payments.PayPalStandard - SmartStore.Plugin.Payments.PayPalStandard - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Payments.PayPalStandard\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Payments.PayPalStandard\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - - - - PreserveNewest - - - Always - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/Views/PaymentPayPalStandard/Configure.cshtml b/src/Plugins/Payments.PayPalStandard/Views/PaymentPayPalStandard/Configure.cshtml deleted file mode 100644 index 3c3f381b2b..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Views/PaymentPayPalStandard/Configure.cshtml +++ /dev/null @@ -1,138 +0,0 @@ -@{ - Layout = ""; -} -@model ConfigurationModel -@using SmartStore.Plugin.Payments.PayPalStandard.Models; -@using SmartStore.Web.Framework; - - - -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - PayPal - -
    -
    - - @Html.Raw(T("Plugins.Payments.PayPalStandard.AdminInstruction")) -
    -
    - @Html.SmartLabelFor(model => model.UseSandbox) - - @Html.EditorFor(model => model.UseSandbox) - @Html.ValidationMessageFor(model => model.UseSandbox) -
    - @Html.SmartLabelFor(model => model.BusinessEmail) - - @Html.EditorFor(model => model.BusinessEmail) - @Html.ValidationMessageFor(model => model.BusinessEmail) -
    - @Html.SmartLabelFor(model => model.PdtToken) - - @Html.EditorFor(model => model.PdtToken) - @Html.ValidationMessageFor(model => model.PdtToken) -
    - @Html.SmartLabelFor(model => model.PdtValidateOrderTotal) - - @Html.EditorFor(model => model.PdtValidateOrderTotal) - @Html.ValidationMessageFor(model => model.PdtValidateOrderTotal) -
    - @Html.SmartLabelFor(model => model.AdditionalFee) - - @Html.EditorFor(model => model.AdditionalFee) - @Html.ValidationMessageFor(model => model.AdditionalFee) -
    - @Html.SmartLabelFor(model => model.AdditionalFeePercentage) - - @Html.EditorFor(model => model.AdditionalFeePercentage) - @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) -
    - @Html.SmartLabelFor(model => model.PassProductNamesAndTotals) - - @Html.EditorFor(model => model.PassProductNamesAndTotals) - @Html.ValidationMessageFor(model => model.PassProductNamesAndTotals) -
    - @Html.SmartLabelFor(model => model.EnableIpn) - - @Html.EditorFor(model => model.EnableIpn) - @Html.ValidationMessageFor(model => model.EnableIpn) -
    - @Html.SmartLabelFor(model => model.IpnUrl) - - @T("Plugins.Payments.PayPalStandard.Fields.EnableIpn.Hint2") - - - @Html.EditorFor(model => model.IpnUrl) - @Html.ValidationMessageFor(model => model.IpnUrl) -
    -   - - -
    -} \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/Views/PaymentPayPalStandard/PaymentInfo.cshtml b/src/Plugins/Payments.PayPalStandard/Views/PaymentPayPalStandard/PaymentInfo.cshtml deleted file mode 100644 index e23a53adfe..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Views/PaymentPayPalStandard/PaymentInfo.cshtml +++ /dev/null @@ -1,11 +0,0 @@ -@{ - Layout = ""; -} -@using SmartStore.Web.Framework; - -
    - PayPal - - @T("Plugins.Payments.PayPalStandard.Fields.RedirectionTip") - -
    diff --git a/src/Plugins/Payments.PayPalStandard/Views/Web.config b/src/Plugins/Payments.PayPalStandard/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Payments.PayPalStandard/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.PayPalStandard/packages.config b/src/Plugins/Payments.PayPalStandard/packages.config deleted file mode 100644 index 8cebc19d79..0000000000 --- a/src/Plugins/Payments.PayPalStandard/packages.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.PayPalStandard/web.config b/src/Plugins/Payments.PayPalStandard/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Payments.PayPalStandard/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.Prepayment/Controllers/PaymentPrepaymentController.cs b/src/Plugins/Payments.Prepayment/Controllers/PaymentPrepaymentController.cs deleted file mode 100644 index d6eaa0176e..0000000000 --- a/src/Plugins/Payments.Prepayment/Controllers/PaymentPrepaymentController.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Plugin.Payments.Prepayment.Models; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Payments; -using SmartStore.Web.Framework.Controllers; - -namespace SmartStore.Plugin.Payments.Prepayment.Controllers -{ - public class PaymentPrepaymentController : PaymentControllerBase - { - private readonly ISettingService _settingService; - private readonly PrepaymentPaymentSettings _prepaymentPaymentSettings; - private readonly ILocalizationService _localizationService; - - public PaymentPrepaymentController(ISettingService settingService, - PrepaymentPaymentSettings prepaymentPaymentSettings, - ILocalizationService localizationService) - { - this._settingService = settingService; - this._prepaymentPaymentSettings = prepaymentPaymentSettings; - this._localizationService = localizationService; - } - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - var model = new ConfigurationModel(); - model.DescriptionText = _prepaymentPaymentSettings.DescriptionText; - model.AdditionalFee = _prepaymentPaymentSettings.AdditionalFee; - model.AdditionalFeePercentage = _prepaymentPaymentSettings.AdditionalFeePercentage; - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - [ValidateInput(false)] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //save settings - _prepaymentPaymentSettings.DescriptionText = model.DescriptionText; - _prepaymentPaymentSettings.AdditionalFee = model.AdditionalFee; - _prepaymentPaymentSettings.AdditionalFeePercentage = model.AdditionalFeePercentage; - _settingService.SaveSetting(_prepaymentPaymentSettings); - - return View(model); - } - - [ChildActionOnly] - public ActionResult PaymentInfo() - { - var model = new PaymentInfoModel(); - - string desc = _prepaymentPaymentSettings.DescriptionText; - - if( desc.StartsWith("@") ) - { - model.DescriptionText = _localizationService.GetResource(desc.Substring(1)); - } - else - { - model.DescriptionText = _prepaymentPaymentSettings.DescriptionText; - } - - return View(model); - } - - [NonAction] - public override IList ValidatePaymentForm(FormCollection form) - { - var warnings = new List(); - return warnings; - } - - [NonAction] - public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) - { - var paymentInfo = new ProcessPaymentRequest(); - return paymentInfo; - } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Description.txt b/src/Plugins/Payments.Prepayment/Description.txt deleted file mode 100644 index 2cb80b0855..0000000000 --- a/src/Plugins/Payments.Prepayment/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Prepayment -SystemName: Payments.Prepayment -Version: 1.4 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Payments.Prepayment.dll -ResourceRootKey: Plugins.Payment.Prepayment \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Localization/resources.de-de.xml b/src/Plugins/Payments.Prepayment/Localization/resources.de-de.xml deleted file mode 100644 index 95480a50b1..0000000000 --- a/src/Plugins/Payments.Prepayment/Localization/resources.de-de.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Vorkasse - - - - - - - - Beschreibung - - - Geben Sie hier die Beschreibung an, die dem Kunden im Bestellprozess angezeigt wird. - - - Zusätzliche Gebühr - - - Bestimmt die Gebühr die dem Kunden für die Nutzung dieser Zahlart berechnet wird. - - - Zusätzliche Gebühren (prozentual) - - - Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. - - - - Sobald Ihre Bestellung abgeschloßen ist, werden Sie persönlich von einem unserer Mitarbeiter kontaktiert, um die Bestellung zu bestätigen. -

    P.S. Dieser Text kann im Admin-Bereich editiert werden.

    - ]]> -
    -
    -
    \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Localization/resources.en-us.xml b/src/Plugins/Payments.Prepayment/Localization/resources.en-us.xml deleted file mode 100644 index 72ec0e2e3b..0000000000 --- a/src/Plugins/Payments.Prepayment/Localization/resources.en-us.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - Prepayment - - - - - - - - Description - - - Enter info that will be shown to customers during checkout. - - - Additional fee - - - Determines the additional fee. - - - Additional fee. Use percentage - - - Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. - - - - In cases where an order is placed, an authorized representative will contact you, personally or over telephone, to confirm the order.
    After the order is confirmed, it will be processed.
    Orders once confirmed, cannot be cancelled.

    P.S. You can edit this text from admin panel.

    - ]]> -
    -
    - -
    \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Models/ConfigurationModel.cs b/src/Plugins/Payments.Prepayment/Models/ConfigurationModel.cs deleted file mode 100644 index 314571e300..0000000000 --- a/src/Plugins/Payments.Prepayment/Models/ConfigurationModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.Prepayment.Models -{ - public class ConfigurationModel : ModelBase - { - [AllowHtml] - [SmartResourceDisplayName("Plugins.Payment.Prepayment.DescriptionText")] - public string DescriptionText { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.Prepayment.AdditionalFee")] - public decimal AdditionalFee { get; set; } - - [SmartResourceDisplayName("Plugins.Payment.Prepayment.AdditionalFeePercentage")] - public bool AdditionalFeePercentage { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Models/PaymentInfoModel.cs b/src/Plugins/Payments.Prepayment/Models/PaymentInfoModel.cs deleted file mode 100644 index 8aa7cf41cf..0000000000 --- a/src/Plugins/Payments.Prepayment/Models/PaymentInfoModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Payments.Prepayment.Models -{ - public class PaymentInfoModel : ModelBase - { - public string DescriptionText { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Notes.txt b/src/Plugins/Payments.Prepayment/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Payments.Prepayment/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/PrepaymentPaymentProcessor.cs b/src/Plugins/Payments.Prepayment/PrepaymentPaymentProcessor.cs deleted file mode 100644 index d65ac15055..0000000000 --- a/src/Plugins/Payments.Prepayment/PrepaymentPaymentProcessor.cs +++ /dev/null @@ -1,217 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Domain.Orders; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Payments.Prepayment.Controllers; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Orders; -using SmartStore.Services.Payments; - -namespace SmartStore.Plugin.Payments.Prepayment -{ - /// - /// Prepayment payment processor - /// - public class PrepaymentPaymentProcessor : PaymentMethodBase - { - #region Fields - - private readonly PrepaymentPaymentSettings _prepaymentPaymentSettings; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; - private readonly IOrderTotalCalculationService _orderTotalCalculationService; - - #endregion - - #region Ctor - - public PrepaymentPaymentProcessor(PrepaymentPaymentSettings prepaymentPaymentSettings, - ISettingService settingService, - ILocalizationService localizationService, - IOrderTotalCalculationService orderTotalCalculationService) - { - this._prepaymentPaymentSettings = prepaymentPaymentSettings; - this._settingService = settingService; - this._localizationService = localizationService; - this._orderTotalCalculationService = orderTotalCalculationService; - } - - #endregion - - #region Methods - - /// - /// Process a payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.NewPaymentStatus = PaymentStatus.Pending; - return result; - } - - /// - /// Gets additional handling fee - /// - /// Shoping cart - /// Additional handling fee - public override decimal GetAdditionalHandlingFee(IList cart) - { - var result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, _prepaymentPaymentSettings.AdditionalFee, _prepaymentPaymentSettings.AdditionalFeePercentage); - return result; - } - - /// - /// Captures payment - /// - /// Capture payment request - /// Capture payment result - public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) - { - var result = new CapturePaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoCaptureSupport")); - return result; - } - - /// - /// Refunds a payment - /// - /// Request - /// Result - public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) - { - var result = new RefundPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRefundSupport")); - return result; - } - - /// - /// Voids a payment - /// - /// Request - /// Result - public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) - { - var result = new VoidPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoVoidSupport")); - return result; - } - - /// - /// Process recurring payment - /// - /// Payment info required for an order processing - /// Process payment result - public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) - { - var result = new ProcessPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Cancels a recurring payment - /// - /// Request - /// Result - public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) - { - var result = new CancelRecurringPaymentResult(); - result.AddError(_localizationService.GetResource("Common.Payment.NoRecurringPaymentSupport")); - return result; - } - - /// - /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods) - /// - /// Order - /// Result - public override bool CanRePostProcessPayment(Order order) - { - if (order == null) - throw new ArgumentNullException("order"); - - //it's not a redirection payment method. So we always return false - return false; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "PaymentPrepayment"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.Prepayment.Controllers" }, { "area", "Payments.Prepayment" } }; - } - - /// - /// Gets a route for payment info - /// - /// Action name - /// Controller name - /// Route values - public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PaymentInfo"; - controllerName = "PaymentPrepayment"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Payments.Prepayment.Controllers" }, { "area", "Payments.Prepayment" } }; - } - - public override Type GetControllerType() - { - return typeof(PaymentPrepaymentController); - } - - public override void Install() - { - var settings = new PrepaymentPaymentSettings() - { - DescriptionText = "@Plugins.Payment.Prepayment.PaymentInfoDescription" - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - public override void Uninstall() - { - //settings - _settingService.DeleteSetting(); - - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Payments.Prepayment", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - /// - /// Gets a payment method type - /// - public override PaymentMethodType PaymentMethodType - { - get - { - return PaymentMethodType.Standard; - } - } - - #endregion - - } -} diff --git a/src/Plugins/Payments.Prepayment/PrepaymentPaymentSettings.cs b/src/Plugins/Payments.Prepayment/PrepaymentPaymentSettings.cs deleted file mode 100644 index 4839352c6d..0000000000 --- a/src/Plugins/Payments.Prepayment/PrepaymentPaymentSettings.cs +++ /dev/null @@ -1,11 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Payments.Prepayment -{ - public class PrepaymentPaymentSettings : ISettings - { - public string DescriptionText { get; set; } - public decimal AdditionalFee { get; set; } - public bool AdditionalFeePercentage { get; set; } - } -} diff --git a/src/Plugins/Payments.Prepayment/Properties/AssemblyInfo.cs b/src/Plugins/Payments.Prepayment/Properties/AssemblyInfo.cs deleted file mode 100644 index bcae0cf874..0000000000 --- a/src/Plugins/Payments.Prepayment/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Payments.Prepayment")] diff --git a/src/Plugins/Payments.Prepayment/RouteProvider.cs b/src/Plugins/Payments.Prepayment/RouteProvider.cs deleted file mode 100644 index f833b4d991..0000000000 --- a/src/Plugins/Payments.Prepayment/RouteProvider.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Payments.Prepayment -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Payments.Prepayment.Configure", - "Plugins/PaymentPrepayment/Configure", - new { controller = "PaymentPrepayment", action = "Configure" }, - new[] { "SmartStore.Plugin.Payments.Prepayment.Controllers" } - ) - .DataTokens["area"] = "Payments.Prepayment"; - - routes.MapRoute("Plugin.Payments.Prepayment.PaymentInfo", - "Plugins/PaymentPrepayment/PaymentInfo", - new { controller = "PaymentPrepayment", action = "PaymentInfo" }, - new[] { "SmartStore.Plugin.Payments.Prepayment.Controllers" } - ) - .DataTokens["area"] = "Payments.Prepayment"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Payments.Prepayment/SmartStore.Plugin.Payments.Prepayment.csproj b/src/Plugins/Payments.Prepayment/SmartStore.Plugin.Payments.Prepayment.csproj deleted file mode 100644 index 3924be02f4..0000000000 --- a/src/Plugins/Payments.Prepayment/SmartStore.Plugin.Payments.Prepayment.csproj +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {5B378AAD-5E5D-441D-9824-30A2995BCA68} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Payments.Prepayment - SmartStore.Plugin.Payments.Prepayment - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Payments.Prepayment\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Payments.Prepayment\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - Always - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Views/PaymentPrepayment/Configure.cshtml b/src/Plugins/Payments.Prepayment/Views/PaymentPrepayment/Configure.cshtml deleted file mode 100644 index 476c0f7aa1..0000000000 --- a/src/Plugins/Payments.Prepayment/Views/PaymentPrepayment/Configure.cshtml +++ /dev/null @@ -1,48 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.Prepayment.Models.ConfigurationModel -@using SmartStore.Web.Framework; -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.DescriptionText) - - @Html.TextAreaFor(model => model.DescriptionText, new { style = "Width: 550px; Height: 350px;" }) - @Html.ValidationMessageFor(model => model.DescriptionText) -
    - @Html.SmartLabelFor(model => model.AdditionalFee) - - @Html.EditorFor(model => model.AdditionalFee) - @Html.ValidationMessageFor(model => model.AdditionalFee) -
    - @Html.SmartLabelFor(model => model.AdditionalFeePercentage) - - @Html.EditorFor(model => model.AdditionalFeePercentage) - @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) -
    -   - - -
    - -} \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/Views/PaymentPrepayment/PaymentInfo.cshtml b/src/Plugins/Payments.Prepayment/Views/PaymentPrepayment/PaymentInfo.cshtml deleted file mode 100644 index 4f27acecbc..0000000000 --- a/src/Plugins/Payments.Prepayment/Views/PaymentPrepayment/PaymentInfo.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Payments.Prepayment.Models.PaymentInfoModel -@using SmartStore.Web.Framework; - - - - -
    - @Html.Raw(Model.DescriptionText) -
    diff --git a/src/Plugins/Payments.Prepayment/Views/Web.config b/src/Plugins/Payments.Prepayment/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Payments.Prepayment/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Payments.Prepayment/icon.png b/src/Plugins/Payments.Prepayment/icon.png deleted file mode 100644 index 8c85000ec9..0000000000 Binary files a/src/Plugins/Payments.Prepayment/icon.png and /dev/null differ diff --git a/src/Plugins/Payments.Prepayment/packages.config b/src/Plugins/Payments.Prepayment/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/Payments.Prepayment/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Payments.Prepayment/web.config b/src/Plugins/Payments.Prepayment/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Payments.Prepayment/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/SMS.Clickatell/ClickatellSMSProvider.cs b/src/Plugins/SMS.Clickatell/ClickatellSMSProvider.cs deleted file mode 100644 index 83f79dc527..0000000000 --- a/src/Plugins/SMS.Clickatell/ClickatellSMSProvider.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.ServiceModel; -using System.Web.Routing; -using SmartStore.Core; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.SMS.Clickatell.Clickatell; -using SmartStore.Services.Common; -using SmartStore.Services.Localization; -using SmartStore.Core.Logging; - -namespace SmartStore.Plugin.SMS.Clickatell -{ - /// - /// Represents the Clickatell SMS provider - /// - public class ClickatellSmsProvider : BasePlugin, IMiscPlugin - { - private readonly ILogger _logger; - private readonly ClickatellSettings _clickatellSettings; - private readonly ILocalizationService _localizationService; - - public ClickatellSmsProvider(ClickatellSettings clickatellSettings, - ILogger logger, - ILocalizationService localizationService) - { - this._clickatellSettings = clickatellSettings; - this._logger = logger; - _localizationService = localizationService; - } - - /// - /// Sends SMS - /// - /// Text - public bool SendSms(string text) - { - try - { - using (var svc = new PushServerWSPortTypeClient(new BasicHttpBinding(), new EndpointAddress("http://api.clickatell.com/soap/webservice_vs.php"))) - { - string authRsp = svc.auth(Int32.Parse(_clickatellSettings.ApiId), _clickatellSettings.Username, _clickatellSettings.Password); - - if (!authRsp.ToUpperInvariant().StartsWith("OK")) - { - throw new SmartException(authRsp); - } - - string ssid = authRsp.Substring(4); - string[] sndRsp = svc.sendmsg(ssid, - Int32.Parse(_clickatellSettings.ApiId), _clickatellSettings.Username, - _clickatellSettings.Password, new string[1] { _clickatellSettings.PhoneNumber }, - String.Empty, text, 0, 0, 0, 0, 0, 0, 0, 0, 0, - String.Empty, 0, String.Empty, String.Empty, String.Empty, 0); - - if (!sndRsp[0].ToUpperInvariant().StartsWith("ID")) - { - throw new SmartException(sndRsp[0]); - } - return true; - } - } - catch (Exception ex) - { - _logger.Error(ex.Message, ex); - } - return false; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "SmsClickatell"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.SMS.Clickatell.Controllers" }, { "area", "SMS.Clickatell" } }; - } - - /// - /// Install plugin - /// - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Mobile.SMS.Clickatell", false); - - base.Uninstall(); - } - } -} diff --git a/src/Plugins/SMS.Clickatell/Description.txt b/src/Plugins/SMS.Clickatell/Description.txt deleted file mode 100644 index cd007a29b0..0000000000 --- a/src/Plugins/SMS.Clickatell/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Clickatell SMS Provider -SystemName: SMS.Clickatell -Version: 1.4 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.SMS.Clickatell.dll -ResourceRootKey: Plugins.Sms.Clickatell \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/Localization/resources.de-de.xml b/src/Plugins/SMS.Clickatell/Localization/resources.de-de.xml deleted file mode 100644 index 33f5697b26..0000000000 --- a/src/Plugins/SMS.Clickatell/Localization/resources.de-de.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - Clickatell SMS-Anbieter - - - - - Um ein Benachrichtigung per SMS zu erhalten wenn eine Bestellung in Ihrem Shop durchgeführt wurde, - müssen folgende Schritte durchgeführt werden. -

    -
      -
    • Registrieren Sie sich hier für einen Clickatell-Account
    • -
    • Clickatell funktioniert in allen Ländern und bietet 10 kostenlose SMS zum Testen der Benachrichtigungen an
    • -
    • Füllen Sie das folgende Formular mit Ihren Clickatell-Accountdaten und der Telefonnummer zu der die Nachrichten gesendet werden sollen
    • -
    • Klicken Sie auf den 'Speichern'-Button
    • -
    • Wenn nun eine neue Bestellung durchgeführt wird, erhalten Sie automatisch eine SMS
    • -
    - ]]> -
    -
    - - Testnachricht konnte nicht gesendet werden - - - Testnachricht wurde erfolgreich verschickt - - - Aktiv - - - Aktivieren Sie hier den SMS-Anbieter - - - API-ID - - - Clickatell API-ID - - - Passwort - - - Clickatell Passwort - - - Telefonnummer - - - Ihre Telefonnummer - - - Nutzername - - - Clickatell Nutzername - - - Text der Nachricht - - - Text der Testnachricht - - - Senden - - - Senden Sie eine Testnachricht - -
    \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/Localization/resources.en-us.xml b/src/Plugins/SMS.Clickatell/Localization/resources.en-us.xml deleted file mode 100644 index ba454d5fcc..0000000000 --- a/src/Plugins/SMS.Clickatell/Localization/resources.en-us.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - Clickatell SMS Provider - - - - To receive an SMS notification when an order is placed from your store you need - to follow a few simple steps, which are shown below:

    -
      -
    • Register for a Clickatell account here
    • -
    • Clickatell works with all countries and includes 10 free messages so you can test SMS notifications
    • -
    • Fill in the form below with your Clickatell account details, including the number you want the notification messages to be sent to
    • -
    • Click 'Save' button
    • -
    • Now when you receive a new order, an SMS text message will be sent to the number you enter below automatically
    • -
    - ]]> -
    -
    - - Test message sending failed - - - Test message was sent - - - Enabled - - - Check to enable SMS provider - - - API ID - - - Clickatell API ID - - - Password - - - Clickatell password - - - Phone number - - - Your phone number - - - Username - - - Clickatell username - - - Message text - - - Text of the test message - - - Send - - - Send test message - -
    \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/Notes.txt b/src/Plugins/SMS.Clickatell/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/SMS.Clickatell/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/Properties/AssemblyInfo.cs b/src/Plugins/SMS.Clickatell/Properties/AssemblyInfo.cs deleted file mode 100644 index 0272cdcf19..0000000000 --- a/src/Plugins/SMS.Clickatell/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.SMS.Clickatell")] diff --git a/src/Plugins/SMS.Clickatell/RouteProvider.cs b/src/Plugins/SMS.Clickatell/RouteProvider.cs deleted file mode 100644 index 063e1b6a15..0000000000 --- a/src/Plugins/SMS.Clickatell/RouteProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.SMS.Clickatell -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("SMS.Clickatell", - "Plugins/SMSClickatell/{action}", - new { controller = "SmsClickatell", action = "Configure" }, - new[] { "SmartStore.Plugin.SMS.Clickatell.Controllers" } - ) - .DataTokens["area"] = "SMS.Clickatell"; - } - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/SMS.Clickatell/Service References/Clickatell/Reference.cs b/src/Plugins/SMS.Clickatell/Service References/Clickatell/Reference.cs deleted file mode 100644 index fe9f329b99..0000000000 --- a/src/Plugins/SMS.Clickatell/Service References/Clickatell/Reference.cs +++ /dev/null @@ -1,357 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.18444 -// -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. -// -//------------------------------------------------------------------------------ - -namespace SmartStore.Plugin.SMS.Clickatell.Clickatell { - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - [System.ServiceModel.ServiceContractAttribute(Namespace="http://api.clickatell.com/soap/webservice", ConfigurationName="Clickatell.PushServerWSPortType")] - internal interface PushServerWSPortType { - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/auth", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string auth(int api_id, string user, string password); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/ping", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string ping(string session_id); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/sendmsg", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] sendmsg( - string session_id, - int api_id, - string user, - string password, - string[] to, - string from, - string text, - int concat, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int unicode, - string msg_type, - string udh, - string data, - int validity); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/querymsg", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] querymsg(string session_id, int api_id, string user, string password, string apimsgid, string climsgid); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/delmsg", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] delmsg(string session_id, string api_id, string user, string password, string apimsgid, string climsgid); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/getbalance", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string getbalance(string session_id, int api_id, string user, string password); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/routeCoverage", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string routeCoverage(string session_id, int api_id, string user, string password, string msisdn); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/si_push", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] si_push( - string session_id, - int api_id, - string user, - string password, - string[] to, - string si_id, - string si_url, - string si_text, - string si_created, - string si_expires, - string si_action, - string from, - int concat, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int validity); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/ind_push", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] ind_push( - string session_id, - int api_id, - string user, - string password, - string[] to, - string mms_subject, - string mms_class, - string mms_expire, - string mms_from, - string mms_url, - string from, - int concat, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int validity); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/token_pay", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string token_pay(string session_id, int api_id, string user, string password, string token); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/startbatch", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] startbatch( - string session_id, - int api_id, - string user, - string password, - string from, - int concat, - string template, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int unicode, - string msg_type, - string udh, - string data, - int validity); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/senditem", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] senditem(string session_id, int api_id, string user, string password, string batch_id, string[] to, string field1, string field2, string field3, string field4); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/quicksend", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] quicksend(string session_id, int api_id, string user, string password, string batch_id, string[] to); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/endbatch", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] endbatch(string session_id, int api_id, string user, string password, string batch_id); - - [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/getmsgcharge", ReplyAction="*")] - [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] - [return: System.ServiceModel.MessageParameterAttribute(Name="return")] - string[] getmsgcharge(string session_id, int api_id, string user, string password, string apimsgid); - } - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - internal interface PushServerWSPortTypeChannel : SmartStore.Plugin.SMS.Clickatell.Clickatell.PushServerWSPortType, System.ServiceModel.IClientChannel { - } - - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] - internal partial class PushServerWSPortTypeClient : System.ServiceModel.ClientBase, SmartStore.Plugin.SMS.Clickatell.Clickatell.PushServerWSPortType { - - public PushServerWSPortTypeClient() { - } - - public PushServerWSPortTypeClient(string endpointConfigurationName) : - base(endpointConfigurationName) { - } - - public PushServerWSPortTypeClient(string endpointConfigurationName, string remoteAddress) : - base(endpointConfigurationName, remoteAddress) { - } - - public PushServerWSPortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : - base(endpointConfigurationName, remoteAddress) { - } - - public PushServerWSPortTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : - base(binding, remoteAddress) { - } - - public string auth(int api_id, string user, string password) { - return base.Channel.auth(api_id, user, password); - } - - public string ping(string session_id) { - return base.Channel.ping(session_id); - } - - public string[] sendmsg( - string session_id, - int api_id, - string user, - string password, - string[] to, - string from, - string text, - int concat, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int unicode, - string msg_type, - string udh, - string data, - int validity) { - return base.Channel.sendmsg(session_id, api_id, user, password, to, from, text, concat, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, unicode, msg_type, udh, data, validity); - } - - public string[] querymsg(string session_id, int api_id, string user, string password, string apimsgid, string climsgid) { - return base.Channel.querymsg(session_id, api_id, user, password, apimsgid, climsgid); - } - - public string[] delmsg(string session_id, string api_id, string user, string password, string apimsgid, string climsgid) { - return base.Channel.delmsg(session_id, api_id, user, password, apimsgid, climsgid); - } - - public string getbalance(string session_id, int api_id, string user, string password) { - return base.Channel.getbalance(session_id, api_id, user, password); - } - - public string routeCoverage(string session_id, int api_id, string user, string password, string msisdn) { - return base.Channel.routeCoverage(session_id, api_id, user, password, msisdn); - } - - public string[] si_push( - string session_id, - int api_id, - string user, - string password, - string[] to, - string si_id, - string si_url, - string si_text, - string si_created, - string si_expires, - string si_action, - string from, - int concat, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int validity) { - return base.Channel.si_push(session_id, api_id, user, password, to, si_id, si_url, si_text, si_created, si_expires, si_action, from, concat, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, validity); - } - - public string[] ind_push( - string session_id, - int api_id, - string user, - string password, - string[] to, - string mms_subject, - string mms_class, - string mms_expire, - string mms_from, - string mms_url, - string from, - int concat, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int validity) { - return base.Channel.ind_push(session_id, api_id, user, password, to, mms_subject, mms_class, mms_expire, mms_from, mms_url, from, concat, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, validity); - } - - public string token_pay(string session_id, int api_id, string user, string password, string token) { - return base.Channel.token_pay(session_id, api_id, user, password, token); - } - - public string[] startbatch( - string session_id, - int api_id, - string user, - string password, - string from, - int concat, - string template, - int deliv_ack, - int msg_callback, - int deliv_time, - float max_credits, - int req_feat, - int queue, - int escalate, - int mo, - string cliMsgId, - int unicode, - string msg_type, - string udh, - string data, - int validity) { - return base.Channel.startbatch(session_id, api_id, user, password, from, concat, template, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, unicode, msg_type, udh, data, validity); - } - - public string[] senditem(string session_id, int api_id, string user, string password, string batch_id, string[] to, string field1, string field2, string field3, string field4) { - return base.Channel.senditem(session_id, api_id, user, password, batch_id, to, field1, field2, field3, field4); - } - - public string[] quicksend(string session_id, int api_id, string user, string password, string batch_id, string[] to) { - return base.Channel.quicksend(session_id, api_id, user, password, batch_id, to); - } - - public string[] endbatch(string session_id, int api_id, string user, string password, string batch_id) { - return base.Channel.endbatch(session_id, api_id, user, password, batch_id); - } - - public string[] getmsgcharge(string session_id, int api_id, string user, string password, string apimsgid) { - return base.Channel.getmsgcharge(session_id, api_id, user, password, apimsgid); - } - } -} diff --git a/src/Plugins/SMS.Clickatell/SmartStore.Plugin.SMS.Clickatell.csproj b/src/Plugins/SMS.Clickatell/SmartStore.Plugin.SMS.Clickatell.csproj deleted file mode 100644 index 459098a4c9..0000000000 --- a/src/Plugins/SMS.Clickatell/SmartStore.Plugin.SMS.Clickatell.csproj +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {E3362B5B-DA5A-4515-BCB0-0DF982F80E89} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.SMS.Clickatell - SmartStore.Plugin.SMS.Clickatell - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\SMS.Clickatell\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\SMS.Clickatell\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - True - True - Reference.svcmap - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - - - - - WCF Proxy Generator - Reference.cs - - - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/Views/SmsClickatell/Configure.cshtml b/src/Plugins/SMS.Clickatell/Views/SmsClickatell/Configure.cshtml deleted file mode 100644 index 1ac541f72c..0000000000 --- a/src/Plugins/SMS.Clickatell/Views/SmsClickatell/Configure.cshtml +++ /dev/null @@ -1,105 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Sms.Clickatell.Models.SmsClickatellModel -@using SmartStore.Web.Framework; - -
    - - @Html.Raw(@T("Plugins.Sms.Clickatell.AdminInstruction")) -
    - -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.Enabled) - - @Html.EditorFor(model => model.Enabled) - @Html.ValidationMessageFor(model => model.Enabled) -
    - @Html.SmartLabelFor(model => model.PhoneNumber) - - @Html.EditorFor(model => model.PhoneNumber) - @Html.ValidationMessageFor(model => model.PhoneNumber) -
    - @Html.SmartLabelFor(model => model.ApiId) - - @Html.EditorFor(model => model.ApiId) - @Html.ValidationMessageFor(model => model.ApiId) -
    - @Html.SmartLabelFor(model => model.Username) - - @Html.EditorFor(model => model.Username) - @Html.ValidationMessageFor(model => model.Username) -
    - @Html.SmartLabelFor(model => model.Password) - - @Html.EditorFor(model => model.Password) - @Html.ValidationMessageFor(model => model.Password) -
    -   - - -
    -
    -

    @T("Plugins.Sms.Clickatell.SendTest.Hint")

    -
    -
    - @Html.SmartLabelFor(model => model.TestMessage) - - @Html.EditorFor(model => model.TestMessage) - @Html.ValidationMessageFor(model => model.TestMessage) -
    -   - - -
    - - if (!String.IsNullOrEmpty(Model.TestSmsResult)) - { -
    - - @Model.TestSmsResult -
    - } -} \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/Views/Web.config b/src/Plugins/SMS.Clickatell/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/SMS.Clickatell/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/SMS.Clickatell/packages.config b/src/Plugins/SMS.Clickatell/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/SMS.Clickatell/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/web.config b/src/Plugins/SMS.Clickatell/web.config deleted file mode 100644 index 8caecad85c..0000000000 --- a/src/Plugins/SMS.Clickatell/web.config +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Shipping.ByTotal/ByTotalShippingComputationMethod.cs b/src/Plugins/Shipping.ByTotal/ByTotalShippingComputationMethod.cs deleted file mode 100644 index 724d818340..0000000000 --- a/src/Plugins/Shipping.ByTotal/ByTotalShippingComputationMethod.cs +++ /dev/null @@ -1,291 +0,0 @@ -using System; -using System.Data.Entity.Migrations; -using System.Web.Routing; -using SmartStore.Core; -using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Shipping.ByTotal.Data; -using SmartStore.Plugin.Shipping.ByTotal.Data.Migrations; -using SmartStore.Plugin.Shipping.ByTotal.Services; -using SmartStore.Services.Catalog; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Core.Logging; -using SmartStore.Services.Shipping; -using SmartStore.Services.Shipping.Tracking; - -namespace SmartStore.Plugin.Shipping.ByTotal -{ - public class ByTotalShippingComputationMethod : BasePlugin, IShippingRateComputationMethod - { - #region Fields - - private readonly IShippingService _shippingService; - private readonly IStoreContext _storeContext; - private readonly IShippingByTotalService _shippingByTotalService; - private readonly ShippingByTotalSettings _shippingByTotalSettings; - private readonly ShippingByTotalObjectContext _objectContext; - private readonly IPriceCalculationService _priceCalculationService; - private readonly ILogger _logger; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; - - #endregion - - #region Ctor - - /// - /// Ctor - /// - /// Shipping service - /// ShippingByTotal service - /// ShippingByTotal settings - /// ShippingByTotal object context - /// PriceCalculation service - /// Settings service - /// Logger - public ByTotalShippingComputationMethod(IShippingService shippingService, - IStoreContext storeContext, - IShippingByTotalService shippingByTotalService, - ShippingByTotalSettings shippingByTotalSettings, - ShippingByTotalObjectContext objectContext, - IPriceCalculationService priceCalculationService, - ILogger logger, - ISettingService settingService, - ILocalizationService localizationService) - { - this._shippingService = shippingService; - this._storeContext = storeContext; - this._shippingByTotalService = shippingByTotalService; - this._shippingByTotalSettings = shippingByTotalSettings; - this._objectContext = objectContext; - this._priceCalculationService = priceCalculationService; - this._logger = logger; - this._settingService = settingService; - this._localizationService = localizationService; - } - - #endregion - - #region Properties - - /// - /// Gets a shipping rate computation method type - /// - public ShippingRateComputationMethodType ShippingRateComputationMethodType - { - get - { - return ShippingRateComputationMethodType.Offline; - } - } - - #endregion - - #region Utilities - - /// - /// Gets the rate for the shipping method - /// - /// the order's subtotal - /// the shipping method identifier - /// country identifier - /// state province identifier - /// Zip code - /// the rate for the shipping method - private decimal? GetRate(decimal subtotal, int shippingMethodId, int storeId, int countryId, int stateProvinceId, string zip) - { - decimal? shippingTotal = null; - - var shippingByTotalRecord = _shippingByTotalService.FindShippingByTotalRecord(shippingMethodId, storeId, countryId, subtotal, stateProvinceId, zip); - - if (shippingByTotalRecord == null) - { - if (_shippingByTotalSettings.LimitMethodsToCreated) - { - return null; - } - else - { - return decimal.Zero; - } - } - - decimal baseCharge = shippingByTotalRecord.BaseCharge; - decimal? maxCharge = shippingByTotalRecord.MaxCharge; - - if (shippingByTotalRecord.UsePercentage && shippingByTotalRecord.ShippingChargePercentage <= decimal.Zero) - { - return baseCharge; //decimal.Zero; - } - - if (!shippingByTotalRecord.UsePercentage && shippingByTotalRecord.ShippingChargeAmount <= decimal.Zero) - { - return decimal.Zero; - } - - if (shippingByTotalRecord.UsePercentage) - { - shippingTotal = Math.Round((decimal)((((float)subtotal) * ((float)shippingByTotalRecord.ShippingChargePercentage)) / 100f), 2); - shippingTotal += baseCharge; - if (maxCharge.HasValue && maxCharge > baseCharge) - { - // shipping charge should not exceed MaxCharge - shippingTotal = Math.Min(shippingTotal.Value, maxCharge.Value); - } - } - else - { - shippingTotal = shippingByTotalRecord.ShippingChargeAmount; - } - - if (shippingTotal < decimal.Zero) - { - shippingTotal = decimal.Zero; - } - - return shippingTotal; - } - - #endregion - - #region Methods - - /// - /// Gets available shipping options - /// - /// A request for getting shipping options - /// Represents a response of getting shipping rate options - public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) - { - if (getShippingOptionRequest == null) - { - throw new ArgumentNullException("getShippingOptionRequest"); - } - - var response = new GetShippingOptionResponse(); - - if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) - { - response.AddError("No shipment items"); - return response; - } - if (getShippingOptionRequest.ShippingAddress == null) - { - response.AddError("Shipping address is not set"); - return response; - } - - var storeId = _storeContext.CurrentStore.Id; - int countryId = getShippingOptionRequest.ShippingAddress.CountryId.HasValue ? getShippingOptionRequest.ShippingAddress.CountryId.Value : 0; - int stateProvinceId = getShippingOptionRequest.ShippingAddress.StateProvinceId.HasValue ? getShippingOptionRequest.ShippingAddress.StateProvinceId.Value : 0; - string zip = getShippingOptionRequest.ShippingAddress.ZipPostalCode; - decimal subTotal = decimal.Zero; - - foreach (var shoppingCartItem in getShippingOptionRequest.Items) - { - if (shoppingCartItem.Item.IsFreeShipping || !shoppingCartItem.Item.IsShipEnabled) - { - continue; - } - subTotal += _priceCalculationService.GetSubTotal(shoppingCartItem, true); - } - - decimal sqThreshold = _shippingByTotalSettings.SmallQuantityThreshold; - decimal sqSurcharge = _shippingByTotalSettings.SmallQuantitySurcharge; - - var shippingMethods = _shippingService.GetAllShippingMethods(countryId); - foreach (var shippingMethod in shippingMethods) - { - decimal? rate = GetRate(subTotal, shippingMethod.Id, storeId, countryId, stateProvinceId, zip); - if (rate.HasValue) - { - if (rate > 0 && sqThreshold > 0 && subTotal <= sqThreshold) - { - // add small quantity surcharge (Mindermengenzuschalg) - rate += sqSurcharge; - } - - var shippingOption = new ShippingOption(); - shippingOption.Name = shippingMethod.Name; - shippingOption.Description = shippingMethod.Description; - shippingOption.Rate = rate.Value; - response.ShippingOptions.Add(shippingOption); - } - } - - return response; - } - - /// - /// Gets fixed shipping rate (if shipping rate computation method allows it and the rate can be calculated before checkout). - /// - /// A request for getting shipping options - /// Fixed shipping rate; or null in case there's no fixed shipping rate - public decimal? GetFixedRate(GetShippingOptionRequest getShippingOptionRequest) - { - return null; - } - - /// - /// Gets a shipment tracker - /// - public IShipmentTracker ShipmentTracker - { - get - { - return null; - } - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out System.Web.Routing.RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "ShippingByTotal"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByTotal.Controllers" }, { "area", "Shipping.ByTotal" } }; - } - - /// - /// Install the plugin - /// - public override void Install() - { - var settings = new ShippingByTotalSettings() - { - LimitMethodsToCreated = false, - SmallQuantityThreshold = 0, - SmallQuantitySurcharge = 0 - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - - _logger.Information(string.Format("Plugin installed: SystemName: {0}, Version: {1}, Description: '{2}'", PluginDescriptor.SystemName, PluginDescriptor.Version, PluginDescriptor.FriendlyName)); - } - - /// - /// Uninstall the plugin - /// - public override void Uninstall() - { - _settingService.DeleteSetting(); - - _localizationService.DeletePluginStringResources(this.PluginDescriptor); - - var migrator = new DbMigrator(new Configuration()); - migrator.Update(DbMigrator.InitialDatabase); - - base.Uninstall(); - } - - #endregion - } -} diff --git a/src/Plugins/Shipping.ByTotal/Controllers/ShippingByTotalController.cs b/src/Plugins/Shipping.ByTotal/Controllers/ShippingByTotalController.cs deleted file mode 100644 index 2452e47b12..0000000000 --- a/src/Plugins/Shipping.ByTotal/Controllers/ShippingByTotalController.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System.Web.Mvc; -using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Directory; -using SmartStore.Plugin.Shipping.ByTotal.Domain; -using SmartStore.Plugin.Shipping.ByTotal.Models; -using SmartStore.Plugin.Shipping.ByTotal.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Directory; -using SmartStore.Services.Shipping; -using SmartStore.Services.Stores; -using SmartStore.Web.Framework.Controllers; -using Telerik.Web.Mvc; - -namespace SmartStore.Plugin.Shipping.ByTotal.Controllers -{ - [AdminAuthorize] - public class ShippingByTotalController : PluginControllerBase - { - private readonly IShippingService _shippingService; - private readonly IStoreService _storeService; - private readonly ISettingService _settingService; - private readonly IShippingByTotalService _shippingByTotalService; - private readonly ShippingByTotalSettings _shippingByTotalSettings; - private readonly ICountryService _countryService; - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; - private readonly AdminAreaSettings _adminAreaSettings; - - public ShippingByTotalController(IShippingService shippingService, - IStoreService storeService, - ISettingService settingService, - IShippingByTotalService shippingByTotalService, - ShippingByTotalSettings shippingByTotalSettings, - ICountryService countryService, - ICurrencyService currencyService, - CurrencySettings currencySettings, - AdminAreaSettings adminAreaSettings) - { - this._shippingService = shippingService; - this._storeService = storeService; - this._settingService = settingService; - this._shippingByTotalService = shippingByTotalService; - this._shippingByTotalSettings = shippingByTotalSettings; - this._countryService = countryService; - this._currencyService = currencyService; - this._currencySettings = currencySettings; - this._adminAreaSettings = adminAreaSettings; - } - - public ActionResult Configure() - { - var shippingMethods = _shippingService.GetAllShippingMethods(); - if (shippingMethods.Count == 0) - { - return Content("No shipping methods can be loaded"); - } - - var model = new ShippingByTotalListModel(); - foreach (var sm in shippingMethods) - { - model.AvailableShippingMethods.Add(new SelectListItem() { Text = sm.Name, Value = sm.Id.ToString() }); - } - - //stores - model.AvailableStores.Add(new SelectListItem() { Text = "*", Value = "0" }); - foreach (var store in _storeService.GetAllStores()) - { - model.AvailableStores.Add(new SelectListItem() { Text = store.Name, Value = store.Id.ToString() }); - } - - //model.AvailableCountries.Add(new SelectListItem() { Text = "*", Value = "0" }); - var countries = _countryService.GetAllCountries(true); - foreach (var c in countries) - { - model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }); - } - - model.LimitMethodsToCreated = _shippingByTotalSettings.LimitMethodsToCreated; - model.SmallQuantityThreshold = _shippingByTotalSettings.SmallQuantityThreshold; - model.SmallQuantitySurcharge = _shippingByTotalSettings.SmallQuantitySurcharge; - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; - model.GridPageSize = _adminAreaSettings.GridPageSize; - - return View(model); - } - - [HttpPost, GridAction(EnableCustomBinding = true)] - public ActionResult RatesList(GridCommand command) - { - int totalCount; - var data = _shippingByTotalService.GetShippingByTotalModels(command.Page - 1, command.PageSize, out totalCount); - - var model = new GridModel - { - Data = data, - Total = totalCount - }; - - return new JsonResult - { - Data = model - }; - } - - [GridAction(EnableCustomBinding = true)] - public ActionResult RateUpdate(ShippingByTotalModel model, GridCommand command) - { - if (!ModelState.IsValid) - { - return new JsonResult { Data = "error" }; - } - - var shippingByTotalRecord = _shippingByTotalService.GetShippingByTotalRecordById(model.Id); - shippingByTotalRecord.Zip = model.Zip == "*" ? null : model.Zip; - shippingByTotalRecord.From = model.From; - shippingByTotalRecord.To = model.To; - shippingByTotalRecord.UsePercentage = model.UsePercentage; - shippingByTotalRecord.ShippingChargeAmount = model.ShippingChargeAmount; - shippingByTotalRecord.ShippingChargePercentage = model.ShippingChargePercentage; - shippingByTotalRecord.BaseCharge = model.BaseCharge; - shippingByTotalRecord.MaxCharge = model.MaxCharge; - _shippingByTotalService.UpdateShippingByTotalRecord(shippingByTotalRecord); - - return RatesList(command); - } - - [GridAction(EnableCustomBinding = true)] - public ActionResult RateDelete(int id, GridCommand command) - { - var shippingByTotalRecord = _shippingByTotalService.GetShippingByTotalRecordById(id); - if (shippingByTotalRecord != null) - { - _shippingByTotalService.DeleteShippingByTotalRecord(shippingByTotalRecord); - } - return RatesList(command); - } - - [HttpPost] - public ActionResult AddShippingRate(ShippingByTotalListModel model) - { - var shippingByTotalRecord = new ShippingByTotalRecord - { - StoreId = model.AddStoreId, - ShippingMethodId = model.AddShippingMethodId, - CountryId = model.AddCountryId, - StateProvinceId = model.AddStateProvinceId, - Zip = model.AddZip, - From = model.AddFrom, - To = model.AddTo, - UsePercentage = model.AddUsePercentage, - ShippingChargePercentage = (model.AddUsePercentage) ? model.AddShippingChargePercentage : 0, - ShippingChargeAmount = (model.AddUsePercentage) ? 0 : model.AddShippingChargeAmount, - BaseCharge = model.AddBaseCharge, - MaxCharge = model.AddMaxCharge - }; - _shippingByTotalService.InsertShippingByTotalRecord(shippingByTotalRecord); - - return Json(new { Result = true }); - } - - [HttpPost] - public ActionResult SaveGeneralSettings(ShippingByTotalListModel model) - { - //save settings - _shippingByTotalSettings.LimitMethodsToCreated = model.LimitMethodsToCreated; - _shippingByTotalSettings.SmallQuantityThreshold = model.SmallQuantityThreshold; - _shippingByTotalSettings.SmallQuantitySurcharge = model.SmallQuantitySurcharge; - - _settingService.SaveSetting(_shippingByTotalSettings); - - return Json(new { Result = true }); - } - } -} diff --git a/src/Plugins/Shipping.ByTotal/Data/Migrations/Configuration.cs b/src/Plugins/Shipping.ByTotal/Data/Migrations/Configuration.cs deleted file mode 100644 index b00e7e6a7c..0000000000 --- a/src/Plugins/Shipping.ByTotal/Data/Migrations/Configuration.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace SmartStore.Plugin.Shipping.ByTotal.Data.Migrations -{ - using System; - using System.Data.Entity; - using System.Data.Entity.Migrations; - using System.Linq; - - internal sealed class Configuration : DbMigrationsConfiguration - { - public Configuration() - { - AutomaticMigrationsEnabled = false; - MigrationsDirectory = @"Data\Migrations"; - ContextKey = "SmartStore.ShippingByTotal"; - } - - protected override void Seed(ShippingByTotalObjectContext context) - { - // This method will be called after migrating to the latest version. - - // You can use the DbSet.AddOrUpdate() helper extension method - // to avoid creating duplicate seed data. E.g. - // - // context.People.AddOrUpdate( - // p => p.FullName, - // new Person { FullName = "Andrew Peters" }, - // new Person { FullName = "Brice Lambson" }, - // new Person { FullName = "Rowan Miller" } - // ); - // - } - } -} diff --git a/src/Plugins/Shipping.ByTotal/Data/ShippingByTotalObjectContext.cs b/src/Plugins/Shipping.ByTotal/Data/ShippingByTotalObjectContext.cs deleted file mode 100644 index 91d180459d..0000000000 --- a/src/Plugins/Shipping.ByTotal/Data/ShippingByTotalObjectContext.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data.Entity; -using System.Data.Entity.Infrastructure; -using System.Data.Entity.Migrations; -using SmartStore.Core; -using SmartStore.Core.Data; -using SmartStore.Data; -using SmartStore.Data.Setup; -using SmartStore.Plugin.Shipping.ByTotal.Data.Migrations; - -namespace SmartStore.Plugin.Shipping.ByTotal.Data -{ - - /// - /// Object context - /// - public class ShippingByTotalObjectContext : ObjectContextBase - { - public const string ALIASKEY = "sm_object_context_shipping_by_total"; - - static ShippingByTotalObjectContext() - { - var initializer = new MigrateDatabaseInitializer - { - TablesToCheck = new[] { "ShippingByTotal"} - }; - Database.SetInitializer(initializer); - } - - /// - /// For tooling support, e.g. EF Migrations - /// - public ShippingByTotalObjectContext() - : base() - { - } - - public ShippingByTotalObjectContext(string nameOrConnectionString) - : base(nameOrConnectionString, ALIASKEY) - { - } - - protected override void OnModelCreating(DbModelBuilder modelBuilder) - { - modelBuilder.Configurations.Add(new ShippingByTotalRecordMap()); - - //disable EdmMetadata generation - //modelBuilder.Conventions.Remove(); - base.OnModelCreating(modelBuilder); - } - - } -} diff --git a/src/Plugins/Shipping.ByTotal/Data/ShippingByTotalRecordMap.cs b/src/Plugins/Shipping.ByTotal/Data/ShippingByTotalRecordMap.cs deleted file mode 100644 index ccd0060abc..0000000000 --- a/src/Plugins/Shipping.ByTotal/Data/ShippingByTotalRecordMap.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Data.Entity.ModelConfiguration; -using SmartStore.Plugin.Shipping.ByTotal.Domain; - -namespace SmartStore.Plugin.Shipping.ByTotal.Data -{ - public class ShippingByTotalRecordMap : EntityTypeConfiguration - { - public ShippingByTotalRecordMap() - { - this.ToTable("ShippingByTotal"); - this.HasKey(x => x.Id); - - this.Property(x => x.Zip).IsOptional().HasMaxLength(400); - } - } -} diff --git a/src/Plugins/Shipping.ByTotal/DependencyRegistrar.cs b/src/Plugins/Shipping.ByTotal/DependencyRegistrar.cs deleted file mode 100644 index 1ae3706050..0000000000 --- a/src/Plugins/Shipping.ByTotal/DependencyRegistrar.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Autofac; -using Autofac.Core; -using Autofac.Integration.Mvc; -using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Data; -using SmartStore.Plugin.Shipping.ByTotal.Data; -using SmartStore.Plugin.Shipping.ByTotal.Domain; -using SmartStore.Plugin.Shipping.ByTotal.Services; - -namespace SmartStore.Plugin.Shipping.ByTotal -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - - //data layer - //register named context - builder.Register(c => new ShippingByTotalObjectContext(DataSettings.Current.DataConnectionString)) - .Named(ShippingByTotalObjectContext.ALIASKEY) - .InstancePerRequest(); - - builder.Register(c => new ShippingByTotalObjectContext(DataSettings.Current.DataConnectionString)) - .InstancePerRequest(); - - //override required repository with our custom context - builder.RegisterType>() - .As>() - .WithParameter(ResolvedParameter.ForNamed(ShippingByTotalObjectContext.ALIASKEY)) - .InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/Shipping.ByTotal/Description.txt b/src/Plugins/Shipping.ByTotal/Description.txt deleted file mode 100644 index 780148a8ee..0000000000 --- a/src/Plugins/Shipping.ByTotal/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Shipping by total -SystemName: Shipping.ByTotal -Version: 1.51 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Shipping.ByTotal.dll -ResourceRootKey: Plugins.Shipping.ByTotal \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/Localization/resources.de-de.xml b/src/Plugins/Shipping.ByTotal/Localization/resources.de-de.xml deleted file mode 100644 index f285b4bc70..0000000000 --- a/src/Plugins/Shipping.ByTotal/Localization/resources.de-de.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - Versand nach Gesamtsumme - - - Neue Versandbedingung hinzufügen - - - Optionen - - - - Land - - - Das Bestimmungsland. Wählen Sie Stern (*), wenn das Land des Kunden bei der Auswertung keine Rolle spielen soll. - - - Region - - - Bundesland/Region/Kanton des Kunden. Wählen Sie Stern (*), wenn die Gebühr unabhängig von Region für alle Kunden im definierten Land gelten soll. - - - PLZ-(Bereich) - - - PLZ-(Bereich) des Kunden, entweder als spezifischer Wert oder als Muster (z.B. 4000-49999 für das PLZ-Gebiet 4). In einem Muster lassen sich auch Wildcards verwenden, wie Stern (*) oder Fragezeichen (?). Lassen Sie das Feld leer, wenn die Gebühr unabhängig von PLZ für alle Kunden im definierten (Bundes)land gelten soll. - - - Versandart - - - Die Versandart, bei der diese Berechnungsmethode angewandt werden soll. - - - Bestellwert von - - - Die Bedingung trifft zu, wenn der Bestellwert im Warenkorb mind. diesen Wert aufweist. - - - Bestellwert bis - - - Die Bedingung trifft zu, wenn der Bestellwert im Warenkorb kleiner als dieser Wert ist. Lassen Sie das Feld leer, wenn Sie keine Obergrenze festlegen möchten. - - - Prozentual - - - Legt fest, ob die Versandgebühr prozentual vom Bestellwert berechnet werden soll. - - - Gebühr % - - - - Gebühr - - - Die Versandgebühr als absoluter Betrag - - - Kein 'Fallback' anbieten - - - Dem Kunden wird während des Checkouts kostenloser Versand als Fallback angeboten, wenn keine der festgelegten Bedingungen zutreffen. Aktivieren Sie diese Option, wenn das nicht gewünscht ist. - - - - Basisgebühr - - - Max. Gebühr - - - Ein Betrag, den die berechneten Versandkosten nicht übersteigen dürfen. - - - Mindermenge bis Bestellwert - - - Warenwert, bis zu dem ein Mindermengenzuschlag erhoben werden soll. Der Zuschlag wird ignoriert, wenn keine Versandkosten anfallen. Verwenden Sie "0", wenn kein Zuschlag erhoben werden soll. - - - Mindermengenzuschlag - - - Mindermengenzuschlag - - - Shop - - - Wird das Sternchen ausgewählt, so wird die Rate auf alle Shops angewandt. - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/Localization/resources.en-us.xml b/src/Plugins/Shipping.ByTotal/Localization/resources.en-us.xml deleted file mode 100644 index 0f123ebfc8..0000000000 --- a/src/Plugins/Shipping.ByTotal/Localization/resources.en-us.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - Shipping by total - - - Add new record - - - Settings - - - - Country - - - If an asterisk is selected, then this shipping rate will apply to all customers, regardless of the country. - - - State / province - - - If an asterisk is selected, then this shipping rate will apply to all customers from the given country, regardless of the state / province. - - - Zip-(Range) - - - Zip/postal code (range), either as specific value or range pattern (e.g. 4000-4999). You can also define wildcard chars like * or ?. If zip is empty, then this shipping rate will apply to all customers from the given country or state / province, regardless of the zip code. - - - Shipping method - - - The shipping method. - - - Order total from - - - Order total from - - - Order total to - - - Order total to - - - Use percentage - - - Check to use 'charge percentage' value. - - - Charge % - - - Charge percentage (of subtotal) - - - Charge - - - Charge amount - - - Limit shipping methods to configured ones - - - If you check this option, then your customers will be limited to shipping options configured here. Otherwise, they'll be able to choose any existing shipping options even if they're not configured here (zero shipping fee in this case). - - - - Base fee - - - Max. fee - - - An amount that the calculated shipping costs may not exceed. - - - Threshold for small quantities - - - Subtotal up to which a "small quantity surcharge" should be added. The surcharge will be ignored if no shipping fee is applied. Use "0" if no fee will be charged. - - - Surcharge for small quantities - - - Surcharge for small quantities - - - Store - - - If an asterisk is selected, then this shipping rate will apply to all stores. - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/Models/ShippingByTotalListModel.cs b/src/Plugins/Shipping.ByTotal/Models/ShippingByTotalListModel.cs deleted file mode 100644 index 02defbab37..0000000000 --- a/src/Plugins/Shipping.ByTotal/Models/ShippingByTotalListModel.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Shipping.ByTotal.Models -{ - public class ShippingByTotalListModel : ModelBase - { - public ShippingByTotalListModel() - { - AvailableCountries = new List(); - AvailableStates = new List(); - AvailableShippingMethods = new List(); - AvailableStores = new List(); - } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Store")] - public int AddStoreId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Country")] - public int? AddCountryId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.StateProvince")] - public int? AddStateProvinceId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Zip")] - public string AddZip { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingMethod")] - public int AddShippingMethodId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.From")] - public decimal AddFrom { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.To")] - public decimal? AddTo { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.UsePercentage")] - public bool AddUsePercentage { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargePercentage")] - public decimal AddShippingChargePercentage { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargeAmount")] - public decimal AddShippingChargeAmount { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.BaseCharge")] - public decimal AddBaseCharge { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.MaxCharge")] - public decimal AddMaxCharge { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.MaxCharge")] - public decimal? MaxCharge { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.LimitMethodsToCreated")] - public bool LimitMethodsToCreated { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.SmallQuantityThreshold")] - public decimal SmallQuantityThreshold { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.SmallQuantitySurcharge")] - public decimal SmallQuantitySurcharge { get; set; } - - public string PrimaryStoreCurrencyCode { get; set; } - - public int GridPageSize { get; set; } - - public IList AvailableCountries { get; set; } - public IList AvailableStates { get; set; } - public IList AvailableShippingMethods { get; set; } - public IList AvailableStores { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/Models/ShippingByTotalModel.cs b/src/Plugins/Shipping.ByTotal/Models/ShippingByTotalModel.cs deleted file mode 100644 index 916148aeda..0000000000 --- a/src/Plugins/Shipping.ByTotal/Models/ShippingByTotalModel.cs +++ /dev/null @@ -1,57 +0,0 @@ -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Shipping.ByTotal.Models -{ - - public class ShippingByTotalModel : EntityModelBase - { - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Store")] - public int StoreId { get; set; } - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Store")] - public string StoreName { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Country")] - public int? CountryId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Country")] - public string CountryName { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.StateProvince")] - public int? StateProvinceId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.StateProvince")] - public string StateProvinceName { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Zip")] - public string Zip { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingMethod")] - public int ShippingMethodId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingMethod")] - public string ShippingMethodName { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.From")] - public decimal From { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.To")] - public decimal? To { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.UsePercentage")] - public bool UsePercentage { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargePercentage")] - public decimal ShippingChargePercentage { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargeAmount")] - public decimal ShippingChargeAmount { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.BaseCharge")] - public decimal BaseCharge { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.MaxCharge")] - public decimal? MaxCharge { get; set; } - - } -} diff --git a/src/Plugins/Shipping.ByTotal/Properties/AssemblyInfo.cs b/src/Plugins/Shipping.ByTotal/Properties/AssemblyInfo.cs deleted file mode 100644 index f8ffd8db8b..0000000000 --- a/src/Plugins/Shipping.ByTotal/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Shipping.ByTotal")] diff --git a/src/Plugins/Shipping.ByTotal/RouteProvider.cs b/src/Plugins/Shipping.ByTotal/RouteProvider.cs deleted file mode 100644 index c37739faca..0000000000 --- a/src/Plugins/Shipping.ByTotal/RouteProvider.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Shipping.ByTotal -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Shipping.ByTotal.Configure", - "Plugins/ShippingByTotal/Configure", - new { controller = "ShippingByTotal", action = "Configure" }, - new[] { "SmartStore.Plugin.Shipping.ByTotal.Controllers" } - ) - .DataTokens["area"] = "Shipping.ByTotal"; - - routes.MapRoute("Plugin.Shipping.ByTotal.AddShippingRate", - "Plugins/ShippingByTotal/AddShippingRate", - new { controller = "ShippingByTotal", action = "AddShippingRate" }, - new[] { "SmartStore.Plugin.Shipping.ByTotal.Controllers" } - ) - .DataTokens["area"] = "Shipping.ByTotal"; - - routes.MapRoute("Plugin.Shipping.ByTotal.SaveGeneralSettings", - "Plugins/ShippingByTotal/SaveGeneralSettings", - new { controller = "ShippingByTotal", action = "SaveGeneralSettings" }, - new[] { "SmartStore.Plugin.Shipping.ByTotal.Controllers" } - ) - .DataTokens["area"] = "Shipping.ByTotal"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Shipping.ByTotal/SmartStore.Plugin.Shipping.ByTotal.csproj b/src/Plugins/Shipping.ByTotal/SmartStore.Plugin.Shipping.ByTotal.csproj deleted file mode 100644 index a1a72de17b..0000000000 --- a/src/Plugins/Shipping.ByTotal/SmartStore.Plugin.Shipping.ByTotal.csproj +++ /dev/null @@ -1,235 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {ACC1E122-B2C8-4441-BDED-D4A77763331A} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Shipping.ByTotal - SmartStore.Plugin.Shipping.ByTotal - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Shipping.ByTotal\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Shipping.ByTotal\ - TRACE - prompt - 4 - false - - - true - ..\..\Presentation\SmartStore.Web\bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - 201403072202413_Initial.cs - - - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} - SmartStore.Data - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - 201403072202413_Initial.cs - - - PreserveNewest - - - - PreserveNewest - - - PreserveNewest - - - - - PreserveNewest - - - Designer - PreserveNewest - - - Designer - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/Views/ShippingByTotal/Configure.cshtml b/src/Plugins/Shipping.ByTotal/Views/ShippingByTotal/Configure.cshtml deleted file mode 100644 index 4a62a746b2..0000000000 --- a/src/Plugins/Shipping.ByTotal/Views/ShippingByTotal/Configure.cshtml +++ /dev/null @@ -1,324 +0,0 @@ -@{ - Layout = ""; -} -@model ShippingByTotalListModel - -@using SmartStore.Plugin.Shipping.ByTotal.Models; -@using SmartStore.Web.Framework; -@using Telerik.Web.Mvc.UI; -@using SmartStore.Web.Framework.UI - - - - @T("Plugins.Shipping.ByTotal.AddNewRecordTitle") - - - - - - -
    - @(Html.Telerik().Grid() - .Name("shipping-bytotal-grid") - .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) - .DataBinding(dataBinding => dataBinding - .Ajax() - .Select("RatesList", "ShippingByTotal", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByTotal.Controllers" }, { "area", "" } }) - .Update("RateUpdate", "ShippingByTotal", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByTotal.Controllers" }, { "area", "" } }) - .Delete("RateDelete", "ShippingByTotal", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByTotal.Controllers" }, { "area", "" } }) - ) - .Columns(columns => - { - columns.Bound(x => x.StoreName).ReadOnly(); - columns.Bound(x => x.CountryName).ReadOnly(); - columns.Bound(x => x.StateProvinceName).ReadOnly(); - columns.Bound(x => x.Zip); - columns.Bound(x => x.ShippingMethodName).ReadOnly(); - columns.Bound(x => x.From); - columns.Bound(x => x.To); - columns.Bound(x => x.UsePercentage) - .Centered() - .Template(item => @Html.SymbolForBool(item.UsePercentage)) - .ClientTemplate(@Html.SymbolForBool("UsePercentage")); - columns.Bound(x => x.ShippingChargePercentage); - columns.Bound(x => x.ShippingChargeAmount); - columns.Bound(x => x.BaseCharge); - columns.Bound(x => x.MaxCharge); - columns.Command(commands => - { - commands.Edit().Localize(T); - commands.Delete().Localize(T); - }).Width(190); - }) - .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) - .Editable(x => x.Mode(GridEditMode.InLine)) - .EnableCustomBinding(true)) -
    - - - -@using (Html.BeginForm()) -{ - - - {Html.SmartStore().Window() - .Name("addrecord-window") - .Title(T("Plugins.Shipping.ByTotal.AddNewRecordTitle")) - .Content( - @ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.AddStoreId) - - @Html.DropDownListFor(model => model.AddStoreId, Model.AvailableStores) - @Html.ValidationMessageFor(model => model.AddStoreId) -
    - @Html.SmartLabelFor(model => model.AddCountryId) - - @Html.DropDownListFor(model => model.AddCountryId, Model.AvailableCountries, "*") - @Html.ValidationMessageFor(model => model.AddCountryId) -
    - @Html.SmartLabelFor(model => model.AddStateProvinceId) - - @Html.DropDownListFor(model => model.AddStateProvinceId, Model.AvailableStates, "*") - @Html.ValidationMessageFor(model => model.AddStateProvinceId) -
    - @Html.SmartLabelFor(model => model.AddZip) - - @Html.EditorFor(model => model.AddZip) - @Html.ValidationMessageFor(model => model.AddZip) -
    - @Html.SmartLabelFor(model => model.AddShippingMethodId) - - @Html.DropDownListFor(model => model.AddShippingMethodId, Model.AvailableShippingMethods) - @Html.ValidationMessageFor(model => model.AddShippingMethodId) -
    - @Html.SmartLabelFor(model => model.AddFrom) - - @Html.EditorFor(model => model.AddFrom) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.AddFrom) -
    - @Html.SmartLabelFor(model => model.AddTo) - - @Html.EditorFor(model => model.AddTo) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.AddTo) -
    - @Html.SmartLabelFor(model => model.AddUsePercentage) - - @Html.EditorFor(model => model.AddUsePercentage) - @Html.ValidationMessageFor(model => model.AddUsePercentage) -
    - @Html.SmartLabelFor(model => model.AddShippingChargePercentage) - - @Html.EditorFor(model => model.AddShippingChargePercentage) - @Html.ValidationMessageFor(model => model.AddShippingChargePercentage) -
    - @Html.SmartLabelFor(model => model.AddBaseCharge) - - @Html.EditorFor(model => model.AddBaseCharge) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.AddBaseCharge) -
    - @Html.SmartLabelFor(model => model.AddMaxCharge) - - @Html.EditorFor(model => model.AddMaxCharge) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.AddMaxCharge) -
    - @Html.SmartLabelFor(model => model.AddShippingChargeAmount) - - @Html.EditorFor(model => model.AddShippingChargeAmount) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.AddShippingChargeAmount) -
    -
    ) - .FooterContent(@ - - - ) - .Modal(true) - .Visible(false) - .Render(); - } - -
    - -
    - @T("Plugins.Shipping.ByTotal.SettingsTitle") - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.SmallQuantityThreshold) - - @Html.EditorFor(model => model.SmallQuantityThreshold) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.SmallQuantityThreshold) -
    - @Html.SmartLabelFor(model => model.SmallQuantitySurcharge) - - @Html.EditorFor(model => model.SmallQuantitySurcharge) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.SmallQuantitySurcharge) -
    - @Html.SmartLabelFor(model => model.LimitMethodsToCreated) - - @Html.EditorFor(model => model.LimitMethodsToCreated) - @Html.ValidationMessageFor(model => model.LimitMethodsToCreated) -
    -   - - -
    -
    -} \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/Views/Web.config b/src/Plugins/Shipping.ByTotal/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Shipping.ByTotal/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Shipping.ByTotal/packages.config b/src/Plugins/Shipping.ByTotal/packages.config deleted file mode 100644 index eda479b209..0000000000 --- a/src/Plugins/Shipping.ByTotal/packages.config +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/web.config b/src/Plugins/Shipping.ByTotal/web.config deleted file mode 100644 index c7103a3dae..0000000000 --- a/src/Plugins/Shipping.ByTotal/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Shipping.ByWeight/Controllers/ShippingByWeightController.cs b/src/Plugins/Shipping.ByWeight/Controllers/ShippingByWeightController.cs deleted file mode 100644 index d022c2854a..0000000000 --- a/src/Plugins/Shipping.ByWeight/Controllers/ShippingByWeightController.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Web.Mvc; -using SmartStore.Core.Domain.Common; -using SmartStore.Core.Domain.Directory; -using SmartStore.Plugin.Shipping.ByWeight.Domain; -using SmartStore.Plugin.Shipping.ByWeight.Models; -using SmartStore.Plugin.Shipping.ByWeight.Services; -using SmartStore.Services.Configuration; -using SmartStore.Services.Directory; -using SmartStore.Services.Shipping; -using SmartStore.Services.Stores; -using SmartStore.Web.Framework.Controllers; -using Telerik.Web.Mvc; - -namespace SmartStore.Plugin.Shipping.ByWeight.Controllers -{ - - public class ShippingByWeightController : PluginControllerBase - { - private readonly IShippingService _shippingService; - private readonly IStoreService _storeService; - private readonly ICountryService _countryService; - private readonly ShippingByWeightSettings _shippingByWeightSettings; - private readonly IShippingByWeightService _shippingByWeightService; - private readonly ISettingService _settingService; - - private readonly ICurrencyService _currencyService; - private readonly CurrencySettings _currencySettings; - private readonly IMeasureService _measureService; - private readonly MeasureSettings _measureSettings; - private readonly AdminAreaSettings _adminAreaSettings; - - public ShippingByWeightController(IShippingService shippingService, - IStoreService storeService, ICountryService countryService, ShippingByWeightSettings shippingByWeightSettings, - IShippingByWeightService shippingByWeightService, ISettingService settingService, - ICurrencyService currencyService, CurrencySettings currencySettings, - IMeasureService measureService, MeasureSettings measureSettings, - AdminAreaSettings adminAreaSettings) - { - this._shippingService = shippingService; - this._storeService = storeService; - this._countryService = countryService; - this._shippingByWeightSettings = shippingByWeightSettings; - this._shippingByWeightService = shippingByWeightService; - this._settingService = settingService; - - this._currencyService = currencyService; - this._currencySettings = currencySettings; - this._measureService = measureService; - this._measureSettings = measureSettings; - this._adminAreaSettings = adminAreaSettings; - } - - public ActionResult Configure() - { - var shippingMethods = _shippingService.GetAllShippingMethods(); - if (shippingMethods.Count == 0) - return Content("No shipping methods can be loaded"); - - var model = new ShippingByWeightListModel(); - foreach (var sm in shippingMethods) - model.AvailableShippingMethods.Add(new SelectListItem() { Text = sm.Name, Value = sm.Id.ToString() }); - - //stores - model.AvailableStores.Add(new SelectListItem() { Text = "*", Value = "0" }); - foreach (var store in _storeService.GetAllStores()) - model.AvailableStores.Add(new SelectListItem() { Text = store.Name, Value = store.Id.ToString() }); - - model.AvailableCountries.Add(new SelectListItem() { Text = "*", Value = "0" }); - var countries = _countryService.GetAllCountries(true); - foreach (var c in countries) - model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }); - model.LimitMethodsToCreated = _shippingByWeightSettings.LimitMethodsToCreated; - model.CalculatePerWeightUnit = _shippingByWeightSettings.CalculatePerWeightUnit; - model.PrimaryStoreCurrencyCode = _currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId).CurrencyCode; - model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; - model.GridPageSize = _adminAreaSettings.GridPageSize; - - return View(model); - } - - [HttpPost, GridAction(EnableCustomBinding = true)] - public ActionResult RatesList(GridCommand command) - { - int totalCount; - var data = _shippingByWeightService.GetShippingByWeightModels(command.Page - 1, command.PageSize, out totalCount); - - var model = new GridModel - { - Data = data, - Total = totalCount - }; - - return new JsonResult - { - Data = model - }; - } - - [GridAction(EnableCustomBinding = true)] - public ActionResult RateUpdate(ShippingByWeightModel model, GridCommand command) - { - var sbw = _shippingByWeightService.GetById(model.Id); - sbw.From = model.From; - sbw.To = model.To; - sbw.UsePercentage = model.UsePercentage; - sbw.ShippingChargeAmount = model.ShippingChargeAmount; - sbw.ShippingChargePercentage = model.ShippingChargePercentage; - sbw.SmallQuantitySurcharge = model.SmallQuantitySurcharge; - sbw.SmallQuantityThreshold = model.SmallQuantityThreshold; - _shippingByWeightService.UpdateShippingByWeightRecord(sbw); - - return RatesList(command); - } - - [GridAction(EnableCustomBinding = true)] - public ActionResult RateDelete(int id, GridCommand command) - { - var sbw = _shippingByWeightService.GetById(id); - _shippingByWeightService.DeleteShippingByWeightRecord(sbw); - - return RatesList(command); - } - - [HttpPost, ActionName("Configure")] - [FormValueRequired("addshippingbyweightrecord")] - public ActionResult AddShippingByWeightRecord(ShippingByWeightListModel model) - { - if (!ModelState.IsValid) - { - return Configure(); - } - - var sbw = new ShippingByWeightRecord() - { - StoreId = model.AddStoreId, - ShippingMethodId = model.AddShippingMethodId, - CountryId = model.AddCountryId, - //StateProvinceId = 0, - From = model.AddFrom, - To = model.AddTo, - UsePercentage = model.AddUsePercentage, - ShippingChargeAmount = model.AddShippingChargeAmount, - ShippingChargePercentage = model.AddShippingChargePercentage, - SmallQuantitySurcharge = model.SmallQuantitySurcharge, - SmallQuantityThreshold = model.SmallQuantityThreshold, - }; - _shippingByWeightService.InsertShippingByWeightRecord(sbw); - - return Configure(); - } - - [HttpPost, ActionName("Configure")] - [FormValueRequired("savegeneralsettings")] - public ActionResult SaveGeneralSettings(ShippingByWeightListModel model) - { - //save settings - _shippingByWeightSettings.LimitMethodsToCreated = model.LimitMethodsToCreated; - _shippingByWeightSettings.CalculatePerWeightUnit = model.CalculatePerWeightUnit; - _settingService.SaveSetting(_shippingByWeightSettings); - - return Configure(); - } - - } -} diff --git a/src/Plugins/Shipping.ByWeight/Data/Migrations/Configuration.cs b/src/Plugins/Shipping.ByWeight/Data/Migrations/Configuration.cs deleted file mode 100644 index 40a22ed650..0000000000 --- a/src/Plugins/Shipping.ByWeight/Data/Migrations/Configuration.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace SmartStore.Plugin.Shipping.ByWeight.Data.Migrations -{ - using System; - using System.Data.Entity; - using System.Data.Entity.Migrations; - using System.Linq; - - internal sealed class Configuration : DbMigrationsConfiguration - { - public Configuration() - { - AutomaticMigrationsEnabled = false; - MigrationsDirectory = @"Data\Migrations"; - ContextKey = "SmartStore.ShippingByWeight"; - } - - protected override void Seed(ShippingByWeightObjectContext context) - { - // This method will be called after migrating to the latest version. - - // You can use the DbSet.AddOrUpdate() helper extension method - // to avoid creating duplicate seed data. E.g. - // - // context.People.AddOrUpdate( - // p => p.FullName, - // new Person { FullName = "Andrew Peters" }, - // new Person { FullName = "Brice Lambson" }, - // new Person { FullName = "Rowan Miller" } - // ); - // - } - } -} diff --git a/src/Plugins/Shipping.ByWeight/Data/ShippingByWeightRecordMap.cs b/src/Plugins/Shipping.ByWeight/Data/ShippingByWeightRecordMap.cs deleted file mode 100644 index bce3700669..0000000000 --- a/src/Plugins/Shipping.ByWeight/Data/ShippingByWeightRecordMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Data.Entity.ModelConfiguration; -using SmartStore.Plugin.Shipping.ByWeight.Domain; - -namespace SmartStore.Plugin.Shipping.ByWeight.Data -{ - public partial class ShippingByWeightRecordMap : EntityTypeConfiguration - { - public ShippingByWeightRecordMap() - { - this.ToTable("ShippingByWeight"); - this.HasKey(x => x.Id); - } - } -} \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/DependencyRegistrar.cs b/src/Plugins/Shipping.ByWeight/DependencyRegistrar.cs deleted file mode 100644 index 94a7086083..0000000000 --- a/src/Plugins/Shipping.ByWeight/DependencyRegistrar.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Autofac; -using Autofac.Core; -using Autofac.Integration.Mvc; -using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Data; -using SmartStore.Plugin.Shipping.ByWeight.Data; -using SmartStore.Plugin.Shipping.ByWeight.Domain; -using SmartStore.Plugin.Shipping.ByWeight.Services; - -namespace SmartStore.Plugin.Shipping.ByWeight -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - - // data layer - // register named context - builder.Register(c => new ShippingByWeightObjectContext(DataSettings.Current.DataConnectionString)) - .Named(ShippingByWeightObjectContext.ALIASKEY) - .InstancePerRequest(); - - builder.Register(c => new ShippingByWeightObjectContext(DataSettings.Current.DataConnectionString)) - .InstancePerRequest(); - - // override required repository with our custom context - builder.RegisterType>() - .As>() - .WithParameter(ResolvedParameter.ForNamed(ShippingByWeightObjectContext.ALIASKEY)) - .InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/Shipping.ByWeight/Description.txt b/src/Plugins/Shipping.ByWeight/Description.txt deleted file mode 100644 index d5fcfef3d7..0000000000 --- a/src/Plugins/Shipping.ByWeight/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Shipping by weight -SystemName: Shipping.ByWeight -Version: 1.61 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Shipping.ByWeight.dll -ResourceRootKey: Plugins.Shipping.ByWeight \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Localization/resources.de-de.xml b/src/Plugins/Shipping.ByWeight/Localization/resources.de-de.xml deleted file mode 100644 index 21cd8af322..0000000000 --- a/src/Plugins/Shipping.ByWeight/Localization/resources.de-de.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - Versand nach Gewicht - - - Land - - - Das Bestimmungsland. Wählen Sie Stern (*), wenn das Land des Kunden bei der Auswertung keine Rolle spielen soll. - - - Versandart - - - Die Versandart, bei der diese Berechnungsmethode angewandt werden soll. - - - Warengewicht von - - - Die Bedingung trifft zu, wenn das Gesamtgewicht aller Positionen im Warenkorb mind. diesen Wert aufweist. - - - Warengewicht bis - - - Die Bedingung trifft zu, wenn das Gesamtgewicht aller Positionen im Warenkorb kleiner als dieser Wert ist. Lassen Sie das Feld leer, wenn Sie keine Obergrenze festlegen möchten. - - - Prozentual - - - Legt fest, ob die Versandgebühr prozentual vom Warenwert (NICHT Gewicht) berechnet werden soll. - - - Gebühr % - - - Prozentsatz für die Gebühr auf den Warenwert. - - - Gebühr - - - Die Versandgebühr als absoluter Betrag ODER Berechnungsfaktor, sofern die entspr. Option aktiviert wurde. - - - Kein 'Fallback' anbieten - - - Dem Kunden wird während des Checkouts kostenloser Versand als Fallback angeboten, wenn keine der festgelegten Bedingungen zutreffen. Aktivieren Sie diese Option, wenn das nicht gewünscht ist. - - - Gebühr mit Gewicht multiplizieren - - - Legt fest, ob die Gebühr mit dem Gesamt-Warengewicht multipliziert werden soll. Diese Option wird ignoriert, wenn eine prozentuale Gebühr erhoben wird. - - - Shop - - - Wird das Sternchen ausgewählt, so wird die Rate auf alle Shops angewandt. - - - Mindermengenzuschlag - - - Bestimmt den Wert des Mindermengenzuschlags. - - - Mindermenge bis Bestellwert - - - Warenwert, bis zu dem ein Mindermengenzuschlag erhoben werden soll. Der Zuschlag wird ignoriert, wenn keine Versandkosten anfallen. Verwenden Sie "0", wenn kein Zuschlag erhoben werden soll. - - - Es wird ein Mindermengenzuschlag von {0} erhoben, da Ihr Bestellwert unter {1} liegt.]]> - - - - Neue Versandbedingung hinzufügen - - - Optionen - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Localization/resources.en-us.xml b/src/Plugins/Shipping.ByWeight/Localization/resources.en-us.xml deleted file mode 100644 index c37cce8305..0000000000 --- a/src/Plugins/Shipping.ByWeight/Localization/resources.en-us.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - Shipping by weight - - - Country - - - If an asterisk is selected, then this shipping rate will apply to all customers, regardless of the country. - - - Shipping method - - - The shipping method. - - - Order weight from - - - Order weight from. - - - Order weight to - - - Order weight to. - - - Use percentage - - - Check to use 'charge percentage' value. - - - Charge percentage (of subtotal) - - - Charge percentage (of subtotal). - - - Charge amount - - - Charge amount. - - - Limit shipping methods to configured ones - - - If you check this option, then your customers will be limited to shipping options configured here. Otherwise, they'll be able to choose any existing shipping options even they've not configured here (zero shipping fee in this case). - - - Calculate per weight unit - - - If you check this option, then rates are multiplied per weight unit (lb, kg, etc). This option is used for the fixed rates (without percents). - - - Store - - - If an asterisk is selected, then this shipping rate will apply to all stores. - - - - Surcharge for small quantities - - - Determines the value of the small quantity surcharge. - - - Threshold for small quantities - - - Subtotal up to which a "small quantity surcharge" should be added. The surcharge will be ignored if no shipping fee is applied. Use "0" if no fee will be charged. - - - - You're charged with a surcharge of {0} because the total of your order hasn't reached {1}.]]> - - - - - Add new record - - - Settings - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Notes.txt b/src/Plugins/Shipping.ByWeight/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Shipping.ByWeight/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Properties/AssemblyInfo.cs b/src/Plugins/Shipping.ByWeight/Properties/AssemblyInfo.cs deleted file mode 100644 index 610ed897e5..0000000000 --- a/src/Plugins/Shipping.ByWeight/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Shipping.ByWeight")] diff --git a/src/Plugins/Shipping.ByWeight/RouteProvider.cs b/src/Plugins/Shipping.ByWeight/RouteProvider.cs deleted file mode 100644 index d3f3690465..0000000000 --- a/src/Plugins/Shipping.ByWeight/RouteProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Shipping.ByWeight -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Shipping.ByWeight.Configure", - "Plugins/ShippingByWeight/Configure", - new { controller = "ShippingByWeight", action = "Configure" }, - new[] { "SmartStore.Plugin.Shipping.ByWeight.Controllers" } - ) - .DataTokens["area"] = "Shipping.ByWeight"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Shipping.ByWeight/SmartStore.Plugin.Shipping.ByWeight.csproj b/src/Plugins/Shipping.ByWeight/SmartStore.Plugin.Shipping.ByWeight.csproj deleted file mode 100644 index ba0f865576..0000000000 --- a/src/Plugins/Shipping.ByWeight/SmartStore.Plugin.Shipping.ByWeight.csproj +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {0793FB50-67BB-461E-B961-2F45887464CF} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Shipping.ByWeight - SmartStore.Plugin.Shipping.ByWeight - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Shipping.ByWeight\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Shipping.ByWeight\ - TRACE - prompt - 4 - false - - - true - ..\..\Presentation\SmartStore.Web\bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - False - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - False - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll - False - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - False - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - False - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - False - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - False - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - False - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - False - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - False - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - False - - - - - - - - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll - False - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - 201403080200108_Initial.cs - - - - 201406041606037_SmallQuantitySurcharge.cs - - - - - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} - SmartStore.Data - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - 201403080200108_Initial.cs - - - 201406041606037_SmallQuantitySurcharge.cs - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - Designer - - - Designer - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Views/ShippingByWeight/Configure.cshtml b/src/Plugins/Shipping.ByWeight/Views/ShippingByWeight/Configure.cshtml deleted file mode 100644 index c31eac7049..0000000000 --- a/src/Plugins/Shipping.ByWeight/Views/ShippingByWeight/Configure.cshtml +++ /dev/null @@ -1,221 +0,0 @@ -@{ - Layout = ""; -} -@model ShippingByWeightListModel -@using SmartStore.Plugin.Shipping.ByWeight.Models; -@using SmartStore.Web.Framework; -@using Telerik.Web.Mvc.UI; -@using System.Linq; - - - - - -
    - @(Html.Telerik().Grid() - .Name("Grid") - .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) - .Columns(columns => - { - columns.Bound(x => x.StoreName).ReadOnly(); - columns.Bound(x => x.CountryName).Width(200).ReadOnly(); - columns.Bound(x => x.ShippingMethodName).Width(200).ReadOnly(); - columns.Bound(x => x.From).Width(100); - columns.Bound(x => x.To).Width(100); - columns.Bound(x => x.UsePercentage) - .Centered() - .Template(item => @Html.SymbolForBool(item.UsePercentage)) - .ClientTemplate(@Html.SymbolForBool("UsePercentage")); - columns.Bound(x => x.ShippingChargePercentage).Width(100); - columns.Bound(x => x.ShippingChargeAmount).Width(100); - columns.Bound(x => x.SmallQuantitySurcharge).Width(100); - columns.Bound(x => x.SmallQuantityThreshold).Width(100); - columns.Command(commands => - { - commands.Edit(); - commands.Delete(); - }).Width(180); - - }) - .Editable(x => - { - x.Mode(GridEditMode.InLine); - }) - .DataBinding(dataBinding => - { - dataBinding.Ajax() - .Select("RatesList", "ShippingByWeight", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByWeight.Controllers" }, { "area", "" } }) - .Update("RateUpdate", "ShippingByWeight", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByWeight.Controllers" }, { "area", "" } }) - .Delete("RateDelete", "ShippingByWeight", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByWeight.Controllers" }, { "area", "" } }); - }) - .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) - .EnableCustomBinding(true)) -
    -

    - -@using (Html.BeginForm()) -{ - - - -
    - @T("Plugins.Shipping.ByWeight.AddNewRecordTitle") - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.AddStoreId) - - @Html.DropDownListFor(model => model.AddStoreId, Model.AvailableStores) - @Html.ValidationMessageFor(model => model.AddStoreId) -
    - @Html.SmartLabelFor(model => model.AddCountryId) - - @Html.DropDownListFor(model => model.AddCountryId, Model.AvailableCountries) - @Html.ValidationMessageFor(model => model.AddCountryId) -
    - @Html.SmartLabelFor(model => model.AddShippingMethodId) - - @Html.DropDownListFor(model => model.AddShippingMethodId, Model.AvailableShippingMethods) - @Html.ValidationMessageFor(model => model.AddShippingMethodId) -
    - @Html.SmartLabelFor(model => model.AddFrom) - - @Html.EditorFor(model => model.AddFrom) [@Model.BaseWeightIn] - @Html.ValidationMessageFor(model => model.AddFrom) -
    - @Html.SmartLabelFor(model => model.AddTo) - - @Html.EditorFor(model => model.AddTo) [@Model.BaseWeightIn] - @Html.ValidationMessageFor(model => model.AddTo) -
    - @Html.SmartLabelFor(model => model.AddUsePercentage) - - @Html.EditorFor(model => model.AddUsePercentage) - @Html.ValidationMessageFor(model => model.AddUsePercentage) -
    - @Html.SmartLabelFor(model => model.AddShippingChargePercentage) - - @Html.EditorFor(model => model.AddShippingChargePercentage) - @Html.ValidationMessageFor(model => model.AddShippingChargePercentage) -
    - @Html.SmartLabelFor(model => model.AddShippingChargeAmount) - - @Html.EditorFor(model => model.AddShippingChargeAmount) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.AddShippingChargeAmount) -
    - @Html.SmartLabelFor(model => model.SmallQuantitySurcharge) - - @Html.EditorFor(model => model.SmallQuantitySurcharge) [@Model.PrimaryStoreCurrencyCode] - @Html.ValidationMessageFor(model => model.SmallQuantitySurcharge) -
    - @Html.SmartLabelFor(model => model.SmallQuantityThreshold) - - @Html.EditorFor(model => model.SmallQuantityThreshold) - @Html.ValidationMessageFor(model => model.SmallQuantityThreshold) -
    -   - - -
    -
    - -
    - @T("Plugins.Shipping.ByWeight.SettingsTitle") - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.CalculatePerWeightUnit) - - @Html.EditorFor(model => model.CalculatePerWeightUnit) - @Html.ValidationMessageFor(model => model.CalculatePerWeightUnit) -
    - @Html.SmartLabelFor(model => model.LimitMethodsToCreated) - - @Html.EditorFor(model => model.LimitMethodsToCreated) - @Html.ValidationMessageFor(model => model.LimitMethodsToCreated) -
    -   - - -
    -
    -} \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Views/Web.config b/src/Plugins/Shipping.ByWeight/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Shipping.ByWeight/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Shipping.ByWeight/packages.config b/src/Plugins/Shipping.ByWeight/packages.config deleted file mode 100644 index 4263d0a15c..0000000000 --- a/src/Plugins/Shipping.ByWeight/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/web.config b/src/Plugins/Shipping.ByWeight/web.config deleted file mode 100644 index c7103a3dae..0000000000 --- a/src/Plugins/Shipping.ByWeight/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Shipping.FixedRate/Controllers/ShippingFixedRateController.cs b/src/Plugins/Shipping.FixedRate/Controllers/ShippingFixedRateController.cs deleted file mode 100644 index 49b8bfa14f..0000000000 --- a/src/Plugins/Shipping.FixedRate/Controllers/ShippingFixedRateController.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Web.Mvc; -using SmartStore.Plugin.Shipping.FixedRate.Models; -using SmartStore.Services.Configuration; -using SmartStore.Services.Shipping; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Controllers; -using Telerik.Web.Mvc; - -namespace SmartStore.Plugin.Shipping.FixedRate.Controllers -{ - - public class ShippingFixedRateController : PluginControllerBase - { - private readonly IShippingService _shippingService; - private readonly ISettingService _settingService; - - public ShippingFixedRateController(IShippingService shippingServicee, ISettingService settingService) - { - this._shippingService = shippingServicee; - this._settingService = settingService; - } - - public ActionResult Configure() - { - var shippingMethods = _shippingService.GetAllShippingMethods(); - if (shippingMethods.Count == 0) - return Content("No shipping methods can be loaded"); - - var tmp = new List(); - foreach (var shippingMethod in shippingMethods) - tmp.Add(new FixedShippingRateModel() - { - ShippingMethodId = shippingMethod.Id, - ShippingMethodName = shippingMethod.Name, - Rate = GetShippingRate(shippingMethod.Id) - }); - - var gridModel = new GridModel - { - Data = tmp, - Total = tmp.Count - }; - - return View(gridModel); - } - - [HttpPost, GridAction(EnableCustomBinding = true)] - public ActionResult Configure(GridCommand command) - { - var tmp = new List(); - foreach (var shippingMethod in _shippingService.GetAllShippingMethods()) - tmp.Add(new FixedShippingRateModel() - { - ShippingMethodId = shippingMethod.Id, - ShippingMethodName = shippingMethod.Name, - Rate = GetShippingRate(shippingMethod.Id) - }); - - var tmp2 = tmp.ForCommand(command); - var gridModel = new GridModel - { - Data = tmp2, - Total = tmp2.Count() - }; - return new JsonResult - { - Data = gridModel - }; - } - - [GridAction(EnableCustomBinding = true)] - public ActionResult ShippingRateUpdate(FixedShippingRateModel model, GridCommand command) - { - int shippingMethodId = model.ShippingMethodId; - decimal rate = model.Rate; - - if (shippingMethodId != 0) - { - _settingService.SetSetting(string.Format("ShippingRateComputationMethod.FixedRate.Rate.ShippingMethodId{0}", shippingMethodId), rate); - } - - var tmp = new List(); - foreach (var shippingMethod in _shippingService.GetAllShippingMethods()) - tmp.Add(new FixedShippingRateModel() - { - ShippingMethodId = shippingMethod.Id, - ShippingMethodName = shippingMethod.Name, - Rate = GetShippingRate(shippingMethod.Id) - }); - - var tmp2 = tmp.ForCommand(command); - var gridModel = new GridModel - { - Data = tmp2, - Total = tmp2.Count() - }; - return new JsonResult - { - Data = gridModel - }; - } - - [NonAction] - protected decimal GetShippingRate(int shippingMethodId) - { - decimal rate = this._settingService.GetSettingByKey(string.Format("ShippingRateComputationMethod.FixedRate.Rate.ShippingMethodId{0}", shippingMethodId)); - return rate; - } - } -} diff --git a/src/Plugins/Shipping.FixedRate/Description.txt b/src/Plugins/Shipping.FixedRate/Description.txt deleted file mode 100644 index 995c1fa76e..0000000000 --- a/src/Plugins/Shipping.FixedRate/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Fixed Rate Shipping -SystemName: Shipping.FixedRate -Version: 1.31 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Shipping.FixedRate.dll -ResourceRootKey: Plugins.Shipping.FixedRateShipping \ No newline at end of file diff --git a/src/Plugins/Shipping.FixedRate/FixedRateShippingComputationMethod.cs b/src/Plugins/Shipping.FixedRate/FixedRateShippingComputationMethod.cs deleted file mode 100644 index 9a7d6fe509..0000000000 --- a/src/Plugins/Shipping.FixedRate/FixedRateShippingComputationMethod.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Plugins; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Shipping; -using SmartStore.Services.Shipping.Tracking; - -namespace SmartStore.Plugin.Shipping.FixedRate -{ - /// - /// Fixed rate shipping computation method - /// - public class FixedRateShippingComputationMethod : BasePlugin, IShippingRateComputationMethod - { - #region Fields - - private readonly ISettingService _settingService; - private readonly IShippingService _shippingService; - private readonly ILocalizationService _localizationService; - - #endregion - - #region Ctor - public FixedRateShippingComputationMethod(ISettingService settingService, - IShippingService shippingService, ILocalizationService localizationService) - { - this._settingService = settingService; - this._shippingService = shippingService; - _localizationService = localizationService; - } - #endregion - - #region Utilities - - private decimal GetRate(int shippingMethodId) - { - string key = string.Format("ShippingRateComputationMethod.FixedRate.Rate.ShippingMethodId{0}", shippingMethodId); - decimal rate = this._settingService.GetSettingByKey(key); - return rate; - } - #endregion - - #region Methods - - /// - /// Gets available shipping options - /// - /// A request for getting shipping options - /// Represents a response of getting shipping rate options - public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) - { - if (getShippingOptionRequest == null) - throw new ArgumentNullException("getShippingOptionRequest"); - - var response = new GetShippingOptionResponse(); - - if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) - { - response.AddError("No shipment items"); - return response; - } - - int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; - var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId); - foreach (var shippingMethod in shippingMethods) - { - var shippingOption = new ShippingOption(); - shippingOption.Name = shippingMethod.GetLocalized(x => x.Name); - shippingOption.Description = shippingMethod.GetLocalized(x => x.Description); - shippingOption.Rate = GetRate(shippingMethod.Id); - response.ShippingOptions.Add(shippingOption); - } - - return response; - } - - /// - /// Gets fixed shipping rate (if shipping rate computation method allows it and the rate can be calculated before checkout). - /// - /// A request for getting shipping options - /// Fixed shipping rate; or null in case there's no fixed shipping rate - public decimal? GetFixedRate(GetShippingOptionRequest getShippingOptionRequest) - { - if (getShippingOptionRequest == null) - throw new ArgumentNullException("getShippingOptionRequest"); - - int? restrictByCountryId = (getShippingOptionRequest.ShippingAddress != null && getShippingOptionRequest.ShippingAddress.Country != null) ? (int?)getShippingOptionRequest.ShippingAddress.Country.Id : null; - var shippingMethods = this._shippingService.GetAllShippingMethods(restrictByCountryId); - - var rates = new List(); - foreach (var shippingMethod in shippingMethods) - { - decimal rate = GetRate(shippingMethod.Id); - if (!rates.Contains(rate)) - rates.Add(rate); - } - - //return default rate if all of them equal - if (rates.Count == 1) - return rates[0]; - - return null; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "ShippingFixedRate"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.FixedRate.Controllers" }, { "area", "Shipping.FixedRate" } }; - } - - /// - /// Install plugin - /// - public override void Install() - { - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Shipping.FixedRateShipping", false); - - base.Uninstall(); - } - - #endregion - - #region Properties - - /// - /// Gets a shipping rate computation method type - /// - public ShippingRateComputationMethodType ShippingRateComputationMethodType - { - get - { - return ShippingRateComputationMethodType.Offline; - } - } - - /// - /// Gets a shipment tracker - /// - public IShipmentTracker ShipmentTracker - { - get - { - //uncomment a line below to return a general shipment tracker (finds an appropriate tracker by tracking number) - //return new GeneralShipmentTracker(EngineContext.Current.Resolve()); - return null; - } - } - - #endregion - } -} diff --git a/src/Plugins/Shipping.FixedRate/Localization/resources.de-de.xml b/src/Plugins/Shipping.FixedRate/Localization/resources.de-de.xml deleted file mode 100644 index ce24e8ca94..0000000000 --- a/src/Plugins/Shipping.FixedRate/Localization/resources.de-de.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Versand zum Festpreis - - - Name der Versandart - - - Gebühr - - \ No newline at end of file diff --git a/src/Plugins/Shipping.FixedRate/Localization/resources.en-us.xml b/src/Plugins/Shipping.FixedRate/Localization/resources.en-us.xml deleted file mode 100644 index 9f7ec2d875..0000000000 --- a/src/Plugins/Shipping.FixedRate/Localization/resources.en-us.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Fixed rate shipping - - - Shipping method name - - - Rate - - \ No newline at end of file diff --git a/src/Plugins/Shipping.FixedRate/Models/FixedShippingRateModel.cs b/src/Plugins/Shipping.FixedRate/Models/FixedShippingRateModel.cs deleted file mode 100644 index 470015d313..0000000000 --- a/src/Plugins/Shipping.FixedRate/Models/FixedShippingRateModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using SmartStore.Web.Framework; - -namespace SmartStore.Plugin.Shipping.FixedRate.Models -{ - public class FixedShippingRateModel - { - public int ShippingMethodId { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.FixedRateShipping.Fields.ShippingMethodName")] - public string ShippingMethodName { get; set; } - - [SmartResourceDisplayName("Plugins.Shipping.FixedRateShipping.Fields.Rate")] - public decimal Rate { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Shipping.FixedRate/Notes.txt b/src/Plugins/Shipping.FixedRate/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Shipping.FixedRate/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Shipping.FixedRate/Properties/AssemblyInfo.cs b/src/Plugins/Shipping.FixedRate/Properties/AssemblyInfo.cs deleted file mode 100644 index 1a308e2804..0000000000 --- a/src/Plugins/Shipping.FixedRate/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Shipping.FixedRateShipping")] diff --git a/src/Plugins/Shipping.FixedRate/RouteProvider.cs b/src/Plugins/Shipping.FixedRate/RouteProvider.cs deleted file mode 100644 index 88cb9dd72b..0000000000 --- a/src/Plugins/Shipping.FixedRate/RouteProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Shipping.FixedRate -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Shipping.FixedRate.Action", - "Plugins/ShippingFixedRate/{action}", - new { controller = "ShippingFixedRate" }, - new[] { "SmartStore.Plugin.Shipping.FixedRate.Controllers" } - ) - .DataTokens["area"] = "Shipping.FixedRate"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Shipping.FixedRate/SmartStore.Plugin.Shipping.FixedRate.csproj b/src/Plugins/Shipping.FixedRate/SmartStore.Plugin.Shipping.FixedRate.csproj deleted file mode 100644 index f3b8f07fe2..0000000000 --- a/src/Plugins/Shipping.FixedRate/SmartStore.Plugin.Shipping.FixedRate.csproj +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {2DCB7949-24C2-49C7-872C-C948E43717E7} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Shipping.FixedRate - SmartStore.Plugin.Shipping.FixedRate - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Shipping.FixedRate\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Shipping.FixedRate\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Shipping.FixedRate/Views/ShippingFixedRate/Configure.cshtml b/src/Plugins/Shipping.FixedRate/Views/ShippingFixedRate/Configure.cshtml deleted file mode 100644 index 007c717613..0000000000 --- a/src/Plugins/Shipping.FixedRate/Views/ShippingFixedRate/Configure.cshtml +++ /dev/null @@ -1,37 +0,0 @@ -@{ - Layout = ""; -} -@model Telerik.Web.Mvc.GridModel -@using Telerik.Web.Mvc.UI; -@using System.Linq; - - - - - -
    - @(Html.Telerik().Grid(Model.Data) - .Name("Grid") - .DataKeys(keys => keys.Add(x => x.ShippingMethodId).RouteKey("ShippingMethodId")) - .Columns(columns => - { - columns.Bound(x => x.ShippingMethodName).Width(500).ReadOnly(); - columns.Bound(x => x.Rate).Width(180); - columns.Command(commands => - { - commands.Edit(); - }); - - }) - .Editable(x => - { - x.Mode(GridEditMode.InLine); - }) - .DataBinding(dataBinding => - { - dataBinding.Ajax() - .Select("Configure", "ShippingFixedRate", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.FixedRate.Controllers" }, { "area", "Shipping.FixedRate" } }) - .Update("ShippingRateUpdate", "ShippingFixedRate", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.FixedRate.Controllers" }, { "area", "Shipping.FixedRate" } }); - }) - .EnableCustomBinding(true)) -
    diff --git a/src/Plugins/Shipping.FixedRate/Views/Web.config b/src/Plugins/Shipping.FixedRate/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Shipping.FixedRate/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Shipping.FixedRate/packages.config b/src/Plugins/Shipping.FixedRate/packages.config deleted file mode 100644 index b06b17d7d3..0000000000 --- a/src/Plugins/Shipping.FixedRate/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Shipping.FixedRate/web.config b/src/Plugins/Shipping.FixedRate/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Shipping.FixedRate/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/SmartStore.AmazonPay/Content/branding.gif b/src/Plugins/SmartStore.AmazonPay/Content/branding.gif new file mode 100644 index 0000000000..bc6f68849f Binary files /dev/null and b/src/Plugins/SmartStore.AmazonPay/Content/branding.gif differ diff --git a/src/Plugins/SmartStore.AmazonPay/Content/icon.png b/src/Plugins/SmartStore.AmazonPay/Content/icon.png new file mode 100644 index 0000000000..9017ca228c Binary files /dev/null and b/src/Plugins/SmartStore.AmazonPay/Content/icon.png differ diff --git a/src/Plugins/SmartStore.AmazonPay/Content/images/favicon.png b/src/Plugins/SmartStore.AmazonPay/Content/images/favicon.png new file mode 100644 index 0000000000..fc2a3c7b62 Binary files /dev/null and b/src/Plugins/SmartStore.AmazonPay/Content/images/favicon.png differ diff --git a/src/Plugins/SmartStore.AmazonPay/Content/images/logo.gif b/src/Plugins/SmartStore.AmazonPay/Content/images/logo.gif new file mode 100644 index 0000000000..bc6f68849f Binary files /dev/null and b/src/Plugins/SmartStore.AmazonPay/Content/images/logo.gif differ diff --git a/src/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css b/src/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css new file mode 100644 index 0000000000..2920ce6f7f --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css @@ -0,0 +1,14 @@ +.config-logo { + width: 339px; + height: 74px; +} + +.amazon-pay-button .selection-text { + text-align: right; + font-weight: bold; + padding: 12px 15px 5px 0; +} + +.amazon-pay-button .button-container { + text-align: right; +} diff --git a/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayCheckoutController.cs b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayCheckoutController.cs new file mode 100644 index 0000000000..4a76ef8295 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayCheckoutController.cs @@ -0,0 +1,47 @@ +using System.Web.Mvc; +using SmartStore.AmazonPay.Services; + +namespace SmartStore.AmazonPay.Controllers +{ + public class AmazonPayCheckoutController : AmazonPayControllerBase + { + private readonly IAmazonPayService _apiService; + + public AmazonPayCheckoutController(IAmazonPayService apiService) + { + _apiService = apiService; + } + + public ActionResult BillingAddress() + { + return RedirectToAction("ShippingAddress", "Checkout", new { area = "" }); + } + + public ActionResult ShippingAddress() + { + var model = _apiService.ProcessPluginRequest(AmazonPayRequestType.Address, TempData); + + return GetActionResult(model); + } + + public ActionResult PaymentMethod() + { + var model = _apiService.ProcessPluginRequest(AmazonPayRequestType.Payment, TempData); + + return GetActionResult(model); + } + + [HttpPost] + public ActionResult PaymentMethod(bool? UseRewardPoints) + { + _apiService.ApplyRewardPoints(UseRewardPoints ?? false); + + return RedirectToAction("Confirm", "Checkout", new { area = "" }); + } + + public ActionResult PaymentInfo() + { + return RedirectToAction("PaymentMethod", "Checkout", new { area = "" }); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayController.cs b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayController.cs new file mode 100644 index 0000000000..25badf2f48 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayController.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.AmazonPay.Models; +using SmartStore.AmazonPay.Services; +using SmartStore.AmazonPay.Settings; +using SmartStore.Services; +using SmartStore.Services.Payments; +using SmartStore.Services.Stores; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.AmazonPay.Controllers +{ + public class AmazonPayController : PaymentControllerBase + { + private readonly IAmazonPayService _apiService; + private readonly ICommonServices _services; + private readonly IStoreService _storeService; + + public AmazonPayController( + IAmazonPayService apiService, + ICommonServices services, + IStoreService storeService) + { + _apiService = apiService; + _services = services; + _storeService = storeService; + } + + [NonAction] + public override IList ValidatePaymentForm(FormCollection form) + { + var warnings = new List(); + return warnings; + } + + [NonAction] + public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) + { + var paymentInfo = new ProcessPaymentRequest(); + return paymentInfo; + } + + [AdminAuthorize] + public ActionResult Configure() + { + var model = new ConfigurationModel(); + int storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + model.Copy(settings, true); + + _apiService.SetupConfiguration(model); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, _services.Settings); + + return View(model); + } + + [HttpPost, AdminAuthorize] + public ActionResult Configure(ConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return Configure(); + + ModelState.Clear(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + int storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + model.Copy(settings, false); + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, _services.Settings); + + _services.Settings.SaveSetting(settings, x => x.DataFetching, 0, false); + _services.Settings.SaveSetting(settings, x => x.PollingMaxOrderCreationDays, 0, false); + + _apiService.DataPollingTaskUpdate(settings.DataFetching == AmazonPayDataFetchingType.Polling, model.PollingTaskMinutes * 60); + + _services.Settings.ClearCache(); + NotifySuccess(_services.Localization.GetResource("Plugins.Payments.AmazonPay.ConfigSaveNote")); + + return Configure(); + } + + [HttpPost] + [ValidateInput(false)] + [RequireHttpsByConfigAttribute(SslRequirement.Yes)] + public ActionResult IPNHandler() + { + _apiService.ProcessIpn(Request); + return Content("OK"); + } + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayControllerBase.cs b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayControllerBase.cs new file mode 100644 index 0000000000..b9f4858333 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayControllerBase.cs @@ -0,0 +1,29 @@ +using System.Web.Mvc; +using SmartStore.AmazonPay.Models; +using SmartStore.AmazonPay.Services; +using SmartStore.Web.Framework.Controllers; + +namespace SmartStore.AmazonPay.Controllers +{ + public abstract partial class AmazonPayControllerBase : PublicControllerBase + { + protected ActionResult GetActionResult(AmazonPayViewModel model) + { + switch (model.Result) + { + case AmazonPayResultType.None: + return new EmptyResult(); + + case AmazonPayResultType.PluginView: + return View(model); + + case AmazonPayResultType.Unauthorized: + return new HttpUnauthorizedResult(); + + case AmazonPayResultType.Redirect: + default: + return RedirectToAction(model.RedirectAction, model.RedirectController, new { area = "" }); + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayShoppingCartController.cs b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayShoppingCartController.cs new file mode 100644 index 0000000000..ef5a8c90d9 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Controllers/AmazonPayShoppingCartController.cs @@ -0,0 +1,71 @@ +using System.Web.Mvc; +using SmartStore.AmazonPay.Services; + +namespace SmartStore.AmazonPay.Controllers +{ + public class AmazonPayShoppingCartController : AmazonPayControllerBase + { + private readonly IAmazonPayService _apiService; + + public AmazonPayShoppingCartController(IAmazonPayService apiService) + { + _apiService = apiService; + } + + public ActionResult LoginHandler(string orderReferenceId) + { + var model = _apiService.ProcessPluginRequest(AmazonPayRequestType.LoginHandler, TempData, orderReferenceId); + + return GetActionResult(model); + } + + [ChildActionOnly] + public ActionResult ShoppingCart() + { + if (ControllerContext.ParentActionViewContext.RequestContext.RouteData.IsRouteEqual("ShoppingCart", "Cart")) + { + var model = _apiService.ProcessPluginRequest(AmazonPayRequestType.ShoppingCart, TempData); + + return GetActionResult(model); + } + return new EmptyResult(); + } + + [ChildActionOnly] + public ActionResult OrderReviewData(bool renderAmazonPayView) + { + if (renderAmazonPayView) + { + var model = _apiService.ProcessPluginRequest(AmazonPayRequestType.OrderReviewData, TempData); + + return View(model); + } + return new EmptyResult(); + } + + [ChildActionOnly] + public ActionResult MiniShoppingCart(bool renderAmazonPayView) + { + if (renderAmazonPayView) + { + var model = _apiService.ProcessPluginRequest(AmazonPayRequestType.MiniShoppingCart, TempData); + + return GetActionResult(model); + } + return new EmptyResult(); + } + + [ChildActionOnly] + public ActionResult WidgetLibrary() + { + // not possible to load it asynchronously cause of document.write inside + string widgetUrl = _apiService.GetWidgetUrl(); + + if (widgetUrl.HasValue()) + { + return this.Content("".FormatWith(widgetUrl)); + } + return new EmptyResult(); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/DependencyRegistrar.cs b/src/Plugins/SmartStore.AmazonPay/DependencyRegistrar.cs new file mode 100644 index 0000000000..a8a2263ede --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/DependencyRegistrar.cs @@ -0,0 +1,31 @@ +using Autofac; +using Autofac.Integration.Mvc; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.Core.Plugins; +using SmartStore.AmazonPay.Api; +using SmartStore.AmazonPay.Filters; +using SmartStore.AmazonPay.Services; +using SmartStore.Web.Controllers; + +namespace SmartStore.AmazonPay +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + + if (isActiveModule) + { + builder.RegisterType().AsActionFilterFor().InstancePerRequest(); + } + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Description.txt b/src/Plugins/SmartStore.AmazonPay/Description.txt new file mode 100644 index 0000000000..8237c4a7ad --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Description.txt @@ -0,0 +1,10 @@ +FriendlyName: Pay with Amazon +SystemName: SmartStore.AmazonPay +Version: 2.6.0 +Group: Payment +MinAppVersion: 2.5.0 +Author: SmartStore AG +DisplayOrder: 1 +FileName: SmartStore.AmazonPay.dll +ResourceRootKey: Plugins.Payments.AmazonPay +Url: http://community.smartstore.com/marketplace/file/11-amazon-payments-plugin/ \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Events/MessageTokenEventConsumer.cs b/src/Plugins/SmartStore.AmazonPay/Events/MessageTokenEventConsumer.cs new file mode 100644 index 0000000000..78f10c09e2 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Events/MessageTokenEventConsumer.cs @@ -0,0 +1,47 @@ +using System.Linq; +using SmartStore.AmazonPay.Services; +using SmartStore.Core.Domain.Messages; +using SmartStore.Core.Events; +using SmartStore.Core.Plugins; +using SmartStore.Services; +using SmartStore.Services.Messages; +using SmartStore.Services.Orders; +using SmartStore.Web.Framework; + +namespace SmartStore.AmazonPay.Events +{ + public class MessageTokenEventConsumer : IConsumer> + { + private readonly IPluginFinder _pluginFinder; + private readonly ICommonServices _services; + private readonly IOrderService _orderService; + + public MessageTokenEventConsumer( + IPluginFinder pluginFinder, + ICommonServices services, + IOrderService orderService) + { + _pluginFinder = pluginFinder; + _services = services; + _orderService = orderService; + } + + public void HandleEvent(MessageTokensAddedEvent messageTokenEvent) + { + if (!messageTokenEvent.Message.Name.IsCaseInsensitiveEqual("OrderPlaced.CustomerNotification")) + return; + + var storeId = _services.StoreContext.CurrentStore.Id; + + if (!_pluginFinder.IsPluginReady(_services.Settings, AmazonPayCore.SystemName, storeId)) + return; + + var order = _orderService.SearchOrders(storeId, _services.WorkContext.CurrentCustomer.Id, null, null, null, null, null, null, null, null, 0, 1).FirstOrDefault(); + + var isAmazonPayment = (order != null && order.PaymentMethodSystemName.IsCaseInsensitiveEqual(AmazonPayCore.SystemName)); + var tokenValue = (isAmazonPayment ? _services.Localization.GetResource("Plugins.Payments.AmazonPay.BillingAddressMessageNote") : ""); + + messageTokenEvent.Tokens.Add(new Token("SmartStore.AmazonPay.BillingAddressMessageNote", tokenValue)); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Extensions/AmazonPayApiExtensions.cs b/src/Plugins/SmartStore.AmazonPay/Extensions/AmazonPayApiExtensions.cs new file mode 100644 index 0000000000..8d1c2e6f08 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Extensions/AmazonPayApiExtensions.cs @@ -0,0 +1,223 @@ +using System; +using System.Linq; +using System.Text; +using OffAmazonPaymentsService; +using OffAmazonPaymentsService.Model; +using SmartStore.AmazonPay.Extensions; +using SmartStore.AmazonPay.Services; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Orders; +using SmartStore.Services.Directory; +using SmartStore.Services.Localization; + +namespace SmartStore.AmazonPay.Api +{ + public static class AmazonPayApiExtensions + { + public static bool GetErrorStrings(this OffAmazonPaymentsServiceException exception, out string shortMessage, out string fullMessage) + { + shortMessage = fullMessage = null; + + try + { + + if (exception.Message.HasValue()) + { + shortMessage = exception.Message; + var sb = new StringBuilder(); + + sb.AppendLine("Caught Exception: " + exception.Message); + sb.AppendLine("Response Status Code: " + exception.StatusCode); + sb.AppendLine("Error Code: " + exception.ErrorCode); + sb.AppendLine("Error Type: " + exception.ErrorType); + sb.AppendLine("Request ID: " + exception.RequestId); + sb.AppendLine("XML: " + exception.XML); + + if (exception.ResponseHeaderMetadata != null) + sb.AppendLine("ResponseHeaderMetadata: " + exception.ResponseHeaderMetadata.ToString()); + + fullMessage = sb.ToString(); + } + } + catch (Exception) { } + + return shortMessage.HasValue(); + } + + public static string ToFormatedAddress(this Address amazonAddress, ICountryService countryService, IStateProvinceService stateProvinceService) + { + var sb = new StringBuilder(); + + try + { + var city = (amazonAddress.IsSetCity() ? amazonAddress.City : null); + var zip = (amazonAddress.IsSetPostalCode() ? amazonAddress.PostalCode : null); + + sb.AppendLine(""); + + if (amazonAddress.Name.HasValue()) + sb.AppendLine(amazonAddress.Name); + + if (amazonAddress.AddressLine1.HasValue()) + sb.AppendLine(amazonAddress.AddressLine1); + + if (amazonAddress.AddressLine2.HasValue()) + sb.AppendLine(amazonAddress.AddressLine2); + + if (amazonAddress.AddressLine3.HasValue()) + sb.AppendLine(amazonAddress.AddressLine3); + + sb.AppendLine(zip.Grow(city, " ")); + + if (amazonAddress.IsSetStateOrRegion()) + { + var stateProvince = stateProvinceService.GetStateProvinceByAbbreviation(amazonAddress.StateOrRegion); + + if (stateProvince == null) + sb.AppendLine(amazonAddress.StateOrRegion); + else + sb.AppendLine("{0} {1}".FormatWith(amazonAddress.StateOrRegion, stateProvince.GetLocalized(x => x.Name))); + } + + if (amazonAddress.IsSetCountryCode()) + { + var country = countryService.GetCountryByTwoOrThreeLetterIsoCode(amazonAddress.CountryCode); + + if (country == null) + sb.AppendLine(amazonAddress.CountryCode); + else + sb.AppendLine("{0} {1}".FormatWith(amazonAddress.CountryCode, country.GetLocalized(x => x.Name))); + } + + if (amazonAddress.Phone.HasValue()) + { + sb.AppendLine(amazonAddress.Phone); + } + } + catch (Exception exc) + { + exc.Dump(); + } + + return sb.ToString(); + } + + public static void ToAddress(this Address amazonAddress, SmartStore.Core.Domain.Common.Address address, ICountryService countryService, + IStateProvinceService stateProvinceService, out bool countryAllowsShipping, out bool countryAllowsBilling) + { + countryAllowsShipping = countryAllowsBilling = true; + + if (amazonAddress.IsSetName()) + { + address.ToFirstAndLastName(amazonAddress.Name); + } + + if (amazonAddress.IsSetAddressLine1()) + { + address.Address1 = amazonAddress.AddressLine1.TrimSafe().Truncate(4000); + } + + if (amazonAddress.IsSetAddressLine2()) + { + address.Address2 = amazonAddress.AddressLine2.TrimSafe().Truncate(4000); + } + + if (amazonAddress.IsSetAddressLine3()) + { + address.Address2 = address.Address2.Grow(amazonAddress.AddressLine3.TrimSafe(), ", ").Truncate(4000); + } + + // normalize + if (address.Address1.IsEmpty() && address.Address2.HasValue()) + { + address.Address1 = address.Address2; + address.Address2 = null; + } + else if (address.Address1.HasValue() && address.Address1 == address.Address2) + { + address.Address2 = null; + } + + if (amazonAddress.IsSetCity()) + { + address.City = amazonAddress.City.TrimSafe().Truncate(4000); + } + + if (amazonAddress.IsSetPostalCode()) + { + address.ZipPostalCode = amazonAddress.PostalCode.TrimSafe().Truncate(4000); + } + + if (amazonAddress.IsSetPhone()) + { + address.PhoneNumber = amazonAddress.Phone.TrimSafe().Truncate(4000); + } + + if (amazonAddress.IsSetCountryCode()) + { + var country = countryService.GetCountryByTwoOrThreeLetterIsoCode(amazonAddress.CountryCode); + + if (country != null) + { + address.CountryId = country.Id; + countryAllowsShipping = country.AllowsShipping; + countryAllowsBilling = country.AllowsBilling; + } + } + + if (amazonAddress.IsSetStateOrRegion()) + { + var stateProvince = stateProvinceService.GetStateProvinceByAbbreviation(amazonAddress.StateOrRegion); + + if (stateProvince != null) + address.StateProvinceId = stateProvince.Id; + } + + //amazonAddress.District, amazonAddress.County ?? + + if (address.CountryId == 0) + address.CountryId = null; + + if (address.StateProvinceId == 0) + address.StateProvinceId = null; + } + + public static void ToAddress(this OrderReferenceDetails details, SmartStore.Core.Domain.Common.Address address, ICountryService countryService, + IStateProvinceService stateProvinceService, out bool countryAllowsShipping, out bool countryAllowsBilling) + { + countryAllowsShipping = countryAllowsBilling = true; + + if (details.IsSetBuyer() && details.Buyer.IsSetEmail()) + { + address.Email = details.Buyer.Email; + } + + if (details.IsSetDestination() && details.Destination.IsSetPhysicalDestination()) + { + details.Destination.PhysicalDestination.ToAddress(address, countryService, stateProvinceService, out countryAllowsShipping, out countryAllowsBilling); + } + } + + public static Order GetOrderByAmazonId(this IRepository orderRepository, string amazonId) + { + // S02-9777218-8608106 OrderReferenceId + // S02-9777218-8608106-A088344 Auth ID + // S02-9777218-8608106-C088344 Capture ID + + if (amazonId.HasValue()) + { + string amazonOrderReferenceId = amazonId.Substring(0, amazonId.LastIndexOf('-')); + if (amazonOrderReferenceId.HasValue()) + { + var orders = orderRepository.Table + .Where(x => x.PaymentMethodSystemName == AmazonPayCore.SystemName && x.AuthorizationTransactionId.StartsWith(amazonOrderReferenceId)) + .ToList(); + + if (orders.Count() == 1) + return orders.FirstOrDefault(); + } + } + return null; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Extensions/MiscExtensions.cs b/src/Plugins/SmartStore.AmazonPay/Extensions/MiscExtensions.cs new file mode 100644 index 0000000000..13f63ef965 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Extensions/MiscExtensions.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using System.Linq; +using System.Web; +using SmartStore.AmazonPay.Services; +using SmartStore.Core.Domain.Common; +using SmartStore.Services.Common; +using SmartStore.Services.Localization; + +namespace SmartStore.AmazonPay.Extensions +{ + public static class MiscExtensions + { + public static void ToFirstAndLastName(this string name, out string firstName, out string lastName) + { + if (!string.IsNullOrWhiteSpace(name)) + { + int index = name.LastIndexOf(' '); + if (index == -1) + { + firstName = ""; + lastName = name; + } + else + { + firstName = name.Substring(0, index); + lastName = name.Substring(index + 1); + } + + firstName = firstName.EmptyNull().Truncate(4000); + lastName = lastName.EmptyNull().Truncate(4000); + } + else + { + firstName = lastName = ""; + } + } + + public static void ToFirstAndLastName(this Address address, string name) + { + string firstName, lastName; + name.ToFirstAndLastName(out firstName, out lastName); + + address.FirstName = firstName; + address.LastName = lastName; + } + + public static bool HasAmazonPayState(this HttpContextBase httpContext) + { + var checkoutState = httpContext.GetCheckoutState(); + + if (checkoutState != null && checkoutState.CustomProperties.ContainsKey(AmazonPayCore.AmazonPayCheckoutStateKey)) + { + var state = checkoutState.CustomProperties[AmazonPayCore.AmazonPayCheckoutStateKey] as AmazonPayCheckoutState; + + return (state != null && state.OrderReferenceId.HasValue()); + } + return false; + } + + public static AmazonPayCheckoutState GetAmazonPayState(this HttpContextBase httpContext, ILocalizationService localizationService) + { + AmazonPayCheckoutState state = null; + var checkoutState = httpContext.GetCheckoutState(); + + if (checkoutState == null || (state = (AmazonPayCheckoutState)checkoutState.CustomProperties[AmazonPayCore.AmazonPayCheckoutStateKey]) == null) + throw new SmartException(localizationService.GetResource("Plugins.Payments.AmazonPay.MissingCheckoutSessionState")); + + return state; + } + + public static Address FindAddress(this List
    addresses, Address address, bool uncompleteToo) + { + var match = addresses.FindAddress(address.FirstName, address.LastName, + address.PhoneNumber, address.Email, address.FaxNumber, address.Company, + address.Address1, address.Address2, + address.City, address.StateProvinceId, address.ZipPostalCode, address.CountryId); + + if (match == null && uncompleteToo) + { + // compare with AmazonPayApiExtensions.ToAddress + + match = addresses.FirstOrDefault(x => + x.FirstName == null && x.LastName == null && + x.Address1 == null && x.Address2 == null && + x.City == address.City && x.ZipPostalCode == address.ZipPostalCode && + x.PhoneNumber == null && + x.CountryId == address.CountryId && x.StateProvinceId == address.StateProvinceId + ); + } + + return match; + } + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Filters/AmazonPayCheckoutFilter.cs b/src/Plugins/SmartStore.AmazonPay/Filters/AmazonPayCheckoutFilter.cs new file mode 100644 index 0000000000..9efdbb4fd7 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Filters/AmazonPayCheckoutFilter.cs @@ -0,0 +1,73 @@ +using System; +using System.Linq; +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.AmazonPay.Extensions; +using SmartStore.AmazonPay.Services; + +namespace SmartStore.AmazonPay.Filters +{ + public class AmazonPayCheckoutFilter : IActionFilter + { + private static readonly string[] s_interceptableActions = new string[] { "BillingAddress", "ShippingAddress", "ShippingMethod", "PaymentMethod" }; + private readonly Lazy _apiService; + + public AmazonPayCheckoutFilter(Lazy apiService) + { + _apiService = apiService; + } + + private static bool IsInterceptableAction(string actionName) + { + return s_interceptableActions.Contains(actionName, StringComparer.OrdinalIgnoreCase); + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + if (filterContext == null || filterContext.ActionDescriptor == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) + return; + + if (!filterContext.HttpContext.HasAmazonPayState()) + return; + + string actionName = filterContext.ActionDescriptor.ActionName; + + if (!IsInterceptableAction(actionName)) + return; + + if (actionName.IsCaseInsensitiveEqual("ShippingMethod")) + { + var model = _apiService.Value.ProcessPluginRequest(AmazonPayRequestType.ShippingMethod, filterContext.Controller.TempData); + + if (model.Result == AmazonPayResultType.Redirect) // shipping to selected address not possible + { + var urlHelper = new UrlHelper(filterContext.HttpContext.Request.RequestContext); + var url = urlHelper.Action("ShippingAddress", "Checkout", new { area = "" }); + + filterContext.Result = new RedirectResult(url, false); + } + } + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + if (filterContext == null || filterContext.ActionDescriptor == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) + return; + + if (!filterContext.HttpContext.HasAmazonPayState()) + return; + + string actionName = filterContext.ActionDescriptor.ActionName; + + if (!IsInterceptableAction(actionName)) + return; + + if (actionName.IsCaseInsensitiveEqual("ShippingMethod")) + return; + + var routeValues = new RouteValueDictionary(new { action = actionName, controller = "AmazonPayCheckout" }); + + filterContext.Result = new RedirectToRouteResult("SmartStore.AmazonPay", routeValues); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Localization/resources.de-de.xml b/src/Plugins/SmartStore.AmazonPay/Localization/resources.de-de.xml new file mode 100644 index 0000000000..fbe79d7119 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Localization/resources.de-de.xml @@ -0,0 +1,253 @@ + + + Bezahlen mit Amazon + + + Bezahlen mit Amazon + + + + + Registrieren Sie sich zunächst bei Amazon Payments.

    +

    So richten Sie "Bezahlen mit Amazon" ein:

      +
    • Tragen Sie Ihre Amazon-Zugangsdaten unten in die dafür vorgesehenen Felder ein. Sie finden diese Daten in Ihrem Amazon Seller Central Konto.
    • +
    • Ihre Händlernummer finden Sie dort rechts oben unter Einstellungen > Integrationseinstellungen.
    • +
    • Die beiden Zugangsschlüssel finden Sie dort links oben unter Integration > MWS Access Key. In diesem Dokument finden Sie Bilder, wie Sie diese erstellen.
    • +
    • Falls Sie Sofortbenachrichtigungen (IPN) erhalten möchten (SSL zwingend erforderlich!), so tragen Sie die unten aufgeführte IPN URL unter Einstellungen > Integrationseinstellungen > Sofortbenachrichtigungs-Einstellungen > Händler-URL ein.
    • +
    +

    Bitte fügen Sie Informationen zu "Bezahlen mit Amazon" auf Ihrer Seite der Zahlungsarten ein (siehe CMS > Seiten). Bildmaterial finden Sie hier. +Textvorschläge:

      +
    • Option 1: Bezahlen mit Amazon: Zahlen Sie jetzt mit den Zahl- und Lieferinformationen aus Ihrem Amazon-Konto.
    • +
    • Option 2: Sie sind Amazon-Kunde? Zahlen Sie jetzt mit den Zahl- und Lieferinformationen aus Ihrem Amazon-Konto.
    • +
    • Option 3: Sie sind Amazon-Kunde? Zahlen Sie jetzt mit den Daten aus Ihrem Amazon-Konto.
    • +

    ]]> +
    +
    + + Bitte beachten Sie, dass es sich bei dieser Rechnungsadresse unter Umständen nicht um die für diese Bestellung gültige handelt! + + + Es wurde keine Auftrags-Referenz-ID durch Amazon übermittelt! + + + Die Zahlungsart "Bezahlen mit Amazon" ist für Shop "{0}" nicht verfügbar. + + + Fehlender Checkout-Sitzungsstatus für "Bezahlen mit Amazon". Ihre Zahlung kann leider nicht bearbeitet werden. Bitte gehen Sie zurück in den Warenkorb und Durchlaufen Sie den Checkout erneut. + + + Ein Auftrag mit der Zahlungsart "Bezahlen mit Amazon" und der Kennung {0} wurde nicht gefunden. + + + + Leider wurde die Zahlung zu Ihrer Bestellung in unserem Onlineshop von Amazon Payments zurückgewiesen. Bitte kontaktieren Sie uns.

    ]]> +
    +
    + + oder + + + Amazon Payments meldet + + + Ein Versand in das ausgewählte Land ist leider nicht möglich. Bitte wählen Sie eine andere Versandadresse. + + + Die Einstellungen wurden erfolgreich gespeichert. Starten Sie die Anwendung bitte neu, falls "Aktualisierung des Zahlungsstatus" geändert wurde. + + + Zugangsdaten;Datenaustausch;Gestaltung;Sonstiges + + + {0};Die Rechnungsadresse wurde nicht von Amazon übernommen, da sie entweder fehlt oder eine Rechnungslegung in dieses Land deaktiviert ist.{0}]]> + + + Mitteilungstyp;Mitteilungs ID;Autorisierungs ID;Buchungs ID;Rückerstatattungs ID;Referenz ID;Status;Statusaktualisierung;Gebühr;Autorisierungsbetrag;Buchungsbetrag;Erstattungsbetrag;Sofort buchen;Erstellt am;Verfällt am + + + Sandbox benutzen + + + Legt fest, ob die Sandbox (Testumgebung) genutzt werden soll. + + + Ihre Händlernummer + + + Die Händlernummer, die Sie währen der Registrierung bei Amazon Seller Central erhalten haben. + + + Marktplatz + + + Das Land unter dem Sie Ihr Amazon Verkäuferkonto registriert haben. + + + Deutschland + + + Großbritannien + + + Ihr Zugangsschlüssel + + + Den Zugangsschlüssel finden Sie bei Amazon's Seller Central unter Integration - MWS Access Key. + + + Ihr geheimer Schlüssel + + + Den geheimen Schlüssel finden Sie bei Amazon's Seller Central unter Integration - MWS Access Key. + + + Farbe des Amazon-Login-Button + + + Die bevorzugte Farbe des Amazon-Login-Button im Warenkorb. + + + Orange + + + Hellgrau + + + Größe des Amazon-Login-Buttons + + + Die Größe "Bezahlen mit Amazon" Buttons auf der Warenkorbseite. + + + Medium (126 x 24 Pixel) + + + Groß (151 x 27 Pixel) + + + Extra-Groß (173 x 27 Pixel) + + + Aktualisierung des Zahlungsstatus + + + Legt die Methode fest mit deren Hilfe der Zahlungsstatus aktualisiert werden soll. + + + IPN (Sofortbenachrichtigungen) erfordert, dass ein gültiges SSL-Zertifikat auf diesem Server installiert ist. Achten Sie darauf, das das SSL-Zertifikat von einer vertrauenswürdigen Zertifizierungsstelle ausgegeben werden muss, selbstsignierte Zertifikate sind nicht zulässig. + + + IPN (Instant Payment Notification) + + + Automatischer Abruf (Polling) + + + IPN URL + + + Bitte geben Sie diese URL bei Amazon Seller Central unter Integrationseinstellungen - Sofortbenachrichtigungs-Einstellungen - Händler-URL ein. + + + Zahlungsaktion + + + Legt fest, wann abgebucht werden soll. + + + Sofort abbuchen + + + Autorisierung sofort, Abbuchung später + + + Bitte benutzen Sie "Sofort abbuchen" nur, wenn Sie Ware am selben Tag der Bestellung verschicken und Sie für diesen Dienst zugelassen sind. Aktivieren Sie diese Option bitte erst nach Rücksprache mit Amazon Payments. + + + Kundendaten übernehmen + + + Legt fest, ob und wann die bei Amazon hinterlegte E-Mail-Adresse und Telefonnummer des Kunden übernommen werden sollen. + + + Nur wenn noch nicht vorhanden + + + Immer + + + Button im Miniwarenkorb anzeigen + + + Legt fest, ob der "Bezahlen mit Amazon" Button auch im Miniwarenkorb angezeigt werden soll. + + + Breite des Adressen-Widgets + + + In Pixel. Gültige Werte für einspaltige Widgets sind 200 bis 399 und für zweispaltige Widgets 400 bis 600. + + + Höhe des Adressen-Widgets + + + In Pixel. Gültige Werte sind 228 bis 400. + + + Breite des Zahlungs-Widgets + + + In Pixel. Gültige Werte für einspaltige Widgets sind 200 bis 399 und für zweispaltige Widgets 400 bis 600. + + + Höhe des Zahlungs-Widgets + + + In Pixel. Gültige Werte sind 228 bis 400. + + + Zusätzliche Gebühren + + + Zusätzliche Gebühren, die dem Kunden für die Inanspruchnahme des Dienstes berechnet werden sollen. + + + Bitte berechnen Sie zusätzliche Gebühren erst nach Rücksprache mit Amazon Payments. Hierfür ist eine ausdrückliche Genehmigung erforderlich. + + + Zusätzliche Gebühren (prozentual) + + + Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. + + + Auftragsnotizen anlegen + + + Legt fest, dass Auftragsnotizen hinsichtlich des Datenaustausches mit Amazon Payment angelegt werden sollen. + + + Zeitspanne (in Minuten) + + + Legt fest, wie oft Zahlungsdaten vom Amazon Payments Server abgerufen werden sollen. + + + Maximales Auftragsalter (in Tagen) + + + Legt fest, dass nur Aufträge, die nicht älter als x Tage sind, in die Aktualisierung der Zahlungsdaten einbezogen werden sollen. + + + Über Ablehnung einer Autorisierung informieren + + + Legt fest, dass Auftragsnotizen im Fall einer Ablehnung einer Autorisierung durch Amazon angelegt werden, die auch für den Kunden einsehbar sind. Zusätzlich wir der Kunde per Email über den Sachverhalt informiert. + + + Fehlermeldung anhängen + + + Legt fest, ob der genaue Wortlaut der Fehlermeldung der Auftragsnotiz bzw. Email angehängt werden soll. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Localization/resources.en-us.xml b/src/Plugins/SmartStore.AmazonPay/Localization/resources.en-us.xml new file mode 100644 index 0000000000..d5163d3ef3 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Localization/resources.en-us.xml @@ -0,0 +1,253 @@ + + + Pay with Amazon + + + Pay with Amazon + + + + + Register now at Amazon Payments.

    +

    How to set up "Pay with Amazon":

      +
    • Enter your Amazon credentials in the fields provided below. You can find these credentials in your Amazon Seller Central account.
    • +
    • You can find the Merchant ID in Seller Central at Settings > Integration Settings.
    • +
    • You can find both access keys in Seller Central at Integration > MWS Access Key.
    • +
    • If you would like to receive instant payment notifications (SSL required!) enter the IPN URL listed bewlow under Settings > Integration Settings > Instant Notification Settings > Merchant URL.
    • +
    +

    Please add information about "Pay with Amazon" on your payment page (see CMS > Topics). You will find picture material here. +Text suggestions:

      +
    • Option 1: Pay with Amazon: Pay now with the payment and shipping information from your Amazon account.
    • +
    • Option 2: Already Amazon customer? Pay now with the payment and shipping information from your Amazon account.
    • +
    • Option 3: Already Amazon customer? Pay now with the data from your Amazon account.
    • +

    ]]> +
    +
    + + Please note that this billing address is possibly not the valid billing address for this order! + + + There was no order reference ID transmitted by Amazon! + + + Payment method "Pay with Amazon" is not available for store "{0}". + + + Missing checkout session state for "Pay with Amazon". Your payment cannot be processed. Please go to your shopping cart and checkout again. + + + Cannot find an order with the payment method "Pay with Amazon" and the identification {0}. + + + + Unfortunately Amazon Payments declined the payment for your order in our online shop. Please contact us.

    ]]> +
    +
    + + or + + + Amazon Payments reports + + + Shipping to the selected country is not allowed. Please choose an other shipping address. + + + The settings were successfully saved. Please restart the application if "Updating the payment status" has been changed. + + + Access data;Data exchange;Layout;Miscellaneous + + + {0}The billing address from Amazon was not applied because it is missing or billing to that country is deactivated.{0};]]> + + + Message type;Message ID;Authorization ID;Capture ID;Refund ID;Reference ID;State;State update;Fee;Authorized amount;Captured amount;Refunded amount;Capture now;Creation;Expiration + + + Use Sandbox + + + Check the box to use the sandbox (testing environment). + + + Your Merchant ID + + + The Merchant ID you received during registration at Amazon's Seller Central. + + + Marketplace + + + The country where you registered your Amazon seller account. + + + Germany + + + United Kingdom of Great Britain + + + Your access key + + + You can find the access key at Amazon's Seller Central under Integration - MWS Access Key. + + + Your secret key + + + You can find the secret key at Amazon's Seller Central under Integration - MWS Access Key. + + + Amazon login button color + + + The prefered color of the Amazon login button on shopping cart page. + + + Orange + + + Light gray + + + Size of Amazon login button + + + The size of the "Pay with Amazon" button on the shopping cart page. + + + Medium (126 x 24 pixel) + + + Large (151 x 27 pixel) + + + Extra large (173 x 27 ixel) + + + Updating the payment status + + + Specifies the method used to update the payment status. + + + IPN (instant payment notification) requires valid SSL certificate to be installed on this server. Pay attention that the SSL certificate must be issued by a trusted Certificate Authority, self-signed certificates are not permittted. + + + IPN (Instant Payment Notification) + + + Data polling + + + IPN URL + + + Please enter this URL at Amazon Seller Central under Integration Settings - Instant Notification Settings - Merchant URL. + + + Payment action + + + Specifies when to debit the customer account. + + + Immediately debit + + + Authorize immediately, debit later + + + Please use "Immediately debit" method only in the case you are shipping goods on the same day they are ordered and you have been white-listed for this service. Do not activate this option without contacting Amazon Payments first. + + + Apply customer data + + + Specifies whether and when the Amazon email address and telephone number of the customer should be saved. + + + Only if empty + + + Always + + + Show button in mini shopping cart + + + Specifies to show the "Pay with Amazon" button in the mini shopping cart too. + + + Width of address widget + + + Valid values for one-column widgets are 200 to 399 pixel and for two-column widgets 400 to 600 pixel. + + + Height of address widget + + + Valid values are 228 to 400 pixel. + + + Width of payment widget + + + Valid values for one-column widgets are 200 to 399 pixel and for two-column widgets 400 to 600 pixel. + + + Height of payment widget + + + Valid values are 228 to 400 pixel. + + + Additional fee + + + Enter additional fee to charge your customers. + + + This option requires a permission through Amazon Payments. Please do not calculate additional fees without contacting Amazon Payments first. + + + Additional fee percentage + + + Specifies whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. + + + Create order notes + + + Specifies that order notes should be created in context of the data exchange with Amazon Payments. + + + Frequency (in minutes) + + + Specifies how often status of the different object shall be polled from Amazon Payments servers. + + + Maximal order age (in days) + + + Specifies that only orders which are not older than x days to be included in payment data updates. + + + Inform about a refusal of an authorization + + + Specifies to create order notes in case of a declination of an Amazon payment, which are visible for customers too. In addition the customer is informed by email about the case. + + + Append error message + + + Specifies to append the error message to the order note and email. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Models/AmazonPayViewModel.cs b/src/Plugins/SmartStore.AmazonPay/Models/AmazonPayViewModel.cs new file mode 100644 index 0000000000..066e9dd9db --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Models/AmazonPayViewModel.cs @@ -0,0 +1,59 @@ +using System; +using SmartStore.AmazonPay.Services; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.AmazonPay.Models +{ + public class AmazonPayViewModel : ModelBase + { + public AmazonPayViewModel() + { + IsShippable = true; + RedirectAction = "Cart"; + RedirectController = "ShoppingCart"; + Result = AmazonPayResultType.PluginView; + WidgetUrl = AmazonPayCore.UrlWidgetProduction.FormatWith("de"); + } + + public string SystemName { get { return AmazonPayCore.SystemName; } } + + public string SellerId { get; set; } + public string ClientId { get; set; } + + public string WidgetUrl { get; set; } + public string ButtonUrl { get; set; } + public string LoginHandlerUrl { get; set; } + + public bool IsShippable { get; set; } + public bool IsRecurring { get; set; } + + public AmazonPayRequestType Type { get; set; } + public AmazonPayResultType Result { get; set; } + public string RedirectAction { get; set; } + public string RedirectController { get; set; } + + public string OrderReferenceId { get; set; } + public string Warning { get; set; } + + public int AddressWidgetWidth { get; set; } + public int AddressWidgetHeight { get; set; } + + public int PaymentWidgetWidth { get; set; } + public int PaymentWidgetHeight { get; set; } + + public bool DisplayRewardPoints { get; set; } + public int RewardPointsBalance { get; set; } + public string RewardPointsAmount { get; set; } + public bool UseRewardPoints { get; set; } + + public string ShippingMethod { get; set; } + + public string GetWidgetId + { + get + { + return "AmazonPay" + Type.ToString(); + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Models/ConfigurationModel.cs b/src/Plugins/SmartStore.AmazonPay/Models/ConfigurationModel.cs new file mode 100644 index 0000000000..aa40e32f0f --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Models/ConfigurationModel.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.AmazonPay.Services; +using SmartStore.AmazonPay.Settings; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.AmazonPay.Models +{ + public class ConfigurationModel : ModelBase + { + public string[] ConfigGroups { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.UseSandbox")] + public bool UseSandbox { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.SellerId")] + public string SellerId { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AccessKey")] + public string AccessKey { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.SecretKey")] + public string SecretKey { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.Marketplace")] + public string Marketplace { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AmazonButtonColor")] + public string AmazonButtonColor { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AmazonButtonSize")] + public string AmazonButtonSize { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.DataFetching")] + public AmazonPayDataFetchingType DataFetching { get; set; } + public List DataFetchings { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.IpnUrl")] + public string IpnUrl { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.PollingTaskMinutes")] + public int PollingTaskMinutes { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.PollingMaxOrderCreationDays")] + public int PollingMaxOrderCreationDays { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.TransactionType")] + public AmazonPayTransactionType TransactionType { get; set; } + public List TransactionTypes { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.SaveEmailAndPhone")] + public AmazonPaySaveDataType? SaveEmailAndPhone { get; set; } + public List SaveEmailAndPhones { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.ShowButtonInMiniShoppingCart")] + public bool ShowButtonInMiniShoppingCart { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AddressWidgetWidth")] + public int AddressWidgetWidth { get; set; } + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AddressWidgetHeight")] + public int AddressWidgetHeight { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.PaymentWidgetWidth")] + public int PaymentWidgetWidth { get; set; } + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.PaymentWidgetHeight")] + public int PaymentWidgetHeight { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AdditionalFee")] + public decimal AdditionalFee { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AdditionalFeePercentage")] + public bool AdditionalFeePercentage { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.AddOrderNotes")] + public bool AddOrderNotes { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.InformCustomerAboutErrors")] + public bool InformCustomerAboutErrors { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.AmazonPay.InformCustomerAddErrors")] + public bool InformCustomerAddErrors { get; set; } + + public void Copy(AmazonPaySettings settings, bool fromSettings) + { + if (fromSettings) + { + UseSandbox = settings.UseSandbox; + SellerId = settings.SellerId; + AccessKey = settings.AccessKey; + SecretKey = settings.SecretKey; + Marketplace = settings.Marketplace; + DataFetching = settings.DataFetching; + PollingMaxOrderCreationDays = settings.PollingMaxOrderCreationDays; + TransactionType = settings.TransactionType; + SaveEmailAndPhone = settings.SaveEmailAndPhone; + ShowButtonInMiniShoppingCart = settings.ShowButtonInMiniShoppingCart; + AmazonButtonColor = settings.AmazonButtonColor; + AmazonButtonSize = settings.AmazonButtonSize; + AddressWidgetWidth = settings.AddressWidgetWidth; + AddressWidgetHeight = settings.AddressWidgetHeight; + PaymentWidgetWidth = settings.PaymentWidgetWidth; + PaymentWidgetHeight = settings.PaymentWidgetHeight; + AdditionalFee = settings.AdditionalFee; + AdditionalFeePercentage = settings.AdditionalFeePercentage; + AddOrderNotes = settings.AddOrderNotes; + InformCustomerAboutErrors = settings.InformCustomerAboutErrors; + InformCustomerAddErrors = settings.InformCustomerAddErrors; + } + else + { + settings.UseSandbox = UseSandbox; + settings.SellerId = SellerId; + settings.AccessKey = AccessKey; + settings.SecretKey = SecretKey; + settings.Marketplace = Marketplace; + settings.DataFetching = DataFetching; + settings.PollingMaxOrderCreationDays = PollingMaxOrderCreationDays; + settings.TransactionType = TransactionType; + settings.SaveEmailAndPhone = SaveEmailAndPhone; + settings.ShowButtonInMiniShoppingCart = ShowButtonInMiniShoppingCart; + settings.AmazonButtonColor = AmazonButtonColor; + settings.AmazonButtonSize = AmazonButtonSize; + settings.AddressWidgetWidth = AddressWidgetWidth; + settings.AddressWidgetHeight = AddressWidgetHeight; + settings.PaymentWidgetWidth = PaymentWidgetWidth; + settings.PaymentWidgetHeight = PaymentWidgetHeight; + settings.AdditionalFee = AdditionalFee; + settings.AdditionalFeePercentage = AdditionalFeePercentage; + settings.AddOrderNotes = AddOrderNotes; + settings.InformCustomerAboutErrors = InformCustomerAboutErrors; + settings.InformCustomerAddErrors = InformCustomerAddErrors; + } + } + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Plugin.cs b/src/Plugins/SmartStore.AmazonPay/Plugin.cs new file mode 100644 index 0000000000..61a133c505 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Plugin.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Web.Routing; +using SmartStore.AmazonPay.Controllers; +using SmartStore.AmazonPay.Services; +using SmartStore.AmazonPay.Settings; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Plugins; +using SmartStore.Services; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; + +namespace SmartStore.AmazonPay +{ + [DependentWidgets("Widgets.AmazonPay")] + public class Plugin : PaymentPluginBase, IConfigurable + { + private readonly IAmazonPayService _apiService; + private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly ICommonServices _services; + + public Plugin( + IAmazonPayService apiService, + IOrderTotalCalculationService orderTotalCalculationService, + ICommonServices services) + { + _apiService = apiService; + _orderTotalCalculationService = orderTotalCalculationService; + _services = services; + } + + public override void Install() + { + _services.Settings.SaveSetting(new AmazonPaySettings()); + + _services.Localization.ImportPluginResourcesFromXml(this.PluginDescriptor); + + _apiService.DataPollingTaskInit(); + + base.Install(); + } + + public override void Uninstall() + { + _apiService.DataPollingTaskDelete(); + + _services.Settings.DeleteSetting(); + + _services.Localization.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); + + base.Uninstall(); + } + + public override PreProcessPaymentResult PreProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = _apiService.PreProcessPayment(processPaymentRequest); + return result; + } + + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = _apiService.ProcessPayment(processPaymentRequest); + return result; + } + + public override void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest) + { + _apiService.PostProcessPayment(postProcessPaymentRequest); + } + + public override decimal GetAdditionalHandlingFee(IList cart) + { + var result = decimal.Zero; + try + { + var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); + + result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, settings.AdditionalFee, settings.AdditionalFeePercentage); + } + catch (Exception exc) + { + _apiService.LogError(exc); + } + return result; + + } + + public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) + { + var result = _apiService.Capture(capturePaymentRequest); + return result; + } + + public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) + { + var result = _apiService.Refund(refundPaymentRequest); + return result; + } + + public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) + { + var result = _apiService.Void(voidPaymentRequest); + return result; + } + + + public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "AmazonPay"; + routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.AmazonPay.Controllers" }, { "area", AmazonPayCore.SystemName } }; + } + + public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "ShoppingCart"; + controllerName = "AmazonPayShoppingCart"; + routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.AmazonPay.Controllers" }, { "area", AmazonPayCore.SystemName } }; + } + + public override Type GetControllerType() + { + return typeof(AmazonPayController); + } + + public override bool SupportCapture + { + get { return true; } + } + + public override bool SupportPartiallyRefund + { + get { return true; } + } + + public override bool SupportRefund + { + get { return true; } + } + + public override bool SupportVoid + { + get { return true; } + } + + public override PaymentMethodType PaymentMethodType + { + get { return PaymentMethodType.StandardAndButton; } + } + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.AmazonPay/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..c5f7d8458a --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.AmazonPay")] diff --git a/src/Plugins/SmartStore.AmazonPay/RouteProvider.cs b/src/Plugins/SmartStore.AmazonPay/RouteProvider.cs new file mode 100644 index 0000000000..a44b2d50f3 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/RouteProvider.cs @@ -0,0 +1,30 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.AmazonPay.Services; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.AmazonPay +{ + public class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.AmazonPay", + "Plugins/SmartStore.AmazonPay/{controller}/{action}", + new { controller = "AmazonPay" }, + new[] { "SmartStore.AmazonPay.Controllers" } + ) + .DataTokens["area"] = AmazonPayCore.SystemName; + + // for backward compatibility (IPN!) + routes.MapRoute("SmartStore.AmazonPay.Legacy", + "Plugins/PaymentsAmazonPay/{action}", + new { controller = "AmazonPay" }, + new[] { "SmartStore.AmazonPay.Controllers" } + ) + .DataTokens["area"] = AmazonPayCore.SystemName; + } + + public int Priority { get { return 0; } } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Scripts/smartstore.amazonpay.js b/src/Plugins/SmartStore.AmazonPay/Scripts/smartstore.amazonpay.js new file mode 100644 index 0000000000..a6859e9443 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Scripts/smartstore.amazonpay.js @@ -0,0 +1,33 @@ + +(function (amazonpay, $, undefined) { + + amazonpay.init = function () { + + // show/hide transaction type warning + $('#TransactionType').change(function () { + $('#TransactionTypeWarning').toggle($(this).val() === '2'); + }).trigger('change'); + + // show/hide status fetching warning + $('#DataFetching').change(function () { + var val = $(this).val(), + configTable = $('#AmazonPayConfigTable'); + + $('#DataFetchingWarning').toggle(val === '1'); + + configTable.find('.data-fetching').hide(); + if (val === '1') + configTable.find('.data-fetching-ipn').show(); + else if (val === '2') + configTable.find('.data-fetching-polling').show(); + + }).trigger('change'); + + // show/hide inform customer add errors option + $('#InformCustomerAboutErrors').change(function () { + $('#InformCustomerAddErrorsContainer').toggle($(this).is(':checked')); + }).trigger('change'); + + }; + +}(window.amazonpay = window.amazonpay || {}, jQuery)); \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs new file mode 100644 index 0000000000..59e41a1e2b --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayApi.cs @@ -0,0 +1,815 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using OffAmazonPaymentsService; +using OffAmazonPaymentsService.Model; +using SmartStore.AmazonPay.Extensions; +using SmartStore.AmazonPay.Services; +using SmartStore.AmazonPay.Settings; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Plugins; +using SmartStore.Services; +using SmartStore.Services.Common; +using SmartStore.Services.Directory; +using SmartStore.Services.Helpers; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Utilities; + +namespace SmartStore.AmazonPay.Api +{ + public class AmazonPayApi : IAmazonPayApi + { + private readonly ICountryService _countryService; + private readonly IStateProvinceService _stateProvinceService; + private readonly IOrderService _orderService; + private readonly IAddressService _addressService; + private readonly IDateTimeHelper _dateTimeHelper; + private readonly CurrencySettings _currencySettings; + private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly ICommonServices _services; + + public AmazonPayApi( + ICountryService countryService, + IStateProvinceService stateProvinceService, + IOrderService orderService, + IAddressService addressService, + IDateTimeHelper dateTimeHelper, + CurrencySettings currencySettings, + IOrderTotalCalculationService orderTotalCalculationService, + ICommonServices services) + { + _countryService = countryService; + _stateProvinceService = stateProvinceService; + _orderService = orderService; + _addressService = addressService; + _dateTimeHelper = dateTimeHelper; + _currencySettings = currencySettings; + _orderTotalCalculationService = orderTotalCalculationService; + _services = services; + } + + private string GetRandomId(string prefix) + { + string str = prefix + CommonHelper.GenerateRandomDigitCode(20); + return str.Truncate(32); + } + + public void GetConstraints(OrderReferenceDetails details, IList warnings) + { + try + { + if (details != null && warnings != null && details.IsSetConstraints()) + { + foreach (var constraint in details.Constraints.Constraint) + { + string warning = "{0} ({1})".FormatWith(constraint.Description, constraint.ConstraintID); + warnings.Add(warning); + } + } + } + catch (Exception) { } + } + + public bool FindAndApplyAddress(OrderReferenceDetails details, Customer customer, bool isShippable, bool forceToTakeAmazonAddress) + { + // PlaceOrder requires billing address but we don't get one from Amazon here. so use shipping address instead until we get it from amazon. + bool countryAllowsShipping, countryAllowsBilling; + + var amazonAddress = new SmartStore.Core.Domain.Common.Address() + { + CreatedOnUtc = DateTime.UtcNow + }; + + details.ToAddress(amazonAddress, _countryService, _stateProvinceService, out countryAllowsShipping, out countryAllowsBilling); + + if (isShippable && !countryAllowsShipping) + return false; + + if (amazonAddress.Email.IsEmpty()) + amazonAddress.Email = customer.Email; + + if (forceToTakeAmazonAddress) + { + // first time to get in touch with an amazon address + var existingAddress = customer.Addresses.ToList().FindAddress(amazonAddress, true); + + if (existingAddress == null) + { + customer.Addresses.Add(amazonAddress); + customer.BillingAddress = amazonAddress; + } + else + { + customer.BillingAddress = existingAddress; + } + } + else + { + if (customer.BillingAddress == null) + { + customer.Addresses.Add(amazonAddress); + customer.BillingAddress = amazonAddress; + } + + // we already have the address but it is uncomplete, so just complete it + details.ToAddress(customer.BillingAddress, _countryService, _stateProvinceService, out countryAllowsShipping, out countryAllowsBilling); + + // but now we could have dublicates + int newAddressId = customer.BillingAddress.Id; + var addresses = customer.Addresses.Where(x => x.Id != newAddressId).ToList(); + + var existingAddress = addresses.FindAddress(customer.BillingAddress, false); + + if (existingAddress != null) + { + // remove the new and take the old one + customer.RemoveAddress(customer.BillingAddress); + customer.BillingAddress = existingAddress; + + try + { + _addressService.DeleteAddress(newAddressId); + } + catch (Exception exc) + { + exc.Dump(); + } + } + } + + customer.ShippingAddress = (isShippable ? customer.BillingAddress : null); + + return true; + } + public bool FulfillBillingAddress(AmazonPaySettings settings, Order order, AuthorizationDetails details, out string formattedAddress) + { + formattedAddress = ""; + + if (details == null) + { + AmazonPayApiData data; + details = GetAuthorizationDetails(new AmazonPayClient(settings), order.AuthorizationTransactionId, out data); + } + + if (details == null || !details.IsSetAuthorizationBillingAddress()) + return false; + + bool countryAllowsShipping, countryAllowsBilling; + + // override billing address cause it is just copy of the shipping address + details.AuthorizationBillingAddress.ToAddress(order.BillingAddress, _countryService, _stateProvinceService, out countryAllowsShipping, out countryAllowsBilling); + + if (!countryAllowsBilling) + { + formattedAddress = details.AuthorizationBillingAddress.ToFormatedAddress(_countryService, _stateProvinceService); + return false; + } + + order.BillingAddress.CreatedOnUtc = DateTime.UtcNow; + + if (order.BillingAddress.Email.IsEmpty()) + order.BillingAddress.Email = order.Customer.Email; + + _orderService.UpdateOrder(order); + + formattedAddress = details.AuthorizationBillingAddress.ToFormatedAddress(_countryService, _stateProvinceService); + + return true; + } + + public OrderReferenceDetails GetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, string addressConsentToken = null) + { + var request = new GetOrderReferenceDetailsRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonOrderReferenceId = orderReferenceId; + request.AddressConsentToken = addressConsentToken; + + var response = client.Service.GetOrderReferenceDetails(request); + + if (response != null && response.IsSetGetOrderReferenceDetailsResult()) + { + var detailsResult = response.GetOrderReferenceDetailsResult; + + if (detailsResult.IsSetOrderReferenceDetails()) + return detailsResult.OrderReferenceDetails; + } + return null; + } + + public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, decimal? orderTotalAmount, + string currencyCode, string orderGuid = null, string storeName = null) + { + var request = new SetOrderReferenceDetailsRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonOrderReferenceId = orderReferenceId; + + var attributes = new OrderReferenceAttributes(); + //attributes.SellerNote = client.Settings.SellerNoteOrderReference.Truncate(1024); + attributes.PlatformId = AmazonPayCore.PlatformId; + + if (orderTotalAmount.HasValue) + { + attributes.OrderTotal = new OrderTotal + { + Amount = orderTotalAmount.Value.ToString("0.00", CultureInfo.InvariantCulture), + CurrencyCode = currencyCode ?? "EUR" + }; + } + + if (orderGuid.HasValue()) + { + attributes.SellerOrderAttributes = new SellerOrderAttributes + { + SellerOrderId = orderGuid, + StoreName = storeName + }; + } + + request.OrderReferenceAttributes = attributes; + + var response = client.Service.SetOrderReferenceDetails(request); + + if (response != null && response.IsSetSetOrderReferenceDetailsResult()) + { + var detailsResult = response.SetOrderReferenceDetailsResult; + + if (detailsResult.IsSetOrderReferenceDetails()) + return detailsResult.OrderReferenceDetails; + } + return null; + } + + public OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, string currencyCode, List cart) + { + decimal orderTotalDiscountAmountBase = decimal.Zero; + Discount orderTotalAppliedDiscount = null; + List appliedGiftCards = null; + int redeemedRewardPoints = 0; + decimal redeemedRewardPointsAmount = decimal.Zero; + + decimal? shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart, + out orderTotalDiscountAmountBase, out orderTotalAppliedDiscount, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount); + + if (shoppingCartTotalBase.HasValue) + { + return SetOrderReferenceDetails(client, orderReferenceId, shoppingCartTotalBase, currencyCode); + } + + return null; + } + + /// Confirm an order reference informs Amazon that the buyer has placed the order. + public void ConfirmOrderReference(AmazonPayClient client, string orderReferenceId) + { + var request = new ConfirmOrderReferenceRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonOrderReferenceId = orderReferenceId; + + var response = client.Service.ConfirmOrderReference(request); + } + + public void CancelOrderReference(AmazonPayClient client, string orderReferenceId) + { + var request = new CancelOrderReferenceRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonOrderReferenceId = orderReferenceId; + + var response = client.Service.CancelOrderReference(request); + } + + public void CloseOrderReference(AmazonPayClient client, string orderReferenceId) + { + var request = new CloseOrderReferenceRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonOrderReferenceId = orderReferenceId; + + var response = client.Service.CloseOrderReference(request); + } + + /// Asynchronous as long as we do not set TransactionTimeout to 0. So transaction is always in pending state after return. + public void Authorize(AmazonPayClient client, ProcessPaymentResult result, List errors, string orderReferenceId, decimal orderTotalAmount, string currencyCode, string orderGuid) + { + var request = new AuthorizeRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonOrderReferenceId = orderReferenceId; + request.AuthorizationReferenceId = GetRandomId("Authorize"); + request.CaptureNow = (client.Settings.TransactionType == AmazonPayTransactionType.AuthorizeAndCapture); + //request.SellerAuthorizationNote = client.Settings.SellerNoteAuthorization.Truncate(256); + + request.AuthorizationAmount = new Price() + { + Amount = orderTotalAmount.ToString("0.00", CultureInfo.InvariantCulture), + CurrencyCode = currencyCode ?? "EUR" + }; + + var response = client.Service.Authorize(request); + + if (response != null && response.IsSetAuthorizeResult() && response.AuthorizeResult.IsSetAuthorizationDetails()) + { + var details = response.AuthorizeResult.AuthorizationDetails; + + result.AuthorizationTransactionId = details.AmazonAuthorizationId; + result.AuthorizationTransactionCode = details.AuthorizationReferenceId; + + if (details.IsSetAuthorizationStatus()) + { + var status = details.AuthorizationStatus; + + if (status.IsSetState()) + { + result.AuthorizationTransactionResult = status.State.ToString(); + } + + if (request.CaptureNow && details.IsSetIdList() && details.IdList.IsSetmember() && details.IdList.member.Count() > 0) + { + result.CaptureTransactionId = details.IdList.member[0]; + } + + if (status.IsSetReasonCode()) + { + if (status.ReasonCode.IsCaseInsensitiveEqual("InvalidPaymentMethod") || status.ReasonCode.IsCaseInsensitiveEqual("AmazonRejected") || + status.ReasonCode.IsCaseInsensitiveEqual("ProcessingFailure") || status.ReasonCode.IsCaseInsensitiveEqual("TransactionTimedOut") || + status.ReasonCode.IsCaseInsensitiveEqual("TransactionTimeout")) + { + if (status.IsSetReasonDescription()) + errors.Add("{0}: {1}".FormatWith(status.ReasonCode, status.ReasonDescription)); + else + errors.Add(status.ReasonCode); + } + } + } + } + + // The response to the Authorize call includes the AuthorizationStatus response element, which will be always be + // set to Pending if you have selected the asynchronous mode of operation. + + result.NewPaymentStatus = Core.Domain.Payments.PaymentStatus.Pending; + } + + public AuthorizationDetails GetAuthorizationDetails(AmazonPayClient client, string authorizationId, out AmazonPayApiData data) + { + data = new AmazonPayApiData(); + + AuthorizationDetails details = null; + var request = new GetAuthorizationDetailsRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonAuthorizationId = authorizationId; + + var response = client.Service.GetAuthorizationDetails(request); + + if (response.IsSetGetAuthorizationDetailsResult()) + { + var result = response.GetAuthorizationDetailsResult; + + if (result != null && result.IsSetAuthorizationDetails()) + details = result.AuthorizationDetails; + } + + try + { + data.MessageType = "GetAuthorizationDetails"; + + if (response.IsSetResponseMetadata() && response.ResponseMetadata.IsSetRequestId()) + data.MessageId = response.ResponseMetadata.RequestId; + + if (details != null) + { + if (details.IsSetAmazonAuthorizationId()) + data.AuthorizationId = details.AmazonAuthorizationId; + + if (details.IsSetAuthorizationReferenceId()) + data.ReferenceId = details.AuthorizationReferenceId; + + if (details.IsSetIdList() && details.IdList.IsSetmember()) + data.CaptureId = (details.IdList.member != null && details.IdList.member.Count > 0 ? details.IdList.member[0] : null); + + if (details.IsSetAuthorizationFee()) + data.Fee = new AmazonPayApiPrice(details.AuthorizationFee.Amount, details.AuthorizationFee.CurrencyCode); + + if (details.IsSetAuthorizationAmount()) + data.AuthorizedAmount = new AmazonPayApiPrice(details.AuthorizationAmount.Amount, details.AuthorizationAmount.CurrencyCode); + + if (details.IsSetCapturedAmount()) + data.CapturedAmount = new AmazonPayApiPrice(details.CapturedAmount.Amount, details.CapturedAmount.CurrencyCode); + + if (details.IsSetCaptureNow()) + data.CaptureNow = details.CaptureNow; + + if (details.IsSetCreationTimestamp()) + data.Creation = details.CreationTimestamp; + + if (details.IsSetExpirationTimestamp()) + data.Expiration = details.ExpirationTimestamp; + + if (details.IsSetAuthorizationStatus()) + { + data.ReasonCode = details.AuthorizationStatus.ReasonCode; + data.ReasonDescription = details.AuthorizationStatus.ReasonDescription; + data.State = details.AuthorizationStatus.State.ToString(); + data.StateLastUpdate = details.AuthorizationStatus.LastUpdateTimestamp; + } + } + } + catch (Exception exc) + { + exc.Dump(); + } + return details; + } + + public void Capture(AmazonPayClient client, CapturePaymentRequest capture, CapturePaymentResult result) + { + result.NewPaymentStatus = capture.Order.PaymentStatus; + + var request = new CaptureRequest(); + var store = _services.StoreService.GetStoreById(capture.Order.StoreId); + + request.SellerId = client.Settings.SellerId; + request.AmazonAuthorizationId = capture.Order.AuthorizationTransactionId; + request.CaptureReferenceId = GetRandomId("Capture"); + //request.SellerCaptureNote = client.Settings.SellerNoteCapture.Truncate(255); + + request.CaptureAmount = new Price + { + Amount = capture.Order.OrderTotal.ToString("0.00", CultureInfo.InvariantCulture), + CurrencyCode = store.PrimaryStoreCurrency.CurrencyCode + }; + + var response = client.Service.Capture(request); + + if (response != null && response.IsSetCaptureResult() && response.CaptureResult.IsSetCaptureDetails()) + { + var details = response.CaptureResult.CaptureDetails; + + result.CaptureTransactionId = details.AmazonCaptureId; + + if (details.IsSetCaptureStatus() && details.CaptureStatus.IsSetState()) + { + result.CaptureTransactionResult = details.CaptureStatus.State.ToString().Grow(details.CaptureStatus.ReasonCode, " "); + + if (details.CaptureStatus.State == PaymentStatus.COMPLETED) + result.NewPaymentStatus = Core.Domain.Payments.PaymentStatus.Paid; + } + } + } + + public CaptureDetails GetCaptureDetails(AmazonPayClient client, string captureId, out AmazonPayApiData data) + { + data = new AmazonPayApiData(); + + CaptureDetails details = null; + var request = new GetCaptureDetailsRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonCaptureId = captureId; + + var response = client.Service.GetCaptureDetails(request); + + if (response != null && response.IsSetGetCaptureDetailsResult()) + { + var result = response.GetCaptureDetailsResult; + if (result != null && result.IsSetCaptureDetails()) + details = result.CaptureDetails; + } + + try + { + data.MessageType = "GetCaptureDetails"; + + if (response.IsSetResponseMetadata() && response.ResponseMetadata.IsSetRequestId()) + data.MessageId = response.ResponseMetadata.RequestId; + + if (details != null) + { + if (details.IsSetAmazonCaptureId()) + data.CaptureId = details.AmazonCaptureId; + + if (details.IsSetCaptureReferenceId()) + data.ReferenceId = details.CaptureReferenceId; + + if (details.IsSetCaptureFee()) + data.Fee = new AmazonPayApiPrice(details.CaptureFee.Amount, details.CaptureFee.CurrencyCode); + + if (details.IsSetCaptureAmount()) + data.CapturedAmount = new AmazonPayApiPrice(details.CaptureAmount.Amount, details.CaptureAmount.CurrencyCode); + + if (details.IsSetRefundedAmount()) + data.RefundedAmount = new AmazonPayApiPrice(details.RefundedAmount.Amount, details.RefundedAmount.CurrencyCode); + + if (details.IsSetCreationTimestamp()) + data.Creation = details.CreationTimestamp; + + if (details.IsSetCaptureStatus()) + { + data.ReasonCode = details.CaptureStatus.ReasonCode; + data.ReasonDescription = details.CaptureStatus.ReasonDescription; + data.State = details.CaptureStatus.State.ToString(); + data.StateLastUpdate = details.CaptureStatus.LastUpdateTimestamp; + } + } + } + catch (Exception exc) + { + exc.Dump(); + } + return details; + } + + public string Refund(AmazonPayClient client, RefundPaymentRequest refund, RefundPaymentResult result) + { + result.NewPaymentStatus = refund.Order.PaymentStatus; + + string amazonRefundId = null; + var store = _services.StoreService.GetStoreById(refund.Order.StoreId); + + var request = new RefundRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonCaptureId = refund.Order.CaptureTransactionId; + request.RefundReferenceId = GetRandomId("Refund"); + //request.SellerRefundNote = client.Settings.SellerNoteRefund.Truncate(255); + + request.RefundAmount = new Price + { + Amount = refund.AmountToRefund.ToString("0.00", CultureInfo.InvariantCulture), + CurrencyCode = store.PrimaryStoreCurrency.CurrencyCode + }; + + var response = client.Service.Refund(request); + + if (response != null && response.IsSetRefundResult() && response.RefundResult.IsSetRefundDetails()) + { + var details = response.RefundResult.RefundDetails; + + amazonRefundId = details.AmazonRefundId; + + if (details.IsSetRefundStatus() && details.RefundStatus.IsSetState()) + { + if (refund.IsPartialRefund) + result.NewPaymentStatus = Core.Domain.Payments.PaymentStatus.PartiallyRefunded; + else + result.NewPaymentStatus = Core.Domain.Payments.PaymentStatus.Refunded; + } + } + return amazonRefundId; + } + + public RefundDetails GetRefundDetails(AmazonPayClient client, string refundId, out AmazonPayApiData data) + { + data = new AmazonPayApiData(); + + RefundDetails details = null; + var request = new GetRefundDetailsRequest(); + request.SellerId = client.Settings.SellerId; + request.AmazonRefundId = refundId; + + var response = client.Service.GetRefundDetails(request); + + if (response != null && response.IsSetGetRefundDetailsResult()) + { + var result = response.GetRefundDetailsResult; + if (result != null && result.IsSetRefundDetails()) + details = result.RefundDetails; + } + + try + { + data.MessageType = "GetRefundDetails"; + + if (response.IsSetResponseMetadata() && response.ResponseMetadata.IsSetRequestId()) + data.MessageId = response.ResponseMetadata.RequestId; + + if (details != null) + { + if (details.IsSetAmazonRefundId()) + data.RefundId = details.AmazonRefundId; + + if (details.IsSetRefundReferenceId()) + data.ReferenceId = details.RefundReferenceId; + + if (details.IsSetFeeRefunded()) + data.Fee = new AmazonPayApiPrice(details.FeeRefunded.Amount, details.FeeRefunded.CurrencyCode); + + if (details.IsSetRefundAmount()) + data.RefundedAmount = new AmazonPayApiPrice(details.RefundAmount.Amount, details.RefundAmount.CurrencyCode); + + if (details.IsSetCreationTimestamp()) + data.Creation = details.CreationTimestamp; + + if (details.IsSetRefundStatus()) + { + data.ReasonCode = details.RefundStatus.ReasonCode; + data.ReasonDescription = details.RefundStatus.ReasonDescription; + data.State = details.RefundStatus.State.ToString(); + data.StateLastUpdate = details.RefundStatus.LastUpdateTimestamp; + } + } + } + catch (Exception exc) + { + exc.Dump(); + } + return details; + } + + public string ToInfoString(AmazonPayApiData data) + { + var sb = new StringBuilder(); + + try + { + string[] strings = _services.Localization.GetResource("Plugins.Payments.AmazonPay.MessageStrings").SplitSafe(";"); + + string state = data.State.Grow(data.ReasonCode, " "); + if (data.ReasonDescription.HasValue()) + state = "{0} ({1})".FormatWith(state, data.ReasonDescription); + + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.MessageTyp), data.MessageType.NaIfEmpty())); + + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.State), state)); + + var stateDate = _dateTimeHelper.ConvertToUserTime(data.StateLastUpdate, DateTimeKind.Utc); + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.StateUpdate), stateDate.ToString())); + + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.MessageId), data.MessageId.NaIfEmpty())); + + if (data.AuthorizationId.HasValue()) + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.AuthorizationID), data.AuthorizationId)); + + if (data.CaptureId.HasValue()) + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.CaptureID), data.CaptureId)); + + if (data.RefundId.HasValue()) + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.RefundID), data.RefundId)); + + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.ReferenceID), data.ReferenceId.NaIfEmpty())); + + if (data.Fee != null && data.Fee.Amount != 0.0) + { + bool isSigned = (data.MessageType.IsCaseInsensitiveEqual("RefundNotification") || data.MessageType.IsCaseInsensitiveEqual("GetRefundDetails")); + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.Fee), (isSigned ? "-" : "") + data.Fee.ToString())); + } + + if (data.AuthorizedAmount != null && data.AuthorizedAmount.Amount != 0.0) + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.AuthorizedAmount), data.AuthorizedAmount.ToString())); + + if (data.CapturedAmount != null && data.CapturedAmount.Amount != 0.0) + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.CapturedAmount), data.CapturedAmount.ToString())); + + if (data.RefundedAmount != null && data.RefundedAmount.Amount != 0.0) + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.RefundedAmount), data.RefundedAmount.ToString())); + + if (data.CaptureNow.HasValue) + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.CaptureNow), data.CaptureNow.Value.ToString())); + + var creationDate = _dateTimeHelper.ConvertToUserTime(data.Creation, DateTimeKind.Utc); + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.Creation), creationDate.ToString())); + + if (data.Expiration.HasValue) + { + var expirationDate = _dateTimeHelper.ConvertToUserTime(data.Expiration.Value, DateTimeKind.Utc); + sb.AppendLine("{0}: {1}".FormatWith(strings.SafeGet((int)AmazonPayMessage.Expiration), expirationDate.ToString())); + } + } + catch (Exception exc) + { + exc.Dump(); + } + return sb.ToString(); + } + + public AmazonPayApiData ParseNotification(HttpRequestBase request) + { + string json = null; + + using (var reader = new StreamReader(request.InputStream)) + { + json = reader.ReadToEnd(); + } + + var parser = new OffAmazonPaymentsNotifications.NotificationsParser(); + var message = parser.ParseRawMessage(request.Headers, json); + + var data = new AmazonPayApiData() + { + MessageType = message.NotificationType.ToString(), + MessageId = ((OffAmazonPaymentsNotifications.IpnNotificationMetadata)message.NotificationMetadata).NotificationReferenceId + }; + + if (message.NotificationType == OffAmazonPaymentsNotifications.NotificationType.AuthorizationNotification) + { + var details = ((OffAmazonPaymentsNotifications.AuthorizationNotification)message).AuthorizationDetails; + + data.AuthorizationId = details.AmazonAuthorizationId; + data.CaptureId = details.IdList.SafeGet(0); + data.ReferenceId = details.AuthorizationReferenceId; + data.CaptureNow = details.CaptureNow; + data.Creation = details.CreationTimestamp; + + if (details.AuthorizationFee != null) + data.Fee = new AmazonPayApiPrice(details.AuthorizationFee.Amount, details.AuthorizationFee.CurrencyCode); + + if (details.AuthorizationAmount != null) + data.AuthorizedAmount = new AmazonPayApiPrice(details.AuthorizationAmount.Amount, details.AuthorizationAmount.CurrencyCode); + + if (details.CapturedAmount != null) + data.CapturedAmount = new AmazonPayApiPrice(details.CapturedAmount.Amount, details.CapturedAmount.CurrencyCode); + + if (details.ExpirationTimestampSpecified) + data.Expiration = details.ExpirationTimestamp; + + if (details.AuthorizationStatus != null) + { + data.ReasonCode = details.AuthorizationStatus.ReasonCode; + data.ReasonDescription = details.AuthorizationStatus.ReasonDescription; + data.State = details.AuthorizationStatus.State; + data.StateLastUpdate = details.AuthorizationStatus.LastUpdateTimestamp; + } + } + else if (message.NotificationType == OffAmazonPaymentsNotifications.NotificationType.CaptureNotification) + { + var details = ((OffAmazonPaymentsNotifications.CaptureNotification)message).CaptureDetails; + + data.CaptureId = details.AmazonCaptureId; + data.ReferenceId = details.CaptureReferenceId; + data.Creation = details.CreationTimestamp; + + if (details.CaptureFee != null) + data.Fee = new AmazonPayApiPrice(details.CaptureFee.Amount, details.CaptureFee.CurrencyCode); + + if (details.CaptureAmount != null) + data.CapturedAmount = new AmazonPayApiPrice(details.CaptureAmount.Amount, details.CaptureAmount.CurrencyCode); + + if (details.RefundedAmount != null) + data.RefundedAmount = new AmazonPayApiPrice(details.RefundedAmount.Amount, details.RefundedAmount.CurrencyCode); + + if (details.CaptureStatus != null) + { + data.ReasonCode = details.CaptureStatus.ReasonCode; + data.ReasonDescription = details.CaptureStatus.ReasonDescription; + data.State = details.CaptureStatus.State; + data.StateLastUpdate = details.CaptureStatus.LastUpdateTimestamp; + } + } + else if (message.NotificationType == OffAmazonPaymentsNotifications.NotificationType.RefundNotification) + { + var details = ((OffAmazonPaymentsNotifications.RefundNotification)message).RefundDetails; + + data.RefundId = details.AmazonRefundId; + data.ReferenceId = details.RefundReferenceId; + data.Creation = details.CreationTimestamp; + + if (details.FeeRefunded != null) + data.Fee = new AmazonPayApiPrice(details.FeeRefunded.Amount, details.FeeRefunded.CurrencyCode); + + if (details.RefundAmount != null) + data.RefundedAmount = new AmazonPayApiPrice(details.RefundAmount.Amount, details.RefundAmount.CurrencyCode); + + if (details.RefundStatus != null) + { + data.ReasonCode = details.RefundStatus.ReasonCode; + data.ReasonDescription = details.RefundStatus.ReasonDescription; + data.State = details.RefundStatus.State; + data.StateLastUpdate = details.RefundStatus.LastUpdateTimestamp; + } + } + + return data; + } + } + + + public class AmazonPayClient + { + public AmazonPayClient(AmazonPaySettings settings) + { + string appVersion = "1.0"; + + try + { + appVersion = EngineContext.Current.Resolve().GetPluginDescriptorBySystemName(AmazonPayCore.SystemName).Version.ToString(); + } + catch (Exception) { } + + var config = new OffAmazonPaymentsServiceConfig() + { + ServiceURL = (settings.UseSandbox ? AmazonPayCore.UrlApiEuSandbox : AmazonPayCore.UrlApiEuProduction) + }; + + config.SetUserAgent(AmazonPayCore.AppName, appVersion); + + Settings = settings; + Service = new OffAmazonPaymentsServiceClient(AmazonPayCore.AppName, appVersion, settings.AccessKey, settings.SecretKey, config); + } + + public IOffAmazonPaymentsService Service { get; private set; } + public AmazonPaySettings Settings { get; private set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayCore.cs b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayCore.cs new file mode 100644 index 0000000000..da9480d3db --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayCore.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using SmartStore.AmazonPay.Api; +using SmartStore.AmazonPay.Settings; +using SmartStore.Core.Domain.Orders; + +namespace SmartStore.AmazonPay.Services +{ + public static class AmazonPayCore + { + public static string PlatformId { get { return "A3OJ83WFYM72IY"; } } + public static string AppName { get { return "SmartStore.Net " + SystemName; } } + public static string SystemName { get { return "SmartStore.AmazonPay"; } } + public static string AmazonPayCheckoutStateKey { get { return SystemName + ".CheckoutState"; } } + public static string AmazonPayOrderAttributeKey { get { return SystemName + ".OrderAttribute"; } } + public static string AmazonPayRefundIdKey { get { return SystemName + ".RefundId"; } } + public static string DataPollingTaskType { get { return "SmartStore.AmazonPay.DataPollingTask, SmartStore.AmazonPay"; } } + + public static string UrlApiEuSandbox { get { return "https://mws-eu.amazonservices.com/OffAmazonPayments_Sandbox/2013-01-01/"; } } + public static string UrlApiEuProduction { get { return "https://mws-eu.amazonservices.com/OffAmazonPayments/2013-01-01/"; } } + + public static string UrlWidgetSandbox { get { return "https://static-eu.payments-amazon.com/OffAmazonPayments/{0}/sandbox/js/Widgets.js"; } } + public static string UrlWidgetProduction { get { return "https://static-eu.payments-amazon.com/OffAmazonPayments/{0}/js/Widgets.js"; } } + + public static string UrlButtonSandbox { get { return "https://payments-sandbox.amazon.{0}/gp/widgets/button"; } } + public static string UrlButtonProduction { get { return "https://payments.amazon.{0}/gp/widgets/button"; } } + + public static string UrlIpnSchema { get { return "https://amazonpayments.s3.amazonaws.com/documents/payments_ipn.xsd"; } } + } + + + public class AmazonPayCheckoutState + { + public string OrderReferenceId { get; set; } + } + + + public class AmazonPayActionState + { + public Guid OrderGuid { get; set; } + public List Errors { get; set; } + } + + + [Serializable] + public class AmazonPayOrderAttribute + { + public string OrderReferenceId { get; set; } + public bool IsBillingAddressApplied { get; set; } + } + + + public class PollingLoopData + { + public PollingLoopData(int orderId) + { + OrderId = orderId; + } + + public int OrderId { get; private set; } + public Order Order { get; set; } + public AmazonPaySettings Settings { get; set; } + public AmazonPayClient Client { get; set; } + } + + + public class AmazonPayApiData + { + public string MessageType { get; set; } + public string MessageId { get; set; } + public string AuthorizationId { get; set; } + public string CaptureId { get; set; } + public string RefundId { get; set; } + public string ReferenceId { get; set; } + + public string ReasonCode { get; set; } + public string ReasonDescription { get; set; } + public string State { get; set; } + public DateTime StateLastUpdate { get; set; } + + public AmazonPayApiPrice Fee { get; set; } + public AmazonPayApiPrice AuthorizedAmount { get; set; } + public AmazonPayApiPrice CapturedAmount { get; set; } + public AmazonPayApiPrice RefundedAmount { get; set; } + + public bool? CaptureNow { get; set; } + public DateTime Creation { get; set; } + public DateTime? Expiration { get; set; } + + public string AnyAmazonId + { + get + { + if (CaptureId.HasValue()) + return CaptureId; + if (AuthorizationId.HasValue()) + return AuthorizationId; + return RefundId; + } + } + } + + + public class AmazonPayApiPrice + { + public AmazonPayApiPrice() + { + } + public AmazonPayApiPrice(double amount, string currenycCode) + { + Amount = amount; + CurrencyCode = currenycCode; + } + public AmazonPayApiPrice(string amount, string currenycCode) + { + double d; + if (amount.HasValue() && double.TryParse(amount, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) + Amount = d; + + CurrencyCode = currenycCode; + } + + public double Amount { get; set; } + public string CurrencyCode { get; set; } + + public override string ToString() + { + string str = Amount.ToString("0.00", CultureInfo.InvariantCulture); + return str.Grow(CurrencyCode, " "); + } + } + + + public enum AmazonPayRequestType : int + { + None = 0, + ShoppingCart, + Address, + Payment, + OrderReviewData, + ShippingMethod, + MiniShoppingCart, + LoginHandler + } + + public enum AmazonPayTransactionType : int + { + None = 0, + Authorize, + AuthorizeAndCapture + } + + public enum AmazonPaySaveDataType : int + { + None = 0, + OnlyIfEmpty, + Always + } + + public enum AmazonPayDataFetchingType : int + { + None = 0, + Ipn, + Polling + } + + public enum AmazonPayResultType : int + { + None = 0, + PluginView, + Redirect, + Unauthorized + } + + public enum AmazonPayOrderNote : int + { + FunctionExecuted = 0, + Answer, + BillingAddressApplied, + AmazonMessageProcessed, + BillingAddressCountryNotAllowed + } + + public enum AmazonPayMessage : int + { + MessageTyp = 0, + MessageId, + AuthorizationID, + CaptureID, + RefundID, + ReferenceID, + State, + StateUpdate, + Fee, + AuthorizedAmount, + CapturedAmount, + RefundedAmount, + CaptureNow, + Creation, + Expiration + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs new file mode 100644 index 0000000000..12bbea250b --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Services/AmazonPayService.cs @@ -0,0 +1,1317 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using System.Xml.Serialization; +using Autofac; +using OffAmazonPaymentsService; +using SmartStore.AmazonPay.Api; +using SmartStore.AmazonPay.Extensions; +using SmartStore.AmazonPay.Models; +using SmartStore.AmazonPay.Settings; +using SmartStore.Core.Async; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Logging; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Services; +using SmartStore.Services.Catalog; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; +using SmartStore.Services.Messages; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Services.Tasks; + +namespace SmartStore.AmazonPay.Services +{ + public class AmazonPayService : IAmazonPayService + { + private readonly IAmazonPayApi _api; + private readonly HttpContextBase _httpContext; + private readonly ICommonServices _services; + private readonly IPaymentService _paymentService; + private readonly IGenericAttributeService _genericAttributeService; + private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly ICurrencyService _currencyService; + private readonly CurrencySettings _currencySettings; + private readonly ICustomerService _customerService; + private readonly IPriceFormatter _priceFormatter; + private readonly OrderSettings _orderSettings; + private readonly RewardPointsSettings _rewardPointsSettings; + private readonly IOrderService _orderService; + private readonly IRepository _orderRepository; + private readonly IOrderProcessingService _orderProcessingService; + private readonly IScheduleTaskService _scheduleTaskService; + private readonly IWorkflowMessageService _workflowMessageService; + + public AmazonPayService( + IAmazonPayApi api, + HttpContextBase httpContext, + ICommonServices services, + IPaymentService paymentService, + IGenericAttributeService genericAttributeService, + IOrderTotalCalculationService orderTotalCalculationService, + ICurrencyService currencyService, + CurrencySettings currencySettings, + ICustomerService customerService, + IPriceFormatter priceFormatter, + OrderSettings orderSettings, + RewardPointsSettings rewardPointsSettings, + IOrderService orderService, + IRepository orderRepository, + IOrderProcessingService orderProcessingService, + IScheduleTaskService scheduleTaskService, + IWorkflowMessageService workflowMessageService) + { + _api = api; + _httpContext = httpContext; + _services = services; + _paymentService = paymentService; + _genericAttributeService = genericAttributeService; + _orderTotalCalculationService = orderTotalCalculationService; + _currencyService = currencyService; + _currencySettings = currencySettings; + _customerService = customerService; + _priceFormatter = priceFormatter; + _orderSettings = orderSettings; + _rewardPointsSettings = rewardPointsSettings; + _orderService = orderService; + _orderRepository = orderRepository; + _orderProcessingService = orderProcessingService; + _scheduleTaskService = scheduleTaskService; + _workflowMessageService = workflowMessageService; + + T = NullLocalizer.Instance; + Logger = NullLogger.Instance; + } + + public Localizer T { get; set; } + public ILogger Logger { get; set; } + + private string GetPluginUrl(string action, bool useSsl = false) + { + string pluginUrl = "{0}Plugins/SmartStore.AmazonPay/AmazonPay/{1}".FormatWith(_services.WebHelper.GetStoreLocation(useSsl), action); + return pluginUrl; + } + + //private decimal? GetOrderTotal() + //{ + // decimal orderTotalDiscountAmountBase = decimal.Zero; + // Discount orderTotalAppliedDiscount = null; + // List appliedGiftCards = null; + // int redeemedRewardPoints = 0; + // decimal redeemedRewardPointsAmount = decimal.Zero; + + // var cart = _services.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, _services.StoreContext.CurrentStore.Id); + + // decimal? shoppingCartTotalBase = _orderTotalCalculationService.GetShoppingCartTotal(cart, + // out orderTotalDiscountAmountBase, out orderTotalAppliedDiscount, out appliedGiftCards, out redeemedRewardPoints, out redeemedRewardPointsAmount); + + // if (shoppingCartTotalBase.HasValue) // shipping method needs to be selected here! + // { + // decimal shoppingCartTotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotalBase.Value, _services.WorkContext.WorkingCurrency); + + // return shoppingCartTotal; + // } + // return null; + //} + + private void SerializeOrderAttribute(AmazonPayOrderAttribute attribute, Order order) + { + if (attribute != null) + { + var sb = new StringBuilder(); + using (var writer = new StringWriter(sb)) + { + var serializer = new XmlSerializer(typeof(AmazonPayOrderAttribute)); + serializer.Serialize(writer, attribute); + + _genericAttributeService.SaveAttribute(order, AmazonPayCore.AmazonPayOrderAttributeKey, sb.ToString(), order.StoreId); + } + } + } + private AmazonPayOrderAttribute DeserializeOrderAttribute(Order order) + { + var serialized = order.GetAttribute(AmazonPayCore.AmazonPayOrderAttributeKey, _genericAttributeService, order.StoreId); + + if (!serialized.HasValue()) + { + var attribute = new AmazonPayOrderAttribute(); + + // legacy < v.1.14 + attribute.OrderReferenceId = order.GetAttribute(AmazonPayCore.SystemName + ".OrderReferenceId", order.StoreId); + + return attribute; + } + + using (var reader = new StringReader(serialized)) + { + var serializer = new XmlSerializer(typeof(AmazonPayOrderAttribute)); + return (AmazonPayOrderAttribute)serializer.Deserialize(reader); + } + } + + public void LogError(Exception exception, string shortMessage = null, string fullMessage = null, bool notify = false, IList errors = null) + { + try + { + if (exception != null) + { + shortMessage = exception.Message; + fullMessage = exception.ToString(); + exception.Dump(); + } + + if (shortMessage.HasValue()) + { + Logger.InsertLog(LogLevel.Error, shortMessage, fullMessage.EmptyNull()); + + if (notify) + _services.Notifier.Error(new LocalizedString(shortMessage)); + } + } + catch (Exception) { } + + if (errors != null && shortMessage.HasValue()) + errors.Add(shortMessage); + } + public void LogAmazonError(OffAmazonPaymentsServiceException exception, bool notify = false, IList errors = null) + { + try + { + string shortMessage, fullMessage; + + if (exception.GetErrorStrings(out shortMessage, out fullMessage)) + { + Logger.InsertLog(LogLevel.Error, shortMessage, fullMessage); + + if (notify) + _services.Notifier.Error(new LocalizedString(shortMessage)); + + if (errors != null) + errors.Add(shortMessage); + } + } + catch (Exception) { } + } + + private bool IsActive(int storeId, bool logInactive = false) + { + bool isActive = _paymentService.IsPaymentMethodActive(AmazonPayCore.SystemName, storeId); + + if (!isActive && logInactive) + { + LogError(null, T("Plugins.Payments.AmazonPay.PaymentMethodNotActive", _services.StoreContext.CurrentStore.Name)); + } + return isActive; + } + + public void AddOrderNote(AmazonPaySettings settings, Order order, AmazonPayOrderNote note, string anyString = null, bool isIpn = false) + { + try + { + if (!settings.AddOrderNotes || order == null) + return; + + var sb = new StringBuilder(); + + string[] orderNoteStrings = T("Plugins.Payments.AmazonPay.OrderNoteStrings").Text.SplitSafe(";"); + string faviconUrl = "{0}Plugins/{1}/Content/images/favicon.png".FormatWith(_services.WebHelper.GetStoreLocation(false), AmazonPayCore.SystemName); + + sb.AppendFormat("", faviconUrl); + + if (anyString.HasValue()) + { + anyString = orderNoteStrings.SafeGet((int)note).FormatWith(anyString); + } + else + { + anyString = orderNoteStrings.SafeGet((int)note); + anyString = anyString.Replace("{0}", ""); + } + + if (anyString.HasValue()) + { + sb.AppendFormat("{0}", anyString); + } + + if (isIpn) + order.HasNewPaymentNotification = true; + + order.OrderNotes.Add(new OrderNote + { + Note = sb.ToString(), + DisplayToCustomer = false, + CreatedOnUtc = DateTime.UtcNow + }); + + _orderService.UpdateOrder(order); + } + catch (Exception exc) + { + LogError(exc); + } + } + + public void SetupConfiguration(ConfigurationModel model) + { + model.DataFetchings = new List() + { + new SelectListItem + { + Text = T("Common.Unspecified").Text, + Value = "" + }, + new SelectListItem + { + Selected = (model.DataFetching == AmazonPayDataFetchingType.Ipn), + Text = T("Plugins.Payments.AmazonPay.DataFetching.Ipn"), + Value = ((int)AmazonPayDataFetchingType.Ipn).ToString() + }, + new SelectListItem + { + Selected = (model.DataFetching == AmazonPayDataFetchingType.Polling), + Text = T("Plugins.Payments.AmazonPay.DataFetching.Polling"), + Value = ((int)AmazonPayDataFetchingType.Polling).ToString() + } + }; + + model.TransactionTypes = new List() + { + new SelectListItem + { + Selected = (model.TransactionType == AmazonPayTransactionType.AuthorizeAndCapture), + Text = T("Plugins.Payments.AmazonPay.TransactionType.AuthAndCapture"), + Value = ((int)AmazonPayTransactionType.AuthorizeAndCapture).ToString() + }, + new SelectListItem + { + Selected = (model.TransactionType == AmazonPayTransactionType.Authorize), + Text = T("Plugins.Payments.AmazonPay.TransactionType.Auth"), + Value = ((int)AmazonPayTransactionType.Authorize).ToString() + } + }; + + model.SaveEmailAndPhones = new List() + { + new SelectListItem + { + Text = T("Common.Unspecified").Text, + Value = "" + }, + new SelectListItem + { + Selected = (model.SaveEmailAndPhone == AmazonPaySaveDataType.OnlyIfEmpty), + Text = T("Plugins.Payments.AmazonPay.AmazonPaySaveDataType.OnlyIfEmpty"), + Value = ((int)AmazonPaySaveDataType.OnlyIfEmpty).ToString() + }, + new SelectListItem + { + Selected = (model.SaveEmailAndPhone == AmazonPaySaveDataType.Always), + Text = T("Plugins.Payments.AmazonPay.AmazonPaySaveDataType.Always"), + Value = ((int)AmazonPaySaveDataType.Always).ToString() + } + }; + + model.IpnUrl = GetPluginUrl("IPNHandler", _services.StoreContext.CurrentStore.SslEnabled); + + model.ConfigGroups = T("Plugins.Payments.AmazonPay.ConfigGroups").Text.SplitSafe(";"); + + var task = _scheduleTaskService.GetTaskByType(AmazonPayCore.DataPollingTaskType); + + if (task == null) + model.PollingTaskMinutes = 30; + else + model.PollingTaskMinutes = 30; // (task.Seconds / 60); + } + + public string GetWidgetUrl() + { + try + { + var store = _services.StoreContext.CurrentStore; + + if (IsActive(store.Id)) + { + var settings = _services.Settings.LoadSetting(store.Id); + if (settings.SellerId.HasValue()) + return settings.GetWidgetUrl(); + } + } + catch (Exception exc) + { + LogError(exc); + } + return ""; + } + + public AmazonPayViewModel ProcessPluginRequest(AmazonPayRequestType type, TempDataDictionary tempData, string orderReferenceId = null) + { + var model = new AmazonPayViewModel(); + model.Type = type; + + try + { + var store = _services.StoreContext.CurrentStore; + var customer = _services.WorkContext.CurrentCustomer; + var cart = customer.GetCartItems(ShoppingCartType.ShoppingCart, store.Id); + + if (type == AmazonPayRequestType.LoginHandler) + { + if (string.IsNullOrWhiteSpace(orderReferenceId)) + { + LogError(null, T("Plugins.Payments.AmazonPay.MissingOrderReferenceId"), null, true); + model.Result = AmazonPayResultType.Redirect; + return model; + } + + if (cart.Count <= 0 || !IsActive(store.Id)) + { + model.Result = AmazonPayResultType.Redirect; + return model; + } + + if (customer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed) + { + model.Result = AmazonPayResultType.Unauthorized; + return model; + } + + var checkoutState = _httpContext.GetCheckoutState(); + + if (checkoutState == null) + { + Logger.InsertLog(LogLevel.Warning, "Checkout state is null in AmazonPayService.ValidateAndInitiateCheckout!"); + model.Result = AmazonPayResultType.Redirect; + return model; + } + + var state = new AmazonPayCheckoutState() + { + OrderReferenceId = orderReferenceId + }; + + if (checkoutState.CustomProperties.ContainsKey(AmazonPayCore.AmazonPayCheckoutStateKey)) + checkoutState.CustomProperties[AmazonPayCore.AmazonPayCheckoutStateKey] = state; + else + checkoutState.CustomProperties.Add(AmazonPayCore.AmazonPayCheckoutStateKey, state); + + //_httpContext.Session.SafeSet(AmazonPayCore.AmazonPayCheckoutStateKey, state); + + model.RedirectAction = "Index"; + model.RedirectController = "Checkout"; + model.Result = AmazonPayResultType.Redirect; + return model; + } + else if (type == AmazonPayRequestType.ShoppingCart || type == AmazonPayRequestType.MiniShoppingCart) + { + if (cart.Count <= 0 || !IsActive(store.Id)) + { + model.Result = AmazonPayResultType.None; + return model; + } + + string storeLocation = _services.WebHelper.GetStoreLocation(store.SslEnabled); + model.LoginHandlerUrl = "{0}Plugins/SmartStore.AmazonPay/AmazonPayShoppingCart/LoginHandler".FormatWith(storeLocation); + } + else + { + if (!_httpContext.HasAmazonPayState() || cart.Count <= 0) + { + model.Result = AmazonPayResultType.Redirect; + return model; + } + + if (customer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed) + { + model.Result = AmazonPayResultType.Unauthorized; + return model; + } + + var state = _httpContext.GetAmazonPayState(_services.Localization); + + model.OrderReferenceId = state.OrderReferenceId; + //model.IsOrderConfirmed = state.IsOrderConfirmed; + } + + var currency = store.PrimaryStoreCurrency; + var settings = _services.Settings.LoadSetting(store.Id); + + model.SellerId = settings.SellerId; + model.ClientId = settings.AccessKey; + model.IsShippable = cart.RequiresShipping(); + model.IsRecurring = cart.IsRecurring(); + model.WidgetUrl = settings.GetWidgetUrl(); + model.ButtonUrl = settings.GetButtonUrl(type); + model.AddressWidgetWidth = Math.Max(settings.AddressWidgetWidth, 200); + model.AddressWidgetHeight = Math.Max(settings.AddressWidgetHeight, 228); + model.PaymentWidgetWidth = Math.Max(settings.PaymentWidgetWidth, 200); + model.PaymentWidgetHeight = Math.Max(settings.PaymentWidgetHeight, 228); + + if (type == AmazonPayRequestType.MiniShoppingCart) + { + if (!settings.ShowButtonInMiniShoppingCart) + { + model.Result = AmazonPayResultType.None; + return model; + } + } + else if (type == AmazonPayRequestType.Address) + { + if (!model.IsShippable) + { + model.RedirectAction = "ShippingMethod"; + model.RedirectController = "Checkout"; + model.Result = AmazonPayResultType.Redirect; + return model; + } + + var shippingToCountryNotAllowed = tempData[AmazonPayCore.SystemName + "ShippingToCountryNotAllowed"]; + + if (shippingToCountryNotAllowed != null && true == (bool)shippingToCountryNotAllowed) + model.Warning = T("Plugins.Payments.AmazonPay.ShippingToCountryNotAllowed"); + } + else if (type == AmazonPayRequestType.ShippingMethod) + { + model.RedirectAction = model.RedirectController = ""; + + if (model.IsShippable) + { + var client = new AmazonPayClient(settings); + var details = _api.GetOrderReferenceDetails(client, model.OrderReferenceId); + + if (_api.FindAndApplyAddress(details, customer, model.IsShippable, true)) + { + _customerService.UpdateCustomer(customer); + model.Result = AmazonPayResultType.None; + return model; + } + else + { + tempData[AmazonPayCore.SystemName + "ShippingToCountryNotAllowed"] = true; + model.RedirectAction = "ShippingAddress"; + model.RedirectController = "Checkout"; + model.Result = AmazonPayResultType.Redirect; + return model; + } + } + } + else if (type == AmazonPayRequestType.Payment) + { + if (_rewardPointsSettings.Enabled && !model.IsRecurring) + { + int rewardPointsBalance = customer.GetRewardPointsBalance(); + decimal rewardPointsAmountBase = _orderTotalCalculationService.ConvertRewardPointsToAmount(rewardPointsBalance); + decimal rewardPointsAmount = _currencyService.ConvertFromPrimaryStoreCurrency(rewardPointsAmountBase, currency); + + if (rewardPointsAmount > decimal.Zero) + { + model.DisplayRewardPoints = true; + model.RewardPointsAmount = _priceFormatter.FormatPrice(rewardPointsAmount, true, false); + model.RewardPointsBalance = rewardPointsBalance; + } + } + + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedPaymentMethod, AmazonPayCore.SystemName, store.Id); + + var client = new AmazonPayClient(settings); + var unused = _api.SetOrderReferenceDetails(client, model.OrderReferenceId, store.PrimaryStoreCurrency.CurrencyCode, cart); + + // this is ugly... + var paymentRequest = _httpContext.Session["OrderPaymentInfo"] as ProcessPaymentRequest; + if (paymentRequest == null) + { + _httpContext.Session["OrderPaymentInfo"] = new ProcessPaymentRequest(); + } + } + else if (type == AmazonPayRequestType.OrderReviewData) + { + if (model.IsShippable) + { + var shippingOption = customer.GetAttribute(SystemCustomerAttributeNames.SelectedShippingOption, store.Id); + if (shippingOption != null) + model.ShippingMethod = shippingOption.Name; + } + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc, notify: true); + } + catch (Exception exc) + { + LogError(exc, notify: true); + } + return model; + } + + public void ApplyRewardPoints(bool useRewardPoints) + { + if (_rewardPointsSettings.Enabled) + { + _genericAttributeService.SaveAttribute(_services.WorkContext.CurrentCustomer, + SystemCustomerAttributeNames.UseRewardPointsDuringCheckout, useRewardPoints, _services.StoreContext.CurrentStore.Id); + } + } + + private string GetAuthorizationState(AmazonPayClient client, string authorizationId) + { + try + { + if (authorizationId.HasValue()) + { + AmazonPayApiData data; + + if (_api.GetAuthorizationDetails(client, authorizationId, out data) != null) + return data.State; + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc); + } + catch (Exception exc) + { + LogError(exc); + } + return null; + } + + private void CloseOrderReference(AmazonPaySettings settings, Order order) + { + // You can still perform captures against any open authorizations, but you cannot create any new authorizations on the + // Order Reference object. You can still execute refunds against the Order Reference object. + + try + { + var client = new AmazonPayClient(settings); + + var orderAttribute = DeserializeOrderAttribute(order); + + _api.CloseOrderReference(client, orderAttribute.OrderReferenceId); + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc); + } + catch (Exception exc) + { + LogError(exc); + } + } + + private void ProcessAuthorizationResult(AmazonPayClient client, Order order, AmazonPayApiData data, OffAmazonPaymentsService.Model.AuthorizationDetails details) + { + string formattedAddress; + var orderAttribute = DeserializeOrderAttribute(order); + + if (!orderAttribute.IsBillingAddressApplied) + { + if (_api.FulfillBillingAddress(client.Settings, order, details, out formattedAddress)) + { + AddOrderNote(client.Settings, order, AmazonPayOrderNote.BillingAddressApplied, formattedAddress); + + orderAttribute.IsBillingAddressApplied = true; + SerializeOrderAttribute(orderAttribute, order); + } + else if (formattedAddress.HasValue()) + { + AddOrderNote(client.Settings, order, AmazonPayOrderNote.BillingAddressCountryNotAllowed, formattedAddress); + + orderAttribute.IsBillingAddressApplied = true; + SerializeOrderAttribute(orderAttribute, order); + } + } + + if (data.State.IsCaseInsensitiveEqual("Pending")) + return; + + string newResult = data.State.Grow(data.ReasonCode, " "); + + if (_orderProcessingService.CanMarkOrderAsAuthorized(order)) + { + _orderProcessingService.MarkAsAuthorized(order); + } + + if (data.State.IsCaseInsensitiveEqual("Closed") && data.ReasonCode.IsCaseInsensitiveEqual("OrderReferenceCanceled") && _orderProcessingService.CanVoidOffline(order)) + { + _orderProcessingService.VoidOffline(order); // cancelation at amazon seller central + } + else if (data.State.IsCaseInsensitiveEqual("Declined") && _orderProcessingService.CanVoidOffline(order)) + { + _orderProcessingService.VoidOffline(order); + } + + if (!newResult.IsCaseInsensitiveEqual(order.AuthorizationTransactionResult)) + { + order.AuthorizationTransactionResult = newResult; + + if (order.CaptureTransactionId.IsEmpty() && data.CaptureId.HasValue()) + order.CaptureTransactionId = data.CaptureId; // captured at amazon seller central + + _orderService.UpdateOrder(order); + + AddOrderNote(client.Settings, order, AmazonPayOrderNote.AmazonMessageProcessed, _api.ToInfoString(data), true); + } + } + private void ProcessCaptureResult(AmazonPayClient client, Order order, AmazonPayApiData data) + { + if (data.State.IsCaseInsensitiveEqual("Pending")) + return; + + string newResult = data.State.Grow(data.ReasonCode, " "); + + if (data.State.IsCaseInsensitiveEqual("Completed") && _orderProcessingService.CanMarkOrderAsPaid(order)) + { + _orderProcessingService.MarkOrderAsPaid(order); + + CloseOrderReference(client.Settings, order); + } + else if (data.State.IsCaseInsensitiveEqual("Declined") && _orderProcessingService.CanVoidOffline(order)) + { + if (!GetAuthorizationState(client, order.AuthorizationTransactionId).IsCaseInsensitiveEqual("Open")) + { + _orderProcessingService.VoidOffline(order); + } + } + + if (!newResult.IsCaseInsensitiveEqual(order.CaptureTransactionResult)) + { + order.CaptureTransactionResult = newResult; + _orderService.UpdateOrder(order); + + AddOrderNote(client.Settings, order, AmazonPayOrderNote.AmazonMessageProcessed, _api.ToInfoString(data), true); + } + } + private void ProcessRefundResult(AmazonPayClient client, Order order, AmazonPayApiData data) + { + if (data.State.IsCaseInsensitiveEqual("Pending")) + return; + + if (data.RefundedAmount != null && data.RefundedAmount.Amount != 0.0) // totally refunded amount + { + // we could only process it once cause otherwise order.RefundedAmount would getting wrong. + if (order.RefundedAmount == decimal.Zero) + { + decimal refundAmount = Convert.ToDecimal(data.RefundedAmount.Amount); + decimal receivable = order.OrderTotal - refundAmount; + + if (receivable <= decimal.Zero) + { + if (_orderProcessingService.CanRefundOffline(order)) + { + _orderProcessingService.RefundOffline(order); + + if (client.Settings.DataFetching == AmazonPayDataFetchingType.Polling) + AddOrderNote(client.Settings, order, AmazonPayOrderNote.AmazonMessageProcessed, _api.ToInfoString(data), true); + } + } + else + { + if (_orderProcessingService.CanPartiallyRefundOffline(order, refundAmount)) + { + _orderProcessingService.PartiallyRefundOffline(order, refundAmount); + + if (client.Settings.DataFetching == AmazonPayDataFetchingType.Polling) + AddOrderNote(client.Settings, order, AmazonPayOrderNote.AmazonMessageProcessed, _api.ToInfoString(data), true); + } + } + } + } + + if (client.Settings.DataFetching == AmazonPayDataFetchingType.Ipn) + AddOrderNote(client.Settings, order, AmazonPayOrderNote.AmazonMessageProcessed, _api.ToInfoString(data), true); + } + + private void PollingLoop(PollingLoopData data, Func poll) + { + try + { + var sleepMillSec = 8000; + var loopMillSec = 90000; + var startTime = DateTime.Now.TimeOfDay; + + for (int i = 0; i < 99 && (DateTime.Now.TimeOfDay.Milliseconds - startTime.Milliseconds) <= loopMillSec; ++i) + { + // inside the loop cause other instances are also updating the order + data.Order = _orderService.GetOrderById(data.OrderId); + + if (data.Settings == null) + data.Settings = _services.Settings.LoadSetting(data.Order.StoreId); + + if (data.Client == null) + data.Client = new AmazonPayClient(data.Settings); + + if (!poll()) + break; + + Thread.Sleep(sleepMillSec); + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc); + } + catch (Exception exc) + { + LogError(exc); + } + } + private void EarlyPolling(int orderId, AmazonPaySettings settings) + { + // the Authorization object moves to the Open state after remaining in the Pending state for 30 seconds. + + AmazonPayApiData data; + var d = new PollingLoopData(orderId); + d.Settings = settings; + + PollingLoop(d, () => + { + if (d.Order.AuthorizationTransactionId.IsEmpty()) + return false; + + var details = _api.GetAuthorizationDetails(d.Client, d.Order.AuthorizationTransactionId, out data); + + if (!data.State.IsCaseInsensitiveEqual("pending")) + { + ProcessAuthorizationResult(d.Client, d.Order, data, details); + return false; + } + return true; + }); + + + PollingLoop(d, () => + { + if (d.Order.CaptureTransactionId.IsEmpty()) + return false; + + _api.GetCaptureDetails(d.Client, d.Order.CaptureTransactionId, out data); + + ProcessCaptureResult(d.Client, d.Order, data); + + return data.State.IsCaseInsensitiveEqual("pending"); + }); + } + + private Order FindOrder(AmazonPayApiData data) + { + Order order = null; + string errorId = null; + + if (data.MessageType.IsCaseInsensitiveEqual("AuthorizationNotification")) + { + if ((order = _orderService.GetOrderByPaymentAuthorization(AmazonPayCore.SystemName, data.AuthorizationId)) == null) + errorId = "AuthorizationId {0}".FormatWith(data.AuthorizationId); + } + else if (data.MessageType.IsCaseInsensitiveEqual("CaptureNotification")) + { + if ((order = _orderService.GetOrderByPaymentCapture(AmazonPayCore.SystemName, data.CaptureId)) == null) + order = _orderRepository.GetOrderByAmazonId(data.AnyAmazonId); + + if (order == null) + errorId = "CaptureId {0}".FormatWith(data.CaptureId); + } + else if (data.MessageType.IsCaseInsensitiveEqual("RefundNotification")) + { + var attribute = _genericAttributeService.GetAttributes(AmazonPayCore.AmazonPayRefundIdKey, "Order") + .Where(x => x.Value == data.RefundId) + .FirstOrDefault(); + + if (attribute == null || (order = _orderService.GetOrderById(attribute.EntityId)) == null) + order = _orderRepository.GetOrderByAmazonId(data.AnyAmazonId); + + if (order == null) + errorId = "RefundId {0}".FormatWith(data.RefundId); + } + + if (errorId.HasValue()) + Logger.InsertLog(LogLevel.Warning, T("Plugins.Payments.AmazonPay.OrderNotFound", errorId), ""); + + return order; + } + public void AddCustomerOrderNoteLoop(AmazonPayActionState state) + { + try + { + var sleepMillSec = 4000; + var loopMillSec = 40000; + var startTime = DateTime.Now.TimeOfDay; + + for (int i = 0; i < 99 && (DateTime.Now.TimeOfDay.Milliseconds - startTime.Milliseconds) <= loopMillSec; ++i) + { + var order = _orderService.GetOrderByGuid(state.OrderGuid); + if (order != null) + { + var sb = new StringBuilder(T("Plugins.Payments.AmazonPay.AuthorizationHardDeclineMessage")); + + if (state.Errors != null) + { + foreach (var error in state.Errors) + sb.AppendFormat("

    {0}

    ", error); + } + + var orderNote = new OrderNote() + { + DisplayToCustomer = true, + Note = sb.ToString(), + CreatedOnUtc = DateTime.UtcNow, + }; + + order.OrderNotes.Add(orderNote); + _orderService.UpdateOrder(order); + + _workflowMessageService.SendNewOrderNoteAddedCustomerNotification(orderNote, _services.WorkContext.WorkingLanguage.Id); + break; + } + + Thread.Sleep(sleepMillSec); + } + } + catch (Exception exc) + { + LogError(exc); + } + } + + public PreProcessPaymentResult PreProcessPayment(ProcessPaymentRequest request) + { + // fulfill the Amazon checkout + var result = new PreProcessPaymentResult(); + + try + { + var orderGuid = request.OrderGuid.ToString(); + var store = _services.StoreService.GetStoreById(request.StoreId); + var customer = _customerService.GetCustomerById(request.CustomerId); + var currency = store.PrimaryStoreCurrency; + var settings = _services.Settings.LoadSetting(store.Id); + var state = _httpContext.GetAmazonPayState(_services.Localization); + var client = new AmazonPayClient(settings); + + if (!IsActive(store.Id, true)) + { + //_httpContext.ResetCheckoutState(); + + result.AddError(T("Plugins.Payments.AmazonPay.PaymentMethodNotActive", store.Name)); + return result; + } + + var preConfirmDetails = _api.SetOrderReferenceDetails(client, state.OrderReferenceId, request.OrderTotal, currency.CurrencyCode, orderGuid, store.Name); + + _api.GetConstraints(preConfirmDetails, result.Errors); + + if (!result.Success) + return result; + + _api.ConfirmOrderReference(client, state.OrderReferenceId); + + // address and payment cannot be changed if order is in open state, amazon widgets then might show an error. + //state.IsOrderConfirmed = true; + + var cart = customer.GetCartItems(ShoppingCartType.ShoppingCart, store.Id); + var isShippable = cart.RequiresShipping(); + + // note: billing address is only available after authorization is in a non-pending and non-declined state. + var details = _api.GetOrderReferenceDetails(client, state.OrderReferenceId); + + _api.FindAndApplyAddress(details, customer, isShippable, false); + + if (details.IsSetBuyer() && details.Buyer.IsSetEmail() && settings.CanSaveEmailAndPhone(customer.Email)) + { + customer.Email = details.Buyer.Email; + } + + _customerService.UpdateCustomer(customer); + + if (details.IsSetBuyer() && details.Buyer.IsSetPhone() && settings.CanSaveEmailAndPhone(customer.GetAttribute(SystemCustomerAttributeNames.Phone, store.Id))) + { + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Phone, details.Buyer.Phone); + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc, errors: result.Errors); + } + catch (Exception exc) + { + LogError(exc, errors: result.Errors); + } + + return result; + } + + public ProcessPaymentResult ProcessPayment(ProcessPaymentRequest request) + { + // initiate Amazon payment. We do not add errors to request.Errors cause of asynchronous processing. + var result = new ProcessPaymentResult(); + var errors = new List(); + bool informCustomerAboutErrors = false; + bool informCustomerAddErrors = false; + + try + { + var orderGuid = request.OrderGuid.ToString(); + var store = _services.StoreService.GetStoreById(request.StoreId); + var currency = store.PrimaryStoreCurrency; + var settings = _services.Settings.LoadSetting(store.Id); + var state = _httpContext.GetAmazonPayState(_services.Localization); + var client = new AmazonPayClient(settings); + + informCustomerAboutErrors = settings.InformCustomerAboutErrors; + informCustomerAddErrors = settings.InformCustomerAddErrors; + + _api.Authorize(client, result, errors, state.OrderReferenceId, request.OrderTotal, currency.CurrencyCode, orderGuid); + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc, errors: errors); + } + catch (Exception exc) + { + LogError(exc, errors: errors); + } + + if (informCustomerAboutErrors && errors != null && errors.Count > 0) + { + // customer needs to be informed of an amazon error here. hooking OrderPlaced.CustomerNotification won't work + // cause of asynchronous processing. solution: we add a customer order note that is also send as an email. + + var state = new AmazonPayActionState() { OrderGuid = request.OrderGuid }; + + if (informCustomerAddErrors) + { + state.Errors = new List(); + state.Errors.AddRange(errors); + } + + AsyncRunner.Run((container, ct, o) => + { + var obj = o as AmazonPayActionState; + container.Resolve().AddCustomerOrderNoteLoop(obj); + }, + state, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + } + + return result; + } + + public void PostProcessPayment(PostProcessPaymentRequest request) + { + // early polling... note we do not have the amazon billing address yet + //try + //{ + // int orderId = request.Order.Id; + // var settings = _services.Settings.LoadSetting(request.Order.StoreId); + + // if (orderId != 0 && settings.StatusFetching == AmazonPayStatusFetchingType.Polling) + // { + // AsyncRunner.Run((container, obj) => + // { + // var amazonService = container.Resolve(); + // amazonService.EarlyPolling(orderId, obj as AmazonPaySettings); + // }, + // settings, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); + // } + //} + //catch (OffAmazonPaymentsServiceException exc) + //{ + // LogAmazonError(exc); + //} + //catch (Exception exc) + //{ + // LogError(exc); + //} + + try + { + var state = _httpContext.GetAmazonPayState(_services.Localization); + + var orderAttribute = new AmazonPayOrderAttribute() + { + OrderReferenceId = state.OrderReferenceId + }; + + SerializeOrderAttribute(orderAttribute, request.Order); + } + catch (Exception exc) + { + LogError(exc); + } + } + + public CapturePaymentResult Capture(CapturePaymentRequest request) + { + var result = new CapturePaymentResult() + { + NewPaymentStatus = request.Order.PaymentStatus + }; + + try + { + var settings = _services.Settings.LoadSetting(request.Order.StoreId); + var client = new AmazonPayClient(settings); + + _api.Capture(client, request, result); + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc, errors: result.Errors); + } + catch (Exception exc) + { + LogError(exc, errors: result.Errors); + } + return result; + } + + public RefundPaymentResult Refund(RefundPaymentRequest request) + { + var result = new RefundPaymentResult() + { + NewPaymentStatus = request.Order.PaymentStatus + }; + + try + { + var settings = _services.Settings.LoadSetting(request.Order.StoreId); + var client = new AmazonPayClient(settings); + + string amazonRefundId = _api.Refund(client, request, result); + + if (amazonRefundId.HasValue() && request.Order.Id != 0) + { + _genericAttributeService.InsertAttribute(new GenericAttribute() + { + EntityId = request.Order.Id, + KeyGroup = "Order", + Key = AmazonPayCore.AmazonPayRefundIdKey, + Value = amazonRefundId, + StoreId = request.Order.StoreId + }); + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc, errors: result.Errors); + } + catch (Exception exc) + { + LogError(exc, errors: result.Errors); + } + return result; + } + + public VoidPaymentResult Void(VoidPaymentRequest request) + { + var result = new VoidPaymentResult() + { + NewPaymentStatus = request.Order.PaymentStatus + }; + + // redundant... cause payment infrastructure hides "void" and displays "refund" instead. + //if (request.Order.PaymentStatus == PaymentStatus.Paid) + //{ + // var refundRequest = new RefundPaymentRequest() + // { + // Order = request.Order, + // IsPartialRefund = false, + // AmountToRefund = request.Order.OrderTotal + // }; + + // var refundResult = Refund(refundRequest); + + // result.Errors.AddRange(refundResult.Errors); + // return result; + //} + + try + { + if (request.Order.PaymentStatus == PaymentStatus.Pending || request.Order.PaymentStatus == PaymentStatus.Authorized) + { + var settings = _services.Settings.LoadSetting(request.Order.StoreId); + var client = new AmazonPayClient(settings); + + var orderAttribute = DeserializeOrderAttribute(request.Order); + + _api.CancelOrderReference(client, orderAttribute.OrderReferenceId); + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc, errors: result.Errors); + } + catch (Exception exc) + { + LogError(exc, errors: result.Errors); + } + return result; + } + + public void ProcessIpn(HttpRequestBase request) + { + try + { + var data = _api.ParseNotification(request); + var order = FindOrder(data); + + if (order == null || !IsActive(order.StoreId)) + return; + + var client = new AmazonPayClient(_services.Settings.LoadSetting(order.StoreId)); + + if (client.Settings.DataFetching != AmazonPayDataFetchingType.Ipn) + return; + + if (data.MessageType.IsCaseInsensitiveEqual("AuthorizationNotification")) + { + ProcessAuthorizationResult(client, order, data, null); + return; + } + else if (data.MessageType.IsCaseInsensitiveEqual("CaptureNotification")) + { + ProcessCaptureResult(client, order, data); + return; + } + else if (data.MessageType.IsCaseInsensitiveEqual("RefundNotification")) + { + ProcessRefundResult(client, order, data); + return; + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc); + } + catch (Exception exc) + { + LogError(exc); + } + } + + public void DataPollingTaskProcess() + { + try + { + // ignore cancelled and completed (paid and shipped) orders. ignore old orders too. + + var data = new AmazonPayApiData(); + int pollingMaxOrderCreationDays = _services.Settings.GetSettingByKey("AmazonPaySettings.PollingMaxOrderCreationDays", 31); + var isTooOld = DateTime.UtcNow.AddDays(-(pollingMaxOrderCreationDays)); + + var query = + from x in _orderRepository.Table + where x.PaymentMethodSystemName == AmazonPayCore.SystemName && x.CreatedOnUtc > isTooOld && + !x.Deleted && x.OrderStatusId < (int)OrderStatus.Complete && x.PaymentStatusId != (int)PaymentStatus.Voided + orderby x.Id descending + select x; + + var orders = query.ToList(); + + //"- start polling {0} orders".FormatWith(orders.Count).Dump(); + + foreach (var order in orders) + { + try + { + var client = new AmazonPayClient(_services.Settings.LoadSetting(order.StoreId)); + + if (client.Settings.DataFetching == AmazonPayDataFetchingType.Polling) + { + if (order.AuthorizationTransactionId.HasValue()) + { + var details = _api.GetAuthorizationDetails(client, order.AuthorizationTransactionId, out data); + + ProcessAuthorizationResult(client, order, data, details); + } + + if (order.CaptureTransactionId.HasValue()) + { + if (_orderProcessingService.CanMarkOrderAsPaid(order) || _orderProcessingService.CanVoidOffline(order) || + _orderProcessingService.CanRefundOffline(order) || _orderProcessingService.CanPartiallyRefundOffline(order, 0.01M)) + { + var details = _api.GetCaptureDetails(client, order.CaptureTransactionId, out data); + + ProcessCaptureResult(client, order, data); + + if (_orderProcessingService.CanRefundOffline(order) || _orderProcessingService.CanPartiallyRefundOffline(order, 0.01M)) + { + // note status polling: we cannot use GetRefundDetails to reflect refund(s) made at Amazon seller central cause we + // do not have any refund-id and there is no api endpoint that serves them. so we only can process CaptureDetails.RefundedAmount. + + ProcessRefundResult(client, order, data); + } + } + } + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc); + } + catch (Exception exc) + { + LogError(exc); + } + } + } + catch (OffAmazonPaymentsServiceException exc) + { + LogAmazonError(exc); + } + catch (Exception exc) + { + LogError(exc); + } + } + + public void DataPollingTaskInit() + { + var task = _scheduleTaskService.GetTaskByType(AmazonPayCore.DataPollingTaskType); + if (task == null) + { + _scheduleTaskService.InsertTask(new ScheduleTask + { + Name = "{0} data polling".FormatWith(AmazonPayCore.SystemName), + CronExpression = "*/30 * * * *", // Every 30 minutes + Type = AmazonPayCore.DataPollingTaskType, + Enabled = false, + StopOnError = false, + }); + } + } + + public void DataPollingTaskUpdate(bool enabled, int seconds) + { + var task = _scheduleTaskService.GetTaskByType(AmazonPayCore.DataPollingTaskType); + if (task != null) + { + task.Enabled = enabled; + //task.Seconds = seconds; + + _scheduleTaskService.UpdateTask(task); + } + } + + public void DataPollingTaskDelete() + { + var task = _scheduleTaskService.GetTaskByType(AmazonPayCore.DataPollingTaskType); + if (task != null) + _scheduleTaskService.DeleteTask(task); + } + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayApi.cs b/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayApi.cs new file mode 100644 index 0000000000..70d72d9aa1 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayApi.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Web; +using OffAmazonPaymentsService.Model; +using SmartStore.AmazonPay.Services; +using SmartStore.AmazonPay.Settings; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; +using SmartStore.Services.Payments; + +namespace SmartStore.AmazonPay.Api +{ + public partial interface IAmazonPayApi + { + void GetConstraints(OrderReferenceDetails details, IList warnings); + + bool FindAndApplyAddress(OrderReferenceDetails details, Customer customer, bool isShippable, bool forceToTakeAmazonAddress); + bool FulfillBillingAddress(AmazonPaySettings settings, Order order, AuthorizationDetails details, out string formattedAddress); + + OrderReferenceDetails GetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, string addressConsentToken = null); + + OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, decimal? orderTotalAmount, + string currencyCode, string orderGuid = null, string storeName = null); + + OrderReferenceDetails SetOrderReferenceDetails(AmazonPayClient client, string orderReferenceId, string currencyCode, List cart); + + void ConfirmOrderReference(AmazonPayClient client, string orderReferenceId); + + void CancelOrderReference(AmazonPayClient client, string orderReferenceId); + + void CloseOrderReference(AmazonPayClient client, string orderReferenceId); + + void Authorize(AmazonPayClient client, ProcessPaymentResult result, List errors, string orderReferenceId, decimal orderTotalAmount, + string currencyCode, string orderGuid); + + AuthorizationDetails GetAuthorizationDetails(AmazonPayClient client, string authorizationId, out AmazonPayApiData data); + + void Capture(AmazonPayClient client, CapturePaymentRequest capture, CapturePaymentResult result); + + CaptureDetails GetCaptureDetails(AmazonPayClient client, string captureId, out AmazonPayApiData data); + + string Refund(AmazonPayClient client, RefundPaymentRequest refund, RefundPaymentResult result); + + RefundDetails GetRefundDetails(AmazonPayClient client, string refundId, out AmazonPayApiData data); + + string ToInfoString(AmazonPayApiData data); + + AmazonPayApiData ParseNotification(HttpRequestBase request); + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayService.cs b/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayService.cs new file mode 100644 index 0000000000..5e14a4d77e --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Services/IAmazonPayService.cs @@ -0,0 +1,52 @@ +using System; +using System.Web; +using System.Web.Mvc; +using System.Collections.Generic; +using OffAmazonPaymentsService; +using SmartStore.AmazonPay.Models; +using SmartStore.AmazonPay.Settings; +using SmartStore.Core.Domain.Orders; +using SmartStore.Services.Payments; + +namespace SmartStore.AmazonPay.Services +{ + public partial interface IAmazonPayService + { + void LogError(Exception exception, string shortMessage = null, string fullMessage = null, bool notify = false, IList errors = null); + void LogAmazonError(OffAmazonPaymentsServiceException exception, bool notify = false, IList errors = null); + + void AddOrderNote(AmazonPaySettings settings, Order order, AmazonPayOrderNote note, string anyString = null, bool isIpn = false); + + void SetupConfiguration(ConfigurationModel model); + + string GetWidgetUrl(); + + AmazonPayViewModel ProcessPluginRequest(AmazonPayRequestType type, TempDataDictionary tempData, string orderReferenceId = null); + + void ApplyRewardPoints(bool useRewardPoints); + + void AddCustomerOrderNoteLoop(AmazonPayActionState state); + + PreProcessPaymentResult PreProcessPayment(ProcessPaymentRequest request); + + ProcessPaymentResult ProcessPayment(ProcessPaymentRequest request); + + void PostProcessPayment(PostProcessPaymentRequest request); + + CapturePaymentResult Capture(CapturePaymentRequest request); + + RefundPaymentResult Refund(RefundPaymentRequest request); + + VoidPaymentResult Void(VoidPaymentRequest request); + + void ProcessIpn(HttpRequestBase request); + + void DataPollingTaskProcess(); + + void DataPollingTaskInit(); + + void DataPollingTaskUpdate(bool enabled, int seconds); + + void DataPollingTaskDelete(); + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/Settings/AmazonPaySettings.cs b/src/Plugins/SmartStore.AmazonPay/Settings/AmazonPaySettings.cs new file mode 100644 index 0000000000..6acdaf0f18 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Settings/AmazonPaySettings.cs @@ -0,0 +1,103 @@ +using System.Web; +using SmartStore.Core.Configuration; +using SmartStore.AmazonPay.Services; + +namespace SmartStore.AmazonPay.Settings +{ + public class AmazonPaySettings : ISettings + { + public AmazonPaySettings() + { + Marketplace = "de"; + DataFetching = AmazonPayDataFetchingType.Ipn; + TransactionType = AmazonPayTransactionType.Authorize; + SaveEmailAndPhone = AmazonPaySaveDataType.OnlyIfEmpty; + AmazonButtonColor = "orange"; + AmazonButtonSize = "x-large"; + AddressWidgetWidth = PaymentWidgetWidth = 400; + AddressWidgetHeight = PaymentWidgetHeight = 260; + AddOrderNotes = true; + InformCustomerAboutErrors = true; + InformCustomerAddErrors = true; + PollingMaxOrderCreationDays = 31; + } + + public bool UseSandbox { get; set; } + + public string SellerId { get; set; } + public string AccessKey { get; set; } + public string SecretKey { get; set; } + public string Marketplace { get; set; } + + public AmazonPayDataFetchingType DataFetching { get; set; } + public AmazonPayTransactionType TransactionType { get; set; } + + public AmazonPaySaveDataType? SaveEmailAndPhone { get; set; } + public bool ShowButtonInMiniShoppingCart { get; set; } + + public int PollingMaxOrderCreationDays { get; set; } + + public string AmazonButtonColor { get; set; } + public string AmazonButtonSize { get; set; } + + public int AddressWidgetWidth { get; set; } + public int AddressWidgetHeight { get; set; } + + public int PaymentWidgetWidth { get; set; } + public int PaymentWidgetHeight { get; set; } + + public decimal AdditionalFee { get; set; } + public bool AdditionalFeePercentage { get; set; } + + public bool AddOrderNotes { get; set; } + + public bool InformCustomerAboutErrors { get; set; } + public bool InformCustomerAddErrors { get; set; } + + public string GetApiUrl() + { + return (UseSandbox ? AmazonPayCore.UrlApiEuSandbox : AmazonPayCore.UrlApiEuProduction); + } + + public string GetWidgetUrl() + { + if (SellerId.IsEmpty()) + return null; + + string url = (UseSandbox ? AmazonPayCore.UrlWidgetSandbox : AmazonPayCore.UrlWidgetProduction); + url = url.FormatWith(Marketplace ?? "de"); + + return "{0}?sellerId={1}".FormatWith( + url, + HttpUtility.UrlEncode(SellerId) + ); + } + + public string GetButtonUrl(AmazonPayRequestType view) + { + //bool isGerman = _services.WorkContext.WorkingLanguage.UniqueSeoCode.IsCaseInsensitiveEqual("DE"); + string marketplace = Marketplace ?? "de"; + if (marketplace.IsCaseInsensitiveEqual("uk")) + marketplace = "co.uk"; + + string buttonSize = (view == AmazonPayRequestType.MiniShoppingCart ? "medium" : AmazonButtonSize); + + string url = (UseSandbox ? AmazonPayCore.UrlButtonSandbox : AmazonPayCore.UrlButtonProduction); + url = url.FormatWith(marketplace); + + return "{0}?sellerId={1}&size={2}&color={3}".FormatWith( + url, + HttpUtility.UrlEncode(SellerId), + HttpUtility.UrlEncode(buttonSize ?? "x-large"), + HttpUtility.UrlEncode(AmazonButtonColor ?? "orange") + ); + } + + public bool CanSaveEmailAndPhone(string value) + { + return ( + SaveEmailAndPhone == AmazonPaySaveDataType.Always || (SaveEmailAndPhone == AmazonPaySaveDataType.OnlyIfEmpty && value.IsEmpty()) + ); + } + } +} diff --git a/src/Plugins/SmartStore.AmazonPay/SmartStore.AmazonPay.csproj b/src/Plugins/SmartStore.AmazonPay/SmartStore.AmazonPay.csproj new file mode 100644 index 0000000000..3cbc8fcb83 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/SmartStore.AmazonPay.csproj @@ -0,0 +1,298 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + {611E4AC2-CA21-5C81-6B4B-3ABA87B91A25} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.AmazonPay + SmartStore.AmazonPay + v4.5.1 + 512 + + + + + + + + + ..\..\ + true + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.AmazonPay\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.AmazonPay\ + TRACE + prompt + 4 + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + False + lib\OffAmazonPaymentsNotifications.dll + + + False + lib\OffAmazonPaymentsService.dll + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + Always + + + Always + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + Always + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541ad-f659-47da-8763-16f36c5cd2f4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + {4f1f649c-1020-45be-a487-f416d9297ff3} + SmartStore.Web + False + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 55814 + / + http://localhost:57287/ + False + True + http://www.smartstore.net + False + + + + + + xcopy /s /y "$(ProjectDir)lib\*.*" "$(TargetDir)*.*" + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Tasks/DataPollingTask.cs b/src/Plugins/SmartStore.AmazonPay/Tasks/DataPollingTask.cs new file mode 100644 index 0000000000..58c40dc0d6 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Tasks/DataPollingTask.cs @@ -0,0 +1,21 @@ +using SmartStore.Core.Infrastructure; +using SmartStore.AmazonPay.Services; +using SmartStore.Services.Tasks; + +namespace SmartStore.AmazonPay +{ + public class DataPollingTask : ITask + { + private readonly IAmazonPayService _apiService; + + public DataPollingTask(IAmazonPayService apiService) + { + _apiService = apiService; + } + + public void Execute(TaskExecutionContext ctx) + { + _apiService.DataPollingTaskProcess(); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPay/Configure.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPay/Configure.cshtml new file mode 100644 index 0000000000..3d77fb69e4 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPay/Configure.cshtml @@ -0,0 +1,325 @@ +@using SmartStore.Web.Framework; +@using SmartStore.Web.Framework.UI; +@using SmartStore.AmazonPay.Models; +@using SmartStore.AmazonPay.Extensions; +@model ConfigurationModel +@{ + Layout = ""; + Html.AddCssFileParts(true, Url.Content("~/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css")); + Html.AddScriptParts(true, Url.Content("~/Plugins/SmartStore.AmazonPay/Scripts/smartstore.amazonpay.js")); +} + +
    +
    +
    + + @Html.Raw(@T("Plugins.Payments.AmazonPay.AdminInstruction")) +
    +
    +
    + + + +
    +
    + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + @Model.ConfigGroups.SafeGet(0) +
    +
    +
    + @Html.SmartLabelFor(model => model.UseSandbox) + + @Html.SettingEditorFor(model => model.UseSandbox) + @Html.ValidationMessageFor(model => model.UseSandbox) +
    + @Html.SmartLabelFor(model => model.SellerId) + + @Html.SettingEditorFor(model => model.SellerId) + @Html.ValidationMessageFor(model => model.SellerId) +
    + @Html.SmartLabelFor(model => model.AccessKey) + + @Html.SettingEditorFor(model => model.AccessKey) + @Html.ValidationMessageFor(model => model.AccessKey) +
    + @Html.SmartLabelFor(model => model.SecretKey) + + @Html.SettingEditorFor(model => model.SecretKey) + @Html.ValidationMessageFor(model => model.SecretKey) +
    + @Html.SmartLabelFor(model => model.Marketplace) + + @Html.SettingOverrideCheckbox(model => model.Marketplace) + @Html.DropDownListFor(model => model.Marketplace, new List() + { + new SelectListItem { Text = @T("Plugins.Payments.AmazonPay.Marketplace.De"), Value = "de" }, + new SelectListItem { Text = @T("Plugins.Payments.AmazonPay.Marketplace.Uk"), Value = "uk" } + }) + @Html.ValidationMessageFor(model => model.Marketplace) +
    +
    +
    @Model.ConfigGroups.SafeGet(1)
    +
    +
    + @Html.SmartLabelFor(model => model.TransactionType) + + @Html.SettingOverrideCheckbox(model => model.TransactionType) + @Html.DropDownListFor(model => model.TransactionType, Model.TransactionTypes) + @Html.ValidationMessageFor(model => model.TransactionType) +
    +
    + @T("Plugins.Payments.AmazonPay.TransactionType.Warning") +
    +
    + @Html.SmartLabelFor(model => model.SaveEmailAndPhone) + + @Html.SettingOverrideCheckbox(model => model.SaveEmailAndPhone) + @Html.DropDownListFor(model => model.SaveEmailAndPhone, Model.SaveEmailAndPhones) + @Html.ValidationMessageFor(model => model.SaveEmailAndPhone) +
    + @Html.SmartLabelFor(model => model.AddOrderNotes) + + @Html.SettingEditorFor(model => model.AddOrderNotes) + @Html.ValidationMessageFor(model => model.AddOrderNotes) +
    + @Html.SmartLabelFor(model => model.InformCustomerAboutErrors) + + @Html.SettingEditorFor(model => model.InformCustomerAboutErrors) + @Html.ValidationMessageFor(model => model.InformCustomerAboutErrors) +
    + @Html.SmartLabelFor(model => model.InformCustomerAddErrors) + + @Html.SettingEditorFor(model => model.InformCustomerAddErrors) + @Html.ValidationMessageFor(model => model.InformCustomerAddErrors) +
    + @Html.SmartLabelFor(model => model.DataFetching) + + @Html.DropDownListFor(model => model.DataFetching, Model.DataFetchings) + @Html.ValidationMessageFor(model => model.DataFetching) +
    + @Html.SmartLabelFor(model => model.IpnUrl) + + @Html.DisplayFor(model => model.IpnUrl) +
    + @Html.SmartLabelFor(model => model.PollingTaskMinutes) + + @Html.EditorFor(model => model.PollingTaskMinutes) + @Html.ValidationMessageFor(model => model.PollingTaskMinutes) +
    + @Html.SmartLabelFor(model => model.PollingMaxOrderCreationDays) + + @Html.EditorFor(model => model.PollingMaxOrderCreationDays) + @Html.ValidationMessageFor(model => model.PollingMaxOrderCreationDays) +
    +
    + @T("Plugins.Payments.AmazonPay.DataFetching.Warning") +
    +
    +
    +
    @Model.ConfigGroups.SafeGet(2)
    +
    +
    + @Html.SmartLabelFor(model => model.AmazonButtonColor) + + @Html.SettingOverrideCheckbox(model => model.AmazonButtonColor) + @Html.DropDownListFor(model => model.AmazonButtonColor, new List() + { + new SelectListItem { Text = @T("Plugins.Payments.AmazonPay.AmazonButtonColor.Orange"), Value = "orange" }, + new SelectListItem { Text = @T("Plugins.Payments.AmazonPay.AmazonButtonColor.Tan"), Value = "tan" } + }) + @Html.ValidationMessageFor(model => model.AmazonButtonColor) +
    + @Html.SmartLabelFor(model => model.AmazonButtonSize) + + @Html.SettingOverrideCheckbox(model => model.AmazonButtonSize) + @Html.DropDownListFor(model => model.AmazonButtonSize, new List() + { + new SelectListItem { Text = @T("Plugins.Payments.AmazonPay.AmazonButtonSize.Medium"), Value = "medium" }, + new SelectListItem { Text = @T("Plugins.Payments.AmazonPay.AmazonButtonSize.Large"), Value = "large" }, + new SelectListItem { Text = @T("Plugins.Payments.AmazonPay.AmazonButtonSize.Xlarge"), Value = "x-large" } + }) + @Html.ValidationMessageFor(model => model.AmazonButtonSize) +
    + @Html.SmartLabelFor(model => model.AddressWidgetWidth) + + @Html.SettingEditorFor(model => model.AddressWidgetWidth) + @Html.ValidationMessageFor(model => model.AddressWidgetWidth) +
    + @Html.SmartLabelFor(model => model.AddressWidgetHeight) + + @Html.SettingEditorFor(model => model.AddressWidgetHeight) + @Html.ValidationMessageFor(model => model.AddressWidgetHeight) +
    + @Html.SmartLabelFor(model => model.PaymentWidgetWidth) + + @Html.SettingEditorFor(model => model.PaymentWidgetWidth) + @Html.ValidationMessageFor(model => model.PaymentWidgetWidth) +
    + @Html.SmartLabelFor(model => model.PaymentWidgetHeight) + + @Html.SettingEditorFor(model => model.PaymentWidgetHeight) + @Html.ValidationMessageFor(model => model.PaymentWidgetHeight) +
    +
    +
    @Model.ConfigGroups.SafeGet(3)
    +
    +
    + @Html.SmartLabelFor(model => model.ShowButtonInMiniShoppingCart) + + @Html.SettingEditorFor(model => model.ShowButtonInMiniShoppingCart) + @Html.ValidationMessageFor(model => model.ShowButtonInMiniShoppingCart) +
    + @Html.SmartLabelFor(model => model.AdditionalFee) + + @Html.SettingEditorFor(model => model.AdditionalFee) + @Html.ValidationMessageFor(model => model.AdditionalFee) +
    + @Html.SmartLabelFor(model => model.AdditionalFeePercentage) + + @Html.SettingEditorFor(model => model.AdditionalFeePercentage) + @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) +
    +
    + @T("Plugins.Payments.AmazonPay.AdditionalFee.Warning") +
    +
      + +
    +} + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/PaymentMethod.Mobile.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/PaymentMethod.Mobile.cshtml new file mode 100644 index 0000000000..b1a2a86dce --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/PaymentMethod.Mobile.cshtml @@ -0,0 +1,62 @@ +@using SmartStore.Web.Models.Checkout; + +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +@{ + Layout = "~/Views/Shared/_Root.cshtml"; + + Html.AddTitleParts(T("PageTitle.Checkout").Text); +} + +
    +
    +

    @T("Checkout.SelectPaymentMethod")

    +
    + +
    + @Html.Widget("checkout_payment_method_top") + + @using (Html.BeginForm("PaymentMethod", "AmazonPayCheckout", new { area = Model.SystemName }, FormMethod.Post)) + { + if (Model.DisplayRewardPoints) + { +
    + @Html.EditorFor(model => model.UseRewardPoints) + +
    + } + +
    +
    +
    + +
    + +
    + + @Html.Widget("checkout_payment_method_bottom") + } +
    +
    + + diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/PaymentMethod.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/PaymentMethod.cshtml new file mode 100644 index 0000000000..97428bf60d --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/PaymentMethod.cshtml @@ -0,0 +1,80 @@ +@using SmartStore.Web.Models.Checkout; + +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +@{ + Layout = "~/Views/Shared/_Checkout.cshtml"; + + Html.AddTitleParts(T("PageTitle.Checkout").Text); + Html.AddCssFileParts(true, Url.Content("~/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css")); +} + +@section orderProgress{ + @Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Payment, area = "" }) +} + +
    +
    +

    @T("Checkout.SelectPaymentMethod")

    +
    + +
    + @Html.Widget("checkout_payment_method_top") + + @using (Html.BeginForm("PaymentMethod", "AmazonPayCheckout", new { area = Model.SystemName }, FormMethod.Post)) + { + if (Model.DisplayRewardPoints) + { +
    + +
    + } + +
    +
    +
    + +
    +
    +
    + +  @T("Common.Back") + + + +
    +
    +
    + + @Html.Widget("checkout_payment_method_bottom") + } +
    +
    + + diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/ShippingAddress.Mobile.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/ShippingAddress.Mobile.cshtml new file mode 100644 index 0000000000..92da862a33 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/ShippingAddress.Mobile.cshtml @@ -0,0 +1,66 @@ +@using SmartStore.Web.Models.Checkout; + +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +@{ + Layout = "~/Views/Shared/_Root.cshtml"; + + Html.AddTitleParts(T("PageTitle.Checkout").Text); +} + +
    +
    +

    @T("Checkout.ShippingAddress")

    +
    + +
    + @Html.Widget("mobile_checkout_shipping_address_top") + + @if (Model.Warning.HasValue()) + { +
    +
      +
    • @Model.Warning
    • +
    +
    + } + +
    +
    +
    + + @Html.Widget("mobile_checkout_shipping_address_middle") + + + + @Html.Widget("mobile_checkout_shipping_address_bottom") +
    +
    + + diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/ShippingAddress.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/ShippingAddress.cshtml new file mode 100644 index 0000000000..43a362503e --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayCheckout/ShippingAddress.cshtml @@ -0,0 +1,74 @@ +@using SmartStore.Web.Models.Checkout; + +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +@{ + Layout = "~/Views/Shared/_Checkout.cshtml"; + + Html.AddTitleParts(T("PageTitle.Checkout").Text); + Html.AddCssFileParts(true, Url.Content("~/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css")); +} + +@section orderProgress{ + @Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Address, area = "" }) +} + +
    +
    +

    @T("Checkout.ShippingAddress")

    +
    + +
    + @Html.Widget("checkout_shipping_address_top") + + @if (Model.Warning.HasValue()) + { +
    @Model.Warning
    + } + +
    +
    +
    + + @Html.Widget("checkout_shipping_address_middle") + + + + @Html.Widget("checkout_shipping_address_bottom") +
    +
    + + diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/MiniShoppingCart.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/MiniShoppingCart.cshtml new file mode 100644 index 0000000000..e6f8bc8ab2 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/MiniShoppingCart.cshtml @@ -0,0 +1,12 @@ +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +
    +
    + @T("Plugins.Payments.AmazonPay.SelectionText") +
    +
    + +
    +
    + +@Html.Partial("ScriptingLoginButton", Model) \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/OrderReviewData.Mobile.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/OrderReviewData.Mobile.cshtml new file mode 100644 index 0000000000..c5a2fc670e --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/OrderReviewData.Mobile.cshtml @@ -0,0 +1,42 @@ +@using SmartStore.Web.Framework; + +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +
    + @if (Model.IsShippable) + { +
    + @if (Model.ShippingMethod.HasValue()) + { +
    +
    + @T("Order.ShippingMethod") +
    +
    + @Model.ShippingMethod +
    +
    + } + +
    + @T("Order.ShippingAddress") +
    +
    +
    +
    +
    + } + +
    +
    + @T("Order.PaymentMethod") +
    +
    +
    +
    +
    +
    + +
    + +@Html.Partial("ScriptingReadWidgets", Model) \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/OrderReviewData.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/OrderReviewData.cshtml new file mode 100644 index 0000000000..dd3310996c --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/OrderReviewData.cshtml @@ -0,0 +1,59 @@ +@using SmartStore.Web.Framework; + +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +@{ + Html.AddCssFileParts(true, Url.Content("~/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css")); +} + +
    +
    + + @if (Model.IsShippable) + { +
    +
    +
    + @T("Order.ShippingAddress") + @T("Common.Change") +
    +
    +
    +
    +
    +
    + } + +
    +
    +
    + @T("Order.PaymentMethod") + @T("Common.Change") +
    +
    +
    +
    +
    +
    + +
    + + @if (Model.ShippingMethod.HasValue()) + { +
    +
    +
    + @T("Order.ShippingMethod") + @T("Common.Change") +
    +
    + @Model.ShippingMethod +
    +
    +
    + } +
    + +
    + +@Html.Partial("ScriptingReadWidgets", Model) \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ScriptingLoginButton.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ScriptingLoginButton.cshtml new file mode 100644 index 0000000000..0d2df6af7b --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ScriptingLoginButton.cshtml @@ -0,0 +1,25 @@ +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + + diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ScriptingReadWidgets.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ScriptingReadWidgets.cshtml new file mode 100644 index 0000000000..c81d770773 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ScriptingReadWidgets.cshtml @@ -0,0 +1,41 @@ +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + + diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ShoppingCart.Mobile.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ShoppingCart.Mobile.cshtml new file mode 100644 index 0000000000..f7011c55a1 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ShoppingCart.Mobile.cshtml @@ -0,0 +1,14 @@ +@using SmartStore.Web.Framework; +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +@{ + Layout = ""; +} + +
    +
    + +
    +
    + +@Html.Partial("ScriptingLoginButton", Model) \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ShoppingCart.cshtml b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ShoppingCart.cshtml new file mode 100644 index 0000000000..ebc2408f82 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/AmazonPayShoppingCart/ShoppingCart.cshtml @@ -0,0 +1,22 @@ +@using SmartStore.Web.Framework; +@model SmartStore.AmazonPay.Models.AmazonPayViewModel + +@{ + Layout = ""; + Html.AddCssFileParts(true, Url.Content("~/Plugins/SmartStore.AmazonPay/Content/smartstore.amazonpay.css")); +} +@if (!String.IsNullOrEmpty(Model.SellerId)) { +
    +
    + @T("Plugins.Payments.AmazonPay.SelectionText") +
    + +
    +
    + +
    +
    +
    + + @Html.Partial("ScriptingLoginButton", Model) +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/Views/Web.config b/src/Plugins/SmartStore.AmazonPay/Views/Web.config new file mode 100644 index 0000000000..52f7e9b6f7 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.AmazonPay/Widgets/AmazonPayWidget.cs b/src/Plugins/SmartStore.AmazonPay/Widgets/AmazonPayWidget.cs new file mode 100644 index 0000000000..81b4a739e4 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/Widgets/AmazonPayWidget.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Web; +using System.Web.Routing; +using SmartStore.Web.Models.ShoppingCart; +using SmartStore.AmazonPay.Services; +using SmartStore.AmazonPay.Extensions; +using SmartStore.Services.Cms; +using SmartStore.Core.Plugins; + +namespace SmartStore.AmazonPay.Widgets +{ + [SystemName("Widgets.AmazonPay")] + [FriendlyName("Pay with Amazon")] + public class AmazonPayWidget : IWidget + { + private readonly HttpContextBase _httpContext; + + public AmazonPayWidget(HttpContextBase httpContext) + { + _httpContext = httpContext; + } + + public IList GetWidgetZones() + { + return new List() + { + "order_summary_content_before", "mobile_order_summary_content_before", + "mini_shopping_cart_bottom", + "head_html_tag", "mobile_head_html_tag" + }; + } + + public void GetDisplayWidgetRoute(string widgetZone, object model, int storeId, out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + bool renderAmazonPayView = true; + + if (widgetZone.IsCaseInsensitiveEqual("head_html_tag") || widgetZone.IsCaseInsensitiveEqual("mobile_head_html_tag")) + { + actionName = "WidgetLibrary"; + } + else if (widgetZone.IsCaseInsensitiveEqual("mini_shopping_cart_bottom")) + { + actionName = "MiniShoppingCart"; + + var viewModel = model as MiniShoppingCartModel; + if (viewModel != null) + renderAmazonPayView = viewModel.DisplayCheckoutButton; + } + else + { + actionName = "OrderReviewData"; + + renderAmazonPayView = (_httpContext.HasAmazonPayState() && _httpContext.Request.RequestContext.RouteData.IsRouteEqual("Checkout", "Confirm")); + + if (renderAmazonPayView) + { + var viewModel = model as ShoppingCartModel; + if (viewModel != null) + viewModel.OrderReviewData.Display = false; + } + } + + controllerName = "AmazonPayShoppingCart"; + + routeValues = new RouteValueDictionary() + { + { "Namespaces", "SmartStore.AmazonPay.Controllers" }, + { "area", AmazonPayCore.SystemName }, + { "renderAmazonPayView", renderAmazonPayView } + }; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/changelog.md b/src/Plugins/SmartStore.AmazonPay/changelog.md new file mode 100644 index 0000000000..c22eca67c8 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/changelog.md @@ -0,0 +1,52 @@ +#Release Notes + +##Pay with Amazon 2.2.0.3 +###Improvements +* Added message token %SmartStore.AmazonPay.BillingAddressMessageNote% for billing address note in order placed customer notification + +##Pay with Amazon 2.2.0.2 +###Bugfixes +* Send currency code of primary store currency (not of working currency) to payment gateway + +##Pay with Amazon 2.2.0.1 +### New Features +* Supports order list label for new incoming IPNs + +##Pay with Amazon 1.20 +###Bugfixes +* PlatformID must be .NET ID not merchant ID. PlatformID needs to be identical for all orders + +##Pay with Amazon 1.19 +###Bugfixes +* Declined authorization IPN did not void the payment status + +##Pay with Amazon 1.18 +###Bugfixes +* Order wasn't found if the capturing\refunding took place at Amazon Seller Central and the notification came through IPN + +##Pay with Amazon 1.17 +###Improvements +* Amazon payments review + +##Pay with Amazon 1.16 +###Bugfixes +* Reflect refunds made at amazon seller central when using data polling + +##Pay with Amazon 1.15 +###Bugfixes +* Multistore configuration might be lost if "All stores" are left empty + +##Pay with Amazon 1.14 +###Bugfixes +* Data polling did not reflect the transaction status correctly if the action took place at amazon seller central + +##Pay with Amazon 1.13 +###Bugfixes +* Sometimes shipping method restrictions were not applied +* Shipping tab in checkout may show "Shipping address is not set" even if set + +##Pay with Amazon 1.12 +###Improvements +* Created this changelog +* Changed string „Bezahlen über Amazon“ into „Bezahlen mit Amazon“ + diff --git a/src/Plugins/SmartStore.AmazonPay/lib/OffAmazonPaymentsNotifications.dll b/src/Plugins/SmartStore.AmazonPay/lib/OffAmazonPaymentsNotifications.dll new file mode 100644 index 0000000000..597f5524c2 Binary files /dev/null and b/src/Plugins/SmartStore.AmazonPay/lib/OffAmazonPaymentsNotifications.dll differ diff --git a/src/Plugins/SmartStore.AmazonPay/lib/OffAmazonPaymentsService.dll b/src/Plugins/SmartStore.AmazonPay/lib/OffAmazonPaymentsService.dll new file mode 100644 index 0000000000..3114c7f9e4 Binary files /dev/null and b/src/Plugins/SmartStore.AmazonPay/lib/OffAmazonPaymentsService.dll differ diff --git a/src/Plugins/SmartStore.AmazonPay/packages.config b/src/Plugins/SmartStore.AmazonPay/packages.config new file mode 100644 index 0000000000..dd197b961a --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.AmazonPay/web.config b/src/Plugins/SmartStore.AmazonPay/web.config new file mode 100644 index 0000000000..3fd5b09a23 --- /dev/null +++ b/src/Plugins/SmartStore.AmazonPay/web.config @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.Clickatell/AdminMenu.cs b/src/Plugins/SmartStore.Clickatell/AdminMenu.cs new file mode 100644 index 0000000000..27ea086787 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/AdminMenu.cs @@ -0,0 +1,29 @@ +using SmartStore.Collections; +using SmartStore.Web.Framework.UI; + +namespace SmartStore.Clickatell +{ + public class AdminMenu : AdminMenuProvider + { + protected override void BuildMenuCore(TreeNode pluginsNode) + { + var menuItem = new MenuItem().ToBuilder() + .Text("Clickatell SMS Provider") + .ResKey("Plugins.FriendlyName.SmartStore.Clickatell") + .Icon("send-o") + .Action("ConfigurePlugin", "Plugin", new { systemName = "SmartStore.Clickatell", area = "Admin" }) + .ToItem(); + + pluginsNode.Prepend(menuItem); + } + + public override int Ordinal + { + get + { + return 100; + } + } + + } +} diff --git a/src/Plugins/SMS.Clickatell/ClickatellSettings.cs b/src/Plugins/SmartStore.Clickatell/ClickatellSettings.cs similarity index 95% rename from src/Plugins/SMS.Clickatell/ClickatellSettings.cs rename to src/Plugins/SmartStore.Clickatell/ClickatellSettings.cs index 5a5dd8e807..287f57a4e9 100644 --- a/src/Plugins/SMS.Clickatell/ClickatellSettings.cs +++ b/src/Plugins/SmartStore.Clickatell/ClickatellSettings.cs @@ -1,7 +1,7 @@  using SmartStore.Core.Configuration; -namespace SmartStore.Plugin.SMS.Clickatell +namespace SmartStore.Clickatell { public class ClickatellSettings : ISettings { diff --git a/src/Plugins/SmartStore.Clickatell/ClickatellSmsProvider.cs b/src/Plugins/SmartStore.Clickatell/ClickatellSmsProvider.cs new file mode 100644 index 0000000000..cd7fca5a22 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/ClickatellSmsProvider.cs @@ -0,0 +1,100 @@ +using System; +using System.ServiceModel; +using System.Web.Routing; +using SmartStore.Clickatell.Clickatell; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; + +namespace SmartStore.Clickatell +{ + /// + /// Represents the Clickatell SMS provider + /// + public class ClickatellSmsProvider : BasePlugin, IConfigurable + { + private readonly ILogger _logger; + private readonly ClickatellSettings _clickatellSettings; + private readonly ILocalizationService _localizationService; + + public ClickatellSmsProvider(ClickatellSettings clickatellSettings, + ILogger logger, + ILocalizationService localizationService) + { + this._clickatellSettings = clickatellSettings; + this._logger = logger; + _localizationService = localizationService; + } + + /// + /// Sends SMS + /// + /// Text + public bool SendSms(string text) + { + try + { + using (var svc = new PushServerWSPortTypeClient(new BasicHttpBinding(), new EndpointAddress("http://api.clickatell.com/soap/webservice_vs.php"))) + { + string authRsp = svc.auth(Int32.Parse(_clickatellSettings.ApiId), _clickatellSettings.Username, _clickatellSettings.Password); + + if (!authRsp.ToUpperInvariant().StartsWith("OK")) + { + throw new SmartException(authRsp); + } + + string ssid = authRsp.Substring(4); + string[] sndRsp = svc.sendmsg(ssid, + Int32.Parse(_clickatellSettings.ApiId), _clickatellSettings.Username, + _clickatellSettings.Password, new string[1] { _clickatellSettings.PhoneNumber }, + String.Empty, text, 0, 0, 0, 0, 0, 0, 0, 0, 0, + String.Empty, 0, String.Empty, String.Empty, String.Empty, 0); + + if (!sndRsp[0].ToUpperInvariant().StartsWith("ID")) + { + throw new SmartException(sndRsp[0]); + } + return true; + } + } + catch (Exception ex) + { + _logger.Error(ex.Message, ex); + } + return false; + } + + /// + /// Gets a route for provider configuration + /// + /// Action name + /// Controller name + /// Route values + public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "SmsClickatell"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.Clickatell" } }; + } + + /// + /// Install plugin + /// + public override void Install() + { + _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + } + + /// + /// Uninstall plugin + /// + public override void Uninstall() + { + _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); + + base.Uninstall(); + } + } +} diff --git a/src/Plugins/SMS.Clickatell/Controllers/SmsClickatellController.cs b/src/Plugins/SmartStore.Clickatell/Controllers/SmsClickatellController.cs similarity index 93% rename from src/Plugins/SMS.Clickatell/Controllers/SmsClickatellController.cs rename to src/Plugins/SmartStore.Clickatell/Controllers/SmsClickatellController.cs index b951acfac0..82be6e7725 100644 --- a/src/Plugins/SMS.Clickatell/Controllers/SmsClickatellController.cs +++ b/src/Plugins/SmartStore.Clickatell/Controllers/SmsClickatellController.cs @@ -1,15 +1,18 @@ using System; using System.Web.Mvc; using SmartStore.Core.Plugins; -using SmartStore.Plugin.Sms.Clickatell.Models; -using SmartStore.Plugin.SMS.Clickatell; +using SmartStore.Clickatell.Models; +using SmartStore.Clickatell; using SmartStore.Services.Configuration; using SmartStore.Services.Localization; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Security; -namespace SmartStore.Plugin.Sms.Clickatell.Controllers +namespace SmartStore.Clickatell.Controllers { + [AdminAuthorize] public class SmsClickatellController : PluginControllerBase { private readonly ClickatellSettings _clickatellSettings; @@ -70,7 +73,7 @@ public ActionResult TestSms(SmsClickatellModel model) } else { - var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName("Mobile.SMS.Clickatell"); + var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName("SmartStore.Clickatell"); if (pluginDescriptor == null) throw new Exception("Cannot load the plugin"); var plugin = pluginDescriptor.Instance() as ClickatellSmsProvider; diff --git a/src/Plugins/SmartStore.Clickatell/Description.txt b/src/Plugins/SmartStore.Clickatell/Description.txt new file mode 100644 index 0000000000..177b509843 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/Description.txt @@ -0,0 +1,8 @@ +FriendlyName: Clickatell SMS Provider +SystemName: SmartStore.Clickatell +Group: Mobile +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 1 +FileName: SmartStore.Clickatell.dll +ResourceRootKey: Plugins.Sms.Clickatell \ No newline at end of file diff --git a/src/Plugins/SmartStore.Clickatell/Localization/resources.de-de.xml b/src/Plugins/SmartStore.Clickatell/Localization/resources.de-de.xml new file mode 100644 index 0000000000..6a88b543c5 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/Localization/resources.de-de.xml @@ -0,0 +1,70 @@ + + + Clickatell SMS-Anbieter + + + + + Um ein Benachrichtigung per SMS zu erhalten wenn eine Bestellung in Ihrem Shop durchgeführt wurde, + müssen folgende Schritte durchgeführt werden. +

    +
      +
    • Registrieren Sie sich hier für einen Clickatell-Account
    • +
    • Clickatell funktioniert in allen Ländern und bietet 10 kostenlose SMS zum Testen der Benachrichtigungen an
    • +
    • Füllen Sie das folgende Formular mit Ihren Clickatell-Accountdaten und der Telefonnummer zu der die Nachrichten gesendet werden sollen
    • +
    • Klicken Sie auf den 'Speichern'-Button
    • +
    • Wenn nun eine neue Bestellung durchgeführt wird, erhalten Sie automatisch eine SMS
    • +
    + ]]> +
    +
    + + Testnachricht konnte nicht gesendet werden + + + Testnachricht wurde erfolgreich verschickt + + + Aktiv + + + Aktivieren Sie hier den SMS-Anbieter + + + API-ID + + + Clickatell API-ID + + + Passwort + + + Clickatell Passwort + + + Telefonnummer + + + Ihre Telefonnummer + + + Nutzername + + + Clickatell Nutzername + + + Text der Nachricht + + + Text der Testnachricht + + + Senden + + + Senden Sie eine Testnachricht + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.Clickatell/Localization/resources.en-us.xml b/src/Plugins/SmartStore.Clickatell/Localization/resources.en-us.xml new file mode 100644 index 0000000000..4a42186f01 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/Localization/resources.en-us.xml @@ -0,0 +1,68 @@ + + + Clickatell SMS Provider + + + + To receive an SMS notification when an order is placed from your store you need + to follow a few simple steps, which are shown below:

    +
      +
    • Register for a Clickatell account here
    • +
    • Clickatell works with all countries and includes 10 free messages so you can test SMS notifications
    • +
    • Fill in the form below with your Clickatell account details, including the number you want the notification messages to be sent to
    • +
    • Click 'Save' button
    • +
    • Now when you receive a new order, an SMS text message will be sent to the number you enter below automatically
    • +
    + ]]> +
    +
    + + Test message sending failed + + + Test message was sent + + + Enabled + + + Check the box to enable SMS provider + + + API ID + + + Clickatell API ID + + + Password + + + Clickatell password + + + Phone number + + + Your phone number + + + Username + + + Clickatell username + + + Message text + + + Text of the test message + + + Send + + + Send test message + +
    \ No newline at end of file diff --git a/src/Plugins/SMS.Clickatell/Models/SmsClickatellModel.cs b/src/Plugins/SmartStore.Clickatell/Models/SmsClickatellModel.cs similarity index 88% rename from src/Plugins/SMS.Clickatell/Models/SmsClickatellModel.cs rename to src/Plugins/SmartStore.Clickatell/Models/SmsClickatellModel.cs index 5af1c7c6d6..8d505b1072 100644 --- a/src/Plugins/SMS.Clickatell/Models/SmsClickatellModel.cs +++ b/src/Plugins/SmartStore.Clickatell/Models/SmsClickatellModel.cs @@ -1,6 +1,7 @@ using SmartStore.Web.Framework; +using System.ComponentModel.DataAnnotations; -namespace SmartStore.Plugin.Sms.Clickatell.Models +namespace SmartStore.Clickatell.Models { public class SmsClickatellModel { @@ -17,6 +18,7 @@ public class SmsClickatellModel public string Username { get; set; } [SmartResourceDisplayName("Plugins.Sms.Clickatell.Fields.Password")] + [DataType(DataType.Password)] public string Password { get; set; } diff --git a/src/Plugins/SMS.Clickatell/OrderPlacedEventConsumer.cs b/src/Plugins/SmartStore.Clickatell/OrderPlacedEventConsumer.cs similarity index 91% rename from src/Plugins/SMS.Clickatell/OrderPlacedEventConsumer.cs rename to src/Plugins/SmartStore.Clickatell/OrderPlacedEventConsumer.cs index 75e3c14310..3ba9e1742b 100644 --- a/src/Plugins/SMS.Clickatell/OrderPlacedEventConsumer.cs +++ b/src/Plugins/SmartStore.Clickatell/OrderPlacedEventConsumer.cs @@ -6,7 +6,7 @@ using SmartStore.Core; using SmartStore.Services.Configuration; -namespace SmartStore.Plugin.SMS.Clickatell +namespace SmartStore.Clickatell { public class OrderPlacedEventConsumer : IConsumer { @@ -14,7 +14,7 @@ public class OrderPlacedEventConsumer : IConsumer private readonly IPluginFinder _pluginFinder; private readonly IOrderService _orderService; private readonly IStoreContext _storeContext; - private readonly ISettingService _settingService; // codehint: sm-add + private readonly ISettingService _settingService; public OrderPlacedEventConsumer(ClickatellSettings clickatellSettings, IPluginFinder pluginFinder, @@ -26,7 +26,7 @@ public OrderPlacedEventConsumer(ClickatellSettings clickatellSettings, this._pluginFinder = pluginFinder; this._orderService = orderService; this._storeContext = storeContext; - this._settingService = settingService; // codehint: sm-add + this._settingService = settingService; } /// @@ -40,7 +40,7 @@ public void HandleEvent(OrderPlacedEvent eventMessage) return; //is plugin installed? - var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName("Mobile.SMS.Clickatell"); + var pluginDescriptor = _pluginFinder.GetPluginDescriptorBySystemName("SmartStore.Clickatell"); if (pluginDescriptor == null) return; diff --git a/src/Plugins/SmartStore.Clickatell/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.Clickatell/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..a1ffc6dc25 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.Clickatell")] diff --git a/src/Plugins/SmartStore.Clickatell/RouteProvider.cs b/src/Plugins/SmartStore.Clickatell/RouteProvider.cs new file mode 100644 index 0000000000..956b559e91 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/RouteProvider.cs @@ -0,0 +1,26 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.Clickatell +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.Clickatell", + "Plugins/SmartStore.Clickatell/{action}", + new { controller = "SmsClickatell", action = "Configure" }, + new[] { "SmartStore.Clickatell.Controllers" } + ) + .DataTokens["area"] = "SmartStore.Clickatell"; + } + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.Clickatell/Service References/Clickatell/Reference.cs b/src/Plugins/SmartStore.Clickatell/Service References/Clickatell/Reference.cs new file mode 100644 index 0000000000..fe2b19478f --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/Service References/Clickatell/Reference.cs @@ -0,0 +1,357 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.34209 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace SmartStore.Clickatell.Clickatell { + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(Namespace="http://api.clickatell.com/soap/webservice", ConfigurationName="Clickatell.PushServerWSPortType")] + internal interface PushServerWSPortType { + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/auth", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string auth(int api_id, string user, string password); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/ping", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string ping(string session_id); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/sendmsg", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] sendmsg( + string session_id, + int api_id, + string user, + string password, + string[] to, + string from, + string text, + int concat, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int unicode, + string msg_type, + string udh, + string data, + int validity); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/querymsg", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] querymsg(string session_id, int api_id, string user, string password, string apimsgid, string climsgid); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/delmsg", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] delmsg(string session_id, string api_id, string user, string password, string apimsgid, string climsgid); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/getbalance", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string getbalance(string session_id, int api_id, string user, string password); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/routeCoverage", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string routeCoverage(string session_id, int api_id, string user, string password, string msisdn); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/si_push", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] si_push( + string session_id, + int api_id, + string user, + string password, + string[] to, + string si_id, + string si_url, + string si_text, + string si_created, + string si_expires, + string si_action, + string from, + int concat, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int validity); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/ind_push", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] ind_push( + string session_id, + int api_id, + string user, + string password, + string[] to, + string mms_subject, + string mms_class, + string mms_expire, + string mms_from, + string mms_url, + string from, + int concat, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int validity); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/token_pay", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string token_pay(string session_id, int api_id, string user, string password, string token); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/startbatch", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] startbatch( + string session_id, + int api_id, + string user, + string password, + string from, + int concat, + string template, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int unicode, + string msg_type, + string udh, + string data, + int validity); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/senditem", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] senditem(string session_id, int api_id, string user, string password, string batch_id, string[] to, string field1, string field2, string field3, string field4); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/quicksend", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] quicksend(string session_id, int api_id, string user, string password, string batch_id, string[] to); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/endbatch", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] endbatch(string session_id, int api_id, string user, string password, string batch_id); + + [System.ServiceModel.OperationContractAttribute(Action="http://api.clickatell.com/soap/webservice_vs.php/getmsgcharge", ReplyAction="*")] + [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, SupportFaults=true, Use=System.ServiceModel.OperationFormatUse.Encoded)] + [return: System.ServiceModel.MessageParameterAttribute(Name="return")] + string[] getmsgcharge(string session_id, int api_id, string user, string password, string apimsgid); + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + internal interface PushServerWSPortTypeChannel : SmartStore.Clickatell.Clickatell.PushServerWSPortType, System.ServiceModel.IClientChannel { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + internal partial class PushServerWSPortTypeClient : System.ServiceModel.ClientBase, SmartStore.Clickatell.Clickatell.PushServerWSPortType { + + public PushServerWSPortTypeClient() { + } + + public PushServerWSPortTypeClient(string endpointConfigurationName) : + base(endpointConfigurationName) { + } + + public PushServerWSPortTypeClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public PushServerWSPortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public PushServerWSPortTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) { + } + + public string auth(int api_id, string user, string password) { + return base.Channel.auth(api_id, user, password); + } + + public string ping(string session_id) { + return base.Channel.ping(session_id); + } + + public string[] sendmsg( + string session_id, + int api_id, + string user, + string password, + string[] to, + string from, + string text, + int concat, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int unicode, + string msg_type, + string udh, + string data, + int validity) { + return base.Channel.sendmsg(session_id, api_id, user, password, to, from, text, concat, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, unicode, msg_type, udh, data, validity); + } + + public string[] querymsg(string session_id, int api_id, string user, string password, string apimsgid, string climsgid) { + return base.Channel.querymsg(session_id, api_id, user, password, apimsgid, climsgid); + } + + public string[] delmsg(string session_id, string api_id, string user, string password, string apimsgid, string climsgid) { + return base.Channel.delmsg(session_id, api_id, user, password, apimsgid, climsgid); + } + + public string getbalance(string session_id, int api_id, string user, string password) { + return base.Channel.getbalance(session_id, api_id, user, password); + } + + public string routeCoverage(string session_id, int api_id, string user, string password, string msisdn) { + return base.Channel.routeCoverage(session_id, api_id, user, password, msisdn); + } + + public string[] si_push( + string session_id, + int api_id, + string user, + string password, + string[] to, + string si_id, + string si_url, + string si_text, + string si_created, + string si_expires, + string si_action, + string from, + int concat, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int validity) { + return base.Channel.si_push(session_id, api_id, user, password, to, si_id, si_url, si_text, si_created, si_expires, si_action, from, concat, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, validity); + } + + public string[] ind_push( + string session_id, + int api_id, + string user, + string password, + string[] to, + string mms_subject, + string mms_class, + string mms_expire, + string mms_from, + string mms_url, + string from, + int concat, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int validity) { + return base.Channel.ind_push(session_id, api_id, user, password, to, mms_subject, mms_class, mms_expire, mms_from, mms_url, from, concat, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, validity); + } + + public string token_pay(string session_id, int api_id, string user, string password, string token) { + return base.Channel.token_pay(session_id, api_id, user, password, token); + } + + public string[] startbatch( + string session_id, + int api_id, + string user, + string password, + string from, + int concat, + string template, + int deliv_ack, + int msg_callback, + int deliv_time, + float max_credits, + int req_feat, + int queue, + int escalate, + int mo, + string cliMsgId, + int unicode, + string msg_type, + string udh, + string data, + int validity) { + return base.Channel.startbatch(session_id, api_id, user, password, from, concat, template, deliv_ack, msg_callback, deliv_time, max_credits, req_feat, queue, escalate, mo, cliMsgId, unicode, msg_type, udh, data, validity); + } + + public string[] senditem(string session_id, int api_id, string user, string password, string batch_id, string[] to, string field1, string field2, string field3, string field4) { + return base.Channel.senditem(session_id, api_id, user, password, batch_id, to, field1, field2, field3, field4); + } + + public string[] quicksend(string session_id, int api_id, string user, string password, string batch_id, string[] to) { + return base.Channel.quicksend(session_id, api_id, user, password, batch_id, to); + } + + public string[] endbatch(string session_id, int api_id, string user, string password, string batch_id) { + return base.Channel.endbatch(session_id, api_id, user, password, batch_id); + } + + public string[] getmsgcharge(string session_id, int api_id, string user, string password, string apimsgid) { + return base.Channel.getmsgcharge(session_id, api_id, user, password, apimsgid); + } + } +} diff --git a/src/Plugins/SMS.Clickatell/Service References/Clickatell/Reference.svcmap b/src/Plugins/SmartStore.Clickatell/Service References/Clickatell/Reference.svcmap similarity index 100% rename from src/Plugins/SMS.Clickatell/Service References/Clickatell/Reference.svcmap rename to src/Plugins/SmartStore.Clickatell/Service References/Clickatell/Reference.svcmap diff --git a/src/Plugins/SMS.Clickatell/Service References/Clickatell/configuration.svcinfo b/src/Plugins/SmartStore.Clickatell/Service References/Clickatell/configuration.svcinfo similarity index 100% rename from src/Plugins/SMS.Clickatell/Service References/Clickatell/configuration.svcinfo rename to src/Plugins/SmartStore.Clickatell/Service References/Clickatell/configuration.svcinfo diff --git a/src/Plugins/SMS.Clickatell/Service References/Clickatell/configuration91.svcinfo b/src/Plugins/SmartStore.Clickatell/Service References/Clickatell/configuration91.svcinfo similarity index 100% rename from src/Plugins/SMS.Clickatell/Service References/Clickatell/configuration91.svcinfo rename to src/Plugins/SmartStore.Clickatell/Service References/Clickatell/configuration91.svcinfo diff --git a/src/Plugins/SMS.Clickatell/Service References/Clickatell/webservice_vs.wsdl b/src/Plugins/SmartStore.Clickatell/Service References/Clickatell/webservice_vs.wsdl similarity index 100% rename from src/Plugins/SMS.Clickatell/Service References/Clickatell/webservice_vs.wsdl rename to src/Plugins/SmartStore.Clickatell/Service References/Clickatell/webservice_vs.wsdl diff --git a/src/Plugins/SmartStore.Clickatell/SmartStore.Clickatell.csproj b/src/Plugins/SmartStore.Clickatell/SmartStore.Clickatell.csproj new file mode 100644 index 0000000000..f7e9ee7a8e --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/SmartStore.Clickatell.csproj @@ -0,0 +1,241 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {E3362B5B-DA5A-4515-BCB0-0DF982F80E89} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.Clickatell + SmartStore.Clickatell + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.Clickatell\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.Clickatell\ + TRACE + prompt + 4 + false + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + True + True + Reference.svcmap + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + WCF Proxy Generator + Reference.cs + + + + + PreserveNewest + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 65206 + / + http://localhost:53086/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Clickatell/Views/SmsClickatell/Configure.cshtml b/src/Plugins/SmartStore.Clickatell/Views/SmsClickatell/Configure.cshtml new file mode 100644 index 0000000000..03b16cb275 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/Views/SmsClickatell/Configure.cshtml @@ -0,0 +1,105 @@ +@using SmartStore.Web.Framework; +@model SmartStore.Clickatell.Models.SmsClickatellModel +@{ + Layout = ""; +} + +
    + + @Html.Raw(@T("Plugins.Sms.Clickatell.AdminInstruction")) +
    + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.Enabled) + + @Html.EditorFor(model => model.Enabled) + @Html.ValidationMessageFor(model => model.Enabled) +
    + @Html.SmartLabelFor(model => model.PhoneNumber) + + @Html.EditorFor(model => model.PhoneNumber) + @Html.ValidationMessageFor(model => model.PhoneNumber) +
    + @Html.SmartLabelFor(model => model.ApiId) + + @Html.EditorFor(model => model.ApiId) + @Html.ValidationMessageFor(model => model.ApiId) +
    + @Html.SmartLabelFor(model => model.Username) + + @Html.EditorFor(model => model.Username) + @Html.ValidationMessageFor(model => model.Username) +
    + @Html.SmartLabelFor(model => model.Password) + + @Html.EditorFor(model => model.Password) + @Html.ValidationMessageFor(model => model.Password) +
    +   + + +
    +
    +
    @T("Plugins.Sms.Clickatell.SendTest.Hint")
    +
    +
    + @Html.SmartLabelFor(model => model.TestMessage) + + @Html.EditorFor(model => model.TestMessage) + @Html.ValidationMessageFor(model => model.TestMessage) +
    +   + + +
    + + if (!String.IsNullOrEmpty(Model.TestSmsResult)) + { +
    + + @Model.TestSmsResult +
    + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.Clickatell/Views/Web.config b/src/Plugins/SmartStore.Clickatell/Views/Web.config new file mode 100644 index 0000000000..31b7dee187 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/Views/Web.config @@ -0,0 +1,34 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SMS.Clickatell/icon.png b/src/Plugins/SmartStore.Clickatell/icon.png similarity index 100% rename from src/Plugins/SMS.Clickatell/icon.png rename to src/Plugins/SmartStore.Clickatell/icon.png diff --git a/src/Plugins/SmartStore.Clickatell/packages.config b/src/Plugins/SmartStore.Clickatell/packages.config new file mode 100644 index 0000000000..4bc06fc1a7 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Clickatell/web.config b/src/Plugins/SmartStore.Clickatell/web.config new file mode 100644 index 0000000000..ba87d0f098 --- /dev/null +++ b/src/Plugins/SmartStore.Clickatell/web.config @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.DevTools/AdminMenu.cs b/src/Plugins/SmartStore.DevTools/AdminMenu.cs new file mode 100644 index 0000000000..25ae68e381 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/AdminMenu.cs @@ -0,0 +1,28 @@ +using SmartStore.Collections; +using SmartStore.Web.Framework.UI; + +namespace SmartStore.DevTools +{ + public class AdminMenu : AdminMenuProvider + { + protected override void BuildMenuCore(TreeNode pluginsNode) + { + var menuItem = new MenuItem().ToBuilder() + .Text("Developer Tools") + .Icon("code") + .Action("ConfigurePlugin", "Plugin", new { systemName = "SmartStore.DevTools", area = "Admin" }) + .ToItem(); + + pluginsNode.Prepend(menuItem); + + // uncomment to add to admin menu (see plugin sub-menu) + //var backendExtensionItem = new MenuItem().ToBuilder() + // .Text("Backend extension") + // .Icon("area-chart") + // .Action("BackendExtension", "DevTools", new { area = "SmartStore.DevTools" }) + // .ToItem(); + + //pluginsNode.Append(backendExtensionItem); + } + } +} diff --git a/src/Plugins/SmartStore.DevTools/Controllers/DevToolsController.cs b/src/Plugins/SmartStore.DevTools/Controllers/DevToolsController.cs new file mode 100644 index 0000000000..5700d55470 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Controllers/DevToolsController.cs @@ -0,0 +1,82 @@ +using System.Web.Mvc; +using SmartStore.DevTools.Models; +using SmartStore.Services; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.DevTools.Controllers +{ + + public class DevToolsController : SmartController + { + private readonly ICommonServices _services; + + public DevToolsController(ICommonServices services) + { + _services = services; + } + + [AdminAuthorize, ChildActionOnly] + public ActionResult Configure() + { + // load settings for a chosen store scope + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, settings, storeScope, _services.Settings); + + return View(settings); + } + + [HttpPost, AdminAuthorize, ChildActionOnly] + public ActionResult Configure(ProfilerSettings model, FormCollection form) + { + if (!ModelState.IsValid) + return Configure(); + + ModelState.Clear(); + + // load settings for a chosen store scope + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + + storeDependingSettingHelper.UpdateSettings(model /*settings*/, form, storeScope, _services.Settings); + _services.Settings.ClearCache(); + + return Configure(); + } + + public ActionResult MiniProfiler() + { + return View(); + } + + public ActionResult WidgetZone(string widgetZone) + { + var storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + if (settings.DisplayWidgetZones) + { + ViewData["widgetZone"] = widgetZone; + + return View(); + } + + return new EmptyResult(); + } + + [AdminAuthorize] + public ActionResult BackendExtension() + { + var model = new BackendExtensionModel + { + Welcome = "Hello world!" + }; + + return View(model); + } + } +} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/Controllers/MyCheckoutController.cs b/src/Plugins/SmartStore.DevTools/Controllers/MyCheckoutController.cs similarity index 85% rename from src/Plugins/Developer.DevTools/Controllers/MyCheckoutController.cs rename to src/Plugins/SmartStore.DevTools/Controllers/MyCheckoutController.cs index 37b1e5be8a..ef7ca20cf2 100644 --- a/src/Plugins/Developer.DevTools/Controllers/MyCheckoutController.cs +++ b/src/Plugins/SmartStore.DevTools/Controllers/MyCheckoutController.cs @@ -6,7 +6,7 @@ //using SmartStore.Web.Controllers; //using SmartStore.Web.Framework.Controllers; -//namespace SmartStore.Plugin.Developer.DevTools.Controllers +//namespace SmartStore.DevTools.Controllers //{ // public class MyCheckoutController : PublicControllerBase // { diff --git a/src/Plugins/SmartStore.DevTools/DependencyRegistrar.cs b/src/Plugins/SmartStore.DevTools/DependencyRegistrar.cs new file mode 100644 index 0000000000..4e4cb6d96d --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/DependencyRegistrar.cs @@ -0,0 +1,37 @@ +using Autofac; +using Autofac.Integration.Mvc; +using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.DevTools.Filters; +using SmartStore.DevTools.Services; +using SmartStore.Web.Framework.Controllers; + +namespace SmartStore.DevTools +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + + if (isActiveModule && DataSettings.DatabaseIsInstalled()) + { + // intercept ALL public store controller actions + builder.RegisterType().AsActionFilterFor(); + builder.RegisterType().AsActionFilterFor(); + + //// intercept CatalogController's Product action + //builder.RegisterType().AsResultFilterFor(x => x.Product(default(int), default(string))).InstancePerRequest(); + //builder.RegisterType().AsActionFilterFor().InstancePerRequest(); + //// intercept CheckoutController's Index action (to hijack the checkout or payment workflow) + //builder.RegisterType().AsActionFilterFor(x => x.Index()).InstancePerRequest(); + } + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.DevTools/Description.txt b/src/Plugins/SmartStore.DevTools/Description.txt new file mode 100644 index 0000000000..b169d8b16a --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Description.txt @@ -0,0 +1,8 @@ +FriendlyName: SmartStore.NET Developer Tools (MiniProfiler and other goodies) +SystemName: SmartStore.DevTools +Group: Developer +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 1 +FileName: SmartStore.DevTools.dll +ResourceRootKey: Plugins.Developer.DevTools \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/DevToolsPlugin.cs b/src/Plugins/SmartStore.DevTools/DevToolsPlugin.cs similarity index 87% rename from src/Plugins/Developer.DevTools/DevToolsPlugin.cs rename to src/Plugins/SmartStore.DevTools/DevToolsPlugin.cs index db5d20ef01..10e0592a42 100644 --- a/src/Plugins/Developer.DevTools/DevToolsPlugin.cs +++ b/src/Plugins/SmartStore.DevTools/DevToolsPlugin.cs @@ -6,10 +6,9 @@ using SmartStore.Services.Common; using SmartStore.Services.Configuration; -namespace SmartStore.Plugin.Developer.DevTools +namespace SmartStore.DevTools { - - public class DevToolsPlugin : BasePlugin, IMiscPlugin + public class DevToolsPlugin : BasePlugin, IConfigurable { private readonly ISettingService _settingService; @@ -25,7 +24,7 @@ public void GetConfigurationRoute(out string actionName, out string controllerNa { actionName = "Configure"; controllerName = "DevTools"; - routeValues = new RouteValueDictionary(new { area = "Developer.DevTools" }); + routeValues = new RouteValueDictionary() { { "area", "SmartStore.DevTools" } }; } public override void Install() diff --git a/src/Plugins/Developer.DevTools/Filters/ProfilerFilter.cs b/src/Plugins/SmartStore.DevTools/Filters/ProfilerFilter.cs similarity index 82% rename from src/Plugins/Developer.DevTools/Filters/ProfilerFilter.cs rename to src/Plugins/SmartStore.DevTools/Filters/ProfilerFilter.cs index 581d49ed36..2971dabe08 100644 --- a/src/Plugins/Developer.DevTools/Filters/ProfilerFilter.cs +++ b/src/Plugins/SmartStore.DevTools/Filters/ProfilerFilter.cs @@ -8,13 +8,13 @@ using System.Web.Mvc; using SmartStore.Core.Logging; using SmartStore.Core.Localization; -using SmartStore.Plugin.Developer.DevTools.Services; +using SmartStore.DevTools.Services; using SmartStore.Core; using SmartStore.Services; using SmartStore.Services.Customers; using SmartStore.Web.Framework.UI; -namespace SmartStore.Plugin.Developer.DevTools.Filters +namespace SmartStore.DevTools.Filters { public class ProfilerFilter : IActionFilter, IResultFilter { @@ -46,7 +46,7 @@ public void OnActionExecuting(ActionExecutingContext filterContext) string.Empty; string controller = string.Concat(filterContext.Controller.ToString().Split('.').Last(), "."); string action = filterContext.ActionDescriptor.ActionName; - this._profiler.Value.StepStart("ActionFilter", "Controller: " + area + controller + action); + this._profiler.Value.StepStart("ActionFilter", "Action: " + area + controller + action); } public void OnActionExecuted(ActionExecutedContext filterContext) @@ -54,7 +54,10 @@ public void OnActionExecuted(ActionExecutedContext filterContext) if (!_profilerSettings.EnableMiniProfilerInPublicStore) return; - this._profiler.Value.StepStop("ActionFilter"); + if (!(filterContext.Result is ViewResultBase)) + { + this._profiler.Value.StepStop("ActionFilter"); + } } public void OnResultExecuting(ResultExecutingContext filterContext) @@ -63,7 +66,8 @@ public void OnResultExecuting(ResultExecutingContext filterContext) return; // should only run on a full view rendering result - if (!(filterContext.Result is ViewResultBase)) + var result = filterContext.Result as ViewResultBase; + if (result == null) { return; } @@ -73,16 +77,23 @@ public void OnResultExecuting(ResultExecutingContext filterContext) return; } + var viewName = result.ViewName; + if (viewName.IsEmpty()) + { + string action = (filterContext.RouteData.Values["action"] as string).EmptyNull(); + viewName = action; + } + + this._profiler.Value.StepStart("ResultFilter", string.Format("{0}: {1}", result is PartialViewResult ? "Partial" : "View", viewName)); + if (!filterContext.IsChildAction) { _widgetProvider.Value.RegisterAction( "head_html_tag", "MiniProfiler", "DevTools", - new { Namespaces = "SmartStore.Plugin.Developer.DevTools.Controllers", area = "Developer.DevTools" }); + new { area = "SmartStore.DevTools" }); } - - this._profiler.Value.StepStart("ResultFilter", string.Format("Result: {0}", filterContext.Result)); } public void OnResultExecuted(ResultExecutedContext filterContext) @@ -102,15 +113,11 @@ public void OnResultExecuted(ResultExecutedContext filterContext) } this._profiler.Value.StepStop("ResultFilter"); + this._profiler.Value.StepStop("ActionFilter"); } private bool ShouldProfile(HttpContextBase ctx) { - if (_services.WorkContext.IsAdmin) - { - return false; - } - if (!_services.WorkContext.CurrentCustomer.IsAdmin()) { return ctx.Request.IsLocal; diff --git a/src/Plugins/Developer.DevTools/Filters/Samples/SampleActionFilter.cs b/src/Plugins/SmartStore.DevTools/Filters/Samples/SampleActionFilter.cs similarity index 95% rename from src/Plugins/Developer.DevTools/Filters/Samples/SampleActionFilter.cs rename to src/Plugins/SmartStore.DevTools/Filters/Samples/SampleActionFilter.cs index 2a2e79c3b6..e1cb06dc72 100644 --- a/src/Plugins/Developer.DevTools/Filters/Samples/SampleActionFilter.cs +++ b/src/Plugins/SmartStore.DevTools/Filters/Samples/SampleActionFilter.cs @@ -9,7 +9,7 @@ using SmartStore.Core.Logging; using SmartStore.Core.Localization; -namespace SmartStore.Plugin.Developer.DevTools.Filters +namespace SmartStore.DevTools.Filters { public class SampleActionFilter : IActionFilter { diff --git a/src/Plugins/Developer.DevTools/Filters/Samples/SampleCheckoutFilter.cs b/src/Plugins/SmartStore.DevTools/Filters/Samples/SampleCheckoutFilter.cs similarity index 93% rename from src/Plugins/Developer.DevTools/Filters/Samples/SampleCheckoutFilter.cs rename to src/Plugins/SmartStore.DevTools/Filters/Samples/SampleCheckoutFilter.cs index cd5d9342a3..59f4856a07 100644 --- a/src/Plugins/Developer.DevTools/Filters/Samples/SampleCheckoutFilter.cs +++ b/src/Plugins/SmartStore.DevTools/Filters/Samples/SampleCheckoutFilter.cs @@ -11,7 +11,7 @@ using SmartStore.Core.Localization; using SmartStore.Utilities; -namespace SmartStore.Plugin.Developer.DevTools.Filters +namespace SmartStore.DevTools.Filters { public class SampleCheckoutFilter : IActionFilter { diff --git a/src/Plugins/Developer.DevTools/Filters/Samples/SampleResultFilter.cs b/src/Plugins/SmartStore.DevTools/Filters/Samples/SampleResultFilter.cs similarity index 90% rename from src/Plugins/Developer.DevTools/Filters/Samples/SampleResultFilter.cs rename to src/Plugins/SmartStore.DevTools/Filters/Samples/SampleResultFilter.cs index 93c5290b95..941ef81a1a 100644 --- a/src/Plugins/Developer.DevTools/Filters/Samples/SampleResultFilter.cs +++ b/src/Plugins/SmartStore.DevTools/Filters/Samples/SampleResultFilter.cs @@ -6,9 +6,9 @@ using System.Threading.Tasks; using System.Web; using System.Web.Mvc; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; -namespace SmartStore.Plugin.Developer.DevTools.Filters +namespace SmartStore.DevTools.Filters { public class SampleResultFilter : IResultFilter { diff --git a/src/Plugins/SmartStore.DevTools/Filters/WidgetZoneFilter.cs b/src/Plugins/SmartStore.DevTools/Filters/WidgetZoneFilter.cs new file mode 100644 index 0000000000..253fdd0b60 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Filters/WidgetZoneFilter.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core.Logging; +using SmartStore.Core.Localization; +using SmartStore.DevTools.Services; +using SmartStore.Core; +using SmartStore.Services; +using SmartStore.Services.Customers; +using SmartStore.Web.Framework.UI; +using SmartStore.Utilities; +using System.IO; + +namespace SmartStore.DevTools.Filters +{ + public class WidgetZoneFilter : IActionFilter, IResultFilter + { + private readonly ICommonServices _services; + private readonly Lazy _widgetProvider; + private readonly ProfilerSettings _profilerSettings; + + public WidgetZoneFilter( + ICommonServices services, + Lazy widgetProvider, + ProfilerSettings profilerSettings) + { + this._services = services; + this._widgetProvider = widgetProvider; + this._profilerSettings = profilerSettings; + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + } + + public void OnResultExecuting(ResultExecutingContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + + // should only run on a full view rendering result + var result = filterContext.Result as ViewResultBase; + if (result == null) + { + return; + } + + if (!this.ShouldRender(filterContext.HttpContext)) + { + return; + } + + if (!filterContext.IsChildAction) + { + _widgetProvider.Value.RegisterAction( + new Wildcard("*"), + "WidgetZone", + "DevTools", + new { area = "SmartStore.DevTools" }); + } + + var viewName = result.ViewName; + + if (viewName.IsEmpty()) + { + string action = (filterContext.RouteData.Values["action"] as string).EmptyNull(); + viewName = action; + + if (action == "WidgetsByZone") + { + var model = result.Model as WidgetZoneModel; + + filterContext.Result = new ViewResult + { + ViewName = "~/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml", + }; + filterContext.RouteData.Values.Add("widgetZone", model.WidgetZone); + } + } + } + + public void OnResultExecuted(ResultExecutedContext filterContext) + { + if (!_profilerSettings.DisplayWidgetZones) + return; + + // should only run on a full view rendering result + if (!(filterContext.Result is ViewResultBase)) + { + return; + } + + if (!this.ShouldRender(filterContext.HttpContext)) + { + return; + } + } + + private bool ShouldRender(HttpContextBase ctx) + { + if (!_services.WorkContext.CurrentCustomer.IsAdmin()) + { + return ctx.Request.IsLocal; + } + + return true; + } + + } +} diff --git a/src/Plugins/SmartStore.DevTools/Models/BackendExtensionModel.cs b/src/Plugins/SmartStore.DevTools/Models/BackendExtensionModel.cs new file mode 100644 index 0000000000..2db540028f --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Models/BackendExtensionModel.cs @@ -0,0 +1,9 @@ +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.DevTools.Models +{ + public class BackendExtensionModel : ModelBase + { + public string Welcome { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/ProfilerHttpModule.cs b/src/Plugins/SmartStore.DevTools/ProfilerHttpModule.cs new file mode 100644 index 0000000000..c2e585d0eb --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/ProfilerHttpModule.cs @@ -0,0 +1,78 @@ +using System; +using System.Web; +using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; +using StackExchange.Profiling; + +namespace SmartStore.DevTools +{ + + public class ProfilerHttpModule : IHttpModule + { + private const string MP_KEY = "sm.miniprofiler.started"; + + public void Init(HttpApplication context) + { + context.BeginRequest += OnBeginRequest; + context.EndRequest += OnEndRequest; + } + + public static void OnBeginRequest(object sender, EventArgs e) + { + var app = (HttpApplication)sender; + if (ShouldProfile(app)) + { + MiniProfiler.Start(); + if (app.Context != null && app.Context.Items != null) + { + app.Context.Items[MP_KEY] = true; + } + } + } + + public static void OnEndRequest(object sender, EventArgs e) + { + var app = (HttpApplication)sender; + if (app.Context != null && app.Context.Items != null && app.Context.Items.Contains(MP_KEY)) + { + MiniProfiler.Stop(); + } + } + + private static bool ShouldProfile(HttpApplication app) + { + if (app.Context == null || app.Context.Request == null) + return false; + + if (!DataSettings.DatabaseIsInstalled()) + { + return false; + } + + var url = app.Context.Request.AppRelativeCurrentExecutionFilePath; + if (url.StartsWith("~/admin", StringComparison.InvariantCultureIgnoreCase) || url.StartsWith("~/mini-profiler", StringComparison.InvariantCultureIgnoreCase) || url.StartsWith("~/bundles", StringComparison.InvariantCultureIgnoreCase)) + { + return false; + } + + ProfilerSettings settings; + if (!EngineContext.Current.ContainerManager.TryResolve(null, out settings)) + { + return false; + } + + if (!settings.EnableMiniProfilerInPublicStore) + { + return false; + } + + return true; + } + + public void Dispose() + { + // nothing to dispose + } + } + +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.DevTools/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..409d93eb12 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.DevTools")] diff --git a/src/Plugins/SmartStore.DevTools/RouteProvider.cs b/src/Plugins/SmartStore.DevTools/RouteProvider.cs new file mode 100644 index 0000000000..607fff468d --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/RouteProvider.cs @@ -0,0 +1,35 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.DevTools +{ + + public class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.DevTools", + "Plugin/SmartStore.DevTools/{action}/{id}", + new { controller = "DevTools", action = "Configure", id = UrlParameter.Optional }, + new[] { "SmartStore.DevTools.Controllers" } + ) + .DataTokens["area"] = "SmartStore.DevTools"; + + //routes.MapRoute("SmartStore.DevTools.MyCheckout", + // "MyCheckout/{action}", + // new { controller = "MyCheckout", action = "MyBillingAddress" }, + // new[] { "SmartStore.DevTools.Controllers" } + //) + //.DataTokens["area"] = "SmartStore.DevTools"; + } + public int Priority + { + get + { + return 0; + } + } + } + +} diff --git a/src/Plugins/SmartStore.DevTools/Services/IProfilerService.cs b/src/Plugins/SmartStore.DevTools/Services/IProfilerService.cs new file mode 100644 index 0000000000..bf4a87f497 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Services/IProfilerService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace SmartStore.DevTools.Services +{ + public interface IProfilerService + { + void StepStart(string key, string message); + void StepStop(string key); + } +} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/Services/ProfilerService.cs b/src/Plugins/SmartStore.DevTools/Services/ProfilerService.cs similarity index 79% rename from src/Plugins/Developer.DevTools/Services/ProfilerService.cs rename to src/Plugins/SmartStore.DevTools/Services/ProfilerService.cs index 7c60791512..e490e592f2 100644 --- a/src/Plugins/Developer.DevTools/Services/ProfilerService.cs +++ b/src/Plugins/SmartStore.DevTools/Services/ProfilerService.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using StackExchange.Profiling; -namespace SmartStore.Plugin.Developer.DevTools.Services +namespace SmartStore.DevTools.Services { public class ProfilerService : IProfilerService, IDisposable { @@ -23,7 +23,7 @@ protected MiniProfiler Profiler } } - public void StepStart(string key, string message, bool isVerbose = false) + public void StepStart(string key, string message) { if (this.Profiler == null) { @@ -31,7 +31,7 @@ public void StepStart(string key, string message, bool isVerbose = false) } var stack = this.steps.GetOrAdd(key, k => new ConcurrentStack()); - var step = this.Profiler.Step(message, isVerbose ? ProfileLevel.Verbose : ProfileLevel.Info); + var step = this.Profiler.Step(message); stack.Push(step); } @@ -43,9 +43,12 @@ public void StepStop(string key) } IDisposable step; - if (this.steps[key].TryPop(out step)) + if (this.steps.ContainsKey(key)) { - step.Dispose(); + if (this.steps[key].TryPop(out step)) + { + step.Dispose(); + } } } diff --git a/src/Plugins/SmartStore.DevTools/Settings/ProfilerSettings.cs b/src/Plugins/SmartStore.DevTools/Settings/ProfilerSettings.cs new file mode 100644 index 0000000000..88da20c658 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Settings/ProfilerSettings.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using SmartStore.Core.Configuration; + +namespace SmartStore.DevTools +{ + public class ProfilerSettings : ISettings + { + public bool EnableMiniProfilerInPublicStore { get; set; } + + public bool DisplayWidgetZones { get; set; } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj new file mode 100644 index 0000000000..c8f46ee502 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/SmartStore.DevTools.csproj @@ -0,0 +1,260 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {542B9C12-E2A1-49BB-9134-0E3484F9D669} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.DevTools + SmartStore.DevTools + v4.5.1 + 512 + + ..\..\ + true + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.DevTools\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.DevTools\ + TRACE + prompt + 4 + false + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + False + ..\..\packages\MiniProfiler.3.1.1.140\lib\net40\MiniProfiler.dll + True + + + False + ..\..\packages\MiniProfiler.EF6.3.0.11\lib\net40\MiniProfiler.EntityFramework6.dll + True + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} + SmartStore.Data + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + PreserveNewest + + + + + + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + bin\ + + + + + + + Dieses Projekt verweist auf mindestens ein NuGet-Paket, das auf diesem Computer fehlt. Aktivieren Sie die Wiederherstellung von NuGet-Paketen, um die fehlende Datei herunterzuladen. Weitere Informationen finden Sie unter "http://go.microsoft.com/fwlink/?LinkID=322105". Die fehlende Datei ist "{0}". + + + + + + + + + + False + True + 63704 + / + http://localhost:52742/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/Starter.cs b/src/Plugins/SmartStore.DevTools/Starter.cs new file mode 100644 index 0000000000..b8b9d3c97c --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Starter.cs @@ -0,0 +1,31 @@ +using Microsoft.Web.Infrastructure.DynamicModuleHelper; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Plugins; +using SmartStore.Web.Framework; + +namespace SmartStore.DevTools +{ + + public class ProfilerPreApplicationStart : IPreApplicationStart + { + public void Start() + { + DynamicModuleUtility.RegisterModule(typeof(ProfilerHttpModule)); + SmartUrlRoutingModule.RegisterRoutablePath("/mini-profiler-resources/(.*)"); + } + } + + public class ProfilerStartupTask : IStartupTask + { + public void Execute() + { + StackExchange.Profiling.EntityFramework6.MiniProfilerEF6.Initialize(); + } + + public int Order + { + get { return int.MinValue; } + } + } + +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DevTools/Views/DevTools/BackendExtension.cshtml b/src/Plugins/SmartStore.DevTools/Views/DevTools/BackendExtension.cshtml new file mode 100644 index 0000000000..d2e818b648 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Views/DevTools/BackendExtension.cshtml @@ -0,0 +1,18 @@ +@using SmartStore.DevTools.Models; +@model BackendExtensionModel +@{ + Layout = "~/Administration/Views/Shared/_AdminLayout.cshtml"; + + ViewBag.Title = "My SmartStore.NET backend extension page"; +} + +
    +
    + + My SmartStore.NET backend extension page +
    +
    + +
    + @Model.Welcome +
    diff --git a/src/Plugins/SmartStore.DevTools/Views/DevTools/Configure.cshtml b/src/Plugins/SmartStore.DevTools/Views/DevTools/Configure.cshtml new file mode 100644 index 0000000000..7f1bdc6101 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Views/DevTools/Configure.cshtml @@ -0,0 +1,39 @@ +@model SmartStore.DevTools.ProfilerSettings +@using SmartStore.Web.Framework; + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.EnableMiniProfilerInPublicStore) + + @Html.SettingEditorFor(model => model.EnableMiniProfilerInPublicStore) + @Html.ValidationMessageFor(model => model.EnableMiniProfilerInPublicStore) +
    + @Html.SmartLabelFor(model => model.DisplayWidgetZones) + + @Html.SettingEditorFor(model => model.DisplayWidgetZones) + @Html.ValidationMessageFor(model => model.DisplayWidgetZones) +
    +   + + +
    +} \ No newline at end of file diff --git a/src/Plugins/Developer.DevTools/Views/DevTools/MiniProfiler.cshtml b/src/Plugins/SmartStore.DevTools/Views/DevTools/MiniProfiler.cshtml similarity index 100% rename from src/Plugins/Developer.DevTools/Views/DevTools/MiniProfiler.cshtml rename to src/Plugins/SmartStore.DevTools/Views/DevTools/MiniProfiler.cshtml diff --git a/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml b/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml new file mode 100644 index 0000000000..222fe683e0 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Views/DevTools/WidgetZone.cshtml @@ -0,0 +1,3 @@ + + Widget Zone + diff --git a/src/Plugins/Developer.DevTools/Views/MyCheckout/MyBillingAddress.cshtml b/src/Plugins/SmartStore.DevTools/Views/MyCheckout/MyBillingAddress.cshtml similarity index 100% rename from src/Plugins/Developer.DevTools/Views/MyCheckout/MyBillingAddress.cshtml rename to src/Plugins/SmartStore.DevTools/Views/MyCheckout/MyBillingAddress.cshtml diff --git a/src/Plugins/SmartStore.DevTools/Views/Web.config b/src/Plugins/SmartStore.DevTools/Views/Web.config new file mode 100644 index 0000000000..1812533ab9 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Views/Web.config @@ -0,0 +1,65 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.DevTools/Web.config b/src/Plugins/SmartStore.DevTools/Web.config new file mode 100644 index 0000000000..b076d239ac --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/Web.config @@ -0,0 +1,135 @@ + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.DevTools/packages.config b/src/Plugins/SmartStore.DevTools/packages.config new file mode 100644 index 0000000000..325d93b6d4 --- /dev/null +++ b/src/Plugins/SmartStore.DevTools/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Controllers/DiscountRulesController.cs b/src/Plugins/SmartStore.DiscountRules/Controllers/DiscountRulesController.cs new file mode 100644 index 0000000000..7e6605a2f3 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Controllers/DiscountRulesController.cs @@ -0,0 +1,352 @@ +using System; +using System.Linq; +using System.Web.Mvc; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Localization; +using SmartStore.DiscountRules.Models; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; +using SmartStore.Services.Discounts; +using SmartStore.Services.Stores; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; + +namespace SmartStore.DiscountRules.Controllers +{ + + [AdminAuthorize] + public class DiscountRulesController : PluginControllerBase + { + private readonly IDiscountService _discountService; + private readonly Lazy _customerService; + private readonly Lazy _countryService; + private readonly Lazy _storeService; + + public DiscountRulesController( + IDiscountService discountService, + Lazy customerService, + Lazy countryService, + Lazy storeService) + { + this._discountService = discountService; + this._customerService = customerService; + this._countryService = countryService; + this._storeService = storeService; + } + + #region Global + + [NonAction] + private ActionResult HandleGet(int discountId, int? discountRequirementId, string prefix, Func modelCreator) where TModel : DiscountRuleModelBase + { + var discount = _discountService.GetDiscountById(discountId); + if (discount == null) + throw new ArgumentException(T("Plugins.SmartStore.DiscountRules.ConfigureDiscountNotLoaded")); + + DiscountRequirement discountRequirement = null; + if (discountRequirementId.HasValue) + { + discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); + if (discountRequirement == null) + return Content(T("Plugins.SmartStore.DiscountRules.ConfigureRequirementFailed")); + } + + var model = modelCreator(discountRequirement); + model.RequirementId = discountRequirementId.GetValueOrDefault(); + model.DiscountId = discountId; + + //add a prefix + ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("{0}{1}", prefix, discountRequirementId.GetValueOrDefault(0).ToString()); + + return View(model); + } + + [NonAction] + private ActionResult HandlePost(int discountId, int? discountRequirementId, Action updater, Func creator) where TModel : DiscountRuleModelBase + { + var discount = _discountService.GetDiscountById(discountId); + if (discount == null) + throw new ArgumentException(T("Plugins.SmartStore.DiscountRules.ConfigureDiscountNotLoaded")); + + DiscountRequirement discountRequirement = null; + if (discountRequirementId.HasValue) + discountRequirement = discount.DiscountRequirements.Where(dr => dr.Id == discountRequirementId.Value).FirstOrDefault(); + + if (discountRequirement != null) + { + // update existing rule + updater(discountRequirement); + _discountService.UpdateDiscount(discountRequirement.Discount); + } + else + { + // save new rule + discountRequirement = creator(); + discount.DiscountRequirements.Add(discountRequirement); + _discountService.UpdateDiscount(discount); + } + + return Json(new { Result = true, NewRequirementId = discountRequirement.Id }, JsonRequestBehavior.AllowGet); + } + + #endregion + + + #region Customer Role Is + + public ActionResult CustomerRole(int discountId, int? discountRequirementId) + { + return HandleGet(discountId, discountRequirementId, "DiscountRulesCustomerRoles", (req) => { + var model = new CustomerRoleModel(); + // countries + model.AvailableCustomerRoles.Add(new SelectListItem() { Text = T("Plugins.DiscountRequirement.MustBeAssignedToCustomerRole.ConfigureSelectCustomerRole"), Value = "0" }); + foreach (var cr in _customerService.Value.GetAllCustomerRoles(true)) + { + model.AvailableCustomerRoles.Add(new SelectListItem() { Text = cr.Name, Value = cr.Id.ToString(), Selected = req != null && cr.Id == req.RestrictedToCustomerRoleId }); + if (req != null && cr.Id == req.RestrictedToCustomerRoleId) + { + model.CustomerRoleId = cr.Id; + } + } + return model; + }); + } + + [HttpPost] + public ActionResult CustomerRole(int discountId, int? discountRequirementId, int customerRoleId) + { + return HandlePost( + discountId, + discountRequirementId, + req => req.RestrictedToCustomerRoleId = customerRoleId, + () => new DiscountRequirement + { + DiscountRequirementRuleSystemName = "DiscountRequirement.MustBeAssignedToCustomerRole", + RestrictedToCustomerRoleId = customerRoleId + } + ); + } + + #endregion + + + #region Billing Country Is + + public ActionResult BillingCountry(int discountId, int? discountRequirementId) + { + return HandleGet(discountId, discountRequirementId, "DiscountRulesBillingCountry", (req) => + { + var model = new BillingCountryModel(); + // countries + model.AvailableCountries.Add(new SelectListItem() { Text = T("Plugins.DiscountRules.BillingCountry.Fields.SelectCountry"), Value = "0" }); + foreach (var c in _countryService.Value.GetAllCountries(true)) + { + model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString(), Selected = req != null && c.Id == req.BillingCountryId }); + if (req != null && c.Id == req.BillingCountryId) + { + model.CountryId = c.Id; + } + } + return model; + }); + } + + [HttpPost] + public ActionResult BillingCountry(int discountId, int? discountRequirementId, int countryId) + { + return HandlePost( + discountId, + discountRequirementId, + req => req.BillingCountryId = countryId, + () => new DiscountRequirement + { + DiscountRequirementRuleSystemName = "DiscountRequirement.BillingCountryIs", + BillingCountryId = countryId, + } + ); + } + + #endregion + + + #region Shipping Country Is + + public ActionResult ShippingCountry(int discountId, int? discountRequirementId) + { + return HandleGet(discountId, discountRequirementId, "DiscountRulesShippingCountry", (req) => + { + var model = new ShippingCountryModel(); + //countries + model.AvailableCountries.Add(new SelectListItem() { Text = T("Plugins.DiscountRules.ShippingCountry.Fields.SelectCountry"), Value = "0" }); + foreach (var c in _countryService.Value.GetAllCountries(true)) + { + model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString(), Selected = req != null && c.Id == req.ShippingCountryId }); + if (req != null && c.Id == req.ShippingCountryId) + { + model.CountryId = c.Id; + } + } + return model; + }); + } + + [HttpPost] + public ActionResult ShippingCountry(int discountId, int? discountRequirementId, int countryId) + { + return HandlePost( + discountId, + discountRequirementId, + req => req.ShippingCountryId = countryId, + () => new DiscountRequirement + { + DiscountRequirementRuleSystemName = "DiscountRequirement.ShippingCountryIs", + ShippingCountryId = countryId + } + ); + } + + #endregion + + + #region Store + + public ActionResult Store(int discountId, int? discountRequirementId) + { + return HandleGet(discountId, discountRequirementId, "DiscountRulesStore", (req) => + { + var model = new StoreModel(); + + if (req != null) + model.StoreId = req.RestrictedToStoreId ?? 0; + + //stores + model.AvailableStores.Add(new SelectListItem() { Text = T("Plugins.DiscountRules.Store.Fields.SelectStore").Text, Value = "0" }); + foreach (var s in _storeService.Value.GetAllStores()) + model.AvailableStores.Add(new SelectListItem() { Text = s.Name, Value = s.Id.ToString(), Selected = req != null && s.Id == model.StoreId }); + return model; + }); + } + + [HttpPost] + public ActionResult Store(int discountId, int? discountRequirementId, int storeId) + { + return HandlePost( + discountId, + discountRequirementId, + req => req.RestrictedToStoreId = storeId, + () => new DiscountRequirement + { + DiscountRequirementRuleSystemName = "DiscountRequirement.Store", + RestrictedToStoreId = storeId, + } + ); + } + + #endregion + + + #region HasOneProduct + + public ActionResult HasOneProduct(int discountId, int? discountRequirementId) + { + return HandleGet(discountId, discountRequirementId, "DiscountRulesHasOneProduct", (req) => + { + var model = new HasOneProductModel(); + model.Products = req != null ? req.RestrictedProductIds : ""; + return model; + }); + } + + [HttpPost] + public ActionResult HasOneProduct(int discountId, int? discountRequirementId, string productIds) + { + return HandlePost( + discountId, + discountRequirementId, + req => req.RestrictedProductIds = productIds, + () => new DiscountRequirement + { + DiscountRequirementRuleSystemName = "DiscountRequirement.HasOneProduct", + RestrictedProductIds = productIds, + } + ); + } + + #endregion + + + #region HasAllProducts + + public ActionResult HasAllProducts(int discountId, int? discountRequirementId) + { + return HandleGet(discountId, discountRequirementId, "DiscountRulesHasAllProducts", (req) => + { + var model = new HasAllProductsModel(); + model.Products = req != null ? req.RestrictedProductIds : ""; + return model; + }); + } + + [HttpPost] + public ActionResult HasAllProducts(int discountId, int? discountRequirementId, string productIds) + { + return HandlePost( + discountId, + discountRequirementId, + req => req.RestrictedProductIds = productIds, + () => new DiscountRequirement + { + DiscountRequirementRuleSystemName = "DiscountRequirement.HasAllProducts", + RestrictedProductIds = productIds, + } + ); + } + + #endregion + + + #region HadSpentAmount + + public ActionResult HadSpentAmount(int discountId, int? discountRequirementId) + { + return HandleGet(discountId, discountRequirementId, "DiscountRulesHadSpentAmount", (req) => + { + // parse settings from ExtraData + string extraData = null; + if (req != null) + { + extraData = req.ExtraData; + } + var settings = HadSpentAmountRule.DeserializeSettings(extraData); + + var model = new HadSpentAmountModel(); + model.SpentAmount = req != null ? req.SpentAmount : decimal.Zero; + model.LimitToCurrentBasketSubTotal = settings.LimitToCurrentBasketSubTotal; + + return model; + }); + } + + [HttpPost] + public ActionResult HadSpentAmount(int discountId, int? discountRequirementId, decimal spentAmount, string settings) + { + return HandlePost( + discountId, + discountRequirementId, + req => + { + req.SpentAmount = spentAmount; + req.ExtraData = settings; + }, + () => new DiscountRequirement + { + DiscountRequirementRuleSystemName = "DiscountRequirement.HadSpentAmount", + ExtraData = settings, + SpentAmount = spentAmount + } + ); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Description.txt b/src/Plugins/SmartStore.DiscountRules/Description.txt new file mode 100644 index 0000000000..f4bb29d728 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Description.txt @@ -0,0 +1,9 @@ +FriendlyName: Common discount requirement rules +Description: Contains common discount requirement rule providers like "Billing country is", "Customer role is", "Had spent amount" etc. +Group: Marketing +SystemName: SmartStore.DiscountRules +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 0 +FileName: SmartStore.DiscountRules.dll +ResourceRootKey: Plugins.SmartStore.DiscountRules diff --git a/src/Plugins/SmartStore.DiscountRules/Localization/resources.de-de.xml b/src/Plugins/SmartStore.DiscountRules/Localization/resources.de-de.xml new file mode 100644 index 0000000000..f28cb787c5 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Localization/resources.de-de.xml @@ -0,0 +1,145 @@ + + + + Standard Rabattregeln + + + Stellt Standard Rabattregeln zur Verfügung - u.A. "Land ist", "Kundengruppe ist", "Hat Betrag x ausgegeben" etc. + + + + Rabatt konnte nicht geladen werden + + + Anforderung konnte nicht geladen werden + + + + + Der Kunde muss einer Kundengruppe zugeordnet sein + + + + + Wählen Sie eine Kundengruppe + + + Benötigte Kundengruppe + + + Der Rabatt wird angewendet, wenn der Kunde zur gewählten Kundengruppe gehört. + + + + + + + Land der Rechnungsadresse ist + + + + + Wählen Sie ein Land + + + Land der Rechnungsadresse + + + Wählen Sie das Land, dass in der Rechnungsadresse vorausgesetzt wird. + + + + + + + + Land der Lieferadresse ist + + + + + Wählen Sie ein Land + + + Land der Lieferadresse + + + Wählen Sie das Land, dass in der Lieferadresse vorausgesetzt wird. + + + + + + + Auf bestimmten Shop begrenzt + + + + + Shop auswählen + + + Shop + + + Wählen Sie den Shop für diesen Rabatt. + + + + + + + + Kunde hat einen der folgenden Produkte in seinem Warenkorb + + + + + Produkte + + + Kommagetrennte Liste von Produkt-IDs (z.B. 77, 123, 156). Die ID eines Produkts findet sich in seiner Detailansicht. Man kann die Liste außerdem um Mengenangaben ({Produkt-ID}:{Menge} z.B.: 77:1, 123:2, 156:3) oder um einen Mengenbereich ergänzen ({Produkt-ID}:{Minimale Menge}-{Maximale Menge} z.B.: 77:1-3, 123:2-5, 156:3-8). + + + + + + + + Kunde hat folgende Produkte in seinem Warenkorb + + + + + Produkte + + + Kommagetrennte Liste von Produkt-IDs (z.B. 77, 123, 156). Die ID eines Produkts findet sich in seiner Detailansicht. Man kann die Liste außerdem um Mengenangaben ({Produkt-ID}:{Menge} z.B.: 77:1, 123:2, 156:3) oder um einen Mengenbereich ergänzen ({Produkt-ID}:{Minimale Menge}-{Maximale Menge} z.B.: 77:1-3, 123:2-5, 156:3-8). + + + + + + + + Kunde hat Betrag x ausgegeben + + + + + Betrag + + + Der Rabatt wird angewendet, wenn der Kunde den angegebenen Betrag ausgegeben hat. + + + Bezogen auf Warenkorb-Zwischensumme + + + Legt fest, ob sich der angegebene Betrag auf die Zwischensumme im aktuellen Warenkorb oder - wenn inaktiv - auf die Summe aller zuvor vom Kunden getätigten Bestellungen bezieht. + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Localization/resources.en-us.xml b/src/Plugins/SmartStore.DiscountRules/Localization/resources.en-us.xml new file mode 100644 index 0000000000..66720d5e11 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Localization/resources.en-us.xml @@ -0,0 +1,118 @@ + + + + Discount could not be loaded + + + Failed to load requirement + + + + + + + Select a customer role + + + Required customer role + + + Discount will be applied if customer is in the selected customer role. + + + + + + + + + Select country + + + Billing country + + + Select required billing country. + + + + + + + + + + Select country + + + Shipping country + + + Select required shipping country. + + + + + + + + + + Select store + + + Store + + + Select the store in which this discount will be valid. + + + + + + + + + + Restricted products + + + The comma-separated list of product identifiers (e.g. 77, 123, 156). You can find a product ID on its details page. You can also specify the comma-separated list of product identifiers with quantities ({Product ID}:{Quantity}. for example, 77:1, 123:2, 156:3). And you can also specify the comma-separated list of product identifiers with quantity range ({Product ID}:{Min quantity}-{Max quantity}. for example, 77:1-3, 123:2-5, 156:3-8). + + + + + + + + + + Restricted products + + + The comma-separated list of product identifiers (e.g. 77, 123, 156). You can find a product ID on its details page. You can also specify the comma-separated list of product identifiers with quantities ({Product ID}:{Quantity}. for example, 77:1, 123:2, 156:3). And you can also specify the comma-separated list of product identifiers with quantity range ({Product ID}:{Min quantity}-{Max quantity}. for example, 77:1-3, 123:2-5, 156:3-8). + + + + + + + + + + Amount spent + + + Discount will be applied if customer has spent/purchased x.xx amount. + + + Limit to basket subtotal + + + Specifies whether the amount refers to the current basket subtotal or - when unselected - to the sum of all previously incurred orders. + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/BillingCountryModel.cs b/src/Plugins/SmartStore.DiscountRules/Models/BillingCountryModel.cs new file mode 100644 index 0000000000..1e12fd0397 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/BillingCountryModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; + +namespace SmartStore.DiscountRules.Models +{ + public class BillingCountryModel : DiscountRuleModelBase + { + public BillingCountryModel() + { + AvailableCountries = new List(); + } + [SmartResourceDisplayName("Plugins.DiscountRules.BillingCountry.Fields.Country")] + public int CountryId { get; set; } + public IList AvailableCountries { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/CustomerRoleModel.cs b/src/Plugins/SmartStore.DiscountRules/Models/CustomerRoleModel.cs new file mode 100644 index 0000000000..5c4884ae8d --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/CustomerRoleModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; + +namespace SmartStore.DiscountRules.Models +{ + public class CustomerRoleModel : DiscountRuleModelBase + { + public CustomerRoleModel() + { + AvailableCustomerRoles = new List(); + } + [SmartResourceDisplayName("Plugins.DiscountRequirement.MustBeAssignedToCustomerRole.Fields.CustomerRole")] + public int CustomerRoleId { get; set; } + public IList AvailableCustomerRoles { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/DiscountRuleModelBase.cs b/src/Plugins/SmartStore.DiscountRules/Models/DiscountRuleModelBase.cs new file mode 100644 index 0000000000..cd4c4aab83 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/DiscountRuleModelBase.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Web.Mvc; + +namespace SmartStore.DiscountRules.Models +{ + public abstract class DiscountRuleModelBase + { + public int DiscountId { get; set; } + public int RequirementId { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/HadSpentAmountModel.cs b/src/Plugins/SmartStore.DiscountRules/Models/HadSpentAmountModel.cs new file mode 100644 index 0000000000..aedf3f6cfa --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/HadSpentAmountModel.cs @@ -0,0 +1,13 @@ +using SmartStore.Web.Framework; + +namespace SmartStore.DiscountRules.Models +{ + public class HadSpentAmountModel : DiscountRuleModelBase + { + [SmartResourceDisplayName("Plugins.DiscountRules.HadSpentAmount.Fields.Amount")] + public decimal SpentAmount { get; set; } + + [SmartResourceDisplayName("Plugins.DiscountRules.HadSpentAmount.Fields.LimitToCurrentBasketSubTotal")] + public bool LimitToCurrentBasketSubTotal { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/HasAllProductsModel.cs b/src/Plugins/SmartStore.DiscountRules/Models/HasAllProductsModel.cs new file mode 100644 index 0000000000..6ad4ef09fa --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/HasAllProductsModel.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; + +namespace SmartStore.DiscountRules.Models +{ + public class HasAllProductsModel : DiscountRuleModelBase + { + [SmartResourceDisplayName("Plugins.DiscountRules.HasAllProducts.Fields.Products")] + public string Products { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/HasOneProductModel.cs b/src/Plugins/SmartStore.DiscountRules/Models/HasOneProductModel.cs new file mode 100644 index 0000000000..3f4bed1434 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/HasOneProductModel.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; + +namespace SmartStore.DiscountRules.Models +{ + public class HasOneProductModel : DiscountRuleModelBase + { + [SmartResourceDisplayName("Plugins.DiscountRules.HasOneProduct.Fields.Products")] + public string Products { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/ShippingCountryModel.cs b/src/Plugins/SmartStore.DiscountRules/Models/ShippingCountryModel.cs new file mode 100644 index 0000000000..c510b24c19 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/ShippingCountryModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; + +namespace SmartStore.DiscountRules.Models +{ + public class ShippingCountryModel : DiscountRuleModelBase + { + public ShippingCountryModel() + { + AvailableCountries = new List(); + } + [SmartResourceDisplayName("Plugins.DiscountRules.ShippingCountry.Fields.Country")] + public int CountryId { get; set; } + public IList AvailableCountries { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Models/StoreModel.cs b/src/Plugins/SmartStore.DiscountRules/Models/StoreModel.cs new file mode 100644 index 0000000000..8599c54212 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Models/StoreModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; + +namespace SmartStore.DiscountRules.Models +{ + public class StoreModel : DiscountRuleModelBase + { + public StoreModel() + { + AvailableStores = new List(); + } + [SmartResourceDisplayName("Plugins.DiscountRules.Store.Fields.Store")] + public int StoreId { get; set; } + public IList AvailableStores { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.CustomerRoles/Notes.txt b/src/Plugins/SmartStore.DiscountRules/Notes.txt similarity index 100% rename from src/Plugins/DiscountRules.CustomerRoles/Notes.txt rename to src/Plugins/SmartStore.DiscountRules/Notes.txt diff --git a/src/Plugins/SmartStore.DiscountRules/Plugin.cs b/src/Plugins/SmartStore.DiscountRules/Plugin.cs new file mode 100644 index 0000000000..e9bd38659a --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Plugin.cs @@ -0,0 +1,40 @@ +using System; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; +using SmartStore.Services.Configuration; + +namespace SmartStore.DiscountRules +{ + + public partial class Plugin : BasePlugin + { + private readonly ILocalizationService _localizationService; + + public Plugin(ILocalizationService _localizationService) + { + this._localizationService = _localizationService; + } + + public override void Install() + { + _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + } + + public override void Uninstall() + { + _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); + + _localizationService.DeleteLocaleStringResources("Plugins.DiscountRequirement.MustBeAssignedToCustomerRole"); + _localizationService.DeleteLocaleStringResources("Plugins.DiscountRules.BillingCountry"); + _localizationService.DeleteLocaleStringResources("Plugins.DiscountRules.ShippingCountry"); + _localizationService.DeleteLocaleStringResources("Plugins.DiscountRules.Store"); + _localizationService.DeleteLocaleStringResources("Plugins.DiscountRules.HasOneProduct"); + _localizationService.DeleteLocaleStringResources("Plugins.DiscountRules.HasAllProducts"); + _localizationService.DeleteLocaleStringResources("Plugins.DiscountRules.HadSpentAmount"); + + base.Uninstall(); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.DiscountRules/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..4b90ccacbf --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.DiscountRules")] diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/BillingCountryRule.cs b/src/Plugins/SmartStore.DiscountRules/Providers/BillingCountryRule.cs new file mode 100644 index 0000000000..a7c8b76b66 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/BillingCountryRule.cs @@ -0,0 +1,41 @@ +using System; +using SmartStore.Core; +using SmartStore.Core.Plugins; +using SmartStore.Services.Discounts; +using SmartStore.Services.Localization; + +namespace SmartStore.DiscountRules +{ + [SystemName("DiscountRequirement.BillingCountryIs")] + [FriendlyName("Billing country is")] + [DisplayOrder(5)] + public partial class BillingCountryRule : DiscountRequirementRuleBase + { + public override bool CheckRequirement(CheckDiscountRequirementRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.DiscountRequirement == null) + throw new SmartException("Discount requirement is not set"); + + if (request.Customer == null) + return false; + + if (request.Customer.BillingAddress == null) + return false; + + if (request.DiscountRequirement.BillingCountryId == 0) + return false; + + bool result = request.Customer.BillingAddress.CountryId == request.DiscountRequirement.BillingCountryId; + return result; + } + + protected override string GetActionName() + { + return "BillingCountry"; + } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/CustomerRoleRule.cs b/src/Plugins/SmartStore.DiscountRules/Providers/CustomerRoleRule.cs new file mode 100644 index 0000000000..080a24302f --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/CustomerRoleRule.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; +using SmartStore.Core; +using SmartStore.Core.Plugins; +using SmartStore.Services.Discounts; +using SmartStore.Services.Localization; +using SmartStore.Services.Configuration; + +namespace SmartStore.DiscountRules +{ + [SystemName("DiscountRequirement.MustBeAssignedToCustomerRole")] + [FriendlyName("Must be assigned to customer role")] + [DisplayOrder(0)] + public partial class CustomerRoleRule : DiscountRequirementRuleBase + { + public override bool CheckRequirement(CheckDiscountRequirementRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.DiscountRequirement == null) + throw new SmartException("Discount requirement is not set"); + + if (request.Customer == null) + return false; + + if (!request.DiscountRequirement.RestrictedToCustomerRoleId.HasValue) + return false; + + foreach (var customerRole in request.Customer.CustomerRoles.Where(cr => cr.Active).ToList()) + if (request.DiscountRequirement.RestrictedToCustomerRoleId == customerRole.Id) + return true; + + return false; + } + + protected override string GetActionName() + { + return "CustomerRole"; + } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/DiscountRequirementRuleBase.cs b/src/Plugins/SmartStore.DiscountRules/Providers/DiscountRequirementRuleBase.cs new file mode 100644 index 0000000000..18c61607de --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/DiscountRequirementRuleBase.cs @@ -0,0 +1,24 @@ +using System; +using SmartStore.Core; +using SmartStore.Core.Plugins; +using SmartStore.Services.Discounts; + +namespace SmartStore.DiscountRules +{ + public abstract class DiscountRequirementRuleBase : IDiscountRequirementRule + { + public abstract bool CheckRequirement(CheckDiscountRequirementRequest request); + + public string GetConfigurationUrl(int discountId, int? discountRequirementId) + { + string result = "Plugins/SmartStore.DiscountRules/DiscountRules/{0}?discountId={1}".FormatInvariant(GetActionName(), discountId); + if (discountRequirementId.HasValue) + { + result += string.Format("&discountRequirementId={0}", discountRequirementId.Value); + } + return result; + } + + protected abstract string GetActionName(); + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/HadSpentAmountRule.cs b/src/Plugins/SmartStore.DiscountRules/Providers/HadSpentAmountRule.cs new file mode 100644 index 0000000000..69d7f2614b --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/HadSpentAmountRule.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.DiscountRules.Settings; +using SmartStore.Services.Catalog; +using SmartStore.Services.Customers; +using SmartStore.Services.Discounts; +using SmartStore.Services.Orders; +using SmartStore.Services.Tax; + +namespace SmartStore.DiscountRules +{ + [SystemName("DiscountRequirement.HadSpentAmount")] + [FriendlyName("Customer has spent x amount")] + [DisplayOrder(25)] + public partial class HadSpentAmountRule : DiscountRequirementRuleBase + { + private readonly IOrderService _orderService; + private readonly IPriceCalculationService _priceCalculationService; + private readonly ITaxService _taxService; + private readonly ILogger _logger; + + public HadSpentAmountRule( + IOrderService orderService, + IPriceCalculationService priceCalculationService, + ITaxService taxService, + ILogger logger) + { + _orderService = orderService; + _priceCalculationService = priceCalculationService; + _taxService = taxService; + _logger = logger; + } + + public override bool CheckRequirement(CheckDiscountRequirementRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.DiscountRequirement == null) + throw new SmartException("Discount requirement is not set"); + + if (request.DiscountRequirement.SpentAmount == decimal.Zero) + return true; + + if (request.Customer == null) + return false; + + var settings = DeserializeSettings(request.DiscountRequirement.ExtraData); + + if (settings.LimitToCurrentBasketSubTotal) + { + return CheckCurrentSubTotalRequirement(request); + } + else + { + return CheckTotalHistoryRequirement(request); + } + } + + protected override string GetActionName() + { + return "HadSpentAmount"; + } + + private bool CheckTotalHistoryRequirement(CheckDiscountRequirementRequest request) + { + if (request.Customer.IsGuest()) + return false; + + var orders = _orderService.SearchOrders( + request.Store.Id, + request.Customer.Id, + null, + null, + new int[] { (int)OrderStatus.Complete }, + null, + null, + null, + null, + null, + 0, + int.MaxValue); + + decimal spentAmount = orders.Sum(o => o.OrderTotal); + return spentAmount >= request.DiscountRequirement.SpentAmount; + } + + private bool CheckCurrentSubTotalRequirement(CheckDiscountRequirementRequest request) + { + var spentAmount = decimal.Zero; + + try + { + var taxRate = decimal.Zero; + var cartItems = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id); + + foreach (var cartItem in cartItems) + { + var product = cartItem.Item.Product; + Dictionary mergedValuesClone = null; + + // we must reapply merged values because CheckCurrentSubTotalRequirement uses price calculation and is called by it itself. + // this can cause wrong discount calculation if the cart contains a product several times. + if (product.MergedDataValues != null) + mergedValuesClone = new Dictionary(product.MergedDataValues); + + // includeDiscounts == true produces a stack overflow! + spentAmount += cartItem.Item.Quantity * _taxService.GetProductPrice(product, _priceCalculationService.GetUnitPrice(cartItem, false), out taxRate); + + if (mergedValuesClone != null) + product.MergedDataValues = new Dictionary(mergedValuesClone); + } + } + catch (Exception exception) + { + _logger.Error(exception); + return false; + } + + return spentAmount >= request.DiscountRequirement.SpentAmount; + } + + internal static HadSpentAmountSettings DeserializeSettings(string expression) + { + var settings = new HadSpentAmountSettings(); + if (expression.HasValue()) + { + try + { + settings = JsonConvert.DeserializeObject(expression); + } + catch { } + } + + return settings; + } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/HasAllProductsRule.cs b/src/Plugins/SmartStore.DiscountRules/Providers/HasAllProductsRule.cs new file mode 100644 index 0000000000..afbaf85986 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/HasAllProductsRule.cs @@ -0,0 +1,132 @@ +using System; +using System.Linq; +using SmartStore.Core; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Plugins; +using SmartStore.Services.Discounts; +using SmartStore.Services.Localization; +using SmartStore.Services.Customers; + +namespace SmartStore.DiscountRules +{ + [SystemName("DiscountRequirement.HasAllProducts")] + [FriendlyName("Customer has all of these products in the cart")] + [DisplayOrder(20)] + public partial class HasAllProductsRule : DiscountRequirementRuleBase + { + public override bool CheckRequirement(CheckDiscountRequirementRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.DiscountRequirement == null) + throw new SmartException("Discount requirement is not set"); + + if (String.IsNullOrWhiteSpace(request.DiscountRequirement.RestrictedProductIds)) + return true; + + if (request.Customer == null) + return false; + + //we support three ways of specifying products: + //1. The comma-separated list of product identifiers (e.g. 77, 123, 156). + //2. The comma-separated list of product identifiers with quantities. + // {Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 + //3. The comma-separated list of product identifiers with quantity range. + // {Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 + var restrictedProducts = request.DiscountRequirement.RestrictedProductIds + .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + if (restrictedProducts.Count == 0) + return false; + + //cart + var cart = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id); + + bool allFound = true; + foreach (var restrictedProduct in restrictedProducts) + { + if (String.IsNullOrWhiteSpace(restrictedProduct)) + continue; + + bool found1 = false; + foreach (var sci in cart) + { + if (restrictedProduct.Contains(":")) + { + if (restrictedProduct.Contains("-")) + { + //the third way (the quantity rage specified) + //{Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 + int restrictedProductId = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) + //parsing error; exit; + return false; + int quantityMin = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[0], out quantityMin)) + //parsing error; exit; + return false; + int quantityMax = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[1], out quantityMax)) + //parsing error; exit; + return false; + + if (sci.Item.ProductId == restrictedProductId && quantityMin <= sci.Item.Quantity && sci.Item.Quantity <= quantityMax) + { + found1 = true; + break; + } + } + else + { + //the second way (the quantity specified) + //{Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 + int restrictedProductId = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) + //parsing error; exit; + return false; + int quantity = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1], out quantity)) + //parsing error; exit; + return false; + + if (sci.Item.ProductId == restrictedProductId && sci.Item.Quantity == quantity) + { + found1 = true; + break; + } + } + } + else + { + //the first way (the quantity is not specified) + int restrictedProductId = int.Parse(restrictedProduct); + if (sci.Item.ProductId == restrictedProductId) + { + found1 = true; + break; + } + } + } + + if (!found1) + { + allFound = false; + break; + } + } + + if (allFound) + return true; + + return false; + } + + protected override string GetActionName() + { + return "HasAllProducts"; + } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/HasOneProductRule.cs b/src/Plugins/SmartStore.DiscountRules/Providers/HasOneProductRule.cs new file mode 100644 index 0000000000..b7845e10fe --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/HasOneProductRule.cs @@ -0,0 +1,130 @@ +using System; +using System.Linq; +using SmartStore.Core; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Plugins; +using SmartStore.Services.Discounts; +using SmartStore.Services.Localization; +using SmartStore.Services.Customers; + +namespace SmartStore.DiscountRules +{ + [SystemName("DiscountRequirement.HasOneProduct")] + [FriendlyName("Customer has one of these products in the cart")] + [DisplayOrder(15)] + public partial class HasOneProductRule : DiscountRequirementRuleBase + { + public override bool CheckRequirement(CheckDiscountRequirementRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.DiscountRequirement == null) + throw new SmartException("Discount requirement is not set"); + + if (String.IsNullOrWhiteSpace(request.DiscountRequirement.RestrictedProductIds)) + return true; + + if (request.Customer == null) + return false; + + //we support three ways of specifying products: + //1. The comma-separated list of product identifiers (e.g. 77, 123, 156). + //2. The comma-separated list of product identifiers with quantities. + // {Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 + //3. The comma-separated list of product identifiers with quantity range. + // {Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 + var restrictedProducts = request.DiscountRequirement.RestrictedProductIds + .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.Trim()) + .ToList(); + if (restrictedProducts.Count == 0) + return false; + + //cart + var cart = request.Customer.GetCartItems(ShoppingCartType.ShoppingCart, request.Store.Id); + + bool found = false; + foreach (var restrictedProduct in restrictedProducts) + { + if (String.IsNullOrWhiteSpace(restrictedProduct)) + continue; + + foreach (var sci in cart) + { + if (restrictedProduct.Contains(":")) + { + if (restrictedProduct.Contains("-")) + { + //the third way (the quantity rage specified) + //{Product ID}:{Min quantity}-{Max quantity}. For example, 77:1-3, 123:2-5, 156:3-8 + int restrictedProductId = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) + //parsing error; exit; + return false; + int quantityMin = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[0], out quantityMin)) + //parsing error; exit; + return false; + int quantityMax = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1].Split(new[] { '-' })[1], out quantityMax)) + //parsing error; exit; + return false; + + if (sci.Item.ProductId == restrictedProductId && quantityMin <= sci.Item.Quantity && sci.Item.Quantity <= quantityMax) + { + found = true; + break; + } + } + else + { + //the second way (the quantity specified) + //{Product ID}:{Quantity}. For example, 77:1, 123:2, 156:3 + int restrictedProductId = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[0], out restrictedProductId)) + //parsing error; exit; + return false; + int quantity = 0; + if (!int.TryParse(restrictedProduct.Split(new[] { ':' })[1], out quantity)) + //parsing error; exit; + return false; + + if (sci.Item.ProductId == restrictedProductId && sci.Item.Quantity == quantity) + { + found = true; + break; + } + } + } + else + { + //the first way (the quantity is not specified) + int restrictedProductId = int.Parse(restrictedProduct); + if (sci.Item.ProductId == restrictedProductId) + { + found = true; + break; + } + } + } + + if (found) + { + break; + } + } + + if (found) + return true; + + return false; + } + + protected override string GetActionName() + { + return "HasOneProduct"; + } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/ShippingCountryRule.cs b/src/Plugins/SmartStore.DiscountRules/Providers/ShippingCountryRule.cs new file mode 100644 index 0000000000..147057caa8 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/ShippingCountryRule.cs @@ -0,0 +1,41 @@ +using System; +using SmartStore.Core; +using SmartStore.Core.Plugins; +using SmartStore.Services.Discounts; +using SmartStore.Services.Localization; + +namespace SmartStore.DiscountRules +{ + [SystemName("DiscountRequirement.ShippingCountryIs")] + [FriendlyName("Shipping country is")] + [DisplayOrder(10)] + public partial class ShippingCountryRule : DiscountRequirementRuleBase + { + public override bool CheckRequirement(CheckDiscountRequirementRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.DiscountRequirement == null) + throw new SmartException("Discount requirement is not set"); + + if (request.Customer == null) + return false; + + if (request.Customer.ShippingAddress == null) + return false; + + if (request.DiscountRequirement.ShippingCountryId == 0) + return false; + + bool result = request.Customer.ShippingAddress.CountryId == request.DiscountRequirement.ShippingCountryId; + return result; + } + + protected override string GetActionName() + { + return "ShippingCountry"; + } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Providers/StoreRule.cs b/src/Plugins/SmartStore.DiscountRules/Providers/StoreRule.cs new file mode 100644 index 0000000000..55afd191be --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Providers/StoreRule.cs @@ -0,0 +1,40 @@ +using System; +using SmartStore.Core; +using SmartStore.Core.Plugins; +using SmartStore.Services.Discounts; +using SmartStore.Services.Localization; + +namespace SmartStore.DiscountRules +{ + [SystemName("DiscountRequirement.Store")] + [FriendlyName("Restricted to store")] + [DisplayOrder(30)] + public partial class StoreRule : DiscountRequirementRuleBase + { + public override bool CheckRequirement(CheckDiscountRequirementRequest request) + { + if (request == null) + throw new ArgumentNullException("request"); + + if (request.DiscountRequirement == null) + throw new SmartException("Discount requirement is not set"); + + if (request.Customer == null) + return false; + + var storeId = request.DiscountRequirement.RestrictedToStoreId ?? 0; + + if (storeId == 0) + return false; + + bool result = request.Store.Id == storeId; + return result; + } + + protected override string GetActionName() + { + return "Store"; + } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/RouteProvider.cs b/src/Plugins/SmartStore.DiscountRules/RouteProvider.cs new file mode 100644 index 0000000000..4f6c8fb679 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/RouteProvider.cs @@ -0,0 +1,26 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.DiscountRules +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.DiscountRules", + "Plugins/SmartStore.DiscountRules/{controller}/{action}", + new { controller = "DiscountRules", action = "Index" }, + new[] { "SmartStore.DiscountRules.Controllers" } + ) + .DataTokens["area"] = "SmartStore.DiscountRules"; + } + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.DiscountRules/Settings/HadSpentAmountSettings.cs b/src/Plugins/SmartStore.DiscountRules/Settings/HadSpentAmountSettings.cs new file mode 100644 index 0000000000..817e92f076 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Settings/HadSpentAmountSettings.cs @@ -0,0 +1,8 @@ + +namespace SmartStore.DiscountRules.Settings +{ + public class HadSpentAmountSettings + { + public bool LimitToCurrentBasketSubTotal { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/SmartStore.DiscountRules.csproj b/src/Plugins/SmartStore.DiscountRules/SmartStore.DiscountRules.csproj new file mode 100644 index 0000000000..dc162de8da --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/SmartStore.DiscountRules.csproj @@ -0,0 +1,252 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {E2291595-9C99-4408-898B-A3E3BB4864CC} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.DiscountRules + SmartStore.DiscountRules + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.DiscountRules\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.DiscountRules\ + TRACE + prompt + 4 + false + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + PreserveNewest + + + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + + + + + PreserveNewest + + + PreserveNewest + Designer + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 51143 + / + http://localhost:56865/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/BillingCountry.cshtml b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/BillingCountry.cshtml new file mode 100644 index 0000000000..2e567c9c30 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/BillingCountry.cshtml @@ -0,0 +1,29 @@ +@{ + Layout = ""; +} +@model SmartStore.DiscountRules.Models.BillingCountryModel +@using SmartStore.Web.Framework; + + + + + + +
    + @Html.SmartLabelFor(model => model.CountryId) + +
    +
    + @Html.DropDownListFor(model => model.CountryId, Model.AvailableCountries, new { data_routeparam = "countryId" }) + +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/CustomerRole.cshtml b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/CustomerRole.cshtml new file mode 100644 index 0000000000..7bd1f69387 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/CustomerRole.cshtml @@ -0,0 +1,29 @@ +@{ + Layout = ""; +} +@model SmartStore.DiscountRules.Models.CustomerRoleModel +@using SmartStore.Web.Framework; + + + + + + +
    + @Html.SmartLabelFor(model => model.CustomerRoleId) + +
    +
    + @Html.DropDownListFor(model => model.CustomerRoleId, Model.AvailableCustomerRoles, new { data_routeparam = "customerRoleId" }) + +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HadSpentAmount.cshtml b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HadSpentAmount.cshtml new file mode 100644 index 0000000000..1dac222388 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HadSpentAmount.cshtml @@ -0,0 +1,60 @@ +@{ + Layout = ""; +} +@model SmartStore.DiscountRules.Models.HadSpentAmountModel +@using SmartStore.Web.Framework; + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SpentAmount) + + @Html.Hidden("SpentAmountVal", Model.SpentAmount, new { data_routeparam = "spentAmount" }) + @Html.EditorFor(model => model.SpentAmount) + @Html.ValidationMessageFor(model => model.SpentAmount) +
    + @Html.SmartLabelFor(model => model.LimitToCurrentBasketSubTotal) + + @Html.CheckBoxFor(model => model.LimitToCurrentBasketSubTotal, new { data_routeparam = "settings", data_routevalue = ViewData.TemplateInfo.HtmlFieldPrefix + "_getSettings" }) + @Html.ValidationMessageFor(model => model.LimitToCurrentBasketSubTotal) +
    +   + + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HasAllProducts.cshtml b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HasAllProducts.cshtml new file mode 100644 index 0000000000..49e58a68c4 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HasAllProducts.cshtml @@ -0,0 +1,29 @@ +@{ + Layout = ""; +} +@model SmartStore.DiscountRules.Models.HasAllProductsModel +@using SmartStore.Web.Framework; + + + + + + +
    + @Html.SmartLabelFor(model => model.Products) + +
    +
    + @Html.TextBoxFor(model => model.Products, new { data_routeparam = "productIds" }) + +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HasOneProduct.cshtml b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HasOneProduct.cshtml new file mode 100644 index 0000000000..a41b23d073 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/HasOneProduct.cshtml @@ -0,0 +1,29 @@ +@{ + Layout = ""; +} +@model SmartStore.DiscountRules.Models.HasOneProductModel +@using SmartStore.Web.Framework; + + + + + + +
    + @Html.SmartLabelFor(model => model.Products) + +
    +
    + @Html.TextBoxFor(model => model.Products, new { data_routeparam = "productIds" }) + +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/ShippingCountry.cshtml b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/ShippingCountry.cshtml new file mode 100644 index 0000000000..184b4b81bb --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/ShippingCountry.cshtml @@ -0,0 +1,29 @@ +@{ + Layout = ""; +} +@model SmartStore.DiscountRules.Models.ShippingCountryModel +@using SmartStore.Web.Framework; + + + + + + +
    + @Html.SmartLabelFor(model => model.CountryId) + +
    +
    + @Html.DropDownListFor(model => model.CountryId, Model.AvailableCountries, new { data_routeparam = "countryId" }) + +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/Store.cshtml b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/Store.cshtml new file mode 100644 index 0000000000..7a9d9bfd09 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/DiscountRules/Store.cshtml @@ -0,0 +1,29 @@ +@{ + Layout = ""; +} +@model SmartStore.DiscountRules.Models.StoreModel +@using SmartStore.Web.Framework; + + + + + + +
    + @Html.SmartLabelFor(model => model.StoreId) + +
    +
    + @Html.DropDownListFor(model => model.StoreId, Model.AvailableStores, new { data_routeparam = "storeId" }) + +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/Views/Web.config b/src/Plugins/SmartStore.DiscountRules/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.DiscountRules/packages.config b/src/Plugins/SmartStore.DiscountRules/packages.config new file mode 100644 index 0000000000..0325f33297 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.DiscountRules/web.config b/src/Plugins/SmartStore.DiscountRules/web.config new file mode 100644 index 0000000000..ba87d0f098 --- /dev/null +++ b/src/Plugins/SmartStore.DiscountRules/web.config @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.FacebookAuth/Content/facebookstyles.css b/src/Plugins/SmartStore.FacebookAuth/Content/facebookstyles.css new file mode 100644 index 0000000000..a16c3e4d52 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Content/facebookstyles.css @@ -0,0 +1,13 @@ + +/* Facebook +================================================ */ + +.btn.btn-facebook { + background: #405e94; +} +.btn.btn-facebook:hover { + background: #3a5587; +} +.btn.btn-facebook:active { + background: #344c79; +} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/icon.png b/src/Plugins/SmartStore.FacebookAuth/Content/icon.png similarity index 100% rename from src/Plugins/ExternalAuth.Facebook/icon.png rename to src/Plugins/SmartStore.FacebookAuth/Content/icon.png diff --git a/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs new file mode 100644 index 0000000000..5a99884991 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Controllers/ExternalAuthFacebookController.cs @@ -0,0 +1,156 @@ +using System.Web.Mvc; +using SmartStore.Core.Domain.Customers; +using SmartStore.FacebookAuth.Core; +using SmartStore.FacebookAuth.Models; +using SmartStore.Services; +using SmartStore.Services.Authentication.External; +using SmartStore.Services.Security; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.FacebookAuth.Controllers +{ + //[UnitOfWork] + public class ExternalAuthFacebookController : PluginControllerBase + { + private readonly IOAuthProviderFacebookAuthorizer _oAuthProviderFacebookAuthorizer; + private readonly IOpenAuthenticationService _openAuthenticationService; + private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; + private readonly ICommonServices _services; + + public ExternalAuthFacebookController( + IOAuthProviderFacebookAuthorizer oAuthProviderFacebookAuthorizer, + IOpenAuthenticationService openAuthenticationService, + ExternalAuthenticationSettings externalAuthenticationSettings, + ICommonServices services) + { + this._oAuthProviderFacebookAuthorizer = oAuthProviderFacebookAuthorizer; + this._openAuthenticationService = openAuthenticationService; + this._externalAuthenticationSettings = externalAuthenticationSettings; + this._services = services; + } + + private bool HasPermission(bool notify = true) + { + bool hasPermission = _services.Permissions.Authorize(StandardPermissionProvider.ManageExternalAuthenticationMethods); + + if (notify && !hasPermission) + NotifyError(_services.Localization.GetResource("Admin.AccessDenied.Description")); + + return hasPermission; + } + + [AdminAuthorize, ChildActionOnly] + public ActionResult Configure() + { + if (!HasPermission(false)) + return AccessDeniedPartialView(); + + var model = new ConfigurationModel(); + int storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + model.ClientKeyIdentifier = settings.ClientKeyIdentifier; + model.ClientSecret = settings.ClientSecret; + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, _services.Settings); + + return View(model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly] + public ActionResult Configure(ConfigurationModel model, FormCollection form) + { + if (!HasPermission(false)) + return Configure(); + + if (!ModelState.IsValid) + return Configure(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + int storeScope = this.GetActiveStoreScopeConfiguration(_services.StoreService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + settings.ClientKeyIdentifier = model.ClientKeyIdentifier; + settings.ClientSecret = model.ClientSecret; + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, _services.Settings); + _services.Settings.ClearCache(); + + NotifySuccess(_services.Localization.GetResource("Admin.Common.DataSuccessfullySaved")); + + return Configure(); + } + + [ChildActionOnly] + public ActionResult PublicInfo() + { + return View(); + } + + [NonAction] + private ActionResult LoginInternal(string returnUrl, bool verifyResponse) + { + var processor = _openAuthenticationService.LoadExternalAuthenticationMethodBySystemName(Provider.SystemName, _services.StoreContext.CurrentStore.Id); + if (processor == null || !processor.IsMethodActive(_externalAuthenticationSettings)) + { + throw new SmartException("Facebook module cannot be loaded"); + } + + var viewModel = new LoginModel(); + TryUpdateModel(viewModel); + + var result = _oAuthProviderFacebookAuthorizer.Authorize(returnUrl, verifyResponse); + switch (result.AuthenticationStatus) + { + case OpenAuthenticationStatus.Error: + { + if (!result.Success) + foreach (var error in result.Errors) + NotifyError(error); + + return new RedirectResult(Url.LogOn(returnUrl)); + } + case OpenAuthenticationStatus.AssociateOnLogon: + { + return new RedirectResult(Url.LogOn(returnUrl)); + } + case OpenAuthenticationStatus.AutoRegisteredEmailValidation: + { + //result + return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.EmailValidation }); + } + case OpenAuthenticationStatus.AutoRegisteredAdminApproval: + { + return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.AdminApproval }); + } + case OpenAuthenticationStatus.AutoRegisteredStandard: + { + return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.Standard }); + } + default: + break; + } + + if (result.Result != null) + return result.Result; + + return HttpContext.Request.IsAuthenticated ? + RedirectToReferrer(returnUrl, "~/") : + new RedirectResult(Url.LogOn(returnUrl)); + } + + public ActionResult Login(string returnUrl) + { + return LoginInternal(returnUrl, false); + } + + public ActionResult LoginCallback(string returnUrl) + { + return LoginInternal(returnUrl, true); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/Core/FacebookOAuth2Client.cs b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookOAuth2Client.cs new file mode 100644 index 0000000000..5f0960101b --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookOAuth2Client.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Data; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Web; +using System.Web.Script.Serialization; +using DotNetOpenAuth.AspNet; +using DotNetOpenAuth.AspNet.Clients; +using Newtonsoft.Json; + +namespace SmartStore.FacebookAuth.Core +{ + /// + /// + internal class FacebookOAuth2Client : OAuth2Client + { + /// + /// The authorization endpoint. + /// + private const string AuthorizationEndpoint = "https://www.facebook.com/v2.8/dialog/oauth"; + /// + /// The token endpoint. + /// + private const string TokenEndpoint = "https://graph.facebook.com/v2.8/oauth/access_token"; + /// + /// The user info endpoint. + /// + private const string UserInfoEndpoint = "https://graph.facebook.com/v2.8/me"; + /// + /// The app id. + /// + private readonly string _appId; + /// + /// The app secret. + /// + private readonly string _appSecret; + + /// + /// The requested scopes. + /// + private readonly string[] _requestedScopes; + + + /// + /// Creates a new Facebook OAuth2 client, requesting the default "email" scope. + /// + /// The Facebook App Id + /// The Facebook App Secret + public FacebookOAuth2Client(string appId, string appSecret) + : this(appId, appSecret, new[] { "email" }) { } + + /// + /// Creates a new Facebook OAuth2 client. + /// + /// The Facebook App Id + /// The Facebook App Secret + /// One or more requested scopes, passed without the base URI. + public FacebookOAuth2Client(string appId, string appSecret, params string[] requestedScopes) + : base("facebook") + { + if (string.IsNullOrWhiteSpace(appId)) + throw new ArgumentNullException("appId"); + + if (string.IsNullOrWhiteSpace(appSecret)) + throw new ArgumentNullException("appSecret"); + + if (requestedScopes == null) + throw new ArgumentNullException("requestedScopes"); + + if (requestedScopes.Length == 0) + throw new ArgumentException("One or more scopes must be requested.", "requestedScopes"); + + _appId = appId; + _appSecret = appSecret; + _requestedScopes = requestedScopes; + } + + public override void RequestAuthentication(HttpContextBase context, Uri returnUrl) + { + string redirectUrl = this.GetServiceLoginUrl(returnUrl).AbsoluteUri; + context.Response.Redirect(redirectUrl, endResponse: true); + } + + public new AuthenticationResult VerifyAuthentication(HttpContextBase context) + { + throw new NoNullAllowedException(); + } + + public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl) + { + string code = context.Request.QueryString["code"]; + if (string.IsNullOrEmpty(code)) + { + return AuthenticationResult.Failed; + } + + string accessToken = this.QueryAccessToken(returnPageUrl, code); + if (accessToken == null) + { + return AuthenticationResult.Failed; + } + + IDictionary userData = this.GetUserData(accessToken); + if (userData == null) + { + return AuthenticationResult.Failed; + } + + string id = userData["id"]; + string name; + + // Some oAuth providers do not return value for the 'username' attribute. + // In that case, try the 'name' attribute. If it's still unavailable, fall back to 'id' + if (!userData.TryGetValue("username", out name) && !userData.TryGetValue("name", out name)) + { + name = id; + } + + // add the access token to the user data dictionary just in case page developers want to use it + userData["accesstoken"] = accessToken; + + return new AuthenticationResult( + isSuccessful: true, provider: this.ProviderName, providerUserId: id, userName: name, extraData: userData); + } + + protected override Uri GetServiceLoginUrl(Uri returnUrl) + { + var state = string.IsNullOrEmpty(returnUrl.Query) ? string.Empty : returnUrl.Query.Substring(1); + + return BuildUri(AuthorizationEndpoint, new NameValueCollection + { + { "client_id", _appId }, + { "scope", string.Join(" ", _requestedScopes) }, + { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) }, + { "state", state }, + }); + } + + protected override IDictionary GetUserData(string accessToken) + { + var uri = BuildUri(UserInfoEndpoint, new NameValueCollection { { "access_token", accessToken } }); + + var webRequest = (HttpWebRequest)WebRequest.Create(uri); + + using (var webResponse = webRequest.GetResponse()) + using (var stream = webResponse.GetResponseStream()) + { + if (stream == null) + return null; + + using (var textReader = new StreamReader(stream)) + { + var json = textReader.ReadToEnd(); + var extraData = JsonConvert.DeserializeObject>(json); + var data = extraData.ToDictionary(x => x.Key, x => x.Value.ToString()); + + data.Add("picture", string.Format("https://graph.facebook.com/{0}/picture", data["id"])); + + return data; + } + } + } + + public string QueryAccessTokenByCode(Uri returnUrl, string authorizationCode) + { + return this.QueryAccessToken(returnUrl, authorizationCode); + } + + protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) + { + var uri = BuildUri(TokenEndpoint, new NameValueCollection + { + { "code", authorizationCode }, + { "client_id", _appId }, + { "client_secret", _appSecret }, + { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) }, + }); + + var webRequest = (HttpWebRequest)WebRequest.Create(uri); + string accessToken = null; + HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse(); + + // handle response from FB + // this will not be a url with params like the first request to get the 'code' + Encoding rEncoding = Encoding.GetEncoding(response.CharacterSet); + + using (StreamReader sr = new StreamReader(response.GetResponseStream(), rEncoding)) + { + var serializer = new JavaScriptSerializer(); + var jsonObject = serializer.DeserializeObject(sr.ReadToEnd()); + var jConvert = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(jsonObject)); + + Dictionary desirializedJsonObject = JsonConvert.DeserializeObject>(jConvert.ToString()); + accessToken = desirializedJsonObject["access_token"].ToString(); + } + return accessToken; + } + + private static Uri BuildUri(string baseUri, NameValueCollection queryParameters) + { + var keyValuePairs = queryParameters.AllKeys.Select(k => HttpUtility.UrlEncode(k) + "=" + HttpUtility.UrlEncode(queryParameters[k])); + var qs = String.Join("&", keyValuePairs); + + var builder = new UriBuilder(baseUri) { Query = qs }; + return builder.Uri; + } + + /// + /// Facebook works best when return data be packed into a "state" parameter. + /// This should be called before verifying the request, so that the url is rewritten to support this. + /// + public static void RewriteRequest() + { + var ctx = HttpContext.Current; + + var stateString = HttpUtility.UrlDecode(ctx.Request.QueryString["state"]); + if (stateString == null || !stateString.Contains("__provider__=facebook")) + return; + + var q = HttpUtility.ParseQueryString(stateString); + q.Add(ctx.Request.QueryString); + q.Remove("state"); + + ctx.RewritePath(ctx.Request.Path + "?" + q); + } + } +} \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/Core/FacebookProviderAuthorizer.cs b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs similarity index 75% rename from src/Plugins/ExternalAuth.Facebook/Core/FacebookProviderAuthorizer.cs rename to src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs index ab3452308c..378599e6d5 100644 --- a/src/Plugins/ExternalAuth.Facebook/Core/FacebookProviderAuthorizer.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Core/FacebookProviderAuthorizer.cs @@ -2,29 +2,32 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Net; using System.Text; using System.Web; using System.Web.Mvc; using DotNetOpenAuth.AspNet; using DotNetOpenAuth.AspNet.Clients; -using SmartStore.Core; +using Newtonsoft.Json.Linq; using SmartStore.Core.Domain.Customers; +using SmartStore.Services; using SmartStore.Services.Authentication.External; -namespace SmartStore.Plugin.ExternalAuth.Facebook.Core +namespace SmartStore.FacebookAuth.Core { - public class FacebookProviderAuthorizer : IOAuthProviderFacebookAuthorizer + public class FacebookProviderAuthorizer : IOAuthProviderFacebookAuthorizer { #region Fields private readonly IExternalAuthorizer _authorizer; private readonly IOpenAuthenticationService _openAuthenticationService; private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; - private readonly FacebookExternalAuthSettings _facebookExternalAuthSettings; private readonly HttpContextBase _httpContext; - private readonly IWebHelper _webHelper; - private FacebookClient _facebookApplication; + private readonly ICommonServices _services; + + private FacebookOAuth2Client _facebookApplication; #endregion @@ -33,25 +36,33 @@ public class FacebookProviderAuthorizer : IOAuthProviderFacebookAuthorizer public FacebookProviderAuthorizer(IExternalAuthorizer authorizer, IOpenAuthenticationService openAuthenticationService, ExternalAuthenticationSettings externalAuthenticationSettings, - FacebookExternalAuthSettings facebookExternalAuthSettings, HttpContextBase httpContext, - IWebHelper webHelper) + ICommonServices services) { this._authorizer = authorizer; this._openAuthenticationService = openAuthenticationService; this._externalAuthenticationSettings = externalAuthenticationSettings; - this._facebookExternalAuthSettings = facebookExternalAuthSettings; this._httpContext = httpContext; - this._webHelper = webHelper; + this._services = services; } #endregion #region Utilities - private FacebookClient FacebookApplication + private FacebookOAuth2Client FacebookApplication { - get { return _facebookApplication ?? (_facebookApplication = new FacebookClient(_facebookExternalAuthSettings.ClientKeyIdentifier, _facebookExternalAuthSettings.ClientSecret)); } + get + { + if (_facebookApplication == null) + { + var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); + + _facebookApplication = new FacebookOAuth2Client(settings.ClientKeyIdentifier, settings.ClientSecret); + } + + return _facebookApplication; + } } private AuthorizeState VerifyAuthentication(string returnUrl) @@ -82,18 +93,50 @@ private AuthorizeState VerifyAuthentication(string returnUrl) } var state = new AuthorizeState(returnUrl, OpenAuthenticationStatus.Error); - var error = authResult.Error != null ? authResult.Error.Message : "Unknown error"; - state.AddError(error); - return state; + + state.AddError(authResult.Error != null + ? authResult.Error.Message + : _services.Localization.GetResource("Admin.Common.UnknownError")); + + return state; } + private string GetEmailFromFacebook(string accessToken) + { + var result = ""; + var webRequest = WebRequest.Create("https://graph.facebook.com/me?fields=email&access_token=" + EscapeUriDataStringRfc3986(accessToken)); + + using (var webResponse = webRequest.GetResponse()) + using (var stream = webResponse.GetResponseStream()) + using (var reader = new StreamReader(stream)) + { + var strResponse = reader.ReadToEnd(); + var info = JObject.Parse(strResponse); + + if (info["email"] != null) + { + result = info["email"].ToString(); + } + } + return result; + } + private void ParseClaims(AuthenticationResult authenticationResult, OAuthAuthenticationParameters parameters) { var claims = new UserClaims(); claims.Contact = new ContactClaims(); + if (authenticationResult.ExtraData.ContainsKey("username")) + { claims.Contact.Email = authenticationResult.ExtraData["username"]; + } + else + { + claims.Contact.Email = GetEmailFromFacebook(authenticationResult.ExtraData["accesstoken"]); + } + claims.Name = new NameClaims(); + if (authenticationResult.ExtraData.ContainsKey("name")) { var name = authenticationResult.ExtraData["name"]; @@ -122,7 +165,7 @@ private AuthorizeState RequestAuthentication(string returnUrl) private Uri GenerateLocalCallbackUri() { - string url = string.Format("{0}plugins/externalauthFacebook/logincallback/", _webHelper.GetStoreLocation()); + string url = string.Format("{0}Plugins/SmartStore.FacebookAuth/logincallback/", _services.WebHelper.GetStoreLocation()); return new Uri(url); } @@ -131,10 +174,14 @@ private Uri GenerateServiceLoginUrl() //code copied from DotNetOpenAuth.AspNet.Clients.FacebookClient file var builder = new UriBuilder("https://www.facebook.com/dialog/oauth"); var args = new Dictionary(); - args.Add("client_id", _facebookExternalAuthSettings.ClientKeyIdentifier); + var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); + + args.Add("client_id", settings.ClientKeyIdentifier); args.Add("redirect_uri", GenerateLocalCallbackUri().AbsoluteUri); args.Add("scope", "email"); + AppendQueryArgs(builder, args); + return builder.Uri; } @@ -152,6 +199,7 @@ private void AppendQueryArgs(UriBuilder builder, IEnumerable> args) { if (!args.Any>()) @@ -169,7 +217,9 @@ private string CreateQueryString(IEnumerable> args) builder.Length--; return builder.ToString(); } + private readonly string[] UriRfc3986CharsToEscape = new string[] { "!", "*", "'", "(", ")" }; + private string EscapeUriDataStringRfc3986(string value) { StringBuilder builder = new StringBuilder(Uri.EscapeDataString(value)); diff --git a/src/Plugins/ExternalAuth.Facebook/Core/IOAuthProviderFacebookAuthorizer.cs b/src/Plugins/SmartStore.FacebookAuth/Core/IOAuthProviderFacebookAuthorizer.cs similarity index 76% rename from src/Plugins/ExternalAuth.Facebook/Core/IOAuthProviderFacebookAuthorizer.cs rename to src/Plugins/SmartStore.FacebookAuth/Core/IOAuthProviderFacebookAuthorizer.cs index d040de7b4a..004b117a1c 100644 --- a/src/Plugins/ExternalAuth.Facebook/Core/IOAuthProviderFacebookAuthorizer.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Core/IOAuthProviderFacebookAuthorizer.cs @@ -2,7 +2,7 @@ using SmartStore.Services.Authentication.External; -namespace SmartStore.Plugin.ExternalAuth.Facebook.Core +namespace SmartStore.FacebookAuth.Core { public interface IOAuthProviderFacebookAuthorizer : IExternalProviderAuthorizer { diff --git a/src/Plugins/ExternalAuth.Facebook/Core/OAuthAuthenticationParameters.cs b/src/Plugins/SmartStore.FacebookAuth/Core/OAuthAuthenticationParameters.cs similarity index 94% rename from src/Plugins/ExternalAuth.Facebook/Core/OAuthAuthenticationParameters.cs rename to src/Plugins/SmartStore.FacebookAuth/Core/OAuthAuthenticationParameters.cs index 2e4dba9436..722482aa13 100644 --- a/src/Plugins/ExternalAuth.Facebook/Core/OAuthAuthenticationParameters.cs +++ b/src/Plugins/SmartStore.FacebookAuth/Core/OAuthAuthenticationParameters.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using SmartStore.Services.Authentication.External; -namespace SmartStore.Plugin.ExternalAuth.Facebook.Core +namespace SmartStore.FacebookAuth.Core { [Serializable] public class OAuthAuthenticationParameters : OpenAuthenticationParameters diff --git a/src/Plugins/SmartStore.FacebookAuth/Core/Provider.cs b/src/Plugins/SmartStore.FacebookAuth/Core/Provider.cs new file mode 100644 index 0000000000..61ed3cde9c --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Core/Provider.cs @@ -0,0 +1,14 @@ + +namespace SmartStore.FacebookAuth.Core +{ + public static class Provider + { + public static string SystemName + { + get + { + return "SmartStore.FacebookAuth"; + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/DependencyRegistrar.cs b/src/Plugins/SmartStore.FacebookAuth/DependencyRegistrar.cs new file mode 100644 index 0000000000..ef4c32cf34 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/DependencyRegistrar.cs @@ -0,0 +1,20 @@ +using Autofac; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.FacebookAuth.Core; + +namespace SmartStore.FacebookAuth +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.FacebookAuth/Description.txt b/src/Plugins/SmartStore.FacebookAuth/Description.txt new file mode 100644 index 0000000000..d60a7a363b --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Description.txt @@ -0,0 +1,8 @@ +FriendlyName: Facebook +SystemName: SmartStore.FacebookAuth +Group: Security +Version: 2.6.0.1 +MinAppVersion: 2.5.0 +DisplayOrder: 5 +FileName: SmartStore.FacebookAuth.dll +ResourceRootKey: Plugins.ExternalAuth.Facebook \ No newline at end of file diff --git a/src/Plugins/ExternalAuth.Facebook/FacebookExternalAuthMethod.cs b/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthMethod.cs similarity index 85% rename from src/Plugins/ExternalAuth.Facebook/FacebookExternalAuthMethod.cs rename to src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthMethod.cs index d0f0625dc5..d3a0ea7b26 100644 --- a/src/Plugins/ExternalAuth.Facebook/FacebookExternalAuthMethod.cs +++ b/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthMethod.cs @@ -1,18 +1,21 @@ using System.Web.Routing; using SmartStore.Core.Plugins; +using SmartStore.FacebookAuth.Core; using SmartStore.Services.Authentication.External; using SmartStore.Services.Localization; -namespace SmartStore.Plugin.ExternalAuth.Facebook +namespace SmartStore.FacebookAuth { /// /// Facebook externalAuth processor /// - public class FacebookExternalAuthMethod : BasePlugin, IExternalAuthenticationMethod + public class FacebookExternalAuthMethod : BasePlugin, IExternalAuthenticationMethod, IConfigurable { #region Fields + private readonly FacebookExternalAuthSettings _facebookExternalAuthSettings; private readonly ILocalizationService _localizationService; + #endregion #region Ctor @@ -37,7 +40,7 @@ public void GetConfigurationRoute(out string actionName, out string controllerNa { actionName = "Configure"; controllerName = "ExternalAuthFacebook"; - routeValues = new RouteValueDictionary( new { Namespaces = "SmartStore.Plugin.ExternalAuth.Facebook.Controllers", area = "ExternalAuth.Facebook" } ); + routeValues = new RouteValueDictionary(new { Namespaces = "SmartStore.FacebookAuth.Controllers", area = Provider.SystemName }); } /// @@ -50,7 +53,7 @@ public void GetPublicInfoRoute(out string actionName, out string controllerName, { actionName = "PublicInfo"; controllerName = "ExternalAuthFacebook"; - routeValues = new RouteValueDictionary(new { Namespaces = "SmartStore.Plugin.ExternalAuth.Facebook.Controllers", area = "ExternalAuth.Facebook" }); + routeValues = new RouteValueDictionary(new { Namespaces = "SmartStore.FacebookAuth.Controllers", area = Provider.SystemName }); } /// @@ -68,7 +71,6 @@ public override void Uninstall() { //locales _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.ExternalAuth.Facebook", false); base.Uninstall(); } diff --git a/src/Plugins/ExternalAuth.Facebook/FacebookExternalAuthSettings.cs b/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthSettings.cs similarity index 81% rename from src/Plugins/ExternalAuth.Facebook/FacebookExternalAuthSettings.cs rename to src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthSettings.cs index 691bc09196..63be9434d9 100644 --- a/src/Plugins/ExternalAuth.Facebook/FacebookExternalAuthSettings.cs +++ b/src/Plugins/SmartStore.FacebookAuth/FacebookExternalAuthSettings.cs @@ -1,6 +1,6 @@ using SmartStore.Core.Configuration; -namespace SmartStore.Plugin.ExternalAuth.Facebook +namespace SmartStore.FacebookAuth { public class FacebookExternalAuthSettings : ISettings { diff --git a/src/Plugins/SmartStore.FacebookAuth/Localization/resources.de-de.xml b/src/Plugins/SmartStore.FacebookAuth/Localization/resources.de-de.xml new file mode 100644 index 0000000000..34d1ab5e11 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Localization/resources.de-de.xml @@ -0,0 +1,28 @@ + + + Facebook + + + + +
  • Die Facebook Zugangsdaten (s.u.) erhalten Sie, indem Sie bei Facebook unter Entwickler eine Anwendung mit der Option Facebook-Anmeldung erstellen.
  • +
  • Aktivieren Sie in den Kundeneinstellungen die automatische Registrierung, falls extern autorisierte Besucher automatisch registriert werden sollen.
  • +]]> +
    +
    + + Mit Facebook anmelden + + + Benutzer-Schlüssel-Identifikator (App ID) + + + Geben Sie hier Ihren Benutzer-Schlüssel-Identifikator (App ID) an. + + + Benutzer-Sicherheitsschlüssel (App Secret) + + + Geben Sie hier Ihren Benutzer-Sicherheitsschlüssel (App Secret) an. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/Localization/resources.en-us.xml b/src/Plugins/SmartStore.FacebookAuth/Localization/resources.en-us.xml new file mode 100644 index 0000000000..e1594d213b --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Localization/resources.en-us.xml @@ -0,0 +1,28 @@ + + + Facebook + + + + +
  • Create an application with the facebook login option in the developer area at facebook to get the facebook access data (see below).
  • +
  • Activate auto registration in the customer settings if you want externally authorized visitors to be registered automatically.
  • +]]> +
    +
    + + Sign in with Facebook + + + Client key identifier (App ID) + + + Enter your client key identifier (App ID) here. + + + Client secret (App Secret) + + + Enter your client secret (App Secret) here. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/Models/ConfigurationModel.cs b/src/Plugins/SmartStore.FacebookAuth/Models/ConfigurationModel.cs new file mode 100644 index 0000000000..928feab5b2 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Models/ConfigurationModel.cs @@ -0,0 +1,14 @@ +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.FacebookAuth.Models +{ + public class ConfigurationModel : ModelBase + { + [SmartResourceDisplayName("Plugins.ExternalAuth.Facebook.ClientKeyIdentifier")] + public string ClientKeyIdentifier { get; set; } + + [SmartResourceDisplayName("Plugins.ExternalAuth.Facebook.ClientSecret")] + public string ClientSecret { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/Models/LoginModel.cs b/src/Plugins/SmartStore.FacebookAuth/Models/LoginModel.cs new file mode 100644 index 0000000000..7ead3856b1 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Models/LoginModel.cs @@ -0,0 +1,10 @@ + +namespace SmartStore.FacebookAuth.Models +{ + public class LoginModel + { + public string ExternalIdentifier { get; set; } + public string KnownProvider { get; set; } + public string ReturnUrl { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/DiscountRules.HadSpentAmount/Notes.txt b/src/Plugins/SmartStore.FacebookAuth/Notes.txt similarity index 100% rename from src/Plugins/DiscountRules.HadSpentAmount/Notes.txt rename to src/Plugins/SmartStore.FacebookAuth/Notes.txt diff --git a/src/Plugins/SmartStore.FacebookAuth/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.FacebookAuth/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..68fc74c1af --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.FacebookAuth")] diff --git a/src/Plugins/SmartStore.FacebookAuth/RouteProvider.cs b/src/Plugins/SmartStore.FacebookAuth/RouteProvider.cs new file mode 100644 index 0000000000..90465eb41a --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/RouteProvider.cs @@ -0,0 +1,27 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.FacebookAuth.Core; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.FacebookAuth +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.FacebookAuth", + "Plugins/SmartStore.FacebookAuth/{action}", + new { controller = "ExternalAuthFacebook" }, + new[] { "SmartStore.FacebookAuth.Controllers" } + ) + .DataTokens["area"] = Provider.SystemName; + } + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.FacebookAuth/SmartStore.FacebookAuth.csproj b/src/Plugins/SmartStore.FacebookAuth/SmartStore.FacebookAuth.csproj new file mode 100644 index 0000000000..85992eb451 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/SmartStore.FacebookAuth.csproj @@ -0,0 +1,283 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {446FED73-BCA1-4D8F-BC13-EA1507C7EF29} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.FacebookAuth + SmartStore.FacebookAuth + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.FacebookAuth\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.FacebookAuth\ + TRACE + prompt + 4 + false + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + False + ..\..\packages\DotNetOpenAuth.AspNet.4.3.4.13329\lib\net45-full\DotNetOpenAuth.AspNet.dll + True + + + False + ..\..\packages\DotNetOpenAuth.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.Core.dll + True + + + False + ..\..\packages\DotNetOpenAuth.OAuth.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OAuth.dll + True + + + False + ..\..\packages\DotNetOpenAuth.OAuth.Consumer.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OAuth.Consumer.dll + True + + + False + ..\..\packages\DotNetOpenAuth.OpenId.Core.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OpenId.dll + True + + + False + ..\..\packages\DotNetOpenAuth.OpenId.RelyingParty.4.3.4.13329\lib\net45-full\DotNetOpenAuth.OpenId.RelyingParty.dll + True + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + False + ..\..\packages\Microsoft.Net.Http.2.2.19\lib\net45\System.Net.Http.Extensions.dll + + + False + ..\..\packages\Microsoft.Net.Http.2.2.19\lib\net45\System.Net.Http.Primitives.dll + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + Always + + + PreserveNewest + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + + + + + + False + True + 64276 + / + http://localhost:53089/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/Configure.cshtml b/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/Configure.cshtml new file mode 100644 index 0000000000..60dc28cea5 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/Configure.cshtml @@ -0,0 +1,52 @@ +@{ + Layout = ""; +} +@model SmartStore.FacebookAuth.Models.ConfigurationModel +@using SmartStore.Web.Framework; + +
    + + @Html.Raw(T("Plugins.ExternalAuth.Facebook.AdminInstruction")) +
    + +
    + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@Html.ValidationSummary(false) + +
    + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.ClientKeyIdentifier) + + @Html.SettingEditorFor(model => model.ClientKeyIdentifier) + @Html.ValidationMessageFor(model => model.ClientKeyIdentifier) +
    + @Html.SmartLabelFor(model => model.ClientSecret) + + @Html.SettingEditorFor(model => model.ClientSecret) + @Html.ValidationMessageFor(model => model.ClientSecret) +
    +   + + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/PublicInfo.cshtml b/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/PublicInfo.cshtml new file mode 100644 index 0000000000..13b2aeb29a --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Views/ExternalAuthFacebook/PublicInfo.cshtml @@ -0,0 +1,11 @@ +@using SmartStore.Web.Framework.UI +@{ + Layout = ""; + Html.AddCssFileParts(true, "~/Plugins/SmartStore.FacebookAuth/Content/facebookstyles.css"); +} + + + + @T("Plugins.ExternalAuth.Facebook.Login") + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/Views/Web.config b/src/Plugins/SmartStore.FacebookAuth/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.FacebookAuth/packages.config b/src/Plugins/SmartStore.FacebookAuth/packages.config new file mode 100644 index 0000000000..2cd39833bf --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/packages.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.FacebookAuth/web.config b/src/Plugins/SmartStore.FacebookAuth/web.config new file mode 100644 index 0000000000..68523a15bc --- /dev/null +++ b/src/Plugins/SmartStore.FacebookAuth/web.config @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/Widgets.GoogleAnalytics/icon.png b/src/Plugins/SmartStore.GoogleAnalytics/Content/icon.png similarity index 100% rename from src/Plugins/Widgets.GoogleAnalytics/icon.png rename to src/Plugins/SmartStore.GoogleAnalytics/Content/icon.png diff --git a/src/Plugins/Widgets.GoogleAnalytics/Controllers/WidgetsGoogleAnalyticsController.cs b/src/Plugins/SmartStore.GoogleAnalytics/Controllers/WidgetsGoogleAnalyticsController.cs similarity index 81% rename from src/Plugins/Widgets.GoogleAnalytics/Controllers/WidgetsGoogleAnalyticsController.cs rename to src/Plugins/SmartStore.GoogleAnalytics/Controllers/WidgetsGoogleAnalyticsController.cs index 235e014148..6e14ec3d1b 100644 --- a/src/Plugins/Widgets.GoogleAnalytics/Controllers/WidgetsGoogleAnalyticsController.cs +++ b/src/Plugins/SmartStore.GoogleAnalytics/Controllers/WidgetsGoogleAnalyticsController.cs @@ -7,16 +7,17 @@ using SmartStore.Core.Domain; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Orders; -using SmartStore.Plugin.Widgets.GoogleAnalytics.Models; +using SmartStore.GoogleAnalytics.Models; using SmartStore.Services.Catalog; using SmartStore.Services.Configuration; using SmartStore.Core.Logging; using SmartStore.Services.Orders; using SmartStore.Services.Stores; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.Settings; -namespace SmartStore.Plugin.Widgets.GoogleAnalytics.Controllers +namespace SmartStore.GoogleAnalytics.Controllers { public class WidgetsGoogleAnalyticsController : SmartController @@ -70,6 +71,8 @@ public ActionResult Configure() [ValidateInput(false)] public ActionResult Configure(ConfigurationModel model, FormCollection form) { + ModelState.Clear(); + //load settings for a chosen store scope var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); var googleAnalyticsSettings = _settingService.LoadSetting(storeScope); @@ -115,7 +118,6 @@ public ActionResult PublicInfo(string widgetZone) Logger.InsertLog(SmartStore.Core.Domain.Logging.LogLevel.Error, "Error creating scripts for google ecommerce tracking", ex.ToString()); } return Content(globalScript); - //return View("SmartStore.Plugin.Widgets.GoogleAnalytics.Views.WidgetsGoogleAnalytics.PublicInfo", model); } private Order GetLastOrder() @@ -125,19 +127,6 @@ private Order GetLastOrder() return order; } - // private string GetTrackingScript() { var googleAnalyticsSettings = _settingService.LoadSetting(_storeContext.CurrentStore.Id); @@ -148,42 +137,6 @@ private string GetTrackingScript() return analyticsTrackingScript; } - // private string GetEcommerceScript(Order order) { var googleAnalyticsSettings = _settingService.LoadSetting(_storeContext.CurrentStore.Id); @@ -205,6 +158,7 @@ private string GetEcommerceScript(Order order) analyticsEcommerceScript = analyticsEcommerceScript.Replace("{CITY}", order.BillingAddress == null ? "" : FixIllegalJavaScriptChars(order.BillingAddress.City)); analyticsEcommerceScript = analyticsEcommerceScript.Replace("{STATEPROVINCE}", order.BillingAddress == null || order.BillingAddress.StateProvince == null ? "" : FixIllegalJavaScriptChars(order.BillingAddress.StateProvince.Name)); analyticsEcommerceScript = analyticsEcommerceScript.Replace("{COUNTRY}", order.BillingAddress == null || order.BillingAddress.Country == null ? "" : FixIllegalJavaScriptChars(order.BillingAddress.Country.Name)); + analyticsEcommerceScript = analyticsEcommerceScript.Replace("{CURRENCY}", order.CustomerCurrencyCode); var sb = new StringBuilder(); foreach (var item in order.OrderItems) diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Description.txt b/src/Plugins/SmartStore.GoogleAnalytics/Description.txt new file mode 100644 index 0000000000..59bf21b018 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/Description.txt @@ -0,0 +1,9 @@ +FriendlyName: Google Analytics +SystemName: SmartStore.GoogleAnalytics +Group: Analytics +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 1 +FileName: SmartStore.GoogleAnalytics.dll +ResourceRootKey: Plugins.Widgets.GoogleAnalytics +Url: http://community.smartstore.com/marketplace/file/25-google-analytics/ \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs new file mode 100644 index 0000000000..185c203527 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticPlugin.cs @@ -0,0 +1,146 @@ +using System.Collections.Generic; +using System.Web.Routing; +using SmartStore.Core.Plugins; +using SmartStore.Services.Cms; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; + +namespace SmartStore.GoogleAnalytics +{ + /// + /// Google Analytics Plugin + /// + public class GoogleAnalyticPlugin : BasePlugin, IWidget, IConfigurable + { + private readonly ISettingService _settingService; + private readonly GoogleAnalyticsSettings _googleAnalyticsSettings; + private readonly ILocalizationService _localizationService; + + public GoogleAnalyticPlugin(ISettingService settingService, + GoogleAnalyticsSettings googleAnalyticsSettings, + ILocalizationService localizationService) + { + this._settingService = settingService; + this._googleAnalyticsSettings = googleAnalyticsSettings; + _localizationService = localizationService; + } + + /// + /// Gets widget zones where this widget should be rendered + /// + /// Widget zones + public IList GetWidgetZones() + { + var zones = new List() { "head_html_tag", "mobile_head_html_tag" }; + if(!string.IsNullOrWhiteSpace(_googleAnalyticsSettings.WidgetZone)) + { + zones = new List() { + _googleAnalyticsSettings.WidgetZone, + _googleAnalyticsSettings.WidgetZone == "head_html_tag" ? "mobile_head_html_tag" : "mobile_body_end_html_tag_after" + }; + } + + return zones; + } + + /// + /// Gets a route for provider configuration + /// + /// Action name + /// Controller name + /// Route values + public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "WidgetsGoogleAnalytics"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.GoogleAnalytics" } }; + } + + /// + /// Gets a route for displaying widget + /// + /// Widget zone where it's displayed + /// Action name + /// Controller name + /// Route values + public void GetDisplayWidgetRoute(string widgetZone, object model, int storeId, out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "PublicInfo"; + controllerName = "WidgetsGoogleAnalytics"; + routeValues = new RouteValueDictionary() + { + {"area", "SmartStore.GoogleAnalytics"}, + {"widgetZone", widgetZone} + }; + } + + /// + /// Install plugin + /// + public override void Install() + { + var settings = new GoogleAnalyticsSettings() + { + GoogleId = "UA-0000000-0", + TrackingScript = @" + ", + EcommerceScript = @" + ga('require', 'ecommerce'); + + ga('ecommerce:addTransaction', { + 'id': '{ORDERID}', + 'affiliation': '{SITE}', + 'revenue': '{TOTAL}', + 'shipping': '{SHIP}', + 'tax': '{TAX}', + 'currency': '{CURRENCY}' + }); + + {DETAILS} + + ga('ecommerce:send'); + ", + EcommerceDetailScript = @" + ga('ecommerce:addItem', { + 'id': '{ORDERID}', + 'name': '{PRODUCTNAME}', + 'sku': '{PRODUCTSKU}', + 'category': '{CATEGORYNAME}', + 'price': '{UNITPRICE}', + 'quantity': '{QUANTITY}' + }); + ", + + }; + _settingService.SaveSetting(settings); + + _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + } + + /// + /// Uninstall plugin + /// + public override void Uninstall() + { + //locales + _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); + _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Widgets.GoogleAnalytics", false); + + _settingService.DeleteSetting(); + + base.Uninstall(); + } + } +} diff --git a/src/Plugins/Widgets.GoogleAnalytics/GoogleAnalyticsSettings.cs b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticsSettings.cs similarity index 87% rename from src/Plugins/Widgets.GoogleAnalytics/GoogleAnalyticsSettings.cs rename to src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticsSettings.cs index 06fac8ffb5..698ed4ac80 100644 --- a/src/Plugins/Widgets.GoogleAnalytics/GoogleAnalyticsSettings.cs +++ b/src/Plugins/SmartStore.GoogleAnalytics/GoogleAnalyticsSettings.cs @@ -1,7 +1,7 @@  using SmartStore.Core.Configuration; -namespace SmartStore.Plugin.Widgets.GoogleAnalytics +namespace SmartStore.GoogleAnalytics { public class GoogleAnalyticsSettings : ISettings { diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.de-de.xml b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.de-de.xml new file mode 100644 index 0000000000..d7f6055f92 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.de-de.xml @@ -0,0 +1,44 @@ + + + Google Analytics + + + + Google Analytics ist ein kostenloser Statistikdienst von Google. Der Dienst erfasst Statistiken über Besucher und Ecommerce-Konversion auf Ihrer Webseite.

    +

    Führen Sie die folgenden Schritte aus um Google Analytics auf Ihrer Webseite einzubinden:

    +
      +
    • Erstellen Sie hier einen Google-Analytics-Account und folgen Sie dem Wizard um Ihre Webseite zuzufügen.
    • +
    • Kopieren Sie die Google-Analytics-ID in das entspechende Feld in folgendem Formular.
    • +
    • Kopieren Sie den Tracking-Code in die Tracking-Code-Box in folgendem Formular.
    • +
    • Klicken Sie den Speichern-Button.
    • +
    • Aktivieren Sie das Google Analytics Widget unter CMS > Widgets und Google Analytics wird in Ihre Webseite integriert.
    • +
    + ]]> +
    +
    + + ID + + + Geben Sie hier Ihre "Google Analytics"-ID an. + + + Tracking-Code mit {ECOMMERCE}-Zeile + + + Kopieren Sie den von Google erzeugten Tracking-Code in dieses Feld. {GOOGLEID} und {ECOMMERCE} werden automatisch ersetzt. + + + Tracking-Code für {ECOMMERCE}-Teil, mit {DETAILS}-Zeile + + + Kopieren Sie den von Google erzeugten Tracking-Code in dieses Feld. {ORDERID}, {SITE}, {TOTAL}, {TAX}, {SHIP}, {CITY}, {STATEPROVINCE}, {COUNTRY} und {DETAILS} werden automatisch ersetzt. + + + Tracking-Code für {DETAILS}-Teil + + + Kopieren Sie den von Google erzeugten Tracking-Code in dieses Feld. {ORDERID}, {PRODUCTSKU}, {PRODUCTNAME}, {CATEGORYNAME}, {UNITPRICE} und {QUANTITY} werden automatisch ersetzt. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.en-us.xml b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.en-us.xml new file mode 100644 index 0000000000..d54877d501 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/Localization/resources.en-us.xml @@ -0,0 +1,44 @@ + + + Google Analytics + + + + Google Analytics is a free website statistics tool from Google. It keeps track of statistics about the visitors and ecommerce conversion on your website.

    +

    Follow the next steps to enable Google Analytics integration:

    +
      +
    • Create a Google Analytics account and follow the wizard to add your website.
    • +
    • Copy the Google Analytics ID into the ID field below.
    • +
    • Copy the tracking code from Google Analytics into the Tracking Code field below.
    • +
    • Click the Save button below.
    • +
    • Activate the Google Analytics widget under CMS > Widgets to integrate Google Analytics into your store.
    • +
    + ]]> +
    +
    + + ID + + + Enter Google Analytics ID. + + + Tracking code with {ECOMMERCE} line + + + Paste the tracking code generated by Google Analytics here. {GOOGLEID} and {ECOMMERCE} will be dynamically replaced. + + + Tracking code for {ECOMMERCE} part, with {DETAILS} line + + + Paste the tracking code generated by Google analytics here. {ORDERID}, {SITE}, {TOTAL}, {TAX}, {SHIP}, {CITY}, {STATEPROVINCE}, {COUNTRY}, {DETAILS} will be dynamically replaced. + + + Tracking code for {DETAILS} part + + + Paste the tracking code generated by Google analytics here. {ORDERID}, {PRODUCTSKU}, {PRODUCTNAME}, {CATEGORYNAME}, {UNITPRICE}, {QUANTITY} will be dynamically replaced. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Models/ConfigurationModel.cs b/src/Plugins/SmartStore.GoogleAnalytics/Models/ConfigurationModel.cs new file mode 100644 index 0000000000..61a1f37fda --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/Models/ConfigurationModel.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.GoogleAnalytics.Models +{ + public class ConfigurationModel : ModelBase + { + + public ConfigurationModel() + { + AvailableZones = new List(); + } + + [SmartResourceDisplayName("Admin.ContentManagement.Widgets.ChooseZone")] + public string ZoneId { get; set; } + public IList AvailableZones { get; set; } + + + [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.GoogleId")] + [AllowHtml] + public string GoogleId { get; set; } + + [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.TrackingScript")] + [AllowHtml] + //tracking code + public string TrackingScript { get; set; } + + [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.EcommerceScript")] + [AllowHtml] + public string EcommerceScript { get; set; } + + [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.EcommerceDetailScript")] + [AllowHtml] + public string EcommerceDetailScript { get; set; } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.GoogleAnalytics/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..fcbe9f9b2f --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.GoogleAnalytics")] diff --git a/src/Plugins/SmartStore.GoogleAnalytics/RouteProvider.cs b/src/Plugins/SmartStore.GoogleAnalytics/RouteProvider.cs new file mode 100644 index 0000000000..02140b8d4e --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/RouteProvider.cs @@ -0,0 +1,27 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.GoogleAnalytics +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.GoogleAnalytics", + "Plugins/SmartStore.GoogleAnalytics/{action}", + new { controller = "WidgetsGoogleAnalytics", action = "Configure" }, + new[] { "SmartStore.GoogleAnalytics.Controllers" } + ) + .DataTokens["area"] = "SmartStore.GoogleAnalytics"; + } + + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.GoogleAnalytics/SmartStore.GoogleAnalytics.csproj b/src/Plugins/SmartStore.GoogleAnalytics/SmartStore.GoogleAnalytics.csproj new file mode 100644 index 0000000000..0b26e4d1d5 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/SmartStore.GoogleAnalytics.csproj @@ -0,0 +1,215 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {C2B83AF5-80F6-4B8C-8628-FA7DE10C3BB5} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.GoogleAnalytics + SmartStore.GoogleAnalytics + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.GoogleAnalytics\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.GoogleAnalytics\ + TRACE + prompt + 4 + false + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 65379 + / + http://localhost:53073/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Views/Web.config b/src/Plugins/SmartStore.GoogleAnalytics/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.GoogleAnalytics/Views/WidgetsGoogleAnalytics/Configure.cshtml b/src/Plugins/SmartStore.GoogleAnalytics/Views/WidgetsGoogleAnalytics/Configure.cshtml new file mode 100644 index 0000000000..32cbd49177 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/Views/WidgetsGoogleAnalytics/Configure.cshtml @@ -0,0 +1,76 @@ +@{ + Layout = ""; +} +@model SmartStore.GoogleAnalytics.Models.ConfigurationModel +@using SmartStore.Web.Framework; + +
    + @Html.Raw(@T("Plugins.Widgets.GoogleAnalytics.AdminInstruction")) +
    + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.ZoneId) + + @Html.DropDownListFor(model => model.ZoneId, Model.AvailableZones) + @Html.ValidationMessageFor(model => model.ZoneId) +
    + @Html.SmartLabelFor(model => model.GoogleId) + + @Html.SettingEditorFor(model => model.GoogleId) + @Html.ValidationMessageFor(model => model.GoogleId) +
    + @Html.SmartLabelFor(model => model.TrackingScript) + + @Html.SettingOverrideCheckbox(model => model.TrackingScript) + @Html.TextAreaFor(model => model.TrackingScript, new { style = "Width: 600px; Height: 200px;" }) + @Html.ValidationMessageFor(model => model.TrackingScript) +
    + @Html.SmartLabelFor(model => model.EcommerceScript) + + @Html.SettingOverrideCheckbox(model => model.EcommerceScript) + @Html.TextAreaFor(model => model.EcommerceScript, new { style = "Width: 600px; Height: 50px;" }) + @Html.ValidationMessageFor(model => model.EcommerceScript) +
    + @Html.SmartLabelFor(model => model.EcommerceDetailScript) + + @Html.SettingOverrideCheckbox(model => model.EcommerceDetailScript) + @Html.TextAreaFor(model => model.EcommerceDetailScript, new { style = "Width: 600px; Height: 50px;" }) + @Html.ValidationMessageFor(model => model.EcommerceDetailScript) +
    +   + + +
    + +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/packages.config b/src/Plugins/SmartStore.GoogleAnalytics/packages.config new file mode 100644 index 0000000000..4bc06fc1a7 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleAnalytics/web.config b/src/Plugins/SmartStore.GoogleAnalytics/web.config new file mode 100644 index 0000000000..c0f82db177 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleAnalytics/web.config @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/AdminMenu.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/AdminMenu.cs new file mode 100644 index 0000000000..2dbc226f57 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/AdminMenu.cs @@ -0,0 +1,20 @@ +using SmartStore.Collections; +using SmartStore.Web.Framework.UI; + +namespace SmartStore.GoogleMerchantCenter +{ + public class AdminMenu : AdminMenuProvider + { + protected override void BuildMenuCore(TreeNode pluginsNode) + { + var menuItem = new MenuItem().ToBuilder() + .Text("Google Merchant Center") + .ResKey("Plugins.FriendlyName.SmartStore.GoogleMerchantCenter") + .Action("ConfigurePlugin", "Plugin", new { systemName = GoogleMerchantCenterFeedPlugin.SystemName, area = "Admin" }) + .ToItem(); + + pluginsNode.Prepend(menuItem); + } + + } +} diff --git a/src/Plugins/Feed.Froogle/Content/images/mc_logo.png b/src/Plugins/SmartStore.GoogleMerchantCenter/Content/branding.png similarity index 100% rename from src/Plugins/Feed.Froogle/Content/images/mc_logo.png rename to src/Plugins/SmartStore.GoogleMerchantCenter/Content/branding.png diff --git a/src/Plugins/Feed.Froogle/icon.png b/src/Plugins/SmartStore.GoogleMerchantCenter/Content/icon.png similarity index 100% rename from src/Plugins/Feed.Froogle/icon.png rename to src/Plugins/SmartStore.GoogleMerchantCenter/Content/icon.png diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Content/smartstore.gmc.css b/src/Plugins/SmartStore.GoogleMerchantCenter/Content/smartstore.gmc.css new file mode 100644 index 0000000000..4a8bfa9c72 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Content/smartstore.gmc.css @@ -0,0 +1,6 @@ +.edit-taxonomy { + min-width: 460px; +} +.gmc-product-search { + margin-bottom: 8px !important; +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs new file mode 100644 index 0000000000..6c37461c87 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Controllers/FeedGoogleMerchantCenterController.cs @@ -0,0 +1,161 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Domain.Common; +using SmartStore.GoogleMerchantCenter.Models; +using SmartStore.GoogleMerchantCenter.Providers; +using SmartStore.GoogleMerchantCenter.Services; +using SmartStore.Services.DataExchange.Export; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using Telerik.Web.Mvc; + +namespace SmartStore.GoogleMerchantCenter.Controllers +{ + [AdminAuthorize] + public class FeedGoogleMerchantCenterController : PluginControllerBase + { + private readonly IGoogleFeedService _googleFeedService; + private readonly AdminAreaSettings _adminAreaSettings; + private readonly IExportProfileService _exportService; + + public FeedGoogleMerchantCenterController( + IGoogleFeedService googleFeedService, + AdminAreaSettings adminAreaSettings, + IExportProfileService exportService) + { + _googleFeedService = googleFeedService; + _adminAreaSettings = adminAreaSettings; + _exportService = exportService; + } + + public ActionResult ProductEditTab(int productId) + { + var culture = CultureInfo.InvariantCulture; + var model = new GoogleProductModel { ProductId = productId }; + var entity = _googleFeedService.GetGoogleProductRecord(productId); + string notSpecified = T("Common.Unspecified"); + + if (entity != null) + { + model.Taxonomy = entity.Taxonomy; + model.Gender = entity.Gender; + model.AgeGroup = entity.AgeGroup; + model.IsAdult = entity.IsAdult; + model.Color = entity.Color; + model.Size = entity.Size; + model.Material = entity.Material; + model.Pattern = entity.Pattern; + model.Export2 = entity.Export; + model.Multipack2 = entity.Multipack; + model.IsBundle = entity.IsBundle; + model.EnergyEfficiencyClass = entity.EnergyEfficiencyClass; + model.CustomLabel0 = entity.CustomLabel0; + model.CustomLabel1 = entity.CustomLabel1; + model.CustomLabel2 = entity.CustomLabel2; + model.CustomLabel3 = entity.CustomLabel3; + model.CustomLabel4 = entity.CustomLabel4; + } + else + { + model.Export2 = true; + } + + ViewBag.DefaultCategory = ""; + ViewBag.DefaultColor = ""; + ViewBag.DefaultSize = ""; + ViewBag.DefaultMaterial = ""; + ViewBag.DefaultPattern = ""; + ViewBag.DefaultGender = notSpecified; + ViewBag.DefaultAgeGroup = notSpecified; + ViewBag.DefaultIsAdult = ""; + ViewBag.DefaultMultipack2 = ""; + ViewBag.DefaultIsBundle = ""; + ViewBag.DefaultEnergyEfficiencyClass = notSpecified; + ViewBag.DefaultCustomLabel = ""; + + // we do not have export profile context here, so we simply use the first profile + var profile = _exportService.GetExportProfilesBySystemName(GmcXmlExportProvider.SystemName).FirstOrDefault(); + if (profile != null) + { + var config = XmlHelper.Deserialize(profile.ProviderConfigData, typeof(ProfileConfigurationModel)) as ProfileConfigurationModel; + if (config != null) + { + ViewBag.DefaultCategory = config.DefaultGoogleCategory; + ViewBag.DefaultColor = config.Color; + ViewBag.DefaultSize = config.Size; + ViewBag.DefaultMaterial = config.Material; + ViewBag.DefaultPattern = config.Pattern; + + if (config.Gender.HasValue() && config.Gender != GmcXmlExportProvider.Unspecified) + { + ViewBag.DefaultGender = T("Plugins.Feed.Froogle.Gender" + culture.TextInfo.ToTitleCase(config.Gender)); + } + + if (config.AgeGroup.HasValue() && config.AgeGroup != GmcXmlExportProvider.Unspecified) + { + ViewBag.DefaultAgeGroup = T("Plugins.Feed.Froogle.AgeGroup" + culture.TextInfo.ToTitleCase(config.AgeGroup)); + } + } + } + + ViewBag.AvailableGenders = new List + { + new SelectListItem { Value = "male", Text = T("Plugins.Feed.Froogle.GenderMale") }, + new SelectListItem { Value = "female", Text = T("Plugins.Feed.Froogle.GenderFemale") }, + new SelectListItem { Value = "unisex", Text = T("Plugins.Feed.Froogle.GenderUnisex") } + }; + + ViewBag.AvailableAgeGroups = new List + { + new SelectListItem { Value = "adult", Text = T("Plugins.Feed.Froogle.AgeGroupAdult") }, + new SelectListItem { Value = "kids", Text = T("Plugins.Feed.Froogle.AgeGroupKids") }, + }; + + ViewBag.AvailableEnergyEfficiencyClasses = T("Plugins.Feed.Froogle.EnergyEfficiencyClasses").Text + .SplitSafe(",") + .Select(x => new SelectListItem { Value = x, Text = x }) + .ToList(); + + var result = PartialView(model); + result.ViewData.TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "CustomProperties[GMC]" }; + return result; + } + + public ActionResult GoogleCategories() + { + var categories = _googleFeedService.GetTaxonomyList(); + return Json(categories, JsonRequestBehavior.AllowGet); + } + + public ActionResult Configure() + { + var model = new FeedGoogleMerchantCenterModel(); + + model.GridPageSize = _adminAreaSettings.GridPageSize; + model.AvailableGoogleCategories = _googleFeedService.GetTaxonomyList(); + model.EnergyEfficiencyClasses = T("Plugins.Feed.Froogle.EnergyEfficiencyClasses").Text.SplitSafe(","); + + return View(model); + } + + [HttpPost] + public ActionResult GoogleProductEdit(int pk, string name, string value) + { + _googleFeedService.Upsert(pk, name, value); + + return this.Content(""); + } + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult GoogleProductList(GridCommand command, string searchProductName, string touched) + { + return new JsonResult + { + Data = _googleFeedService.GetGridModel(command, searchProductName, touched) + }; + } + } +} diff --git a/src/Plugins/Feed.Froogle/Data/GoogleProductObjectContext.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductObjectContext.cs similarity index 80% rename from src/Plugins/Feed.Froogle/Data/GoogleProductObjectContext.cs rename to src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductObjectContext.cs index 8efaf1870f..2d822a76b9 100644 --- a/src/Plugins/Feed.Froogle/Data/GoogleProductObjectContext.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductObjectContext.cs @@ -6,13 +6,11 @@ using SmartStore.Core; using SmartStore.Data; using SmartStore.Data.Setup; -using SmartStore.Plugin.Feed.Froogle.Data.Migrations; +using SmartStore.GoogleMerchantCenter.Data.Migrations; -namespace SmartStore.Plugin.Feed.Froogle.Data +namespace SmartStore.GoogleMerchantCenter.Data { - /// - /// Object context - /// + public class GoogleProductObjectContext : ObjectContextBase { public const string ALIASKEY = "sm_object_context_google_product"; @@ -43,9 +41,6 @@ public GoogleProductObjectContext(string nameOrConnectionString) protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new GoogleProductRecordMap()); - - //disable EdmMetadata generation - //modelBuilder.Conventions.Remove(); base.OnModelCreating(modelBuilder); } diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductRecordMap.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductRecordMap.cs new file mode 100644 index 0000000000..98aaec1aa4 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/GoogleProductRecordMap.cs @@ -0,0 +1,22 @@ +using System.Data.Entity.ModelConfiguration; +using SmartStore.GoogleMerchantCenter.Domain; + +namespace SmartStore.GoogleMerchantCenter.Data +{ + public partial class GoogleProductRecordMap : EntityTypeConfiguration + { + public GoogleProductRecordMap() + { + this.ToTable("GoogleProduct"); + this.HasKey(x => x.Id); + + this.Property(x => x.EnergyEfficiencyClass).HasMaxLength(50); + + this.Property(x => x.CustomLabel0).HasMaxLength(100); + this.Property(x => x.CustomLabel1).HasMaxLength(100); + this.Property(x => x.CustomLabel2).HasMaxLength(100); + this.Property(x => x.CustomLabel3).HasMaxLength(100); + this.Property(x => x.CustomLabel4).HasMaxLength(100); + } + } +} \ No newline at end of file diff --git a/src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.Designer.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.Designer.cs similarity index 93% rename from src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.Designer.cs rename to src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.Designer.cs index 1551ccf18e..ea2edf43b3 100644 --- a/src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.Designer.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.Designer.cs @@ -1,5 +1,5 @@ // -namespace SmartStore.Plugin.Feed.Froogle.Data.Migrations +namespace SmartStore.GoogleMerchantCenter.Data.Migrations { using System.CodeDom.Compiler; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.cs similarity index 95% rename from src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.cs rename to src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.cs index d5e080b017..983c7d361e 100644 --- a/src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.cs @@ -1,4 +1,4 @@ -namespace SmartStore.Plugin.Feed.Froogle.Data.Migrations +namespace SmartStore.GoogleMerchantCenter.Data.Migrations { using System; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.resx b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.resx similarity index 100% rename from src/Plugins/Feed.Froogle/Data/Migrations/201403112356126_Initial.resx rename to src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201403112356126_Initial.resx diff --git a/src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.Designer.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.Designer.cs similarity index 93% rename from src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.Designer.cs rename to src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.Designer.cs index fc07dda3c1..da776c17b4 100644 --- a/src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.Designer.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.Designer.cs @@ -1,5 +1,5 @@ // -namespace SmartStore.Plugin.Feed.Froogle.Data.Migrations +namespace SmartStore.GoogleMerchantCenter.Data.Migrations { using System.CodeDom.Compiler; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.cs similarity index 92% rename from src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.cs rename to src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.cs index cfed91694c..c4af118dd7 100644 --- a/src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.cs +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.cs @@ -1,4 +1,4 @@ -namespace SmartStore.Plugin.Feed.Froogle.Data.Migrations +namespace SmartStore.GoogleMerchantCenter.Data.Migrations { using System; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.resx b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.resx similarity index 100% rename from src/Plugins/Feed.Froogle/Data/Migrations/201408020941244_IsTouched.resx rename to src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201408020941244_IsTouched.resx diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.Designer.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.Designer.cs new file mode 100644 index 0000000000..981e039008 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.GoogleMerchantCenter.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class IsActive : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(IsActive)); + + string IMigrationMetadata.Id + { + get { return "201504211854125_IsActive"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.cs new file mode 100644 index 0000000000..6d62461bb1 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.cs @@ -0,0 +1,18 @@ +namespace SmartStore.GoogleMerchantCenter.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class IsActive : DbMigration + { + public override void Up() + { + AddColumn("dbo.GoogleProduct", "Export", c => c.Boolean(nullable: false, defaultValue: true)); + } + + public override void Down() + { + DropColumn("dbo.GoogleProduct", "Export"); + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.resx b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.resx new file mode 100644 index 0000000000..ad02e61da9 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201504211854125_IsActive.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAM1ZzW7jNhC+F+g7CDq1QNZynEsbyLvIOj8Iuo6DyNk7LY0dthSpklRg76v10EfqK+xQ/5JlW4rjRW/2iPPNHzXfjP3fP/+6n9Yhs15BKir42D4fDG0LuC8CyldjO9bLD7/Znz7+/JN7E4Rr62t+7sKcQ02uxvaL1tGl4yj/BUKiBiH1pVBiqQe+CB0SCGc0HP7unJ87gBA2YlmW+xRzTUNIvuDXieA+RDombCoCYCqT4xMvQbUeSAgqIj6MbS8kUntaSBjcCbFiMAXpvxCuJ8A1yME10cS2rhgl6JsHbGlbhHOhiUbPL58VeFoKvvIiFBA230SA55aEKcgiuiyPdw1uODLBOaViDuXHSouwJ+D5RZYtp6n+ppzbRTYxnzeYd70xUSc5HdtpDh+lCGJfP4EvZGBbTbuXEyaNTofsoxrlgxbUM+uA7llxvUaD0WA4GJ5Zk5jpWMKYQ6wlYWfWY7xg1P8DNnPxF/AxjxmrhocB4rOaAEXoRgRSb55gmQV9jzE6dT2nqVioVXTSHNxzfTGyrQc0ThYMittTyVcS5R1wkERD8Eg0xscNBiT537LesJUl7rDJ/TBzshZchJscBW8+vta2NSXrL8BX+mVs40fbuqVrCHJJhvzMKXYBVNIyPmgIIw1AntzM1QrupIijkxuaCCZOH45Hv8HJjUzxAkpsdCc3lF3yk9u51xAmt6B8O05nS81FjD22sPRZCAaE934TJxJMI5jxZ+3nWEhUMEcS7A32HAXvB3azjoTU/eJznZJGtskFyVwjB4BsY5jZ4k/wtTkCa91CNMjPGdeorER171MTHujd9KVsq3QvHQHa+Kg9pML5cgRx0hkkn1WcHcOKOyVRhNewMrxkEstLJ5fJB68/gYcphuOrFh4vvC0sIe+QFTSemoYWwC2VSpvpaEFMQSdBuHVsT6l2lCE3vKcaTToui5Mrm89ZS+ww3LUWs2GkTP4t5iNE5SQ1UPjdPvhsoSQTKGFEtgwDSBJxyHcNFPu0K/ReBamIu2OVHF+FKqXdkXISr+Lksu4oJUdXcUppd6SMhKswmag7RkqxVYhU0h2h5M8qSintUfWcIGs1z4XdcWoEWLuE1Qc98EqSq6GV4h41q/FcrXS1J90R62RXRaw/6Y6YM14VK5dto7hOo5E025mz1c8ai0WzV+5jneaRwnrBPg2WcbOOf3hv3qKA9IhtYXpeaWDav7dReIXSJuv9zSaMYrzlgSnhdAlKp7uXjYvqqLFo/3+WXkepgPXffH/4LklNgg9uiz1nuq31MbFy5PLIX4mhYvlLSNa/VtH6L4hHQTWXwKPAaoveUUjVZe4ooObCdhRYYyk7Cqtl8ToOr7lcLWj/W9q2WBla0O+1WL0ZrL5YHY6t31K1PdD33pO6rkkpT2AmFgKjSf2vHXzzJrXNXa5T/WXYvQZFVyWE+Z2Y406CpFCC5mfu+VLkJcC4qx7lR5pvGmiC5SVXUtMl8TU+9kGp5KeEr4TFpojhAoJ7Pot1FOsrpSBcsNpQ7Tr77SfrYt1ndxaZb+o9QkA3qbmhM/45piwo/L5tuV87IMxNyrgHvfK04aDVpkB6ELwjUJa+a4hMs+d6DmHEEEzNuEde4S2+PSv4Aivib/IRZDfI4ULU0+5eU7KSJFQZRqlv/u1wzN8dH78D4O1TvSAZAAA= + + + dbo + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.Designer.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.Designer.cs new file mode 100644 index 0000000000..652bba012c --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.GoogleMerchantCenter.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.3-40302")] + public sealed partial class IsBundle : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(IsBundle)); + + string IMigrationMetadata.Id + { + get { return "201601061649324_IsBundle"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.cs new file mode 100644 index 0000000000..bc8af7c35e --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.cs @@ -0,0 +1,34 @@ +namespace SmartStore.GoogleMerchantCenter.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class IsBundle : DbMigration + { + public override void Up() + { + AddColumn("dbo.GoogleProduct", "Multipack", c => c.Int(nullable: false)); + AddColumn("dbo.GoogleProduct", "IsBundle", c => c.Boolean()); + AddColumn("dbo.GoogleProduct", "IsAdult", c => c.Boolean()); + AddColumn("dbo.GoogleProduct", "EnergyEfficiencyClass", c => c.String(maxLength: 50)); + AddColumn("dbo.GoogleProduct", "CustomLabel0", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel1", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel2", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel3", c => c.String(maxLength: 100)); + AddColumn("dbo.GoogleProduct", "CustomLabel4", c => c.String(maxLength: 100)); + } + + public override void Down() + { + DropColumn("dbo.GoogleProduct", "CustomLabel4"); + DropColumn("dbo.GoogleProduct", "CustomLabel3"); + DropColumn("dbo.GoogleProduct", "CustomLabel2"); + DropColumn("dbo.GoogleProduct", "CustomLabel1"); + DropColumn("dbo.GoogleProduct", "CustomLabel0"); + DropColumn("dbo.GoogleProduct", "EnergyEfficiencyClass"); + DropColumn("dbo.GoogleProduct", "IsAdult"); + DropColumn("dbo.GoogleProduct", "IsBundle"); + DropColumn("dbo.GoogleProduct", "Multipack"); + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.resx b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.resx new file mode 100644 index 0000000000..ebf95a7c54 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/201601061649324_IsBundle.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAM2a227jNhCG7wv0HQRdtUDW8iEF2sDeReIki6BxHETJ3tPS2FGXIlWSCuy+Wi/6SH2Fjs6iJNuSHQe9s0fkNwdS1K+x//37n/GXtU+NNxDS42xiDnp90wDmcNdjq4kZquWnX80vn3/8YXzj+mvjWzZuFI3DmUxOzFelggvLks4r+ET2fM8RXPKl6jnct4jLrWG//5s1GFiACBNZhjF+CpnyfIi/4NcpZw4EKiR0xl2gMrXjFTumGg/EBxkQByam7ROhbMUF9L5yvqIwA+G8EqamwBSI3jVRxDQuqUcwNhvo0jQIY1wRhZFfvEiwleBsZQdoIPR5EwCOWxIqIc3oohjeNrn+MErOKiZmKCeUivsdgYNRWi2rOv2gmpt5NbGeN1h3tYmyjms6MZMaPgruho56AocL1zSqfi+mVERzWlQfp3ms10A9M/bMPcu317A37PV7/TNjGlIVCpgwCJUg9Mx4DBfUc36HzTP/DmzCQkrL6WGCeE0zoAnDCECozRMs06TvMEdLn2dVJ+bTSnOSGtwxNRqaxgM6JwsK+e4p1SvO8iswEESB+0gU5sciBsT1r3mv+EoLt9/lbswzWXPG/U1GwZ2Pt7VpzMj6HthKvU5M/Ggat94a3MySkl+Yh6cATlIi3OsIM3VBnNzN5Qq+Ch4GJ3c05ZSfPh3b+wtO7mSGG1DgQXdyR+kmP7mfOwV+vAuKu+N0vuQzD/GMzT1dcU6BsM534lRAdBDM2YtyMhY+qOAZH4KdYS+B+36wm3XAhTo2vxke1B4+n78fd2DdyauQuRRq4eybduliAB1n3eDpvNrcLJee46Hk2UwpkXLHlvql/x4nS/xkvScLoP0dvgb9d3Y2+Ehnw490NvpIZ+fv7GxsFYKsLtNQFitUUyCatNp88Qc4KhoCa9Ug2VDppqpNpp71JBMXNqjtQhDvhiK8REw3KbvmlPLgCzFvJWo+U/3WFtk/npEgwOqWXgNSi2En7wDTT3Z3KewnDMuRDYo4jzb3hAqOrKByNZIGLtx6QqroPWNBovWdun5t2I6l2rIMmeMdq1EVtsXiZJOjz6m4aPGa1LiYFSdF8W+xHj5OjksDedzNrxA1SvwuRygRDbIa5Vbos23SfNfsklAuQ0rm9qxCLZdRhbU9KZPDZU5ma08p1G6ZU1jbk1I5W8akpvaMRKyWEYmlPaFQomVKYe2w6pnU1NY8M7bnaFJS24TlCx14hVzUaIW5w5ppilFbOu1Ke6IuG8tE/Up7YqYdy6zM1mFfFNpR2xiFucsKZAJSX4DM2oWUakodlBo71KhZZWolax7SYa9oolLbK9qVg4iDrcTBgcThVuLwQOJoK3F0IPF8K/G8iTi2Kg/J6qPaqj2rK+2nqg7YpaiqQ3LvubKqKKhxqmb2d1dr8iYZYhpYqjfPjaSNvZF4PCYCwv6TTiluWlUMmBHmLUGqpENnDvuDYaUd+/9pjVpSurR7f/TDO45eVOC9PcWOL9u1JmPs5cgWI3sjkcwUP/lk/XOZ1r2NeBSq2io8Cqa1A48ilVt+R4Gqbb2jYJXW3VGshvbccbxqC27hdd+lTe23SPKo92q/HQzT22+H5FZrvR1yG1cbb5VA2i2U1oQ7gLCzIZdtolpLruOt3NB/a0TH3ZyD2YMTsocnZI9OyD4/jt2tVVZv03TufrVtfiUKCc+ABccMk/C1gQf3x+qqbWyVfzkfX4P0VgUi+h2dgRPJoQKajbljS54tDuZdjigbUj1ZQBE82MilUN6SOAovOyBl3Pf8RmgY3bL+Atw7Ng9VEKpLKcFfUK1VMrZ2+4+bgHrM43kQfZPvkQKG6UVn85xdhR5187hv64fiNkS0k1LVhVHZKlJfq01OeuCsJSgt3zUEkcxh6hn8gCJMzplN3uCQ2F4k3MOKOJtMfG+H7F8Ivezja4+sBPFlyijmR/8GsaK/g3z+D2Zr4jJAIgAA + + + dbo + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/Configuration.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/Configuration.cs new file mode 100644 index 0000000000..00c0104a40 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Data/Migrations/Configuration.cs @@ -0,0 +1,21 @@ +namespace SmartStore.GoogleMerchantCenter.Data.Migrations +{ + using System; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using System.Linq; + + internal sealed class Configuration : DbMigrationsConfiguration + { + public Configuration() + { + AutomaticMigrationsEnabled = false; + MigrationsDirectory = @"Data\Migrations"; + ContextKey = "SmartStore.FeedGoogle"; // DO NOT CHANGE! + } + + protected override void Seed(GoogleProductObjectContext context) + { + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/DependencyRegistrar.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/DependencyRegistrar.cs new file mode 100644 index 0000000000..ac6e3dd393 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/DependencyRegistrar.cs @@ -0,0 +1,39 @@ +using Autofac; +using Autofac.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.Data; +using SmartStore.GoogleMerchantCenter.Data; +using SmartStore.GoogleMerchantCenter.Domain; +using SmartStore.GoogleMerchantCenter.Services; + +namespace SmartStore.GoogleMerchantCenter +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + + //register named context + builder.Register(c => new GoogleProductObjectContext(DataSettings.Current.DataConnectionString)) + .Named(GoogleProductObjectContext.ALIASKEY) + .InstancePerRequest(); + + builder.Register(c => new GoogleProductObjectContext(DataSettings.Current.DataConnectionString)) + .InstancePerRequest(); + + //override required repository with our custom context + builder.RegisterType>() + .As>() + .WithParameter(ResolvedParameter.ForNamed(GoogleProductObjectContext.ALIASKEY)) + .InstancePerRequest(); + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Description.txt b/src/Plugins/SmartStore.GoogleMerchantCenter/Description.txt new file mode 100644 index 0000000000..6f343b6b69 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Description.txt @@ -0,0 +1,10 @@ +FriendlyName: Google Merchant Center (GMC) feed +SystemName: SmartStore.GoogleMerchantCenter +Group: Marketing +Version: 2.6.0.1 +MinAppVersion: 2.5.0 +Author: SmartStore AG +DisplayOrder: 1 +FileName: SmartStore.GoogleMerchantCenter.dll +ResourceRootKey: Plugins.Feed.Froogle +Url: http://community.smartstore.com/marketplace/file/37-google-merchant-center-gmc-feed/ diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Domain/GoogleProductRecord.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Domain/GoogleProductRecord.cs new file mode 100644 index 0000000000..7064e84880 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Domain/GoogleProductRecord.cs @@ -0,0 +1,44 @@ +using System; +using SmartStore.Core; + +namespace SmartStore.GoogleMerchantCenter.Domain +{ + /// + /// Represents a Google product record + /// + public partial class GoogleProductRecord : BaseEntity + { + public GoogleProductRecord() + { + Export = true; + } + + public int ProductId { get; set; } + + public string Taxonomy { get; set; } + public string Gender { get; set; } + public string AgeGroup { get; set; } + public string Color { get; set; } + public string Size { get; set; } + public string Material { get; set; } + public string Pattern { get; set; } + public string ItemGroupId { get; set; } + + public bool IsTouched { get; set; } + public DateTime CreatedOnUtc { get; set; } + public DateTime UpdatedOnUtc { get; set; } + + public bool Export { get; set; } + + public int Multipack { get; set; } + public bool? IsBundle { get; set; } + public bool? IsAdult { get; set; } + public string EnergyEfficiencyClass { get; set; } + + public string CustomLabel0 { get; set; } + public string CustomLabel1 { get; set; } + public string CustomLabel2 { get; set; } + public string CustomLabel3 { get; set; } + public string CustomLabel4 { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs new file mode 100644 index 0000000000..10b5732247 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Events.cs @@ -0,0 +1,97 @@ +using System; +using SmartStore.Core.Events; +using SmartStore.GoogleMerchantCenter.Domain; +using SmartStore.GoogleMerchantCenter.Models; +using SmartStore.GoogleMerchantCenter.Services; +using SmartStore.Web.Framework.Events; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.GoogleMerchantCenter +{ + public class Events : + IConsumer, + IConsumer + { + private readonly IGoogleFeedService _googleService; + + public Events(IGoogleFeedService googleService) + { + this._googleService = googleService; + } + + public void HandleEvent(TabStripCreated eventMessage) + { + if (eventMessage.TabStripName == "product-edit") + { + var productId = ((TabbableModel)eventMessage.Model).Id; + + eventMessage.ItemFactory.Add().Text("GMC") + .Name("tab-gmc") + .Icon("fa fa-google fa-lg fa-fw") + .LinkHtmlAttributes(new { data_tab_name = "GMC" }) + .Route("SmartStore.GoogleMerchantCenter", new { action = "ProductEditTab", productId = productId }) + .Ajax(); + } + } + + public void HandleEvent(ModelBoundEvent eventMessage) + { + if (!eventMessage.BoundModel.CustomProperties.ContainsKey("GMC")) + return; + + var model = eventMessage.BoundModel.CustomProperties["GMC"] as GoogleProductModel; + if (model == null) + return; + + var utcNow = DateTime.UtcNow; + var entity = _googleService.GetGoogleProductRecord(model.ProductId); + var insert = (entity == null); + + if (entity == null) + { + entity = new GoogleProductRecord + { + ProductId = model.ProductId, + CreatedOnUtc = utcNow + }; + } + + // map objects + entity.AgeGroup = model.AgeGroup; + entity.Color = model.Color; + entity.Gender = model.Gender; + entity.Size = model.Size; + entity.Taxonomy = model.Taxonomy; + entity.Material = model.Material; + entity.Pattern = model.Pattern; + entity.Export = model.Export2; + entity.UpdatedOnUtc = utcNow; + entity.Multipack = model.Multipack2 ?? 0; + entity.IsBundle = model.IsBundle; + entity.IsAdult = model.IsAdult; + entity.EnergyEfficiencyClass = model.EnergyEfficiencyClass; + entity.CustomLabel0 = model.CustomLabel0; + entity.CustomLabel1 = model.CustomLabel1; + entity.CustomLabel2 = model.CustomLabel2; + entity.CustomLabel3 = model.CustomLabel3; + entity.CustomLabel4 = model.CustomLabel4; + + entity.IsTouched = entity.IsTouched(); + + if (!insert && !entity.IsTouched) + { + _googleService.DeleteGoogleProductRecord(entity); + return; + } + + if (insert) + { + _googleService.InsertGoogleProductRecord(entity); + } + else + { + _googleService.UpdateGoogleProductRecord(entity); + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Extensions/MiscExtensions.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Extensions/MiscExtensions.cs new file mode 100644 index 0000000000..5a8dd0168d --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Extensions/MiscExtensions.cs @@ -0,0 +1,38 @@ +using System.Web.Mvc; +using SmartStore.GoogleMerchantCenter.Domain; + +namespace SmartStore.GoogleMerchantCenter +{ + public static class MiscExtensions + { + public static string XEditableLink(this HtmlHelper hlp, string fieldName, string type) + { + string displayText = null; + + if (fieldName == "Gender" || fieldName == "AgeGroup" || fieldName == "Export2" || fieldName == "IsBundle" || fieldName == "IsAdult") + displayText = "<#= {0}Localize #>".FormatInvariant(fieldName); + else + displayText = "<#= {0} #>".FormatInvariant(fieldName); + + string skeleton = + "\" class=\"edit-link-{1}\"" + + " data-pk=\"<#= ProductId #>\" data-name=\"{0}\" data-value=\"<#= {0} #>\" data-inputclass=\"edit-{1}\" data-type=\"{2}\">" + + "{3}"; + + return skeleton.FormatInvariant(fieldName, fieldName.ToLower(), type, displayText); + } + + public static bool IsTouched(this GoogleProductRecord p) + { + if (p != null) + { + return + p.Taxonomy.HasValue() || p.Gender.HasValue() || p.AgeGroup.HasValue() || p.Color.HasValue() || + p.Size.HasValue() || p.Material.HasValue() || p.Pattern.HasValue() || p.ItemGroupId.HasValue() || + !p.Export || p.Multipack != 0 || p.IsBundle.HasValue || p.IsAdult.HasValue || p.EnergyEfficiencyClass.HasValue() || + p.CustomLabel0.HasValue() || p.CustomLabel1.HasValue() || p.CustomLabel2.HasValue() || p.CustomLabel3.HasValue() || p.CustomLabel4.HasValue(); + } + return false; + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Files/taxonomy.de-DE.txt b/src/Plugins/SmartStore.GoogleMerchantCenter/Files/taxonomy.de-DE.txt new file mode 100644 index 0000000000..6be270d3aa --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Files/taxonomy.de-DE.txt @@ -0,0 +1,5427 @@ +Baby & Kleinkind +Baby & Kleinkind > Baby Badebedarf +Baby & Kleinkind > Baby Badebedarf > Babybadewannen +Baby & Kleinkind > Baby Badebedarf > Shampoo-Schutzschilder +Baby & Kleinkind > Baby Gesundheitsbedarf +Baby & Kleinkind > Baby Gesundheitsbedarf > Baby-Gesundheits- & Pflegesets +Baby & Kleinkind > Baby Gesundheitsbedarf > Nasensauger +Baby & Kleinkind > Baby Gesundheitsbedarf > Reinigungstücher für Schnuller +Baby & Kleinkind > Baby Gesundheitsbedarf > Schnuller & Beißringe +Baby & Kleinkind > Baby Gesundheitsbedarf > Schnullerclips & -ketten +Baby & Kleinkind > Babysicherheit +Baby & Kleinkind > Babysicherheit > Baby- & Haustierschutzgitter +Baby & Kleinkind > Babysicherheit > Baby-Schutzleisten +Baby & Kleinkind > Babysicherheit > Babyfone +Baby & Kleinkind > Babysicherheit > Babysicherheitsgurte & -leinen +Baby & Kleinkind > Babysicherheit > Babysicherungen & Schutzvorrichtungen +Baby & Kleinkind > Babysicherheit > Zubehör für Baby- & Haustierschutzgitter +Baby & Kleinkind > Babyspielwaren +Baby & Kleinkind > Babyspielwaren > ABC-Lernspielzeuge +Baby & Kleinkind > Babyspielwaren > Baby-Aktiv-Spielzeug +Baby & Kleinkind > Babyspielwaren > Baby-Mobile-Zubehör +Baby & Kleinkind > Babyspielwaren > Baby-Mobiles +Baby & Kleinkind > Babyspielwaren > Babylauflernhilfen +Baby & Kleinkind > Babyspielwaren > Babyrasseln +Baby & Kleinkind > Babyspielwaren > Babyschaukeln & Türhopser +Baby & Kleinkind > Babyspielwaren > Babywippen +Baby & Kleinkind > Babyspielwaren > Lauf- & Spielgitterreinigungst +Baby & Kleinkind > Babyspielwaren > Schnuller & Beruhigung +Baby & Kleinkind > Babyspielwaren > Sortier-, Stapel- & Steckspielzeug +Baby & Kleinkind > Babyspielwaren > Spiel- & Krabbeldecken +Baby & Kleinkind > Babyspielwaren > Zieh- & Schiebespielzeug +Baby & Kleinkind > Babytransport +Baby & Kleinkind > Babytransport > Baby- & Kleinkindautositze +Baby & Kleinkind > Babytransport > Babyträger +Baby & Kleinkind > Babytransport > Kinderwagen +Baby & Kleinkind > Babytransportzubehör +Baby & Kleinkind > Babytransportzubehör > Einkaufswagen- & Hochstuhlbezüge +Baby & Kleinkind > Babytransportzubehör > Fußsäcke +Baby & Kleinkind > Babytransportzubehör > Zubehör für Baby- & Kleinkindautositze +Baby & Kleinkind > Babytransportzubehör > Zubehör für Babyträger +Baby & Kleinkind > Babytransportzubehör > Zubehör für Kinderwagen +Baby & Kleinkind > Geschenksets für Babys +Baby & Kleinkind > Puckdecken +Baby & Kleinkind > Stillen & Füttern +Baby & Kleinkind > Stillen & Füttern > Baby-Spucktücher +Baby & Kleinkind > Stillen & Füttern > Babyflaschen +Baby & Kleinkind > Stillen & Füttern > Babypflege-Timer +Baby & Kleinkind > Stillen & Füttern > Flaschenwärmer & Sterilisatoren +Baby & Kleinkind > Stillen & Füttern > Lerntassen +Baby & Kleinkind > Stillen & Füttern > Lätzchen +Baby & Kleinkind > Stillen & Füttern > Milchpumpen +Baby & Kleinkind > Stillen & Füttern > Milchpumpenzubehör +Baby & Kleinkind > Stillen & Füttern > Muttermilchbehälter +Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder +Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Baby-Snacks +Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Babygetreide +Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Babynahrung +Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Babysäfte +Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Getränke und Milchmischgetränke +Baby & Kleinkind > Stillen & Füttern > Nahrung für Babys & Kleinkinder > Milchnahrung +Baby & Kleinkind > Stillen & Füttern > Sauger für Babyflaschen +Baby & Kleinkind > Stillen & Füttern > Stillhütchen & -einlagen +Baby & Kleinkind > Stillen & Füttern > Stillkissen +Baby & Kleinkind > Stillen & Füttern > Stillkissenbezüge +Baby & Kleinkind > Stillen & Füttern > Stilltücher +Baby & Kleinkind > Töpfchentraining +Baby & Kleinkind > Töpfchentraining > Töpfchen +Baby & Kleinkind > Töpfchentraining > Töpfchentrainingsets +Baby & Kleinkind > Wickelbedarf +Baby & Kleinkind > Wickelbedarf > Baby-Reinigungstücher +Baby & Kleinkind > Wickelbedarf > Behandlung von Windeldermatitis +Baby & Kleinkind > Wickelbedarf > Behälter & Warmhalter für Baby-Reinigungstücher +Baby & Kleinkind > Wickelbedarf > Wickelauflagen +Baby & Kleinkind > Wickelbedarf > Wickelauflagen & Bezüge +Baby & Kleinkind > Wickelbedarf > Windel-Organizer +Baby & Kleinkind > Wickelbedarf > Windelbeutel +Baby & Kleinkind > Wickelbedarf > Windeleimer +Baby & Kleinkind > Wickelbedarf > Windeleimerzubehör +Baby & Kleinkind > Wickelbedarf > Windeleinlagen +Baby & Kleinkind > Wickelbedarf > Windeln +Baby & Kleinkind > Wickelbedarf > Windelsets +Bekleidung & Accessoires +Bekleidung & Accessoires > Bekleidung +Bekleidung & Accessoires > Bekleidung > Anzüge +Bekleidung & Accessoires > Bekleidung > Anzüge > Anzüge & Hosenanzüge +Bekleidung & Accessoires > Bekleidung > Anzüge > Kostüme +Bekleidung & Accessoires > Bekleidung > Anzüge > Smokings +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby- & Kleinkind-Kombis +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby- & Kleinkind-Oberbekleidung +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby- & Kleinkindsocken +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby-Bodys +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Baby-Schlafkleidung & -Schlafsäcke +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Babyüberhosen +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Bademode für Babys & Kleinkinder +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Kleider für Babys & Kleinkinder +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Kleinkindunterwäsche +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Oberteile für Babys & Kleinkinder +Bekleidung & Accessoires > Bekleidung > Baby- & Kleinkindbekleidung > Unterteile für Babys & Kleinkinder +Bekleidung & Accessoires > Bekleidung > Bademode +Bekleidung & Accessoires > Bekleidung > Brautmoden +Bekleidung & Accessoires > Bekleidung > Brautmoden > Brautjungfernkleider +Bekleidung & Accessoires > Bekleidung > Brautmoden > Brautkleider +Bekleidung & Accessoires > Bekleidung > Einteiler +Bekleidung & Accessoires > Bekleidung > Einteiler > Latzhosen +Bekleidung & Accessoires > Bekleidung > Einteiler > Overalls +Bekleidung & Accessoires > Bekleidung > Einteiler > Turn- & Gymnastikanzüge +Bekleidung & Accessoires > Bekleidung > Hosen +Bekleidung & Accessoires > Bekleidung > Kleider +Bekleidung & Accessoires > Bekleidung > Kombinationen +Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear +Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Bademäntel +Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Loungewear +Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Nachthemden +Bekleidung & Accessoires > Bekleidung > Nachtwäsche & Loungewear > Schlafanzüge +Bekleidung & Accessoires > Bekleidung > Röcke +Bekleidung & Accessoires > Bekleidung > Shirts & Tops +Bekleidung & Accessoires > Bekleidung > Shorts +Bekleidung & Accessoires > Bekleidung > Skorts +Bekleidung & Accessoires > Bekleidung > Sportbekleidung +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > American Football-Hosen +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Boxshorts +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung > Ghillie-Anzüge +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung > Jagd- & Angelwesten +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Jagdbekleidung > Jagd- & taktische Hosen +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Kampfsporthosen +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung > Motorrad-Kombis +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung > Motorradhosen +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Motorradbekleidung > Motorradjacken +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Paintballbekleidung +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradhosen (kurz) +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradhosen (lang) +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradtrikots +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Fahrradträgerhosen +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Radsport-Funktionsbekleidung > Radsport-Zeitfahranzüge +Bekleidung & Accessoires > Bekleidung > Sportbekleidung > Tanzkleider, Tanzröcke und Tanzkostüme +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Dirndl +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Hakama-Hosen +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimono-Oberbekleidung +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Kimonos +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Religiöse Festkleidung +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Religiöse Festkleidung > Tauf- & Kommunionskleider +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Saris +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Trachten Lederhosen +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Traditionelle japanische formelle Kleidung +Bekleidung & Accessoires > Bekleidung > Traditionelle & Festkleidung > Yukata +Bekleidung & Accessoires > Bekleidung > Uniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Arbeitshosen +Bekleidung & Accessoires > Bekleidung > Uniformen > Fliegeruniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Militäruniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Schuluniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sicherheitsdienst-Bekleidung +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > American Football-Uniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Baseballuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Basketballuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Cheerleading-Uniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Fußballuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Hockeyuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Kampfsportuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Kricketuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Ringeruniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Schiedsrichteruniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Sportuniformen > Softballuniformen +Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe +Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe > Kochhosen +Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe > Kochjacken +Bekleidung & Accessoires > Bekleidung > Uniformen > Uniformen für das Restaurantgewerbe > Kochmützen +Bekleidung & Accessoires > Bekleidung > Uniformen > Ärztekittel +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > BH-Einlagen +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > BH-Träger & -Erweiterungen +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > BH-Träger-Pads +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > BH-Zubehör > Brustaufkleber +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Büstenhalter +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous-Accessoires +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous-Accessoires > Strumpfbänder +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Dessous-Accessoires > Strumpfhalter +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Lange Unterhosen +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Petticoats & Rüschenhöschen +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Shapewear +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Socken +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Strumpfhosen +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Suspensorien +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Unterhemden +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Unterhosen +Bekleidung & Accessoires > Bekleidung > Unterwäsche & Socken > Unterwäsche +Bekleidung & Accessoires > Bekleidung > Überbekleidung +Bekleidung & Accessoires > Bekleidung > Überbekleidung > Chaps +Bekleidung & Accessoires > Bekleidung > Überbekleidung > Mäntel & Jacken +Bekleidung & Accessoires > Bekleidung > Überbekleidung > Regenanzüge +Bekleidung & Accessoires > Bekleidung > Überbekleidung > Regenhosen +Bekleidung & Accessoires > Bekleidung > Überbekleidung > Schneehosen und - anzüge +Bekleidung & Accessoires > Bekleidung > Überbekleidung > Westen +Bekleidung & Accessoires > Bekleidungsaccessoires +Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung +Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung > Obis +Bekleidung & Accessoires > Bekleidungsaccessoires > Accessoires für traditionelle Kleidung > Tabi-Socken +Bekleidung & Accessoires > Bekleidungsaccessoires > Ansteckbuttons +Bekleidung & Accessoires > Bekleidungsaccessoires > Armstulpen +Bekleidung & Accessoires > Bekleidungsaccessoires > Bandanas & Stofftücher +Bekleidung & Accessoires > Bekleidungsaccessoires > Beinstulpen +Bekleidung & Accessoires > Bekleidungsaccessoires > Braut-Accessoires +Bekleidung & Accessoires > Bekleidungsaccessoires > Braut-Accessoires > Brautschleier +Bekleidung & Accessoires > Bekleidungsaccessoires > Einstecktücher +Bekleidung & Accessoires > Bekleidungsaccessoires > Fächer +Bekleidung & Accessoires > Bekleidungsaccessoires > Gürtel +Bekleidung & Accessoires > Bekleidungsaccessoires > Gürtelschnallen +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Diademe +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Duttkissen +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haargabeln +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haargummis +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarklammern, -nadeln & -clips +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarkränze +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarkämme +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarnetze +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Haarverlängerungen +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Perücken +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Perücken-Accessoires +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Perücken-Accessoires > Perückenkleber +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Perücken-Accessoires > Perückennetze +Bekleidung & Accessoires > Bekleidungsaccessoires > Haaraccessoires > Stirnbänder +Bekleidung & Accessoires > Bekleidungsaccessoires > Halswärmer +Bekleidung & Accessoires > Bekleidungsaccessoires > Handschuhe & Fausthandschuhe +Bekleidung & Accessoires > Bekleidungsaccessoires > Hosenträger +Bekleidung & Accessoires > Bekleidungsaccessoires > Hüte +Bekleidung & Accessoires > Bekleidungsaccessoires > Knopfnieten +Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher +Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher > Fascinators +Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher > Kopfschmuck +Bekleidung & Accessoires > Bekleidungsaccessoires > Kopfbekleidung & -tücher > Turbane +Bekleidung & Accessoires > Bekleidungsaccessoires > Kragenstäbchen +Bekleidung & Accessoires > Bekleidungsaccessoires > Krawatten +Bekleidung & Accessoires > Bekleidungsaccessoires > Krawattennadeln +Bekleidung & Accessoires > Bekleidungsaccessoires > Leis +Bekleidung & Accessoires > Bekleidungsaccessoires > Manschettenknöpfe +Bekleidung & Accessoires > Bekleidungsaccessoires > Muffe +Bekleidung & Accessoires > Bekleidungsaccessoires > Ohrenschützer +Bekleidung & Accessoires > Bekleidungsaccessoires > Schals & Halstücher +Bekleidung & Accessoires > Bekleidungsaccessoires > Schwangerschaftsgürtel & Bauchstützen +Bekleidung & Accessoires > Bekleidungsaccessoires > Schweißbänder +Bekleidung & Accessoires > Bekleidungsaccessoires > Schärpen +Bekleidung & Accessoires > Bekleidungsaccessoires > Sonnenbrillen +Bekleidung & Accessoires > Bekleidungsaccessoires > Sturmhauben +Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung +Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Baby- & Kleinkindhandschuhe +Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Babyschutzbekleidung +Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Gürtel für Babys & Kleinkinder +Bekleidung & Accessoires > Bekleidungsaccessoires > Zubehör für Baby- & Kleinkindbekleidung > Kopfbedeckungen für Babys & Kleinkinder +Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires +Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Brieftaschenketten +Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Scheckheftetuis +Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Schlüsselanhänger +Bekleidung & Accessoires > Handtaschen & Geldbörsenaccessoires > Tragebänder +Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis +Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Ausweistaschen +Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Geldbeutel & Geldklammern +Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Handtaschen +Bekleidung & Accessoires > Handtaschen, Geldbörsen & Etuis > Visitenkartenetuis +Bekleidung & Accessoires > Kostüme & Accessoires +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Glatzen +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Kostüm-Accessoire-Sets +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Kostüm-Handschuhe +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Kostümhüte +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Plastikschmuck +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Spezial-Schminkeffekte +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Tabakwarenimitate +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümaccessoires > Umhänge für Kostüme +Bekleidung & Accessoires > Kostüme & Accessoires > Kostüme & Verkleidungen +Bekleidung & Accessoires > Kostüme & Accessoires > Kostümschuhe +Bekleidung & Accessoires > Kostüme & Accessoires > Masken +Bekleidung & Accessoires > Schmuck +Bekleidung & Accessoires > Schmuck > Armbanduhren & Taschenuhren +Bekleidung & Accessoires > Schmuck > Armbänder +Bekleidung & Accessoires > Schmuck > Broschen und Anstecknadeln +Bekleidung & Accessoires > Schmuck > Charms & Anhänger +Bekleidung & Accessoires > Schmuck > Fußkettchen +Bekleidung & Accessoires > Schmuck > Halsketten +Bekleidung & Accessoires > Schmuck > Körperschmuck +Bekleidung & Accessoires > Schmuck > Ohrringe +Bekleidung & Accessoires > Schmuck > Ringe +Bekleidung & Accessoires > Schmuck > Schmucksets +Bekleidung & Accessoires > Schmuck > Uhrenaccessoires +Bekleidung & Accessoires > Schmuck > Uhrenaccessoires > Aufkleber für Uhren +Bekleidung & Accessoires > Schmuck > Uhrenaccessoires > Uhrenarmbänder +Bekleidung & Accessoires > Schmuck > Uhrenaccessoires > Uhrenbeweger +Bekleidung & Accessoires > Schuh-Accessoires +Bekleidung & Accessoires > Schuh-Accessoires > Gamaschen +Bekleidung & Accessoires > Schuh-Accessoires > Schnürsenkel +Bekleidung & Accessoires > Schuh-Accessoires > Sporen +Bekleidung & Accessoires > Schuh-Accessoires > Stiefelsocken +Bekleidung & Accessoires > Schuh-Accessoires > Überschuhe +Bekleidung & Accessoires > Schuhe +Bürobedarf +Bürobedarf > Ablage & Organisation +Bürobedarf > Ablage & Organisation > Adressbücher +Bürobedarf > Ablage & Organisation > Akten- & Schreibmappen +Bürobedarf > Ablage & Organisation > Aktenaufbewahrungsboxen +Bürobedarf > Ablage & Organisation > Aktenhüllen und Klemmhefter +Bürobedarf > Ablage & Organisation > Bindesysteme +Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordner +Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör +Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör > Einbandringe +Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör > Klarsichthüllen +Bürobedarf > Ablage & Organisation > Bindesysteme > Aktenordnerzubehör > Registerblätter +Bürobedarf > Ablage & Organisation > Bindesysteme > Bindegeräte +Bürobedarf > Ablage & Organisation > Bindesysteme > Binderücken +Bürobedarf > Ablage & Organisation > CD-/DVD-Ordnungssysteme +Bürobedarf > Ablage & Organisation > Federmappen +Bürobedarf > Ablage & Organisation > Geldkassetten +Bürobedarf > Ablage & Organisation > Kalender, Organizer & Zeitplaner +Bürobedarf > Ablage & Organisation > Karteikästen +Bürobedarf > Ablage & Organisation > Kartenhüllen +Bürobedarf > Ablage & Organisation > Postkartenorganizer +Bürobedarf > Ablage & Organisation > Postsortiersysteme +Bürobedarf > Ablage & Organisation > Register- & Hängemappen +Bürobedarf > Ablage & Organisation > Rezeptkästen +Bürobedarf > Ablage & Organisation > Schreibtischorganizer +Bürobedarf > Ablage & Organisation > Visitenkarten-Ständer +Bürobedarf > Ablage & Organisation > Visitenkartenbücher +Bürobedarf > Bücherzubehör +Bürobedarf > Bücherzubehör > Bucheinbände +Bürobedarf > Bücherzubehör > Buchständer & -stützen +Bürobedarf > Bücherzubehör > Leselampen +Bürobedarf > Bücherzubehör > Lesezeichen +Bürobedarf > Büroarbeitsmittel +Bürobedarf > Büroarbeitsmittel > Bleistiftspitzer +Bürobedarf > Büroarbeitsmittel > Brieföffner +Bürobedarf > Büroarbeitsmittel > Bürostempel +Bürobedarf > Büroarbeitsmittel > Heftgeräte +Bürobedarf > Büroarbeitsmittel > Heftklammernzieher +Bürobedarf > Büroarbeitsmittel > Klebebandabroller +Bürobedarf > Büroarbeitsmittel > Klemmbretter +Bürobedarf > Büroarbeitsmittel > Lupen +Bürobedarf > Büroarbeitsmittel > Schreibgeräte +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Bleistifte +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Bleistifte > Schreibbleistifte +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Bleistifte > Zeichenbleistifte & Buntstifte +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Füller- & Bleistift-Sets +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Füller & Bleistifte > Schreibstifte, Kugelschreiber & Füller +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Markierstifte & Textmarker +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Multifunktions-Schreibgeräte +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Pastellkreiden +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Tafelkreide +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Wachsmalstifte +Bürobedarf > Büroarbeitsmittel > Schreibgeräte > Zeichenkohle +Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör +Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör > Bleistiftminen +Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör > Füllertinte & -patronen +Bürobedarf > Büroarbeitsmittel > Schreibwerkzeugzubehör > Marker-Nachfülltinte +Bürobedarf > Büroarbeitsmittel > Tischglocken +Bürobedarf > Bürogeräte +Bürobedarf > Bürogeräte > Aktenvernichter +Bürobedarf > Bürogeräte > Diktiergeräte & Geräte zur Transkription +Bürobedarf > Bürogeräte > Elektronische Wörterbücher & Übersetzungsgeräte +Bürobedarf > Bürogeräte > Etikettendrucker +Bürobedarf > Bürogeräte > Frankiermaschinen +Bürobedarf > Bürogeräte > Laminiergeräte +Bürobedarf > Bürogeräte > Schreibmaschinen +Bürobedarf > Bürogeräte > Stempeluhren +Bürobedarf > Bürogeräte > Taschenrechner +Bürobedarf > Bürogeräte > Taschenrechner-Zubehör +Bürobedarf > Büromatten & Stuhlunterlagen +Bürobedarf > Büromatten & Stuhlunterlagen > Arbeitsplatzmatten +Bürobedarf > Büromatten & Stuhlunterlagen > Büromatten +Bürobedarf > Büromatten & Stuhlunterlagen > Stuhlunterlagen +Bürobedarf > Bürowagen +Bürobedarf > Bürowagen > Aktenwagen +Bürobedarf > Bürowagen > Bücherwagen +Bürobedarf > Bürowagen > Medienwagen +Bürobedarf > Bürowagen > Mehrzweckwagen +Bürobedarf > Bürowagen > Postwagen +Bürobedarf > Impulsschweißgeräte +Bürobedarf > Laptophalter +Bürobedarf > Namensschilder +Bürobedarf > Papierbearbeitung +Bürobedarf > Papierbearbeitung > Blattwender +Bürobedarf > Papierbearbeitung > Briefbeschwerer +Bürobedarf > Papierbearbeitung > Locher +Bürobedarf > Papierbearbeitung > Papierfalzmaschinen +Bürobedarf > Papierbearbeitung > Papierrüttler +Bürobedarf > Papierbearbeitung > Schreibunterlagen +Bürobedarf > Präsentationsbedarf +Bürobedarf > Präsentationsbedarf > Ausstellungstafeln +Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Hartschaumstoffplatten +Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Pinnwände +Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Plakatkartons +Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Trägerplatten +Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Zubehör für Anschlagbretter +Bürobedarf > Präsentationsbedarf > Ausstellungstafeln > Zubehör für Anschlagbretter > Dekorative Elemente für Anschlagbretter +Bürobedarf > Präsentationsbedarf > Dokumentenkameras +Bürobedarf > Präsentationsbedarf > Flipchart-Blöcke +Bürobedarf > Präsentationsbedarf > Flipcharts +Bürobedarf > Präsentationsbedarf > Folien +Bürobedarf > Präsentationsbedarf > Laserpointer +Bürobedarf > Präsentationsbedarf > Lesepulte +Bürobedarf > Präsentationsbedarf > Präsentationsfernbedienungen +Bürobedarf > Präsentationsbedarf > Schreibtafeln +Bürobedarf > Präsentationsbedarf > Whiteboards +Bürobedarf > Schreibtischunterlagen +Bürobedarf > Schreibwaren +Bürobedarf > Schreibwaren > Büroklammern & Papierklammern +Bürobedarf > Schreibwaren > Büroklebeband +Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder +Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Adressaufkleber +Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Klebebänder für Etikettiergeräte +Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Label Clips +Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Trennblätter +Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Versandanhänger +Bürobedarf > Schreibwaren > Etiketten & Anhängerschilder > Versandaufkleber & -etiketten +Bürobedarf > Schreibwaren > Gummibänder +Bürobedarf > Schreibwaren > Heftklammern +Bürobedarf > Schreibwaren > Klebepads +Bürobedarf > Schreibwaren > Korrekturflüssigkeiten, Korrekturstifte & Korrekturbänder +Bürobedarf > Schreibwaren > Laminierfolie & Schutzhüllen +Bürobedarf > Schreibwaren > Musterklammern +Bürobedarf > Schreibwaren > Papierprodukte +Bürobedarf > Schreibwaren > Papierprodukte > Blanko-Ausweise +Bürobedarf > Schreibwaren > Papierprodukte > Briefpapier +Bürobedarf > Schreibwaren > Papierprodukte > Briefumschläge +Bürobedarf > Schreibwaren > Papierprodukte > Drucker- & Kopierpapier +Bürobedarf > Schreibwaren > Papierprodukte > Feinkarton +Bürobedarf > Schreibwaren > Papierprodukte > Geschäftsformulare & -belege +Bürobedarf > Schreibwaren > Papierprodukte > Haftnotizen +Bürobedarf > Schreibwaren > Papierprodukte > Karteikarten +Bürobedarf > Schreibwaren > Papierprodukte > Kassenrollen +Bürobedarf > Schreibwaren > Papierprodukte > Notizbücher & Notizblöcke +Bürobedarf > Schreibwaren > Papierprodukte > Papier für Hefter +Bürobedarf > Schreibwaren > Papierprodukte > Postkarten +Bürobedarf > Schreibwaren > Papierprodukte > Scheckformulare +Bürobedarf > Schreibwaren > Papierprodukte > Visitenkarten +Bürobedarf > Schreibwaren > Radiergummis +Bürobedarf > Schreibwaren > Reißzwecken & Pins +Bürobedarf > Versandbedarf +Bürobedarf > Versandbedarf > Packband +Bürobedarf > Versandbedarf > Umzugs- & Versandkartons +Bürobedarf > Versandbedarf > Verpackungsmaterialien +Elektronik +Elektronik > Audio +Elektronik > Audio > Audiokomponenten +Elektronik > Audio > Audiokomponenten > AV-Receiver +Elektronik > Audio > Audiokomponenten > Audiomixer +Elektronik > Audio > Audiokomponenten > Audiotransmitter +Elektronik > Audio > Audiokomponenten > Audiotransmitter > Bluetooth-Sender +Elektronik > Audio > Audiokomponenten > Audiotransmitter > FM-Transmitter +Elektronik > Audio > Audiokomponenten > Audioverstärker +Elektronik > Audio > Audiokomponenten > Audioverstärker > Kopfhörerverstärker +Elektronik > Audio > Audiokomponenten > Audioverstärker > Stereoverstärker +Elektronik > Audio > Audiokomponenten > Channel Strips +Elektronik > Audio > Audiokomponenten > DI-Boxen +Elektronik > Audio > Audiokomponenten > Kopfhörer & Headsets +Elektronik > Audio > Audiokomponenten > Lautsprecher +Elektronik > Audio > Audiokomponenten > Mikrofone +Elektronik > Audio > Audiokomponenten > Signalprozessoren +Elektronik > Audio > Audiokomponenten > Signalprozessoren > Effektprozessoren +Elektronik > Audio > Audiokomponenten > Signalprozessoren > Equalizer +Elektronik > Audio > Audiokomponenten > Signalprozessoren > Frequenzweichen +Elektronik > Audio > Audiokomponenten > Signalprozessoren > Mikrofonvorverstärker +Elektronik > Audio > Audiokomponenten > Signalprozessoren > Noise Gates & Kompressoren +Elektronik > Audio > Audiokomponenten > Signalprozessoren > Phono-Vorverstärker +Elektronik > Audio > Audiokomponenten > Signalprozessoren > Steuerungssysteme für PA-Anlagen +Elektronik > Audio > Audiokomponenten > Studio-Aufnahmesets +Elektronik > Audio > Audioplayer & -rekorder +Elektronik > Audio > Audioplayer & -rekorder > CD-Player & -Rekorder +Elektronik > Audio > Audioplayer & -rekorder > Diktiergeräte +Elektronik > Audio > Audioplayer & -rekorder > Ghettoblaster +Elektronik > Audio > Audioplayer & -rekorder > Heimkinosysteme +Elektronik > Audio > Audioplayer & -rekorder > Jukeboxen +Elektronik > Audio > Audioplayer & -rekorder > Karaokesysteme +Elektronik > Audio > Audioplayer & -rekorder > Kassettenspieler & -Rekorder +Elektronik > Audio > Audioplayer & -rekorder > MP3-Player +Elektronik > Audio > Audioplayer & -rekorder > Mehrspurrekorder +Elektronik > Audio > Audioplayer & -rekorder > MiniDisc-Player +Elektronik > Audio > Audioplayer & -rekorder > Plattenspieler +Elektronik > Audio > Audioplayer & -rekorder > Radios +Elektronik > Audio > Audioplayer & -rekorder > Stereoanlagen +Elektronik > Audio > Audioplayer & -rekorder > Tonbandgeräte +Elektronik > Audio > Audiozubehör +Elektronik > Audio > Audiozubehör > Audio- & Video-Receiver-Zubehör +Elektronik > Audio > Audiozubehör > Kopfhörer- & Headset-Zubehör +Elektronik > Audio > Audiozubehör > Kopfhörer- & Headset-Zubehör > Kopfhörer- & In-Ear-Ohrhörer-Polster +Elektronik > Audio > Audiozubehör > Lautsprecherzubehör +Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Bass-Shaker +Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Lautsprecherkomponenten & -sets +Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Lautsprecherständer +Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Lautsprechertaschen, -abdeckungen & -cases +Elektronik > Audio > Audiozubehör > Lautsprecherzubehör > Taschen für Lautsprecherständer +Elektronik > Audio > Audiozubehör > Mikrofonständer +Elektronik > Audio > Audiozubehör > Mikrofonzubehör +Elektronik > Audio > Audiozubehör > Plattenspielerzubehör +Elektronik > Audio > Audiozubehör > Satellitenradio-Zubehör +Elektronik > Audio > Audiozubehör > Zubehör für Karaoke-Systeme +Elektronik > Audio > Audiozubehör > Zubehör für Karaoke-Systeme > Karaoke-Speicherchips +Elektronik > Audio > Audiozubehör > Zubehör für MP3-Player +Elektronik > Audio > Audiozubehör > Zubehör für MP3-Player > MP3-Player-Taschen +Elektronik > Audio > Audiozubehör > Zubehör für MP3-Player > Zubehörsets für MP3-Player & Mobiltelefone +Elektronik > Audio > Beschallungsanlagen +Elektronik > Audio > Bühnenausstattung +Elektronik > Audio > Bühnenausstattung > Drahtlossender +Elektronik > Audio > DJ- & Spezialaudiogeräte +Elektronik > Audio > DJ- & Spezialaudiogeräte > DJ CD-Player +Elektronik > Audio > DJ- & Spezialaudiogeräte > DJ Systeme +Elektronik > Audio > Megafone +Elektronik > Computer +Elektronik > Computer > Barebone-Computer +Elektronik > Computer > Computerserver +Elektronik > Computer > Datenbrillen +Elektronik > Computer > Desktop-Computer +Elektronik > Computer > E-Book-Reader & Handheld-Computer +Elektronik > Computer > E-Book-Reader & Handheld-Computer > Datenerfassungsgeräte +Elektronik > Computer > E-Book-Reader & Handheld-Computer > E-Book-Reader +Elektronik > Computer > E-Book-Reader & Handheld-Computer > PDAs +Elektronik > Computer > Interaktive Kioske +Elektronik > Computer > Laptops +Elektronik > Computer > Multitouch-Tischcomputer +Elektronik > Computer > Tablet-PCs +Elektronik > Computer > Thin Clients & Zero Clients +Elektronik > Drucken, Kopieren, Scannen & Faxen +Elektronik > Drucken, Kopieren, Scannen & Faxen > 3D-Drucker +Elektronik > Drucken, Kopieren, Scannen & Faxen > 3D-Drucker-Zubehör +Elektronik > Drucken, Kopieren, Scannen & Faxen > Drucker, Kopierer & Faxgeräte +Elektronik > Drucken, Kopieren, Scannen & Faxen > Scanner +Elektronik > Drucken, Kopieren, Scannen & Faxen > Scannerzubehör +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Duplexeinheiten +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial > Drucker-Farbbänder +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial > Druckerfilter +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial > Druckertrommeln & Sets +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial > Druckerwartungssets +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial > Druckköpfe +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial > Toner & Tintenpatronen +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Drucker-Verbrauchsmaterial > Toner- & Inkjet-Kartuschen +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Druckerspeicher +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Druckertische +Elektronik > Drucken, Kopieren, Scannen & Faxen > Zubehör für Drucker, Kopierer & Faxgeräte > Ersatzteile für Drucker, Kopierer & Faxgeräte +Elektronik > Elektrische Instrumente Seefahrt +Elektronik > Elektrische Instrumente Seefahrt > Audio- und Videoemfpänger +Elektronik > Elektrische Instrumente Seefahrt > Fischfinder +Elektronik > Elektrische Instrumente Seefahrt > Marine-Lautsprecher +Elektronik > Elektrische Instrumente Seefahrt > Schiffsradar +Elektronik > Elektrische Instrumente Seefahrt > Seefunkgeräte +Elektronik > Elektrische Instrumente Seefahrt > Seekartenplotter & GPS +Elektronik > Elektronische Leiterplatten & Bauteile +Elektronik > Elektronische Leiterplatten & Bauteile > Decoder & Encoder für Schaltkreise +Elektronik > Elektronische Leiterplatten & Bauteile > Elektronische Filter +Elektronik > Elektronische Leiterplatten & Bauteile > Halbleiter +Elektronik > Elektronische Leiterplatten & Bauteile > Halbleiter > Dioden +Elektronik > Elektronische Leiterplatten & Bauteile > Halbleiter > Integrierte Schaltkreise & Chips +Elektronik > Elektronische Leiterplatten & Bauteile > Halbleiter > Mikrocontroller +Elektronik > Elektronische Leiterplatten & Bauteile > Halbleiter > Transistoren +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Computer-Leiterplatten +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Computer-Leiterplatten > Computer-Inverterplatine +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Computer-Leiterplatten > Festplatten-Leiterplatten +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Computer-Leiterplatten > Motherboards +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Entwicklungsboard +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Kamera-Leiterplatten +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Leiterplatten für Drucker, Kopierer & Faxgeräte +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Leiterplatten für Fernsehgeräte +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Leiterplatten für Fitnessgeräte +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Leiterplatten für Haushaltsgeräte +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Leiterplatten für Pools und Spas +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplatten > Leiterplatten für Scanner +Elektronik > Elektronische Leiterplatten & Bauteile > Leiterplattenzubehör +Elektronik > Elektronische Leiterplatten & Bauteile > Passive elektronische Bauelemente +Elektronik > Elektronische Leiterplatten & Bauteile > Passive elektronische Bauelemente > Induktoren +Elektronik > Elektronische Leiterplatten & Bauteile > Passive elektronische Bauelemente > Kondensatoren +Elektronik > Elektronische Leiterplatten & Bauteile > Passive elektronische Bauelemente > Oszillatoren +Elektronik > Elektronische Leiterplatten & Bauteile > Passive elektronische Bauelemente > Widerstände +Elektronik > Elektronische Leiterplatten & Bauteile > Platinenentwicklung +Elektronik > Elektronische Leiterplatten & Bauteile > Platinenentwicklung > Steckplatinen +Elektronik > Elektronisches Zubehör +Elektronik > Elektronisches Zubehör > Adapter +Elektronik > Elektronisches Zubehör > Adapter > Audio/Video-Adapter +Elektronik > Elektronisches Zubehör > Adapter > Speicheradapter +Elektronik > Elektronisches Zubehör > Adapter > USB-Adapter +Elektronik > Elektronisches Zubehör > Antennen +Elektronik > Elektronisches Zubehör > Antennenzubehör +Elektronik > Elektronisches Zubehör > Antennenzubehör > Antennenhalterungen & -befestigungen +Elektronik > Elektronisches Zubehör > Antennenzubehör > Dreheinrichtungen +Elektronik > Elektronisches Zubehör > Antennenzubehör > Satelliten-LNBs +Elektronik > Elektronisches Zubehör > Audio- und Video-Splitter & -Switches +Elektronik > Elektronisches Zubehör > Audio- und Video-Splitter & -Switches > DVI-Splitter und -Switches +Elektronik > Elektronisches Zubehör > Audio- und Video-Splitter & -Switches > HDMI-Splitter & -Switches +Elektronik > Elektronisches Zubehör > Audio- und Video-Splitter & -Switches > VGA-Splitter und -Switches +Elektronik > Elektronisches Zubehör > Computerkomponenten +Elektronik > Elektronisches Zubehör > Computerkomponenten > Blade-Server-Gehäuse +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Backplates & I/O Shields +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Kühlkomponenten +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Starter-Kits +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Steckkarten +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Steckkarten > Computer-Steckkarten & -Adapter +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Steckkarten > Grafikkarten & Videoadapter +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Steckkarten > Riser-Karten +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Steckkarten > Soundkarten +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computer-Steckkarten > TV-Karten und -Adapter +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computernetzteile +Elektronik > Elektronisches Zubehör > Computerkomponenten > Computerregale & -Befestigungssysteme +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Computer Mäuse & Trackballs +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Digitale Stifte +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Eingabegeräte zur Gestensteuerung +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Elektronische Kartenlesegeräte +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Fingerabdruck-Lesegeräte +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Gamecontroller +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Grafiktabletts +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > KVM-Switches +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Speicherkartenlesegerät +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Strichcode-Scanner +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Tastaturen +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Touchpads +Elektronik > Elektronisches Zubehör > Computerkomponenten > Eingabegeräte > Ziffernblöcke +Elektronik > Elektronisches Zubehör > Computerkomponenten > Ersatzteile für E-Book-Reader +Elektronik > Elektronisches Zubehör > Computerkomponenten > Ersatzteile für E-Book-Reader > Ersatzbildschirme für E-Book-Reader +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile > Laptop-Bildschirmdigitalisierer +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile > Laptop-Ersatzbildschirme +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile > Laptop-Ersatzkabel +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile > Laptop-Ersatzlautsprecher +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile > Laptop-Ersatztastaturen +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile > Laptop-Scharniere +Elektronik > Elektronisches Zubehör > Computerkomponenten > Laptopteile > Laptopgehäuse +Elektronik > Elektronisches Zubehör > Computerkomponenten > PC-Gehäuse +Elektronik > Elektronisches Zubehör > Computerkomponenten > Prozessoren +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Bandlaufwerke +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer > CD-/DVD-Brenner +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer > Festplatten-Duplizierer +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Datenspeicher-Duplizierer > USB-Laufwerk-Duplizierer +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Disk-Arrays +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Diskettenlaufwerke +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Festplatten +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Festplattenzubehör +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Festplattenzubehör > Festplatten-Dockingstationen +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Festplattenzubehör > Festplatten-Transporttaschen +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Festplattenzubehör > Festplattengehäuse & -steckplätze +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Netzwerkspeichersysteme +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > Optische Laufwerke +Elektronik > Elektronisches Zubehör > Computerkomponenten > Speichergeräte > USB-Massenspeicher +Elektronik > Elektronisches Zubehör > Computerkomponenten > Tablet-PC-Ersatzteile +Elektronik > Elektronisches Zubehör > Computerkomponenten > Tablet-PC-Ersatzteile > Tablet-Bildschirme und Bildschirm-Digitizer +Elektronik > Elektronisches Zubehör > Computerkomponenten > Tablet-PC-Ersatzteile > Tablet-Ersatzlautsprecher +Elektronik > Elektronisches Zubehör > Computerkomponenten > Tablet-PC-Ersatzteile > Tablet-Gehäuse & -Rahmen +Elektronik > Elektronisches Zubehör > Computerkomponenten > USB- & FireWire-Hubs +Elektronik > Elektronisches Zubehör > Computerkomponenten > Zubehör für Eingabegeräte +Elektronik > Elektronisches Zubehör > Computerkomponenten > Zubehör für Eingabegeräte > Halterung für Strichcodeleser +Elektronik > Elektronisches Zubehör > Computerkomponenten > Zubehör für Eingabegeräte > Mäuse und Trackball-Zubehör +Elektronik > Elektronisches Zubehör > Computerkomponenten > Zubehör für Eingabegeräte > Tastaturtasten & -kappen +Elektronik > Elektronisches Zubehör > Computerkomponenten > Zubehör für Eingabegeräte > Zubehör für Gamecontroller +Elektronik > Elektronisches Zubehör > Computerzubehör +Elektronik > Elektronisches Zubehör > Computerzubehör > Computer-Monitorständer +Elektronik > Elektronisches Zubehör > Computerzubehör > Computer-Schutzhüllen +Elektronik > Elektronisches Zubehör > Computerzubehör > Computerzubehör-Sets +Elektronik > Elektronisches Zubehör > Computerzubehör > Ersatzspitzen für Stylus Pens +Elektronik > Elektronisches Zubehör > Computerzubehör > Laptop-Dockingstationen +Elektronik > Elektronisches Zubehör > Computerzubehör > Mousepads +Elektronik > Elektronisches Zubehör > Computerzubehör > Stylus Pens +Elektronik > Elektronisches Zubehör > Computerzubehör > Ständer für Tablet-PCs +Elektronik > Elektronisches Zubehör > Computerzubehör > Tastatur- & Maus-Handballenauflage +Elektronik > Elektronisches Zubehör > Computerzubehör > Tastaturablagen +Elektronik > Elektronisches Zubehör > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer +Elektronik > Elektronisches Zubehör > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > PDA-Zubehör +Elektronik > Elektronisches Zubehör > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > PDA-Zubehör > PDA-Taschen +Elektronik > Elektronisches Zubehör > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > Zubehör für E-Book-Reader +Elektronik > Elektronisches Zubehör > Computerzubehör > Zubehör für E-Book-Reader & Handheld-Computer > Zubehör für E-Book-Reader > E-Book-Reader-Taschen +Elektronik > Elektronisches Zubehör > Drei- und Einbeinstative für Mobiltelefone und Tablets +Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge +Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Blickschutzfilter +Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Display-Schutzfolien +Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Elektronik-Sticker & -Aufkleber +Elektronik > Elektronisches Zubehör > Elektronik-Folien & -Überzüge > Tastaturschutz +Elektronik > Elektronisches Zubehör > Elektronikreiniger +Elektronik > Elektronisches Zubehör > Fernbedienungen +Elektronik > Elektronisches Zubehör > Kabel +Elektronik > Elektronisches Zubehör > Kabel > Audio- & Videokabel +Elektronik > Elektronisches Zubehör > Kabel > Datenübertragungs- & Speicherkabel +Elektronik > Elektronisches Zubehör > Kabel > KVM-Kabel +Elektronik > Elektronisches Zubehör > Kabel > Netzwerkkabel +Elektronik > Elektronisches Zubehör > Kabel > System- & Netzkabel +Elektronik > Elektronisches Zubehör > Kabel > Telefonkabel +Elektronik > Elektronisches Zubehör > Kabel-Management +Elektronik > Elektronisches Zubehör > Kabel-Management > Aderhülsen & Kabelmuffen +Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelbinder +Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelbinderpistolen +Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelmarkierungen +Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelschellen +Elektronik > Elektronisches Zubehör > Kabel-Management > Kabelträger +Elektronik > Elektronisches Zubehör > Kabel-Management > Schalttafeln +Elektronik > Elektronisches Zubehör > Leermedien +Elektronik > Elektronisches Zubehör > Signalstörer +Elektronik > Elektronisches Zubehör > Signalstörer > GPS-Störsender +Elektronik > Elektronisches Zubehör > Signalstörer > Mobiltelefon-Störsender +Elektronik > Elektronisches Zubehör > Signalstörer > Radarstörer +Elektronik > Elektronisches Zubehör > Signalverstärker +Elektronik > Elektronisches Zubehör > Speicher +Elektronik > Elektronisches Zubehör > Speicher > Cache-Speicher +Elektronik > Elektronisches Zubehör > Speicher > Flash-Speicher +Elektronik > Elektronisches Zubehör > Speicher > Flash-Speicher > Flash-Speicherkarten +Elektronik > Elektronisches Zubehör > Speicher > RAM +Elektronik > Elektronisches Zubehör > Speicher > ROM +Elektronik > Elektronisches Zubehör > Speicher > Videospeicher +Elektronik > Elektronisches Zubehör > Speicherkartenzubehör +Elektronik > Elektronisches Zubehör > Speicherkartenzubehör > Speicherkartenetuis +Elektronik > Elektronisches Zubehör > Stromversorgung +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Akkus & Batterien für schnurlose Telefone +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Akkus für Tablet-Computer +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Batterien für E-Book-Reader +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Batterien für Videospielkonsolen & Game-Controller +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Handy-Akkus +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Kameraakkus & -batterien +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Laptopakkus +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > MP3-Player-Batterien +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Mehrzweckbatterien +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > PDA-Batterien +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > USV-Batterien +Elektronik > Elektronisches Zubehör > Stromversorgung > Akkus & Batterien > Videokameraakkus & -batterien +Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör +Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör > Akkuladegeräte für Kameras +Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör > Batteriehalter +Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör > Batterieladegeräte +Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör > Laderegler +Elektronik > Elektronisches Zubehör > Stromversorgung > Batteriezubehör > Universal-Batterieprüfgeräte +Elektronik > Elektronisches Zubehör > Stromversorgung > Brennstoffzellen +Elektronik > Elektronisches Zubehör > Stromversorgung > Gehäuse für Stromversorgungsgeräte +Elektronik > Elektronisches Zubehör > Stromversorgung > Leistungsregler +Elektronik > Elektronisches Zubehör > Stromversorgung > Netzteil- & Ladegerätezubehör +Elektronik > Elektronisches Zubehör > Stromversorgung > Netzteile & Ladegeräte +Elektronik > Elektronisches Zubehör > Stromversorgung > Reiseadapter +Elektronik > Elektronisches Zubehör > Stromversorgung > Steckdosenleisten & Überspannungsschutz +Elektronik > Elektronisches Zubehör > Stromversorgung > USV +Elektronik > Elektronisches Zubehör > Stromversorgung > Zubehör für USV +Elektronik > Elektronisches Zubehör > Stromversorgung > Überspannungsschutzgeräte +Elektronik > GPS-Navigationssysteme +Elektronik > GPS-Tracker +Elektronik > GPS-Zubehör +Elektronik > GPS-Zubehör > GPS-Halterungen +Elektronik > GPS-Zubehör > GPS-Taschen +Elektronik > Geräte zur Mauterhebung +Elektronik > Kommunikationsgeräte +Elektronik > Kommunikationsgeräte > Anrufbeantworter +Elektronik > Kommunikationsgeräte > Anruferkennung +Elektronik > Kommunikationsgeräte > Funkgeräte +Elektronik > Kommunikationsgeräte > Funkgeräte > CB-Funkgeräte +Elektronik > Kommunikationsgeräte > Funkgeräte > Funkscanner +Elektronik > Kommunikationsgeräte > Funkgeräte > Funksprechgeräte +Elektronik > Kommunikationsgeräte > Funkzubehör +Elektronik > Kommunikationsgeräte > Pager +Elektronik > Kommunikationsgeräte > Sprechanlagen +Elektronik > Kommunikationsgeräte > Sprechanlagen-Zubehör +Elektronik > Kommunikationsgeräte > Telefone +Elektronik > Kommunikationsgeräte > Telefone > Konferenztelefone +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefone +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Auswurfhilfen für SIM-Karten +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Ersatzteile für Mobiltelefone +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Handy-Prepaid- & -SIM-Karten +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Handycharms & -anhänger +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Mobiltelefonhalterungen & -ständer +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Mobiltelefontaschen +Elektronik > Kommunikationsgeräte > Telefone > Mobiltelefonzubehör > Zubehör für Mobiltelefon-Kameras +Elektronik > Kommunikationsgeräte > Telefone > Satellitentelefone +Elektronik > Kommunikationsgeräte > Telefone > Schnurlostelefone +Elektronik > Kommunikationsgeräte > Telefone > Schnurtelefone +Elektronik > Kommunikationsgeräte > Telefone > Telefonzubehör +Elektronik > Kommunikationsgeräte > Telefone > Telefonzubehör > Telefonkarten +Elektronik > Kommunikationsgeräte > Videokonferenzsysteme +Elektronik > Komponenten +Elektronik > Komponenten > Beschleunigungssensoren +Elektronik > Komponenten > Modulatoren +Elektronik > Komponenten > Splitter +Elektronik > Komponenten > Steckverbinder +Elektronik > Komponenten > Wandler +Elektronik > Komponenten > Wandler > Audiowandler +Elektronik > Komponenten > Wandler > Signalwandler +Elektronik > Netzwerktechnik +Elektronik > Netzwerktechnik > Bridges & Router +Elektronik > Netzwerktechnik > Bridges & Router > Netzwerk-Bridges +Elektronik > Netzwerktechnik > Bridges & Router > VoIP-Gateways & -Router +Elektronik > Netzwerktechnik > Bridges & Router > Wireless Access Points +Elektronik > Netzwerktechnik > Bridges & Router > Wireless Router +Elektronik > Netzwerktechnik > Druckerserver +Elektronik > Netzwerktechnik > Hubs & Schalter +Elektronik > Netzwerktechnik > Konzentratoren & Multiplexer +Elektronik > Netzwerktechnik > Modems +Elektronik > Netzwerktechnik > Modemzubehör +Elektronik > Netzwerktechnik > Netzwerkkarten +Elektronik > Netzwerktechnik > Netzwerksicherheitssysteme & Firewalls +Elektronik > Netzwerktechnik > PoE-Adapter +Elektronik > Netzwerktechnik > Repeater & Sende/-Empfangsgeräte +Elektronik > Radargeschwindigkeitsmesser +Elektronik > Radarwarner +Elektronik > Spielautomatenbedarf +Elektronik > Spielautomatenbedarf > Basketballspiele +Elektronik > Spielautomatenbedarf > Flipper +Elektronik > Spielautomatenbedarf > Flipper-Zubehör +Elektronik > Spielautomatenbedarf > Skee-Ball-Maschinen +Elektronik > Spielautomatenbedarf > Spielautomaten +Elektronik > Spielautomatenbedarf > Zubehör für Spielautomaten +Elektronik > Video +Elektronik > Video > Computermonitore +Elektronik > Video > Fernseher +Elektronik > Video > Projektoren +Elektronik > Video > Projektoren > Diaprojektoren +Elektronik > Video > Projektoren > Multimedia-Projektoren +Elektronik > Video > Projektoren > Overhead-Projektoren +Elektronik > Video > Satelliten- & Kabelfernsehen +Elektronik > Video > Satelliten- & Kabelfernsehen > Kabelfernsehen-Receiver +Elektronik > Video > Satelliten- & Kabelfernsehen > Satelliten-Receiver +Elektronik > Video > Video-Multiplexer +Elektronik > Video > Videoabspielgeräte & -rekorder +Elektronik > Video > Videoabspielgeräte & -rekorder > DVD- & Blu-ray-Player +Elektronik > Video > Videoabspielgeräte & -rekorder > DVD-Rekorder +Elektronik > Video > Videoabspielgeräte & -rekorder > Digitale Videorekorder +Elektronik > Video > Videoabspielgeräte & -rekorder > Netzwerk-Mediaplayer +Elektronik > Video > Videoabspielgeräte & -rekorder > Videorekorder +Elektronik > Video > Videobearbeitungshardware & Videoproduktionsausrüstung +Elektronik > Video > Videoserver +Elektronik > Video > Videotransmitter +Elektronik > Video > Videozubehör +Elektronik > Video > Videozubehör > 3D-Brillen +Elektronik > Video > Videozubehör > Computerbildschirmzubehör +Elektronik > Video > Videozubehör > Computerbildschirmzubehör > Farbkalibrierung +Elektronik > Video > Videozubehör > Projektorzubehör +Elektronik > Video > Videozubehör > Projektorzubehör > Projektionsleinwände +Elektronik > Video > Videozubehör > Projektorzubehör > Projektorersatzleuchten +Elektronik > Video > Videozubehör > Projektorzubehör > Projektorhalterungen +Elektronik > Video > Videozubehör > Projektorzubehör > Rockvorhänge für Leinwände +Elektronik > Video > Videozubehör > Projektorzubehör > Ständer für Projektionsflächen +Elektronik > Video > Videozubehör > Spulgeräte +Elektronik > Video > Videozubehör > TV-Zubehör +Elektronik > Video > Videozubehör > TV-Zubehör > Ersatzlampen für Fernseher +Elektronik > Video > Videozubehör > TV-Zubehör > TV- & Monitorhalterungen +Elektronik > Video > Videozubehör > TV-Zubehör > TV-Konverter & Receiver +Elektronik > Video > Videozubehör > TV-Zubehör > TV-Lautsprecher +Elektronik > Videospielkonsolen +Elektronik > Zubehör für Videospielkonsolen +Elektronik > Zubehör für Videospielkonsolen > Zubehör für Spielkonsolen +Elektronik > Zubehör für Videospielkonsolen > Zubehör für mobile Spielkonsolen +Fahrzeuge & Teile +Fahrzeuge & Teile > Fahrzeuge +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Autos, LKWs & Lieferwagen +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Gelände- & Allradfahrzeuge +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Gelände- & Allradfahrzeuge > Go-Karts +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Gelände- & Allradfahrzeuge > Quads +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Golfwagen +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Motorräder & -roller +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Schneemobile +Fahrzeuge & Teile > Fahrzeuge > Kraftfahrzeuge > Wohnmobile +Fahrzeuge & Teile > Fahrzeuge > Luftfahrzeuge +Fahrzeuge & Teile > Fahrzeuge > Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeuge > Wasserfahrzeuge > Jetski +Fahrzeuge & Teile > Fahrzeuge > Wasserfahrzeuge > Motorboote +Fahrzeuge & Teile > Fahrzeuge > Wasserfahrzeuge > Segelboote +Fahrzeuge & Teile > Fahrzeuge > Wasserfahrzeuge > Yachten +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > ATV- & UTV-Schutzausrüstung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > ATV- & UTV-Schutzausrüstung > ATV- & UTV-Griffpolster +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Auto-Alarmanlagen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Fernbediente schlüssellose Systeme +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Kfz-Türschlösser +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Kfz-Türschlösser > Kfz-Türschlosssicherungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Kfz-Türschlösser > Türknöpfe +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Kfz-Türschlösser > Türschlösser & Schließsysteme +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Kupplungsschlösser +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Lenkradschlösser +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Motorrad-Schlösser & -Alarmanlagen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Radkrallen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Wegfahrsperren +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Auto-Alarmanlagen & Schließsysteme > Zubehör für Auto-Alarmanlagen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Airbagteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Fensternetze +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Gurtpolster +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Gurtschlösser +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Kfz-Warnflaggen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Sicherheitsgurtbänder +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Sicherheitsgurte +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Unterlegkeile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Warnleuchten +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Kfz-Sicherheitsausrüstung > Überrollkäfige & -bügel +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorrad-Genickschutz +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorrad-Handprotektoren +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorrad-Nierengurte +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorrad: Brust- und Rückenprotektoren +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorrad: Ellbogen- und Handgelenkschützer +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorrad: Knie- & Schienbeinschützer +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorradbrillen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorradhandschuhe +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorradhelme +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Fahrzeugsicherheit > Motorrad-Schutzausrüstung > Motorradhelmersatzteile & -zubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Flugzeugteile & -Zubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > A/V-Player & im Armaturenbrett integrierte Systeme für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Audioverstärker für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Equalizer & Frequenzweichen für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Freisprechanlagen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Halterungen für Kfz-Videomonitore +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Kassettenadapter +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Kassettenspieler für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Lautsprecher für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Parkkameras für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Elektronik > Subwoofer für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Abschleppzubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Aufhängungsteile für Autos +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Bodenbeläge & Polster +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Getriebe- & Antriebsteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Auspuff +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Beleuchtung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Bremsen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Elektroniksysteme +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Innenausstattung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Klimatisierung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motoren +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Motorteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Autofelgen & -räder +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Felgen & Räder für ATV & UTV +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Felgen & Reifen für Kfz > Motorradfelgen & -räder +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Radteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Autoreifen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Motorradreifen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifen > Reifen für ATV & UTV +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Räder > Kfz-Reifenzubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Sensoren & -Messinstrumente +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Sitze +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Spiegel +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kfz-Steuerelemente +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Kraftstoffanlagen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Rahmen- & Karosserieteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Teile für Kfz-Fenster +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Teile > Teile für Kfz-Ölkreislauf +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeug-Hardtops +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeugabdeckplanen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeugabdeckplanen > Bootsabdeckplanen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeugabdeckplanen > Golfcart-Abdeckplanen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeugabdeckplanen > Kfz-Abdeckplanen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeugabdeckplanen > Motorradabdeckplanen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeugabdeckplanen > Unterstände & Abdeckungen für Wohnmobile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Fahrzeugverdecke +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Golfcart-Gehäuse +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Ladeflächenabdeckungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugabdeckungen > Windschutzscheiben-Abdeckungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeuglack +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeuglack > Bremssattellack +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeuglack > Rahmen- & Karosserielack +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Autowaschbürsten +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Autowaschmittel +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Einspritzanlagenreinigungs-Sets +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Fahrzeug-Glasreiniger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Kfz-Teppich- & Polsterreiniger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreinigung > Wachse, Polituren & Schutzmittel für Fahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Aufladegeräte für Fahrzeugbatterien +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Fahrzeugbatterie-Prüfgeräte +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Fahrzeugdiagnosegeräte +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Karosseriedichtmasse +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Kfz-Bremsreparatur-Sets +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Kfz-Starthilfen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Kfz-Überbrückungskabel +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Werkzeuge für Kupplungsausrichtung & -ausbau +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Werkzeuge für Reifenreparatur & -wechsel +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Fahrzeugreparatur- & Spezialwerkzeuge > Windschutzscheibenreparatursets +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Abdeckungen für Anhängerkupplungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Autofolien +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Fahrzeug-Außendesigns +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Fahrzeug-Dekosets +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Fahrzeug-Embleme +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kennzeichen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kennzeichenhalterungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kennzeichenrahmen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Antennenbälle +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Armaturenbrett-Zubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Aufkleber +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Fahnen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Kennzeichenabdeckungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Kfz-Lufterfrischer +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Lenkradbezüge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Magnete +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Rückspiegel-Deko +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Schalthebelverkleidung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Dekor > Schaltknäufe +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Benzin- & Ölzusätze +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Bremsflüssigkeit +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Flüssigkeit für hydraulische Kupplungen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Frostschutzmittel +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Getriebeöl +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Kfz-Schmierstoffe +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Kühlsystemadditive +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Motorreiniger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Motoröl +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Servolenkflüssigkeit +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Tankreiniger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kfz-Flüssigkeiten > Wischwasser +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Kfz-Wartung & -Pflege > Kraftstoffkanister +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Boxen & Sortiersysteme für Ladeflächen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Bügel & Haken für Kopfstützen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Anhänger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Anhänger > Bootsanhänger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Anhänger > Kleinanhänger & Transportanhänger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Anhänger > Pferde- & Viehanhänger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Anhänger > Wohnwagen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Autogepäckträger für Angelruten +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Autogepäckträger für Kanus & Kajaks +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Autogepäckträger für Motorräder & Motorroller +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Autogepäckträger für Skier & Snowboards +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Autogepäckträger für Surfbretter +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Autogewehrhalter +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Fahrradträger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Gepäckträger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträger > Grundgestelle für Autogepäckträger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträgerzubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträgerzubehör > Fahrradträgerzubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Gepäckträgerzubehör > Ski- & Snowboardträger-Zubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Kfz-Ladenetze +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Laderampen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Motorradtaschen & -koffer +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Stauraum- & Transportsysteme > Utensilientaschen fürs Auto +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Anker +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Ankerketten +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Ankerleinen & -seile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Ankerwinden +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Bootshaken +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Bootsleitern +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Klampen & Klemmen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Anlegen & Ankern > Stufentritte +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Beleuchtung für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Benzinuhren für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Kraftstoffleitungen & Teile für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Kraftstoffpumpen & Teile für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Kraftstoffsysteme für Wasserfahrzeuge > Kraftstofftanks & Teile für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Segelbootteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugantriebe & -motoren +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugauspuffteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugauspuffteile > Schalldämpfer & Teile für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugauspuffteile > Wasserfahrzeugkrümmer +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Motorlager für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Motorschlösser für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeug Laufrad +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeug-Zündungsteile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugkolben & Teile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeuglichtmaschinen +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugmotorsteuerung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugpropeller +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugmotorteile > Wasserfahrzeugvergaser & Teile +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugpflege +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugpflege > Wasserfahrzeugpolituren +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugpflege > Wasserfahrzeugreiniger +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugsteuerung +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugsteuerung > Steuerkabel für Wasserfahrzeuge +Fahrzeuge & Teile > Fahrzeugersatzteile & -zubehör > Wasserfahrzeugteile & Zubehör > Wasserfahrzeugsteuerung > Steuerräder für Wasserfahrzeuge +Für Erwachsene +Für Erwachsene > Erotik +Für Erwachsene > Erotik > Erotikbücher +Für Erwachsene > Erotik > Erotische DVDs & Videos +Für Erwachsene > Erotik > Erotische Kleidung +Für Erwachsene > Erotik > Erotische Lebensmittel & Esswaren +Für Erwachsene > Erotik > Erotische Spiele +Für Erwachsene > Erotik > Erotische Zeitschriften +Für Erwachsene > Erotik > Pole Dance-Tanzstangenkits +Für Erwachsene > Erotik > Sexspielzeug +Für Erwachsene > Waffen +Für Erwachsene > Waffen > Elektroschockpistolen & Taser-Waffen +Für Erwachsene > Waffen > Fechtwaffen +Für Erwachsene > Waffen > Hieb- und Stichwaffen +Für Erwachsene > Waffen > Kampfmesser +Für Erwachsene > Waffen > Nunchakus +Für Erwachsene > Waffen > Peitschen +Für Erwachsene > Waffen > Schlagringe +Für Erwachsene > Waffen > Schlagstockwaffen +Für Erwachsene > Waffen > Schusswaffen +Für Erwachsene > Waffen > Schusswaffenzubehör +Für Erwachsene > Waffen > Schusswaffenzubehör > Material & Ausrüstung zum Nachladen von Schusswaffen +Für Erwachsene > Waffen > Schusswaffenzubehör > Material & Ausrüstung zum Nachladen von Schusswaffen > Ladepressen +Für Erwachsene > Waffen > Schusswaffenzubehör > Munition +Für Erwachsene > Waffen > Schusswaffenzubehör > Munitionskisten & -halter +Für Erwachsene > Waffen > Schusswaffenzubehör > Picatinny-Schienen +Für Erwachsene > Waffen > Schusswaffenzubehör > Pistolentaschen +Für Erwachsene > Waffen > Schusswaffenzubehör > Schusswaffengriffe +Für Erwachsene > Waffen > Schusswaffenzubehör > Schusswaffengurte +Für Erwachsene > Waffen > Schusswaffenzubehör > Schusswaffenreinigung +Für Erwachsene > Waffen > Schusswaffenzubehör > Schusswaffenreinigung > Schusswaffen-Reinigungsmittel +Für Erwachsene > Waffen > Schusswaffenzubehör > Schusswaffenreinigung > Schusswaffen-Reinigungspatches +Für Erwachsene > Waffen > Schusswaffenzubehör > Schusswaffenreinigung > Schusswaffen-Reinigungstücher +Für Erwachsene > Waffen > Schusswaffenzubehör > Waffenkoffer und -taschen +Für Erwachsene > Waffen > Schusswaffenzubehör > Waffenleuchten +Für Erwachsene > Waffen > Speerwaffen +Für Erwachsene > Waffen > Tränengas & Pfefferspray +Für Erwachsene > Waffen > Wurfsterne +Gesundheit & Schönheit +Gesundheit & Schönheit > Gesundheitspflege +Gesundheit & Schönheit > Gesundheitspflege > Akupunktur +Gesundheit & Schönheit > Gesundheitspflege > Akupunktur > Akupunkturmodelle +Gesundheit & Schönheit > Gesundheitspflege > Akupunktur > Akupunkturnadeln +Gesundheit & Schönheit > Gesundheitspflege > Amputationsstrümpfe +Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin +Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin > CPAP-Geräte +Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin > CPAP-Masken +Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin > Dampfinhalatoren +Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin > Inhalatoren +Gesundheit & Schönheit > Gesundheitspflege > Beatmungsmedizin > Sauerstoffbehälter +Gesundheit & Schönheit > Gesundheitspflege > Behälter für Verhütungsmittel +Gesundheit & Schönheit > Gesundheitspflege > Bettpfannen +Gesundheit & Schönheit > Gesundheitspflege > Ergo- & Physiotherapeutische Hilfsmittel +Gesundheit & Schönheit > Gesundheitspflege > Ergo- & Physiotherapeutische Hilfsmittel > Elektrische Muskelstimulatoren +Gesundheit & Schönheit > Gesundheitspflege > Ergo- & Physiotherapeutische Hilfsmittel > Therapieschaukeln +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Antiseptika & Reinigung +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Augenwaschbedarf +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Erste-Hilfe-Koffer +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Medizinisches Klebeband & Verbandsmaterial +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Schutzhüllen für Gipsverbände +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Warm & Kalt Therapie +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Warm & Kalt Therapie > Eisanwendungen +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Warm & Kalt Therapie > Wärmecremes +Gesundheit & Schönheit > Gesundheitspflege > Erste Hilfe > Warm & Kalt Therapie > Wärmflaschen & Heizkissen +Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung +Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Energie-Gel & -Nahrung +Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Flüssignahrung zur künstlichen Ernährung +Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Mahlzeitenersatz-Getränke +Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Pürierte Lebensmittel +Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Sportriegel +Gesundheit & Schönheit > Gesundheitspflege > Fitness & Ernährung > Vitamine & Nahrungsergänzungsmittel +Gesundheit & Schönheit > Gesundheitspflege > Hausnotrufgeräte +Gesundheit & Schönheit > Gesundheitspflege > Hörhilfen +Gesundheit & Schönheit > Gesundheitspflege > Inkontinenzartikel +Gesundheit & Schönheit > Gesundheitspflege > Kondome +Gesundheit & Schönheit > Gesundheitspflege > Kontaktgels & -lotionen +Gesundheit & Schönheit > Gesundheitspflege > Lichttherapielampen +Gesundheit & Schönheit > Gesundheitspflege > Medikamente & Arzneimittel +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Aktivitätsmonitore +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Alkoholmessgeräte +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Blutdruckmessgeräte +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Blutzuckermessgeräte +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Cholesterinmessgeräte +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Fieberthermometer +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Fruchtbarkeitsmonitore & Ovulationstests +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Körperfettanalyse +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Personenwaagen +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Pränatale Herzfrequenzmesser +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Messgeräte > Pulsoximeter +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Tests +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Tests > Allergietest-Sets +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Tests > Blutgruppentests +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Tests > Drogentests +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Tests > HIV-Tests +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Tests > Harnwegsinfektionstests +Gesundheit & Schönheit > Gesundheitspflege > Medizinische Tests > Schwangerschaftstests +Gesundheit & Schönheit > Gesundheitspflege > Medizinisches Gleitgel +Gesundheit & Schönheit > Gesundheitspflege > Notfall-Armband +Gesundheit & Schönheit > Gesundheitspflege > Pillendosen +Gesundheit & Schönheit > Gesundheitspflege > Probenbehälter +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Behindertengerechte Möbel & Vorrichtungen +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Behindertengerechte Möbel & Vorrichtungen > Duschbänke & -sitze +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen > Gehstöcke +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen > Krücken +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfen > Rollatoren +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Gehhilfenzubehör +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Elektromobile +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Rollstühle +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Treppenlifte +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör & Bedarf zur Barrierefreiheit > Umlagerungsbretter & -tücher +Gesundheit & Schönheit > Gesundheitspflege > Senioren- & Behindertenbedarf > Zubehör für Behindertengerechte Möbel & Vorrichtungen +Gesundheit & Schönheit > Gesundheitspflege > Spermizide +Gesundheit & Schönheit > Gesundheitspflege > Stützen & Bandagen +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung > Blutzucker-Kontrolllösung +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung > Blutzuckerteststreifen +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Blutzuckermessung > Stechhilfen +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Aktivitätsmonitore +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Badezimmerwaagen +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Blutdrucküberwachungsgeräte +Gesundheit & Schönheit > Gesundheitspflege > Zubehör für biometrische Messgeräte > Zubehör für Blutdrucküberwachungsgeräte > Blutdruckmanschetten +Gesundheit & Schönheit > Körperpflege +Gesundheit & Schönheit > Körperpflege > Augenpflege +Gesundheit & Schönheit > Körperpflege > Augenpflege > Augentropfen +Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillen +Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillengläser +Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillenzubehör +Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillenzubehör > Brillenbänder & -ketten +Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillenzubehör > Brillenetuis & -halter +Gesundheit & Schönheit > Körperpflege > Augenpflege > Brillenzubehör > Kontaktlinsenreiniger +Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsen +Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege +Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege > Kontaktlinsen-Pflegesets +Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege > Kontaktlinsenbehälter +Gesundheit & Schönheit > Körperpflege > Augenpflege > Kontaktlinsenpflege > Kontaktlinsenpflegemittel +Gesundheit & Schönheit > Körperpflege > Augenpflege > Sonnenbrillengläser +Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel +Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Damen-Deodorant +Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Intim-Waschlotionen für Frauen +Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Menstruationstassen +Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Slipeinlagen & Binden +Gesundheit & Schönheit > Körperpflege > Damenhygieneartikel > Tampons +Gesundheit & Schönheit > Körperpflege > Deodorants & Antitranspirante +Gesundheit & Schönheit > Körperpflege > Einlaufsets & -zubehör +Gesundheit & Schönheit > Körperpflege > Fußpflege +Gesundheit & Schönheit > Körperpflege > Fußpflege > Ballenpflege +Gesundheit & Schönheit > Körperpflege > Fußpflege > Einlegesohlen & Einlagen +Gesundheit & Schönheit > Körperpflege > Fußpflege > Fußgeruchskiller +Gesundheit & Schönheit > Körperpflege > Fußpflege > Hühneraugen- & Hornhautprodukte +Gesundheit & Schönheit > Körperpflege > Fußpflege > Zehenspreizer +Gesundheit & Schönheit > Körperpflege > Gleitmittel +Gesundheit & Schönheit > Körperpflege > Haarkosmetik +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haar-Decoloration +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarfärbemittel +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarpflege-Sets +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarscheren +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Haarglätter +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Haartrockner +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Hairstyling-Sets +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Kämme & Bürsten +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Lockenstäbe +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarstyling-Geräte > Lockenwickler +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Haarverdichter +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Mittel für Dauerwellen & Haarglättung, chemische Haarglättung +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Mittel gegen Haarverlust +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Shampoo & Spülung +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Styling-Gel, Haarspray & Haarschaum +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Trockenhauben +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarcolorationen +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte > Haareisenzubehör +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte > Haartrocknerzubehör +Gesundheit & Schönheit > Körperpflege > Haarkosmetik > Zubehör für Haarstyling-Geräte > Lockenwicklerklammern & -nadeln +Gesundheit & Schönheit > Körperpflege > Kosmetika +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Bade- & Naturschwämme +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Badebürsten +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Duschhauben +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Feuchttücher für Erwachsene +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Flüssigseifen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Handdesinfektionsmittel +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Schaumbäder & Badesalze +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Seife +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Seife in Pulverform +Gesundheit & Schönheit > Körperpflege > Kosmetika > Badeartikel > Waschlotion +Gesundheit & Schönheit > Körperpflege > Kosmetika > Düfte +Gesundheit & Schönheit > Körperpflege > Kosmetika > Geschenkkörbe Bad & Körperpflege +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Aknebehandlung +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Anti-Aging-Hautpflegeprodukte +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Bräunungsprodukte +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Bräunungsprodukte > Selbstbräuner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Bräunungsprodukte > Sonnenöle & -lotionen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Gesichtspeeling +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Gesichtsreiniger +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Gesichtsreinigersets +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Insektenschutzmittel +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Komprimierte Gesichtsmasken +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Körperpuder +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Körperöle +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lippenpflege +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Lotion & Feuchtigkeitscremes +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Make-up-Entferner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Porenreinigungspflaster +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Reinigungswasser & Adstringentien +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Sonnencreme +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Vaseline +Gesundheit & Schönheit > Körperpflege > Kosmetika > Hautpflege > Warzenentferner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Applikatoren für Lotionen und Sonnenschutzcremes +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Bimssteine +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Fußfeilen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Gesichtsbürsten +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Gesichtssaunas +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Hautpflegeroller +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Hautreinigungs-Bürstenköpfe +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Hautpflegeutensilien > Mitesser-Entferner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Augenbrauenschablonen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Ersatzkissen für Wimpernzangen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Make-up-Pinsel +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Make-up-Schwämme +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Make-up-Spiegel +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Nachfüllbare Make-up-Paletten & -Koffer +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Pudertücher +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Schlupflid-Kleber & -Klebestreifen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Wimpernformer +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Zubehör für künstliche Wimpern +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Zubehör für künstliche Wimpern > Applikatoren für künstliche Wimpern +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Zubehör für künstliche Wimpern > Entferner für künstliche Wimpern +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Make-up Zubehör > Zubehör für künstliche Wimpern > Kleber für künstliche Wimpern +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Finger- & Zehenspreizer +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Maniküre-Sets +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelfeilen & Sandblattfeilen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelfräser +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelhautscheren +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelhautschieber +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelknipser +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelpiercing-Zubehör +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nagelpolierer +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetik-Zubehör > Maniküre & Pediküre > Nageltrockner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Kosmetiksets +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Augenbrauen Make-up +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Eyeliner & Kajal +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Künstliche Wimpern +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Lidschatten +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Lidschatten-Grundierung +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Mascara +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Mascara-Grundierung +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Augen > Wimpern- & Augenbrauenbehandlung +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Kostüm- & Bühnen-Make-up +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Körper-Make-up +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Körper-Make-up > Bodypainting-Farbe +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Körper-Make-up > Glitter für Körper und Haar +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lipgloss +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lipliner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lippen- & Wangentönung +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lippenstift +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Lippen > Lippenstift-Grundierung +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Spray zum Fixieren von Make-up +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Gesichtsgrundierung +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Grundierungen & Concealer +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Highlighter & Luminizer +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Puder +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Teint > Rouge & Bronzepuder +Gesundheit & Schönheit > Körperpflege > Kosmetika > Make-up > Temporäre Tattoos +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Künstliche Nägel +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagelhautcremes & -Lotionen +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagelkleber +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagelkunst-Zubehör +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagellack-Überlacke und -Trockensprays +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagellacke +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagellackentferner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Nagelpflege > Nagellackverdünner +Gesundheit & Schönheit > Körperpflege > Kosmetika > Reiniger für Kosmetikwerkzeuge +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Augenkissen +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagegeräte +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagestein-Wärmer +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagesteine +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagestühle +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massagetische +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Massageöle +Gesundheit & Schönheit > Körperpflege > Massage & Entspannung > Rückenkratzer +Gesundheit & Schönheit > Körperpflege > Mundpflege +Gesundheit & Schönheit > Körperpflege > Mundpflege > Aufbissschienen +Gesundheit & Schönheit > Körperpflege > Mundpflege > Ersatzdüsen für Mundduschen +Gesundheit & Schönheit > Körperpflege > Mundpflege > Gebissreiniger +Gesundheit & Schönheit > Körperpflege > Mundpflege > Interdentalreiniger +Gesundheit & Schönheit > Körperpflege > Mundpflege > Mundduschen +Gesundheit & Schönheit > Körperpflege > Mundpflege > Mundspray +Gesundheit & Schönheit > Körperpflege > Mundpflege > Mundwasser +Gesundheit & Schönheit > Körperpflege > Mundpflege > Reparatursets für Zahnprothesen +Gesundheit & Schönheit > Körperpflege > Mundpflege > Spangen-, Gebiss- & Aufbissschienendosen +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnaufhellung +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürsten +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör > Ersatzköpfe für Zahnbürsten +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör > Zahnbürstendesinfektionsmittel +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnbürstenzubehör > Zahnbürstenhüllen +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnersatz +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnfleischstimulierende Geräte +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnpasta +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnpastapressen & -spender +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnprothesehaftmittel +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnseide +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zahnstocher +Gesundheit & Schönheit > Körperpflege > Mundpflege > Zungenreiniger +Gesundheit & Schönheit > Körperpflege > Ohrenpflege +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrenreinigungssets +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrenstöpsel +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrentrockner +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrentropfen +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrkerzen +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrlöffel +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrspritzen +Gesundheit & Schönheit > Körperpflege > Ohrenpflege > Ohrstöpselspender +Gesundheit & Schönheit > Körperpflege > Pinzetten +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Alaunstifte +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Elektrorasierer +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haar- & Bartschneider +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haaraufheller +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Elektrolysegeräte +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Enthaarungsmittel +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Enthaarungswachs-Wärmer +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Epilatoren +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Laserhaarentfernung +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Haarentfernung > Waxing-Sets & Zubehör +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasiercreme +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierer & Rasierklingen +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierpinsel +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierschalen +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasiersets +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Rasierwasser +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Zubehör für Haarschneidegeräte & Trimmer +Gesundheit & Schönheit > Körperpflege > Rasieren & Trimmen > Zubehör für elektrische Rasierer +Gesundheit & Schönheit > Körperpflege > Rückengesundheit +Gesundheit & Schönheit > Körperpflege > Rückengesundheit > Stützkissen für Rücken- & Lendenbereich +Gesundheit & Schönheit > Körperpflege > Schlafhilfen +Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Hilfsmittel gegen Schnarchen und Schlaf-Apnoe +Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Reisekissen +Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Schlafmasken +Gesundheit & Schönheit > Körperpflege > Schlafhilfen > Soundmaschinen +Gesundheit & Schönheit > Körperpflege > Sonnenbänke +Gesundheit & Schönheit > Körperpflege > Tanningzelt +Gesundheit & Schönheit > Körperpflege > Wattebällchen +Gesundheit & Schönheit > Körperpflege > Wattestäbchen +Gesundheit & Schönheit > Schmuckreinigung & -pflege +Gesundheit & Schönheit > Schmuckreinigung & -pflege > Dampfstrahlreiniger für Schmuck +Gesundheit & Schönheit > Schmuckreinigung & -pflege > Hilfsmittel zur Schmuckreinigung +Gesundheit & Schönheit > Schmuckreinigung & -pflege > Lösungen und Poliermittel zur Schmuckreinigung +Gesundheit & Schönheit > Schmuckreinigung & -pflege > Schmuckständer & -kästen +Gesundheit & Schönheit > Schmuckreinigung & -pflege > Uhrreparatursätze +Heim & Garten +Heim & Garten > Badzubehör +Heim & Garten > Badzubehör > Badematten & Badteppiche +Heim & Garten > Badzubehör > Badewannen- & Duschablagen +Heim & Garten > Badzubehör > Badewannenkissen +Heim & Garten > Badzubehör > Badezimmer-Zubehörsets +Heim & Garten > Badzubehör > Badzubehörhalterungen +Heim & Garten > Badzubehör > Duschvorhangringe +Heim & Garten > Badzubehör > Duschvorhangstangen +Heim & Garten > Badzubehör > Duschvorhänge +Heim & Garten > Badzubehör > Garderobenhaken +Heim & Garten > Badzubehör > Haltegriffe +Heim & Garten > Badzubehör > Handtuchhalter +Heim & Garten > Badzubehör > Händetrockner +Heim & Garten > Badzubehör > Kosmetiktuchhalter +Heim & Garten > Badzubehör > Medizinschränke +Heim & Garten > Badzubehör > Seifen- & Lotionsspender +Heim & Garten > Badzubehör > Seifenablagen +Heim & Garten > Badzubehör > Toilettenbürsten & -halter +Heim & Garten > Badzubehör > Toilettenbürstenköpfe +Heim & Garten > Badzubehör > Toilettenpapierhalter +Heim & Garten > Badzubehör > Zahnbürstenhalter +Heim & Garten > Badzubehör > Zubehör für Händetrockner +Heim & Garten > Beleuchtung +Heim & Garten > Beleuchtung > Bilderbeleuchtung +Heim & Garten > Beleuchtung > Bodeneinbauleuchten +Heim & Garten > Beleuchtung > Flutlichter & Punktstrahler +Heim & Garten > Beleuchtung > Lampen +Heim & Garten > Beleuchtung > Leuchten +Heim & Garten > Beleuchtung > Leuchten > Deckenleuchten +Heim & Garten > Beleuchtung > Leuchten > Kronleuchter +Heim & Garten > Beleuchtung > Leuchten > Unterbauleuchten +Heim & Garten > Beleuchtung > Leuchten > Wandleuchten, Wandbeleuchtung +Heim & Garten > Beleuchtung > Leuchtmittel +Heim & Garten > Beleuchtung > Leuchtmittel > Glühlampen +Heim & Garten > Beleuchtung > Leuchtmittel > Kompaktleuchtstofflampen +Heim & Garten > Beleuchtung > Leuchtmittel > LED-Leuchtmittel +Heim & Garten > Beleuchtung > Leuchtmittel > Leuchtstoffröhren +Heim & Garten > Beleuchtung > Lichtschienensysteme +Heim & Garten > Beleuchtung > Lichtschienensysteme > Leuchten für Lichtschienensysteme +Heim & Garten > Beleuchtung > Lichtschienensysteme > Schienen für Lichtschienensysteme +Heim & Garten > Beleuchtung > Lichtschienensysteme > Zubehör für Lichtschienensysteme +Heim & Garten > Beleuchtung > Lichtschläuche & Lichterketten +Heim & Garten > Beleuchtung > Nachtlichter & indirekte Beleuchtung +Heim & Garten > Beleuchtung > Notbeleuchtung +Heim & Garten > Beleuchtung > Schwimmende Lichter +Heim & Garten > Beleuchtung > Tiki-Fackeln & Öllampen +Heim & Garten > Beleuchtung > Wegbeleuchtung +Heim & Garten > Beleuchtungszubehör +Heim & Garten > Beleuchtungszubehör > Beleuchtungszeitschaltuhren +Heim & Garten > Beleuchtungszubehör > Brennstoff für Öllampen +Heim & Garten > Beleuchtungszubehör > Lampenschirme +Heim & Garten > Beleuchtungszubehör > Laternenhalterungen +Heim & Garten > Beleuchtungszubehör > Laternensockel +Heim & Garten > Bett- und Haushaltswäsche +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Baldachine & Betthimmel +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Bettbezüge +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Bettlaken +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Bettvolants +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Decken +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Kissenbezüge +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Kopfkissen +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Matratzenschoner +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Matratzenschoner > Matratzenauflagen +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Matratzenschoner > Matratzenbezüge +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Schlafunterlagen +Heim & Garten > Bett- und Haushaltswäsche > Bettwäsche > Steppdecken & Quilts +Heim & Garten > Bett- und Haushaltswäsche > Handtücher +Heim & Garten > Bett- und Haushaltswäsche > Handtücher > Badhandtücher & Waschlappen +Heim & Garten > Bett- und Haushaltswäsche > Handtücher > Geschirrtücher +Heim & Garten > Bett- und Haushaltswäsche > Handtücher > Strandtücher +Heim & Garten > Bett- und Haushaltswäsche > Küchentuchsets +Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche +Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Stoffservietten +Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischläufer +Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischsets +Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischtücher +Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Tischvorhänge +Heim & Garten > Bett- und Haushaltswäsche > Tischwäsche > Zierdecken +Heim & Garten > Dekoration +Heim & Garten > Dekoration > Bilderrahmen +Heim & Garten > Dekoration > Briefkasten-Zubehör +Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkasten-Standanlagen +Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastenanlagen +Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastenfahnen +Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastengehäuse +Heim & Garten > Dekoration > Briefkasten-Zubehör > Briefkastentüren +Heim & Garten > Dekoration > Briefkästen +Heim & Garten > Dekoration > Briefschlitze +Heim & Garten > Dekoration > Brunnen & Teiche +Heim & Garten > Dekoration > Brunnen & Teiche > Brunnen & Wasserfälle +Heim & Garten > Dekoration > Brunnen & Teiche > Brunnen- & Teichzubehör +Heim & Garten > Dekoration > Brunnen & Teiche > Teiche +Heim & Garten > Dekoration > Buchstützen +Heim & Garten > Dekoration > Deko-Aufkleber +Heim & Garten > Dekoration > Dekorative Flaschen +Heim & Garten > Dekoration > Dekorative Gefäße +Heim & Garten > Dekoration > Dekorteller +Heim & Garten > Dekoration > Ecosphere-Kugeln +Heim & Garten > Dekoration > Fensterdrapierung +Heim & Garten > Dekoration > Fensterdrapierung > Buntglasscheiben +Heim & Garten > Dekoration > Fensterdrapierung > Fensterfolie +Heim & Garten > Dekoration > Fensterdrapierung > Fliegengitter +Heim & Garten > Dekoration > Fensterdrapierung > Jalousien & Rollos +Heim & Garten > Dekoration > Fensterdrapierung > Querbehänge +Heim & Garten > Dekoration > Fensterdrapierung > Vorhänge & Gardinen +Heim & Garten > Dekoration > Fensterschmuckmagnete +Heim & Garten > Dekoration > Festtags-Dekoartikel +Heim & Garten > Dekoration > Festtags-Dekoartikel > Adventskalender +Heim & Garten > Dekoration > Festtags-Dekoartikel > Haken für Weihnachtssocken +Heim & Garten > Dekoration > Festtags-Dekoartikel > Krippen +Heim & Garten > Dekoration > Festtags-Dekoartikel > Modellbaudörfer & -zubehör mit saisonalem Bezug +Heim & Garten > Dekoration > Festtags-Dekoartikel > Ostereier-Färbe-Sets +Heim & Garten > Dekoration > Festtags-Dekoartikel > Traditionelle Japanische Puppen +Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsbaumdecken +Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsbaumschmuck +Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsbaumständer +Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsschmuck-Aufhänger +Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsschmuck-Displays +Heim & Garten > Dekoration > Festtags-Dekoartikel > Weihnachtsstrümpfe +Heim & Garten > Dekoration > Figuren zur Dekoration +Heim & Garten > Dekoration > Flaggen & Windsäcke +Heim & Garten > Dekoration > Flammenlose Kerzen +Heim & Garten > Dekoration > Futterspender +Heim & Garten > Dekoration > Futterspender > Eichhörnchenfutterspender +Heim & Garten > Dekoration > Futterspender > Schmetterlingsfutterspender +Heim & Garten > Dekoration > Futterspender > Vogelfutterspender +Heim & Garten > Dekoration > Fußmatten +Heim & Garten > Dekoration > Garderoben +Heim & Garten > Dekoration > Garten- & Trittsteine +Heim & Garten > Dekoration > Gartendeko +Heim & Garten > Dekoration > Glasfensterbilder +Heim & Garten > Dekoration > Globen +Heim & Garten > Dekoration > Hausnummern & Buchstaben +Heim & Garten > Dekoration > Hausnummernschilder +Heim & Garten > Dekoration > Kartonschablonen +Heim & Garten > Dekoration > Kindermesslatten +Heim & Garten > Dekoration > Kreuzblumen +Heim & Garten > Dekoration > Kränze & Girlanden +Heim & Garten > Dekoration > Kunst +Heim & Garten > Dekoration > Kunst > Figuren, Skulpturen & Statuen +Heim & Garten > Dekoration > Kunst > Poster & Bildende Kunst +Heim & Garten > Dekoration > Kunst > Wandteppiche +Heim & Garten > Dekoration > Körbe +Heim & Garten > Dekoration > Kühlschrankmagnete +Heim & Garten > Dekoration > Künstliche Pflanzen +Heim & Garten > Dekoration > Lebensmittel-Attrappen +Heim & Garten > Dekoration > Niederschlags-Messgeräte +Heim & Garten > Dekoration > Quadratische Sitzkissen +Heim & Garten > Dekoration > Raumduft-Zubehör +Heim & Garten > Dekoration > Raumduft-Zubehör > Kerzenlöscher +Heim & Garten > Dekoration > Raumduft-Zubehör > Kerzenständer +Heim & Garten > Dekoration > Raumduft-Zubehör > Räuchermittelhalter +Heim & Garten > Dekoration > Raumduft-Zubehör > Wachs- & Ölwärmer +Heim & Garten > Dekoration > Raumdüfte +Heim & Garten > Dekoration > Raumdüfte > Duftwachs +Heim & Garten > Dekoration > Raumdüfte > Duftöle +Heim & Garten > Dekoration > Raumdüfte > Kerzen +Heim & Garten > Dekoration > Raumdüfte > Lufterfrischer +Heim & Garten > Dekoration > Raumdüfte > Potpourri +Heim & Garten > Dekoration > Raumdüfte > Räuchermittel +Heim & Garten > Dekoration > Regenketten +Heim & Garten > Dekoration > Rückenstützkissen +Heim & Garten > Dekoration > Sanduhren +Heim & Garten > Dekoration > Schalen +Heim & Garten > Dekoration > Schaukästen +Heim & Garten > Dekoration > Schneekugeln +Heim & Garten > Dekoration > Schonbezüge +Heim & Garten > Dekoration > Serviettenringe +Heim & Garten > Dekoration > Sitzpolster +Heim & Garten > Dekoration > Sonnenuhren +Heim & Garten > Dekoration > Sparschweine & -Dosen +Heim & Garten > Dekoration > Spaßschilder +Heim & Garten > Dekoration > Spiegel +Heim & Garten > Dekoration > Spieluhren +Heim & Garten > Dekoration > Tabletts +Heim & Garten > Dekoration > Tapeten +Heim & Garten > Dekoration > Teppiche +Heim & Garten > Dekoration > Traumfänger +Heim & Garten > Dekoration > Trockenblumen +Heim & Garten > Dekoration > Truhen +Heim & Garten > Dekoration > Uhrbauteile +Heim & Garten > Dekoration > Uhren +Heim & Garten > Dekoration > Uhren > Standuhren +Heim & Garten > Dekoration > Uhren > Tisch- und Regaluhren +Heim & Garten > Dekoration > Uhren > Wanduhren +Heim & Garten > Dekoration > Uhren > Wecker +Heim & Garten > Dekoration > Vasen +Heim & Garten > Dekoration > Vasenfüller & Streudeko +Heim & Garten > Dekoration > Vogel- und Tierhäuschen +Heim & Garten > Dekoration > Vogel- und Tierhäuschen > Fledermaushäuschen +Heim & Garten > Dekoration > Vogel- und Tierhäuschen > Schmetterlingshäuschen +Heim & Garten > Dekoration > Vogel- und Tierhäuschen > Vogelhäuschen +Heim & Garten > Dekoration > Vogelhaus-Zubehör +Heim & Garten > Dekoration > Vogeltränken +Heim & Garten > Dekoration > Wetterfahnen & Dachdekoration +Heim & Garten > Dekoration > Windräder +Heim & Garten > Dekoration > Windspiele +Heim & Garten > Dekoration > Zierglocken +Heim & Garten > Dekoration > Zierkissen +Heim & Garten > Dekoration > Ziertafeln +Heim & Garten > Dekoration > Zubehör für Fahnen & Windsäcke +Heim & Garten > Dekoration > Zubehör für Fahnen & Windsäcke > Befestigungsvorrichtungen & -sets für Fahnen- & Windsackstangen +Heim & Garten > Dekoration > Zubehör für Fahnen & Windsäcke > Beleuchtung für Fahnen- & Windsackstangen +Heim & Garten > Dekoration > Zubehör für Fahnen & Windsäcke > Stangen für Fahnen & Windsäcke +Heim & Garten > Dekoration > Zubehör für Futterspender +Heim & Garten > Dekoration > Zubehör zur Fensterdekoration +Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Ersatzteile für Vorhänge & Jalousien +Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Gardinen- & Vorhangringe +Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Gardinen- & Vorhangstangen +Heim & Garten > Dekoration > Zubehör zur Fensterdekoration > Gardinenhalter & -quasten +Heim & Garten > Feuer- & Gasschutz +Heim & Garten > Feuer- & Gasschutz > Feuerlöscher +Heim & Garten > Feuer- & Gasschutz > Feuermelder +Heim & Garten > Feuer- & Gasschutz > Feuermelder-Steuerungen +Heim & Garten > Feuer- & Gasschutz > Hitzemelder +Heim & Garten > Feuer- & Gasschutz > Kästen & Halterungen für Feuerlöscher +Heim & Garten > Feuer- & Gasschutz > Rauch- & Kohlenmonoxidmelder +Heim & Garten > Feuer- & Gasschutz > Sprinkleranlagen +Heim & Garten > Feuer- & Gasschutz > Wassermelder +Heim & Garten > Haushaltsbedarf +Heim & Garten > Haushaltsbedarf > Abfallbehälter +Heim & Garten > Haushaltsbedarf > Abfallbehälter > Müllcontainer +Heim & Garten > Haushaltsbedarf > Abfallbehälter > Mülltonnen & Abfalleimer +Heim & Garten > Haushaltsbedarf > Abfallbehälter > Recycling-Behälter +Heim & Garten > Haushaltsbedarf > Abfallbehälter > Sondermüllbehälter +Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör +Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälter-Verkleidungen +Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälterdeckel +Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälterrollen +Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Abfallbehälterwagen +Heim & Garten > Haushaltsbedarf > Abfallbehälterzubehör > Beschriftungen & Etiketten für Abfallbehälter +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungsbehälter +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungsbeutel +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale > Bügelbrettaufhänger und -ablagen +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale > Mehrzweckhaken +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Aufbewahrungshaken & Regale > Schirmständer +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Fotoaufbewahrung +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Fotoaufbewahrung > Fotoalben +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Fotoaufbewahrung > Fotoboxen +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Haushalts-Ordnungshelfer +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Herrendiener +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Hutschachteln +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Kleiderbügel +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Kleiderständer +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Ladestationen +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Kleider- & Wandschrankaufbewahrung > Schuhregale & -schränke +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Schubladeneinsätze +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Schubladensysteme +Heim & Garten > Haushaltsbedarf > Aufbewahrung & Ordnungssysteme > Tischbesteckkommoden +Heim & Garten > Haushaltsbedarf > Auskleidung für Schubladen & Regale +Heim & Garten > Haushaltsbedarf > Fußbodenschutzfolien & -läufer +Heim & Garten > Haushaltsbedarf > Garagenmatten +Heim & Garten > Haushaltsbedarf > Haushaltsthermometer +Heim & Garten > Haushaltsbedarf > Hygienepapiere +Heim & Garten > Haushaltsbedarf > Hygienepapiere > Küchenrollen & Papierhandtücher +Heim & Garten > Haushaltsbedarf > Hygienepapiere > Papierservietten +Heim & Garten > Haushaltsbedarf > Hygienepapiere > Papiertaschentücher +Heim & Garten > Haushaltsbedarf > Hygienepapiere > Toilettenpapier +Heim & Garten > Haushaltsbedarf > Möbelgleiter +Heim & Garten > Haushaltsbedarf > Müllbeutel +Heim & Garten > Haushaltsbedarf > Müllpressezubehör +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Abzieher +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Besen +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Besen- & Bodenwischerstiele +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Besenköpfe +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Bodenwischeraufsätze +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Eimer +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Ersatz-Wischmops +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Gewebe- & Polsterschutz +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Allzweckreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Backofen- & Grillreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Bodenreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Edelstahlreiniger & -polituren +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Entkalkungsmittel +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Geschirrspülmittel & -seifen +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Glas- & Oberflächenreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Haushaltsdesinfektion +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Klarspüler +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Möbelreiniger & -Politur +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Spülmaschinenreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Teppichreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Textil- & Polsterreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Tiergeruchs- & Fleckenentferner +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Toilettenreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Wannen- & Kachelreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Haushaltsreiniger > Waschmaschinenreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Kehrschaufeln +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Reinigungshandschuhe +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Reinigungstücher +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Scheuerbürsten +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Schwämme & Topfreiniger +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Staubwedel & -Tücher +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Staubwedel-Ersatzköpfe +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Teppichkehrer +Heim & Garten > Haushaltsbedarf > Reinigungsutensilien > Wischmops & Bodenwischer +Heim & Garten > Haushaltsbedarf > Schuhpflege +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhabstreifer +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhanzieher +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhbeutel +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhbürsten +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpflege- & Färbemittel +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpflegesets +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpolierer +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhpolituren & -wachse +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhspanner +Heim & Garten > Haushaltsbedarf > Schuhpflege > Schuhtrockner +Heim & Garten > Haushaltsbedarf > Schuhpflege > Stiefelknechte +Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung +Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Fallen +Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Fliegenklatschen +Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Insektenschutz +Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Insektenschutz > Mittel gegen Haushaltsinsekten +Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Insektenschutz > Tierabwehr +Heim & Garten > Haushaltsbedarf > Schädlingsbekämpfung > Schädlingsbekämpfungsmittel +Heim & Garten > Haushaltsbedarf > Stufenteppiche +Heim & Garten > Haushaltsbedarf > Teppichunterlagen +Heim & Garten > Haushaltsbedarf > Trocknungsmittel +Heim & Garten > Haushaltsbedarf > Wäschepflege +Heim & Garten > Haushaltsbedarf > Wäschepflege > Bleichmittel +Heim & Garten > Haushaltsbedarf > Wäschepflege > Bügelbretter +Heim & Garten > Haushaltsbedarf > Wäschepflege > Bügelbrettunterlagen & -bezüge +Heim & Garten > Haushaltsbedarf > Wäschepflege > Bügeleisenhalter +Heim & Garten > Haushaltsbedarf > Wäschepflege > Ersatzteile für Bügeleisen +Heim & Garten > Haushaltsbedarf > Wäschepflege > Fleckenentferner für Stoffe +Heim & Garten > Haushaltsbedarf > Wäschepflege > Fusselrasierer +Heim & Garten > Haushaltsbedarf > Wäschepflege > Fusselrollen +Heim & Garten > Haushaltsbedarf > Wäschepflege > Mittel gegen Falten & statische Aufladung +Heim & Garten > Haushaltsbedarf > Wäschepflege > Schweißabsorbierungspads +Heim & Garten > Haushaltsbedarf > Wäschepflege > Textilerfrischer +Heim & Garten > Haushaltsbedarf > Wäschepflege > Trockenreinigungssets +Heim & Garten > Haushaltsbedarf > Wäschepflege > Waschbälle +Heim & Garten > Haushaltsbedarf > Wäschepflege > Waschpulver +Heim & Garten > Haushaltsbedarf > Wäschepflege > Weichspüler & Trocknertücher +Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäscheklammern +Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäschekörbe +Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäscheständer +Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäschestärke +Heim & Garten > Haushaltsbedarf > Wäschepflege > Wäschesäcke & Waschkörbe +Heim & Garten > Haushaltsgeräte +Heim & Garten > Haushaltsgeräte > Boden- & Teppichtrockner +Heim & Garten > Haushaltsgeräte > Bohner- & Poliermaschinen +Heim & Garten > Haushaltsgeräte > Dampf-Tapetenlöser +Heim & Garten > Haushaltsgeräte > Futontrockner +Heim & Garten > Haushaltsgeräte > Garagentorantrieb +Heim & Garten > Haushaltsgeräte > Garagentoröffner +Heim & Garten > Haushaltsgeräte > Heißwasserboiler +Heim & Garten > Haushaltsgeräte > Klimatisierung +Heim & Garten > Haushaltsgeräte > Klimatisierung > Fog-Anlagen für den Außenbereich +Heim & Garten > Haushaltsgeräte > Klimatisierung > Kanalheizer +Heim & Garten > Haushaltsgeräte > Klimatisierung > Klimaanlagen +Heim & Garten > Haushaltsgeräte > Klimatisierung > Luftbefeuchter +Heim & Garten > Haushaltsgeräte > Klimatisierung > Luftentfeuchter +Heim & Garten > Haushaltsgeräte > Klimatisierung > Luftreiniger +Heim & Garten > Haushaltsgeräte > Klimatisierung > Radiatoren +Heim & Garten > Haushaltsgeräte > Klimatisierung > Raumheizgeräte +Heim & Garten > Haushaltsgeräte > Klimatisierung > Terrassenstrahler +Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren +Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Deckenventilatoren +Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Handventilatoren +Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Lüftungsventilatoren +Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Tisch- & Standventilatoren +Heim & Garten > Haushaltsgeräte > Klimatisierung > Ventilatoren > Wandventilatoren +Heim & Garten > Haushaltsgeräte > Klimatisierung > Verdunstungskühler +Heim & Garten > Haushaltsgeräte > Klimatisierung > Öfen & Kessel +Heim & Garten > Haushaltsgeräte > Staubsauger +Heim & Garten > Haushaltsgeräte > Teppich- & Dampfreinigungsgeräte +Heim & Garten > Haushaltsgeräte > Ultraschallreiniger +Heim & Garten > Haushaltsgeräte > Waschen & Trocknen +Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Bügeleisen & -systeme +Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Dampfglätter für Bekleidung +Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Dampfpressen +Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Waschmaschinen +Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Waschtrockner +Heim & Garten > Haushaltsgeräte > Waschen & Trocknen > Wäschetrockner +Heim & Garten > Haushaltsgeräte-Zubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Abgasrohre +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Ausgleichsgefäß für Warmwasserbereiter +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Boiler +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Boilerwannen +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Heizelemente +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Heizungslüftung +Heim & Garten > Haushaltsgeräte-Zubehör > Boiler-Zubehör > Opferanoden +Heim & Garten > Haushaltsgeräte-Zubehör > Entfeuchterzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Heizkessel- & Boilerzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Heizkörperzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Heizkörperzubehör > Heizkörperreflexionsfolie +Heim & Garten > Haushaltsgeräte-Zubehör > Heizpilz-Zubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Heizpilz-Zubehör > Heizpilz-Abdeckungen +Heim & Garten > Haushaltsgeräte-Zubehör > Klimaanlagen-Zubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Klimaanlagen-Zubehör > Abdeckungen für Klimaanlagen +Heim & Garten > Haushaltsgeräte-Zubehör > Klimaanlagen-Zubehör > Klimaanlagenfilter +Heim & Garten > Haushaltsgeräte-Zubehör > Luftbefeuchter-Zubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Luftbefeuchter-Zubehör > Luftbefeuchterfilter +Heim & Garten > Haushaltsgeräte-Zubehör > Luftreinigerzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Luftreinigerzubehör > Luftreinigerfilter +Heim & Garten > Haushaltsgeräte-Zubehör > Staubsaugerzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Teppich- & Dampfreinigerzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Ventilatorenzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Bügeleisenzubehör +Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Zubehör für Dampfmaschinen +Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Zubehör für Dampfpressen +Heim & Garten > Haushaltsgeräte-Zubehör > Wasch-Zubehör > Zubehör für Waschmaschinen und Wäschetrockner +Heim & Garten > Haussicherheit +Heim & Garten > Haussicherheit > Bewegungsmelder +Heim & Garten > Haussicherheit > Hausalarmsysteme +Heim & Garten > Haussicherheit > Safe-Zubehör +Heim & Garten > Haussicherheit > Safes & Tresore +Heim & Garten > Haussicherheit > Sensoren für Sicherheitssysteme +Heim & Garten > Haussicherheit > Sicherheitsleuchten +Heim & Garten > Haussicherheit > Sicherheitsspiegel +Heim & Garten > Haussicherheit > Überwachungskamera-Attrappen +Heim & Garten > Haussicherheit > Überwachungsmonitore & -rekorder +Heim & Garten > Holzöfen +Heim & Garten > Kamine +Heim & Garten > Küche & Esszimmer +Heim & Garten > Küche & Esszimmer > Bar-Utensilien +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Absinth-Fontänen +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Bierzapfhähne +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Cocktail- & Barzubehörsets +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Cocktailshaker & Zubehör +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Cocktailshaker & Zubehör > Bar-Eispickel +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Cocktailshaker & Zubehör > Barsiebe +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Cocktailshaker & Zubehör > Cocktailshaker +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Cocktailshaker & Zubehör > Cocktailstößel +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Cocktailshaker & Zubehör > Flaschenöffner +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Dekanter +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Flaschenstöpsel & -verschlüsse +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Flaschenverschlüsse +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Folienschneider +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Getränkewannen & -kühler +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Glasuntersetzer & Bierdeckel +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Korkenzieher +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Kühlsteine & -Sticks für Getränke +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Untersetzerhalter +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Weindekantierer +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Weinflaschenhalter +Heim & Garten > Küche & Esszimmer > Bar-Utensilien > Weinglasanhänger +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Brotdosen & -taschen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Feldflaschen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Flachmänner +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkedeckel +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkehüllen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkehüllen > Dosen- und Flaschenhüllen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Getränkehüllen > Getränkebehälterhüllen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Isolierbehälter +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Kühlboxen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Kühltaschen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Picknickkörbe +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Thermosflaschen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Wasserflaschen +Heim & Garten > Küche & Esszimmer > Essens- & Getränkebehälter > Weinflaschentaschen +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör > Etiketten für Lebensmittel und Getränke +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör > Sauerstoffabsorber +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör > Spender für Frischhaltefolie +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung - Zubehör > Verschlussstreifen & Verschlussclips +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Brotkästen & -taschen +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Frischhaltebeutel +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Honiggläser +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Kecksdosen & -behälter +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittel-Abdeckhauben +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelbehälter +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Alufolien +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Frischhaltefolien +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Pergamentpapier +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Lebensmittelverpackungsmaterial > Wachspapier +Heim & Garten > Küche & Esszimmer > Essensaufbewahrung > Nascheimer +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Auflaufförmchen & Souffléförmchen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Back- & Plätzchenbleche +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Backzubehörsets +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Brotbackformen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Bräter +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Grillbleche mit Fettpfannen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Kuchen- & Quichebackformen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Kuchenbackformen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Muffin- & Gebäckformen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Pizzableche +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backformen > Pizzasteine +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör > Backgewichte +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör > Backmatten & -formen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Backzubehör > Brätereinsätze +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr & Backformen (Kombisets) +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Auflaufformen & Kasserollen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Grillpfannen & -aufsätze +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Grillpressen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Kochgeschirrsets +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Paellapfannen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Pfannen für Crêpes und Pfannkuchen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Rum- & Einmachtöpfe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Sautépfannen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Schmortöpfe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Schnellkochtöpfe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Stiel- & Bratpfannen +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Stieltöpfe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Suppentöpfe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Tajines & Tonkochtöpfe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Wasserbadtöpfe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Wasserkessel +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirr > Woks +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Dampfkörbe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Schnellkochtopfzubehör +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Topf- & Pfannendeckel +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Topf- & Pfannengriffe +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Wokzubehör +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Wokzubehör > Wokbürsten +Heim & Garten > Küche & Esszimmer > Kochgeschirr & Backformen > Kochgeschirrzubehör > Wokzubehör > Wokringe +Heim & Garten > Küche & Esszimmer > Küchenblöcke & Pantryküchen +Heim & Garten > Küche & Esszimmer > Küchengeräte +Heim & Garten > Küche & Esszimmer > Küchengeräte > Abfallzerkleinerer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Abzugshauben +Heim & Garten > Küche & Esszimmer > Küchengeräte > Aufschnittmaschine +Heim & Garten > Küche & Esszimmer > Küchengeräte > Außengrills +Heim & Garten > Küche & Esszimmer > Küchengeräte > Backöfen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Brotbackautomaten +Heim & Garten > Küche & Esszimmer > Küchengeräte > Campingkocher +Heim & Garten > Küche & Esszimmer > Küchengeräte > Dörrautomaten +Heim & Garten > Küche & Esszimmer > Küchengeräte > Eis-Crusher & Eis-Shaver +Heim & Garten > Küche & Esszimmer > Küchengeräte > Eismaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Elektrische Pfannen & Woks +Heim & Garten > Küche & Esszimmer > Küchengeräte > Elektrogrills & -bratplatten +Heim & Garten > Küche & Esszimmer > Küchengeräte > Entsafter +Heim & Garten > Küche & Esszimmer > Küchengeräte > Fonduetöpfe & -Sets +Heim & Garten > Küche & Esszimmer > Küchengeräte > Fritteusen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Gasgrillplatten +Heim & Garten > Küche & Esszimmer > Küchengeräte > Gefrierschränke & -truhen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Geschirrspüler +Heim & Garten > Küche & Esszimmer > Küchengeräte > Getränkewärmer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Grillöfen & Mini-Backöfen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Heißgetränkebereiter +Heim & Garten > Küche & Esszimmer > Küchengeräte > Joghurtmaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Espressokannen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Espressomaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Filterkaffeemaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Perkolatoren & Kaffeebrüher +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Pressstempelkannen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kaffee- & Espressomaschinen > Vakuumbereiter +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochfelder +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochplatten +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Dampfgarer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Eierkocher +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Reiskocher +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Schongarer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Thermokocher +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kochtöpfe & Dampfkochtöpfe > Öfen zum Vakuumgaren +Heim & Garten > Küche & Esszimmer > Küchengeräte > Küchenherde +Heim & Garten > Küche & Esszimmer > Küchengeräte > Kühlschränke +Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittel-Räucheröfen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Lebensmittelmühlen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Messerschärfer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Mikrowellenherde +Heim & Garten > Küche & Esszimmer > Küchengeräte > Milchaufschäumer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Mixer & Pürierstäbe +Heim & Garten > Küche & Esszimmer > Küchengeräte > Mochi-Maschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Müllpressen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Nudelmaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Popcornmaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Slush-Eis-Maschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Sojamilchbereiter +Heim & Garten > Küche & Esszimmer > Küchengeräte > Speiseeismaschinen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer > Buffetwärmer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer > Reiswärmer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer > Speisewärmelampen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Speisewärmer > Warmhaltetische +Heim & Garten > Küche & Esszimmer > Küchengeräte > Teekocher +Heim & Garten > Küche & Esszimmer > Küchengeräte > Temperiermaschinen für Schokolade +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Brezelbackautomat +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Donutmaker +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Mini- & Toastöfen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Muffin- & Cupcake-Maker +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Pizzaöfen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Pizzelle-Eisen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Quesadilla- & Tortilla-Maker +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Sandwichtoaster +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Toaster +Heim & Garten > Küche & Esszimmer > Küchengeräte > Toaster & Grills > Waffeleisen +Heim & Garten > Küche & Esszimmer > Küchengeräte > Trinkwasserspender +Heim & Garten > Küche & Esszimmer > Küchengeräte > Vakuumierer +Heim & Garten > Küche & Esszimmer > Küchengeräte > Wasserfilter +Heim & Garten > Küche & Esszimmer > Küchengeräte > Wasserkocher +Heim & Garten > Küche & Esszimmer > Küchengeräte > Wassersprudler +Heim & Garten > Küche & Esszimmer > Küchengeräte > Weinkühlschränke +Heim & Garten > Küche & Esszimmer > Küchengeräte > Zuckerwattemaschinen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Abkühlgitter +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Abtropf- & Küchensiebe +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Allespicker & Spieße +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Ausstechförmchen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Backpinsel +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Backschaufeln +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Bratenspritzen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Bratschläuche +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dampfgarbeutel +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dessertformen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dosenpressen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dosenöffner +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Dressing-Shaker +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Eiswürfelformen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Elektromesser +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Elektromesserzubehör +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Elektromesserzubehör > Elektromesser-Ersatzklingen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Essig- & Ölspender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Flambierbrenner +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Fleischgabeln +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Fleischklopfer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Fleischpistolen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Geschirrständer & Abtropfflächen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Getränkespender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Gewürzmühlen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kartoffelpressen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Keksmaschine +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kellen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Knoblauchpressen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kochthermometer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kuchen-Dekorationsbedarf +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Kurzzeitmesser & Eieruhren +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenformen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenmesser +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Besteckkästen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Gewürzregale & -ständer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Halter für Küchenutensilien +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Konservenregal +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Küchenrollenhalter & -spender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Küchenschranksysteme +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Messerblöcke & -halter +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Organizer für Küchenutensilien +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Serviettenhalter & -spender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Topfregale +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Trinkgefäßhalter +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Trinkhalmhalter & -spender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Zahnstocherbehälter & -spender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenorganizer > Zuckertütenhalter +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber > Grillschaber +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber > Teigschaber +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschaber > Teigspatel +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenscheren +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenschneidegeräte +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenthermometer-Zubehör +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchentrichter +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenutensilien-Sets +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Küchenzangen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Lebensmittelschablonen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Löffelablagen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Mehlsiebe +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Messbecher & Dosierlöffel +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Mörser & Stößel +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Nahrungsmittelspender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pastaförmchen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pfannenwender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pizzaschneider +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Pizzaschneider-Zubehör +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer > Eiscremeportionierer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer > Eisportionierer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer > Kugelausstecher +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Portionierer > Popcorn- & Pommesschaufeln +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Reiben +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Rührschüsseln +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Salatschleudern +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Saucenspender +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schaumlöffel +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schneebesen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schneidebretter +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schäler & Entkerner +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Schürzen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker > Hummer- & Krebszangen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker > Nussknacker +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spezialbesteck & Nussknacker > Nussknacker > Dekorative Nussknacker +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spülbeckenkörbe +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Spülbeckenmatten +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Stampfer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Sushi-Matten +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teesiebe +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigmischer +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollenzubehör +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollenzubehör > Abstandsringe für Teigrollen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigrollenzubehör > Teigrollenhüllen & -überzüge +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigräder +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Teigtücher +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Topfhandschuhe & Topflappen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Tortenheber +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Ziseliermesser +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Zubehör für Gewürzmühlen +Heim & Garten > Küche & Esszimmer > Küchenhelfer & -utensilien > Zuckerspender +Heim & Garten > Küche & Esszimmer > Tafelgeschirr +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr > Geschirrsets +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr > Schüsseln +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Geschirr > Teller +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Kaffee- & Teekannen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Kaffee- & Teeservices +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Klemmen & Gewichte für Tischdecken +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Salz- & Pfefferstreuer +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck > Bowlenschüsseluntersatz +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck > Terrinendeckel +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierbesteck > Terrinenuntersatz +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Bowleschüsseln +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Butterdosen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Eierbecher +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Karaffen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Kuchenplatten +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Saucièren +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Servierplatten +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Serviertabletts +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Terrinen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Tortenständer +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Servierware > Zuckerdosen & Milchkännchen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Besteck-Sets +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Essstäbchen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Essstäbchenzubehör +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Gabeln +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Löffel +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Tischbestecke > Tafelmesser +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Topfuntersetzer +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Biergläser +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- & Teebecher +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- und Teetassen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Kaffee- und Teeuntertassen +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Schnapsgläser +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Stielgläser +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Trinkbehältersets +Heim & Garten > Küche & Esszimmer > Tafelgeschirr > Trinkgefäße > Trinkgläser +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Anzündkamine +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Außengrillabdeckungen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Außengrillroste & -auflagen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Außengrillspieße & -körbe +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Ersatzteile für Außengrills +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Grillbretter +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Grillwagen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Holzkohle +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Außengrillzubehör > Räucherchips & -Pellets +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Dunstabzugshauben-Zubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Dörrautomatenzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Dörrautomatenzubehör > Dörrautomatenbleche +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Dörrautomatenzubehör > Dörrautomatentabletts +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Entsafterzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fonduesetzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fonduesetzubehör > Chafing Dish- & Fonduebrennpasten +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fonduesetzubehör > Fonduegabeln +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fonduesetzubehör > Fonduetopfständer +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Fritteusenzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Küchenabfallzerkleinerer-Zubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Kühlschrankzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Mikrowellenzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Nudelmaschinenzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Speiseeismaschinenzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Speiseeismaschinenzubehör > Gefrierschüsseln für Speiseeismaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Spülmaschinenzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Toasterzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Vakuumiererzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Vakuumiererzubehör > Vakuumierer-Beutel +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Wasserspenderzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Wasserspenderzubehör > Flaschen für Wasserspender +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Weinkühlschrank-Zubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Brotbackautomaten +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Campingöfen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Eis-Crusher & Eis-Shaver +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Eismaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Gefrierschränke +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Herdplatten, Backöfen und Küchenherde +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Joghurtmaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Aufschäumer +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Ersatzteile für Espresso- & Kaffeemaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeefilter +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeefilterkörbe +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeekannen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeekannenwarmhalter +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeemühlen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Kaffeemühlenzubehör +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Siebträger +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Kaffee- & Espressomaschinen > Wasserfilter für Kaffeemaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Lebensmittelmühlen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Mixer & Pürierstäbe +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Popcornmaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Trinkwassersprudler +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Waffeleisen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Warmhaltetheken +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Warmhaltetheken > Behälter für Warmhaltetheken +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Warmhaltetheken > Deckel für Warmhaltebehälter +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Wasserkocher +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für Zuckerwattemaschinen +Heim & Garten > Küche & Esszimmer > Zubehör für Küchengeräte > Zubehör für elektrische Pfannen & Woks +Heim & Garten > Notfallvorsorge +Heim & Garten > Notfallvorsorge > Erdbebenmelder +Heim & Garten > Notfallvorsorge > Möbelanker +Heim & Garten > Notfallvorsorge > Notfalldecken +Heim & Garten > Notfallvorsorge > Notfallwerkzeuge +Heim & Garten > Notfallvorsorge > Notvorräte +Heim & Garten > Pflanzen +Heim & Garten > Pflanzen > Blumen +Heim & Garten > Pflanzen > Bäume +Heim & Garten > Pflanzen > Grünpflanzen, Büsche & Sträucher +Heim & Garten > Pflanzen > Pflanzen- & Kräuteranbausets +Heim & Garten > Pflanzen > Saatgut +Heim & Garten > Pflanzen > Wasserpflanzen +Heim & Garten > Pool & Spa +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Badeinseln & Schwimmliegen +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Badespielzeug +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Chlorgeneratoren für Pools und Whirlpools +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Mechanische & Chemische Poolreiniger +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Pool- & Whirlpool-Filter +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolabdeckungen & -unterlagen +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolbürsten +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolfolien +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolleitern, -treppen & -rampen +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolreinigungsgeräte +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Poolskimmer +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Schläuche für Poolreiniger +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Sonnendecks +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Sprungbretter +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Swimmingpoolheizungen +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Wartungssets für Pools & Whirlpools +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Wasserrutschen +Heim & Garten > Pool & Spa > Pool- & Whirlpool-Zubehör > Zubehör für Poolabdeckungen +Heim & Garten > Pool & Spa > Pools +Heim & Garten > Pool & Spa > Saunen +Heim & Garten > Pool & Spa > Spa-Becken +Heim & Garten > Rasen & Garten +Heim & Garten > Rasen & Garten > Bewässerungssysteme +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gartenschlauchsprühköpfe +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gartenschlauchzubehör & -ventile +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gartenschläuche +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Gießkannen +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinkler & -köpfe +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinklersysteme +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinklersysteme > Sprinklerventile +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Sprinklersysteme > Steuerelemente für Sprinkleranlagen +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Wasserspender für Pflanzen +Heim & Garten > Rasen & Garten > Bewässerungssysteme > Zubehör für Gießkannen +Heim & Garten > Rasen & Garten > Garten & Balkon +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Bögen, Gitter, Laubengänge & Pergolen +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Gartenbrücken +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Dächer für Pavillions +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Gewichte für Sonnendächer +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Rahmen für Pavillons +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Seitenwand-Sets für Pavillons +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillon-Zubehör > Stangen für Sonnendächer +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Pavillons & Gartenlauben +Heim & Garten > Rasen & Garten > Garten & Balkon > Gartenhäuschen & Gartenbauten > Schuppen, Garagen & Carports +Heim & Garten > Rasen & Garten > Garten & Balkon > Hollywoodschaukeln +Heim & Garten > Rasen & Garten > Garten & Balkon > Hängematten +Heim & Garten > Rasen & Garten > Garten & Balkon > Hängemattenzubehör +Heim & Garten > Rasen & Garten > Garten & Balkon > Markisen +Heim & Garten > Rasen & Garten > Garten & Balkon > Markisen-Zubehör +Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken +Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken > Picknickdecken +Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken > Poncholiner +Heim & Garten > Rasen & Garten > Garten & Balkon > Outdoor-Decken > Strandmatten +Heim & Garten > Rasen & Garten > Garten & Balkon > Sonnenschirme +Heim & Garten > Rasen & Garten > Garten & Balkon > Zubehör für Hollywoodschaukeln +Heim & Garten > Rasen & Garten > Garten & Balkon > Zubehör für Sonnenschirme +Heim & Garten > Rasen & Garten > Garten & Balkon > Zubehör für Sonnenschirme > Sonnenschirmabdeckungen +Heim & Garten > Rasen & Garten > Garten & Balkon > Zubehör für Sonnenschirme > Sonnenschirmbeleuchtung +Heim & Garten > Rasen & Garten > Garten & Balkon > Zubehör für Sonnenschirme > Sonnenschirmschutzhüllen +Heim & Garten > Rasen & Garten > Garten & Balkon > Zubehör für Sonnenschirme > Sonnenschirmstoff +Heim & Garten > Rasen & Garten > Garten & Balkon > Zubehör für Sonnenschirme > Sonnenschirmständer +Heim & Garten > Rasen & Garten > Gartenbau +Heim & Garten > Rasen & Garten > Gartenbau > Blumenkäfige & Zubehör +Heim & Garten > Rasen & Garten > Gartenbau > Blumentöpfe & Pflanzgefäße +Heim & Garten > Rasen & Garten > Gartenbau > Dünger +Heim & Garten > Rasen & Garten > Gartenbau > Gartentopfuntersetzer und Trays +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Astsägen +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Baumscheren +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Gartensicheln & Macheten +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Geräte zum Pflanzen von Knollen +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Mistgabeln +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Pflanzkellen +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Pflanzwerkzeuge +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Rasen- & Gartenspritzgeräte +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Rasenwalzen +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Rechen +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Schaufeln & Spaten +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Schubkarren +Heim & Garten > Rasen & Garten > Gartenbau > Gartenwerkzeuge > Streugeräte +Heim & Garten > Rasen & Garten > Gartenbau > Gewächshäuser +Heim & Garten > Rasen & Garten > Gartenbau > Herbizide +Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren +Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren > Kompost +Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren > Komposter +Heim & Garten > Rasen & Garten > Gartenbau > Kompostieren > Kompostlüfter +Heim & Garten > Rasen & Garten > Gartenbau > Krankheitsbekämpfung +Heim & Garten > Rasen & Garten > Gartenbau > Mulch +Heim & Garten > Rasen & Garten > Gartenbau > Pflanzeinsätze für Blumentöpfe und -kübel +Heim & Garten > Rasen & Garten > Gartenbau > Pflanzenständer +Heim & Garten > Rasen & Garten > Gartenbau > Regenfässer +Heim & Garten > Rasen & Garten > Gartenbau > Sand & Gartenerde +Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies +Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies-Zubehör +Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies-Zubehör > Erdanker & -nägel +Heim & Garten > Rasen & Garten > Gartenbau > Unkrautvlies-Zubehör > Garten - Gewebeband +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit > Gartentaschen +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit > Rollsitze, Sitzhilfen & Kniekissen für Gartenarbeit +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartenarbeit > Umtopftische +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartengeräte +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartengeräte > Aufsätze für Gartengeräte +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartengeräte > Griffe für Gartengeräte +Heim & Garten > Rasen & Garten > Gartenbau > Zubehör für Gartengeräte > Schubkarrenteile +Heim & Garten > Rasen & Garten > Gartenmaschinen +Heim & Garten > Rasen & Garten > Gartenmaschinen > Basiseinheiten für elektrische Gartengeräte +Heim & Garten > Rasen & Garten > Gartenmaschinen > Bodenbearbeitungsmaschinen +Heim & Garten > Rasen & Garten > Gartenmaschinen > Elektrische Heckenscheren +Heim & Garten > Rasen & Garten > Gartenmaschinen > Elektrische Kombi-Gartenmaschinen-Sets +Heim & Garten > Rasen & Garten > Gartenmaschinen > Hochdruckreiniger +Heim & Garten > Rasen & Garten > Gartenmaschinen > Kehrmaschine +Heim & Garten > Rasen & Garten > Gartenmaschinen > Kettensägen +Heim & Garten > Rasen & Garten > Gartenmaschinen > Laubbläser +Heim & Garten > Rasen & Garten > Gartenmaschinen > Laubsauger +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenkantentrimmer +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenlüfter und Vertikutierer +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Aufsitzrasenmäher +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Handrasenmäher +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Mähroboter +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasenmäher > Quad-Anhänger +Heim & Garten > Rasen & Garten > Gartenmaschinen > Rasentrimmer & Freischneider +Heim & Garten > Rasen & Garten > Gartenmaschinen > Schneefräsen +Heim & Garten > Rasen & Garten > Gartenmaschinen > Traktoren +Heim & Garten > Rasen & Garten > Schnee- und Eisbeseitigung +Heim & Garten > Rasen & Garten > Schnee- und Eisbeseitigung > Eiskratzer & Schneebesen +Heim & Garten > Rasen & Garten > Schnee- und Eisbeseitigung > Schneeschaufeln +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Aufsätze für elektrische Kombi-Gartenmaschinen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Aufsätze für elektrische Kombi-Gartenmaschinen > Fräsen- und Grubber-Aufsätze +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Aufsätze für elektrische Kombi-Gartenmaschinen > Heckenscheren-Aufsätze +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Aufsätze für elektrische Kombi-Gartenmaschinen > Laubbläser-Aufsätze +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Aufsätze für elektrische Kombi-Gartenmaschinen > Rasentrimmer-Aufsätze +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Aufsätze für elektrische Kombi-Gartenmaschinen > Stangensägen-Aufsätze +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Aufsätze für elektrische Kombi-Gartenmaschinen > Unkrauttrimmer-Aufsätze +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Batterien für elektrische Kombi-Gartenmaschinen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Heckenscheren-Zubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Hochdruckreiniger-Zubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Kettensägenzubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Kettensägenzubehör > Kettensägenketten +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Kettensägenzubehör > Kettensägenschwerter +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Laubbläser-Zubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Laubbläser-Zubehör > Laubbläser-Rohre +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Grasauffangbehälter +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Mulchkits für Rasenmäher +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Mulchstopfen für Rasenmäher +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenkehrmaschinen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmäher-Antriebsrollen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmäher-Keilriemen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmäher-Reifen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmäher-Reifenschläuche +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmäher-Riemenscheiben +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmäher-Räder +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmäherabdeckungen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Rasenmähermesser +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasenmäher-Zubehör > Wiesenmäher-Zusatzteile +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Rasentrimmer-Zubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Schneefräsenzubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Traktorteile & Zubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Traktorteile & Zubehör > Traktorreifen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Traktorteile & Zubehör > Traktorräder +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Unkrauttrimmer-Zubehör +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Unkrauttrimmer-Zubehör > Abdeckungen für Rasentrimmer-Kabelrollen +Heim & Garten > Rasen & Garten > Zubehör für Gartenmaschinen > Unkrauttrimmer-Zubehör > Messer & Kabelrollen für Rasentrimmer +Heim & Garten > Rauchzubehör +Heim & Garten > Rauchzubehör > Aschenbecher +Heim & Garten > Rauchzubehör > Humidore +Heim & Garten > Rauchzubehör > Humidorzubehör +Heim & Garten > Rauchzubehör > Zigarettenhalter +Heim & Garten > Rauchzubehör > Zigarettenkisten +Heim & Garten > Rauchzubehör > Zigarrenkisten +Heim & Garten > Rauchzubehör > Zigarrenschneider & -locher +Heim & Garten > Schutzhüllen für Sonnenschirme +Heim & Garten > Sonnen- & Regenschirme +Heim & Garten > Zubehör für Kamine & Holzöfen +Heim & Garten > Zubehör für Kamine & Holzöfen > Blasebälge +Heim & Garten > Zubehör für Kamine & Holzöfen > Feuerböcke +Heim & Garten > Zubehör für Kamine & Holzöfen > Feuerholz & Brennstoffe +Heim & Garten > Zubehör für Kamine & Holzöfen > Feuerholz-Aufbewahrung +Heim & Garten > Zubehör für Kamine & Holzöfen > Holzofenventilatoren & -gebläse +Heim & Garten > Zubehör für Kamine & Holzöfen > Kamin- & Holzofenroste +Heim & Garten > Zubehör für Kamine & Holzöfen > Kaminbodenplatten +Heim & Garten > Zubehör für Kamine & Holzöfen > Kamingitter +Heim & Garten > Zubehör für Kamine & Holzöfen > Kaminreflektoren +Heim & Garten > Zubehör für Kamine & Holzöfen > Kaminwerkzeug +Heim & Garten > Zubehör für Kamine & Holzöfen > Zubehör für Feuerholz-Aufbewahrung +Heimwerkerbedarf +Heimwerkerbedarf > Baumaterial +Heimwerkerbedarf > Baumaterial > Chemikalien +Heimwerkerbedarf > Baumaterial > Chemikalien > Abflussreiniger +Heimwerkerbedarf > Baumaterial > Chemikalien > Ammonium +Heimwerkerbedarf > Baumaterial > Chemikalien > Anzünderflüssigkeit +Heimwerkerbedarf > Baumaterial > Chemikalien > Beton- & Mauerreiniger +Heimwerkerbedarf > Baumaterial > Chemikalien > Enteiser +Heimwerkerbedarf > Baumaterial > Chemikalien > Holzterrassen- & -zaunreiniger +Heimwerkerbedarf > Baumaterial > Chemikalien > Kaminreiniger +Heimwerkerbedarf > Baumaterial > Chemikalien > Kältespray für Elektronik +Heimwerkerbedarf > Baumaterial > Chemikalien > Reiniger für Abwassertanks & Senkgruben +Heimwerkerbedarf > Baumaterial > Chemikalien > Säureneutralisierer +Heimwerkerbedarf > Baumaterial > Klebebänder +Heimwerkerbedarf > Baumaterial > Kraftklebstoffe & -leime +Heimwerkerbedarf > Baumaterial > Lösungsmittel, Abbeizmittel & Verdünner +Heimwerkerbedarf > Baumaterial > Lötmetall & Flussmittel +Heimwerkerbedarf > Baumaterial > Malermaterial +Heimwerkerbedarf > Baumaterial > Malermaterial > Farbe +Heimwerkerbedarf > Baumaterial > Malermaterial > Farbenbindemittel +Heimwerkerbedarf > Baumaterial > Malermaterial > Farbstoffe +Heimwerkerbedarf > Baumaterial > Malermaterial > Grundierungen +Heimwerkerbedarf > Baumaterial > Malermaterial > Lacke & Beschichtungen +Heimwerkerbedarf > Baumaterial > Maurermaterial +Heimwerkerbedarf > Baumaterial > Maurermaterial > Mauersteine & Betonblöcke +Heimwerkerbedarf > Baumaterial > Maurermaterial > Mörtel +Heimwerkerbedarf > Baumaterial > Maurermaterial > Zement, Mörtel & Beton +Heimwerkerbedarf > Baumaterial > Primer für Rohrverbindungen +Heimwerkerbedarf > Baumaterial > Schmiermittel +Heimwerkerbedarf > Baumaterial > Schutzbeschichtungen & Dichtmittel +Heimwerkerbedarf > Baumaterial > Wandausbesserungsmaterial & Gips +Heimwerkerbedarf > Baumaterialien +Heimwerkerbedarf > Baumaterialien > Arbeitsplatten +Heimwerkerbedarf > Baumaterialien > Bauholz +Heimwerkerbedarf > Baumaterialien > Bedachung +Heimwerkerbedarf > Baumaterialien > Bedachung > Dachrinnen +Heimwerkerbedarf > Baumaterialien > Bedachung > Dachschindeln & -pfannen +Heimwerkerbedarf > Baumaterialien > Bedachung > Kehlbleche +Heimwerkerbedarf > Baumaterialien > Bedachung > Zubehör für Dachrinnen +Heimwerkerbedarf > Baumaterialien > Betonstahl & -gitter +Heimwerkerbedarf > Baumaterialien > Fenster +Heimwerkerbedarf > Baumaterialien > Fensterbauteile +Heimwerkerbedarf > Baumaterialien > Fensterbauteile > Fensterhebel +Heimwerkerbedarf > Baumaterialien > Fensterbauteile > Fensterrahmen +Heimwerkerbedarf > Baumaterialien > Fensterläden +Heimwerkerbedarf > Baumaterialien > Fußböden & Teppichböden +Heimwerkerbedarf > Baumaterialien > Gipskartonplatten +Heimwerkerbedarf > Baumaterialien > Glas +Heimwerkerbedarf > Baumaterialien > Handläufe und Geländersysteme +Heimwerkerbedarf > Baumaterialien > Hausverkleidung +Heimwerkerbedarf > Baumaterialien > Isolierung +Heimwerkerbedarf > Baumaterialien > Leisten +Heimwerkerbedarf > Baumaterialien > Luken +Heimwerkerbedarf > Baumaterialien > Schalldämpfende Materialien +Heimwerkerbedarf > Baumaterialien > Treppen +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Schlossfallen +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Schlüssellochverzierungen für Türen +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Türdruckplatten +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Türklingeln +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Türklopfer +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Türknäufe & -klinken +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Türrahmen +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Türschließer +Heimwerkerbedarf > Baumaterialien > Türbeschläge & -klingeln > Türstopper +Heimwerkerbedarf > Baumaterialien > Türen +Heimwerkerbedarf > Baumaterialien > Türen > Garagentore +Heimwerkerbedarf > Baumaterialien > Türen > Haustüren +Heimwerkerbedarf > Baumaterialien > Wand- & Deckenfliesen +Heimwerkerbedarf > Baumaterialien > Wandverkleidung +Heimwerkerbedarf > Baumaterialien > Zugluftstopper, Fenster- & Türdichtungen +Heimwerkerbedarf > Bauzubehör +Heimwerkerbedarf > Bauzubehör > Abdeckfolien +Heimwerkerbedarf > Bauzubehör > Befestigungselemente +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Dübel +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Gewindestangen +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Nieten +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Nägel +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Schrauben +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Schrauben & Muttern +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Schraubverbinder +Heimwerkerbedarf > Bauzubehör > Befestigungselemente > Unterlegscheiben +Heimwerkerbedarf > Bauzubehör > Betonformen +Heimwerkerbedarf > Bauzubehör > Bodenspieße +Heimwerkerbedarf > Bauzubehör > Federn +Heimwerkerbedarf > Bauzubehör > Filter & Siebe +Heimwerkerbedarf > Bauzubehör > Gasschläuche +Heimwerkerbedarf > Bauzubehör > Haken, Schnallen & Verschlüsse +Heimwerkerbedarf > Bauzubehör > Haken, Schnallen & Verschlüsse > Gear Tie-Universalkabelbinder +Heimwerkerbedarf > Bauzubehör > Haken, Schnallen & Verschlüsse > Kettenverbinder & -glieder +Heimwerkerbedarf > Bauzubehör > Haken, Schnallen & Verschlüsse > Lasthaken, Trageklemmen & Schäkel +Heimwerkerbedarf > Bauzubehör > Haken, Schnallen & Verschlüsse > Schnallen- & Steckschnallen +Heimwerkerbedarf > Bauzubehör > Halterungen +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile > Bindegarne +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile > Draht +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile > Ketten +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile > Seile +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile > Spanngummis +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile > Spanngurte +Heimwerkerbedarf > Bauzubehör > Ketten, Drähte & Seile > Zugschalterketten und -kordeln +Heimwerkerbedarf > Bauzubehör > Laufrollen +Heimwerkerbedarf > Bauzubehör > Luftschläuche +Heimwerkerbedarf > Bauzubehör > Metallgussformen +Heimwerkerbedarf > Bauzubehör > Planen +Heimwerkerbedarf > Bauzubehör > Richtstützen +Heimwerkerbedarf > Bauzubehör > Scharniere +Heimwerkerbedarf > Bauzubehör > Schmierschläuche +Heimwerkerbedarf > Bauzubehör > Schrankbauteile +Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schlüssellochverzierungen für Schränke +Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schrankbeschläge +Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schrankknäufe & -griffe +Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schrankscharniere +Heimwerkerbedarf > Bauzubehör > Schrankbauteile > Schranktüren +Heimwerkerbedarf > Bauzubehör > Schubladenschienen +Heimwerkerbedarf > Bauzubehör > Spulen +Heimwerkerbedarf > Bauzubehör > Standfüße für Pfosten +Heimwerkerbedarf > Bauzubehör > Transport- und Schallschutzabdeckungen +Heimwerkerbedarf > Bauzubehör > Warnklebeband +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Dienst- & Werkzeuggürtel +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Einsätze zur Werkzeugaufbewahrung +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Gartenschlauchhalterungen +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkbänke +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugetuis +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugkästen +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugschränke +Heimwerkerbedarf > Bauzubehör > Werkzeugaufbewahrung & Ordnungssysteme > Werkzeugtaschen +Heimwerkerbedarf > Bauzubehör > Zylinderstifte & Dübelstangen +Heimwerkerbedarf > Brennstoffbehälter & -tanks +Heimwerkerbedarf > Elektrobedarf +Heimwerkerbedarf > Elektrobedarf > Anker, Rotoren und Statoren +Heimwerkerbedarf > Elektrobedarf > Anschlussdosen & Halterungen +Heimwerkerbedarf > Elektrobedarf > Drahtbindemaschinen +Heimwerkerbedarf > Elektrobedarf > Elektrische Leitungen +Heimwerkerbedarf > Elektrobedarf > Elektromotoren +Heimwerkerbedarf > Elektrobedarf > Elektroschalter +Heimwerkerbedarf > Elektrobedarf > Elektroschalter > Lichtschalter +Heimwerkerbedarf > Elektrobedarf > Elektroschalter > Spezielle elektrische Schalter +Heimwerkerbedarf > Elektrobedarf > Generatoren +Heimwerkerbedarf > Elektrobedarf > Gerätestecker +Heimwerkerbedarf > Elektrobedarf > Heim- & Gebäudeautomatisierung +Heimwerkerbedarf > Elektrobedarf > Kabelanschlüsse & Steckverbinder +Heimwerkerbedarf > Elektrobedarf > Kohlebürsten +Heimwerkerbedarf > Elektrobedarf > Leitungen & Gehäuse +Heimwerkerbedarf > Elektrobedarf > Leitungen & Gehäuse > Kabelkanäle +Heimwerkerbedarf > Elektrobedarf > Leitungen & Gehäuse > Schrumpfschläuche +Heimwerkerbedarf > Elektrobedarf > Schaltnetzteile +Heimwerkerbedarf > Elektrobedarf > Solarenergie-Kits +Heimwerkerbedarf > Elektrobedarf > Solarpaneele +Heimwerkerbedarf > Elektrobedarf > Spannungswandler & -regler +Heimwerkerbedarf > Elektrobedarf > Steckdosen +Heimwerkerbedarf > Elektrobedarf > Steckdosen-Zeitschaltuhren & -Sensoren +Heimwerkerbedarf > Elektrobedarf > Steckdosenabdeckungen +Heimwerkerbedarf > Elektrobedarf > Telefon- & Internetbuchsen +Heimwerkerbedarf > Elektrobedarf > Verlängerungskabel +Heimwerkerbedarf > Elektrobedarf > Verlängerungskabelzubehör +Heimwerkerbedarf > Elektrobedarf > Verteilerkästen +Heimwerkerbedarf > Elektrobedarf > Vorschaltgeräte & Starter +Heimwerkerbedarf > Elektrobedarf > Wandplatten +Heimwerkerbedarf > Elektrobedarf > Wechselrichter +Heimwerkerbedarf > Elektrobedarf > Zubehör für Generatoren +Heimwerkerbedarf > Hauseinzäunung +Heimwerkerbedarf > Hauseinzäunung > Absperrungen +Heimwerkerbedarf > Hauseinzäunung > Beeteinfassungen +Heimwerkerbedarf > Hauseinzäunung > Tore +Heimwerkerbedarf > Hauseinzäunung > Zaunfelder +Heimwerkerbedarf > Hauseinzäunung > Zaungitter +Heimwerkerbedarf > Hauseinzäunung > Zaunlatten +Heimwerkerbedarf > Hauseinzäunung > Zaunpfosten & -querlatten +Heimwerkerbedarf > Hauseinzäunung > Zubehör für Zäune & Gartentore +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen > Filtertrockner +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen > Luftdurchlässe & Abzugsrohre +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen > Luftkanäle +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen > Steuerungen +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen > Steuerungen > Feuchtigkeitsregler +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen > Steuerungen > Schalt- & Bedienungstafeln +Heimwerkerbedarf > Heizen, Belüftung & Klimaanlagen > Steuerungen > Thermostate +Heimwerkerbedarf > Kleinmotoren +Heimwerkerbedarf > Küchen- und Sanitärinstallationen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Brunnenbedarf +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Installationsrohre +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Dichtungen & O-Ringe +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Druckminderer +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Düsen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > In der Wand verbaute Trägerleisten +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Rohranschlüsse & Reduzierstücke +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Rohrflansche +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Rohrkappen & -verschlüsse +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Rohrschellen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Rohrverbinder +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Rohrverbindungsstücke & -halterungen > Ventile +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitär-Reparatursätze +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Armaturen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Badewannen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Badezimmerausstattungen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Duschkabinen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets > Bidets +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets > Toiletten +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Toiletten & Bidets > Urinale +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken & Spülen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken & Spülen > Badezimmerwaschbecken +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Sanitärkeramik & Armaturen > Waschbecken & Spülen > Küchenspülen & Spülbecken +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Schläuche & Leitungen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Salz zur Wasserenthärtung +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Wasserdestillationsgeräte +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Wasserenthärter +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Wasserleitungsfilter +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Wasserspender +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Wasserspender > Trinkbrunnen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Wasserspender > Wasserkühler +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Zubehör für Wasserfilter +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Zubehör für Wasserfilter > Wasserfiltergehäuse +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Trinkwasserspender & Filter > Zubehör für Wasserfilter > Wasserfilterkartuschen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Wasserschaltuhren +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Wasserstandsregler +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten > Abflussauskleidung bzw. -Abdichtung +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten > Abflussgitter +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten > Abflussreinigungswerkzeug +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten > Abflussstöpsel & -filter +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten > Geruchsverschlüsse +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten > Kanal- & Abflussstäbe +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflusskomponenten > Sanitärabläufe +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Abflüsse +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Badewannen- & Duschdüsen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Duscharme & Verbindungsteile +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Duschkabinen & -türen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Duschköpfe +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Duschpaneele +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Duschwannen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Duschwände +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Elektrische & Powerduschen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Duscharmaturen > Wasserfilter für Duschen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Halterungsplatten +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > Bidet-Hähne & -Sprüher +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > Kugelhähne & Verschlüsse +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > Spülkastenabdeckungen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > Spülkästen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > Toilettendeckel +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > Toilettensitze +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > Toilettenverkleidung +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > WC-Papiersitze +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Toiletten- und Bidetzubehör > WC-Spülkastengriffe +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Waschbecken- & Spülenzubehör +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Waschbecken- & Spülenzubehör > Waschbeckenfüße +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Zubehör für Armaturen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Zubehör für Armaturen > Armaturen-Griffe +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Zubehör für Armaturen > Strahlregler +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Zubehör für Badewannen +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Zubehör für Badewannen > Badewanneneinläufe +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Zubehör für Badewannen > Badewannenunterbau & -füße +Heimwerkerbedarf > Küchen- und Sanitärinstallationen > Zubehör für sanitäre Anlagen > Zubehör für Badewannen > Badewannenverkleidungen +Heimwerkerbedarf > Metallpumpen +Heimwerkerbedarf > Metallpumpen > Bewässerungs-, Sprinkler- und Boosterpumpen +Heimwerkerbedarf > Metallpumpen > Brunnenpumpen und -systeme +Heimwerkerbedarf > Metallpumpen > Haushaltsgerätepumpen +Heimwerkerbedarf > Metallpumpen > Pool-, Brunnen- und Teichpumpen +Heimwerkerbedarf > Metallpumpen > Pumpen zur Entwässerung und Wasserleitung +Heimwerkerbedarf > Metallpumpen > Sickergruben-, Abwasser- und Abflusspumpen +Heimwerkerbedarf > Schlösser & Schlüssel +Heimwerkerbedarf > Schlösser & Schlüssel > Kartenschließsysteme +Heimwerkerbedarf > Schlösser & Schlüssel > Schlösser & Riegel +Heimwerkerbedarf > Schlösser & Schlüssel > Schlüsselkappen +Heimwerkerbedarf > Schlösser & Schlüssel > Schlüsselrohlinge +Heimwerkerbedarf > Vorratsbehälter +Heimwerkerbedarf > Werkzeuge +Heimwerkerbedarf > Werkzeuge > Ambosse +Heimwerkerbedarf > Werkzeuge > Arbeitslampen +Heimwerkerbedarf > Werkzeuge > Arbeitsscheinwerfer +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Betonmischer +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Fugenkellen +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Fugenschwamm +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Glättkellen +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Glättmaschinen +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Kanten- & Schneidwerkzeuge +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Maurerkellen +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Maurerschnüre +Heimwerkerbedarf > Werkzeuge > Bauwerkzeuge > Maurerwerkzeuge +Heimwerkerbedarf > Werkzeuge > Betonbesen +Heimwerkerbedarf > Werkzeuge > Biegewerkzeuge für Rohre & Stangen +Heimwerkerbedarf > Werkzeuge > Bodenverdichter +Heimwerkerbedarf > Werkzeuge > Bohrmaschinen +Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Druckluftbohrer +Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Elektrische Handbohrmaschinen +Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Schneckenbohrer +Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Stemmmaschinen +Heimwerkerbedarf > Werkzeuge > Bohrmaschinen > Ständerbohrmaschinen +Heimwerkerbedarf > Werkzeuge > Brecheisen +Heimwerkerbedarf > Werkzeuge > Drehmaschinen +Heimwerkerbedarf > Werkzeuge > Einziehhilfen +Heimwerkerbedarf > Werkzeuge > Elektrohobel +Heimwerkerbedarf > Werkzeuge > Entgrater +Heimwerkerbedarf > Werkzeuge > Fettpressen +Heimwerkerbedarf > Werkzeuge > Feuerzeuge & Streichhölzer +Heimwerkerbedarf > Werkzeuge > Gewindebohrer +Heimwerkerbedarf > Werkzeuge > Gewindeschneidmaschinen +Heimwerkerbedarf > Werkzeuge > Glühbirnenwechsler +Heimwerkerbedarf > Werkzeuge > Griffe +Heimwerkerbedarf > Werkzeuge > Hacken & Spitzhacken +Heimwerkerbedarf > Werkzeuge > Handmischmaschinen +Heimwerkerbedarf > Werkzeuge > Handwerkzeuge für Drähte und Kabel +Heimwerkerbedarf > Werkzeuge > Heißluftpistole +Heimwerkerbedarf > Werkzeuge > Hobel +Heimwerkerbedarf > Werkzeuge > Holzspalter +Heimwerkerbedarf > Werkzeuge > Hämmer +Heimwerkerbedarf > Werkzeuge > Hämmer > Manuelle Hämmer +Heimwerkerbedarf > Werkzeuge > Hämmer > Maschinenbetriebene Hämmer +Heimwerkerbedarf > Werkzeuge > Industrievibratoren +Heimwerkerbedarf > Werkzeuge > Kaminbürste +Heimwerkerbedarf > Werkzeuge > Kittmesser & -spachtel +Heimwerkerbedarf > Werkzeuge > Kompressoren +Heimwerkerbedarf > Werkzeuge > Kontrollspiegel +Heimwerkerbedarf > Werkzeuge > Lasthebemagnete +Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste +Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Arbeitsplattformen +Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Gerüste +Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Leitern +Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Leiterwagen +Heimwerkerbedarf > Werkzeuge > Leitern & Gerüste > Tritthocker +Heimwerkerbedarf > Werkzeuge > Locheisen & Ahlen +Heimwerkerbedarf > Werkzeuge > Lochschaufeln +Heimwerkerbedarf > Werkzeuge > Lötkolben +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Airbrushpistolen +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbrollen +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbrüttler +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbsiebe +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbspritzpistolen +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Farbwannen +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Kantenmaler +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Malerpinsel +Heimwerkerbedarf > Werkzeuge > Malerwerkzeug > Malschwämme +Heimwerkerbedarf > Werkzeuge > Markierwerkzeuge +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Balkensucher +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Barometer +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Durchflussmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Elektrische Prüfgeräte +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Entfernungsmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Feuchtigkeitsmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Gasdetektoren +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Geigerzähler +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Haarlineale +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Hygrometer +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Höhenmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Infrarotthermometer +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Kluppen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Lautstärkemesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Maßbänder +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messerführungen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messinstrumente +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messräder +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Messschieber +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Raumluftmessgeräte +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen > Laser-Wasserwaagen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen > Schaugläser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Richtwaagen > Wasserwaagen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Schwingungsmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Seismographen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Sonden & Suchgeräte +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Stahlbewehrungssucher +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Stangenzirkel +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Theodolite +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Thermoelemente & -säulen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Transducer & Messumformer +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > UV-Lichtmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Waagen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Wetterstationen +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Windgeschwindigkeitsmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Winkel +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Winkelmesser +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Wärmekameras +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > Zollstöcke +Heimwerkerbedarf > Werkzeuge > Messwerkzeuge & Messwertgeber > pH-Meter +Heimwerkerbedarf > Werkzeuge > Multifunktionales Elektrowerkzeug +Heimwerkerbedarf > Werkzeuge > Mühlen +Heimwerkerbedarf > Werkzeuge > Müll- & Papierkrallen +Heimwerkerbedarf > Werkzeuge > Nageleisen +Heimwerkerbedarf > Werkzeuge > Nagler & Tacker +Heimwerkerbedarf > Werkzeuge > Nietwerkzeuge +Heimwerkerbedarf > Werkzeuge > Nietwerkzeuge > Nietpistolen +Heimwerkerbedarf > Werkzeuge > Nietwerkzeuge > Nietzangen +Heimwerkerbedarf > Werkzeuge > Oberfräsen +Heimwerkerbedarf > Werkzeuge > Reibahlen +Heimwerkerbedarf > Werkzeuge > Rohrbürsten +Heimwerkerbedarf > Werkzeuge > Rohrreiniger +Heimwerkerbedarf > Werkzeuge > Rollwagen & Sackkarren +Heimwerkerbedarf > Werkzeuge > Sandstrahler +Heimwerkerbedarf > Werkzeuge > Saugglocken +Heimwerkerbedarf > Werkzeuge > Schlagschrauber +Heimwerkerbedarf > Werkzeuge > Schleifblöcke +Heimwerkerbedarf > Werkzeuge > Schleifer & Poliermaschinen +Heimwerkerbedarf > Werkzeuge > Schleifmaschinen +Heimwerkerbedarf > Werkzeuge > Schneidegeräte +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Betonstahlschneider +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Bolzenschneider +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Cutter +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Fliesen-, Ziegel- & Schindelschneider +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Glasschneider +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Metallscheren & Nibbelmaschinen +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Rohrschneider +Heimwerkerbedarf > Werkzeuge > Schneidegeräte > Zwickzangen +Heimwerkerbedarf > Werkzeuge > Schnitzwerkzeuge & Hohlmeißel +Heimwerkerbedarf > Werkzeuge > Schraubendreher +Heimwerkerbedarf > Werkzeuge > Schraubenschlüssel +Heimwerkerbedarf > Werkzeuge > Schraubzwingen & -stöcke +Heimwerkerbedarf > Werkzeuge > Schweißwerkzeuge & Plasmaschneider +Heimwerkerbedarf > Werkzeuge > Schwingschleifer +Heimwerkerbedarf > Werkzeuge > Schärfgeräte +Heimwerkerbedarf > Werkzeuge > Steckschlüssel +Heimwerkerbedarf > Werkzeuge > Stemmwerkzeuge +Heimwerkerbedarf > Werkzeuge > Stoßmaschinen +Heimwerkerbedarf > Werkzeuge > Sägeböcke +Heimwerkerbedarf > Werkzeuge > Sägen +Heimwerkerbedarf > Werkzeuge > Sägen > Bandsägen +Heimwerkerbedarf > Werkzeuge > Sägen > Dekupiersägen +Heimwerkerbedarf > Werkzeuge > Sägen > Fliesensägen +Heimwerkerbedarf > Werkzeuge > Sägen > Gehrungssägen +Heimwerkerbedarf > Werkzeuge > Sägen > Handkreissägen +Heimwerkerbedarf > Werkzeuge > Sägen > Handsägen +Heimwerkerbedarf > Werkzeuge > Sägen > Plattensägen +Heimwerkerbedarf > Werkzeuge > Sägen > Stichsägen +Heimwerkerbedarf > Werkzeuge > Sägen > Säbelsägen +Heimwerkerbedarf > Werkzeuge > Sägen > Tischkreissägen +Heimwerkerbedarf > Werkzeuge > Sägen > Trennsägen +Heimwerkerbedarf > Werkzeuge > Taschenlampen & Stirnlampen +Heimwerkerbedarf > Werkzeuge > Tischlerbänke +Heimwerkerbedarf > Werkzeuge > Wasseranschluss-Nachschleifwerkzeuge +Heimwerkerbedarf > Werkzeuge > Werkzeugfeilen +Heimwerkerbedarf > Werkzeuge > Werkzeugmesser +Heimwerkerbedarf > Werkzeuge > Werkzeugschlüssel +Heimwerkerbedarf > Werkzeuge > Werkzeugsets +Heimwerkerbedarf > Werkzeuge > Werkzeugsets > Elektrowerkzeug-Combo-Sets +Heimwerkerbedarf > Werkzeuge > Werkzeugsets > Handwerkzeugsets +Heimwerkerbedarf > Werkzeuge > Zangen +Heimwerkerbedarf > Werkzeuge > Äxte +Heimwerkerbedarf > Werkzeuge > Ölfilterabfluss +Heimwerkerbedarf > Werkzeugzubehör +Heimwerkerbedarf > Werkzeugzubehör > Anstreichzubehör +Heimwerkerbedarf > Werkzeugzubehör > Anstreichzubehör > Airbrushzubehör +Heimwerkerbedarf > Werkzeugzubehör > Anstreichzubehör > Anstreichrollenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Anstreichzubehör > Pinselreiniger +Heimwerkerbedarf > Werkzeugzubehör > Axtzubehör +Heimwerkerbedarf > Werkzeugzubehör > Axtzubehör > Axtgriffe +Heimwerkerbedarf > Werkzeugzubehör > Axtzubehör > Axtköpfe +Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör +Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrer & Bits +Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrerschleifgeräte +Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrerverlängerungen +Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrfutter +Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Bohrständer & -führungen +Heimwerkerbedarf > Werkzeugzubehör > Bohrzubehör > Lochsägen +Heimwerkerbedarf > Werkzeugzubehör > Drehmaschinenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Elektrowerkzeug-Akkus +Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör +Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör > Drucklufthammerzubehör +Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör > Hammerköpfe +Heimwerkerbedarf > Werkzeugzubehör > Hammerzubehör > Hammerstiele +Heimwerkerbedarf > Werkzeugzubehör > Keile für Werkzeuggriffe +Heimwerkerbedarf > Werkzeugzubehör > Keilwerkzeuge +Heimwerkerbedarf > Werkzeugzubehör > Klammern +Heimwerkerbedarf > Werkzeugzubehör > Ladegeräte für Elektrowerkzeuge +Heimwerkerbedarf > Werkzeugzubehör > Magnetisierer & Entmagnetisierer +Heimwerkerbedarf > Werkzeugzubehör > Mischwerkzeuge +Heimwerkerbedarf > Werkzeugzubehör > Sandstrahler-Zubehör +Heimwerkerbedarf > Werkzeugzubehör > Sandstrahler-Zubehör > Sandstrahlkabinen +Heimwerkerbedarf > Werkzeugzubehör > Schleifmaschinenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Schleifmaschinenzubehör > Schleifscheiben & -stifte +Heimwerkerbedarf > Werkzeugzubehör > Schleifzubehör +Heimwerkerbedarf > Werkzeugzubehör > Schleifzubehör > Schleifpapier & Schleifschwämme +Heimwerkerbedarf > Werkzeugzubehör > Schneidwerkzeug-Zubehör +Heimwerkerbedarf > Werkzeugzubehör > Schneidwerkzeug-Zubehör > Nibbelmaschinenstempel +Heimwerkerbedarf > Werkzeugzubehör > Schweißzubehör +Heimwerkerbedarf > Werkzeugzubehör > Spannvorrichtungen +Heimwerkerbedarf > Werkzeugzubehör > Steckschlüsseleinsätze +Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Bandsägenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Handkreissägen-Zubehör +Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Kreissägenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Laubsägenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Sägenzubehör > Tischsägenzubehör +Heimwerkerbedarf > Werkzeugzubehör > Werkzeugklingen & -blätter +Heimwerkerbedarf > Werkzeugzubehör > Werkzeugklingen & -blätter > Cutter-, Schaber- & Spachtelklingen +Heimwerkerbedarf > Werkzeugzubehör > Werkzeugklingen & -blätter > Sägeblätter +Heimwerkerbedarf > Werkzeugzubehör > Werkzeugsicherungen +Heimwerkerbedarf > Werkzeugzubehör > Werkzeugständer +Heimwerkerbedarf > Werkzeugzubehör > Werkzeugständer > Sägeständer +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Hacken & Pickel +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Hacken & Pickel > Griffe für Hacken & Pickel +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Lötkolben +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Lötkolben > Lötkolbenspitzen +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Lötkolben > Lötkolbenständer +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber > Multimeter-Zubehör +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber > Zubehör für Gasdetektoren +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber > Zubehör für Messskalen +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Messwerkzeuge & Messwertgeber > Zubehör für Spannungsmesser +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Oberfräsen +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Oberfräsen > Oberfräsenteile +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Oberfräsen > Oberfräsentische +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Stoßmaschinen +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Stoßmaschinen > Stoßmaschinenwerkzeuge +Heimwerkerbedarf > Werkzeugzubehör > Zubehör für Taschenlampen +Kameras & Optik +Kameras & Optik > Fotografie +Kameras & Optik > Fotografie > Aufbewahrung für Negative & Kontaktbögen +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Belichtungsmesser +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Lichtsteuerung +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Lichtsteuerung > Blitzdiffusoren +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Lichtsteuerung > Blitzreflektoren +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Lichtsteuerung > Lichtfilter & Filterfolien +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Lichtsteuerung > Softboxen +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Studio-Halterungen +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Studiohintergründe +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Studioscheinwerfer & -blitzgeräte +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Zubehör für Belichtungsmesser +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Zubehör für Studiobeleuchtung & Blitzgeräte +Kameras & Optik > Fotografie > Beleuchtung & Studiobedarf > Zubehör für Studioständer & -halterungen +Kameras & Optik > Fotografie > Dunkelkammer +Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung +Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Dunkelkammerbecken +Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Entwicklungsschalen, Wascher & Trockner +Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Entwicklungstanks & -spiralen +Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Reprostative +Kameras & Optik > Fotografie > Dunkelkammer > Ausrüstung, Entwicklung & Verarbeitung > Retuschierbedarf & -zubehör +Kameras & Optik > Fotografie > Dunkelkammer > Dunkelkammerleuchten +Kameras & Optik > Fotografie > Dunkelkammer > Fotochemikalien +Kameras & Optik > Fotografie > Dunkelkammer > Fotopapier +Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör +Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Dunkelkammer-Timer +Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Dunkelkammerstaffeleien +Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Fokussierhilfen +Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Fotovergrößerer +Kameras & Optik > Fotografie > Dunkelkammer > Vergrößerungszubehör > Lichtmesser +Kameras & Optik > Fotografie > Passepartouts & Aufziehmaterialien +Kameras & Optik > Kamera- & Optisches Zubehör +Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Video-Objektive +Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Video-Objektive > Kameraobjektive +Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Video-Objektive > Objektive für Überwachungskameras +Kameras & Optik > Kamera- & Optisches Zubehör > Kamera- & Video-Objektive > Videokamera-Objektive +Kameras & Optik > Kamera- & Optisches Zubehör > Kamera-Ersatzkabel +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Bildsensoren +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Blitzhaltesysteme +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Digitale Rückteile +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Ersatzbildschirme & -Displays +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Ersatzgehäuseteile & -klappen +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Ersatztasten & -knöpfe +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Fokusvorrichtungen für Kameras +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamera-Blitzgeräte +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamera-Blitzlichtzubehör +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamera-Fernbedienungen +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kameraausrüstungen +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamerafilme +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kameragurte +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamerahaltegriffe +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kameramonitore +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamerastabilisatoren und -stützen +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamerataschen & -koffer +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Kamerazubehör-Sets +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Schalldämmung & Sound Blimps für Kameras +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Sonnenschutz für Kameras & Sucheraufsätze +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Unterwassergehäuse für Kameras und Videokameras +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Videokameraleuchten +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Zoomkomponenten für Objektive +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Zubehör für Unterwasserkameragehäuse +Kameras & Optik > Kamera- & Optisches Zubehör > Kamerazubehör > Überwachungskamera-Zubehör +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Fernglas- & Fernrohrzubehör +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Taschen & Koffer für optische Instrumente +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Wärmebildzubehör +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Entferungsmesser +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Spektive +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Teleskope +Kameras & Optik > Kamera- & Optisches Zubehör > Optisches Zubehör > Zubehör für Zielfernrohre +Kameras & Optik > Kamera- & Optisches Zubehör > Stative +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Kameraobjektive +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Kameraobjektive > Objektiv- & Filteradapter +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Kameraobjektive > Objektivabdeckungen +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Kameraobjektive > Objektivfilter +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Kameraobjektive > Objektivkonverter +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Kameraobjektive > Objektivtaschen +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Kameraobjektive > Streulichtblenden +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Schellen & Halterungen für Stative +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Stativaufbewahrung +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Stativgriffe +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Stativköpfe +Kameras & Optik > Kamera- & Optisches Zubehör > Zubehör für Stative > Stativspinnen +Kameras & Optik > Kameras +Kameras & Optik > Kameras > Analogkameras +Kameras & Optik > Kameras > Boroskope +Kameras & Optik > Kameras > Digitalkameras +Kameras & Optik > Kameras > Einwegkameras +Kameras & Optik > Kameras > Videokameras +Kameras & Optik > Kameras > Webcams +Kameras & Optik > Kameras > Wildkameras +Kameras & Optik > Kameras > Überwachungskameras +Kameras & Optik > Optische Geräte +Kameras & Optik > Optische Geräte > Ferngläser +Kameras & Optik > Optische Geräte > Fernrohre +Kameras & Optik > Optische Geräte > Fernrohre > Spektive +Kameras & Optik > Optische Geräte > Fernrohre > Teleskope +Kameras & Optik > Optische Geräte > Fernrohre > Waffenspektive & Zielfernrohre +Kameras & Optik > Optische Geräte > Monokulare +Kameras & Optik > Optische Geräte > Optische Entfernungsmesser +Kunst & Unterhaltung +Kunst & Unterhaltung > Eintrittskarten +Kunst & Unterhaltung > Hobby & Kunst +Kunst & Unterhaltung > Hobby & Kunst > Jonglieren +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrung für Kunst- & Bastelmaterial +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrung für Kunst- & Bastelmaterial > Arbeitssets für Näh- und Textilkunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrung für Kunst- & Bastelmaterial > Aufbewahrung für Fäden & Garne +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Aufbewahrung für Kunst- & Bastelmaterial > Aufbewahrung für Näh-, Strick- & Häkelnadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Basteldraht +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Basteldraht > Blumendraht +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Basteldraht > Pfeifenreiniger +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Basteldraht > Schmuck- & Perlendraht +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke > Fixative +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke > Färbemittel für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke > Keramik- & Tonglasuren +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke > Kunst- & Bastelfarben +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke > Malgründe +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke > Stempelkissen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelfarben, -tinten & -lacke > Tinte für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelklebstoffe & -magnete +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelklebstoffe & -magnete > Aufbügelbänder +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelklebstoffe & -magnete > Bastel- & Büroklebstoff +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelklebstoffe & -magnete > Bastelmagnete +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelklebstoffe & -magnete > Blumenklebeband +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelklebstoffe & -magnete > Deko-Klebeband +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelwerkstoffe +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelwerkstoffe > Garne +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelwerkstoffe > Rohwolle +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelwerkstoffe > Schmuck- & Perlenband +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Bastelwerkstoffe > Zwirn +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Befestigungen & Verschlüsse +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Befestigungen & Verschlüsse > Klettverschlüsse +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Befestigungen & Verschlüsse > Knöpfe +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Befestigungen & Verschlüsse > Reißverschlussziehgriffe +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Befestigungen & Verschlüsse > Reißverschlüsse +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Befestigungen & Verschlüsse > Schnallen & Haken +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Befestigungen & Verschlüsse > Ösen & Tüllen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Dochte +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Dochthalter +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Formen & Rohlinge für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Formen & Rohlinge für Kunstarbeiten > Holz & Formen für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Formen & Rohlinge für Kunstarbeiten > Kranz- & Gesteckunterlagen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Formen & Rohlinge für Kunstarbeiten > Moosgummi & Styropor +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Formen & Rohlinge für Kunstarbeiten > Pappmaschee-Formen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Füllmaterial +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Füllmaterial > Füllgranulate +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Füllmaterial > Kissenformen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Füllmaterial > Wattierung & Füllung +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Leder & Vinyl +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten > Bastelfolie +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten > Bastelpapier +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten > Kartenkarton & Scrapbooking-Papier +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten > Origami-Papier +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten > Pergament +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten > Transferpapier +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Papier für Kunstarbeiten > Zeichen- & Malpapier +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Prägepuder +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Rohes Kerzenwachs +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien > Bastelleinwände +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien > Bastelleinwände > Leinwände & Keilrahmen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien > Bastelleinwände > Plastiksegeltuch +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien > Bastelleinwände > Stickleinwände +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien > Bedruckbare Gewebe +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien > Stoffe +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Textilien > Vlieseline +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Töpferei & Bildhauerei +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Töpferei & Bildhauerei > Engoben +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Töpferei & Bildhauerei > Gipsgewebe +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Töpferei & Bildhauerei > Modellierton & Modelliermasse +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Töpferei & Bildhauerei > Pappmaschee-Mischungen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Aufnäher +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Bänder & Einfassungen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Deko-Federn +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Dekorative Aufkleber +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Edelsteine +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Elastikbund +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Pailletten & Glitzer +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Perlen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Schleifen & Rosetten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Schmuck-Basisteile +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Strass & Deko-Elemente +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelmaterialien > Verzierungen & Trimmungen > Textilaufnäher & -aufbügler +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Bastelsets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Flicksets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Kerzenherstellungssets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Mosaikbausätze +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Schmuckherstellungssets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Scrapbooking- & Stempelsets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Sets für die Räucherwerkherstellung +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Sticksets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelsets > Zeichen- & Malsets +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Dekorationswerkzeuge für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Farbmischwerkzeuge +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Farbmischwerkzeuge > Farbpaletten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Farbmischwerkzeuge > Palettenmesser +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Filzpolster & -matten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Fingerhüte +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Klebepistolen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Leuchtkästen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Maschinen für Textilarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Maschinen für Textilarbeiten > Filznadeln & -maschinen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Maschinen für Textilarbeiten > Handwebstühle +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Maschinen für Textilarbeiten > Mechanische Webstühle +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Maschinen für Textilarbeiten > Nähmaschinen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Maschinen für Textilarbeiten > Spinnräder +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Handroller +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Holzbrennwerkzeuge +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Künstlerpinsel +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Maschenmarkierer & -zähler +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Motivstempel +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Schablonen & Matrizen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Schablonendruckmaschinen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Siebdruck-Rakel +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Textilkunst-Messgeräte +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Mess- & Markierwerkzeuge für Kunstarbeiten > Zeichenzirkel +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Näh-, Strick- & Häkelnadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Näh-, Strick- & Häkelnadeln > Häkelnadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Näh-, Strick- & Häkelnadeln > Knüpfhaken +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Näh-, Strick- & Häkelnadeln > Nähmaschinennadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Näh-, Strick- & Häkelnadeln > Nähnadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Näh-, Strick- & Häkelnadeln > Stricknadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Rahmen, Reifen & Spannvorrichtungen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Schneidematten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Schneiderpuppen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Sicherheitsnadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Spanndrähte +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Spannmatten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Bastel- & Büroscheren +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Bastelmesser +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Fadenabschneider +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Heißluftgeräte +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Nahttrenner +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Prägestifte +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Rill- & Perforiergeräte für Papier +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stanz- & Prägewerkzeuge für Kunstarbeiten > Stanzer & Präger für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Stecknadeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Faden- & Garnführer +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Faden- & Garnspulen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Faden- & Garnwickler +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Handspindeln +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Kardierer +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Nadeleinfädler +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Webschlagkämme +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Kunst- & Bastelwerkzeuge > Werkzeuge für die Faden- & Garnverarbeitung > Webschützen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Muster & Formen für Kunstarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Muster & Formen für Kunstarbeiten > Filzformen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Muster & Formen für Kunstarbeiten > Gießformen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Muster & Formen für Kunstarbeiten > Nähmuster +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Muster & Formen für Kunstarbeiten > Stick-, Strick- & Häkelmuster +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Muster & Formen für Kunstarbeiten > Vorlagen für Perlenarbeiten +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge > Ersatzteile für Nähmaschinen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge > Klingen für Bastelmesser +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge > Nähmaschinenfüße +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge > Nähmaschinengehäuse & -abdeckungen +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge > Spinnzubehör +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge > Stempelblöcke +Kunst & Unterhaltung > Hobby & Kunst > Kunsthandwerk & Hobby > Zubehör für Kunst- & Bastelwerkzeuge > Verlängerungstische für Nähmaschinen +Kunst & Unterhaltung > Hobby & Kunst > Modellbau +Kunst & Unterhaltung > Hobby & Kunst > Modellbau > Modellbausätze +Kunst & Unterhaltung > Hobby & Kunst > Modellbau > Modelleisenbahn & Eisenbahnsets +Kunst & Unterhaltung > Hobby & Kunst > Modellbau > Modelleisenbahnzubehör +Kunst & Unterhaltung > Hobby & Kunst > Modellbau > Modellraketen +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Akkordeons & Konzertinas +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Alt- & Baritonhörner +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Euphonien +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Posaunen +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Trompeten & Kornetts +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Tubas +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Blechblasinstrumente > Waldhörner +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Dudelsäcke +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > Audio-Sampler +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > MIDI-Controller +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > Musik-Keyboards +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Elektronische Musikinstrumente > Synthesizer +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Blechflöten +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Blockflöten +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Fagotte +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Flöten +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Kinderflöten +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Klarinetten +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Längsflöten & Panflöten +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Maultrommeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Melodicas +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Mundharmonikas +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Oboen +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Okarinas +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Saxophone +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Holzblasinstrumente > Zugpfeife +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Klaviere +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Bratschen +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Cellos +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Gitarren +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Harfen +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Kontrabässe +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Saiteninstrumente > Violinen +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Basstrommeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Becken +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Elektronische Schlagzeuge +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Glockenspiele & Xylophone +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Gongs +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Finger- & Handzimbeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handschellen & -glocken +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln > Beckentrommeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln > Bongos +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln > Cajons +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln > Congas +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln > Rahmentrommeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln > Sprechtrommeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Handtrommeln > Tablas +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Holzblöcke +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Kastagnetten +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Kuhglocken +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Rasseln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Scraper & Schnarren +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Tamburine +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Triangeln +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Handperkussionsinstrumente > Vibraslaps +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Hi-Hats +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Schlagzeuge +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Snaredrums +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Tom-Toms +Kunst & Unterhaltung > Hobby & Kunst > Musikinstrumente > Schlaginstrumente > Übungspads +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Autogramme +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Briefmarken +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Maßstabsmodelle +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Modellbau-Zubehör +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Münzen & Währungen +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Retro-Werbung +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammelkarten +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammlerwaffen +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammlerwaffen > Dekowaffen +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammlerwaffen > Sammlermesser +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammlerwaffen > Schwerter +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sammlerwaffen > Schwertständer & Schwerthalter +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > American Football-Fanartikel +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Baseball- & Softball-Fanartikel +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Basketball-Fanartikel +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Fußball-Fanartikel +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Hockey-Fanartikel +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Rennsport-Fanartikel +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sport-Fanartikel > Tennis-Fanzubehör +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > American Football-Artikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Baseball- & Softballartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Basketballartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Boxartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Fußballartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Hockeyartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Rennsportartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Sport-Sammelobjekte > Sportartikel mit Autogramm > Tennisartikel mit Autogramm +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Steine & Fossilien +Kunst & Unterhaltung > Hobby & Kunst > Sammlerstücke > Stempelsiegel +Kunst & Unterhaltung > Hobby & Kunst > Zauberbedarf +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Bier- & Weinherstellung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Bier- & Weinherstellung > Abfüllflaschen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Bier- & Weinherstellung > Brauzutaten +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Bier- & Weinherstellung > Sets zum Selbstherstellen von Bier & Wein +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Bier- & Weinherstellung > Weinherstellung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör > Keyboardständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör > Keyboardtaschen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Keyboardzubehör > Sustain-Pedale +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Klavierbänke & Musikerhocker +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Marschgabeln und Notenhalter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Metronome +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Notenständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Dämpfer für Schlagzeug & Becken +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Module für elektronische Schlagzeuge +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware > Beater +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware > Fußmaschinen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeug-Hardware > Schlagzeughalterungen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeugfelle +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Schlagzeugkoffer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Sticks & Besen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Stimmschlüssel +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Ständer für Perkussionsinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Trommelschlägel +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Handperkussionsinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Handperkussionsinstrumente > Ständer für Handperkussionsinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Handperkussionsinstrumente > Taschen für Handperkussionsinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Sticks & Besen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Schlagzeugzubehör > Zubehör für Sticks & Besen > Taschen für Sticks & Besen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Stimmgeräte +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente > Beleuchtung für Instrumentenständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente > Notenklemmen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Ständer für Musikinstrumente > Taschen für Instrumentenständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Taktstöcke +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärker für Musikinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkerzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkerzubehör > Ständer für Verstärker +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkerzubehör > Verstärker-Fußschalter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkerzubehör > Verstärkerabdeckungen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkerzubehör > Verstärkergehäuse +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkerzubehör > Verstärkerknöpfe +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Verstärkerzubehör > Verstärkerröhren +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Aufhängungen & Ständer für Blechinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Klappenöl für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Pflegesets für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Poliertücher für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Reinigungs- & Desinfektionsmittel für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Reinigungswerkzeug für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Blechblasinstrumentenpflege &-reinigung > Schutzvorrichtungen für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Dämpfer für Blechinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Ersatzteile für Blechblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Koffer & Gigbags für Blechinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Blechblasinstrumente > Mundstücke für Blechinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Blockflötenzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Blockflötenzubehör > Blockflötenkoffer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Blockflötenzubehör > Blockflötenteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Blockflötenzubehör > Pflege- & Reinigungsmittel für Blockflöten +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Blätteretui für Holzblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottblattmesser +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottblätter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottpflege & -reinigung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottpflege & -reinigung > Fagottreinigungstücher +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottriemen & -stützen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottteile > Fagott-S-Bögen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Fagottteile > Kleinere Fagottzubehörteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Fagottzubehör > Koffer & Transporttaschen für Fagotte +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenhalter & -ständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung > Flötenpflegesets +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung > Flötenreinigungsstab +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenpflege & -reinigung > Flötenreinigungstücher +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenteile > Flötenkopfstücke +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Flötenteile > Kleinere Flötenzubehörteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Flötenzubehör > Koffer & Transporttaschen für Flöten +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Blattschrauben & Kappen für Klarinetten +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenblätter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenhalter/-ständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung > Klarinettenklappenschutz +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung > Klarinettenpflegesets +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenpflege &-reinigung > Klarinettenreinigungstücher +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenriemen & -stützen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Klarinettenbirnen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Klarinettenmundstücke +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Klarinettentrichter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Klarinettenteile > Kleinere Klarinettenzubehörteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Klarinettenzubehör > Koffer & Transporttaschen für Klarinetten +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Korkfett für Holzblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Mundharmonikazubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Mundharmonikazubehör > Mundharmonika-Etuis +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Mundharmonikazubehör > Mundharmonikahalter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Koffer & Transporttaschen für Oboen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenblätter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenhalter & -ständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenpflege & -reinigung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenpflege & -reinigung > Oboenpflegesets +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenpflege & -reinigung > Oboenreinigungstücher +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenriemen & -stützen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Oboenzubehör > Oboenteile > Kleinere Oboenzubehörteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Poliertücher für Holzblasinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Blattschrauben & Kappen für Saxophone +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Koffer & Transporttaschen für Saxophone +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Rohrblätter für Saxophone +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonhalter & -ständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung > Saxophonklappenschutz +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung > Saxophonpflegesets +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonpflege &-reinigung > Saxophonreinigungstücher +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonriemen/-stützen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile > Kleinere Saxophonzubehörteile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile > Mundstücke für Saxophone +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Holzblasinstrumente > Zubehör für Saxophone > Saxophonteile > Saxophonhälse +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarren-Slides +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenbefeuchter +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrengurte +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenkoffer & -taschen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenplektren +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrensaiten +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrensaitenspanner +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenstimmwirbel +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenständer +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Gitarrenzubehör & -teile +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Kapodaster +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Tonabnehmer für Akustikgitarren +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Gitarrenzubehör > Tonabnehmer für E-Gitarren +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung > Bogenharz +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung > Politur für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Saiteninstrumentenpflege &-reinigung > Reinigungstücher für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Bogenkästen für Streichinstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Bögen für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Dämpfer für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Koffer für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Saiten für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Ständer für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Tonabnehmer für Saiteninstrumente +Kunst & Unterhaltung > Hobby & Kunst > Zubehör für Musikinstrumente > Zubehör für Saiteninstrumente > Zubehör für Streichinstrumente & Harfen > Zubehör & Ersatzteile für Saiteninstrumente +Kunst & Unterhaltung > Party & Feiern +Kunst & Unterhaltung > Party & Feiern > Partyzubehör +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Antwortkarten +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Aufblasbare Partydeko +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Ballon-Sets +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Banner +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Briefsiegel +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Cocktaildekorationen +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Dekorative Pompons +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Einladungskarten +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Eventprogramme +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Feuerwerkskörper +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Geburtstagskerzen +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Halter für Karten zu besonderen Anlässen +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Konfetti +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Luftballons +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Luftschlangenspray +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyartikel +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyartikel > Kleine Geschenke für Hochzeitsgäste +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partygirlanden & -vorhänge +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyhüte +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyspiele +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Partyzubehörsets +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Piñatas +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Platzkarten +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Platzkartenhalter +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Spruchkarten +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Stuhlbezüge +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkhalme & Rührer +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkspiele +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkspiele > Bierpong +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Trinkspiele > Bierpong > Bierpong-Tische +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Tröten, Luftrüssel & Krachmacher +Kunst & Unterhaltung > Party & Feiern > Partyzubehör > Wunderkerzen +Kunst & Unterhaltung > Party & Feiern > Schenken +Kunst & Unterhaltung > Party & Feiern > Schenken > Anstecksträußchen +Kunst & Unterhaltung > Party & Feiern > Schenken > Befestigungsnadeln für Anstecksträußchen +Kunst & Unterhaltung > Party & Feiern > Schenken > Frische Schnittblumen +Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkgutscheine +Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen +Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Geschenkanhänger +Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Geschenkboxen & -dosen +Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Geschenkpapier +Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Geschenktaschen +Kunst & Unterhaltung > Party & Feiern > Schenken > Geschenkverpackungen > Seidenpapier +Kunst & Unterhaltung > Party & Feiern > Schenken > Grußkarten +Kunst & Unterhaltung > Party & Feiern > Trophäen & Preise +Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte +Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Diskokugeln +Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Lichteffektbeleuchtung +Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Lichtmischpulte +Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Nebelmaschinen +Kunst & Unterhaltung > Party & Feiern > Visuelle Effekte > Ständer für Lichteffektbeleuchtung +Medien +Medien > Baupläne für Tischler- und Holzarbeiten +Medien > Bücher +Medien > DVDs & Videos +Medien > Musik & Tonaufnahmen +Medien > Notenblätter +Medien > Produkthandbücher & Gebrauchsanleitungen +Medien > Produkthandbücher & Gebrauchsanleitungen > Bürobedarf-Handbücher +Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Elektrogeräte +Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Elektrowerkzeuge +Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Haushaltsgeräte +Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Küchengeräte +Medien > Produkthandbücher & Gebrauchsanleitungen > Handbücher für Modellbau und Spielzeuge +Medien > Produkthandbücher & Gebrauchsanleitungen > Kamera- & Optikhandbücher +Medien > Produkthandbücher & Gebrauchsanleitungen > Kfz-Handbücher +Medien > Produkthandbücher & Gebrauchsanleitungen > Sport- & Freizeithandbücher +Medien > Zeitschriften & Zeitungen +Möbel +Möbel > Baby- & Kleinkindmöbel +Möbel > Baby- & Kleinkindmöbel > Gitter- & Kinderbettzubehör +Möbel > Baby- & Kleinkindmöbel > Gitter- & Kinderbettzubehör > Bettnestchen & Randschutz für Gitterbetten +Möbel > Baby- & Kleinkindmöbel > Gitter- & Kinderbettzubehör > Umbausätze für Gitterbetten +Möbel > Baby- & Kleinkindmöbel > Gitterbetten & Kleinkinderbetten +Möbel > Baby- & Kleinkindmöbel > Hochstühle & Sitzerhöhungen +Möbel > Baby- & Kleinkindmöbel > Möbelgarnituren für Babies & Kleinkinder +Möbel > Baby- & Kleinkindmöbel > Wickeltische +Möbel > Baby- & Kleinkindmöbel > Wiegen & Stubenwagen +Möbel > Baby- & Kleinkindmöbel > Wiegen- & Stubenwagenzubehör +Möbel > Baby- & Kleinkindmöbel > Zubehör für Hochstühle und Sitzerhöhungen +Möbel > Betten & Zubehör +Möbel > Betten & Zubehör > Bett- & Bettrahmenzubehör +Möbel > Betten & Zubehör > Betten & Bettgestelle +Möbel > Betten & Zubehör > Kopf- & Fußenden +Möbel > Betten & Zubehör > Matratzen +Möbel > Betten & Zubehör > Matratzen-Untergestelle +Möbel > Büromöbel +Möbel > Büromöbel > Arbeitsplätze im Großraumbüro +Möbel > Büromöbel > Arbeitstische +Möbel > Büromöbel > Arbeitstische > Konferenztische +Möbel > Büromöbel > Arbeitstische > Verstellbare Zeichentische +Möbel > Büromöbel > Büro- & Schreibtischstühle +Möbel > Büromöbel > Büromöbelgarnituren +Möbel > Büromöbel > Schreibtische +Möbel > Futonauflagen +Möbel > Futonrahmen +Möbel > Futons +Möbel > Gartenmöbel +Möbel > Gartenmöbel > Aufbewahrungsbehälter für draußen +Möbel > Gartenmöbel > Gartenbetten +Möbel > Gartenmöbel > Gartenhocker +Möbel > Gartenmöbel > Gartenmöbelgarnituren +Möbel > Gartenmöbel > Gartensitzmöbel +Möbel > Gartenmöbel > Gartensitzmöbel > Gartenbänke +Möbel > Gartenmöbel > Gartensitzmöbel > Gartensofaelemente +Möbel > Gartenmöbel > Gartensitzmöbel > Gartensofas +Möbel > Gartenmöbel > Gartensitzmöbel > Gartenstühle +Möbel > Gartenmöbel > Gartensitzmöbel > Sonnenliegen +Möbel > Gartenmöbel > Gartentische +Möbel > Gartenmöbelzubehör +Möbel > Gartenmöbelzubehör > Abdeckungen für Gartenmöbel +Möbel > Kücheninseln & Küchenwagen +Möbel > Kücheninseln & Küchenwagen > Kücheninseln +Möbel > Kücheninseln & Küchenwagen > Küchenwagen +Möbel > Möbel für Unterhaltungselektronik +Möbel > Möbelgarnituren +Möbel > Möbelgarnituren > Badezimmergarnituren +Möbel > Möbelgarnituren > Küchen- & Esszimmergarnituren +Möbel > Möbelgarnituren > Schlafzimmergarnituren +Möbel > Möbelgarnituren > Wohnzimmergarnituren +Möbel > Polsterhocker +Möbel > Raumteiler +Möbel > Raumteilerzubehör +Möbel > Regalsysteme +Möbel > Regalsysteme > Bücherregale & Bücherschränke +Möbel > Regalsysteme > Wandregale & Simse +Möbel > Regalzubehör +Möbel > Regalzubehör > Ersatzregale +Möbel > Schränke +Möbel > Schränke > Aktenschränke +Möbel > Schränke > Aufbewahrungstruhen +Möbel > Schränke > Aufbewahrungstruhen > Aussteuertruhen +Möbel > Schränke > Aufbewahrungstruhen > Spielzeugtruhen +Möbel > Schränke > Buffets & Sideboards +Möbel > Schränke > Bügelcenter +Möbel > Schränke > Büroschränke +Möbel > Schränke > Geschirrschränke +Möbel > Schränke > Kleiderschränke +Möbel > Schränke > Kommoden +Möbel > Schränke > Küchenschränke +Möbel > Schränke > Mediaaufbewahrung +Möbel > Schränke > Spirituosenschränke +Möbel > Schränke > Wasch- und Schminktische +Möbel > Schränke > Wasch- und Schminktische > Badezimmerwaschtische +Möbel > Schränke > Wasch- und Schminktische > Schminktische +Möbel > Schränke > Weinregale +Möbel > Schränke > Zeitschriftenständer +Möbel > Sitzbänke +Möbel > Sitzbänke > Küchen- & Eckbänke +Möbel > Sitzbänke > Schminktischhocker +Möbel > Sitzbänke > Truhen- & Flurbänke +Möbel > Sofa-Zubehör +Möbel > Sofa-Zubehör > Anbausofas +Möbel > Sofa-Zubehör > Sitzverstärkung für Stühle & Sofas +Möbel > Sofas +Möbel > Stuhlzubehör +Möbel > Stuhlzubehör > Ersatzteile für Hängesessel +Möbel > Stühle +Möbel > Stühle > Bodenstühle +Möbel > Stühle > Elektrische Massagesessel +Möbel > Stühle > Hocker & Barhocker +Möbel > Stühle > Hängesessel +Möbel > Stühle > Klappstühle & Holzhocker +Möbel > Stühle > Küchen- und Esszimmerstühle +Möbel > Stühle > Liegemöbel +Möbel > Stühle > Multimediasessel +Möbel > Stühle > Schaukelstühle +Möbel > Stühle > Sessel +Möbel > Stühle > Sessel ohne Armlehnen +Möbel > Stühle > Sitzsäcke +Möbel > Tische +Möbel > Tische > Kinderspieltische +Möbel > Tische > Klapptische +Möbel > Tische > Kotatsu +Möbel > Tische > Küchen- & Esszimmertische +Möbel > Tische > Nachttische +Möbel > Tische > Nähmaschinentische +Möbel > Tische > Poker- & Spieltische +Möbel > Tische > Ziertische +Möbel > Tische > Ziertische > Beistelltische +Möbel > Tische > Ziertische > Couchtische +Möbel > Tische > Ziertische > Konsolentische +Möbel > Tischzubehör +Möbel > Tischzubehör > Tischbeine +Möbel > Tischzubehör > Tischplatten +Möbel > Zubehör für Büromöbel +Möbel > Zubehör für Büromöbel > Bürostuhl-Zubehör +Möbel > Zubehör für Büromöbel > Schreibtischteile & -zubehör +Möbel > Zubehör für Büromöbel > Zubehör für Arbeitsplätze im Großraumbüro +Nahrungsmittel, Getränke & Tabak +Nahrungsmittel, Getränke & Tabak > Getränke +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Alkopops +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Bier +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Cidre +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Cocktail-Bitter +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Cocktail-Premix +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Absinth +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Gin +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Liköre +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Rum +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Shochu & Soju +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Tequila +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Weinbrand +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Whiskey +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Liköre & Spirituosen > Wodka +Nahrungsmittel, Getränke & Tabak > Getränke > Alkoholische Getränke > Wein +Nahrungsmittel, Getränke & Tabak > Getränke > Buttermilch +Nahrungsmittel, Getränke & Tabak > Getränke > Eierlikör +Nahrungsmittel, Getränke & Tabak > Getränke > Essighaltige Getränke +Nahrungsmittel, Getränke & Tabak > Getränke > Getränke mit Fruchtgeschmack +Nahrungsmittel, Getränke & Tabak > Getränke > Getränkepulver +Nahrungsmittel, Getränke & Tabak > Getränke > Kaffee +Nahrungsmittel, Getränke & Tabak > Getränke > Kakao +Nahrungsmittel, Getränke & Tabak > Getränke > Limonaden +Nahrungsmittel, Getränke & Tabak > Getränke > Milch +Nahrungsmittel, Getränke & Tabak > Getränke > Nicht-tierische Milch +Nahrungsmittel, Getränke & Tabak > Getränke > Saft +Nahrungsmittel, Getränke & Tabak > Getränke > Sportgetränke & Energy Drinks +Nahrungsmittel, Getränke & Tabak > Getränke > Tees & Aufgüsse +Nahrungsmittel, Getränke & Tabak > Getränke > Wasser +Nahrungsmittel, Getränke & Tabak > Lebensmittel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Backwaren-Mischungen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Bagels +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Brot & Brötchen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Cupcakes +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Donuts +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Eistüten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Feingebäck +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Karamell-Fudge +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Kuchen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Kuchen zum Kaffee +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Muffins +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Pasteten & Torten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Plätzchen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Tacoschalen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Backwaren > Tortillas & Wraps +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Delikatessen Präsentkörbe +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Apfelbutter +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Frischkäse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Gemüsedip +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Guacamole +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Hummus +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Käse-Dips & -aufstriche +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Marmeladen & Gelees +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Nussbutter +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Salsa-Saucen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Dips & Brotaufstriche > Tapenade +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertige Mahlzeiten und Hauptgerichte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fertiggerichte > Fertige Vorspeisen und Beilagen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Eier +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fisch & Meeresfrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fisch & Meeresfrüchte > Fisch- & Meeresfrüchtekonserven +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fisch & Meeresfrüchte > Frische(r) & tiefgefrorene(r) Fisch/Meeresfrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Fleisch- & Wurstwaren +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Fleischkonserven +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Fleisch, Fisch, Meeresfrüchte & Eier > Fleisch > Frisches & Tiefgefrorenes Fleisch +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backaromen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backfett & Schmalz +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backmischungen für Waffeln und Pfannkuchen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backpulver +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backsoda +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Backwaren-Deko-Sets +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Blockschokoloade +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Bohnenpasten & -saucen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Dosen- und Trockenmilch +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Essbare Backdekoration +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Essig +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Gemahlene Getreideprodukte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Geschmacksneutrale Gelatine +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Hefe +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Kochwein +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Kuchen- & Pastetenfüllungen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Lebensmittelfarben +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Maissirup +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Maisstärke +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Marshmallows +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Mehl +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Melasse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Paniermehl +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Raspeln, Flocken & Tröpfchen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Speiseöle +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Starterkulturen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Stärkemehl & Paniermischungen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Tapiokaperlen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig > Brot- & Gebäckteig +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig > Pastetenteig +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Teig > Plätzchen- & Brownieteig +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Tomatenmark +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Zitronen- und Limettensaft +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Zucker & Süßstoffe +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Zuckerguss & Glasur +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Koch- & Backzutaten > Zuckerwatte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Amarant +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Buchweizen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Couscous +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Frühstücksflocken & Müsli +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Gerste +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Haferflocken, Grütze & Grieß +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Hirse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Quinoa +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Reis +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Roggen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Körner, Reis & Getreide > Weizen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Butter & Margarine +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Hüttenkäse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Joghurt +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Kaffeeweißer +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Käse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Sahne +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Sauerrahm +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Milchprodukte > Schlagsahne +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Nüsse & Samen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Dosenbohnen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Arakachas +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Artischocken +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Auberginen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Choi Sum +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Gartensalat +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Grünkohl +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Mangold +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Pak Choi +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Rauke +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Rübenblätter +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Salatmischungen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Spinat +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Wasserspinat +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Wegwarte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blattgemüse > Yu Choy +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Blumenkohl +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Bohnen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Borretsch +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Brokkoli +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Chinesischer Brokkoli +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Erbsen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Farnspitzen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Fenchelknollen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Gemüsemischungen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Gobo-Wurzel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Gurken +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Ingwer +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kaktusblätter +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kartoffeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Knoblauch +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kohl +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kohlrabi +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Kürbisse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Lotoswurzel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Mais +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Maniok +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Möhren +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Okra +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Paprikaschoten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Pastinaken +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Petersilienwurzeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Pilze +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Porree +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Radieschen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rettich +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rhabarber +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rosenkohl +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rutenkohl +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Rüben +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Schalotten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Sellerie +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Sellerieknollen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Spanische Artischocken +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Spargel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Sprossen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Steckrüben & Kohlrüben +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Süßkartoffeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tamarillos +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tannias +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tarowurzeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Tomaten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Topinambur +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wasserkastanien +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Wasserkresse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Weizengras +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Yambohnen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Yams +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Zuckerrohr +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Gemüse > Zwiebeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Ananas +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Atemoyas +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Avocados +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Bananen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Beeren +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Berg-Papayas +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Birnen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Brasilianische Guaven +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Breiäpfel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Brotfrucht +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Cherimoyas +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Datteln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Feigen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Granatäpfel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Große Sapoten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Guaven +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Homli-Früchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kaktusfeigen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kiwis +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Kokosnüsse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Longan +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Loquats +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Lychees +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Madrono-Früchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Mangostanfrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Melonen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Obstmischungen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Papayas +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Passionsfrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Persimonen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Physalis +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Pitahayas +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Quitten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Rambutans +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Sapoten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Stachelannonen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Steinfrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Steinfrüchte > Aprikosen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Steinfrüchte > Kirschen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Steinfrüchte > Mangos +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Steinfrüchte > Pfirsiche & Nektarinen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Steinfrüchte > Pflaumen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Steinfrüchte > Plumcots +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Sternfrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Tamarinden +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Trauben +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zimtäpfel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte > Grapefruits +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte > Kumquats +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte > Limequats +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte > Limetten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte > Orangen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte > Tangelos +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Zitrusfrüchte > Zitronen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Frisches & Tiefgefrorenes Obst > Äpfel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Fruchtsoßen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Gemüsekonserven +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Getrocknete Bohnen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Getrocknete Früchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Obstkonserven +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Obst & Gemüse > Trockengemüse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Pasta & Nudeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Schokofrüchte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Suppen & Brühen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Süßigkeiten & Schokolade +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Eissnacks +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Speiseeis und gefrorener Joghurt +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tiefkühl-Desserts & -Neuheiten > Stieleis +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Fleischalternativen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Käsealternativen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Seitan +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Tempeh +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Tofu- & Soja-Produkte > Tofu +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Brezeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Chips +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Croûtons +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Dessertküchlein +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Fruchtsnacks +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Getreide- & Müsliriegel +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Grissini +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Kräcker +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Käse-Flips +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Popcorn +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Pudding & Gelatine-Snacks +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Reiskuchen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Reiswaffeln +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Salatgarnituren +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Schweineschwarten +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Sesamsticks +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Studentenfutter +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Vorspeisen & Snacks > Trockenfleisch +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Kräuter & Gewürze +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Mononatriumglutamat +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Pfeffer +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzen & Verfeinern > Salz +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Bratensoße +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Chilisauce +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Cocktailsaucen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Currysauce +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Dessertsaucen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Dessertsaucen > Eissaucen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Dessertsaucen > Fruchttopping +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Eingelegtes Obst und Gemüse +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Fischsauce +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Honig +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Ketchup +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Marinaden und Grillsoßen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Mayonnaise +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Meerrettichsaucen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Oliven & Kapern +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Pastasoßen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Pizzasoße +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Salatdressing +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sataysauce +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sauce tartare +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Senf +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sirup +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Sojasauce +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Süßsaure Soßen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Tahini +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Weiße Soßen und Rahmsoßen +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Worcestershiresauce +Nahrungsmittel, Getränke & Tabak > Lebensmittel > Würzmittel & Saucen > Würzsoße und Chutney +Nahrungsmittel, Getränke & Tabak > Tabakprodukte +Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Kautabak +Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Pfeifen +Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Tabak +Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Vaporizer & Rauchlose Zigaretten +Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Zigaretten +Nahrungsmittel, Getränke & Tabak > Tabakprodukte > Zigarren +Religion & Feierlichkeiten +Religion & Feierlichkeiten > Artikel für Gedenkzeremonien +Religion & Feierlichkeiten > Artikel für Gedenkzeremonien > Urnen +Religion & Feierlichkeiten > Artikel für Hochzeitszeremonien +Religion & Feierlichkeiten > Artikel für Hochzeitszeremonien > Hochzeitsläufer +Religion & Feierlichkeiten > Artikel für Hochzeitszeremonien > Körbe für Blumenmädchen +Religion & Feierlichkeiten > Artikel für Hochzeitszeremonien > Ringkissen +Religion & Feierlichkeiten > Religiöse Artikel +Religion & Feierlichkeiten > Religiöse Artikel > Altare +Religion & Feierlichkeiten > Religiöse Artikel > Gebetskarten +Religion & Feierlichkeiten > Religiöse Artikel > Gebetsketten +Religion & Feierlichkeiten > Religiöse Artikel > Religiöse Schleier +Religion & Feierlichkeiten > Religiöse Artikel > Tarotkarten +Software +Software > Computersoftware +Software > Computersoftware > Antiviren- & Sicherheitssoftware +Software > Computersoftware > Betriebssysteme +Software > Computersoftware > Büroanwendungssoftware +Software > Computersoftware > Compiler & Programmierungstools +Software > Computersoftware > Computerdienstprogramme & -wartung +Software > Computersoftware > GPS-Karten & -Software +Software > Computersoftware > Handheld- & PDA-Software +Software > Computersoftware > Lernsoftware +Software > Computersoftware > Netzwerksoftware +Software > Computersoftware > Software für Multimedia & Design +Software > Computersoftware > Software für Multimedia & Design > Animationsbearbeitungssoftware +Software > Computersoftware > Software für Multimedia & Design > Graphic-Design-Software +Software > Computersoftware > Software für Multimedia & Design > Home-Publishing-Software +Software > Computersoftware > Software für Multimedia & Design > Software für Musikkomposition +Software > Computersoftware > Software für Multimedia & Design > Software zur Erstellung von 3D-Modellen +Software > Computersoftware > Software für Multimedia & Design > Software zur Innenraumgestaltung +Software > Computersoftware > Software für Multimedia & Design > Software zur Medienwiedergabe +Software > Computersoftware > Software für Multimedia & Design > Tonbearbeitungssoftware +Software > Computersoftware > Software für Multimedia & Design > Videobearbeitungssoftware +Software > Computersoftware > Software für Multimedia & Design > Web-Design-Software +Software > Computersoftware > Steuer- & Buchhaltungssoftware +Software > Computersoftware > Unternehmens- & Produktivitätssoftware +Software > Computersoftware > Wiederherstellungsdatenträger +Software > Computersoftware > Wörterbuch- & Übersetzungssoftware +Software > Digital-Content-Software +Software > Digital-Content-Software > Computer-Icons +Software > Digital-Content-Software > Desktop-Hintergrundbilder +Software > Digital-Content-Software > Digitales Bildmaterial +Software > Digital-Content-Software > Dokumentvorlagen +Software > Digital-Content-Software > Fonts +Software > Digital-Content-Software > Stock-Fotografie & Videoclips +Software > Digital-Content-Software > Virtuelles Geld +Software > PC- & Videospiele +Spielzeuge & Spiele +Spielzeuge & Spiele > Puzzles & Geduldspiele +Spielzeuge & Spiele > Puzzles & Geduldspiele > Holzsteckpuzzle +Spielzeuge & Spiele > Puzzles & Geduldspiele > Mechanische Geduldspiele +Spielzeuge & Spiele > Puzzles & Geduldspiele > Puzzle-Zubehör +Spielzeuge & Spiele > Puzzles & Geduldspiele > Puzzles +Spielzeuge & Spiele > Spiel-Timer +Spielzeuge & Spiele > Spiele +Spielzeuge & Spiele > Spiele > Battle Tops +Spielzeuge & Spiele > Spiele > Bingo-Spiele +Spielzeuge & Spiele > Spiele > Blackjack- & Würfelspiel-Sets +Spielzeuge & Spiele > Spiele > Brettspiele +Spielzeuge & Spiele > Spiele > Geschicklichkeitsspiele +Spielzeuge & Spiele > Spiele > Glücksspielautomaten +Spielzeuge & Spiele > Spiele > Kampfkreiselzubehör +Spielzeuge & Spiele > Spiele > Kartenspiele +Spielzeuge & Spiele > Spiele > Kartenspielzubehör +Spielzeuge & Spiele > Spiele > Legespiele +Spielzeuge & Spiele > Spiele > Pokerchip-Zubehör +Spielzeuge & Spiele > Spiele > Pokerchip-Zubehör > Behälter für Pokerchips +Spielzeuge & Spiele > Spiele > Pokerchips & -sets +Spielzeuge & Spiele > Spiele > Rouletteräder & -zubehör +Spielzeuge & Spiele > Spiele > Tragbare elektronische Spiele +Spielzeuge & Spiele > Spiele > Würfelsets & -spiele +Spielzeuge & Spiele > Spielzeug für draußen +Spielzeuge & Spiele > Spielzeug für draußen > Hüpfburg-Zubehör +Spielzeuge & Spiele > Spielzeug für draußen > Hüpfburgen +Spielzeuge & Spiele > Spielzeug für draußen > Rutschen +Spielzeuge & Spiele > Spielzeug für draußen > Sandkästen +Spielzeuge & Spiele > Spielzeug für draußen > Schaukeln +Spielzeuge & Spiele > Spielzeug für draußen > Schaukeln & Spielplatzgeräte +Spielzeuge & Spiele > Spielzeug für draußen > Spielhäuser +Spielzeuge & Spiele > Spielzeug für draußen > Spielzelte & -tunnel +Spielzeuge & Spiele > Spielzeug für draußen > Springstöcke +Spielzeuge & Spiele > Spielzeug für draußen > Stelzen +Spielzeuge & Spiele > Spielzeug für draußen > Trampoline +Spielzeuge & Spiele > Spielzeug für draußen > Trampolinzubehör +Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte +Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte > Planschbecken und Wasserrutschen +Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte > Wassersprenger für Kinder +Spielzeuge & Spiele > Spielzeug für draußen > Wasserspielgeräte > Wassertische +Spielzeuge & Spiele > Spielzeug für draußen > Wippen +Spielzeuge & Spiele > Spielzeug für draußen > Zubehör für Schaukeln & Spielplatzgeräte +Spielzeuge & Spiele > Spielzeuge +Spielzeuge & Spiele > Spielzeuge > Aufziehspielzeug +Spielzeuge & Spiele > Spielzeuge > Bad-Spielzeug +Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug +Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Baukästen +Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Holzbausteine +Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Murmelbahnen +Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Schaumstoffbausteine +Spielzeuge & Spiele > Spielzeuge > Bausteine & Bauspielzeug > Steckbausteine +Spielzeuge & Spiele > Spielzeuge > Bällebad-Zubehör +Spielzeuge & Spiele > Spielzeuge > Bällebad-Zubehör > Bälle für Bällebad +Spielzeuge & Spiele > Spielzeuge > Bällebäder +Spielzeuge & Spiele > Spielzeuge > Bürospielzeug +Spielzeuge & Spiele > Spielzeuge > Bürospielzeug > Magnetspielzeug +Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug +Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Elektrische Kinderfahrzeuge +Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Hand- & Bollerwagen +Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Schiebe- & Pedalfahrzeuge +Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Steckenpferde +Spielzeuge & Spiele > Spielzeuge > Fahr, Wipp- & Schaukelspielzeug > Wipp- & Schaukelspielzeug +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Autos +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Boote +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Flugzeuge +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Hubschrauber +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Motorräder +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Panzer +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Roboter +Spielzeuge & Spiele > Spielzeuge > Ferngesteuertes Spielzeug > Ferngesteuerte Zeppeline +Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug +Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Drachen +Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Luft- & Wasserraketen +Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Spielzeug-Fallschirme +Spielzeuge & Spiele > Spielzeuge > Fliegendes Spielzeug > Spielzeug-Segelflugzeuge +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Ball- & Becherspiele +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Flummis +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Hampelmänner +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Jo-Jos +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Kreisel +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Murmeln +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Paddleball-Spiele +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Seifenblasen +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Seifenblasen-Spielzeug +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Spiele mit Bändern +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Springspirale +Spielzeuge & Spiele > Spielzeuge > Interaktives Spielzeug > Teile und Zubehör für Jo-Jos +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Berufespielzeug & Rollenspiele +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Einkaufsladen +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Elektronisches Rollenspielzeug +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Gartengeräte für Kinder +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Haushaltsspielzeug +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Spielgeld & Banken +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Spielwerkzeug +Spielzeuge & Spiele > Spielzeuge > Kinder-Rollenspiele > Spielzeugküchen & Spielzeuglebensmittel +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Ameisenfarmen +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Astronomisches Spielzeug und astronomische Modelle +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Insektensammlung +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Lernkarten +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Lesespiele +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Schieberechner +Spielzeuge & Spiele > Spielzeuge > Lernspielzeug > Wissenschaftssets +Spielzeuge & Spiele > Spielzeuge > Musikspielzeuge +Spielzeuge & Spiele > Spielzeuge > Musikspielzeuge > Spielzeuginstrumente +Spielzeuge & Spiele > Spielzeuge > Optische Spielzeuge +Spielzeuge & Spiele > Spielzeuge > Optische Spielzeuge > Kaleidoskope +Spielzeuge & Spiele > Spielzeuge > Optische Spielzeuge > Prismen +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Action- & Spielzeugfiguren +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Marionetten +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Papier- & Magnetpuppen +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppen +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppenhaus-Zubehör +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppenhäuser +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Puppentheater +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Spielzeugsets +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Stofftiere +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Wackelfiguren +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Zubehör für Puppen & Actionfiguren +Spielzeuge & Spiele > Spielzeuge > Puppen, Spielkombinationen & Spielzeugfiguren > Zubehör für Puppen & Puppentheater +Spielzeuge & Spiele > Spielzeuge > Roboter +Spielzeuge & Spiele > Spielzeuge > Spielfahrzeug-Zubehör +Spielzeuge & Spiele > Spielzeuge > Spielzeug-Geschenkkörbe +Spielzeuge & Spiele > Spielzeuge > Spielzeuge zum Malen & Zeichnen +Spielzeuge & Spiele > Spielzeuge > Spielzeuge zum Malen & Zeichnen > Spielteig & Knetmasse +Spielzeuge & Spiele > Spielzeuge > Spielzeuge zum Malen & Zeichnen > Zeichentafeln +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Rennbahnen +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeug-LKWs & -Baumaschinen +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugautos +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugboote +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugflugzeuge +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeughubschrauber +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugmotorräder +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Spielzeugraumschiffe +Spielzeuge & Spiele > Spielzeuge > Spielzeugfahrzeuge > Züge & Eisenbahnsets +Spielzeuge & Spiele > Spielzeuge > Spielzeugwaffen +Spielzeuge & Spiele > Spielzeuge > Spielzeugwaffenzubehör +Spielzeuge & Spiele > Spielzeuge > Sportspielzeug-Zubehör +Spielzeuge & Spiele > Spielzeuge > Sportspielzeug-Zubehör > Fitnessspielzeug-Zubehör +Spielzeuge & Spiele > Spielzeuge > Sportspielzeug-Zubehör > Fitnessspielzeug-Zubehör > Hula-Hoop-Zubehör +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Angelspielzeug +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Baseball für Kinder +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Basketball für Kinder +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Bowling für Kinder +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Bumerangs +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Fingerboards & Fingerboard-Sets +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Fitness-Spielzeug +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Fitness-Spielzeug > Hula-Hoop-Reifen +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Footbags +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Frisbees +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Fußball für Kinder +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Golf für Kinder +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Hockey für Kinder +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Kinderspielbälle +Spielzeuge & Spiele > Spielzeuge > Sportspielzeuge > Spielzeugschläger +Spielzeuge & Spiele > Spielzeuge > Strand- & Sandspielzeug +Spielzeuge & Spiele > Spielzeuge > Zubehör für Flugspielzeug +Spielzeuge & Spiele > Spielzeuge > Zubehör für Flugspielzeug > Zubehör für Drachen +Spielzeuge & Spiele > Spielzeuge > Zubehör für Flugspielzeug > Zubehör für Drachen > Wickelspulen für Drachen +Spielzeuge & Spiele > Spielzeuge > Zubehör für Spielzeugfahrzeuge +Spielzeuge & Spiele > Spielzeuge > Zubehör für Spielzeugfahrzeuge > Autorennbahn-Zubehör +Spielzeuge & Spiele > Spielzeuge > Zubehör für Spielzeugfahrzeuge > Zubehör für Spielzeugeisenbahn +Spielzeuge & Spiele > Spielzeuge > Zubehör für ferngesteuerte Fahrzeuge +Sportartikel +Sportartikel > Athletik +Sportartikel > Athletik > Allgemeine Sportartikel +Sportartikel > Athletik > Allgemeine Sportartikel > Ablagen & Transportwagen für Gymnastikmatten +Sportartikel > Athletik > Allgemeine Sportartikel > Ballpumpen +Sportartikel > Athletik > Allgemeine Sportartikel > Ballpumpenzubehör +Sportartikel > Athletik > Allgemeine Sportartikel > Ballpumpenzubehör > Ballpumpenaufsätze +Sportartikel > Athletik > Allgemeine Sportartikel > Balltaschen & -wagen +Sportartikel > Athletik > Allgemeine Sportartikel > Chalk +Sportartikel > Athletik > Allgemeine Sportartikel > Gymnastikmatten +Sportartikel > Athletik > Allgemeine Sportartikel > Leitern & Hürden für Geschwindigkeits- & Koordinationstraining +Sportartikel > Athletik > Allgemeine Sportartikel > Markierungshütchen +Sportartikel > Athletik > Allgemeine Sportartikel > Masken für Höhentraining +Sportartikel > Athletik > Allgemeine Sportartikel > Megaphone für Sportveranstaltungen +Sportartikel > Athletik > Allgemeine Sportartikel > Sport-Mundschutz +Sportartikel > Athletik > Allgemeine Sportartikel > Stadionsitze und Polster +Sportartikel > Athletik > Allgemeine Sportartikel > Suspensorien für Athleten +Sportartikel > Athletik > Allgemeine Sportartikel > Übungsnetze +Sportartikel > Athletik > American Football +Sportartikel > Athletik > American Football > American Football-Handschuhe +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Girdle Shorts +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Helme +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Facemasks +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Helmpolster +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Helmvisiere +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Helmzubehör > American Football-Kinnriemen +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Nackenschutz +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > American Football-Schulterpads +Sportartikel > Athletik > American Football > American Football-Schutzbekleidung > Schutz-Shirts und -Hemden +Sportartikel > Athletik > American Football > American Football-Torstangen +Sportartikel > Athletik > American Football > American Football-Trainingsausrüstung +Sportartikel > Athletik > American Football > American Football-Trainingsausrüstung > Dummys & Schlitten +Sportartikel > Athletik > American Football > Football-Bälle +Sportartikel > Athletik > American Football > Kicking Tees & Halter für Fußbälle +Sportartikel > Athletik > Baseball & Softball +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Bases +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Schlaghandschuhe +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Schutzkleidung +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Schutzkleidung > Ausrüstung für Fänger +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Schutzkleidung > Baseball- & Softball-Brustpanzer +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Schutzkleidung > Baseball- & Softball-Knie- & Schienbeinschoner +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Schutzkleidung > Baseball- & Softballhelme +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Schutzkleidung > Schutzhelme für Fänger +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Wurfhügel +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softball-Wurfmale +Sportartikel > Athletik > Baseball & Softball > Baseball- & Softballhandschuhe +Sportartikel > Athletik > Baseball & Softball > Baseball-Bälle +Sportartikel > Athletik > Baseball & Softball > Baseballschläger +Sportartikel > Athletik > Baseball & Softball > Softball-Bälle +Sportartikel > Athletik > Baseball & Softball > Softballschläger +Sportartikel > Athletik > Baseball & Softball > Wurfmaschinen +Sportartikel > Athletik > Basketball +Sportartikel > Athletik > Basketball > Basketball-Trainingshilfen +Sportartikel > Athletik > Basketball > Basketballkorbteile & -zubehör +Sportartikel > Athletik > Basketball > Basketballkorbteile & -zubehör > Basketball-Korbbretter +Sportartikel > Athletik > Basketball > Basketballkorbteile & -zubehör > Basketballnetze +Sportartikel > Athletik > Basketball > Basketballkorbteile & -zubehör > Basketballringe +Sportartikel > Athletik > Basketball > Basketballkorbteile & -zubehör > Basketballständer +Sportartikel > Athletik > Basketball > Basketballkorbteile & -zubehör > Schutzverkleidung für Basketballkörbe +Sportartikel > Athletik > Basketball > Basketballkörbe +Sportartikel > Athletik > Basketball > Basketbälle +Sportartikel > Athletik > Boxen & Kampfsport +Sportartikel > Athletik > Boxen & Kampfsport > Boxringe +Sportartikel > Athletik > Boxen & Kampfsport > Boxringelemente +Sportartikel > Athletik > Boxen & Kampfsport > Boxschutzbekleidung +Sportartikel > Athletik > Boxen & Kampfsport > Boxschutzbekleidung > Armschutz +Sportartikel > Athletik > Boxen & Kampfsport > Boxschutzbekleidung > Boxhandschuhe +Sportartikel > Athletik > Boxen & Kampfsport > Boxschutzbekleidung > Handbandagen +Sportartikel > Athletik > Boxen & Kampfsport > Boxschutzbekleidung > Kopfschutz +Sportartikel > Athletik > Boxen & Kampfsport > Boxschutzbekleidung > Körperschutz +Sportartikel > Athletik > Boxen & Kampfsport > Boxschutzbekleidung > Schienbeinschoner +Sportartikel > Athletik > Boxen & Kampfsport > Kampfsportgürtel +Sportartikel > Athletik > Boxen & Kampfsport > Kampfsportwaffen +Sportartikel > Athletik > Boxen & Kampfsport > Trainingsausrüstung für Boxen & Kampfsport +Sportartikel > Athletik > Boxen & Kampfsport > Trainingsausrüstung für Boxen & Kampfsport > Box- & Trainingssackzubehör +Sportartikel > Athletik > Boxen & Kampfsport > Trainingsausrüstung für Boxen & Kampfsport > Box- & Trainingssäcke +Sportartikel > Athletik > Boxen & Kampfsport > Trainingsausrüstung für Boxen & Kampfsport > Boxpratzen +Sportartikel > Athletik > Boxen & Kampfsport > Trainingsausrüstung für Boxen & Kampfsport > Schlagpolster +Sportartikel > Athletik > Boxen & Kampfsport > Trainingsausrüstung für Boxen & Kampfsport > Training-Dummys +Sportartikel > Athletik > Broomball-Ausrüstung +Sportartikel > Athletik > Cheerleading +Sportartikel > Athletik > Cheerleading > Cheerleader-Pompons +Sportartikel > Athletik > Cricket +Sportartikel > Athletik > Cricket > Cricket-Aussrüstungssets +Sportartikel > Athletik > Cricket > Cricket-Schutzkleidung +Sportartikel > Athletik > Cricket > Cricket-Schutzkleidung > Cricket-Beinschutz +Sportartikel > Athletik > Cricket > Cricket-Schutzkleidung > Crickethandschuhe +Sportartikel > Athletik > Cricket > Cricket-Schutzkleidung > Crickethelme +Sportartikel > Athletik > Cricket > Cricketbälle +Sportartikel > Athletik > Cricket > Cricketschläger +Sportartikel > Athletik > Cricket > Cricketschläger-Zubehör +Sportartikel > Athletik > Cricket > Cricketschläger-Zubehör > Cricketschläger-Griffe +Sportartikel > Athletik > Cricket > Cricketstäbe +Sportartikel > Athletik > Eiskunstlauf & Hockey +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Ausrüstungssets für Torwarte +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Eishockeyhosenträger und -gürtel +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Hockey-Ellenbogenschutz +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Hockey-Schienbeinschoner & -Beinschutz +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Hockey-Schulterpolster & -Brustpolster +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Hockeyhandschuhe +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Hockeyhelme +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockey-Schutzausrüstung > Hockeyhosen +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeybälle & Pucks +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeyschlitten +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeyschläger +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeyschlägerpflege +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeyschlägerteile +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeyschlägerteile > Hockey-Schlägerschäfte +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeyschlägerteile > Hockeyschlägerkellen +Sportartikel > Athletik > Eiskunstlauf & Hockey > Hockeytore +Sportartikel > Athletik > Eiskunstlauf & Hockey > Schlittschuhe +Sportartikel > Athletik > Eiskunstlauf & Hockey > Schlittschuhzubehör +Sportartikel > Athletik > Eiskunstlauf & Hockey > Schlittschuhzubehör > Eiskunstlaufstiefel +Sportartikel > Athletik > Eiskunstlauf & Hockey > Schlittschuhzubehör > Kufenschoner +Sportartikel > Athletik > Eiskunstlauf & Hockey > Schlittschuhzubehör > Schlittschuhkufen +Sportartikel > Athletik > Eiskunstlauf & Hockey > Schlittschuhzubehör > Schlittschuhschleifer +Sportartikel > Athletik > Eiskunstlauf & Hockey > Schlittschuhzubehör > Schnürhilfen +Sportartikel > Athletik > Fechten +Sportartikel > Athletik > Fechten > Fechtschutzbekleidung +Sportartikel > Athletik > Fechten > Fechtschutzbekleidung > Fechthandschuhe +Sportartikel > Athletik > Fechten > Fechtschutzbekleidung > Fechtjacken & -E-Westen +Sportartikel > Athletik > Fechten > Fechtschutzbekleidung > Fechtmasken +Sportartikel > Athletik > Fechten > Sportfechtwaffen +Sportartikel > Athletik > Feldhockey & Lacrosse +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockey- & Lacrosse-Schutzkleidung +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockey- & Lacrosse-Schutzkleidung > Feldhockey- & Lacrosse-Handschuhe +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockey- & Lacrosse-Schutzkleidung > Feldhockey- & Lacrosse-Pads +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockey- & Lacrosse-Schutzkleidung > Hockey- & Lacrosse-Helme +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockey- & Lacrosse-Schutzkleidung > Masken & Schutzbrillen +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockeybälle +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockeyschläger +Sportartikel > Athletik > Feldhockey & Lacrosse > Feldhockeytore +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Ausrüstungen +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Bälle +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Schläger +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Schlägerteile +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Schlägerteile > Lacrosse-Schlägerköpfe +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Schlägerteile > Lacrosse-Schlägernetze & Strings +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Schlägerteile > Lacrosse-Schlägerschäfte +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Tore +Sportartikel > Athletik > Feldhockey & Lacrosse > Lacrosse-Trainingszubehör +Sportartikel > Athletik > Fußball +Sportartikel > Athletik > Fußball > Eckfahnen +Sportartikel > Athletik > Fußball > Fußball-Schutzkleidung +Sportartikel > Athletik > Fußball > Fußball-Schutzkleidung > Fußballschienbeinschützer +Sportartikel > Athletik > Fußball > Fußballtore & -netze +Sportartikel > Athletik > Fußball > Fußbälle +Sportartikel > Athletik > Fußball > Torwarthandschuhe +Sportartikel > Athletik > Fußball > Zubehör für Fußballtore +Sportartikel > Athletik > Handball +Sportartikel > Athletik > Handball > Handbälle +Sportartikel > Athletik > Leichtathletik +Sportartikel > Athletik > Leichtathletik > Diskusscheiben +Sportartikel > Athletik > Leichtathletik > Hochsprunglatten +Sportartikel > Athletik > Leichtathletik > Hochsprungmatten +Sportartikel > Athletik > Leichtathletik > Hürden +Sportartikel > Athletik > Leichtathletik > Kugelstoß-Kugeln +Sportartikel > Athletik > Leichtathletik > Speere +Sportartikel > Athletik > Leichtathletik > Stabhochsprungmatten +Sportartikel > Athletik > Leichtathletik > Stabhochsprungstäbe +Sportartikel > Athletik > Leichtathletik > Staffelstäbe +Sportartikel > Athletik > Leichtathletik > Startblöcke +Sportartikel > Athletik > Leichtathletik > Startpistolen +Sportartikel > Athletik > Leichtathletik > Wurfhämmer +Sportartikel > Athletik > Racquetball & Squash +Sportartikel > Athletik > Racquetball & Squash > Racquetball- & Squash-Bälle +Sportartikel > Athletik > Racquetball & Squash > Racquetball-Schläger +Sportartikel > Athletik > Racquetball & Squash > Squash- & Racquetball-Handschuhe +Sportartikel > Athletik > Racquetball & Squash > Squash- & Racquetball-Schutzbrillen +Sportartikel > Athletik > Racquetball & Squash > Squashschläger +Sportartikel > Athletik > Ringen +Sportartikel > Athletik > Ringen > Schutzbekleidung für Ringer +Sportartikel > Athletik > Ringen > Schutzbekleidung für Ringer > Ringer-Kniepolster +Sportartikel > Athletik > Ringen > Schutzbekleidung für Ringer > Ringer-Kopfschutz +Sportartikel > Athletik > Rounders +Sportartikel > Athletik > Rounders > Rounders-Handschuhe +Sportartikel > Athletik > Rounders > Rounders-Schläger +Sportartikel > Athletik > Rugby +Sportartikel > Athletik > Rugby > Rugby-Bälle +Sportartikel > Athletik > Rugby > Rugby-Handschuhe +Sportartikel > Athletik > Rugby > Rugby-Schutzkleidung +Sportartikel > Athletik > Rugby > Rugby-Schutzkleidung > Rugby-Helme +Sportartikel > Athletik > Rugby > Rugby-Tore +Sportartikel > Athletik > Rugby > Rugby-Trainingsausrüstung +Sportartikel > Athletik > Tanzen +Sportartikel > Athletik > Tanzen > Ballettstangen +Sportartikel > Athletik > Tennis +Sportartikel > Athletik > Tennis > Tennisballdosen +Sportartikel > Athletik > Tennis > Tennisballkörbe & -wagen +Sportartikel > Athletik > Tennis > Tennisballwurfmaschinen +Sportartikel > Athletik > Tennis > Tennisbälle +Sportartikel > Athletik > Tennis > Tennisnetze +Sportartikel > Athletik > Tennis > Tennisschläger +Sportartikel > Athletik > Tennis > Tennisschlägerzubehör +Sportartikel > Athletik > Tennis > Tennisschlägerzubehör > Griffbänder +Sportartikel > Athletik > Tennis > Tennisschlägerzubehör > Schlägerdämpfer +Sportartikel > Athletik > Tennis > Tennisschlägerzubehör > Tennissaiten +Sportartikel > Athletik > Tennis > Tennisschlägerzubehör > Tennistaschen +Sportartikel > Athletik > Tennis > Tennisschlägerzubehör > Ösenbänder für Tennisschläger +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Anzeigetafeln +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Begrenzungsmarkierungen für Spielfelder +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Handzähler +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Kapitänsbinden +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Linienrichterfahnen +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Pitch Counter +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Schiedsrichter- & Trainerpfeifen +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Schiedsrichter-Münzen +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Schiedsrichtermappen +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Schiedsrichterstände & -stühle +Sportartikel > Athletik > Trainer- & Schiedsrichterausrüstung > Strafkarten & -flaggen +Sportartikel > Athletik > Turnen +Sportartikel > Athletik > Turnen > Pauschenpferde +Sportartikel > Athletik > Turnen > Schutzausrüstung +Sportartikel > Athletik > Turnen > Schutzausrüstung > Turner-Handbandagen +Sportartikel > Athletik > Turnen > Sprungpferde +Sportartikel > Athletik > Turnen > Turnringe +Sportartikel > Athletik > Turnen > Turnsprungbretter +Sportartikel > Athletik > Turnen > Turnstangen & Schwebebalken +Sportartikel > Athletik > Volleyball +Sportartikel > Athletik > Volleyball > Volleyball-Schutzkleidung +Sportartikel > Athletik > Volleyball > Volleyball-Schutzkleidung > Volleyball-Knieschoner +Sportartikel > Athletik > Volleyball > Volleyball-Trainingshilfen +Sportartikel > Athletik > Volleyball > Volleyballnetze +Sportartikel > Athletik > Volleyball > Volleybälle +Sportartikel > Athletik > Wallyball-Ausrüstung +Sportartikel > Athletik > Wasserball +Sportartikel > Athletik > Wasserball > Wasserballkappen +Sportartikel > Athletik > Wasserball > Wasserballtore +Sportartikel > Athletik > Wasserball > Wasserbälle +Sportartikel > Fitness +Sportartikel > Fitness > Balancetrainer +Sportartikel > Fitness > Bauchtrainer +Sportartikel > Fitness > Cardio +Sportartikel > Fitness > Cardio > Cardiogeräte +Sportartikel > Fitness > Cardio > Cardiogeräte > Crosstrainer +Sportartikel > Fitness > Cardio > Cardiogeräte > Heimtrainer +Sportartikel > Fitness > Cardio > Cardiogeräte > Laufbänder +Sportartikel > Fitness > Cardio > Cardiogeräte > Rudergeräte +Sportartikel > Fitness > Cardio > Cardiogeräte > Stepper +Sportartikel > Fitness > Cardio > Springseile +Sportartikel > Fitness > Cardio > Zubehör für Cardiogeräte +Sportartikel > Fitness > Cardio > Zubehör für Cardiogeräte > Crosstrainer-Zubehör +Sportartikel > Fitness > Cardio > Zubehör für Cardiogeräte > Heimtrainer-Zubehör +Sportartikel > Fitness > Cardio > Zubehör für Cardiogeräte > Laufbandzubehör +Sportartikel > Fitness > Cardio > Zubehör für Cardiogeräte > Rudergerät-Zubehör +Sportartikel > Fitness > Cardio > Zubehör für Cardiogeräte > Stepper-Zubehör +Sportartikel > Fitness > Fitnessbänder +Sportartikel > Fitness > Fitnessgeräte-Sets +Sportartikel > Fitness > Gewichtheben +Sportartikel > Fitness > Gewichtheben > Gewichthebergürtel +Sportartikel > Fitness > Gewichtheben > Gewichtheberhandschuhe & Handgelenkschoner +Sportartikel > Fitness > Gewichtheben > Hanteln +Sportartikel > Fitness > Gewichtheben > Hantelzubehör +Sportartikel > Fitness > Gewichtheben > Hantelzubehör > Hantelstangen +Sportartikel > Fitness > Gewichtheben > Hantelzubehör > Hantelstangen-Feststellringe +Sportartikel > Fitness > Gewichtheben > Hantelzubehör > Hantelständer +Sportartikel > Fitness > Gewichtheben > Krafttrainingsgeräte +Sportartikel > Fitness > Gewichtheben > Zubehör für Krafttrainingsgeräte +Sportartikel > Fitness > Gewichtswesten & -manschetten +Sportartikel > Fitness > Gymnastikbälle +Sportartikel > Fitness > Handtrainer +Sportartikel > Fitness > Inversionstische +Sportartikel > Fitness > Keilmatten +Sportartikel > Fitness > Klimmzugstangen +Sportartikel > Fitness > Matten für Heimtrainer +Sportartikel > Fitness > Medizinbälle +Sportartikel > Fitness > Power Tower +Sportartikel > Fitness > Reaktionsbälle +Sportartikel > Fitness > Schaumroller +Sportartikel > Fitness > Schaumroller-Zubehör +Sportartikel > Fitness > Schaumroller-Zubehör > Aufbewahrungstaschen für Schaumroller +Sportartikel > Fitness > Sicherheitslichter & -reflektoren für Sport +Sportartikel > Fitness > Steppbretter +Sportartikel > Fitness > Stoppuhren +Sportartikel > Fitness > Suspension Trainer +Sportartikel > Fitness > Trainings- & Bremsschirme +Sportartikel > Fitness > Trainingsbänke +Sportartikel > Fitness > Vibrationstrainer +Sportartikel > Fitness > Yoga & Pilates +Sportartikel > Fitness > Yoga & Pilates > Beutel für Yogamatten +Sportartikel > Fitness > Yoga & Pilates > Pilates-Geräte +Sportartikel > Fitness > Yoga & Pilates > Yoga- & Pilatesblöcke +Sportartikel > Fitness > Yoga & Pilates > Yoga- & Pilatesmatten +Sportartikel > Fitness > Yoga & Pilates > Yoga- & Pilatestücher +Sportartikel > Indoor - Aktivitäten +Sportartikel > Indoor - Aktivitäten > Air-Hockey +Sportartikel > Indoor - Aktivitäten > Air-Hockey > Air-Hockey-Ausrüstung +Sportartikel > Indoor - Aktivitäten > Air-Hockey > Air-Hockey-Tische +Sportartikel > Indoor - Aktivitäten > Air-Hockey > Air-Hockey-Tischzubehör +Sportartikel > Indoor - Aktivitäten > Billard +Sportartikel > Indoor - Aktivitäten > Billard > Billarddreiecke +Sportartikel > Indoor - Aktivitäten > Billard > Billardhandschuhe +Sportartikel > Indoor - Aktivitäten > Billard > Billardkugeln +Sportartikel > Indoor - Aktivitäten > Billard > Billardqueues & Queuebrücken +Sportartikel > Indoor - Aktivitäten > Billard > Billardtisch-Beleuchtung +Sportartikel > Indoor - Aktivitäten > Billard > Billardtisch-Teile & Zubehör +Sportartikel > Indoor - Aktivitäten > Billard > Billardtisch-Teile & Zubehör > Ballfangtaschen +Sportartikel > Indoor - Aktivitäten > Billard > Billardtisch-Teile & Zubehör > Billardtisch-Bürsten +Sportartikel > Indoor - Aktivitäten > Billard > Billardtisch-Teile & Zubehör > Billardtücher +Sportartikel > Indoor - Aktivitäten > Billard > Billardtisch-Teile & Zubehör > Billiardtischabdeckungen +Sportartikel > Indoor - Aktivitäten > Billard > Billardtische +Sportartikel > Indoor - Aktivitäten > Billard > Queuezubehör +Sportartikel > Indoor - Aktivitäten > Billard > Queuezubehör > Billiardkoffer +Sportartikel > Indoor - Aktivitäten > Billard > Queuezubehör > Billiardkreide +Sportartikel > Indoor - Aktivitäten > Billard > Queuezubehör > Queueständer +Sportartikel > Indoor - Aktivitäten > Bowling +Sportartikel > Indoor - Aktivitäten > Bowling > Bowling-Handgelenkstützen +Sportartikel > Indoor - Aktivitäten > Bowling > Bowlinghandschuhe +Sportartikel > Indoor - Aktivitäten > Bowling > Bowlingkegel +Sportartikel > Indoor - Aktivitäten > Bowling > Bowlingkugeln +Sportartikel > Indoor - Aktivitäten > Bowling > Bowlingtaschen +Sportartikel > Indoor - Aktivitäten > Dartspiele +Sportartikel > Indoor - Aktivitäten > Dartspiele > Dart-Rückwände +Sportartikel > Indoor - Aktivitäten > Dartspiele > Dartpfeile +Sportartikel > Indoor - Aktivitäten > Dartspiele > Dartscheiben +Sportartikel > Indoor - Aktivitäten > Dartspiele > Dartteile +Sportartikel > Indoor - Aktivitäten > Dartspiele > Dartteile > Dartflights +Sportartikel > Indoor - Aktivitäten > Dartspiele > Dartteile > Dartschäfte +Sportartikel > Indoor - Aktivitäten > Dartspiele > Dartteile > Dartspitzen +Sportartikel > Indoor - Aktivitäten > Jakkolo +Sportartikel > Indoor - Aktivitäten > Jakkolo > Jakkolo-Pulver +Sportartikel > Indoor - Aktivitäten > Jakkolo > Jakkolo-Spielsteine +Sportartikel > Indoor - Aktivitäten > Jakkolo > Shuffleboard-Tische +Sportartikel > Indoor - Aktivitäten > Multispieltische +Sportartikel > Indoor - Aktivitäten > Tischfußball +Sportartikel > Indoor - Aktivitäten > Tischfußball > Tischfußball-Bälle +Sportartikel > Indoor - Aktivitäten > Tischfußball > Tischfußball-Tische +Sportartikel > Indoor - Aktivitäten > Tischfußball > Zubehör für Tischfußballtische +Sportartikel > Indoor - Aktivitäten > Tischtennis +Sportartikel > Indoor - Aktivitäten > Tischtennis > Tischtennis-Roboter +Sportartikel > Indoor - Aktivitäten > Tischtennis > Tischtennisbälle +Sportartikel > Indoor - Aktivitäten > Tischtennis > Tischtennisnetze und -pfosten +Sportartikel > Indoor - Aktivitäten > Tischtennis > Tischtennisplatten +Sportartikel > Indoor - Aktivitäten > Tischtennis > Tischtennisschläger & -sets +Sportartikel > Indoor - Aktivitäten > Tischtennis > Zubehör für Tischtennis-Roboter +Sportartikel > Indoor - Aktivitäten > Tischtennis > Zubehör für Tischtennisschläger +Sportartikel > Outdoor-Aktivitäten +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelgeräte +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelgeräte > Angelblei +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelgeräte > Angelhaken +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelgeräte > Karabiner & Wirbel +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelgeräte > Kunstköder +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelgeräte > Schwimmer +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelkästen & Angeltaschen +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelleinen & -wirbel +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelrollen +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelrollen-Zubehör +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelrollen-Zubehör > Ersatzspulen +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelrollen-Zubehör > Schmierstoffe +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelrollen-Zubehör > Taschen & Behälter +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelruten +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelruten-Zubehör +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelruten-Zubehör > Angelrutenhalter und -ständer +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Angelruten-Zubehör > Taschen & Behälter für Angelruten +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Bissanzeiger +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Fallen für den Angelsport +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Fischernetze +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Gaffs +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Harpunen für den Angelsport +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbefestigung +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbefestigung > Angelschnur +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbefestigung > Pop-Up-Kugeln +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Köderbehälter +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Lebendköder +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Wathosen für Angler & Jäger +Sportartikel > Outdoor-Aktivitäten > Angeln & Fischen > Werkzeuge zum Entfernen des Angelhakens +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Ablagen für Wasserfahrzeuge +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Ablagen für Wasserfahrzeuge > Halterungen für Boards +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Ablagen für Wasserfahrzeuge > Halterungen für Boote +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Neoprenanzugteile +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Neoprenanzugteile > Kappen, Handschuhe & Stiefel für Neoprenanzüge +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Neoprenanzugteile > Neopren-Oberteile +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Neoprenanzugteile > Neopren-Unterteile +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Neoprenanzüge +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Rashguards & Schwimmshirts +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Rettungswesten +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Schwimmwestenzubehör +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Trockenanzüge +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Boots- & Wassersportkleidung > Wassersporthelme +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Handschuhe für den Bootssport +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Kajaks +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Kajakzubehör +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Kanus +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Kanuzubehör +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Paddel & Ruder +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Paddelriemen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Rafts +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Ruderboote +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Bootssport > Tretboote +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Kitesurfen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Kitesurfen > Kiteboard-Taschen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Kitesurfen > Kiteboards +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Kitesurfen > Kiteboardteile +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Kitesurfen > Kitesurfing-Kites +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Kitesurfen > Trapeze für Kite- & Windsurfen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Badekappen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Gegenstromanlagen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Handpaddel +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Nasenklammern +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Pull Buoys +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmbretter +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmbrillen & -masken +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmflossen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmflossen > Monoflossen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmflossen > Trainingsflossen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmflügel +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmgewichte +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmgürtel +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Schwimmhandschuhe +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Schwimmen > Zubehör für Schwimmbrillen & -masken +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Handschuhe für seilgebundene Wassersportarten +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Kneeboarding +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Kneeboarding > Kneeboards +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Tubes & Towables +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wakeboarding +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wakeboarding > Kiteboard- & Wakeboard-Bindungen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wakeboarding > Wakeboard-Ersatzteile +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wakeboarding > Wakeboards +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wasserski +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wasserski > Hydrofoils +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wasserski > Wasserski-Bindungen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wasserski > Wasserskier +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Wasserski > Wasserskikoffer & -taschen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Seilgebundene Wassersportarten > Zugseile für Wassersport +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Bodyboards +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Fußleinen für Surfbretter +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Handschuhe für Surfer +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Paddelboards +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Skimboards +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Surfboard-Taschen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Surfboard-Wachs +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Surfbretter +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Surfbrettfinnen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Surfen > Surfpads +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Atemregler +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Bleigürtel +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Schnorchel +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Tarierwesten +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Tauch- & Schnorchelausrüstung +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Tauch- & Schnorchelflossen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Tauch- & Schnorchelmasken +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Tauchcomputer +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Tauchen & Schnorcheln > Tauchermesser & -scheren +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Windsurfen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Windsurfen > Windsurfboard-Ausrüstung +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Windsurfen > Windsurfboard-Ausrüstung > Windsurf-Finnen +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Windsurfen > Windsurfboard-Ausrüstung > Windsurfmasten +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Windsurfen > Windsurfbretter +Sportartikel > Outdoor-Aktivitäten > Boot- & Wassersport > Windsurfen > Windsurfsegel +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Camping-Töpfe & -Geschirr +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campinghilfsmittel +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campinghilfsmittel > Jagdmesser +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campinghilfsmittel > Multifunktionswerkzeuge & -messer +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campingleuchten & -laternen +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campingmöbel +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campingmöbel > Feldbetten +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campingmöbel > Luftbetten +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Campingmöbel > Zubehör für Luftmatratzen & Schlafunterlagen +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Innenschlafsack +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Isomatten +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Kompressionssäcke +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Mobile Toiletten & Duschen +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Mobile Toiletten & Duschen > Mobile Duschen & Sichtschutz +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Mobile Toiletten & Duschen > Mobile Toiletten & Urinale +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Moskitonetze & Fliegengitter +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Navigationskompasse +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Schlafsäcke +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Taschenwärmer +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Tragbare Wasserfilter & Wasserreiniger +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Trekkingstöcke +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Windschutz +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Zelte +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Zeltzubehör +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Zeltzubehör > Innenzelte +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Zeltzubehör > Vorzelte +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Zeltzubehör > Zeltstangen & -Heringe +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Zeltzubehör > Zeltunterlagen +Sportartikel > Outdoor-Aktivitäten > Camping & Wandern > Zubehör für Trekkingstöcke +Sportartikel > Outdoor-Aktivitäten > Drachenfliegen & Fallschirmspringen +Sportartikel > Outdoor-Aktivitäten > Drachenfliegen & Fallschirmspringen > Fallschirme +Sportartikel > Outdoor-Aktivitäten > Drachenfliegen & Fallschirmspringen > Fluganzüge +Sportartikel > Outdoor-Aktivitäten > Drachenfliegen & Fallschirmspringen > Hängegleiter +Sportartikel > Outdoor-Aktivitäten > Golf +Sportartikel > Outdoor-Aktivitäten > Golf > Golf-Tees +Sportartikel > Outdoor-Aktivitäten > Golf > Golf-Trainingshilfen +Sportartikel > Outdoor-Aktivitäten > Golf > Golf-Zubehörsets +Sportartikel > Outdoor-Aktivitäten > Golf > Golfballmarkierungen +Sportartikel > Outdoor-Aktivitäten > Golf > Golfbälle +Sportartikel > Outdoor-Aktivitäten > Golf > Golffahnen +Sportartikel > Outdoor-Aktivitäten > Golf > Golfhandschuhe +Sportartikel > Outdoor-Aktivitäten > Golf > Golfhandtücher +Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger +Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger-Teile & Zubehör +Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger-Teile & Zubehör > Golfschläger-Schutzhüllen +Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger-Teile & Zubehör > Golfschlägergriffe +Sportartikel > Outdoor-Aktivitäten > Golf > Golfschläger-Teile & Zubehör > Golfschlägerschäfte +Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschen +Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschenzubehör +Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschenzubehör > Golftaschenhüllen +Sportartikel > Outdoor-Aktivitäten > Golf > Golftaschenzubehör > Golftaschentrolleys +Sportartikel > Outdoor-Aktivitäten > Golf > Pitchgabeln +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Armschutz für Bogenschützen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Bogen- & Armbrustteile & -zubehör +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Bögen & Armbrüste +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Bögen & Armbrüste > Armbrüste +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Bögen & Armbrüste > Compoundbögen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Bögen & Armbrüste > Langbögen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Handschuhe & Auslöser +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Köcher +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Pfeile +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Pfeilelemente & Zubehör +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Pfeilelemente & Zubehör > Jagdspitzen & Feldspitzen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Pfeilelemente & Zubehör > Nocken +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Pfeilelemente & Zubehör > Steuerfedern +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Bogenschießen > Zielscheiben für Bogenschießen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Hochsitze +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Jagdansitze & Tarnung +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Jagdhund-Ausrüstung +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Jagdverstärker +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Lockmittel für Wild +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Lockmittel für Wild > Geruchstarnung & Lockdüfte +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Lockmittel für Wild > Jagdköder +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Lockmittel für Wild > Köder, Futter & Mineralien +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Lockmittel für Wild > Lockinstrumente +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Tierfallen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Jagen > Wildfutterautomaten +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Ersatzteile & Zubehör für Paintball-Gewehre +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Ersatzteile & Zubehör für Paintball-Gewehre > Paintball-Drop-Forwards +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Ersatzteile & Zubehör für Paintball-Gewehre > Paintball-Gewehrläufe +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Ersatzteile & Zubehör für Paintball-Gewehre > Paintball-Hopper +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Ersatzteile & Zubehör für Paintball-Gewehre > Paintball-Pressluftflaschen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Paintball-Battlepacks +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Paintball-Granaten +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Paintball-Granatwerfer +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Paintball-Markierer +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball > Paintballs +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball- & Airsoft-Schutzkleidung +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball- & Airsoft-Schutzkleidung > Paintball- & Airsoft-Handschuhe +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball- & Airsoft-Schutzkleidung > Paintball- & Airsoft-Schutzbrillen & Masken +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball- & Airsoft-Schutzkleidung > Paintball- & Airsoft-Schutzpolster +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Paintball- & Airsoft-Schutzkleidung > Paintball- & Airsoft-Westen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Softair +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Softair > Softairkugeln +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Softair > Softairwaffen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Softair > Softairwaffen-Teile & -Zubehör +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Paintball & Airsoft > Softair > Softairwaffen-Teile & -Zubehör > Batterien für Softairwaffen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Schießsportzubehör +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Schießsportzubehör > Stative & Zweibeinständer +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Schießsportzubehör > Stützen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Schießsportzubehör > Zielscheiben +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Schutzkleidung für Jagd- und Schießsport +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Schutzkleidung für Jagd- und Schießsport > Handschuhe für Jagd- und Schießsport +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Schutzkleidung für Jagd- und Schießsport > Jacken für Jagd- und Schießsport +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Tontaubenschießen +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Tontaubenschießen > Tontauben +Sportartikel > Outdoor-Aktivitäten > Jagen und Schießen > Tontaubenschießen > Tontauben-Wurfmaschinen +Sportartikel > Outdoor-Aktivitäten > Kitebuggying +Sportartikel > Outdoor-Aktivitäten > Kitebuggying > Kitebuggy-Zubehör +Sportartikel > Outdoor-Aktivitäten > Kitebuggying > Kitebuggys +Sportartikel > Outdoor-Aktivitäten > Klettern +Sportartikel > Outdoor-Aktivitäten > Klettern > Bouldermatten +Sportartikel > Outdoor-Aktivitäten > Klettern > Chalkbags +Sportartikel > Outdoor-Aktivitäten > Klettern > Eiskletterausrüstung +Sportartikel > Outdoor-Aktivitäten > Klettern > Eisschrauben +Sportartikel > Outdoor-Aktivitäten > Klettern > Expresssets +Sportartikel > Outdoor-Aktivitäten > Klettern > Gurtbänder +Sportartikel > Outdoor-Aktivitäten > Klettern > Karabiner +Sportartikel > Outdoor-Aktivitäten > Klettern > Kletterbekleidung & -zubehör +Sportartikel > Outdoor-Aktivitäten > Klettern > Kletterbekleidung & -zubehör > Kletterhandschuhe +Sportartikel > Outdoor-Aktivitäten > Klettern > Kletterbekleidung & -zubehör > Kletterhelme +Sportartikel > Outdoor-Aktivitäten > Klettern > Kletterbekleidung & -zubehör > Steigeisen +Sportartikel > Outdoor-Aktivitäten > Klettern > Klettergurte +Sportartikel > Outdoor-Aktivitäten > Klettern > Kletterschutzausrüstung +Sportartikel > Outdoor-Aktivitäten > Klettern > Kletterseile +Sportartikel > Outdoor-Aktivitäten > Klettern > Kletterwandgriffe +Sportartikel > Outdoor-Aktivitäten > Klettern > Seilsäcke +Sportartikel > Outdoor-Aktivitäten > Klettern > Sicherungsgeräte +Sportartikel > Outdoor-Aktivitäten > Klettern > Steigklemmen & Abseilausrüstung +Sportartikel > Outdoor-Aktivitäten > Radsport +Sportartikel > Outdoor-Aktivitäten > Radsport > Dreiradzubehör +Sportartikel > Outdoor-Aktivitäten > Radsport > Dreiräder +Sportartikel > Outdoor-Aktivitäten > Radsport > Einradzubehör +Sportartikel > Outdoor-Aktivitäten > Radsport > Einräder +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrrad-Groupsets +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremsen-Sets +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremshebel +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremsrotoren +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradbremsenteile > Bremssättel +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradgabeln +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradkabel +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradkabelgehäuse +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkerverlängerungen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkervorbau +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkkopf-Teile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkkopf-Teile > Fahrradlenkkopf-Abstandsringe +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkkopf-Teile > Fahrradlenkkopf-Halterungen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkköpfe +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradlenkstangen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradrahmen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradreifen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräder +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradachsen & -spanner +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradfelgen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradfußrasten +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradnaben +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradnabenteile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Fahrradspeichen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Felgenbänder +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradräderzubehör > Speichennippel +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradsattelstützen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradsattelstützenklemmen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradgangschaltungen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradkassetten +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradketten +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradkettenkränze +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradkurbeln +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradpedale +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Fahrradschalthebel +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschaltungsteile > Tretlagergehäuse +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradschläuche +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradständer +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Fahrradsättel +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Kleinere Fahrradzubehörteile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Reifenventiladapter +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Reifenventile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbauteile > Reifenventilkappen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Fahrrad-Schutzpolster +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Fahrradhandschuhe +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Fahrradhelme +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Fahrradhelmteile und -zubehör +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Fahrradüberschuhe +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Schuhplatten +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Schuhplatten-Zubehör +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Schuhplatten-Zubehör > Schuhplatten-Klemmen & -Keile +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Schuhplatten-Zubehör > Schuhplatten-Schrauben +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradbekleidung & Zubehör > Schuhplatten-Zubehör > Schuhplatten-Schutzhüllen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Dämpferpumpen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrrad-Fußriemen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradabdeckungen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradanhänger +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradcomputer +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradgepäckträger +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradklingeln & -hupen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradkörbe +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradpumpen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradsattelbezüge & -polster +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradschlösser +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradschutzbleche +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradspeichen-Reflektoren +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradspiegel +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradständer & Fahrradparksysteme +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradtaschen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradtaschen & -koffer +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Fahrradwerkzeug +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Flaschenhalter für Fahrradrahmen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Flicken & Reparatur-Sets +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Griffe und Dekor für Fahrradlenker +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Kinderfahrradsitze +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Stützräder +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Surfbretthalterungen für Fahrräder +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Trainingsrollen +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Umrüstsatz für E-Bikes +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Zubehör für Fahrradcomputer +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrradzubehör > Zubehör für Fahrradkindersitze +Sportartikel > Outdoor-Aktivitäten > Radsport > Fahrräder +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Abreitdecken & Weidedecken +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Fliegenmasken +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Hufglocken & Gamaschen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Leckerli für Pferde +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Pferdefutter +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Pferdehaarpflege +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Pferdehaarpflege > Kämme, Bürsten & Striegel +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Pferdehaarpflege > Pferdeschermaschinen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Vitamine & Futterergänzungsmittel für Pferde +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Pferdebedarf > Wurmkur für Pferde +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Gerten & Peitschen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Reithandschuhe +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Reithelme +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Reitausrüstung > Reithosen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Halfter +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Pferdegeschirr +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Pferdeleinen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Sattelgurte +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Steigbügel +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Sättel +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Trensen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Zaumzeug +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Sattel- & Zaumzeug > Zügel +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Sattel & Zaumzeug +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Sattel & Zaumzeug > Sattel- & Zaumzeugbehälter +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Sattel & Zaumzeug > Sattelzubehör +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Sattel & Zaumzeug > Sattelzubehör > Sattelauflagen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Sattel & Zaumzeug > Sattelzubehör > Sattelbezüge und -hüllen +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Sattel & Zaumzeug > Sattelzubehör > Sattelpolster & -decken +Sportartikel > Outdoor-Aktivitäten > Reitsportzubehör > Zubehör für Sattel & Zaumzeug > Sattelzubehör > Satteltaschen +Sportartikel > Outdoor-Aktivitäten > Roller +Sportartikel > Outdoor-Aktivitäten > Skateboarding +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skate-Rails +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skate-Rampen +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Achsen +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Decks +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Kleinteile +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboard-Teile > Skateboard-Rollen +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboarding-Schutzausrüstung +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboarding-Schutzausrüstung > Skate-Helme +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboarding-Schutzausrüstung > Skateboarding-Handschuhe +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboarding-Schutzausrüstung > Skateboarding-Protektoren +Sportartikel > Outdoor-Aktivitäten > Skateboarding > Skateboards +Sportartikel > Outdoor-Aktivitäten > Skaten +Sportartikel > Outdoor-Aktivitäten > Skaten > Inline-Skates +Sportartikel > Outdoor-Aktivitäten > Skaten > Inlineskate-Teile +Sportartikel > Outdoor-Aktivitäten > Skaten > Rollerskates +Sportartikel > Outdoor-Aktivitäten > Skaten > Rollschuh-Teile +Sportartikel > Outdoor-Aktivitäten > Skaten > Rollskis +Sportartikel > Outdoor-Aktivitäten > Skaten > Schutzausrüstung für Skater +Sportartikel > Outdoor-Aktivitäten > Skaten > Schutzausrüstung für Skater > Rollschuh-Polster +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Badminton +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Badminton > Badmintonnetze +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Badminton > Badmintonschläger & -sets +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Badminton > Federball +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Bälle für Paddle-Tennis +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Discgolf +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Discgolf > Discgolf-Fangkörbe +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Discgolf > Discgolf-Taschen +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Paddletennis +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Paddletennis > Paddletennis-Bälle +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Paddletennis > Paddletennis-Schläger +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Pickleball +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Pickleball > Pickleball-Bälle +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Pickleball > Pickleball-Schläger +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Rasenspiele +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Shuffleboard +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Shuffleboard > Shuffleboard-Cues +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Shuffleboard > Shuffleboard-Disks +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Tetherball +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Tetherball > Tetherball-Bälle +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Tetherball > Tetherball-Sets +Sportartikel > Outdoor-Aktivitäten > Spiele im Freien > Tetherball > Tetherball-Stangen +Sportartikel > Outdoor-Aktivitäten > Trinksystem-Zubehör +Sportartikel > Outdoor-Aktivitäten > Trinksystemrucksäcke & -taschen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Lawinenschutz +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Lawinenschutz > Lawinenairbags +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Lawinenschutz > Lawinensonden +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Rodelschlitten +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Schneeschuhe & Zubehör +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Schneeschuhe & Zubehör > Schneeschuh-Bindungen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Schneeschuhe & Zubehör > Schneeschuhe +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ersatzteile für Skibindungen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboard-Ablagen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboard-Brillen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboard-Brillenzubehör +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboard-Brillenzubehör > Ski- & Snowboard-Brillengläser +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboard-Leinen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboard-Taschen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboard-Wachs +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Ski- & Snowboardhelme +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Skibindungen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Skier +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Skier > Alpinskier +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Skier > Langlaufskier +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Skischuhe +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Skistöcke +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Snowboard-Bindungen +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Snowboards +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Snowboardstiefel +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Tuningwerkzeuge für Skis & Snowboards +Sportartikel > Outdoor-Aktivitäten > Wintersport & -Aktivitäten > Skisport & Snowboarden > Zubehör Snowboard-Bindungen +Taschen & Gepäck +Taschen & Gepäck > Aktentaschen +Taschen & Gepäck > Bauchtaschen +Taschen & Gepäck > Einkaufstaschen +Taschen & Gepäck > Gepäckzubehör +Taschen & Gepäck > Gepäckzubehör > Folien & Einsätze für Trockenboxen +Taschen & Gepäck > Gepäckzubehör > Gepäck-Organizer +Taschen & Gepäck > Gepäckzubehör > Gepäckanhänger +Taschen & Gepäck > Gepäckzubehör > Kofferablagen +Taschen & Gepäck > Gepäckzubehör > Koffergurte +Taschen & Gepäck > Gepäckzubehör > Reisebehälter +Taschen & Gepäck > Gepäckzubehör > Reisedokumententaschen +Taschen & Gepäck > Gepäckzubehör > Rucksack-Schutzhüllen +Taschen & Gepäck > Kleidertaschen +Taschen & Gepäck > Koffer +Taschen & Gepäck > Kosmetikkoffer +Taschen & Gepäck > Kulturtaschen +Taschen & Gepäck > Kurier- & Schultertaschen +Taschen & Gepäck > Rucksäcke +Taschen & Gepäck > Seesäcke +Taschen & Gepäck > Trockenboxen +Taschen & Gepäck > Wickeltaschen +Tiere & Tierbedarf +Tiere & Tierbedarf > Haustierbedarf +Tiere & Tierbedarf > Haustierbedarf > Agility-Ausrüstung +Tiere & Tierbedarf > Haustierbedarf > Aquaristik +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquarien +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumbeleuchtung +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumdekoration +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumfilter +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Aquariumständer +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Ausströmersteine & Diffusoren für Aquarien +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Bodengrund für Aquarien +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Fischfutter +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Fischfutterautomaten +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Fischnetze für Aquarien +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Schläuche & Rohre für Aquarien & Teiche +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Temperaturregler für Aquarien +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Wasseraufbereitungsgeräte +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Wasserpflanzendünger +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Zubehör für Aquariumreinigung +Tiere & Tierbedarf > Haustierbedarf > Aquaristik > Überlaufkästen +Tiere & Tierbedarf > Haustierbedarf > Augentropfen für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Begrenzungssysteme +Tiere & Tierbedarf > Haustierbedarf > Bügel für Haustierbekleidung +Tiere & Tierbedarf > Haustierbedarf > Entsorgungssysteme & -werkzeug für Tierkot +Tiere & Tierbedarf > Haustierbedarf > Erkennungsmarken +Tiere & Tierbedarf > Haustierbedarf > Erste-Hilfe-Koffer für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere > Glukosemessgeräte für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere > Schrittzähler für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Fitnessmonitor für Haustiere > Thermometer für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Floh- & Zeckenschutzmittel +Tiere & Tierbedarf > Haustierbedarf > Futter- & Wasserspender +Tiere & Tierbedarf > Haustierbedarf > Glocken & Anhänger +Tiere & Tierbedarf > Haustierbedarf > Halsbänder & Geschirre +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Düfte & Deosprays für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Feuchttücher für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Haartrockner für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Kämme & Bürsten zur Fellpflege +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Nagellack für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Nagelpflege für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Shampoos & Spülungen zur Fellpflege +Tiere & Tierbedarf > Haustierbedarf > Haustierpflegeartikel > Tierhaarschneider +Tiere & Tierbedarf > Haustierbedarf > Haustiertüren +Tiere & Tierbedarf > Haustierbedarf > Hilfsmittel für Tierausbildung +Tiere & Tierbedarf > Haustierbedarf > Hilfsmittel für Tierausbildung > Bodenschutz & Unterlagen +Tiere & Tierbedarf > Haustierbedarf > Hilfsmittel für Tierausbildung > Clicker & Belohnungsspielzeug für Tierausbildung +Tiere & Tierbedarf > Haustierbedarf > Hilfsmittel für Tierausbildung > Pad-Unterlagen für Tierausbildung +Tiere & Tierbedarf > Haustierbedarf > Hilfsmittel für Tierausbildung > Sprays & Lösungen für Tierausbildung +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Einlagen für Hundewindeln +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundebekleidung +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundebetten +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundefutter +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundehütten +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundelaufbänder +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundespielzeug +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundewindeln +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Hundezwinger & -ausläufe +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Leckerbissen für Hunde +Tiere & Tierbedarf > Haustierbedarf > Hundebedarf > Zubehör für Hundezwinger & -ausläufe +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Einlagen für Katzentoilette +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenbekleidung +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenbetten +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenfutter +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenmöbel +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenspielzeug +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzenstreu +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Katzentoiletten +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Leckerbissen für Katzen +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Vorleger für Katzentoiletten +Tiere & Tierbedarf > Haustierbedarf > Katzenbedarf > Zubehör für Katzenmöbel +Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör +Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Decken & Streu für Kleintiere +Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Futter für Kleintiere +Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Lebensräume & Gehege für Kleintiere +Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Leckerli für Kleintiere +Tiere & Tierbedarf > Haustierbedarf > Kleintierzubehör > Zubehör für Lebensräume von Kleintieren +Tiere & Tierbedarf > Haustierbedarf > Kotbeutel +Tiere & Tierbedarf > Haustierbedarf > Leinen +Tiere & Tierbedarf > Haustierbedarf > Maulkörbe +Tiere & Tierbedarf > Haustierbedarf > Medizinische Halsbänder für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Medizinisches Klebeband & Verbandsmaterial für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Mundpflege für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Napfständer +Tiere & Tierbedarf > Haustierbedarf > Napfunterlagen +Tiere & Tierbedarf > Haustierbedarf > Pet-Stroller +Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf +Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Bodengrund für Reptilien & Amphibien +Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Heizung & Beleuchtung für Terrarien +Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Reptilien- & Amphibienfutter +Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Terrarien +Tiere & Tierbedarf > Haustierbedarf > Reptilien- & Amphibienbedarf > Zubehör für Terrarien +Tiere & Tierbedarf > Haustierbedarf > Sonnenschutz für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Spender & Halterungen für Kotbeutel +Tiere & Tierbedarf > Haustierbedarf > Spielgehege für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Tierfutterbehälter +Tiere & Tierbedarf > Haustierbedarf > Tierfutterportionierer +Tiere & Tierbedarf > Haustierbedarf > Tiermedikamente +Tiere & Tierbedarf > Haustierbedarf > Transportboxen & -taschen +Tiere & Tierbedarf > Haustierbedarf > Trennvorrichtungen für den Haustiertransport +Tiere & Tierbedarf > Haustierbedarf > Treppen & Rampen für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Verlängerungsleinen +Tiere & Tierbedarf > Haustierbedarf > Vitamine & Nahrungsergänzungsmittel für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Snacks für Vögel +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Spielvorrichtungen für Vögel +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelfutter +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelkäfige & -ständer +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelkäfigzubehör +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelkäfigzubehör > Futter- & Wasserspender für Vogelkäfige +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelkäfigzubehör > Vogelbäder für Vogelkäfige +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelleitern & -sitzstangen +Tiere & Tierbedarf > Haustierbedarf > Vogelbedarf > Vogelspielzeug +Tiere & Tierbedarf > Haustierbedarf > Wärmekissen für Haustiere +Tiere & Tierbedarf > Haustierbedarf > Zubehör für Haustier-Heizkissen +Tiere & Tierbedarf > Haustierbedarf > Zubehör für Haustierbetten +Tiere & Tierbedarf > Haustierbedarf > Zubehör für Haustierklappen +Tiere & Tierbedarf > Haustierbedarf > Zubehör für Haustiertragetaschen und -boxen +Tiere & Tierbedarf > Lebende Tiere +Wirtschaft & Industrie +Wirtschaft & Industrie > Arbeitsschutzausrüstung +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Chemikalienschutzanzüge +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Gasmasken- & Atemschutzmaskenzubehör +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Halteseile +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Knieschoner +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Kugelsichere Westen +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzbrillen +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzhandschuhe +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzhelme +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzmasken +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzmasken > Feuerwehr-Atemschutzmasken +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzmasken > Gas- & Atemschutzmasken +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzmasken > Medizinische Masken +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schutzmasken > Staubmasken +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Schweißhelme +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Sicherheitsschürzen +Wirtschaft & Industrie > Arbeitsschutzausrüstung > Sicherungsgurte +Wirtschaft & Industrie > Aufbewahrungszubehör für industrielle Zwecke +Wirtschaft & Industrie > Automatisierungskomponenten +Wirtschaft & Industrie > Automatisierungskomponenten > Antriebssysteme mit variabler Frequenz & einstellbarer Drehzahl +Wirtschaft & Industrie > Automatisierungskomponenten > Speicherprogrammierbare Steuerungen +Wirtschaft & Industrie > Baugewerbe +Wirtschaft & Industrie > Baugewerbe > Verkehrskegel +Wirtschaft & Industrie > Baugewerbe > Vermessung +Wirtschaft & Industrie > Bergbau & Steinbruch +Wirtschaft & Industrie > Beschilderung +Wirtschaft & Industrie > Beschilderung > Digitale Schilder +Wirtschaft & Industrie > Beschilderung > Einzelhandelsschilder +Wirtschaft & Industrie > Beschilderung > Elektronische Schilder +Wirtschaft & Industrie > Beschilderung > Elektronische Schilder > LED-Schilder +Wirtschaft & Industrie > Beschilderung > Elektronische Schilder > Neonschilder +Wirtschaft & Industrie > Beschilderung > Geöffnet- und Geschlossen-Schilder +Wirtschaft & Industrie > Beschilderung > Hinweisschilder +Wirtschaft & Industrie > Beschilderung > Notfall- & Notausgangsschilder +Wirtschaft & Industrie > Beschilderung > Parkplatzschilder +Wirtschaft & Industrie > Beschilderung > Sicherheitsschilder +Wirtschaft & Industrie > Beschilderung > Tragbare Schilder +Wirtschaft & Industrie > Beschilderung > Verkehrsschilder +Wirtschaft & Industrie > Beschilderung > Warnschilder +Wirtschaft & Industrie > Beschilderung > Wegweiser +Wirtschaft & Industrie > Beschilderung > Öffnungszeiten-Schilder +Wirtschaft & Industrie > Einzelhandel +Wirtschaft & Industrie > Einzelhandel > Einkaufstüten aus Papier & Plastik +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldscheinprüfgeräte +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldtaschen +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldwechsler +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Geldzählmaschinen für Münzen und Scheine +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Ladenkassen & POS-Terminals +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Münzrollenpapier & Geldscheinbanderolen +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Zubehör für Ladenkassen & POS-Terminals +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Zubehör für Ladenkassen & POS-Terminals > Kassenschubladen +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Zubehör für Ladenkassen & POS-Terminals > Kreditkartenterminals +Wirtschaft & Industrie > Einzelhandel > Geldhandhabung > Zubehör für Ladenkassen & POS-Terminals > Unterschriftenpads +Wirtschaft & Industrie > Einzelhandel > Preisauszeichnungsgeräte +Wirtschaft & Industrie > Einzelhandel > Präsentationsständer für Bekleidung +Wirtschaft & Industrie > Einzelhandel > Schaufensterdeko & -puppen +Wirtschaft & Industrie > Einzelhandel > Schaufensterpuppen +Wirtschaft & Industrie > Einzelhandel > Schaufensterpuppenteile +Wirtschaft & Industrie > Einzelhandel > Vitrinen +Wirtschaft & Industrie > Film & Fernsehen +Wirtschaft & Industrie > Finanzwesen & Versicherung +Wirtschaft & Industrie > Finanzwesen & Versicherung > Bullion +Wirtschaft & Industrie > Forst- & Holzwirtschaft +Wirtschaft & Industrie > Friseur- & Kosmetikgewerbe +Wirtschaft & Industrie > Friseur- & Kosmetikgewerbe > Friseurumhänge & Halskrausen +Wirtschaft & Industrie > Friseur- & Kosmetikgewerbe > Pedikürestuhl +Wirtschaft & Industrie > Friseur- & Kosmetikgewerbe > Salonstühle +Wirtschaft & Industrie > Gewerbliche Lagerung +Wirtschaft & Industrie > Gewerbliche Lagerung > Frachtcontainer +Wirtschaft & Industrie > Gewerbliche Lagerung > Industrieregale +Wirtschaft & Industrie > Gewerbliche Lagerung > Industrieschränke +Wirtschaft & Industrie > Gewerbliche Lagerung > Zäune, Einfriedungen & Türen +Wirtschaft & Industrie > Herstellung +Wirtschaft & Industrie > Hotels & Gaststätten +Wirtschaft & Industrie > Landwirtschaft +Wirtschaft & Industrie > Landwirtschaft > Viehhaltung +Wirtschaft & Industrie > Landwirtschaft > Viehhaltung > Brutapparate +Wirtschaft & Industrie > Landwirtschaft > Viehhaltung > Viehfutter +Wirtschaft & Industrie > Landwirtschaft > Viehhaltung > Viehfutterspender +Wirtschaft & Industrie > Landwirtschaft > Viehhaltung > Viehhalfter +Wirtschaft & Industrie > Materialbeförderung +Wirtschaft & Industrie > Materialbeförderung > Aufzüge & Hebeeinrichtungen +Wirtschaft & Industrie > Materialbeförderung > Aufzüge & Hebeeinrichtungen > Flaschenzüge & Rollen +Wirtschaft & Industrie > Materialbeförderung > Aufzüge & Hebeeinrichtungen > Hebezüge, Kräne & Laufkatzen +Wirtschaft & Industrie > Materialbeförderung > Aufzüge & Hebeeinrichtungen > Hubwagen +Wirtschaft & Industrie > Materialbeförderung > Aufzüge & Hebeeinrichtungen > Personenaufzüge +Wirtschaft & Industrie > Materialbeförderung > Aufzüge & Hebeeinrichtungen > Seilwinden +Wirtschaft & Industrie > Materialbeförderung > Förderanlagen +Wirtschaft & Industrie > Materialbeförderung > Paletten & Ladeflächen +Wirtschaft & Industrie > Medizinischer Bereich +Wirtschaft & Industrie > Medizinischer Bereich > Krankenhaus-Vorhänge +Wirtschaft & Industrie > Medizinischer Bereich > Krankenhausbekleidung +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Bettwäsche +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Automatisierte externe Defibrillatoren +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Medizinische Hebegürtel +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Otoskope & Ophthalmoskope +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Patientenlifter +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Reflexhämmer +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Stethoskope +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Tragen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Vitaldatenmonitore +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Geräte > Zubehör für Vitaldatenmonitore +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Instrumente +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Instrumente > Chirurgische Nadeln und Fäden +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Instrumente > Medizinische Zangen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Instrumente > Skalpelle +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Instrumente > Skalpellklingen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Chiropraktische Tische +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Krankenhaus- und Pflegebetten +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medikamentenaufbewahrung +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medizinische Wagen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medizinische Wagen > Infusionsständer & -wagen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Medizinische Wagen > Reanimationswagen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > OP-Tische +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Möbel > Untersuchungsstühle & -tische +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Schulungsgeräte +Wirtschaft & Industrie > Medizinischer Bereich > Medizinische Schulungsgeräte > HLW-Puppen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf +Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Einweghandschuhe +Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Fingerlinge +Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Mundspatel +Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Nadeln & Spritzen +Wirtschaft & Industrie > Medizinischer Bereich > Medizinischer Bedarf > Stomazubehör +Wirtschaft & Industrie > Medizinischer Bereich > OP-Bekleidung +Wirtschaft & Industrie > Medizinischer Bereich > OP-Hauben +Wirtschaft & Industrie > Medizinischer Bereich > OP-Kittel +Wirtschaft & Industrie > Nahrungsmittelservice +Wirtschaft & Industrie > Nahrungsmittelservice > Auslagenschutz +Wirtschaft & Industrie > Nahrungsmittelservice > Backwarenbehälter +Wirtschaft & Industrie > Nahrungsmittelservice > Einweg-Serviergeschirr +Wirtschaft & Industrie > Nahrungsmittelservice > Einweg-Serviergeschirr > Einwegtabletts +Wirtschaft & Industrie > Nahrungsmittelservice > Einwegbehälter +Wirtschaft & Industrie > Nahrungsmittelservice > Einwegdeckel +Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr +Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegbecher +Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegbesteck +Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegschüsseln +Wirtschaft & Industrie > Nahrungsmittelservice > Einweggeschirr > Einwegteller +Wirtschaft & Industrie > Nahrungsmittelservice > Eisbehälter +Wirtschaft & Industrie > Nahrungsmittelservice > Gemüseschleudern +Wirtschaft & Industrie > Nahrungsmittelservice > Hot-Dog-Grills +Wirtschaft & Industrie > Nahrungsmittelservice > Kippbare Industriepfannen +Wirtschaft & Industrie > Nahrungsmittelservice > Lebensmittelkörbe +Wirtschaft & Industrie > Nahrungsmittelservice > Scheck- & Kartenetuis +Wirtschaft & Industrie > Nahrungsmittelservice > Servierwagen +Wirtschaft & Industrie > Nahrungsmittelservice > Spülwannen +Wirtschaft & Industrie > Nahrungsmittelservice > Takeaway-Behälter +Wirtschaft & Industrie > Nahrungsmittelservice > Teller- & Speisenwärmer +Wirtschaft & Industrie > Nahrungsmittelservice > Verkaufsautomaten +Wirtschaft & Industrie > Piercing & Tätowieren +Wirtschaft & Industrie > Piercing & Tätowieren > Piercingbedarf +Wirtschaft & Industrie > Piercing & Tätowieren > Piercingbedarf > Piercingnadeln +Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf +Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tattoo-Abdeckungen +Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tätowierfarben +Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tätowiermaschinen +Wirtschaft & Industrie > Piercing & Tätowieren > Tätowierbedarf > Tätowiernadeln +Wirtschaft & Industrie > Reinigungswagen +Wirtschaft & Industrie > Schwermaschinen +Wirtschaft & Industrie > Schwermaschinen > Häcksler +Wirtschaft & Industrie > Strafverfolgung +Wirtschaft & Industrie > Strafverfolgung > Metalldetektoren +Wirtschaft & Industrie > Strafverfolgung > Schellen +Wirtschaft & Industrie > Werbung & Marketing +Wirtschaft & Industrie > Werbung & Marketing > Broschüren +Wirtschaft & Industrie > Werbung & Marketing > Messestand-Displays +Wirtschaft & Industrie > Werbung & Marketing > Messetheken +Wirtschaft & Industrie > Wissenschaft & Labor +Wirtschaft & Industrie > Wissenschaft & Labor > Biochemikalien +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Autoklaven +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Gefriertrockenmaschinen +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Labor-Gefrierschränke +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Labor-Heizplatten +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Labormixer +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Labortrichter +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Laboröfen +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskope +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Ersatzlampen für Mikroskope +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Mikroskop-Objektivlinsen +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Mikroskopkameras +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Mikroskopokulare & Adapter +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikroskopzubehör > Objektträger +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Mikrotome +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Spektrometer +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Trockeneismaschinen +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Zentrifugen +Wirtschaft & Industrie > Wissenschaft & Labor > Laborausstattung > Zubehör für Spektrometer +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Bechergläse +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Laborkolben +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Messzylinder +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Petrischalen +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Pipetten +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Reagenzglasständer +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Reagenzgläser +Wirtschaft & Industrie > Wissenschaft & Labor > Laborbedarf > Spritzflaschen +Wirtschaft & Industrie > Wissenschaft & Labor > Laborchemikalien +Wirtschaft & Industrie > Wissenschaft & Labor > Laborproben +Wirtschaft & Industrie > Wissenschaft & Labor > Sezierinstrumente +Wirtschaft & Industrie > Zahnmedizin +Wirtschaft & Industrie > Zahnmedizin > Prophy-Paste +Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente +Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente > Dappengläser +Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente > Dentalspiegel +Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente > Prophy-Kelche +Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente > Prophy-Köpfe +Wirtschaft & Industrie > Zahnmedizin > Zahnmedizinische Instrumente > Zahnmedizinische Instrumentensets +Wirtschaft & Industrie > Zahnmedizin > Zahnzement \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Files/taxonomy.en-US.txt b/src/Plugins/SmartStore.GoogleMerchantCenter/Files/taxonomy.en-US.txt new file mode 100644 index 0000000000..671672c564 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Files/taxonomy.en-US.txt @@ -0,0 +1,5427 @@ +Animals & Pet Supplies +Animals & Pet Supplies > Live Animals +Animals & Pet Supplies > Pet Supplies +Animals & Pet Supplies > Pet Supplies > Bird Supplies +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories > Bird Cage Bird Baths +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories > Bird Cage Food & Water Dishes +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cages & Stands +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Food +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Gyms & Playstands +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Ladders & Perches +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Toys +Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Treats +Animals & Pet Supplies > Pet Supplies > Cat Supplies +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Apparel +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Beds +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Furniture +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Furniture Accessories +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Box Liners +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Box Mats +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Boxes +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Toys +Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Treats +Animals & Pet Supplies > Pet Supplies > Dog Supplies +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Apparel +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Beds +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Diaper Pads & Liners +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Diapers +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Houses +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennel & Run Accessories +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennels & Runs +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Toys +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Treadmills +Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Treats +Animals & Pet Supplies > Pet Supplies > Fish Supplies +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium & Pond Tubing +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Air Stones & Diffusers +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Cleaning Supplies +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Decor +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Filters +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Fish Nets +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Gravel & Substrates +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Lighting +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Overflow Boxes +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Stands +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Temperature Controllers +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Water Treatments +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquariums +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquatic Plant Fertilizers +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Feeders +Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Food +Animals & Pet Supplies > Pet Supplies > Pet Agility Equipment +Animals & Pet Supplies > Pet Supplies > Pet Apparel Hangers +Animals & Pet Supplies > Pet Supplies > Pet Bed Accessories +Animals & Pet Supplies > Pet Supplies > Pet Bells & Charms +Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors +Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Glucose Meters +Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Pedometers +Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Thermometers +Animals & Pet Supplies > Pet Supplies > Pet Bowl Mats +Animals & Pet Supplies > Pet Supplies > Pet Bowl Stands +Animals & Pet Supplies > Pet Supplies > Pet Bowls, Feeders & Waterers +Animals & Pet Supplies > Pet Supplies > Pet Carrier & Crate Accessories +Animals & Pet Supplies > Pet Supplies > Pet Carriers & Crates +Animals & Pet Supplies > Pet Supplies > Pet Collars & Harnesses +Animals & Pet Supplies > Pet Supplies > Pet Containment Systems +Animals & Pet Supplies > Pet Supplies > Pet Door Accessories +Animals & Pet Supplies > Pet Supplies > Pet Doors +Animals & Pet Supplies > Pet Supplies > Pet Eye Drops & Lubricants +Animals & Pet Supplies > Pet Supplies > Pet First Aid & Emergency Kits +Animals & Pet Supplies > Pet Supplies > Pet Flea & Tick Control +Animals & Pet Supplies > Pet Supplies > Pet Food Containers +Animals & Pet Supplies > Pet Supplies > Pet Food Scoops +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Combs & Brushes +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Fragrances & Deodorizing Sprays +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Hair Clippers & Trimmers +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Hair Dryers +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Polish +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Tools +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Shampoo & Conditioner +Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Wipes +Animals & Pet Supplies > Pet Supplies > Pet Heating Pad Accessories +Animals & Pet Supplies > Pet Supplies > Pet Heating Pads +Animals & Pet Supplies > Pet Supplies > Pet ID Tags +Animals & Pet Supplies > Pet Supplies > Pet Leash Extensions +Animals & Pet Supplies > Pet Supplies > Pet Leashes +Animals & Pet Supplies > Pet Supplies > Pet Medical Collars +Animals & Pet Supplies > Pet Supplies > Pet Medical Tape & Bandages +Animals & Pet Supplies > Pet Supplies > Pet Medicine +Animals & Pet Supplies > Pet Supplies > Pet Muzzles +Animals & Pet Supplies > Pet Supplies > Pet Oral Care Supplies +Animals & Pet Supplies > Pet Supplies > Pet Playpens +Animals & Pet Supplies > Pet Supplies > Pet Steps & Ramps +Animals & Pet Supplies > Pet Supplies > Pet Strollers +Animals & Pet Supplies > Pet Supplies > Pet Sunscreen +Animals & Pet Supplies > Pet Supplies > Pet Training Aids +Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Clickers & Treat Dispensers +Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Pad Holders +Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Pads +Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Sprays & Solutions +Animals & Pet Supplies > Pet Supplies > Pet Vitamins & Supplements +Animals & Pet Supplies > Pet Supplies > Pet Waste Bag Dispensers & Holders +Animals & Pet Supplies > Pet Supplies > Pet Waste Bags +Animals & Pet Supplies > Pet Supplies > Pet Waste Disposal Systems & Tools +Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies +Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Food +Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Accessories +Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Heating & Lighting +Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitats +Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Substrates +Animals & Pet Supplies > Pet Supplies > Small Animal Supplies +Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Bedding +Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Food +Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitat Accessories +Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitats & Cages +Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Treats +Animals & Pet Supplies > Pet Supplies > Vehicle Pet Barriers +Apparel & Accessories +Apparel & Accessories > Clothing +Apparel & Accessories > Clothing > Activewear +Apparel & Accessories > Clothing > Activewear > Bicycle Activewear +Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Bibs +Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Jerseys +Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Shorts & Briefs +Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Skinsuits +Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Tights +Apparel & Accessories > Clothing > Activewear > Boxing Shorts +Apparel & Accessories > Clothing > Activewear > Dance Dresses, Skirts & Costumes +Apparel & Accessories > Clothing > Activewear > Football Pants +Apparel & Accessories > Clothing > Activewear > Hunting Clothing +Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Ghillie Suits +Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Fishing Vests +Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Tactical Pants +Apparel & Accessories > Clothing > Activewear > Martial Arts Shorts +Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing +Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Jackets +Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Pants +Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Suits +Apparel & Accessories > Clothing > Activewear > Paintball Clothing +Apparel & Accessories > Clothing > Baby & Toddler Clothing +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Bottoms +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Diaper Covers +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Dresses +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outerwear +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outfits +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Sleepwear +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Socks & Tights +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Swimwear +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Tops +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby One-Pieces +Apparel & Accessories > Clothing > Baby & Toddler Clothing > Toddler Underwear +Apparel & Accessories > Clothing > Dresses +Apparel & Accessories > Clothing > One-Pieces +Apparel & Accessories > Clothing > One-Pieces > Jumpsuits & Rompers +Apparel & Accessories > Clothing > One-Pieces > Leotards & Unitards +Apparel & Accessories > Clothing > One-Pieces > Overalls +Apparel & Accessories > Clothing > Outerwear +Apparel & Accessories > Clothing > Outerwear > Chaps +Apparel & Accessories > Clothing > Outerwear > Coats & Jackets +Apparel & Accessories > Clothing > Outerwear > Rain Pants +Apparel & Accessories > Clothing > Outerwear > Rain Suits +Apparel & Accessories > Clothing > Outerwear > Snow Pants & Suits +Apparel & Accessories > Clothing > Outerwear > Vests +Apparel & Accessories > Clothing > Outfit Sets +Apparel & Accessories > Clothing > Pants +Apparel & Accessories > Clothing > Shirts & Tops +Apparel & Accessories > Clothing > Shorts +Apparel & Accessories > Clothing > Skirts +Apparel & Accessories > Clothing > Skorts +Apparel & Accessories > Clothing > Sleepwear & Loungewear +Apparel & Accessories > Clothing > Sleepwear & Loungewear > Loungewear +Apparel & Accessories > Clothing > Sleepwear & Loungewear > Nightgowns +Apparel & Accessories > Clothing > Sleepwear & Loungewear > Pajamas +Apparel & Accessories > Clothing > Sleepwear & Loungewear > Robes +Apparel & Accessories > Clothing > Suits +Apparel & Accessories > Clothing > Suits > Pant Suits +Apparel & Accessories > Clothing > Suits > Skirt Suits +Apparel & Accessories > Clothing > Suits > Tuxedos +Apparel & Accessories > Clothing > Swimwear +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Dirndls +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Hakama Trousers +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Japanese Black Formal Wear +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimono Outerwear +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Religious Ceremonial Clothing +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Religious Ceremonial Clothing > Baptism & Communion Dresses +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Saris & Lehengas +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Traditional Leather Pants +Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Yukata +Apparel & Accessories > Clothing > Underwear & Socks +Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories +Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Strap Pads +Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Straps & Extenders +Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Enhancing Inserts +Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Petals & Concealers +Apparel & Accessories > Clothing > Underwear & Socks > Bras +Apparel & Accessories > Clothing > Underwear & Socks > Hosiery +Apparel & Accessories > Clothing > Underwear & Socks > Jock Straps +Apparel & Accessories > Clothing > Underwear & Socks > Lingerie +Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories +Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garter Belts +Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garters +Apparel & Accessories > Clothing > Underwear & Socks > Long Johns +Apparel & Accessories > Clothing > Underwear & Socks > Petticoats & Pettipants +Apparel & Accessories > Clothing > Underwear & Socks > Shapewear +Apparel & Accessories > Clothing > Underwear & Socks > Socks +Apparel & Accessories > Clothing > Underwear & Socks > Undershirts +Apparel & Accessories > Clothing > Underwear & Socks > Underwear +Apparel & Accessories > Clothing > Underwear & Socks > Underwear Slips +Apparel & Accessories > Clothing > Uniforms +Apparel & Accessories > Clothing > Uniforms > Contractor Pants & Coveralls +Apparel & Accessories > Clothing > Uniforms > Flight Suits +Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms +Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Hats +Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Jackets +Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Pants +Apparel & Accessories > Clothing > Uniforms > Military Uniforms +Apparel & Accessories > Clothing > Uniforms > School Uniforms +Apparel & Accessories > Clothing > Uniforms > Security Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Baseball Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Basketball Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cheerleading Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cricket Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Football Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Hockey Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Martial Arts Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Officiating Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Soccer Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Softball Uniforms +Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Wrestling Uniforms +Apparel & Accessories > Clothing > Uniforms > White Coats +Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses +Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Bridal Party Dresses +Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Wedding Dresses +Apparel & Accessories > Clothing Accessories +Apparel & Accessories > Clothing Accessories > Arm Warmers & Sleeves +Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories +Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Belts +Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Gloves & Mittens +Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Hats +Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby Protective Wear +Apparel & Accessories > Clothing Accessories > Balaclavas +Apparel & Accessories > Clothing Accessories > Bandanas & Headties +Apparel & Accessories > Clothing Accessories > Belt Buckles +Apparel & Accessories > Clothing Accessories > Belts +Apparel & Accessories > Clothing Accessories > Bridal Accessories +Apparel & Accessories > Clothing Accessories > Bridal Accessories > Bridal Veils +Apparel & Accessories > Clothing Accessories > Button Studs +Apparel & Accessories > Clothing Accessories > Collar Stays +Apparel & Accessories > Clothing Accessories > Cufflinks +Apparel & Accessories > Clothing Accessories > Decorative Fans +Apparel & Accessories > Clothing Accessories > Earmuffs +Apparel & Accessories > Clothing Accessories > Gloves & Mittens +Apparel & Accessories > Clothing Accessories > Hair Accessories +Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Bun & Volume Shapers +Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Combs +Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Extensions +Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Forks & Sticks +Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Nets +Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips +Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Wreaths +Apparel & Accessories > Clothing Accessories > Hair Accessories > Headbands +Apparel & Accessories > Clothing Accessories > Hair Accessories > Ponytail Holders +Apparel & Accessories > Clothing Accessories > Hair Accessories > Tiaras +Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories +Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories > Wig Caps +Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories > Wig Glue & Tape +Apparel & Accessories > Clothing Accessories > Hair Accessories > Wigs +Apparel & Accessories > Clothing Accessories > Hand Muffs +Apparel & Accessories > Clothing Accessories > Handkerchiefs +Apparel & Accessories > Clothing Accessories > Hats +Apparel & Accessories > Clothing Accessories > Headwear +Apparel & Accessories > Clothing Accessories > Headwear > Fascinators +Apparel & Accessories > Clothing Accessories > Headwear > Headdresses +Apparel & Accessories > Clothing Accessories > Headwear > Turbans +Apparel & Accessories > Clothing Accessories > Leg Warmers +Apparel & Accessories > Clothing Accessories > Leis +Apparel & Accessories > Clothing Accessories > Maternity Belts & Support Bands +Apparel & Accessories > Clothing Accessories > Neck Gaiters +Apparel & Accessories > Clothing Accessories > Neckties +Apparel & Accessories > Clothing Accessories > Pinback Buttons +Apparel & Accessories > Clothing Accessories > Sashes +Apparel & Accessories > Clothing Accessories > Scarves & Shawls +Apparel & Accessories > Clothing Accessories > Sunglasses +Apparel & Accessories > Clothing Accessories > Suspenders +Apparel & Accessories > Clothing Accessories > Tie Clips +Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories +Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Obis +Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Tabi Socks +Apparel & Accessories > Clothing Accessories > Wristbands +Apparel & Accessories > Costumes & Accessories +Apparel & Accessories > Costumes & Accessories > Costume Accessories +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Bald Caps +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Accessory Sets +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Capes +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Gloves +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Hats +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Special Effects +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Tobacco Products +Apparel & Accessories > Costumes & Accessories > Costume Accessories > Pretend Jewelry +Apparel & Accessories > Costumes & Accessories > Costume Shoes +Apparel & Accessories > Costumes & Accessories > Costumes +Apparel & Accessories > Costumes & Accessories > Masks +Apparel & Accessories > Handbag & Wallet Accessories +Apparel & Accessories > Handbag & Wallet Accessories > Checkbook Covers +Apparel & Accessories > Handbag & Wallet Accessories > Keychains +Apparel & Accessories > Handbag & Wallet Accessories > Lanyards +Apparel & Accessories > Handbag & Wallet Accessories > Wallet Chains +Apparel & Accessories > Handbags, Wallets & Cases +Apparel & Accessories > Handbags, Wallets & Cases > Badge & Pass Holders +Apparel & Accessories > Handbags, Wallets & Cases > Business Card Cases +Apparel & Accessories > Handbags, Wallets & Cases > Handbags +Apparel & Accessories > Handbags, Wallets & Cases > Wallets & Money Clips +Apparel & Accessories > Jewelry +Apparel & Accessories > Jewelry > Anklets +Apparel & Accessories > Jewelry > Body Jewelry +Apparel & Accessories > Jewelry > Bracelets +Apparel & Accessories > Jewelry > Brooches & Lapel Pins +Apparel & Accessories > Jewelry > Charms & Pendants +Apparel & Accessories > Jewelry > Earrings +Apparel & Accessories > Jewelry > Jewelry Sets +Apparel & Accessories > Jewelry > Necklaces +Apparel & Accessories > Jewelry > Rings +Apparel & Accessories > Jewelry > Watch Accessories +Apparel & Accessories > Jewelry > Watch Accessories > Watch Bands +Apparel & Accessories > Jewelry > Watch Accessories > Watch Stickers & Decals +Apparel & Accessories > Jewelry > Watch Accessories > Watch Winders +Apparel & Accessories > Jewelry > Watches +Apparel & Accessories > Shoe Accessories +Apparel & Accessories > Shoe Accessories > Boot Liners +Apparel & Accessories > Shoe Accessories > Gaiters +Apparel & Accessories > Shoe Accessories > Shoe Covers +Apparel & Accessories > Shoe Accessories > Shoelaces +Apparel & Accessories > Shoe Accessories > Spurs +Apparel & Accessories > Shoes +Arts & Entertainment +Arts & Entertainment > Event Tickets +Arts & Entertainment > Hobbies & Creative Arts +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Candle Making Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Drawing & Painting Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Fabric Repair Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Incense Making Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Jewelry Making Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Mosaic Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Needlecraft Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Scrapbooking & Stamping Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Toy Craft Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Cardstock & Scrapbooking Paper +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Construction Paper +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Craft Foil +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Drawing & Painting Paper +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Origami Paper +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Transfer Paper +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Vellum Paper +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Buttons & Snaps +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Clasps & Hooks +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Eyelets & Grommets +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Hook and Loop Fasteners +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Zipper Pulls +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Zippers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art & Craft Paint +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art Fixatives +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art Ink +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Ceramic & Pottery Glazes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Craft Dyes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Ink Pads +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Paint Mediums +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Craft Foam & Styrofoam +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Craft Wood & Shapes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Papier Mache Shapes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Wreath & Floral Frames +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Craft & Office Glue +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Craft Magnets +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Decorative Tape +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Floral Tape +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Fusible Tape +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Jewelry & Beading Cord +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Thread & Floss +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Unspun Fiber +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Yarn +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Craft Pipe Cleaners +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Floral Wire +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Jewelry & Beading Wire +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Appliques & Patches +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Beads +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Bows & Yo-Yos +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Decorative Stickers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Elastic +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Feathers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Jewelry Findings +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Loose Stones +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Rhinestones & Flatbacks +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Ribbons & Trim +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Sequins & Glitter +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Sew-in Labels +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embossing Powder +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Batting & Stuffing +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Filling Pellets +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Pillow Forms +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Leather & Vinyl +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Clay & Modeling Dough +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Papier Mache Mixes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Plaster Gauze +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Pottery Slips +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Raw Candle Wax +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Needlecraft Canvas +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Painting Canvas +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Plastic Canvas +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Fabric +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Interfacing +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Printable Fabric +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Wick Tabs +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Wicks +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Craft Knife Blades +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Craft Machine Cases & Covers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Extension Tables +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Feet +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Replacement Parts +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Spinning Wheel Accessories +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Stamp Blocks +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Blocking Mats +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Blocking Wires +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools > Palette Knives +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools > Palettes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft & Office Scissors +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Cutters & Embossers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Knives +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Scoring Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Embossing Heat Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Embossing Pens & Styluses +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Seam Rippers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Thread & Yarn Cutters +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Decoration Makers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Art Brushes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Brayer Rollers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Decorative Stamps +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Drafting Compasses +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Screen Printing Squeegees +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stencil Machines +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stencils & Die Cuts +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stitch Markers & Counters +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Textile Art Gauges & Rulers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Wood Burning Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Cutting Mats +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Dress Forms +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Felting Pads & Mats +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Frames, Hoops & Stretchers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Glue Guns +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Light Boxes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Crochet Hooks +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Hand-Sewing Needles +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Knitting Needles +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Latch & Locker Hooks +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Sewing Machine Needles +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Safety Pins +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Straight Pins +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Felting Needles & Machines +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Hand Looms +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Mechanical Looms +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Sewing Machines +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Spinning Wheels +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thimbles & Sewing Palms +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Fiber Cards & Brushes +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Hand Spindles +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Needle Threaders +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread & Yarn Guides +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread & Yarn Spools +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread, Yarn & Bobbin Winders +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Weaving Beaters +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Weaving Shuttles +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Needle, Pin & Hook Organizers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Sewing Baskets & Kits +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Thread & Yarn Organizers +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Beading Patterns +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Craft Molds +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Felting Molds +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Needlecraft Patterns +Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Sewing Patterns +Arts & Entertainment > Hobbies & Creative Arts > Collectibles +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Autographs +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Trading Cards +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Guns +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Knives +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Swords +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Sword Stands & Displays +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Postage Stamps +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Rocks & Fossils +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Model Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Models +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Seal Stamps +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Auto Racing Autographed Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Baseball & Softball Autographed Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Basketball Autographed Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Boxing Autographed Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Football Autographed Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Hockey Autographed Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Soccer Autographed Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Tennis Autographed Sports Paraphernalia +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Auto Racing Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Baseball & Softball Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Basketball Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Football Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Hockey Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Soccer Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Tennis Fan Accessories +Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Vintage Advertisements +Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies +Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Beer Brewing Grains & Malts +Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Bottling Bottles +Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Homebrewing & Winemaking Kits +Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Wine Making +Arts & Entertainment > Hobbies & Creative Arts > Juggling +Arts & Entertainment > Hobbies & Creative Arts > Magic & Novelties +Arts & Entertainment > Hobbies & Creative Arts > Model Making +Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Rocketry +Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Train Accessories +Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Trains & Train Sets +Arts & Entertainment > Hobbies & Creative Arts > Model Making > Scale Model Kits +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Care Kits +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Cleaners & Sanitizers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Cleaning Tools +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Guards +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Lubricants +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Polishing Cloths +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Cases & Gigbags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Mouthpieces +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Mutes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Replacement Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Straps & Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Conductor Batons +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Electronic Tuners +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Metronomes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Benches & Stools +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Lyres & Flip Folders +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Music Stand Bags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Music Stand Lights +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Sheet Music Clips +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Cabinets +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Covers & Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Footswitches +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Knobs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Tubes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifiers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Musical Keyboard Bags & Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Musical Keyboard Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Sustain Pedals +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Cymbal & Drum Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Cymbal & Drum Mutes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Heads +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Keys +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Bass Drum Beaters +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Drum Kit Mounting Hardware +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Drum Pedals +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Stick & Brush Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Stick & Brush Accessories > Drum Stick & Brush Bags & Holders +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Sticks & Brushes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Electronic Drum Modules +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Bags & Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Stands & Mounts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Percussion Mallets +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Percussion Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Acoustic Guitar Pickups +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Capos +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Electric Guitar Pickups +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Cases & Gig Bags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Fittings & Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Humidifiers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Picks +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Slides +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Straps +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar String Winders +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Strings +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Tuning Pegs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Bow Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Bows +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Fittings & Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Mutes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Pickups +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Strings +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > Bow Rosin +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Cleaning Cloths +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Polish +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning > Bassoon Swabs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Cases & Gigbags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Bocals +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Small Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Reeds +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Straps & Supports +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Care Kits +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Pad Savers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Swabs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Cases & Gigbags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Ligatures & Caps +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Barrels +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Bells +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Mouthpieces +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Small Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Pegs & Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Reeds +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Straps & Supports +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Care Kits +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Cleaning Rods +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Swabs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Cases & Gigbags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Headjoints +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Small Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Pegs & Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Holders +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Care Kits +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Swabs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Cases & Gigbags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts > Oboe Small Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Pegs & Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Reeds +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Straps & Supports +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Care Kits +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Pad Savers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Swabs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Cases & Gigbags +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Ligatures & Caps +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Mouthpieces +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Necks +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Small Parts +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Pegs & Stands +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Reeds +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Straps & Supports +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Cork Grease +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Polishing Cloths +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Reed Cases +Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Reed Knives +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Accordions & Concertinas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Bagpipes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Alto & Baritone Horns +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Euphoniums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > French Horns +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Trombones +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Trumpets & Cornets +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Tubas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Audio Samplers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > MIDI Controllers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Musical Keyboards +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Sound Synthesizers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Bass Drums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Cymbals +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Drum Kits +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Electronic Drums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Glockenspiels & Xylophones +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Gongs +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Claves & Castanets +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Finger & Hand Cymbals +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Bells & Chimes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Bongos +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Cajons +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Congas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Frame Drums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Goblet Drums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Tablas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Talking Drums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Blocks +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Cowbells +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Scrapers & Ratchets +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Shakers +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Triangles +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Tambourines +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Vibraslaps +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hi-Hats +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Practice Pads +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Snare Drums +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Tom-Toms +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Pianos +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Cellos +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Guitars +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Harps +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Upright Basses +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violins +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Bassoons +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Clarinets +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutophones +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Harmonicas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Jew's Harps +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Melodicas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Musical Pipes +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Oboes & English Horns +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Ocarinas +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Recorders +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Saxophones +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Tin Whistles +Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Train Whistles +Arts & Entertainment > Party & Celebration +Arts & Entertainment > Party & Celebration > Gift Giving +Arts & Entertainment > Party & Celebration > Gift Giving > Corsage & Boutonnière Pins +Arts & Entertainment > Party & Celebration > Gift Giving > Corsages & Boutonnières +Arts & Entertainment > Party & Celebration > Gift Giving > Fresh Cut Flowers +Arts & Entertainment > Party & Celebration > Gift Giving > Gift Cards & Certificates +Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping +Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Bags +Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Boxes & Tins +Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Tags & Labels +Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Tissue Paper +Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Wrapping Paper +Arts & Entertainment > Party & Celebration > Gift Giving > Greeting & Note Cards +Arts & Entertainment > Party & Celebration > Party Supplies +Arts & Entertainment > Party & Celebration > Party Supplies > Advice Cards +Arts & Entertainment > Party & Celebration > Party Supplies > Balloon Kits +Arts & Entertainment > Party & Celebration > Party Supplies > Balloons +Arts & Entertainment > Party & Celebration > Party Supplies > Banners +Arts & Entertainment > Party & Celebration > Party Supplies > Birthday Candles +Arts & Entertainment > Party & Celebration > Party Supplies > Chair Sashes +Arts & Entertainment > Party & Celebration > Party Supplies > Cocktail Decorations +Arts & Entertainment > Party & Celebration > Party Supplies > Confetti +Arts & Entertainment > Party & Celebration > Party Supplies > Decorative Pom-Poms +Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games +Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong +Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong > Beer Pong Tables +Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Straws & Stirrers +Arts & Entertainment > Party & Celebration > Party Supplies > Envelope Seals +Arts & Entertainment > Party & Celebration > Party Supplies > Event Programs +Arts & Entertainment > Party & Celebration > Party Supplies > Fireworks & Firecrackers +Arts & Entertainment > Party & Celebration > Party Supplies > Inflatable Party Decorations +Arts & Entertainment > Party & Celebration > Party Supplies > Invitations +Arts & Entertainment > Party & Celebration > Party Supplies > Noisemakers & Party Blowers +Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors +Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors > Wedding Favors +Arts & Entertainment > Party & Celebration > Party Supplies > Party Games +Arts & Entertainment > Party & Celebration > Party Supplies > Party Hats +Arts & Entertainment > Party & Celebration > Party Supplies > Party Streamers & Curtains +Arts & Entertainment > Party & Celebration > Party Supplies > Party Supply Kits +Arts & Entertainment > Party & Celebration > Party Supplies > Piñatas +Arts & Entertainment > Party & Celebration > Party Supplies > Place Card Holders +Arts & Entertainment > Party & Celebration > Party Supplies > Place Cards +Arts & Entertainment > Party & Celebration > Party Supplies > Response Cards +Arts & Entertainment > Party & Celebration > Party Supplies > Sparklers +Arts & Entertainment > Party & Celebration > Party Supplies > Special Occasion Card Boxes & Holders +Arts & Entertainment > Party & Celebration > Party Supplies > Spray String +Arts & Entertainment > Party & Celebration > Special Effects +Arts & Entertainment > Party & Celebration > Special Effects > Disco Balls +Arts & Entertainment > Party & Celebration > Special Effects > Fog Machines +Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Controllers +Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Light Stands +Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Lighting +Arts & Entertainment > Party & Celebration > Trophies & Awards +Baby & Toddler +Baby & Toddler > Baby Bathing +Baby & Toddler > Baby Bathing > Baby Bathtubs & Bath Seats +Baby & Toddler > Baby Bathing > Shower Visors +Baby & Toddler > Baby Gift Sets +Baby & Toddler > Baby Health +Baby & Toddler > Baby Health > Baby Health & Grooming Kits +Baby & Toddler > Baby Health > Nasal Aspirators +Baby & Toddler > Baby Health > Pacifier Clips & Holders +Baby & Toddler > Baby Health > Pacifier Wipes +Baby & Toddler > Baby Health > Pacifiers & Teethers +Baby & Toddler > Baby Safety +Baby & Toddler > Baby Safety > Baby & Pet Gate Accessories +Baby & Toddler > Baby Safety > Baby & Pet Gates +Baby & Toddler > Baby Safety > Baby Monitors +Baby & Toddler > Baby Safety > Baby Safety Harnesses & Leashes +Baby & Toddler > Baby Safety > Baby Safety Locks & Guards +Baby & Toddler > Baby Safety > Baby Safety Rails +Baby & Toddler > Baby Toys & Activity Equipment +Baby & Toddler > Baby Toys & Activity Equipment > Alphabet Toys +Baby & Toddler > Baby Toys & Activity Equipment > Baby Activity Toys +Baby & Toddler > Baby Toys & Activity Equipment > Baby Bouncers & Rockers +Baby & Toddler > Baby Toys & Activity Equipment > Baby Jumpers & Swings +Baby & Toddler > Baby Toys & Activity Equipment > Baby Mobile Accessories +Baby & Toddler > Baby Toys & Activity Equipment > Baby Mobiles +Baby & Toddler > Baby Toys & Activity Equipment > Baby Soothers +Baby & Toddler > Baby Toys & Activity Equipment > Baby Walkers & Entertainers +Baby & Toddler > Baby Toys & Activity Equipment > Play Mats & Gyms +Baby & Toddler > Baby Toys & Activity Equipment > Play Yards +Baby & Toddler > Baby Toys & Activity Equipment > Push & Pull Toys +Baby & Toddler > Baby Toys & Activity Equipment > Rattles +Baby & Toddler > Baby Toys & Activity Equipment > Sorting & Stacking Toys +Baby & Toddler > Baby Transport +Baby & Toddler > Baby Transport > Baby & Toddler Car Seats +Baby & Toddler > Baby Transport > Baby Carriers +Baby & Toddler > Baby Transport > Baby Strollers +Baby & Toddler > Baby Transport Accessories +Baby & Toddler > Baby Transport Accessories > Baby & Toddler Car Seat Accessories +Baby & Toddler > Baby Transport Accessories > Baby Carrier Accessories +Baby & Toddler > Baby Transport Accessories > Baby Stroller Accessories +Baby & Toddler > Baby Transport Accessories > Baby Transport Liners & Sacks +Baby & Toddler > Baby Transport Accessories > Shopping Cart & High Chair Covers +Baby & Toddler > Diapering +Baby & Toddler > Diapering > Baby Wipe Dispensers & Warmers +Baby & Toddler > Diapering > Baby Wipes +Baby & Toddler > Diapering > Changing Mat & Tray Covers +Baby & Toddler > Diapering > Changing Mats & Trays +Baby & Toddler > Diapering > Diaper Kits +Baby & Toddler > Diapering > Diaper Liners +Baby & Toddler > Diapering > Diaper Organizers +Baby & Toddler > Diapering > Diaper Pail Accessories +Baby & Toddler > Diapering > Diaper Pails +Baby & Toddler > Diapering > Diaper Rash Treatments +Baby & Toddler > Diapering > Diaper Wet Bags +Baby & Toddler > Diapering > Diapers +Baby & Toddler > Nursing & Feeding +Baby & Toddler > Nursing & Feeding > Baby & Toddler Food +Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Cereal +Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Drinks +Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Food +Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Formula +Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Snacks +Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Toddler Nutrition Drinks & Shakes +Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples & Liners +Baby & Toddler > Nursing & Feeding > Baby Bottles +Baby & Toddler > Nursing & Feeding > Baby Care Timers +Baby & Toddler > Nursing & Feeding > Bibs +Baby & Toddler > Nursing & Feeding > Bottle Warmers & Sterilizers +Baby & Toddler > Nursing & Feeding > Breast Milk Storage Containers +Baby & Toddler > Nursing & Feeding > Breast Pump Accessories +Baby & Toddler > Nursing & Feeding > Breast Pumps +Baby & Toddler > Nursing & Feeding > Burp Cloths +Baby & Toddler > Nursing & Feeding > Nursing Covers +Baby & Toddler > Nursing & Feeding > Nursing Pads & Shields +Baby & Toddler > Nursing & Feeding > Nursing Pillow Covers +Baby & Toddler > Nursing & Feeding > Nursing Pillows +Baby & Toddler > Nursing & Feeding > Sippy Cups +Baby & Toddler > Potty Training +Baby & Toddler > Potty Training > Potty Seats +Baby & Toddler > Potty Training > Potty Training Kits +Baby & Toddler > Swaddling & Receiving Blankets +Business & Industrial +Business & Industrial > Advertising & Marketing +Business & Industrial > Advertising & Marketing > Brochures +Business & Industrial > Advertising & Marketing > Trade Show Counters +Business & Industrial > Advertising & Marketing > Trade Show Displays +Business & Industrial > Agriculture +Business & Industrial > Agriculture > Animal Husbandry +Business & Industrial > Agriculture > Animal Husbandry > Egg Incubators +Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed +Business & Industrial > Agriculture > Animal Husbandry > Livestock Feeders & Waterers +Business & Industrial > Agriculture > Animal Husbandry > Livestock Halters +Business & Industrial > Automation Control Components +Business & Industrial > Automation Control Components > Programmable Logic Controllers +Business & Industrial > Automation Control Components > Variable Frequency & Adjustable Speed Drives +Business & Industrial > Construction +Business & Industrial > Construction > Surveying +Business & Industrial > Construction > Traffic Cones & Barrels +Business & Industrial > Dentistry +Business & Industrial > Dentistry > Dental Cement +Business & Industrial > Dentistry > Dental Tools +Business & Industrial > Dentistry > Dental Tools > Dappen Dishes +Business & Industrial > Dentistry > Dental Tools > Dental Mirrors +Business & Industrial > Dentistry > Dental Tools > Dental Tool Sets +Business & Industrial > Dentistry > Dental Tools > Prophy Cups +Business & Industrial > Dentistry > Dental Tools > Prophy Heads +Business & Industrial > Dentistry > Prophy Paste +Business & Industrial > Film & Television +Business & Industrial > Finance & Insurance +Business & Industrial > Finance & Insurance > Bullion +Business & Industrial > Food Service +Business & Industrial > Food Service > Bakery Boxes +Business & Industrial > Food Service > Bus Tubs +Business & Industrial > Food Service > Check Presenters +Business & Industrial > Food Service > Concession Food Containers +Business & Industrial > Food Service > Disposable Lids +Business & Industrial > Food Service > Disposable Serveware +Business & Industrial > Food Service > Disposable Serveware > Disposable Serving Trays +Business & Industrial > Food Service > Disposable Tableware +Business & Industrial > Food Service > Disposable Tableware > Disposable Bowls +Business & Industrial > Food Service > Disposable Tableware > Disposable Cups +Business & Industrial > Food Service > Disposable Tableware > Disposable Cutlery +Business & Industrial > Food Service > Disposable Tableware > Disposable Plates +Business & Industrial > Food Service > Food Service Baskets +Business & Industrial > Food Service > Food Service Carts +Business & Industrial > Food Service > Food Washers & Dryers +Business & Industrial > Food Service > Hot Dog Rollers +Business & Industrial > Food Service > Ice Bins +Business & Industrial > Food Service > Plate & Dish Warmers +Business & Industrial > Food Service > Sneeze Guards +Business & Industrial > Food Service > Take-Out Containers +Business & Industrial > Food Service > Tilt Skillets +Business & Industrial > Food Service > Vending Machines +Business & Industrial > Forestry & Logging +Business & Industrial > Hairdressing & Cosmetology +Business & Industrial > Hairdressing & Cosmetology > Hairdressing Capes & Neck Covers +Business & Industrial > Hairdressing & Cosmetology > Pedicure Chairs +Business & Industrial > Hairdressing & Cosmetology > Salon Chairs +Business & Industrial > Heavy Machinery +Business & Industrial > Heavy Machinery > Chippers +Business & Industrial > Hotel & Hospitality +Business & Industrial > Industrial Storage +Business & Industrial > Industrial Storage > Industrial Cabinets +Business & Industrial > Industrial Storage > Industrial Shelving +Business & Industrial > Industrial Storage > Shipping Containers +Business & Industrial > Industrial Storage > Wire Partitions, Enclosures & Doors +Business & Industrial > Industrial Storage Accessories +Business & Industrial > Janitorial Carts & Caddies +Business & Industrial > Law Enforcement +Business & Industrial > Law Enforcement > Cuffs +Business & Industrial > Law Enforcement > Metal Detectors +Business & Industrial > Manufacturing +Business & Industrial > Material Handling +Business & Industrial > Material Handling > Conveyors +Business & Industrial > Material Handling > Lifts & Hoists +Business & Industrial > Material Handling > Lifts & Hoists > Hoists, Cranes & Trolleys +Business & Industrial > Material Handling > Lifts & Hoists > Jacks & Lift Trucks +Business & Industrial > Material Handling > Lifts & Hoists > Personnel Lifts +Business & Industrial > Material Handling > Lifts & Hoists > Pulleys, Blocks & Sheaves +Business & Industrial > Material Handling > Lifts & Hoists > Winches +Business & Industrial > Material Handling > Pallets & Loading Platforms +Business & Industrial > Medical +Business & Industrial > Medical > Hospital Curtains +Business & Industrial > Medical > Hospital Gowns +Business & Industrial > Medical > Medical Bedding +Business & Industrial > Medical > Medical Equipment +Business & Industrial > Medical > Medical Equipment > Automated External Defibrillators +Business & Industrial > Medical > Medical Equipment > Gait Belts +Business & Industrial > Medical > Medical Equipment > Medical Reflex Hammers & Tuning Forks +Business & Industrial > Medical > Medical Equipment > Medical Stretchers & Gurneys +Business & Industrial > Medical > Medical Equipment > Otoscopes & Ophthalmoscopes +Business & Industrial > Medical > Medical Equipment > Patient Lifts +Business & Industrial > Medical > Medical Equipment > Stethoscopes +Business & Industrial > Medical > Medical Equipment > Vital Signs Monitor Accessories +Business & Industrial > Medical > Medical Equipment > Vital Signs Monitors +Business & Industrial > Medical > Medical Furniture +Business & Industrial > Medical > Medical Furniture > Chiropractic Tables +Business & Industrial > Medical > Medical Furniture > Examination Chairs & Tables +Business & Industrial > Medical > Medical Furniture > Homecare & Hospital Beds +Business & Industrial > Medical > Medical Furniture > Medical Cabinets +Business & Industrial > Medical > Medical Furniture > Medical Carts +Business & Industrial > Medical > Medical Furniture > Medical Carts > Crash Carts +Business & Industrial > Medical > Medical Furniture > Medical Carts > IV Poles & Carts +Business & Industrial > Medical > Medical Furniture > Surgical Tables +Business & Industrial > Medical > Medical Instruments +Business & Industrial > Medical > Medical Instruments > Medical Forceps +Business & Industrial > Medical > Medical Instruments > Scalpel Blades +Business & Industrial > Medical > Medical Instruments > Scalpels +Business & Industrial > Medical > Medical Instruments > Surgical Needles & Sutures +Business & Industrial > Medical > Medical Supplies +Business & Industrial > Medical > Medical Supplies > Disposable Gloves +Business & Industrial > Medical > Medical Supplies > Finger Cots +Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes +Business & Industrial > Medical > Medical Supplies > Ostomy Supplies +Business & Industrial > Medical > Medical Supplies > Tongue Depressors +Business & Industrial > Medical > Medical Teaching Equipment +Business & Industrial > Medical > Medical Teaching Equipment > Medical & Emergency Response Training Mannequins +Business & Industrial > Medical > Scrub Caps +Business & Industrial > Medical > Scrubs +Business & Industrial > Medical > Surgical Gowns +Business & Industrial > Mining & Quarrying +Business & Industrial > Piercing & Tattooing +Business & Industrial > Piercing & Tattooing > Piercing Supplies +Business & Industrial > Piercing & Tattooing > Piercing Supplies > Piercing Needles +Business & Industrial > Piercing & Tattooing > Tattooing Supplies +Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattoo Cover-Ups +Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Inks +Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Machines +Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Needles +Business & Industrial > Retail +Business & Industrial > Retail > Clothing Display Racks +Business & Industrial > Retail > Display Mannequins +Business & Industrial > Retail > Mannequin Parts +Business & Industrial > Retail > Money Handling +Business & Industrial > Retail > Money Handling > Banknote Verifiers +Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories +Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Cash Drawers & Trays +Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Credit Card Terminals +Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Signature Capture Pads +Business & Industrial > Retail > Money Handling > Cash Registers & POS Terminals +Business & Industrial > Retail > Money Handling > Coin & Bill Counters +Business & Industrial > Retail > Money Handling > Money Changers +Business & Industrial > Retail > Money Handling > Money Deposit Bags +Business & Industrial > Retail > Money Handling > Paper Coin Wrappers & Bill Straps +Business & Industrial > Retail > Paper & Plastic Shopping Bags +Business & Industrial > Retail > Pricing Guns +Business & Industrial > Retail > Retail Display Cases +Business & Industrial > Retail > Retail Display Props & Models +Business & Industrial > Science & Laboratory +Business & Industrial > Science & Laboratory > Biochemicals +Business & Industrial > Science & Laboratory > Dissection Kits +Business & Industrial > Science & Laboratory > Laboratory Chemicals +Business & Industrial > Science & Laboratory > Laboratory Equipment +Business & Industrial > Science & Laboratory > Laboratory Equipment > Autoclaves +Business & Industrial > Science & Laboratory > Laboratory Equipment > Centrifuges +Business & Industrial > Science & Laboratory > Laboratory Equipment > Dry Ice Makers +Business & Industrial > Science & Laboratory > Laboratory Equipment > Freeze-Drying Machines +Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Blenders +Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Freezers +Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Funnels +Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Hot Plates +Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Ovens +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Cameras +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Eyepieces & Adapters +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Objective Lenses +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Replacement Bulbs +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Slides +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscopes +Business & Industrial > Science & Laboratory > Laboratory Equipment > Microtomes +Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometer Accessories +Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometers +Business & Industrial > Science & Laboratory > Laboratory Specimens +Business & Industrial > Science & Laboratory > Laboratory Supplies +Business & Industrial > Science & Laboratory > Laboratory Supplies > Beakers +Business & Industrial > Science & Laboratory > Laboratory Supplies > Graduated Cylinders +Business & Industrial > Science & Laboratory > Laboratory Supplies > Laboratory Flasks +Business & Industrial > Science & Laboratory > Laboratory Supplies > Petri Dishes +Business & Industrial > Science & Laboratory > Laboratory Supplies > Pipettes +Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tube Racks +Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tubes +Business & Industrial > Science & Laboratory > Laboratory Supplies > Wash Bottles +Business & Industrial > Signage +Business & Industrial > Signage > Business Hour Signs +Business & Industrial > Signage > Digital Signs +Business & Industrial > Signage > Electric Signs +Business & Industrial > Signage > Electric Signs > LED Signs +Business & Industrial > Signage > Electric Signs > Neon Signs +Business & Industrial > Signage > Emergency & Exit Signs +Business & Industrial > Signage > Facility Identification Signs +Business & Industrial > Signage > Open & Closed Signs +Business & Industrial > Signage > Parking Signs & Permits +Business & Industrial > Signage > Policy Signs +Business & Industrial > Signage > Retail & Sale Signs +Business & Industrial > Signage > Road & Traffic Signs +Business & Industrial > Signage > Safety & Warning Signs +Business & Industrial > Signage > Security Signs +Business & Industrial > Signage > Sidewalk & Yard Signs +Business & Industrial > Work Safety Protective Gear +Business & Industrial > Work Safety Protective Gear > Bullet Proof Vests +Business & Industrial > Work Safety Protective Gear > Gas Mask & Respirator Accessories +Business & Industrial > Work Safety Protective Gear > Hardhats +Business & Industrial > Work Safety Protective Gear > Hazardous Material Suits +Business & Industrial > Work Safety Protective Gear > Protective Aprons +Business & Industrial > Work Safety Protective Gear > Protective Eyewear +Business & Industrial > Work Safety Protective Gear > Protective Masks +Business & Industrial > Work Safety Protective Gear > Protective Masks > Dust Masks +Business & Industrial > Work Safety Protective Gear > Protective Masks > Fireman's Masks +Business & Industrial > Work Safety Protective Gear > Protective Masks > Gas Masks & Respirators +Business & Industrial > Work Safety Protective Gear > Protective Masks > Medical Masks +Business & Industrial > Work Safety Protective Gear > Safety Gloves +Business & Industrial > Work Safety Protective Gear > Safety Knee Pads +Business & Industrial > Work Safety Protective Gear > Welding Helmets +Business & Industrial > Work Safety Protective Gear > Work Safety Harnesses +Business & Industrial > Work Safety Protective Gear > Work Safety Tethers +Cameras & Optics +Cameras & Optics > Camera & Optic Accessories +Cameras & Optics > Camera & Optic Accessories > Camera & Optic Replacement Cables +Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses +Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Camera Lenses +Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Surveillance Camera Lenses +Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Video Camera Lenses +Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories +Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens & Filter Adapter Rings +Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Bags +Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Caps +Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Converters +Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Filters +Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Hoods +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Accessory Sets +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Bags & Cases +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Body Replacement Panels & Doors +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Digital Backs +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Film +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Flash Accessories +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Flashes +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Focus Devices +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Gears +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Grips +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Image Sensors +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Lens Zoom Units +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Remote Controls +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Replacement Buttons & Knobs +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Replacement Screens & Displays +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Silencers & Sound Blimps +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Stabilizers & Supports +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Straps +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Sun Hoods & Viewfinder Attachments +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Flash Brackets +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > On-Camera Monitors +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Surveillance Camera Accessories +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Underwater Camera Housing Accessories +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Underwater Camera Housings +Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Video Camera Lights +Cameras & Optics > Camera & Optic Accessories > Optic Accessories +Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Binocular & Monocular Accessories +Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Optics Bags & Cases +Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Rangefinder Accessories +Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Spotting Scope Accessories +Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Telescope Accessories +Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Thermal Optic Accessories +Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Weapon Scope & Sight Accessories +Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories +Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Cases +Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Heads +Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Collars & Mounts +Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Handles +Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Spreaders +Cameras & Optics > Camera & Optic Accessories > Tripods & Monopods +Cameras & Optics > Cameras +Cameras & Optics > Cameras > Borescopes +Cameras & Optics > Cameras > Digital Cameras +Cameras & Optics > Cameras > Disposable Cameras +Cameras & Optics > Cameras > Film Cameras +Cameras & Optics > Cameras > Surveillance Cameras +Cameras & Optics > Cameras > Trail Cameras +Cameras & Optics > Cameras > Video Cameras +Cameras & Optics > Cameras > Webcams +Cameras & Optics > Optics +Cameras & Optics > Optics > Binoculars +Cameras & Optics > Optics > Monoculars +Cameras & Optics > Optics > Rangefinders +Cameras & Optics > Optics > Scopes +Cameras & Optics > Optics > Scopes > Spotting Scopes +Cameras & Optics > Optics > Scopes > Telescopes +Cameras & Optics > Optics > Scopes > Weapon Scopes & Sights +Cameras & Optics > Photography +Cameras & Optics > Photography > Darkroom +Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment +Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Copystands +Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Darkroom Sinks +Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Developing Tanks & Reels +Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Print Trays, Washers & Dryers +Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Retouching Equipment & Supplies +Cameras & Optics > Photography > Darkroom > Enlarging Equipment +Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Easels +Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Timers +Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Focusing Aids +Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Analyzers +Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Enlargers +Cameras & Optics > Photography > Darkroom > Photographic Chemicals +Cameras & Optics > Photography > Darkroom > Photographic Paper +Cameras & Optics > Photography > Darkroom > Safelights +Cameras & Optics > Photography > Lighting & Studio +Cameras & Optics > Photography > Lighting & Studio > Light Meter Accessories +Cameras & Optics > Photography > Lighting & Studio > Light Meters +Cameras & Optics > Photography > Lighting & Studio > Studio Backgrounds +Cameras & Optics > Photography > Lighting & Studio > Studio Light & Flash Accessories +Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls +Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Flash Diffusers +Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Flash Reflectors +Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Lighting Filters & Gobos +Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Softboxes +Cameras & Optics > Photography > Lighting & Studio > Studio Lights & Flashes +Cameras & Optics > Photography > Lighting & Studio > Studio Stand & Mount Accessories +Cameras & Optics > Photography > Lighting & Studio > Studio Stands & Mounts +Cameras & Optics > Photography > Photo Mounting Supplies +Cameras & Optics > Photography > Photo Negative & Slide Storage +Electronics +Electronics > Arcade Equipment +Electronics > Arcade Equipment > Basketball Arcade Games +Electronics > Arcade Equipment > Pinball Machine Accessories +Electronics > Arcade Equipment > Pinball Machines +Electronics > Arcade Equipment > Skee-Ball Machines +Electronics > Arcade Equipment > Video Game Arcade Cabinet Accessories +Electronics > Arcade Equipment > Video Game Arcade Cabinets +Electronics > Audio +Electronics > Audio > Audio Accessories +Electronics > Audio > Audio Accessories > Audio & Video Receiver Accessories +Electronics > Audio > Audio Accessories > Headphone & Headset Accessories +Electronics > Audio > Audio Accessories > Headphone & Headset Accessories > Headphone Cushions & Tips +Electronics > Audio > Audio Accessories > Karaoke System Accessories +Electronics > Audio > Audio Accessories > Karaoke System Accessories > Karaoke Chips +Electronics > Audio > Audio Accessories > MP3 Player Accessories +Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player & Mobile Phone Accessory Sets +Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player Cases +Electronics > Audio > Audio Accessories > Microphone Accessories +Electronics > Audio > Audio Accessories > Microphone Stands +Electronics > Audio > Audio Accessories > Satellite Radio Accessories +Electronics > Audio > Audio Accessories > Speaker Accessories +Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Bags, Covers & Cases +Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Components & Kits +Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stand Bags +Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stands & Mounts +Electronics > Audio > Audio Accessories > Speaker Accessories > Tactile Transducers +Electronics > Audio > Audio Accessories > Turntable Accessories +Electronics > Audio > Audio Components +Electronics > Audio > Audio Components > Audio & Video Receivers +Electronics > Audio > Audio Components > Audio Amplifiers +Electronics > Audio > Audio Components > Audio Amplifiers > Headphone Amplifiers +Electronics > Audio > Audio Components > Audio Amplifiers > Power Amplifiers +Electronics > Audio > Audio Components > Audio Mixers +Electronics > Audio > Audio Components > Audio Transmitters +Electronics > Audio > Audio Components > Audio Transmitters > Bluetooth Transmitters +Electronics > Audio > Audio Components > Audio Transmitters > FM Transmitters +Electronics > Audio > Audio Components > Channel Strips +Electronics > Audio > Audio Components > Direct Boxes +Electronics > Audio > Audio Components > Headphones & Headsets +Electronics > Audio > Audio Components > Microphones +Electronics > Audio > Audio Components > Signal Processors +Electronics > Audio > Audio Components > Signal Processors > Crossovers +Electronics > Audio > Audio Components > Signal Processors > Effects Processors +Electronics > Audio > Audio Components > Signal Processors > Equalizers +Electronics > Audio > Audio Components > Signal Processors > Loudspeaker Management Systems +Electronics > Audio > Audio Components > Signal Processors > Microphone Preamps +Electronics > Audio > Audio Components > Signal Processors > Noise Gates & Compressors +Electronics > Audio > Audio Components > Signal Processors > Phono Preamps +Electronics > Audio > Audio Components > Speakers +Electronics > Audio > Audio Components > Studio Recording Bundles +Electronics > Audio > Audio Players & Recorders +Electronics > Audio > Audio Players & Recorders > Boomboxes +Electronics > Audio > Audio Players & Recorders > CD Players & Recorders +Electronics > Audio > Audio Players & Recorders > Cassette Players & Recorders +Electronics > Audio > Audio Players & Recorders > Home Theater Systems +Electronics > Audio > Audio Players & Recorders > Jukeboxes +Electronics > Audio > Audio Players & Recorders > Karaoke Systems +Electronics > Audio > Audio Players & Recorders > MP3 Players +Electronics > Audio > Audio Players & Recorders > MiniDisc Players & Recorders +Electronics > Audio > Audio Players & Recorders > Multitrack Recorders +Electronics > Audio > Audio Players & Recorders > Radios +Electronics > Audio > Audio Players & Recorders > Reel-to-Reel Tape Players & Recorders +Electronics > Audio > Audio Players & Recorders > Stereo Systems +Electronics > Audio > Audio Players & Recorders > Turntables & Record Players +Electronics > Audio > Audio Players & Recorders > Voice Recorders +Electronics > Audio > Bullhorns +Electronics > Audio > DJ & Specialty Audio +Electronics > Audio > DJ & Specialty Audio > DJ CD Players +Electronics > Audio > DJ & Specialty Audio > DJ Systems +Electronics > Audio > Public Address Systems +Electronics > Audio > Stage Equipment +Electronics > Audio > Stage Equipment > Wireless Transmitters +Electronics > Circuit Boards & Components +Electronics > Circuit Boards & Components > Circuit Board Accessories +Electronics > Circuit Boards & Components > Circuit Decoders & Encoders +Electronics > Circuit Boards & Components > Circuit Prototyping +Electronics > Circuit Boards & Components > Circuit Prototyping > Breadboards +Electronics > Circuit Boards & Components > Electronic Filters +Electronics > Circuit Boards & Components > Passive Circuit Components +Electronics > Circuit Boards & Components > Passive Circuit Components > Capacitors +Electronics > Circuit Boards & Components > Passive Circuit Components > Electronic Oscillators +Electronics > Circuit Boards & Components > Passive Circuit Components > Inductors +Electronics > Circuit Boards & Components > Passive Circuit Components > Resistors +Electronics > Circuit Boards & Components > Printed Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Camera Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Computer Inverter Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Hard Drive Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Motherboards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Development Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Exercise Machine Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Household Appliance Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Pool & Spa Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Printer, Copier, & Fax Machine Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Scanner Circuit Boards +Electronics > Circuit Boards & Components > Printed Circuit Boards > Television Circuit Boards +Electronics > Circuit Boards & Components > Semiconductors +Electronics > Circuit Boards & Components > Semiconductors > Diodes +Electronics > Circuit Boards & Components > Semiconductors > Integrated Circuits & Chips +Electronics > Circuit Boards & Components > Semiconductors > Microcontrollers +Electronics > Circuit Boards & Components > Semiconductors > Transistors +Electronics > Communications +Electronics > Communications > Answering Machines +Electronics > Communications > Caller IDs +Electronics > Communications > Communication Radio Accessories +Electronics > Communications > Communication Radios +Electronics > Communications > Communication Radios > CB Radios +Electronics > Communications > Communication Radios > Radio Scanners +Electronics > Communications > Communication Radios > Two-Way Radios +Electronics > Communications > Intercom Accessories +Electronics > Communications > Intercoms +Electronics > Communications > Pagers +Electronics > Communications > Telephony +Electronics > Communications > Telephony > Conference Phones +Electronics > Communications > Telephony > Corded Phones +Electronics > Communications > Telephony > Cordless Phones +Electronics > Communications > Telephony > Mobile Phone Accessories +Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Camera Accessories +Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Cases +Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Charms & Straps +Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Pre-Paid Cards & SIM Cards +Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Replacement Parts +Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Stands +Electronics > Communications > Telephony > Mobile Phone Accessories > SIM Card Ejection Tools +Electronics > Communications > Telephony > Mobile Phones +Electronics > Communications > Telephony > Satellite Phones +Electronics > Communications > Telephony > Telephone Accessories +Electronics > Communications > Telephony > Telephone Accessories > Phone Cards +Electronics > Communications > Video Conferencing +Electronics > Components +Electronics > Components > Accelerometers +Electronics > Components > Converters +Electronics > Components > Converters > Audio Converters +Electronics > Components > Converters > Scan Converters +Electronics > Components > Electronics Component Connectors +Electronics > Components > Modulators +Electronics > Components > Splitters +Electronics > Computers +Electronics > Computers > Barebone Computers +Electronics > Computers > Computer Servers +Electronics > Computers > Desktop Computers +Electronics > Computers > Handheld Devices +Electronics > Computers > Handheld Devices > Data Collectors +Electronics > Computers > Handheld Devices > E-Book Readers +Electronics > Computers > Handheld Devices > PDAs +Electronics > Computers > Interactive Kiosks +Electronics > Computers > Laptops +Electronics > Computers > Smart Glasses +Electronics > Computers > Tablet Computers +Electronics > Computers > Thin & Zero Clients +Electronics > Computers > Touch Table Computers +Electronics > Electronics Accessories +Electronics > Electronics Accessories > Adapters +Electronics > Electronics Accessories > Adapters > Audio & Video Cable Adapters & Couplers +Electronics > Electronics Accessories > Adapters > Memory Card Adapters +Electronics > Electronics Accessories > Adapters > USB Adapters +Electronics > Electronics Accessories > Antenna Accessories +Electronics > Electronics Accessories > Antenna Accessories > Antenna Mounts & Brackets +Electronics > Electronics Accessories > Antenna Accessories > Antenna Rotators +Electronics > Electronics Accessories > Antenna Accessories > Satellite LNBs +Electronics > Electronics Accessories > Antennas +Electronics > Electronics Accessories > Audio & Video Splitters & Switches +Electronics > Electronics Accessories > Audio & Video Splitters & Switches > DVI Splitters & Switches +Electronics > Electronics Accessories > Audio & Video Splitters & Switches > HDMI Splitters & Switches +Electronics > Electronics Accessories > Audio & Video Splitters & Switches > VGA Splitters & Switches +Electronics > Electronics Accessories > Blank Media +Electronics > Electronics Accessories > Cable Management +Electronics > Electronics Accessories > Cable Management > Cable Clips +Electronics > Electronics Accessories > Cable Management > Cable Tie Guns +Electronics > Electronics Accessories > Cable Management > Cable Trays +Electronics > Electronics Accessories > Cable Management > Patch Panels +Electronics > Electronics Accessories > Cable Management > Wire & Cable Identification Markers +Electronics > Electronics Accessories > Cable Management > Wire & Cable Sleeves +Electronics > Electronics Accessories > Cable Management > Wire & Cable Ties +Electronics > Electronics Accessories > Cables +Electronics > Electronics Accessories > Cables > Audio & Video Cables +Electronics > Electronics Accessories > Cables > KVM Cables +Electronics > Electronics Accessories > Cables > Network Cables +Electronics > Electronics Accessories > Cables > Storage & Data Transfer Cables +Electronics > Electronics Accessories > Cables > System & Power Cables +Electronics > Electronics Accessories > Cables > Telephone Cables +Electronics > Electronics Accessories > Computer Accessories +Electronics > Electronics Accessories > Computer Accessories > Computer Accessory Sets +Electronics > Electronics Accessories > Computer Accessories > Computer Covers & Skins +Electronics > Electronics Accessories > Computer Accessories > Computer Risers & Stands +Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories +Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories +Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories > E-Book Reader Cases +Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > PDA Accessories +Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > PDA Accessories > PDA Cases +Electronics > Electronics Accessories > Computer Accessories > Keyboard & Mouse Wrist Rests +Electronics > Electronics Accessories > Computer Accessories > Keyboard Trays & Platforms +Electronics > Electronics Accessories > Computer Accessories > Laptop Docking Stations +Electronics > Electronics Accessories > Computer Accessories > Mouse Pads +Electronics > Electronics Accessories > Computer Accessories > Stylus Pen Nibs & Refills +Electronics > Electronics Accessories > Computer Accessories > Stylus Pens +Electronics > Electronics Accessories > Computer Accessories > Tablet Computer Docks & Stands +Electronics > Electronics Accessories > Computer Components +Electronics > Electronics Accessories > Computer Components > Blade Server Enclosures +Electronics > Electronics Accessories > Computer Components > Computer Backplates & I/O Shields +Electronics > Electronics Accessories > Computer Components > Computer Power Supplies +Electronics > Electronics Accessories > Computer Components > Computer Processors +Electronics > Electronics Accessories > Computer Components > Computer Racks & Mounts +Electronics > Electronics Accessories > Computer Components > Computer Starter Kits +Electronics > Electronics Accessories > Computer Components > Computer System Cooling Parts +Electronics > Electronics Accessories > Computer Components > Desktop Computer & Server Cases +Electronics > Electronics Accessories > Computer Components > E-Book Reader Parts +Electronics > Electronics Accessories > Computer Components > E-Book Reader Parts > E-Book Reader Screens & Screen Digitizers +Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters +Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Audio Cards & Adapters +Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Computer Interface Cards & Adapters +Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Riser Cards +Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > TV Tuner Cards & Adapters +Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Video Cards & Adapters +Electronics > Electronics Accessories > Computer Components > Input Device Accessories +Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Barcode Scanner Stands +Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Game Controller Accessories +Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Keyboard Keys & Caps +Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Mice & Trackball Accessories +Electronics > Electronics Accessories > Computer Components > Input Devices +Electronics > Electronics Accessories > Computer Components > Input Devices > Barcode Scanners +Electronics > Electronics Accessories > Computer Components > Input Devices > Digital Note Taking Pens +Electronics > Electronics Accessories > Computer Components > Input Devices > Electronic Card Readers +Electronics > Electronics Accessories > Computer Components > Input Devices > Fingerprint Readers +Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers +Electronics > Electronics Accessories > Computer Components > Input Devices > Gesture Control Input Devices +Electronics > Electronics Accessories > Computer Components > Input Devices > Graphics Tablets +Electronics > Electronics Accessories > Computer Components > Input Devices > KVM Switches +Electronics > Electronics Accessories > Computer Components > Input Devices > Keyboards +Electronics > Electronics Accessories > Computer Components > Input Devices > Memory Card Readers +Electronics > Electronics Accessories > Computer Components > Input Devices > Mice & Trackballs +Electronics > Electronics Accessories > Computer Components > Input Devices > Numeric Keypads +Electronics > Electronics Accessories > Computer Components > Input Devices > Touchpads +Electronics > Electronics Accessories > Computer Components > Laptop Parts +Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Hinges +Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Housings & Trim +Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Cables +Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Keyboards +Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Screens +Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Speakers +Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Screen Digitizers +Electronics > Electronics Accessories > Computer Components > Storage Devices +Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators +Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > CD/DVD Duplicators +Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > Hard Drive Duplicators +Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > USB Drive Duplicators +Electronics > Electronics Accessories > Computer Components > Storage Devices > Floppy Drives +Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories +Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Carrying Cases +Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Docks +Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Enclosures & Mounts +Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Arrays +Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drives +Electronics > Electronics Accessories > Computer Components > Storage Devices > Network Storage Systems +Electronics > Electronics Accessories > Computer Components > Storage Devices > Optical Drives +Electronics > Electronics Accessories > Computer Components > Storage Devices > Tape Drives +Electronics > Electronics Accessories > Computer Components > Storage Devices > USB Flash Drives +Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts +Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Housings & Trim +Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Replacement Speakers +Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Screens & Screen Digitizers +Electronics > Electronics Accessories > Computer Components > USB & FireWire Hubs +Electronics > Electronics Accessories > Electronics Cleaners +Electronics > Electronics Accessories > Electronics Films & Shields +Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals +Electronics > Electronics Accessories > Electronics Films & Shields > Keyboard Protectors +Electronics > Electronics Accessories > Electronics Films & Shields > Privacy Filters +Electronics > Electronics Accessories > Electronics Films & Shields > Screen Protectors +Electronics > Electronics Accessories > Memory +Electronics > Electronics Accessories > Memory > Cache Memory +Electronics > Electronics Accessories > Memory > Flash Memory +Electronics > Electronics Accessories > Memory > Flash Memory > Flash Memory Cards +Electronics > Electronics Accessories > Memory > RAM +Electronics > Electronics Accessories > Memory > ROM +Electronics > Electronics Accessories > Memory > Video Memory +Electronics > Electronics Accessories > Memory Accessories +Electronics > Electronics Accessories > Memory Accessories > Memory Cases +Electronics > Electronics Accessories > Mobile Phone & Tablet Tripods & Monopods +Electronics > Electronics Accessories > Power +Electronics > Electronics Accessories > Power > Batteries +Electronics > Electronics Accessories > Power > Batteries > Camera Batteries +Electronics > Electronics Accessories > Power > Batteries > Cordless Phone Batteries +Electronics > Electronics Accessories > Power > Batteries > E-Book Reader Batteries +Electronics > Electronics Accessories > Power > Batteries > General Purpose Batteries +Electronics > Electronics Accessories > Power > Batteries > Laptop Batteries +Electronics > Electronics Accessories > Power > Batteries > MP3 Player Batteries +Electronics > Electronics Accessories > Power > Batteries > Mobile Phone Batteries +Electronics > Electronics Accessories > Power > Batteries > PDA Batteries +Electronics > Electronics Accessories > Power > Batteries > Tablet Computer Batteries +Electronics > Electronics Accessories > Power > Batteries > UPS Batteries +Electronics > Electronics Accessories > Power > Batteries > Video Camera Batteries +Electronics > Electronics Accessories > Power > Batteries > Video Game Console & Controller Batteries +Electronics > Electronics Accessories > Power > Battery Accessories +Electronics > Electronics Accessories > Power > Battery Accessories > Battery Charge Controllers +Electronics > Electronics Accessories > Power > Battery Accessories > Battery Holders +Electronics > Electronics Accessories > Power > Battery Accessories > Camera Battery Chargers +Electronics > Electronics Accessories > Power > Battery Accessories > General Purpose Battery Chargers +Electronics > Electronics Accessories > Power > Battery Accessories > General Purpose Battery Testers +Electronics > Electronics Accessories > Power > Fuel Cells +Electronics > Electronics Accessories > Power > Power Adapter & Charger Accessories +Electronics > Electronics Accessories > Power > Power Adapters & Chargers +Electronics > Electronics Accessories > Power > Power Control Units +Electronics > Electronics Accessories > Power > Power Strips & Surge Suppressors +Electronics > Electronics Accessories > Power > Power Supply Enclosures +Electronics > Electronics Accessories > Power > Surge Protection Devices +Electronics > Electronics Accessories > Power > Travel Converters & Adapters +Electronics > Electronics Accessories > Power > UPS +Electronics > Electronics Accessories > Power > UPS Accessories +Electronics > Electronics Accessories > Remote Controls +Electronics > Electronics Accessories > Signal Boosters +Electronics > Electronics Accessories > Signal Jammers +Electronics > Electronics Accessories > Signal Jammers > GPS Jammers +Electronics > Electronics Accessories > Signal Jammers > Mobile Phone Jammers +Electronics > Electronics Accessories > Signal Jammers > Radar Jammers +Electronics > GPS Accessories +Electronics > GPS Accessories > GPS Cases +Electronics > GPS Accessories > GPS Mounts +Electronics > GPS Navigation Systems +Electronics > GPS Tracking Devices +Electronics > Marine Electronics +Electronics > Marine Electronics > Fish Finders +Electronics > Marine Electronics > Marine Audio & Video Receivers +Electronics > Marine Electronics > Marine Chartplotters & GPS +Electronics > Marine Electronics > Marine Radar +Electronics > Marine Electronics > Marine Radios +Electronics > Marine Electronics > Marine Speakers +Electronics > Networking +Electronics > Networking > Bridges & Routers +Electronics > Networking > Bridges & Routers > Network Bridges +Electronics > Networking > Bridges & Routers > VoIP Gateways & Routers +Electronics > Networking > Bridges & Routers > Wireless Access Points +Electronics > Networking > Bridges & Routers > Wireless Routers +Electronics > Networking > Concentrators & Multiplexers +Electronics > Networking > Hubs & Switches +Electronics > Networking > Modem Accessories +Electronics > Networking > Modems +Electronics > Networking > Network Cards & Adapters +Electronics > Networking > Network Security & Firewall Devices +Electronics > Networking > Power Over Ethernet Adapters +Electronics > Networking > Print Servers +Electronics > Networking > Repeaters & Transceivers +Electronics > Print, Copy, Scan & Fax +Electronics > Print, Copy, Scan & Fax > 3D Printer Accessories +Electronics > Print, Copy, Scan & Fax > 3D Printers +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Drums & Drum Kits +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Filters +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Maintenance Kits +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Ribbons +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printheads +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Toner & Inkjet Cartridge Refills +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Toner & Inkjet Cartridges +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Duplexers +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Memory +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Stands +Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer, Copier & Fax Machine Replacement Parts +Electronics > Print, Copy, Scan & Fax > Printers, Copiers & Fax Machines +Electronics > Print, Copy, Scan & Fax > Scanner Accessories +Electronics > Print, Copy, Scan & Fax > Scanners +Electronics > Radar Detectors +Electronics > Speed Radars +Electronics > Toll Collection Devices +Electronics > Video +Electronics > Video > Computer Monitors +Electronics > Video > Projectors +Electronics > Video > Projectors > Multimedia Projectors +Electronics > Video > Projectors > Overhead Projectors +Electronics > Video > Projectors > Slide Projectors +Electronics > Video > Satellite & Cable TV +Electronics > Video > Satellite & Cable TV > Cable TV Receivers +Electronics > Video > Satellite & Cable TV > Satellite Receivers +Electronics > Video > Televisions +Electronics > Video > Video Accessories +Electronics > Video > Video Accessories > 3D Glasses +Electronics > Video > Video Accessories > Computer Monitor Accessories +Electronics > Video > Video Accessories > Computer Monitor Accessories > Color Calibrators +Electronics > Video > Video Accessories > Projector Accessories +Electronics > Video > Video Accessories > Projector Accessories > Projection & Tripod Skirts +Electronics > Video > Video Accessories > Projector Accessories > Projection Screen Stands +Electronics > Video > Video Accessories > Projector Accessories > Projection Screens +Electronics > Video > Video Accessories > Projector Accessories > Projector Mounts +Electronics > Video > Video Accessories > Projector Accessories > Projector Replacement Lamps +Electronics > Video > Video Accessories > Rewinders +Electronics > Video > Video Accessories > Television Parts & Accessories +Electronics > Video > Video Accessories > Television Parts & Accessories > TV & Monitor Mounts +Electronics > Video > Video Accessories > Television Parts & Accessories > TV Converter Boxes +Electronics > Video > Video Accessories > Television Parts & Accessories > TV Replacement Lamps +Electronics > Video > Video Accessories > Television Parts & Accessories > TV Replacement Speakers +Electronics > Video > Video Editing Hardware & Production Equipment +Electronics > Video > Video Multiplexers +Electronics > Video > Video Players & Recorders +Electronics > Video > Video Players & Recorders > DVD & Blu-ray Players +Electronics > Video > Video Players & Recorders > DVD Recorders +Electronics > Video > Video Players & Recorders > Digital Video Recorders +Electronics > Video > Video Players & Recorders > Streaming & Home Media Players +Electronics > Video > Video Players & Recorders > VCRs +Electronics > Video > Video Servers +Electronics > Video > Video Transmitters +Electronics > Video Game Console Accessories +Electronics > Video Game Console Accessories > Home Game Console Accessories +Electronics > Video Game Console Accessories > Portable Game Console Accessories +Electronics > Video Game Consoles +Food, Beverages & Tobacco +Food, Beverages & Tobacco > Beverages +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Beer +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Bitters +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Cocktail Mixes +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Flavored Alcoholic Beverages +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Hard Cider +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Absinthe +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Brandy +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Gin +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Liqueurs +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Rum +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Shochu & Soju +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Tequila +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Vodka +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Whiskey +Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Wine +Food, Beverages & Tobacco > Beverages > Buttermilk +Food, Beverages & Tobacco > Beverages > Coffee +Food, Beverages & Tobacco > Beverages > Eggnog +Food, Beverages & Tobacco > Beverages > Fruit Flavored Drinks +Food, Beverages & Tobacco > Beverages > Hot Chocolate +Food, Beverages & Tobacco > Beverages > Juice +Food, Beverages & Tobacco > Beverages > Milk +Food, Beverages & Tobacco > Beverages > Non-Dairy Milk +Food, Beverages & Tobacco > Beverages > Powdered Beverage Mixes +Food, Beverages & Tobacco > Beverages > Soda +Food, Beverages & Tobacco > Beverages > Sports & Energy Drinks +Food, Beverages & Tobacco > Beverages > Tea & Infusions +Food, Beverages & Tobacco > Beverages > Vinegar Drinks +Food, Beverages & Tobacco > Beverages > Water +Food, Beverages & Tobacco > Food Items +Food, Beverages & Tobacco > Food Items > Bakery +Food, Beverages & Tobacco > Food Items > Bakery > Bagels +Food, Beverages & Tobacco > Food Items > Bakery > Bakery Assortments +Food, Beverages & Tobacco > Food Items > Bakery > Breads & Buns +Food, Beverages & Tobacco > Food Items > Bakery > Cakes & Dessert Bars +Food, Beverages & Tobacco > Food Items > Bakery > Coffee Cakes +Food, Beverages & Tobacco > Food Items > Bakery > Cookies +Food, Beverages & Tobacco > Food Items > Bakery > Cupcakes +Food, Beverages & Tobacco > Food Items > Bakery > Donuts +Food, Beverages & Tobacco > Food Items > Bakery > Fudge +Food, Beverages & Tobacco > Food Items > Bakery > Ice Cream Cones +Food, Beverages & Tobacco > Food Items > Bakery > Muffins +Food, Beverages & Tobacco > Food Items > Bakery > Pastries & Scones +Food, Beverages & Tobacco > Food Items > Bakery > Pies & Tarts +Food, Beverages & Tobacco > Food Items > Bakery > Taco Shells & Tostadas +Food, Beverages & Tobacco > Food Items > Bakery > Tortillas & Wraps +Food, Beverages & Tobacco > Food Items > Candied & Chocolate Covered Fruit +Food, Beverages & Tobacco > Food Items > Candy & Chocolate +Food, Beverages & Tobacco > Food Items > Condiments & Sauces +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Cocktail Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Curry Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Fruit Toppings +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Ice Cream Syrup +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Fish Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Gravy +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Honey +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Horseradish Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Hot Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Ketchup +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Marinades & Grilling Sauces +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mayonnaise +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mustard +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Olives & Capers +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pasta Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pickled Fruits & Vegetables +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pizza Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Relish & Chutney +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Salad Dressing +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Satay Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Soy Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Sweet and Sour Sauces +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tahini +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tartar Sauce +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > White & Cream Sauces +Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Worcestershire Sauce +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chips +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chocolate +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Flavors & Extracts +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Powder +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Soda +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Batter & Coating Mixes +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bean Paste +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bread Crumbs +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Canned & Dry Milk +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cookie Decorating Kits +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oils +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Starch +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Wine +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Corn Syrup +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Bread & Pastry Dough +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Cookie & Brownie Dough +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Pie Crusts +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Floss Sugar +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Flour +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Food Coloring +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Frosting & Icing +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Lemon & Lime Juice +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Marshmallows +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Meal +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Molasses +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Pie & Pastry Fillings +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Shortening & Lard +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Starter Cultures +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Sugar & Sweeteners +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Tapioca Pearls +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Tomato Paste +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Unflavored Gelatin +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Vinegar +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Waffle & Pancake Mixes +Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Yeast +Food, Beverages & Tobacco > Food Items > Dairy Products +Food, Beverages & Tobacco > Food Items > Dairy Products > Butter & Margarine +Food, Beverages & Tobacco > Food Items > Dairy Products > Cheese +Food, Beverages & Tobacco > Food Items > Dairy Products > Coffee Creamer +Food, Beverages & Tobacco > Food Items > Dairy Products > Cottage Cheese +Food, Beverages & Tobacco > Food Items > Dairy Products > Cream +Food, Beverages & Tobacco > Food Items > Dairy Products > Sour Cream +Food, Beverages & Tobacco > Food Items > Dairy Products > Whipped Cream +Food, Beverages & Tobacco > Food Items > Dairy Products > Yogurt +Food, Beverages & Tobacco > Food Items > Dips & Spreads +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Apple Butter +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cheese Dips & Spreads +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cream Cheese +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Guacamole +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Hummus +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Jams & Jellies +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Nut Butters +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Salsa +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Tapenade +Food, Beverages & Tobacco > Food Items > Dips & Spreads > Vegetable Dip +Food, Beverages & Tobacco > Food Items > Food Gift Baskets +Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties +Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Cream & Frozen Yogurt +Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Cream Novelties +Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Pops +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Jarred Fruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Jarred Vegetables +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Prepared Beans +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Fruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Vegetables +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dry Beans +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Apples +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Atemoyas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Avocados +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Babacos +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Bananas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Berries +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Breadfruit +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cactus Pears +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cherimoyas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Grapefruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Kumquats +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Lemons +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Limequats +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Limes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Oranges +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Tangelos +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Coconuts +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Dates +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Feijoas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Figs +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Fruit Mixes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Grapes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Guavas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Homely Fruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Kiwis +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Longan +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Loquats +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Lychees +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Madroño +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mamey +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mangosteens +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Melons +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Papayas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Passion Fruit +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pears +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Persimmons +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Physalis +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pineapples +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pitahayas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pomegranates +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Quince +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Rambutans +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapodillo +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapote +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Soursops +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Starfruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Apricots +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Cherries +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Mangoes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Peaches & Nectarines +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Plumcots +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Plums +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sugar Apples +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Tamarindo +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Arracachas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Artichokes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Asparagus +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beans +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beets +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Borage +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Broccoli +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Brussel Sprouts +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cabbage +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cactus Leaves +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cardoon +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Carrots +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cauliflower +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery Roots +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Corn +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cucumbers +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Eggplants +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fennel Bulbs +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fiddlehead Ferns +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Choy +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Lan +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Garlic +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Ginger Root +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gobo Root +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Arugula +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Beet Greens +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Bok Choy +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Chard +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Chicory +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Choy Sum +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Kale +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Lettuce +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > On Choy +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Salad Mixes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Spinach +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Yu Choy +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Horseradish Root +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Jicama +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Kohlrabi +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Leeks +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Lotus Roots +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Malangas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Mushrooms +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Okra +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Onions +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsley Roots +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsnips +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peppers +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Potatoes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Radishes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Rhubarb +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Shallots +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sprouts +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Squashes & Gourds +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sugar Cane +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sunchokes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sweet Potatoes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tamarillos +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Taro Root +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tomatoes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Turnips & Rutabagas +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Vegetable Mixes +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Water Chestnuts +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Watercress +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Wheatgrass +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yams +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yuca Root +Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fruit Sauces +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Amaranth +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Barley +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Buckwheat +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Cereal & Granola +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Couscous +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Millet +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Oats, Grits & Hot Cereal +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Quinoa +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rice +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rye +Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Wheat +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Canned Meats +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Fresh & Frozen Meats +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Lunch & Deli Meats +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Canned Seafood +Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Fresh & Frozen Seafood +Food, Beverages & Tobacco > Food Items > Nuts & Seeds +Food, Beverages & Tobacco > Food Items > Pasta & Noodles +Food, Beverages & Tobacco > Food Items > Prepared Foods +Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Appetizers & Side Dishes +Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Meals & Entrées +Food, Beverages & Tobacco > Food Items > Seasonings & Spices +Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices +Food, Beverages & Tobacco > Food Items > Seasonings & Spices > MSG +Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Pepper +Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Salt +Food, Beverages & Tobacco > Food Items > Snack Foods +Food, Beverages & Tobacco > Food Items > Snack Foods > Breadsticks +Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars +Food, Beverages & Tobacco > Food Items > Snack Foods > Cheese Puffs +Food, Beverages & Tobacco > Food Items > Snack Foods > Chips +Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers +Food, Beverages & Tobacco > Food Items > Snack Foods > Croutons +Food, Beverages & Tobacco > Food Items > Snack Foods > Fruit Snacks +Food, Beverages & Tobacco > Food Items > Snack Foods > Jerky +Food, Beverages & Tobacco > Food Items > Snack Foods > Popcorn +Food, Beverages & Tobacco > Food Items > Snack Foods > Pork Rinds +Food, Beverages & Tobacco > Food Items > Snack Foods > Pretzels +Food, Beverages & Tobacco > Food Items > Snack Foods > Pudding & Gelatin Snacks +Food, Beverages & Tobacco > Food Items > Snack Foods > Puffed Rice Cakes +Food, Beverages & Tobacco > Food Items > Snack Foods > Salad Toppings +Food, Beverages & Tobacco > Food Items > Snack Foods > Sesame Sticks +Food, Beverages & Tobacco > Food Items > Snack Foods > Snack Cakes +Food, Beverages & Tobacco > Food Items > Snack Foods > Sticky Rice Cakes +Food, Beverages & Tobacco > Food Items > Snack Foods > Trail & Snack Mixes +Food, Beverages & Tobacco > Food Items > Soups & Broths +Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products +Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Cheese Alternatives +Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Meat Alternatives +Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Seitan +Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tempeh +Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tofu +Food, Beverages & Tobacco > Tobacco Products +Food, Beverages & Tobacco > Tobacco Products > Chewing Tobacco +Food, Beverages & Tobacco > Tobacco Products > Cigarettes +Food, Beverages & Tobacco > Tobacco Products > Cigars +Food, Beverages & Tobacco > Tobacco Products > Loose Tobacco +Food, Beverages & Tobacco > Tobacco Products > Smoking Pipes +Food, Beverages & Tobacco > Tobacco Products > Vaporizers & Electronic Cigarettes +Furniture +Furniture > Baby & Toddler Furniture +Furniture > Baby & Toddler Furniture > Baby & Toddler Furniture Sets +Furniture > Baby & Toddler Furniture > Bassinet & Cradle Accessories +Furniture > Baby & Toddler Furniture > Bassinets & Cradles +Furniture > Baby & Toddler Furniture > Changing Tables +Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories +Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Bumpers & Liners +Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Conversion Kits +Furniture > Baby & Toddler Furniture > Cribs & Toddler Beds +Furniture > Baby & Toddler Furniture > High Chair & Booster Seat Accessories +Furniture > Baby & Toddler Furniture > High Chairs & Booster Seats +Furniture > Beds & Accessories +Furniture > Beds & Accessories > Bed & Bed Frame Accessories +Furniture > Beds & Accessories > Beds & Bed Frames +Furniture > Beds & Accessories > Headboards & Footboards +Furniture > Beds & Accessories > Mattress Foundations +Furniture > Beds & Accessories > Mattresses +Furniture > Benches +Furniture > Benches > Kitchen & Dining Benches +Furniture > Benches > Storage & Entryway Benches +Furniture > Benches > Vanity Benches +Furniture > Cabinets & Storage +Furniture > Cabinets & Storage > Armoires & Wardrobes +Furniture > Cabinets & Storage > Buffets & Sideboards +Furniture > Cabinets & Storage > China Cabinets & Hutches +Furniture > Cabinets & Storage > Dressers +Furniture > Cabinets & Storage > File Cabinets +Furniture > Cabinets & Storage > Ironing Centers +Furniture > Cabinets & Storage > Kitchen Cabinets +Furniture > Cabinets & Storage > Magazine Racks +Furniture > Cabinets & Storage > Media Storage Cabinets & Racks +Furniture > Cabinets & Storage > Storage Cabinets & Lockers +Furniture > Cabinets & Storage > Storage Chests +Furniture > Cabinets & Storage > Storage Chests > Hope Chests +Furniture > Cabinets & Storage > Storage Chests > Toy Chests +Furniture > Cabinets & Storage > Vanities +Furniture > Cabinets & Storage > Vanities > Bathroom Vanities +Furniture > Cabinets & Storage > Vanities > Bedroom Vanities +Furniture > Cabinets & Storage > Wine & Liquor Cabinets +Furniture > Cabinets & Storage > Wine Racks +Furniture > Carts & Islands +Furniture > Carts & Islands > Kitchen & Dining Carts +Furniture > Carts & Islands > Kitchen Islands +Furniture > Chair Accessories +Furniture > Chair Accessories > Hanging Chair Replacement Parts +Furniture > Chairs +Furniture > Chairs > Arm Chairs, Recliners & Sleeper Chairs +Furniture > Chairs > Bean Bag Chairs +Furniture > Chairs > Chaises +Furniture > Chairs > Electric Massaging Chairs +Furniture > Chairs > Floor Chairs +Furniture > Chairs > Folding Chairs & Stools +Furniture > Chairs > Gaming Chairs +Furniture > Chairs > Hanging Chairs +Furniture > Chairs > Kitchen & Dining Room Chairs +Furniture > Chairs > Rocking Chairs +Furniture > Chairs > Slipper Chairs +Furniture > Chairs > Table & Bar Stools +Furniture > Entertainment Centers & TV Stands +Furniture > Furniture Sets +Furniture > Furniture Sets > Bathroom Furniture Sets +Furniture > Furniture Sets > Bedroom Furniture Sets +Furniture > Furniture Sets > Kitchen & Dining Furniture Sets +Furniture > Furniture Sets > Living Room Furniture Sets +Furniture > Futon Frames +Furniture > Futon Pads +Furniture > Futons +Furniture > Office Furniture +Furniture > Office Furniture > Desks +Furniture > Office Furniture > Office Chairs +Furniture > Office Furniture > Office Furniture Sets +Furniture > Office Furniture > Workspace Tables +Furniture > Office Furniture > Workspace Tables > Art & Drafting Tables +Furniture > Office Furniture > Workspace Tables > Conference Room Tables +Furniture > Office Furniture > Workstations & Cubicles +Furniture > Office Furniture Accessories +Furniture > Office Furniture Accessories > Desk Parts & Accessories +Furniture > Office Furniture Accessories > Office Chair Accessories +Furniture > Office Furniture Accessories > Workstation & Cubicle Accessories +Furniture > Ottomans +Furniture > Outdoor Furniture +Furniture > Outdoor Furniture > Outdoor Beds +Furniture > Outdoor Furniture > Outdoor Furniture Sets +Furniture > Outdoor Furniture > Outdoor Ottomans +Furniture > Outdoor Furniture > Outdoor Seating +Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Benches +Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Chairs +Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Sectional Sofa Units +Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Sofas +Furniture > Outdoor Furniture > Outdoor Seating > Sunloungers +Furniture > Outdoor Furniture > Outdoor Storage Boxes +Furniture > Outdoor Furniture > Outdoor Tables +Furniture > Outdoor Furniture Accessories +Furniture > Outdoor Furniture Accessories > Outdoor Furniture Covers +Furniture > Room Divider Accessories +Furniture > Room Dividers +Furniture > Shelving +Furniture > Shelving > Bookcases & Standing Shelves +Furniture > Shelving > Wall Shelves & Ledges +Furniture > Shelving Accessories +Furniture > Shelving Accessories > Replacement Shelves +Furniture > Sofa Accessories +Furniture > Sofa Accessories > Chair & Sofa Supports +Furniture > Sofa Accessories > Sectional Sofa Units +Furniture > Sofas +Furniture > Table Accessories +Furniture > Table Accessories > Table Legs +Furniture > Table Accessories > Table Tops +Furniture > Tables +Furniture > Tables > Accent Tables +Furniture > Tables > Accent Tables > Coffee Tables +Furniture > Tables > Accent Tables > End Tables +Furniture > Tables > Accent Tables > Sofa Tables +Furniture > Tables > Activity Tables +Furniture > Tables > Folding Tables +Furniture > Tables > Kitchen & Dining Room Tables +Furniture > Tables > Kotatsu +Furniture > Tables > Nightstands +Furniture > Tables > Poker & Game Tables +Furniture > Tables > Sewing Machine Tables +Hardware +Hardware > Building Consumables +Hardware > Building Consumables > Chemicals +Hardware > Building Consumables > Chemicals > Acid Neutralizers +Hardware > Building Consumables > Chemicals > Ammonia +Hardware > Building Consumables > Chemicals > Chimney Cleaners +Hardware > Building Consumables > Chemicals > Concrete & Masonry Cleaners +Hardware > Building Consumables > Chemicals > De-icers +Hardware > Building Consumables > Chemicals > Deck & Fence Cleaners +Hardware > Building Consumables > Chemicals > Drain Cleaners +Hardware > Building Consumables > Chemicals > Electrical Freeze Sprays +Hardware > Building Consumables > Chemicals > Lighter Fluid +Hardware > Building Consumables > Chemicals > Septic Tank & Cesspool Treatments +Hardware > Building Consumables > Hardware Glue & Adhesives +Hardware > Building Consumables > Hardware Tape +Hardware > Building Consumables > Lubricants +Hardware > Building Consumables > Masonry Consumables +Hardware > Building Consumables > Masonry Consumables > Bricks & Concrete Blocks +Hardware > Building Consumables > Masonry Consumables > Cement, Mortar & Concrete Mixes +Hardware > Building Consumables > Masonry Consumables > Grout +Hardware > Building Consumables > Painting Consumables +Hardware > Building Consumables > Painting Consumables > Paint +Hardware > Building Consumables > Painting Consumables > Paint Binders +Hardware > Building Consumables > Painting Consumables > Primers +Hardware > Building Consumables > Painting Consumables > Stains +Hardware > Building Consumables > Painting Consumables > Varnishes & Finishes +Hardware > Building Consumables > Plumbing Primer +Hardware > Building Consumables > Protective Coatings & Sealants +Hardware > Building Consumables > Solder & Flux +Hardware > Building Consumables > Solvents, Strippers & Thinners +Hardware > Building Consumables > Wall Patching Compounds & Plaster +Hardware > Building Materials +Hardware > Building Materials > Countertops +Hardware > Building Materials > Door Hardware +Hardware > Building Materials > Door Hardware > Door Bells & Chimes +Hardware > Building Materials > Door Hardware > Door Closers +Hardware > Building Materials > Door Hardware > Door Frames +Hardware > Building Materials > Door Hardware > Door Keyhole Escutcheons +Hardware > Building Materials > Door Hardware > Door Knobs & Handles +Hardware > Building Materials > Door Hardware > Door Knockers +Hardware > Building Materials > Door Hardware > Door Push Plates +Hardware > Building Materials > Door Hardware > Door Stops +Hardware > Building Materials > Door Hardware > Door Strikes +Hardware > Building Materials > Doors +Hardware > Building Materials > Doors > Garage Doors +Hardware > Building Materials > Doors > Home Doors +Hardware > Building Materials > Drywall +Hardware > Building Materials > Flooring & Carpet +Hardware > Building Materials > Glass +Hardware > Building Materials > Handrails & Railing Systems +Hardware > Building Materials > Hatches +Hardware > Building Materials > Insulation +Hardware > Building Materials > Lumber & Sheet Stock +Hardware > Building Materials > Molding +Hardware > Building Materials > Rebar & Remesh +Hardware > Building Materials > Roofing +Hardware > Building Materials > Roofing > Gutter Accessories +Hardware > Building Materials > Roofing > Gutters +Hardware > Building Materials > Roofing > Roof Flashings +Hardware > Building Materials > Roofing > Roofing Shingles & Tiles +Hardware > Building Materials > Shutters +Hardware > Building Materials > Siding +Hardware > Building Materials > Sound Dampening Panels & Foam +Hardware > Building Materials > Staircases +Hardware > Building Materials > Wall & Ceiling Tile +Hardware > Building Materials > Wall Paneling +Hardware > Building Materials > Weather Stripping & Weatherization Supplies +Hardware > Building Materials > Window Hardware +Hardware > Building Materials > Window Hardware > Window Cranks +Hardware > Building Materials > Window Hardware > Window Frames +Hardware > Building Materials > Windows +Hardware > Fencing & Barriers +Hardware > Fencing & Barriers > Fence & Gate Accessories +Hardware > Fencing & Barriers > Fence Panels +Hardware > Fencing & Barriers > Fence Pickets +Hardware > Fencing & Barriers > Fence Posts & Rails +Hardware > Fencing & Barriers > Garden Borders & Edging +Hardware > Fencing & Barriers > Gates +Hardware > Fencing & Barriers > Lattice +Hardware > Fencing & Barriers > Safety & Crowd Control Barriers +Hardware > Fuel Containers & Tanks +Hardware > Hardware Accessories +Hardware > Hardware Accessories > Brackets & Reinforcement Braces +Hardware > Hardware Accessories > Cabinet Hardware +Hardware > Hardware Accessories > Cabinet Hardware > Cabinet & Furniture Keyhole Escutcheons +Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Backplates +Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Catches +Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Doors +Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Knobs & Handles +Hardware > Hardware Accessories > Casters +Hardware > Hardware Accessories > Chain, Wire & Rope +Hardware > Hardware Accessories > Chain, Wire & Rope > Bungee Cords +Hardware > Hardware Accessories > Chain, Wire & Rope > Chains +Hardware > Hardware Accessories > Chain, Wire & Rope > Pull Chains +Hardware > Hardware Accessories > Chain, Wire & Rope > Ropes & Hardware Cable +Hardware > Hardware Accessories > Chain, Wire & Rope > Tie Down Straps +Hardware > Hardware Accessories > Chain, Wire & Rope > Twine +Hardware > Hardware Accessories > Chain, Wire & Rope > Utility Wire +Hardware > Hardware Accessories > Coils +Hardware > Hardware Accessories > Concrete Molds +Hardware > Hardware Accessories > Dowel Pins & Rods +Hardware > Hardware Accessories > Drawer Slides +Hardware > Hardware Accessories > Drop Cloths +Hardware > Hardware Accessories > Filters & Screens +Hardware > Hardware Accessories > Flagging & Caution Tape +Hardware > Hardware Accessories > Gas Hoses +Hardware > Hardware Accessories > Ground Spikes +Hardware > Hardware Accessories > Hardware Fasteners +Hardware > Hardware Accessories > Hardware Fasteners > Drywall Anchors +Hardware > Hardware Accessories > Hardware Fasteners > Nails +Hardware > Hardware Accessories > Hardware Fasteners > Nuts & Bolts +Hardware > Hardware Accessories > Hardware Fasteners > Rivets +Hardware > Hardware Accessories > Hardware Fasteners > Screw Posts +Hardware > Hardware Accessories > Hardware Fasteners > Screws +Hardware > Hardware Accessories > Hardware Fasteners > Threaded Rods +Hardware > Hardware Accessories > Hardware Fasteners > Washers +Hardware > Hardware Accessories > Hinges +Hardware > Hardware Accessories > Hooks, Buckles & Fasteners +Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Chain Connectors & Links +Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Gear Ties +Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Lifting Hooks, Clamps & Shackles +Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Utility Buckles +Hardware > Hardware Accessories > Lubrication Hoses +Hardware > Hardware Accessories > Metal Casting Molds +Hardware > Hardware Accessories > Moving & Soundproofing Blankets & Covers +Hardware > Hardware Accessories > Pneumatic Hoses +Hardware > Hardware Accessories > Post Base Plates +Hardware > Hardware Accessories > Springs +Hardware > Hardware Accessories > Tarps +Hardware > Hardware Accessories > Tool Storage & Organization +Hardware > Hardware Accessories > Tool Storage & Organization > Garden Hose Storage +Hardware > Hardware Accessories > Tool Storage & Organization > Tool & Equipment Belts +Hardware > Hardware Accessories > Tool Storage & Organization > Tool Bags +Hardware > Hardware Accessories > Tool Storage & Organization > Tool Boxes +Hardware > Hardware Accessories > Tool Storage & Organization > Tool Cabinets & Chests +Hardware > Hardware Accessories > Tool Storage & Organization > Tool Organizer Liners & Inserts +Hardware > Hardware Accessories > Tool Storage & Organization > Tool Sheaths +Hardware > Hardware Accessories > Tool Storage & Organization > Work Benches +Hardware > Hardware Accessories > Wall Jacks & Braces +Hardware > Hardware Pumps +Hardware > Hardware Pumps > Home Appliance Pumps +Hardware > Hardware Pumps > Pool, Fountain & Pond Pumps +Hardware > Hardware Pumps > Sprinkler, Booster & Irrigation System Pumps +Hardware > Hardware Pumps > Sump, Sewage & Effluent Pumps +Hardware > Hardware Pumps > Utility Pumps +Hardware > Hardware Pumps > Well Pumps & Systems +Hardware > Heating, Ventilation & Air Conditioning +Hardware > Heating, Ventilation & Air Conditioning > Air & Filter Dryers +Hardware > Heating, Ventilation & Air Conditioning > Air Ducts +Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls +Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Control Panels +Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Humidistats +Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Thermostats +Hardware > Heating, Ventilation & Air Conditioning > Vents & Flues +Hardware > Locks & Keys +Hardware > Locks & Keys > Key Blanks +Hardware > Locks & Keys > Key Caps +Hardware > Locks & Keys > Key Card Entry Systems +Hardware > Locks & Keys > Locks & Latches +Hardware > Plumbing +Hardware > Plumbing > Plumbing Fittings & Supports +Hardware > Plumbing > Plumbing Fittings & Supports > Gaskets & O-Rings +Hardware > Plumbing > Plumbing Fittings & Supports > In-Wall Carriers & Mounting Frames +Hardware > Plumbing > Plumbing Fittings & Supports > Nozzles +Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Adapters & Bushings +Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Caps & Plugs +Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Connectors +Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Flanges +Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Pipe Clamps +Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Regulators +Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Valves +Hardware > Plumbing > Plumbing Fixture Hardware & Parts +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Bases & Feet +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Skirts +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Spouts +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Covers & Strainers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Frames +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Liners +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Openers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Rods +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Plumbing Traps +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Plumbing Wastes +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drains +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories > Faucet Aerators +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories > Faucet Handles & Controls +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Fixture Plates +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Bathtub & Shower Jets +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Electric & Power Showers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Arms & Connectors +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Bases +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Columns +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Doors & Enclosures +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Heads +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Walls & Surrounds +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Water Filters +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Sink Accessories +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Sink Accessories > Sink Legs +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Ballcocks & Flappers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Bidet Faucets & Sprayers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet & Bidet Seats +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Seat Covers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Seat Lid Covers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tank Covers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tank Levers +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tanks +Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Trim +Hardware > Plumbing > Plumbing Fixtures +Hardware > Plumbing > Plumbing Fixtures > Bathroom Suites +Hardware > Plumbing > Plumbing Fixtures > Bathtubs +Hardware > Plumbing > Plumbing Fixtures > Faucets +Hardware > Plumbing > Plumbing Fixtures > Shower Stalls & Kits +Hardware > Plumbing > Plumbing Fixtures > Sinks +Hardware > Plumbing > Plumbing Fixtures > Sinks > Bathroom Sinks +Hardware > Plumbing > Plumbing Fixtures > Sinks > Kitchen & Utility Sinks +Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets +Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Bidets +Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Toilets +Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Urinals +Hardware > Plumbing > Plumbing Hoses & Supply Lines +Hardware > Plumbing > Plumbing Pipes +Hardware > Plumbing > Plumbing Repair Kits +Hardware > Plumbing > Water Dispensing & Filtration +Hardware > Plumbing > Water Dispensing & Filtration > In-Line Water Filters +Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers +Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Drinking Fountains +Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Water Chillers +Hardware > Plumbing > Water Dispensing & Filtration > Water Distillers +Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories +Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Cartridges +Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Housings +Hardware > Plumbing > Water Dispensing & Filtration > Water Softener Salt +Hardware > Plumbing > Water Dispensing & Filtration > Water Softeners +Hardware > Plumbing > Water Levelers +Hardware > Plumbing > Water Timers +Hardware > Plumbing > Well Supplies +Hardware > Power & Electrical Supplies +Hardware > Power & Electrical Supplies > Armatures, Rotors & Stators +Hardware > Power & Electrical Supplies > Ballasts & Starters +Hardware > Power & Electrical Supplies > Carbon Brushes +Hardware > Power & Electrical Supplies > Circuit Breaker Panels +Hardware > Power & Electrical Supplies > Conduit & Housings +Hardware > Power & Electrical Supplies > Conduit & Housings > Electrical Conduit +Hardware > Power & Electrical Supplies > Conduit & Housings > Heat-Shrink Tubing +Hardware > Power & Electrical Supplies > Electrical Motors +Hardware > Power & Electrical Supplies > Electrical Mount Boxes & Brackets +Hardware > Power & Electrical Supplies > Electrical Plug Caps +Hardware > Power & Electrical Supplies > Electrical Switches +Hardware > Power & Electrical Supplies > Electrical Switches > Light Switches +Hardware > Power & Electrical Supplies > Electrical Switches > Specialty Electrical Switches & Relays +Hardware > Power & Electrical Supplies > Electrical Wires & Cable +Hardware > Power & Electrical Supplies > Extension Cord Accessories +Hardware > Power & Electrical Supplies > Extension Cords +Hardware > Power & Electrical Supplies > Generator Accessories +Hardware > Power & Electrical Supplies > Generators +Hardware > Power & Electrical Supplies > Home Automation Kits +Hardware > Power & Electrical Supplies > Phone & Data Jacks +Hardware > Power & Electrical Supplies > Power Converters +Hardware > Power & Electrical Supplies > Power Inlets +Hardware > Power & Electrical Supplies > Power Inverters +Hardware > Power & Electrical Supplies > Power Outlets & Sockets +Hardware > Power & Electrical Supplies > Solar Energy Kits +Hardware > Power & Electrical Supplies > Solar Panels +Hardware > Power & Electrical Supplies > Voltage Transformers & Regulators +Hardware > Power & Electrical Supplies > Wall Plates & Covers +Hardware > Power & Electrical Supplies > Wall Socket Controls & Sensors +Hardware > Power & Electrical Supplies > Wire Caps & Nuts +Hardware > Power & Electrical Supplies > Wire Terminals & Connectors +Hardware > Small Engines +Hardware > Storage Tanks +Hardware > Tool Accessories +Hardware > Tool Accessories > Abrasive Blaster Accessories +Hardware > Tool Accessories > Abrasive Blaster Accessories > Sandblasting Cabinets +Hardware > Tool Accessories > Axe Accessories +Hardware > Tool Accessories > Axe Accessories > Axe Handles +Hardware > Tool Accessories > Axe Accessories > Axe Heads +Hardware > Tool Accessories > Cutter Accessories +Hardware > Tool Accessories > Cutter Accessories > Nibbler Dies +Hardware > Tool Accessories > Drill & Screwdriver Accessories +Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill & Screwdriver Bits +Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Bit Extensions +Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Bit Sharpeners +Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Chucks +Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Stands & Guides +Hardware > Tool Accessories > Drill & Screwdriver Accessories > Hole Saws +Hardware > Tool Accessories > Driver Accessories +Hardware > Tool Accessories > Flashlight Accessories +Hardware > Tool Accessories > Grinder Accessories +Hardware > Tool Accessories > Grinder Accessories > Grinding Wheels & Points +Hardware > Tool Accessories > Hammer Accessories +Hardware > Tool Accessories > Hammer Accessories > Air Hammer Accessories +Hardware > Tool Accessories > Hammer Accessories > Hammer Handles +Hardware > Tool Accessories > Hammer Accessories > Hammer Heads +Hardware > Tool Accessories > Industrial Staples +Hardware > Tool Accessories > Jigs +Hardware > Tool Accessories > Magnetizers & Demagnetizers +Hardware > Tool Accessories > Mattock & Pickaxe Accessories +Hardware > Tool Accessories > Mattock & Pickaxe Accessories > Mattock & Pickaxe Handles +Hardware > Tool Accessories > Measuring Tool & Sensor Accessories +Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Electrical Testing Tool Accessories +Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Gas Detector Accessories +Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Measuring Scale Accessories +Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Multimeter Accessories +Hardware > Tool Accessories > Mixing Tool Paddles +Hardware > Tool Accessories > Paint Tool Accessories +Hardware > Tool Accessories > Paint Tool Accessories > Airbrush Accessories +Hardware > Tool Accessories > Paint Tool Accessories > Paint Brush Cleaning Solutions +Hardware > Tool Accessories > Paint Tool Accessories > Paint Roller Accessories +Hardware > Tool Accessories > Power Tool Batteries +Hardware > Tool Accessories > Power Tool Chargers +Hardware > Tool Accessories > Router Accessories +Hardware > Tool Accessories > Router Accessories > Router Bits +Hardware > Tool Accessories > Router Accessories > Router Tables +Hardware > Tool Accessories > Sanding Accessories +Hardware > Tool Accessories > Sanding Accessories > Sandpaper & Sanding Sponges +Hardware > Tool Accessories > Saw Accessories +Hardware > Tool Accessories > Saw Accessories > Band Saw Accessories +Hardware > Tool Accessories > Saw Accessories > Handheld Circular Saw Accessories +Hardware > Tool Accessories > Saw Accessories > Jigsaw Accessories +Hardware > Tool Accessories > Saw Accessories > Miter Saw Accessories +Hardware > Tool Accessories > Saw Accessories > Table Saw Accessories +Hardware > Tool Accessories > Shaper Accessories +Hardware > Tool Accessories > Shaper Accessories > Shaper Cutters +Hardware > Tool Accessories > Soldering Iron Accessories +Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Stands +Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Tips +Hardware > Tool Accessories > Tool Blades +Hardware > Tool Accessories > Tool Blades > Cutter & Scraper Blades +Hardware > Tool Accessories > Tool Blades > Saw Blades +Hardware > Tool Accessories > Tool Handle Wedges +Hardware > Tool Accessories > Tool Safety Tethers +Hardware > Tool Accessories > Tool Sockets +Hardware > Tool Accessories > Tool Stands +Hardware > Tool Accessories > Tool Stands > Saw Stands +Hardware > Tool Accessories > Wedge Tools +Hardware > Tool Accessories > Welding Accessories +Hardware > Tools +Hardware > Tools > Abrasive Blasters +Hardware > Tools > Anvils +Hardware > Tools > Axes +Hardware > Tools > Carpentry Jointers +Hardware > Tools > Carving Chisels & Gouges +Hardware > Tools > Caulking Tools +Hardware > Tools > Chimney Brushes +Hardware > Tools > Compactors +Hardware > Tools > Compressors +Hardware > Tools > Concrete Brooms +Hardware > Tools > Cutters +Hardware > Tools > Cutters > Bolt Cutters +Hardware > Tools > Cutters > Glass Cutters +Hardware > Tools > Cutters > Handheld Metal Shears & Nibblers +Hardware > Tools > Cutters > Nippers +Hardware > Tools > Cutters > Pipe Cutters +Hardware > Tools > Cutters > Rebar Cutters +Hardware > Tools > Cutters > Tile & Shingle Cutters +Hardware > Tools > Cutters > Utility Knives +Hardware > Tools > Deburrers +Hardware > Tools > Dollies & Hand Trucks +Hardware > Tools > Drills +Hardware > Tools > Drills > Augers +Hardware > Tools > Drills > Drill Presses +Hardware > Tools > Drills > Handheld Power Drills +Hardware > Tools > Drills > Mortisers +Hardware > Tools > Drills > Pneumatic Drills +Hardware > Tools > Electrician Fish Tape +Hardware > Tools > Flashlights & Headlamps +Hardware > Tools > Grease Guns +Hardware > Tools > Grinders +Hardware > Tools > Grips +Hardware > Tools > Hammers +Hardware > Tools > Hammers > Manual Hammers +Hardware > Tools > Hammers > Powered Hammers +Hardware > Tools > Handheld Power Mixers +Hardware > Tools > Hardware Torches +Hardware > Tools > Heat Guns +Hardware > Tools > Impact Wrenches & Drivers +Hardware > Tools > Industrial Vibrators +Hardware > Tools > Inspection Mirrors +Hardware > Tools > Ladders & Scaffolding +Hardware > Tools > Ladders & Scaffolding > Ladder Carts +Hardware > Tools > Ladders & Scaffolding > Ladders +Hardware > Tools > Ladders & Scaffolding > Scaffolding +Hardware > Tools > Ladders & Scaffolding > Step Stools +Hardware > Tools > Ladders & Scaffolding > Work Platforms +Hardware > Tools > Lathes +Hardware > Tools > Light Bulb Changers +Hardware > Tools > Lighters & Matches +Hardware > Tools > Log Splitters +Hardware > Tools > Magnetic Sweepers +Hardware > Tools > Marking Tools +Hardware > Tools > Masonry Tools +Hardware > Tools > Masonry Tools > Brick Tools +Hardware > Tools > Masonry Tools > Cement Mixers +Hardware > Tools > Masonry Tools > Construction Lines +Hardware > Tools > Masonry Tools > Floats +Hardware > Tools > Masonry Tools > Grout Sponges +Hardware > Tools > Masonry Tools > Masonry Edgers & Groovers +Hardware > Tools > Masonry Tools > Masonry Jointers +Hardware > Tools > Masonry Tools > Masonry Trowels +Hardware > Tools > Masonry Tools > Power Trowels +Hardware > Tools > Mattocks & Pickaxes +Hardware > Tools > Measuring Tools & Sensors +Hardware > Tools > Measuring Tools & Sensors > Air Quality Meters +Hardware > Tools > Measuring Tools & Sensors > Altimeters +Hardware > Tools > Measuring Tools & Sensors > Anemometers +Hardware > Tools > Measuring Tools & Sensors > Barometers +Hardware > Tools > Measuring Tools & Sensors > Calipers +Hardware > Tools > Measuring Tools & Sensors > Cruising Rods +Hardware > Tools > Measuring Tools & Sensors > Distance Meters +Hardware > Tools > Measuring Tools & Sensors > Dividers +Hardware > Tools > Measuring Tools & Sensors > Electrical Testing Tools +Hardware > Tools > Measuring Tools & Sensors > Flow Meters & Controllers +Hardware > Tools > Measuring Tools & Sensors > Gas Detectors +Hardware > Tools > Measuring Tools & Sensors > Gauges +Hardware > Tools > Measuring Tools & Sensors > Geiger Counters +Hardware > Tools > Measuring Tools & Sensors > Hygrometers +Hardware > Tools > Measuring Tools & Sensors > Infrared Thermometers +Hardware > Tools > Measuring Tools & Sensors > Knife Guides +Hardware > Tools > Measuring Tools & Sensors > Levels +Hardware > Tools > Measuring Tools & Sensors > Levels > Bubble Levels +Hardware > Tools > Measuring Tools & Sensors > Levels > Laser Levels +Hardware > Tools > Measuring Tools & Sensors > Levels > Sight Levels +Hardware > Tools > Measuring Tools & Sensors > Measuring Scales +Hardware > Tools > Measuring Tools & Sensors > Measuring Wheels +Hardware > Tools > Measuring Tools & Sensors > Moisture Meters +Hardware > Tools > Measuring Tools & Sensors > Probes & Finders +Hardware > Tools > Measuring Tools & Sensors > Protractors +Hardware > Tools > Measuring Tools & Sensors > Rebar Locators +Hardware > Tools > Measuring Tools & Sensors > Rulers +Hardware > Tools > Measuring Tools & Sensors > Seismometer +Hardware > Tools > Measuring Tools & Sensors > Sound Meters +Hardware > Tools > Measuring Tools & Sensors > Squares +Hardware > Tools > Measuring Tools & Sensors > Straight Edges +Hardware > Tools > Measuring Tools & Sensors > Stud Sensors +Hardware > Tools > Measuring Tools & Sensors > Tape Measures +Hardware > Tools > Measuring Tools & Sensors > Theodolites +Hardware > Tools > Measuring Tools & Sensors > Thermal Imaging Cameras +Hardware > Tools > Measuring Tools & Sensors > Thermocouples & Thermopiles +Hardware > Tools > Measuring Tools & Sensors > Transducers +Hardware > Tools > Measuring Tools & Sensors > UV Light Meters +Hardware > Tools > Measuring Tools & Sensors > Vibration Meters +Hardware > Tools > Measuring Tools & Sensors > Weather Forecasters & Stations +Hardware > Tools > Measuring Tools & Sensors > pH Meters +Hardware > Tools > Milling Machines +Hardware > Tools > Multifunction Power Tools +Hardware > Tools > Nail Pullers +Hardware > Tools > Nailers & Staplers +Hardware > Tools > Oil Filter Drains +Hardware > Tools > Paint Tools +Hardware > Tools > Paint Tools > Airbrushes +Hardware > Tools > Paint Tools > Paint Brushes +Hardware > Tools > Paint Tools > Paint Edgers +Hardware > Tools > Paint Tools > Paint Rollers +Hardware > Tools > Paint Tools > Paint Shakers +Hardware > Tools > Paint Tools > Paint Sponges +Hardware > Tools > Paint Tools > Paint Sprayers +Hardware > Tools > Paint Tools > Paint Strainers +Hardware > Tools > Paint Tools > Paint Trays +Hardware > Tools > Pickup Tools +Hardware > Tools > Pipe & Bar Benders +Hardware > Tools > Pipe & Tube Cleaners +Hardware > Tools > Pipe Brushes +Hardware > Tools > Planers +Hardware > Tools > Planes +Hardware > Tools > Pliers +Hardware > Tools > Plungers +Hardware > Tools > Polishers & Buffers +Hardware > Tools > Post Hole Diggers +Hardware > Tools > Pry Bars +Hardware > Tools > Punches & Awls +Hardware > Tools > Putty Knives & Scrapers +Hardware > Tools > Reamers +Hardware > Tools > Riveting Tools +Hardware > Tools > Riveting Tools > Rivet Guns +Hardware > Tools > Riveting Tools > Rivet Pliers +Hardware > Tools > Routing Tools +Hardware > Tools > Sanders +Hardware > Tools > Sanding Blocks +Hardware > Tools > Saw Horses +Hardware > Tools > Saws +Hardware > Tools > Saws > Band Saws +Hardware > Tools > Saws > Cut-Off Saws +Hardware > Tools > Saws > Hand Saws +Hardware > Tools > Saws > Handheld Circular Saws +Hardware > Tools > Saws > Jigsaws +Hardware > Tools > Saws > Masonry & Tile Saws +Hardware > Tools > Saws > Miter Saws +Hardware > Tools > Saws > Panel Saws +Hardware > Tools > Saws > Reciprocating Saws +Hardware > Tools > Saws > Scroll Saws +Hardware > Tools > Saws > Table Saws +Hardware > Tools > Screwdrivers +Hardware > Tools > Shapers +Hardware > Tools > Sharpeners +Hardware > Tools > Socket Drivers +Hardware > Tools > Soldering Irons +Hardware > Tools > Tap Reseaters +Hardware > Tools > Taps & Dies +Hardware > Tools > Threading Machines +Hardware > Tools > Tool Clamps & Vises +Hardware > Tools > Tool Files +Hardware > Tools > Tool Keys +Hardware > Tools > Tool Knives +Hardware > Tools > Tool Sets +Hardware > Tools > Tool Sets > Hand Tool Sets +Hardware > Tools > Tool Sets > Power Tool Combo Sets +Hardware > Tools > Welding Guns & Plasma Cutters +Hardware > Tools > Wire & Cable Hand Tools +Hardware > Tools > Work Lights +Hardware > Tools > Wrenches +Health & Beauty +Health & Beauty > Health Care +Health & Beauty > Health Care > Acupuncture +Health & Beauty > Health Care > Acupuncture > Acupuncture Models +Health & Beauty > Health Care > Acupuncture > Acupuncture Needles +Health & Beauty > Health Care > Bed Pans +Health & Beauty > Health Care > Biometric Monitor Accessories +Health & Beauty > Health Care > Biometric Monitor Accessories > Activity Monitor Accessories +Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories +Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Control Solution +Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Test Strips +Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Lancing Devices +Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories +Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories > Blood Pressure Monitor Cuffs +Health & Beauty > Health Care > Biometric Monitor Accessories > Body Weight Scale Accessories +Health & Beauty > Health Care > Biometric Monitors +Health & Beauty > Health Care > Biometric Monitors > Activity Monitors +Health & Beauty > Health Care > Biometric Monitors > Blood Glucose Meters +Health & Beauty > Health Care > Biometric Monitors > Blood Pressure Monitors +Health & Beauty > Health Care > Biometric Monitors > Body Fat Analyzers +Health & Beauty > Health Care > Biometric Monitors > Body Weight Scales +Health & Beauty > Health Care > Biometric Monitors > Breathalyzers +Health & Beauty > Health Care > Biometric Monitors > Cholesterol Analyzers +Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors and Ovulation Tests +Health & Beauty > Health Care > Biometric Monitors > Medical Thermometers +Health & Beauty > Health Care > Biometric Monitors > Prenatal Heart Rate Monitors +Health & Beauty > Health Care > Biometric Monitors > Pulse Oximeters +Health & Beauty > Health Care > Condoms +Health & Beauty > Health Care > Conductivity Gels & Lotions +Health & Beauty > Health Care > Contraceptive Cases +Health & Beauty > Health Care > First Aid +Health & Beauty > Health Care > First Aid > Antiseptics & Cleaning Supplies +Health & Beauty > Health Care > First Aid > Cast & Bandage Protectors +Health & Beauty > Health Care > First Aid > Eye Wash Supplies +Health & Beauty > Health Care > First Aid > First Aid Kits +Health & Beauty > Health Care > First Aid > Hot & Cold Therapies +Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Heat Rubs +Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Heating Pads +Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Ice Packs +Health & Beauty > Health Care > First Aid > Medical Tape & Bandages +Health & Beauty > Health Care > Fitness & Nutrition +Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Bars +Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Drinks & Shakes +Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Gels & Chews +Health & Beauty > Health Care > Fitness & Nutrition > Nutritional Food Purées +Health & Beauty > Health Care > Fitness & Nutrition > Tube Feeding Supplements +Health & Beauty > Health Care > Fitness & Nutrition > Vitamins & Supplements +Health & Beauty > Health Care > Hearing Aids +Health & Beauty > Health Care > Incontinence Aids +Health & Beauty > Health Care > Light Therapy Lamps +Health & Beauty > Health Care > Medical Alarm Systems +Health & Beauty > Health Care > Medical Identification Tags & Jewelry +Health & Beauty > Health Care > Medical Tests +Health & Beauty > Health Care > Medical Tests > Allergy Test Kits +Health & Beauty > Health Care > Medical Tests > Blood Typing Test Kits +Health & Beauty > Health Care > Medical Tests > Drug Tests +Health & Beauty > Health Care > Medical Tests > HIV Tests +Health & Beauty > Health Care > Medical Tests > Pregnancy Tests +Health & Beauty > Health Care > Medical Tests > Urinary Tract Infection Tests +Health & Beauty > Health Care > Medicine & Drugs +Health & Beauty > Health Care > Mobility & Accessibility +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Mobility Scooters +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Stair Lifts +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Transfer Boards & Sheets +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Wheelchairs +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment Accessories +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures +Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures > Shower Benches & Seats +Health & Beauty > Health Care > Mobility & Accessibility > Walking Aid Accessories +Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids +Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Canes & Walking Sticks +Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Crutches +Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Walkers +Health & Beauty > Health Care > Occupational & Physical Therapy Equipment +Health & Beauty > Health Care > Occupational & Physical Therapy Equipment > Electrical Muscle Stimulators +Health & Beauty > Health Care > Occupational & Physical Therapy Equipment > Therapeutic Swings +Health & Beauty > Health Care > Pillboxes +Health & Beauty > Health Care > Respiratory Care +Health & Beauty > Health Care > Respiratory Care > Nebulizers +Health & Beauty > Health Care > Respiratory Care > Oxygen Tanks +Health & Beauty > Health Care > Respiratory Care > PAP Machines +Health & Beauty > Health Care > Respiratory Care > PAP Masks +Health & Beauty > Health Care > Respiratory Care > Steam Inhalers +Health & Beauty > Health Care > Specimen Cups +Health & Beauty > Health Care > Spermicides +Health & Beauty > Health Care > Stump Shrinkers +Health & Beauty > Health Care > Supports & Braces +Health & Beauty > Health Care > Surgical Lubricants +Health & Beauty > Jewelry Cleaning & Care +Health & Beauty > Jewelry Cleaning & Care > Jewelry Cleaning Solutions & Polishes +Health & Beauty > Jewelry Cleaning & Care > Jewelry Cleaning Tools +Health & Beauty > Jewelry Cleaning & Care > Jewelry Holders +Health & Beauty > Jewelry Cleaning & Care > Jewelry Steam Cleaners +Health & Beauty > Jewelry Cleaning & Care > Watch Repair Kits +Health & Beauty > Personal Care +Health & Beauty > Personal Care > Back Care +Health & Beauty > Personal Care > Back Care > Back & Lumbar Support Cushions +Health & Beauty > Personal Care > Cosmetics +Health & Beauty > Personal Care > Cosmetics > Bath & Body +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Adult Hygienic Wipes +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bar Soap +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Additives +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Brushes +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Sponges & Loofahs +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Body Wash +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Hand Sanitizers & Wipes +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Liquid Hand Soap +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Powdered Hand Soap +Health & Beauty > Personal Care > Cosmetics > Bath & Body > Shower Caps +Health & Beauty > Personal Care > Cosmetics > Bath & Body Gift Sets +Health & Beauty > Personal Care > Cosmetics > Cosmetic Sets +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tool Cleansers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Double Eyelid Glue & Tape +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyebrow Stencils +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curler Refills +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curlers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Face Mirrors +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Facial Blotting Paper +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Adhesive +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Applicators +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Remover +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Brushes +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Sponges +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Refillable Makeup Palettes & Cases +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Pushers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Scissors +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Manicure & Pedicure Spacers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Manicure Tool Sets +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Buffers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Clippers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Drill Accessories +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Drills +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Dryers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Files & Emery Boards +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Facial Saunas +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Foot Files +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Lotion & Sunscreen Applicators +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Pumice Stones +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Extractors +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Rollers +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Cleansing Brush Heads +Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Cleansing Brushes & Systems +Health & Beauty > Personal Care > Cosmetics > Makeup +Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup +Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body & Hair Glitter +Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body Paint & Foundation +Health & Beauty > Personal Care > Cosmetics > Makeup > Costume & Stage Makeup +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eye Primer +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eye Shadow +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyebrow Enhancers +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyeliner +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > False Eyelashes +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Lash & Brow Growth Treatments +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Mascara +Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Mascara Primer +Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup +Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Blushes & Bronzers +Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Face Powder +Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Face Primer +Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Foundations & Concealers +Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Highlighters & Luminizers +Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup +Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip & Cheek Stains +Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Gloss +Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Liner +Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Primer +Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lipstick +Health & Beauty > Personal Care > Cosmetics > Makeup > Makeup Finishing Sprays +Health & Beauty > Personal Care > Cosmetics > Makeup > Temporary Tattoos +Health & Beauty > Personal Care > Cosmetics > Nail Care +Health & Beauty > Personal Care > Cosmetics > Nail Care > Cuticle Cream & Oil +Health & Beauty > Personal Care > Cosmetics > Nail Care > False Nails +Health & Beauty > Personal Care > Cosmetics > Nail Care > Manicure Glue +Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Art Kits & Accessories +Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Drying Drops & Sprays +Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Removers +Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Thinners +Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polishes +Health & Beauty > Personal Care > Cosmetics > Perfume & Cologne +Health & Beauty > Personal Care > Cosmetics > Skin Care +Health & Beauty > Personal Care > Cosmetics > Skin Care > Acne Treatments & Kits +Health & Beauty > Personal Care > Cosmetics > Skin Care > Anti-Aging Skin Care Kits +Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Oil +Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Powder +Health & Beauty > Personal Care > Cosmetics > Skin Care > Compressed Skin Care Mask Sheets +Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansers +Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansing Kits +Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Pore Strips +Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments +Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer +Health & Beauty > Personal Care > Cosmetics > Skin Care > Makeup Removers +Health & Beauty > Personal Care > Cosmetics > Skin Care > Petroleum Jelly +Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Care Masks & Peels +Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Insect Repellent +Health & Beauty > Personal Care > Cosmetics > Skin Care > Sunscreen +Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products +Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Self Tanner +Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Tanning Oil & Lotion +Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents +Health & Beauty > Personal Care > Cosmetics > Skin Care > Wart Removers +Health & Beauty > Personal Care > Cotton Balls +Health & Beauty > Personal Care > Cotton Swabs +Health & Beauty > Personal Care > Deodorant & Anti-Perspirant +Health & Beauty > Personal Care > Ear Care +Health & Beauty > Personal Care > Ear Care > Ear Candles +Health & Beauty > Personal Care > Ear Care > Ear Drops +Health & Beauty > Personal Care > Ear Care > Ear Dryers +Health & Beauty > Personal Care > Ear Care > Ear Picks & Spoons +Health & Beauty > Personal Care > Ear Care > Ear Syringes +Health & Beauty > Personal Care > Ear Care > Ear Wax Removal Kits +Health & Beauty > Personal Care > Ear Care > Earplug Dispensers +Health & Beauty > Personal Care > Ear Care > Earplugs +Health & Beauty > Personal Care > Enema Kits & Supplies +Health & Beauty > Personal Care > Feminine Sanitary Supplies +Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Deodorant +Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Douches & Creams +Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Pads & Protectors +Health & Beauty > Personal Care > Feminine Sanitary Supplies > Menstrual Cups +Health & Beauty > Personal Care > Feminine Sanitary Supplies > Tampons +Health & Beauty > Personal Care > Foot Care +Health & Beauty > Personal Care > Foot Care > Bunion Care Supplies +Health & Beauty > Personal Care > Foot Care > Corn & Callus Care Supplies +Health & Beauty > Personal Care > Foot Care > Foot Odor Removers +Health & Beauty > Personal Care > Foot Care > Insoles & Inserts +Health & Beauty > Personal Care > Foot Care > Toe Spacers +Health & Beauty > Personal Care > Hair Care +Health & Beauty > Personal Care > Hair Care > Hair Care Kits +Health & Beauty > Personal Care > Hair Care > Hair Color +Health & Beauty > Personal Care > Hair Care > Hair Color Removers +Health & Beauty > Personal Care > Hair Care > Hair Coloring Accessories +Health & Beauty > Personal Care > Hair Care > Hair Loss Concealers +Health & Beauty > Personal Care > Hair Care > Hair Loss Treatments +Health & Beauty > Personal Care > Hair Care > Hair Permanents & Straighteners +Health & Beauty > Personal Care > Hair Care > Hair Shears +Health & Beauty > Personal Care > Hair Care > Hair Steamers & Heat Caps +Health & Beauty > Personal Care > Hair Care > Hair Styling Products +Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories +Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Curler Clips & Pins +Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Dryer Accessories +Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Iron Accessories +Health & Beauty > Personal Care > Hair Care > Hair Styling Tools +Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Combs & Brushes +Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Curling Irons +Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Curlers +Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Dryers +Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Straighteners +Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Styling Tool Sets +Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner +Health & Beauty > Personal Care > Massage & Relaxation +Health & Beauty > Personal Care > Massage & Relaxation > Back Scratchers +Health & Beauty > Personal Care > Massage & Relaxation > Eye Pillows +Health & Beauty > Personal Care > Massage & Relaxation > Massage Chairs +Health & Beauty > Personal Care > Massage & Relaxation > Massage Oil +Health & Beauty > Personal Care > Massage & Relaxation > Massage Stone Warmers +Health & Beauty > Personal Care > Massage & Relaxation > Massage Stones +Health & Beauty > Personal Care > Massage & Relaxation > Massage Tables +Health & Beauty > Personal Care > Massage & Relaxation > Massagers +Health & Beauty > Personal Care > Oral Care +Health & Beauty > Personal Care > Oral Care > Breath Spray +Health & Beauty > Personal Care > Oral Care > Dental Floss +Health & Beauty > Personal Care > Oral Care > Dental Mouthguards +Health & Beauty > Personal Care > Oral Care > Dental Water Jet Replacement Tips +Health & Beauty > Personal Care > Oral Care > Dental Water Jets +Health & Beauty > Personal Care > Oral Care > Denture Adhesives +Health & Beauty > Personal Care > Oral Care > Denture Cleaners +Health & Beauty > Personal Care > Oral Care > Denture Repair Kits +Health & Beauty > Personal Care > Oral Care > Dentures +Health & Beauty > Personal Care > Oral Care > Gum Stimulators +Health & Beauty > Personal Care > Oral Care > Mouthwash +Health & Beauty > Personal Care > Oral Care > Orthodontic Appliance Cases +Health & Beauty > Personal Care > Oral Care > Power Flossers +Health & Beauty > Personal Care > Oral Care > Teeth Whiteners +Health & Beauty > Personal Care > Oral Care > Tongue Scrapers +Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories +Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Covers +Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Replacement Heads +Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Sanitizers +Health & Beauty > Personal Care > Oral Care > Toothbrushes +Health & Beauty > Personal Care > Oral Care > Toothpaste +Health & Beauty > Personal Care > Oral Care > Toothpaste Squeezers & Dispensers +Health & Beauty > Personal Care > Oral Care > Toothpicks +Health & Beauty > Personal Care > Personal Lubricants +Health & Beauty > Personal Care > Shaving & Grooming +Health & Beauty > Personal Care > Shaving & Grooming > Aftershave +Health & Beauty > Personal Care > Shaving & Grooming > Body & Facial Hair Bleach +Health & Beauty > Personal Care > Shaving & Grooming > Electric Razor Accessories +Health & Beauty > Personal Care > Shaving & Grooming > Electric Razors +Health & Beauty > Personal Care > Shaving & Grooming > Hair Clipper & Trimmer Accessories +Health & Beauty > Personal Care > Shaving & Grooming > Hair Clippers & Trimmers +Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal +Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Depilatories +Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Electrolysis Devices +Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Epilators +Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Hair Removal Wax Warmers +Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Laser & IPL Hair Removal Devices +Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Waxing Kits & Supplies +Health & Beauty > Personal Care > Shaving & Grooming > Razors & Razor Blades +Health & Beauty > Personal Care > Shaving & Grooming > Shaving Bowls & Mugs +Health & Beauty > Personal Care > Shaving & Grooming > Shaving Brushes +Health & Beauty > Personal Care > Shaving & Grooming > Shaving Cream +Health & Beauty > Personal Care > Shaving & Grooming > Shaving Kits +Health & Beauty > Personal Care > Shaving & Grooming > Styptic Pencils +Health & Beauty > Personal Care > Sleeping Aids +Health & Beauty > Personal Care > Sleeping Aids > Eye Masks +Health & Beauty > Personal Care > Sleeping Aids > Snoring & Sleep Apnea Aids +Health & Beauty > Personal Care > Sleeping Aids > Travel Pillows +Health & Beauty > Personal Care > Sleeping Aids > White Noise Machines +Health & Beauty > Personal Care > Spray Tanning Tents +Health & Beauty > Personal Care > Tanning Beds +Health & Beauty > Personal Care > Tweezers +Health & Beauty > Personal Care > Vision Care +Health & Beauty > Personal Care > Vision Care > Contact Lens Care +Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Care Kits +Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Cases +Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Solution +Health & Beauty > Personal Care > Vision Care > Contact Lenses +Health & Beauty > Personal Care > Vision Care > Eye Drops & Lubricants +Health & Beauty > Personal Care > Vision Care > Eyeglass Lenses +Health & Beauty > Personal Care > Vision Care > Eyeglasses +Health & Beauty > Personal Care > Vision Care > Eyewear Accessories +Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Cases & Holders +Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Lens Cleaning Solutions +Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Straps & Chains +Health & Beauty > Personal Care > Vision Care > Sunglass Lenses +Home & Garden +Home & Garden > Bathroom Accessories +Home & Garden > Bathroom Accessories > Bath Caddies +Home & Garden > Bathroom Accessories > Bath Mats & Rugs +Home & Garden > Bathroom Accessories > Bath Pillows +Home & Garden > Bathroom Accessories > Bathroom Accessory Mounts +Home & Garden > Bathroom Accessories > Bathroom Accessory Sets +Home & Garden > Bathroom Accessories > Facial Tissue Holders +Home & Garden > Bathroom Accessories > Hand Dryer Accessories +Home & Garden > Bathroom Accessories > Hand Dryers +Home & Garden > Bathroom Accessories > Medicine Cabinets +Home & Garden > Bathroom Accessories > Robe Hooks +Home & Garden > Bathroom Accessories > Safety Grab Bars +Home & Garden > Bathroom Accessories > Shower Curtain Rings +Home & Garden > Bathroom Accessories > Shower Curtains +Home & Garden > Bathroom Accessories > Shower Rods +Home & Garden > Bathroom Accessories > Soap & Lotion Dispensers +Home & Garden > Bathroom Accessories > Soap Dishes & Holders +Home & Garden > Bathroom Accessories > Toilet Brush Replacement Heads +Home & Garden > Bathroom Accessories > Toilet Brushes & Holders +Home & Garden > Bathroom Accessories > Toilet Paper Holders +Home & Garden > Bathroom Accessories > Toothbrush Holders +Home & Garden > Bathroom Accessories > Towel Racks & Holders +Home & Garden > Business & Home Security +Home & Garden > Business & Home Security > Dummy Surveillance Cameras +Home & Garden > Business & Home Security > Home Alarm Systems +Home & Garden > Business & Home Security > Motion Sensors +Home & Garden > Business & Home Security > Safety & Security Mirrors +Home & Garden > Business & Home Security > Security Lights +Home & Garden > Business & Home Security > Security Monitors & Recorders +Home & Garden > Business & Home Security > Security Safe Accessories +Home & Garden > Business & Home Security > Security Safes +Home & Garden > Business & Home Security > Security System Sensors +Home & Garden > Decor +Home & Garden > Decor > Address Signs +Home & Garden > Decor > Artificial Flora +Home & Garden > Decor > Artificial Food +Home & Garden > Decor > Artwork +Home & Garden > Decor > Artwork > Decorative Tapestries +Home & Garden > Decor > Artwork > Posters, Prints, & Visual Artwork +Home & Garden > Decor > Artwork > Sculptures & Statues +Home & Garden > Decor > Backrest Pillows +Home & Garden > Decor > Baskets +Home & Garden > Decor > Bird & Wildlife Feeder Accessories +Home & Garden > Decor > Bird & Wildlife Feeders +Home & Garden > Decor > Bird & Wildlife Feeders > Bird Feeders +Home & Garden > Decor > Bird & Wildlife Feeders > Butterfly Feeders +Home & Garden > Decor > Bird & Wildlife Feeders > Squirrel Feeders +Home & Garden > Decor > Bird & Wildlife House Accessories +Home & Garden > Decor > Bird & Wildlife Houses +Home & Garden > Decor > Bird & Wildlife Houses > Bat Houses +Home & Garden > Decor > Bird & Wildlife Houses > Birdhouses +Home & Garden > Decor > Bird & Wildlife Houses > Butterfly Houses +Home & Garden > Decor > Bird Baths +Home & Garden > Decor > Bookends +Home & Garden > Decor > Cardboard Cutouts +Home & Garden > Decor > Chair & Sofa Cushions +Home & Garden > Decor > Clock Parts +Home & Garden > Decor > Clocks +Home & Garden > Decor > Clocks > Alarm Clocks +Home & Garden > Decor > Clocks > Desk & Shelf Clocks +Home & Garden > Decor > Clocks > Floor & Grandfather Clocks +Home & Garden > Decor > Clocks > Wall Clocks +Home & Garden > Decor > Coat & Hat Racks +Home & Garden > Decor > Decorative Bells +Home & Garden > Decor > Decorative Bottles +Home & Garden > Decor > Decorative Bowls +Home & Garden > Decor > Decorative Jars +Home & Garden > Decor > Decorative Plaques +Home & Garden > Decor > Decorative Plates +Home & Garden > Decor > Decorative Trays +Home & Garden > Decor > Door Mats +Home & Garden > Decor > Dreamcatchers +Home & Garden > Decor > Dried Flowers +Home & Garden > Decor > Ecospheres +Home & Garden > Decor > Figurines +Home & Garden > Decor > Finials +Home & Garden > Decor > Flag & Windsock Accessories +Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Pole Lights +Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Pole Mounting Hardware & Kits +Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Poles +Home & Garden > Decor > Flags & Windsocks +Home & Garden > Decor > Flameless Candles +Home & Garden > Decor > Fountains & Ponds +Home & Garden > Decor > Fountains & Ponds > Fountain & Pond Accessories +Home & Garden > Decor > Fountains & Ponds > Fountains & Waterfalls +Home & Garden > Decor > Fountains & Ponds > Ponds +Home & Garden > Decor > Garden & Stepping Stones +Home & Garden > Decor > Growth Charts +Home & Garden > Decor > Home Decor Decals +Home & Garden > Decor > Home Fragrance Accessories +Home & Garden > Decor > Home Fragrance Accessories > Candle & Oil Warmers +Home & Garden > Decor > Home Fragrance Accessories > Candle Holders +Home & Garden > Decor > Home Fragrance Accessories > Candle Snuffers +Home & Garden > Decor > Home Fragrance Accessories > Incense Holders +Home & Garden > Decor > Home Fragrances +Home & Garden > Decor > Home Fragrances > Air Fresheners +Home & Garden > Decor > Home Fragrances > Candles +Home & Garden > Decor > Home Fragrances > Fragrance Oil +Home & Garden > Decor > Home Fragrances > Incense +Home & Garden > Decor > Home Fragrances > Potpourri +Home & Garden > Decor > Home Fragrances > Wax Tarts +Home & Garden > Decor > Hourglasses +Home & Garden > Decor > House Numbers & Letters +Home & Garden > Decor > Lawn Ornaments & Garden Sculptures +Home & Garden > Decor > Mail Slots +Home & Garden > Decor > Mailbox Accessories +Home & Garden > Decor > Mailbox Accessories > Mailbox Covers +Home & Garden > Decor > Mailbox Accessories > Mailbox Enclosures +Home & Garden > Decor > Mailbox Accessories > Mailbox Flags +Home & Garden > Decor > Mailbox Accessories > Mailbox Posts +Home & Garden > Decor > Mailbox Accessories > Mailbox Replacement Doors +Home & Garden > Decor > Mailboxes +Home & Garden > Decor > Mirrors +Home & Garden > Decor > Music Boxes +Home & Garden > Decor > Napkin Rings +Home & Garden > Decor > Novelty Signs +Home & Garden > Decor > Ottoman Cushions +Home & Garden > Decor > Picture Frames +Home & Garden > Decor > Piggy Banks & Money Jars +Home & Garden > Decor > Rain Chains +Home & Garden > Decor > Rain Gauges +Home & Garden > Decor > Refrigerator Magnets +Home & Garden > Decor > Rugs +Home & Garden > Decor > Seasonal & Holiday Decorations +Home & Garden > Decor > Seasonal & Holiday Decorations > Advent Calendars +Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Skirts +Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Stands +Home & Garden > Decor > Seasonal & Holiday Decorations > Easter Egg Decorating Kits +Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornament Displays & Stands +Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornament Hooks +Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornaments +Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stocking Hangers +Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stockings +Home & Garden > Decor > Seasonal & Holiday Decorations > Japanese Traditional Dolls +Home & Garden > Decor > Seasonal & Holiday Decorations > Nativity Sets +Home & Garden > Decor > Seasonal & Holiday Decorations > Seasonal Village Sets & Accessories +Home & Garden > Decor > Shadow Boxes +Home & Garden > Decor > Slipcovers +Home & Garden > Decor > Snow Globes +Home & Garden > Decor > Suncatchers +Home & Garden > Decor > Sundials +Home & Garden > Decor > Throw Pillows +Home & Garden > Decor > Trunks +Home & Garden > Decor > Vase Fillers & Table Scatters +Home & Garden > Decor > Vases +Home & Garden > Decor > Wallpaper +Home & Garden > Decor > Weather Vanes & Roof Decor +Home & Garden > Decor > Wind Chimes +Home & Garden > Decor > Wind Wheels & Spinners +Home & Garden > Decor > Window Magnets +Home & Garden > Decor > Window Treatment Accessories +Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rings +Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rods +Home & Garden > Decor > Window Treatment Accessories > Curtain Holdbacks & Tassels +Home & Garden > Decor > Window Treatment Accessories > Window Treatment Replacement Parts +Home & Garden > Decor > Window Treatments +Home & Garden > Decor > Window Treatments > Curtains & Drapes +Home & Garden > Decor > Window Treatments > Stained Glass Panels +Home & Garden > Decor > Window Treatments > Window Blinds & Shades +Home & Garden > Decor > Window Treatments > Window Films +Home & Garden > Decor > Window Treatments > Window Screens +Home & Garden > Decor > Window Treatments > Window Valances & Cornices +Home & Garden > Decor > World Globes +Home & Garden > Decor > Wreaths & Garlands +Home & Garden > Emergency Preparedness +Home & Garden > Emergency Preparedness > Earthquake Alarms +Home & Garden > Emergency Preparedness > Emergency Blankets +Home & Garden > Emergency Preparedness > Emergency Food Kits +Home & Garden > Emergency Preparedness > Emergency Tools & Kits +Home & Garden > Emergency Preparedness > Furniture Anchors +Home & Garden > Fireplace & Wood Stove Accessories +Home & Garden > Fireplace & Wood Stove Accessories > Bellows +Home & Garden > Fireplace & Wood Stove Accessories > Fireplace & Wood Stove Grates +Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Andirons +Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Reflectors +Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Screens +Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Tools +Home & Garden > Fireplace & Wood Stove Accessories > Firewood & Fuel +Home & Garden > Fireplace & Wood Stove Accessories > Hearth Pads +Home & Garden > Fireplace & Wood Stove Accessories > Log Rack & Carrier Accessories +Home & Garden > Fireplace & Wood Stove Accessories > Log Racks & Carriers +Home & Garden > Fireplace & Wood Stove Accessories > Wood Stove Fans & Blowers +Home & Garden > Fireplaces +Home & Garden > Flood, Fire & Gas Safety +Home & Garden > Flood, Fire & Gas Safety > Fire Alarm Control Panels +Home & Garden > Flood, Fire & Gas Safety > Fire Alarms +Home & Garden > Flood, Fire & Gas Safety > Fire Extinguisher & Equipment Storage +Home & Garden > Flood, Fire & Gas Safety > Fire Extinguishers +Home & Garden > Flood, Fire & Gas Safety > Fire Sprinklers +Home & Garden > Flood, Fire & Gas Safety > Heat Detectors +Home & Garden > Flood, Fire & Gas Safety > Smoke & Carbon Monoxide Detectors +Home & Garden > Flood, Fire & Gas Safety > Water & Flood Detectors +Home & Garden > Household Appliance Accessories +Home & Garden > Household Appliance Accessories > Air Conditioner Accessories +Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Covers +Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Filters +Home & Garden > Household Appliance Accessories > Air Purifier Accessories +Home & Garden > Household Appliance Accessories > Air Purifier Accessories > Air Purifier Filters +Home & Garden > Household Appliance Accessories > Dehumidifier Accessories +Home & Garden > Household Appliance Accessories > Fan Accessories +Home & Garden > Household Appliance Accessories > Floor & Steam Cleaner Accessories +Home & Garden > Household Appliance Accessories > Furnace & Boiler Accessories +Home & Garden > Household Appliance Accessories > Heating Radiator Accessories +Home & Garden > Household Appliance Accessories > Heating Radiator Accessories > Heating Radiator Reflectors +Home & Garden > Household Appliance Accessories > Humidifier Accessories +Home & Garden > Household Appliance Accessories > Humidifier Accessories > Humidifier Filters +Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories +Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Garment Steamer Accessories +Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Iron Accessories +Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Steam Press Accessories +Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Washer & Dryer Accessories +Home & Garden > Household Appliance Accessories > Patio Heater Accessories +Home & Garden > Household Appliance Accessories > Patio Heater Accessories > Patio Heater Covers +Home & Garden > Household Appliance Accessories > Vacuum Accessories +Home & Garden > Household Appliance Accessories > Water Heater Accessories +Home & Garden > Household Appliance Accessories > Water Heater Accessories > Anode Rods +Home & Garden > Household Appliance Accessories > Water Heater Accessories > Hot Water Tanks +Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Elements +Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Expansion Tanks +Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Pans +Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Stacks +Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Vents +Home & Garden > Household Appliances +Home & Garden > Household Appliances > Climate Control Appliances +Home & Garden > Household Appliances > Climate Control Appliances > Air Conditioners +Home & Garden > Household Appliances > Climate Control Appliances > Air Purifiers +Home & Garden > Household Appliances > Climate Control Appliances > Dehumidifiers +Home & Garden > Household Appliances > Climate Control Appliances > Duct Heaters +Home & Garden > Household Appliances > Climate Control Appliances > Evaporative Coolers +Home & Garden > Household Appliances > Climate Control Appliances > Fans +Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ceiling Fans +Home & Garden > Household Appliances > Climate Control Appliances > Fans > Desk & Pedestal Fans +Home & Garden > Household Appliances > Climate Control Appliances > Fans > Powered Hand Fans & Misters +Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ventilation Fans +Home & Garden > Household Appliances > Climate Control Appliances > Fans > Wall Mount Fans +Home & Garden > Household Appliances > Climate Control Appliances > Furnaces & Boilers +Home & Garden > Household Appliances > Climate Control Appliances > Heating Radiators +Home & Garden > Household Appliances > Climate Control Appliances > Humidifiers +Home & Garden > Household Appliances > Climate Control Appliances > Outdoor Misting Systems +Home & Garden > Household Appliances > Climate Control Appliances > Patio Heaters +Home & Garden > Household Appliances > Climate Control Appliances > Space Heaters +Home & Garden > Household Appliances > Floor & Carpet Dryers +Home & Garden > Household Appliances > Floor & Steam Cleaners +Home & Garden > Household Appliances > Floor Polishers & Buffers +Home & Garden > Household Appliances > Futon Dryers +Home & Garden > Household Appliances > Garage Door Keypads & Remotes +Home & Garden > Household Appliances > Garage Door Openers +Home & Garden > Household Appliances > Laundry Appliances +Home & Garden > Household Appliances > Laundry Appliances > Dryers +Home & Garden > Household Appliances > Laundry Appliances > Garment Steamers +Home & Garden > Household Appliances > Laundry Appliances > Irons & Ironing Systems +Home & Garden > Household Appliances > Laundry Appliances > Laundry Combo Units +Home & Garden > Household Appliances > Laundry Appliances > Steam Presses +Home & Garden > Household Appliances > Laundry Appliances > Washing Machines +Home & Garden > Household Appliances > Ultrasonic Cleaners +Home & Garden > Household Appliances > Vacuums +Home & Garden > Household Appliances > Wallpaper Steamers +Home & Garden > Household Appliances > Water Heaters +Home & Garden > Household Supplies +Home & Garden > Household Supplies > Drawer & Shelf Liners +Home & Garden > Household Supplies > Floor Protection Films & Runners +Home & Garden > Household Supplies > Furniture Floor Protectors +Home & Garden > Household Supplies > Garage Floor Mats +Home & Garden > Household Supplies > Garbage Bags +Home & Garden > Household Supplies > Household Cleaning Supplies +Home & Garden > Household Supplies > Household Cleaning Supplies > Broom & Mop Handles +Home & Garden > Household Supplies > Household Cleaning Supplies > Broom Heads +Home & Garden > Household Supplies > Household Cleaning Supplies > Brooms +Home & Garden > Household Supplies > Household Cleaning Supplies > Buckets +Home & Garden > Household Supplies > Household Cleaning Supplies > Carpet Sweepers +Home & Garden > Household Supplies > Household Cleaning Supplies > Cleaning Gloves +Home & Garden > Household Supplies > Household Cleaning Supplies > Duster Refills +Home & Garden > Household Supplies > Household Cleaning Supplies > Dusters +Home & Garden > Household Supplies > Household Cleaning Supplies > Dustpans +Home & Garden > Household Supplies > Household Cleaning Supplies > Fabric & Upholstery Protectors +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > All-Purpose Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Carpet Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Descalers & Decalcifiers +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dish Detergent & Soap +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dishwasher Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Fabric & Upholstery Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Floor Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Furniture Cleaners & Polish +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Household Disinfectants +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Oven & Grill Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Pet Odor & Stain Removers +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Rinse Aids +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Stainless Steel Cleaners & Polishes +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Toilet Bowl Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Tub & Tile Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Washing Machine Cleaners +Home & Garden > Household Supplies > Household Cleaning Supplies > Mop Heads & Refills +Home & Garden > Household Supplies > Household Cleaning Supplies > Mops +Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brush Heads & Refills +Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brushes +Home & Garden > Household Supplies > Household Cleaning Supplies > Shop Towels & General-Purpose Cleaning Cloths +Home & Garden > Household Supplies > Household Cleaning Supplies > Sponges & Scouring Pads +Home & Garden > Household Supplies > Household Cleaning Supplies > Squeegees +Home & Garden > Household Supplies > Household Paper Products +Home & Garden > Household Supplies > Household Paper Products > Facial Tissues +Home & Garden > Household Supplies > Household Paper Products > Paper Napkins +Home & Garden > Household Supplies > Household Paper Products > Paper Towels +Home & Garden > Household Supplies > Household Paper Products > Toilet Paper +Home & Garden > Household Supplies > Household Thermometers +Home & Garden > Household Supplies > Laundry Supplies +Home & Garden > Household Supplies > Laundry Supplies > Bleach +Home & Garden > Household Supplies > Laundry Supplies > Clothespins +Home & Garden > Household Supplies > Laundry Supplies > Dry Cleaning Kits +Home & Garden > Household Supplies > Laundry Supplies > Drying Racks & Hangers +Home & Garden > Household Supplies > Laundry Supplies > Fabric Refreshers +Home & Garden > Household Supplies > Laundry Supplies > Fabric Shavers +Home & Garden > Household Supplies > Laundry Supplies > Fabric Softeners & Dryer Sheets +Home & Garden > Household Supplies > Laundry Supplies > Fabric Stain Removers +Home & Garden > Household Supplies > Laundry Supplies > Fabric Starch +Home & Garden > Household Supplies > Laundry Supplies > Garment Shields +Home & Garden > Household Supplies > Laundry Supplies > Iron Rests +Home & Garden > Household Supplies > Laundry Supplies > Ironing Board Pads & Covers +Home & Garden > Household Supplies > Laundry Supplies > Ironing Board Replacement Parts +Home & Garden > Household Supplies > Laundry Supplies > Ironing Boards +Home & Garden > Household Supplies > Laundry Supplies > Laundry Balls +Home & Garden > Household Supplies > Laundry Supplies > Laundry Baskets +Home & Garden > Household Supplies > Laundry Supplies > Laundry Detergent +Home & Garden > Household Supplies > Laundry Supplies > Laundry Wash Bags & Frames +Home & Garden > Household Supplies > Laundry Supplies > Lint Rollers +Home & Garden > Household Supplies > Laundry Supplies > Wrinkle Releasers & Anti-Static Sprays +Home & Garden > Household Supplies > Moisture Absorbers +Home & Garden > Household Supplies > Pest Control +Home & Garden > Household Supplies > Pest Control > Fly Swatters +Home & Garden > Household Supplies > Pest Control > Pest Control Traps +Home & Garden > Household Supplies > Pest Control > Pesticides +Home & Garden > Household Supplies > Pest Control > Repellents +Home & Garden > Household Supplies > Pest Control > Repellents > Animal & Pet Repellents +Home & Garden > Household Supplies > Pest Control > Repellents > Household Insect Repellents +Home & Garden > Household Supplies > Rug Pads +Home & Garden > Household Supplies > Shoe Care & Tools +Home & Garden > Household Supplies > Shoe Care & Tools > Boot Pulls +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Bags +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Brushes +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Care Kits +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Dryers +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Horns & Dressing Aids +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishers +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishes & Waxes +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Scrapers +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Treatments & Dyes +Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Trees & Shapers +Home & Garden > Household Supplies > Stair Treads +Home & Garden > Household Supplies > Storage & Organization +Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage +Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Charging Valets +Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Closet Organizers & Garment Racks +Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Clothes Valets +Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hangers +Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hat Boxes +Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Shoe Racks & Organizers +Home & Garden > Household Supplies > Storage & Organization > Flatware Chests +Home & Garden > Household Supplies > Storage & Organization > Household Drawer Organizer Inserts +Home & Garden > Household Supplies > Storage & Organization > Household Storage Bags +Home & Garden > Household Supplies > Storage & Organization > Household Storage Caddies +Home & Garden > Household Supplies > Storage & Organization > Household Storage Containers +Home & Garden > Household Supplies > Storage & Organization > Household Storage Drawers +Home & Garden > Household Supplies > Storage & Organization > Photo Storage +Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Albums +Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Storage Boxes +Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks +Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Ironing Board Hooks & Racks +Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Umbrella Stands & Racks +Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Utility Hooks +Home & Garden > Household Supplies > Trash Compactor Accessories +Home & Garden > Household Supplies > Waste Containment +Home & Garden > Household Supplies > Waste Containment > Dumpsters +Home & Garden > Household Supplies > Waste Containment > Hazardous Waste Containers +Home & Garden > Household Supplies > Waste Containment > Recycling Containers +Home & Garden > Household Supplies > Waste Containment > Trash Cans & Wastebaskets +Home & Garden > Household Supplies > Waste Containment Accessories +Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Carts +Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Enclosures +Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Labels & Signs +Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Lids +Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Wheels +Home & Garden > Kitchen & Dining +Home & Garden > Kitchen & Dining > Barware +Home & Garden > Kitchen & Dining > Barware > Absinthe Fountains +Home & Garden > Kitchen & Dining > Barware > Beer Dispensers & Taps +Home & Garden > Kitchen & Dining > Barware > Beverage Chilling Cubes & Sticks +Home & Garden > Kitchen & Dining > Barware > Beverage Tubs & Chillers +Home & Garden > Kitchen & Dining > Barware > Bottle Caps +Home & Garden > Kitchen & Dining > Barware > Bottle Stoppers & Savers +Home & Garden > Kitchen & Dining > Barware > Coaster Holders +Home & Garden > Kitchen & Dining > Barware > Coasters +Home & Garden > Kitchen & Dining > Barware > Cocktail & Barware Tool Sets +Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools +Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Bar Ice Picks +Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Bottle Openers +Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Cocktail Shakers +Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Cocktail Strainers +Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Muddlers +Home & Garden > Kitchen & Dining > Barware > Corkscrews +Home & Garden > Kitchen & Dining > Barware > Decanters +Home & Garden > Kitchen & Dining > Barware > Foil Cutters +Home & Garden > Kitchen & Dining > Barware > Wine Aerators +Home & Garden > Kitchen & Dining > Barware > Wine Bottle Holders +Home & Garden > Kitchen & Dining > Barware > Wine Glass Charms +Home & Garden > Kitchen & Dining > Cookware & Bakeware +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bakeware Sets +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Baking & Cookie Sheets +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bread Pans & Molds +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Broiling Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Cake Pans & Molds +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Muffin & Pastry Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pie & Quiche Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Stones +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Ramekins & Souffle Dishes +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Roasting Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Mats & Liners +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Weights +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Roasting Pan Racks +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware & Bakeware Combo Sets +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Casserole Dishes +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Cookware Sets +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Crêpe & Blini Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Double Boilers +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Dutch Ovens +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Fermentation & Pickling Crocks +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Griddles & Grill Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Grill Presses +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Paella Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Pressure Cookers & Canners +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Saucepans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Sauté Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Skillets & Frying Pans +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stock Pots +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stovetop Kettles +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Tagines & Clay Cooking Pots +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Woks +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Handles +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Lids +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pressure Cooker & Canner Accessories +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Steamer Baskets +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Brushes +Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Rings +Home & Garden > Kitchen & Dining > Food & Beverage Carriers +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Airpots +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Canteens +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Coolers +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Can & Bottle Sleeves +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Cup Sleeves +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Flasks +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Insulated Bags +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Lunch Boxes & Totes +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Picnic Baskets +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Replacement Drink Lids +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Thermoses +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Water Bottles +Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Wine Carrier Bags +Home & Garden > Kitchen & Dining > Food Storage +Home & Garden > Kitchen & Dining > Food Storage > Bread Boxes & Bags +Home & Garden > Kitchen & Dining > Food Storage > Candy Buckets +Home & Garden > Kitchen & Dining > Food Storage > Cookie Jars +Home & Garden > Kitchen & Dining > Food Storage > Food Container Covers +Home & Garden > Kitchen & Dining > Food Storage > Food Storage Bags +Home & Garden > Kitchen & Dining > Food Storage > Food Storage Containers +Home & Garden > Kitchen & Dining > Food Storage > Food Wraps +Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Foil +Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Parchment Paper +Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Plastic Wrap +Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Wax Paper +Home & Garden > Kitchen & Dining > Food Storage > Honey Jars +Home & Garden > Kitchen & Dining > Food Storage Accessories +Home & Garden > Kitchen & Dining > Food Storage Accessories > Food & Beverage Labels +Home & Garden > Kitchen & Dining > Food Storage Accessories > Food Wrap Dispensers +Home & Garden > Kitchen & Dining > Food Storage Accessories > Oxygen Absorbers +Home & Garden > Kitchen & Dining > Food Storage Accessories > Twist Ties & Bag Clips +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Breadmaker Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanter Warmers +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanters +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filter Baskets +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filters +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Grinder Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Grinders +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Maker & Espresso Machine Replacement Parts +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Maker Water Filters +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Frothing Pitchers +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Portafilters +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cooktop, Oven & Range Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cotton Candy Machine Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Deep Fryer Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Dishwasher Parts & Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Electric Kettle Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Electric Skillet & Wok Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Cooking Gel Fuels +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Forks +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Pot Stands +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Sheets +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Trays +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Grinder Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer & Blender Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Freezer Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Garbage Disposal Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories > Ice Cream Maker Freezer Bowls +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Crusher & Shaver Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Maker Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Juicer Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Microwave Oven Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Briquettes +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Chimneys +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Carts +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Covers +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Racks & Toppers +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Replacement Parts +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Spits & Baskets +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grilling Planks +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Smoking Chips & Pellets +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Pasta Maker Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Popcorn Maker Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Portable Cooking Stove Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Range Hood Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Refrigerator Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Soda Maker Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pan Covers +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pans +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Toaster Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories > Vacuum Sealer Bags +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Waffle Iron Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories > Water Cooler Bottles +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Wine Fridge Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Yogurt Maker Accessories +Home & Garden > Kitchen & Dining > Kitchen Appliances +Home & Garden > Kitchen & Dining > Kitchen Appliances > Beverage Warmers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Breadmakers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Chocolate Tempering Machines +Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines +Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Drip Coffee Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Electric & Stovetop Espresso Pots +Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Espresso Machines +Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > French Presses +Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Percolators +Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Vacuum Coffee Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Cooktops +Home & Garden > Kitchen & Dining > Kitchen Appliances > Cotton Candy Machines +Home & Garden > Kitchen & Dining > Kitchen Appliances > Deep Fryers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Deli Slicers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Dishwashers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Griddles & Grills +Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Kettles +Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Skillets & Woks +Home & Garden > Kitchen & Dining > Kitchen Appliances > Fondue Pots & Sets +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Egg Cookers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Food Steamers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Rice Cookers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Slow Cookers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Thermal Cookers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Water Ovens +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Dehydrators +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Mixers & Blenders +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Smokers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Chafing Dishes +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Food Heat Lamps +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Rice Keepers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Steam Tables +Home & Garden > Kitchen & Dining > Kitchen Appliances > Freezers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Frozen Drink Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Garbage Disposals +Home & Garden > Kitchen & Dining > Kitchen Appliances > Gas Griddles +Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Drink Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Plates +Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Cream Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Crushers & Shavers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Juicers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Knife Sharpeners +Home & Garden > Kitchen & Dining > Kitchen Appliances > Microwave Ovens +Home & Garden > Kitchen & Dining > Kitchen Appliances > Milk Frothers & Steamers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Mochi Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Outdoor Grills +Home & Garden > Kitchen & Dining > Kitchen Appliances > Ovens +Home & Garden > Kitchen & Dining > Kitchen Appliances > Pasta Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Popcorn Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Portable Cooking Stoves +Home & Garden > Kitchen & Dining > Kitchen Appliances > Range Hoods +Home & Garden > Kitchen & Dining > Kitchen Appliances > Ranges +Home & Garden > Kitchen & Dining > Kitchen Appliances > Refrigerators +Home & Garden > Kitchen & Dining > Kitchen Appliances > Roaster Ovens & Rotisseries +Home & Garden > Kitchen & Dining > Kitchen Appliances > Soda Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Soy Milk Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Tea Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Countertop & Toaster Ovens +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Donut Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Muffin & Cupcake Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizza Makers & Ovens +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizzelle Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pretzel Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Sandwich Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Toasters +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Tortilla & Flatbread Makers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Waffle Irons +Home & Garden > Kitchen & Dining > Kitchen Appliances > Trash Compactors +Home & Garden > Kitchen & Dining > Kitchen Appliances > Vacuum Sealers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Coolers +Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Filters +Home & Garden > Kitchen & Dining > Kitchen Appliances > Wine Fridges +Home & Garden > Kitchen & Dining > Kitchen Appliances > Yogurt Makers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Aprons +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Baking Peels +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basters +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basting Brushes +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Beverage Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Decorating Supplies +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Servers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Crushers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Openers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Carving Forks +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Channel Knives +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Colanders & Strainers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Condiment Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Cutters +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Presses +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometer Accessories +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Timers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Torches +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooling Racks +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cutting Boards +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dish Racks & Drain Boards +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dough Wheels +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories > Electric Knife Replacement Blades +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knives +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Flour Sifters +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food & Drink Stencils +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Lobster & Crab Crackers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers > Decorative Nutcrackers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Graters & Zesters +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Peelers & Corers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Steaming Bags +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Sticks & Skewers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Funnels +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Garlic Presses +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Gelatin Molds +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ice Cube Trays +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Jerky Guns +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Knives +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Molds +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Can Organizers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Drinkware Holders +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Cabinet Organizers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Counter & Beverage Station Organizers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Utensil Holders & Racks +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Knife Blocks & Holders +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Napkin Holders & Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Paper Towel Holders & Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Pot Racks +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Spice Organizers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Straw Holders & Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Sugar Caddies +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Toothpick Holders & Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Utensil & Flatware Trays +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bench Scrapers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bowl Scrapers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Grill Scrapers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Shears +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Utensil Sets +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ladles +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mashers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Measuring Cups & Spoons +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Meat Tenderizers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mixing Bowls +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mortars & Pestles +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oil & Vinegar Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Bags +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Mitts & Pot Holders +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pasta Molds & Stamps +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Blenders +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Cloths +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutter Accessories +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutters +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ricers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Covers & Sleeves +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Rings +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pins +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Dressing Mixers & Shakers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Spinners +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Cream Scoops +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Scoops +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Melon Ballers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Popcorn & French Fry Scoops +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Caddies +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Mats & Grids +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Slotted Spoons +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spatulas +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spice Grinder Accessories +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spice Grinders +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spoon Rests +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sugar Dispensers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sushi Mats +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tea Strainers +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tongs +Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Whisks +Home & Garden > Kitchen & Dining > Prefabricated Kitchens & Kitchenettes +Home & Garden > Kitchen & Dining > Tableware +Home & Garden > Kitchen & Dining > Tableware > Coffee & Tea Sets +Home & Garden > Kitchen & Dining > Tableware > Coffee Servers & Tea Pots +Home & Garden > Kitchen & Dining > Tableware > Dinnerware +Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Bowls +Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Dinnerware Sets +Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Plates +Home & Garden > Kitchen & Dining > Tableware > Drinkware +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Beer Glasses +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Cups +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Saucers +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Drinkware Sets +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Mugs +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Shot Glasses +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware +Home & Garden > Kitchen & Dining > Tableware > Drinkware > Tumblers +Home & Garden > Kitchen & Dining > Tableware > Flatware +Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopstick Accessories +Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopsticks +Home & Garden > Kitchen & Dining > Tableware > Flatware > Flatware Sets +Home & Garden > Kitchen & Dining > Tableware > Flatware > Forks +Home & Garden > Kitchen & Dining > Tableware > Flatware > Spoons +Home & Garden > Kitchen & Dining > Tableware > Flatware > Table Knives +Home & Garden > Kitchen & Dining > Tableware > Salt & Pepper Shakers +Home & Garden > Kitchen & Dining > Tableware > Serveware +Home & Garden > Kitchen & Dining > Tableware > Serveware > Butter Dishes +Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Boards +Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Stands +Home & Garden > Kitchen & Dining > Tableware > Serveware > Egg Cups +Home & Garden > Kitchen & Dining > Tableware > Serveware > Gravy Boats +Home & Garden > Kitchen & Dining > Tableware > Serveware > Punch Bowls +Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Pitchers & Carafes +Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Platters +Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Trays +Home & Garden > Kitchen & Dining > Tableware > Serveware > Sugar Bowls & Creamers +Home & Garden > Kitchen & Dining > Tableware > Serveware > Tureens +Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories +Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Punch Bowl Stands +Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Lids +Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Stands +Home & Garden > Kitchen & Dining > Tableware > Tablecloth Clips & Weights +Home & Garden > Kitchen & Dining > Tableware > Trivets +Home & Garden > Lawn & Garden +Home & Garden > Lawn & Garden > Gardening +Home & Garden > Lawn & Garden > Gardening > Composting +Home & Garden > Lawn & Garden > Gardening > Composting > Compost +Home & Garden > Lawn & Garden > Gardening > Composting > Compost Aerators +Home & Garden > Lawn & Garden > Gardening > Composting > Composters +Home & Garden > Lawn & Garden > Gardening > Disease Control +Home & Garden > Lawn & Garden > Gardening > Fertilizers +Home & Garden > Lawn & Garden > Gardening > Garden Pot Saucers & Trays +Home & Garden > Lawn & Garden > Gardening > Gardening Accessories +Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Scooters, Seats & Kneelers +Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Totes +Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Potting Benches +Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories +Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Gardening Tool Handles +Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Gardening Tool Heads +Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Wheelbarrow Parts +Home & Garden > Lawn & Garden > Gardening > Gardening Tools +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Bulb Planting Tools +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Cultivating Tools +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Forks +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Sickles & Machetes +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Trowels +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn & Garden Sprayers +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn Rollers +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Saws +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Shears +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Rakes +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Shovels & Spades +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Spreaders +Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Wheelbarrows +Home & Garden > Lawn & Garden > Gardening > Greenhouses +Home & Garden > Lawn & Garden > Gardening > Herbicides +Home & Garden > Lawn & Garden > Gardening > Landscape Fabric +Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories +Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories > Landscape Fabric Staples & Pins +Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories > Landscape Fabric Tape +Home & Garden > Lawn & Garden > Gardening > Mulch +Home & Garden > Lawn & Garden > Gardening > Plant Cages & Supports +Home & Garden > Lawn & Garden > Gardening > Plant Stands +Home & Garden > Lawn & Garden > Gardening > Pot & Planter Liners +Home & Garden > Lawn & Garden > Gardening > Pots & Planters +Home & Garden > Lawn & Garden > Gardening > Rain Barrels +Home & Garden > Lawn & Garden > Gardening > Sands & Soils +Home & Garden > Lawn & Garden > Outdoor Living +Home & Garden > Lawn & Garden > Outdoor Living > Awning Accessories +Home & Garden > Lawn & Garden > Outdoor Living > Awnings +Home & Garden > Lawn & Garden > Outdoor Living > Hammock Parts & Accessories +Home & Garden > Lawn & Garden > Outdoor Living > Hammocks +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Beach Mats +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Picnic Blankets +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Poncho Liners +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopies & Gazebos +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Enclosure Kits +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Frames +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Tops +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Poles +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Weights +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Arches, Trellises, Arbors & Pergolas +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Bridges +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Sheds, Garages & Carports +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella & Sunshade Fabric +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Bases +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Covers +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Enclosure Kits +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Lights +Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrellas & Sunshades +Home & Garden > Lawn & Garden > Outdoor Living > Porch Swing Accessories +Home & Garden > Lawn & Garden > Outdoor Living > Porch Swings +Home & Garden > Lawn & Garden > Outdoor Power Equipment +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Chainsaws +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Grass Edgers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Hedge Trimmers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Aerators & Dethatchers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Riding Mowers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Robotic Mowers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Tow-Behind Mowers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Walk-Behind Mowers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Vacuums +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Leaf Blowers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Base Units +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Sets +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Power Sweepers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Power Tillers & Cultivators +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Pressure Washers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Snow Blowers +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Tractors +Home & Garden > Lawn & Garden > Outdoor Power Equipment > Weed Trimmers +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Bars +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Chains +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Grass Edger Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Hedge Trimmer Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Brush Mower Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Bags +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Belts +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Blades +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Covers +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Mulch Kits +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Mulch Plugs & Plates +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Pulleys & Idlers +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Tire Tubes +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Tires +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Wheels +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Striping Kits +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Sweepers +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories > Leaf Blower Tubes +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Grass Edger Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Ground & Leaf Blower Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Hedge Trimmer Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Pole Saw Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Tiller & Cultivator Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Weed Trimmer Attachments +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Outdoor Power Equipment Batteries +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Pressure Washer Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Snow Blower Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories > Tractor Tires +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories > Tractor Wheels +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Blades & Spools +Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Spool Covers +Home & Garden > Lawn & Garden > Snow Removal +Home & Garden > Lawn & Garden > Snow Removal > Ice Scrapers & Snow Brushes +Home & Garden > Lawn & Garden > Snow Removal > Snow Shovels +Home & Garden > Lawn & Garden > Watering & Irrigation +Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hose Fittings & Valves +Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hose Spray Nozzles +Home & Garden > Lawn & Garden > Watering & Irrigation > Garden Hoses +Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories +Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories > Sprinkler Controls +Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinkler Accessories > Sprinkler Valves +Home & Garden > Lawn & Garden > Watering & Irrigation > Sprinklers & Sprinkler Heads +Home & Garden > Lawn & Garden > Watering & Irrigation > Watering Can Accesssories +Home & Garden > Lawn & Garden > Watering & Irrigation > Watering Cans +Home & Garden > Lawn & Garden > Watering & Irrigation > Watering Globes & Spikes +Home & Garden > Lighting +Home & Garden > Lighting > Emergency Lighting +Home & Garden > Lighting > Floating & Submersible Lights +Home & Garden > Lighting > Flood & Spot Lights +Home & Garden > Lighting > In-Ground Lights +Home & Garden > Lighting > Lamps +Home & Garden > Lighting > Landscape Pathway Lighting +Home & Garden > Lighting > Light Bulbs +Home & Garden > Lighting > Light Bulbs > Compact Fluorescent Lamps +Home & Garden > Lighting > Light Bulbs > Fluorescent Tubes +Home & Garden > Lighting > Light Bulbs > Incandescent Light Bulbs +Home & Garden > Lighting > Light Bulbs > LED Light Bulbs +Home & Garden > Lighting > Light Ropes & Strings +Home & Garden > Lighting > Lighting Fixtures +Home & Garden > Lighting > Lighting Fixtures > Cabinet Light Fixtures +Home & Garden > Lighting > Lighting Fixtures > Ceiling Light Fixtures +Home & Garden > Lighting > Lighting Fixtures > Chandeliers +Home & Garden > Lighting > Lighting Fixtures > Wall Light Fixtures +Home & Garden > Lighting > Night Lights & Ambient Lighting +Home & Garden > Lighting > Picture Lights +Home & Garden > Lighting > Tiki Torches & Oil Lamps +Home & Garden > Lighting > Track Lighting +Home & Garden > Lighting > Track Lighting > Track Lighting Accessories +Home & Garden > Lighting > Track Lighting > Track Lighting Fixtures +Home & Garden > Lighting > Track Lighting > Track Lighting Rails +Home & Garden > Lighting Accessories +Home & Garden > Lighting Accessories > Lamp Post Bases +Home & Garden > Lighting Accessories > Lamp Post Mounts +Home & Garden > Lighting Accessories > Lamp Shades +Home & Garden > Lighting Accessories > Lighting Timers +Home & Garden > Lighting Accessories > Oil Lamp Fuel +Home & Garden > Linens & Bedding +Home & Garden > Linens & Bedding > Bedding +Home & Garden > Linens & Bedding > Bedding > Bed Canopies +Home & Garden > Linens & Bedding > Bedding > Bed Sheets +Home & Garden > Linens & Bedding > Bedding > Bedskirts +Home & Garden > Linens & Bedding > Bedding > Blankets +Home & Garden > Linens & Bedding > Bedding > Duvet Covers +Home & Garden > Linens & Bedding > Bedding > Mattress Protectors +Home & Garden > Linens & Bedding > Bedding > Mattress Protectors > Mattress Encasements +Home & Garden > Linens & Bedding > Bedding > Mattress Protectors > Mattress Pads +Home & Garden > Linens & Bedding > Bedding > Nap Mats +Home & Garden > Linens & Bedding > Bedding > Pillowcases & Shams +Home & Garden > Linens & Bedding > Bedding > Pillows +Home & Garden > Linens & Bedding > Bedding > Quilts & Comforters +Home & Garden > Linens & Bedding > Kitchen Linens Sets +Home & Garden > Linens & Bedding > Table Linens +Home & Garden > Linens & Bedding > Table Linens > Cloth Napkins +Home & Garden > Linens & Bedding > Table Linens > Doilies +Home & Garden > Linens & Bedding > Table Linens > Placemats +Home & Garden > Linens & Bedding > Table Linens > Table Runners +Home & Garden > Linens & Bedding > Table Linens > Table Skirts +Home & Garden > Linens & Bedding > Table Linens > Tablecloths +Home & Garden > Linens & Bedding > Towels +Home & Garden > Linens & Bedding > Towels > Bath Towels & Washcloths +Home & Garden > Linens & Bedding > Towels > Beach Towels +Home & Garden > Linens & Bedding > Towels > Kitchen Towels +Home & Garden > Parasols & Rain Umbrellas +Home & Garden > Plants +Home & Garden > Plants > Aquatic Plants +Home & Garden > Plants > Flowers +Home & Garden > Plants > Indoor & Outdoor Plants +Home & Garden > Plants > Plant & Herb Growing Kits +Home & Garden > Plants > Seeds +Home & Garden > Plants > Trees +Home & Garden > Pool & Spa +Home & Garden > Pool & Spa > Pool & Spa Accessories +Home & Garden > Pool & Spa > Pool & Spa Accessories > Diving Boards +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool & Spa Chlorine Generators +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool & Spa Filters +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool & Spa Maintenance Kits +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Brushes & Brooms +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cleaner Hoses +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cleaners & Chemicals +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Cover Accessories +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Covers & Ground Cloths +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Deck Kits +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Floats & Loungers +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Heaters +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Ladders, Steps & Ramps +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Liners +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Skimmers +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Sweeps & Vacuums +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Toys +Home & Garden > Pool & Spa > Pool & Spa Accessories > Pool Water Slides +Home & Garden > Pool & Spa > Saunas +Home & Garden > Pool & Spa > Spas +Home & Garden > Pool & Spa > Swimming Pools +Home & Garden > Smoking Accessories +Home & Garden > Smoking Accessories > Ashtrays +Home & Garden > Smoking Accessories > Cigar Cases +Home & Garden > Smoking Accessories > Cigar Cutters & Punches +Home & Garden > Smoking Accessories > Cigarette Cases +Home & Garden > Smoking Accessories > Cigarette Holders +Home & Garden > Smoking Accessories > Humidor Accessories +Home & Garden > Smoking Accessories > Humidors +Home & Garden > Umbrella Sleeves & Cases +Home & Garden > Wood Stoves +Luggage & Bags +Luggage & Bags > Backpacks +Luggage & Bags > Briefcases +Luggage & Bags > Cosmetic & Toiletry Bags +Luggage & Bags > Diaper Bags +Luggage & Bags > Dry Boxes +Luggage & Bags > Duffel Bags +Luggage & Bags > Fanny Packs +Luggage & Bags > Garment Bags +Luggage & Bags > Luggage Accessories +Luggage & Bags > Luggage Accessories > Dry Box Liners & Inserts +Luggage & Bags > Luggage Accessories > Luggage Covers +Luggage & Bags > Luggage Accessories > Luggage Racks & Stands +Luggage & Bags > Luggage Accessories > Luggage Straps +Luggage & Bags > Luggage Accessories > Luggage Tags +Luggage & Bags > Luggage Accessories > Packing Organizers +Luggage & Bags > Luggage Accessories > Travel Bottles & Containers +Luggage & Bags > Luggage Accessories > Travel Pouches +Luggage & Bags > Messenger Bags +Luggage & Bags > Shopping Totes +Luggage & Bags > Suitcases +Luggage & Bags > Train Cases +Mature +Mature > Erotic +Mature > Erotic > Erotic Books +Mature > Erotic > Erotic Clothing +Mature > Erotic > Erotic DVDs & Videos +Mature > Erotic > Erotic Food & Edibles +Mature > Erotic > Erotic Games +Mature > Erotic > Erotic Magazines +Mature > Erotic > Pole Dancing Kits +Mature > Erotic > Sex Toys +Mature > Weapons +Mature > Weapons > Brass Knuckles +Mature > Weapons > Clubs & Batons +Mature > Weapons > Combat Knives +Mature > Weapons > Gun Care & Accessories +Mature > Weapons > Gun Care & Accessories > Ammunition +Mature > Weapons > Gun Care & Accessories > Ammunition Cases & Holders +Mature > Weapons > Gun Care & Accessories > Gun Cases & Range Bags +Mature > Weapons > Gun Care & Accessories > Gun Cleaning +Mature > Weapons > Gun Care & Accessories > Gun Cleaning > Gun Cleaning Cloths & Swabs +Mature > Weapons > Gun Care & Accessories > Gun Cleaning > Gun Cleaning Patches +Mature > Weapons > Gun Care & Accessories > Gun Cleaning > Gun Cleaning Solvents +Mature > Weapons > Gun Care & Accessories > Gun Grips +Mature > Weapons > Gun Care & Accessories > Gun Holsters +Mature > Weapons > Gun Care & Accessories > Gun Lights +Mature > Weapons > Gun Care & Accessories > Gun Rails +Mature > Weapons > Gun Care & Accessories > Gun Slings +Mature > Weapons > Gun Care & Accessories > Reloading Supplies & Equipment +Mature > Weapons > Gun Care & Accessories > Reloading Supplies & Equipment > Ammunition Reloading Presses +Mature > Weapons > Guns +Mature > Weapons > Mace & Pepper Spray +Mature > Weapons > Nunchucks +Mature > Weapons > Spears +Mature > Weapons > Staff & Stick Weapons +Mature > Weapons > Stun Guns & Tasers +Mature > Weapons > Swords +Mature > Weapons > Throwing Stars +Mature > Weapons > Whips +Media +Media > Books +Media > Carpentry & Woodworking Project Plans +Media > DVDs & Videos +Media > Magazines & Newspapers +Media > Music & Sound Recordings +Media > Product Manuals +Media > Product Manuals > Camera & Optics Manuals +Media > Product Manuals > Electronics Manuals +Media > Product Manuals > Exercise & Fitness Equipment Manuals +Media > Product Manuals > Household Appliance Manuals +Media > Product Manuals > Kitchen Appliance Manuals +Media > Product Manuals > Model & Toys Manuals +Media > Product Manuals > Office Supply Manuals +Media > Product Manuals > Power Tool & Equipment Manuals +Media > Product Manuals > Vehicle Service Manuals +Media > Sheet Music +Office Supplies +Office Supplies > Book Accessories +Office Supplies > Book Accessories > Book Covers +Office Supplies > Book Accessories > Book Lights +Office Supplies > Book Accessories > Book Stands & Rests +Office Supplies > Book Accessories > Bookmarks +Office Supplies > Desk Pads & Blotters +Office Supplies > Filing & Organization +Office Supplies > Filing & Organization > Address Books +Office Supplies > Filing & Organization > Binding Supplies +Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories +Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Binder Rings +Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Index Dividers +Office Supplies > Filing & Organization > Binding Supplies > Binder Accessories > Sheet Protectors +Office Supplies > Filing & Organization > Binding Supplies > Binders +Office Supplies > Filing & Organization > Binding Supplies > Binding Combs & Spines +Office Supplies > Filing & Organization > Binding Supplies > Binding Machines +Office Supplies > Filing & Organization > Business Card Books +Office Supplies > Filing & Organization > Business Card Stands +Office Supplies > Filing & Organization > CD/DVD Cases & Organizers +Office Supplies > Filing & Organization > Calendars, Organizers & Planners +Office Supplies > Filing & Organization > Card Files +Office Supplies > Filing & Organization > Card Sleeves +Office Supplies > Filing & Organization > Cash Boxes +Office Supplies > Filing & Organization > Desk Organizers +Office Supplies > Filing & Organization > File Boxes +Office Supplies > Filing & Organization > File Folders +Office Supplies > Filing & Organization > Folders & Report Covers +Office Supplies > Filing & Organization > Greeting Card Organizers +Office Supplies > Filing & Organization > Mail Sorters +Office Supplies > Filing & Organization > Pen & Pencil Cases +Office Supplies > Filing & Organization > Portfolios & Padfolios +Office Supplies > Filing & Organization > Recipe Card Boxes +Office Supplies > General Office Supplies +Office Supplies > General Office Supplies > Brass Fasteners +Office Supplies > General Office Supplies > Correction Fluids, Pens & Tapes +Office Supplies > General Office Supplies > Erasers +Office Supplies > General Office Supplies > Labels & Tags +Office Supplies > General Office Supplies > Labels & Tags > Address Labels +Office Supplies > General Office Supplies > Labels & Tags > Folder Tabs +Office Supplies > General Office Supplies > Labels & Tags > Label Clips +Office Supplies > General Office Supplies > Labels & Tags > Label Tapes & Refill Rolls +Office Supplies > General Office Supplies > Labels & Tags > Shipping Labels +Office Supplies > General Office Supplies > Labels & Tags > Shipping Tags +Office Supplies > General Office Supplies > Laminating Film, Pouches & Sheets +Office Supplies > General Office Supplies > Mounting Putty +Office Supplies > General Office Supplies > Office Tape +Office Supplies > General Office Supplies > Paper Clips & Clamps +Office Supplies > General Office Supplies > Paper Products +Office Supplies > General Office Supplies > Paper Products > Binder Paper +Office Supplies > General Office Supplies > Paper Products > Blank ID Cards +Office Supplies > General Office Supplies > Paper Products > Business Cards +Office Supplies > General Office Supplies > Paper Products > Business Forms & Receipts +Office Supplies > General Office Supplies > Paper Products > Checks +Office Supplies > General Office Supplies > Paper Products > Cover Paper +Office Supplies > General Office Supplies > Paper Products > Envelopes +Office Supplies > General Office Supplies > Paper Products > Index Cards +Office Supplies > General Office Supplies > Paper Products > Notebooks & Notepads +Office Supplies > General Office Supplies > Paper Products > Post Cards +Office Supplies > General Office Supplies > Paper Products > Printer & Copier Paper +Office Supplies > General Office Supplies > Paper Products > Receipt & Adding Machine Paper Rolls +Office Supplies > General Office Supplies > Paper Products > Stationery +Office Supplies > General Office Supplies > Paper Products > Sticky Notes +Office Supplies > General Office Supplies > Rubber Bands +Office Supplies > General Office Supplies > Staples +Office Supplies > General Office Supplies > Tacks & Pushpins +Office Supplies > Impulse Sealers +Office Supplies > Lap Desks +Office Supplies > Name Plates +Office Supplies > Office & Chair Mats +Office Supplies > Office & Chair Mats > Anti-Fatigue Mats +Office Supplies > Office & Chair Mats > Chair Mats +Office Supplies > Office & Chair Mats > Office Mats +Office Supplies > Office Carts +Office Supplies > Office Carts > AV Carts +Office Supplies > Office Carts > Book Carts +Office Supplies > Office Carts > File Carts +Office Supplies > Office Carts > Mail Carts +Office Supplies > Office Carts > Utility Carts +Office Supplies > Office Equipment +Office Supplies > Office Equipment > Calculator Accessories +Office Supplies > Office Equipment > Calculators +Office Supplies > Office Equipment > Electronic Dictionaries & Translators +Office Supplies > Office Equipment > Label Makers +Office Supplies > Office Equipment > Laminators +Office Supplies > Office Equipment > Office Shredders +Office Supplies > Office Equipment > Postage Meters +Office Supplies > Office Equipment > Time & Attendance Clocks +Office Supplies > Office Equipment > Transcribers & Dictation Systems +Office Supplies > Office Equipment > Typewriters +Office Supplies > Office Instruments +Office Supplies > Office Instruments > Call Bells +Office Supplies > Office Instruments > Clipboards +Office Supplies > Office Instruments > Letter Openers +Office Supplies > Office Instruments > Magnifiers +Office Supplies > Office Instruments > Office Rubber Stamps +Office Supplies > Office Instruments > Pencil Sharpeners +Office Supplies > Office Instruments > Staple Removers +Office Supplies > Office Instruments > Staplers +Office Supplies > Office Instruments > Tape Dispensers +Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories +Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Marker & Highlighter Ink Refills +Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Pen Ink & Refills +Office Supplies > Office Instruments > Writing & Drawing Instrument Accessories > Pencil Lead & Refills +Office Supplies > Office Instruments > Writing & Drawing Instruments +Office Supplies > Office Instruments > Writing & Drawing Instruments > Art Charcoals +Office Supplies > Office Instruments > Writing & Drawing Instruments > Chalk +Office Supplies > Office Instruments > Writing & Drawing Instruments > Crayons +Office Supplies > Office Instruments > Writing & Drawing Instruments > Markers & Highlighters +Office Supplies > Office Instruments > Writing & Drawing Instruments > Multifunction Writing Instruments +Office Supplies > Office Instruments > Writing & Drawing Instruments > Pastels +Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils +Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pen & Pencil Sets +Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils +Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Art Pencils +Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pencils > Writing Pencils +Office Supplies > Office Instruments > Writing & Drawing Instruments > Pens & Pencils > Pens +Office Supplies > Paper Handling +Office Supplies > Paper Handling > Fingertip Grips +Office Supplies > Paper Handling > Hole Punches +Office Supplies > Paper Handling > Paper Folding Machines +Office Supplies > Paper Handling > Paper Joggers +Office Supplies > Paper Handling > Paperweights +Office Supplies > Paper Handling > Pencil Boards +Office Supplies > Presentation Supplies +Office Supplies > Presentation Supplies > Chalkboards +Office Supplies > Presentation Supplies > Display Boards +Office Supplies > Presentation Supplies > Display Boards > Bulletin Board Accessories +Office Supplies > Presentation Supplies > Display Boards > Bulletin Board Accessories > Bulletin Board Trim +Office Supplies > Presentation Supplies > Display Boards > Bulletin Boards +Office Supplies > Presentation Supplies > Display Boards > Foam Boards +Office Supplies > Presentation Supplies > Display Boards > Mounting Boards +Office Supplies > Presentation Supplies > Display Boards > Poster Boards +Office Supplies > Presentation Supplies > Document Cameras +Office Supplies > Presentation Supplies > Dry-Erase Boards +Office Supplies > Presentation Supplies > Easel Pads +Office Supplies > Presentation Supplies > Easels +Office Supplies > Presentation Supplies > Laser Pointers +Office Supplies > Presentation Supplies > Lecterns +Office Supplies > Presentation Supplies > Transparencies +Office Supplies > Presentation Supplies > Wireless Presenters +Office Supplies > Shipping Supplies +Office Supplies > Shipping Supplies > Moving & Shipping Boxes +Office Supplies > Shipping Supplies > Packing Materials +Office Supplies > Shipping Supplies > Packing Tape +Religious & Ceremonial +Religious & Ceremonial > Memorial Ceremony Supplies +Religious & Ceremonial > Memorial Ceremony Supplies > Memorial Urns +Religious & Ceremonial > Religious Items +Religious & Ceremonial > Religious Items > Prayer Beads +Religious & Ceremonial > Religious Items > Prayer Cards +Religious & Ceremonial > Religious Items > Religious Altars +Religious & Ceremonial > Religious Items > Religious Veils +Religious & Ceremonial > Religious Items > Tarot Cards +Religious & Ceremonial > Wedding Ceremony Supplies +Religious & Ceremonial > Wedding Ceremony Supplies > Aisle Runners +Religious & Ceremonial > Wedding Ceremony Supplies > Flower Girl Baskets +Religious & Ceremonial > Wedding Ceremony Supplies > Ring Pillows & Holders +Software +Software > Computer Software +Software > Computer Software > Antivirus & Security Software +Software > Computer Software > Business & Productivity Software +Software > Computer Software > Compilers & Programming Tools +Software > Computer Software > Computer Utilities & Maintenance Software +Software > Computer Software > Dictionary & Translation Software +Software > Computer Software > Educational Software +Software > Computer Software > Financial, Tax & Accounting Software +Software > Computer Software > GPS Map Data & Software +Software > Computer Software > Handheld & PDA Software +Software > Computer Software > Multimedia & Design Software +Software > Computer Software > Multimedia & Design Software > 3D Modeling Software +Software > Computer Software > Multimedia & Design Software > Animation Editing Software +Software > Computer Software > Multimedia & Design Software > Graphic Design & Illustration Software +Software > Computer Software > Multimedia & Design Software > Home & Interior Design Software +Software > Computer Software > Multimedia & Design Software > Home Publishing Software +Software > Computer Software > Multimedia & Design Software > Media Viewing Software +Software > Computer Software > Multimedia & Design Software > Music Composition Software +Software > Computer Software > Multimedia & Design Software > Sound Editing Software +Software > Computer Software > Multimedia & Design Software > Video Editing Software +Software > Computer Software > Multimedia & Design Software > Web Design Software +Software > Computer Software > Network Software +Software > Computer Software > Office Application Software +Software > Computer Software > Operating Systems +Software > Computer Software > Restore Disks +Software > Digital Goods & Currency +Software > Digital Goods & Currency > Computer Icons +Software > Digital Goods & Currency > Desktop Wallpaper +Software > Digital Goods & Currency > Digital Artwork +Software > Digital Goods & Currency > Document Templates +Software > Digital Goods & Currency > Fonts +Software > Digital Goods & Currency > Stock Photographs & Video Footage +Software > Digital Goods & Currency > Virtual Currency +Software > Video Game Software +Sporting Goods +Sporting Goods > Athletics +Sporting Goods > Athletics > Baseball & Softball +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Bases & Plates +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Batting Gloves +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Gloves & Mitts +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Pitching Mats +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Pitching Mounds +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Baseball & Softball Batting Helmets +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Baseball & Softball Chest Protectors +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Baseball & Softball Leg Guards +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Catchers Equipment Sets +Sporting Goods > Athletics > Baseball & Softball > Baseball & Softball Protective Gear > Catchers Helmets & Masks +Sporting Goods > Athletics > Baseball & Softball > Baseball Bats +Sporting Goods > Athletics > Baseball & Softball > Baseballs +Sporting Goods > Athletics > Baseball & Softball > Pitching Machines +Sporting Goods > Athletics > Baseball & Softball > Softball Bats +Sporting Goods > Athletics > Baseball & Softball > Softballs +Sporting Goods > Athletics > Basketball +Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories +Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Backboards +Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Hoop Padding +Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Hoop Posts +Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Nets +Sporting Goods > Athletics > Basketball > Basketball Hoop Parts & Accessories > Basketball Rims +Sporting Goods > Athletics > Basketball > Basketball Hoops +Sporting Goods > Athletics > Basketball > Basketball Training Aids +Sporting Goods > Athletics > Basketball > Basketballs +Sporting Goods > Athletics > Boxing & Martial Arts +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & MMA Hand Wraps +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & Martial Arts Arm Guards +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & Martial Arts Body Protectors +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing & Martial Arts Headgear +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > Boxing Gloves & Mitts +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Protective Gear > MMA Shin Guards +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Boxing & MMA Punch Mitts +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Grappling Dummies +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Punching & Training Bag Accessories +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Punching & Training Bags +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing & Martial Arts Training Equipment > Strike Shields +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing Ring Parts +Sporting Goods > Athletics > Boxing & Martial Arts > Boxing Rings +Sporting Goods > Athletics > Boxing & Martial Arts > Martial Arts Belts +Sporting Goods > Athletics > Boxing & Martial Arts > Martial Arts Weapons +Sporting Goods > Athletics > Broomball Equipment +Sporting Goods > Athletics > Cheerleading +Sporting Goods > Athletics > Cheerleading > Cheerleading Pom Poms +Sporting Goods > Athletics > Coaching & Officiating +Sporting Goods > Athletics > Coaching & Officiating > Captains Armbands +Sporting Goods > Athletics > Coaching & Officiating > Field & Court Boundary Markers +Sporting Goods > Athletics > Coaching & Officiating > Flip Coins & Discs +Sporting Goods > Athletics > Coaching & Officiating > Linesman Flags +Sporting Goods > Athletics > Coaching & Officiating > Penalty Cards & Flags +Sporting Goods > Athletics > Coaching & Officiating > Pitch Counters +Sporting Goods > Athletics > Coaching & Officiating > Referee Stands & Chairs +Sporting Goods > Athletics > Coaching & Officiating > Referee Wallets +Sporting Goods > Athletics > Coaching & Officiating > Scoreboards +Sporting Goods > Athletics > Coaching & Officiating > Sport & Safety Whistles +Sporting Goods > Athletics > Coaching & Officiating > Umpire Indicators +Sporting Goods > Athletics > Cricket +Sporting Goods > Athletics > Cricket > Cricket Balls +Sporting Goods > Athletics > Cricket > Cricket Bat Accessories +Sporting Goods > Athletics > Cricket > Cricket Bat Accessories > Cricket Bat Grips +Sporting Goods > Athletics > Cricket > Cricket Bats +Sporting Goods > Athletics > Cricket > Cricket Equipment Sets +Sporting Goods > Athletics > Cricket > Cricket Protective Gear +Sporting Goods > Athletics > Cricket > Cricket Protective Gear > Cricket Gloves +Sporting Goods > Athletics > Cricket > Cricket Protective Gear > Cricket Helmets +Sporting Goods > Athletics > Cricket > Cricket Protective Gear > Cricket Leg Guards +Sporting Goods > Athletics > Cricket > Cricket Stumps +Sporting Goods > Athletics > Dancing +Sporting Goods > Athletics > Dancing > Ballet Barres +Sporting Goods > Athletics > Fencing +Sporting Goods > Athletics > Fencing > Fencing Protective Gear +Sporting Goods > Athletics > Fencing > Fencing Protective Gear > Fencing Gloves & Cuffs +Sporting Goods > Athletics > Fencing > Fencing Protective Gear > Fencing Jackets & Lamés +Sporting Goods > Athletics > Fencing > Fencing Protective Gear > Fencing Masks +Sporting Goods > Athletics > Fencing > Fencing Weapons +Sporting Goods > Athletics > Field Hockey & Lacrosse +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Gloves +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Helmets +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Masks & Goggles +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey & Lacrosse Protective Gear > Field Hockey & Lacrosse Pads +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey Balls +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey Goals +Sporting Goods > Athletics > Field Hockey & Lacrosse > Field Hockey Sticks +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Balls +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Equipment Sets +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Goals +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts > Lacrosse Mesh & String +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts > Lacrosse Stick Heads +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Stick Parts > Lacrosse Stick Shafts +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Sticks +Sporting Goods > Athletics > Field Hockey & Lacrosse > Lacrosse Training Aids +Sporting Goods > Athletics > Figure Skating & Hockey +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Balls & Pucks +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Goals +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Elbow Pads +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Gloves +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Goalie Equipment Sets +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Helmets +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Pants +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Shin Guards & Leg Pads +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Shoulder Pads & Chest Protectors +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Protective Gear > Hockey Suspenders & Belts +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Sledges +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Care +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Parts +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Parts > Hockey Stick Blades +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Stick Parts > Hockey Stick Shafts +Sporting Goods > Athletics > Figure Skating & Hockey > Hockey Sticks +Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories +Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Figure Skate Boots +Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Ice Skate Blades +Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Ice Skate Sharpeners +Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Skate Blade Guards +Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skate Parts & Accessories > Skate Lace Tighteners +Sporting Goods > Athletics > Figure Skating & Hockey > Ice Skates +Sporting Goods > Athletics > Football +Sporting Goods > Athletics > Football > Football Gloves +Sporting Goods > Athletics > Football > Football Goal Posts +Sporting Goods > Athletics > Football > Football Kicking Tees & Holders +Sporting Goods > Athletics > Football > Football Protective Gear +Sporting Goods > Athletics > Football > Football Protective Gear > Football Girdles +Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories +Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Chin Straps +Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Face Masks +Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Helmet Padding +Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmet Accessories > Football Helmet Visors +Sporting Goods > Athletics > Football > Football Protective Gear > Football Helmets +Sporting Goods > Athletics > Football > Football Protective Gear > Football Neck Rolls +Sporting Goods > Athletics > Football > Football Protective Gear > Football Rib Protection Shirts & Vests +Sporting Goods > Athletics > Football > Football Protective Gear > Football Shoulder Pads +Sporting Goods > Athletics > Football > Football Training Equipment +Sporting Goods > Athletics > Football > Football Training Equipment > Football Dummies & Sleds +Sporting Goods > Athletics > Football > Footballs +Sporting Goods > Athletics > General Purpose Athletic Equipment +Sporting Goods > Athletics > General Purpose Athletic Equipment > Altitude Training Masks +Sporting Goods > Athletics > General Purpose Athletic Equipment > Athletic Cups +Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Carrying Bags & Carts +Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Pump Accessories +Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Pump Accessories > Ball Pump Needles +Sporting Goods > Athletics > General Purpose Athletic Equipment > Ball Pumps +Sporting Goods > Athletics > General Purpose Athletic Equipment > Exercise & Gym Mat Storage Racks & Carts +Sporting Goods > Athletics > General Purpose Athletic Equipment > Grip Spray & Chalk +Sporting Goods > Athletics > General Purpose Athletic Equipment > Gym Mats +Sporting Goods > Athletics > General Purpose Athletic Equipment > Practice Nets & Screens +Sporting Goods > Athletics > General Purpose Athletic Equipment > Speed & Agility Ladders & Hurdles +Sporting Goods > Athletics > General Purpose Athletic Equipment > Sports & Agility Cones +Sporting Goods > Athletics > General Purpose Athletic Equipment > Sports Megaphones +Sporting Goods > Athletics > General Purpose Athletic Equipment > Sports Mouthguards +Sporting Goods > Athletics > General Purpose Athletic Equipment > Stadium Seats & Cushions +Sporting Goods > Athletics > Gymnastics +Sporting Goods > Athletics > Gymnastics > Gymnastics Bars & Balance Beams +Sporting Goods > Athletics > Gymnastics > Gymnastics Protective Gear +Sporting Goods > Athletics > Gymnastics > Gymnastics Protective Gear > Gymnastics Grips +Sporting Goods > Athletics > Gymnastics > Gymnastics Rings +Sporting Goods > Athletics > Gymnastics > Gymnastics Springboards +Sporting Goods > Athletics > Gymnastics > Pommel Horses +Sporting Goods > Athletics > Gymnastics > Vaulting Horses +Sporting Goods > Athletics > Racquetball & Squash +Sporting Goods > Athletics > Racquetball & Squash > Racquetball & Squash Balls +Sporting Goods > Athletics > Racquetball & Squash > Racquetball & Squash Eyewear +Sporting Goods > Athletics > Racquetball & Squash > Racquetball & Squash Gloves +Sporting Goods > Athletics > Racquetball & Squash > Racquetball Racquets +Sporting Goods > Athletics > Racquetball & Squash > Squash Racquets +Sporting Goods > Athletics > Rounders +Sporting Goods > Athletics > Rounders > Rounders Bats +Sporting Goods > Athletics > Rounders > Rounders Gloves +Sporting Goods > Athletics > Rugby +Sporting Goods > Athletics > Rugby > Rugby Balls +Sporting Goods > Athletics > Rugby > Rugby Gloves +Sporting Goods > Athletics > Rugby > Rugby Posts +Sporting Goods > Athletics > Rugby > Rugby Protective Gear +Sporting Goods > Athletics > Rugby > Rugby Protective Gear > Rugby Headgear +Sporting Goods > Athletics > Rugby > Rugby Training Aids +Sporting Goods > Athletics > Soccer +Sporting Goods > Athletics > Soccer > Soccer Balls +Sporting Goods > Athletics > Soccer > Soccer Corner Flags +Sporting Goods > Athletics > Soccer > Soccer Gloves +Sporting Goods > Athletics > Soccer > Soccer Goal Accessories +Sporting Goods > Athletics > Soccer > Soccer Goals +Sporting Goods > Athletics > Soccer > Soccer Protective Gear +Sporting Goods > Athletics > Soccer > Soccer Protective Gear > Soccer Shin Guards +Sporting Goods > Athletics > Team Handball +Sporting Goods > Athletics > Team Handball > Handballs +Sporting Goods > Athletics > Tennis +Sporting Goods > Athletics > Tennis > Tennis Ball Hoppers & Carts +Sporting Goods > Athletics > Tennis > Tennis Ball Machines +Sporting Goods > Athletics > Tennis > Tennis Ball Savers +Sporting Goods > Athletics > Tennis > Tennis Balls +Sporting Goods > Athletics > Tennis > Tennis Nets +Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories +Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Racquet Vibration Dampeners +Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet Bags +Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet Grips & Tape +Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet Grommets +Sporting Goods > Athletics > Tennis > Tennis Racquet Accessories > Tennis Racquet String +Sporting Goods > Athletics > Tennis > Tennis Racquets +Sporting Goods > Athletics > Track & Field +Sporting Goods > Athletics > Track & Field > Discus +Sporting Goods > Athletics > Track & Field > High Jump Crossbars +Sporting Goods > Athletics > Track & Field > High Jump Pits +Sporting Goods > Athletics > Track & Field > Javelins +Sporting Goods > Athletics > Track & Field > Pole Vault Pits +Sporting Goods > Athletics > Track & Field > Relay Batons +Sporting Goods > Athletics > Track & Field > Shot Puts +Sporting Goods > Athletics > Track & Field > Starter Pistols +Sporting Goods > Athletics > Track & Field > Throwing Hammers +Sporting Goods > Athletics > Track & Field > Track Hurdles +Sporting Goods > Athletics > Track & Field > Track Starting Blocks +Sporting Goods > Athletics > Track & Field > Vaulting Poles +Sporting Goods > Athletics > Volleyball +Sporting Goods > Athletics > Volleyball > Volleyball Nets +Sporting Goods > Athletics > Volleyball > Volleyball Protective Gear +Sporting Goods > Athletics > Volleyball > Volleyball Protective Gear > Volleyball Knee Pads +Sporting Goods > Athletics > Volleyball > Volleyball Training Aids +Sporting Goods > Athletics > Volleyball > Volleyballs +Sporting Goods > Athletics > Wallyball Equipment +Sporting Goods > Athletics > Water Polo +Sporting Goods > Athletics > Water Polo > Water Polo Balls +Sporting Goods > Athletics > Water Polo > Water Polo Caps +Sporting Goods > Athletics > Water Polo > Water Polo Goals +Sporting Goods > Athletics > Wrestling +Sporting Goods > Athletics > Wrestling > Wrestling Protective Gear +Sporting Goods > Athletics > Wrestling > Wrestling Protective Gear > Wrestling Headgear +Sporting Goods > Athletics > Wrestling > Wrestling Protective Gear > Wrestling Knee Pads +Sporting Goods > Exercise & Fitness +Sporting Goods > Exercise & Fitness > Ab Wheels & Rollers +Sporting Goods > Exercise & Fitness > Aerobic Steps +Sporting Goods > Exercise & Fitness > Balance Trainers +Sporting Goods > Exercise & Fitness > Cardio +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Elliptical Trainer Accessories +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Exercise Bike Accessories +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Rowing Machine Accessories +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Stair Climber & Stepper Accessories +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machine Accessories > Treadmill Accessories +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Elliptical Trainers +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Exercise Bikes +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Rowing Machines +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Stair Climbers & Steppers +Sporting Goods > Exercise & Fitness > Cardio > Cardio Machines > Treadmills +Sporting Goods > Exercise & Fitness > Cardio > Jump Ropes +Sporting Goods > Exercise & Fitness > Exercise Balls +Sporting Goods > Exercise & Fitness > Exercise Bands +Sporting Goods > Exercise & Fitness > Exercise Benches +Sporting Goods > Exercise & Fitness > Exercise Equipment Mats +Sporting Goods > Exercise & Fitness > Exercise Machine & Equipment Sets +Sporting Goods > Exercise & Fitness > Exercise Wedges +Sporting Goods > Exercise & Fitness > Foam Roller Accessories +Sporting Goods > Exercise & Fitness > Foam Roller Accessories > Foam Roller Storage Bags +Sporting Goods > Exercise & Fitness > Foam Rollers +Sporting Goods > Exercise & Fitness > Hand Exercisers +Sporting Goods > Exercise & Fitness > Inversion Tables & Systems +Sporting Goods > Exercise & Fitness > Medicine Balls +Sporting Goods > Exercise & Fitness > Power Towers +Sporting Goods > Exercise & Fitness > Push Up & Pull Up Bars +Sporting Goods > Exercise & Fitness > Reaction Balls +Sporting Goods > Exercise & Fitness > Speed & Resistance Parachutes +Sporting Goods > Exercise & Fitness > Sport Safety Lights & Reflectors +Sporting Goods > Exercise & Fitness > Stopwatches +Sporting Goods > Exercise & Fitness > Suspension Trainers +Sporting Goods > Exercise & Fitness > Vibration Exercise Machines +Sporting Goods > Exercise & Fitness > Weight Lifting +Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories +Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories > Free Weight Storage Racks +Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories > Weight Bar Collars +Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weight Accessories > Weight Bars +Sporting Goods > Exercise & Fitness > Weight Lifting > Free Weights +Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Belts +Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Gloves & Hand Supports +Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Machine & Exercise Bench Accessories +Sporting Goods > Exercise & Fitness > Weight Lifting > Weight Lifting Machines & Racks +Sporting Goods > Exercise & Fitness > Weighted Clothing +Sporting Goods > Exercise & Fitness > Yoga & Pilates +Sporting Goods > Exercise & Fitness > Yoga & Pilates > Pilates Machines +Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Blocks +Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Mats +Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga & Pilates Towels +Sporting Goods > Exercise & Fitness > Yoga & Pilates > Yoga Mat Bags & Straps +Sporting Goods > Indoor Games +Sporting Goods > Indoor Games > Air Hockey +Sporting Goods > Indoor Games > Air Hockey > Air Hockey Equipment +Sporting Goods > Indoor Games > Air Hockey > Air Hockey Table Parts +Sporting Goods > Indoor Games > Air Hockey > Air Hockey Tables +Sporting Goods > Indoor Games > Billiards +Sporting Goods > Indoor Games > Billiards > Billiard Ball Racks +Sporting Goods > Indoor Games > Billiards > Billiard Balls +Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories +Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories > Billiard Cue Cases +Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories > Billiard Cue Chalk +Sporting Goods > Indoor Games > Billiards > Billiard Cue Accessories > Billiard Cue Racks +Sporting Goods > Indoor Games > Billiards > Billiard Cues & Bridges +Sporting Goods > Indoor Games > Billiards > Billiard Gloves +Sporting Goods > Indoor Games > Billiards > Billiard Table Lights +Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories +Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Pockets +Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Table Brushes +Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Table Cloth +Sporting Goods > Indoor Games > Billiards > Billiard Table Parts & Accessories > Billiard Table Covers +Sporting Goods > Indoor Games > Billiards > Billiard Tables +Sporting Goods > Indoor Games > Bowling +Sporting Goods > Indoor Games > Bowling > Bowling Ball Bags +Sporting Goods > Indoor Games > Bowling > Bowling Balls +Sporting Goods > Indoor Games > Bowling > Bowling Gloves +Sporting Goods > Indoor Games > Bowling > Bowling Pins +Sporting Goods > Indoor Games > Bowling > Bowling Wrist Supports +Sporting Goods > Indoor Games > Foosball +Sporting Goods > Indoor Games > Foosball > Foosball Balls +Sporting Goods > Indoor Games > Foosball > Foosball Table Parts & Accessories +Sporting Goods > Indoor Games > Foosball > Foosball Tables +Sporting Goods > Indoor Games > Multi-Game Tables +Sporting Goods > Indoor Games > Ping Pong +Sporting Goods > Indoor Games > Ping Pong > Ping Pong Balls +Sporting Goods > Indoor Games > Ping Pong > Ping Pong Nets & Posts +Sporting Goods > Indoor Games > Ping Pong > Ping Pong Paddle Accessories +Sporting Goods > Indoor Games > Ping Pong > Ping Pong Paddles & Sets +Sporting Goods > Indoor Games > Ping Pong > Ping Pong Robot Accessories +Sporting Goods > Indoor Games > Ping Pong > Ping Pong Robots +Sporting Goods > Indoor Games > Ping Pong > Ping Pong Tables +Sporting Goods > Indoor Games > Table Shuffleboard +Sporting Goods > Indoor Games > Table Shuffleboard > Shuffleboard Tables +Sporting Goods > Indoor Games > Table Shuffleboard > Table Shuffleboard Powder +Sporting Goods > Indoor Games > Table Shuffleboard > Table Shuffleboard Pucks +Sporting Goods > Indoor Games > Throwing Darts +Sporting Goods > Indoor Games > Throwing Darts > Dart Backboards +Sporting Goods > Indoor Games > Throwing Darts > Dart Parts +Sporting Goods > Indoor Games > Throwing Darts > Dart Parts > Dart Flights +Sporting Goods > Indoor Games > Throwing Darts > Dart Parts > Dart Shafts +Sporting Goods > Indoor Games > Throwing Darts > Dart Parts > Dart Tips +Sporting Goods > Indoor Games > Throwing Darts > Dartboards +Sporting Goods > Indoor Games > Throwing Darts > Darts +Sporting Goods > Outdoor Recreation +Sporting Goods > Outdoor Recreation > Boating & Water Sports +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Boating Gloves +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Canoe Accessories +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Canoes +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Kayak Accessories +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Kayaks +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Paddle Leashes +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Paddles & Oars +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Pedal Boats +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Row Boats +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Rafting > Whitewater Rafts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Drysuits +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Life Jacket Accessories +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Life Jackets +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Rash Guards & Swim Shirts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Water Sport Helmets +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces > Wetsuit Bottoms +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces > Wetsuit Hoods, Gloves & Boots +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuit Pieces > Wetsuit Tops +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Boating & Water Sport Apparel > Wetsuits +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Buoyancy Compensators +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Dive Computers +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving & Snorkeling Equipment Sets +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving & Snorkeling Fins +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving & Snorkeling Masks +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving Belts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving Knives & Shears +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Diving Regulators +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Diving & Snorkeling > Snorkels +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kiteboard Cases +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kiteboard Parts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kiteboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kitesurfing & Windsurfing Harnesses +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Kitesurfing > Kitesurfing Kites +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Bodyboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Paddleboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Skimboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surf Leashes +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboard Cases & Bags +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboard Fins +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboard Wax +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfing Gloves +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Surfing > Surfing Tail Pads +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Child Swimming Aids +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Hand Paddles +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Kickboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Pull Buoys +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Belts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Caps +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Gloves +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Goggle & Mask Accessories +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Goggles & Masks +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swim Weights +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Fins +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Fins > Monofins +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Fins > Training Fins +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Machines +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Swimming > Swimming Nose Clips +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Kneeboarding +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Kneeboarding > Kneeboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Towable Rafts & Tubes +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Towed Water Sport Gloves +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding > Kiteboard & Wakeboard Bindings +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding > Wakeboard Parts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Wakeboarding > Wakeboards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Sit-Down Hydrofoils +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Water Ski Bindings +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Water Ski Cases & Bags +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Skiing > Water Skis +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Towed Water Sports > Water Sport Tow Cables +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Watercraft Storage Racks +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Watercraft Storage Racks > Boat Storage Racks +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Watercraft Storage Racks > Water Sport Board Storage Racks +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Board Parts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Board Parts > Windsurfing Board Fins +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Board Parts > Windsurfing Board Masts +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Boards +Sporting Goods > Outdoor Recreation > Boating & Water Sports > Windsurfing > Windsurfing Sails +Sporting Goods > Outdoor Recreation > Camping & Hiking +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture > Air Mattress & Sleeping Pad Accessories +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture > Air Mattresses +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camp Furniture > Cots +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Cookware & Dinnerware +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Lights & Lanterns +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Tools +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Tools > Hunting & Survival Knives +Sporting Goods > Outdoor Recreation > Camping & Hiking > Camping Tools > Multifunction Tools & Knives +Sporting Goods > Outdoor Recreation > Camping & Hiking > Chemical Hand Warmers +Sporting Goods > Outdoor Recreation > Camping & Hiking > Compression Sacks +Sporting Goods > Outdoor Recreation > Camping & Hiking > Hiking Pole Accessories +Sporting Goods > Outdoor Recreation > Camping & Hiking > Hiking Poles +Sporting Goods > Outdoor Recreation > Camping & Hiking > Mosquito Nets & Insect Screens +Sporting Goods > Outdoor Recreation > Camping & Hiking > Navigational Compasses +Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Toilets & Showers +Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Toilets & Showers > Portable Showers & Privacy Enclosures +Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Toilets & Showers > Portable Toilets & Urination Devices +Sporting Goods > Outdoor Recreation > Camping & Hiking > Portable Water Filters & Purifiers +Sporting Goods > Outdoor Recreation > Camping & Hiking > Sleeping Bag Liners +Sporting Goods > Outdoor Recreation > Camping & Hiking > Sleeping Bags +Sporting Goods > Outdoor Recreation > Camping & Hiking > Sleeping Pads +Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories +Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Inner Tents +Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Tent Footprints +Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Tent Poles & Stakes +Sporting Goods > Outdoor Recreation > Camping & Hiking > Tent Accessories > Tent Vestibules +Sporting Goods > Outdoor Recreation > Camping & Hiking > Tents +Sporting Goods > Outdoor Recreation > Camping & Hiking > Windbreaks +Sporting Goods > Outdoor Recreation > Climbing +Sporting Goods > Outdoor Recreation > Climbing > Belay Devices +Sporting Goods > Outdoor Recreation > Climbing > Carabiners +Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories +Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories > Climbing Gloves +Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories > Climbing Helmets +Sporting Goods > Outdoor Recreation > Climbing > Climbing Apparel & Accessories > Crampons +Sporting Goods > Outdoor Recreation > Climbing > Climbing Ascenders & Descenders +Sporting Goods > Outdoor Recreation > Climbing > Climbing Chalk Bags +Sporting Goods > Outdoor Recreation > Climbing > Climbing Crash Pads +Sporting Goods > Outdoor Recreation > Climbing > Climbing Harnesses +Sporting Goods > Outdoor Recreation > Climbing > Climbing Protection Devices +Sporting Goods > Outdoor Recreation > Climbing > Climbing Rope +Sporting Goods > Outdoor Recreation > Climbing > Climbing Rope Bags +Sporting Goods > Outdoor Recreation > Climbing > Climbing Webbing +Sporting Goods > Outdoor Recreation > Climbing > Ice Climbing Tools +Sporting Goods > Outdoor Recreation > Climbing > Ice Screws +Sporting Goods > Outdoor Recreation > Climbing > Indoor Climbing Holds +Sporting Goods > Outdoor Recreation > Climbing > Quickdraws +Sporting Goods > Outdoor Recreation > Cycling +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Bags & Panniers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Baskets +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Bells & Horns +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Cages +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Child Seat Accessories +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Child Seats +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Computer Accessories +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Computers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Covers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Fenders +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Front & Rear Racks +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Handlebar Grips & Decor +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Locks +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Mirrors +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Pumps +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Saddle Pads & Seat Covers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Shock Pumps +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Spoke Beads +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Stands & Storage +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Tire Repair Supplies & Kits +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Toe Straps & Clips +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Tools +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Trailers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Trainers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Training Wheels +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Transport Bags & Cases +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Bicycle Water Sport Board Racks +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Accessories > Electric Bicycle Conversion Kits +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Calipers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Levers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Rotors +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Brake Parts > Bicycle Brake Sets +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Cable Housings +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Cables +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Bottom Brackets +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Cassettes & Freewheels +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Chainrings +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Chains +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Cranks +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Derailleurs +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Pedals +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Drivetrain Parts > Bicycle Shifters +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Forks +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Frames +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Groupsets +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Handlebar Extensions +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Handlebars +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts > Bicycle Headset Bearings +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headset Parts > Bicycle Headset Spacers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Headsets +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Kickstands +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Saddles +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Seatpost Clamps +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Seatposts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Small Parts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Stems +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tire Valve Adapters +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tire Valve Caps +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tire Valves +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tires +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Tubes +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Foot Pegs +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Hub Parts +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Hubs +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Rim Strips +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Spokes +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Axles & Skewers +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Nipples +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheel Parts > Bicycle Wheel Rims +Sporting Goods > Outdoor Recreation > Cycling > Bicycle Parts > Bicycle Wheels +Sporting Goods > Outdoor Recreation > Cycling > Bicycles +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories > Bicycle Cleat Bolts +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories > Bicycle Cleat Covers +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleat Accessories > Bicycle Cleat Shims & Wedges +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Cleats +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Gloves +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Helmet Parts & Accessories +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Helmets +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Protective Pads +Sporting Goods > Outdoor Recreation > Cycling > Cycling Apparel & Accessories > Bicycle Shoe Covers +Sporting Goods > Outdoor Recreation > Cycling > Tricycle Accessories +Sporting Goods > Outdoor Recreation > Cycling > Tricycles +Sporting Goods > Outdoor Recreation > Cycling > Unicycle Accessories +Sporting Goods > Outdoor Recreation > Cycling > Unicycles +Sporting Goods > Outdoor Recreation > Equestrian +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Blankets & Sheets +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Boots & Leg Wraps +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Feed +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Fly Masks +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Grooming +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Grooming > Horse Clippers & Trimmers +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Grooming > Horse Grooming Combs, Brushes & Mitts +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Treats +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Vitamins & Supplements +Sporting Goods > Outdoor Recreation > Equestrian > Horse Care > Horse Wormers +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Bridle Bits +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Bridles +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Cinches +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Halters +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Harnesses +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Horse Leads +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Reins +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Saddles +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack > Stirrups +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Horse Tack Boxes +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Bags & Panniers +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Covers & Cases +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Pads & Blankets +Sporting Goods > Outdoor Recreation > Equestrian > Horse Tack Accessories > Saddle Accessories > Saddle Racks +Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories +Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Equestrian Gloves +Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Equestrian Helmets +Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Riding Crops & Whips +Sporting Goods > Outdoor Recreation > Equestrian > Riding Apparel & Accessories > Riding Pants +Sporting Goods > Outdoor Recreation > Fishing +Sporting Goods > Outdoor Recreation > Fishing > Bite Alarms +Sporting Goods > Outdoor Recreation > Fishing > Fishing & Hunting Waders +Sporting Goods > Outdoor Recreation > Fishing > Fishing Bait & Chum Containers +Sporting Goods > Outdoor Recreation > Fishing > Fishing Gaffs +Sporting Goods > Outdoor Recreation > Fishing > Fishing Hook Removal Tools +Sporting Goods > Outdoor Recreation > Fishing > Fishing Lines & Leaders +Sporting Goods > Outdoor Recreation > Fishing > Fishing Nets +Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories +Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories > Fishing Reel Bags & Cases +Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories > Fishing Reel Lubricants +Sporting Goods > Outdoor Recreation > Fishing > Fishing Reel Accessories > Fishing Reel Replacement Spools +Sporting Goods > Outdoor Recreation > Fishing > Fishing Reels +Sporting Goods > Outdoor Recreation > Fishing > Fishing Rod Accessories +Sporting Goods > Outdoor Recreation > Fishing > Fishing Rod Accessories > Fishing Rod Bags & Cases +Sporting Goods > Outdoor Recreation > Fishing > Fishing Rod Accessories > Fishing Rod Holders & Storage Racks +Sporting Goods > Outdoor Recreation > Fishing > Fishing Rods +Sporting Goods > Outdoor Recreation > Fishing > Fishing Spears +Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle +Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Baits & Lures +Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Floats +Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Hooks +Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Sinkers +Sporting Goods > Outdoor Recreation > Fishing > Fishing Tackle > Fishing Snaps & Swivels +Sporting Goods > Outdoor Recreation > Fishing > Fishing Traps +Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials +Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials > Fishing Beads +Sporting Goods > Outdoor Recreation > Fishing > Fly Tying Materials > Fishing Yarn +Sporting Goods > Outdoor Recreation > Fishing > Live Bait +Sporting Goods > Outdoor Recreation > Fishing > Tackle Bags & Boxes +Sporting Goods > Outdoor Recreation > Golf +Sporting Goods > Outdoor Recreation > Golf > Divot Tools +Sporting Goods > Outdoor Recreation > Golf > Golf Accessory Sets +Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories +Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories > Golf Bag Carts +Sporting Goods > Outdoor Recreation > Golf > Golf Bag Accessories > Golf Bag Covers & Cases +Sporting Goods > Outdoor Recreation > Golf > Golf Bags +Sporting Goods > Outdoor Recreation > Golf > Golf Ball Markers +Sporting Goods > Outdoor Recreation > Golf > Golf Balls +Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories +Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Grips +Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Headcovers +Sporting Goods > Outdoor Recreation > Golf > Golf Club Parts & Accessories > Golf Club Shafts +Sporting Goods > Outdoor Recreation > Golf > Golf Clubs +Sporting Goods > Outdoor Recreation > Golf > Golf Flags +Sporting Goods > Outdoor Recreation > Golf > Golf Gloves +Sporting Goods > Outdoor Recreation > Golf > Golf Tees +Sporting Goods > Outdoor Recreation > Golf > Golf Towels +Sporting Goods > Outdoor Recreation > Golf > Golf Training Aids +Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving +Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving > Air Suits +Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving > Hang Gliders +Sporting Goods > Outdoor Recreation > Hang Gliding & Skydiving > Parachutes +Sporting Goods > Outdoor Recreation > Hunting & Shooting +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Archery Armguards +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Archery Gloves & Releases +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Archery Targets +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories > Arrow Fletchings +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories > Arrow Nocks +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrow Parts & Accessories > Broadheads & Field Points +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Arrows & Bolts +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bow & Crossbow Accessories +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows > Compound Bows +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows > Crossbows +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Bows & Crossbows > Recurve & Longbows +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Archery > Quivers +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Clay Pigeon Shooting +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Clay Pigeon Shooting > Clay Pigeon Throwers +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Clay Pigeon Shooting > Clay Pigeons +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting & Shooting Protective Gear +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting & Shooting Protective Gear > Hunting & Shooting Gloves +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting & Shooting Protective Gear > Hunting & Shooting Jackets +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Animal Traps +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Hearing Enhancers +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Hunting Blinds & Screens +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Hunting Dog Equipment +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Tree Stands +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wild Game Feeders +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Cover Scents & Scent Attractants +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Hunting & Wildlife Calls +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Hunting & Wildlife Decoys +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Hunting > Wildlife Attractants > Wildlife Bait, Feed & Minerals +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Gun Parts & Accessories +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Gun Parts & Accessories > Airsoft Gun Batteries +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Guns +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Airsoft > Airsoft Pellets +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Gloves +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Goggles & Masks +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Pads +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball & Airsoft Protective Gear > Paintball & Airsoft Vests +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Grenade Launchers +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Grenades +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Air Tanks +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Gun Barrels +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Gun Drop Forwards +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Gun Parts & Accessories > Paintball Hoppers +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Guns +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintball Harnesses & Packs +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Paintball & Airsoft > Paintball > Paintballs +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories > Shooting Rests +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories > Shooting Sticks & Bipods +Sporting Goods > Outdoor Recreation > Hunting & Shooting > Shooting & Range Accessories > Shooting Targets +Sporting Goods > Outdoor Recreation > Hydration System Accessories +Sporting Goods > Outdoor Recreation > Hydration Systems +Sporting Goods > Outdoor Recreation > Inline & Roller Skating +Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline & Roller Skating Protective Gear +Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline & Roller Skating Protective Gear > Roller Skating Pads +Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline Skate Parts +Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Inline Skates +Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Roller Skate Parts +Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Roller Skates +Sporting Goods > Outdoor Recreation > Inline & Roller Skating > Roller Skis +Sporting Goods > Outdoor Recreation > Kite Buggying +Sporting Goods > Outdoor Recreation > Kite Buggying > Kite Buggies +Sporting Goods > Outdoor Recreation > Kite Buggying > Kite Buggy Accessories +Sporting Goods > Outdoor Recreation > Outdoor Games +Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton +Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton > Badminton Nets +Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton > Badminton Racquets & Sets +Sporting Goods > Outdoor Recreation > Outdoor Games > Badminton > Shuttlecocks +Sporting Goods > Outdoor Recreation > Outdoor Games > Deck Shuffleboard +Sporting Goods > Outdoor Recreation > Outdoor Games > Deck Shuffleboard > Deck Shuffleboard Cues +Sporting Goods > Outdoor Recreation > Outdoor Games > Deck Shuffleboard > Deck Shuffleboard Pucks +Sporting Goods > Outdoor Recreation > Outdoor Games > Disc Golf +Sporting Goods > Outdoor Recreation > Outdoor Games > Disc Golf > Disc Golf Bags +Sporting Goods > Outdoor Recreation > Outdoor Games > Disc Golf > Disc Golf Baskets +Sporting Goods > Outdoor Recreation > Outdoor Games > Lawn Games +Sporting Goods > Outdoor Recreation > Outdoor Games > Paddle Ball Sets +Sporting Goods > Outdoor Recreation > Outdoor Games > Pickleball +Sporting Goods > Outdoor Recreation > Outdoor Games > Pickleball > Pickleball Paddles +Sporting Goods > Outdoor Recreation > Outdoor Games > Pickleball > Pickleballs +Sporting Goods > Outdoor Recreation > Outdoor Games > Platform & Paddle Tennis +Sporting Goods > Outdoor Recreation > Outdoor Games > Platform & Paddle Tennis > Platform & Paddle Tennis Paddles +Sporting Goods > Outdoor Recreation > Outdoor Games > Platform & Paddle Tennis > Platform Tennis Balls +Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball +Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball > Tetherball Poles +Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball > Tetherball Sets +Sporting Goods > Outdoor Recreation > Outdoor Games > Tetherball > Tetherballs +Sporting Goods > Outdoor Recreation > Riding Scooters +Sporting Goods > Outdoor Recreation > Skateboarding +Sporting Goods > Outdoor Recreation > Skateboarding > Skate Rails +Sporting Goods > Outdoor Recreation > Skateboarding > Skate Ramps +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Decks +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Small Parts +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Trucks +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboard Parts > Skateboard Wheels +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear > Skate Helmets +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear > Skateboarding Gloves +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboarding Protective Gear > Skateboarding Pads +Sporting Goods > Outdoor Recreation > Skateboarding > Skateboards +Sporting Goods > Outdoor Recreation > Winter Sports & Activities +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Avalanche Safety +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Avalanche Safety > Avalanche Probes +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Avalanche Safety > Avalanche Safety Airbags +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Bags +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Goggle Accessories +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Goggle Accessories > Ski & Snowboard Goggle Lenses +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Goggles +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Helmets +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Leashes +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Storage Racks +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Tuning Tools +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski & Snowboard Wax +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Binding Parts +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Bindings +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Boots +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Ski Poles +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Skis +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Skis > Cross-Country Skis +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Skis > Downhill Skis +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboard Binding Parts +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboard Bindings +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboard Boots +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Skiing & Snowboarding > Snowboards +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Sleds +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Snowshoeing +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Snowshoeing > Snowshoe Bindings +Sporting Goods > Outdoor Recreation > Winter Sports & Activities > Snowshoeing > Snowshoes +Toys & Games +Toys & Games > Game Timers +Toys & Games > Games +Toys & Games > Games > Battle Top Accessories +Toys & Games > Games > Battle Tops +Toys & Games > Games > Bingo Sets +Toys & Games > Games > Blackjack & Craps Sets +Toys & Games > Games > Board Games +Toys & Games > Games > Card Game Accessories +Toys & Games > Games > Card Games +Toys & Games > Games > Dexterity Games +Toys & Games > Games > Dice Sets & Games +Toys & Games > Games > Poker Chip Accessories +Toys & Games > Games > Poker Chip Accessories > Poker Chip Carriers & Trays +Toys & Games > Games > Poker Chips & Sets +Toys & Games > Games > Portable Electronic Games +Toys & Games > Games > Roulette Wheels & Sets +Toys & Games > Games > Slot Machines +Toys & Games > Games > Tile Games +Toys & Games > Outdoor Play Equipment +Toys & Games > Outdoor Play Equipment > Inflatable Bouncer Accessories +Toys & Games > Outdoor Play Equipment > Inflatable Bouncers +Toys & Games > Outdoor Play Equipment > Play Swings +Toys & Games > Outdoor Play Equipment > Play Tents & Tunnels +Toys & Games > Outdoor Play Equipment > Playhouses +Toys & Games > Outdoor Play Equipment > Pogo Sticks +Toys & Games > Outdoor Play Equipment > Sandboxes +Toys & Games > Outdoor Play Equipment > See Saws +Toys & Games > Outdoor Play Equipment > Slides +Toys & Games > Outdoor Play Equipment > Stilts +Toys & Games > Outdoor Play Equipment > Swing Set & Playset Accessories +Toys & Games > Outdoor Play Equipment > Swing Sets & Playsets +Toys & Games > Outdoor Play Equipment > Trampoline Accessories +Toys & Games > Outdoor Play Equipment > Trampolines +Toys & Games > Outdoor Play Equipment > Water Play Equipment +Toys & Games > Outdoor Play Equipment > Water Play Equipment > Play Sprinkers +Toys & Games > Outdoor Play Equipment > Water Play Equipment > Water Parks & Slides +Toys & Games > Outdoor Play Equipment > Water Play Equipment > Water Tables +Toys & Games > Puzzles +Toys & Games > Puzzles > Jigsaw Puzzle Accessories +Toys & Games > Puzzles > Jigsaw Puzzles +Toys & Games > Puzzles > Mechanical Puzzles +Toys & Games > Puzzles > Wooden & Pegged Puzzles +Toys & Games > Toys +Toys & Games > Toys > Activity Toys +Toys & Games > Toys > Activity Toys > Ball & Cup Games +Toys & Games > Toys > Activity Toys > Bouncy Balls +Toys & Games > Toys > Activity Toys > Bubble Blowing Solution +Toys & Games > Toys > Activity Toys > Bubble Blowing Toys +Toys & Games > Toys > Activity Toys > Coiled Spring Toys +Toys & Games > Toys > Activity Toys > Marbles +Toys & Games > Toys > Activity Toys > Paddle Ball Toys +Toys & Games > Toys > Activity Toys > Ribbon & Streamer Toys +Toys & Games > Toys > Activity Toys > Spinning Tops +Toys & Games > Toys > Activity Toys > Toy Jacks +Toys & Games > Toys > Activity Toys > Yo-Yo Parts & Accessories +Toys & Games > Toys > Activity Toys > Yo-Yos +Toys & Games > Toys > Art & Drawing Toys +Toys & Games > Toys > Art & Drawing Toys > Play Dough & Putty +Toys & Games > Toys > Art & Drawing Toys > Toy Drawing Tablets +Toys & Games > Toys > Ball Pit Accessories +Toys & Games > Toys > Ball Pit Accessories > Ball Pit Balls +Toys & Games > Toys > Ball Pits +Toys & Games > Toys > Bath Toys +Toys & Games > Toys > Beach & Sand Toys +Toys & Games > Toys > Building Toys +Toys & Games > Toys > Building Toys > Construction Set Toys +Toys & Games > Toys > Building Toys > Foam Blocks +Toys & Games > Toys > Building Toys > Interlocking Blocks +Toys & Games > Toys > Building Toys > Marble Track Sets +Toys & Games > Toys > Building Toys > Wooden Blocks +Toys & Games > Toys > Dolls, Playsets & Toy Figures +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Action & Toy Figures +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Bobblehead Figures +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Doll & Action Figure Accessories +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dollhouse Accessories +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dollhouses +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Dolls +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Paper & Magnetic Dolls +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppet & Puppet Theater Accessories +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppet Theaters +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Puppets & Marionettes +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Stuffed Animals +Toys & Games > Toys > Dolls, Playsets & Toy Figures > Toy Playsets +Toys & Games > Toys > Educational Toys +Toys & Games > Toys > Educational Toys > Ant Farms +Toys & Games > Toys > Educational Toys > Astronomy Toys & Models +Toys & Games > Toys > Educational Toys > Bug Collecting Kits +Toys & Games > Toys > Educational Toys > Educational Flash Cards +Toys & Games > Toys > Educational Toys > Reading Toys +Toys & Games > Toys > Educational Toys > Science & Exploration Sets +Toys & Games > Toys > Educational Toys > Toy Abacuses +Toys & Games > Toys > Executive Toys +Toys & Games > Toys > Executive Toys > Magnet Toys +Toys & Games > Toys > Flying Toy Accessories +Toys & Games > Toys > Flying Toy Accessories > Kite Accessories +Toys & Games > Toys > Flying Toy Accessories > Kite Accessories > Kite Line Reels & Winders +Toys & Games > Toys > Flying Toys +Toys & Games > Toys > Flying Toys > Air & Water Rockets +Toys & Games > Toys > Flying Toys > Kites +Toys & Games > Toys > Flying Toys > Toy Gliders +Toys & Games > Toys > Flying Toys > Toy Parachutes +Toys & Games > Toys > Musical Toys +Toys & Games > Toys > Musical Toys > Toy Instruments +Toys & Games > Toys > Play Vehicle Accessories +Toys & Games > Toys > Play Vehicle Accessories > Toy Race Car & Track Accessories +Toys & Games > Toys > Play Vehicle Accessories > Toy Train Accessories +Toys & Games > Toys > Play Vehicles +Toys & Games > Toys > Play Vehicles > Toy Airplanes +Toys & Games > Toys > Play Vehicles > Toy Boats +Toys & Games > Toys > Play Vehicles > Toy Cars +Toys & Games > Toys > Play Vehicles > Toy Helicopters +Toys & Games > Toys > Play Vehicles > Toy Motorcycles +Toys & Games > Toys > Play Vehicles > Toy Race Car & Track Sets +Toys & Games > Toys > Play Vehicles > Toy Spaceships +Toys & Games > Toys > Play Vehicles > Toy Trains & Train Sets +Toys & Games > Toys > Play Vehicles > Toy Trucks & Construction Vehicles +Toys & Games > Toys > Pretend Play +Toys & Games > Toys > Pretend Play > Play Money & Banking +Toys & Games > Toys > Pretend Play > Pretend Electronics +Toys & Games > Toys > Pretend Play > Pretend Housekeeping +Toys & Games > Toys > Pretend Play > Pretend Lawn & Garden +Toys & Games > Toys > Pretend Play > Pretend Professions & Role Playing +Toys & Games > Toys > Pretend Play > Pretend Shopping & Grocery +Toys & Games > Toys > Pretend Play > Toy Kitchens & Play Food +Toys & Games > Toys > Pretend Play > Toy Tools +Toys & Games > Toys > Remote Control Toy Accessories +Toys & Games > Toys > Remote Control Toys +Toys & Games > Toys > Remote Control Toys > Remote Control Airships & Blimps +Toys & Games > Toys > Remote Control Toys > Remote Control Boats & Watercraft +Toys & Games > Toys > Remote Control Toys > Remote Control Cars & Trucks +Toys & Games > Toys > Remote Control Toys > Remote Control Helicopters +Toys & Games > Toys > Remote Control Toys > Remote Control Motorcycles +Toys & Games > Toys > Remote Control Toys > Remote Control Planes +Toys & Games > Toys > Remote Control Toys > Remote Control Robots +Toys & Games > Toys > Remote Control Toys > Remote Control Tanks +Toys & Games > Toys > Riding Toy Accessories +Toys & Games > Toys > Riding Toys +Toys & Games > Toys > Riding Toys > Electric Riding Vehicles +Toys & Games > Toys > Riding Toys > Hobby Horses +Toys & Games > Toys > Riding Toys > Push & Pedal Riding Vehicles +Toys & Games > Toys > Riding Toys > Rocking & Spring Riding Toys +Toys & Games > Toys > Riding Toys > Wagons +Toys & Games > Toys > Robotic Toys +Toys & Games > Toys > Sports Toy Accessories +Toys & Games > Toys > Sports Toy Accessories > Fitness Toy Accessories +Toys & Games > Toys > Sports Toy Accessories > Fitness Toy Accessories > Hula Hoop Accessories +Toys & Games > Toys > Sports Toys +Toys & Games > Toys > Sports Toys > Baseball Toys +Toys & Games > Toys > Sports Toys > Basketball Toys +Toys & Games > Toys > Sports Toys > Boomerangs +Toys & Games > Toys > Sports Toys > Bowling Toys +Toys & Games > Toys > Sports Toys > Fingerboards & Fingerboard Sets +Toys & Games > Toys > Sports Toys > Fishing Toys +Toys & Games > Toys > Sports Toys > Fitness Toys +Toys & Games > Toys > Sports Toys > Fitness Toys > Hula Hoops +Toys & Games > Toys > Sports Toys > Flying Discs +Toys & Games > Toys > Sports Toys > Footbags +Toys & Games > Toys > Sports Toys > Golf Toys +Toys & Games > Toys > Sports Toys > Hockey Toys +Toys & Games > Toys > Sports Toys > Playground Balls +Toys & Games > Toys > Sports Toys > Racquet Sport Toys +Toys & Games > Toys > Sports Toys > Toy Footballs +Toys & Games > Toys > Toy Gift Baskets +Toys & Games > Toys > Toy Weapon & Gadget Accessories +Toys & Games > Toys > Toy Weapons & Gadgets +Toys & Games > Toys > Visual Toys +Toys & Games > Toys > Visual Toys > Kaleidoscopes +Toys & Games > Toys > Visual Toys > Prisms +Toys & Games > Toys > Wind-Up Toys +Vehicles & Parts +Vehicles & Parts > Vehicle Parts & Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Aircraft Parts & Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle A/V Players & In-Dash Systems +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Amplifiers +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Cassette Adapters +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Cassette Players +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Equalizers & Crossovers +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Parking Cameras +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Speakerphones +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Speakers +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Subwoofers +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Electronics > Motor Vehicle Video Monitor Mounts +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Braking +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Carpet & Upholstery +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Climate Control +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Controls +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Oil Circulation +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engine Parts +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Engines +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Exhaust +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Frame & Body Parts +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Fuel Systems +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Interior Fittings +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Lighting +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Mirrors +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Power & Electrical Systems +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Seating +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Sensors & Gauges +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Suspension Parts +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Towing +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Transmission & Drivetrain Parts +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Automotive Rims & Wheels +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Motorcycle Rims & Wheels +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Rims & Wheels > Off-Road and All-Terrain Vehicle Rims & Wheels +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tire Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Automotive Tires +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Motorcycle Tires +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Tires > Off-Road and All-Terrain Vehicle Tires +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Wheel Systems > Motor Vehicle Wheel Parts +Vehicles & Parts > Vehicle Parts & Accessories > Motor Vehicle Parts > Motor Vehicle Window Parts & Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Portable Fuel Cans +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Car Wash Brushes +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Car Wash Solutions +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Carpet & Upholstery Cleaners +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Fuel Injection Cleaning Kits +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Glass Cleaners +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Cleaning > Vehicle Waxes, Polishes & Protectants +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Golf Cart Enclosures +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Motor Vehicle Windshield Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Tonneau Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Hardtops +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Soft Tops +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Automotive Storage Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Golf Cart Storage Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Motorcycle Storage Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Recreational Vehicle Storage Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Covers > Vehicle Storage Covers > Watercraft Storage Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Bumper Stickers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Air Fresheners +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Antenna Balls +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Dashboard Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Decals +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Decor Accessory Sets +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Display Flags +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Emblems & Hood Ornaments +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Hitch Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plate Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plate Frames +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plate Mounts & Holders +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle License Plates +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Magnets +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Rear View Mirror Ornaments +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Shift Boots +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Shift Knobs +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Steering Wheel Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Decor > Vehicle Wraps +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Antifreeze +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Brake Fluid +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Cooling System Additives +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Engine Degreasers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Fuel System Cleaners +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Greases +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Hydraulic Clutch Fluid +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Motor Oil +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Performance Additives +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Power Steering Fluid +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Transmission Fluid +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Fluids > Vehicle Windshield Fluid +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Paint +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Paint > Motor Vehicle Body Paint +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Paint > Motor Vehicle Brake Caliper Paint +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Motor Vehicle Brake Service Kits +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Motor Vehicle Clutch Alignment & Removal Tools +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Battery Chargers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Battery Testers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Body Filler +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Diagnostic Scanners +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Jump Starters +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Jumper Cables +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Vehicle Tire Repair & Tire Changing Tools +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Maintenance, Care & Decor > Vehicle Repair & Specialty Tools > Windshield Repair Kits +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Chest & Back Protectors +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Elbow & Wrist Guards +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Gloves +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Goggles +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Hand Guards +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Helmet Parts & Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Helmets +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Kidney Belts +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Knee & Shin Guards +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Motorcycle Protective Gear > Motorcycle Neck Braces +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Off-Road & All-Terrain Vehicle Protective Gear +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Off-Road & All-Terrain Vehicle Protective Gear > ATV & UTV Bar Pads +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Automotive Alarm Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Automotive Alarm Systems +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Motorcycle Alarms & Locks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts > Vehicle Door Lock Actuators +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts > Vehicle Door Lock Knobs +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Door Locks & Parts > Vehicle Door Locks & Locking Systems +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Hitch Locks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Immobilizers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Remote Keyless Systems +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Steering Wheel Locks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Alarms & Locks > Vehicle Wheel Clamps +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Car Window Nets +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Emergency Road Flares +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Motor Vehicle Airbag Parts +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Motor Vehicle Roll Cages & Bars +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belt Buckles +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belt Covers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belt Straps +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Seat Belts +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Warning Whips +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Safety & Security > Vehicle Safety Equipment > Vehicle Wheel Chocks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Cargo Nets +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Rack Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Rack Accessories > Vehicle Bicycle Rack Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Rack Accessories > Vehicle Ski & Snowboard Rack Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Base Rack Systems +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Bicycle Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Boat Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Cargo Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Fishing Rod Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Gun Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Motorcycle & Scooter Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Ski & Snowboard Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Carrying Racks > Vehicle Water Sport Board Racks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Loading Ramps +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Boat Trailers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Horse & Livestock Trailers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Travel Trailers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motor Vehicle Trailers > Utility & Cargo Trailers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Motorcycle Bags & Panniers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Truck Bed Storage Boxes & Organizers +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Vehicle Headrest Hangers & Hooks +Vehicles & Parts > Vehicle Parts & Accessories > Vehicle Storage & Cargo > Vehicle Organizers +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Chains +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Lines & Ropes +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchor Windlasses +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Anchors +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Boat Hooks +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Boat Ladders +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Dock Cleats +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Docking & Anchoring > Dock Steps +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Sailboat Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care > Watercraft Cleaners +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Care > Watercraft Polishes +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Alternators +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Carburetors & Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Engine Controls +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Ignition Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Impellers +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Motor Locks +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Motor Mounts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Pistons & Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engine Parts > Watercraft Propellers +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Engines & Motors +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts > Watercraft Manifolds +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Exhaust Parts > Watercraft Mufflers & Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Lines & Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Meters +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Pumps & Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Fuel Systems > Watercraft Fuel Tanks & Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Lighting +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts > Watercraft Steering Cables +Vehicles & Parts > Vehicle Parts & Accessories > Watercraft Parts & Accessories > Watercraft Steering Parts > Watercraft Steering Wheels +Vehicles & Parts > Vehicles +Vehicles & Parts > Vehicles > Aircraft +Vehicles & Parts > Vehicles > Motor Vehicles +Vehicles & Parts > Vehicles > Motor Vehicles > Cars, Trucks & Vans +Vehicles & Parts > Vehicles > Motor Vehicles > Golf Carts +Vehicles & Parts > Vehicles > Motor Vehicles > Motorcycles & Scooters +Vehicles & Parts > Vehicles > Motor Vehicles > Off-Road and All-Terrain Vehicles +Vehicles & Parts > Vehicles > Motor Vehicles > Off-Road and All-Terrain Vehicles > ATVs & UTVs +Vehicles & Parts > Vehicles > Motor Vehicles > Off-Road and All-Terrain Vehicles > Go Karts & Dune Buggies +Vehicles & Parts > Vehicles > Motor Vehicles > Recreational Vehicles +Vehicles & Parts > Vehicles > Motor Vehicles > Snowmobiles +Vehicles & Parts > Vehicles > Watercraft +Vehicles & Parts > Vehicles > Watercraft > Motor Boats +Vehicles & Parts > Vehicles > Watercraft > Personal Watercraft +Vehicles & Parts > Vehicles > Watercraft > Sailboats +Vehicles & Parts > Vehicles > Watercraft > Yachts \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/GoogleMerchantCenterFeedPlugin.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/GoogleMerchantCenterFeedPlugin.cs new file mode 100644 index 0000000000..3808bca487 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/GoogleMerchantCenterFeedPlugin.cs @@ -0,0 +1,64 @@ +using System.Data.Entity.Migrations; +using System.Web.Routing; +using SmartStore.Core.Plugins; +using SmartStore.GoogleMerchantCenter.Data.Migrations; +using SmartStore.GoogleMerchantCenter.Services; +using SmartStore.Services; + +namespace SmartStore.GoogleMerchantCenter +{ + public class GoogleMerchantCenterFeedPlugin : BasePlugin, IConfigurable + { + private readonly IGoogleFeedService _googleFeedService; + private readonly ICommonServices _services; + + public GoogleMerchantCenterFeedPlugin( + IGoogleFeedService googleFeedService, + ICommonServices services) + { + _googleFeedService = googleFeedService; + _services = services; + } + + public static string SystemName + { + get { return "SmartStore.GoogleMerchantCenter"; } + } + + /// + /// Gets a route for provider configuration + /// + /// Action name + /// Controller name + /// Route values + public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "FeedGoogleMerchantCenter"; + routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.GoogleMerchantCenter.Controllers" }, { "area", SystemName } }; + } + + /// + /// Install plugin + /// + public override void Install() + { + _services.Localization.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + } + + /// + /// Uninstall plugin + /// + public override void Uninstall() + { + _services.Localization.DeleteLocaleStringResources(PluginDescriptor.ResourceRootKey); + + var migrator = new DbMigrator(new Configuration()); + migrator.Update(DbMigrator.InitialDatabase); + + base.Uninstall(); + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.de-de.xml b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.de-de.xml new file mode 100644 index 0000000000..17b90e856c --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.de-de.xml @@ -0,0 +1,235 @@ + + + Google Merchant Center Feed + + + Ermöglicht den Export von Produktdaten im Feed-Format von Google Merchant Center (GMC). + + + Google Merchant Center XML Feed + + + Ermöglicht den Export von Produktdaten im XML Feed-Format von Google Merchant Center (GMC). + + + + + +
  • Für die Produktidentifizierung muss entweder die GTIN (z.B. als UPC, EAN etc.) oder der Hersteller samt Hersteller-Artikelnummer (MPN) hinterlegt sein. Google empfiehlt die Angabe aller drei Informationen.
  • +
  • Standard Steuer- und Versanddaten sind in den Einstellungen Ihres Google-Merchant-Center-Kontos zu hinterlegen.
  • +
  • Mehr Informationen zu benötigten Feldern finden Sie im Artikel Produkt-Feed-Spezifikationen.
  • +
  • Eine Liste mit allen gültigen Google-Produkt-Kategorie finden Sie hier.
  • +]]> +
    +
    + + Standard-Google-Kategorie fehlt + + + Standard-Google-Kategorie + + + Wird verwendet, falls auf Produktebene keine Kategorie angegeben ist. + + + Produkt + + + Google-Kategorie + + + Legt die dem Artikel entsprechende Google-Kategorie fest. Zwingend erforderlich. + + + Zusätzliche Bilder + + + Legt fest, ob mehr als ein Produktbild exportiert werden soll. Bis zu 10 sind möglich. + + + Zustand + + + Zustand des Artikels. + + + Neu + + + Gebraucht + + + Erneuert + + + Verfügbarkeit + + + Verfügbarkeit des Artikels. + + + Vorrätig + + + Vergriffen + + + Vorbestellt + + + Aktionspreis exportieren + + + Legt fest, ob ein Aktionspreis inkl. Aktionszeitraum exportiert werden soll, sofern ein solcher für das jeweilige Produkt existiert. + + + Geschlecht + + + Angabe ist für bestimmte Artikel z.B. Bekleidung erforderlich. + + + Herren + + + Damen + + + Unisex + + + Altersgruppe + + + Angabe ist für bestimmte Artikel, z.B. Bekleidung erforderlich. + + + Erwachsene + + + Kinder + + + Farbe + + + Angabe ist für bestimmte Artikel, z.B. Bekleidung erforderlich. + + + Größe + + + Angabe ist für bestimmte Artikel, z.B. Bekleidung erforderlich. + + + Material + + + Material, aus dem das Produkt besteht. Angabe ist z.B. bei Bekleidung sinnvoll. + + + Muster + + + Muster oder grafisches Druckdesign eines Produktes. Angabe ist z.B. bei Bekleidung sinnvoll. + + + Leer + + + Produktname + + + Produktnamen durchsuchen. + + + Bearbeitet + + + Sucht nach Datensätzen, die bearbeitet oder noch nicht bearbeitet wurden. + + + Bearbeitet + + + Noch nicht bearbeitet + + + Verfällt in Tagen + + + Anzahl der Tage, nach dem die Artikel verfallen bzw. nicht mehr angezeigt werden sollen. Der Wert 0 bewirkt, dass kein Verfallsdatum exportiert wird. + + + Der Wert muss zwischen 0 und 29 Tagen liegen. + + + Versanddaten exportieren + + + Legt fest, ob das Gewicht eines Produktes exportiert werden soll. + + + Grundpreis exportieren + + + Legt fest, ob der Grundpreis eines Produktes exportiert werden soll. + + + Multipack + + + Anzahl identischer Produkte in einem händlerdefinierten Multipack. Muss größer 1 sein. + + + Bundle + + + Händlerdefiniertes Produktpaket bestehend aus einem Haupt- und mehreren Zubehörartikel bzw. Add-ons. + + + Nicht jugendfrei + + + Produkt, welches nur für erwachsene Nutzer bestimmt ist. + + + Energieeffizienz + + + Die Energieeffizienzklasse des Produktes gemäß EU-Richtlinie 2010/30/EU. Mögliche Werte sind G, F, E, D, C, B, A, A+, A++, A+++. + + + A+++,A++,A+,A,B,C,D,E,F,G + + + Label 0 + + + Benutzerdefiniertes Label 0. Dient der individuellen Gruppierung von Produkten. + + + Label 1 + + + Benutzerdefiniertes Label 1. Dient der individuellen Gruppierung von Produkten. + + + Label 2 + + + Benutzerdefiniertes Label 2. Dient der individuellen Gruppierung von Produkten. + + + Label 3 + + + Benutzerdefiniertes Label 3. Dient der individuellen Gruppierung von Produkten. + + + Label 4 + + + Benutzerdefiniertes Label 4. Dient der individuellen Gruppierung von Produkten. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml new file mode 100644 index 0000000000..3b75a8c306 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Localization/resources.en-us.xml @@ -0,0 +1,235 @@ + + + Google Merchant Center feed + + + Allows you to export product data in the feed format of Google Merchant Center (GMC). + + + Google Merchant Center XML feed + + + Allows to export product data in XML feed format of Google Merchant Center (GMC). + + + + + +
  • Either the GTIN (such as UPC, EAN, etc.) or manufacturer and manufacturer part number (MPN) are required for product identification. Google recommends that all three pieces of information be specified.
  • +
  • Specify default tax and shipping values in your Google Merchant Center account settings.
  • +
  • In order to get more info about required fields look at the following article Product feed specification.
  • +
  • You can find a list of all Google categories here.
  • +]]> +
    +
    + + Default Google category is not set + + + Default Google category + + + Will be used if there is no category specified on produkt level. + + + Product + + + Google Category + + + Specifies the Google category corresponding to the product. Mandatory. + + + Additional images + + + Check the box if you want to export more than one image. Up to 10 are possible. + + + Condition + + + Condition of the product. + + + New + + + Used + + + Refurbished + + + Availability + + + Availability of the product. + + + In stock + + + Out of stock + + + Preorder + + + Export special price + + + Activate this option if you want to export special price and special price period. + + + Gender + + + Required for particular products, for example clothes. + + + Male + + + Female + + + Unisex + + + Age group + + + Required for particular products, for example clothes. + + + Adults + + + Kids + + + Color + + + Required for particular products, for example clothes. + + + Size + + + Required for particular products, for example clothes. + + + Material + + + The material or fabric that a product is made out of. Usefull for clothes for instance. + + + Muster + + + The pattern or graphic print featured on a product. Usefull for clothes for instance. + + + Empty + + + Product name + + + Search product names. + + + Edited + + + Searches for records which have or have not been edited yet. + + + Edited + + + Not edited yet + + + Expires in days + + + Number of days after products should expire or no longer appear. A value of 0 causes that no expiry date will be exported. + + + The value must be between 0 and 29 days. + + + Export shipping data + + + Activate this option if you want to export the weight of the product. + + + Export base price + + + Activate this option if you want to export the base price of the product. + + + Multipack + + + Number of identical products in a merchant defined multipack. Must be greater than 1. + + + Bundle + + + Merchant defined product package consisting of one main and several accessories or add-ons. + + + Adult + + + Product, which is intended only for adult users. + + + Energy efficiency + + + The energy efficiency class of the product in accordance with EU directive 2010/30/EU. Possible values are G, F, E, D, C, B, A, A +, A++, A+++. + + + A+++,A++,A+,A,B,C,D,E,F,G + + + Label 0 + + + Custom label 0 serves the individual grouping of products. + + + Label 1 + + + Custom label 1 serves the individual grouping of products. + + + Label 2 + + + Custom label 2 serves the individual grouping of products. + + + Label 3 + + + Custom label 3 serves the individual grouping of products. + + + Label 4 + + + Custom label 4 serves the individual grouping of products. + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Models/FeedGoogleMerchantCenterModel.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/FeedGoogleMerchantCenterModel.cs new file mode 100644 index 0000000000..36c5f02799 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/FeedGoogleMerchantCenterModel.cs @@ -0,0 +1,141 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Text; +using Newtonsoft.Json; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.GoogleMerchantCenter.Models +{ + public class FeedGoogleMerchantCenterModel + { + public int GridPageSize { get; set; } + + public string[] AvailableGoogleCategories { get; set; } + public string AvailableGoogleCategoriesAsJson + { + get + { + if (AvailableGoogleCategories != null && AvailableGoogleCategories.Length > 0) + return JsonConvert.SerializeObject(AvailableGoogleCategories); + return "[ ]"; + } + } + + public string[] EnergyEfficiencyClasses { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.SearchProductName")] + public string SearchProductName { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.SearchIsTouched")] + public string SearchIsTouched { get; set; } + } + + public class GoogleProductModel : ModelBase + { + public int TotalCount { get; set; } + + //this attribute is required to disable editing + [ScaffoldColumn(false)] + public int ProductId + { + get { return Id; } + set { Id = value; } + } + public int Id { get; set; } + + //this attribute is required to disable editing + [ReadOnly(true)] + [ScaffoldColumn(false)] + [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.ProductName")] + public string Name { get; set; } + + public string SKU { get; set; } + public int ProductTypeId { get; set; } + public ProductType ProductType { get { return (ProductType)ProductTypeId; } } + public string ProductTypeName { get; set; } + public string ProductTypeLabelHint + { + get + { + switch (ProductType) + { + case ProductType.SimpleProduct: + return "smnet-hide"; + case ProductType.GroupedProduct: + return "success"; + case ProductType.BundledProduct: + return "info"; + default: + return ""; + } + } + } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Products.GoogleCategory")] + public string Taxonomy { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Gender")] + public string Gender { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.AgeGroup")] + public string AgeGroup { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Color")] + public string Color { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Size")] + public string Size { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Material")] + public string Material { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Pattern")] + public string Pattern { get; set; } + + [SmartResourceDisplayName("Common.Export")] + public int Export { get; set; } + [SmartResourceDisplayName("Common.Export")] + public bool Export2 + { + get { return Export != 0; } + set { Export = (value ? 1 : 0); } + } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Multipack")] + public int Multipack { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.Multipack")] + public int? Multipack2 + { + get { return Multipack > 0 ? Multipack : (int?)null; } + set { Multipack = (value ?? 0); } + } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.IsBundle")] + public bool? IsBundle { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.IsAdult")] + public bool? IsAdult { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.EnergyEfficiencyClass")] + public string EnergyEfficiencyClass { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel0")] + public string CustomLabel0 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel1")] + public string CustomLabel1 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel2")] + public string CustomLabel2 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel3")] + public string CustomLabel3 { get; set; } + [SmartResourceDisplayName("Plugins.Feed.Froogle.CustomLabel4")] + public string CustomLabel4 { get; set; } + + public string GenderLocalize { get; set; } + public string AgeGroupLocalize { get; set; } + public string Export2Localize { get; set; } + public string IsBundleLocalize { get; set; } + public string IsAdultLocalize { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Models/ProfileConfigurationModel.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/ProfileConfigurationModel.cs new file mode 100644 index 0000000000..69d81d50dd --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Models/ProfileConfigurationModel.cs @@ -0,0 +1,77 @@ +using System; +using System.Xml.Serialization; +using FluentValidation.Attributes; +using Newtonsoft.Json; +using SmartStore.GoogleMerchantCenter.Validators; +using SmartStore.Web.Framework; + +namespace SmartStore.GoogleMerchantCenter.Models +{ + [Serializable] + [Validator(typeof(ProfileConfigurationValidator))] + public class ProfileConfigurationModel + { + public ProfileConfigurationModel() + { + Condition = "new"; + AdditionalImages = true; + SpecialPrice = true; + } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.DefaultGoogleCategory")] + public string DefaultGoogleCategory { get; set; } + + [XmlIgnore] + public string[] AvailableGoogleCategories { get; set; } + + [XmlIgnore] + public string AvailableGoogleCategoriesAsJson + { + get + { + if (AvailableGoogleCategories != null && AvailableGoogleCategories.Length > 0) + return JsonConvert.SerializeObject(AvailableGoogleCategories); + return ""; + } + } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.AdditionalImages")] + public bool AdditionalImages { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Condition")] + public string Condition { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Availability")] + public string Availability { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.SpecialPrice")] + public bool SpecialPrice { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Gender")] + public string Gender { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.AgeGroup")] + public string AgeGroup { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Color")] + public string Color { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Size")] + public string Size { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Material")] + public string Material { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.Pattern")] + public string Pattern { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.ExpirationDays")] + public int ExpirationDays { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.ExportShipping")] + public bool ExportShipping { get; set; } + + [SmartResourceDisplayName("Plugins.Feed.Froogle.ExportBasePrice")] + public bool ExportBasePrice { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..6017fc692f --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.GoogleMerchantCenter")] diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs new file mode 100644 index 0000000000..3edd31e361 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Providers/GmcXmlExportProvider.cs @@ -0,0 +1,439 @@ +using System; +using System.Linq; +using System.Xml; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.GoogleMerchantCenter.Models; +using SmartStore.GoogleMerchantCenter.Services; +using SmartStore.Services.DataExchange.Export; +using SmartStore.Services.Directory; + +namespace SmartStore.GoogleMerchantCenter.Providers +{ + [SystemName("Feeds.GoogleMerchantCenterProductXml")] + [FriendlyName("Google Merchant Center XML product feed")] + [DisplayOrder(1)] + [ExportFeatures(Features = + ExportFeatures.CreatesInitialPublicDeployment | + ExportFeatures.CanOmitGroupedProducts | + ExportFeatures.CanProjectAttributeCombinations | + ExportFeatures.CanProjectDescription | + ExportFeatures.UsesSkuAsMpnFallback | + ExportFeatures.OffersBrandFallback | + ExportFeatures.CanIncludeMainPicture | + ExportFeatures.UsesSpecialPrice)] + public class GmcXmlExportProvider : ExportProviderBase + { + private const string _googleNamespace = "http://base.google.com/ns/1.0"; + + private readonly IGoogleFeedService _googleFeedService; + private readonly IMeasureService _measureService; + private readonly MeasureSettings _measureSettings; + + public GmcXmlExportProvider( + IGoogleFeedService googleFeedService, + IMeasureService measureService, + MeasureSettings measureSettings) + { + _googleFeedService = googleFeedService; + _measureService = measureService; + _measureSettings = measureSettings; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + private string BasePriceUnits(string value) + { + const string defaultValue = "kg"; + + if (value.IsEmpty()) + return defaultValue; + + // TODO: Product.BasePriceMeasureUnit should be localized + switch (value.ToLowerInvariant()) + { + case "mg": + case "milligramm": + case "milligram": + return "mg"; + case "g": + case "gramm": + case "gram": + return "g"; + case "kg": + case "kilogramm": + case "kilogram": + return "kg"; + + case "ml": + case "milliliter": + case "millilitre": + return "ml"; + case "cl": + case "zentiliter": + case "centilitre": + return "cl"; + case "l": + case "liter": + case "litre": + return "l"; + case "cbm": + case "kubikmeter": + case "cubic metre": + return "cbm"; + + case "cm": + case "zentimeter": + case "centimetre": + return "cm"; + case "m": + case "meter": + return "m"; + + case "qm²": + case "quadratmeter": + case "square metre": + return "sqm"; + + default: + return defaultValue; + } + } + + private bool BasePriceSupported(int baseAmount, string unit) + { + if (baseAmount == 1 || baseAmount == 10 || baseAmount == 100) + return true; + + if (baseAmount == 75 && unit == "cl") + return true; + + if ((baseAmount == 50 || baseAmount == 1000) && unit == "kg") + return true; + + return false; + } + + public static string SystemName + { + get { return "Feeds.GoogleMerchantCenterProductXml"; } + } + + public static string Unspecified + { + get { return "__nospec__"; } + } + + public override ExportConfigurationInfo ConfigurationInfo + { + get + { + return new ExportConfigurationInfo + { + PartialViewName = "~/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml", + ModelType = typeof(ProfileConfigurationModel), + Initialize = obj => + { + var model = (obj as ProfileConfigurationModel); + + model.AvailableGoogleCategories = _googleFeedService.GetTaxonomyList(); + } + }; + } + } + + public override string FileExtension + { + get { return "XML"; } + } + + protected override void Export(ExportExecuteContext context) + { + dynamic currency = context.Currency; + string measureWeightSystemKey = ""; + var dateFormat = "yyyy-MM-ddTHH:mmZ"; + + var measureWeight = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId); + + if (measureWeight != null) + measureWeightSystemKey = measureWeight.SystemKeyword; + + var config = (context.ConfigurationData as ProfileConfigurationModel) ?? new ProfileConfigurationModel(); + + using (var writer = XmlWriter.Create(context.DataStream, ExportXmlHelper.DefaultSettings)) + { + writer.WriteStartDocument(); + writer.WriteStartElement("rss"); + writer.WriteAttributeString("version", "2.0"); + writer.WriteAttributeString("xmlns", "g", null, _googleNamespace); + writer.WriteStartElement("channel"); + writer.WriteElementString("title", "{0} - Feed for Google Merchant Center".FormatInvariant((string)context.Store.Name)); + writer.WriteElementString("link", "http://base.google.com/base/"); + writer.WriteElementString("description", "Information about products"); + + while (context.Abort == DataExchangeAbortion.None && context.DataSegmenter.ReadNextSegment()) + { + var segment = context.DataSegmenter.CurrentSegment; + + int[] productIds = segment.Select(x => (int)((dynamic)x).Id).ToArray(); + var googleProducts = _googleFeedService.GetGoogleProductRecords(productIds); + + foreach (dynamic product in segment) + { + if (context.Abort != DataExchangeAbortion.None) + break; + + Product entity = product.Entity; + var gmc = googleProducts.FirstOrDefault(x => x.ProductId == entity.Id); + + if (gmc != null && !gmc.Export) + continue; + + writer.WriteStartElement("item"); + + try + { + string category = (gmc == null ? null : gmc.Taxonomy); + string productType = product._CategoryPath; + string mainImageUrl = product._MainPictureUrl; + var price = (decimal)product.Price; + var uniqueId = (string)product._UniqueId; + string brand = product._Brand; + string gtin = product.Gtin; + string mpn = product.ManufacturerPartNumber; + string condition = "new"; + string availability = "in stock"; + + var specialPrice = product._FutureSpecialPrice as decimal?; + if (!specialPrice.HasValue) + specialPrice = product._SpecialPrice; + + if (category.IsEmpty()) + category = config.DefaultGoogleCategory; + + if (category.IsEmpty()) + context.Log.Error(T("Plugins.Feed.Froogle.MissingDefaultCategory")); + + if (config.Condition.IsCaseInsensitiveEqual(Unspecified)) + { + condition = ""; + } + else if (config.Condition.HasValue()) + { + condition = config.Condition; + } + + if (config.Availability.IsCaseInsensitiveEqual(Unspecified)) + { + availability = ""; + } + else if (config.Availability.HasValue()) + { + availability = config.Availability; + } + else + { + if (entity.ManageInventoryMethod == ManageInventoryMethod.ManageStock && entity.StockQuantity <= 0) + { + if (entity.BackorderMode == BackorderMode.NoBackorders) + availability = "out of stock"; + else if (entity.BackorderMode == BackorderMode.AllowQtyBelow0 || entity.BackorderMode == BackorderMode.AllowQtyBelow0AndNotifyCustomer) + availability = (entity.AvailableForPreOrder ? "preorder" : "out of stock"); + } + } + + writer.WriteElementString("g", "id", _googleNamespace, uniqueId); + + writer.WriteStartElement("title"); + writer.WriteCData(((string)product.Name).Truncate(70).RemoveInvalidXmlChars()); + writer.WriteEndElement(); + + writer.WriteStartElement("description"); + writer.WriteCData(((string)product.FullDescription).RemoveInvalidXmlChars()); + writer.WriteEndElement(); + + writer.WriteStartElement("g", "google_product_category", _googleNamespace); + writer.WriteCData(category.RemoveInvalidXmlChars()); + writer.WriteFullEndElement(); + + if (productType.HasValue()) + { + writer.WriteStartElement("g", "product_type", _googleNamespace); + writer.WriteCData(productType.RemoveInvalidXmlChars()); + writer.WriteFullEndElement(); + } + + writer.WriteElementString("link", (string)product._DetailUrl); + + if (mainImageUrl.HasValue()) + { + writer.WriteElementString("g", "image_link", _googleNamespace, mainImageUrl); + } + + if (config.AdditionalImages) + { + var imageCount = 0; + foreach (dynamic productPicture in product.ProductPictures) + { + string pictureUrl = productPicture.Picture._ImageUrl; + if (pictureUrl.HasValue() && (mainImageUrl.IsEmpty() || !mainImageUrl.IsCaseInsensitiveEqual(pictureUrl)) && ++imageCount <= 10) + { + writer.WriteElementString("g", "additional_image_link", _googleNamespace, pictureUrl); + } + } + } + + writer.WriteElementString("g", "condition", _googleNamespace, condition); + writer.WriteElementString("g", "availability", _googleNamespace, availability); + + if (availability == "preorder" && entity.AvailableStartDateTimeUtc.HasValue && entity.AvailableStartDateTimeUtc.Value > DateTime.UtcNow) + { + var availabilityDate = entity.AvailableStartDateTimeUtc.Value.ToString(dateFormat); + + writer.WriteElementString("g", "availability_date", _googleNamespace, availabilityDate); + } + + if (config.SpecialPrice && specialPrice.HasValue) + { + writer.WriteElementString("g", "sale_price", _googleNamespace, specialPrice.Value.FormatInvariant() + " " + (string)currency.CurrencyCode); + + if (entity.SpecialPriceStartDateTimeUtc.HasValue && entity.SpecialPriceEndDateTimeUtc.HasValue) + { + var specialPriceDate = "{0}/{1}".FormatInvariant( + entity.SpecialPriceStartDateTimeUtc.Value.ToString(dateFormat), entity.SpecialPriceEndDateTimeUtc.Value.ToString(dateFormat)); + + writer.WriteElementString("g", "sale_price_effective_date", _googleNamespace, specialPriceDate); + } + + price = (product._RegularPrice as decimal?) ?? price; + } + + writer.WriteElementString("g", "price", _googleNamespace, price.FormatInvariant() + " " + (string)currency.CurrencyCode); + + writer.WriteCData("gtin", gtin, "g", _googleNamespace); + writer.WriteCData("brand", brand, "g", _googleNamespace); + writer.WriteCData("mpn", mpn, "g", _googleNamespace); + + if (config.Gender.IsCaseInsensitiveEqual(Unspecified)) + writer.WriteCData("gender", "", "g", _googleNamespace); + else + writer.WriteCData("gender", gmc != null && gmc.Gender.HasValue() ? gmc.Gender : config.Gender, "g", _googleNamespace); + + if (config.AgeGroup.IsCaseInsensitiveEqual(Unspecified)) + writer.WriteCData("age_group", "", "g", _googleNamespace); + else + writer.WriteCData("age_group", gmc != null && gmc.AgeGroup.HasValue() ? gmc.AgeGroup : config.AgeGroup, "g", _googleNamespace); + + writer.WriteCData("color", gmc != null && gmc.Color.HasValue() ? gmc.Color : config.Color, "g", _googleNamespace); + writer.WriteCData("size", gmc != null && gmc.Size.HasValue() ? gmc.Size : config.Size, "g", _googleNamespace); + writer.WriteCData("material", gmc != null && gmc.Material.HasValue() ? gmc.Material : config.Material, "g", _googleNamespace); + writer.WriteCData("pattern", gmc != null && gmc.Pattern.HasValue() ? gmc.Pattern : config.Pattern, "g", _googleNamespace); + writer.WriteCData("item_group_id", gmc != null && gmc.ItemGroupId.HasValue() ? gmc.ItemGroupId : "", "g", _googleNamespace); + + writer.WriteElementString("g", "identifier_exists", _googleNamespace, gtin.HasValue() || brand.HasValue() || mpn.HasValue() ? "TRUE" : "FALSE"); + + if (config.ExpirationDays > 0) + { + writer.WriteElementString("g", "expiration_date", _googleNamespace, DateTime.UtcNow.AddDays(config.ExpirationDays).ToString("yyyy-MM-dd")); + } + + if (config.ExportShipping) + { + string weightInfo; + var weight = ((decimal)product.Weight).FormatInvariant(); + + if (measureWeightSystemKey.IsCaseInsensitiveEqual("gram")) + weightInfo = weight + " g"; + else if (measureWeightSystemKey.IsCaseInsensitiveEqual("lb")) + weightInfo = weight + " lb"; + else if (measureWeightSystemKey.IsCaseInsensitiveEqual("ounce")) + weightInfo = weight + " oz"; + else + weightInfo = weight + " kg"; + + writer.WriteElementString("g", "shipping_weight", _googleNamespace, weightInfo); + } + + if (config.ExportBasePrice && entity.BasePriceHasValue) + { + var measureUnit = BasePriceUnits((string)product.BasePriceMeasureUnit); + + if (BasePriceSupported(entity.BasePriceBaseAmount ?? 0, measureUnit)) + { + var basePriceMeasure = "{0} {1}".FormatInvariant((entity.BasePriceAmount ?? decimal.Zero).FormatInvariant(), measureUnit); + var basePriceBaseMeasure = "{0} {1}".FormatInvariant(entity.BasePriceBaseAmount ?? 1, measureUnit); + + writer.WriteElementString("g", "unit_pricing_measure", _googleNamespace, basePriceMeasure); + writer.WriteElementString("g", "unit_pricing_base_measure", _googleNamespace, basePriceBaseMeasure); + } + } + + if (gmc != null && gmc.Multipack > 1) + { + writer.WriteElementString("g", "multipack", _googleNamespace, gmc.Multipack.ToString()); + } + + if (gmc != null && gmc.IsBundle.HasValue) + { + writer.WriteElementString("g", "is_bundle", _googleNamespace, gmc.IsBundle.Value ? "TRUE" : "FALSE"); + } + + if (gmc != null && gmc.IsAdult.HasValue) + { + writer.WriteElementString("g", "adult", _googleNamespace, gmc.IsAdult.Value ? "TRUE" : "FALSE"); + } + + if (gmc != null && gmc.EnergyEfficiencyClass.HasValue()) + { + writer.WriteElementString("g", "energy_efficiency_class", _googleNamespace, gmc.EnergyEfficiencyClass); + } + + if (gmc != null && gmc.CustomLabel0.HasValue()) + { + writer.WriteElementString("g", "custom_label_0", _googleNamespace, gmc.CustomLabel0); + } + + if (gmc != null && gmc.CustomLabel1.HasValue()) + { + writer.WriteElementString("g", "custom_label_1", _googleNamespace, gmc.CustomLabel1); + } + + if (gmc != null && gmc.CustomLabel2.HasValue()) + { + writer.WriteElementString("g", "custom_label_2", _googleNamespace, gmc.CustomLabel2); + } + + if (gmc != null && gmc.CustomLabel3.HasValue()) + { + writer.WriteElementString("g", "custom_label_3", _googleNamespace, gmc.CustomLabel3); + } + + if (gmc != null && gmc.CustomLabel4.HasValue()) + { + writer.WriteElementString("g", "custom_label_4", _googleNamespace, gmc.CustomLabel4); + } + + ++context.RecordsSucceeded; + } + catch (Exception exception) + { + context.RecordException(exception, entity.Id); + } + + writer.WriteEndElement(); // item + } + } + + writer.WriteEndElement(); // channel + writer.WriteEndElement(); // rss + writer.WriteEndDocument(); + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/RouteProvider.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/RouteProvider.cs new file mode 100644 index 0000000000..d0e3b85340 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/RouteProvider.cs @@ -0,0 +1,27 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.GoogleMerchantCenter +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.GoogleMerchantCenter", + "Plugins/SmartStore.GoogleMerchantCenter/{action}", + new { controller = "FeedGoogleMerchantCenter", action = "Configure" }, + new[] { "SmartStore.GoogleMerchantCenter.Controllers" } + ) + .DataTokens["area"] = GoogleMerchantCenterFeedPlugin.SystemName; + } + + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs new file mode 100644 index 0000000000..b5fab3af04 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/GoogleFeedService.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Localization; +using SmartStore.Core.Plugins; +using SmartStore.GoogleMerchantCenter.Domain; +using SmartStore.GoogleMerchantCenter.Models; +using SmartStore.Services; +using Telerik.Web.Mvc; + +namespace SmartStore.GoogleMerchantCenter.Services +{ + public partial class GoogleFeedService : IGoogleFeedService + { + private const string _googleNamespace = "http://base.google.com/ns/1.0"; + + private readonly IRepository _gpRepository; + private readonly ICommonServices _services; + private readonly IPluginFinder _pluginFinder; + + public GoogleFeedService( + IRepository gpRepository, + ICommonServices services, + IPluginFinder pluginFinder) + { + _gpRepository = gpRepository; + _services = services; + _pluginFinder = pluginFinder; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + public GoogleProductRecord GetGoogleProductRecord(int productId) + { + if (productId == 0) + return null; + + var query = + from gp in _gpRepository.Table + where gp.ProductId == productId + select gp; + + var record = query.FirstOrDefault(); + return record; + } + + public List GetGoogleProductRecords(int[] productIds) + { + if (productIds == null || productIds.Length == 0) + return new List(); + + var lst = _gpRepository.TableUntracked.Where(x => productIds.Contains(x.ProductId)).ToList(); + return lst; + } + + public void InsertGoogleProductRecord(GoogleProductRecord record) + { + if (record == null) + throw new ArgumentNullException("googleProductRecord"); + + _gpRepository.Insert(record); + } + + public void UpdateGoogleProductRecord(GoogleProductRecord record) + { + if (record == null) + throw new ArgumentNullException("record"); + + _gpRepository.Update(record); + } + + public void DeleteGoogleProductRecord(GoogleProductRecord record) + { + if (record == null) + throw new ArgumentNullException("record"); + + _gpRepository.Delete(record); + } + + public void Upsert(int pk, string name, string value) + { + if (pk == 0 || name.IsEmpty()) + return; + + var product = GetGoogleProductRecord(pk); + bool insert = (product == null); + var utcNow = DateTime.UtcNow; + + if (product == null) + { + product = new GoogleProductRecord + { + ProductId = pk, + CreatedOnUtc = utcNow + }; + } + + switch (name) + { + case "Taxonomy": + product.Taxonomy = value; + break; + case "Gender": + product.Gender = value; + break; + case "AgeGroup": + product.AgeGroup = value; + break; + case "Color": + product.Color = value; + break; + case "Size": + product.Size = value; + break; + case "Material": + product.Material = value; + break; + case "Pattern": + product.Pattern = value; + break; + case "Export2": + product.Export = value.ToBool(true); + break; + case "Multipack2": + product.Multipack = value.ToInt(); + break; + case "IsBundle": + product.IsBundle = (value.IsEmpty() ? (bool?)null : value.ToBool()); + break; + case "IsAdult": + product.IsAdult = (value.IsEmpty() ? (bool?)null : value.ToBool()); + break; + case "EnergyEfficiencyClass": + product.EnergyEfficiencyClass = value; + break; + case "CustomLabel0": + product.CustomLabel0 = value; + break; + case "CustomLabel1": + product.CustomLabel1 = value; + break; + case "CustomLabel2": + product.CustomLabel2 = value; + break; + case "CustomLabel3": + product.CustomLabel3 = value; + break; + case "CustomLabel4": + product.CustomLabel4 = value; + break; + } + + product.UpdatedOnUtc = utcNow; + product.IsTouched = product.IsTouched(); + + if (!insert && !product.IsTouched) + { + _gpRepository.Delete(product); + return; + } + + if (insert) + { + _gpRepository.Insert(product); + } + else + { + _gpRepository.Update(product); + } + } + + public GridModel GetGridModel(GridCommand command, string searchProductName = null, string touched = null) + { + var model = new GridModel(); + var textInfo = CultureInfo.InvariantCulture.TextInfo; + string yes = T("Admin.Common.Yes"); + string no = T("Admin.Common.No"); + + // there's no way to share a context instance across repositories in EF. + // so we have to fallback to pure SQL here to get the data paged and filtered. + + var whereClause = new StringBuilder("(NOT ([t2].[Deleted] = 1)) AND ([t2].[VisibleIndividually] = 1)"); + + if (searchProductName.HasValue()) + { + whereClause.AppendFormat(" AND ([t2].[Name] LIKE '%{0}%')", searchProductName.Replace("'", "''")); + } + + if (touched.HasValue()) + { + if (touched.IsCaseInsensitiveEqual("touched")) + whereClause.Append(" AND ([t2].[IsTouched] = 1)"); + else + whereClause.Append(" AND ([t2].[IsTouched] = 0 OR [t2].[IsTouched] IS NULL)"); + } + + string sql = null; + string sqlCount = null; + var isSqlServer = DataSettings.Current.IsSqlServer; + + if (isSqlServer) + { + // fastest possible paged data query + sql = + "SELECT [TotalCount], [t3].[Id], [t3].[Name], [t3].[SKU], [t3].[ProductTypeId], [t3].[value] AS [Taxonomy], [t3].[value2] AS [Gender], [t3].[value3] AS [AgeGroup], [t3].[value4] AS [Color], [t3].[value5] AS [Size], [t3].[value6] AS [Material], [t3].[value7] AS [Pattern], [t3].[value8] AS [Export], [t3].[value9] AS [Multipack], [t3].[value10] AS [IsBundle], [t3].[value11] AS [IsAdult], [t3].[value12] AS [EnergyEfficiencyClass], [t3].[value13] AS [CustomLabel0], [t3].[value14] AS [CustomLabel1], [t3].[value15] AS [CustomLabel2], [t3].[value16] AS [CustomLabel3], [t3].[value17] AS [CustomLabel4]" + + " FROM (" + + " SELECT COUNT(id) OVER() [TotalCount], ROW_NUMBER() OVER (ORDER BY [t2].[Name]) AS [ROW_NUMBER], [t2].[Id], [t2].[Name], [t2].[SKU], [t2].[ProductTypeId], [t2].[value], [t2].[value2], [t2].[value3], [t2].[value4], [t2].[value5], [t2].[value6], [t2].[value7], [t2].[value8], [t2].[value9], [t2].[value10], [t2].[value11], [t2].[value12], [t2].[value13], [t2].[value14], [t2].[value15], [t2].[value16], [t2].[value17]" + + " FROM (" + + " SELECT [t0].[Id], [t0].[Name], [t0].[SKU], [t0].[ProductTypeId], [t1].[Taxonomy] AS [value], [t1].[Gender] AS [value2], [t1].[AgeGroup] AS [value3], [t1].[Color] AS [value4], [t1].[Size] AS [value5], [t1].[Material] AS [value6], [t1].[Pattern] AS [value7], COALESCE([t1].[Export],1) AS [value8], COALESCE([t1].[Multipack],0) AS [value9], [t1].[IsBundle] AS [value10], [t1].[IsAdult] AS [value11], [t1].[EnergyEfficiencyClass] AS [value12], [t1].[CustomLabel0] AS [value13], [t1].[CustomLabel1] AS [value14], [t1].[CustomLabel2] AS [value15], [t1].[CustomLabel3] AS [value16], [t1].[CustomLabel4] AS [value17], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched]" + + " FROM [Product] AS [t0]" + + " LEFT OUTER JOIN [GoogleProduct] AS [t1] ON [t0].[Id] = [t1].[ProductId]" + + " ) AS [t2]" + + " WHERE " + whereClause.ToString() + + " ) AS [t3]" + + " WHERE [t3].[ROW_NUMBER] BETWEEN {0} + 1 AND {0} + {1}" + + " ORDER BY [t3].[ROW_NUMBER]"; + } + else + { + // OFFSET... FETCH NEXT requires SQL Server 2012 or SQL CE 4 + sql = + "SELECT [t2].[Id], [t2].[Name], [t2].[SKU], [t2].[ProductTypeId], [t2].[value] AS [Taxonomy], [t2].[value2] AS [Gender], [t2].[value3] AS [AgeGroup], [t2].[value4] AS [Color], [t2].[value5] AS [Size], [t2].[value6] AS [Material], [t2].[value7] AS [Pattern], [t2].[value8] AS [Export], [t2].[value9] AS [Multipack], [t2].[value10] AS [IsBundle], [t2].[value11] AS [IsAdult], [t2].[value12] AS [EnergyEfficiencyClass], [t2].[value13] AS [CustomLabel0], [t2].[value14] AS [CustomLabel1], [t2].[value15] AS [CustomLabel2], [t2].[value16] AS [CustomLabel3], [t2].[value17] AS [CustomLabel4]" + + " FROM (" + + " SELECT [t0].[Id], [t0].[Name], [t0].[SKU], [t0].[ProductTypeId], [t1].[Taxonomy] AS [value], [t1].[Gender] AS [value2], [t1].[AgeGroup] AS [value3], [t1].[Color] AS [value4], [t1].[Size] AS [value5], [t1].[Material] AS [value6], [t1].[Pattern] AS [value7], COALESCE([t1].[Export],1) AS [value8], COALESCE([t1].[Multipack],0) AS [value9], [t1].[IsBundle] AS [value10], [t1].[IsAdult] AS [value11], [t1].[EnergyEfficiencyClass] AS [value12], [t1].[CustomLabel0] AS [value13], [t1].[CustomLabel1] AS [value14], [t1].[CustomLabel2] AS [value15], [t1].[CustomLabel3] AS [value16], [t1].[CustomLabel4] AS [value17], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched] AS [IsTouched]" + + " FROM [Product] AS [t0]" + + " LEFT OUTER JOIN [GoogleProduct] AS [t1] ON [t0].[Id] = [t1].[ProductId]" + + " ) AS [t2]" + + " WHERE " + whereClause.ToString() + + " ORDER BY [t2].[Name]" + + " OFFSET {0} ROWS FETCH NEXT {1} ROWS ONLY"; + + sqlCount = + "SELECT COUNT(*)" + + " FROM (" + + " SELECT [t0].[Id], [t0].[Name], [t0].[Deleted], [t0].[VisibleIndividually], [t1].[IsTouched] AS [IsTouched]" + + " FROM [Product] AS [t0]" + + " LEFT OUTER JOIN [GoogleProduct] AS [t1] ON [t0].[Id] = [t1].[ProductId]" + + " ) AS [t2]" + + " WHERE " + whereClause.ToString(); + } + + + var data = _gpRepository.Context.SqlQuery(sql, (command.Page - 1) * command.PageSize, command.PageSize).ToList(); + + data.ForEach(x => + { + if (x.ProductType != ProductType.SimpleProduct) + x.ProductTypeName = T("Admin.Catalog.Products.ProductType.{0}.Label".FormatInvariant(x.ProductType.ToString())); + + if (x.Gender.HasValue()) + x.GenderLocalize = T("Plugins.Feed.Froogle.Gender" + textInfo.ToTitleCase(x.Gender)); + + if (x.AgeGroup.HasValue()) + x.AgeGroupLocalize = T("Plugins.Feed.Froogle.AgeGroup" + textInfo.ToTitleCase(x.AgeGroup)); + + x.Export2Localize = (x.Export == 0 ? no : yes); + + if (x.IsBundle.HasValue) + x.IsBundleLocalize = (x.IsBundle.Value ? yes : no); + else + x.IsBundleLocalize = null; + + if (x.IsAdult.HasValue) + x.IsAdultLocalize = (x.IsAdult.Value ? yes : no); + else + x.IsAdultLocalize = null; + }); + + model.Data = data; + model.Total = (data.Count > 0 ? data.First().TotalCount : 0); + + if (data.Count > 0) + { + if (isSqlServer) + model.Total = data.First().TotalCount; + else + model.Total = _gpRepository.Context.SqlQuery(sqlCount).FirstOrDefault(); + } + else + { + model.Total = 0; + } + + return model; + } + + public string[] GetTaxonomyList() + { + try + { + var descriptor = _pluginFinder.GetPluginDescriptorBySystemName(GoogleMerchantCenterFeedPlugin.SystemName); + + var fileDir = Path.Combine(descriptor.OriginalAssemblyFile.Directory.FullName, "Files"); + var fileName = "taxonomy.{0}.txt".FormatWith(_services.WorkContext.WorkingLanguage.LanguageCulture ?? "de-DE"); + var path = Path.Combine(fileDir, fileName); + + if (!File.Exists(path)) + path = Path.Combine(fileDir, "taxonomy.en-US.txt"); + + string[] lines = File.ReadAllLines(path, Encoding.UTF8); + + return lines; + } + catch (Exception exc) + { + exc.Dump(); + } + + return new string[] { }; + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Services/IGoogleFeedService.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/IGoogleFeedService.cs new file mode 100644 index 0000000000..6b89e81213 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Services/IGoogleFeedService.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using SmartStore.GoogleMerchantCenter.Domain; +using SmartStore.GoogleMerchantCenter.Models; +using Telerik.Web.Mvc; + +namespace SmartStore.GoogleMerchantCenter.Services +{ + public partial interface IGoogleFeedService + { + GoogleProductRecord GetGoogleProductRecord(int productId); + + List GetGoogleProductRecords(int[] productIds); + + void InsertGoogleProductRecord(GoogleProductRecord record); + + void UpdateGoogleProductRecord(GoogleProductRecord record); + + void DeleteGoogleProductRecord(GoogleProductRecord record); + + void Upsert(int pk, string name, string value); + + GridModel GetGridModel(GridCommand command, string searchProductName = null, string touched = null); + + string[] GetTaxonomyList(); + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj new file mode 100644 index 0000000000..f743627997 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/SmartStore.GoogleMerchantCenter.csproj @@ -0,0 +1,316 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {965A02F0-FC84-4AC4-91E4-79EADFC1CA9D} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.GoogleMerchantCenter + SmartStore.GoogleMerchantCenter + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.GoogleMerchantCenter\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.GoogleMerchantCenter\ + TRACE + prompt + 4 + false + + + true + ..\..\Presentation\SmartStore.Web\bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\packages\FluentValidation.5.6.2.0\lib\Net45\FluentValidation.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + False + ..\..\..\lib\Telerik\Telerik.Web.Mvc.dll + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + 201403112356126_Initial.cs + + + + 201408020941244_IsTouched.cs + + + + 201504211854125_IsActive.cs + + + + 201601061649324_IsBundle.cs + + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} + SmartStore.Data + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + 201403112356126_Initial.cs + + + PreserveNewest + + + PreserveNewest + + + 201408020941244_IsTouched.cs + + + 201504211854125_IsActive.cs + + + 201601061649324_IsBundle.cs + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + + + Designer + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + + PreserveNewest + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 52746 + / + http://localhost:53087/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Validators/ProfileConfigurationValidator.cs b/src/Plugins/SmartStore.GoogleMerchantCenter/Validators/ProfileConfigurationValidator.cs new file mode 100644 index 0000000000..9799ada57f --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Validators/ProfileConfigurationValidator.cs @@ -0,0 +1,15 @@ +using FluentValidation; +using SmartStore.GoogleMerchantCenter.Models; +using SmartStore.Services.Localization; + +namespace SmartStore.GoogleMerchantCenter.Validators +{ + public class ProfileConfigurationValidator : AbstractValidator + { + public ProfileConfigurationValidator(ILocalizationService localize) + { + RuleFor(x => x.ExpirationDays).InclusiveBetween(0, 29) + .WithMessage(localize.GetResource("Plugins.Feed.Froogle.ExpirationDays.Validate")); + } + } +} diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml new file mode 100644 index 0000000000..d91ec16571 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/Configure.cshtml @@ -0,0 +1,272 @@ +@model FeedGoogleMerchantCenterModel +@using SmartStore.GoogleMerchantCenter; +@using SmartStore.GoogleMerchantCenter.Models; +@using SmartStore.GoogleMerchantCenter.Providers; +@using SmartStore.Web.Framework; +@using Telerik.Web.Mvc.UI; +@using SmartStore.Web.Framework.UI; + +@{ + Layout = ""; + + Html.AddCssFileParts(true, "~/Content/x-editable/bootstrap-editable.css"); + Html.AddCssFileParts(true, "~/Plugins/SmartStore.GoogleMerchantCenter/Content/smartstore.gmc.css"); + Html.AppendScriptParts(true, "~/Content/x-editable/bootstrap-editable.js"); +} + +
    +
    +
    + + @Html.Raw(@T("Plugins.Feed.Froogle.AdminInstruction")) +
    +
    + @Html.Action("InfoProfile", "Export", new { systemName = GmcXmlExportProvider.SystemName, returnUrl = Request.RawUrl, area = "admin" }) +
    +
    +
    + + Google Merchant Center + +
    +
    + +

     

    + +
    + + + + + + + +
    + + + + + + + + + + + + + + + + +
    + @(Html.Telerik().Grid() + .Name("gmc-products-grid") + .DataKeys(keys => + { + keys.Add(x => x.ProductId).RouteKey("ProductId"); + }) + .Columns(c => + { + c.Bound(x => x.ProductId) + .ReadOnly() + .Visible(false); + c.Bound(x => x.Name) + .ReadOnly().Visible(true) + .Template(x => @Html.LabeledProductName(x.ProductId, x.Name, x.ProductTypeName, x.ProductTypeLabelHint)) + .ClientTemplate(@Html.LabeledProductName("ProductId", "Name")); + c.Bound(x => x.SKU) + .ReadOnly() + .Visible(true); + c.Bound(x => x.Export2) + .ClientTemplate(Html.XEditableLink("Export2", "select2")); + c.Bound(x => x.Taxonomy) + .ClientTemplate(Html.XEditableLink("Taxonomy", "typeahead")); + c.Bound(x => x.Gender) + .ClientTemplate(Html.XEditableLink("Gender", "select2")); + c.Bound(x => x.AgeGroup) + .ClientTemplate(Html.XEditableLink("AgeGroup", "select2")); + c.Bound(x => x.IsAdult) + .ClientTemplate(Html.XEditableLink("IsAdult", "select2")); + c.Bound(x => x.Color) + .ClientTemplate(Html.XEditableLink("Color", "text")); + c.Bound(x => x.Size) + .ClientTemplate(Html.XEditableLink("Size", "text")); + c.Bound(x => x.Material) + .ClientTemplate(Html.XEditableLink("Material", "text")); + c.Bound(x => x.Pattern) + .ClientTemplate(Html.XEditableLink("Pattern", "text")); + c.Bound(x => x.Multipack2) + .ClientTemplate(Html.XEditableLink("Multipack2", "text")); + c.Bound(x => x.IsBundle) + .ClientTemplate(Html.XEditableLink("IsBundle", "select2")); + c.Bound(x => x.EnergyEfficiencyClass) + .ClientTemplate(Html.XEditableLink("EnergyEfficiencyClass", "select2")); + c.Bound(x => x.CustomLabel0) + .ClientTemplate(Html.XEditableLink("CustomLabel0", "text")); + c.Bound(x => x.CustomLabel1) + .ClientTemplate(Html.XEditableLink("CustomLabel1", "text")); + c.Bound(x => x.CustomLabel2) + .ClientTemplate(Html.XEditableLink("CustomLabel2", "text")); + c.Bound(x => x.CustomLabel3) + .ClientTemplate(Html.XEditableLink("CustomLabel3", "text")); + c.Bound(x => x.CustomLabel4) + .ClientTemplate(Html.XEditableLink("CustomLabel4", "text")); + }) + .ClientEvents(e => + { + e.OnDataBound("OnGridDataBound"); + e.OnDataBinding("OnGridDataBinding"); + e.OnError("OnGridError"); + }) + .DataBinding(dataBinding => + { + dataBinding.Ajax().Select("GoogleProductList", "FeedGoogleMerchantCenter"); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .PreserveGridState() + .EnableCustomBinding(true) + ) +
    +
    + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProductEditTab.cshtml b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProductEditTab.cshtml new file mode 100644 index 0000000000..c20ef9acd7 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProductEditTab.cshtml @@ -0,0 +1,192 @@ +@model SmartStore.GoogleMerchantCenter.Models.GoogleProductModel + +@{ + Layout = ""; +} + + + +@* VERY IMPORTANT for proper model binding *@ +@Html.Hidden("__Type__", Model.GetType().AssemblyQualifiedName) + +@Html.HiddenFor(m => m.ProductId) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(m => m.Export2) + + @Html.EditorFor(m => m.Export2) + @Html.ValidationMessageFor(m => m.Export2) +
    + @Html.SmartLabelFor(m => m.Taxonomy) + + @Html.TextBoxFor(m => m.Taxonomy, new { data_provide = "typeahead", placeholder = ViewBag.DefaultCategory, style = "width: 97%", autocomplete = "off" }) + @Html.ValidationMessageFor(m => m.Taxonomy) +
    + @Html.SmartLabelFor(m => m.Gender) + + @Html.DropDownListFor(m => m.Gender, (IEnumerable)ViewBag.AvailableGenders, (string)ViewBag.DefaultGender) + @Html.ValidationMessageFor(m => m.Gender) +
    + @Html.SmartLabelFor(m => m.AgeGroup) + + @Html.DropDownListFor(m => m.AgeGroup, (IEnumerable)ViewBag.AvailableAgeGroups, (string)ViewBag.DefaultAgeGroup) + @Html.ValidationMessageFor(m => m.AgeGroup) +
    + @Html.SmartLabelFor(m => m.IsAdult) + + @Html.EditorFor(m => m.IsAdult, new { placeholder = ViewBag.DefaultIsAdult }) + @Html.ValidationMessageFor(m => m.IsAdult) +
    + @Html.SmartLabelFor(m => m.Color) + + @Html.TextBoxFor(m => m.Color, new { placeholder = ViewBag.DefaultColor }) + @Html.ValidationMessageFor(m => m.Color) +
    + @Html.SmartLabelFor(m => m.Size) + + @Html.TextBoxFor(m => m.Size, new { placeholder = ViewBag.DefaultSize }) + @Html.ValidationMessageFor(m => m.Size) +
    + @Html.SmartLabelFor(m => m.Material) + + @Html.TextBoxFor(m => m.Material, new { placeholder = ViewBag.DefaultMaterial }) + @Html.ValidationMessageFor(m => m.Material) +
    + @Html.SmartLabelFor(m => m.Pattern) + + @Html.TextBoxFor(m => m.Pattern, new { placeholder = ViewBag.DefaultPattern }) + @Html.ValidationMessageFor(m => m.Pattern) +
    + @Html.SmartLabelFor(m => m.Multipack2) + + @Html.EditorFor(m => m.Multipack2, new { placeholder = ViewBag.DefaultMultipack2 }) + @Html.ValidationMessageFor(m => m.Multipack2) +
    + @Html.SmartLabelFor(m => m.IsBundle) + + @Html.EditorFor(m => m.IsBundle, new { placeholder = ViewBag.DefaultIsBundle }) + @Html.ValidationMessageFor(m => m.IsBundle) +
    + @Html.SmartLabelFor(m => m.EnergyEfficiencyClass) + + @Html.DropDownListFor(m => m.EnergyEfficiencyClass, (IEnumerable)ViewBag.AvailableEnergyEfficiencyClasses, (string)ViewBag.DefaultEnergyEfficiencyClass) + @Html.ValidationMessageFor(m => m.EnergyEfficiencyClass) +
    + @Html.SmartLabelFor(m => m.CustomLabel0) + + @Html.EditorFor(m => m.CustomLabel0, new { placeholder = ViewBag.DefaultCustomLabel }) + @Html.ValidationMessageFor(m => m.CustomLabel0) +
    + @Html.SmartLabelFor(m => m.CustomLabel1) + + @Html.EditorFor(m => m.CustomLabel1, new { placeholder = ViewBag.DefaultCustomLabel }) + @Html.ValidationMessageFor(m => m.CustomLabel1) +
    + @Html.SmartLabelFor(m => m.CustomLabel2) + + @Html.EditorFor(m => m.CustomLabel2, new { placeholder = ViewBag.DefaultCustomLabel }) + @Html.ValidationMessageFor(m => m.CustomLabel2) +
    + @Html.SmartLabelFor(m => m.CustomLabel3) + + @Html.EditorFor(m => m.CustomLabel3, new { placeholder = ViewBag.DefaultCustomLabel }) + @Html.ValidationMessageFor(m => m.CustomLabel3) +
    + @Html.SmartLabelFor(m => m.CustomLabel4) + + @Html.EditorFor(m => m.CustomLabel4, new { placeholder = ViewBag.DefaultCustomLabel }) + @Html.ValidationMessageFor(m => m.CustomLabel4) +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml new file mode 100644 index 0000000000..5f41005fb9 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/FeedGoogleMerchantCenter/ProfileConfiguration.cshtml @@ -0,0 +1,163 @@ +@using SmartStore.GoogleMerchantCenter.Providers +@using SmartStore.GoogleMerchantCenter.Models; +@model ProfileConfigurationModel +@{ + Layout = null; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(m => m.DefaultGoogleCategory) + + @Html.TextBoxFor(m => m.DefaultGoogleCategory, new { data_provide = "typeahead", placeholder = Model.DefaultGoogleCategory, style = "width: 98%", autocomplete = "off", + data_items = 18, data_source = Model.AvailableGoogleCategoriesAsJson }) + @Html.ValidationMessageFor(m => m.DefaultGoogleCategory) +
    + @Html.SmartLabelFor(m => m.ExpirationDays) + + @Html.EditorFor(m => m.ExpirationDays) + @Html.ValidationMessageFor(m => m.ExpirationDays) +
    + @Html.SmartLabelFor(m => m.Condition) + + @Html.DropDownList("Condition", new List + { + new SelectListItem { Text = T("Common.Auto"), Value = "" }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.ConditionNew"), Value = "new" }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.ConditionUsed"), Value = "used" }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.ConditionRefurbished"), Value = "refurbished" } + }) + @Html.ValidationMessageFor(m => m.Condition) +
    + @Html.SmartLabelFor(m => m.Availability) + + @Html.DropDownList("Availability", new List + { + new SelectListItem { Text = T("Common.Auto"), Value = "" }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.AvailabilityInStock"), Value = "in stock" }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.AvailabilityOutOfStock"), Value = "out of stock" }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.AvailabilityPreorder"), Value = "preorder" } + }) + @Html.ValidationMessageFor(m => m.Availability) +
    + @Html.SmartLabelFor(m => m.Gender) + + @Html.DropDownList("Gender", new List + { + new SelectListItem { Text = T("Common.Auto"), Value = "" }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.GenderMale"), Value = "male" }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.GenderFemale"), Value = "female" }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.GenderUnisex"), Value = "unisex" } + }) + @Html.ValidationMessageFor(m => m.Gender) +
    + @Html.SmartLabelFor(m => m.AgeGroup) + + @Html.DropDownList("AgeGroup", new List + { + new SelectListItem { Text = T("Common.Auto"), Value = "" }, + new SelectListItem { Text = T("Common.Unspecified"), Value = GmcXmlExportProvider.Unspecified }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.AgeGroupAdult"), Value = "adult" }, + new SelectListItem { Text = T("Plugins.Feed.Froogle.AgeGroupKids"), Value = "kids" } + }) + @Html.ValidationMessageFor(m => m.AgeGroup) +
    + @Html.SmartLabelFor(m => m.Color) + + @Html.EditorFor(m => m.Color) + @Html.ValidationMessageFor(m => m.Color) +
    + @Html.SmartLabelFor(m => m.Size) + + @Html.EditorFor(m => m.Size) + @Html.ValidationMessageFor(m => m.Size) +
    + @Html.SmartLabelFor(m => m.Material) + + @Html.EditorFor(m => m.Material) + @Html.ValidationMessageFor(m => m.Material) +
    + @Html.SmartLabelFor(m => m.Pattern) + + @Html.EditorFor(m => m.Pattern) + @Html.ValidationMessageFor(m => m.Pattern) +
    + @Html.SmartLabelFor(m => m.AdditionalImages) + + @Html.EditorFor(m => m.AdditionalImages) + @Html.ValidationMessageFor(m => m.AdditionalImages) +
    + @Html.SmartLabelFor(m => m.SpecialPrice) + + @Html.EditorFor(m => m.SpecialPrice) + @Html.ValidationMessageFor(m => m.SpecialPrice) +
    + @Html.SmartLabelFor(m => m.ExportShipping) + + @Html.EditorFor(m => m.ExportShipping) + @Html.ValidationMessageFor(m => m.ExportShipping) +
    + @Html.SmartLabelFor(m => m.ExportBasePrice) + + @Html.EditorFor(m => m.ExportBasePrice) + @Html.ValidationMessageFor(m => m.ExportBasePrice) +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/Views/Web.config b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/changelog.md b/src/Plugins/SmartStore.GoogleMerchantCenter/changelog.md new file mode 100644 index 0000000000..2c1f7000cf --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/changelog.md @@ -0,0 +1,39 @@ +#Release Notes + +##Google Merchant Center (GMC) 2.6.0.1 + ###Bugfixes + * Id should be unique when exporting attribute combinations as products + * No special price exported when the special price period was not specified + +##Google Merchant Center (GMC) 2.5.0.1 +###Bugfixes +* GMC feed does not generate the sale price if the sale price is set for a future date + +##Google Merchant Center (GMC) 2.2.0.5 +###New Features +* Supports GMC fields: multipack, bundle, adult, energy efficiency class and custom label (0 to 4) +* Export of availability date +###Improvements +* Removed "online_only" because it's not part of the GMC feed specification anymore + +##Google Merchant Center (GMC) 2.2.0.4 +###Improvements +* Supports new export framework +###Bugfixes +* Availability value "available for order" deprecated + +##Google Merchant Center (GMC) 2.2.0.3 +###Bugfixes +* Include\exclude option in product tab should initially be activated + +##Google Merchant Center (GMC) 2.2.0.2 +###Improvements +* Supporting of paged google-product data query for SQL-Server Compact Edition + +##Google Merchant Center (GMC) 2.2.0.1 +###New Features +* #582 Option to include\exclude a product + +##Google Merchant Center (GMC) 2.2.0 +###Improvements +* Paged product query to reduce memory payload \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/packages.config b/src/Plugins/SmartStore.GoogleMerchantCenter/packages.config new file mode 100644 index 0000000000..3527aa9a5c --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.GoogleMerchantCenter/web.config b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config new file mode 100644 index 0000000000..ba87d0f098 --- /dev/null +++ b/src/Plugins/SmartStore.GoogleMerchantCenter/web.config @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/Payments.CashOnDelivery/icon.png b/src/Plugins/SmartStore.OfflinePayment/Content/icon-Payments.CashOnDelivery.png similarity index 100% rename from src/Plugins/Payments.CashOnDelivery/icon.png rename to src/Plugins/SmartStore.OfflinePayment/Content/icon-Payments.CashOnDelivery.png diff --git a/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs b/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs new file mode 100644 index 0000000000..14ef7c989e --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Controllers/OfflinePaymentController.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using Autofac; +using FluentValidation; +using FluentValidation.Results; +using SmartStore.Core.Localization; +using SmartStore.OfflinePayment.Models; +using SmartStore.OfflinePayment.Settings; +using SmartStore.OfflinePayment.Validators; +using SmartStore.Services; +using SmartStore.Services.Payments; +using SmartStore.Services.Stores; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.OfflinePayment.Controllers +{ + + public class OfflinePaymentController : PaymentControllerBase + { + private readonly IComponentContext _ctx; + private readonly ICommonServices _services; + private readonly IStoreService _storeService; + + public OfflinePaymentController( + ICommonServices services, + IStoreService storeService, + IComponentContext ctx) + { + this._services = services; + this._storeService = storeService; + this._ctx = ctx; + } + + #region Global + + private List GetTransactModes() + { + var list = new List + { + new SelectListItem { Text = T("Enums.SmartStore.Core.Domain.Payments.PaymentStatus.Pending"), Value = ((int)TransactMode.Pending).ToString() }, + new SelectListItem { Text = T("Enums.SmartStore.Core.Domain.Payments.PaymentStatus.Authorized"), Value = ((int)TransactMode.Authorize).ToString() }, + new SelectListItem { Text = T("Enums.SmartStore.Core.Domain.Payments.PaymentStatus.Paid"), Value = ((int)TransactMode.Paid).ToString() } + }; + + return list; + } + + [NonAction] + private TModel ConfigureGet(Action fn = null) + where TModel : ConfigurationModelBase, new() + where TSetting : PaymentSettingsBase, new() + { + var model = new TModel(); + + int storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + model.DescriptionText = settings.DescriptionText; + model.AdditionalFee = settings.AdditionalFee; + model.AdditionalFeePercentage = settings.AdditionalFeePercentage; + + if (fn != null) + { + fn(model, settings); + } + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, _services.Settings); + + return model; + } + + [NonAction] + private void ConfigurePost(TModel model, FormCollection form, Action fn = null) + where TModel : ConfigurationModelBase, new() + where TSetting : PaymentSettingsBase, new() + { + ModelState.Clear(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + int storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _services.WorkContext); + var settings = _services.Settings.LoadSetting(storeScope); + + settings.DescriptionText = model.DescriptionText; + settings.AdditionalFee = model.AdditionalFee; + settings.AdditionalFeePercentage = model.AdditionalFeePercentage; + + if (fn != null) + { + fn(settings); + } + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, _services.Settings); + _services.Settings.ClearCache(); + + NotifySuccess(_services.Localization.GetResource("Admin.Common.DataSuccessfullySaved")); + } + + [NonAction] + private TModel PaymentInfoGet(Action fn = null) + where TModel : PaymentInfoModelBase, new() + where TSetting : PaymentSettingsBase, new() + { + var settings = _ctx.Resolve(); + var model = new TModel(); + model.DescriptionText = GetLocalizedText(settings.DescriptionText); + + if (fn != null) + { + fn(model, settings); + } + + return model; + } + + private string GetLocalizedText(string text) + { + if (text.EmptyNull().StartsWith("@")) + { + return T(text.Substring(1)); + } + + return text; + } + + [NonAction] + public override IList ValidatePaymentForm(FormCollection form) + { + var warnings = new List(); + IValidator validator; + ValidationResult validationResult = null; + + string type = form["OfflinePaymentMethodType"].NullEmpty(); + + if (type.HasValue()) + { + if (type == "Manual") + { + validator = new ManualPaymentInfoValidator(_services.Localization); + var model = new ManualPaymentInfoModel + { + CardholderName = form["CardholderName"], + CardNumber = form["CardNumber"], + CardCode = form["CardCode"] + }; + validationResult = validator.Validate(model); + } + else if (type == "DirectDebit") + { + validator = new DirectDebitPaymentInfoValidator(_services.Localization); + var model = new DirectDebitPaymentInfoModel + { + EnterIBAN = form["EnterIBAN"], + DirectDebitAccountHolder = form["DirectDebitAccountHolder"], + DirectDebitAccountNumber = form["DirectDebitAccountNumber"], + DirectDebitBankCode = form["DirectDebitBankCode"], + DirectDebitCountry = form["DirectDebitCountry"], + DirectDebitBankName = form["DirectDebitBankName"], + DirectDebitIban = form["DirectDebitIban"], + DirectDebitBic = form["DirectDebitBic"] + }; + validationResult = validator.Validate(model); + } + + if (validationResult != null && !validationResult.IsValid) + { + validationResult.Errors.Each(x => warnings.Add(x.ErrorMessage)); + } + } + + return warnings; + } + + [NonAction] + public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) + { + var paymentInfo = new ProcessPaymentRequest(); + + string type = form["OfflinePaymentMethodType"].NullEmpty(); + + if (type.HasValue()) + { + if (type == "Manual") + { + paymentInfo.CreditCardType = form["CreditCardType"]; + paymentInfo.CreditCardName = form["CardholderName"]; + paymentInfo.CreditCardNumber = form["CardNumber"]; + paymentInfo.CreditCardExpireMonth = int.Parse(form["ExpireMonth"]); + paymentInfo.CreditCardExpireYear = int.Parse(form["ExpireYear"]); + paymentInfo.CreditCardCvv2 = form["CardCode"]; + } + else if (type == "DirectDebit") + { + paymentInfo.DirectDebitAccountHolder = form["DirectDebitAccountHolder"]; + paymentInfo.DirectDebitAccountNumber = form["DirectDebitAccountNumber"]; + paymentInfo.DirectDebitBankCode = form["DirectDebitBankCode"]; + paymentInfo.DirectDebitBankName = form["DirectDebitBankName"]; + paymentInfo.DirectDebitBic = form["DirectDebitBic"]; + paymentInfo.DirectDebitCountry = form["DirectDebitCountry"]; + paymentInfo.DirectDebitIban = form["DirectDebitIban"]; + } + else if (type == "PurchaseOrderNumber") + { + paymentInfo.PurchaseOrderNumber = form["PurchaseOrderNumber"]; + } + } + + return paymentInfo; + } + + [NonAction] + public override string GetPaymentSummary(FormCollection form) + { + string type = form["OfflinePaymentMethodType"].NullEmpty(); + + if (type.HasValue()) + { + if (type == "Manual") + { + var number = form["CardNumber"]; + return "{0}, {1}, {2}".FormatCurrent( + form["CreditCardType"], + form["CardholderName"], + number.Mask(4) + ); + } + else if (type == "DirectDebit") + { + if (form["DirectDebitAccountNumber"].HasValue() && (form["DirectDebitBankCode"].HasValue()) && form["DirectDebitAccountHolder"].HasValue()) + { + var number = form["DirectDebitAccountNumber"]; + return "{0}, {1}, {2}".FormatCurrent( + form["DirectDebitAccountHolder"], + form["DirectDebitBankName"].NullEmpty() ?? form["DirectDebitBankCode"], + number.Mask(4) + ); + } + else if (form["DirectDebitIban"].HasValue()) + { + var number = form["DirectDebitIban"]; + return number.Mask(8); + } + } + else if (type == "PurchaseOrderNumber") + { + return form["PurchaseOrderNumber"]; + } + } + + return null; + } + + #endregion + + + #region CashOnDelivery + + [AdminAuthorize, ChildActionOnly] + public ActionResult CashOnDeliveryConfigure() + { + var model = ConfigureGet(); + + return View("GenericConfigure", model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult CashOnDeliveryConfigure(CashOnDeliveryConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return CashOnDeliveryConfigure(); + + ConfigurePost(model, form); + + return CashOnDeliveryConfigure(); + } + + public ActionResult CashOnDeliveryPaymentInfo() + { + var model = PaymentInfoGet(); + return PartialView("GenericPaymentInfo", model); + } + + #endregion + + + #region Invoice + + [ChildActionOnly, AdminAuthorize] + public ActionResult InvoiceConfigure() + { + var model = ConfigureGet(); + + return View("GenericConfigure", model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult InvoiceConfigure(InvoiceConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return InvoiceConfigure(); + + ConfigurePost(model, form); + + return InvoiceConfigure(); + } + + public ActionResult InvoicePaymentInfo() + { + var model = PaymentInfoGet(); + return PartialView("GenericPaymentInfo", model); + } + + #endregion + + + #region PayInStore + + [ChildActionOnly, AdminAuthorize] + public ActionResult PayInStoreConfigure() + { + var model = ConfigureGet(); + + return View("GenericConfigure", model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult PayInStoreConfigure(PayInStoreConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return PayInStoreConfigure(); + + ConfigurePost(model, form); + + return PayInStoreConfigure(); + } + + public ActionResult PayInStorePaymentInfo() + { + var model = PaymentInfoGet(); + return PartialView("GenericPaymentInfo", model); + } + + #endregion + + + #region Prepayment + + [AdminAuthorize, ChildActionOnly] + public ActionResult PrepaymentConfigure() + { + var model = ConfigureGet(); + + return View("GenericConfigure", model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult PrepaymentConfigure(PrepaymentConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return PrepaymentConfigure(); + + ConfigurePost(model, form); + + return PrepaymentConfigure(); + } + + public ActionResult PrepaymentPaymentInfo() + { + var model = PaymentInfoGet(); + return PartialView("GenericPaymentInfo", model); + } + + #endregion + + + #region DirectDebit + + [AdminAuthorize, ChildActionOnly] + public ActionResult DirectDebitConfigure() + { + var model = ConfigureGet(); + + return View("GenericConfigure", model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult DirectDebitConfigure(DirectDebitConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return DirectDebitConfigure(); + + ConfigurePost(model, form); + + return DirectDebitConfigure(); + } + + public ActionResult DirectDebitPaymentInfo() + { + var model = PaymentInfoGet(); + + var form = this.GetPaymentData(); + model.DirectDebitAccountHolder = form["DirectDebitAccountHolder"]; + model.DirectDebitAccountNumber = form["DirectDebitAccountNumber"]; + model.DirectDebitBankCode = form["DirectDebitBankCode"]; + model.DirectDebitBankName = form["DirectDebitBankName"]; + model.DirectDebitBic = form["DirectDebitBic"]; + model.DirectDebitCountry = form["DirectDebitCountry"]; + model.DirectDebitIban = form["DirectDebitIban"]; + + return PartialView(model); + } + + #endregion + + + #region Manual + + [AdminAuthorize, ChildActionOnly] + public ActionResult ManualConfigure() + { + var model = ConfigureGet((m, s) => + { + m.TransactMode = s.TransactMode; + m.TransactModeValues = GetTransactModes(); + m.ExcludedCreditCards = s.ExcludedCreditCards.SplitSafe(","); + + m.AvailableCreditCards = ManualProvider.CreditCardTypes + .Select(x => new SelectListItem + { + Text = x.Text, + Value = x.Value, + Selected = m.ExcludedCreditCards.Contains(x.Value) + }) + .ToList(); + }); + + return View(model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult ManualConfigure(ManualConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return ManualConfigure(); + + ConfigurePost(model, form, s => + { + s.TransactMode = model.TransactMode; + s.ExcludedCreditCards = string.Join(",", model.ExcludedCreditCards ?? new string[0]); + }); + + return ManualConfigure(); + } + + public ActionResult ManualPaymentInfo() + { + var model = PaymentInfoGet((m, s) => + { + var excludedCreditCards = s.ExcludedCreditCards.SplitSafe(","); + + foreach (var creditCard in ManualProvider.CreditCardTypes) + { + if (!excludedCreditCards.Any(x => x.IsCaseInsensitiveEqual(creditCard.Value))) + { + m.CreditCardTypes.Add(new SelectListItem + { + Text = creditCard.Text, + Value = creditCard.Value + }); + } + } + }); + + // years + for (int i = 0; i < 15; i++) + { + string year = Convert.ToString(DateTime.Now.Year + i); + model.ExpireYears.Add(new SelectListItem { Text = year, Value = year }); + } + + // months + for (int i = 1; i <= 12; i++) + { + string text = (i < 10) ? "0" + i.ToString() : i.ToString(); + model.ExpireMonths.Add(new SelectListItem { Text = text, Value = i.ToString() }); + } + + // set postback values + var form = this.GetPaymentData(); + model.CardholderName = form["CardholderName"]; + model.CardNumber = form["CardNumber"]; + model.CardCode = form["CardCode"]; + + var selectedCcType = model.CreditCardTypes.Where(x => x.Value.Equals(form["CreditCardType"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (selectedCcType != null) + selectedCcType.Selected = true; + var selectedMonth = model.ExpireMonths.Where(x => x.Value.Equals(form["ExpireMonth"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (selectedMonth != null) + selectedMonth.Selected = true; + var selectedYear = model.ExpireYears.Where(x => x.Value.Equals(form["ExpireYear"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (selectedYear != null) + selectedYear.Selected = true; + + return PartialView(model); + } + + #endregion + + #region PurchaseOrderNumber + + [AdminAuthorize] + [ChildActionOnly] + public ActionResult PurchaseOrderNumberConfigure() + { + var model = ConfigureGet(); + + return View("GenericConfigure", model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly, ValidateInput(false)] + public ActionResult PurchaseOrderNumberConfigure(PurchaseOrderNumberConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return InvoiceConfigure(); + + ConfigurePost(model, form); + + return PurchaseOrderNumberConfigure(); + } + + public ActionResult PurchaseOrderNumberPaymentInfo() + { + var model = PaymentInfoGet(); + + var form = this.GetPaymentData(); + model.PurchaseOrderNumber = form["PurchaseOrderNumber"]; + + return PartialView("PurchaseOrderNumberPaymentInfo", model); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Description.txt b/src/Plugins/SmartStore.OfflinePayment/Description.txt new file mode 100644 index 0000000000..db6f0241f9 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Description.txt @@ -0,0 +1,9 @@ +FriendlyName: Offline Payment Methods +Description: Contains common offline payment methods like Direct Debit, Invoice, Prepayment etc. +Group: Payment +SystemName: SmartStore.OfflinePayment +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 0 +FileName: SmartStore.OfflinePayment.dll +ResourceRootKey: Plugins.SmartStore.OfflinePayment diff --git a/src/Plugins/SmartStore.OfflinePayment/Localization/resources.de-de.xml b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.de-de.xml new file mode 100644 index 0000000000..a9f2235ba1 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.de-de.xml @@ -0,0 +1,237 @@ + + + + Offline Zahlungsarten + + + Stellt Offline Zahlungsarten zur Verfügung - u.A. Bankeinzug, Kreditkarte, Rechnung, Vorkasse, Nachnahme etc. + + + + Beschreibung + + + Geben Sie hier die Beschreibung an, die dem Kunden im Bestellprozess angezeigt wird. + + + Zusätzliche Gebühr + + + Bestimmt die Gebühr, die dem Kunden für die Nutzung dieser Zahlart berechnet wird. + + + Zusätzliche Gebühren (prozentual) + + + Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Ein fester Wert wird verwendet, falls diese Option nicht aktiviert ist. + + + + + Nachnahme + + + + + + + + + + + + + + + + + + + Rechnung + + + + + + + + + + + + + + + + + + + Barzahlung + + + + + + + + + + + + + + + + + + + Vorkasse + + + + + + + + + + + + + + + + + + + Kreditkarte (manuell) + + + + + + + + + + Zahlungsstatus nach Bestellabschluss + + + Legt den Zahlungsstatus nach Bestellabschluss fest. + + + Auszuschließende Kreditkarten + + + Kreditkarten mit denen Kunden nicht zahlen dürfen. + + + + + + + Lastschrifteinzug (ELV) + + + + + + + + + + + + + + + Kontoinhaber + + + Name des Kontoinhabers + + + Kontonummer + + + BLZ + + + Bankleitzahl + + + Land + + + Land der Bankverbindung. + + + Name der Bank + + + IBAN + + + International Bank Account Number + + + BIC + + + Bank Interchange Code + + + IBAN eingeben + + + Nein + + + Ja + + + Geben Sie bitte den Namen des Kontoinhabers ein. + + + Geben Sie bitte Ihre Kontonummer ein. + + + Geben Sie bitte die Bankleitzahl (BLZ) ein. + + + Geben Sie bitte die IBAN (International Bank Account Number) ein. + + + Geben Sie bitte die BIC (Bank Interchange Code) ein. + + + + + + + Bestellnummer + + + + + + + + + + Bestellnummer + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Localization/resources.en-us.xml b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.en-us.xml new file mode 100644 index 0000000000..af3d0cc477 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Localization/resources.en-us.xml @@ -0,0 +1,233 @@ + + + + Description + + + Enter info that will be shown to customers during checkout. + + + Additional fee + + + Determines the additional fee. + + + Additional fee. Use percentage + + + Determines whether to apply a percentage additional fee to the order total. If not enabled, a fixed value is used. + + + + + Cash on delivery + + + + + + + + + + + + + + + + + + + Invoice + + + + + + + + + + + + + + + + + + + Pay in store + + + + + + + + + + + + + + + + + + + Prepayment + + + + + + + + + + + + + + + + + + + Credit card (manual) + + + + + + + + + + Payment status after order completion + + + Specifies the payment status after order completion. + + + Excluded credit cards + + + Credit cards that customers may not pay with. + + + + + + + Direct Debit + + + + + + + + + + + + + + + Account holder name + + + Holder name of the bank account + + + Account number + + + Bank code + + + Bank code number + + + Country + + + Country of your bank account. + + + Bank name + + + Name of your bank. + + + IBAN + + + International Bank Account Number + + + BIC + + + Bank Interchange Code + + + Enter IBAN + + + No + + + Yes + + + Please enter the name of the account holder. + + + Please enter your account number. + + + Please enter the bank code. + + + Please enter the IBAN (International Bank Account Number). + + + Please enter the BIC (Bank Interchange Code). + + + + + + + Purchase order + + + + + + + + + + PO Number + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Models/ConfigurationModel.cs b/src/Plugins/SmartStore.OfflinePayment/Models/ConfigurationModel.cs new file mode 100644 index 0000000000..ba59935fdb --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Models/ConfigurationModel.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.OfflinePayment.Settings; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.OfflinePayment.Models +{ + public abstract class ConfigurationModelBase : ModelBase + { + [AllowHtml] + [SmartResourceDisplayName("Plugins.SmartStore.OfflinePayment.DescriptionText")] + public string DescriptionText { get; set; } + + [SmartResourceDisplayName("Plugins.SmartStore.OfflinePayment.AdditionalFee")] + public decimal AdditionalFee { get; set; } + + [SmartResourceDisplayName("Plugins.SmartStore.OfflinePayment.AdditionalFeePercentage")] + public bool AdditionalFeePercentage { get; set; } + } + + public class CashOnDeliveryConfigurationModel : ConfigurationModelBase + { + } + + public class DirectDebitConfigurationModel : ConfigurationModelBase + { + } + + public class InvoiceConfigurationModel : ConfigurationModelBase + { + } + + public class ManualConfigurationModel : ConfigurationModelBase + { + [SmartResourceDisplayName("Plugins.Payments.Manual.Fields.TransactMode")] + public TransactMode TransactMode { get; set; } + public List TransactModeValues { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.Manual.ExcludedCreditCards")] + public string[] ExcludedCreditCards { get; set; } + public List AvailableCreditCards { get; set; } + } + + public class PayInStoreConfigurationModel : ConfigurationModelBase + { + } + + public class PrepaymentConfigurationModel : ConfigurationModelBase + { + } + + public class PurchaseOrderNumberConfigurationModel : ConfigurationModelBase + { + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Models/PaymentInfoModel.cs b/src/Plugins/SmartStore.OfflinePayment/Models/PaymentInfoModel.cs new file mode 100644 index 0000000000..b13dd98de0 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Models/PaymentInfoModel.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.OfflinePayment.Models +{ + public abstract class PaymentInfoModelBase : ModelBase + { + public string DescriptionText { get; set; } + } + + public class CashOnDeliveryPaymentInfoModel : PaymentInfoModelBase + { + } + + public class DirectDebitPaymentInfoModel : PaymentInfoModelBase + { + public DirectDebitPaymentInfoModel() + { + EnterIBAN = "iban"; + } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.EnterIBAN")] + public string EnterIBAN { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitAccountHolder")] + public string DirectDebitAccountHolder { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitAccountNumber")] + public string DirectDebitAccountNumber { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitBankCode")] + public string DirectDebitBankCode { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitCountry")] + public string DirectDebitCountry { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitBankName")] + public string DirectDebitBankName { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitIban")] + public string DirectDebitIban { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.DirectDebit.DirectDebitBic")] + public string DirectDebitBic { get; set; } + + public List Countries { get; set; } + } + + public class InvoicePaymentInfoModel : PaymentInfoModelBase + { + } + + public class ManualPaymentInfoModel : PaymentInfoModelBase + { + public ManualPaymentInfoModel() + { + CreditCardTypes = new List(); + ExpireMonths = new List(); + ExpireYears = new List(); + } + + [SmartResourceDisplayName("Payment.SelectCreditCard")] + [AllowHtml] + public string CreditCardType { get; set; } + [SmartResourceDisplayName("Payment.SelectCreditCard")] + public IList CreditCardTypes { get; set; } + + [SmartResourceDisplayName("Payment.CardholderName")] + [AllowHtml] + public string CardholderName { get; set; } + + [SmartResourceDisplayName("Payment.CardNumber")] + [AllowHtml] + public string CardNumber { get; set; } + + [SmartResourceDisplayName("Payment.ExpirationDate")] + [AllowHtml] + public string ExpireMonth { get; set; } + [SmartResourceDisplayName("Payment.ExpirationDate")] + [AllowHtml] + public string ExpireYear { get; set; } + public IList ExpireMonths { get; set; } + public IList ExpireYears { get; set; } + + [SmartResourceDisplayName("Payment.CardCode")] + [AllowHtml] + public string CardCode { get; set; } + } + + public class PayInStorePaymentInfoModel : PaymentInfoModelBase + { + } + + public class PrepaymentPaymentInfoModel : PaymentInfoModelBase + { + } + + public class PurchaseOrderNumberPaymentInfoModel : PaymentInfoModelBase + { + [SmartResourceDisplayName("Plugins.Payment.PurchaseOrder.PurchaseOrderNumber")] + [AllowHtml] + public string PurchaseOrderNumber { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Plugin.cs b/src/Plugins/SmartStore.OfflinePayment/Plugin.cs new file mode 100644 index 0000000000..f496f22698 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Plugin.cs @@ -0,0 +1,88 @@ +using System; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; +using SmartStore.Services.Configuration; +using SmartStore.OfflinePayment.Settings; +using SmartStore.Services; + +namespace SmartStore.OfflinePayment +{ + + public partial class Plugin : BasePlugin + { + private readonly ICommonServices _services; + + public Plugin(ICommonServices services) + { + this._services = services; + } + + public override void Install() + { + var settings = _services.Settings; + var loc = _services.Localization; + + // add settings + settings.SaveSetting(new CashOnDeliveryPaymentSettings + { + DescriptionText = "@Plugins.Payment.CashOnDelivery.PaymentInfoDescription" + }); + settings.SaveSetting(new InvoicePaymentSettings + { + DescriptionText = "@Plugins.Payment.Invoice.PaymentInfoDescription" + }); + settings.SaveSetting(new PayInStorePaymentSettings + { + DescriptionText = "@Plugins.Payment.PayInStore.PaymentInfoDescription" + }); + settings.SaveSetting(new PrepaymentPaymentSettings + { + DescriptionText = "@Plugins.Payment.Prepayment.PaymentInfoDescription" + }); + settings.SaveSetting(new ManualPaymentSettings + { + DescriptionText = "@Plugins.Payments.Manual.PaymentInfoDescription", + TransactMode = TransactMode.Pending + }); + settings.SaveSetting(new DirectDebitPaymentSettings + { + DescriptionText = "@Plugins.Payments.DirectDebit.PaymentInfoDescription" + }); + settings.SaveSetting(new PurchaseOrderNumberPaymentSettings + { + DescriptionText = "@Plugins.Payments.PurchaseOrderNumber.PaymentInfoDescription", + TransactMode = TransactMode.Pending + }); + + // add resources + loc.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + } + + public override void Uninstall() + { + var settings = _services.Settings; + var loc = _services.Localization; + + // delete settings + settings.DeleteSetting(); + settings.DeleteSetting(); + settings.DeleteSetting(); + settings.DeleteSetting(); + settings.DeleteSetting(); + settings.DeleteSetting(); + + // delete resources + loc.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); + loc.DeleteLocaleStringResources("Plugins.Payment.CashOnDelivery"); + loc.DeleteLocaleStringResources("Plugins.Payment.Invoice"); + loc.DeleteLocaleStringResources("Plugins.Payment.PayInStore"); + loc.DeleteLocaleStringResources("Plugins.Payment.Prepayment"); + loc.DeleteLocaleStringResources("Plugins.Payments.Manual"); + loc.DeleteLocaleStringResources("Plugins.Payments.DirectDebit"); + + base.Uninstall(); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.OfflinePayment/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b8a1d9435b --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.OfflinePayment")] diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/CashOnDeliveryProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/CashOnDeliveryProvider.cs new file mode 100644 index 0000000000..696f1cbabd --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/CashOnDeliveryProvider.cs @@ -0,0 +1,16 @@ +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; + +namespace SmartStore.OfflinePayment +{ + [SystemName("Payments.CashOnDelivery")] + [FriendlyName("Cash On Delivery (COD)")] + [DisplayOrder(1)] + public class CashOnDeliveryPaymentProcessor : OfflinePaymentProviderBase, IConfigurable + { + protected override string GetActionPrefix() + { + return "CashOnDelivery"; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/DirectDebitProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/DirectDebitProvider.cs new file mode 100644 index 0000000000..88cc051a90 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/DirectDebitProvider.cs @@ -0,0 +1,34 @@ +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; +using SmartStore.Services.Payments; + +namespace SmartStore.OfflinePayment +{ + [SystemName("Payments.DirectDebit")] + [FriendlyName("Direct Debit")] + [DisplayOrder(1)] + public class DirectDebitProvider : OfflinePaymentProviderBase, IConfigurable + { + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + result.AllowStoringDirectDebit = true; + result.NewPaymentStatus = PaymentStatus.Pending; + return result; + } + + protected override string GetActionPrefix() + { + return "DirectDebit"; + } + + public override bool RequiresInteraction + { + get + { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/InvoiceProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/InvoiceProvider.cs new file mode 100644 index 0000000000..3608124f58 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/InvoiceProvider.cs @@ -0,0 +1,16 @@ +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; + +namespace SmartStore.OfflinePayment +{ + [SystemName("Payments.Invoice")] + [FriendlyName("Invoice")] + [DisplayOrder(1)] + public class InvoiceProvider : OfflinePaymentProviderBase, IConfigurable + { + protected override string GetActionPrefix() + { + return "Invoice"; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/ManualProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/ManualProvider.cs new file mode 100644 index 0000000000..4f4331c2eb --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/ManualProvider.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; +using SmartStore.Services.Payments; + +namespace SmartStore.OfflinePayment +{ + [SystemName("Payments.Manual")] + [FriendlyName("Credit Card (manual)")] + [DisplayOrder(1)] + public class ManualProvider : OfflinePaymentProviderBase, IConfigurable + { + public static List CreditCardTypes + { + get + { + var creditCardTypes = new List + { + new SelectListItem { Text = "Visa", Value = "Visa" }, + new SelectListItem { Text = "Master Card", Value = "MasterCard" }, + new SelectListItem { Text = "Discover", Value = "Discover" }, + new SelectListItem { Text = "Amex", Value = "Amex" } + }; + return creditCardTypes; + } + } + + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + var settings = CommonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + + result.AllowStoringCreditCardNumber = true; + + switch (settings.TransactMode) + { + case TransactMode.Pending: + result.NewPaymentStatus = PaymentStatus.Pending; + break; + case TransactMode.Authorize: + result.NewPaymentStatus = PaymentStatus.Authorized; + break; + case TransactMode.Paid: + result.NewPaymentStatus = PaymentStatus.Paid; + break; + default: + result.AddError(T("Common.Payment.TranactionTypeNotSupported")); + return result; + } + + return result; + } + + public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + var settings = CommonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + + result.AllowStoringCreditCardNumber = true; + switch (settings.TransactMode) + { + case TransactMode.Pending: + result.NewPaymentStatus = PaymentStatus.Pending; + break; + case TransactMode.Authorize: + result.NewPaymentStatus = PaymentStatus.Authorized; + break; + case TransactMode.Paid: + result.NewPaymentStatus = PaymentStatus.Paid; + break; + default: + { + result.AddError(T("Common.Payment.TranactionTypeNotSupported")); + return result; + } + } + + return result; + } + + public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest cancelPaymentRequest) + { + return new CancelRecurringPaymentResult(); + } + + public override RecurringPaymentType RecurringPaymentType + { + get + { + return RecurringPaymentType.Manual; + } + } + + protected override string GetActionPrefix() + { + return "Manual"; + } + + public override bool RequiresInteraction + { + get + { + return true; + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/OfflinePaymentProviderBase.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/OfflinePaymentProviderBase.cs new file mode 100644 index 0000000000..abe6b73027 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/OfflinePaymentProviderBase.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Web.Routing; +using SmartStore.Core.Configuration; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.OfflinePayment.Controllers; +using SmartStore.OfflinePayment.Settings; +using SmartStore.Services; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; + +namespace SmartStore.OfflinePayment +{ + public abstract class OfflinePaymentProviderBase : PaymentMethodBase + where TSetting : PaymentSettingsBase, ISettings, new() + { + public ICommonServices CommonServices { get; set; } + public IOrderTotalCalculationService OrderTotalCalculationService { get; set; } + + public override Type GetControllerType() + { + return typeof(OfflinePaymentController); + } + + public override PaymentMethodType PaymentMethodType + { + get + { + return PaymentMethodType.Standard; + } + } + + protected abstract string GetActionPrefix(); + + public override decimal GetAdditionalHandlingFee(IList cart) + { + var result = decimal.Zero; + try + { + var settings = CommonServices.Settings.LoadSetting(CommonServices.StoreContext.CurrentStore.Id); + + result = this.CalculateAdditionalFee(OrderTotalCalculationService, cart, settings.AdditionalFee, settings.AdditionalFeePercentage); + } + catch (Exception) + { + } + return result; + } + + public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "{0}Configure".FormatInvariant(GetActionPrefix()); + controllerName = "OfflinePayment"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.OfflinePayment" } }; + } + + public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "{0}PaymentInfo".FormatInvariant(GetActionPrefix()); + controllerName = "OfflinePayment"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.OfflinePayment" } }; + } + + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + result.NewPaymentStatus = PaymentStatus.Pending; + return result; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/PayInStoreProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/PayInStoreProvider.cs new file mode 100644 index 0000000000..6d61b37828 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/PayInStoreProvider.cs @@ -0,0 +1,16 @@ +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; + +namespace SmartStore.OfflinePayment +{ + [SystemName("Payments.PayInStore")] + [FriendlyName("Pay In Store")] + [DisplayOrder(1)] + public class PayInStoreProvider : OfflinePaymentProviderBase, IConfigurable + { + protected override string GetActionPrefix() + { + return "PayInStore"; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/PrepaymentStoreProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/PrepaymentStoreProvider.cs new file mode 100644 index 0000000000..48b36849d4 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/PrepaymentStoreProvider.cs @@ -0,0 +1,16 @@ +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; + +namespace SmartStore.OfflinePayment +{ + [SystemName("Payments.Prepayment")] + [FriendlyName("Prepayment")] + [DisplayOrder(1)] + public class PrepaymentProvider : OfflinePaymentProviderBase, IConfigurable + { + protected override string GetActionPrefix() + { + return "Prepayment"; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Providers/PurchaseOrderNumberProvider.cs b/src/Plugins/SmartStore.OfflinePayment/Providers/PurchaseOrderNumberProvider.cs new file mode 100644 index 0000000000..530dfd1d3a --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Providers/PurchaseOrderNumberProvider.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Web.Routing; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Plugins; +using SmartStore.OfflinePayment.Settings; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; +using SmartStore.Services.Payments; + +namespace SmartStore.OfflinePayment +{ + [SystemName("SmartStore.PurchaseOrderNumber")] + [FriendlyName("Purchase Order Number")] + [DisplayOrder(10)] + public class PurchaseOrderNumberProvider : OfflinePaymentProviderBase, IConfigurable + { + private readonly ISettingService _settingService; + private readonly ILocalizationService _localizationService; + + public PurchaseOrderNumberProvider(ISettingService settingService, ILocalizationService localizationService) + { + _settingService = settingService; + _localizationService = localizationService; + } + + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + var settings = CommonServices.Settings.LoadSetting(processPaymentRequest.StoreId); + + result.AllowStoringCreditCardNumber = true; + switch (settings.TransactMode) + { + case TransactMode.Pending: + result.NewPaymentStatus = PaymentStatus.Pending; + break; + case TransactMode.Authorize: + result.NewPaymentStatus = PaymentStatus.Authorized; + break; + case TransactMode.Paid: + result.NewPaymentStatus = PaymentStatus.Paid; + break; + default: + { + result.AddError(T("Common.Payment.TranactionTypeNotSupported")); + return result; + } + } + + return result; + } + + public override bool RequiresInteraction + { + get + { + return true; + } + } + + protected override string GetActionPrefix() + { + return "PurchaseOrderNumber"; + } + + } +} diff --git a/src/Plugins/SmartStore.OfflinePayment/RouteProvider.cs b/src/Plugins/SmartStore.OfflinePayment/RouteProvider.cs new file mode 100644 index 0000000000..70a8e63318 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/RouteProvider.cs @@ -0,0 +1,26 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.OfflinePayment +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.OfflinePayment", + "Plugins/SmartStore.OfflinePayment/{action}", + new { controller = "OfflinePayment", action = "Index" }, + new[] { "SmartStore.OfflinePayment.Controllers" } + ) + .DataTokens["area"] = "SmartStore.OfflinePayment"; + } + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.OfflinePayment/Settings/OfflinePaymentSettings.cs b/src/Plugins/SmartStore.OfflinePayment/Settings/OfflinePaymentSettings.cs new file mode 100644 index 0000000000..52fbe9bc18 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Settings/OfflinePaymentSettings.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using SmartStore.Core.Configuration; + +namespace SmartStore.OfflinePayment.Settings +{ + public abstract class PaymentSettingsBase : ISettings + { + public string DescriptionText { get; set; } + public decimal AdditionalFee { get; set; } + public bool AdditionalFeePercentage { get; set; } + } + + public class CashOnDeliveryPaymentSettings : PaymentSettingsBase, ISettings + { + } + + public class DirectDebitPaymentSettings : PaymentSettingsBase, ISettings + { + } + + public class InvoicePaymentSettings : PaymentSettingsBase, ISettings + { + } + + public class ManualPaymentSettings : PaymentSettingsBase, ISettings + { + public TransactMode TransactMode { get; set; } + public string ExcludedCreditCards { get; set; } + } + + public class PurchaseOrderNumberPaymentSettings : PaymentSettingsBase, ISettings + { + public TransactMode TransactMode { get; set; } + } + + public class PayInStorePaymentSettings : PaymentSettingsBase, ISettings + { + } + + public class PrepaymentPaymentSettings : PaymentSettingsBase, ISettings + { + } + + /// + /// Represents manual payment processor transaction mode + /// + public enum TransactMode + { + /// + /// Pending + /// + Pending = 0, + + /// + /// Authorize + /// + Authorize = 1, + + /// + /// Paid + /// + Paid = 2 + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/SmartStore.OfflinePayment.csproj b/src/Plugins/SmartStore.OfflinePayment/SmartStore.OfflinePayment.csproj new file mode 100644 index 0000000000..9083d62e99 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/SmartStore.OfflinePayment.csproj @@ -0,0 +1,259 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {692E9D31-1393-47BF-B372-63F671052F89} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.OfflinePayment + SmartStore.OfflinePayment + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.OfflinePayment\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.OfflinePayment\ + TRACE + prompt + 4 + false + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\FluentValidation.5.6.2.0\lib\Net45\FluentValidation.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + Always + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 51143 + / + http://localhost:56865/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Validators/DirectDebitPaymentInfoValidator.cs b/src/Plugins/SmartStore.OfflinePayment/Validators/DirectDebitPaymentInfoValidator.cs new file mode 100644 index 0000000000..7698daebba --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Validators/DirectDebitPaymentInfoValidator.cs @@ -0,0 +1,29 @@ +using FluentValidation; +using SmartStore.OfflinePayment.Models; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Validators; + +namespace SmartStore.OfflinePayment.Validators +{ + public class DirectDebitPaymentInfoValidator : AbstractValidator + { + public DirectDebitPaymentInfoValidator(ILocalizationService localize) + { + RuleFor(x => x.DirectDebitAccountHolder).NotEmpty() + .WithMessage(localize.GetResource("Plugins.Payments.DirectDebit.DirectDebitAccountHolderRequired")); + + + RuleFor(x => x.DirectDebitAccountNumber).NotEmpty().When(x => x.EnterIBAN == "no-iban") + .WithMessage(localize.GetResource("Plugins.Payments.DirectDebit.DirectDebitAccountNumberRequired")); + + RuleFor(x => x.DirectDebitBankCode).NotEmpty().When(x => x.EnterIBAN == "no-iban") + .WithMessage(localize.GetResource("Plugins.Payments.DirectDebit.DirectDebitBankCodeRequired")); + + + RuleFor(x => x.DirectDebitIban).Matches(RegularExpressions.IsIban).When(x => x.EnterIBAN == "iban") + .WithMessage(localize.GetResource("Plugins.Payments.DirectDebit.DirectDebitIbanRequired")); + + RuleFor(x => x.DirectDebitBic).Matches(RegularExpressions.IsBic).When(x => x.EnterIBAN == "iban") + .WithMessage(localize.GetResource("Plugins.Payments.DirectDebit.DirectDebitBicRequired")); + }} +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Validators/ManualPaymentInfoValidator.cs b/src/Plugins/SmartStore.OfflinePayment/Validators/ManualPaymentInfoValidator.cs new file mode 100644 index 0000000000..5fa9e03a2f --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Validators/ManualPaymentInfoValidator.cs @@ -0,0 +1,20 @@ +using FluentValidation; +using SmartStore.OfflinePayment.Models; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Validators; + +namespace SmartStore.OfflinePayment.Validators +{ + public class ManualPaymentInfoValidator : AbstractValidator + { + public ManualPaymentInfoValidator(ILocalizationService localizationService) + { + //useful links: + //http://fluentvalidation.codeplex.com/wikipage?title=Custom&referringTitle=Documentation&ANCHOR#CustomValidator + //http://benjii.me/2010/11/credit-card-validator-attribute-for-asp-net-mvc-3/ + + RuleFor(x => x.CardholderName).NotEmpty().WithMessage(localizationService.GetResource("Payment.CardholderName.Required")); + RuleFor(x => x.CardNumber).IsCreditCard().WithMessage(localizationService.GetResource("Payment.CardNumber.Wrong")); + RuleFor(x => x.CardCode).Matches(@"^[0-9]{3,4}$").WithMessage(localizationService.GetResource("Payment.CardCode.Wrong")); + }} +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/DirectDebitPaymentInfo.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/DirectDebitPaymentInfo.cshtml new file mode 100644 index 0000000000..49303754cf --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/DirectDebitPaymentInfo.cshtml @@ -0,0 +1,98 @@ +@model SmartStore.OfflinePayment.Models.DirectDebitPaymentInfoModel +@using SmartStore.Web.Framework; + +@{ + Layout = ""; +} + +

    + @Html.Raw(Model.DescriptionText) +

    + +@Html.Hidden("OfflinePaymentMethodType", "DirectDebit") + +
    +
    + @Html.LabelFor(model => model.EnterIBAN, new { @class = "control-label" }) +
    + + +
    +
    + +
    + @Html.LabelFor(model => model.DirectDebitAccountHolder, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.DirectDebitAccountHolder, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.DirectDebitAccountHolder) +
    +
    + +
    +
    + @Html.LabelFor(model => model.DirectDebitAccountNumber, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.DirectDebitAccountNumber, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.DirectDebitAccountNumber) +
    +
    +
    + @Html.LabelFor(model => model.DirectDebitBankCode, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.DirectDebitBankCode, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.DirectDebitBankCode) +
    +
    +
    + @Html.LabelFor(model => model.DirectDebitCountry, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.DirectDebitCountry, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.DirectDebitCountry) +
    +
    +
    + +
    +
    + @Html.LabelFor(model => model.DirectDebitIban, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.DirectDebitIban, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.DirectDebitIban) +
    +
    +
    + @Html.LabelFor(model => model.DirectDebitBic, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.DirectDebitBic, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.DirectDebitBic) +
    +
    +
    + +
    + @Html.LabelFor(model => model.DirectDebitBankName, new { @class = "control-label" }) +
    + @Html.TextBoxFor(model => model.DirectDebitBankName, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.DirectDebitBankName) +
    +
    +
    + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/GenericConfigure.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/GenericConfigure.cshtml new file mode 100644 index 0000000000..2ab0e0ac76 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/GenericConfigure.cshtml @@ -0,0 +1,51 @@ +@model SmartStore.OfflinePayment.Models.ConfigurationModelBase +@using SmartStore.Web.Framework; + +@{ + Layout = ""; +} + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.DescriptionText) + + @Html.SettingOverrideCheckbox(model => model.DescriptionText) + @Html.TextAreaFor(model => model.DescriptionText, new { style = "width: 550px; height: 100px;" }) + @Html.ValidationMessageFor(model => model.DescriptionText) +
    + @Html.SmartLabelFor(model => model.AdditionalFee) + + @Html.SettingEditorFor(model => model.AdditionalFee) + @Html.ValidationMessageFor(model => model.AdditionalFee) +
    + @Html.SmartLabelFor(model => model.AdditionalFeePercentage) + + @Html.SettingEditorFor(model => model.AdditionalFeePercentage) + @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) +
      + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/GenericPaymentInfo.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/GenericPaymentInfo.cshtml new file mode 100644 index 0000000000..934a973af0 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/GenericPaymentInfo.cshtml @@ -0,0 +1,9 @@ +@model SmartStore.OfflinePayment.Models.PaymentInfoModelBase + +@{ + Layout = ""; +} + +
    + @Html.Raw(Model.DescriptionText) +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualConfigure.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualConfigure.cshtml new file mode 100644 index 0000000000..89604eb07f --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualConfigure.cshtml @@ -0,0 +1,58 @@ +@model SmartStore.OfflinePayment.Models.ManualConfigurationModel +@using SmartStore.Web.Framework; +@{ + Layout = ""; +} + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.TransactMode) + + @Html.SettingOverrideCheckbox(model => model.TransactMode) + @Html.DropDownListFor(model => model.TransactMode, Model.TransactModeValues) +
    + @Html.SmartLabelFor(model => model.ExcludedCreditCards) + + @Html.SettingOverrideCheckbox(model => model.ExcludedCreditCards) + @Html.ListBoxFor(x => x.ExcludedCreditCards, new MultiSelectList(Model.AvailableCreditCards, "Value", "Text"), new { multiple = "multiple" }) + @Html.ValidationMessageFor(model => model.ExcludedCreditCards) +
    + @Html.SmartLabelFor(model => model.AdditionalFee) + + @Html.SettingEditorFor(model => model.AdditionalFee) + @Html.ValidationMessageFor(model => model.AdditionalFee) +
    + @Html.SmartLabelFor(model => model.AdditionalFeePercentage) + + @Html.SettingEditorFor(model => model.AdditionalFeePercentage) + @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) +
      + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualPaymentInfo.Mobile.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualPaymentInfo.Mobile.cshtml new file mode 100644 index 0000000000..dc1a947aab --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualPaymentInfo.Mobile.cshtml @@ -0,0 +1,27 @@ +@model SmartStore.OfflinePayment.Models.ManualPaymentInfoModel + +@{ + Layout = ""; +} + +@Html.Hidden("OfflinePaymentMethodType", "Manual") + +@Html.SmartLabelFor(model => model.CreditCardTypes, false) +@Html.DropDownListFor(model => model.CreditCardType, Model.CreditCardTypes, new { data_native_menu = "false" }) +@Html.SmartLabelFor(model => model.CardholderName, false) +@Html.TextBoxFor(model => model.CardholderName, new { autocomplete = "off" }) +@Html.ValidationMessageFor(model => model.CardholderName) +@Html.SmartLabelFor(model => model.CardNumber, false) +@Html.TextBoxFor(model => model.CardNumber, new { autocomplete = "off", maxlength = 22 }) +@Html.ValidationMessageFor(model => model.CardNumber) +@Html.SmartLabelFor(model => model.ExpireMonth, false) +
    +
    + @Html.DropDownListFor(model => model.ExpireMonth, Model.ExpireMonths, new { data_native_menu = "false" }) + / + @Html.DropDownListFor(model => model.ExpireYear, Model.ExpireYears, new { data_native_menu = "false" }) +
    +
    +@Html.SmartLabelFor(model => model.CardCode, false) +@Html.TextBoxFor(model => model.CardCode, new { style = "Width: 60px;", autocomplete = "off", maxlength = 4 }) +@Html.ValidationMessageFor(model => model.CardCode) \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualPaymentInfo.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualPaymentInfo.cshtml new file mode 100644 index 0000000000..496e51212d --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/ManualPaymentInfo.cshtml @@ -0,0 +1,45 @@ +@model SmartStore.OfflinePayment.Models.ManualPaymentInfoModel + +@{ + Layout = ""; +} + +@Html.Hidden("OfflinePaymentMethodType", "Manual") + +
    +
    + @Html.LabelFor(model => model.CreditCardTypes, new { @class = "control-label required" }) +
    + @Html.DropDownListFor(model => model.CreditCardType, Model.CreditCardTypes, new { @class = "dropdownlists", style = "min-width: 180px;" }) +
    +
    +
    + @Html.LabelFor(model => model.CardholderName, new { @class = "control-label required" }) +
    + @Html.TextBoxFor(model => model.CardholderName, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.CardholderName) +
    +
    +
    + @Html.LabelFor(model => model.CardNumber, new { @class = "control-label required" }) +
    + @Html.TextBoxFor(model => model.CardNumber, new { autocomplete = "off", maxlength = 22 }) + @Html.ValidationMessageFor(model => model.CardNumber) +
    +
    +
    + @Html.LabelFor(model => model.ExpireMonth, new { @class = "control-label required" }) +
    + @Html.DropDownListFor(model => model.ExpireMonth, Model.ExpireMonths, new { @class = "dropdownlists", style = "min-width: 83px;" }) + / + @Html.DropDownListFor(model => model.ExpireYear, Model.ExpireYears, new { @class = "dropdownlists", style = "min-width: 83px;" }) +
    +
    +
    + @Html.LabelFor(model => model.CardCode, new { @class = "control-label required" }) +
    + @Html.TextBoxFor(model => model.CardCode, new { style = "width: 60px;", autocomplete = "off", maxlength = 4 }) + @Html.ValidationMessageFor(model => model.CardCode) +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.Mobile.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.Mobile.cshtml new file mode 100644 index 0000000000..87191ec5e0 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.Mobile.cshtml @@ -0,0 +1,10 @@ +@{ + Layout = ""; +} +@using SmartStore.Web.Framework; +@using SmartStore.OfflinePayment.Models; +@model PurchaseOrderNumberPaymentInfoModel + +@Html.SmartLabelFor(model => model.PurchaseOrderNumber, false) +@Html.TextBoxFor(model => model.PurchaseOrderNumber, new { autocomplete = "off" }) +@Html.ValidationMessageFor(model => model.PurchaseOrderNumber) diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.cshtml b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.cshtml new file mode 100644 index 0000000000..0d21481f2d --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/OfflinePayment/PurchaseOrderNumberPaymentInfo.cshtml @@ -0,0 +1,20 @@ +@using SmartStore.Web.Framework; +@using SmartStore.OfflinePayment.Models; + +@model PurchaseOrderNumberPaymentInfoModel + +@{ + Layout = ""; +} + +@Html.Hidden("OfflinePaymentMethodType", "PurchaseOrderNumber") + +
    +
    + @Html.LabelFor(model => model.PurchaseOrderNumber, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.PurchaseOrderNumber, new { style = "width: 165px;", autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.PurchaseOrderNumber) +
    +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/Views/Web.config b/src/Plugins/SmartStore.OfflinePayment/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.OfflinePayment/changelog.md b/src/Plugins/SmartStore.OfflinePayment/changelog.md new file mode 100644 index 0000000000..a7d6c374d2 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/changelog.md @@ -0,0 +1,9 @@ +#Release Notes + +##Offline Payment Methods 2.5.0 +###New Features +* Option to exclude credit card types + +##Offline Payment Methods 1.1 +###Improvements +* Multistore configuration \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/packages.config b/src/Plugins/SmartStore.OfflinePayment/packages.config new file mode 100644 index 0000000000..5669aa5ceb --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.OfflinePayment/web.config b/src/Plugins/SmartStore.OfflinePayment/web.config new file mode 100644 index 0000000000..ba87d0f098 --- /dev/null +++ b/src/Plugins/SmartStore.OfflinePayment/web.config @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/Payments.PayPalStandard/branding.png b/src/Plugins/SmartStore.PayPal/Content/branding.png similarity index 100% rename from src/Plugins/Payments.PayPalStandard/branding.png rename to src/Plugins/SmartStore.PayPal/Content/branding.png diff --git a/src/Plugins/SmartStore.PayPal/Content/favicon.png b/src/Plugins/SmartStore.PayPal/Content/favicon.png new file mode 100644 index 0000000000..aa29944a07 Binary files /dev/null and b/src/Plugins/SmartStore.PayPal/Content/favicon.png differ diff --git a/src/Plugins/Payments.PayPalStandard/icon.png b/src/Plugins/SmartStore.PayPal/Content/icon.png similarity index 100% rename from src/Plugins/Payments.PayPalStandard/icon.png rename to src/Plugins/SmartStore.PayPal/Content/icon.png diff --git a/src/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css b/src/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css new file mode 100644 index 0000000000..06e549454c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css @@ -0,0 +1,30 @@ +#paypal-checkout .selection-text { + text-align: right; + font-weight: bold; + padding: 12px 15px 0 0; +} + +#paypal-checkout .form-horizontal { + text-align: right; +} + +#paypal-checkout #paypal-express-button { + cursor: pointer; +} +.paypal-standard-public { + margin-bottom: 10px; +} +.form-horizontal.paypal-direct #s2id_CreditCardType{ + min-width: 180px; +} +.form-horizontal.paypal-direct #CardholderName, +.form-horizontal.paypal-direct #CardNumber{ + width: 165px; +} +.form-horizontal.paypal-direct #s2id_ExpireMonth, +.form-horizontal.paypal-direct #s2id_ExpireYears { + min-width: 83px; +} +.form-horizontal.paypal-direct #CardCode { + width: 60px; +} diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalControllerBase.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalControllerBase.cs new file mode 100644 index 0000000000..06d2c94600 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalControllerBase.cs @@ -0,0 +1,325 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core.Configuration; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Logging; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.Controllers; + +namespace SmartStore.PayPal.Controllers +{ + public abstract class PayPalControllerBase : PaymentControllerBase where TSetting : PayPalSettingsBase, ISettings, new() + { + public PayPalControllerBase( + string systemName, + IPaymentService paymentService, + IOrderService orderService, + IOrderProcessingService orderProcessingService) + { + SystemName = systemName; + PaymentService = paymentService; + OrderService = orderService; + OrderProcessingService = orderProcessingService; + } + + protected string SystemName { get; private set; } + protected IPaymentService PaymentService { get; private set; } + protected IOrderService OrderService { get; private set; } + protected IOrderProcessingService OrderProcessingService { get; private set; } + + protected PaymentStatus GetPaymentStatus(string paymentStatus, string pendingReason, decimal payPalTotal, decimal orderTotal) + { + var result = PaymentStatus.Pending; + + if (paymentStatus == null) + paymentStatus = string.Empty; + + if (pendingReason == null) + pendingReason = string.Empty; + + switch (paymentStatus.ToLowerInvariant()) + { + case "pending": + switch (pendingReason.ToLowerInvariant()) + { + case "authorization": + result = PaymentStatus.Authorized; + break; + default: + result = PaymentStatus.Pending; + break; + } + break; + case "processed": + case "completed": + case "canceled_reversal": + result = PaymentStatus.Paid; + break; + case "denied": + case "expired": + case "failed": + case "voided": + result = PaymentStatus.Voided; + break; + case "reversed": + result = PaymentStatus.Refunded; + break; + case "refunded": + if ((Math.Abs(orderTotal) - Math.Abs(payPalTotal)) > decimal.Zero) + result = PaymentStatus.PartiallyRefunded; + else + result = PaymentStatus.Refunded; + break; + default: + break; + } + return result; + } + + protected bool VerifyIPN(PayPalSettingsBase settings, string formString, out Dictionary values) + { + // settings: multistore context not possible here. we need the custom value to determine what store it is. + + var request = settings.GetPayPalWebRequest(); + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + request.UserAgent = Request.UserAgent; + + var formContent = string.Format("{0}&cmd=_notify-validate", formString); + request.ContentLength = formContent.Length; + + using (var sw = new StreamWriter(request.GetRequestStream(), Encoding.ASCII)) + { + sw.Write(formContent); + } + + string response = null; + using (var sr = new StreamReader(request.GetResponse().GetResponseStream())) + { + response = HttpUtility.UrlDecode(sr.ReadToEnd()); + } + + var success = response.Trim().Equals("VERIFIED", StringComparison.OrdinalIgnoreCase); + + values = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var item in formString.SplitSafe("&")) + { + var line = HttpUtility.UrlDecode(item).TrimSafe(); + var equalIndex = line.IndexOf('='); + + if (equalIndex >= 0) + values.Add(line.Substring(0, equalIndex), line.Substring(equalIndex + 1)); + } + + return success; + } + + [ValidateInput(false)] + public ActionResult IPNHandler() + { + if (!PaymentService.IsPaymentMethodActive(SystemName, Services.StoreContext.CurrentStore.Id)) + throw new SmartException(T("Plugins.Payments.PayPal.NoModuleLoading")); + + var settings = Services.Settings.LoadSetting(); + byte[] param = Request.BinaryRead(Request.ContentLength); + //var strRequest = Encoding.ASCII.GetString(param); + var strRequest = Encoding.UTF8.GetString(param); + Dictionary values; + var sb = new StringBuilder(); + + if (VerifyIPN(settings, strRequest, out values)) + { + #region values + + decimal total = decimal.Zero; + try + { + total = decimal.Parse(values["mc_gross"], new CultureInfo("en-US")); + } + catch { } + + string payer_status = string.Empty; + values.TryGetValue("payer_status", out payer_status); + string payment_status = string.Empty; + values.TryGetValue("payment_status", out payment_status); + string pending_reason = string.Empty; + values.TryGetValue("pending_reason", out pending_reason); + string mc_currency = string.Empty; + values.TryGetValue("mc_currency", out mc_currency); + string txn_id = string.Empty; + values.TryGetValue("txn_id", out txn_id); + string txn_type = string.Empty; + values.TryGetValue("txn_type", out txn_type); + string rp_invoice_id = string.Empty; + values.TryGetValue("rp_invoice_id", out rp_invoice_id); + string payment_type = string.Empty; + values.TryGetValue("payment_type", out payment_type); + string payer_id = string.Empty; + values.TryGetValue("payer_id", out payer_id); + string receiver_id = string.Empty; + values.TryGetValue("receiver_id", out receiver_id); + string invoice = string.Empty; + values.TryGetValue("invoice", out invoice); + string payment_fee = string.Empty; + values.TryGetValue("payment_fee", out payment_fee); + + #endregion + + sb.AppendLine("PayPal IPN:"); + foreach (KeyValuePair kvp in values.Where(x => x.Value.HasValue())) + { + sb.AppendLine(kvp.Key + ": " + kvp.Value); + } + + switch (txn_type) + { + case "recurring_payment_profile_created": + //do nothing here + break; + case "recurring_payment": + #region Recurring payment + { + Guid orderNumberGuid = Guid.Empty; + try + { + orderNumberGuid = new Guid(rp_invoice_id); + } + catch { } + + var initialOrder = OrderService.GetOrderByGuid(orderNumberGuid); + if (initialOrder != null) + { + var newPaymentStatus = GetPaymentStatus(payment_status, pending_reason, total, initialOrder.OrderTotal); + var recurringPayments = OrderService.SearchRecurringPayments(0, 0, initialOrder.Id, null); + + foreach (var rp in recurringPayments) + { + switch (newPaymentStatus) + { + case PaymentStatus.Authorized: + case PaymentStatus.Paid: + { + var recurringPaymentHistory = rp.RecurringPaymentHistory; + if (recurringPaymentHistory.Count == 0) + { + //first payment + var rph = new RecurringPaymentHistory + { + RecurringPaymentId = rp.Id, + OrderId = initialOrder.Id, + CreatedOnUtc = DateTime.UtcNow + }; + rp.RecurringPaymentHistory.Add(rph); + OrderService.UpdateRecurringPayment(rp); + } + else + { + //next payments + OrderProcessingService.ProcessNextRecurringPayment(rp); + } + } + break; + } + } + + Logger.Information(T("Plugins.Payments.PayPal.IpnRecurringPaymentInfo"), new SmartException(sb.ToString())); + } + else + { + Logger.Error(T("Plugins.Payments.PayPal.IpnOrderNotFound"), new SmartException(sb.ToString())); + } + } + #endregion + break; + default: + #region Standard payment + { + var orderNumber = ""; + var orderNumberGuid = Guid.Empty; + values.TryGetValue("custom", out orderNumber); + + try + { + orderNumberGuid = new Guid(orderNumber); + } + catch { } + + var order = OrderService.GetOrderByGuid(orderNumberGuid); + if (order != null) + { + order.HasNewPaymentNotification = true; + + OrderService.AddOrderNote(order, sb.ToString()); + + if (settings.IpnChangesPaymentStatus) + { + var newPaymentStatus = GetPaymentStatus(payment_status, pending_reason, total, order.OrderTotal); + + switch (newPaymentStatus) + { + case PaymentStatus.Pending: + break; + case PaymentStatus.Authorized: + if (OrderProcessingService.CanMarkOrderAsAuthorized(order)) + { + OrderProcessingService.MarkAsAuthorized(order); + } + break; + case PaymentStatus.Paid: + if (OrderProcessingService.CanMarkOrderAsPaid(order)) + { + OrderProcessingService.MarkOrderAsPaid(order); + } + break; + case PaymentStatus.Refunded: + if (OrderProcessingService.CanRefundOffline(order)) + { + OrderProcessingService.RefundOffline(order); + } + break; + case PaymentStatus.PartiallyRefunded: + if (OrderProcessingService.CanPartiallyRefundOffline(order, Math.Abs(total))) + { + OrderProcessingService.PartiallyRefundOffline(order, Math.Abs(total)); + } + break; + case PaymentStatus.Voided: + if (OrderProcessingService.CanVoidOffline(order)) + { + OrderProcessingService.VoidOffline(order); + } + break; + default: + break; + } + } + } + else + { + Logger.Error(T("Plugins.Payments.PayPal.IpnOrderNotFound"), new SmartException(sb.ToString())); + } + } + #endregion + break; + } + } + else + { + Logger.Error(T("Plugins.Payments.PayPal.IpnFailed"), new SmartException(strRequest)); + } + + //nothing should be rendered to visitor + return Content(""); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalDirectController.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalDirectController.cs new file mode 100644 index 0000000000..abdf2df189 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalDirectController.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using SmartStore.Core.Domain.Payments; +using SmartStore.PayPal.Models; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.PayPal.Validators; +using SmartStore.Services; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.PayPal.Controllers +{ + public class PayPalDirectController : PayPalControllerBase + { + private readonly ICommonServices _services; + + public PayPalDirectController( + IPaymentService paymentService, + IOrderService orderService, + IOrderProcessingService orderProcessingService, + PaymentSettings paymentSettings, + ICommonServices services) : base( + PayPalDirectProvider.SystemName, + paymentService, + orderService, + orderProcessingService) + { + _services = services; + } + + private SelectList TransactModeValues(TransactMode selected) + { + return new SelectList(new List + { + new { ID = (int)TransactMode.Authorize, Name = T("Plugins.Payments.PayPalDirect.ModeAuth") }, + new { ID = (int)TransactMode.AuthorizeAndCapture, Name = T("Plugins.Payments.PayPalDirect.ModeAuthAndCapture") } + }, + "ID", "Name", (int)selected); + } + + [AdminAuthorize, ChildActionOnly] + public ActionResult Configure() + { + var model = new PayPalDirectConfigurationModel(); + int storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + model.Copy(settings, true); + + model.TransactModeValues = TransactModeValues(settings.TransactMode); + + model.AvailableSecurityProtocols = PayPalService.GetSecurityProtocols() + .Select(x => new SelectListItem { Value = ((int)x.Key).ToString(), Text = x.Value }) + .ToList(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, Services.Settings); + + return View(model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly] + public ActionResult Configure(PayPalDirectConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return Configure(); + + ModelState.Clear(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + int storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + model.Copy(settings, false); + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, Services.Settings); + + // multistore context not possible, see IPN handling + Services.Settings.SaveSetting(settings, x => x.UseSandbox, 0, false); + + Services.Settings.ClearCache(); + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return Configure(); + } + + public ActionResult PaymentInfo() + { + var model = new PayPalDirectPaymentInfoModel(); + + //CC types + model.CreditCardTypes.Add(new SelectListItem + { + Text = "Visa", + Value = "Visa", + }); + model.CreditCardTypes.Add(new SelectListItem + { + Text = "Master card", + Value = "MasterCard", + }); + model.CreditCardTypes.Add(new SelectListItem + { + Text = "Discover", + Value = "Discover", + }); + model.CreditCardTypes.Add(new SelectListItem + { + Text = "Amex", + Value = "Amex", + }); + + //years + for (int i = 0; i < 15; i++) + { + string year = Convert.ToString(DateTime.Now.Year + i); + model.ExpireYears.Add(new SelectListItem + { + Text = year, + Value = year, + }); + } + + //months + for (int i = 1; i <= 12; i++) + { + string text = (i < 10) ? "0" + i.ToString() : i.ToString(); + model.ExpireMonths.Add(new SelectListItem + { + Text = text, + Value = i.ToString(), + }); + } + + //set postback values + var form = this.GetPaymentData(); + model.CardholderName = form["CardholderName"]; + model.CardNumber = form["CardNumber"]; + model.CardCode = form["CardCode"]; + + var selectedCcType = model.CreditCardTypes.Where(x => x.Value.Equals(form["CreditCardType"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (selectedCcType != null) + selectedCcType.Selected = true; + var selectedMonth = model.ExpireMonths.Where(x => x.Value.Equals(form["ExpireMonth"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (selectedMonth != null) + selectedMonth.Selected = true; + var selectedYear = model.ExpireYears.Where(x => x.Value.Equals(form["ExpireYear"], StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (selectedYear != null) + selectedYear.Selected = true; + + return PartialView(model); + } + + [NonAction] + public override IList ValidatePaymentForm(FormCollection form) + { + var warnings = new List(); + var validator = new PaymentInfoValidator(Services.Localization); + + var model = new PayPalDirectPaymentInfoModel + { + CardholderName = form["CardholderName"], + CardNumber = form["CardNumber"], + CardCode = form["CardCode"], + ExpireMonth = form["ExpireMonth"], + ExpireYear = form["ExpireYear"] + }; + + var validationResult = validator.Validate(model); + if (!validationResult.IsValid) + { + validationResult.Errors.Each(x => warnings.Add(x.ErrorMessage)); + } + return warnings; + } + + [NonAction] + public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) + { + var paymentInfo = new ProcessPaymentRequest(); + + paymentInfo.CreditCardType = form["CreditCardType"]; + paymentInfo.CreditCardName = form["CardholderName"]; + paymentInfo.CreditCardNumber = form["CardNumber"]; + paymentInfo.CreditCardExpireMonth = int.Parse(form["ExpireMonth"]); + paymentInfo.CreditCardExpireYear = int.Parse(form["ExpireYear"]); + paymentInfo.CreditCardCvv2 = form["CardCode"]; + + return paymentInfo; + } + + [NonAction] + public override string GetPaymentSummary(FormCollection form) + { + var number = form["CardNumber"]; + + return "{0}, {1}, {2}".FormatInvariant( + form["CreditCardType"], + form["CardholderName"], + number.Mask(4) + ); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs new file mode 100644 index 0000000000..776d1a210a --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalExpressController.cs @@ -0,0 +1,375 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Web.Mvc; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Logging; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Shipping; +using SmartStore.PayPal.Models; +using SmartStore.PayPal.PayPalSvc; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.PayPal.Validators; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.PayPal.Controllers +{ + public class PayPalExpressController : PayPalControllerBase + { + private readonly OrderSettings _orderSettings; + private readonly ICurrencyService _currencyService; + private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly ICustomerService _customerService; + private readonly IGenericAttributeService _genericAttributeService; + + public PayPalExpressController( + IPaymentService paymentService, + IOrderService orderService, + IOrderProcessingService orderProcessingService, + OrderSettings orderSettings, + ICurrencyService currencyService, + IOrderTotalCalculationService orderTotalCalculationService, + ICustomerService customerService, + IGenericAttributeService genericAttributeService) : base( + PayPalExpressProvider.SystemName, + paymentService, + orderService, + orderProcessingService) + { + _orderSettings = orderSettings; + _currencyService = currencyService; + _orderTotalCalculationService = orderTotalCalculationService; + _customerService = customerService; + _genericAttributeService = genericAttributeService; + } + + private SelectList TransactModeValues(TransactMode selected) + { + return new SelectList(new List + { + new { ID = (int)TransactMode.Authorize, Name = T("Plugins.Payments.PayPalExpress.ModeAuth") }, + new { ID = (int)TransactMode.AuthorizeAndCapture, Name = T("Plugins.Payments.PayPalExpress.ModeAuthAndCapture") } + }, + "ID", "Name", (int)selected); + } + + private string GetCheckoutButtonUrl(PayPalExpressPaymentSettings settings) + { + const string expressCheckoutButton = "https://www.paypalobjects.com/{0}/i/btn/btn_xpressCheckout.gif"; + + HttpWebResponse response = null; + var culture = Services.WorkContext.WorkingLanguage.LanguageCulture; + + if (settings.SecurityProtocol.HasValue) + { + ServicePointManager.SecurityProtocol = settings.SecurityProtocol.Value; + } + + var buttonUrl = expressCheckoutButton.FormatInvariant(culture.Replace("-", "_")); + var request = (HttpWebRequest)WebRequest.Create(buttonUrl); + request.Method = "HEAD"; + + try + { + response = (HttpWebResponse)request.GetResponse(); + return buttonUrl; + } + catch (WebException) + { + /* A WebException will be thrown if the status of the response is not `200 OK` */ + return expressCheckoutButton.FormatInvariant("en_US"); + } + finally + { + if (response != null) + { + response.Close(); + } + } + } + + [AdminAuthorize, ChildActionOnly] + public ActionResult Configure() + { + var model = new PayPalExpressConfigurationModel(); + int storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + model.Copy(settings, true); + + model.TransactModeValues = TransactModeValues(settings.TransactMode); + + model.AvailableSecurityProtocols = PayPalService.GetSecurityProtocols() + .Select(x => new SelectListItem { Value = ((int)x.Key).ToString(), Text = x.Value }) + .ToList(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, Services.Settings); + + return View(model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly] + public ActionResult Configure(PayPalExpressConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return Configure(); + + ModelState.Clear(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + int storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + model.Copy(settings, false); + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, Services.Settings); + + // multistore context not possible, see IPN handling + Services.Settings.SaveSetting(settings, x => x.UseSandbox, 0, false); + + Services.Settings.ClearCache(); + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return Configure(); + } + + public ActionResult PaymentInfo() + { + var model = new PayPalExpressPaymentInfoModel(); + model.CurrentPageIsBasket = ControllerContext.ParentActionViewContext.RequestContext.RouteData.IsRouteEqual("ShoppingCart", "Cart"); + + if (model.CurrentPageIsBasket) + { + var settings = Services.Settings.LoadSetting(Services.StoreContext.CurrentStore.Id); + + model.SubmitButtonImageUrl = GetCheckoutButtonUrl(settings); + } + + return PartialView(model); + } + + public ActionResult MiniShoppingCart() + { + var settings = Services.Settings.LoadSetting(Services.StoreContext.CurrentStore.Id); + + if (settings.ShowButtonInMiniShoppingCart) + { + var model = new PayPalExpressPaymentInfoModel(); + model.SubmitButtonImageUrl = GetCheckoutButtonUrl(settings); + + return PartialView(model); + } + + return new EmptyResult(); + } + + public ActionResult SubmitButton() + { + try + { + //user validation + if ((Services.WorkContext.CurrentCustomer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed)) + return RedirectToRoute("Login"); + + var store = Services.StoreContext.CurrentStore; + var customer = Services.WorkContext.CurrentCustomer; + var settings = Services.Settings.LoadSetting(store.Id); + var cart = Services.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, store.Id); + + if (cart.Count == 0) + return RedirectToRoute("ShoppingCart"); + + if (String.IsNullOrEmpty(settings.ApiAccountName)) + throw new ApplicationException("PayPal API Account Name is not set"); + if (String.IsNullOrEmpty(settings.ApiAccountPassword)) + throw new ApplicationException("PayPal API Password is not set"); + if (String.IsNullOrEmpty(settings.Signature)) + throw new ApplicationException("PayPal API Signature is not set"); + + var provider = PaymentService.LoadPaymentMethodBySystemName(PayPalExpressProvider.SystemName, true); + var processor = provider != null ? provider.Value as PayPalExpressProvider : null; + if (processor == null) + throw new SmartException("PayPal Express Checkout module cannot be loaded"); + + var processPaymentRequest = new PayPalProcessPaymentRequest(); + + processPaymentRequest.StoreId = store.Id; + + //Get sub-total and discounts that apply to sub-total + decimal orderSubTotalDiscountAmountBase = decimal.Zero; + Discount orderSubTotalAppliedDiscount = null; + decimal subTotalWithoutDiscountBase = decimal.Zero; + decimal subTotalWithDiscountBase = decimal.Zero; + + _orderTotalCalculationService.GetShoppingCartSubTotal(cart, + out orderSubTotalDiscountAmountBase, out orderSubTotalAppliedDiscount, out subTotalWithoutDiscountBase, out subTotalWithDiscountBase); + + //order total + decimal resultTemp = decimal.Zero; + resultTemp += subTotalWithDiscountBase; + + //Get discounts that apply to Total + Discount appliedDiscount = null; + var discountAmount = _orderTotalCalculationService.GetOrderTotalDiscount(customer, resultTemp, out appliedDiscount); + + //if the current total is less than the discount amount, we only make the discount equal to the current total + if (resultTemp < discountAmount) + discountAmount = resultTemp; + + //reduce subtotal + resultTemp -= discountAmount; + + if (resultTemp < decimal.Zero) + resultTemp = decimal.Zero; + + decimal tempDiscount = discountAmount + orderSubTotalDiscountAmountBase; + + resultTemp = _currencyService.ConvertFromPrimaryStoreCurrency(resultTemp, Services.WorkContext.WorkingCurrency); + if (tempDiscount > decimal.Zero) + { + tempDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(tempDiscount, Services.WorkContext.WorkingCurrency); + } + + processPaymentRequest.PaymentMethodSystemName = PayPalExpressProvider.SystemName; + processPaymentRequest.OrderTotal = resultTemp; + processPaymentRequest.Discount = tempDiscount; + processPaymentRequest.IsRecurringPayment = false; + + //var selectedPaymentMethodSystemName = _workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.SelectedPaymentMethod, _storeContext.CurrentStore.Id); + + processPaymentRequest.CustomerId = Services.WorkContext.CurrentCustomer.Id; + this.Session["OrderPaymentInfo"] = processPaymentRequest; + + var resp = processor.SetExpressCheckout(processPaymentRequest, cart); + + if (resp.Ack == AckCodeType.Success) + { + processPaymentRequest.PaypalToken = resp.Token; + processPaymentRequest.OrderGuid = new Guid(); + processPaymentRequest.IsShippingMethodSet = ControllerContext.RouteData.IsRouteEqual("ShoppingCart", "Cart"); + this.Session["OrderPaymentInfo"] = processPaymentRequest; + + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedPaymentMethod, PayPalExpressProvider.SystemName, store.Id); + + var result = new RedirectResult(String.Format(settings.GetPayPalUrl() + "?cmd=_express-checkout&useraction=commit&token={0}", resp.Token)); + + return result; + } + else + { + var error = new StringBuilder("We apologize, but an error has occured.
    "); + foreach (var errormsg in resp.Errors) + { + error.AppendLine(String.Format("{0} | {1} | {2}", errormsg.ErrorCode, errormsg.ShortMessage, errormsg.LongMessage)); + } + + Logger.InsertLog(LogLevel.Error, resp.Errors[0].ShortMessage, resp.Errors[0].LongMessage, customer); + + NotifyError(error.ToString(), false); + + return RedirectToAction("Cart", "ShoppingCart", new { area = "" }); + } + } + catch (Exception ex) + { + Logger.InsertLog(LogLevel.Error, ex.Message, ex.StackTrace, Services.WorkContext.CurrentCustomer); + + NotifyError(ex.Message, false); + + return RedirectToAction("Cart", "ShoppingCart", new { area = "" }); + + } + } + + public ActionResult GetDetails(string token) + { + var provider = PaymentService.LoadPaymentMethodBySystemName("Payments.PayPalExpress", true); + var processor = provider != null ? provider.Value as PayPalExpressProvider : null; + if (processor == null) + throw new SmartException("PayPal Express module cannot be loaded"); + + var resp = processor.GetExpressCheckoutDetails(token); + + if (resp.Ack == AckCodeType.Success) + { + var paymentInfo = this.Session["OrderPaymentInfo"] as ProcessPaymentRequest; + paymentInfo = processor.SetCheckoutDetails(paymentInfo, resp.GetExpressCheckoutDetailsResponseDetails); + this.Session["OrderPaymentInfo"] = paymentInfo; + + var store = Services.StoreContext.CurrentStore; + var customer = _customerService.GetCustomerById(paymentInfo.CustomerId); + + Services.WorkContext.CurrentCustomer = customer; + _customerService.UpdateCustomer(Services.WorkContext.CurrentCustomer); + + var selectedShippingOption = Services.WorkContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.SelectedShippingOption, store.Id); + if (selectedShippingOption != null) + { + return RedirectToAction("Confirm", "Checkout", new { area = "" }); + } + else + { + //paymentInfo.RequiresPaymentWorkflow = false; + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedPaymentMethod, paymentInfo.PaymentMethodSystemName, store.Id); + _customerService.UpdateCustomer(customer); + + return RedirectToAction("BillingAddress", "Checkout", new { area = "" }); + } + } + else + { + var error = new StringBuilder("We apologize, but an error has occured.
    "); + foreach (var errormsg in resp.Errors) + { + error.AppendLine(String.Format("{0} | {1} | {2}", errormsg.ErrorCode, errormsg.ShortMessage, errormsg.LongMessage)); + } + + Logger.InsertLog(LogLevel.Error, resp.Errors[0].ShortMessage, resp.Errors[0].LongMessage, Services.WorkContext.CurrentCustomer); + + NotifyError(error.ToString(), false); + + return RedirectToAction("Cart", "ShoppingCart", new { area = "" }); + } + } + + [NonAction] + public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) + { + var paymentInfo = new ProcessPaymentRequest(); + return paymentInfo; + } + + [NonAction] + public override IList ValidatePaymentForm(FormCollection form) + { + var warnings = new List(); + + var validator = new PayPalExpressPaymentInfoValidator(Services.Localization); + var model = new PayPalExpressPaymentInfoModel(); + + var validationResult = validator.Validate(model); + + if (!validationResult.IsValid) + { + foreach (var error in validationResult.Errors) + { + warnings.Add(error.ErrorMessage); + } + } + + return warnings; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalPlusController.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalPlusController.cs new file mode 100644 index 0000000000..7a835f3d19 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalPlusController.cs @@ -0,0 +1,408 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Html; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.Models; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.PayPal.Validators; +using SmartStore.Services.Catalog; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; +using SmartStore.Services.Localization; +using SmartStore.Services.Payments; +using SmartStore.Services.Tax; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Plugins; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.PayPal.Controllers +{ + public class PayPalPlusController : PayPalRestApiControllerBase + { + private readonly HttpContextBase _httpContext; + private readonly PluginMediator _pluginMediator; + private readonly IGenericAttributeService _genericAttributeService; + private readonly IPaymentService _paymentService; + private readonly ITaxService _taxService; + private readonly ICurrencyService _currencyService; + private readonly IPriceFormatter _priceFormatter; + + public PayPalPlusController( + HttpContextBase httpContext, + PluginMediator pluginMediator, + IPayPalService payPalService, + IGenericAttributeService genericAttributeService, + IPaymentService paymentService, + ITaxService taxService, + ICurrencyService currencyService, + IPriceFormatter priceFormatter) : base( + PayPalPlusProvider.SystemName, + payPalService) + { + _httpContext = httpContext; + _pluginMediator = pluginMediator; + _genericAttributeService = genericAttributeService; + _paymentService = paymentService; + _taxService = taxService; + _currencyService = currencyService; + _priceFormatter = priceFormatter; + } + + private string GetPaymentMethodName(Provider provider) + { + if (provider != null) + { + var name = _pluginMediator.GetLocalizedFriendlyName(provider.Metadata); + + if (name.IsEmpty()) + name = provider.Metadata.FriendlyName; + + if (name.IsEmpty()) + name = provider.Metadata.SystemName; + + return name; + } + return ""; + } + + private string GetPaymentFee(Provider provider, List cart) + { + var paymentMethodAdditionalFee = provider.Value.GetAdditionalHandlingFee(cart); + var rateBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, Services.WorkContext.CurrentCustomer); + var rate = _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, Services.WorkContext.WorkingCurrency); + + if (rate != decimal.Zero) + { + return _priceFormatter.FormatPaymentMethodAdditionalFee(rate, true); + } + return ""; + } + + private PayPalPlusCheckoutModel.ThirdPartyPaymentMethod GetThirdPartyPaymentMethodModel( + Provider provider, + PayPalPlusPaymentSettings settings, + Store store) + { + var model = new PayPalPlusCheckoutModel.ThirdPartyPaymentMethod(); + model.MethodName = GetPaymentMethodName(provider); + model.RedirectUrl = Url.Action("CheckoutReturn", "PayPalPlus", new { area = Plugin.SystemName, systemName = provider.Metadata.SystemName }, store.SslEnabled ? "https" : "http"); + + try + { + if (settings.DisplayPaymentMethodDescription) + { + // not the short description, the full description is intended for frontend + var paymentMethod = _paymentService.GetPaymentMethodBySystemName(provider.Metadata.SystemName); + if (paymentMethod != null) + { + var description = paymentMethod.GetLocalized(x => x.FullDescription); + if (description.HasValue()) + { + description = HtmlUtils.ConvertHtmlToPlainText(description); + description = HtmlUtils.StripTags(HttpUtility.HtmlDecode(description)); + + if (description.HasValue()) + model.Description = description.EncodeJsString(); + } + } + } + } + catch { } + + try + { + if (settings.DisplayPaymentMethodLogo && provider.Metadata.PluginDescriptor != null && store.SslEnabled) + { + var brandImageUrl = _pluginMediator.GetBrandImageUrl(provider.Metadata); + if (brandImageUrl.HasValue()) + { + if (brandImageUrl.StartsWith("~")) + brandImageUrl = brandImageUrl.Substring(1); + + var uri = new UriBuilder(Uri.UriSchemeHttps, Request.Url.Host, -1, brandImageUrl); + model.ImageUrl = uri.ToString(); + } + } + } + catch { } + + return model; + } + + [NonAction] + public override IList ValidatePaymentForm(FormCollection form) + { + var warnings = new List(); + return warnings; + } + + [NonAction] + public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) + { + var paymentInfo = new ProcessPaymentRequest(); + return paymentInfo; + } + + [AdminAuthorize, ChildActionOnly] + public ActionResult Configure() + { + var storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + var model = new PayPalPlusConfigurationModel + { + ConfigGroups = T("Plugins.SmartStore.PayPal.ConfigGroups").Text.SplitSafe(";") + }; + + model.AvailableSecurityProtocols = PayPal.Services.PayPalService.GetSecurityProtocols() + .Select(x => new SelectListItem { Value = ((int)x.Key).ToString(), Text = x.Value }) + .ToList(); + + // it's better to also offer inactive methods here but filter them out in frontend + var methods = _paymentService.LoadAllPaymentMethods(storeScope); + + model.AvailableThirdPartyPaymentMethods = methods + .Where(x => + x.Metadata.PluginDescriptor.SystemName != Plugin.SystemName && + !x.Value.RequiresInteraction && + (x.Metadata.PluginDescriptor.SystemName == "SmartStore.OfflinePayment" || x.Value.PaymentMethodType == PaymentMethodType.Redirection)) + .Select(x => new SelectListItem { Value = x.Metadata.SystemName, Text = GetPaymentMethodName(x) }) + .ToList(); + + + model.Copy(settings, true); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, Services.Settings); + + return View(model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly] + public ActionResult Configure(PayPalPlusConfigurationModel model, FormCollection form) + { + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + var storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + var oldClientId = settings.ClientId; + var oldSecret = settings.Secret; + var oldProfileId = settings.ExperienceProfileId; + + var validator = new PayPalPlusConfigValidator(Services.Localization, x => + { + return storeScope == 0 || storeDependingSettingHelper.IsOverrideChecked(settings, x, form); + }); + + validator.Validate(model, ModelState); + + if (!ModelState.IsValid) + return Configure(); + + ModelState.Clear(); + + model.Copy(settings, false); + + // credentials changed: reset profile and webhook id to avoid errors + if (!oldClientId.IsCaseInsensitiveEqual(settings.ClientId) || !oldSecret.IsCaseInsensitiveEqual(settings.Secret)) + { + if (oldProfileId.IsCaseInsensitiveEqual(settings.ExperienceProfileId)) + settings.ExperienceProfileId = null; + + settings.WebhookId = null; + } + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, Services.Settings); + + Services.Settings.SaveSetting(settings, x => x.UseSandbox, 0, false); + + Services.Settings.ClearCache(); + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return Configure(); + } + + public ActionResult PaymentInfo() + { + return new EmptyResult(); + } + + public ActionResult PaymentWall() + { + var sb = new StringBuilder(); + var store = Services.StoreContext.CurrentStore; + var customer = Services.WorkContext.CurrentCustomer; + var language = Services.WorkContext.WorkingLanguage; + var settings = Services.Settings.LoadSetting(store.Id); + var cart = customer.GetCartItems(ShoppingCartType.ShoppingCart, store.Id); + + var pppMethod = _paymentService.GetPaymentMethodBySystemName(PayPalPlusProvider.SystemName); + var pppProvider = _paymentService.LoadPaymentMethodBySystemName(PayPalPlusProvider.SystemName, false, store.Id); + + var methods = _paymentService.LoadActivePaymentMethods(customer, cart, store.Id, null, false); + var session = _httpContext.GetPayPalSessionData(); + + var model = new PayPalPlusCheckoutModel(); + model.ThirdPartyPaymentMethods = new List(); + model.UseSandbox = settings.UseSandbox; + model.LanguageCulture = (language.LanguageCulture ?? "de_DE").Replace("-", "_"); + model.PayPalPlusPseudoMessageFlag = TempData["PayPalPlusPseudoMessageFlag"] as string; + model.PayPalFee = GetPaymentFee(pppProvider, cart); + model.HasAnyFees = model.PayPalFee.HasValue(); + + if (pppMethod != null) + { + model.FullDescription = pppMethod.GetLocalized(x => x.FullDescription, language.Id); + } + + if (customer.BillingAddress != null && customer.BillingAddress.Country != null) + { + model.BillingAddressCountryCode = customer.BillingAddress.Country.TwoLetterIsoCode; + } + + foreach (var systemName in settings.ThirdPartyPaymentMethods) + { + var provider = methods.FirstOrDefault(x => x.Metadata.SystemName == systemName); + if (provider != null) + { + var methodModel = GetThirdPartyPaymentMethodModel(provider, settings, store); + model.ThirdPartyPaymentMethods.Add(methodModel); + + var fee = GetPaymentFee(provider, cart); + if (fee.HasValue()) + model.HasAnyFees = true; + if (sb.Length > 0) + sb.Append(", "); + sb.AppendFormat("['{0}','{1}']", methodModel.MethodName.Replace("'", ""), fee); + } + } + + model.ThirdPartyFees = sb.ToString(); + + // we must create a new paypal payment each time the payment wall is rendered because otherwise patch payment can fail + // with "Item amount must add up to specified amount subtotal (or total if amount details not specified)". + session.PaymentId = null; + session.ApprovalUrl = null; + + var result = PayPalService.EnsureAccessToken(session, settings); + if (result.Success) + { + var protocol = (store.SslEnabled ? "https" : "http"); + var returnUrl = Url.Action("CheckoutReturn", "PayPalPlus", new { area = Plugin.SystemName }, protocol); + var cancelUrl = Url.Action("CheckoutCancel", "PayPalPlus", new { area = Plugin.SystemName }, protocol); + + result = PayPalService.CreatePayment(settings, session, cart, PayPalPlusProvider.SystemName, returnUrl, cancelUrl); + if (result.Success && result.Json != null) + { + foreach (var link in result.Json.links) + { + if (((string)link.rel).IsCaseInsensitiveEqual("approval_url")) + { + session.PaymentId = result.Id; + session.ApprovalUrl = link.href; + break; + } + } + } + else + { + model.ErrorMessage = result.ErrorMessage; + } + } + else + { + model.ErrorMessage = result.ErrorMessage; + } + + model.ApprovalUrl = session.ApprovalUrl; + + return View(model); + } + + [HttpPost] + public ActionResult PatchShipping() + { + var store = Services.StoreContext.CurrentStore; + var customer = Services.WorkContext.CurrentCustomer; + var settings = Services.Settings.LoadSetting(store.Id); + var cart = customer.GetCartItems(ShoppingCartType.ShoppingCart, store.Id); + var session = HttpContext.GetPayPalSessionData(); + + var apiResult = PayPalService.PatchShipping(settings, session, cart, PayPalPlusProvider.SystemName); + + return new JsonResult { Data = new { success = apiResult.Success, error = apiResult.ErrorMessage } }; + } + + public ActionResult CheckoutCompleted() + { + var instruct = _httpContext.Session[PayPalPlusProvider.CheckoutCompletedKey] as string; + + if (instruct.HasValue()) + { + return Content(instruct); + } + + return new EmptyResult(); + } + + [ValidateInput(false)] + public ActionResult CheckoutReturn(string systemName, string paymentId, string PayerID) + { + // Request.QueryString: + // paymentId: PAY-0TC88803RP094490KK4KM6AI, token: EC-5P379249AL999154U, PayerID: 5L9K773HHJLPN + + var customer = Services.WorkContext.CurrentCustomer; + var store = Services.StoreContext.CurrentStore; + var settings = Services.Settings.LoadSetting(store.Id); + var session = _httpContext.GetPayPalSessionData(); + + if (systemName.IsEmpty()) + systemName = PayPalPlusProvider.SystemName; + + if (paymentId.HasValue() && session.PaymentId.IsEmpty()) + session.PaymentId = paymentId; + + session.PayerId = PayerID; + + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedPaymentMethod, systemName, store.Id); + + var paymentRequest = _httpContext.Session["OrderPaymentInfo"] as ProcessPaymentRequest; + if (paymentRequest == null) + { + _httpContext.Session["OrderPaymentInfo"] = new ProcessPaymentRequest + { + PaymentMethodSystemName = systemName + }; + } + + return RedirectToAction("Confirm", "Checkout", new { area = "" }); + } + + [ValidateInput(false)] + public ActionResult CheckoutCancel() + { + // Request.QueryString: + // token: EC-6JM38216F6718012L, ppp_msg: 1 + + // undocumented + var pseudoMessageFlag = Request.QueryString["ppp_msg"] as string; + + if (pseudoMessageFlag.HasValue()) + { + TempData["PayPalPlusPseudoMessageFlag"] = pseudoMessageFlag; + } + + // back to where he came from + return RedirectToAction("PaymentMethod", "Checkout", new { area = "" }); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalRestApiControllerBase.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalRestApiControllerBase.cs new file mode 100644 index 0000000000..8d5818e5d5 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalRestApiControllerBase.cs @@ -0,0 +1,177 @@ +using System; +using System.IO; +using System.Net; +using System.Web.Mvc; +using SmartStore.Core.Configuration; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; + +namespace SmartStore.PayPal.Controllers +{ + public abstract class PayPalRestApiControllerBase : PaymentControllerBase where TSetting : PayPalApiSettingsBase, ISettings, new() + { + public PayPalRestApiControllerBase( + string systemName, + IPayPalService payPalService) + { + SystemName = systemName; + PayPalService = payPalService; + } + + private string GetControllerName() + { + return GetType().Name.Replace("Controller", ""); + } + + protected string SystemName { get; private set; } + protected IPayPalService PayPalService { get; private set; } + + [AdminAuthorize] + public ActionResult UpsertExperienceProfile() + { + var storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + var store = Services.StoreService.GetStoreById(storeScope == 0 ? Services.StoreContext.CurrentStore.Id : storeScope); + var session = new PayPalSessionData(); + + var result = PayPalService.EnsureAccessToken(session, settings); + if (result.Success) + { + result = PayPalService.UpsertCheckoutExperience(settings, session, store); + if (result.Success && result.Id.HasValue()) + { + settings.ExperienceProfileId = result.Id; + Services.Settings.SaveSetting(settings, x => x.ExperienceProfileId, storeScope, false); + Services.Settings.ClearCache(); + } + } + + if (result.Success) + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + else + NotifyError(result.ErrorMessage); + + return RedirectToAction("ConfigureProvider", "Plugin", new { area = "admin", systemName = SystemName }); + } + + [AdminAuthorize] + public ActionResult DeleteExperienceProfile() + { + var storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + var session = new PayPalSessionData(); + + var result = PayPalService.EnsureAccessToken(session, settings); + if (result.Success) + { + result = PayPalService.DeleteCheckoutExperience(settings, session); + if (result.Success) + { + settings.ExperienceProfileId = null; + Services.Settings.SaveSetting(settings, x => x.ExperienceProfileId, storeScope, false); + Services.Settings.ClearCache(); + } + } + + if (result.Success) + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + else + NotifyError(result.ErrorMessage); + + return RedirectToAction("ConfigureProvider", "Plugin", new { area = "admin", systemName = SystemName }); + } + + [AdminAuthorize] + public ActionResult CreateWebhook() + { + var settings = Services.Settings.LoadSetting(); + var session = new PayPalSessionData(); + + if (settings.WebhookId.HasValue()) + { + var unused = PayPalService.DeleteWebhook(settings, session); + + Services.Settings.SaveSetting(settings, x => x.WebhookId, 0, false); + } + + var url = Url.Action("Webhook", GetControllerName(), new { area = Plugin.SystemName }, "https"); + + var result = PayPalService.EnsureAccessToken(session, settings); + if (result.Success) + { + result = PayPalService.CreateWebhook(settings, session, url); + if (result.Success) + { + settings.WebhookId = result.Id; + Services.Settings.SaveSetting(settings, x => x.WebhookId, 0, false); + } + } + + Services.Settings.ClearCache(); + + if (result.Success) + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + else + NotifyError(result.ErrorMessage); + + return RedirectToAction("ConfigureProvider", "Plugin", new { area = "admin", systemName = SystemName }); + } + + [AdminAuthorize] + public ActionResult DeleteWebhook() + { + var settings = Services.Settings.LoadSetting(); + var session = new PayPalSessionData(); + + if (settings.WebhookId.HasValue()) + { + var result = PayPalService.EnsureAccessToken(session, settings); + if (result.Success) + { + result = PayPalService.DeleteWebhook(settings, session); + if (result.Success) + { + settings.WebhookId = null; + Services.Settings.SaveSetting(settings, x => x.WebhookId, 0, false); + Services.Settings.ClearCache(); + } + } + + if (result.Success) + NotifySuccess(T("Admin.Common.TaskSuccessfullyProcessed")); + else + NotifyError(result.ErrorMessage); + } + + return RedirectToAction("ConfigureProvider", "Plugin", new { area = "admin", systemName = SystemName }); + } + + [ValidateInput(false)] + public ActionResult Webhook() + { + HttpStatusCode result = HttpStatusCode.OK; + + try + { + string json = null; + using (var reader = new StreamReader(Request.InputStream)) + { + json = reader.ReadToEnd(); + } + + var settings = Services.Settings.LoadSetting(); + + result = PayPalService.ProcessWebhook(settings, Request.Headers, json, PayPalPlusProvider.SystemName); + } + catch (Exception exception) + { + PayPalService.LogError(exception, isWarning: true); + } + + return new HttpStatusCodeResult(result); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Controllers/PayPalStandardController.cs b/src/Plugins/SmartStore.PayPal/Controllers/PayPalStandardController.cs new file mode 100644 index 0000000000..e007d86dfc --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Controllers/PayPalStandardController.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Web.Mvc; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Logging; +using SmartStore.PayPal.Models; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Settings; + +namespace SmartStore.PayPal.Controllers +{ + public class PayPalStandardController : PayPalControllerBase + { + public PayPalStandardController( + IPaymentService paymentService, + IOrderService orderService, + IOrderProcessingService orderProcessingService) : base( + PayPalStandardProvider.SystemName, + paymentService, + orderService, + orderProcessingService) + { + } + + [AdminAuthorize, ChildActionOnly] + public ActionResult Configure() + { + var model = new PayPalStandardConfigurationModel(); + int storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + model.Copy(settings, true); + + model.AvailableSecurityProtocols = PayPalService.GetSecurityProtocols() + .Select(x => new SelectListItem { Value = ((int)x.Key).ToString(), Text = x.Value }) + .ToList(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + storeDependingSettingHelper.GetOverrideKeys(settings, model, storeScope, Services.Settings); + + return View(model); + } + + [HttpPost, AdminAuthorize, ChildActionOnly] + public ActionResult Configure(PayPalStandardConfigurationModel model, FormCollection form) + { + if (!ModelState.IsValid) + return Configure(); + + ModelState.Clear(); + + var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); + int storeScope = this.GetActiveStoreScopeConfiguration(Services.StoreService, Services.WorkContext); + var settings = Services.Settings.LoadSetting(storeScope); + + model.Copy(settings, false); + + storeDependingSettingHelper.UpdateSettings(settings, form, storeScope, Services.Settings); + + // multistore context not possible, see IPN handling + Services.Settings.SaveSetting(settings, x => x.UseSandbox, 0, false); + + Services.Settings.ClearCache(); + NotifySuccess(T("Admin.Common.DataSuccessfullySaved")); + + return Configure(); + } + + public ActionResult PaymentInfo() + { + return PartialView(); + } + + [NonAction] + public override IList ValidatePaymentForm(FormCollection form) + { + var warnings = new List(); + return warnings; + } + + [NonAction] + public override ProcessPaymentRequest GetPaymentInfo(FormCollection form) + { + var paymentInfo = new ProcessPaymentRequest(); + return paymentInfo; + } + + [ValidateInput(false)] + public ActionResult PDTHandler(FormCollection form) + { + Dictionary values; + var tx = Services.WebHelper.QueryString("tx"); + var utcNow = DateTime.UtcNow; + var orderNumberGuid = Guid.Empty; + var orderNumber = string.Empty; + var total = decimal.Zero; + string response; + + var provider = PaymentService.LoadPaymentMethodBySystemName(SystemName, true); + var processor = (provider != null ? provider.Value as PayPalStandardProvider : null); + if (processor == null) + throw new SmartException(T("Plugins.Payments.PayPal.NoModuleLoading")); + + var settings = Services.Settings.LoadSetting(); + + if (processor.GetPDTDetails(tx, settings, out values, out response)) + { + values.TryGetValue("custom", out orderNumber); + + try + { + orderNumberGuid = new Guid(orderNumber); + } + catch { } + + var order = OrderService.GetOrderByGuid(orderNumberGuid); + + if (order != null) + { + try + { + total = decimal.Parse(values["mc_gross"], new CultureInfo("en-US")); + } + catch (Exception exc) + { + Logger.Error(T("Plugins.Payments.PayPalStandard.FailedGetGross"), exc); + } + + string payer_status = string.Empty; + values.TryGetValue("payer_status", out payer_status); + string payment_status = string.Empty; + values.TryGetValue("payment_status", out payment_status); + string pending_reason = string.Empty; + values.TryGetValue("pending_reason", out pending_reason); + string mc_currency = string.Empty; + values.TryGetValue("mc_currency", out mc_currency); + string txn_id = string.Empty; + values.TryGetValue("txn_id", out txn_id); + string payment_type = string.Empty; + values.TryGetValue("payment_type", out payment_type); + string payer_id = string.Empty; + values.TryGetValue("payer_id", out payer_id); + string receiver_id = string.Empty; + values.TryGetValue("receiver_id", out receiver_id); + string invoice = string.Empty; + values.TryGetValue("invoice", out invoice); + string payment_fee = string.Empty; + values.TryGetValue("payment_fee", out payment_fee); + + var paymentNote = T("Plugins.Payments.PayPalStandard.PaymentNote", + total, mc_currency, payer_status, payment_status, pending_reason, txn_id, payment_type, payer_id, receiver_id, invoice, payment_fee); + + OrderService.AddOrderNote(order, paymentNote); + + // validate order total... you may get differences if settings.PassProductNamesAndTotals is true + if (settings.PdtValidateOrderTotal) + { + var roundedTotal = Math.Round(total, 2); + var roundedOrderTotal = Math.Round(order.OrderTotal, 2); + var roundedDifference = Math.Abs(roundedTotal - roundedOrderTotal); + + if (!roundedTotal.Equals(roundedOrderTotal)) + { + var message = T("Plugins.Payments.PayPalStandard.UnequalTotalOrder", + total, roundedOrderTotal.FormatInvariant(), order.OrderTotal, roundedDifference.FormatInvariant()); + + if (settings.PdtValidateOnlyWarn) + { + OrderService.AddOrderNote(order, message); + } + else + { + Logger.Error(message); + + return RedirectToAction("Index", "Home", new { area = "" }); + } + } + } + + // mark order as paid + var newPaymentStatus = GetPaymentStatus(payment_status, pending_reason, total, order.OrderTotal); + + if (newPaymentStatus == PaymentStatus.Paid) + { + // note, order can be marked as paid through IPN + if (order.AuthorizationTransactionId.IsEmpty()) + { + order.AuthorizationTransactionId = order.CaptureTransactionId = txn_id; + order.AuthorizationTransactionResult = order.CaptureTransactionResult = "Success"; + + OrderService.UpdateOrder(order); + } + + if (OrderProcessingService.CanMarkOrderAsPaid(order)) + { + OrderProcessingService.MarkOrderAsPaid(order); + } + } + } + + return RedirectToAction("Completed", "Checkout", new { area = "" }); + } + else + { + try + { + values.TryGetValue("custom", out orderNumber); + orderNumberGuid = new Guid(orderNumber); + + var order = OrderService.GetOrderByGuid(orderNumberGuid); + OrderService.AddOrderNote(order, "{0} {1}".FormatInvariant(T("Plugins.Payments.PayPalStandard.PdtFailed"), response)); + } + catch { } + + return RedirectToAction("Index", "Home", new { area = "" }); + } + } + + public ActionResult CancelOrder(FormCollection form) + { + var order = OrderService.SearchOrders(Services.StoreContext.CurrentStore.Id, Services.WorkContext.CurrentCustomer.Id, null, null, null, null, null, null, null, null, 0, 1) + .FirstOrDefault(); + + if (order != null) + { + return RedirectToAction("Details", "Order", new { id = order.Id, area = "" }); + } + + return RedirectToAction("Index", "Home", new { area = "" }); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/DependencyRegistrar.cs b/src/Plugins/SmartStore.PayPal/DependencyRegistrar.cs new file mode 100644 index 0000000000..95e7e8f1c3 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/DependencyRegistrar.cs @@ -0,0 +1,38 @@ +using Autofac; +using Autofac.Integration.Mvc; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.PayPal.Filters; +using SmartStore.PayPal.Services; +using SmartStore.Web.Controllers; + +namespace SmartStore.PayPal +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + + if (isActiveModule) + { + builder.RegisterType().AsActionFilterFor(x => x.PaymentMethod()).InstancePerRequest(); + + builder.RegisterType().AsActionFilterFor(x => x.FlyoutShoppingCart()).InstancePerRequest(); + + builder.RegisterType() + .AsActionFilterFor(x => x.PaymentMethod()) + .InstancePerRequest(); + + builder.RegisterType() + .AsActionFilterFor(x => x.Completed()) + .InstancePerRequest(); + } + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.PayPal/Description.txt b/src/Plugins/SmartStore.PayPal/Description.txt new file mode 100644 index 0000000000..b96ae172bb --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Description.txt @@ -0,0 +1,10 @@ +FriendlyName: PayPal +Description: Provides the PayPal payment methods PayPal Standard, PayPal Direct, PayPal Express and PayPal PLUS. +SystemName: SmartStore.PayPal +Group: Payment +Version: 2.6.0.5 +MinAppVersion: 2.5.0 +DisplayOrder: 1 +FileName: SmartStore.PayPal.dll +ResourceRootKey: Plugins.SmartStore.PayPal +Url: http://community.smartstore.com/marketplace/file/29-paypal-payment-plugins/ \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Extensions/MiscExtensions.cs b/src/Plugins/SmartStore.PayPal/Extensions/MiscExtensions.cs new file mode 100644 index 0000000000..352d70d951 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Extensions/MiscExtensions.cs @@ -0,0 +1,40 @@ +using System.Net; +using System.Web; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Orders; + +namespace SmartStore.PayPal +{ + internal static class MiscExtensions + { + public static string GetPayPalUrl(this PayPalSettingsBase settings) + { + return settings.UseSandbox ? + "https://www.sandbox.paypal.com/cgi-bin/webscr" : + "https://www.paypal.com/cgi-bin/webscr"; + } + + public static HttpWebRequest GetPayPalWebRequest(this PayPalSettingsBase settings) + { + if (settings.SecurityProtocol.HasValue) + { + ServicePointManager.SecurityProtocol = settings.SecurityProtocol.Value; + } + + var request = (HttpWebRequest)WebRequest.Create(GetPayPalUrl(settings)); + return request; + } + + public static PayPalSessionData GetPayPalSessionData(this HttpContextBase httpContext, CheckoutState state = null) + { + if (state == null) + state = httpContext.GetCheckoutState(); + + if (!state.CustomProperties.ContainsKey(PayPalPlusProvider.SystemName)) + state.CustomProperties.Add(PayPalPlusProvider.SystemName, new PayPalSessionData()); + + return state.CustomProperties[PayPalPlusProvider.SystemName] as PayPalSessionData; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Filters/PayPalExpressCheckoutFilter.cs b/src/Plugins/SmartStore.PayPal/Filters/PayPalExpressCheckoutFilter.cs new file mode 100644 index 0000000000..317fae97a0 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Filters/PayPalExpressCheckoutFilter.cs @@ -0,0 +1,73 @@ +using System; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Core.Domain.Customers; +using SmartStore.Services; +using SmartStore.Services.Common; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal.Filters +{ + public class PayPalExpressCheckoutFilter : IActionFilter + { + private static readonly string[] s_interceptableActions = new string[] { "PaymentMethod" }; + + private readonly IGenericAttributeService _genericAttributeService; + private readonly HttpContextBase _httpContext; + private readonly ICommonServices _services; + + public PayPalExpressCheckoutFilter( + IGenericAttributeService genericAttributeService, + HttpContextBase httpContext, + ICommonServices services) + { + _genericAttributeService = genericAttributeService; + _httpContext = httpContext; + _services = services; + } + + private static bool IsInterceptableAction(string actionName) + { + return s_interceptableActions.Contains(actionName, StringComparer.OrdinalIgnoreCase); + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + if (filterContext == null || filterContext.ActionDescriptor == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) + return; + + var attr = Convert.ToBoolean(filterContext.HttpContext.GetCheckoutState().CustomProperties["PayPalExpressButtonUsed"]); + + //verify paypalexpressprovider was used + if (attr == true) + { + var store = _services.StoreContext.CurrentStore; + var customer = _services.WorkContext.CurrentCustomer; + + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedPaymentMethod, PayPalExpressProvider.SystemName, store.Id); + + var paymentRequest = _httpContext.Session["OrderPaymentInfo"] as ProcessPaymentRequest; + if (paymentRequest == null) + { + _httpContext.Session["OrderPaymentInfo"] = new ProcessPaymentRequest(); + } + + //delete property for backward navigation + _httpContext.GetCheckoutState().CustomProperties.Remove("PayPalExpressButtonUsed"); + + filterContext.Result = new RedirectToRouteResult( + new RouteValueDictionary { + { "Controller", "Checkout" }, + { "Action", "Confirm" }, + { "area", null } + }); + } + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Filters/PayPalExpressWidgetZoneFilter.cs b/src/Plugins/SmartStore.PayPal/Filters/PayPalExpressWidgetZoneFilter.cs new file mode 100644 index 0000000000..f5eaa49d36 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Filters/PayPalExpressWidgetZoneFilter.cs @@ -0,0 +1,69 @@ +using System; +using System.Web.Mvc; +using SmartStore.PayPal.Settings; +using SmartStore.Services; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.UI; +using SmartStore.Web.Models.ShoppingCart; + +namespace SmartStore.PayPal.Filters +{ + public class PayPalExpressWidgetZoneFilter : IActionFilter, IResultFilter + { + private readonly Lazy _widgetProvider; + private readonly Lazy _paymentService; + private readonly Lazy _services; + private readonly Lazy _payPalExpressSettings; + + public PayPalExpressWidgetZoneFilter( + Lazy widgetProvider, + Lazy paymentService, + Lazy services, + Lazy payPalExpressSettings) + { + _widgetProvider = widgetProvider; + _paymentService = paymentService; + _services = services; + _payPalExpressSettings = payPalExpressSettings; + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + } + + public void OnResultExecuting(ResultExecutingContext filterContext) + { + if (filterContext.IsChildAction) + return; + + // should only run on a full view rendering result + var result = filterContext.Result as ViewResultBase; + if (result == null) + return; + + var controller = filterContext.RouteData.Values["controller"] as string; + var action = filterContext.RouteData.Values["action"] as string; + + if (action.IsCaseInsensitiveEqual("FlyoutShoppingCart") && controller.IsCaseInsensitiveEqual("ShoppingCart")) + { + var model = filterContext.Controller.ViewData.Model as MiniShoppingCartModel; + + if (model != null && model.DisplayCheckoutButton && _payPalExpressSettings.Value.ShowButtonInMiniShoppingCart) + { + if (_paymentService.Value.IsPaymentMethodActive(PayPalExpressProvider.SystemName, _services.Value.StoreContext.CurrentStore.Id)) + { + _widgetProvider.Value.RegisterAction("mini_shopping_cart_bottom", "MiniShoppingCart", "PayPalExpress", new { area = "SmartStore.PayPal" }); + } + } + } + } + + public void OnResultExecuted(ResultExecutedContext filterContext) + { + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Filters/PayPalPlusCheckoutFilter.cs b/src/Plugins/SmartStore.PayPal/Filters/PayPalPlusCheckoutFilter.cs new file mode 100644 index 0000000000..7c47079830 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Filters/PayPalPlusCheckoutFilter.cs @@ -0,0 +1,49 @@ +using System; +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Core.Domain.Customers; +using SmartStore.Services; +using SmartStore.Services.Common; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal.Filters +{ + public class PayPalPlusCheckoutFilter : IActionFilter + { + private readonly ICommonServices _services; + private readonly IPaymentService _paymentService; + private readonly Lazy _genericAttributeService; + + public PayPalPlusCheckoutFilter( + ICommonServices services, + IPaymentService paymentService, + Lazy genericAttributeService) + { + _services = services; + _paymentService = paymentService; + _genericAttributeService = genericAttributeService; + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + if (filterContext == null || filterContext.ActionDescriptor == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) + return; + + var store = _services.StoreContext.CurrentStore; + + if (!_paymentService.IsPaymentMethodActive(PayPalPlusProvider.SystemName, store.Id)) + return; + + _genericAttributeService.Value.SaveAttribute(_services.WorkContext.CurrentCustomer, SystemCustomerAttributeNames.SelectedPaymentMethod, PayPalPlusProvider.SystemName, store.Id); + + var routeValues = new RouteValueDictionary(new { action = "PaymentWall", controller = "PayPalPlus" }); + + filterContext.Result = new RedirectToRouteResult("SmartStore.PayPalPlus", routeValues); + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Filters/PayPalPlusWidgetZoneFilter.cs b/src/Plugins/SmartStore.PayPal/Filters/PayPalPlusWidgetZoneFilter.cs new file mode 100644 index 0000000000..cbe12c7aaf --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Filters/PayPalPlusWidgetZoneFilter.cs @@ -0,0 +1,58 @@ +using System; +using System.Web; +using System.Web.Mvc; +using SmartStore.Web.Framework.UI; + +namespace SmartStore.PayPal.Filters +{ + public class PayPalPlusWidgetZoneFilter : IActionFilter, IResultFilter + { + private readonly Lazy _httpContext; + private readonly Lazy _widgetProvider; + + public PayPalPlusWidgetZoneFilter( + Lazy httpContext, + Lazy widgetProvider) + { + _httpContext = httpContext; + _widgetProvider = widgetProvider; + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + } + + public void OnResultExecuting(ResultExecutingContext filterContext) + { + if (filterContext.IsChildAction) + return; + + // should only run on a full view rendering result + var result = filterContext.Result as ViewResultBase; + if (result == null) + return; + + var controller = filterContext.RouteData.Values["controller"] as string; + var action = filterContext.RouteData.Values["action"] as string; + + if (action.IsCaseInsensitiveEqual("Completed") && controller.IsCaseInsensitiveEqual("Checkout")) + { + var instruct = _httpContext.Value.Session[PayPalPlusProvider.CheckoutCompletedKey] as string; + + if (instruct.HasValue()) + { + _widgetProvider.Value.RegisterAction("checkout_completed_top", "CheckoutCompleted", "PayPalPlus", new { area = Plugin.SystemName }); + _widgetProvider.Value.RegisterAction("mobile_checkout_completed_top", "CheckoutCompleted", "PayPalPlus", new { area = Plugin.SystemName }); + } + } + } + + public void OnResultExecuted(ResultExecutedContext filterContext) + { + } + } +} diff --git a/src/Plugins/SmartStore.PayPal/Localization/resources.de-de.xml b/src/Plugins/SmartStore.PayPal/Localization/resources.de-de.xml new file mode 100644 index 0000000000..0568ab1572 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Localization/resources.de-de.xml @@ -0,0 +1,453 @@ + + + + PayPal Zahlungsarten + + + Stellt die PayPal-Zahlungsarten PayPal Standard, PayPal Direct, PayPal Express und PayPal PLUS zur Verfügung. + + + + API Zugang;Datenaustausch;Sonstiges + + + {0}]]> + + + Mitteilung;Ereignis;Ereignis-ID;Status;Betrag;Zahlungs-ID + + + Sonstiges + + + {0} hat die Forderung gegen Sie im Rahmen eines laufenden Factoringvertrages an die PayPal (Europe) S.àr.l. et Cie, S.C.A. abgetreten. Zahlungen mit schuldbefreiender Wirkung können nur an die PayPal (Europe) S.àr.l. et Cie, S.C.A. geleistet werden. + + + Bitte überweisen Sie den fälligen Betrag auf folgendes Konto. + + + Referenz;Bankleitzahl;Bank;BIC;IBAN;Kontoinhaber;Kontonummer;Betrag;Zahlung fällig am;Details + + + Mitteilung wurde ignoriert, da {0} Aufträge mit der Payment-ID {1} gefunden wurden. + + + Währung {0} entspricht nicht der Leitwährung des Shops {1}. + + + Keine Weiterleitungs-URL von PayPal erhalten. + + + + Client-ID + + + Legt die API Client-ID fest. + + + Secret + + + Legt die API Secret fest. + + + Bitte geben Sie Ihre API Zugangsdaten ein. + + + Experience Profil-ID + + + Legt die Experience Profil-ID fest. Das Profil beinhaltet globale Daten wie z.B. Shop-Name und -Logo. Ein Profil braucht nur einmalig angelegt werden. Über den Button können Sie ein neues Profil erstellen oder ein vorhandenes aktualisieren. + + + Experience Profil-ID + + + Webhook-ID + + + Legt die Webhook-ID fest. Über einen Webhook sendet PayPal Statusänderungen von Zahlungen an Ihren Shop, wodurch der Zahlungsstatus Ihrer Aufträge automatisch aktualisert werden kann. + + + + + + Sandbox benutzen + + + Aktiviert die Nutzung der PayPal Sandbox (Testumgebung). + + + Zahlungsstatus über IPN ändern + + + Legt fest, ob durch eingehende IPNs der Zahlunsgstatus eines Auftrags angepasst werden soll. + + + Transaktionsmodus + + + Bestimmen Sie den Transaktionsmodus. + + + Sicherheitsprotokoll + + + Legt das mit der PayPal-API zu verwendende Sicherheitsprotokoll fest. + + + API Benutzername + + + Geben Sie Ihren API Benutzername ein. + + + API Passwort + + + Geben Sie Ihr API Passwort ein. + + + Signatur + + + Geben Sie Ihre Signatur ein. + + + Zusätzliche Gebühren + + + Zusätzliche Gebühren, die dem Kunden berechnet werden sollen. + + + Zusätzliche Gebühren (prozentual) + + + Zusätzliche prozentuale Gebühr zum Gesamtbetrag. Es wird ein fester Wert verwendet, falls diese Option nicht aktiviert ist. + + + Das Zahlungsmodul Modul konnte nicht geladen werden. + + + PayPal IPN. Wiederkehrende Zahlung. + + + PayPal IPN. Bestellung konnte nicht gefunden werden. + + + PayPal IPN. Benachrichtigung konnte nicht abgerufen werden. + + + Teilerstattung von {0} + + + Zahlartgebühren + + + Rabatt + + + Angewendeter Geschenkgutschein + + + + + + PayPal Express + + + + + + Stellen Sie bitte sicher, dass PayPal die Primärwährung Ihres Shops unterstützt, falls Sie dieses Gateway benutzen!

    +
      +
    1. Loggen Sie sich in Ihr PayPal-Konto ein.
    2. +
    3. Klicken Sie auf den Register Mein Profil.
    4. +
    5. Klicken Sie unter Verkäufer/Händler auf API-Zugriff.
    6. +
    7. Klicken Sie auf API-Berechtigung anfordern.
    8. +
    9. Wählen Sie die Option Fordern Sie eine API-Signature an.
    10. +
    11. Klicken Sie auf Zustimmen und senden.
    12. +
    +

    Aktivieren Sie optional den PayPal-Service zum Empfang von IPN-Nachrichten (Instant Payment Notification):

    +
      +
    1. In Ihr Premier- oder Business-Konto einloggen.
    2. +
    3. Auf den Register Mein Profil klicken.
    4. +
    5. Unter Sprach-Kodierung > Weitere Einstellungen wählen Sie bitte UTF-8.
    6. +
    7. Sofortige Zahlungsbestätigung klicken.
    8. +
    9. Einstellungen für sofortige Zahlungsbestätigungen wählen klicken.
    10. +
    11. Bei Benachrichtigungs-URL die URL Ihres IPN-Handlers (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalExpress/IPNHandler) eingeben.
    12. +
    13. Speichern klicken. Danach sollten Sie eine Nachricht über die erfolgreiche Aktivierung von IPN erhalten.
    14. +
    ]]> +
    +
    + + Wiederkehrende Zahlung + + + Nicht unterstützte Zyklus-Zeit. + + + Sofort abbuchen + + + Autorisierung sofort, Abbuchung später + + + oder + + + Button im Miniwarenkorb anzeigen + + + Legt fest, ob der Checkout-Button im Miniwarenkorb angezeigt werden soll. + + + Bestätigte E-Mail-Adresse + + + Legt fest, ob es sich bei der verwendeten E-Mail-Adresse, um eine von PayPal bestätigte Adresse handeln muss. + + + Anzeige der Lieferadresse unterdrücken + + + Legt fest, ob auf der PayPal Seite die Lieferadresse angezeigt werden soll. + + + Zeitlimit für API-Callback + + + Legt das Zeitlimit für API-Callbacks fest. + + + Versandkosten (Fallback) + + + Legt die Versandkosten fest, falls keine anderen ermittelt werden können. + +
    +
    + + + + PayPal Direct + + + + + + Stellen Sie bitte sicher, dass PayPal die Primärwährung Ihres Shops unterstützt, falls Sie dieses Gateway benutzen!

    +
      +
    1. Loggen Sie sich in Ihr PayPal-Konto ein.
    2. +
    3. Klicken Sie auf den Register Mein Profil.
    4. +
    5. Klicken Sie unter Verkäufer/Händler auf API-Zugriff.
    6. +
    7. Klicken Sie auf API-Berechtigung anfordern.
    8. +
    9. Wählen Sie die Option Fordern Sie eine API-Signature an.
    10. +
    11. Klicken Sie auf Zustimmen und senden.
    12. +
    +

    Aktivieren Sie optional den PayPal-Service zum Empfang von IPN-Nachrichten (Instant Payment Notification):

    +
      +
    1. In Ihr Premier- oder Business-Konto einloggen.
    2. +
    3. Auf den Register Mein Profil klicken.
    4. +
    5. Unter Sprach-Kodierung > Weitere Einstellungen wählen Sie bitte UTF-8.
    6. +
    7. Sofortige Zahlungsbestätigung klicken.
    8. +
    9. Einstellungen für sofortige Zahlungsbestätigungen wählen klicken.
    10. +
    11. Bei Benachrichtigungs-URL die URL Ihres IPN-Handlers (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalDirect/IPNHandler) eingeben.
    12. +
    13. Speichern klicken. Danach sollten Sie eine Nachricht über die erfolgreiche Aktivierung von IPN erhalten.
    14. +
    ]]> +
    +
    + + Wiederkehrende Zahlung + + + Nicht unterstützte Zyklus-Zeit. + + + Sofort abbuchen + + + Autorisierung sofort, Abbuchung später + +
    +
    + + + PayPal Standard + + + + + + Stellen Sie bitte sicher, dass PayPal die Primärwährung Ihres Shops unterstützt, falls Sie dieses Gateway benutzen.

    +

    Sie müssen PDT (Payment Data Transfer) und die automatische Rückleitung in Ihrem PayPal-Profil aktivieren, um PDT nutzen zu können. + Ferner benötigen Sie einen PDT-Identitäts-Token, der für jede PDT-Kommunikation mit PayPal erforderlich ist. + Folgen Sie den Schritten, um Ihr Konto für PDT zu konfigurieren:

    +
      +
    1. Loggen Sie sich in Ihr PayPal-Konto ein.
    2. +
    3. Klicken Sie auf den Register Mein Profil.
    4. +
    5. Klicken Sie unter Verkäufer/Händler auf Website-Einstellungen.
    6. +
    7. Aktivieren Sie Automatische Rückleitung.
    8. +
    9. Als Rückleitungs-URL geben Sie bitte die Seite Ihres Shops ein, die die Transaktions-ID von PayPal nach einer Kundenzahlung empfängt (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalStandard/PDTHandler).
    10. +
    11. Aktivieren Sie Übertragung der Zahlungsdaten.
    12. +
    13. Klicken Sie auf Speichern.
    14. +
    15. Klicken Sie unter Verkäufer/Händler auf Website-Einstellungen.
    16. +
    17. Scrollen Sie runter zu Übertragung der Zahlungsdaten, um den PDT-Identitäts-Token einzusehen.
    18. +
    +

    Es gibt zwei Wege, um IPN-Nachrichten (Instant Payment Notification) zu empfangen (optional):

    +
      +
    1. Unten IPN aktivieren abhaken. Die URL zu Ihrem IPN-Handler wird dann über die Anfrage übermittelt.
    2. +
    3. + Ihr PayPal-Konto für diesen Service konfigurieren. Schritte hierzu: +
        +
      1. In Ihr Premier- oder Business-Konto einloggen.
      2. +
      3. Auf den Register Mein Profil klicken.
      4. +
      5. Unter Sprach-Kodierung > Weitere Einstellungen wählen Sie bitte UTF-8.
      6. +
      7. Zurück zu Mein Profil und auf Sofortige Zahlungsbestätigung klicken.
      8. +
      9. Einstellungen für sofortige Zahlungsbestätigungen wählen klicken.
      10. +
      11. Bei Benachrichtigungs-URL die URL Ihres IPN-Handlers (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalStandard/IPNHandler) eingeben.
      12. +
      13. Speichern klicken. Danach sollten Sie eine Nachricht über die erfolgreiche Aktivierung von IPN erhalten.
      14. +
      +
    4. +
    ]]> +
    +
    + + Nach Bestätigung der Bestellung werden Sie direkt zu PayPal weitergeleitet. Halten Sie bitte Ihre Daten für das Online-Banking bereit. + + + Business E-Mail + + + PayPal Business E-Mail festlegen. + + + PDT-Identitäts-Token + + + PDT-Identitäts-Token festlegen. + + + Gesamtbetrag überprüfen + + + Aktivieren Sie diese Option, falls der durch PayPal übermittelte Gesamtbetrag überprüft werden soll. + + + Nur warnen + + + Legt fest, ob im Falle einer Nichtübereinstimmung des Gesamtbetrags lediglich eine Auftragsnotiz angelegt werden soll. Ansonsten wird ein Fehler erzeugt und der Zahlungsstatus wird nicht aktualisiert. + + + Produktbezeichnungen und Einzelpreise übermitteln + + + Aktivieren Sie diese Option, falls Produktbezeichnungen und Einzelpreise an PayPal übermittelt werden sollen. + + + IPN aktivieren + + + Aktivieren Sie diese Option, falls IPN (Instant Payment Notification) aktiviert werden soll. + + + Leer lassen, falls die URL des Standard-IPN-Handlers verwendet werden soll. + + + IPN-Handler (URL) + + + URL zum IPN-Handler festlegen. + + + PayPal Standard PDT. Fehler beim Abruf von mc_gross. + + + PayPal Standard PDT. Der übermittelte Gesamtbetrag {0} entspricht nicht dem des Shops {1} (ungerundet {2}). Die Differenz beträgt {3}. + + + PayPal Standard PDT ist fehlgeschlagen. + + + Unvollständige Zugangsdaten für die PayPal API. Bitte geben Sie die erforderlichen Zugangsdaten im Konfigurationsbereich ein. + + + Versandgebühren + + + Umsatzsteuer + + + + + + +
    +
    + + + PayPal PLUS + + + + + + PayPal PLUS bietet die Möglichkeit per PayPal, Kreditkarte, Lastschriftverfahren und per Rechnung zu bezahlen. +Die Bezahlung auf Rechnung steht möglicherweise nicht allen Händlern zur Verfügung. PayPal PLUS unterstützt nur den Transaktionstyp der sofortigen Buchung und ist derzeit nur in Deutschland verfügbar.

    +

    PayPal PLUS ersetzt die Zahlartenliste im Kassenbereich durch die PayPal Payment Wall. Sie können der Payment Wall jedoch bis zu 5 weitere Offline- bzw. Weiterleitungszahlarten hinzufügen.

    +

    So richten Sie PayPal PLUS ein: +

      +
    1. Legen Sie unter My Apps & Credentials eine neue REST API Anwendung an. +Unter Manage your applications finden Sie weitere Informationen zum Thema PayPal Anwendungen (Englisch).
    2. +
    3. Klicken Sie auf den Namen der Anwendung und tragen Sie Client-ID und Secret weiter unten auf dieser Seite ein. Speichern.
    4. +
    5. Optional: Klicken Sie unten bei Experience Profil-ID auf Hinzufügen, um ein Profil zu erstellen. Ihre Shop-Daten (Name, Logo etc.) werden Käufern dadurch beim Bezahlen auf den PayPal-Seiten angezeigt.
    6. +
    7. Optional: Klicken Sie unten bei Webhook-ID auf Hinzufügen, um einen Webhook zu erstellen. Über einen Webhook empfängt der Shop PayPal-Mitteilungen und aktualisiert u.U. den Zahlungsstatus Ihrer Aufträge.
    8. +

    ]]> +
    +
    + + Wir können Ihnen leider keine PayPal PLUS Zahlungsart anbieten. Bitte versuchen Sie er später erneut. + + + Entschuldigung, das hat gerade nicht funktioniert. Bitte versuchen Sie es erneut oder wählen Sie eine andere Zahlungsmethode. + + + .]]> + + + Weitere Zahlarten + + + Sie können bis zu 5 weitere Zahlarten festlegen. Diese werden zusammen mit den PayPal PLUS Zahlarten im Kassenbereich angeboten. + + + Es können maximal 5 weitere Zahlarten festgelegt werden. + + + Logo der Zahlarten anzeigen + + + Legt fest, ob für die weiteren Zahlarten deren Logo angezeigt werden soll. SSL erforderlich. + + + Beschreibung der Zahlarten anzeigen + + + Legt fest, ob für die weiteren Zahlarten deren Beschreibung angezeigt werden soll. + +
    +
    + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Localization/resources.en-us.xml b/src/Plugins/SmartStore.PayPal/Localization/resources.en-us.xml new file mode 100644 index 0000000000..700b806aa7 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Localization/resources.en-us.xml @@ -0,0 +1,453 @@ + + + + PayPal Payment Methods + + + Provides the PayPal payment methods PayPal Standard, PayPal Direct, PayPal Express and PayPal PLUS. + + + + API access;Data exchange;Miscellaneous + + + {0}]]> + + + Message;Event;Event-ID;State;Amount;Payment-ID + + + Miscellaneous + + + The execution of the payment has been declined by PayPal. + + + {0} hat die Forderung gegen Sie im Rahmen eines laufenden Factoringvertrages an die PayPal (Europe) S.àr.l. et Cie, S.C.A. abgetreten. Zahlungen mit schuldbefreiender Wirkung können nur an die PayPal (Europe) S.àr.l. et Cie, S.C.A. geleistet werden. + + + Please transfer the due amount to the following bank account. + + + Reference;Bank routing number;Bank;BIC;IBAN;Account holder;Account number;Amount;Payment due date;Details + + + Message has been ignored because {0} orders with payment ID {1} found. + + + Currency {0} does not equal primary store currency {1}. + + + No redirect URL received from PayPal. + + + + Client ID + + + Specifies the API client ID. + + + Secret + + + Specifies the API secret. + + + Please enter your API credentials. + + + Experience profile ID + + + Specifies the experience profile ID. The profile contains global data like shop name and logo. A profile needs to be created only once. Using the button, you can create a new profile or update an existing one. + + + Webhook ID + + + Specifies the webhook ID. PayPal sends payment status changes via a webhook to your shop, whereby the payment status of your orders can be automatically synced. + + + + + + Use Sandbox + + + Check the box to enable Sandbox (testing environment). + + + IPN may change payment status + + + Specifies whether received IPNs should change the payment status of an order. + + + Transaction mode + + + Specify the payment transaction mode. + + + Security protocol + + + Specifies the security protocol to use with the PayPal API. + + + API Account Name + + + Specify the API account name. + + + API Account Password + + + Specify the API account password. + + + Signature + + + Enter the signature. + + + Additional fee + + + Enter additional fee to charge your customers. + + + Additional fee. Use percentage. + + + Specifies whether to apply a percentage additional fee to the order total. A fixed value is used if not enabled. + + + The payment module cannot be loaded. + + + PayPal IPN. Recurring payment. + + + PayPal IPN. Order cannot be found. + + + PayPal IPN. Failed to retrieve notification. + + + Partial refund of {0} + + + Payment method fee + + + Discount + + + Giftcard Applied + + + + + + PayPal Express + + + + + + If you're using this gateway ensure that your primary store currency is supported by Paypal!

    +
      +
    1. Log into your PayPal account.
    2. +
    3. Click on Profile from the Home Menu.
    4. +
    5. Under Account Information choose API Access.
    6. +
    7. Choose Request API credentials.
    8. +
    9. Choose API Signature as the credential type.
    10. +
    11. Enable the checkbox and agree to the license Terms-I agree to the API Certificate Terms of Use and terms incorporated therein and press the Submit button.
    12. +
    +

    Before being able to receive IPN (Instant Payment Notification) messages (optional), you'll need to activate this service; follow these steps:

    +
      +
    1. Log in to your Premier or Business account.
    2. +
    3. Click the Profile subtab.
    4. +
    5. Click Language Encoding and More options and select UTF-8.
    6. +
    7. Click Instant Payment Notification in the Selling Preferences column.
    8. +
    9. Click the Edit IPN Settings button to update your settings.
    10. +
    11. Select Receive IPN messages (enabled) and enter the URL of your IPN handler (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalExpress/IPNHandler).
    12. +
    13. Click Save, and you should get a message that you have successfully activated IPN.
    14. +
    ]]> +
    +
    + + recurring payment + + + Not supported cycle period. + + + Immediately debit + + + Authorize immediately, debit later + + + or + + + Show button in mini shopping cart + + + Soecifies to show the checkout button in the mini shopping cart. + + + Confirmed email address + + + Choose whether the used email address has to be confirmed by PayPal. + + + Disable display of the shipping address. + + + Disables display of the shipping address. + + + Timeout for API callback + + + Determines the timeout for API callbacks. + + + Shipping costs (fallback) + + + Determines shipping costs if no other could be obtained. + +
    +
    + + + PayPal Direct + + + + + + If you're using this gateway ensure that your primary store currency is supported by Paypal!

    +
      +
    1. Log into your PayPal account.
    2. +
    3. Click on Profile from the Home Menu.
    4. +
    5. Under Account Information choose API Access.
    6. +
    7. Choose Request API credentials.
    8. +
    9. Choose API Signature as the credential type.
    10. +
    11. Enable the checkbox and agree to the license Terms-I agree to the API Certificate Terms of Use and terms incorporated therein and press the Submit button.
    12. +
    +

    Before being able to receive IPN (Instant Payment Notification) messages (optional), you'll need to activate this service; follow these steps:

    +
      +
    1. Log in to your Premier or Business account.
    2. +
    3. Click the Profile subtab.
    4. +
    5. Click Language Encoding and More options and select UTF-8.
    6. +
    7. Click Instant Payment Notification in the Selling Preferences column.
    8. +
    9. Click the Edit IPN Settings button to update your settings.
    10. +
    11. Select Receive IPN messages (enabled) and enter the URL of your IPN handler (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalDirect/IPNHandler).
    12. +
    13. Click Save, and you should get a message that you have successfully activated IPN.
    14. +
    ]]> +
    +
    + + recurring payment + + + Not supported cycle period. + + + Immediately debit + + + Authorize immediately, debit later + +
    +
    + + + PayPal Standard + + + + + + If you're using this gateway ensure that your primary store currency is supported by Paypal.

    +

    To use PDT (Payment Data Transfer), you must activate PDT and Auto Return in your PayPal account profile. + You must also acquire a PDT identity token, which is used in all PDT communication + you send to PayPal. Follow these steps to configure your account for PDT:

    +
      +
    1. Log in to your PayPal account.
    2. +
    3. Click the Profile subtab.
    4. +
    5. Click Website Payment Preferences in the Seller Preferences column.
    6. +
    7. Under Auto Return for Website Payments, click the On radio button.
    8. +
    9. For the Return URL, enter the URL on your site that will receive the transaction ID posted by PayPal after a customer payment (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalStandard/PDTHandler).
    10. +
    11. Under Payment Data Transfer, click the On radio button.
    12. +
    13. Click Save.
    14. +
    15. Click Website Payment Preferences in the Seller Preferences column.
    16. +
    17. Scroll down to Payment Data Transfer of the page to view your PDT identity token.
    18. +
    +

    Two ways to be able to receive IPN (Instant Payment Notification) messages (optional):

    +
      +
    1. Check Enable IPN below. It will include in the request the url of you IPN handler.
    2. +
    3. + The second way is to configure your paypal account to activate this service; follow these steps: +
        +
      1. Log in to your Premier or Business account.
      2. +
      3. Click the Profile subtab.
      4. +
      5. Click Language Encoding and More options and select UTF-8.
      6. +
      7. Back to Profile click Instant Payment Notification in the Selling Preferences column.
      8. +
      9. Click the Edit IPN Settings button to update your settings.
      10. +
      11. Select Receive IPN messages (Enabled) and enter the URL of your IPN handler (https://www.yourStore.com/Plugins/SmartStore.PayPal/PayPalStandard/IPNHandler).
      12. +
      13. Click Save, and you should get a message that you have successfully activated IPN.
      14. +
      +
    4. +
    ]]> +
    +
    + + After confirmation of the order, you will be redirected straight to PayPal. Please provide your data for online banking. + + + Business Email + + + Specify your PayPal business email. + + + PDT Identity Token + + + Specify PDT identity token + + + Validate order total + + + Check the box if the PDT handler should validate PayPal's order totals. + + + Only warn + + + Specifies whether to add an order note if the order total is unequal. Otherwise an error will be logged and the payment status is not updated. + + + Transmit product names and unit prices + + + Check the box if product names and unit prices should be transmitted to PayPal. + + + Enable IPN + + + Check the box if IPN (Instant Payment Notification) is enabled. + + + Leave blank to use the default IPN handler URL. + + + IPN Handler + + + Specify IPN Handler. + + + PayPal Standard PDT. Error getting mc_gross. + + + PayPal Standard PDT. Returned order total {0} doesn't equal order total {1} (not rounded {2}). The difference is {3}. + + + PayPal Standard PDT failed. + + + Incomplete credentials for the PayPal API. Please enter the required data in the configuration area. + + + Shipping fee + + + Sales tax + + + + + + +
    +
    + + + PayPal PLUS + + + + + + PayPal PLUS is a solution where PayPal offers PayPal, Credit Card, Direct Debit (ELV) and pay upon invoice as individual payment options on the payment selection page. +Pay upon invoice may not be available for all merchants. PayPal PLUS only supports the transaction type of instant settlement and is only available in Germany at the moment.

    +

    PayPal PLUS replaces the list of payment methods in checkout by the PayPal payment wall. You can add up to 5 offline or redirection payment methods to the payment wall.

    +

    How to set up PayPal PLUS: +

      +
    1. Create a new REST API application under My Apps & Credentials. +Go to Manage your applications to get more information about PayPal applications.
    2. +
    3. Click the name of the application and enter Client-ID and Secret below on this page. Save.
    4. +
    5. Optional: Click Add next to Experience profile ID to create a new profile. Your shop data (name, logo etc.) can now be displayed to customers when paying on PayPal pages.
    6. +
    7. Optional: Click Add next to Webhook-ID to create a webhook. Through a webhook the shop receives PayPal messages und possibly updates the payment state of your orders.
    8. +

    ]]> +
    +
    + + Unfortunately we cannot offer you a PayPal PLUS payment method. Please try again later. + + + I'm sorry, that just didn't work. Please try again or select another payment method. + + + .]]> + + + More payment methods + + + You can set up to 5 more payment methods. These are offered along with the PayPal PLUS payment methods during the checkout process. + + + Maximum of 5 third party payment methods can be specified. + + + Display logo of other payment methods + + + Specifies whether to display the logo for other payment methods. SSL required. + + + Display description of other payment methods + + + Specifies whether to display the description for other payment methods. + +
    +
    + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Models/ApiConfigurationModels.cs b/src/Plugins/SmartStore.PayPal/Models/ApiConfigurationModels.cs new file mode 100644 index 0000000000..f81f6c2d7f --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Models/ApiConfigurationModels.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Net; +using System.Web.Mvc; +using SmartStore.PayPal.Settings; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.PayPal.Models +{ + public abstract class ApiConfigurationModel: ModelBase + { + public string[] ConfigGroups { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.UseSandbox")] + public bool UseSandbox { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.IpnChangesPaymentStatus")] + public bool IpnChangesPaymentStatus { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.TransactMode")] + public int TransactMode { get; set; } + public SelectList TransactModeValues { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.SecurityProtocol")] + public SecurityProtocolType? SecurityProtocol { get; set; } + public List AvailableSecurityProtocols { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.ApiAccountName")] + public string ApiAccountName { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.ApiAccountPassword")] + [DataType(DataType.Password)] + public string ApiAccountPassword { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.Signature")] + public string Signature { get; set; } + + [SmartResourceDisplayName("Plugins.SmartStore.PayPal.ClientId")] + public string ClientId { get; set; } + + [SmartResourceDisplayName("Plugins.SmartStore.PayPal.Secret")] + public string Secret { get; set; } + + [SmartResourceDisplayName("Plugins.SmartStore.PayPal.ExperienceProfileId")] + public string ExperienceProfileId { get; set; } + + [SmartResourceDisplayName("Plugins.SmartStore.PayPal.WebhookId")] + public string WebhookId { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.AdditionalFee")] + public decimal AdditionalFee { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.AdditionalFeePercentage")] + public bool AdditionalFeePercentage { get; set; } + } + + public class PayPalDirectConfigurationModel : ApiConfigurationModel + { + public void Copy(PayPalDirectPaymentSettings settings, bool fromSettings) + { + if (fromSettings) + { + SecurityProtocol = settings.SecurityProtocol; + UseSandbox = settings.UseSandbox; + IpnChangesPaymentStatus = settings.IpnChangesPaymentStatus; + TransactMode = Convert.ToInt32(settings.TransactMode); + ApiAccountName = settings.ApiAccountName; + ApiAccountPassword = settings.ApiAccountPassword; + Signature = settings.Signature; + AdditionalFee = settings.AdditionalFee; + AdditionalFeePercentage = settings.AdditionalFeePercentage; + } + else + { + settings.SecurityProtocol = SecurityProtocol; + settings.UseSandbox = UseSandbox; + settings.IpnChangesPaymentStatus = IpnChangesPaymentStatus; + settings.TransactMode = (TransactMode)TransactMode; + settings.ApiAccountName = ApiAccountName; + settings.ApiAccountPassword = ApiAccountPassword; + settings.Signature = Signature; + settings.AdditionalFee = AdditionalFee; + settings.AdditionalFeePercentage = AdditionalFeePercentage; + } + } + } + + public class PayPalExpressConfigurationModel : ApiConfigurationModel + { + [SmartResourceDisplayName("Plugins.Payments.PayPalExpress.Fields.ShowButtonInMiniShoppingCart")] + public bool ShowButtonInMiniShoppingCart { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalExpress.Fields.ConfirmedShipment")] + public bool ConfirmedShipment { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalExpress.Fields.NoShipmentAddress")] + public bool NoShipmentAddress { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalExpress.Fields.CallbackTimeout")] + public int CallbackTimeout { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalExpress.Fields.DefaultShippingPrice")] + public decimal DefaultShippingPrice { get; set; } + + public void Copy(PayPalExpressPaymentSettings settings, bool fromSettings) + { + if (fromSettings) + { + SecurityProtocol = settings.SecurityProtocol; + UseSandbox = settings.UseSandbox; + IpnChangesPaymentStatus = settings.IpnChangesPaymentStatus; + TransactMode = Convert.ToInt32(settings.TransactMode); + ApiAccountName = settings.ApiAccountName; + ApiAccountPassword = settings.ApiAccountPassword; + Signature = settings.Signature; + AdditionalFee = settings.AdditionalFee; + AdditionalFeePercentage = settings.AdditionalFeePercentage; + ShowButtonInMiniShoppingCart = settings.ShowButtonInMiniShoppingCart; + ConfirmedShipment = settings.ConfirmedShipment; + NoShipmentAddress = settings.NoShipmentAddress; + CallbackTimeout = settings.CallbackTimeout; + DefaultShippingPrice = settings.DefaultShippingPrice; + } + else + { + settings.SecurityProtocol = SecurityProtocol; + settings.UseSandbox = UseSandbox; + settings.IpnChangesPaymentStatus = IpnChangesPaymentStatus; + settings.TransactMode = (TransactMode)TransactMode; + settings.ApiAccountName = ApiAccountName; + settings.ApiAccountPassword = ApiAccountPassword; + settings.Signature = Signature; + settings.AdditionalFee = AdditionalFee; + settings.AdditionalFeePercentage = AdditionalFeePercentage; + settings.ShowButtonInMiniShoppingCart = ShowButtonInMiniShoppingCart; + settings.ConfirmedShipment = ConfirmedShipment; + settings.NoShipmentAddress = NoShipmentAddress; + settings.CallbackTimeout = CallbackTimeout; + settings.DefaultShippingPrice = DefaultShippingPrice; + } + } + } + + + public class PayPalPlusConfigurationModel : ApiConfigurationModel + { + [SmartResourceDisplayName("Plugins.Payments.PayPalPlus.ThirdPartyPaymentMethods")] + public List ThirdPartyPaymentMethods { get; set; } + public List AvailableThirdPartyPaymentMethods { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalPlus.DisplayPaymentMethodLogo")] + public bool DisplayPaymentMethodLogo { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalPlus.DisplayPaymentMethodDescription")] + public bool DisplayPaymentMethodDescription { get; set; } + + + public void Copy(PayPalPlusPaymentSettings settings, bool fromSettings) + { + if (fromSettings) + { + SecurityProtocol = settings.SecurityProtocol; + UseSandbox = settings.UseSandbox; + TransactMode = (int)Settings.TransactMode.AuthorizeAndCapture; + AdditionalFee = settings.AdditionalFee; + AdditionalFeePercentage = settings.AdditionalFeePercentage; + + ClientId = settings.ClientId; + Secret = settings.Secret; + ExperienceProfileId = settings.ExperienceProfileId; + WebhookId = settings.WebhookId; + ThirdPartyPaymentMethods = settings.ThirdPartyPaymentMethods; + DisplayPaymentMethodLogo = settings.DisplayPaymentMethodLogo; + DisplayPaymentMethodDescription = settings.DisplayPaymentMethodDescription; + } + else + { + settings.SecurityProtocol = SecurityProtocol; + settings.UseSandbox = UseSandbox; + settings.TransactMode = Settings.TransactMode.AuthorizeAndCapture; + settings.AdditionalFee = AdditionalFee; + settings.AdditionalFeePercentage = AdditionalFeePercentage; + + settings.ClientId = ClientId; + settings.Secret = Secret; + settings.ExperienceProfileId = ExperienceProfileId; + settings.WebhookId = WebhookId; + settings.ThirdPartyPaymentMethods = ThirdPartyPaymentMethods; + settings.DisplayPaymentMethodLogo = DisplayPaymentMethodLogo; + settings.DisplayPaymentMethodDescription = DisplayPaymentMethodDescription; + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Models/PayPalDirectPaymentInfoModel.cs b/src/Plugins/SmartStore.PayPal/Models/PayPalDirectPaymentInfoModel.cs new file mode 100644 index 0000000000..7f2d0cfbd3 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Models/PayPalDirectPaymentInfoModel.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.PayPal.Models +{ + public class PayPalDirectPaymentInfoModel : ModelBase + { + public PayPalDirectPaymentInfoModel() + { + CreditCardTypes = new List(); + ExpireMonths = new List(); + ExpireYears = new List(); + } + + [SmartResourceDisplayName("Payment.SelectCreditCard")] + [AllowHtml] + public string CreditCardType { get; set; } + + [SmartResourceDisplayName("Payment.SelectCreditCard")] + public IList CreditCardTypes { get; set; } + + [SmartResourceDisplayName("Payment.CardholderName")] + [AllowHtml] + public string CardholderName { get; set; } + + [SmartResourceDisplayName("Payment.CardNumber")] + [AllowHtml] + public string CardNumber { get; set; } + + [SmartResourceDisplayName("Payment.ExpirationDate")] + [AllowHtml] + public string ExpireMonth { get; set; } + + [SmartResourceDisplayName("Payment.ExpirationDate")] + [AllowHtml] + public string ExpireYear { get; set; } + + public IList ExpireMonths { get; set; } + public IList ExpireYears { get; set; } + + [SmartResourceDisplayName("Payment.CardCode")] + [AllowHtml] + public string CardCode { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Models/PayPalExpressPaymentInfoModel.cs b/src/Plugins/SmartStore.PayPal/Models/PayPalExpressPaymentInfoModel.cs new file mode 100644 index 0000000000..a485049605 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Models/PayPalExpressPaymentInfoModel.cs @@ -0,0 +1,17 @@ +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.PayPal.Models +{ + public class PayPalExpressPaymentInfoModel : ModelBase + { + public PayPalExpressPaymentInfoModel() + { + + } + + public bool CurrentPageIsBasket { get; set; } + + public string SubmitButtonImageUrl { get; set; } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Models/PayPalPlusCheckoutModel.cs b/src/Plugins/SmartStore.PayPal/Models/PayPalPlusCheckoutModel.cs new file mode 100644 index 0000000000..280d76ec24 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Models/PayPalPlusCheckoutModel.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.PayPal.Models +{ + public class PayPalPlusCheckoutModel : ModelBase + { + public bool UseSandbox { get; set; } + public string BillingAddressCountryCode { get; set; } + public string LanguageCulture { get; set; } + public string ApprovalUrl { get; set; } + public string ErrorMessage { get; set; } + public string PayPalPlusPseudoMessageFlag { get; set; } + public string FullDescription { get; set; } + public string PayPalFee { get; set; } + public string ThirdPartyFees { get; set; } + public bool HasAnyFees { get; set; } + + public List ThirdPartyPaymentMethods { get; set; } + + public class ThirdPartyPaymentMethod + { + public string RedirectUrl { get; set; } + public string MethodName { get; set; } + public string ImageUrl { get; set; } + public string Description { get; set; } + public string PaymentFee { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Models/PayPalStandardConfigurationModel.cs b/src/Plugins/SmartStore.PayPal/Models/PayPalStandardConfigurationModel.cs new file mode 100644 index 0000000000..9adc991fc6 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Models/PayPalStandardConfigurationModel.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Net; +using System.Web.Mvc; +using SmartStore.PayPal.Settings; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.PayPal.Models +{ + public class PayPalStandardConfigurationModel : ModelBase + { + [SmartResourceDisplayName("Plugins.Payments.PayPal.SecurityProtocol")] + public SecurityProtocolType? SecurityProtocol { get; set; } + public List AvailableSecurityProtocols { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.UseSandbox")] + public bool UseSandbox { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.IpnChangesPaymentStatus")] + public bool IpnChangesPaymentStatus { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.BusinessEmail")] + public string BusinessEmail { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.PDTToken")] + public string PdtToken { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.PDTValidateOrderTotal")] + public bool PdtValidateOrderTotal { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.PdtValidateOnlyWarn")] + public bool PdtValidateOnlyWarn { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.AdditionalFee")] + public decimal AdditionalFee { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPal.AdditionalFeePercentage")] + public bool AdditionalFeePercentage { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.PassProductNamesAndTotals")] + public bool PassProductNamesAndTotals { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.EnableIpn")] + public bool EnableIpn { get; set; } + + [SmartResourceDisplayName("Plugins.Payments.PayPalStandard.Fields.IpnUrl")] + public string IpnUrl { get; set; } + + public void Copy(PayPalStandardPaymentSettings settings, bool fromSettings) + { + if (fromSettings) + { + SecurityProtocol = settings.SecurityProtocol; + UseSandbox = settings.UseSandbox; + IpnChangesPaymentStatus = settings.IpnChangesPaymentStatus; + BusinessEmail = settings.BusinessEmail; + PdtToken = settings.PdtToken; + PdtValidateOrderTotal = settings.PdtValidateOrderTotal; + PdtValidateOnlyWarn = settings.PdtValidateOnlyWarn; + AdditionalFee = settings.AdditionalFee; + AdditionalFeePercentage = settings.AdditionalFeePercentage; + PassProductNamesAndTotals = settings.PassProductNamesAndTotals; + EnableIpn = settings.EnableIpn; + IpnUrl = settings.IpnUrl; + } + else + { + settings.SecurityProtocol = SecurityProtocol; + settings.UseSandbox = UseSandbox; + settings.IpnChangesPaymentStatus = IpnChangesPaymentStatus; + settings.BusinessEmail = BusinessEmail; + settings.PdtToken = PdtToken; + settings.PdtValidateOrderTotal = PdtValidateOrderTotal; + settings.PdtValidateOnlyWarn = PdtValidateOnlyWarn; + settings.AdditionalFee = AdditionalFee; + settings.AdditionalFeePercentage = AdditionalFeePercentage; + settings.PassProductNamesAndTotals = PassProductNamesAndTotals; + settings.EnableIpn = EnableIpn; + settings.IpnUrl = IpnUrl; + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Plugin.cs b/src/Plugins/SmartStore.PayPal/Plugin.cs new file mode 100644 index 0000000000..472a7f2680 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Plugin.cs @@ -0,0 +1,75 @@ +using System; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; + +namespace SmartStore.PayPal +{ + public class Plugin : BasePlugin + { + private readonly ISettingService _settingService; + private readonly ILocalizationService _localizationService; + private readonly Lazy _payPalService; + + public Plugin( + ISettingService settingService, + ILocalizationService localizationService, + Lazy payPalService) + { + _settingService = settingService; + _localizationService = localizationService; + _payPalService = payPalService; + } + + public static string SystemName + { + get { return "SmartStore.PayPal"; } + } + + public override void Install() + { + _settingService.SaveSetting(new PayPalExpressPaymentSettings()); + _settingService.SaveSetting(new PayPalDirectPaymentSettings()); + _settingService.SaveSetting(new PayPalStandardPaymentSettings()); + _settingService.SaveSetting(new PayPalPlusPaymentSettings()); + + _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + } + + public override void Uninstall() + { + try + { + var settings = _settingService.LoadSetting(); + if (settings.WebhookId.HasValue()) + { + var session = new PayPalSessionData(); + var result = _payPalService.Value.EnsureAccessToken(session, settings); + + if (result.Success) + result = _payPalService.Value.DeleteWebhook(settings, session); + + if (!result.Success) + _payPalService.Value.LogError(null, result.ErrorMessage); + } + } + catch (Exception exception) + { + _payPalService.Value.LogError(exception); + } + + _settingService.DeleteSetting(); + _settingService.DeleteSetting(); + _settingService.DeleteSetting(); + _settingService.DeleteSetting(); + + _localizationService.DeleteLocaleStringResources(PluginDescriptor.ResourceRootKey); + + base.Uninstall(); + } + } +} diff --git a/src/Plugins/SmartStore.PayPal/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.PayPal/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..833f59d6a2 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.PayPal")] diff --git a/src/Plugins/SmartStore.PayPal/Properties/Settings.Designer.cs b/src/Plugins/SmartStore.PayPal/Properties/Settings.Designer.cs new file mode 100644 index 0000000000..a9236cb586 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Properties/Settings.Designer.cs @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.34209 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace SmartStore.PayPal.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)] + [global::System.Configuration.DefaultSettingValueAttribute("https://api.sandbox.paypal.com/2.0/")] + public string SmartStore_Plugin_Payments_PayPalExpress_PayPalSvc_PayPalAPIInterfaceService { + get { + return ((string)(this["SmartStore_Plugin_Payments_PayPalExpress_PayPalSvc_PayPalAPIInterfaceService"])); + } + } + } +} diff --git a/src/Plugins/SmartStore.PayPal/Properties/Settings.settings b/src/Plugins/SmartStore.PayPal/Properties/Settings.settings new file mode 100644 index 0000000000..73b638d765 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Properties/Settings.settings @@ -0,0 +1,9 @@ + + + + + + https://api.sandbox.paypal.com/2.0/ + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalDirectProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalDirectProvider.cs new file mode 100644 index 0000000000..96a41d0cfa --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalDirectProvider.cs @@ -0,0 +1,311 @@ +using System; +using System.Globalization; +using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.Controllers; +using SmartStore.PayPal.PayPalSvc; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Customers; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal +{ + [SystemName("Payments.PayPalDirect")] + [FriendlyName("PayPal Direct")] + [DisplayOrder(1)] + public class PayPalDirectProvider : PayPalProviderBase + { + private readonly ICustomerService _customerService; + + public PayPalDirectProvider( + ICustomerService customerService) + { + _customerService = customerService; + } + + public static string SystemName { get { return "Payments.PayPalDirect"; } } + + public override bool RequiresInteraction + { + get + { + return true; + } + } + + public override RecurringPaymentType RecurringPaymentType + { + get + { + return RecurringPaymentType.Automatic; + } + } + + public override PaymentMethodType PaymentMethodType + { + get + { + return PaymentMethodType.Standard; + } + } + + private CreditCardTypeType GetCreditCardType(string creditCardType) + { + var creditCardTypeType = (CreditCardTypeType)Enum.Parse(typeof(CreditCardTypeType), creditCardType); + return creditCardTypeType; + } + + private CountryCodeType GetCountryCodeType(Country country) + { + CountryCodeType payerCountry = CountryCodeType.US; + try + { + payerCountry = (CountryCodeType)Enum.Parse(typeof(CountryCodeType), country.TwoLetterIsoCode); + } + catch { } + + return payerCountry; + } + + protected override string GetControllerName() + { + return "PayPalDirect"; + } + + public override Type GetControllerType() + { + return typeof(PayPalDirectController); + } + + protected override string GetResourceRootKey() + { + return "Plugins.Payments.PayPalDirect"; + } + + /// + /// Process a payment + /// + /// Payment info required for an order processing + /// Process payment result + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + + var store = Services.StoreService.GetStoreById(processPaymentRequest.StoreId); + var customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); + + var req = new DoDirectPaymentReq(); + req.DoDirectPaymentRequest = new DoDirectPaymentRequestType(); + req.DoDirectPaymentRequest.Version = ApiVersion; + + var details = new DoDirectPaymentRequestDetailsType(); + req.DoDirectPaymentRequest.DoDirectPaymentRequestDetails = details; + details.IPAddress = Services.WebHelper.GetCurrentIpAddress(); + + if (details.IPAddress.IsEmpty()) + details.IPAddress = "127.0.0.1"; + + if (settings.TransactMode == TransactMode.Authorize) + details.PaymentAction = PaymentActionCodeType.Authorization; + else + details.PaymentAction = PaymentActionCodeType.Sale; + + //credit card + details.CreditCard = new CreditCardDetailsType(); + details.CreditCard.CreditCardNumber = processPaymentRequest.CreditCardNumber; + details.CreditCard.CreditCardType = GetCreditCardType(processPaymentRequest.CreditCardType); + details.CreditCard.ExpMonthSpecified = true; + details.CreditCard.ExpMonth = processPaymentRequest.CreditCardExpireMonth; + details.CreditCard.ExpYearSpecified = true; + details.CreditCard.ExpYear = processPaymentRequest.CreditCardExpireYear; + details.CreditCard.CVV2 = processPaymentRequest.CreditCardCvv2; + details.CreditCard.CardOwner = new PayerInfoType(); + details.CreditCard.CardOwner.PayerCountry = GetCountryCodeType(customer.BillingAddress.Country); + details.CreditCard.CreditCardTypeSpecified = true; + //billing address + details.CreditCard.CardOwner.Address = new AddressType(); + details.CreditCard.CardOwner.Address.CountrySpecified = true; + details.CreditCard.CardOwner.Address.Street1 = customer.BillingAddress.Address1; + details.CreditCard.CardOwner.Address.Street2 = customer.BillingAddress.Address2; + details.CreditCard.CardOwner.Address.CityName = customer.BillingAddress.City; + if (customer.BillingAddress.StateProvince != null) + details.CreditCard.CardOwner.Address.StateOrProvince = customer.BillingAddress.StateProvince.Abbreviation; + else + details.CreditCard.CardOwner.Address.StateOrProvince = "CA"; + details.CreditCard.CardOwner.Address.Country = GetCountryCodeType(customer.BillingAddress.Country); + details.CreditCard.CardOwner.Address.PostalCode = customer.BillingAddress.ZipPostalCode; + details.CreditCard.CardOwner.Payer = customer.BillingAddress.Email; + details.CreditCard.CardOwner.PayerName = new PersonNameType(); + details.CreditCard.CardOwner.PayerName.FirstName = customer.BillingAddress.FirstName; + details.CreditCard.CardOwner.PayerName.LastName = customer.BillingAddress.LastName; + + //order totals + var payPalCurrency = GetApiCurrency(store.PrimaryStoreCurrency); + + details.PaymentDetails = new PaymentDetailsType(); + details.PaymentDetails.OrderTotal = new BasicAmountType(); + details.PaymentDetails.OrderTotal.Value = Math.Round(processPaymentRequest.OrderTotal, 2).ToString("N", new CultureInfo("en-us")); + details.PaymentDetails.OrderTotal.currencyID = payPalCurrency; + details.PaymentDetails.Custom = processPaymentRequest.OrderGuid.ToString(); + details.PaymentDetails.ButtonSource = SmartStoreVersion.CurrentFullVersion; + //shipping + if (customer.ShippingAddress != null) + { + if (customer.ShippingAddress.StateProvince != null && customer.ShippingAddress.Country != null) + { + var shippingAddress = new AddressType(); + shippingAddress.Name = customer.ShippingAddress.FirstName + " " + customer.ShippingAddress.LastName; + shippingAddress.Street1 = customer.ShippingAddress.Address1; + shippingAddress.CityName = customer.ShippingAddress.City; + shippingAddress.StateOrProvince = customer.ShippingAddress.StateProvince.Abbreviation; + shippingAddress.PostalCode = customer.ShippingAddress.ZipPostalCode; + shippingAddress.Country = (CountryCodeType)Enum.Parse(typeof(CountryCodeType), customer.ShippingAddress.Country.TwoLetterIsoCode, true); + shippingAddress.CountrySpecified = true; + details.PaymentDetails.ShipToAddress = shippingAddress; + } + } + + //send request + using (var service = GetApiAaService(settings)) + { + var response = service.DoDirectPayment(req); + + var error = ""; + var success = IsSuccess(response, out error); + + if (success) + { + result.AvsResult = response.AVSCode; + result.AuthorizationTransactionCode = response.CVV2Code; + if (settings.TransactMode == TransactMode.Authorize) + { + result.AuthorizationTransactionId = response.TransactionID; + result.AuthorizationTransactionResult = response.Ack.ToString(); + + result.NewPaymentStatus = PaymentStatus.Authorized; + } + else + { + result.CaptureTransactionId = response.TransactionID; + result.CaptureTransactionResult = response.Ack.ToString(); + + result.NewPaymentStatus = PaymentStatus.Paid; + } + } + else + { + result.AddError(error); + } + } + return result; + } + + /// + /// Process recurring payment + /// + /// Payment info required for an order processing + /// Process payment result + public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + + var store = Services.StoreService.GetStoreById(processPaymentRequest.StoreId); + var customer = _customerService.GetCustomerById(processPaymentRequest.CustomerId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); + + var req = new CreateRecurringPaymentsProfileReq(); + req.CreateRecurringPaymentsProfileRequest = new CreateRecurringPaymentsProfileRequestType(); + req.CreateRecurringPaymentsProfileRequest.Version = ApiVersion; + var details = new CreateRecurringPaymentsProfileRequestDetailsType(); + req.CreateRecurringPaymentsProfileRequest.CreateRecurringPaymentsProfileRequestDetails = details; + + details.CreditCard = new CreditCardDetailsType(); + details.CreditCard.CreditCardNumber = processPaymentRequest.CreditCardNumber; + details.CreditCard.CreditCardType = GetCreditCardType(processPaymentRequest.CreditCardType); + details.CreditCard.ExpMonthSpecified = true; + details.CreditCard.ExpMonth = processPaymentRequest.CreditCardExpireMonth; + details.CreditCard.ExpYearSpecified = true; + details.CreditCard.ExpYear = processPaymentRequest.CreditCardExpireYear; + details.CreditCard.CVV2 = processPaymentRequest.CreditCardCvv2; + details.CreditCard.CardOwner = new PayerInfoType(); + details.CreditCard.CardOwner.PayerCountry = GetCountryCodeType(customer.BillingAddress.Country); + details.CreditCard.CreditCardTypeSpecified = true; + + details.CreditCard.CardOwner.Address = new AddressType(); + details.CreditCard.CardOwner.Address.CountrySpecified = true; + details.CreditCard.CardOwner.Address.Street1 = customer.BillingAddress.Address1; + details.CreditCard.CardOwner.Address.Street2 = customer.BillingAddress.Address2; + details.CreditCard.CardOwner.Address.CityName = customer.BillingAddress.City; + if (customer.BillingAddress.StateProvince != null) + details.CreditCard.CardOwner.Address.StateOrProvince = customer.BillingAddress.StateProvince.Abbreviation; + else + details.CreditCard.CardOwner.Address.StateOrProvince = "CA"; + details.CreditCard.CardOwner.Address.Country = GetCountryCodeType(customer.BillingAddress.Country); + details.CreditCard.CardOwner.Address.PostalCode = customer.BillingAddress.ZipPostalCode; + details.CreditCard.CardOwner.Payer = customer.BillingAddress.Email; + details.CreditCard.CardOwner.PayerName = new PersonNameType(); + details.CreditCard.CardOwner.PayerName.FirstName = customer.BillingAddress.FirstName; + details.CreditCard.CardOwner.PayerName.LastName = customer.BillingAddress.LastName; + + //start date + details.RecurringPaymentsProfileDetails = new RecurringPaymentsProfileDetailsType(); + details.RecurringPaymentsProfileDetails.BillingStartDate = DateTime.UtcNow; + details.RecurringPaymentsProfileDetails.ProfileReference = processPaymentRequest.OrderGuid.ToString(); + + //schedule + details.ScheduleDetails = new ScheduleDetailsType(); + details.ScheduleDetails.Description = T("Plugins.Payments.PayPalDirect.RecurringPayment"); + details.ScheduleDetails.PaymentPeriod = new BillingPeriodDetailsType(); + details.ScheduleDetails.PaymentPeriod.Amount = new BasicAmountType(); + details.ScheduleDetails.PaymentPeriod.Amount.Value = Math.Round(processPaymentRequest.OrderTotal, 2).ToString("N", new CultureInfo("en-us")); + details.ScheduleDetails.PaymentPeriod.Amount.currencyID = GetApiCurrency(store.PrimaryStoreCurrency); + details.ScheduleDetails.PaymentPeriod.BillingFrequency = processPaymentRequest.RecurringCycleLength; + switch (processPaymentRequest.RecurringCyclePeriod) + { + case RecurringProductCyclePeriod.Days: + details.ScheduleDetails.PaymentPeriod.BillingPeriod = BillingPeriodType.Day; + break; + case RecurringProductCyclePeriod.Weeks: + details.ScheduleDetails.PaymentPeriod.BillingPeriod = BillingPeriodType.Week; + break; + case RecurringProductCyclePeriod.Months: + details.ScheduleDetails.PaymentPeriod.BillingPeriod = BillingPeriodType.Month; + break; + case RecurringProductCyclePeriod.Years: + details.ScheduleDetails.PaymentPeriod.BillingPeriod = BillingPeriodType.Year; + break; + default: + throw new SmartException(T("Plugins.Payments.PayPalDirect.NotSupportedPeriod")); + } + details.ScheduleDetails.PaymentPeriod.TotalBillingCycles = processPaymentRequest.RecurringTotalCycles; + details.ScheduleDetails.PaymentPeriod.TotalBillingCyclesSpecified = true; + + using (var service = GetApiAaService(settings)) + { + var response = service.CreateRecurringPaymentsProfile(req); + + var error = ""; + var success = IsSuccess(response, out error); + + if (success) + { + result.NewPaymentStatus = PaymentStatus.Pending; + if (response.CreateRecurringPaymentsProfileResponseDetails != null) + { + result.SubscriptionTransactionId = response.CreateRecurringPaymentsProfileResponseDetails.ProfileID; + } + } + else + { + result.AddError(error); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalExpressProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalExpressProvider.cs new file mode 100644 index 0000000000..98c4e8e223 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalExpressProvider.cs @@ -0,0 +1,597 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Web; +using SmartStore.Core; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.Controllers; +using SmartStore.PayPal.PayPalSvc; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Catalog; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Services.Shipping; +using SmartStore.Services.Tax; + +namespace SmartStore.PayPal +{ + [SystemName("Payments.PayPalExpress")] + [FriendlyName("PayPal Express")] + [DisplayOrder(0)] + public partial class PayPalExpressProvider : PayPalProviderBase + { + private readonly ICurrencyService _currencyService; + private readonly IPriceCalculationService _priceCalculationService; + private readonly ITaxService _taxService; + private readonly IGenericAttributeService _genericAttributeService; + private readonly IStateProvinceService _stateProvinceService; + private readonly IGiftCardService _giftCardService; + private readonly IShippingService _shippingService; + private readonly ICustomerService _customerService; + private readonly ICountryService _countryService; + private readonly HttpContextBase _httpContext; + + public PayPalExpressProvider( + ICurrencyService currencyService, + IPriceCalculationService priceCalculationService, + ITaxService taxService, + IGenericAttributeService genericAttributeService, + IStateProvinceService stateProvinceService, + IGiftCardService giftCardService, + IShippingService shippingService, + ICustomerService customerService, + ICountryService countryService, + HttpContextBase httpContext) + { + _currencyService = currencyService; + _priceCalculationService = priceCalculationService; + _taxService = taxService; + _genericAttributeService = genericAttributeService; + _stateProvinceService = stateProvinceService; + _giftCardService = giftCardService; + _shippingService = shippingService; + _customerService = customerService; + _countryService = countryService; + _httpContext = httpContext; + } + + public static string SystemName { get { return "Payments.PayPalExpress"; } } + + public override PaymentMethodType PaymentMethodType + { + get + { + return PaymentMethodType.StandardAndButton; + } + } + + private PaymentActionCodeType GetPaymentAction(PayPalExpressPaymentSettings settings) + { + if (settings.TransactMode == TransactMode.Authorize) + { + return PaymentActionCodeType.Authorization; + } + else + { + return PaymentActionCodeType.Sale; + } + } + + protected override string GetResourceRootKey() + { + return "Plugins.Payments.PayPalExpress"; + } + + /// + /// Process a payment + /// + /// Payment info required for an order processing + /// Process payment result + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); + + var doPayment = DoExpressCheckoutPayment(processPaymentRequest); + + if (doPayment.Ack == AckCodeType.Success) + { + if (GetPaymentAction(settings) == PaymentActionCodeType.Authorization) + { + result.AuthorizationTransactionId = doPayment.DoExpressCheckoutPaymentResponseDetails.PaymentInfo.FirstOrDefault().TransactionID; + result.AuthorizationTransactionResult = doPayment.Ack.ToString(); + + result.NewPaymentStatus = PaymentStatus.Authorized; + } + else + { + result.CaptureTransactionId = doPayment.DoExpressCheckoutPaymentResponseDetails.PaymentInfo.FirstOrDefault().TransactionID; + result.CaptureTransactionResult = doPayment.Ack.ToString(); + + result.NewPaymentStatus = PaymentStatus.Paid; + } + + //result.AuthorizationTransactionId = processPaymentRequest.PaypalToken; + //result.CaptureTransactionId = doPayment.DoExpressCheckoutPaymentResponseDetails.PaymentInfo.FirstOrDefault().TransactionID; + //result.CaptureTransactionResult = doPayment.Ack.ToString(); + } + else + { + result.NewPaymentStatus = PaymentStatus.Pending; + + result.Errors.Each(x => result.AddError(x)); + } + + return result; + } + + /// + /// Process recurring payment + /// + /// Payment info required for an order processing + /// Process payment result + public override ProcessPaymentResult ProcessRecurringPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + //TODO + return result; + } + + protected override string GetControllerName() + { + return "PayPalExpress"; + } + + public override Type GetControllerType() + { + return typeof(PayPalExpressController); + } + + public SetExpressCheckoutResponseType SetExpressCheckout(PayPalProcessPaymentRequest processPaymentRequest, IList cart) + { + var result = new SetExpressCheckoutResponseType(); + var store = Services.StoreService.GetStoreById(processPaymentRequest.StoreId); + var customer = Services.WorkContext.CurrentCustomer; + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); + var payPalCurrency = GetApiCurrency(store.PrimaryStoreCurrency); + var excludingTax = (Services.WorkContext.GetTaxDisplayTypeFor(customer, store.Id) == TaxDisplayType.ExcludingTax); + + var req = new SetExpressCheckoutReq + { + SetExpressCheckoutRequest = new SetExpressCheckoutRequestType + { + Version = ApiVersion, + SetExpressCheckoutRequestDetails = new SetExpressCheckoutRequestDetailsType() + } + }; + + var details = new SetExpressCheckoutRequestDetailsType + { + PaymentAction = GetPaymentAction(settings), + PaymentActionSpecified = true, + CancelURL = Services.WebHelper.GetStoreLocation(store.SslEnabled) + "cart", + ReturnURL = Services.WebHelper.GetStoreLocation(store.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalExpress/GetDetails", + //CallbackURL = _webHelper.GetStoreLocation(currentStore.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalExpress/ShippingOptions?CustomerID=" + _workContext.CurrentCustomer.Id.ToString(), + //CallbackTimeout = _payPalExpressPaymentSettings.CallbackTimeout.ToString() + ReqConfirmShipping = settings.ConfirmedShipment.ToString(), + NoShipping = settings.NoShipmentAddress.ToString() + }; + + // populate cart + var taxRate = decimal.Zero; + var unitPriceTaxRate = decimal.Zero; + var itemTotal = decimal.Zero; + var cartItems = new List(); + + foreach (var item in cart) + { + var product = item.Item.Product; + var unitPrice = _priceCalculationService.GetUnitPrice(item, true); + var shoppingCartUnitPriceWithDiscount = excludingTax + ? _taxService.GetProductPrice(product, unitPrice, false, customer, out taxRate) + : _taxService.GetProductPrice(product, unitPrice, true, customer, out unitPriceTaxRate); + + cartItems.Add(new PaymentDetailsItemType + { + Name = product.Name, + Number = product.Sku, + Quantity = item.Item.Quantity.ToString(), + // this is the per item cost + Amount = new BasicAmountType + { + currencyID = payPalCurrency, + Value = shoppingCartUnitPriceWithDiscount.FormatInvariant() + } + }); + + itemTotal += (item.Item.Quantity * shoppingCartUnitPriceWithDiscount); + }; + + // additional handling fee + var additionalHandlingFee = GetAdditionalHandlingFee(cart); + cartItems.Add(new PaymentDetailsItemType + { + Name = T("Plugins.Payments.PayPal.PaymentMethodFee").Text, + Quantity = "1", + Amount = new BasicAmountType() + { + currencyID = payPalCurrency, + Value = additionalHandlingFee.FormatInvariant() + } + }); + + itemTotal += GetAdditionalHandlingFee(cart); + + //shipping + var shippingTotal = decimal.Zero; + if (cart.RequiresShipping()) + { + decimal? shoppingCartShippingBase = OrderTotalCalculationService.GetShoppingCartShippingTotal(cart); + if (shoppingCartShippingBase.HasValue && shoppingCartShippingBase > 0) + { + shippingTotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartShippingBase.Value, Services.WorkContext.WorkingCurrency); + } + else + { + shippingTotal = settings.DefaultShippingPrice; + } + } + + //This is the default if the Shipping Callback fails + //var shippingOptions = new List(); + //shippingOptions.Add(new ShippingOptionType() + //{ + // ShippingOptionIsDefault = "true", + // ShippingOptionName = "Standard Shipping", + // ShippingOptionAmount = new BasicAmountType() + // { + // Value = shippingTotal.ToString(), //This is the default value used for shipping if the Instant Update API returns an error or does not answer within the callback time + // currencyID = PaypalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)) + // } + //}); + //details.FlatRateShippingOptions = shippingOptions.ToArray(); + //details.TotalType = TotalType.EstimatedTotal; + + // get total tax + //SortedDictionary taxRates = null; + //decimal shoppingCartTaxBase = OrderTotalCalculationService.GetTaxTotal(cart, out taxRates); + //decimal shoppingCartTax = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTaxBase, CommonServices.WorkContext.WorkingCurrency); + + // discount + var discount = -processPaymentRequest.Discount; + if (discount != 0) + { + cartItems.Add(new PaymentDetailsItemType + { + Name = T("Plugins.Payments.PayPal.ThreadrockDiscount").Text, + Quantity = "1", + Amount = new BasicAmountType // this is the total discount + { + currencyID = payPalCurrency, + Value = discount.FormatInvariant() + } + }); + + itemTotal += discount; + } + + if (!cart.IsRecurring()) + { + //we don't apply gift cards for recurring products + var giftCards = _giftCardService.GetActiveGiftCardsAppliedByCustomer(customer); + if (giftCards != null) + { + foreach (var gc in giftCards) + { + if (itemTotal > decimal.Zero) + { + decimal remainingAmount = gc.GetGiftCardRemainingAmount(); + decimal amountCanBeUsed = decimal.Zero; + if (itemTotal > remainingAmount) + amountCanBeUsed = remainingAmount; + else + amountCanBeUsed = itemTotal - .01M; + + decimal amountToSubtract = -amountCanBeUsed; + + cartItems.Add(new PaymentDetailsItemType + { + Name = T("Plugins.Payments.PayPal.GiftcardApplied").Text, + Quantity = "1", + Amount = new BasicAmountType + { + currencyID = payPalCurrency, + Value = amountToSubtract.FormatInvariant() + } + }); + + //reduce subtotal + itemTotal += amountToSubtract; + } + } + } + } + + // populate payment details + var paymentDetails = new PaymentDetailsType + { + ItemTotal = new BasicAmountType + { + Value = Math.Round(itemTotal, 2).FormatInvariant(), + currencyID = payPalCurrency + }, + ShippingTotal = new BasicAmountType + { + Value = Math.Round(shippingTotal, 2).FormatInvariant(), + currencyID = payPalCurrency + }, + //TaxTotal = new BasicAmountType + //{ + // Value = Math.Round(shoppingCartTax, 2).ToString("N", new CultureInfo("en-us")), + // currencyID = PayPalHelper.GetPaypalCurrency(_currencyService.GetCurrencyById(_currencySettings.PrimaryStoreCurrencyId)) + //}, + OrderTotal = new BasicAmountType + { + Value = Math.Round(itemTotal + shippingTotal, 2).FormatInvariant(), + currencyID = payPalCurrency + }, + Custom = processPaymentRequest.OrderGuid.ToString(), + ButtonSource = SmartStoreVersion.CurrentFullVersion, + PaymentAction = GetPaymentAction(settings), + PaymentDetailsItem = cartItems.ToArray() + }; + details.PaymentDetails = new[] { paymentDetails }; + + details.ShippingMethodSpecified = true; + + req.SetExpressCheckoutRequest.SetExpressCheckoutRequestDetails.Custom = processPaymentRequest.OrderGuid.ToString(); + req.SetExpressCheckoutRequest.SetExpressCheckoutRequestDetails = details; + + using (var service = GetApiAaService(settings)) + { + result = service.SetExpressCheckout(req); + } + + _httpContext.GetCheckoutState().CustomProperties.Add("PayPalExpressButtonUsed", true); + return result; + } + + public GetExpressCheckoutDetailsResponseType GetExpressCheckoutDetails(string token) + { + var result = new GetExpressCheckoutDetailsResponseType(); + var settings = Services.Settings.LoadSetting(Services.StoreContext.CurrentStore.Id); + + using (var service = GetApiAaService(settings)) + { + var req = new GetExpressCheckoutDetailsReq(); + req.GetExpressCheckoutDetailsRequest = new GetExpressCheckoutDetailsRequestType + { + Token = token, + Version = ApiVersion + }; + + result = service.GetExpressCheckoutDetails(req); + } + return result; + } + + public ProcessPaymentRequest SetCheckoutDetails(ProcessPaymentRequest processPaymentRequest, GetExpressCheckoutDetailsResponseDetailsType checkoutDetails) + { + int customerId = Convert.ToInt32(Services.WorkContext.CurrentCustomer.Id.ToString()); + var customer = _customerService.GetCustomerById(customerId); + var settings = Services.Settings.LoadSetting(Services.StoreContext.CurrentStore.Id); + + Services.WorkContext.CurrentCustomer = customer; + + //var cart = customer.ShoppingCartItems.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList(); + var cart = Services.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, Services.StoreContext.CurrentStore.Id); + + // get/update billing address + string billingFirstName = checkoutDetails.PayerInfo.PayerName.FirstName; + string billingLastName = checkoutDetails.PayerInfo.PayerName.LastName; + string billingEmail = checkoutDetails.PayerInfo.Payer; + string billingAddress1 = checkoutDetails.PayerInfo.Address.Street1; + string billingAddress2 = checkoutDetails.PayerInfo.Address.Street2; + string billingPhoneNumber = checkoutDetails.PayerInfo.ContactPhone; + string billingCity = checkoutDetails.PayerInfo.Address.CityName; + int? billingStateProvinceId = null; + var billingStateProvince = _stateProvinceService.GetStateProvinceByAbbreviation(checkoutDetails.PayerInfo.Address.StateOrProvince); + if (billingStateProvince != null) + billingStateProvinceId = billingStateProvince.Id; + string billingZipPostalCode = checkoutDetails.PayerInfo.Address.PostalCode; + int? billingCountryId = null; + var billingCountry = _countryService.GetCountryByTwoLetterIsoCode(checkoutDetails.PayerInfo.Address.Country.ToString()); + if (billingCountry != null) + billingCountryId = billingCountry.Id; + + var billingAddress = customer.Addresses.FindAddress( + billingFirstName, billingLastName, billingPhoneNumber, + billingEmail, string.Empty, string.Empty, billingAddress1, billingAddress2, billingCity, + billingStateProvinceId, billingZipPostalCode, billingCountryId); + + if (billingAddress == null) + { + billingAddress = new Core.Domain.Common.Address() + { + FirstName = billingFirstName, + LastName = billingLastName, + PhoneNumber = billingPhoneNumber, + Email = billingEmail, + FaxNumber = string.Empty, + Company = string.Empty, + Address1 = billingAddress1, + Address2 = billingAddress2, + City = billingCity, + StateProvinceId = billingStateProvinceId, + ZipPostalCode = billingZipPostalCode, + CountryId = billingCountryId, + CreatedOnUtc = DateTime.UtcNow, + }; + customer.Addresses.Add(billingAddress); + } + + //set default billing address + customer.BillingAddress = billingAddress; + _customerService.UpdateCustomer(customer); + + var genericAttributeService = EngineContext.Current.Resolve(); + genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedShippingOption, null); + + bool shoppingCartRequiresShipping = cart.RequiresShipping(); + if (shoppingCartRequiresShipping) + { + var paymentDetails = checkoutDetails.PaymentDetails.FirstOrDefault(); + string[] shippingFullname = paymentDetails.ShipToAddress.Name.Trim().Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); + string shippingFirstName = shippingFullname[0]; + string shippingLastName = string.Empty; + if (shippingFullname.Length > 1) + shippingLastName = shippingFullname[1]; + string shippingEmail = checkoutDetails.PayerInfo.Payer; + string shippingAddress1 = paymentDetails.ShipToAddress.Street1; + string shippingAddress2 = paymentDetails.ShipToAddress.Street2; + string shippingPhoneNumber = paymentDetails.ShipToAddress.Phone; + string shippingCity = paymentDetails.ShipToAddress.CityName; + int? shippingStateProvinceId = null; + var shippingStateProvince = _stateProvinceService.GetStateProvinceByAbbreviation(paymentDetails.ShipToAddress.StateOrProvince); + if (shippingStateProvince != null) + shippingStateProvinceId = shippingStateProvince.Id; + int? shippingCountryId = null; + string shippingZipPostalCode = paymentDetails.ShipToAddress.PostalCode; + var shippingCountry = _countryService.GetCountryByTwoLetterIsoCode(paymentDetails.ShipToAddress.Country.ToString()); + if (shippingCountry != null) + shippingCountryId = shippingCountry.Id; + + var shippingAddress = customer.Addresses.FindAddress( + shippingFirstName, shippingLastName, shippingPhoneNumber, + shippingEmail, string.Empty, string.Empty, + shippingAddress1, shippingAddress2, shippingCity, + shippingStateProvinceId, shippingZipPostalCode, shippingCountryId); + + if (shippingAddress == null) + { + shippingAddress = new Core.Domain.Common.Address() + { + FirstName = shippingFirstName, + LastName = shippingLastName, + PhoneNumber = shippingPhoneNumber, + Email = shippingEmail, + FaxNumber = string.Empty, + Company = string.Empty, + Address1 = shippingAddress1, + Address2 = shippingAddress2, + City = shippingCity, + StateProvinceId = shippingStateProvinceId, + ZipPostalCode = shippingZipPostalCode, + CountryId = shippingCountryId, + CreatedOnUtc = DateTime.UtcNow, + }; + customer.Addresses.Add(shippingAddress); + } + + customer.ShippingAddress = shippingAddress; + _customerService.UpdateCustomer(customer); + } + + bool isShippingSet = false; + GetShippingOptionResponse getShippingOptionResponse = _shippingService.GetShippingOptions(cart, customer.ShippingAddress); + + if (checkoutDetails.UserSelectedOptions != null) + { + if (getShippingOptionResponse.Success && getShippingOptionResponse.ShippingOptions.Count > 0) + { + foreach (var shippingOption in getShippingOptionResponse.ShippingOptions) + { + if (checkoutDetails.UserSelectedOptions.ShippingOptionName.Contains(shippingOption.Name) && + checkoutDetails.UserSelectedOptions.ShippingOptionName.Contains(shippingOption.Description)) + { + _genericAttributeService.SaveAttribute(Services.WorkContext.CurrentCustomer, SystemCustomerAttributeNames.SelectedShippingOption, shippingOption); + isShippingSet = true; + break; + } + + } + } + + if (!isShippingSet) + { + var shippingOption = new ShippingOption(); + shippingOption.Name = checkoutDetails.UserSelectedOptions.ShippingOptionName; + decimal shippingPrice = settings.DefaultShippingPrice; + decimal.TryParse(checkoutDetails.UserSelectedOptions.ShippingOptionAmount.Value, out shippingPrice); + shippingOption.Rate = shippingPrice; + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.SelectedShippingOption, shippingOption); + } + } + + processPaymentRequest.PaypalPayerId = checkoutDetails.PayerInfo.PayerID; + + + return processPaymentRequest; + } + + public DoExpressCheckoutPaymentResponseType DoExpressCheckoutPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new DoExpressCheckoutPaymentResponseType(); + var store = Services.StoreService.GetStoreById(processPaymentRequest.StoreId); + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); + + // populate payment details + var paymentDetails = new PaymentDetailsType + { + OrderTotal = new BasicAmountType + { + Value = Math.Round(processPaymentRequest.OrderTotal, 2).ToString("N", new CultureInfo("en-us")), + currencyID = GetApiCurrency(store.PrimaryStoreCurrency) + }, + Custom = processPaymentRequest.OrderGuid.ToString(), + ButtonSource = SmartStoreVersion.CurrentFullVersion + }; + + // build the request + var req = new DoExpressCheckoutPaymentReq + { + DoExpressCheckoutPaymentRequest = new DoExpressCheckoutPaymentRequestType + { + Version = ApiVersion, + DoExpressCheckoutPaymentRequestDetails = new DoExpressCheckoutPaymentRequestDetailsType + { + Token = processPaymentRequest.PaypalToken, + PayerID = processPaymentRequest.PaypalPayerId, + PaymentAction = GetPaymentAction(settings), + PaymentActionSpecified = true, + PaymentDetails = new PaymentDetailsType[] + { + paymentDetails + } + } + } + }; + + //execute request + using (var service = GetApiAaService(settings)) + { + result = service.DoExpressCheckoutPayment(req); + } + return result; + } + } + + + public class PayPalProcessPaymentRequest : ProcessPaymentRequest + { + /// + /// Gets or sets an order Discount Amount + /// + public decimal Discount { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalPlusProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalPlusProvider.cs new file mode 100644 index 0000000000..45e251d2d0 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalPlusProvider.cs @@ -0,0 +1,32 @@ +using System; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.Controllers; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal +{ + [SystemName("Payments.PayPalPlus")] + [FriendlyName("PayPal PLUS")] + [DisplayOrder(1)] + public partial class PayPalPlusProvider : PayPalRestApiProviderBase + { + public static string SystemName + { + get { return "Payments.PayPalPlus"; } + } + + public override PaymentMethodType PaymentMethodType + { + get + { + return PaymentMethodType.StandardAndRedirection; + } + } + + public override Type GetControllerType() + { + return typeof(PayPalPlusController); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalProviderBase.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalProviderBase.cs new file mode 100644 index 0000000000..1c65bd39dd --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalProviderBase.cs @@ -0,0 +1,398 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Text; +using System.Web.Routing; +using SmartStore.Core.Configuration; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.PayPalSvc; +using SmartStore.PayPal.Settings; +using SmartStore.Services; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal +{ + public abstract class PayPalProviderBase : PaymentMethodBase, IConfigurable where TSetting : PayPalApiSettingsBase, ISettings, new() + { + protected PayPalProviderBase() + { + Logger = NullLogger.Instance; + } + + public static string ApiVersion + { + get { return "109"; } + } + + public ILogger Logger { get; set; } + public ICommonServices Services { get; set; } + public IOrderService OrderService { get; set; } + public IOrderTotalCalculationService OrderTotalCalculationService { get; set; } + + public override bool SupportCapture + { + get { return true; } + } + + public override bool SupportPartiallyRefund + { + get { return true; } + } + + public override bool SupportRefund + { + get { return true; } + } + + public override bool SupportVoid + { + get { return true; } + } + + protected abstract string GetResourceRootKey(); + + protected PayPalAPIAASoapBinding GetApiAaService(TSetting settings) + { + if (settings.SecurityProtocol.HasValue) + { + ServicePointManager.SecurityProtocol = settings.SecurityProtocol.Value; + } + + var service = new PayPalAPIAASoapBinding(); + + service.Url = settings.UseSandbox ? "https://api-3t.sandbox.paypal.com/2.0/" : "https://api-3t.paypal.com/2.0/"; + + service.RequesterCredentials = GetApiCredentials(settings); + + return service; + } + + protected PayPalAPISoapBinding GetApiService(TSetting settings) + { + if (settings.SecurityProtocol.HasValue) + { + ServicePointManager.SecurityProtocol = settings.SecurityProtocol.Value; + } + + var service = new PayPalAPISoapBinding(); + + service.Url = settings.UseSandbox ? "https://api-3t.sandbox.paypal.com/2.0/" : "https://api-3t.paypal.com/2.0/"; + + service.RequesterCredentials = GetApiCredentials(settings); + + return service; + } + + protected CustomSecurityHeaderType GetApiCredentials(PayPalApiSettingsBase settings) + { + var customSecurityHeaderType = new CustomSecurityHeaderType(); + + customSecurityHeaderType.Credentials = new UserIdPasswordType(); + customSecurityHeaderType.Credentials.Username = settings.ApiAccountName; + customSecurityHeaderType.Credentials.Password = settings.ApiAccountPassword; + customSecurityHeaderType.Credentials.Signature = settings.Signature; + customSecurityHeaderType.Credentials.Subject = ""; + + return customSecurityHeaderType; + } + + protected CurrencyCodeType GetApiCurrency(Currency currency) + { + var currencyCodeType = CurrencyCodeType.USD; + try + { + currencyCodeType = (CurrencyCodeType)Enum.Parse(typeof(CurrencyCodeType), currency.CurrencyCode, true); + } + catch { } + + return currencyCodeType; + } + + protected bool IsSuccess(AbstractResponseType abstractResponse, out string errorMsg) + { + var success = false; + var sb = new StringBuilder(); + + switch (abstractResponse.Ack) + { + case AckCodeType.Success: + case AckCodeType.SuccessWithWarning: + success = true; + break; + default: + break; + } + + if (null != abstractResponse.Errors) + { + foreach (ErrorType errorType in abstractResponse.Errors) + { + if (errorType.ShortMessage.IsEmpty()) + continue; + + if (sb.Length > 0) + sb.Append(Environment.NewLine); + + sb.Append("{0}: {1}".FormatInvariant(Services.Localization.GetResource("Admin.System.Log.Fields.ShortMessage"), errorType.ShortMessage)); + sb.AppendLine(" ({0}).".FormatInvariant(errorType.ErrorCode)); + + if (errorType.LongMessage.HasValue() && errorType.LongMessage != errorType.ShortMessage) + sb.AppendLine("{0}: {1}".FormatInvariant(Services.Localization.GetResource("Admin.System.Log.Fields.FullMessage"), errorType.LongMessage)); + } + } + + errorMsg = sb.ToString(); + return success; + } + + protected abstract string GetControllerName(); + + /// + /// Gets additional handling fee + /// + /// Shoping cart + /// Additional handling fee + public override decimal GetAdditionalHandlingFee(IList cart) + { + var result = decimal.Zero; + try + { + var settings = Services.Settings.LoadSetting(); + + result = this.CalculateAdditionalFee(OrderTotalCalculationService, cart, settings.AdditionalFee, settings.AdditionalFeePercentage); + } + catch (Exception) + { + } + return result; + } + + /// + /// Captures payment + /// + /// Capture payment request + /// Capture payment result + public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) + { + var result = new CapturePaymentResult + { + NewPaymentStatus = capturePaymentRequest.Order.PaymentStatus + }; + + var settings = Services.Settings.LoadSetting(capturePaymentRequest.Order.StoreId); + var currencyCode = Services.WorkContext.WorkingCurrency.CurrencyCode ?? "EUR"; + + var authorizationId = capturePaymentRequest.Order.AuthorizationTransactionId; + + var req = new DoCaptureReq(); + req.DoCaptureRequest = new DoCaptureRequestType(); + req.DoCaptureRequest.Version = ApiVersion; + req.DoCaptureRequest.AuthorizationID = authorizationId; + req.DoCaptureRequest.Amount = new BasicAmountType(); + req.DoCaptureRequest.Amount.Value = Math.Round(capturePaymentRequest.Order.OrderTotal, 2).ToString("N", new CultureInfo("en-us")); + req.DoCaptureRequest.Amount.currencyID = (CurrencyCodeType)Enum.Parse(typeof(CurrencyCodeType), currencyCode, true); + req.DoCaptureRequest.CompleteType = CompleteCodeType.Complete; + + using (var service = GetApiAaService(settings)) + { + var response = service.DoCapture(req); + + var error = ""; + var success = IsSuccess(response, out error); + + if (success) + { + result.NewPaymentStatus = PaymentStatus.Paid; + result.CaptureTransactionId = response.DoCaptureResponseDetails.PaymentInfo.TransactionID; + result.CaptureTransactionResult = response.Ack.ToString(); + } + else + { + result.AddError(error); + } + } + return result; + } + + public override RefundPaymentResult Refund(RefundPaymentRequest request) + { + // "Transaction refused (10009). You can not refund this type of transaction.": + // merchant must accept the payment in his PayPal account + var result = new RefundPaymentResult + { + NewPaymentStatus = request.Order.PaymentStatus + }; + + var settings = Services.Settings.LoadSetting(request.Order.StoreId); + + var transactionId = request.Order.CaptureTransactionId; + + var req = new RefundTransactionReq(); + req.RefundTransactionRequest = new RefundTransactionRequestType(); + + if (request.IsPartialRefund) + { + var store = Services.StoreService.GetStoreById(request.Order.StoreId); + var currencyCode = store.PrimaryStoreCurrency.CurrencyCode; + + req.RefundTransactionRequest.RefundType = RefundType.Partial; + + req.RefundTransactionRequest.Amount = new BasicAmountType(); + req.RefundTransactionRequest.Amount.Value = Math.Round(request.AmountToRefund, 2).ToString("N", new CultureInfo("en-us")); + req.RefundTransactionRequest.Amount.currencyID = (CurrencyCodeType)Enum.Parse(typeof(CurrencyCodeType), currencyCode, true); + + // see https://developer.paypal.com/docs/classic/express-checkout/digital-goods/ECDGIssuingRefunds/ + // https://developer.paypal.com/docs/classic/api/merchant/RefundTransaction_API_Operation_NVP/ + var memo = Services.Localization.GetResource("Plugins.SmartStore.PayPal.PartialRefundMemo", 0, false, "", true); + if (memo.HasValue()) + { + req.RefundTransactionRequest.Memo = memo.FormatInvariant(req.RefundTransactionRequest.Amount.Value); + } + } + else + { + req.RefundTransactionRequest.RefundType = RefundType.Full; + } + + req.RefundTransactionRequest.RefundTypeSpecified = true; + req.RefundTransactionRequest.Version = ApiVersion; + req.RefundTransactionRequest.TransactionID = transactionId; + + using (var service = GetApiService(settings)) + { + var response = service.RefundTransaction(req); + + var error = ""; + var Success = IsSuccess(response, out error); + + if (Success) + { + if (request.IsPartialRefund) + result.NewPaymentStatus = PaymentStatus.PartiallyRefunded; + else + result.NewPaymentStatus = PaymentStatus.Refunded; + + //cancelPaymentResult.RefundTransactionID = response.RefundTransactionID; + } + else + { + result.AddError(error); + } + } + + return result; + } + + /// + /// Voids a payment + /// + /// Request + /// Result + public override VoidPaymentResult Void(VoidPaymentRequest request) + { + var result = new VoidPaymentResult + { + NewPaymentStatus = request.Order.PaymentStatus + }; + + var settings = Services.Settings.LoadSetting(request.Order.StoreId); + + var transactionId = request.Order.AuthorizationTransactionId; + + if (transactionId.IsEmpty()) + transactionId = request.Order.CaptureTransactionId; + + var req = new DoVoidReq(); + req.DoVoidRequest = new DoVoidRequestType(); + req.DoVoidRequest.Version = ApiVersion; + req.DoVoidRequest.AuthorizationID = transactionId; + + using (var service = GetApiAaService(settings)) + { + var response = service.DoVoid(req); + + var error = ""; + var success = IsSuccess(response, out error); + + if (success) + { + result.NewPaymentStatus = PaymentStatus.Voided; + //result.VoidTransactionID = response.RefundTransactionID; + } + else + { + result.AddError(error); + } + } + return result; + } + + /// + /// Cancels a recurring payment + /// + /// Request + /// Result + public override CancelRecurringPaymentResult CancelRecurringPayment(CancelRecurringPaymentRequest request) + { + var result = new CancelRecurringPaymentResult(); + var order = request.Order; + var settings = Services.Settings.LoadSetting(order.StoreId); + + var req = new ManageRecurringPaymentsProfileStatusReq(); + req.ManageRecurringPaymentsProfileStatusRequest = new ManageRecurringPaymentsProfileStatusRequestType(); + req.ManageRecurringPaymentsProfileStatusRequest.Version = ApiVersion; + var details = new ManageRecurringPaymentsProfileStatusRequestDetailsType(); + req.ManageRecurringPaymentsProfileStatusRequest.ManageRecurringPaymentsProfileStatusRequestDetails = details; + + details.Action = StatusChangeActionType.Cancel; + //Recurring payments profile ID returned in the CreateRecurringPaymentsProfile response + details.ProfileID = order.SubscriptionTransactionId; + + using (var service = GetApiAaService(settings)) + { + var response = service.ManageRecurringPaymentsProfileStatus(req); + + string error = ""; + if (!IsSuccess(response, out error)) + { + result.AddError(error); + } + } + + return result; + } + + /// + /// Gets a route for provider configuration + /// + /// Action name + /// Controller name + /// Route values + public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = GetControllerName(); + routeValues = new RouteValueDictionary() { { "area", "SmartStore.PayPal" } }; + } + + /// + /// Gets a route for payment info + /// + /// Action name + /// Controller name + /// Route values + public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "PaymentInfo"; + controllerName = GetControllerName(); + routeValues = new RouteValueDictionary() { { "area", "SmartStore.PayPal" } }; + } + } +} + diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalRestApiProviderBase.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalRestApiProviderBase.cs new file mode 100644 index 0000000000..2330c9d336 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalRestApiProviderBase.cs @@ -0,0 +1,258 @@ +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.Routing; +using SmartStore.Core.Configuration; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.Services; +using SmartStore.PayPal.Settings; +using SmartStore.Services; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal +{ + public abstract class PayPalRestApiProviderBase : PaymentMethodBase, IConfigurable where TSetting : PayPalApiSettingsBase, ISettings, new() + { + protected PayPalRestApiProviderBase() + { + Logger = NullLogger.Instance; + } + + public ILogger Logger { get; set; } + public HttpContextBase HttpContext { get; set; } + public ICommonServices Services { get; set; } + public IOrderService OrderService { get; set; } + public IOrderTotalCalculationService OrderTotalCalculationService { get; set; } + public IPayPalService PayPalService { get; set; } + + protected string GetControllerName() + { + return GetControllerType().Name.EmptyNull().Replace("Controller", ""); + } + + public static string CheckoutCompletedKey + { + get { return "PayPalCheckoutCompleted"; } + } + + public override bool SupportCapture + { + get { return true; } + } + + public override bool SupportPartiallyRefund + { + get { return true; } + } + + public override bool SupportRefund + { + get { return true; } + } + + public override bool SupportVoid + { + get { return true; } + } + + public override decimal GetAdditionalHandlingFee(IList cart) + { + var result = decimal.Zero; + try + { + var settings = Services.Settings.LoadSetting(); + + result = this.CalculateAdditionalFee(OrderTotalCalculationService, cart, settings.AdditionalFee, settings.AdditionalFeePercentage); + } + catch (Exception) + { + } + return result; + } + + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult + { + NewPaymentStatus = PaymentStatus.Pending + }; + + HttpContext.Session.SafeRemove(CheckoutCompletedKey); + + var settings = Services.Settings.LoadSetting(processPaymentRequest.StoreId); + var session = HttpContext.GetPayPalSessionData(); + + processPaymentRequest.OrderGuid = session.OrderGuid; + + var apiResult = PayPalService.ExecutePayment(settings, session); + + if (apiResult.Success && apiResult.Json != null) + { + var state = (string)apiResult.Json.state; + string reasonCode = null; + dynamic relatedObject = null; + + if (!state.IsCaseInsensitiveEqual("failed")) + { + // the payment id is required to find the order during webhook message processing + result.AuthorizationTransactionCode = apiResult.Id; + + // intent: "sale" for immediate payment, "authorize" for pre-authorized payments and "order" for an order. + // info required cause API has different endpoints for different intents. + var intent = (string)apiResult.Json.intent; + + if (intent.IsCaseInsensitiveEqual("sale")) + { + relatedObject = apiResult.Json.transactions[0].related_resources[0].sale; + + session.PaymentInstruction = PayPalService.ParsePaymentInstruction(apiResult.Json.payment_instruction) as PayPalPaymentInstruction; + } + else + { + relatedObject = apiResult.Json.transactions[0].related_resources[0].authorization; + } + + if (relatedObject != null) + { + state = (string)relatedObject.state; + reasonCode = (string)relatedObject.reason_code; + + // see PayPalService.Refund() + result.AuthorizationTransactionResult = "{0} ({1})".FormatInvariant(state.NaIfEmpty(), intent.NaIfEmpty()); + result.AuthorizationTransactionId = (string)relatedObject.id; + + result.NewPaymentStatus = PayPalService.GetPaymentStatus(state, reasonCode, PaymentStatus.Authorized); + + if (result.NewPaymentStatus == PaymentStatus.Paid) + { + result.CaptureTransactionResult = result.AuthorizationTransactionResult; + result.CaptureTransactionId = result.AuthorizationTransactionId; + } + } + } + else + { + var failureReason = (string)apiResult.Json.failure_reason; + + result.Errors.Add(T("Plugins.SmartStore.PayPal.PaymentExecuteFailed").Text.Grow(failureReason, " ")); + } + } + + if (!apiResult.Success) + result.Errors.Add(apiResult.ErrorMessage); + + return result; + } + + public override void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest) + { + var instruction = PayPalService.CreatePaymentInstruction(HttpContext.GetPayPalSessionData().PaymentInstruction); + + if (instruction.HasValue()) + { + HttpContext.Session[CheckoutCompletedKey] = instruction; + + OrderService.AddOrderNote(postProcessPaymentRequest.Order, instruction, true); + } + } + + public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymentRequest) + { + var result = new CapturePaymentResult + { + NewPaymentStatus = capturePaymentRequest.Order.PaymentStatus + }; + + var settings = Services.Settings.LoadSetting(capturePaymentRequest.Order.StoreId); + var session = new PayPalSessionData(); + + var apiResult = PayPalService.EnsureAccessToken(session, settings); + if (apiResult.Success) + { + apiResult = PayPalService.Capture(settings, session, capturePaymentRequest); + + if (apiResult.Success) + result.NewPaymentStatus = PaymentStatus.Paid; + } + + if (!apiResult.Success) + result.Errors.Add(apiResult.ErrorMessage); + + return result; + } + + public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest) + { + var result = new RefundPaymentResult + { + NewPaymentStatus = refundPaymentRequest.Order.PaymentStatus + }; + + var settings = Services.Settings.LoadSetting(refundPaymentRequest.Order.StoreId); + var session = new PayPalSessionData(); + + var apiResult = PayPalService.EnsureAccessToken(session, settings); + if (apiResult.Success) + { + apiResult = PayPalService.Refund(settings, session, refundPaymentRequest); + if (apiResult.Success) + { + if (refundPaymentRequest.IsPartialRefund) + result.NewPaymentStatus = PaymentStatus.PartiallyRefunded; + else + result.NewPaymentStatus = PaymentStatus.Refunded; + } + } + + if (!apiResult.Success) + result.Errors.Add(apiResult.ErrorMessage); + + return result; + } + + public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest) + { + var result = new VoidPaymentResult + { + NewPaymentStatus = voidPaymentRequest.Order.PaymentStatus + }; + + var settings = Services.Settings.LoadSetting(voidPaymentRequest.Order.StoreId); + var session = new PayPalSessionData(); + + var apiResult = PayPalService.EnsureAccessToken(session, settings); + if (apiResult.Success) + { + apiResult = PayPalService.Void(settings, session, voidPaymentRequest); + if (apiResult.Success) + { + result.NewPaymentStatus = PaymentStatus.Voided; + } + } + + if (!apiResult.Success) + result.Errors.Add(apiResult.ErrorMessage); + + return result; + } + + public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = GetControllerName(); + routeValues = new RouteValueDictionary { { "area", "SmartStore.PayPal" } }; + } + + public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "PaymentInfo"; + controllerName = GetControllerName(); + routeValues = new RouteValueDictionary { { "area", "SmartStore.PayPal" } }; + } + } +} + diff --git a/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs new file mode 100644 index 0000000000..4632649153 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Providers/PayPalStandardProvider.cs @@ -0,0 +1,614 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Routing; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.PayPal.Controllers; +using SmartStore.PayPal.Settings; +using SmartStore.Services; +using SmartStore.Services.Localization; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal +{ + [SystemName("Payments.PayPalStandard")] + [FriendlyName("PayPal Standard")] + [DisplayOrder(2)] + public partial class PayPalStandardProvider : PaymentPluginBase, IConfigurable + { + private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly ICommonServices _services; + private readonly ILogger _logger; + + public PayPalStandardProvider( + IOrderTotalCalculationService orderTotalCalculationService, + ICommonServices services, + ILogger logger) + { + _orderTotalCalculationService = orderTotalCalculationService; + _services = services; + _logger = logger; + } + + public static string SystemName { get { return "Payments.PayPalStandard"; } } + + public override PaymentMethodType PaymentMethodType + { + get + { + return PaymentMethodType.Redirection; + } + } + + /// + /// Process a payment + /// + /// Payment info required for an order processing + /// Process payment result + public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest processPaymentRequest) + { + var result = new ProcessPaymentResult(); + result.NewPaymentStatus = PaymentStatus.Pending; + + var settings = _services.Settings.LoadSetting(processPaymentRequest.StoreId); + + if (settings.BusinessEmail.IsEmpty() || settings.PdtToken.IsEmpty()) + { + result.AddError(T("Plugins.Payments.PayPalStandard.InvalidCredentials")); + } + + return result; + } + + /// + /// Post process payment (used by payment gateways that require redirecting to a third-party URL) + /// + /// Payment info required for an order processing + public override void PostProcessPayment(PostProcessPaymentRequest postProcessPaymentRequest) + { + if (postProcessPaymentRequest.Order.PaymentStatus == PaymentStatus.Paid) + return; + + var store = _services.StoreService.GetStoreById(postProcessPaymentRequest.Order.StoreId); + var settings = _services.Settings.LoadSetting(postProcessPaymentRequest.Order.StoreId); + + var builder = new StringBuilder(); + builder.Append(settings.GetPayPalUrl()); + + string orderNumber = postProcessPaymentRequest.Order.GetOrderNumber(); + string cmd = (settings.PassProductNamesAndTotals ? "_cart" : "_xclick"); + + builder.AppendFormat("?cmd={0}&business={1}", cmd, HttpUtility.UrlEncode(settings.BusinessEmail)); + + if (settings.PassProductNamesAndTotals) + { + builder.AppendFormat("&upload=1"); + + int index = 0; + decimal cartTotal = decimal.Zero; + //var caValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(postProcessPaymentRequest.Order.CheckoutAttributesXml); + + var lineItems = GetLineItems(postProcessPaymentRequest, out cartTotal); + + AdjustLineItemAmounts(lineItems, postProcessPaymentRequest); + + foreach (var item in lineItems.OrderBy(x => (int)x.Type)) + { + ++index; + builder.AppendFormat("&item_name_" + index + "={0}", HttpUtility.UrlEncode(item.Name)); + builder.AppendFormat("&amount_" + index + "={0}", item.AmountRounded.ToString("0.00", CultureInfo.InvariantCulture)); + builder.AppendFormat("&quantity_" + index + "={0}", item.Quantity); + } + + #region old code + + //var cartItems = postProcessPaymentRequest.Order.OrderItems; + //int x = 1; + //foreach (var item in cartItems) + //{ + // var unitPriceExclTax = item.UnitPriceExclTax; + // var priceExclTax = item.PriceExclTax; + // //round + // var unitPriceExclTaxRounded = Math.Round(unitPriceExclTax, 2); + + // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(item.Product.Name)); + // builder.AppendFormat("&amount_" + x + "={0}", unitPriceExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); + // builder.AppendFormat("&quantity_" + x + "={0}", item.Quantity); + // x++; + // cartTotal += priceExclTax; + //} + + ////the checkout attributes that have a dollar value and send them to Paypal as items to be paid for + //foreach (var val in caValues) + //{ + // var attPrice = _taxService.GetCheckoutAttributePrice(val, false, postProcessPaymentRequest.Order.Customer); + // //round + // var attPriceRounded = Math.Round(attPrice, 2); + // if (attPrice > decimal.Zero) //if it has a price + // { + // var ca = val.CheckoutAttribute; + // if (ca != null) + // { + // var attName = ca.Name; //set the name + // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(attName)); //name + // builder.AppendFormat("&amount_" + x + "={0}", attPriceRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount + // builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity + // x++; + // cartTotal += attPrice; + // } + // } + //} + + ////order totals + + ////shipping + //var orderShippingExclTax = postProcessPaymentRequest.Order.OrderShippingExclTax; + //var orderShippingExclTaxRounded = Math.Round(orderShippingExclTax, 2); + //if (orderShippingExclTax > decimal.Zero) + //{ + // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(_localizationService.GetResource("Plugins.Payments.PayPalStandard.ShippingFee"))); + // builder.AppendFormat("&amount_" + x + "={0}", orderShippingExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); + // builder.AppendFormat("&quantity_" + x + "={0}", 1); + // x++; + // cartTotal += orderShippingExclTax; + //} + + ////payment method additional fee + //var paymentMethodAdditionalFeeExclTax = postProcessPaymentRequest.Order.PaymentMethodAdditionalFeeExclTax; + //var paymentMethodAdditionalFeeExclTaxRounded = Math.Round(paymentMethodAdditionalFeeExclTax, 2); + //if (paymentMethodAdditionalFeeExclTax > decimal.Zero) + //{ + // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(_localizationService.GetResource("Plugins.Payments.PayPalStandard.PaymentMethodFee"))); + // builder.AppendFormat("&amount_" + x + "={0}", paymentMethodAdditionalFeeExclTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); + // builder.AppendFormat("&quantity_" + x + "={0}", 1); + // x++; + // cartTotal += paymentMethodAdditionalFeeExclTax; + //} + + ////tax + //var orderTax = postProcessPaymentRequest.Order.OrderTax; + //var orderTaxRounded = Math.Round(orderTax, 2); + //if (orderTax > decimal.Zero) + //{ + // //builder.AppendFormat("&tax_1={0}", orderTax.ToString("0.00", CultureInfo.InvariantCulture)); + + // //add tax as item + // builder.AppendFormat("&item_name_" + x + "={0}", HttpUtility.UrlEncode(_localizationService.GetResource("Plugins.Payments.PayPalStandard.SalesTax"))); + // builder.AppendFormat("&amount_" + x + "={0}", orderTaxRounded.ToString("0.00", CultureInfo.InvariantCulture)); //amount + // builder.AppendFormat("&quantity_" + x + "={0}", 1); //quantity + + // cartTotal += orderTax; + // x++; + //} + + #endregion + + if (cartTotal > postProcessPaymentRequest.Order.OrderTotal) + { + // Take the difference between what the order total is and what it should be and use that as the "discount". + // The difference equals the amount of the gift card and/or reward points used. + decimal discountTotal = cartTotal - postProcessPaymentRequest.Order.OrderTotal; + discountTotal = Math.Round(discountTotal, 2); + + //gift card or rewared point amount applied to cart in SmartStore.NET - shows in Paypal as "discount" + builder.AppendFormat("&discount_amount_cart={0}", discountTotal.ToString("0.00", CultureInfo.InvariantCulture)); + } + } + else + { + //pass order total + string totalItemName = "{0} {1}".FormatWith(T("Checkout.OrderNumber"), orderNumber); + builder.AppendFormat("&item_name={0}", HttpUtility.UrlEncode(totalItemName)); + var orderTotal = Math.Round(postProcessPaymentRequest.Order.OrderTotal, 2); + builder.AppendFormat("&amount={0}", orderTotal.ToString("0.00", CultureInfo.InvariantCulture)); + } + + builder.AppendFormat("&custom={0}", postProcessPaymentRequest.Order.OrderGuid); + builder.AppendFormat("&charset={0}", "utf-8"); + builder.Append(string.Format("&no_note=1¤cy_code={0}", HttpUtility.UrlEncode(store.PrimaryStoreCurrency.CurrencyCode))); + builder.AppendFormat("&invoice={0}", HttpUtility.UrlEncode(orderNumber)); + builder.AppendFormat("&rm=2", new object[0]); + + Address address = null; + + if (postProcessPaymentRequest.Order.ShippingStatus != ShippingStatus.ShippingNotRequired) + { + address = postProcessPaymentRequest.Order.ShippingAddress ?? postProcessPaymentRequest.Order.BillingAddress; + + builder.AppendFormat("&no_shipping=2", new object[0]); + } + else + { + address = postProcessPaymentRequest.Order.BillingAddress; + + builder.AppendFormat("&no_shipping=1", new object[0]); + } + + var returnUrl = _services.WebHelper.GetStoreLocation(store.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalStandard/PDTHandler"; + var cancelReturnUrl = _services.WebHelper.GetStoreLocation(store.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalStandard/CancelOrder"; + builder.AppendFormat("&return={0}&cancel_return={1}", HttpUtility.UrlEncode(returnUrl), HttpUtility.UrlEncode(cancelReturnUrl)); + + //Instant Payment Notification (server to server message) + if (settings.EnableIpn) + { + string ipnUrl; + if (String.IsNullOrWhiteSpace(settings.IpnUrl)) + ipnUrl = _services.WebHelper.GetStoreLocation(store.SslEnabled) + "Plugins/SmartStore.PayPal/PayPalStandard/IPNHandler"; + else + ipnUrl = settings.IpnUrl; + builder.AppendFormat("¬ify_url={0}", ipnUrl); + } + + //address + builder.AppendFormat("&address_override=1"); + builder.AppendFormat("&first_name={0}", HttpUtility.UrlEncode(address.FirstName)); + builder.AppendFormat("&last_name={0}", HttpUtility.UrlEncode(address.LastName)); + builder.AppendFormat("&address1={0}", HttpUtility.UrlEncode(address.Address1)); + builder.AppendFormat("&address2={0}", HttpUtility.UrlEncode(address.Address2)); + builder.AppendFormat("&city={0}", HttpUtility.UrlEncode(address.City)); + //if (!String.IsNullOrEmpty(address.PhoneNumber)) + //{ + // //strip out all non-digit characters from phone number; + // string billingPhoneNumber = System.Text.RegularExpressions.Regex.Replace(address.PhoneNumber, @"\D", string.Empty); + // if (billingPhoneNumber.Length >= 10) + // { + // builder.AppendFormat("&night_phone_a={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(0, 3))); + // builder.AppendFormat("&night_phone_b={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(3, 3))); + // builder.AppendFormat("&night_phone_c={0}", HttpUtility.UrlEncode(billingPhoneNumber.Substring(6, 4))); + // } + //} + if (address.StateProvince != null) + builder.AppendFormat("&state={0}", HttpUtility.UrlEncode(address.StateProvince.Abbreviation)); + else + builder.AppendFormat("&state={0}", ""); + + if (address.Country != null) + builder.AppendFormat("&country={0}", HttpUtility.UrlEncode(address.Country.TwoLetterIsoCode)); + else + builder.AppendFormat("&country={0}", ""); + + builder.AppendFormat("&zip={0}", HttpUtility.UrlEncode(address.ZipPostalCode)); + builder.AppendFormat("&email={0}", HttpUtility.UrlEncode(address.Email)); + + postProcessPaymentRequest.RedirectUrl = builder.ToString(); + } + + /// + /// Gets a value indicating whether customers can complete a payment after order is placed but not completed (for redirection payment methods) + /// + /// Order + /// Result + public override bool CanRePostProcessPayment(Order order) + { + if (order == null) + throw new ArgumentNullException("order"); + + if (order.PaymentStatus == PaymentStatus.Pending && (DateTime.UtcNow - order.CreatedOnUtc).TotalSeconds > 5) + { + return true; + } + return true; + } + + public override Type GetControllerType() + { + return typeof(PayPalStandardController); + } + + public override decimal GetAdditionalHandlingFee(IList cart) + { + var result = decimal.Zero; + try + { + var settings = _services.Settings.LoadSetting(_services.StoreContext.CurrentStore.Id); + + result = this.CalculateAdditionalFee(_orderTotalCalculationService, cart, settings.AdditionalFee, settings.AdditionalFeePercentage); + } + catch (Exception) + { + } + return result; + } + + /// + /// Gets PDT details + /// + /// TX + /// Values + /// Response + /// Result + public bool GetPDTDetails(string tx, PayPalStandardPaymentSettings settings, out Dictionary values, out string response) + { + var request = settings.GetPayPalWebRequest(); + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + + var formContent = string.Format("cmd=_notify-synch&at={0}&tx={1}", settings.PdtToken, tx); + request.ContentLength = formContent.Length; + + using (var sw = new StreamWriter(request.GetRequestStream(), Encoding.ASCII)) + { + sw.Write(formContent); + } + + response = null; + using (var sr = new StreamReader(request.GetResponse().GetResponseStream())) + { + response = HttpUtility.UrlDecode(sr.ReadToEnd()); + } + + values = new Dictionary(StringComparer.OrdinalIgnoreCase); + + var firstLine = true; + var success = false; + + foreach (string l in response.Split('\n')) + { + string line = l.Trim(); + if (firstLine) + { + success = line.Equals("SUCCESS", StringComparison.OrdinalIgnoreCase); + firstLine = false; + } + else + { + int equalPox = line.IndexOf('='); + if (equalPox >= 0) + values.Add(line.Substring(0, equalPox), line.Substring(equalPox + 1)); + } + } + + return success; + } + + /// + /// Splits the difference of two value into a portion value (for each item) and a rest value + /// + /// The difference value + /// Number of lines\items to split the difference + /// Portion value + /// Rest value + private void SplitDifference(decimal difference, int numberOfLines, out decimal portion, out decimal rest) + { + portion = rest = decimal.Zero; + + if (numberOfLines == 0) + numberOfLines = 1; + + int intDifference = (int)(difference * 100); + int intPortion = (int)Math.Truncate((double)intDifference / (double)numberOfLines); + int intRest = intDifference % numberOfLines; + + portion = Math.Round(((decimal)intPortion) / 100, 2); + rest = Math.Round(((decimal)intRest) / 100, 2); + + Debug.Assert(difference == ((numberOfLines * portion) + rest)); + } + + /// + /// Get all PayPal line items + /// + /// Post process paymenmt request object + /// List with checkout attribute values + /// Receives the calculated cart total amount + /// All items for PayPal Standard API + public List GetLineItems(PostProcessPaymentRequest postProcessPaymentRequest, out decimal cartTotal) + { + cartTotal = decimal.Zero; + + var order = postProcessPaymentRequest.Order; + var lst = new List(); + + // order items... checkout attributes are included in order total + foreach (var orderItem in order.OrderItems) + { + var item = new PayPalLineItem + { + Type = PayPalItemType.CartItem, + Name = orderItem.Product.GetLocalized(x => x.Name), + Quantity = orderItem.Quantity, + Amount = orderItem.UnitPriceExclTax + }; + lst.Add(item); + + cartTotal += orderItem.PriceExclTax; + } + + // shipping + if (order.OrderShippingExclTax > decimal.Zero) + { + var item = new PayPalLineItem + { + Type = PayPalItemType.Shipping, + Name = T("Plugins.Payments.PayPalStandard.ShippingFee").Text, + Quantity = 1, + Amount = order.OrderShippingExclTax + }; + lst.Add(item); + + cartTotal += order.OrderShippingExclTax; + } + + // payment fee + if (order.PaymentMethodAdditionalFeeExclTax > decimal.Zero) + { + var item = new PayPalLineItem + { + Type = PayPalItemType.PaymentFee, + Name = T("Plugins.Payments.PayPal.PaymentMethodFee").Text, + Quantity = 1, + Amount = order.PaymentMethodAdditionalFeeExclTax + }; + lst.Add(item); + + cartTotal += order.PaymentMethodAdditionalFeeExclTax; + } + + // tax + if (order.OrderTax > decimal.Zero) + { + var item = new PayPalLineItem + { + Type = PayPalItemType.Tax, + Name = T("Plugins.Payments.PayPalStandard.SalesTax").Text, + Quantity = 1, + Amount = order.OrderTax + }; + lst.Add(item); + + cartTotal += order.OrderTax; + } + + return lst; + } + + /// + /// Manually adjusts the net prices for cart items to avoid rounding differences with the PayPal API. + /// + /// PayPal line items + /// Post process paymenmt request object + /// + /// In detail: We add what we have thrown away in the checkout when we rounded prices to two decimal places. + /// It's a workaround. Better solution would be to store the thrown away decimal places for each OrderItem in the database. + /// More details: http://magento.xonu.de/magento-extensions/empfehlungen/magento-paypal-rounding-error-fix/ + /// + public void AdjustLineItemAmounts(List paypalItems, PostProcessPaymentRequest postProcessPaymentRequest) + { + try + { + var cartItems = paypalItems.Where(x => x.Type == PayPalItemType.CartItem); + + if (cartItems.Count() <= 0) + return; + + decimal totalSmartStore = Math.Round(postProcessPaymentRequest.Order.OrderSubtotalExclTax, 2); + decimal totalPayPal = decimal.Zero; + decimal delta, portion, rest; + + // calculate what PayPal calculates + cartItems.Each(x => totalPayPal += (x.AmountRounded * x.Quantity)); + totalPayPal = Math.Round(totalPayPal, 2, MidpointRounding.AwayFromZero); + + // calculate difference + delta = Math.Round(totalSmartStore - totalPayPal, 2); + //"SM: {0}, PP: {1}, delta: {2}".FormatInvariant(totalSmartStore, totalPayPal, delta).Dump(); + + if (delta == decimal.Zero) + return; + + // prepare lines... only lines with quantity = 1 are adjustable. if there is no one, create one. + if (!cartItems.Any(x => x.Quantity == 1)) + { + var item = cartItems.First(x => x.Quantity > 1); + item.Quantity -= 1; + var newItem = item.Clone(); + newItem.Quantity = 1; + paypalItems.Insert(paypalItems.IndexOf(item) + 1, newItem); + } + + var cartItemsOneQuantity = paypalItems.Where(x => x.Type == PayPalItemType.CartItem && x.Quantity == 1); + Debug.Assert(cartItemsOneQuantity.Count() > 0); + + SplitDifference(delta, cartItemsOneQuantity.Count(), out portion, out rest); + + if (portion != decimal.Zero) + { + cartItems + .Where(x => x.Quantity == 1) + .Each(x => x.Amount = x.Amount + portion); + } + + if (rest != decimal.Zero) + { + var restItem = cartItems.First(x => x.Quantity == 1); + restItem.Amount = restItem.Amount + rest; + } + + //"SM: {0}, PP: {1}, delta: {2} (portion: {3}, rest: {4})".FormatInvariant(totalSmartStore, totalPayPal, delta, portion, rest).Dump(); + } + catch (Exception exception) + { + _logger.Error(exception.Message, exception); + } + } + + /// + /// Gets a route for provider configuration + /// + /// Action name + /// Controller name + /// Route values + public override void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "PayPalStandard"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.PayPal" } }; + } + + /// + /// Gets a route for payment info + /// + /// Action name + /// Controller name + /// Route values + public override void GetPaymentInfoRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "PaymentInfo"; + controllerName = "PayPalStandard"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.PayPal" } }; + } + } + + + public class PayPalLineItem : ICloneable + { + public PayPalItemType Type { get; set; } + public string Name { get; set; } + public int Quantity { get; set; } + public decimal Amount { get; set; } + + public decimal AmountRounded + { + get + { + return Math.Round(Amount, 2); + } + } + + public PayPalLineItem Clone() + { + var item = new PayPalLineItem + { + Type = this.Type, + Name = this.Name, + Quantity = this.Quantity, + Amount = this.Amount + }; + return item; + } + + object ICloneable.Clone() + { + return this.Clone(); + } + } + + public enum PayPalItemType + { + CartItem = 0, + Shipping, + PaymentFee, + Tax + } +} diff --git a/src/Plugins/SmartStore.PayPal/RouteProvider.cs b/src/Plugins/SmartStore.PayPal/RouteProvider.cs new file mode 100644 index 0000000000..74e44ce093 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/RouteProvider.cs @@ -0,0 +1,93 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.PayPal +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.PayPalExpress", + "Plugins/SmartStore.PayPal/{controller}/{action}", + new { controller = "PayPalExpress", action = "Index" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalDirect", + "Plugins/SmartStore.PayPal/{controller}/{action}", + new { controller = "PayPalDirect", action = "Index" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalStandard", + "Plugins/SmartStore.PayPal/{controller}/{action}", + new { controller = "PayPalStandard", action = "Index" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalPlus", + "Plugins/SmartStore.PayPal/{controller}/{action}", + new { controller = "PayPalPlus", action = "Index" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = Plugin.SystemName; + + + + //Legacay Routes + routes.MapRoute("SmartStore.PayPalExpress.IPN", + "Plugins/PaymentPayPalExpress/IPNHandler", + new { controller = "PayPalExpress", action = "IPNHandler" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalDirect.IPN", + "Plugins/PaymentPayPalDirect/IPNHandler", + new { controller = "PayPalDirect", action = "IPNHandler" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalStandard.IPN", + "Plugins/PaymentPayPalStandard/IPNHandler", + new { controller = "PayPalStandard", action = "IPNHandler" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalStandard.PDT", + "Plugins/PaymentPayPalStandard/PDTHandler", + new { controller = "PayPalStandard", action = "PDTHandler" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalExpress.RedirectFromPaymentInfo", + "Plugins/PaymentPayPalExpress/RedirectFromPaymentInfo", + new { controller = "PayPalExpress", action = "RedirectFromPaymentInfo" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + + routes.MapRoute("SmartStore.PayPalStandard.CancelOrder", + "Plugins/PaymentPayPalStandard/CancelOrder", + new { controller = "PayPalStandard", action = "CancelOrder" }, + new[] { "SmartStore.PayPal.Controllers" } + ) + .DataTokens["area"] = "SmartStore.PayPal"; + } + + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.PayPal/Services/IPayPalService.cs b/src/Plugins/SmartStore.PayPal/Services/IPayPalService.cs new file mode 100644 index 0000000000..2f4b94c1c9 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Services/IPayPalService.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Net; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Stores; +using SmartStore.PayPal.Settings; +using SmartStore.Services.Payments; + +namespace SmartStore.PayPal.Services +{ + public interface IPayPalService + { + void AddOrderNote(PayPalSettingsBase settings, Order order, string anyString, bool isIpn = false); + + void LogError(Exception exception, string shortMessage = null, string fullMessage = null, bool notify = false, IList errors = null, bool isWarning = false); + + PayPalPaymentInstruction ParsePaymentInstruction(dynamic json); + + string CreatePaymentInstruction(PayPalPaymentInstruction instruct); + + PaymentStatus GetPaymentStatus(string state, string reasonCode, PaymentStatus defaultStatus); + + PayPalResponse CallApi(string method, string path, string accessToken, PayPalApiSettingsBase settings, string data); + + PayPalResponse EnsureAccessToken(PayPalSessionData session, PayPalApiSettingsBase settings); + + PayPalResponse GetPayment(PayPalApiSettingsBase settings, PayPalSessionData session); + + PayPalResponse CreatePayment( + PayPalApiSettingsBase settings, + PayPalSessionData session, + List cart, + string providerSystemName, + string returnUrl, + string cancelUrl); + + PayPalResponse PatchShipping( + PayPalApiSettingsBase settings, + PayPalSessionData session, + List cart, + string providerSystemName); + + PayPalResponse ExecutePayment(PayPalApiSettingsBase settings, PayPalSessionData session); + + PayPalResponse Refund(PayPalApiSettingsBase settings, PayPalSessionData session, RefundPaymentRequest request); + + PayPalResponse Capture(PayPalApiSettingsBase settings, PayPalSessionData session, CapturePaymentRequest request); + + PayPalResponse Void(PayPalApiSettingsBase settings, PayPalSessionData session, VoidPaymentRequest request); + + PayPalResponse UpsertCheckoutExperience(PayPalApiSettingsBase settings, PayPalSessionData session, Store store); + + PayPalResponse DeleteCheckoutExperience(PayPalApiSettingsBase settings, PayPalSessionData session); + + PayPalResponse CreateWebhook(PayPalApiSettingsBase settings, PayPalSessionData session, string url); + + PayPalResponse DeleteWebhook(PayPalApiSettingsBase settings, PayPalSessionData session); + + HttpStatusCode ProcessWebhook( + PayPalApiSettingsBase settings, + NameValueCollection headers, + string rawJson, + string providerSystemName); + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Services/PayPalEnums.cs b/src/Plugins/SmartStore.PayPal/Services/PayPalEnums.cs new file mode 100644 index 0000000000..d5bba1b72c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Services/PayPalEnums.cs @@ -0,0 +1,27 @@ + +namespace SmartStore.PayPal.Services +{ + public enum PayPalPaymentInstructionItem + { + Reference = 0, + BankRoutingNumber, + Bank, + Bic, + Iban, + AccountHolder, + AccountNumber, + Amount, + PaymentDueDate, + Details + } + + public enum PayPalMessage + { + Message = 0, + Event, + EventId, + State, + Amount, + PaymentId + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Services/PayPalService.cs b/src/Plugins/SmartStore.PayPal/Services/PayPalService.cs new file mode 100644 index 0000000000..62e53f01d5 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Services/PayPalService.cs @@ -0,0 +1,1177 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Web; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Logging; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.PayPal.Settings; +using SmartStore.Services; +using SmartStore.Services.Catalog; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; +using SmartStore.Services.Orders; +using SmartStore.Services.Payments; +using SmartStore.Services.Tax; + +namespace SmartStore.PayPal.Services +{ + public class PayPalService : IPayPalService + { + private readonly Lazy> _orderRepository; + private readonly ICommonServices _services; + private readonly IOrderService _orderService; + private readonly IOrderProcessingService _orderProcessingService; + private readonly IOrderTotalCalculationService _orderTotalCalculationService; + private readonly IPaymentService _paymentService; + private readonly IPriceCalculationService _priceCalculationService; + private readonly ITaxService _taxService; + private readonly ICurrencyService _currencyService; + private readonly Lazy _pictureService; + private readonly Lazy _companyInfoSettings; + + public PayPalService( + Lazy> orderRepository, + ICommonServices services, + IOrderService orderService, + IOrderProcessingService orderProcessingService, + IOrderTotalCalculationService orderTotalCalculationService, + IPaymentService paymentService, + IPriceCalculationService priceCalculationService, + ITaxService taxService, + ICurrencyService currencyService, + Lazy pictureService, + Lazy companyInfoSettings) + { + _orderRepository = orderRepository; + _services = services; + _orderService = orderService; + _orderProcessingService = orderProcessingService; + _orderTotalCalculationService = orderTotalCalculationService; + _paymentService = paymentService; + _priceCalculationService = priceCalculationService; + _taxService = taxService; + _currencyService = currencyService; + _pictureService = pictureService; + _companyInfoSettings = companyInfoSettings; + + T = NullLocalizer.Instance; + Logger = NullLogger.Instance; + } + + public Localizer T { get; set; } + public ILogger Logger { get; set; } + + private Dictionary CreateAddress(Address addr, bool addRecipientName) + { + var dic = new Dictionary(); + + dic.Add("line1", addr.Address1.Truncate(100)); + + if (addr.Address2.HasValue()) + { + dic.Add("line2", addr.Address2.Truncate(100)); + } + + dic.Add("city", addr.City.Truncate(50)); + + if (addr.CountryId != 0 && addr.Country != null) + { + dic.Add("country_code", addr.Country.TwoLetterIsoCode); + } + + dic.Add("postal_code", addr.ZipPostalCode.Truncate(20)); + + if (addr.StateProvinceId != 0 && addr.StateProvince != null) + { + dic.Add("state", addr.StateProvince.Abbreviation.Truncate(100)); + } + + if (addRecipientName) + { + dic.Add("recipient_name", addr.GetFullName().Truncate(50)); + } + + return dic; + } + + private Dictionary CreateAmount( + Store store, + Customer customer, + List cart, + string providerSystemName, + List> items) + { + var amount = new Dictionary(); + var amountDetails = new Dictionary(); + var language = _services.WorkContext.WorkingLanguage; + var currency = _services.WorkContext.WorkingCurrency; + var currencyCode = store.PrimaryStoreCurrency.CurrencyCode; + var includingTax = (_services.WorkContext.GetTaxDisplayTypeFor(customer, store.Id) == TaxDisplayType.IncludingTax); + + Discount orderAppliedDiscount; + List appliedGiftCards; + int redeemedRewardPoints = 0; + decimal redeemedRewardPointsAmount; + decimal orderDiscountInclTax; + decimal totalOrderItems = decimal.Zero; + var taxTotal = decimal.Zero; + + var shipping = Math.Round(_orderTotalCalculationService.GetShoppingCartShippingTotal(cart) ?? decimal.Zero, 2); + + var additionalHandlingFee = _paymentService.GetAdditionalHandlingFee(cart, providerSystemName); + var paymentFeeBase = _taxService.GetPaymentMethodAdditionalFee(additionalHandlingFee, customer); + var paymentFee = Math.Round(_currencyService.ConvertFromPrimaryStoreCurrency(paymentFeeBase, currency), 2); + + var total = Math.Round(_orderTotalCalculationService.GetShoppingCartTotal(cart, out orderDiscountInclTax, out orderAppliedDiscount, out appliedGiftCards, + out redeemedRewardPoints, out redeemedRewardPointsAmount) ?? decimal.Zero, 2); + + // line items + foreach (var item in cart) + { + decimal unitPriceTaxRate = decimal.Zero; + decimal unitPrice = _priceCalculationService.GetUnitPrice(item, true); + decimal productPrice = _taxService.GetProductPrice(item.Item.Product, unitPrice, includingTax, customer, out unitPriceTaxRate); + + if (items != null && productPrice != decimal.Zero) + { + var line = new Dictionary(); + line.Add("quantity", item.Item.Quantity); + line.Add("name", item.Item.Product.GetLocalized(x => x.Name, language.Id, true, false).Truncate(127)); + line.Add("price", productPrice.FormatInvariant()); + line.Add("currency", currencyCode); + line.Add("sku", item.Item.Product.Sku.Truncate(50)); + items.Add(line); + } + + totalOrderItems += (Math.Round(productPrice, 2) * item.Item.Quantity); + } + + if (items != null && paymentFee != decimal.Zero) + { + var line = new Dictionary(); + line.Add("quantity", "1"); + line.Add("name", T("Order.PaymentMethodAdditionalFee").Text.Truncate(127)); + line.Add("price", paymentFee.FormatInvariant()); + line.Add("currency", currencyCode); + items.Add(line); + + totalOrderItems += Math.Round(paymentFee, 2); + } + + if (!includingTax) + { + // "To avoid rounding errors we recommend not submitting tax amounts on line item basis. + // Calculated tax amounts for the entire shopping basket may be submitted in the amount objects. + // In this case the item amounts will be treated as amounts excluding tax. + // In a B2C scenario, where taxes are included, no taxes should be submitted to PayPal." + + SortedDictionary taxRates = null; + taxTotal = Math.Round(_orderTotalCalculationService.GetTaxTotal(cart, out taxRates), 2); + + amountDetails.Add("tax", taxTotal.FormatInvariant()); + } + + var itemsPlusMisc = (totalOrderItems + taxTotal + shipping); + + if (total != itemsPlusMisc) + { + var otherAmount = Math.Round(total - itemsPlusMisc, 2); + totalOrderItems += otherAmount; + + if (items != null && otherAmount != decimal.Zero) + { + // e.g. discount applied to cart total + var line = new Dictionary(); + line.Add("quantity", "1"); + line.Add("name", T("Plugins.SmartStore.PayPal.Other").Text.Truncate(127)); + line.Add("price", otherAmount.FormatInvariant()); + line.Add("currency", currencyCode); + items.Add(line); + } + } + + // fill amount object + amountDetails.Add("shipping", shipping.FormatInvariant()); + amountDetails.Add("subtotal", totalOrderItems.FormatInvariant()); + + //if (paymentFee != decimal.Zero) + //{ + // amountDetails.Add("handling_fee", paymentFee.FormatInvariant()); + //} + + amount.Add("total", total.FormatInvariant()); + amount.Add("currency", currencyCode); + amount.Add("details", amountDetails); + + return amount; + } + + private string ToInfoString(dynamic json) + { + var sb = new StringBuilder(); + + try + { + string[] strings = T("Plugins.SmartStore.PayPal.MessageStrings").Text.SplitSafe(";"); + var message = (string)json.summary; + var eventType = (string)json.event_type; + var eventId = (string)json.id; + string state = null; + string amount = null; + string paymentId = null; + + if (json.resource != null) + { + state = (string)json.resource.state; + paymentId = (string)json.resource.parent_payment; + + if (json.resource.amount != null) + amount = string.Concat((string)json.resource.amount.total, " ", (string)json.resource.amount.currency); + } + + sb.AppendLine("{0}: {1}".FormatInvariant(strings.SafeGet((int)PayPalMessage.Message), message.NaIfEmpty())); + sb.AppendLine("{0}: {1}".FormatInvariant(strings.SafeGet((int)PayPalMessage.Event), eventType.NaIfEmpty())); + sb.AppendLine("{0}: {1}".FormatInvariant(strings.SafeGet((int)PayPalMessage.EventId), eventId.NaIfEmpty())); + sb.AppendLine("{0}: {1}".FormatInvariant(strings.SafeGet((int)PayPalMessage.PaymentId), paymentId.NaIfEmpty())); + sb.AppendLine("{0}: {1}".FormatInvariant(strings.SafeGet((int)PayPalMessage.State), state.NaIfEmpty())); + sb.AppendLine("{0}: {1}".FormatInvariant(strings.SafeGet((int)PayPalMessage.Amount), amount.NaIfEmpty())); + } + catch { } + + return sb.ToString(); + } + + public static string GetApiUrl(bool sandbox) + { + return sandbox ? "https://api.sandbox.paypal.com" : "https://api.paypal.com"; + } + + public static Dictionary GetSecurityProtocols() + { + var dic = new Dictionary(); + + foreach (SecurityProtocolType protocol in Enum.GetValues(typeof(SecurityProtocolType))) + { + string friendlyName = null; + switch (protocol) + { + case SecurityProtocolType.Ssl3: + friendlyName = "SSL 3.0"; + break; + case SecurityProtocolType.Tls: + friendlyName = "TLS 1.0"; + break; + case SecurityProtocolType.Tls11: + friendlyName = "TLS 1.1"; + break; + case SecurityProtocolType.Tls12: + friendlyName = "TLS 1.2"; + break; + default: + friendlyName = protocol.ToString().ToUpper(); + break; + } + + dic.Add(protocol, friendlyName); + } + return dic; + } + + public void AddOrderNote(PayPalSettingsBase settings, Order order, string anyString, bool isIpn = false) + { + try + { + if (order == null || anyString.IsEmpty() || (settings != null && !settings.AddOrderNotes)) + return; + + string[] orderNoteStrings = T("Plugins.SmartStore.PayPal.OrderNoteStrings").Text.SplitSafe(";"); + var faviconUrl = "{0}Plugins/{1}/Content/favicon.png".FormatInvariant(_services.WebHelper.GetStoreLocation(false), Plugin.SystemName); + + var sb = new StringBuilder(); + sb.AppendFormat("", faviconUrl); + + var note = orderNoteStrings.SafeGet(0).FormatInvariant(anyString); + + sb.AppendFormat("{0}", note); + + if (isIpn) + order.HasNewPaymentNotification = true; + + _orderService.AddOrderNote(order, sb.ToString()); + } + catch { } + } + + public void LogError(Exception exception, string shortMessage = null, string fullMessage = null, bool notify = false, IList errors = null, bool isWarning = false) + { + try + { + if (exception != null) + { + shortMessage = exception.ToAllMessages(); + fullMessage = exception.ToString(); + } + + if (shortMessage.HasValue()) + { + shortMessage = "PayPal. " + shortMessage; + Logger.InsertLog(isWarning ? LogLevel.Warning : LogLevel.Error, shortMessage, fullMessage.EmptyNull()); + + if (notify) + { + if (isWarning) + _services.Notifier.Warning(new LocalizedString(shortMessage)); + else + _services.Notifier.Error(new LocalizedString(shortMessage)); + } + } + } + catch (Exception) { } + + if (errors != null && shortMessage.HasValue()) + { + errors.Add(shortMessage); + } + } + + public PayPalPaymentInstruction ParsePaymentInstruction(dynamic json) + { + if (json == null) + return null; + + DateTime dt; + var result = new PayPalPaymentInstruction(); + + try + { + result.ReferenceNumber = (string)json.reference_number; + result.Type = (string)json.instruction_type; + result.Note = (string)json.note; + + if (DateTime.TryParse((string)json.payment_due_date, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt)) + { + result.DueDate = dt; + } + + if (json.amount != null) + { + result.AmountCurrencyCode = (string)json.amount.currency; + result.Amount = decimal.Parse((string)json.amount.value, CultureInfo.InvariantCulture); + } + + var rbi = json.recipient_banking_instruction; + + if (rbi != null) + { + result.RecipientBanking = new PayPalPaymentInstruction.RecipientBankingInstruction(); + result.RecipientBanking.BankName = (string)rbi.bank_name; + result.RecipientBanking.AccountHolderName = (string)rbi.account_holder_name; + result.RecipientBanking.AccountNumber = (string)rbi.account_number; + result.RecipientBanking.RoutingNumber = (string)rbi.routing_number; + result.RecipientBanking.Iban = (string)rbi.international_bank_account_number; + result.RecipientBanking.Bic = (string)rbi.bank_identifier_code; + } + + if (json.links != null) + { + result.Link = (string)json.links[0].href; + } + } + catch { } + + return result; + } + + public string CreatePaymentInstruction(PayPalPaymentInstruction instruct) + { + if (instruct == null || instruct.RecipientBanking == null) + return null; + + if (!instruct.IsManualBankTransfer && !instruct.IsPayUponInvoice) + return null; + + var sb = new StringBuilder("
    "); + var paragraphTemplate = "
    {0}
    "; + var rowTemplate = "{0}: {1}
    "; + var instructStrings = T("Plugins.SmartStore.PayPal.PaymentInstructionStrings").Text.SplitSafe(";"); + + if (instruct.IsManualBankTransfer) + { + sb.AppendFormat(paragraphTemplate, T("Plugins.SmartStore.PayPal.ManualBankTransferNote")); + + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Reference), instruct.ReferenceNumber); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.AccountNumber), instruct.RecipientBanking.AccountNumber); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.AccountHolder), instruct.RecipientBanking.AccountHolderName); + + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Bank), instruct.RecipientBanking.BankName); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Iban), instruct.RecipientBanking.Iban); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Bic), instruct.RecipientBanking.Bic); + } + else if (instruct.IsPayUponInvoice) + { + string amount = null; + var culture = new CultureInfo(_services.WorkContext.WorkingLanguage.LanguageCulture ?? "de-DE"); + + try + { + var currency = _currencyService.GetCurrencyByCode(instruct.AmountCurrencyCode); + var format = (currency != null && currency.CustomFormatting.HasValue() ? currency.CustomFormatting : "C"); + + amount = instruct.Amount.ToString(format, culture); + } + catch { } + + if (amount.IsEmpty()) + { + amount = string.Concat(instruct.Amount.ToString("N"), " ", instruct.AmountCurrencyCode); + } + + var intro = T("Plugins.SmartStore.PayPal.PayUponInvoiceLegalNote", _companyInfoSettings.Value.CompanyName.NaIfEmpty()); + + // /v1/payments/payment//payment-instruction not working anymore. Serves 401 unauthorized. + //if (instruct.Link.HasValue()) + //{ + // intro = "{0} {2}.".FormatInvariant(intro, instruct.Link, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Details)); + //} + + sb.AppendFormat(paragraphTemplate, intro); + + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Bank), instruct.RecipientBanking.BankName); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.AccountHolder), instruct.RecipientBanking.AccountHolderName); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Iban), instruct.RecipientBanking.Iban); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Bic), instruct.RecipientBanking.Bic); + sb.Append("
    "); + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Amount), amount); + if (instruct.DueDate.HasValue) + { + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.PaymentDueDate), instruct.DueDate.Value.ToString("d", culture)); + } + sb.AppendFormat(rowTemplate, instructStrings.SafeGet((int)PayPalPaymentInstructionItem.Reference), instruct.ReferenceNumber); + } + + sb.Append("
    "); + + return sb.ToString(); + } + + public PaymentStatus GetPaymentStatus(string state, string reasonCode, PaymentStatus defaultStatus) + { + var result = defaultStatus; + + if (state == null) + state = string.Empty; + + if (reasonCode == null) + reasonCode = string.Empty; + + switch (state.ToLowerInvariant()) + { + case "authorized": + result = PaymentStatus.Authorized; + break; + case "pending": + switch (reasonCode.ToLowerInvariant()) + { + case "authorization": + result = PaymentStatus.Authorized; + break; + default: + result = PaymentStatus.Pending; + break; + } + break; + case "completed": + case "captured": + case "partially_captured": + case "canceled_reversal": + result = PaymentStatus.Paid; + break; + case "denied": + case "expired": + case "failed": + case "voided": + result = PaymentStatus.Voided; + break; + case "reversed": + case "refunded": + result = PaymentStatus.Refunded; + break; + case "partially_refunded": + result = PaymentStatus.PartiallyRefunded; + break; + } + + return result; + } + + public PayPalResponse CallApi(string method, string path, string accessToken, PayPalApiSettingsBase settings, string data) + { + var isJson = (data.HasValue() && (data.StartsWith("{") || data.StartsWith("["))); + var encoding = (isJson ? Encoding.UTF8 : Encoding.ASCII); + var result = new PayPalResponse(); + HttpWebResponse webResponse = null; + + var url = GetApiUrl(settings.UseSandbox) + path.EnsureStartsWith("/"); + + if (method.IsCaseInsensitiveEqual("GET") && data.HasValue()) + url = url.EnsureEndsWith("?") + data; + + if (settings.SecurityProtocol.HasValue) + ServicePointManager.SecurityProtocol = settings.SecurityProtocol.Value; + + var request = (HttpWebRequest)WebRequest.Create(url); + request.Method = method; + request.Accept = "application/json"; + request.ContentType = (isJson ? "application/json" : "application/x-www-form-urlencoded"); + + try + { + if (HttpContext.Current != null && HttpContext.Current.Request != null) + request.UserAgent = HttpContext.Current.Request.UserAgent; + else + request.UserAgent = Plugin.SystemName; + } + catch { } + + if (path.EmptyNull().EndsWith("/token")) + { + // see https://github.com/paypal/sdk-core-dotnet/blob/master/Source/SDK/OAuthTokenCredential.cs + byte[] credentials = Encoding.UTF8.GetBytes("{0}:{1}".FormatInvariant(settings.ClientId, settings.Secret)); + + request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(credentials)); + } + else + { + request.Headers["Authorization"] = "Bearer " + accessToken.EmptyNull(); + } + + request.Headers["PayPal-Partner-Attribution-Id"] = "SmartStoreAG_Cart_PayPalPlus"; + + if (data.HasValue() && (method.IsCaseInsensitiveEqual("POST") || method.IsCaseInsensitiveEqual("PUT") || method.IsCaseInsensitiveEqual("PATCH"))) + { + byte[] bytes = encoding.GetBytes(data); + + request.ContentLength = bytes.Length; + + using (var stream = request.GetRequestStream()) + { + stream.Write(bytes, 0, bytes.Length); + } + } + else + { + request.ContentLength = 0; + } + + try + { + webResponse = request.GetResponse() as HttpWebResponse; + result.Success = ((int)webResponse.StatusCode < 400); + } + catch (WebException wexc) + { + result.Success = false; + result.ErrorMessage = wexc.ToString(); + webResponse = wexc.Response as HttpWebResponse; + } + catch (Exception exception) + { + result.Success = false; + result.ErrorMessage = exception.ToString(); + LogError(exception); + } + + try + { + if (webResponse != null) + { + using (var reader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8)) + { + var rawResponse = reader.ReadToEnd(); + if (rawResponse.HasValue()) + { + try + { + if (rawResponse.StartsWith("[")) + result.Json = JArray.Parse(rawResponse); + else + result.Json = JObject.Parse(rawResponse); + + if (result.Json != null) + { + if (!result.Success) + { + var name = (string)result.Json.name; + var message = (string)result.Json.message; + + if (name.IsEmpty()) + name = (string)result.Json.error; + + if (message.IsEmpty()) + message = (string)result.Json.error_description; + + result.ErrorMessage = "{0} ({1}).".FormatInvariant(message.NaIfEmpty(), name.NaIfEmpty()); + } + } + } + catch + { + if (!result.Success) + result.ErrorMessage = rawResponse; + } + } + } + + if (!result.Success) + { + if (result.ErrorMessage.IsEmpty()) + result.ErrorMessage = webResponse.StatusDescription; + + LogError(null, result.ErrorMessage, string.Concat(data.NaIfEmpty(), "\r\n\r\n", result.Json == null ? "" : result.Json.ToString()), false); + } + } + } + catch (Exception exception) + { + LogError(exception); + } + finally + { + if (webResponse != null) + { + webResponse.Close(); + webResponse.Dispose(); + } + } + + return result; + } + + public PayPalResponse EnsureAccessToken(PayPalSessionData session, PayPalApiSettingsBase settings) + { + if (session.AccessToken.IsEmpty() || DateTime.UtcNow >= session.TokenExpiration) + { + var result = CallApi("POST", "/v1/oauth2/token", null, settings, "grant_type=client_credentials"); + + if (result.Success) + { + session.AccessToken = (string)result.Json.access_token; + + var expireSeconds = ((string)result.Json.expires_in).ToInt(5 * 60); + + session.TokenExpiration = DateTime.UtcNow.AddSeconds(expireSeconds); + } + else + { + return result; + } + } + + return new PayPalResponse + { + Success = session.AccessToken.HasValue() + }; + } + + public PayPalResponse GetPayment(PayPalApiSettingsBase settings, PayPalSessionData session) + { + var result = CallApi("GET", "/v1/payments/payment/" + session.PaymentId, session.AccessToken, settings, null); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + return result; + } + + public PayPalResponse CreatePayment( + PayPalApiSettingsBase settings, + PayPalSessionData session, + List cart, + string providerSystemName, + string returnUrl, + string cancelUrl) + { + var store = _services.StoreContext.CurrentStore; + var customer = _services.WorkContext.CurrentCustomer; + + //var dateOfBirth = customer.GetAttribute(SystemCustomerAttributeNames.DateOfBirth); + + var data = new Dictionary(); + var redirectUrls = new Dictionary(); + var payer = new Dictionary(); + //var payerInfo = new Dictionary(); + var transaction = new Dictionary(); + var items = new List>(); + var itemList = new Dictionary(); + + // "PayPal PLUS only supports transaction type “Sale” (instant settlement)" + if (providerSystemName == PayPalPlusProvider.SystemName) + data.Add("intent", "sale"); + else + data.Add("intent", settings.TransactMode == TransactMode.AuthorizeAndCapture ? "sale" : "authorize"); + + if (settings.ExperienceProfileId.HasValue()) + data.Add("experience_profile_id", settings.ExperienceProfileId); + + // redirect urls + if (returnUrl.HasValue()) + redirectUrls.Add("return_url", returnUrl); + + if (cancelUrl.HasValue()) + redirectUrls.Add("cancel_url", cancelUrl); + + if (redirectUrls.Any()) + data.Add("redirect_urls", redirectUrls); + + // payer, payer_info + // paypal review: do not transmit + //if (dateOfBirth.HasValue) + //{ + // payerInfo.Add("birth_date", dateOfBirth.Value.ToString("yyyy-MM-dd")); + //} + //if (customer.BillingAddress != null) + //{ + // payerInfo.Add("billing_address", CreateAddress(customer.BillingAddress, false)); + //} + + payer.Add("payment_method", "paypal"); + //payer.Add("payer_info", payerInfo); + data.Add("payer", payer); + + var amount = CreateAmount(store, customer, cart, providerSystemName, items); + + itemList.Add("items", items); + + transaction.Add("amount", amount); + transaction.Add("item_list", itemList); + transaction.Add("invoice_number", session.OrderGuid.ToString()); + + data.Add("transactions", new List> { transaction }); + + var result = CallApi("POST", "/v1/payments/payment", session.AccessToken, settings, JsonConvert.SerializeObject(data)); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + //Logger.InsertLog(LogLevel.Information, "PayPal PLUS", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + (result.Json != null ? result.Json.ToString() : "")); + + return result; + } + + public PayPalResponse PatchShipping( + PayPalApiSettingsBase settings, + PayPalSessionData session, + List cart, + string providerSystemName) + { + var data = new List>(); + var amountTotal = new Dictionary(); + + var store = _services.StoreContext.CurrentStore; + var customer = _services.WorkContext.CurrentCustomer; + + if (customer.ShippingAddress != null) + { + var shippingAddress = new Dictionary(); + shippingAddress.Add("op", "add"); + shippingAddress.Add("path", "/transactions/0/item_list/shipping_address"); + shippingAddress.Add("value", CreateAddress(customer.ShippingAddress, true)); + data.Add(shippingAddress); + } + + // update of whole amount object required. patching single amount values not possible (MALFORMED_REQUEST). + var amount = CreateAmount(store, customer, cart, providerSystemName, null); + + amountTotal.Add("op", "replace"); + amountTotal.Add("path", "/transactions/0/amount"); + amountTotal.Add("value", amount); + data.Add(amountTotal); + + var result = CallApi("PATCH", "/v1/payments/payment/{0}".FormatInvariant(session.PaymentId), session.AccessToken, settings, JsonConvert.SerializeObject(data)); + + //Logger.InsertLog(LogLevel.Information, "PayPal PLUS", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + (result.Json != null ? result.Json.ToString() : "")); + + return result; + } + + public PayPalResponse ExecutePayment(PayPalApiSettingsBase settings, PayPalSessionData session) + { + var data = new Dictionary(); + data.Add("payer_id", session.PayerId); + + var result = CallApi("POST", "/v1/payments/payment/{0}/execute".FormatInvariant(session.PaymentId), session.AccessToken, settings, JsonConvert.SerializeObject(data)); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + + //Logger.InsertLog(LogLevel.Information, "PayPal PLUS", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + result.Json.ToString()); + } + + return result; + } + + public PayPalResponse Refund(PayPalApiSettingsBase settings, PayPalSessionData session, RefundPaymentRequest request) + { + var data = new Dictionary(); + var store = _services.StoreService.GetStoreById(request.Order.StoreId); + var isSale = request.Order.AuthorizationTransactionResult.Contains("(sale)"); + + var path = "/v1/payments/{0}/{1}/refund".FormatInvariant(isSale ? "sale" : "capture", request.Order.CaptureTransactionId); + + var amount = new Dictionary(); + amount.Add("total", request.AmountToRefund.FormatInvariant()); + amount.Add("currency", store.PrimaryStoreCurrency.CurrencyCode); + + data.Add("amount", amount); + + var result = CallApi("POST", path, session.AccessToken, settings, data.Any() ? JsonConvert.SerializeObject(data) : null); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + //Logger.InsertLog(LogLevel.Information, "PayPal Refund", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + (result.Json != null ? result.Json.ToString() : "")); + + return result; + } + + public PayPalResponse Capture(PayPalApiSettingsBase settings, PayPalSessionData session, CapturePaymentRequest request) + { + var data = new Dictionary(); + //var isAuthorize = request.Order.AuthorizationTransactionCode.IsCaseInsensitiveEqual("authorize"); + + var path = "/v1/payments/authorization/{0}/capture".FormatInvariant(request.Order.AuthorizationTransactionId); + + var store = _services.StoreService.GetStoreById(request.Order.StoreId); + + var amount = new Dictionary(); + amount.Add("total", request.Order.OrderTotal.FormatInvariant()); + amount.Add("currency", store.PrimaryStoreCurrency.CurrencyCode); + + data.Add("amount", amount); + + var result = CallApi("POST", path, session.AccessToken, settings, JsonConvert.SerializeObject(data)); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + return result; + } + + public PayPalResponse Void(PayPalApiSettingsBase settings, PayPalSessionData session, VoidPaymentRequest request) + { + var path = "/v1/payments/authorization/{0}/void".FormatInvariant(request.Order.AuthorizationTransactionId); + + var result = CallApi("POST", path, session.AccessToken, settings, null); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + return result; + } + + public PayPalResponse UpsertCheckoutExperience(PayPalApiSettingsBase settings, PayPalSessionData session, Store store) + { + PayPalResponse result; + var name = store.Name; + var logo = _pictureService.Value.GetPictureById(store.LogoPictureId); + var path = "/v1/payment-experience/web-profiles"; + + var data = new Dictionary(); + var presentation = new Dictionary(); + var inpuFields = new Dictionary(); + + // find existing profile id, only one profile per profile name possible + if (settings.ExperienceProfileId.IsEmpty()) + { + result = CallApi("GET", path, session.AccessToken, settings, null); + if (result.Success && result.Json != null) + { + foreach (var profile in result.Json) + { + var profileName = (string)profile.name; + if (profileName.IsCaseInsensitiveEqual(name)) + { + settings.ExperienceProfileId = (string)profile.id; + break; + } + } + } + } + + presentation.Add("brand_name", name); + presentation.Add("locale_code", _services.WorkContext.WorkingLanguage.UniqueSeoCode.EmptyNull().ToUpper()); + + if (logo != null) + presentation.Add("logo_image", _pictureService.Value.GetPictureUrl(logo, showDefaultPicture: false, storeLocation: store.Url)); + + inpuFields.Add("allow_note", false); + inpuFields.Add("no_shipping", 0); + inpuFields.Add("address_override", 1); + + data.Add("name", name); + data.Add("presentation", presentation); + data.Add("input_fields", inpuFields); + + if (settings.ExperienceProfileId.HasValue()) + path = string.Concat(path, "/", HttpUtility.UrlPathEncode(settings.ExperienceProfileId)); + + result = CallApi(settings.ExperienceProfileId.HasValue() ? "PUT" : "POST", path, session.AccessToken, settings, JsonConvert.SerializeObject(data)); + + if (result.Success) + { + if (result.Json != null) + result.Id = (string)result.Json.id; + else + result.Id = settings.ExperienceProfileId; + } + + return result; + } + + public PayPalResponse DeleteCheckoutExperience(PayPalApiSettingsBase settings, PayPalSessionData session) + { + var result = CallApi("DELETE", "/v1/payment-experience/web-profiles/" + settings.ExperienceProfileId, session.AccessToken, settings, null); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + return result; + } + + public PayPalResponse CreateWebhook(PayPalApiSettingsBase settings, PayPalSessionData session, string url) + { + var data = new Dictionary(); + var events = new List>(); + + events.Add(new Dictionary { { "name", "PAYMENT.AUTHORIZATION.VOIDED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.CAPTURE.COMPLETED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.CAPTURE.DENIED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.CAPTURE.PENDING" } }); + events.Add(new Dictionary { { "name", "PAYMENT.CAPTURE.REFUNDED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.CAPTURE.REVERSED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.SALE.COMPLETED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.SALE.DENIED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.SALE.PENDING" } }); + events.Add(new Dictionary { { "name", "PAYMENT.SALE.REFUNDED" } }); + events.Add(new Dictionary { { "name", "PAYMENT.SALE.REVERSED" } }); + + data.Add("url", url); + data.Add("event_types", events); + + var result = CallApi("POST", "/v1/notifications/webhooks", session.AccessToken, settings, JsonConvert.SerializeObject(data)); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + return result; + } + + public PayPalResponse DeleteWebhook(PayPalApiSettingsBase settings, PayPalSessionData session) + { + var result = CallApi("DELETE", "/v1/notifications/webhooks/" + settings.WebhookId, session.AccessToken, settings, null); + + if (result.Success && result.Json != null) + { + result.Id = (string)result.Json.id; + } + + return result; + } + + /// return 503 (HttpStatusCode.ServiceUnavailable) to ask paypal to resend it at later time again + public HttpStatusCode ProcessWebhook( + PayPalApiSettingsBase settings, + NameValueCollection headers, + string rawJson, + string providerSystemName) + { + if (rawJson.IsEmpty()) + return HttpStatusCode.OK; + + dynamic json = JObject.Parse(rawJson); + var eventType = (string)json.event_type; + + //foreach (var key in headers.AllKeys)"{0}: {1}".FormatInvariant(key, headers[key]).Dump(); + //string data = JsonConvert.SerializeObject(json, Formatting.Indented);data.Dump(); + + + // validating against PayPal SDK failing using sandbox, so better we do not use it: + //var apiContext = new global::PayPal.Api.APIContext + //{ + // AccessToken = "I do not have one here", + // Config = new Dictionary + // { + // { "mode", settings.UseSandbox ? "sandbox" : "live" }, + // { "clientId", settings.ClientId }, + // { "clientSecret", settings.Secret }, + // { "webhook.id", setting.WebhookId }, + // } + //}; + //var result = global::PayPal.Api.WebhookEvent.ValidateReceivedEvent(apiContext, headers, rawJson, webhookId); + //} + + var paymentId = (string)json.resource.parent_payment; + if (paymentId.IsEmpty()) + { + LogError(null, T("Plugins.SmartStore.PayPal.FoundOrderForPayment", 0, "".NaIfEmpty()), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true); + return HttpStatusCode.OK; + } + + var orders = _orderRepository.Value.Table + .Where(x => x.PaymentMethodSystemName == providerSystemName && x.AuthorizationTransactionCode == paymentId) + .ToList(); + + if (orders.Count != 1) + { + LogError(null, T("Plugins.SmartStore.PayPal.FoundOrderForPayment", orders.Count, paymentId), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true); + return HttpStatusCode.OK; + } + + var order = orders.First(); + var store = _services.StoreService.GetStoreById(order.StoreId); + + var total = decimal.Zero; + var currency = (string)json.resource.amount.currency; + var primaryCurrency = store.PrimaryStoreCurrency.CurrencyCode; + + if (!primaryCurrency.IsCaseInsensitiveEqual(currency)) + { + LogError(null, T("Plugins.SmartStore.PayPal.CurrencyNotEqual", currency.NaIfEmpty(), primaryCurrency), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true); + return HttpStatusCode.OK; + } + + eventType = eventType.Substring(eventType.LastIndexOf('.') + 1); + + var newPaymentStatus = GetPaymentStatus(eventType, "authorization", order.PaymentStatus); + + var isValidTotal = decimal.TryParse((string)json.resource.amount.total, NumberStyles.Currency, CultureInfo.InvariantCulture, out total); + + if (newPaymentStatus == PaymentStatus.Refunded && (Math.Abs(order.OrderTotal) - Math.Abs(total)) > decimal.Zero) + { + newPaymentStatus = PaymentStatus.PartiallyRefunded; + } + + switch (newPaymentStatus) + { + case PaymentStatus.Pending: + break; + case PaymentStatus.Authorized: + if (_orderProcessingService.CanMarkOrderAsAuthorized(order)) + _orderProcessingService.MarkAsAuthorized(order); + break; + case PaymentStatus.Paid: + if (_orderProcessingService.CanMarkOrderAsPaid(order)) + _orderProcessingService.MarkOrderAsPaid(order); + break; + case PaymentStatus.Refunded: + if (_orderProcessingService.CanRefundOffline(order)) + _orderProcessingService.RefundOffline(order); + break; + case PaymentStatus.PartiallyRefunded: + if (_orderProcessingService.CanPartiallyRefundOffline(order, Math.Abs(total))) + _orderProcessingService.PartiallyRefundOffline(order, Math.Abs(total)); + break; + case PaymentStatus.Voided: + if (_orderProcessingService.CanVoidOffline(order)) + _orderProcessingService.VoidOffline(order); + break; + } + + AddOrderNote(settings, order, (string)ToInfoString(json), true); + + return HttpStatusCode.OK; + } + } + + + public class PayPalResponse + { + public bool Success { get; set; } + public dynamic Json { get; set; } + public string ErrorMessage { get; set; } + public string Id { get; set; } + } + + public class PayPalSessionData + { + public PayPalSessionData() + { + OrderGuid = Guid.NewGuid(); + } + + public string AccessToken { get; set; } + public DateTime TokenExpiration { get; set; } + public string PaymentId { get; set; } + public string PayerId { get; set; } + public string ApprovalUrl { get; set; } + public Guid OrderGuid { get; private set; } + public PayPalPaymentInstruction PaymentInstruction { get; set; } + } + + public class PayPalPaymentInstruction + { + public string ReferenceNumber { get; set; } + public string Type { get; set; } + public decimal Amount { get; set; } + public string AmountCurrencyCode { get; set; } + public DateTime? DueDate { get; set; } + public string Note { get; set; } + public string Link { get; set; } + + public RecipientBankingInstruction RecipientBanking { get; set; } + + public bool IsManualBankTransfer + { + get { return Type.IsCaseInsensitiveEqual("MANUAL_BANK_TRANSFER"); } + } + + public bool IsPayUponInvoice + { + get { return Type.IsCaseInsensitiveEqual("PAY_UPON_INVOICE"); } + } + + public class RecipientBankingInstruction + { + public string BankName { get; set; } + public string AccountHolderName { get; set; } + public string AccountNumber { get; set; } + public string RoutingNumber { get; set; } + public string Iban { get; set; } + public string Bic { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Settings/PayPalSettings.cs b/src/Plugins/SmartStore.PayPal/Settings/PayPalSettings.cs new file mode 100644 index 0000000000..8109422c68 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Settings/PayPalSettings.cs @@ -0,0 +1,162 @@ +using System.Collections.Generic; +using System.Net; +using SmartStore.Core.Configuration; +using SmartStore.PayPal.Services; + +namespace SmartStore.PayPal.Settings +{ + public abstract class PayPalSettingsBase + { + public PayPalSettingsBase() + { + SecurityProtocol = SecurityProtocolType.Tls12; + IpnChangesPaymentStatus = true; + AddOrderNotes = true; + } + + public SecurityProtocolType? SecurityProtocol { get; set; } + + public bool UseSandbox { get; set; } + + public bool AddOrderNotes { get; set; } + + /// + /// Gets or sets a value indicating whether to "additional fee" is specified as percentage. true - percentage, false - fixed value. + /// + public bool AdditionalFeePercentage { get; set; } + + public decimal AdditionalFee { get; set; } + + /// + /// Gets or sets a value indicating whether an IPN should change the payment status + /// + public bool IpnChangesPaymentStatus { get; set; } + } + + public abstract class PayPalApiSettingsBase : PayPalSettingsBase + { + public TransactMode TransactMode { get; set; } + public string ApiAccountName { get; set; } + public string ApiAccountPassword { get; set; } + public string Signature { get; set; } + + /// + /// PayPal client id + /// + public string ClientId { get; set; } + + /// + /// PayPal secret + /// + public string Secret { get; set; } + + /// + /// PayPal experience profile id + /// + public string ExperienceProfileId { get; set; } + + /// + /// PayPal webhook id + /// + public string WebhookId { get; set; } + } + + + public class PayPalDirectPaymentSettings : PayPalApiSettingsBase, ISettings + { + public PayPalDirectPaymentSettings() + { + UseSandbox = true; + TransactMode = TransactMode.Authorize; + } + } + + public class PayPalExpressPaymentSettings : PayPalApiSettingsBase, ISettings + { + public PayPalExpressPaymentSettings() + { + UseSandbox = true; + TransactMode = TransactMode.Authorize; + } + + /// + /// Determines whether the checkout button is displayed beneath the cart + /// + //public bool DisplayCheckoutButton { get; set; } + + /// + /// Specifies whether to display the checkout button in mini shopping cart + /// + public bool ShowButtonInMiniShoppingCart { get; set; } + + /// + /// Determines whether the shipment address has to be confirmed by PayPal + /// + public bool ConfirmedShipment { get; set; } + + /// + /// Determines whether the shipment address is transmitted to PayPal + /// + public bool NoShipmentAddress { get; set; } + + /// + /// Callback timeout + /// + public int CallbackTimeout { get; set; } + + /// + /// Default shipping price + /// + public decimal DefaultShippingPrice { get; set; } + } + + public class PayPalPlusPaymentSettings : PayPalApiSettingsBase, ISettings + { + public PayPalPlusPaymentSettings() + { + UseSandbox = true; + } + + /// + /// Specifies other payment methods to be offered in payment wall + /// + public List ThirdPartyPaymentMethods { get; set; } + + /// + /// Specifies whether to display the logo of a third party payment method + /// + public bool DisplayPaymentMethodLogo { get; set; } + + /// + /// Specifies whether to display the description of a third party payment method + /// + public bool DisplayPaymentMethodDescription { get; set; } + } + + public class PayPalStandardPaymentSettings : PayPalSettingsBase, ISettings + { + public PayPalStandardPaymentSettings() + { + UseSandbox = true; + EnableIpn = true; + } + + public string BusinessEmail { get; set; } + public string PdtToken { get; set; } + public bool PassProductNamesAndTotals { get; set; } + public bool PdtValidateOrderTotal { get; set; } + public bool PdtValidateOnlyWarn { get; set; } + public bool EnableIpn { get; set; } + public string IpnUrl { get; set; } + } + + + /// + /// Represents payment processor transaction mode + /// + public enum TransactMode + { + Authorize = 1, + AuthorizeAndCapture = 2 + } +} diff --git a/src/Plugins/SmartStore.PayPal/SmartStore.PayPal.csproj b/src/Plugins/SmartStore.PayPal/SmartStore.PayPal.csproj new file mode 100644 index 0000000000..e82c4a4097 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/SmartStore.PayPal.csproj @@ -0,0 +1,509 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {BD1D993C-50E7-40DF-83BB-45455F9CE402} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.PayPal + SmartStore.PayPal + v4.5.1 + 512 + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.PayPal\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.PayPal\ + TRACE + prompt + 4 + false + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + ..\..\packages\FluentValidation.5.6.2.0\lib\Net45\FluentValidation.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + False + + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Settings.settings + + + + + + + True + True + Reference.map + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + False + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + False + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + False + + + {4f1f649c-1020-45be-a487-f416d9297ff3} + SmartStore.Web + False + + + + + PreserveNewest + + + PreserveNewest + + + + + PreserveNewest + + + PreserveNewest + + + Always + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + PreserveNewest + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + PreserveNewest + + + PreserveNewest + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Designer + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Designer + + + Designer + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + + MSDiscoCodeGenerator + Reference.cs + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + PreserveNewest + + + Reference.map + + + + + PreserveNewest + + + + + + + + + + + Dynamic + Web References\PayPalSvc\ + https://www.paypalobjects.com/wsdl/PayPalSvc.wsdl + + + + + Settings + SmartStore_Plugin_Payments_PayPalExpress_PayPalSvc_PayPalAPIInterfaceService + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + bin\ + + + + + + + + + + + False + True + 60378 + / + http://localhost:53131/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Validators/PayPalDirectPaymentInfoValidator.cs b/src/Plugins/SmartStore.PayPal/Validators/PayPalDirectPaymentInfoValidator.cs new file mode 100644 index 0000000000..e0e7356110 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Validators/PayPalDirectPaymentInfoValidator.cs @@ -0,0 +1,22 @@ +using FluentValidation; +using SmartStore.PayPal.Models; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Validators; + +namespace SmartStore.PayPal.Validators +{ + public class PaymentInfoValidator : AbstractValidator + { + public PaymentInfoValidator(ILocalizationService localizationService) { + //useful links: + //http://fluentvalidation.codeplex.com/wikipage?title=Custom&referringTitle=Documentation&ANCHOR#CustomValidator + //http://benjii.me/2010/11/credit-card-validator-attribute-for-asp-net-mvc-3/ + + RuleFor(x => x.CardholderName).NotEmpty().WithMessage(localizationService.GetResource("Payment.CardholderName.Required")); + RuleFor(x => x.CardNumber).IsCreditCard().WithMessage(localizationService.GetResource("Payment.CardNumber.Wrong")); + RuleFor(x => x.CardCode).Matches(@"^[0-9]{3,4}$").WithMessage(localizationService.GetResource("Payment.CardCode.Wrong")); + RuleFor(x => x.ExpireMonth).NotEmpty().WithMessage(localizationService.GetResource("Payment.ExpireMonth.Required")); + RuleFor(x => x.ExpireYear).NotEmpty().WithMessage(localizationService.GetResource("Payment.ExpireYear.Required")); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Validators/PayPalExpressPaymentInfoValidator.cs b/src/Plugins/SmartStore.PayPal/Validators/PayPalExpressPaymentInfoValidator.cs new file mode 100644 index 0000000000..3290fdb4f7 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Validators/PayPalExpressPaymentInfoValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using SmartStore.PayPal.Models; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Validators; + +namespace SmartStore.PayPal.Validators +{ + public class PayPalExpressPaymentInfoValidator : AbstractValidator + { + public PayPalExpressPaymentInfoValidator(ILocalizationService localizationService) { + + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Validators/PayPalPlusConfigValidator.cs b/src/Plugins/SmartStore.PayPal/Validators/PayPalPlusConfigValidator.cs new file mode 100644 index 0000000000..b7355b4299 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Validators/PayPalPlusConfigValidator.cs @@ -0,0 +1,33 @@ +using System; +using FluentValidation; +using SmartStore.PayPal.Models; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Validators; + +namespace SmartStore.PayPal.Validators +{ + public class PayPalPlusConfigValidator : SmartValidatorBase + { + public PayPalPlusConfigValidator(ILocalizationService localize, Func addRule) + { + if (addRule("ClientId")) + { + RuleFor(x => x.ClientId).NotEmpty() + .WithMessage(localize.GetResource("Plugins.SmartStore.PayPal.ValidateClientIdAndSecret")); + } + + if (addRule("Secret")) + { + RuleFor(x => x.Secret).NotEmpty() + .WithMessage(localize.GetResource("Plugins.SmartStore.PayPal.ValidateClientIdAndSecret")); + } + + if (addRule("ThirdPartyPaymentMethods")) + { + RuleFor(x => x.ThirdPartyPaymentMethods) + .Must(x => x == null || x.Count <= 5) + .WithMessage(localize.GetResource("Plugins.Payments.PayPalPlus.ValidateThirdPartyPaymentMethods")); + } + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/Configure.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/Configure.cshtml new file mode 100644 index 0000000000..128ae981b6 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/Configure.cshtml @@ -0,0 +1,120 @@ +@using SmartStore.PayPal.Models; +@using SmartStore.Web.Framework; +@model PayPalDirectConfigurationModel +@{ + Layout = ""; + Html.AddCssFileParts(true, "~/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css"); +} + +
    +
    +
    + + @Html.Raw(T("Plugins.Payments.PayPalDirect.AdminInstruction")) +
    +
    +
    + + PayPal + +
    +
    + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.TransactMode) + + @Html.SettingOverrideCheckbox(model => model.TransactMode) + @Html.DropDownListFor(model => model.TransactMode, Model.TransactModeValues) +
    + @Html.SmartLabelFor(model => model.SecurityProtocol) + + @Html.DropDownListFor(model => model.SecurityProtocol, Model.AvailableSecurityProtocols, T("Common.Unspecified")) +
    + @Html.SmartLabelFor(model => model.UseSandbox) + + @*multistore context not possible, see IPN handling*@ + @Html.EditorFor(model => model.UseSandbox) + @Html.ValidationMessageFor(model => model.UseSandbox) +
    + @Html.SmartLabelFor(model => model.ApiAccountName) + + @Html.SettingEditorFor(model => model.ApiAccountName) + @Html.ValidationMessageFor(model => model.ApiAccountName) +
    + @Html.SmartLabelFor(model => model.ApiAccountPassword) + + @Html.SettingEditorFor(model => model.ApiAccountPassword) + @Html.ValidationMessageFor(model => model.ApiAccountPassword) +
    + @Html.SmartLabelFor(model => model.Signature) + + @Html.SettingEditorFor(model => model.Signature) + @Html.ValidationMessageFor(model => model.Signature) +
    + @Html.SmartLabelFor(model => model.IpnChangesPaymentStatus) + + @Html.SettingEditorFor(model => model.IpnChangesPaymentStatus) + @Html.ValidationMessageFor(model => model.IpnChangesPaymentStatus) +
    + @Html.SmartLabelFor(model => model.AdditionalFee) + + @Html.SettingEditorFor(model => model.AdditionalFee) + @Html.ValidationMessageFor(model => model.AdditionalFee) +
    + @Html.SmartLabelFor(model => model.AdditionalFeePercentage) + + @Html.SettingEditorFor(model => model.AdditionalFeePercentage) + @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) +
    +   + + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/PaymentInfo.Mobile.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/PaymentInfo.Mobile.cshtml new file mode 100644 index 0000000000..aeb9300a95 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/PaymentInfo.Mobile.cshtml @@ -0,0 +1,25 @@ +@{ + Layout = ""; +} +@model PayPalDirectPaymentInfoModel +@using SmartStore.PayPal.Models; +@using SmartStore.Web.Framework; + +@Html.SmartLabelFor(model => model.CreditCardTypes, false) +@Html.DropDownListFor(model => model.CreditCardType, Model.CreditCardTypes, new { data_native_menu = "false" }) +@Html.SmartLabelFor(model => model.CardholderName, false) +@Html.TextBoxFor(model => model.CardholderName, new { autocomplete = "off" }) +@Html.ValidationMessageFor(model => model.CardholderName) +@Html.SmartLabelFor(model => model.CardNumber, false) +@Html.TextBoxFor(model => model.CardNumber, new { autocomplete = "off", maxlength = 22 }) +@Html.ValidationMessageFor(model => model.CardNumber) +@Html.SmartLabelFor(model => model.ExpireMonth, false) +
    +
    + @Html.DropDownListFor(model => model.ExpireMonth, Model.ExpireMonths, new { data_native_menu = "false" }) + @Html.DropDownListFor(model => model.ExpireYear, Model.ExpireYears, new { data_native_menu = "false" }) +
    +
    +@Html.SmartLabelFor(model => model.CardCode, false) +@Html.TextBoxFor(model => model.CardCode, new { autocomplete = "off", maxlength = 4 }) +@Html.ValidationMessageFor(model => model.CardCode) diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/PaymentInfo.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/PaymentInfo.cshtml new file mode 100644 index 0000000000..3262f8eea2 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalDirect/PaymentInfo.cshtml @@ -0,0 +1,45 @@ +@{ + Layout = ""; + Html.AddCssFileParts(true, "~/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css"); +} +@model PayPalDirectPaymentInfoModel +@using SmartStore.PayPal.Models; +@using SmartStore.Web.Framework; + +
    +
    + @Html.LabelFor(model => model.CreditCardTypes, new { @class="control-label required" }) +
    + @Html.DropDownListFor(model => model.CreditCardType, Model.CreditCardTypes, new { @class = "dropdownlists" }) +
    +
    +
    + @Html.LabelFor(model => model.CardholderName, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.CardholderName, new { autocomplete = "off" }) + @Html.ValidationMessageFor(model => model.CardholderName) +
    +
    +
    + @Html.LabelFor(model => model.CardNumber, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.CardNumber, new { autocomplete = "off", maxlength = 22 }) + @Html.ValidationMessageFor(model => model.CardNumber) +
    +
    +
    + @Html.LabelFor(model => model.ExpireMonth, new { @class="control-label required" }) +
    + @Html.DropDownListFor(model => model.ExpireMonth, Model.ExpireMonths, new { @class = "dropdownlists" }) + / + @Html.DropDownListFor(model => model.ExpireYear, Model.ExpireYears, new { @class = "dropdownlists" }) +
    +
    +
    + @Html.LabelFor(model => model.CardCode, new { @class="control-label required" }) +
    + @Html.TextBoxFor(model => model.CardCode, new { autocomplete = "off", maxlength = 4 }) + @Html.ValidationMessageFor(model => model.CardCode) +
    +
    +
    diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/Configure.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/Configure.cshtml new file mode 100644 index 0000000000..5738f2df4a --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/Configure.cshtml @@ -0,0 +1,166 @@ +@using SmartStore.PayPal.Models; +@using SmartStore.Web.Framework; +@using SmartStore.Web.Framework.UI; +@model PayPalExpressConfigurationModel +@{ + Layout = ""; + Html.AddCssFileParts(true, "~/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css"); +} + +
    +
    +
    + + @Html.Raw(T("Plugins.Payments.PayPalExpress.AdminInstruction")) +
    +
    +
    + + PayPal + +
    +
    + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.TransactMode) + + @Html.SettingOverrideCheckbox(model => model.TransactMode) + @Html.DropDownListFor(model => model.TransactMode, Model.TransactModeValues) +
    + @Html.SmartLabelFor(model => model.SecurityProtocol) + + @Html.DropDownListFor(model => model.SecurityProtocol, Model.AvailableSecurityProtocols, T("Common.Unspecified")) +
    + @Html.SmartLabelFor(model => model.UseSandbox) + + @*multistore context not possible, see IPN handling*@ + @Html.EditorFor(model => model.UseSandbox) + @Html.ValidationMessageFor(model => model.UseSandbox) +
    + @Html.SmartLabelFor(model => model.ApiAccountName) + + @Html.SettingEditorFor(model => model.ApiAccountName) + @Html.ValidationMessageFor(model => model.ApiAccountName) +
    + @Html.SmartLabelFor(model => model.ApiAccountPassword) + + @Html.SettingEditorFor(model => model.ApiAccountPassword) + @Html.ValidationMessageFor(model => model.ApiAccountPassword) +
    + @Html.SmartLabelFor(model => model.Signature) + + @Html.SettingEditorFor(model => model.Signature) + @Html.ValidationMessageFor(model => model.Signature) +
    + @Html.SmartLabelFor(model => model.CallbackTimeout) + + @Html.SettingEditorFor(model => model.CallbackTimeout) + @Html.ValidationMessageFor(model => model.CallbackTimeout) +
    + @Html.SmartLabelFor(model => model.IpnChangesPaymentStatus) + + @Html.SettingEditorFor(model => model.IpnChangesPaymentStatus) + @Html.ValidationMessageFor(model => model.IpnChangesPaymentStatus) +
    + @Html.SmartLabelFor(model => model.ShowButtonInMiniShoppingCart) + + @Html.SettingEditorFor(model => model.ShowButtonInMiniShoppingCart) + @Html.ValidationMessageFor(model => model.ShowButtonInMiniShoppingCart) +
    + @Html.SmartLabelFor(model => model.NoShipmentAddress) + + @Html.SettingEditorFor(model => model.NoShipmentAddress) + @Html.ValidationMessageFor(model => model.NoShipmentAddress) +
    + @Html.SmartLabelFor(model => model.ConfirmedShipment) + + @Html.SettingEditorFor(model => model.ConfirmedShipment) + @Html.ValidationMessageFor(model => model.ConfirmedShipment) +
    + @Html.SmartLabelFor(model => model.DefaultShippingPrice) + + @Html.SettingEditorFor(model => model.DefaultShippingPrice) + @Html.ValidationMessageFor(model => model.DefaultShippingPrice) +
    + @Html.SmartLabelFor(model => model.AdditionalFee) + + @Html.SettingEditorFor(model => model.AdditionalFee) + @Html.ValidationMessageFor(model => model.AdditionalFee) +
    + @Html.SmartLabelFor(model => model.AdditionalFeePercentage) + + @Html.SettingEditorFor(model => model.AdditionalFeePercentage) + @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) +
    +   + + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/MiniShoppingCart.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/MiniShoppingCart.cshtml new file mode 100644 index 0000000000..3296cbd446 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/MiniShoppingCart.cshtml @@ -0,0 +1,10 @@ +@model SmartStore.PayPal.Models.PayPalExpressPaymentInfoModel +
    +
    + @T("Plugins.Payments.PayPalExpress.SelectionText") +
    +
    + + +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/PaymentInfo.Mobile.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/PaymentInfo.Mobile.cshtml new file mode 100644 index 0000000000..a53d4ee068 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/PaymentInfo.Mobile.cshtml @@ -0,0 +1,14 @@ +@{ + Layout = ""; +} +@model SmartStore.PayPal.Models.PayPalExpressPaymentInfoModel +@using SmartStore.Web.Framework; + +@if (Model.CurrentPageIsBasket) +{ +
    + + + +
    +} diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/PaymentInfo.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/PaymentInfo.cshtml new file mode 100644 index 0000000000..998eb4a6c0 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalExpress/PaymentInfo.cshtml @@ -0,0 +1,22 @@ +@{ + Layout = ""; + Html.AddCssFileParts(true, Url.Content("~/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css")); +} +@model SmartStore.PayPal.Models.PayPalExpressPaymentInfoModel +@using SmartStore.Web.Framework; + +@if (Model.CurrentPageIsBasket) +{ +
    +
    + @T("Plugins.Payments.PayPalExpress.SelectionText") +
    + +
    + + + + +
    +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/Configure.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/Configure.cshtml new file mode 100644 index 0000000000..129922ca27 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/Configure.cshtml @@ -0,0 +1,207 @@ +@using SmartStore.PayPal; +@using SmartStore.PayPal.Models; +@using SmartStore.Web.Framework; +@using SmartStore.Web.Framework.UI; +@model PayPalPlusConfigurationModel +@{ + Layout = ""; + Html.AddCssFileParts(true, "~/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css"); + + var hasCredentials = (Model.ClientId.HasValue() && Model.Secret.HasValue()); +} + +
    +
    +
    + + @Html.Raw(T("Plugins.Payments.PayPalPlus.AdminInstruction")) +
    +
    +
    + + PayPal + +
    +
    + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@Html.ValidationSummary(false) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + @Model.ConfigGroups.SafeGet(0) +
    +
    +
    + @Html.SmartLabelFor(model => model.UseSandbox) + + @Html.EditorFor(model => model.UseSandbox) + @Html.ValidationMessageFor(model => model.UseSandbox) +
    + @Html.SmartLabelFor(model => model.ClientId) + + @Html.SettingOverrideCheckbox(model => model.ClientId) + @Html.TextBoxFor(model => model.ClientId, new { @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ClientId) +
    + @Html.SmartLabelFor(model => model.Secret) + + @Html.SettingOverrideCheckbox(model => model.Secret) + @Html.TextBoxFor(model => model.Secret, new { @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.Secret) +
    +
    +
    + @Model.ConfigGroups.SafeGet(1) +
    +
    +
    + @Html.SmartLabelFor(model => model.SecurityProtocol) + + @Html.DropDownListFor(model => model.SecurityProtocol, Model.AvailableSecurityProtocols, T("Common.Unspecified")) +
    + @Html.SmartLabelFor(model => model.ExperienceProfileId) + + @Html.SettingEditorFor(model => model.ExperienceProfileId) + + +   + @T(Model.ExperienceProfileId.HasValue() ? "Common.Refresh" : "Common.AddNew") + + + @if (Model.ExperienceProfileId.HasValue()) + { + +  @T("Admin.Common.Delete") + + } + + @Html.ValidationMessageFor(model => model.ExperienceProfileId) +
    + @Html.SmartLabelFor(model => model.WebhookId) + + @* IPNs and webhook messages have no store context, so multistore configuration not possible here *@ + @Html.EditorFor(model => model.WebhookId) + + @if (Model.WebhookId.HasValue()) + { + +  @T("Admin.Common.Delete") + + } + else + { + +  @T("Common.AddNew") + + } + + @Html.ValidationMessageFor(model => model.WebhookId) +
    +
    +
    + @Model.ConfigGroups.SafeGet(2) +
    +
    +
    + @Html.SmartLabelFor(model => model.ThirdPartyPaymentMethods) + + @Html.SettingOverrideCheckbox(model => model.ThirdPartyPaymentMethods) + @Html.ListBoxFor(x => x.ThirdPartyPaymentMethods, + new MultiSelectList(Model.AvailableThirdPartyPaymentMethods, "Value", "Text"), + new { multiple = "multiple", @class = "control-xlarge" }) + @Html.ValidationMessageFor(model => model.ThirdPartyPaymentMethods) +
    + @Html.SmartLabelFor(model => model.DisplayPaymentMethodLogo) + + @Html.SettingEditorFor(model => model.DisplayPaymentMethodLogo) + @Html.ValidationMessageFor(model => model.DisplayPaymentMethodLogo) +
    + @Html.SmartLabelFor(model => model.DisplayPaymentMethodDescription) + + @Html.SettingEditorFor(model => model.DisplayPaymentMethodDescription) + @Html.ValidationMessageFor(model => model.DisplayPaymentMethodDescription) +
    + @Html.SmartLabelFor(model => model.AdditionalFee) + + @Html.SettingEditorFor(model => model.AdditionalFee) + @Html.ValidationMessageFor(model => model.AdditionalFee) +
    + @Html.SmartLabelFor(model => model.AdditionalFeePercentage) + + @Html.SettingEditorFor(model => model.AdditionalFeePercentage) + @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) +
    +   + + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWall.Mobile.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWall.Mobile.cshtml new file mode 100644 index 0000000000..266ae25887 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWall.Mobile.cshtml @@ -0,0 +1,66 @@ +@using SmartStore.Web.Models.Checkout; +@using SmartStore.PayPal.Models; +@model PayPalPlusCheckoutModel +@{ + Layout = "~/Views/Shared/_Root.cshtml"; + Html.AddTitleParts(T("PageTitle.Checkout").Text); +} + +@Html.Partial("PaymentWallScripting") + +
    +
    +

    @T("Checkout.SelectPaymentMethod")

    +
    +
    + @Html.Widget("mobile_checkout_payment_method_top") + + @if (Model.ErrorMessage.HasValue()) + { +
    +
      +
    • @Html.Raw(T("Plugins.Payments.PayPalPlus.MethodUnavailable"))
    • +
    • + @if (!Model.ApprovalUrl.HasValue()) + { + @T("Plugins.SmartStore.PayPal.NoApprovalUrlReturned") + } + @Model.ErrorMessage +
    • +
    +
    + } + else if (Model.PayPalPlusPseudoMessageFlag.HasValue() && Model.PayPalPlusPseudoMessageFlag == "1") + { +
    +
      +
    • @Html.Raw(T("Plugins.Payments.PayPalPlus.SorryFailure"))
    • +
    +
    + } + + @if (Model.FullDescription.HasValue()) + { +
    + @Html.Raw(Model.FullDescription) +
    + } + + @if (Model.HasAnyFees) + { + + } + +
    + +
    + +
    + +
    + + @Html.Widget("mobile_checkout_payment_method_bottom") +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWall.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWall.cshtml new file mode 100644 index 0000000000..461b02a3ab --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWall.cshtml @@ -0,0 +1,69 @@ +@using SmartStore.Web.Models.Checkout; +@using SmartStore.PayPal.Models; +@model PayPalPlusCheckoutModel +@{ + Layout = "~/Views/Shared/_Checkout.cshtml"; + Html.AddTitleParts(T("PageTitle.Checkout").Text); +} +@section orderProgress +{ + @Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Payment }) +} + +@Html.Partial("PaymentWallScripting") + +
    +
    +

    @T("Checkout.SelectPaymentMethod")

    +
    +
    + @Html.Widget("checkout_payment_method_top") + + @if (Model.ErrorMessage.HasValue()) + { +
    + @Html.Raw(T("Plugins.Payments.PayPalPlus.MethodUnavailable")) +
    + @if (!Model.ApprovalUrl.HasValue()) + { + @T("Plugins.SmartStore.PayPal.NoApprovalUrlReturned") + } + @Model.ErrorMessage +
    + } + else if (Model.PayPalPlusPseudoMessageFlag.HasValue() && Model.PayPalPlusPseudoMessageFlag == "1") + { +
    + @Html.Raw(T("Plugins.Payments.PayPalPlus.SorryFailure")) +
    + } + + @if (Model.FullDescription.HasValue()) + { +
    + @Html.Raw(Model.FullDescription) +
    + } + + @if (Model.HasAnyFees) + { + + } + +
    + +
    + +  @T("Common.Back") + + + +
    + + @Html.Widget("checkout_payment_method_bottom") +
    +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWallScripting.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWallScripting.cshtml new file mode 100644 index 0000000000..c1f2cdf6f0 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWallScripting.cshtml @@ -0,0 +1,117 @@ +@using SmartStore.PayPal +@using SmartStore.PayPal.Models +@model PayPalPlusCheckoutModel + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalStandard/Configure.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalStandard/Configure.cshtml new file mode 100644 index 0000000000..5846c1ed43 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalStandard/Configure.cshtml @@ -0,0 +1,167 @@ +@using SmartStore.PayPal.Models; +@using SmartStore.Web.Framework; +@model PayPalStandardConfigurationModel +@{ + Layout = ""; +} + +
    +
    +
    + + @Html.Raw(T("Plugins.Payments.PayPalStandard.AdminInstruction")) +
    +
    +
    + + PayPal + +
    +
    + +@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SecurityProtocol) + + @Html.DropDownListFor(model => model.SecurityProtocol, Model.AvailableSecurityProtocols, T("Common.Unspecified")) +
    + @Html.SmartLabelFor(model => model.UseSandbox) + + @*multistore context not possible, see IPN handling*@ + @Html.EditorFor(model => model.UseSandbox) + @Html.ValidationMessageFor(model => model.UseSandbox) +
    + @Html.SmartLabelFor(model => model.BusinessEmail) + + @Html.SettingEditorFor(model => model.BusinessEmail) + @Html.ValidationMessageFor(model => model.BusinessEmail) +
    + @Html.SmartLabelFor(model => model.PdtToken) + + @Html.SettingEditorFor(model => model.PdtToken) + @Html.ValidationMessageFor(model => model.PdtToken) +
    + @Html.SmartLabelFor(model => model.PdtValidateOrderTotal) + + @Html.SettingEditorFor(model => model.PdtValidateOrderTotal) + @Html.ValidationMessageFor(model => model.PdtValidateOrderTotal) +
    + @Html.SmartLabelFor(model => model.PdtValidateOnlyWarn) + + @Html.SettingEditorFor(model => model.PdtValidateOnlyWarn) + @Html.ValidationMessageFor(model => model.PdtValidateOnlyWarn) +
    + @Html.SmartLabelFor(model => model.AdditionalFee) + + @Html.SettingEditorFor(model => model.AdditionalFee) + @Html.ValidationMessageFor(model => model.AdditionalFee) +
    + @Html.SmartLabelFor(model => model.AdditionalFeePercentage) + + @Html.SettingEditorFor(model => model.AdditionalFeePercentage) + @Html.ValidationMessageFor(model => model.AdditionalFeePercentage) +
    + @Html.SmartLabelFor(model => model.PassProductNamesAndTotals) + + @Html.SettingEditorFor(model => model.PassProductNamesAndTotals) + @Html.ValidationMessageFor(model => model.PassProductNamesAndTotals) +
    + @Html.SmartLabelFor(model => model.EnableIpn) + + @Html.SettingEditorFor(model => model.EnableIpn) + @Html.ValidationMessageFor(model => model.EnableIpn) +
    + @Html.SmartLabelFor(model => model.IpnChangesPaymentStatus) + + @Html.SettingEditorFor(model => model.IpnChangesPaymentStatus) + @Html.ValidationMessageFor(model => model.IpnChangesPaymentStatus) +
    + @Html.SmartLabelFor(model => model.IpnUrl) + + @Html.SettingEditorFor(model => model.IpnUrl) + @Html.ValidationMessageFor(model => model.IpnUrl) +
    +
    + @T("Plugins.Payments.PayPalStandard.Fields.EnableIpn.Hint2") +
    +
    +   + + +
    +} + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Views/PayPalStandard/PaymentInfo.cshtml b/src/Plugins/SmartStore.PayPal/Views/PayPalStandard/PaymentInfo.cshtml new file mode 100644 index 0000000000..ee77251801 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/PayPalStandard/PaymentInfo.cshtml @@ -0,0 +1,13 @@ +@{ + Layout = ""; +} +@using SmartStore.Web.Framework; + +
    + + PayPal + +
    + @T("Plugins.Payments.PayPalStandard.Fields.RedirectionTip") +
    +
    diff --git a/src/Plugins/SmartStore.PayPal/Views/Web.config b/src/Plugins/SmartStore.PayPal/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/AddressVerifyResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/AddressVerifyResponseType1.datasource new file mode 100644 index 0000000000..ec0277609b --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/AddressVerifyResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.AddressVerifyResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BAUpdateResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BAUpdateResponseType1.datasource new file mode 100644 index 0000000000..91a053f5ff --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BAUpdateResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BAUpdateResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMButtonSearchResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMButtonSearchResponseType1.datasource new file mode 100644 index 0000000000..0f746c7d08 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMButtonSearchResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BMButtonSearchResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMCreateButtonResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMCreateButtonResponseType1.datasource new file mode 100644 index 0000000000..1029809ff8 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMCreateButtonResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BMCreateButtonResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMGetButtonDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMGetButtonDetailsResponseType1.datasource new file mode 100644 index 0000000000..cdde10a947 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMGetButtonDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BMGetButtonDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMGetInventoryResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMGetInventoryResponseType1.datasource new file mode 100644 index 0000000000..0ee379f30e --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMGetInventoryResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BMGetInventoryResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMManageButtonStatusResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMManageButtonStatusResponseType1.datasource new file mode 100644 index 0000000000..c1708ffd10 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMManageButtonStatusResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BMManageButtonStatusResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMSetInventoryResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMSetInventoryResponseType1.datasource new file mode 100644 index 0000000000..6be469df52 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMSetInventoryResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BMSetInventoryResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMUpdateButtonResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMUpdateButtonResponseType1.datasource new file mode 100644 index 0000000000..b9228e6bdf --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BMUpdateButtonResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BMUpdateButtonResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BillOutstandingAmountResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BillOutstandingAmountResponseType1.datasource new file mode 100644 index 0000000000..59b9170ade --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BillOutstandingAmountResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BillOutstandingAmountResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BillUserResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BillUserResponseType1.datasource new file mode 100644 index 0000000000..8577b782d7 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/BillUserResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.BillUserResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CancelRecoupResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CancelRecoupResponseType1.datasource new file mode 100644 index 0000000000..f3ae101fc3 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CancelRecoupResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.CancelRecoupResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CompleteRecoupResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CompleteRecoupResponseType1.datasource new file mode 100644 index 0000000000..098c7c4fca --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CompleteRecoupResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.CompleteRecoupResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CoreComponentTypes.xsd b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CoreComponentTypes.xsd new file mode 100644 index 0000000000..6a50c5b46c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CoreComponentTypes.xsd @@ -0,0 +1,51 @@ + + + + + + + + + + + + + On requests, you must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + Specifies a universally unique identifier. The UUID can + only contain digits from 0-9 and letters from A-F. The + UUID must be 32 characters long. For example, + 1FB02B2-9D27-3acb-ABA2-9D539C374228 + + + + + + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateBillingAgreementResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateBillingAgreementResponseType1.datasource new file mode 100644 index 0000000000..3e192ba71e --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateBillingAgreementResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.CreateBillingAgreementResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateMobilePaymentResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateMobilePaymentResponseType1.datasource new file mode 100644 index 0000000000..b18423f63d --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateMobilePaymentResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.CreateMobilePaymentResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateRecurringPaymentsProfileResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateRecurringPaymentsProfileResponseType1.datasource new file mode 100644 index 0000000000..bbfd271be0 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/CreateRecurringPaymentsProfileResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.CreateRecurringPaymentsProfileResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoAuthorizationResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoAuthorizationResponseType1.datasource new file mode 100644 index 0000000000..ba676b8620 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoAuthorizationResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoAuthorizationResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoCancelResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoCancelResponseType1.datasource new file mode 100644 index 0000000000..37076edf33 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoCancelResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoCancelResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoCaptureResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoCaptureResponseType1.datasource new file mode 100644 index 0000000000..d88232b3ef --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoCaptureResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoCaptureResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoDirectPaymentResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoDirectPaymentResponseType1.datasource new file mode 100644 index 0000000000..2aa8bbaa06 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoDirectPaymentResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoDirectPaymentResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoExpressCheckoutPaymentResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoExpressCheckoutPaymentResponseType1.datasource new file mode 100644 index 0000000000..850af8a0f2 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoExpressCheckoutPaymentResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoExpressCheckoutPaymentResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoMobileCheckoutPaymentResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoMobileCheckoutPaymentResponseType1.datasource new file mode 100644 index 0000000000..5e1ca5dd9c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoMobileCheckoutPaymentResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoMobileCheckoutPaymentResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoNonReferencedCreditResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoNonReferencedCreditResponseType1.datasource new file mode 100644 index 0000000000..534d76aa18 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoNonReferencedCreditResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoNonReferencedCreditResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoReauthorizationResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoReauthorizationResponseType1.datasource new file mode 100644 index 0000000000..0441cef50b --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoReauthorizationResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoReauthorizationResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoReferenceTransactionResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoReferenceTransactionResponseType1.datasource new file mode 100644 index 0000000000..7742527e2d --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoReferenceTransactionResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoReferenceTransactionResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoUATPAuthorizationResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoUATPAuthorizationResponseType1.datasource new file mode 100644 index 0000000000..67ca77b1f6 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoUATPAuthorizationResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoUATPAuthorizationResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoUATPExpressCheckoutPaymentResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoUATPExpressCheckoutPaymentResponseType1.datasource new file mode 100644 index 0000000000..c1a25d5f7c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoUATPExpressCheckoutPaymentResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoUATPExpressCheckoutPaymentResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoVoidResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoVoidResponseType1.datasource new file mode 100644 index 0000000000..588928591a --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/DoVoidResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.DoVoidResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/EnhancedDataTypes.xsd b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/EnhancedDataTypes.xsd new file mode 100644 index 0000000000..5a5139ba81 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/EnhancedDataTypes.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/EnterBoardingResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/EnterBoardingResponseType1.datasource new file mode 100644 index 0000000000..c9a4533ea7 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/EnterBoardingResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.EnterBoardingResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ExecuteCheckoutOperationsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ExecuteCheckoutOperationsResponseType1.datasource new file mode 100644 index 0000000000..ed93656bab --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ExecuteCheckoutOperationsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.ExecuteCheckoutOperationsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ExternalRememberMeOptOutResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ExternalRememberMeOptOutResponseType1.datasource new file mode 100644 index 0000000000..09e7a27f73 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ExternalRememberMeOptOutResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.ExternalRememberMeOptOutResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetAccessPermissionDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetAccessPermissionDetailsResponseType1.datasource new file mode 100644 index 0000000000..126aec7d4b --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetAccessPermissionDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetAccessPermissionDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetAuthDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetAuthDetailsResponseType1.datasource new file mode 100644 index 0000000000..effcb91711 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetAuthDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetAuthDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBalanceResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBalanceResponseType1.datasource new file mode 100644 index 0000000000..0195e8fb79 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBalanceResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetBalanceResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBillingAgreementCustomerDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBillingAgreementCustomerDetailsResponseType1.datasource new file mode 100644 index 0000000000..141d30f889 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBillingAgreementCustomerDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetBillingAgreementCustomerDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBoardingDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBoardingDetailsResponseType1.datasource new file mode 100644 index 0000000000..735ce0038e --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetBoardingDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetBoardingDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetExpressCheckoutDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetExpressCheckoutDetailsResponseType1.datasource new file mode 100644 index 0000000000..c37ffa9714 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetExpressCheckoutDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetExpressCheckoutDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetIncentiveEvaluationResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetIncentiveEvaluationResponseType1.datasource new file mode 100644 index 0000000000..125a1ac540 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetIncentiveEvaluationResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetIncentiveEvaluationResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetMobileStatusResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetMobileStatusResponseType1.datasource new file mode 100644 index 0000000000..0baf71137d --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetMobileStatusResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetMobileStatusResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetPalDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetPalDetailsResponseType1.datasource new file mode 100644 index 0000000000..252c9f0bfa --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetPalDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetPalDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetRecurringPaymentsProfileDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetRecurringPaymentsProfileDetailsResponseType1.datasource new file mode 100644 index 0000000000..260411e174 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetRecurringPaymentsProfileDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetRecurringPaymentsProfileDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetTransactionDetailsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetTransactionDetailsResponseType1.datasource new file mode 100644 index 0000000000..e347d410ed --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/GetTransactionDetailsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.GetTransactionDetailsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/InitiateRecoupResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/InitiateRecoupResponseType1.datasource new file mode 100644 index 0000000000..f698a0f4e3 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/InitiateRecoupResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.InitiateRecoupResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ManagePendingTransactionStatusResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ManagePendingTransactionStatusResponseType1.datasource new file mode 100644 index 0000000000..2aa919f0d2 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ManagePendingTransactionStatusResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.ManagePendingTransactionStatusResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ManageRecurringPaymentsProfileStatusResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ManageRecurringPaymentsProfileStatusResponseType1.datasource new file mode 100644 index 0000000000..1c8e8e39b2 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ManageRecurringPaymentsProfileStatusResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.ManageRecurringPaymentsProfileStatusResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/MassPayResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/MassPayResponseType1.datasource new file mode 100644 index 0000000000..3c0bc96da1 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/MassPayResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.MassPayResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/PayPalSvc.wsdl b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/PayPalSvc.wsdl new file mode 100644 index 0000000000..93f4243276 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/PayPalSvc.wsdl @@ -0,0 +1,4392 @@ + + + + + + + + + + + + + + Installment Period. +
    Optional
    +
    +
    + + + + Installment Frequency. +
    Optional
    +
    +
    + + + + Installment Cycles. +
    Optional
    +
    +
    + + + + Installment Amount. +
    Optional
    +
    +
    + + + + Installment Amount. +
    Optional
    +
    +
    + + + + Installment Amount. +
    Optional
    +
    +
    +
    +
    + + + + + + Option Selection. +
    Required
    + Character length and limitations: 12 single-byte alphanumeric characters +
    +
    +
    + + + + Option Price. +
    Optional
    +
    +
    + + + + Option Type +
    Optional
    +
    +
    + +
    +
    + + + + + + Option Name. +
    Optional
    +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + Type of Button to create. +

    Required

    + Must be one of the following: BUYNOW, CART, GIFTCERTIFICATE. SUBSCRIBE, PAYMENTPLAN, AUTOBILLING, DONATE, VIEWCART or UNSUBSCRIBE +
    +
    +
    + + + + button code. +

    optional

    + Must be one of the following: hosted, encrypted or cleartext +
    +
    +
    + + + + Button sub type. +

    optional for button types buynow and cart only

    + Must Be either PRODUCTS or SERVICES +
    +
    +
    + + + + Button Variable information +

    At least one required recurring

    + Character length and limitations: 63 single-byte alphanumeric characters +
    +
    +
    + + + + + Details of each option for the button. +

    Optional
    +
    +
    + + + + Button image to use. +

    Optional

    + Must be one of: REG, SML, or CC +
    +
    +
    + + + + Button URL for custom button image. +

    Optional

    + Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + Text to use on Buy Now Button. +

    Optional

    + Must be either BUYNOW or PAYNOW +
    +
    +
    + + + + Text to use on Subscribe button. +

    Optional

    + Must be either BUYNOW or SUBSCRIBE +
    +
    +
    + + + + Button Country. +

    Optional

    + Must be valid ISO country code +
    +
    +
    + + + + Button language code. +

    Optional

    + Character length and limitations: 3 single-byte alphanumeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hosted Button id of the button to update. +

    Required

    + Character length and limitations: 10 single-byte numeric characters +
    +
    +
    + + + + Type of Button to create. +

    Required

    + Must be one of the following: BUYNOW, CART, GIFTCERTIFICATE. SUBSCRIBE, PAYMENTPLAN, AUTOBILLING, DONATE, VIEWCART or UNSUBSCRIBE +
    +
    +
    + + + + button code. +

    optional

    + Must be one of the following: hosted, encrypted or cleartext +
    +
    +
    + + + + Button sub type. +

    optional for button types buynow and cart only

    + Must Be either PRODUCTS or SERVICES +
    +
    +
    + + + + Button Variable information +

    At least one required recurring

    + Character length and limitations: 63 single-byte alphanumeric characters +
    +
    +
    + + + + + Details of each option for the button. +

    Optional
    +
    +
    + + + + Button image to use. +

    Optional

    + Must be one of: REG, SML, or CC +
    +
    +
    + + + + Button URL for custom button image. +

    Optional

    + Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + Text to use on Buy Now Button. +

    Optional

    + Must be either BUYNOW or PAYNOW +
    +
    +
    + + + + Text to use on Subscribe button. +

    Optional

    + Must be either BUYNOW or SUBSCRIBE +
    +
    +
    + + + + Button Country. +

    Optional

    + Must be valid ISO country code +
    +
    +
    + + + + Button language code. +

    Optional

    + Character length and limitations: 2 single-byte alphanumeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Button ID of Hosted button. +

    Required

    + Character length and limitations: 10 single-byte numeric characters +
    +
    +
    + + + + Requested Status change for hosted button. +

    Required

    + Character length and limitations: 1 single-byte alphanumeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + Button ID of button to return. +

    Required

    + Character length and limitations: 10 single-byte numeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + Type of button. +

    + One of the following: BUYNOW, CART, GIFTCERTIFICATE. SUBSCRIBE, PAYMENTPLAN, AUTOBILLING, DONATE, VIEWCART or UNSUBSCRIBE +
    +
    +
    + + + + Type of button code. +

    + One of the following: hosted, encrypted or cleartext +
    +
    +
    + + + + Button sub type. +

    optional for button types buynow and cart only

    + Either PRODUCTS or SERVICES +
    +
    +
    + + + + Button Variable information +

    + Character length and limitations: 63 single-byte alphanumeric characters +
    +
    +
    + + + + + Text field +

    +
    +
    + + + + Button image to use. +

    + One of: REG, SML, or CC +
    +
    +
    + + + + Button URL for custom button image. +

    +
    +
    + + + + Text to use on Buy Now Button. +

    + Either BUYNOW or PAYNOW +
    +
    +
    + + + + Text to use on Subscribe button. +

    + Must be either BUYNOW or SUBSCRIBE +
    +
    +
    + + + + Button Country. +

    + Valid ISO country code or 'International' +
    +
    +
    + + + + Button language code. +

    + Character length and limitations: 3 single-byte alphanumeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + Hosted Button ID of button you wish to change. +

    Required

    + Character length and limitations: 10 single-byte numeric characters +
    +
    +
    + + + + Is Inventory tracked. +

    Required

    + 0 or 1 +
    +
    +
    + + + + Is PNL Tracked. +

    Required

    + 0 or 1 +
    +
    +
    + + + + + Option Index. +

    Optional

    + Character length and limitations: 1 single-byte alphanumeric characters +
    +
    +
    + + + + + URL of page to display when an item is soldout. +

    Optional

    + Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + Whether to use the same digital download key repeatedly. +

    Optional
    +
    +
    + + + + Whether to append these keys to the list or not (replace). +

    Optional
    +
    +
    + + + + Zero or more digital download keys to distribute to customers after transaction is completed. +

    Optional

    + Character length and limitations: 1000 single-byte alphanumeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + Hosted Button ID of the button to return inventory for. +

    Required

    + Character length and limitations: 10 single-byte numeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The earliest transaction date at which to start the search. No wildcards are allowed. +

    Required
    +
    +
    + + + + The latest transaction date to be included in the search +

    + Optional +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + Unique identifier of the transaction you are refunding. +

    Optional

    +Character length and limitations: 17 single-byte alphanumeric characters +
    +
    +
    + + + Encrypted PayPal customer account identification number. +

    Optional

    +Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + Invoice number corresponding to transaction details for tracking the refund of a payment. This parameter is passed by the merchant or recipient while refunding the transaction. This parameter does not affect the business logic, it is persisted in the DB for transaction reference +
    Optional
    +
    +
    + + + Type of refund you are making +

    Required
    +
    +
    + + + Refund amount. +

    +Amount is required if RefundType is Partial. +

    +NOTE: If RefundType is Full, do not set Amount. +
    +
    +
    + + + Custom memo about the refund. +

    +Optional +

    +Character length and limitations: 255 single-byte alphanumeric characters +
    +
    +
    + + + The maximum time till which refund must be tried. +

    + Optional +
    +
    +
    + + + The type of funding source for refund. +

    + Optional +
    +
    +
    + + + Flag to indicate that the customer was already given store credit for a given transaction. This will allow us to make sure we do not double refund. +

    Optional
    +
    +
    + + + To pass the Merchant store information

    Optional
    +
    +
    + + + Information about the individual details of the items to be refunded.
    Optional
    +
    +
    + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    +
    +
    +
    +
    + + + + + + + Unique transaction ID of the refund. +

    +Character length and limitations:17 single-byte characters +
    +
    +
    + + + Amount subtracted from PayPal balance of original recipient of payment to make this refund + + + + + + Transaction fee refunded to original recipient of payment + + + + + + Amount of money refunded to original payer + + + + + Total of all previous refunds + + + + + Contains Refund Payment status information. + + + + + Any general information like offer details that is reinstated or any other marketing data + + + + + Return msgsubid back to merchant + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unique identifier of a transaction. +

    Required

    +The details for some kinds of transactions cannot be retrieved with GetTransactionDetailsRequest. You cannot obtain details of bank transfer withdrawals, for example. +

    +Character length and limitations: 17 single-byte alphanumeric characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + This flag indicates that the response should include FMFDetails + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The earliest transaction date at which to start the search. No wildcards are allowed. +

    Required
    +
    +
    + + + The latest transaction date to be included in the search +

    +Optional +
    +
    +
    + + + Search by the buyer's email address +

    +Optional +

    +Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + Search by the receiver's email address. If the merchant account has only one email, this is the primary email. Can also be a non-primary email. +

    +Optional +
    +
    +
    + + + Search by the PayPal Account Optional receipt ID +

    +Optional +
    +
    +
    + + + Search by the transaction ID. +

    +Optional +

    +The returned results are from the merchant's transaction records. +

    +Character length and limitations: 19 single-byte characters maximum +
    +
    +
    + + + Search by Recurring Payment Profile id. The ProfileID is returned as part of the CreateRecurringPaymentsProfile API response. +

    +Optional +
    +
    +
    + + + Search by the buyer's name +

    +Optional +

    +Salutation: 20 single-byte character limit. +

    +FirstName: 25 single-byte character limit. +

    +MiddleName: 25 single-byte character limit. +

    +LastName: 25 single-byte character limit. +

    +Suffix: 12 single-byte character limit. +
    +
    +
    + + + Search by item number of the purchased goods. +

    +Optional +

    +To search for purchased items not related to auctions, set the AuctionItemNumber element to the value of the HTML item_number variable set in the shopping cart for the original transaction.
    +
    +
    + + + Search by invoice identification key, as set by you for the original transaction. InvoiceID searches the invoice records for items sold by the merchant, not the items purchased. +

    +Optional +

    +The value for InvoiceID must exactly match an invoice identification number. No wildcards are allowed. +

    +Character length and limitations: 127 single-byte characters maximum
    +
    +
    + + + + + Search by classification of transaction. Some kinds of possible classes of transactions are not searchable with TransactionSearchRequest. You cannot search for bank transfer withdrawals, for example. +

    +Optional +

    +All: all transaction classifications. +

    +Sent: only payments sent. +

    +Received: only payments received. +

    +MassPay: only mass payments. +

    +MoneyRequest: only money requests. +

    +FundsAdded: only funds added to balance. +

    +FundsWithdrawn: only funds withdrawn from balance. +

    +Referral: only transactions involving referrals. +

    +Fee: only transactions involving fees. +

    +Subscription: only transactions involving subscriptions. +

    +Dividend: only transactions involving dividends. +

    +Billpay: only transactions involving BillPay Transactions. +

    +Refund: only transactions involving funds. +

    +CurrencyConversions: only transactions involving currency conversions. +

    +BalanceTransfer: only transactions involving balance transfers. +

    +Reversal: only transactions involving BillPay reversals. +

    +Shipping: only transactions involving UPS shipping fees. +

    +BalanceAffecting: only transactions that affect the account balance. +

    +ECheck: only transactions involving eCheck +

    +ForcedPostTransaction: forced post transaction. +

    +NonReferencedRefunds: non-referenced refunds. +
    +
    +
    + + + Search by transaction amount +

    +Optional +

    +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies.
    +
    +
    + + + Search by currency code +

    +Optional +
    +
    +
    + + + Search by transaction status +

    +Optional +

    +Pending: The payment is pending. The specific reason the payment is pending is returned by the GetTransactionDetails APIPendingReason element. For more information, see PendingReason. +

    +Processing: The payment is being processed. +

    +Success: The payment has been completed and the funds have been added successfully to your account balance. +

    +Denied: You denied the payment. This happens only if the payment was previously pending. +

    +Reversed: A payment was reversed due to a chargeback or other type of reversal. The funds have been removed from your account balance and returned to the buyer. +
    +
    +
    +
    +
    +
    +
    + + + + + + + Results of a Transaction Search. + + + + + + + + + + + + + + + + + + + + + + Subject line of the email sent to all recipients. This subject is not contained in the input file; you must create it with your application. +

    +Optional +

    +Character length and limitations: 255 single-byte alphanumeric characters +
    +
    +
    + + + Indicates how you identify the recipients of payments in all MassPayItems: either by EmailAddress (ReceiverEmail in MassPayItem), PhoneNumber (ReceiverPhone in MassPayItem), or by UserID (ReceiverID in MassPayItem). +

    Required. You must specify one or the other of EmailAddress or UserID. +
    +
    +
    + + + Known as BN code, to track the partner referred merchant transactions. +

    +Optional +

    +Character length and limitations: 32 single-byte alphanumeric characters +
    +
    +
    + + + Details of each payment. A single MassPayRequest can include up to 250 MassPayItems. +

    Required
    +
    +
    +
    +
    +
    +
    + + + + + + + + + MassPayRequestItemType + + + + + + Email address of recipient. +

    Required

    +You must specify ReceiverEmail, ReceiverPhone, or ReceiverID, but all MassPayItems in a request must use the same field to specify recipients. +

    +Character length and limitations: 127 single-byte characters maximum. +
    +
    +
    + + + Phone number of recipient. +

    Required

    +You must specify ReceiverEmail, ReceiverPhone, or ReceiverID, but all MassPayItems in a request must use the same field to specify recipients. +

    +
    +
    + + + Unique PayPal customer account number. This value corresponds to the value of PayerID returned by GetTransactionDetails. +

    Required

    +You must specify ReceiverEmail, ReceiverPhone, or ReceiverID, but all MassPayItems in a request must use the same field to specify recipients. +

    +Character length and limitations: 17 single-byte characters maximum. +
    +
    +
    + + + Payment amount. You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    Required

    +You cannot mix currencies in a single MassPayRequest. A single request must include items that are of the same currency. +
    +
    +
    + + + Transaction-specific identification number for tracking in an accounting system. +

    +Optional +

    +Character length and limitations: 30 single-byte characters. No whitespace allowed. +
    +
    +
    + + + Custom note for each recipient. +

    +Optional +

    +Character length and limitations: 4,000 single-byte alphanumeric characters +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Email address of buyer to be verified. +

    Required

    +Maximum string length: 255 single-byte characters Input mask: ?@?.?? + +
    +
    +
    + + + First line of buyer’s billing or shipping street address to be verified. +

    Required

    For verification, input value of street address must match the first three single-byte characters of the street address on file for the PayPal account. +

    +Maximum string length: 35 single-byte characters Alphanumeric plus - , . ‘ # \ Whitespace and case of input value are ignored. +
    +
    +
    + + + Postal code to be verified. +

    Required

    + +For verification, input value of postal code must match the first five single-byte characters of the postal code on file for the PayPal account. +

    +Maximum string length: 16 single-byte characters Whitespace and case of input value are ignored. +
    +
    +
    +
    +
    +
    +
    + + + + + + + Confirmation of a match, with one of the following tokens: +

    +None: The input value of the Email object does not match any email address on file at PayPal. +

    +Confirmed: If the value of the StreetMatch object is Matched, PayPal responds that the entire postal address is confirmed. +

    +Unconfirmed: PayPal responds that the postal address is unconfirmed
    +
    +
    + + + PayPal has compared the postal address you want to verify with the postal address on file at PayPal. +

    + None: The input value of the Email object does not match any email address on file at PayPal. In addition, an error response is returned. No further comparison of other input values has been made. +

    +Matched: The street address matches the street address on file at PayPal. +

    +Unmatched: The street address does not match the street address on file at PayPal. +
    +
    +
    + + + PayPal has compared the zip code you want to verify with the zip code on file for the email address. +

    + None: The street address was unmatched. No further comparison of other input values has been made. +

    Matched: The zip code matches the zip code on file at PayPal. +

    Unmatched: The zip code does not match the zip code on file at PayPal. +
    +
    +
    + + + Two-character country code (ISO 3166) on file for the PayPal email address. + + + + + The token prevents a buyer from using any street address other than the address on file at PayPal during additional purchases he might make from the merchant. It contains encrypted information about the user’s street address and email address. You can pass the value of the token with the Buy Now button HTML address_api_token variable so that PayPal prevents the buyer from using any street address or email address other than those verified by PayPal. The token is valid for 24 hours. +
    +Character length and limitations: 94 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + A unique token that identifies this boarding session. +Use this token with the GetBoarding Details API call. +

    +Character length and limitations: 64 alphanumeric characters. The token has the following format: +

    +OB-61characterstring
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + A unique token returned by the EnterBoarding API call that identifies this boarding session. +

    Required

    +Character length and limitations: 64 alphanumeric characters. The token has the following format: +

    +OB-61characterstring
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A timestamped token by which you identify to PayPal that you are processing this user. The token expires after three hours. +

    +Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + A timestamped token, the value of which was returned by SetAuthFlowParam Response. +

    Required

    +Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A timestamped token by which you identify to PayPal that you are processing this user. The token expires after three hours. +

    +Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + Unique PayPal customer account number, the value of which was returned by GetAuthDetails Response. +

    Required

    + Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + The status of the update call, Success/Failure. +

    + Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + A timestamped token, the value of which was returned by SetAuthFlowParam Response. +

    Required

    + Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A timestamped token by which you identify to PayPal that you are processing this payment with Express Checkout. The token expires after three hours. If you set Token in the SetExpressCheckoutRequest, the value of Token in the response is identical to the value in the request. +

    +Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A timestamped token, the value of which was returned by SetExpressCheckoutResponse. +

    Required

    +Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + This flag indicates that the response should include FMFDetails + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This flag indicates that the response should include FMFDetails + + + + + + + + + + + + + + The amount of the payment as specified by you on DoDirectPaymentRequest. + + + + + + Address Verification System response code. Character limit: One single-byte alphanumeric character +
    AVS CodeMeaningMatched Details
    A AddressAddress only (no ZIP)
    B International “A”Address only (no ZIP)
    CInternational “N” None
    DInternational “X” Address and Postal Code
    E Not allowed for MOTO (Internet/Phone) transactions Not applicable
    F UK-specific “X”Address and Postal Code
    G Global Unavailable Not applicable
    I International UnavailableNot applicable
    N NoNone
    PPostal (International “Z”)Postal Code only (no Address)
    RRetryNot applicable
    S Service not Supported Not applicable
    U UnavailableNot applicable
    W Whole ZIPNine-digit ZIP code (no Address)
    X Exact match Address and nine-digit ZIP code
    Y YesAddress and five-digit ZIP
    Z ZIP Five-digit ZIP code (no Address)
    All others Error Not applicable
    +
    +
    + + + + Result of the CVV2 check by PayPal. +
    CVV2 CodeMeaningMatched Details
    M MatchCVV2
    N No match None
    P Not ProcessedNot applicable
    SService not SupportedNot applicable
    U UnavailableNot applicable
    XNo response Not applicable
    All others ErrorNot applicable
    +
    +
    + + + + Transaction identification number. +

    + Character length and limitations: 19 characters maximum.
    +
    +
    + + + + The reason why a particular transaction went in pending. + + + + + + + This will identify the actual transaction status. + + + + + + + + + Response code from the processor when a recurring transaction is declined. + + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + Msg Sub Id that was used for the orginal operation. + + + + + Original API's type + + + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    +
    +
    +
    +
    + + + + + + + Return msgsubid back to merchant + + + + + + + + + + + + + + + + + + + + + + The authorization identification number of the payment you want to capture. +

    Required

    +Character length and limits: 19 single-byte characters maximum +
    +
    +
    + + + Amount to authorize. You must set the currencyID attribute to USD. +

    Required

    +Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,) +
    +
    +
    + + + Indicates if this capture is the last capture you intend to make. The default is Complete. If CompleteType is Complete, any remaining amount of the original reauthorized transaction is automatically voided. +

    Required

    +Character length and limits: 12 single-byte alphanumeric characters +
    +
    +
    + + + An informational note about this settlement that is displayed to the payer in email and in transaction history. +

    +Optional +

    +Character length and limits: 255 single-byte characters +
    +
    +
    + + + Your invoice number or other identification number. +

    +The InvoiceID value is recorded only if the authorization you are capturing is an order authorization, not a basic authorization. +

    +Optional +

    +Character length and limits: 127 single-byte alphanumeric characters +
    +
    +
    + + + Contains enhanced data like airline itinerary information. +

    Not Required
    +
    +
    + + + dynamic descriptor +

    +Dynamic descriptor is used for merchant to provide detail of a transaction appears on statement +

    Optional

    +Character length and limits: <18 characters alphanumeric characters +
    +
    +
    + + + To pass the Merchant store information

    Optional
    +
    +
    + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    + + + This holds key-value pair which merchants wants to pass it to the open wallet-PLCC processor

    Optional
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + The value of a previously authorized transaction identification number returned by a PayPal product. You can obtain a buyer's transaction number from the TransactionID element of the PayerInfo structure returned by GetTransactionDetailsResponse. +

    Required

    +Character length and limits: 19 single-byte characters maximum +
    +
    +
    + + + Amount to reauthorize. +

    Required

    +Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    +
    +
    +
    +
    + + + + + + + A new authorization identification number. +

    Character length and limits: 19 single-byte characters +
    +
    +
    + + + + Return msgsubid back to merchant + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + The value of the original authorization identification number returned by a PayPal product. +

    +If you are voiding a transaction that has been reauthorized, use the ID from the original authorization, and not the reauthorization. +

    Required

    +Character length and limits: 19 single-byte characters +
    +
    +
    + + + An informational note about this settlement that is displayed to the payer in email and in transaction history. +

    +Optional +

    +Character length and limits: 255 single-byte characters +
    +
    +
    + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    +
    +
    +
    +
    + + + + + + + The authorization identification number you specified in the request. +

    +Character length and limits: 19 single-byte characters +
    +
    +
    + + + Return msgsubid back to merchant + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + The value of the order’s transaction identification number returned by a PayPal product. +

    Required

    Character length and limits: 19 single-byte characters maximum +
    +
    +
    + + + Type of transaction to authorize. The only allowable value is Order, which means that the transaction represents a customer order that can be fulfilled over 29 days. +

    +Optional +
    +
    +
    + + + Amount to authorize. +

    Required

    +Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Address the order will be shipped to. +

    + Optional +

    +
    +
    + + + + Information about the individual purchased items + + + + + + + Sum of cost of all items in this order. + You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    + Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Total shipping costs for this order. + You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    + Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Total handling costs for this order. + You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    + Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Sum of tax for all items in this order. + You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    + Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Total shipping insurance costs for this order.
    + Optional
    +
    +
    + + + + Shipping discount for this order, specified as a negative number.
    + Optional
    +
    +
    + + + + Description of items the customer is purchasing. +

    + Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + A free-form field for your own use. +

    + Optional +

    Character length and limitations: 256 single-byte alphanumeric characters +
    +
    +
    + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    + + + + IP Address of the buyer + + + +
    +
    +
    +
    + + + + + + + An authorization identification number. +

    +Character length and limits: 19 single-byte characters +
    +
    +
    + + + The amount and currency you specified in the request. + + + + + + + Return msgsubid back to merchant + + +
    +
    +
    +
    + + + + + + + + + + + + + + + + The value of the authorizationâtransaction identification number returned by a PayPal product. +

    Required

    Character length and limits: 19 single-byte characters maximum +
    +
    +
    + + + + Shipping Address for this transaction. + + + + + + + IP Address of the buyer + + + +
    +
    +
    +
    + + + + + + + An authorization identification number. +

    + Character length and limits: 19 single-byte characters +
    +
    +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + + + UATP card details +

    Required
    +
    +
    + + + Type of transaction to authorize. The only allowable value is Order, which means that the transaction represents a customer order that can be fulfilled over 29 days. +

    +Optional +
    +
    +
    + + + Amount to authorize. +

    Required

    +Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + Invoice ID. A pass through. + + + + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    +
    +
    +
    +
    + + + + + + + + Auth Authorization Code. + + + + + + Invoice ID. A pass through. + + + + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Indicates whether the phone is activated for mobile payments +

    +
    +
    + + + Indicates whether the password is enabled for particular account +

    +
    +
    + + + Indicates whether there is a payment pending from the phone +

    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + A timestamped token by which you identify to PayPal that you are processing this payment with Mobile Checkout. The token expires after three hours. +

    +Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + A timestamped token, the value of which was returned by SetMobileCheckoutResponse. +

    Required

    +Character length and limitations: 20 single-byte characters +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This flag indicates that the response should include FMFDetails + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The merchant passes in the ExternalRememberMeID to identify the user to opt out. This is a 17-character + alphanumeric (encrypted) string that identifies the buyer's remembered login with a merchant and has + meaning only to the merchant. +

    Required

    +
    +
    + + + + E-mail address or secure merchant account ID of merchant to associate with + external remember-me. + + + +
    +
    +
    +
    + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/Reference.cs b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/Reference.cs new file mode 100644 index 0000000000..b8c6682313 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/Reference.cs @@ -0,0 +1,28598 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.34209 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +// +// Der Quellcode wurde automatisch mit Microsoft.VSDesigner generiert. Version 4.0.30319.34209. +// +#pragma warning disable 1591 + +namespace SmartStore.PayPal.PayPalSvc { + using System; + using System.Web.Services; + using System.Diagnostics; + using System.Web.Services.Protocols; + using System.Xml.Serialization; + using System.ComponentModel; + + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="PayPalAPISoapBinding", Namespace="urn:ebay:api:PayPalAPI")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AbstractResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AbstractRequestType))] + public partial class PayPalAPISoapBinding : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private CustomSecurityHeaderType requesterCredentialsField; + + private System.Threading.SendOrPostCallback RefundTransactionOperationCompleted; + + private System.Threading.SendOrPostCallback InitiateRecoupOperationCompleted; + + private System.Threading.SendOrPostCallback CompleteRecoupOperationCompleted; + + private System.Threading.SendOrPostCallback CancelRecoupOperationCompleted; + + private System.Threading.SendOrPostCallback GetTransactionDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback BMCreateButtonOperationCompleted; + + private System.Threading.SendOrPostCallback BMUpdateButtonOperationCompleted; + + private System.Threading.SendOrPostCallback BMManageButtonStatusOperationCompleted; + + private System.Threading.SendOrPostCallback BMGetButtonDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback BMSetInventoryOperationCompleted; + + private System.Threading.SendOrPostCallback BMGetInventoryOperationCompleted; + + private System.Threading.SendOrPostCallback BMButtonSearchOperationCompleted; + + private System.Threading.SendOrPostCallback BillUserOperationCompleted; + + private System.Threading.SendOrPostCallback TransactionSearchOperationCompleted; + + private System.Threading.SendOrPostCallback MassPayOperationCompleted; + + private System.Threading.SendOrPostCallback BillAgreementUpdateOperationCompleted; + + private System.Threading.SendOrPostCallback AddressVerifyOperationCompleted; + + private System.Threading.SendOrPostCallback EnterBoardingOperationCompleted; + + private System.Threading.SendOrPostCallback GetBoardingDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback CreateMobilePaymentOperationCompleted; + + private System.Threading.SendOrPostCallback GetMobileStatusOperationCompleted; + + private System.Threading.SendOrPostCallback SetMobileCheckoutOperationCompleted; + + private System.Threading.SendOrPostCallback DoMobileCheckoutPaymentOperationCompleted; + + private System.Threading.SendOrPostCallback GetBalanceOperationCompleted; + + private System.Threading.SendOrPostCallback GetPalDetailsOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public PayPalAPISoapBinding() { + this.Url = global::SmartStore.PayPal.Properties.Settings.Default.SmartStore_Plugin_Payments_PayPalExpress_PayPalSvc_PayPalAPIInterfaceService; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public CustomSecurityHeaderType RequesterCredentials { + get { + return this.requesterCredentialsField; + } + set { + this.requesterCredentialsField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event RefundTransactionCompletedEventHandler RefundTransactionCompleted; + + /// + public event InitiateRecoupCompletedEventHandler InitiateRecoupCompleted; + + /// + public event CompleteRecoupCompletedEventHandler CompleteRecoupCompleted; + + /// + public event CancelRecoupCompletedEventHandler CancelRecoupCompleted; + + /// + public event GetTransactionDetailsCompletedEventHandler GetTransactionDetailsCompleted; + + /// + public event BMCreateButtonCompletedEventHandler BMCreateButtonCompleted; + + /// + public event BMUpdateButtonCompletedEventHandler BMUpdateButtonCompleted; + + /// + public event BMManageButtonStatusCompletedEventHandler BMManageButtonStatusCompleted; + + /// + public event BMGetButtonDetailsCompletedEventHandler BMGetButtonDetailsCompleted; + + /// + public event BMSetInventoryCompletedEventHandler BMSetInventoryCompleted; + + /// + public event BMGetInventoryCompletedEventHandler BMGetInventoryCompleted; + + /// + public event BMButtonSearchCompletedEventHandler BMButtonSearchCompleted; + + /// + public event BillUserCompletedEventHandler BillUserCompleted; + + /// + public event TransactionSearchCompletedEventHandler TransactionSearchCompleted; + + /// + public event MassPayCompletedEventHandler MassPayCompleted; + + /// + public event BillAgreementUpdateCompletedEventHandler BillAgreementUpdateCompleted; + + /// + public event AddressVerifyCompletedEventHandler AddressVerifyCompleted; + + /// + public event EnterBoardingCompletedEventHandler EnterBoardingCompleted; + + /// + public event GetBoardingDetailsCompletedEventHandler GetBoardingDetailsCompleted; + + /// + public event CreateMobilePaymentCompletedEventHandler CreateMobilePaymentCompleted; + + /// + public event GetMobileStatusCompletedEventHandler GetMobileStatusCompleted; + + /// + public event SetMobileCheckoutCompletedEventHandler SetMobileCheckoutCompleted; + + /// + public event DoMobileCheckoutPaymentCompletedEventHandler DoMobileCheckoutPaymentCompleted; + + /// + public event GetBalanceCompletedEventHandler GetBalanceCompleted; + + /// + public event GetPalDetailsCompletedEventHandler GetPalDetailsCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("RefundTransactionResponse", Namespace="urn:ebay:api:PayPalAPI")] + public RefundTransactionResponseType RefundTransaction([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] RefundTransactionReq RefundTransactionReq) { + object[] results = this.Invoke("RefundTransaction", new object[] { + RefundTransactionReq}); + return ((RefundTransactionResponseType)(results[0])); + } + + /// + public void RefundTransactionAsync(RefundTransactionReq RefundTransactionReq) { + this.RefundTransactionAsync(RefundTransactionReq, null); + } + + /// + public void RefundTransactionAsync(RefundTransactionReq RefundTransactionReq, object userState) { + if ((this.RefundTransactionOperationCompleted == null)) { + this.RefundTransactionOperationCompleted = new System.Threading.SendOrPostCallback(this.OnRefundTransactionOperationCompleted); + } + this.InvokeAsync("RefundTransaction", new object[] { + RefundTransactionReq}, this.RefundTransactionOperationCompleted, userState); + } + + private void OnRefundTransactionOperationCompleted(object arg) { + if ((this.RefundTransactionCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.RefundTransactionCompleted(this, new RefundTransactionCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("InitiateRecoupResponse", Namespace="urn:ebay:api:PayPalAPI")] + public InitiateRecoupResponseType InitiateRecoup([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] InitiateRecoupReq InitiateRecoupReq) { + object[] results = this.Invoke("InitiateRecoup", new object[] { + InitiateRecoupReq}); + return ((InitiateRecoupResponseType)(results[0])); + } + + /// + public void InitiateRecoupAsync(InitiateRecoupReq InitiateRecoupReq) { + this.InitiateRecoupAsync(InitiateRecoupReq, null); + } + + /// + public void InitiateRecoupAsync(InitiateRecoupReq InitiateRecoupReq, object userState) { + if ((this.InitiateRecoupOperationCompleted == null)) { + this.InitiateRecoupOperationCompleted = new System.Threading.SendOrPostCallback(this.OnInitiateRecoupOperationCompleted); + } + this.InvokeAsync("InitiateRecoup", new object[] { + InitiateRecoupReq}, this.InitiateRecoupOperationCompleted, userState); + } + + private void OnInitiateRecoupOperationCompleted(object arg) { + if ((this.InitiateRecoupCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.InitiateRecoupCompleted(this, new InitiateRecoupCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CompleteRecoupResponse", Namespace="urn:ebay:api:PayPalAPI")] + public CompleteRecoupResponseType CompleteRecoup([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] CompleteRecoupReq CompleteRecoupReq) { + object[] results = this.Invoke("CompleteRecoup", new object[] { + CompleteRecoupReq}); + return ((CompleteRecoupResponseType)(results[0])); + } + + /// + public void CompleteRecoupAsync(CompleteRecoupReq CompleteRecoupReq) { + this.CompleteRecoupAsync(CompleteRecoupReq, null); + } + + /// + public void CompleteRecoupAsync(CompleteRecoupReq CompleteRecoupReq, object userState) { + if ((this.CompleteRecoupOperationCompleted == null)) { + this.CompleteRecoupOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCompleteRecoupOperationCompleted); + } + this.InvokeAsync("CompleteRecoup", new object[] { + CompleteRecoupReq}, this.CompleteRecoupOperationCompleted, userState); + } + + private void OnCompleteRecoupOperationCompleted(object arg) { + if ((this.CompleteRecoupCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CompleteRecoupCompleted(this, new CompleteRecoupCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CancelRecoupResponse", Namespace="urn:ebay:api:PayPalAPI")] + public CancelRecoupResponseType CancelRecoup([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] CancelRecoupReq CancelRecoupReq) { + object[] results = this.Invoke("CancelRecoup", new object[] { + CancelRecoupReq}); + return ((CancelRecoupResponseType)(results[0])); + } + + /// + public void CancelRecoupAsync(CancelRecoupReq CancelRecoupReq) { + this.CancelRecoupAsync(CancelRecoupReq, null); + } + + /// + public void CancelRecoupAsync(CancelRecoupReq CancelRecoupReq, object userState) { + if ((this.CancelRecoupOperationCompleted == null)) { + this.CancelRecoupOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCancelRecoupOperationCompleted); + } + this.InvokeAsync("CancelRecoup", new object[] { + CancelRecoupReq}, this.CancelRecoupOperationCompleted, userState); + } + + private void OnCancelRecoupOperationCompleted(object arg) { + if ((this.CancelRecoupCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CancelRecoupCompleted(this, new CancelRecoupCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetTransactionDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetTransactionDetailsResponseType GetTransactionDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetTransactionDetailsReq GetTransactionDetailsReq) { + object[] results = this.Invoke("GetTransactionDetails", new object[] { + GetTransactionDetailsReq}); + return ((GetTransactionDetailsResponseType)(results[0])); + } + + /// + public void GetTransactionDetailsAsync(GetTransactionDetailsReq GetTransactionDetailsReq) { + this.GetTransactionDetailsAsync(GetTransactionDetailsReq, null); + } + + /// + public void GetTransactionDetailsAsync(GetTransactionDetailsReq GetTransactionDetailsReq, object userState) { + if ((this.GetTransactionDetailsOperationCompleted == null)) { + this.GetTransactionDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetTransactionDetailsOperationCompleted); + } + this.InvokeAsync("GetTransactionDetails", new object[] { + GetTransactionDetailsReq}, this.GetTransactionDetailsOperationCompleted, userState); + } + + private void OnGetTransactionDetailsOperationCompleted(object arg) { + if ((this.GetTransactionDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetTransactionDetailsCompleted(this, new GetTransactionDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BMCreateButtonResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BMCreateButtonResponseType BMCreateButton([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BMCreateButtonReq BMCreateButtonReq) { + object[] results = this.Invoke("BMCreateButton", new object[] { + BMCreateButtonReq}); + return ((BMCreateButtonResponseType)(results[0])); + } + + /// + public void BMCreateButtonAsync(BMCreateButtonReq BMCreateButtonReq) { + this.BMCreateButtonAsync(BMCreateButtonReq, null); + } + + /// + public void BMCreateButtonAsync(BMCreateButtonReq BMCreateButtonReq, object userState) { + if ((this.BMCreateButtonOperationCompleted == null)) { + this.BMCreateButtonOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBMCreateButtonOperationCompleted); + } + this.InvokeAsync("BMCreateButton", new object[] { + BMCreateButtonReq}, this.BMCreateButtonOperationCompleted, userState); + } + + private void OnBMCreateButtonOperationCompleted(object arg) { + if ((this.BMCreateButtonCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BMCreateButtonCompleted(this, new BMCreateButtonCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BMUpdateButtonResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BMUpdateButtonResponseType BMUpdateButton([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BMUpdateButtonReq BMUpdateButtonReq) { + object[] results = this.Invoke("BMUpdateButton", new object[] { + BMUpdateButtonReq}); + return ((BMUpdateButtonResponseType)(results[0])); + } + + /// + public void BMUpdateButtonAsync(BMUpdateButtonReq BMUpdateButtonReq) { + this.BMUpdateButtonAsync(BMUpdateButtonReq, null); + } + + /// + public void BMUpdateButtonAsync(BMUpdateButtonReq BMUpdateButtonReq, object userState) { + if ((this.BMUpdateButtonOperationCompleted == null)) { + this.BMUpdateButtonOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBMUpdateButtonOperationCompleted); + } + this.InvokeAsync("BMUpdateButton", new object[] { + BMUpdateButtonReq}, this.BMUpdateButtonOperationCompleted, userState); + } + + private void OnBMUpdateButtonOperationCompleted(object arg) { + if ((this.BMUpdateButtonCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BMUpdateButtonCompleted(this, new BMUpdateButtonCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BMManageButtonStatusResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BMManageButtonStatusResponseType BMManageButtonStatus([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BMManageButtonStatusReq BMManageButtonStatusReq) { + object[] results = this.Invoke("BMManageButtonStatus", new object[] { + BMManageButtonStatusReq}); + return ((BMManageButtonStatusResponseType)(results[0])); + } + + /// + public void BMManageButtonStatusAsync(BMManageButtonStatusReq BMManageButtonStatusReq) { + this.BMManageButtonStatusAsync(BMManageButtonStatusReq, null); + } + + /// + public void BMManageButtonStatusAsync(BMManageButtonStatusReq BMManageButtonStatusReq, object userState) { + if ((this.BMManageButtonStatusOperationCompleted == null)) { + this.BMManageButtonStatusOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBMManageButtonStatusOperationCompleted); + } + this.InvokeAsync("BMManageButtonStatus", new object[] { + BMManageButtonStatusReq}, this.BMManageButtonStatusOperationCompleted, userState); + } + + private void OnBMManageButtonStatusOperationCompleted(object arg) { + if ((this.BMManageButtonStatusCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BMManageButtonStatusCompleted(this, new BMManageButtonStatusCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BMGetButtonDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BMGetButtonDetailsResponseType BMGetButtonDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BMGetButtonDetailsReq BMGetButtonDetailsReq) { + object[] results = this.Invoke("BMGetButtonDetails", new object[] { + BMGetButtonDetailsReq}); + return ((BMGetButtonDetailsResponseType)(results[0])); + } + + /// + public void BMGetButtonDetailsAsync(BMGetButtonDetailsReq BMGetButtonDetailsReq) { + this.BMGetButtonDetailsAsync(BMGetButtonDetailsReq, null); + } + + /// + public void BMGetButtonDetailsAsync(BMGetButtonDetailsReq BMGetButtonDetailsReq, object userState) { + if ((this.BMGetButtonDetailsOperationCompleted == null)) { + this.BMGetButtonDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBMGetButtonDetailsOperationCompleted); + } + this.InvokeAsync("BMGetButtonDetails", new object[] { + BMGetButtonDetailsReq}, this.BMGetButtonDetailsOperationCompleted, userState); + } + + private void OnBMGetButtonDetailsOperationCompleted(object arg) { + if ((this.BMGetButtonDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BMGetButtonDetailsCompleted(this, new BMGetButtonDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BMSetInventoryResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BMSetInventoryResponseType BMSetInventory([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BMSetInventoryReq BMSetInventoryReq) { + object[] results = this.Invoke("BMSetInventory", new object[] { + BMSetInventoryReq}); + return ((BMSetInventoryResponseType)(results[0])); + } + + /// + public void BMSetInventoryAsync(BMSetInventoryReq BMSetInventoryReq) { + this.BMSetInventoryAsync(BMSetInventoryReq, null); + } + + /// + public void BMSetInventoryAsync(BMSetInventoryReq BMSetInventoryReq, object userState) { + if ((this.BMSetInventoryOperationCompleted == null)) { + this.BMSetInventoryOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBMSetInventoryOperationCompleted); + } + this.InvokeAsync("BMSetInventory", new object[] { + BMSetInventoryReq}, this.BMSetInventoryOperationCompleted, userState); + } + + private void OnBMSetInventoryOperationCompleted(object arg) { + if ((this.BMSetInventoryCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BMSetInventoryCompleted(this, new BMSetInventoryCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BMGetInventoryResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BMGetInventoryResponseType BMGetInventory([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BMGetInventoryReq BMGetInventoryReq) { + object[] results = this.Invoke("BMGetInventory", new object[] { + BMGetInventoryReq}); + return ((BMGetInventoryResponseType)(results[0])); + } + + /// + public void BMGetInventoryAsync(BMGetInventoryReq BMGetInventoryReq) { + this.BMGetInventoryAsync(BMGetInventoryReq, null); + } + + /// + public void BMGetInventoryAsync(BMGetInventoryReq BMGetInventoryReq, object userState) { + if ((this.BMGetInventoryOperationCompleted == null)) { + this.BMGetInventoryOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBMGetInventoryOperationCompleted); + } + this.InvokeAsync("BMGetInventory", new object[] { + BMGetInventoryReq}, this.BMGetInventoryOperationCompleted, userState); + } + + private void OnBMGetInventoryOperationCompleted(object arg) { + if ((this.BMGetInventoryCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BMGetInventoryCompleted(this, new BMGetInventoryCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BMButtonSearchResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BMButtonSearchResponseType BMButtonSearch([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BMButtonSearchReq BMButtonSearchReq) { + object[] results = this.Invoke("BMButtonSearch", new object[] { + BMButtonSearchReq}); + return ((BMButtonSearchResponseType)(results[0])); + } + + /// + public void BMButtonSearchAsync(BMButtonSearchReq BMButtonSearchReq) { + this.BMButtonSearchAsync(BMButtonSearchReq, null); + } + + /// + public void BMButtonSearchAsync(BMButtonSearchReq BMButtonSearchReq, object userState) { + if ((this.BMButtonSearchOperationCompleted == null)) { + this.BMButtonSearchOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBMButtonSearchOperationCompleted); + } + this.InvokeAsync("BMButtonSearch", new object[] { + BMButtonSearchReq}, this.BMButtonSearchOperationCompleted, userState); + } + + private void OnBMButtonSearchOperationCompleted(object arg) { + if ((this.BMButtonSearchCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BMButtonSearchCompleted(this, new BMButtonSearchCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BillUserResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BillUserResponseType BillUser([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BillUserReq BillUserReq) { + object[] results = this.Invoke("BillUser", new object[] { + BillUserReq}); + return ((BillUserResponseType)(results[0])); + } + + /// + public void BillUserAsync(BillUserReq BillUserReq) { + this.BillUserAsync(BillUserReq, null); + } + + /// + public void BillUserAsync(BillUserReq BillUserReq, object userState) { + if ((this.BillUserOperationCompleted == null)) { + this.BillUserOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBillUserOperationCompleted); + } + this.InvokeAsync("BillUser", new object[] { + BillUserReq}, this.BillUserOperationCompleted, userState); + } + + private void OnBillUserOperationCompleted(object arg) { + if ((this.BillUserCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BillUserCompleted(this, new BillUserCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("TransactionSearchResponse", Namespace="urn:ebay:api:PayPalAPI")] + public TransactionSearchResponseType TransactionSearch([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] TransactionSearchReq TransactionSearchReq) { + object[] results = this.Invoke("TransactionSearch", new object[] { + TransactionSearchReq}); + return ((TransactionSearchResponseType)(results[0])); + } + + /// + public void TransactionSearchAsync(TransactionSearchReq TransactionSearchReq) { + this.TransactionSearchAsync(TransactionSearchReq, null); + } + + /// + public void TransactionSearchAsync(TransactionSearchReq TransactionSearchReq, object userState) { + if ((this.TransactionSearchOperationCompleted == null)) { + this.TransactionSearchOperationCompleted = new System.Threading.SendOrPostCallback(this.OnTransactionSearchOperationCompleted); + } + this.InvokeAsync("TransactionSearch", new object[] { + TransactionSearchReq}, this.TransactionSearchOperationCompleted, userState); + } + + private void OnTransactionSearchOperationCompleted(object arg) { + if ((this.TransactionSearchCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.TransactionSearchCompleted(this, new TransactionSearchCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("MassPayResponse", Namespace="urn:ebay:api:PayPalAPI")] + public MassPayResponseType MassPay([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] MassPayReq MassPayReq) { + object[] results = this.Invoke("MassPay", new object[] { + MassPayReq}); + return ((MassPayResponseType)(results[0])); + } + + /// + public void MassPayAsync(MassPayReq MassPayReq) { + this.MassPayAsync(MassPayReq, null); + } + + /// + public void MassPayAsync(MassPayReq MassPayReq, object userState) { + if ((this.MassPayOperationCompleted == null)) { + this.MassPayOperationCompleted = new System.Threading.SendOrPostCallback(this.OnMassPayOperationCompleted); + } + this.InvokeAsync("MassPay", new object[] { + MassPayReq}, this.MassPayOperationCompleted, userState); + } + + private void OnMassPayOperationCompleted(object arg) { + if ((this.MassPayCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.MassPayCompleted(this, new MassPayCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BAUpdateResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BAUpdateResponseType BillAgreementUpdate([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BillAgreementUpdateReq BillAgreementUpdateReq) { + object[] results = this.Invoke("BillAgreementUpdate", new object[] { + BillAgreementUpdateReq}); + return ((BAUpdateResponseType)(results[0])); + } + + /// + public void BillAgreementUpdateAsync(BillAgreementUpdateReq BillAgreementUpdateReq) { + this.BillAgreementUpdateAsync(BillAgreementUpdateReq, null); + } + + /// + public void BillAgreementUpdateAsync(BillAgreementUpdateReq BillAgreementUpdateReq, object userState) { + if ((this.BillAgreementUpdateOperationCompleted == null)) { + this.BillAgreementUpdateOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBillAgreementUpdateOperationCompleted); + } + this.InvokeAsync("BillAgreementUpdate", new object[] { + BillAgreementUpdateReq}, this.BillAgreementUpdateOperationCompleted, userState); + } + + private void OnBillAgreementUpdateOperationCompleted(object arg) { + if ((this.BillAgreementUpdateCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BillAgreementUpdateCompleted(this, new BillAgreementUpdateCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("AddressVerifyResponse", Namespace="urn:ebay:api:PayPalAPI")] + public AddressVerifyResponseType AddressVerify([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] AddressVerifyReq AddressVerifyReq) { + object[] results = this.Invoke("AddressVerify", new object[] { + AddressVerifyReq}); + return ((AddressVerifyResponseType)(results[0])); + } + + /// + public void AddressVerifyAsync(AddressVerifyReq AddressVerifyReq) { + this.AddressVerifyAsync(AddressVerifyReq, null); + } + + /// + public void AddressVerifyAsync(AddressVerifyReq AddressVerifyReq, object userState) { + if ((this.AddressVerifyOperationCompleted == null)) { + this.AddressVerifyOperationCompleted = new System.Threading.SendOrPostCallback(this.OnAddressVerifyOperationCompleted); + } + this.InvokeAsync("AddressVerify", new object[] { + AddressVerifyReq}, this.AddressVerifyOperationCompleted, userState); + } + + private void OnAddressVerifyOperationCompleted(object arg) { + if ((this.AddressVerifyCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.AddressVerifyCompleted(this, new AddressVerifyCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("EnterBoardingResponse", Namespace="urn:ebay:api:PayPalAPI")] + public EnterBoardingResponseType EnterBoarding([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] EnterBoardingReq EnterBoardingReq) { + object[] results = this.Invoke("EnterBoarding", new object[] { + EnterBoardingReq}); + return ((EnterBoardingResponseType)(results[0])); + } + + /// + public void EnterBoardingAsync(EnterBoardingReq EnterBoardingReq) { + this.EnterBoardingAsync(EnterBoardingReq, null); + } + + /// + public void EnterBoardingAsync(EnterBoardingReq EnterBoardingReq, object userState) { + if ((this.EnterBoardingOperationCompleted == null)) { + this.EnterBoardingOperationCompleted = new System.Threading.SendOrPostCallback(this.OnEnterBoardingOperationCompleted); + } + this.InvokeAsync("EnterBoarding", new object[] { + EnterBoardingReq}, this.EnterBoardingOperationCompleted, userState); + } + + private void OnEnterBoardingOperationCompleted(object arg) { + if ((this.EnterBoardingCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.EnterBoardingCompleted(this, new EnterBoardingCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetBoardingDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetBoardingDetailsResponseType GetBoardingDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetBoardingDetailsReq GetBoardingDetailsReq) { + object[] results = this.Invoke("GetBoardingDetails", new object[] { + GetBoardingDetailsReq}); + return ((GetBoardingDetailsResponseType)(results[0])); + } + + /// + public void GetBoardingDetailsAsync(GetBoardingDetailsReq GetBoardingDetailsReq) { + this.GetBoardingDetailsAsync(GetBoardingDetailsReq, null); + } + + /// + public void GetBoardingDetailsAsync(GetBoardingDetailsReq GetBoardingDetailsReq, object userState) { + if ((this.GetBoardingDetailsOperationCompleted == null)) { + this.GetBoardingDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetBoardingDetailsOperationCompleted); + } + this.InvokeAsync("GetBoardingDetails", new object[] { + GetBoardingDetailsReq}, this.GetBoardingDetailsOperationCompleted, userState); + } + + private void OnGetBoardingDetailsOperationCompleted(object arg) { + if ((this.GetBoardingDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetBoardingDetailsCompleted(this, new GetBoardingDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateMobilePaymentResponse", Namespace="urn:ebay:api:PayPalAPI")] + public CreateMobilePaymentResponseType CreateMobilePayment([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] CreateMobilePaymentReq CreateMobilePaymentReq) { + object[] results = this.Invoke("CreateMobilePayment", new object[] { + CreateMobilePaymentReq}); + return ((CreateMobilePaymentResponseType)(results[0])); + } + + /// + public void CreateMobilePaymentAsync(CreateMobilePaymentReq CreateMobilePaymentReq) { + this.CreateMobilePaymentAsync(CreateMobilePaymentReq, null); + } + + /// + public void CreateMobilePaymentAsync(CreateMobilePaymentReq CreateMobilePaymentReq, object userState) { + if ((this.CreateMobilePaymentOperationCompleted == null)) { + this.CreateMobilePaymentOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateMobilePaymentOperationCompleted); + } + this.InvokeAsync("CreateMobilePayment", new object[] { + CreateMobilePaymentReq}, this.CreateMobilePaymentOperationCompleted, userState); + } + + private void OnCreateMobilePaymentOperationCompleted(object arg) { + if ((this.CreateMobilePaymentCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateMobilePaymentCompleted(this, new CreateMobilePaymentCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetMobileStatusResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetMobileStatusResponseType GetMobileStatus([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetMobileStatusReq GetMobileStatusReq) { + object[] results = this.Invoke("GetMobileStatus", new object[] { + GetMobileStatusReq}); + return ((GetMobileStatusResponseType)(results[0])); + } + + /// + public void GetMobileStatusAsync(GetMobileStatusReq GetMobileStatusReq) { + this.GetMobileStatusAsync(GetMobileStatusReq, null); + } + + /// + public void GetMobileStatusAsync(GetMobileStatusReq GetMobileStatusReq, object userState) { + if ((this.GetMobileStatusOperationCompleted == null)) { + this.GetMobileStatusOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetMobileStatusOperationCompleted); + } + this.InvokeAsync("GetMobileStatus", new object[] { + GetMobileStatusReq}, this.GetMobileStatusOperationCompleted, userState); + } + + private void OnGetMobileStatusOperationCompleted(object arg) { + if ((this.GetMobileStatusCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetMobileStatusCompleted(this, new GetMobileStatusCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("SetMobileCheckoutResponse", Namespace="urn:ebay:api:PayPalAPI")] + public SetMobileCheckoutResponseType SetMobileCheckout([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] SetMobileCheckoutReq SetMobileCheckoutReq) { + object[] results = this.Invoke("SetMobileCheckout", new object[] { + SetMobileCheckoutReq}); + return ((SetMobileCheckoutResponseType)(results[0])); + } + + /// + public void SetMobileCheckoutAsync(SetMobileCheckoutReq SetMobileCheckoutReq) { + this.SetMobileCheckoutAsync(SetMobileCheckoutReq, null); + } + + /// + public void SetMobileCheckoutAsync(SetMobileCheckoutReq SetMobileCheckoutReq, object userState) { + if ((this.SetMobileCheckoutOperationCompleted == null)) { + this.SetMobileCheckoutOperationCompleted = new System.Threading.SendOrPostCallback(this.OnSetMobileCheckoutOperationCompleted); + } + this.InvokeAsync("SetMobileCheckout", new object[] { + SetMobileCheckoutReq}, this.SetMobileCheckoutOperationCompleted, userState); + } + + private void OnSetMobileCheckoutOperationCompleted(object arg) { + if ((this.SetMobileCheckoutCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.SetMobileCheckoutCompleted(this, new SetMobileCheckoutCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoMobileCheckoutPaymentResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoMobileCheckoutPaymentResponseType DoMobileCheckoutPayment([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoMobileCheckoutPaymentReq DoMobileCheckoutPaymentReq) { + object[] results = this.Invoke("DoMobileCheckoutPayment", new object[] { + DoMobileCheckoutPaymentReq}); + return ((DoMobileCheckoutPaymentResponseType)(results[0])); + } + + /// + public void DoMobileCheckoutPaymentAsync(DoMobileCheckoutPaymentReq DoMobileCheckoutPaymentReq) { + this.DoMobileCheckoutPaymentAsync(DoMobileCheckoutPaymentReq, null); + } + + /// + public void DoMobileCheckoutPaymentAsync(DoMobileCheckoutPaymentReq DoMobileCheckoutPaymentReq, object userState) { + if ((this.DoMobileCheckoutPaymentOperationCompleted == null)) { + this.DoMobileCheckoutPaymentOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoMobileCheckoutPaymentOperationCompleted); + } + this.InvokeAsync("DoMobileCheckoutPayment", new object[] { + DoMobileCheckoutPaymentReq}, this.DoMobileCheckoutPaymentOperationCompleted, userState); + } + + private void OnDoMobileCheckoutPaymentOperationCompleted(object arg) { + if ((this.DoMobileCheckoutPaymentCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoMobileCheckoutPaymentCompleted(this, new DoMobileCheckoutPaymentCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetBalanceResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetBalanceResponseType GetBalance([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetBalanceReq GetBalanceReq) { + object[] results = this.Invoke("GetBalance", new object[] { + GetBalanceReq}); + return ((GetBalanceResponseType)(results[0])); + } + + /// + public void GetBalanceAsync(GetBalanceReq GetBalanceReq) { + this.GetBalanceAsync(GetBalanceReq, null); + } + + /// + public void GetBalanceAsync(GetBalanceReq GetBalanceReq, object userState) { + if ((this.GetBalanceOperationCompleted == null)) { + this.GetBalanceOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetBalanceOperationCompleted); + } + this.InvokeAsync("GetBalance", new object[] { + GetBalanceReq}, this.GetBalanceOperationCompleted, userState); + } + + private void OnGetBalanceOperationCompleted(object arg) { + if ((this.GetBalanceCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetBalanceCompleted(this, new GetBalanceCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetPalDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetPalDetailsResponseType GetPalDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetPalDetailsReq GetPalDetailsReq) { + object[] results = this.Invoke("GetPalDetails", new object[] { + GetPalDetailsReq}); + return ((GetPalDetailsResponseType)(results[0])); + } + + /// + public void GetPalDetailsAsync(GetPalDetailsReq GetPalDetailsReq) { + this.GetPalDetailsAsync(GetPalDetailsReq, null); + } + + /// + public void GetPalDetailsAsync(GetPalDetailsReq GetPalDetailsReq, object userState) { + if ((this.GetPalDetailsOperationCompleted == null)) { + this.GetPalDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetPalDetailsOperationCompleted); + } + this.InvokeAsync("GetPalDetails", new object[] { + GetPalDetailsReq}, this.GetPalDetailsOperationCompleted, userState); + } + + private void OnGetPalDetailsOperationCompleted(object arg) { + if ((this.GetPalDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetPalDetailsCompleted(this, new GetPalDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="PayPalAPIAASoapBinding", Namespace="urn:ebay:api:PayPalAPI")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AbstractResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AbstractRequestType))] + public partial class PayPalAPIAASoapBinding : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private CustomSecurityHeaderType requesterCredentialsField; + + private System.Threading.SendOrPostCallback DoExpressCheckoutPaymentOperationCompleted; + + private System.Threading.SendOrPostCallback DoUATPExpressCheckoutPaymentOperationCompleted; + + private System.Threading.SendOrPostCallback SetAuthFlowParamOperationCompleted; + + private System.Threading.SendOrPostCallback GetAuthDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback SetAccessPermissionsOperationCompleted; + + private System.Threading.SendOrPostCallback UpdateAccessPermissionsOperationCompleted; + + private System.Threading.SendOrPostCallback GetAccessPermissionDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback GetIncentiveEvaluationOperationCompleted; + + private System.Threading.SendOrPostCallback SetExpressCheckoutOperationCompleted; + + private System.Threading.SendOrPostCallback ExecuteCheckoutOperationsOperationCompleted; + + private System.Threading.SendOrPostCallback GetExpressCheckoutDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback DoDirectPaymentOperationCompleted; + + private System.Threading.SendOrPostCallback ManagePendingTransactionStatusOperationCompleted; + + private System.Threading.SendOrPostCallback DoCancelOperationCompleted; + + private System.Threading.SendOrPostCallback DoCaptureOperationCompleted; + + private System.Threading.SendOrPostCallback DoReauthorizationOperationCompleted; + + private System.Threading.SendOrPostCallback DoVoidOperationCompleted; + + private System.Threading.SendOrPostCallback DoAuthorizationOperationCompleted; + + private System.Threading.SendOrPostCallback UpdateAuthorizationOperationCompleted; + + private System.Threading.SendOrPostCallback SetCustomerBillingAgreementOperationCompleted; + + private System.Threading.SendOrPostCallback GetBillingAgreementCustomerDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback CreateBillingAgreementOperationCompleted; + + private System.Threading.SendOrPostCallback DoReferenceTransactionOperationCompleted; + + private System.Threading.SendOrPostCallback DoNonReferencedCreditOperationCompleted; + + private System.Threading.SendOrPostCallback DoUATPAuthorizationOperationCompleted; + + private System.Threading.SendOrPostCallback CreateRecurringPaymentsProfileOperationCompleted; + + private System.Threading.SendOrPostCallback GetRecurringPaymentsProfileDetailsOperationCompleted; + + private System.Threading.SendOrPostCallback ManageRecurringPaymentsProfileStatusOperationCompleted; + + private System.Threading.SendOrPostCallback BillOutstandingAmountOperationCompleted; + + private System.Threading.SendOrPostCallback UpdateRecurringPaymentsProfileOperationCompleted; + + private System.Threading.SendOrPostCallback ReverseTransactionOperationCompleted; + + private System.Threading.SendOrPostCallback ExternalRememberMeOptOutOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public PayPalAPIAASoapBinding() { + this.Url = "https://api-aa.sandbox.paypal.com/2.0/"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public CustomSecurityHeaderType RequesterCredentials { + get { + return this.requesterCredentialsField; + } + set { + this.requesterCredentialsField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event DoExpressCheckoutPaymentCompletedEventHandler DoExpressCheckoutPaymentCompleted; + + /// + public event DoUATPExpressCheckoutPaymentCompletedEventHandler DoUATPExpressCheckoutPaymentCompleted; + + /// + public event SetAuthFlowParamCompletedEventHandler SetAuthFlowParamCompleted; + + /// + public event GetAuthDetailsCompletedEventHandler GetAuthDetailsCompleted; + + /// + public event SetAccessPermissionsCompletedEventHandler SetAccessPermissionsCompleted; + + /// + public event UpdateAccessPermissionsCompletedEventHandler UpdateAccessPermissionsCompleted; + + /// + public event GetAccessPermissionDetailsCompletedEventHandler GetAccessPermissionDetailsCompleted; + + /// + public event GetIncentiveEvaluationCompletedEventHandler GetIncentiveEvaluationCompleted; + + /// + public event SetExpressCheckoutCompletedEventHandler SetExpressCheckoutCompleted; + + /// + public event ExecuteCheckoutOperationsCompletedEventHandler ExecuteCheckoutOperationsCompleted; + + /// + public event GetExpressCheckoutDetailsCompletedEventHandler GetExpressCheckoutDetailsCompleted; + + /// + public event DoDirectPaymentCompletedEventHandler DoDirectPaymentCompleted; + + /// + public event ManagePendingTransactionStatusCompletedEventHandler ManagePendingTransactionStatusCompleted; + + /// + public event DoCancelCompletedEventHandler DoCancelCompleted; + + /// + public event DoCaptureCompletedEventHandler DoCaptureCompleted; + + /// + public event DoReauthorizationCompletedEventHandler DoReauthorizationCompleted; + + /// + public event DoVoidCompletedEventHandler DoVoidCompleted; + + /// + public event DoAuthorizationCompletedEventHandler DoAuthorizationCompleted; + + /// + public event UpdateAuthorizationCompletedEventHandler UpdateAuthorizationCompleted; + + /// + public event SetCustomerBillingAgreementCompletedEventHandler SetCustomerBillingAgreementCompleted; + + /// + public event GetBillingAgreementCustomerDetailsCompletedEventHandler GetBillingAgreementCustomerDetailsCompleted; + + /// + public event CreateBillingAgreementCompletedEventHandler CreateBillingAgreementCompleted; + + /// + public event DoReferenceTransactionCompletedEventHandler DoReferenceTransactionCompleted; + + /// + public event DoNonReferencedCreditCompletedEventHandler DoNonReferencedCreditCompleted; + + /// + public event DoUATPAuthorizationCompletedEventHandler DoUATPAuthorizationCompleted; + + /// + public event CreateRecurringPaymentsProfileCompletedEventHandler CreateRecurringPaymentsProfileCompleted; + + /// + public event GetRecurringPaymentsProfileDetailsCompletedEventHandler GetRecurringPaymentsProfileDetailsCompleted; + + /// + public event ManageRecurringPaymentsProfileStatusCompletedEventHandler ManageRecurringPaymentsProfileStatusCompleted; + + /// + public event BillOutstandingAmountCompletedEventHandler BillOutstandingAmountCompleted; + + /// + public event UpdateRecurringPaymentsProfileCompletedEventHandler UpdateRecurringPaymentsProfileCompleted; + + /// + public event ReverseTransactionCompletedEventHandler ReverseTransactionCompleted; + + /// + public event ExternalRememberMeOptOutCompletedEventHandler ExternalRememberMeOptOutCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoExpressCheckoutPaymentResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoExpressCheckoutPaymentResponseType DoExpressCheckoutPayment([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoExpressCheckoutPaymentReq DoExpressCheckoutPaymentReq) { + object[] results = this.Invoke("DoExpressCheckoutPayment", new object[] { + DoExpressCheckoutPaymentReq}); + return ((DoExpressCheckoutPaymentResponseType)(results[0])); + } + + /// + public void DoExpressCheckoutPaymentAsync(DoExpressCheckoutPaymentReq DoExpressCheckoutPaymentReq) { + this.DoExpressCheckoutPaymentAsync(DoExpressCheckoutPaymentReq, null); + } + + /// + public void DoExpressCheckoutPaymentAsync(DoExpressCheckoutPaymentReq DoExpressCheckoutPaymentReq, object userState) { + if ((this.DoExpressCheckoutPaymentOperationCompleted == null)) { + this.DoExpressCheckoutPaymentOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoExpressCheckoutPaymentOperationCompleted); + } + this.InvokeAsync("DoExpressCheckoutPayment", new object[] { + DoExpressCheckoutPaymentReq}, this.DoExpressCheckoutPaymentOperationCompleted, userState); + } + + private void OnDoExpressCheckoutPaymentOperationCompleted(object arg) { + if ((this.DoExpressCheckoutPaymentCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoExpressCheckoutPaymentCompleted(this, new DoExpressCheckoutPaymentCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoUATPExpressCheckoutPaymentResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoUATPExpressCheckoutPaymentResponseType DoUATPExpressCheckoutPayment([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoUATPExpressCheckoutPaymentReq DoUATPExpressCheckoutPaymentReq) { + object[] results = this.Invoke("DoUATPExpressCheckoutPayment", new object[] { + DoUATPExpressCheckoutPaymentReq}); + return ((DoUATPExpressCheckoutPaymentResponseType)(results[0])); + } + + /// + public void DoUATPExpressCheckoutPaymentAsync(DoUATPExpressCheckoutPaymentReq DoUATPExpressCheckoutPaymentReq) { + this.DoUATPExpressCheckoutPaymentAsync(DoUATPExpressCheckoutPaymentReq, null); + } + + /// + public void DoUATPExpressCheckoutPaymentAsync(DoUATPExpressCheckoutPaymentReq DoUATPExpressCheckoutPaymentReq, object userState) { + if ((this.DoUATPExpressCheckoutPaymentOperationCompleted == null)) { + this.DoUATPExpressCheckoutPaymentOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoUATPExpressCheckoutPaymentOperationCompleted); + } + this.InvokeAsync("DoUATPExpressCheckoutPayment", new object[] { + DoUATPExpressCheckoutPaymentReq}, this.DoUATPExpressCheckoutPaymentOperationCompleted, userState); + } + + private void OnDoUATPExpressCheckoutPaymentOperationCompleted(object arg) { + if ((this.DoUATPExpressCheckoutPaymentCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoUATPExpressCheckoutPaymentCompleted(this, new DoUATPExpressCheckoutPaymentCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("SetAuthFlowParamResponse", Namespace="urn:ebay:api:PayPalAPI")] + public SetAuthFlowParamResponseType SetAuthFlowParam([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] SetAuthFlowParamReq SetAuthFlowParamReq) { + object[] results = this.Invoke("SetAuthFlowParam", new object[] { + SetAuthFlowParamReq}); + return ((SetAuthFlowParamResponseType)(results[0])); + } + + /// + public void SetAuthFlowParamAsync(SetAuthFlowParamReq SetAuthFlowParamReq) { + this.SetAuthFlowParamAsync(SetAuthFlowParamReq, null); + } + + /// + public void SetAuthFlowParamAsync(SetAuthFlowParamReq SetAuthFlowParamReq, object userState) { + if ((this.SetAuthFlowParamOperationCompleted == null)) { + this.SetAuthFlowParamOperationCompleted = new System.Threading.SendOrPostCallback(this.OnSetAuthFlowParamOperationCompleted); + } + this.InvokeAsync("SetAuthFlowParam", new object[] { + SetAuthFlowParamReq}, this.SetAuthFlowParamOperationCompleted, userState); + } + + private void OnSetAuthFlowParamOperationCompleted(object arg) { + if ((this.SetAuthFlowParamCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.SetAuthFlowParamCompleted(this, new SetAuthFlowParamCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetAuthDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetAuthDetailsResponseType GetAuthDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetAuthDetailsReq GetAuthDetailsReq) { + object[] results = this.Invoke("GetAuthDetails", new object[] { + GetAuthDetailsReq}); + return ((GetAuthDetailsResponseType)(results[0])); + } + + /// + public void GetAuthDetailsAsync(GetAuthDetailsReq GetAuthDetailsReq) { + this.GetAuthDetailsAsync(GetAuthDetailsReq, null); + } + + /// + public void GetAuthDetailsAsync(GetAuthDetailsReq GetAuthDetailsReq, object userState) { + if ((this.GetAuthDetailsOperationCompleted == null)) { + this.GetAuthDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetAuthDetailsOperationCompleted); + } + this.InvokeAsync("GetAuthDetails", new object[] { + GetAuthDetailsReq}, this.GetAuthDetailsOperationCompleted, userState); + } + + private void OnGetAuthDetailsOperationCompleted(object arg) { + if ((this.GetAuthDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetAuthDetailsCompleted(this, new GetAuthDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("SetAccessPermissionsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public SetAccessPermissionsResponseType SetAccessPermissions([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] SetAccessPermissionsReq SetAccessPermissionsReq) { + object[] results = this.Invoke("SetAccessPermissions", new object[] { + SetAccessPermissionsReq}); + return ((SetAccessPermissionsResponseType)(results[0])); + } + + /// + public void SetAccessPermissionsAsync(SetAccessPermissionsReq SetAccessPermissionsReq) { + this.SetAccessPermissionsAsync(SetAccessPermissionsReq, null); + } + + /// + public void SetAccessPermissionsAsync(SetAccessPermissionsReq SetAccessPermissionsReq, object userState) { + if ((this.SetAccessPermissionsOperationCompleted == null)) { + this.SetAccessPermissionsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnSetAccessPermissionsOperationCompleted); + } + this.InvokeAsync("SetAccessPermissions", new object[] { + SetAccessPermissionsReq}, this.SetAccessPermissionsOperationCompleted, userState); + } + + private void OnSetAccessPermissionsOperationCompleted(object arg) { + if ((this.SetAccessPermissionsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.SetAccessPermissionsCompleted(this, new SetAccessPermissionsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("UpdateAccessPermissionsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public UpdateAccessPermissionsResponseType UpdateAccessPermissions([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] UpdateAccessPermissionsReq UpdateAccessPermissionsReq) { + object[] results = this.Invoke("UpdateAccessPermissions", new object[] { + UpdateAccessPermissionsReq}); + return ((UpdateAccessPermissionsResponseType)(results[0])); + } + + /// + public void UpdateAccessPermissionsAsync(UpdateAccessPermissionsReq UpdateAccessPermissionsReq) { + this.UpdateAccessPermissionsAsync(UpdateAccessPermissionsReq, null); + } + + /// + public void UpdateAccessPermissionsAsync(UpdateAccessPermissionsReq UpdateAccessPermissionsReq, object userState) { + if ((this.UpdateAccessPermissionsOperationCompleted == null)) { + this.UpdateAccessPermissionsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnUpdateAccessPermissionsOperationCompleted); + } + this.InvokeAsync("UpdateAccessPermissions", new object[] { + UpdateAccessPermissionsReq}, this.UpdateAccessPermissionsOperationCompleted, userState); + } + + private void OnUpdateAccessPermissionsOperationCompleted(object arg) { + if ((this.UpdateAccessPermissionsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.UpdateAccessPermissionsCompleted(this, new UpdateAccessPermissionsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetAccessPermissionDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetAccessPermissionDetailsResponseType GetAccessPermissionDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetAccessPermissionDetailsReq GetAccessPermissionDetailsReq) { + object[] results = this.Invoke("GetAccessPermissionDetails", new object[] { + GetAccessPermissionDetailsReq}); + return ((GetAccessPermissionDetailsResponseType)(results[0])); + } + + /// + public void GetAccessPermissionDetailsAsync(GetAccessPermissionDetailsReq GetAccessPermissionDetailsReq) { + this.GetAccessPermissionDetailsAsync(GetAccessPermissionDetailsReq, null); + } + + /// + public void GetAccessPermissionDetailsAsync(GetAccessPermissionDetailsReq GetAccessPermissionDetailsReq, object userState) { + if ((this.GetAccessPermissionDetailsOperationCompleted == null)) { + this.GetAccessPermissionDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetAccessPermissionDetailsOperationCompleted); + } + this.InvokeAsync("GetAccessPermissionDetails", new object[] { + GetAccessPermissionDetailsReq}, this.GetAccessPermissionDetailsOperationCompleted, userState); + } + + private void OnGetAccessPermissionDetailsOperationCompleted(object arg) { + if ((this.GetAccessPermissionDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetAccessPermissionDetailsCompleted(this, new GetAccessPermissionDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetIncentiveEvaluationResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetIncentiveEvaluationResponseType GetIncentiveEvaluation([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetIncentiveEvaluationReq GetIncentiveEvaluationReq) { + object[] results = this.Invoke("GetIncentiveEvaluation", new object[] { + GetIncentiveEvaluationReq}); + return ((GetIncentiveEvaluationResponseType)(results[0])); + } + + /// + public void GetIncentiveEvaluationAsync(GetIncentiveEvaluationReq GetIncentiveEvaluationReq) { + this.GetIncentiveEvaluationAsync(GetIncentiveEvaluationReq, null); + } + + /// + public void GetIncentiveEvaluationAsync(GetIncentiveEvaluationReq GetIncentiveEvaluationReq, object userState) { + if ((this.GetIncentiveEvaluationOperationCompleted == null)) { + this.GetIncentiveEvaluationOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetIncentiveEvaluationOperationCompleted); + } + this.InvokeAsync("GetIncentiveEvaluation", new object[] { + GetIncentiveEvaluationReq}, this.GetIncentiveEvaluationOperationCompleted, userState); + } + + private void OnGetIncentiveEvaluationOperationCompleted(object arg) { + if ((this.GetIncentiveEvaluationCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetIncentiveEvaluationCompleted(this, new GetIncentiveEvaluationCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("SetExpressCheckoutResponse", Namespace="urn:ebay:api:PayPalAPI")] + public SetExpressCheckoutResponseType SetExpressCheckout([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] SetExpressCheckoutReq SetExpressCheckoutReq) { + object[] results = this.Invoke("SetExpressCheckout", new object[] { + SetExpressCheckoutReq}); + return ((SetExpressCheckoutResponseType)(results[0])); + } + + /// + public void SetExpressCheckoutAsync(SetExpressCheckoutReq SetExpressCheckoutReq) { + this.SetExpressCheckoutAsync(SetExpressCheckoutReq, null); + } + + /// + public void SetExpressCheckoutAsync(SetExpressCheckoutReq SetExpressCheckoutReq, object userState) { + if ((this.SetExpressCheckoutOperationCompleted == null)) { + this.SetExpressCheckoutOperationCompleted = new System.Threading.SendOrPostCallback(this.OnSetExpressCheckoutOperationCompleted); + } + this.InvokeAsync("SetExpressCheckout", new object[] { + SetExpressCheckoutReq}, this.SetExpressCheckoutOperationCompleted, userState); + } + + private void OnSetExpressCheckoutOperationCompleted(object arg) { + if ((this.SetExpressCheckoutCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.SetExpressCheckoutCompleted(this, new SetExpressCheckoutCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ExecuteCheckoutOperationsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public ExecuteCheckoutOperationsResponseType ExecuteCheckoutOperations([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] ExecuteCheckoutOperationsReq ExecuteCheckoutOperationsReq) { + object[] results = this.Invoke("ExecuteCheckoutOperations", new object[] { + ExecuteCheckoutOperationsReq}); + return ((ExecuteCheckoutOperationsResponseType)(results[0])); + } + + /// + public void ExecuteCheckoutOperationsAsync(ExecuteCheckoutOperationsReq ExecuteCheckoutOperationsReq) { + this.ExecuteCheckoutOperationsAsync(ExecuteCheckoutOperationsReq, null); + } + + /// + public void ExecuteCheckoutOperationsAsync(ExecuteCheckoutOperationsReq ExecuteCheckoutOperationsReq, object userState) { + if ((this.ExecuteCheckoutOperationsOperationCompleted == null)) { + this.ExecuteCheckoutOperationsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnExecuteCheckoutOperationsOperationCompleted); + } + this.InvokeAsync("ExecuteCheckoutOperations", new object[] { + ExecuteCheckoutOperationsReq}, this.ExecuteCheckoutOperationsOperationCompleted, userState); + } + + private void OnExecuteCheckoutOperationsOperationCompleted(object arg) { + if ((this.ExecuteCheckoutOperationsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ExecuteCheckoutOperationsCompleted(this, new ExecuteCheckoutOperationsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetExpressCheckoutDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetExpressCheckoutDetailsResponseType GetExpressCheckoutDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetExpressCheckoutDetailsReq GetExpressCheckoutDetailsReq) { + object[] results = this.Invoke("GetExpressCheckoutDetails", new object[] { + GetExpressCheckoutDetailsReq}); + return ((GetExpressCheckoutDetailsResponseType)(results[0])); + } + + /// + public void GetExpressCheckoutDetailsAsync(GetExpressCheckoutDetailsReq GetExpressCheckoutDetailsReq) { + this.GetExpressCheckoutDetailsAsync(GetExpressCheckoutDetailsReq, null); + } + + /// + public void GetExpressCheckoutDetailsAsync(GetExpressCheckoutDetailsReq GetExpressCheckoutDetailsReq, object userState) { + if ((this.GetExpressCheckoutDetailsOperationCompleted == null)) { + this.GetExpressCheckoutDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetExpressCheckoutDetailsOperationCompleted); + } + this.InvokeAsync("GetExpressCheckoutDetails", new object[] { + GetExpressCheckoutDetailsReq}, this.GetExpressCheckoutDetailsOperationCompleted, userState); + } + + private void OnGetExpressCheckoutDetailsOperationCompleted(object arg) { + if ((this.GetExpressCheckoutDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetExpressCheckoutDetailsCompleted(this, new GetExpressCheckoutDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoDirectPaymentResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoDirectPaymentResponseType DoDirectPayment([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoDirectPaymentReq DoDirectPaymentReq) { + object[] results = this.Invoke("DoDirectPayment", new object[] { + DoDirectPaymentReq}); + return ((DoDirectPaymentResponseType)(results[0])); + } + + /// + public void DoDirectPaymentAsync(DoDirectPaymentReq DoDirectPaymentReq) { + this.DoDirectPaymentAsync(DoDirectPaymentReq, null); + } + + /// + public void DoDirectPaymentAsync(DoDirectPaymentReq DoDirectPaymentReq, object userState) { + if ((this.DoDirectPaymentOperationCompleted == null)) { + this.DoDirectPaymentOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoDirectPaymentOperationCompleted); + } + this.InvokeAsync("DoDirectPayment", new object[] { + DoDirectPaymentReq}, this.DoDirectPaymentOperationCompleted, userState); + } + + private void OnDoDirectPaymentOperationCompleted(object arg) { + if ((this.DoDirectPaymentCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoDirectPaymentCompleted(this, new DoDirectPaymentCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ManagePendingTransactionStatusResponse", Namespace="urn:ebay:api:PayPalAPI")] + public ManagePendingTransactionStatusResponseType ManagePendingTransactionStatus([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] ManagePendingTransactionStatusReq ManagePendingTransactionStatusReq) { + object[] results = this.Invoke("ManagePendingTransactionStatus", new object[] { + ManagePendingTransactionStatusReq}); + return ((ManagePendingTransactionStatusResponseType)(results[0])); + } + + /// + public void ManagePendingTransactionStatusAsync(ManagePendingTransactionStatusReq ManagePendingTransactionStatusReq) { + this.ManagePendingTransactionStatusAsync(ManagePendingTransactionStatusReq, null); + } + + /// + public void ManagePendingTransactionStatusAsync(ManagePendingTransactionStatusReq ManagePendingTransactionStatusReq, object userState) { + if ((this.ManagePendingTransactionStatusOperationCompleted == null)) { + this.ManagePendingTransactionStatusOperationCompleted = new System.Threading.SendOrPostCallback(this.OnManagePendingTransactionStatusOperationCompleted); + } + this.InvokeAsync("ManagePendingTransactionStatus", new object[] { + ManagePendingTransactionStatusReq}, this.ManagePendingTransactionStatusOperationCompleted, userState); + } + + private void OnManagePendingTransactionStatusOperationCompleted(object arg) { + if ((this.ManagePendingTransactionStatusCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ManagePendingTransactionStatusCompleted(this, new ManagePendingTransactionStatusCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoCancelResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoCancelResponseType DoCancel([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoCancelReq DoCancelReq) { + object[] results = this.Invoke("DoCancel", new object[] { + DoCancelReq}); + return ((DoCancelResponseType)(results[0])); + } + + /// + public void DoCancelAsync(DoCancelReq DoCancelReq) { + this.DoCancelAsync(DoCancelReq, null); + } + + /// + public void DoCancelAsync(DoCancelReq DoCancelReq, object userState) { + if ((this.DoCancelOperationCompleted == null)) { + this.DoCancelOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoCancelOperationCompleted); + } + this.InvokeAsync("DoCancel", new object[] { + DoCancelReq}, this.DoCancelOperationCompleted, userState); + } + + private void OnDoCancelOperationCompleted(object arg) { + if ((this.DoCancelCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoCancelCompleted(this, new DoCancelCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoCaptureResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoCaptureResponseType DoCapture([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoCaptureReq DoCaptureReq) { + object[] results = this.Invoke("DoCapture", new object[] { + DoCaptureReq}); + return ((DoCaptureResponseType)(results[0])); + } + + /// + public void DoCaptureAsync(DoCaptureReq DoCaptureReq) { + this.DoCaptureAsync(DoCaptureReq, null); + } + + /// + public void DoCaptureAsync(DoCaptureReq DoCaptureReq, object userState) { + if ((this.DoCaptureOperationCompleted == null)) { + this.DoCaptureOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoCaptureOperationCompleted); + } + this.InvokeAsync("DoCapture", new object[] { + DoCaptureReq}, this.DoCaptureOperationCompleted, userState); + } + + private void OnDoCaptureOperationCompleted(object arg) { + if ((this.DoCaptureCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoCaptureCompleted(this, new DoCaptureCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoReauthorizationResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoReauthorizationResponseType DoReauthorization([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoReauthorizationReq DoReauthorizationReq) { + object[] results = this.Invoke("DoReauthorization", new object[] { + DoReauthorizationReq}); + return ((DoReauthorizationResponseType)(results[0])); + } + + /// + public void DoReauthorizationAsync(DoReauthorizationReq DoReauthorizationReq) { + this.DoReauthorizationAsync(DoReauthorizationReq, null); + } + + /// + public void DoReauthorizationAsync(DoReauthorizationReq DoReauthorizationReq, object userState) { + if ((this.DoReauthorizationOperationCompleted == null)) { + this.DoReauthorizationOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoReauthorizationOperationCompleted); + } + this.InvokeAsync("DoReauthorization", new object[] { + DoReauthorizationReq}, this.DoReauthorizationOperationCompleted, userState); + } + + private void OnDoReauthorizationOperationCompleted(object arg) { + if ((this.DoReauthorizationCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoReauthorizationCompleted(this, new DoReauthorizationCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoVoidResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoVoidResponseType DoVoid([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoVoidReq DoVoidReq) { + object[] results = this.Invoke("DoVoid", new object[] { + DoVoidReq}); + return ((DoVoidResponseType)(results[0])); + } + + /// + public void DoVoidAsync(DoVoidReq DoVoidReq) { + this.DoVoidAsync(DoVoidReq, null); + } + + /// + public void DoVoidAsync(DoVoidReq DoVoidReq, object userState) { + if ((this.DoVoidOperationCompleted == null)) { + this.DoVoidOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoVoidOperationCompleted); + } + this.InvokeAsync("DoVoid", new object[] { + DoVoidReq}, this.DoVoidOperationCompleted, userState); + } + + private void OnDoVoidOperationCompleted(object arg) { + if ((this.DoVoidCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoVoidCompleted(this, new DoVoidCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoAuthorizationResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoAuthorizationResponseType DoAuthorization([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoAuthorizationReq DoAuthorizationReq) { + object[] results = this.Invoke("DoAuthorization", new object[] { + DoAuthorizationReq}); + return ((DoAuthorizationResponseType)(results[0])); + } + + /// + public void DoAuthorizationAsync(DoAuthorizationReq DoAuthorizationReq) { + this.DoAuthorizationAsync(DoAuthorizationReq, null); + } + + /// + public void DoAuthorizationAsync(DoAuthorizationReq DoAuthorizationReq, object userState) { + if ((this.DoAuthorizationOperationCompleted == null)) { + this.DoAuthorizationOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoAuthorizationOperationCompleted); + } + this.InvokeAsync("DoAuthorization", new object[] { + DoAuthorizationReq}, this.DoAuthorizationOperationCompleted, userState); + } + + private void OnDoAuthorizationOperationCompleted(object arg) { + if ((this.DoAuthorizationCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoAuthorizationCompleted(this, new DoAuthorizationCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("UpdateAuthorizationResponse", Namespace="urn:ebay:api:PayPalAPI")] + public UpdateAuthorizationResponseType UpdateAuthorization([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] UpdateAuthorizationReq UpdateAuthorizationReq) { + object[] results = this.Invoke("UpdateAuthorization", new object[] { + UpdateAuthorizationReq}); + return ((UpdateAuthorizationResponseType)(results[0])); + } + + /// + public void UpdateAuthorizationAsync(UpdateAuthorizationReq UpdateAuthorizationReq) { + this.UpdateAuthorizationAsync(UpdateAuthorizationReq, null); + } + + /// + public void UpdateAuthorizationAsync(UpdateAuthorizationReq UpdateAuthorizationReq, object userState) { + if ((this.UpdateAuthorizationOperationCompleted == null)) { + this.UpdateAuthorizationOperationCompleted = new System.Threading.SendOrPostCallback(this.OnUpdateAuthorizationOperationCompleted); + } + this.InvokeAsync("UpdateAuthorization", new object[] { + UpdateAuthorizationReq}, this.UpdateAuthorizationOperationCompleted, userState); + } + + private void OnUpdateAuthorizationOperationCompleted(object arg) { + if ((this.UpdateAuthorizationCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.UpdateAuthorizationCompleted(this, new UpdateAuthorizationCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("SetCustomerBillingAgreementResponse", Namespace="urn:ebay:api:PayPalAPI")] + public SetCustomerBillingAgreementResponseType SetCustomerBillingAgreement([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] SetCustomerBillingAgreementReq SetCustomerBillingAgreementReq) { + object[] results = this.Invoke("SetCustomerBillingAgreement", new object[] { + SetCustomerBillingAgreementReq}); + return ((SetCustomerBillingAgreementResponseType)(results[0])); + } + + /// + public void SetCustomerBillingAgreementAsync(SetCustomerBillingAgreementReq SetCustomerBillingAgreementReq) { + this.SetCustomerBillingAgreementAsync(SetCustomerBillingAgreementReq, null); + } + + /// + public void SetCustomerBillingAgreementAsync(SetCustomerBillingAgreementReq SetCustomerBillingAgreementReq, object userState) { + if ((this.SetCustomerBillingAgreementOperationCompleted == null)) { + this.SetCustomerBillingAgreementOperationCompleted = new System.Threading.SendOrPostCallback(this.OnSetCustomerBillingAgreementOperationCompleted); + } + this.InvokeAsync("SetCustomerBillingAgreement", new object[] { + SetCustomerBillingAgreementReq}, this.SetCustomerBillingAgreementOperationCompleted, userState); + } + + private void OnSetCustomerBillingAgreementOperationCompleted(object arg) { + if ((this.SetCustomerBillingAgreementCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.SetCustomerBillingAgreementCompleted(this, new SetCustomerBillingAgreementCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetBillingAgreementCustomerDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetBillingAgreementCustomerDetailsResponseType GetBillingAgreementCustomerDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetBillingAgreementCustomerDetailsReq GetBillingAgreementCustomerDetailsReq) { + object[] results = this.Invoke("GetBillingAgreementCustomerDetails", new object[] { + GetBillingAgreementCustomerDetailsReq}); + return ((GetBillingAgreementCustomerDetailsResponseType)(results[0])); + } + + /// + public void GetBillingAgreementCustomerDetailsAsync(GetBillingAgreementCustomerDetailsReq GetBillingAgreementCustomerDetailsReq) { + this.GetBillingAgreementCustomerDetailsAsync(GetBillingAgreementCustomerDetailsReq, null); + } + + /// + public void GetBillingAgreementCustomerDetailsAsync(GetBillingAgreementCustomerDetailsReq GetBillingAgreementCustomerDetailsReq, object userState) { + if ((this.GetBillingAgreementCustomerDetailsOperationCompleted == null)) { + this.GetBillingAgreementCustomerDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetBillingAgreementCustomerDetailsOperationCompleted); + } + this.InvokeAsync("GetBillingAgreementCustomerDetails", new object[] { + GetBillingAgreementCustomerDetailsReq}, this.GetBillingAgreementCustomerDetailsOperationCompleted, userState); + } + + private void OnGetBillingAgreementCustomerDetailsOperationCompleted(object arg) { + if ((this.GetBillingAgreementCustomerDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetBillingAgreementCustomerDetailsCompleted(this, new GetBillingAgreementCustomerDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateBillingAgreementResponse", Namespace="urn:ebay:api:PayPalAPI")] + public CreateBillingAgreementResponseType CreateBillingAgreement([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] CreateBillingAgreementReq CreateBillingAgreementReq) { + object[] results = this.Invoke("CreateBillingAgreement", new object[] { + CreateBillingAgreementReq}); + return ((CreateBillingAgreementResponseType)(results[0])); + } + + /// + public void CreateBillingAgreementAsync(CreateBillingAgreementReq CreateBillingAgreementReq) { + this.CreateBillingAgreementAsync(CreateBillingAgreementReq, null); + } + + /// + public void CreateBillingAgreementAsync(CreateBillingAgreementReq CreateBillingAgreementReq, object userState) { + if ((this.CreateBillingAgreementOperationCompleted == null)) { + this.CreateBillingAgreementOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateBillingAgreementOperationCompleted); + } + this.InvokeAsync("CreateBillingAgreement", new object[] { + CreateBillingAgreementReq}, this.CreateBillingAgreementOperationCompleted, userState); + } + + private void OnCreateBillingAgreementOperationCompleted(object arg) { + if ((this.CreateBillingAgreementCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateBillingAgreementCompleted(this, new CreateBillingAgreementCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoReferenceTransactionResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoReferenceTransactionResponseType DoReferenceTransaction([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoReferenceTransactionReq DoReferenceTransactionReq) { + object[] results = this.Invoke("DoReferenceTransaction", new object[] { + DoReferenceTransactionReq}); + return ((DoReferenceTransactionResponseType)(results[0])); + } + + /// + public void DoReferenceTransactionAsync(DoReferenceTransactionReq DoReferenceTransactionReq) { + this.DoReferenceTransactionAsync(DoReferenceTransactionReq, null); + } + + /// + public void DoReferenceTransactionAsync(DoReferenceTransactionReq DoReferenceTransactionReq, object userState) { + if ((this.DoReferenceTransactionOperationCompleted == null)) { + this.DoReferenceTransactionOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoReferenceTransactionOperationCompleted); + } + this.InvokeAsync("DoReferenceTransaction", new object[] { + DoReferenceTransactionReq}, this.DoReferenceTransactionOperationCompleted, userState); + } + + private void OnDoReferenceTransactionOperationCompleted(object arg) { + if ((this.DoReferenceTransactionCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoReferenceTransactionCompleted(this, new DoReferenceTransactionCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoNonReferencedCreditResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoNonReferencedCreditResponseType DoNonReferencedCredit([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoNonReferencedCreditReq DoNonReferencedCreditReq) { + object[] results = this.Invoke("DoNonReferencedCredit", new object[] { + DoNonReferencedCreditReq}); + return ((DoNonReferencedCreditResponseType)(results[0])); + } + + /// + public void DoNonReferencedCreditAsync(DoNonReferencedCreditReq DoNonReferencedCreditReq) { + this.DoNonReferencedCreditAsync(DoNonReferencedCreditReq, null); + } + + /// + public void DoNonReferencedCreditAsync(DoNonReferencedCreditReq DoNonReferencedCreditReq, object userState) { + if ((this.DoNonReferencedCreditOperationCompleted == null)) { + this.DoNonReferencedCreditOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoNonReferencedCreditOperationCompleted); + } + this.InvokeAsync("DoNonReferencedCredit", new object[] { + DoNonReferencedCreditReq}, this.DoNonReferencedCreditOperationCompleted, userState); + } + + private void OnDoNonReferencedCreditOperationCompleted(object arg) { + if ((this.DoNonReferencedCreditCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoNonReferencedCreditCompleted(this, new DoNonReferencedCreditCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DoUATPAuthorizationResponse", Namespace="urn:ebay:api:PayPalAPI")] + public DoUATPAuthorizationResponseType DoUATPAuthorization([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] DoUATPAuthorizationReq DoUATPAuthorizationReq) { + object[] results = this.Invoke("DoUATPAuthorization", new object[] { + DoUATPAuthorizationReq}); + return ((DoUATPAuthorizationResponseType)(results[0])); + } + + /// + public void DoUATPAuthorizationAsync(DoUATPAuthorizationReq DoUATPAuthorizationReq) { + this.DoUATPAuthorizationAsync(DoUATPAuthorizationReq, null); + } + + /// + public void DoUATPAuthorizationAsync(DoUATPAuthorizationReq DoUATPAuthorizationReq, object userState) { + if ((this.DoUATPAuthorizationOperationCompleted == null)) { + this.DoUATPAuthorizationOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDoUATPAuthorizationOperationCompleted); + } + this.InvokeAsync("DoUATPAuthorization", new object[] { + DoUATPAuthorizationReq}, this.DoUATPAuthorizationOperationCompleted, userState); + } + + private void OnDoUATPAuthorizationOperationCompleted(object arg) { + if ((this.DoUATPAuthorizationCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DoUATPAuthorizationCompleted(this, new DoUATPAuthorizationCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateRecurringPaymentsProfileResponse", Namespace="urn:ebay:api:PayPalAPI")] + public CreateRecurringPaymentsProfileResponseType CreateRecurringPaymentsProfile([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] CreateRecurringPaymentsProfileReq CreateRecurringPaymentsProfileReq) { + object[] results = this.Invoke("CreateRecurringPaymentsProfile", new object[] { + CreateRecurringPaymentsProfileReq}); + return ((CreateRecurringPaymentsProfileResponseType)(results[0])); + } + + /// + public void CreateRecurringPaymentsProfileAsync(CreateRecurringPaymentsProfileReq CreateRecurringPaymentsProfileReq) { + this.CreateRecurringPaymentsProfileAsync(CreateRecurringPaymentsProfileReq, null); + } + + /// + public void CreateRecurringPaymentsProfileAsync(CreateRecurringPaymentsProfileReq CreateRecurringPaymentsProfileReq, object userState) { + if ((this.CreateRecurringPaymentsProfileOperationCompleted == null)) { + this.CreateRecurringPaymentsProfileOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateRecurringPaymentsProfileOperationCompleted); + } + this.InvokeAsync("CreateRecurringPaymentsProfile", new object[] { + CreateRecurringPaymentsProfileReq}, this.CreateRecurringPaymentsProfileOperationCompleted, userState); + } + + private void OnCreateRecurringPaymentsProfileOperationCompleted(object arg) { + if ((this.CreateRecurringPaymentsProfileCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateRecurringPaymentsProfileCompleted(this, new CreateRecurringPaymentsProfileCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetRecurringPaymentsProfileDetailsResponse", Namespace="urn:ebay:api:PayPalAPI")] + public GetRecurringPaymentsProfileDetailsResponseType GetRecurringPaymentsProfileDetails([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] GetRecurringPaymentsProfileDetailsReq GetRecurringPaymentsProfileDetailsReq) { + object[] results = this.Invoke("GetRecurringPaymentsProfileDetails", new object[] { + GetRecurringPaymentsProfileDetailsReq}); + return ((GetRecurringPaymentsProfileDetailsResponseType)(results[0])); + } + + /// + public void GetRecurringPaymentsProfileDetailsAsync(GetRecurringPaymentsProfileDetailsReq GetRecurringPaymentsProfileDetailsReq) { + this.GetRecurringPaymentsProfileDetailsAsync(GetRecurringPaymentsProfileDetailsReq, null); + } + + /// + public void GetRecurringPaymentsProfileDetailsAsync(GetRecurringPaymentsProfileDetailsReq GetRecurringPaymentsProfileDetailsReq, object userState) { + if ((this.GetRecurringPaymentsProfileDetailsOperationCompleted == null)) { + this.GetRecurringPaymentsProfileDetailsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetRecurringPaymentsProfileDetailsOperationCompleted); + } + this.InvokeAsync("GetRecurringPaymentsProfileDetails", new object[] { + GetRecurringPaymentsProfileDetailsReq}, this.GetRecurringPaymentsProfileDetailsOperationCompleted, userState); + } + + private void OnGetRecurringPaymentsProfileDetailsOperationCompleted(object arg) { + if ((this.GetRecurringPaymentsProfileDetailsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetRecurringPaymentsProfileDetailsCompleted(this, new GetRecurringPaymentsProfileDetailsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ManageRecurringPaymentsProfileStatusResponse", Namespace="urn:ebay:api:PayPalAPI")] + public ManageRecurringPaymentsProfileStatusResponseType ManageRecurringPaymentsProfileStatus([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] ManageRecurringPaymentsProfileStatusReq ManageRecurringPaymentsProfileStatusReq) { + object[] results = this.Invoke("ManageRecurringPaymentsProfileStatus", new object[] { + ManageRecurringPaymentsProfileStatusReq}); + return ((ManageRecurringPaymentsProfileStatusResponseType)(results[0])); + } + + /// + public void ManageRecurringPaymentsProfileStatusAsync(ManageRecurringPaymentsProfileStatusReq ManageRecurringPaymentsProfileStatusReq) { + this.ManageRecurringPaymentsProfileStatusAsync(ManageRecurringPaymentsProfileStatusReq, null); + } + + /// + public void ManageRecurringPaymentsProfileStatusAsync(ManageRecurringPaymentsProfileStatusReq ManageRecurringPaymentsProfileStatusReq, object userState) { + if ((this.ManageRecurringPaymentsProfileStatusOperationCompleted == null)) { + this.ManageRecurringPaymentsProfileStatusOperationCompleted = new System.Threading.SendOrPostCallback(this.OnManageRecurringPaymentsProfileStatusOperationCompleted); + } + this.InvokeAsync("ManageRecurringPaymentsProfileStatus", new object[] { + ManageRecurringPaymentsProfileStatusReq}, this.ManageRecurringPaymentsProfileStatusOperationCompleted, userState); + } + + private void OnManageRecurringPaymentsProfileStatusOperationCompleted(object arg) { + if ((this.ManageRecurringPaymentsProfileStatusCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ManageRecurringPaymentsProfileStatusCompleted(this, new ManageRecurringPaymentsProfileStatusCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BillOutstandingAmountResponse", Namespace="urn:ebay:api:PayPalAPI")] + public BillOutstandingAmountResponseType BillOutstandingAmount([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] BillOutstandingAmountReq BillOutstandingAmountReq) { + object[] results = this.Invoke("BillOutstandingAmount", new object[] { + BillOutstandingAmountReq}); + return ((BillOutstandingAmountResponseType)(results[0])); + } + + /// + public void BillOutstandingAmountAsync(BillOutstandingAmountReq BillOutstandingAmountReq) { + this.BillOutstandingAmountAsync(BillOutstandingAmountReq, null); + } + + /// + public void BillOutstandingAmountAsync(BillOutstandingAmountReq BillOutstandingAmountReq, object userState) { + if ((this.BillOutstandingAmountOperationCompleted == null)) { + this.BillOutstandingAmountOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBillOutstandingAmountOperationCompleted); + } + this.InvokeAsync("BillOutstandingAmount", new object[] { + BillOutstandingAmountReq}, this.BillOutstandingAmountOperationCompleted, userState); + } + + private void OnBillOutstandingAmountOperationCompleted(object arg) { + if ((this.BillOutstandingAmountCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BillOutstandingAmountCompleted(this, new BillOutstandingAmountCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("UpdateRecurringPaymentsProfileResponse", Namespace="urn:ebay:api:PayPalAPI")] + public UpdateRecurringPaymentsProfileResponseType UpdateRecurringPaymentsProfile([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] UpdateRecurringPaymentsProfileReq UpdateRecurringPaymentsProfileReq) { + object[] results = this.Invoke("UpdateRecurringPaymentsProfile", new object[] { + UpdateRecurringPaymentsProfileReq}); + return ((UpdateRecurringPaymentsProfileResponseType)(results[0])); + } + + /// + public void UpdateRecurringPaymentsProfileAsync(UpdateRecurringPaymentsProfileReq UpdateRecurringPaymentsProfileReq) { + this.UpdateRecurringPaymentsProfileAsync(UpdateRecurringPaymentsProfileReq, null); + } + + /// + public void UpdateRecurringPaymentsProfileAsync(UpdateRecurringPaymentsProfileReq UpdateRecurringPaymentsProfileReq, object userState) { + if ((this.UpdateRecurringPaymentsProfileOperationCompleted == null)) { + this.UpdateRecurringPaymentsProfileOperationCompleted = new System.Threading.SendOrPostCallback(this.OnUpdateRecurringPaymentsProfileOperationCompleted); + } + this.InvokeAsync("UpdateRecurringPaymentsProfile", new object[] { + UpdateRecurringPaymentsProfileReq}, this.UpdateRecurringPaymentsProfileOperationCompleted, userState); + } + + private void OnUpdateRecurringPaymentsProfileOperationCompleted(object arg) { + if ((this.UpdateRecurringPaymentsProfileCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.UpdateRecurringPaymentsProfileCompleted(this, new UpdateRecurringPaymentsProfileCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ReverseTransactionResponse", Namespace="urn:ebay:api:PayPalAPI")] + public ReverseTransactionResponseType ReverseTransaction([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] ReverseTransactionReq ReverseTransactionReq) { + object[] results = this.Invoke("ReverseTransaction", new object[] { + ReverseTransactionReq}); + return ((ReverseTransactionResponseType)(results[0])); + } + + /// + public void ReverseTransactionAsync(ReverseTransactionReq ReverseTransactionReq) { + this.ReverseTransactionAsync(ReverseTransactionReq, null); + } + + /// + public void ReverseTransactionAsync(ReverseTransactionReq ReverseTransactionReq, object userState) { + if ((this.ReverseTransactionOperationCompleted == null)) { + this.ReverseTransactionOperationCompleted = new System.Threading.SendOrPostCallback(this.OnReverseTransactionOperationCompleted); + } + this.InvokeAsync("ReverseTransaction", new object[] { + ReverseTransactionReq}, this.ReverseTransactionOperationCompleted, userState); + } + + private void OnReverseTransactionOperationCompleted(object arg) { + if ((this.ReverseTransactionCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ReverseTransactionCompleted(this, new ReverseTransactionCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ExternalRememberMeOptOutResponse", Namespace="urn:ebay:api:PayPalAPI")] + public ExternalRememberMeOptOutResponseType ExternalRememberMeOptOut([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] ExternalRememberMeOptOutReq ExternalRememberMeOptOutReq) { + object[] results = this.Invoke("ExternalRememberMeOptOut", new object[] { + ExternalRememberMeOptOutReq}); + return ((ExternalRememberMeOptOutResponseType)(results[0])); + } + + /// + public void ExternalRememberMeOptOutAsync(ExternalRememberMeOptOutReq ExternalRememberMeOptOutReq) { + this.ExternalRememberMeOptOutAsync(ExternalRememberMeOptOutReq, null); + } + + /// + public void ExternalRememberMeOptOutAsync(ExternalRememberMeOptOutReq ExternalRememberMeOptOutReq, object userState) { + if ((this.ExternalRememberMeOptOutOperationCompleted == null)) { + this.ExternalRememberMeOptOutOperationCompleted = new System.Threading.SendOrPostCallback(this.OnExternalRememberMeOptOutOperationCompleted); + } + this.InvokeAsync("ExternalRememberMeOptOut", new object[] { + ExternalRememberMeOptOutReq}, this.ExternalRememberMeOptOutOperationCompleted, userState); + } + + private void OnExternalRememberMeOptOutOperationCompleted(object arg) { + if ((this.ExternalRememberMeOptOutCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ExternalRememberMeOptOutCompleted(this, new ExternalRememberMeOptOutCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + [System.Xml.Serialization.XmlRootAttribute("RequesterCredentials", Namespace="urn:ebay:api:PayPalAPI", IsNullable=false)] + public partial class CustomSecurityHeaderType : System.Web.Services.Protocols.SoapHeader { + + private string eBayAuthTokenField; + + private string hardExpirationWarningField; + + private UserIdPasswordType credentialsField; + + /// + public string eBayAuthToken { + get { + return this.eBayAuthTokenField; + } + set { + this.eBayAuthTokenField = value; + } + } + + /// + public string HardExpirationWarning { + get { + return this.hardExpirationWarningField; + } + set { + this.hardExpirationWarningField = value; + } + } + + /// + public UserIdPasswordType Credentials { + get { + return this.credentialsField; + } + set { + this.credentialsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class UserIdPasswordType { + + private string appIdField; + + private string devIdField; + + private string authCertField; + + private string usernameField; + + private string passwordField; + + private string signatureField; + + private string subjectField; + + private string authTokenField; + + /// + public string AppId { + get { + return this.appIdField; + } + set { + this.appIdField = value; + } + } + + /// + public string DevId { + get { + return this.devIdField; + } + set { + this.devIdField = value; + } + } + + /// + public string AuthCert { + get { + return this.authCertField; + } + set { + this.authCertField = value; + } + } + + /// + public string Username { + get { + return this.usernameField; + } + set { + this.usernameField = value; + } + } + + /// + public string Password { + get { + return this.passwordField; + } + set { + this.passwordField = value; + } + } + + /// + public string Signature { + get { + return this.signatureField; + } + set { + this.signatureField = value; + } + } + + /// + public string Subject { + get { + return this.subjectField; + } + set { + this.subjectField = value; + } + } + + /// + public string AuthToken { + get { + return this.authTokenField; + } + set { + this.authTokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ReverseTransactionResponseDetailsType { + + private string reverseTransactionIDField; + + private string statusField; + + /// + [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] + public string ReverseTransactionID { + get { + return this.reverseTransactionIDField; + } + set { + this.reverseTransactionIDField = value; + } + } + + /// + public string Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class UpdateRecurringPaymentsProfileResponseDetailsType { + + private string profileIDField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BillOutstandingAmountResponseDetailsType { + + private string profileIDField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ManageRecurringPaymentsProfileStatusResponseDetailsType { + + private string profileIDField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class RecurringPaymentsSummaryType { + + private System.DateTime nextBillingDateField; + + private bool nextBillingDateFieldSpecified; + + private int numberCyclesCompletedField; + + private int numberCyclesRemainingField; + + private BasicAmountType outstandingBalanceField; + + private int failedPaymentCountField; + + private System.DateTime lastPaymentDateField; + + private bool lastPaymentDateFieldSpecified; + + private BasicAmountType lastPaymentAmountField; + + /// + public System.DateTime NextBillingDate { + get { + return this.nextBillingDateField; + } + set { + this.nextBillingDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool NextBillingDateSpecified { + get { + return this.nextBillingDateFieldSpecified; + } + set { + this.nextBillingDateFieldSpecified = value; + } + } + + /// + public int NumberCyclesCompleted { + get { + return this.numberCyclesCompletedField; + } + set { + this.numberCyclesCompletedField = value; + } + } + + /// + public int NumberCyclesRemaining { + get { + return this.numberCyclesRemainingField; + } + set { + this.numberCyclesRemainingField = value; + } + } + + /// + public BasicAmountType OutstandingBalance { + get { + return this.outstandingBalanceField; + } + set { + this.outstandingBalanceField = value; + } + } + + /// + public int FailedPaymentCount { + get { + return this.failedPaymentCountField; + } + set { + this.failedPaymentCountField = value; + } + } + + /// + public System.DateTime LastPaymentDate { + get { + return this.lastPaymentDateField; + } + set { + this.lastPaymentDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool LastPaymentDateSpecified { + get { + return this.lastPaymentDateFieldSpecified; + } + set { + this.lastPaymentDateFieldSpecified = value; + } + } + + /// + public BasicAmountType LastPaymentAmount { + get { + return this.lastPaymentAmountField; + } + set { + this.lastPaymentAmountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:CoreComponentTypes")] + public partial class BasicAmountType { + + private CurrencyCodeType currencyIDField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public CurrencyCodeType currencyID { + get { + return this.currencyIDField; + } + set { + this.currencyIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum CurrencyCodeType { + + /// + AFA, + + /// + ALL, + + /// + DZD, + + /// + ADP, + + /// + AOA, + + /// + ARS, + + /// + AMD, + + /// + AWG, + + /// + AZM, + + /// + BSD, + + /// + BHD, + + /// + BDT, + + /// + BBD, + + /// + BYR, + + /// + BZD, + + /// + BMD, + + /// + BTN, + + /// + INR, + + /// + BOV, + + /// + BOB, + + /// + BAM, + + /// + BWP, + + /// + BRL, + + /// + BND, + + /// + BGL, + + /// + BGN, + + /// + BIF, + + /// + KHR, + + /// + CAD, + + /// + CVE, + + /// + KYD, + + /// + XAF, + + /// + CLF, + + /// + CLP, + + /// + CNY, + + /// + COP, + + /// + KMF, + + /// + CDF, + + /// + CRC, + + /// + HRK, + + /// + CUP, + + /// + CYP, + + /// + CZK, + + /// + DKK, + + /// + DJF, + + /// + DOP, + + /// + TPE, + + /// + ECV, + + /// + ECS, + + /// + EGP, + + /// + SVC, + + /// + ERN, + + /// + EEK, + + /// + ETB, + + /// + FKP, + + /// + FJD, + + /// + GMD, + + /// + GEL, + + /// + GHC, + + /// + GIP, + + /// + GTQ, + + /// + GNF, + + /// + GWP, + + /// + GYD, + + /// + HTG, + + /// + HNL, + + /// + HKD, + + /// + HUF, + + /// + ISK, + + /// + IDR, + + /// + IRR, + + /// + IQD, + + /// + ILS, + + /// + JMD, + + /// + JPY, + + /// + JOD, + + /// + KZT, + + /// + KES, + + /// + AUD, + + /// + KPW, + + /// + KRW, + + /// + KWD, + + /// + KGS, + + /// + LAK, + + /// + LVL, + + /// + LBP, + + /// + LSL, + + /// + LRD, + + /// + LYD, + + /// + CHF, + + /// + LTL, + + /// + MOP, + + /// + MKD, + + /// + MGF, + + /// + MWK, + + /// + MYR, + + /// + MVR, + + /// + MTL, + + /// + EUR, + + /// + MRO, + + /// + MUR, + + /// + MXN, + + /// + MXV, + + /// + MDL, + + /// + MNT, + + /// + XCD, + + /// + MZM, + + /// + MMK, + + /// + ZAR, + + /// + NAD, + + /// + NPR, + + /// + ANG, + + /// + XPF, + + /// + NZD, + + /// + NIO, + + /// + NGN, + + /// + NOK, + + /// + OMR, + + /// + PKR, + + /// + PAB, + + /// + PGK, + + /// + PYG, + + /// + PEN, + + /// + PHP, + + /// + PLN, + + /// + USD, + + /// + QAR, + + /// + ROL, + + /// + RUB, + + /// + RUR, + + /// + RWF, + + /// + SHP, + + /// + WST, + + /// + STD, + + /// + SAR, + + /// + SCR, + + /// + SLL, + + /// + SGD, + + /// + SKK, + + /// + SIT, + + /// + SBD, + + /// + SOS, + + /// + LKR, + + /// + SDD, + + /// + SRG, + + /// + SZL, + + /// + SEK, + + /// + SYP, + + /// + TWD, + + /// + TJS, + + /// + TZS, + + /// + THB, + + /// + XOF, + + /// + TOP, + + /// + TTD, + + /// + TND, + + /// + TRY, + + /// + TMM, + + /// + UGX, + + /// + UAH, + + /// + AED, + + /// + GBP, + + /// + USS, + + /// + USN, + + /// + UYU, + + /// + UZS, + + /// + VUV, + + /// + VEB, + + /// + VND, + + /// + MAD, + + /// + YER, + + /// + YUM, + + /// + ZMK, + + /// + ZWD, + + /// + CustomCode, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetRecurringPaymentsProfileDetailsResponseDetailsType { + + private string profileIDField; + + private RecurringPaymentsProfileStatusType profileStatusField; + + private string descriptionField; + + private AutoBillType autoBillOutstandingAmountField; + + private int maxFailedPaymentsField; + + private RecurringPaymentsProfileDetailsType recurringPaymentsProfileDetailsField; + + private BillingPeriodDetailsType currentRecurringPaymentsPeriodField; + + private RecurringPaymentsSummaryType recurringPaymentsSummaryField; + + private CreditCardDetailsType creditCardField; + + private BillingPeriodDetailsType trialRecurringPaymentsPeriodField; + + private BillingPeriodDetailsType regularRecurringPaymentsPeriodField; + + private BasicAmountType trialAmountPaidField; + + private BasicAmountType regularAmountPaidField; + + private BasicAmountType aggregateAmountField; + + private BasicAmountType aggregateOptionalAmountField; + + private System.DateTime finalPaymentDueDateField; + + private bool finalPaymentDueDateFieldSpecified; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + + /// + public RecurringPaymentsProfileStatusType ProfileStatus { + get { + return this.profileStatusField; + } + set { + this.profileStatusField = value; + } + } + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + + /// + public AutoBillType AutoBillOutstandingAmount { + get { + return this.autoBillOutstandingAmountField; + } + set { + this.autoBillOutstandingAmountField = value; + } + } + + /// + public int MaxFailedPayments { + get { + return this.maxFailedPaymentsField; + } + set { + this.maxFailedPaymentsField = value; + } + } + + /// + public RecurringPaymentsProfileDetailsType RecurringPaymentsProfileDetails { + get { + return this.recurringPaymentsProfileDetailsField; + } + set { + this.recurringPaymentsProfileDetailsField = value; + } + } + + /// + public BillingPeriodDetailsType CurrentRecurringPaymentsPeriod { + get { + return this.currentRecurringPaymentsPeriodField; + } + set { + this.currentRecurringPaymentsPeriodField = value; + } + } + + /// + public RecurringPaymentsSummaryType RecurringPaymentsSummary { + get { + return this.recurringPaymentsSummaryField; + } + set { + this.recurringPaymentsSummaryField = value; + } + } + + /// + public CreditCardDetailsType CreditCard { + get { + return this.creditCardField; + } + set { + this.creditCardField = value; + } + } + + /// + public BillingPeriodDetailsType TrialRecurringPaymentsPeriod { + get { + return this.trialRecurringPaymentsPeriodField; + } + set { + this.trialRecurringPaymentsPeriodField = value; + } + } + + /// + public BillingPeriodDetailsType RegularRecurringPaymentsPeriod { + get { + return this.regularRecurringPaymentsPeriodField; + } + set { + this.regularRecurringPaymentsPeriodField = value; + } + } + + /// + public BasicAmountType TrialAmountPaid { + get { + return this.trialAmountPaidField; + } + set { + this.trialAmountPaidField = value; + } + } + + /// + public BasicAmountType RegularAmountPaid { + get { + return this.regularAmountPaidField; + } + set { + this.regularAmountPaidField = value; + } + } + + /// + public BasicAmountType AggregateAmount { + get { + return this.aggregateAmountField; + } + set { + this.aggregateAmountField = value; + } + } + + /// + public BasicAmountType AggregateOptionalAmount { + get { + return this.aggregateOptionalAmountField; + } + set { + this.aggregateOptionalAmountField = value; + } + } + + /// + public System.DateTime FinalPaymentDueDate { + get { + return this.finalPaymentDueDateField; + } + set { + this.finalPaymentDueDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FinalPaymentDueDateSpecified { + get { + return this.finalPaymentDueDateFieldSpecified; + } + set { + this.finalPaymentDueDateFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum RecurringPaymentsProfileStatusType { + + /// + ActiveProfile, + + /// + PendingProfile, + + /// + CancelledProfile, + + /// + ExpiredProfile, + + /// + SuspendedProfile, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AutoBillType { + + /// + NoAutoBill, + + /// + AddToNextBilling, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class RecurringPaymentsProfileDetailsType { + + private string subscriberNameField; + + private AddressType subscriberShippingAddressField; + + private System.DateTime billingStartDateField; + + private string profileReferenceField; + + /// + public string SubscriberName { + get { + return this.subscriberNameField; + } + set { + this.subscriberNameField = value; + } + } + + /// + public AddressType SubscriberShippingAddress { + get { + return this.subscriberShippingAddressField; + } + set { + this.subscriberShippingAddressField = value; + } + } + + /// + public System.DateTime BillingStartDate { + get { + return this.billingStartDateField; + } + set { + this.billingStartDateField = value; + } + } + + /// + public string ProfileReference { + get { + return this.profileReferenceField; + } + set { + this.profileReferenceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class AddressType { + + private string nameField; + + private string street1Field; + + private string street2Field; + + private string cityNameField; + + private string stateOrProvinceField; + + private CountryCodeType countryField; + + private bool countryFieldSpecified; + + private string countryNameField; + + private string phoneField; + + private string postalCodeField; + + private string addressIDField; + + private AddressOwnerCodeType addressOwnerField; + + private bool addressOwnerFieldSpecified; + + private string externalAddressIDField; + + private string internationalNameField; + + private string internationalStateAndCityField; + + private string internationalStreetField; + + private AddressStatusCodeType addressStatusField; + + private bool addressStatusFieldSpecified; + + private AddressNormalizationStatusCodeType addressNormalizationStatusField; + + private bool addressNormalizationStatusFieldSpecified; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Street1 { + get { + return this.street1Field; + } + set { + this.street1Field = value; + } + } + + /// + public string Street2 { + get { + return this.street2Field; + } + set { + this.street2Field = value; + } + } + + /// + public string CityName { + get { + return this.cityNameField; + } + set { + this.cityNameField = value; + } + } + + /// + public string StateOrProvince { + get { + return this.stateOrProvinceField; + } + set { + this.stateOrProvinceField = value; + } + } + + /// + public CountryCodeType Country { + get { + return this.countryField; + } + set { + this.countryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CountrySpecified { + get { + return this.countryFieldSpecified; + } + set { + this.countryFieldSpecified = value; + } + } + + /// + public string CountryName { + get { + return this.countryNameField; + } + set { + this.countryNameField = value; + } + } + + /// + public string Phone { + get { + return this.phoneField; + } + set { + this.phoneField = value; + } + } + + /// + public string PostalCode { + get { + return this.postalCodeField; + } + set { + this.postalCodeField = value; + } + } + + /// + public string AddressID { + get { + return this.addressIDField; + } + set { + this.addressIDField = value; + } + } + + /// + public AddressOwnerCodeType AddressOwner { + get { + return this.addressOwnerField; + } + set { + this.addressOwnerField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AddressOwnerSpecified { + get { + return this.addressOwnerFieldSpecified; + } + set { + this.addressOwnerFieldSpecified = value; + } + } + + /// + public string ExternalAddressID { + get { + return this.externalAddressIDField; + } + set { + this.externalAddressIDField = value; + } + } + + /// + public string InternationalName { + get { + return this.internationalNameField; + } + set { + this.internationalNameField = value; + } + } + + /// + public string InternationalStateAndCity { + get { + return this.internationalStateAndCityField; + } + set { + this.internationalStateAndCityField = value; + } + } + + /// + public string InternationalStreet { + get { + return this.internationalStreetField; + } + set { + this.internationalStreetField = value; + } + } + + /// + public AddressStatusCodeType AddressStatus { + get { + return this.addressStatusField; + } + set { + this.addressStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AddressStatusSpecified { + get { + return this.addressStatusFieldSpecified; + } + set { + this.addressStatusFieldSpecified = value; + } + } + + /// + public AddressNormalizationStatusCodeType AddressNormalizationStatus { + get { + return this.addressNormalizationStatusField; + } + set { + this.addressNormalizationStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AddressNormalizationStatusSpecified { + get { + return this.addressNormalizationStatusFieldSpecified; + } + set { + this.addressNormalizationStatusFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum CountryCodeType { + + /// + AF, + + /// + AL, + + /// + DZ, + + /// + AS, + + /// + AD, + + /// + AO, + + /// + AI, + + /// + AQ, + + /// + AG, + + /// + AR, + + /// + AM, + + /// + AW, + + /// + AU, + + /// + AT, + + /// + AZ, + + /// + BS, + + /// + BH, + + /// + BD, + + /// + BB, + + /// + BY, + + /// + BE, + + /// + BZ, + + /// + BJ, + + /// + BM, + + /// + BT, + + /// + BO, + + /// + BA, + + /// + BW, + + /// + BV, + + /// + BR, + + /// + IO, + + /// + BN, + + /// + BG, + + /// + BF, + + /// + BI, + + /// + KH, + + /// + CM, + + /// + CA, + + /// + CV, + + /// + KY, + + /// + CF, + + /// + TD, + + /// + CL, + + /// + C2, + + /// + CN, + + /// + CX, + + /// + CC, + + /// + CO, + + /// + KM, + + /// + CG, + + /// + CD, + + /// + CK, + + /// + CR, + + /// + CI, + + /// + HR, + + /// + CU, + + /// + CY, + + /// + CZ, + + /// + DK, + + /// + DJ, + + /// + DM, + + /// + DO, + + /// + TP, + + /// + EC, + + /// + EG, + + /// + SV, + + /// + GQ, + + /// + ER, + + /// + EE, + + /// + ET, + + /// + FK, + + /// + FO, + + /// + FJ, + + /// + FI, + + /// + FR, + + /// + GF, + + /// + PF, + + /// + TF, + + /// + GA, + + /// + GM, + + /// + GE, + + /// + DE, + + /// + GH, + + /// + GI, + + /// + GR, + + /// + GL, + + /// + GD, + + /// + GP, + + /// + GU, + + /// + GT, + + /// + GN, + + /// + GW, + + /// + GY, + + /// + HT, + + /// + HM, + + /// + VA, + + /// + HN, + + /// + HK, + + /// + HU, + + /// + IS, + + /// + IN, + + /// + ID, + + /// + IR, + + /// + IQ, + + /// + IE, + + /// + IL, + + /// + IT, + + /// + JM, + + /// + JP, + + /// + JO, + + /// + KZ, + + /// + KE, + + /// + KI, + + /// + KP, + + /// + KR, + + /// + KW, + + /// + KG, + + /// + LA, + + /// + LV, + + /// + LB, + + /// + LS, + + /// + LR, + + /// + LY, + + /// + LI, + + /// + LT, + + /// + LU, + + /// + MO, + + /// + MK, + + /// + MG, + + /// + MW, + + /// + MY, + + /// + MV, + + /// + ML, + + /// + MT, + + /// + MH, + + /// + MQ, + + /// + MR, + + /// + MU, + + /// + YT, + + /// + MX, + + /// + FM, + + /// + MD, + + /// + MC, + + /// + MN, + + /// + MS, + + /// + MA, + + /// + MZ, + + /// + MM, + + /// + NA, + + /// + NR, + + /// + NP, + + /// + NL, + + /// + AN, + + /// + NC, + + /// + NZ, + + /// + NI, + + /// + NE, + + /// + NG, + + /// + NU, + + /// + NF, + + /// + MP, + + /// + NO, + + /// + OM, + + /// + PK, + + /// + PW, + + /// + PS, + + /// + PA, + + /// + PG, + + /// + PY, + + /// + PE, + + /// + PH, + + /// + PN, + + /// + PL, + + /// + PT, + + /// + PR, + + /// + QA, + + /// + RE, + + /// + RO, + + /// + RU, + + /// + RW, + + /// + SH, + + /// + KN, + + /// + LC, + + /// + PM, + + /// + VC, + + /// + WS, + + /// + SM, + + /// + ST, + + /// + SA, + + /// + SN, + + /// + SC, + + /// + SL, + + /// + SG, + + /// + SK, + + /// + SI, + + /// + SB, + + /// + SO, + + /// + ZA, + + /// + GS, + + /// + ES, + + /// + LK, + + /// + SD, + + /// + SR, + + /// + SJ, + + /// + SZ, + + /// + SE, + + /// + CH, + + /// + SY, + + /// + TW, + + /// + TJ, + + /// + TZ, + + /// + TH, + + /// + TG, + + /// + TK, + + /// + TO, + + /// + TT, + + /// + TN, + + /// + TR, + + /// + TM, + + /// + TC, + + /// + TV, + + /// + UG, + + /// + UA, + + /// + AE, + + /// + GB, + + /// + US, + + /// + UM, + + /// + UY, + + /// + UZ, + + /// + VU, + + /// + VE, + + /// + VN, + + /// + VG, + + /// + VI, + + /// + WF, + + /// + EH, + + /// + YE, + + /// + YU, + + /// + ZM, + + /// + ZW, + + /// + AA, + + /// + QM, + + /// + QN, + + /// + QO, + + /// + QP, + + /// + CS, + + /// + CustomCode, + + /// + GG, + + /// + IM, + + /// + JE, + + /// + TL, + + /// + RS, + + /// + ME, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AddressOwnerCodeType { + + /// + PayPal, + + /// + eBay, + + /// + CustomCode, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AddressStatusCodeType { + + /// + None, + + /// + Confirmed, + + /// + Unconfirmed, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AddressNormalizationStatusCodeType { + + /// + None, + + /// + Normalized, + + /// + Unnormalized, + + /// + UserPreferred, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BillingPeriodDetailsType { + + private BillingPeriodType billingPeriodField; + + private int billingFrequencyField; + + private int totalBillingCyclesField; + + private bool totalBillingCyclesFieldSpecified; + + private BasicAmountType amountField; + + private BasicAmountType shippingAmountField; + + private BasicAmountType taxAmountField; + + /// + public BillingPeriodType BillingPeriod { + get { + return this.billingPeriodField; + } + set { + this.billingPeriodField = value; + } + } + + /// + public int BillingFrequency { + get { + return this.billingFrequencyField; + } + set { + this.billingFrequencyField = value; + } + } + + /// + public int TotalBillingCycles { + get { + return this.totalBillingCyclesField; + } + set { + this.totalBillingCyclesField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TotalBillingCyclesSpecified { + get { + return this.totalBillingCyclesFieldSpecified; + } + set { + this.totalBillingCyclesFieldSpecified = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public BasicAmountType ShippingAmount { + get { + return this.shippingAmountField; + } + set { + this.shippingAmountField = value; + } + } + + /// + public BasicAmountType TaxAmount { + get { + return this.taxAmountField; + } + set { + this.taxAmountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BillingPeriodType { + + /// + NoBillingPeriodType, + + /// + Day, + + /// + Week, + + /// + SemiMonth, + + /// + Month, + + /// + Year, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class CreditCardDetailsType { + + private CreditCardTypeType creditCardTypeField; + + private bool creditCardTypeFieldSpecified; + + private string creditCardNumberField; + + private int expMonthField; + + private bool expMonthFieldSpecified; + + private int expYearField; + + private bool expYearFieldSpecified; + + private PayerInfoType cardOwnerField; + + private string cVV2Field; + + private int startMonthField; + + private bool startMonthFieldSpecified; + + private int startYearField; + + private bool startYearFieldSpecified; + + private string issueNumberField; + + private ThreeDSecureRequestType threeDSecureRequestField; + + /// + public CreditCardTypeType CreditCardType { + get { + return this.creditCardTypeField; + } + set { + this.creditCardTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CreditCardTypeSpecified { + get { + return this.creditCardTypeFieldSpecified; + } + set { + this.creditCardTypeFieldSpecified = value; + } + } + + /// + public string CreditCardNumber { + get { + return this.creditCardNumberField; + } + set { + this.creditCardNumberField = value; + } + } + + /// + public int ExpMonth { + get { + return this.expMonthField; + } + set { + this.expMonthField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExpMonthSpecified { + get { + return this.expMonthFieldSpecified; + } + set { + this.expMonthFieldSpecified = value; + } + } + + /// + public int ExpYear { + get { + return this.expYearField; + } + set { + this.expYearField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExpYearSpecified { + get { + return this.expYearFieldSpecified; + } + set { + this.expYearFieldSpecified = value; + } + } + + /// + public PayerInfoType CardOwner { + get { + return this.cardOwnerField; + } + set { + this.cardOwnerField = value; + } + } + + /// + public string CVV2 { + get { + return this.cVV2Field; + } + set { + this.cVV2Field = value; + } + } + + /// + public int StartMonth { + get { + return this.startMonthField; + } + set { + this.startMonthField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StartMonthSpecified { + get { + return this.startMonthFieldSpecified; + } + set { + this.startMonthFieldSpecified = value; + } + } + + /// + public int StartYear { + get { + return this.startYearField; + } + set { + this.startYearField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StartYearSpecified { + get { + return this.startYearFieldSpecified; + } + set { + this.startYearFieldSpecified = value; + } + } + + /// + public string IssueNumber { + get { + return this.issueNumberField; + } + set { + this.issueNumberField = value; + } + } + + /// + public ThreeDSecureRequestType ThreeDSecureRequest { + get { + return this.threeDSecureRequestField; + } + set { + this.threeDSecureRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum CreditCardTypeType { + + /// + Visa, + + /// + MasterCard, + + /// + Discover, + + /// + Amex, + + /// + Switch, + + /// + Solo, + + /// + Maestro, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PayerInfoType { + + private string payerField; + + private string payerIDField; + + private PayPalUserStatusCodeType payerStatusField; + + private bool payerStatusFieldSpecified; + + private PersonNameType payerNameField; + + private CountryCodeType payerCountryField; + + private bool payerCountryFieldSpecified; + + private string payerBusinessField; + + private AddressType addressField; + + private string contactPhoneField; + + private TaxIdDetailsType taxIdDetailsField; + + private EnhancedPayerInfoType enhancedPayerInfoField; + + /// + public string Payer { + get { + return this.payerField; + } + set { + this.payerField = value; + } + } + + /// + public string PayerID { + get { + return this.payerIDField; + } + set { + this.payerIDField = value; + } + } + + /// + public PayPalUserStatusCodeType PayerStatus { + get { + return this.payerStatusField; + } + set { + this.payerStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PayerStatusSpecified { + get { + return this.payerStatusFieldSpecified; + } + set { + this.payerStatusFieldSpecified = value; + } + } + + /// + public PersonNameType PayerName { + get { + return this.payerNameField; + } + set { + this.payerNameField = value; + } + } + + /// + public CountryCodeType PayerCountry { + get { + return this.payerCountryField; + } + set { + this.payerCountryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PayerCountrySpecified { + get { + return this.payerCountryFieldSpecified; + } + set { + this.payerCountryFieldSpecified = value; + } + } + + /// + public string PayerBusiness { + get { + return this.payerBusinessField; + } + set { + this.payerBusinessField = value; + } + } + + /// + public AddressType Address { + get { + return this.addressField; + } + set { + this.addressField = value; + } + } + + /// + public string ContactPhone { + get { + return this.contactPhoneField; + } + set { + this.contactPhoneField = value; + } + } + + /// + public TaxIdDetailsType TaxIdDetails { + get { + return this.taxIdDetailsField; + } + set { + this.taxIdDetailsField = value; + } + } + + /// + public EnhancedPayerInfoType EnhancedPayerInfo { + get { + return this.enhancedPayerInfoField; + } + set { + this.enhancedPayerInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PayPalUserStatusCodeType { + + /// + verified, + + /// + unverified, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PersonNameType { + + private string salutationField; + + private string firstNameField; + + private string middleNameField; + + private string lastNameField; + + private string suffixField; + + /// + public string Salutation { + get { + return this.salutationField; + } + set { + this.salutationField = value; + } + } + + /// + public string FirstName { + get { + return this.firstNameField; + } + set { + this.firstNameField = value; + } + } + + /// + public string MiddleName { + get { + return this.middleNameField; + } + set { + this.middleNameField = value; + } + } + + /// + public string LastName { + get { + return this.lastNameField; + } + set { + this.lastNameField = value; + } + } + + /// + public string Suffix { + get { + return this.suffixField; + } + set { + this.suffixField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class TaxIdDetailsType { + + private string taxIdTypeField; + + private string taxIdField; + + /// + public string TaxIdType { + get { + return this.taxIdTypeField; + } + set { + this.taxIdTypeField = value; + } + } + + /// + public string TaxId { + get { + return this.taxIdField; + } + set { + this.taxIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedPayerInfoType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ThreeDSecureRequestType { + + private string eci3dsField; + + private string cavvField; + + private string xidField; + + private string mpiVendor3dsField; + + private string authStatus3dsField; + + /// + public string Eci3ds { + get { + return this.eci3dsField; + } + set { + this.eci3dsField = value; + } + } + + /// + public string Cavv { + get { + return this.cavvField; + } + set { + this.cavvField = value; + } + } + + /// + public string Xid { + get { + return this.xidField; + } + set { + this.xidField = value; + } + } + + /// + public string MpiVendor3ds { + get { + return this.mpiVendor3dsField; + } + set { + this.mpiVendor3dsField = value; + } + } + + /// + public string AuthStatus3ds { + get { + return this.authStatus3dsField; + } + set { + this.authStatus3dsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class CreateRecurringPaymentsProfileResponseDetailsType { + + private string profileIDField; + + private RecurringPaymentsProfileStatusType profileStatusField; + + private bool profileStatusFieldSpecified; + + private string transactionIDField; + + private string dCCProcessorResponseField; + + private string dCCReturnCodeField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + + /// + public RecurringPaymentsProfileStatusType ProfileStatus { + get { + return this.profileStatusField; + } + set { + this.profileStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProfileStatusSpecified { + get { + return this.profileStatusFieldSpecified; + } + set { + this.profileStatusFieldSpecified = value; + } + } + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public string DCCProcessorResponse { + get { + return this.dCCProcessorResponseField; + } + set { + this.dCCProcessorResponseField = value; + } + } + + /// + public string DCCReturnCode { + get { + return this.dCCReturnCodeField; + } + set { + this.dCCReturnCodeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoNonReferencedCreditResponseDetailsType { + + private BasicAmountType amountField; + + private string transactionIDField; + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoReferenceTransactionResponseDetailsType { + + private string billingAgreementIDField; + + private PaymentInfoType paymentInfoField; + + private BasicAmountType amountField; + + private string aVSCodeField; + + private string cVV2CodeField; + + private string transactionIDField; + + private string paymentAdviceCodeField; + + private string msgSubIDField; + + /// + public string BillingAgreementID { + get { + return this.billingAgreementIDField; + } + set { + this.billingAgreementIDField = value; + } + } + + /// + public PaymentInfoType PaymentInfo { + get { + return this.paymentInfoField; + } + set { + this.paymentInfoField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string AVSCode { + get { + return this.aVSCodeField; + } + set { + this.aVSCodeField = value; + } + } + + /// + public string CVV2Code { + get { + return this.cVV2CodeField; + } + set { + this.cVV2CodeField = value; + } + } + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public string PaymentAdviceCode { + get { + return this.paymentAdviceCodeField; + } + set { + this.paymentAdviceCodeField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentInfoType { + + private string transactionIDField; + + private string ebayTransactionIDField; + + private string parentTransactionIDField; + + private string receiptIDField; + + private PaymentTransactionCodeType transactionTypeField; + + private PaymentCodeType paymentTypeField; + + private bool paymentTypeFieldSpecified; + + private RefundSourceCodeType refundSourceCodeTypeField; + + private bool refundSourceCodeTypeFieldSpecified; + + private System.DateTime expectedeCheckClearDateField; + + private System.DateTime paymentDateField; + + private BasicAmountType grossAmountField; + + private BasicAmountType feeAmountField; + + private BasicAmountType settleAmountField; + + private BasicAmountType taxAmountField; + + private string exchangeRateField; + + private PaymentStatusCodeType paymentStatusField; + + private PendingStatusCodeType pendingReasonField; + + private bool pendingReasonFieldSpecified; + + private ReversalReasonCodeType reasonCodeField; + + private bool reasonCodeFieldSpecified; + + private string holdDecisionField; + + private string shippingMethodField; + + private string protectionEligibilityField; + + private string protectionEligibilityTypeField; + + private string receiptReferenceNumberField; + + private POSTransactionCodeType pOSTransactionTypeField; + + private bool pOSTransactionTypeFieldSpecified; + + private string shipAmountField; + + private string shipHandleAmountField; + + private string shipDiscountField; + + private string insuranceAmountField; + + private string subjectField; + + private string storeIDField; + + private string terminalIDField; + + private SellerDetailsType sellerDetailsField; + + private string paymentRequestIDField; + + private FMFDetailsType fMFDetailsField; + + private EnhancedPaymentInfoType enhancedPaymentInfoField; + + private ErrorType paymentErrorField; + + private InstrumentDetailsType instrumentDetailsField; + + private OfferDetailsType offerDetailsField; + + private string binEligibilityField; + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public string EbayTransactionID { + get { + return this.ebayTransactionIDField; + } + set { + this.ebayTransactionIDField = value; + } + } + + /// + public string ParentTransactionID { + get { + return this.parentTransactionIDField; + } + set { + this.parentTransactionIDField = value; + } + } + + /// + public string ReceiptID { + get { + return this.receiptIDField; + } + set { + this.receiptIDField = value; + } + } + + /// + public PaymentTransactionCodeType TransactionType { + get { + return this.transactionTypeField; + } + set { + this.transactionTypeField = value; + } + } + + /// + public PaymentCodeType PaymentType { + get { + return this.paymentTypeField; + } + set { + this.paymentTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentTypeSpecified { + get { + return this.paymentTypeFieldSpecified; + } + set { + this.paymentTypeFieldSpecified = value; + } + } + + /// + public RefundSourceCodeType RefundSourceCodeType { + get { + return this.refundSourceCodeTypeField; + } + set { + this.refundSourceCodeTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RefundSourceCodeTypeSpecified { + get { + return this.refundSourceCodeTypeFieldSpecified; + } + set { + this.refundSourceCodeTypeFieldSpecified = value; + } + } + + /// + public System.DateTime ExpectedeCheckClearDate { + get { + return this.expectedeCheckClearDateField; + } + set { + this.expectedeCheckClearDateField = value; + } + } + + /// + public System.DateTime PaymentDate { + get { + return this.paymentDateField; + } + set { + this.paymentDateField = value; + } + } + + /// + public BasicAmountType GrossAmount { + get { + return this.grossAmountField; + } + set { + this.grossAmountField = value; + } + } + + /// + public BasicAmountType FeeAmount { + get { + return this.feeAmountField; + } + set { + this.feeAmountField = value; + } + } + + /// + public BasicAmountType SettleAmount { + get { + return this.settleAmountField; + } + set { + this.settleAmountField = value; + } + } + + /// + public BasicAmountType TaxAmount { + get { + return this.taxAmountField; + } + set { + this.taxAmountField = value; + } + } + + /// + public string ExchangeRate { + get { + return this.exchangeRateField; + } + set { + this.exchangeRateField = value; + } + } + + /// + public PaymentStatusCodeType PaymentStatus { + get { + return this.paymentStatusField; + } + set { + this.paymentStatusField = value; + } + } + + /// + public PendingStatusCodeType PendingReason { + get { + return this.pendingReasonField; + } + set { + this.pendingReasonField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PendingReasonSpecified { + get { + return this.pendingReasonFieldSpecified; + } + set { + this.pendingReasonFieldSpecified = value; + } + } + + /// + public ReversalReasonCodeType ReasonCode { + get { + return this.reasonCodeField; + } + set { + this.reasonCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReasonCodeSpecified { + get { + return this.reasonCodeFieldSpecified; + } + set { + this.reasonCodeFieldSpecified = value; + } + } + + /// + public string HoldDecision { + get { + return this.holdDecisionField; + } + set { + this.holdDecisionField = value; + } + } + + /// + public string ShippingMethod { + get { + return this.shippingMethodField; + } + set { + this.shippingMethodField = value; + } + } + + /// + public string ProtectionEligibility { + get { + return this.protectionEligibilityField; + } + set { + this.protectionEligibilityField = value; + } + } + + /// + public string ProtectionEligibilityType { + get { + return this.protectionEligibilityTypeField; + } + set { + this.protectionEligibilityTypeField = value; + } + } + + /// + public string ReceiptReferenceNumber { + get { + return this.receiptReferenceNumberField; + } + set { + this.receiptReferenceNumberField = value; + } + } + + /// + public POSTransactionCodeType POSTransactionType { + get { + return this.pOSTransactionTypeField; + } + set { + this.pOSTransactionTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool POSTransactionTypeSpecified { + get { + return this.pOSTransactionTypeFieldSpecified; + } + set { + this.pOSTransactionTypeFieldSpecified = value; + } + } + + /// + public string ShipAmount { + get { + return this.shipAmountField; + } + set { + this.shipAmountField = value; + } + } + + /// + public string ShipHandleAmount { + get { + return this.shipHandleAmountField; + } + set { + this.shipHandleAmountField = value; + } + } + + /// + public string ShipDiscount { + get { + return this.shipDiscountField; + } + set { + this.shipDiscountField = value; + } + } + + /// + public string InsuranceAmount { + get { + return this.insuranceAmountField; + } + set { + this.insuranceAmountField = value; + } + } + + /// + public string Subject { + get { + return this.subjectField; + } + set { + this.subjectField = value; + } + } + + /// + public string StoreID { + get { + return this.storeIDField; + } + set { + this.storeIDField = value; + } + } + + /// + public string TerminalID { + get { + return this.terminalIDField; + } + set { + this.terminalIDField = value; + } + } + + /// + public SellerDetailsType SellerDetails { + get { + return this.sellerDetailsField; + } + set { + this.sellerDetailsField = value; + } + } + + /// + public string PaymentRequestID { + get { + return this.paymentRequestIDField; + } + set { + this.paymentRequestIDField = value; + } + } + + /// + public FMFDetailsType FMFDetails { + get { + return this.fMFDetailsField; + } + set { + this.fMFDetailsField = value; + } + } + + /// + public EnhancedPaymentInfoType EnhancedPaymentInfo { + get { + return this.enhancedPaymentInfoField; + } + set { + this.enhancedPaymentInfoField = value; + } + } + + /// + public ErrorType PaymentError { + get { + return this.paymentErrorField; + } + set { + this.paymentErrorField = value; + } + } + + /// + public InstrumentDetailsType InstrumentDetails { + get { + return this.instrumentDetailsField; + } + set { + this.instrumentDetailsField = value; + } + } + + /// + public OfferDetailsType OfferDetails { + get { + return this.offerDetailsField; + } + set { + this.offerDetailsField = value; + } + } + + /// + public string BinEligibility { + get { + return this.binEligibilityField; + } + set { + this.binEligibilityField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentTransactionCodeType { + + /// + none, + + /// + [System.Xml.Serialization.XmlEnumAttribute("web-accept")] + webaccept, + + /// + cart, + + /// + [System.Xml.Serialization.XmlEnumAttribute("send-money")] + sendmoney, + + /// + [System.Xml.Serialization.XmlEnumAttribute("subscr-failed")] + subscrfailed, + + /// + [System.Xml.Serialization.XmlEnumAttribute("subscr-cancel")] + subscrcancel, + + /// + [System.Xml.Serialization.XmlEnumAttribute("subscr-payment")] + subscrpayment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("subscr-signup")] + subscrsignup, + + /// + [System.Xml.Serialization.XmlEnumAttribute("subscr-eot")] + subscreot, + + /// + [System.Xml.Serialization.XmlEnumAttribute("subscr-modify")] + subscrmodify, + + /// + [System.Xml.Serialization.XmlEnumAttribute("mercht-pmt")] + merchtpmt, + + /// + [System.Xml.Serialization.XmlEnumAttribute("mass-pay")] + masspay, + + /// + [System.Xml.Serialization.XmlEnumAttribute("virtual-terminal")] + virtualterminal, + + /// + [System.Xml.Serialization.XmlEnumAttribute("integral-evolution")] + integralevolution, + + /// + [System.Xml.Serialization.XmlEnumAttribute("express-checkout")] + expresscheckout, + + /// + [System.Xml.Serialization.XmlEnumAttribute("pro-hosted")] + prohosted, + + /// + [System.Xml.Serialization.XmlEnumAttribute("pro-api")] + proapi, + + /// + credit, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentCodeType { + + /// + none, + + /// + echeck, + + /// + instant, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum RefundSourceCodeType { + + /// + any, + + /// + @default, + + /// + instant, + + /// + echeck, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentStatusCodeType { + + /// + None, + + /// + Completed, + + /// + Failed, + + /// + Pending, + + /// + Denied, + + /// + Refunded, + + /// + Reversed, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Canceled-Reversal")] + CanceledReversal, + + /// + Processed, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Partially-Refunded")] + PartiallyRefunded, + + /// + Voided, + + /// + Expired, + + /// + [System.Xml.Serialization.XmlEnumAttribute("In-Progress")] + InProgress, + + /// + Created, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Completed-Funds-Held")] + CompletedFundsHeld, + + /// + Instant, + + /// + Delayed, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PendingStatusCodeType { + + /// + none, + + /// + echeck, + + /// + intl, + + /// + verify, + + /// + address, + + /// + unilateral, + + /// + other, + + /// + upgrade, + + /// + [System.Xml.Serialization.XmlEnumAttribute("multi-currency")] + multicurrency, + + /// + authorization, + + /// + order, + + /// + [System.Xml.Serialization.XmlEnumAttribute("payment-review")] + paymentreview, + + /// + [System.Xml.Serialization.XmlEnumAttribute("regulatory-review")] + regulatoryreview, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ReversalReasonCodeType { + + /// + none, + + /// + chargeback, + + /// + guarantee, + + /// + [System.Xml.Serialization.XmlEnumAttribute("buyer-complaint")] + buyercomplaint, + + /// + refund, + + /// + other, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum POSTransactionCodeType { + + /// + F, + + /// + S, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SellerDetailsType { + + private string sellerIdField; + + private string sellerUserNameField; + + private System.DateTime sellerRegistrationDateField; + + private bool sellerRegistrationDateFieldSpecified; + + private string payPalAccountIDField; + + private string secureMerchantAccountIDField; + + /// + public string SellerId { + get { + return this.sellerIdField; + } + set { + this.sellerIdField = value; + } + } + + /// + public string SellerUserName { + get { + return this.sellerUserNameField; + } + set { + this.sellerUserNameField = value; + } + } + + /// + public System.DateTime SellerRegistrationDate { + get { + return this.sellerRegistrationDateField; + } + set { + this.sellerRegistrationDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SellerRegistrationDateSpecified { + get { + return this.sellerRegistrationDateFieldSpecified; + } + set { + this.sellerRegistrationDateFieldSpecified = value; + } + } + + /// + public string PayPalAccountID { + get { + return this.payPalAccountIDField; + } + set { + this.payPalAccountIDField = value; + } + } + + /// + public string SecureMerchantAccountID { + get { + return this.secureMerchantAccountIDField; + } + set { + this.secureMerchantAccountIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class FMFDetailsType { + + private RiskFilterDetailsType[] acceptFiltersField; + + private RiskFilterDetailsType[] pendingFiltersField; + + private RiskFilterDetailsType[] denyFiltersField; + + private RiskFilterDetailsType[] reportFiltersField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Filters", IsNullable=false)] + public RiskFilterDetailsType[] AcceptFilters { + get { + return this.acceptFiltersField; + } + set { + this.acceptFiltersField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Filters", IsNullable=false)] + public RiskFilterDetailsType[] PendingFilters { + get { + return this.pendingFiltersField; + } + set { + this.pendingFiltersField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Filters", IsNullable=false)] + public RiskFilterDetailsType[] DenyFilters { + get { + return this.denyFiltersField; + } + set { + this.denyFiltersField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Filters", IsNullable=false)] + public RiskFilterDetailsType[] ReportFilters { + get { + return this.reportFiltersField; + } + set { + this.reportFiltersField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class RiskFilterDetailsType { + + private int idField; + + private string nameField; + + private string descriptionField; + + /// + public int Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedPaymentInfoType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ErrorType { + + private string shortMessageField; + + private string longMessageField; + + private string errorCodeField; + + private SeverityCodeType severityCodeField; + + private ErrorParameterType[] errorParametersField; + + /// + public string ShortMessage { + get { + return this.shortMessageField; + } + set { + this.shortMessageField = value; + } + } + + /// + public string LongMessage { + get { + return this.longMessageField; + } + set { + this.longMessageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string ErrorCode { + get { + return this.errorCodeField; + } + set { + this.errorCodeField = value; + } + } + + /// + public SeverityCodeType SeverityCode { + get { + return this.severityCodeField; + } + set { + this.severityCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ErrorParameters")] + public ErrorParameterType[] ErrorParameters { + get { + return this.errorParametersField; + } + set { + this.errorParametersField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum SeverityCodeType { + + /// + Warning, + + /// + Error, + + /// + PartialSuccess, + + /// + CustomCode, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ErrorParameterType { + + private string valueField; + + private string paramIDField; + + /// + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string ParamID { + get { + return this.paramIDField; + } + set { + this.paramIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class InstrumentDetailsType { + + private string instrumentCategoryField; + + private string instrumentIDField; + + /// + public string InstrumentCategory { + get { + return this.instrumentCategoryField; + } + set { + this.instrumentCategoryField = value; + } + } + + /// + public string InstrumentID { + get { + return this.instrumentIDField; + } + set { + this.instrumentIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class OfferDetailsType { + + private string offerCodeField; + + private BMLOfferInfoType bMLOfferInfoField; + + /// + public string OfferCode { + get { + return this.offerCodeField; + } + set { + this.offerCodeField = value; + } + } + + /// + public BMLOfferInfoType BMLOfferInfo { + get { + return this.bMLOfferInfoField; + } + set { + this.bMLOfferInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BMLOfferInfoType { + + private string offerTrackingIDField; + + /// + public string OfferTrackingID { + get { + return this.offerTrackingIDField; + } + set { + this.offerTrackingIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetBillingAgreementCustomerDetailsResponseDetailsType { + + private PayerInfoType payerInfoField; + + private AddressType billingAddressField; + + /// + public PayerInfoType PayerInfo { + get { + return this.payerInfoField; + } + set { + this.payerInfoField = value; + } + } + + /// + public AddressType BillingAddress { + get { + return this.billingAddressField; + } + set { + this.billingAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoMobileCheckoutPaymentResponseDetailsType { + + private string customField; + + private string invoiceIDField; + + private PayerInfoType payerInfoField; + + private PaymentInfoType paymentInfoField; + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public PayerInfoType PayerInfo { + get { + return this.payerInfoField; + } + set { + this.payerInfoField = value; + } + } + + /// + public PaymentInfoType PaymentInfo { + get { + return this.paymentInfoField; + } + set { + this.paymentInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class AuthorizationInfoType { + + private PaymentStatusCodeType paymentStatusField; + + private PendingStatusCodeType pendingReasonField; + + private bool pendingReasonFieldSpecified; + + private string protectionEligibilityField; + + private string protectionEligibilityTypeField; + + /// + public PaymentStatusCodeType PaymentStatus { + get { + return this.paymentStatusField; + } + set { + this.paymentStatusField = value; + } + } + + /// + public PendingStatusCodeType PendingReason { + get { + return this.pendingReasonField; + } + set { + this.pendingReasonField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PendingReasonSpecified { + get { + return this.pendingReasonFieldSpecified; + } + set { + this.pendingReasonFieldSpecified = value; + } + } + + /// + public string ProtectionEligibility { + get { + return this.protectionEligibilityField; + } + set { + this.protectionEligibilityField = value; + } + } + + /// + public string ProtectionEligibilityType { + get { + return this.protectionEligibilityTypeField; + } + set { + this.protectionEligibilityTypeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoCaptureResponseDetailsType { + + private string authorizationIDField; + + private PaymentInfoType paymentInfoField; + + private string msgSubIDField; + + private string partnerFundingSourceIDField; + + /// + public string AuthorizationID { + get { + return this.authorizationIDField; + } + set { + this.authorizationIDField = value; + } + } + + /// + public PaymentInfoType PaymentInfo { + get { + return this.paymentInfoField; + } + set { + this.paymentInfoField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + + /// + public string PartnerFundingSourceID { + get { + return this.partnerFundingSourceIDField; + } + set { + this.partnerFundingSourceIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class CoupledPaymentInfoType { + + private string coupledPaymentRequestIDField; + + private string coupledPaymentIDField; + + /// + public string CoupledPaymentRequestID { + get { + return this.coupledPaymentRequestIDField; + } + set { + this.coupledPaymentRequestIDField = value; + } + } + + /// + public string CoupledPaymentID { + get { + return this.coupledPaymentIDField; + } + set { + this.coupledPaymentIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoExpressCheckoutPaymentResponseDetailsType { + + private string tokenField; + + private PaymentInfoType[] paymentInfoField; + + private string billingAgreementIDField; + + private string redirectRequiredField; + + private string noteField; + + private string successPageRedirectRequestedField; + + private UserSelectedOptionType userSelectedOptionsField; + + private CoupledPaymentInfoType[] coupledPaymentInfoField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentInfo")] + public PaymentInfoType[] PaymentInfo { + get { + return this.paymentInfoField; + } + set { + this.paymentInfoField = value; + } + } + + /// + public string BillingAgreementID { + get { + return this.billingAgreementIDField; + } + set { + this.billingAgreementIDField = value; + } + } + + /// + public string RedirectRequired { + get { + return this.redirectRequiredField; + } + set { + this.redirectRequiredField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + + /// + public string SuccessPageRedirectRequested { + get { + return this.successPageRedirectRequestedField; + } + set { + this.successPageRedirectRequestedField = value; + } + } + + /// + public UserSelectedOptionType UserSelectedOptions { + get { + return this.userSelectedOptionsField; + } + set { + this.userSelectedOptionsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("CoupledPaymentInfo")] + public CoupledPaymentInfoType[] CoupledPaymentInfo { + get { + return this.coupledPaymentInfoField; + } + set { + this.coupledPaymentInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class UserSelectedOptionType { + + private string shippingCalculationModeField; + + private string insuranceOptionSelectedField; + + private string shippingOptionIsDefaultField; + + private BasicAmountType shippingOptionAmountField; + + private string shippingOptionNameField; + + /// + public string ShippingCalculationMode { + get { + return this.shippingCalculationModeField; + } + set { + this.shippingCalculationModeField = value; + } + } + + /// + public string InsuranceOptionSelected { + get { + return this.insuranceOptionSelectedField; + } + set { + this.insuranceOptionSelectedField = value; + } + } + + /// + public string ShippingOptionIsDefault { + get { + return this.shippingOptionIsDefaultField; + } + set { + this.shippingOptionIsDefaultField = value; + } + } + + /// + public BasicAmountType ShippingOptionAmount { + get { + return this.shippingOptionAmountField; + } + set { + this.shippingOptionAmountField = value; + } + } + + /// + public string ShippingOptionName { + get { + return this.shippingOptionNameField; + } + set { + this.shippingOptionNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class RefreshTokenStatusDetailsType { + + private string refreshTokenStatusField; + + private string refreshTokenField; + + private string immutableIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string RefreshTokenStatus { + get { + return this.refreshTokenStatusField; + } + set { + this.refreshTokenStatusField = value; + } + } + + /// + public string RefreshToken { + get { + return this.refreshTokenField; + } + set { + this.refreshTokenField = value; + } + } + + /// + public string ImmutableID { + get { + return this.immutableIDField; + } + set { + this.immutableIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ExternalRememberMeStatusDetailsType { + + private string externalRememberMeStatusField; + + private string externalRememberMeIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string ExternalRememberMeStatus { + get { + return this.externalRememberMeStatusField; + } + set { + this.externalRememberMeStatusField = value; + } + } + + /// + public string ExternalRememberMeID { + get { + return this.externalRememberMeIDField; + } + set { + this.externalRememberMeIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentRequestInfoType { + + private string transactionIdField; + + private string paymentRequestIDField; + + private ErrorType paymentErrorField; + + /// + public string TransactionId { + get { + return this.transactionIdField; + } + set { + this.transactionIdField = value; + } + } + + /// + public string PaymentRequestID { + get { + return this.paymentRequestIDField; + } + set { + this.paymentRequestIDField = value; + } + } + + /// + public ErrorType PaymentError { + get { + return this.paymentErrorField; + } + set { + this.paymentErrorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveAppliedDetailsType { + + private string paymentRequestIDField; + + private string itemIdField; + + private string externalTxnIdField; + + private BasicAmountType discountAmountField; + + private string subTypeField; + + /// + public string PaymentRequestID { + get { + return this.paymentRequestIDField; + } + set { + this.paymentRequestIDField = value; + } + } + + /// + public string ItemId { + get { + return this.itemIdField; + } + set { + this.itemIdField = value; + } + } + + /// + public string ExternalTxnId { + get { + return this.externalTxnIdField; + } + set { + this.externalTxnIdField = value; + } + } + + /// + public BasicAmountType DiscountAmount { + get { + return this.discountAmountField; + } + set { + this.discountAmountField = value; + } + } + + /// + public string SubType { + get { + return this.subTypeField; + } + set { + this.subTypeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveDetailsType { + + private string uniqueIdentifierField; + + private IncentiveSiteAppliedOnType siteAppliedOnField; + + private bool siteAppliedOnFieldSpecified; + + private BasicAmountType totalDiscountAmountField; + + private IncentiveAppliedStatusType statusField; + + private bool statusFieldSpecified; + + private string errorCodeField; + + private IncentiveAppliedDetailsType[] incentiveAppliedDetailsField; + + /// + public string UniqueIdentifier { + get { + return this.uniqueIdentifierField; + } + set { + this.uniqueIdentifierField = value; + } + } + + /// + public IncentiveSiteAppliedOnType SiteAppliedOn { + get { + return this.siteAppliedOnField; + } + set { + this.siteAppliedOnField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SiteAppliedOnSpecified { + get { + return this.siteAppliedOnFieldSpecified; + } + set { + this.siteAppliedOnFieldSpecified = value; + } + } + + /// + public BasicAmountType TotalDiscountAmount { + get { + return this.totalDiscountAmountField; + } + set { + this.totalDiscountAmountField = value; + } + } + + /// + public IncentiveAppliedStatusType Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StatusSpecified { + get { + return this.statusFieldSpecified; + } + set { + this.statusFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string ErrorCode { + get { + return this.errorCodeField; + } + set { + this.errorCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("IncentiveAppliedDetails")] + public IncentiveAppliedDetailsType[] IncentiveAppliedDetails { + get { + return this.incentiveAppliedDetailsField; + } + set { + this.incentiveAppliedDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum IncentiveSiteAppliedOnType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("INCENTIVE-SITE-APPLIED-ON-UNKNOWN")] + INCENTIVESITEAPPLIEDONUNKNOWN, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INCENTIVE-SITE-APPLIED-ON-MERCHANT")] + INCENTIVESITEAPPLIEDONMERCHANT, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INCENTIVE-SITE-APPLIED-ON-PAYPAL")] + INCENTIVESITEAPPLIEDONPAYPAL, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum IncentiveAppliedStatusType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("INCENTIVE-APPLIED-STATUS-SUCCESS")] + INCENTIVEAPPLIEDSTATUSSUCCESS, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INCENTIVE-APPLIED-STATUS-ERROR")] + INCENTIVEAPPLIEDSTATUSERROR, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetExpressCheckoutDetailsResponseDetailsType { + + private string tokenField; + + private PayerInfoType payerInfoField; + + private string customField; + + private string invoiceIDField; + + private string contactPhoneField; + + private bool billingAgreementAcceptedStatusField; + + private bool billingAgreementAcceptedStatusFieldSpecified; + + private string redirectRequiredField; + + private AddressType billingAddressField; + + private string noteField; + + private string checkoutStatusField; + + private BasicAmountType payPalAdjustmentField; + + private PaymentDetailsType[] paymentDetailsField; + + private UserSelectedOptionType userSelectedOptionsField; + + private IncentiveDetailsType[] incentiveDetailsField; + + private string giftMessageField; + + private string giftReceiptEnableField; + + private string giftWrapNameField; + + private BasicAmountType giftWrapAmountField; + + private string buyerMarketingEmailField; + + private string surveyQuestionField; + + private string[] surveyChoiceSelectedField; + + private PaymentRequestInfoType[] paymentRequestInfoField; + + private ExternalRememberMeStatusDetailsType externalRememberMeStatusDetailsField; + + private RefreshTokenStatusDetailsType refreshTokenStatusDetailsField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + + /// + public PayerInfoType PayerInfo { + get { + return this.payerInfoField; + } + set { + this.payerInfoField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public string ContactPhone { + get { + return this.contactPhoneField; + } + set { + this.contactPhoneField = value; + } + } + + /// + public bool BillingAgreementAcceptedStatus { + get { + return this.billingAgreementAcceptedStatusField; + } + set { + this.billingAgreementAcceptedStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BillingAgreementAcceptedStatusSpecified { + get { + return this.billingAgreementAcceptedStatusFieldSpecified; + } + set { + this.billingAgreementAcceptedStatusFieldSpecified = value; + } + } + + /// + public string RedirectRequired { + get { + return this.redirectRequiredField; + } + set { + this.redirectRequiredField = value; + } + } + + /// + public AddressType BillingAddress { + get { + return this.billingAddressField; + } + set { + this.billingAddressField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + + /// + public string CheckoutStatus { + get { + return this.checkoutStatusField; + } + set { + this.checkoutStatusField = value; + } + } + + /// + public BasicAmountType PayPalAdjustment { + get { + return this.payPalAdjustmentField; + } + set { + this.payPalAdjustmentField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentDetails")] + public PaymentDetailsType[] PaymentDetails { + get { + return this.paymentDetailsField; + } + set { + this.paymentDetailsField = value; + } + } + + /// + public UserSelectedOptionType UserSelectedOptions { + get { + return this.userSelectedOptionsField; + } + set { + this.userSelectedOptionsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("IncentiveDetails")] + public IncentiveDetailsType[] IncentiveDetails { + get { + return this.incentiveDetailsField; + } + set { + this.incentiveDetailsField = value; + } + } + + /// + public string GiftMessage { + get { + return this.giftMessageField; + } + set { + this.giftMessageField = value; + } + } + + /// + public string GiftReceiptEnable { + get { + return this.giftReceiptEnableField; + } + set { + this.giftReceiptEnableField = value; + } + } + + /// + public string GiftWrapName { + get { + return this.giftWrapNameField; + } + set { + this.giftWrapNameField = value; + } + } + + /// + public BasicAmountType GiftWrapAmount { + get { + return this.giftWrapAmountField; + } + set { + this.giftWrapAmountField = value; + } + } + + /// + public string BuyerMarketingEmail { + get { + return this.buyerMarketingEmailField; + } + set { + this.buyerMarketingEmailField = value; + } + } + + /// + public string SurveyQuestion { + get { + return this.surveyQuestionField; + } + set { + this.surveyQuestionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("SurveyChoiceSelected")] + public string[] SurveyChoiceSelected { + get { + return this.surveyChoiceSelectedField; + } + set { + this.surveyChoiceSelectedField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentRequestInfo")] + public PaymentRequestInfoType[] PaymentRequestInfo { + get { + return this.paymentRequestInfoField; + } + set { + this.paymentRequestInfoField = value; + } + } + + /// + public ExternalRememberMeStatusDetailsType ExternalRememberMeStatusDetails { + get { + return this.externalRememberMeStatusDetailsField; + } + set { + this.externalRememberMeStatusDetailsField = value; + } + } + + /// + public RefreshTokenStatusDetailsType RefreshTokenStatusDetails { + get { + return this.refreshTokenStatusDetailsField; + } + set { + this.refreshTokenStatusDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentDetailsType { + + private BasicAmountType orderTotalField; + + private BasicAmountType itemTotalField; + + private BasicAmountType shippingTotalField; + + private BasicAmountType handlingTotalField; + + private BasicAmountType taxTotalField; + + private string orderDescriptionField; + + private string customField; + + private string invoiceIDField; + + private string buttonSourceField; + + private string notifyURLField; + + private AddressType shipToAddressField; + + private string multiShippingField; + + private string fulfillmentReferenceNumberField; + + private AddressType fulfillmentAddressField; + + private PaymentCategoryType paymentCategoryTypeField; + + private bool paymentCategoryTypeFieldSpecified; + + private ShippingServiceCodeType shippingMethodField; + + private bool shippingMethodFieldSpecified; + + private System.DateTime profileAddressChangeDateField; + + private bool profileAddressChangeDateFieldSpecified; + + private PaymentDetailsItemType[] paymentDetailsItemField; + + private BasicAmountType insuranceTotalField; + + private BasicAmountType shippingDiscountField; + + private string insuranceOptionOfferedField; + + private AllowedPaymentMethodType allowedPaymentMethodField; + + private bool allowedPaymentMethodFieldSpecified; + + private EnhancedPaymentDataType enhancedPaymentDataField; + + private SellerDetailsType sellerDetailsField; + + private string noteTextField; + + private string transactionIdField; + + private PaymentActionCodeType paymentActionField; + + private bool paymentActionFieldSpecified; + + private string paymentRequestIDField; + + private string orderURLField; + + private string softDescriptorField; + + private string branchLevelField; + + private OfferDetailsType offerDetailsField; + + private RecurringFlagType recurringField; + + private bool recurringFieldSpecified; + + private PaymentReasonType paymentReasonField; + + private bool paymentReasonFieldSpecified; + + /// + public BasicAmountType OrderTotal { + get { + return this.orderTotalField; + } + set { + this.orderTotalField = value; + } + } + + /// + public BasicAmountType ItemTotal { + get { + return this.itemTotalField; + } + set { + this.itemTotalField = value; + } + } + + /// + public BasicAmountType ShippingTotal { + get { + return this.shippingTotalField; + } + set { + this.shippingTotalField = value; + } + } + + /// + public BasicAmountType HandlingTotal { + get { + return this.handlingTotalField; + } + set { + this.handlingTotalField = value; + } + } + + /// + public BasicAmountType TaxTotal { + get { + return this.taxTotalField; + } + set { + this.taxTotalField = value; + } + } + + /// + public string OrderDescription { + get { + return this.orderDescriptionField; + } + set { + this.orderDescriptionField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public string ButtonSource { + get { + return this.buttonSourceField; + } + set { + this.buttonSourceField = value; + } + } + + /// + public string NotifyURL { + get { + return this.notifyURLField; + } + set { + this.notifyURLField = value; + } + } + + /// + public AddressType ShipToAddress { + get { + return this.shipToAddressField; + } + set { + this.shipToAddressField = value; + } + } + + /// + public string MultiShipping { + get { + return this.multiShippingField; + } + set { + this.multiShippingField = value; + } + } + + /// + public string FulfillmentReferenceNumber { + get { + return this.fulfillmentReferenceNumberField; + } + set { + this.fulfillmentReferenceNumberField = value; + } + } + + /// + public AddressType FulfillmentAddress { + get { + return this.fulfillmentAddressField; + } + set { + this.fulfillmentAddressField = value; + } + } + + /// + public PaymentCategoryType PaymentCategoryType { + get { + return this.paymentCategoryTypeField; + } + set { + this.paymentCategoryTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentCategoryTypeSpecified { + get { + return this.paymentCategoryTypeFieldSpecified; + } + set { + this.paymentCategoryTypeFieldSpecified = value; + } + } + + /// + public ShippingServiceCodeType ShippingMethod { + get { + return this.shippingMethodField; + } + set { + this.shippingMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ShippingMethodSpecified { + get { + return this.shippingMethodFieldSpecified; + } + set { + this.shippingMethodFieldSpecified = value; + } + } + + /// + public System.DateTime ProfileAddressChangeDate { + get { + return this.profileAddressChangeDateField; + } + set { + this.profileAddressChangeDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProfileAddressChangeDateSpecified { + get { + return this.profileAddressChangeDateFieldSpecified; + } + set { + this.profileAddressChangeDateFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentDetailsItem")] + public PaymentDetailsItemType[] PaymentDetailsItem { + get { + return this.paymentDetailsItemField; + } + set { + this.paymentDetailsItemField = value; + } + } + + /// + public BasicAmountType InsuranceTotal { + get { + return this.insuranceTotalField; + } + set { + this.insuranceTotalField = value; + } + } + + /// + public BasicAmountType ShippingDiscount { + get { + return this.shippingDiscountField; + } + set { + this.shippingDiscountField = value; + } + } + + /// + public string InsuranceOptionOffered { + get { + return this.insuranceOptionOfferedField; + } + set { + this.insuranceOptionOfferedField = value; + } + } + + /// + public AllowedPaymentMethodType AllowedPaymentMethod { + get { + return this.allowedPaymentMethodField; + } + set { + this.allowedPaymentMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AllowedPaymentMethodSpecified { + get { + return this.allowedPaymentMethodFieldSpecified; + } + set { + this.allowedPaymentMethodFieldSpecified = value; + } + } + + /// + public EnhancedPaymentDataType EnhancedPaymentData { + get { + return this.enhancedPaymentDataField; + } + set { + this.enhancedPaymentDataField = value; + } + } + + /// + public SellerDetailsType SellerDetails { + get { + return this.sellerDetailsField; + } + set { + this.sellerDetailsField = value; + } + } + + /// + public string NoteText { + get { + return this.noteTextField; + } + set { + this.noteTextField = value; + } + } + + /// + public string TransactionId { + get { + return this.transactionIdField; + } + set { + this.transactionIdField = value; + } + } + + /// + public PaymentActionCodeType PaymentAction { + get { + return this.paymentActionField; + } + set { + this.paymentActionField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentActionSpecified { + get { + return this.paymentActionFieldSpecified; + } + set { + this.paymentActionFieldSpecified = value; + } + } + + /// + public string PaymentRequestID { + get { + return this.paymentRequestIDField; + } + set { + this.paymentRequestIDField = value; + } + } + + /// + public string OrderURL { + get { + return this.orderURLField; + } + set { + this.orderURLField = value; + } + } + + /// + public string SoftDescriptor { + get { + return this.softDescriptorField; + } + set { + this.softDescriptorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string BranchLevel { + get { + return this.branchLevelField; + } + set { + this.branchLevelField = value; + } + } + + /// + public OfferDetailsType OfferDetails { + get { + return this.offerDetailsField; + } + set { + this.offerDetailsField = value; + } + } + + /// + public RecurringFlagType Recurring { + get { + return this.recurringField; + } + set { + this.recurringField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RecurringSpecified { + get { + return this.recurringFieldSpecified; + } + set { + this.recurringFieldSpecified = value; + } + } + + /// + public PaymentReasonType PaymentReason { + get { + return this.paymentReasonField; + } + set { + this.paymentReasonField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentReasonSpecified { + get { + return this.paymentReasonFieldSpecified; + } + set { + this.paymentReasonFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentCategoryType { + + /// + InternationalShipping, + + /// + LocalDelivery, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ShippingServiceCodeType { + + /// + UPSGround, + + /// + UPS3rdDay, + + /// + UPS2ndDay, + + /// + UPSNextDay, + + /// + USPSPriority, + + /// + USPSParcel, + + /// + USPSMedia, + + /// + USPSFirstClass, + + /// + ShippingMethodStandard, + + /// + ShippingMethodExpress, + + /// + ShippingMethodNextDay, + + /// + USPSExpressMail, + + /// + USPSGround, + + /// + Download, + + /// + WillCall_Or_Pickup, + + /// + CustomCode, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentDetailsItemType { + + private string nameField; + + private string numberField; + + private string quantityField; + + private BasicAmountType taxField; + + private BasicAmountType amountField; + + private EbayItemPaymentDetailsItemType ebayItemPaymentDetailsItemField; + + private string promoCodeField; + + private ProductCategoryType productCategoryField; + + private bool productCategoryFieldSpecified; + + private string descriptionField; + + private MeasureType itemWeightField; + + private MeasureType itemLengthField; + + private MeasureType itemWidthField; + + private MeasureType itemHeightField; + + private string itemURLField; + + private EnhancedItemDataType enhancedItemDataField; + + private ItemCategoryType itemCategoryField; + + private bool itemCategoryFieldSpecified; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Number { + get { + return this.numberField; + } + set { + this.numberField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string Quantity { + get { + return this.quantityField; + } + set { + this.quantityField = value; + } + } + + /// + public BasicAmountType Tax { + get { + return this.taxField; + } + set { + this.taxField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public EbayItemPaymentDetailsItemType EbayItemPaymentDetailsItem { + get { + return this.ebayItemPaymentDetailsItemField; + } + set { + this.ebayItemPaymentDetailsItemField = value; + } + } + + /// + public string PromoCode { + get { + return this.promoCodeField; + } + set { + this.promoCodeField = value; + } + } + + /// + public ProductCategoryType ProductCategory { + get { + return this.productCategoryField; + } + set { + this.productCategoryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProductCategorySpecified { + get { + return this.productCategoryFieldSpecified; + } + set { + this.productCategoryFieldSpecified = value; + } + } + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + + /// + public MeasureType ItemWeight { + get { + return this.itemWeightField; + } + set { + this.itemWeightField = value; + } + } + + /// + public MeasureType ItemLength { + get { + return this.itemLengthField; + } + set { + this.itemLengthField = value; + } + } + + /// + public MeasureType ItemWidth { + get { + return this.itemWidthField; + } + set { + this.itemWidthField = value; + } + } + + /// + public MeasureType ItemHeight { + get { + return this.itemHeightField; + } + set { + this.itemHeightField = value; + } + } + + /// + public string ItemURL { + get { + return this.itemURLField; + } + set { + this.itemURLField = value; + } + } + + /// + public EnhancedItemDataType EnhancedItemData { + get { + return this.enhancedItemDataField; + } + set { + this.enhancedItemDataField = value; + } + } + + /// + public ItemCategoryType ItemCategory { + get { + return this.itemCategoryField; + } + set { + this.itemCategoryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ItemCategorySpecified { + get { + return this.itemCategoryFieldSpecified; + } + set { + this.itemCategoryFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class EbayItemPaymentDetailsItemType { + + private string itemNumberField; + + private string auctionTransactionIdField; + + private string orderIdField; + + private string cartIDField; + + /// + public string ItemNumber { + get { + return this.itemNumberField; + } + set { + this.itemNumberField = value; + } + } + + /// + public string AuctionTransactionId { + get { + return this.auctionTransactionIdField; + } + set { + this.auctionTransactionIdField = value; + } + } + + /// + public string OrderId { + get { + return this.orderIdField; + } + set { + this.orderIdField = value; + } + } + + /// + public string CartID { + get { + return this.cartIDField; + } + set { + this.cartIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ProductCategoryType { + + /// + Other, + + /// + Airlines, + + /// + Antiques, + + /// + Art, + + /// + Cameras_Photos, + + /// + Cars_Boats_Vehicles_Parts, + + /// + CellPhones_Telecom, + + /// + Coins_PaperMoney, + + /// + Collectibles, + + /// + Computers_Networking, + + /// + ConsumerElectronics, + + /// + Jewelry_Watches, + + /// + MusicalInstruments, + + /// + RealEstate, + + /// + SportsMemorabilia_Cards_FanShop, + + /// + Stamps, + + /// + Tickets, + + /// + Travels, + + /// + Gambling, + + /// + Alcohol, + + /// + Tobacco, + + /// + MoneyTransfer, + + /// + Software, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:CoreComponentTypes")] + public partial class MeasureType { + + private string unitField; + + private double valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="token")] + public string unit { + get { + return this.unitField; + } + set { + this.unitField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public double Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedItemDataType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ItemCategoryType { + + /// + Physical, + + /// + Digital, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AllowedPaymentMethodType { + + /// + Default, + + /// + InstantPaymentOnly, + + /// + AnyFundingSource, + + /// + InstantFundingSource, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedPaymentDataType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentActionCodeType { + + /// + None, + + /// + Authorization, + + /// + Sale, + + /// + Order, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum RecurringFlagType { + + /// + Y, + + /// + y, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentReasonType { + + /// + None, + + /// + Refund, + + /// + ReturnShipment, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class AuthorizationResponseType { + + private AckCodeType statusField; + + private ErrorType[] authorizationErrorField; + + /// + public AckCodeType Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AuthorizationError")] + public ErrorType[] AuthorizationError { + get { + return this.authorizationErrorField; + } + set { + this.authorizationErrorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AckCodeType { + + /// + Success, + + /// + Failure, + + /// + Warning, + + /// + SuccessWithWarning, + + /// + FailureWithWarning, + + /// + PartialSuccess, + + /// + CustomCode, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SetDataResponseType { + + private string tokenField; + + private AddressType[] shippingAddressesField; + + private ErrorType[] setDataErrorField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ShippingAddresses")] + public AddressType[] ShippingAddresses { + get { + return this.shippingAddressesField; + } + set { + this.shippingAddressesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("SetDataError")] + public ErrorType[] SetDataError { + get { + return this.setDataErrorField; + } + set { + this.setDataErrorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ExecuteCheckoutOperationsResponseDetailsType { + + private SetDataResponseType setDataResponseField; + + private AuthorizationResponseType authorizationResponseField; + + /// + public SetDataResponseType SetDataResponse { + get { + return this.setDataResponseField; + } + set { + this.setDataResponseField = value; + } + } + + /// + public AuthorizationResponseType AuthorizationResponse { + get { + return this.authorizationResponseField; + } + set { + this.authorizationResponseField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveAppliedToType { + + private string bucketIdField; + + private string itemIdField; + + private BasicAmountType incentiveAmountField; + + private string subTypeField; + + /// + public string BucketId { + get { + return this.bucketIdField; + } + set { + this.bucketIdField = value; + } + } + + /// + public string ItemId { + get { + return this.itemIdField; + } + set { + this.itemIdField = value; + } + } + + /// + public BasicAmountType IncentiveAmount { + get { + return this.incentiveAmountField; + } + set { + this.incentiveAmountField = value; + } + } + + /// + public string SubType { + get { + return this.subTypeField; + } + set { + this.subTypeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveDetailType { + + private string redemptionCodeField; + + private string displayCodeField; + + private string programIdField; + + private IncentiveTypeCodeType incentiveTypeField; + + private bool incentiveTypeFieldSpecified; + + private string incentiveDescriptionField; + + private IncentiveAppliedToType[] appliedToField; + + private string statusField; + + private string errorCodeField; + + /// + public string RedemptionCode { + get { + return this.redemptionCodeField; + } + set { + this.redemptionCodeField = value; + } + } + + /// + public string DisplayCode { + get { + return this.displayCodeField; + } + set { + this.displayCodeField = value; + } + } + + /// + public string ProgramId { + get { + return this.programIdField; + } + set { + this.programIdField = value; + } + } + + /// + public IncentiveTypeCodeType IncentiveType { + get { + return this.incentiveTypeField; + } + set { + this.incentiveTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IncentiveTypeSpecified { + get { + return this.incentiveTypeFieldSpecified; + } + set { + this.incentiveTypeFieldSpecified = value; + } + } + + /// + public string IncentiveDescription { + get { + return this.incentiveDescriptionField; + } + set { + this.incentiveDescriptionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AppliedTo")] + public IncentiveAppliedToType[] AppliedTo { + get { + return this.appliedToField; + } + set { + this.appliedToField = value; + } + } + + /// + public string Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + + /// + public string ErrorCode { + get { + return this.errorCodeField; + } + set { + this.errorCodeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum IncentiveTypeCodeType { + + /// + Coupon, + + /// + eBayGiftCertificate, + + /// + eBayGiftCard, + + /// + PayPalRewardVoucher, + + /// + MerchantGiftCertificate, + + /// + eBayRewardVoucher, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetIncentiveEvaluationResponseDetailsType { + + private IncentiveDetailType[] incentiveDetailsField; + + private string requestIdField; + + /// + [System.Xml.Serialization.XmlElementAttribute("IncentiveDetails")] + public IncentiveDetailType[] IncentiveDetails { + get { + return this.incentiveDetailsField; + } + set { + this.incentiveDetailsField = value; + } + } + + /// + public string RequestId { + get { + return this.requestIdField; + } + set { + this.requestIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetAccessPermissionDetailsResponseDetailsType { + + private string firstNameField; + + private string lastNameField; + + private string emailField; + + private string[] accessPermissionNameField; + + private string[] accessPermissionStatusField; + + private string payerIDField; + + /// + public string FirstName { + get { + return this.firstNameField; + } + set { + this.firstNameField = value; + } + } + + /// + public string LastName { + get { + return this.lastNameField; + } + set { + this.lastNameField = value; + } + } + + /// + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AccessPermissionName")] + public string[] AccessPermissionName { + get { + return this.accessPermissionNameField; + } + set { + this.accessPermissionNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AccessPermissionStatus")] + public string[] AccessPermissionStatus { + get { + return this.accessPermissionStatusField; + } + set { + this.accessPermissionStatusField = value; + } + } + + /// + public string PayerID { + get { + return this.payerIDField; + } + set { + this.payerIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetAuthDetailsResponseDetailsType { + + private string firstNameField; + + private string lastNameField; + + private string emailField; + + private string payerIDField; + + /// + public string FirstName { + get { + return this.firstNameField; + } + set { + this.firstNameField = value; + } + } + + /// + public string LastName { + get { + return this.lastNameField; + } + set { + this.lastNameField = value; + } + } + + /// + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + public string PayerID { + get { + return this.payerIDField; + } + set { + this.payerIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class APICredentialsType { + + private string usernameField; + + private string passwordField; + + private string signatureField; + + private string certificateField; + + private APIAuthenticationType typeField; + + /// + public string Username { + get { + return this.usernameField; + } + set { + this.usernameField = value; + } + } + + /// + public string Password { + get { + return this.passwordField; + } + set { + this.passwordField = value; + } + } + + /// + public string Signature { + get { + return this.signatureField; + } + set { + this.signatureField = value; + } + } + + /// + public string Certificate { + get { + return this.certificateField; + } + set { + this.certificateField = value; + } + } + + /// + public APIAuthenticationType Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum APIAuthenticationType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("Auth-None")] + AuthNone, + + /// + Cert, + + /// + Sign, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetBoardingDetailsResponseDetailsType { + + private BoardingStatusType statusField; + + private System.DateTime startDateField; + + private System.DateTime lastUpdatedField; + + private string reasonField; + + private string programNameField; + + private string programCodeField; + + private string campaignIDField; + + private UserWithdrawalLimitTypeType userWithdrawalLimitField; + + private bool userWithdrawalLimitFieldSpecified; + + private string partnerCustomField; + + private PayerInfoType accountOwnerField; + + private APICredentialsType credentialsField; + + private string configureAPIsField; + + private string emailVerificationStatusField; + + private string vettingStatusField; + + private string bankAccountVerificationStatusField; + + /// + public BoardingStatusType Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + + /// + public System.DateTime StartDate { + get { + return this.startDateField; + } + set { + this.startDateField = value; + } + } + + /// + public System.DateTime LastUpdated { + get { + return this.lastUpdatedField; + } + set { + this.lastUpdatedField = value; + } + } + + /// + public string Reason { + get { + return this.reasonField; + } + set { + this.reasonField = value; + } + } + + /// + public string ProgramName { + get { + return this.programNameField; + } + set { + this.programNameField = value; + } + } + + /// + public string ProgramCode { + get { + return this.programCodeField; + } + set { + this.programCodeField = value; + } + } + + /// + public string CampaignID { + get { + return this.campaignIDField; + } + set { + this.campaignIDField = value; + } + } + + /// + public UserWithdrawalLimitTypeType UserWithdrawalLimit { + get { + return this.userWithdrawalLimitField; + } + set { + this.userWithdrawalLimitField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool UserWithdrawalLimitSpecified { + get { + return this.userWithdrawalLimitFieldSpecified; + } + set { + this.userWithdrawalLimitFieldSpecified = value; + } + } + + /// + public string PartnerCustom { + get { + return this.partnerCustomField; + } + set { + this.partnerCustomField = value; + } + } + + /// + public PayerInfoType AccountOwner { + get { + return this.accountOwnerField; + } + set { + this.accountOwnerField = value; + } + } + + /// + public APICredentialsType Credentials { + get { + return this.credentialsField; + } + set { + this.credentialsField = value; + } + } + + /// + public string ConfigureAPIs { + get { + return this.configureAPIsField; + } + set { + this.configureAPIsField = value; + } + } + + /// + public string EmailVerificationStatus { + get { + return this.emailVerificationStatusField; + } + set { + this.emailVerificationStatusField = value; + } + } + + /// + public string VettingStatus { + get { + return this.vettingStatusField; + } + set { + this.vettingStatusField = value; + } + } + + /// + public string BankAccountVerificationStatus { + get { + return this.bankAccountVerificationStatusField; + } + set { + this.bankAccountVerificationStatusField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BoardingStatusType { + + /// + Unknown, + + /// + Completed, + + /// + Cancelled, + + /// + Pending, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum UserWithdrawalLimitTypeType { + + /// + Unknown, + + /// + Limited, + + /// + Unlimited, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BAUpdateResponseDetailsType { + + private string billingAgreementIDField; + + private string billingAgreementDescriptionField; + + private MerchantPullStatusCodeType billingAgreementStatusField; + + private string billingAgreementCustomField; + + private PayerInfoType payerInfoField; + + private BasicAmountType billingAgreementMaxField; + + private AddressType billingAddressField; + + /// + public string BillingAgreementID { + get { + return this.billingAgreementIDField; + } + set { + this.billingAgreementIDField = value; + } + } + + /// + public string BillingAgreementDescription { + get { + return this.billingAgreementDescriptionField; + } + set { + this.billingAgreementDescriptionField = value; + } + } + + /// + public MerchantPullStatusCodeType BillingAgreementStatus { + get { + return this.billingAgreementStatusField; + } + set { + this.billingAgreementStatusField = value; + } + } + + /// + public string BillingAgreementCustom { + get { + return this.billingAgreementCustomField; + } + set { + this.billingAgreementCustomField = value; + } + } + + /// + public PayerInfoType PayerInfo { + get { + return this.payerInfoField; + } + set { + this.payerInfoField = value; + } + } + + /// + public BasicAmountType BillingAgreementMax { + get { + return this.billingAgreementMaxField; + } + set { + this.billingAgreementMaxField = value; + } + } + + /// + public AddressType BillingAddress { + get { + return this.billingAddressField; + } + set { + this.billingAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum MerchantPullStatusCodeType { + + /// + Active, + + /// + Canceled, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentTransactionSearchResultType { + + private System.DateTime timestampField; + + private string timezoneField; + + private string typeField; + + private string payerField; + + private string payerDisplayNameField; + + private string transactionIDField; + + private string statusField; + + private BasicAmountType grossAmountField; + + private BasicAmountType feeAmountField; + + private BasicAmountType netAmountField; + + /// + public System.DateTime Timestamp { + get { + return this.timestampField; + } + set { + this.timestampField = value; + } + } + + /// + public string Timezone { + get { + return this.timezoneField; + } + set { + this.timezoneField = value; + } + } + + /// + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public string Payer { + get { + return this.payerField; + } + set { + this.payerField = value; + } + } + + /// + public string PayerDisplayName { + get { + return this.payerDisplayNameField; + } + set { + this.payerDisplayNameField = value; + } + } + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public string Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + + /// + public BasicAmountType GrossAmount { + get { + return this.grossAmountField; + } + set { + this.grossAmountField = value; + } + } + + /// + public BasicAmountType FeeAmount { + get { + return this.feeAmountField; + } + set { + this.feeAmountField = value; + } + } + + /// + public BasicAmountType NetAmount { + get { + return this.netAmountField; + } + set { + this.netAmountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class MerchantPullInfoType { + + private MerchantPullStatusCodeType mpStatusField; + + private BasicAmountType mpMaxField; + + private string mpCustomField; + + private string descField; + + private string invoiceField; + + private string customField; + + private string paymentSourceIDField; + + /// + public MerchantPullStatusCodeType MpStatus { + get { + return this.mpStatusField; + } + set { + this.mpStatusField = value; + } + } + + /// + public BasicAmountType MpMax { + get { + return this.mpMaxField; + } + set { + this.mpMaxField = value; + } + } + + /// + public string MpCustom { + get { + return this.mpCustomField; + } + set { + this.mpCustomField = value; + } + } + + /// + public string Desc { + get { + return this.descField; + } + set { + this.descField = value; + } + } + + /// + public string Invoice { + get { + return this.invoiceField; + } + set { + this.invoiceField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string PaymentSourceID { + get { + return this.paymentSourceIDField; + } + set { + this.paymentSourceIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class MerchantPullPaymentResponseType { + + private PayerInfoType payerInfoField; + + private PaymentInfoType paymentInfoField; + + private MerchantPullInfoType merchantPullInfoField; + + /// + public PayerInfoType PayerInfo { + get { + return this.payerInfoField; + } + set { + this.payerInfoField = value; + } + } + + /// + public PaymentInfoType PaymentInfo { + get { + return this.paymentInfoField; + } + set { + this.paymentInfoField = value; + } + } + + /// + public MerchantPullInfoType MerchantPullInfo { + get { + return this.merchantPullInfoField; + } + set { + this.merchantPullInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ThreeDSecureResponseType { + + private string vpasField; + + private string eciSubmitted3DSField; + + /// + public string Vpas { + get { + return this.vpasField; + } + set { + this.vpasField = value; + } + } + + /// + public string EciSubmitted3DS { + get { + return this.eciSubmitted3DSField; + } + set { + this.eciSubmitted3DSField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ThreeDSecureInfoType { + + private ThreeDSecureRequestType threeDSecureRequestField; + + private ThreeDSecureResponseType threeDSecureResponseField; + + /// + public ThreeDSecureRequestType ThreeDSecureRequest { + get { + return this.threeDSecureRequestField; + } + set { + this.threeDSecureRequestField = value; + } + } + + /// + public ThreeDSecureResponseType ThreeDSecureResponse { + get { + return this.threeDSecureResponseField; + } + set { + this.threeDSecureResponseField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class OfferCouponInfoType { + + private string typeField; + + private string idField; + + private string amountField; + + private string amountCurrencyField; + + /// + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public string ID { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public string Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string AmountCurrency { + get { + return this.amountCurrencyField; + } + set { + this.amountCurrencyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class AuctionInfoType { + + private string buyerIDField; + + private System.DateTime closingDateField; + + private bool closingDateFieldSpecified; + + private string multiItemField; + + /// + public string BuyerID { + get { + return this.buyerIDField; + } + set { + this.buyerIDField = value; + } + } + + /// + public System.DateTime ClosingDate { + get { + return this.closingDateField; + } + set { + this.closingDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ClosingDateSpecified { + get { + return this.closingDateFieldSpecified; + } + set { + this.closingDateFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string multiItem { + get { + return this.multiItemField; + } + set { + this.multiItemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SubscriptionTermsType { + + private BasicAmountType amountField; + + private string periodField; + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string period { + get { + return this.periodField; + } + set { + this.periodField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SubscriptionInfoType { + + private string subscriptionIDField; + + private System.DateTime subscriptionDateField; + + private bool subscriptionDateFieldSpecified; + + private System.DateTime effectiveDateField; + + private bool effectiveDateFieldSpecified; + + private System.DateTime retryTimeField; + + private bool retryTimeFieldSpecified; + + private string usernameField; + + private string passwordField; + + private string recurrencesField; + + private SubscriptionTermsType[] termsField; + + private string reattemptField; + + private string recurringField; + + /// + public string SubscriptionID { + get { + return this.subscriptionIDField; + } + set { + this.subscriptionIDField = value; + } + } + + /// + public System.DateTime SubscriptionDate { + get { + return this.subscriptionDateField; + } + set { + this.subscriptionDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SubscriptionDateSpecified { + get { + return this.subscriptionDateFieldSpecified; + } + set { + this.subscriptionDateFieldSpecified = value; + } + } + + /// + public System.DateTime EffectiveDate { + get { + return this.effectiveDateField; + } + set { + this.effectiveDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool EffectiveDateSpecified { + get { + return this.effectiveDateFieldSpecified; + } + set { + this.effectiveDateFieldSpecified = value; + } + } + + /// + public System.DateTime RetryTime { + get { + return this.retryTimeField; + } + set { + this.retryTimeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RetryTimeSpecified { + get { + return this.retryTimeFieldSpecified; + } + set { + this.retryTimeFieldSpecified = value; + } + } + + /// + public string Username { + get { + return this.usernameField; + } + set { + this.usernameField = value; + } + } + + /// + public string Password { + get { + return this.passwordField; + } + set { + this.passwordField = value; + } + } + + /// + public string Recurrences { + get { + return this.recurrencesField; + } + set { + this.recurrencesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Terms")] + public SubscriptionTermsType[] Terms { + get { + return this.termsField; + } + set { + this.termsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string reattempt { + get { + return this.reattemptField; + } + set { + this.reattemptField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string recurring { + get { + return this.recurringField; + } + set { + this.recurringField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class OptionType { + + private string nameField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentItemType { + + private string ebayItemTxnIdField; + + private string nameField; + + private string numberField; + + private string quantityField; + + private string salesTaxField; + + private string shippingAmountField; + + private string handlingAmountField; + + private InvoiceItemType invoiceItemDetailsField; + + private string couponIDField; + + private string couponAmountField; + + private string couponAmountCurrencyField; + + private string loyaltyCardDiscountAmountField; + + private string loyaltyCardDiscountCurrencyField; + + private BasicAmountType amountField; + + private OptionType[] optionsField; + + /// + public string EbayItemTxnId { + get { + return this.ebayItemTxnIdField; + } + set { + this.ebayItemTxnIdField = value; + } + } + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Number { + get { + return this.numberField; + } + set { + this.numberField = value; + } + } + + /// + public string Quantity { + get { + return this.quantityField; + } + set { + this.quantityField = value; + } + } + + /// + public string SalesTax { + get { + return this.salesTaxField; + } + set { + this.salesTaxField = value; + } + } + + /// + public string ShippingAmount { + get { + return this.shippingAmountField; + } + set { + this.shippingAmountField = value; + } + } + + /// + public string HandlingAmount { + get { + return this.handlingAmountField; + } + set { + this.handlingAmountField = value; + } + } + + /// + public InvoiceItemType InvoiceItemDetails { + get { + return this.invoiceItemDetailsField; + } + set { + this.invoiceItemDetailsField = value; + } + } + + /// + public string CouponID { + get { + return this.couponIDField; + } + set { + this.couponIDField = value; + } + } + + /// + public string CouponAmount { + get { + return this.couponAmountField; + } + set { + this.couponAmountField = value; + } + } + + /// + public string CouponAmountCurrency { + get { + return this.couponAmountCurrencyField; + } + set { + this.couponAmountCurrencyField = value; + } + } + + /// + public string LoyaltyCardDiscountAmount { + get { + return this.loyaltyCardDiscountAmountField; + } + set { + this.loyaltyCardDiscountAmountField = value; + } + } + + /// + public string LoyaltyCardDiscountCurrency { + get { + return this.loyaltyCardDiscountCurrencyField; + } + set { + this.loyaltyCardDiscountCurrencyField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Options")] + public OptionType[] Options { + get { + return this.optionsField; + } + set { + this.optionsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class InvoiceItemType { + + private string nameField; + + private string descriptionField; + + private string eANField; + + private string sKUField; + + private string returnPolicyIdentifierField; + + private BasicAmountType priceField; + + private BasicAmountType itemPriceField; + + private double itemCountField; + + private bool itemCountFieldSpecified; + + private UnitOfMeasure itemCountUnitField; + + private bool itemCountUnitFieldSpecified; + + private DiscountType[] discountField; + + private bool taxableField; + + private bool taxableFieldSpecified; + + private double taxRateField; + + private bool taxRateFieldSpecified; + + private AdditionalFeeType[] additionalFeesField; + + private bool reimbursableField; + + private bool reimbursableFieldSpecified; + + private string mPNField; + + private string iSBNField; + + private string pLUField; + + private string modelNumberField; + + private string styleNumberField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + + /// + public string EAN { + get { + return this.eANField; + } + set { + this.eANField = value; + } + } + + /// + public string SKU { + get { + return this.sKUField; + } + set { + this.sKUField = value; + } + } + + /// + public string ReturnPolicyIdentifier { + get { + return this.returnPolicyIdentifierField; + } + set { + this.returnPolicyIdentifierField = value; + } + } + + /// + public BasicAmountType Price { + get { + return this.priceField; + } + set { + this.priceField = value; + } + } + + /// + public BasicAmountType ItemPrice { + get { + return this.itemPriceField; + } + set { + this.itemPriceField = value; + } + } + + /// + public double ItemCount { + get { + return this.itemCountField; + } + set { + this.itemCountField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ItemCountSpecified { + get { + return this.itemCountFieldSpecified; + } + set { + this.itemCountFieldSpecified = value; + } + } + + /// + public UnitOfMeasure ItemCountUnit { + get { + return this.itemCountUnitField; + } + set { + this.itemCountUnitField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ItemCountUnitSpecified { + get { + return this.itemCountUnitFieldSpecified; + } + set { + this.itemCountUnitFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Discount")] + public DiscountType[] Discount { + get { + return this.discountField; + } + set { + this.discountField = value; + } + } + + /// + public bool Taxable { + get { + return this.taxableField; + } + set { + this.taxableField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TaxableSpecified { + get { + return this.taxableFieldSpecified; + } + set { + this.taxableFieldSpecified = value; + } + } + + /// + public double TaxRate { + get { + return this.taxRateField; + } + set { + this.taxRateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TaxRateSpecified { + get { + return this.taxRateFieldSpecified; + } + set { + this.taxRateFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AdditionalFees")] + public AdditionalFeeType[] AdditionalFees { + get { + return this.additionalFeesField; + } + set { + this.additionalFeesField = value; + } + } + + /// + public bool Reimbursable { + get { + return this.reimbursableField; + } + set { + this.reimbursableField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReimbursableSpecified { + get { + return this.reimbursableFieldSpecified; + } + set { + this.reimbursableFieldSpecified = value; + } + } + + /// + public string MPN { + get { + return this.mPNField; + } + set { + this.mPNField = value; + } + } + + /// + public string ISBN { + get { + return this.iSBNField; + } + set { + this.iSBNField = value; + } + } + + /// + public string PLU { + get { + return this.pLUField; + } + set { + this.pLUField = value; + } + } + + /// + public string ModelNumber { + get { + return this.modelNumberField; + } + set { + this.modelNumberField = value; + } + } + + /// + public string StyleNumber { + get { + return this.styleNumberField; + } + set { + this.styleNumberField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum UnitOfMeasure { + + /// + EA, + + /// + Hours, + + /// + Days, + + /// + Seconds, + + /// + CrateOf12, + + /// + [System.Xml.Serialization.XmlEnumAttribute("6Pack")] + Item6Pack, + + /// + GLI, + + /// + GLL, + + /// + LTR, + + /// + INH, + + /// + FOT, + + /// + MMT, + + /// + CMQ, + + /// + MTR, + + /// + MTK, + + /// + MTQ, + + /// + GRM, + + /// + KGM, + + /// + KG, + + /// + LBR, + + /// + ANN, + + /// + CEL, + + /// + FAH, + + /// + RESERVED, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DiscountType { + + private string nameField; + + private string descriptionField; + + private BasicAmountType amountField; + + private RedeemedOfferType redeemedOfferTypeField; + + private bool redeemedOfferTypeFieldSpecified; + + private string redeemedOfferIDField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public RedeemedOfferType RedeemedOfferType { + get { + return this.redeemedOfferTypeField; + } + set { + this.redeemedOfferTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RedeemedOfferTypeSpecified { + get { + return this.redeemedOfferTypeFieldSpecified; + } + set { + this.redeemedOfferTypeFieldSpecified = value; + } + } + + /// + public string RedeemedOfferID { + get { + return this.redeemedOfferIDField; + } + set { + this.redeemedOfferIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum RedeemedOfferType { + + /// + MERCHANT_COUPON, + + /// + LOYALTY_CARD, + + /// + MANUFACTURER_COUPON, + + /// + RESERVED, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class AdditionalFeeType { + + private string typeField; + + private BasicAmountType amountField; + + /// + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentItemInfoType { + + private string invoiceIDField; + + private string customField; + + private string memoField; + + private string salesTaxField; + + private PaymentItemType[] paymentItemField; + + private SubscriptionInfoType subscriptionField; + + private AuctionInfoType auctionField; + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string Memo { + get { + return this.memoField; + } + set { + this.memoField = value; + } + } + + /// + public string SalesTax { + get { + return this.salesTaxField; + } + set { + this.salesTaxField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentItem")] + public PaymentItemType[] PaymentItem { + get { + return this.paymentItemField; + } + set { + this.paymentItemField = value; + } + } + + /// + public SubscriptionInfoType Subscription { + get { + return this.subscriptionField; + } + set { + this.subscriptionField = value; + } + } + + /// + public AuctionInfoType Auction { + get { + return this.auctionField; + } + set { + this.auctionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ReceiverInfoType { + + private string businessField; + + private string receiverField; + + private string receiverIDField; + + /// + public string Business { + get { + return this.businessField; + } + set { + this.businessField = value; + } + } + + /// + public string Receiver { + get { + return this.receiverField; + } + set { + this.receiverField = value; + } + } + + /// + public string ReceiverID { + get { + return this.receiverIDField; + } + set { + this.receiverIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentTransactionType { + + private ReceiverInfoType receiverInfoField; + + private PayerInfoType payerInfoField; + + private string tPLReferenceIDField; + + private PaymentInfoType paymentInfoField; + + private PaymentItemInfoType paymentItemInfoField; + + private OfferCouponInfoType offerCouponInfoField; + + private AddressType secondaryAddressField; + + private UserSelectedOptionType userSelectedOptionsField; + + private string giftMessageField; + + private string giftReceiptField; + + private string giftWrapNameField; + + private BasicAmountType giftWrapAmountField; + + private string buyerEmailOptInField; + + private string surveyQuestionField; + + private string[] surveyChoiceSelectedField; + + /// + public ReceiverInfoType ReceiverInfo { + get { + return this.receiverInfoField; + } + set { + this.receiverInfoField = value; + } + } + + /// + public PayerInfoType PayerInfo { + get { + return this.payerInfoField; + } + set { + this.payerInfoField = value; + } + } + + /// + public string TPLReferenceID { + get { + return this.tPLReferenceIDField; + } + set { + this.tPLReferenceIDField = value; + } + } + + /// + public PaymentInfoType PaymentInfo { + get { + return this.paymentInfoField; + } + set { + this.paymentInfoField = value; + } + } + + /// + public PaymentItemInfoType PaymentItemInfo { + get { + return this.paymentItemInfoField; + } + set { + this.paymentItemInfoField = value; + } + } + + /// + public OfferCouponInfoType OfferCouponInfo { + get { + return this.offerCouponInfoField; + } + set { + this.offerCouponInfoField = value; + } + } + + /// + public AddressType SecondaryAddress { + get { + return this.secondaryAddressField; + } + set { + this.secondaryAddressField = value; + } + } + + /// + public UserSelectedOptionType UserSelectedOptions { + get { + return this.userSelectedOptionsField; + } + set { + this.userSelectedOptionsField = value; + } + } + + /// + public string GiftMessage { + get { + return this.giftMessageField; + } + set { + this.giftMessageField = value; + } + } + + /// + public string GiftReceipt { + get { + return this.giftReceiptField; + } + set { + this.giftReceiptField = value; + } + } + + /// + public string GiftWrapName { + get { + return this.giftWrapNameField; + } + set { + this.giftWrapNameField = value; + } + } + + /// + public BasicAmountType GiftWrapAmount { + get { + return this.giftWrapAmountField; + } + set { + this.giftWrapAmountField = value; + } + } + + /// + public string BuyerEmailOptIn { + get { + return this.buyerEmailOptInField; + } + set { + this.buyerEmailOptInField = value; + } + } + + /// + public string SurveyQuestion { + get { + return this.surveyQuestionField; + } + set { + this.surveyQuestionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("SurveyChoiceSelected")] + public string[] SurveyChoiceSelected { + get { + return this.surveyChoiceSelectedField; + } + set { + this.surveyChoiceSelectedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedCompleteRecoupResponseDetailsType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class RefundInfoType { + + private PaymentStatusCodeType refundStatusField; + + private bool refundStatusFieldSpecified; + + private PendingStatusCodeType pendingReasonField; + + private bool pendingReasonFieldSpecified; + + /// + public PaymentStatusCodeType RefundStatus { + get { + return this.refundStatusField; + } + set { + this.refundStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RefundStatusSpecified { + get { + return this.refundStatusFieldSpecified; + } + set { + this.refundStatusFieldSpecified = value; + } + } + + /// + public PendingStatusCodeType PendingReason { + get { + return this.pendingReasonField; + } + set { + this.pendingReasonField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PendingReasonSpecified { + get { + return this.pendingReasonFieldSpecified; + } + set { + this.pendingReasonFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ButtonSearchResultType { + + private string hostedButtonIDField; + + private string buttonTypeField; + + private string itemNameField; + + private System.DateTime modifyDateField; + + private bool modifyDateFieldSpecified; + + /// + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + + /// + public string ButtonType { + get { + return this.buttonTypeField; + } + set { + this.buttonTypeField = value; + } + } + + /// + public string ItemName { + get { + return this.itemNameField; + } + set { + this.itemNameField = value; + } + } + + /// + public System.DateTime ModifyDate { + get { + return this.modifyDateField; + } + set { + this.modifyDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ModifyDateSpecified { + get { + return this.modifyDateFieldSpecified; + } + set { + this.modifyDateFieldSpecified = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ExternalRememberMeOptOutResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ReverseTransactionResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetPalDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(UpdateRecurringPaymentsProfileResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BillOutstandingAmountResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ManageRecurringPaymentsProfileStatusResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetRecurringPaymentsProfileDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CreateRecurringPaymentsProfileResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoNonReferencedCreditResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoReferenceTransactionResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CreateBillingAgreementResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetBillingAgreementCustomerDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetCustomerBillingAgreementResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetBalanceResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoMobileCheckoutPaymentResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetMobileCheckoutResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetMobileStatusResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CreateMobilePaymentResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(UpdateAuthorizationResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoAuthorizationResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoUATPAuthorizationResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoVoidResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoReauthorizationResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoCaptureResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoCancelResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoDirectPaymentResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ManagePendingTransactionStatusResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoExpressCheckoutPaymentResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoUATPExpressCheckoutPaymentResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetExpressCheckoutDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ExecuteCheckoutOperationsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetExpressCheckoutResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetIncentiveEvaluationResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetAccessPermissionDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(UpdateAccessPermissionsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetAccessPermissionsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetAuthDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetAuthFlowParamResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetBoardingDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(EnterBoardingResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AddressVerifyResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BAUpdateResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(MassPayResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(TransactionSearchResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BillUserResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetTransactionDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CancelRecoupResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CompleteRecoupResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(InitiateRecoupResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(RefundTransactionResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMButtonSearchResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMGetInventoryResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMSetInventoryResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMGetButtonDetailsResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMManageButtonStatusResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMUpdateButtonResponseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMCreateButtonResponseType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public abstract partial class AbstractResponseType { + + private System.DateTime timestampField; + + private bool timestampFieldSpecified; + + private AckCodeType ackField; + + private string correlationIDField; + + private ErrorType[] errorsField; + + private string versionField; + + private string buildField; + + private System.Xml.XmlElement anyField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public System.DateTime Timestamp { + get { + return this.timestampField; + } + set { + this.timestampField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TimestampSpecified { + get { + return this.timestampFieldSpecified; + } + set { + this.timestampFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public AckCodeType Ack { + get { + return this.ackField; + } + set { + this.ackField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string CorrelationID { + get { + return this.correlationIDField; + } + set { + this.correlationIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Errors", Order=3)] + public ErrorType[] Errors { + get { + return this.errorsField; + } + set { + this.errorsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=4)] + public string Version { + get { + return this.versionField; + } + set { + this.versionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=5)] + public string Build { + get { + return this.buildField; + } + set { + this.buildField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ExternalRememberMeOptOutResponseType : AbstractResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ReverseTransactionResponseType : AbstractResponseType { + + private ReverseTransactionResponseDetailsType reverseTransactionResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public ReverseTransactionResponseDetailsType ReverseTransactionResponseDetails { + get { + return this.reverseTransactionResponseDetailsField; + } + set { + this.reverseTransactionResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetPalDetailsResponseType : AbstractResponseType { + + private string palField; + + private string localeField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Pal { + get { + return this.palField; + } + set { + this.palField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string Locale { + get { + return this.localeField; + } + set { + this.localeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateRecurringPaymentsProfileResponseType : AbstractResponseType { + + private UpdateRecurringPaymentsProfileResponseDetailsType updateRecurringPaymentsProfileResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public UpdateRecurringPaymentsProfileResponseDetailsType UpdateRecurringPaymentsProfileResponseDetails { + get { + return this.updateRecurringPaymentsProfileResponseDetailsField; + } + set { + this.updateRecurringPaymentsProfileResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BillOutstandingAmountResponseType : AbstractResponseType { + + private BillOutstandingAmountResponseDetailsType billOutstandingAmountResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public BillOutstandingAmountResponseDetailsType BillOutstandingAmountResponseDetails { + get { + return this.billOutstandingAmountResponseDetailsField; + } + set { + this.billOutstandingAmountResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ManageRecurringPaymentsProfileStatusResponseType : AbstractResponseType { + + private ManageRecurringPaymentsProfileStatusResponseDetailsType manageRecurringPaymentsProfileStatusResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public ManageRecurringPaymentsProfileStatusResponseDetailsType ManageRecurringPaymentsProfileStatusResponseDetails { + get { + return this.manageRecurringPaymentsProfileStatusResponseDetailsField; + } + set { + this.manageRecurringPaymentsProfileStatusResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetRecurringPaymentsProfileDetailsResponseType : AbstractResponseType { + + private GetRecurringPaymentsProfileDetailsResponseDetailsType getRecurringPaymentsProfileDetailsResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public GetRecurringPaymentsProfileDetailsResponseDetailsType GetRecurringPaymentsProfileDetailsResponseDetails { + get { + return this.getRecurringPaymentsProfileDetailsResponseDetailsField; + } + set { + this.getRecurringPaymentsProfileDetailsResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateRecurringPaymentsProfileResponseType : AbstractResponseType { + + private CreateRecurringPaymentsProfileResponseDetailsType createRecurringPaymentsProfileResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public CreateRecurringPaymentsProfileResponseDetailsType CreateRecurringPaymentsProfileResponseDetails { + get { + return this.createRecurringPaymentsProfileResponseDetailsField; + } + set { + this.createRecurringPaymentsProfileResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoNonReferencedCreditResponseType : AbstractResponseType { + + private DoNonReferencedCreditResponseDetailsType doNonReferencedCreditResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public DoNonReferencedCreditResponseDetailsType DoNonReferencedCreditResponseDetails { + get { + return this.doNonReferencedCreditResponseDetailsField; + } + set { + this.doNonReferencedCreditResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoReferenceTransactionResponseType : AbstractResponseType { + + private DoReferenceTransactionResponseDetailsType doReferenceTransactionResponseDetailsField; + + private FMFDetailsType fMFDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public DoReferenceTransactionResponseDetailsType DoReferenceTransactionResponseDetails { + get { + return this.doReferenceTransactionResponseDetailsField; + } + set { + this.doReferenceTransactionResponseDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public FMFDetailsType FMFDetails { + get { + return this.fMFDetailsField; + } + set { + this.fMFDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateBillingAgreementResponseType : AbstractResponseType { + + private string billingAgreementIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string BillingAgreementID { + get { + return this.billingAgreementIDField; + } + set { + this.billingAgreementIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBillingAgreementCustomerDetailsResponseType : AbstractResponseType { + + private GetBillingAgreementCustomerDetailsResponseDetailsType getBillingAgreementCustomerDetailsResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public GetBillingAgreementCustomerDetailsResponseDetailsType GetBillingAgreementCustomerDetailsResponseDetails { + get { + return this.getBillingAgreementCustomerDetailsResponseDetailsField; + } + set { + this.getBillingAgreementCustomerDetailsResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetCustomerBillingAgreementResponseType : AbstractResponseType { + + private string tokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBalanceResponseType : AbstractResponseType { + + private BasicAmountType balanceField; + + private System.DateTime balanceTimeStampField; + + private BasicAmountType[] balanceHoldingsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public BasicAmountType Balance { + get { + return this.balanceField; + } + set { + this.balanceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public System.DateTime BalanceTimeStamp { + get { + return this.balanceTimeStampField; + } + set { + this.balanceTimeStampField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("BalanceHoldings", Order=2)] + public BasicAmountType[] BalanceHoldings { + get { + return this.balanceHoldingsField; + } + set { + this.balanceHoldingsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoMobileCheckoutPaymentResponseType : AbstractResponseType { + + private DoMobileCheckoutPaymentResponseDetailsType doMobileCheckoutPaymentResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public DoMobileCheckoutPaymentResponseDetailsType DoMobileCheckoutPaymentResponseDetails { + get { + return this.doMobileCheckoutPaymentResponseDetailsField; + } + set { + this.doMobileCheckoutPaymentResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetMobileCheckoutResponseType : AbstractResponseType { + + private string tokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetMobileStatusResponseType : AbstractResponseType { + + private string isActivatedField; + + private string isPasswordSetField; + + private string paymentPendingField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer", Order=0)] + public string IsActivated { + get { + return this.isActivatedField; + } + set { + this.isActivatedField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer", Order=1)] + public string IsPasswordSet { + get { + return this.isPasswordSetField; + } + set { + this.isPasswordSetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer", Order=2)] + public string PaymentPending { + get { + return this.paymentPendingField; + } + set { + this.paymentPendingField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateMobilePaymentResponseType : AbstractResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateAuthorizationResponseType : AbstractResponseType { + + private string transactionIDField; + + private AuthorizationInfoType authorizationInfoField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=1)] + public AuthorizationInfoType AuthorizationInfo { + get { + return this.authorizationInfoField; + } + set { + this.authorizationInfoField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoUATPAuthorizationResponseType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoAuthorizationResponseType : AbstractResponseType { + + private string transactionIDField; + + private BasicAmountType amountField; + + private AuthorizationInfoType authorizationInfoField; + + private string msgSubIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=2)] + public AuthorizationInfoType AuthorizationInfo { + get { + return this.authorizationInfoField; + } + set { + this.authorizationInfoField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=3)] + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoUATPAuthorizationResponseType : DoAuthorizationResponseType { + + private UATPDetailsType uATPDetailsField; + + private string authorizationCodeField; + + private string invoiceIDField; + + private string msgSubID1Field; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public UATPDetailsType UATPDetails { + get { + return this.uATPDetailsField; + } + set { + this.uATPDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string AuthorizationCode { + get { + return this.authorizationCodeField; + } + set { + this.authorizationCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("MsgSubID", Order=3)] + public string MsgSubID1 { + get { + return this.msgSubID1Field; + } + set { + this.msgSubID1Field = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class UATPDetailsType { + + private string uATPNumberField; + + private int expMonthField; + + private int expYearField; + + /// + public string UATPNumber { + get { + return this.uATPNumberField; + } + set { + this.uATPNumberField = value; + } + } + + /// + public int ExpMonth { + get { + return this.expMonthField; + } + set { + this.expMonthField = value; + } + } + + /// + public int ExpYear { + get { + return this.expYearField; + } + set { + this.expYearField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoVoidResponseType : AbstractResponseType { + + private string authorizationIDField; + + private string msgSubIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string AuthorizationID { + get { + return this.authorizationIDField; + } + set { + this.authorizationIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoReauthorizationResponseType : AbstractResponseType { + + private string authorizationIDField; + + private AuthorizationInfoType authorizationInfoField; + + private string msgSubIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string AuthorizationID { + get { + return this.authorizationIDField; + } + set { + this.authorizationIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=1)] + public AuthorizationInfoType AuthorizationInfo { + get { + return this.authorizationInfoField; + } + set { + this.authorizationInfoField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoCaptureResponseType : AbstractResponseType { + + private DoCaptureResponseDetailsType doCaptureResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public DoCaptureResponseDetailsType DoCaptureResponseDetails { + get { + return this.doCaptureResponseDetailsField; + } + set { + this.doCaptureResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoCancelResponseType : AbstractResponseType { + + private string msgSubIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoDirectPaymentResponseType : AbstractResponseType { + + private BasicAmountType amountField; + + private string aVSCodeField; + + private string cVV2CodeField; + + private string transactionIDField; + + private PendingStatusCodeType pendingReasonField; + + private bool pendingReasonFieldSpecified; + + private PaymentStatusCodeType paymentStatusField; + + private bool paymentStatusFieldSpecified; + + private FMFDetailsType fMFDetailsField; + + private ThreeDSecureResponseType threeDSecureResponseField; + + private string paymentAdviceCodeField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string AVSCode { + get { + return this.aVSCodeField; + } + set { + this.aVSCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string CVV2Code { + get { + return this.cVV2CodeField; + } + set { + this.cVV2CodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=3)] + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=4)] + public PendingStatusCodeType PendingReason { + get { + return this.pendingReasonField; + } + set { + this.pendingReasonField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PendingReasonSpecified { + get { + return this.pendingReasonFieldSpecified; + } + set { + this.pendingReasonFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=5)] + public PaymentStatusCodeType PaymentStatus { + get { + return this.paymentStatusField; + } + set { + this.paymentStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentStatusSpecified { + get { + return this.paymentStatusFieldSpecified; + } + set { + this.paymentStatusFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=6)] + public FMFDetailsType FMFDetails { + get { + return this.fMFDetailsField; + } + set { + this.fMFDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=7)] + public ThreeDSecureResponseType ThreeDSecureResponse { + get { + return this.threeDSecureResponseField; + } + set { + this.threeDSecureResponseField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=8)] + public string PaymentAdviceCode { + get { + return this.paymentAdviceCodeField; + } + set { + this.paymentAdviceCodeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ManagePendingTransactionStatusResponseType : AbstractResponseType { + + private string transactionIDField; + + private string statusField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoUATPExpressCheckoutPaymentResponseType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoExpressCheckoutPaymentResponseType : AbstractResponseType { + + private DoExpressCheckoutPaymentResponseDetailsType doExpressCheckoutPaymentResponseDetailsField; + + private FMFDetailsType fMFDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public DoExpressCheckoutPaymentResponseDetailsType DoExpressCheckoutPaymentResponseDetails { + get { + return this.doExpressCheckoutPaymentResponseDetailsField; + } + set { + this.doExpressCheckoutPaymentResponseDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public FMFDetailsType FMFDetails { + get { + return this.fMFDetailsField; + } + set { + this.fMFDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoUATPExpressCheckoutPaymentResponseType : DoExpressCheckoutPaymentResponseType { + + private UATPDetailsType uATPDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public UATPDetailsType UATPDetails { + get { + return this.uATPDetailsField; + } + set { + this.uATPDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetExpressCheckoutDetailsResponseType : AbstractResponseType { + + private GetExpressCheckoutDetailsResponseDetailsType getExpressCheckoutDetailsResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public GetExpressCheckoutDetailsResponseDetailsType GetExpressCheckoutDetailsResponseDetails { + get { + return this.getExpressCheckoutDetailsResponseDetailsField; + } + set { + this.getExpressCheckoutDetailsResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ExecuteCheckoutOperationsResponseType : AbstractResponseType { + + private ExecuteCheckoutOperationsResponseDetailsType executeCheckoutOperationsResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public ExecuteCheckoutOperationsResponseDetailsType ExecuteCheckoutOperationsResponseDetails { + get { + return this.executeCheckoutOperationsResponseDetailsField; + } + set { + this.executeCheckoutOperationsResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetExpressCheckoutResponseType : AbstractResponseType { + + private string tokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetIncentiveEvaluationResponseType : AbstractResponseType { + + private GetIncentiveEvaluationResponseDetailsType getIncentiveEvaluationResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public GetIncentiveEvaluationResponseDetailsType GetIncentiveEvaluationResponseDetails { + get { + return this.getIncentiveEvaluationResponseDetailsField; + } + set { + this.getIncentiveEvaluationResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetAccessPermissionDetailsResponseType : AbstractResponseType { + + private GetAccessPermissionDetailsResponseDetailsType getAccessPermissionDetailsResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public GetAccessPermissionDetailsResponseDetailsType GetAccessPermissionDetailsResponseDetails { + get { + return this.getAccessPermissionDetailsResponseDetailsField; + } + set { + this.getAccessPermissionDetailsResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateAccessPermissionsResponseType : AbstractResponseType { + + private string statusField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetAccessPermissionsResponseType : AbstractResponseType { + + private string tokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetAuthDetailsResponseType : AbstractResponseType { + + private GetAuthDetailsResponseDetailsType getAuthDetailsResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public GetAuthDetailsResponseDetailsType GetAuthDetailsResponseDetails { + get { + return this.getAuthDetailsResponseDetailsField; + } + set { + this.getAuthDetailsResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetAuthFlowParamResponseType : AbstractResponseType { + + private string tokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBoardingDetailsResponseType : AbstractResponseType { + + private GetBoardingDetailsResponseDetailsType getBoardingDetailsResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public GetBoardingDetailsResponseDetailsType GetBoardingDetailsResponseDetails { + get { + return this.getBoardingDetailsResponseDetailsField; + } + set { + this.getBoardingDetailsResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class EnterBoardingResponseType : AbstractResponseType { + + private string tokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class AddressVerifyResponseType : AbstractResponseType { + + private AddressStatusCodeType confirmationCodeField; + + private MatchStatusCodeType streetMatchField; + + private MatchStatusCodeType zipMatchField; + + private bool zipMatchFieldSpecified; + + private CountryCodeType countryCodeField; + + private bool countryCodeFieldSpecified; + + private string payPalTokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public AddressStatusCodeType ConfirmationCode { + get { + return this.confirmationCodeField; + } + set { + this.confirmationCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public MatchStatusCodeType StreetMatch { + get { + return this.streetMatchField; + } + set { + this.streetMatchField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public MatchStatusCodeType ZipMatch { + get { + return this.zipMatchField; + } + set { + this.zipMatchField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ZipMatchSpecified { + get { + return this.zipMatchFieldSpecified; + } + set { + this.zipMatchFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=3)] + public CountryCodeType CountryCode { + get { + return this.countryCodeField; + } + set { + this.countryCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CountryCodeSpecified { + get { + return this.countryCodeFieldSpecified; + } + set { + this.countryCodeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=4)] + public string PayPalToken { + get { + return this.payPalTokenField; + } + set { + this.payPalTokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum MatchStatusCodeType { + + /// + None, + + /// + Matched, + + /// + Unmatched, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BAUpdateResponseType : AbstractResponseType { + + private BAUpdateResponseDetailsType bAUpdateResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public BAUpdateResponseDetailsType BAUpdateResponseDetails { + get { + return this.bAUpdateResponseDetailsField; + } + set { + this.bAUpdateResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class MassPayResponseType : AbstractResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class TransactionSearchResponseType : AbstractResponseType { + + private PaymentTransactionSearchResultType[] paymentTransactionsField; + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentTransactions", Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public PaymentTransactionSearchResultType[] PaymentTransactions { + get { + return this.paymentTransactionsField; + } + set { + this.paymentTransactionsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BillUserResponseType : AbstractResponseType { + + private MerchantPullPaymentResponseType billUserResponseDetailsField; + + private FMFDetailsType fMFDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public MerchantPullPaymentResponseType BillUserResponseDetails { + get { + return this.billUserResponseDetailsField; + } + set { + this.billUserResponseDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public FMFDetailsType FMFDetails { + get { + return this.fMFDetailsField; + } + set { + this.fMFDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetTransactionDetailsResponseType : AbstractResponseType { + + private PaymentTransactionType paymentTransactionDetailsField; + + private ThreeDSecureInfoType threeDSecureDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public PaymentTransactionType PaymentTransactionDetails { + get { + return this.paymentTransactionDetailsField; + } + set { + this.paymentTransactionDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=1)] + public ThreeDSecureInfoType ThreeDSecureDetails { + get { + return this.threeDSecureDetailsField; + } + set { + this.threeDSecureDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CancelRecoupResponseType : AbstractResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CompleteRecoupResponseType : AbstractResponseType { + + private EnhancedCompleteRecoupResponseDetailsType enhancedCompleteRecoupResponseDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes", Order=0)] + public EnhancedCompleteRecoupResponseDetailsType EnhancedCompleteRecoupResponseDetails { + get { + return this.enhancedCompleteRecoupResponseDetailsField; + } + set { + this.enhancedCompleteRecoupResponseDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class InitiateRecoupResponseType : AbstractResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class RefundTransactionResponseType : AbstractResponseType { + + private string refundTransactionIDField; + + private BasicAmountType netRefundAmountField; + + private BasicAmountType feeRefundAmountField; + + private BasicAmountType grossRefundAmountField; + + private BasicAmountType totalRefundedAmountField; + + private RefundInfoType refundInfoField; + + private string receiptDataField; + + private string msgSubIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=0)] + public string RefundTransactionID { + get { + return this.refundTransactionIDField; + } + set { + this.refundTransactionIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public BasicAmountType NetRefundAmount { + get { + return this.netRefundAmountField; + } + set { + this.netRefundAmountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public BasicAmountType FeeRefundAmount { + get { + return this.feeRefundAmountField; + } + set { + this.feeRefundAmountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=3)] + public BasicAmountType GrossRefundAmount { + get { + return this.grossRefundAmountField; + } + set { + this.grossRefundAmountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=4)] + public BasicAmountType TotalRefundedAmount { + get { + return this.totalRefundedAmountField; + } + set { + this.totalRefundedAmountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=5)] + public RefundInfoType RefundInfo { + get { + return this.refundInfoField; + } + set { + this.refundInfoField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=6)] + public string ReceiptData { + get { + return this.receiptDataField; + } + set { + this.receiptDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=7)] + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMButtonSearchResponseType : AbstractResponseType { + + private ButtonSearchResultType[] buttonSearchResultField; + + /// + [System.Xml.Serialization.XmlElementAttribute("ButtonSearchResult", Namespace="urn:ebay:apis:eBLBaseComponents", Order=0)] + public ButtonSearchResultType[] ButtonSearchResult { + get { + return this.buttonSearchResultField; + } + set { + this.buttonSearchResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMGetInventoryResponseType : AbstractResponseType { + + private string hostedButtonIDField; + + private string trackInvField; + + private string trackPnlField; + + private ItemTrackingDetailsType itemTrackingDetailsField; + + private string optionIndexField; + + private string optionNameField; + + private OptionTrackingDetailsType[] optionTrackingDetailsField; + + private string soldoutURLField; + + private string[] digitalDownloadKeysField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string TrackInv { + get { + return this.trackInvField; + } + set { + this.trackInvField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string TrackPnl { + get { + return this.trackPnlField; + } + set { + this.trackPnlField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents", Order=3)] + public ItemTrackingDetailsType ItemTrackingDetails { + get { + return this.itemTrackingDetailsField; + } + set { + this.itemTrackingDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=4)] + public string OptionIndex { + get { + return this.optionIndexField; + } + set { + this.optionIndexField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=5)] + public string OptionName { + get { + return this.optionNameField; + } + set { + this.optionNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OptionTrackingDetails", Namespace="urn:ebay:apis:eBLBaseComponents", Order=6)] + public OptionTrackingDetailsType[] OptionTrackingDetails { + get { + return this.optionTrackingDetailsField; + } + set { + this.optionTrackingDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=7)] + public string SoldoutURL { + get { + return this.soldoutURLField; + } + set { + this.soldoutURLField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("DigitalDownloadKeys", Order=8)] + public string[] DigitalDownloadKeys { + get { + return this.digitalDownloadKeysField; + } + set { + this.digitalDownloadKeysField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ItemTrackingDetailsType { + + private string itemNumberField; + + private string itemQtyField; + + private string itemQtyDeltaField; + + private string itemAlertField; + + private string itemCostField; + + /// + public string ItemNumber { + get { + return this.itemNumberField; + } + set { + this.itemNumberField = value; + } + } + + /// + public string ItemQty { + get { + return this.itemQtyField; + } + set { + this.itemQtyField = value; + } + } + + /// + public string ItemQtyDelta { + get { + return this.itemQtyDeltaField; + } + set { + this.itemQtyDeltaField = value; + } + } + + /// + public string ItemAlert { + get { + return this.itemAlertField; + } + set { + this.itemAlertField = value; + } + } + + /// + public string ItemCost { + get { + return this.itemCostField; + } + set { + this.itemCostField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class OptionTrackingDetailsType { + + private string optionNumberField; + + private string optionQtyField; + + private string optionSelectField; + + private string optionQtyDeltaField; + + private string optionAlertField; + + private string optionCostField; + + /// + public string OptionNumber { + get { + return this.optionNumberField; + } + set { + this.optionNumberField = value; + } + } + + /// + public string OptionQty { + get { + return this.optionQtyField; + } + set { + this.optionQtyField = value; + } + } + + /// + public string OptionSelect { + get { + return this.optionSelectField; + } + set { + this.optionSelectField = value; + } + } + + /// + public string OptionQtyDelta { + get { + return this.optionQtyDeltaField; + } + set { + this.optionQtyDeltaField = value; + } + } + + /// + public string OptionAlert { + get { + return this.optionAlertField; + } + set { + this.optionAlertField = value; + } + } + + /// + public string OptionCost { + get { + return this.optionCostField; + } + set { + this.optionCostField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMSetInventoryResponseType : AbstractResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMGetButtonDetailsResponseType : AbstractResponseType { + + private string websiteField; + + private string emailField; + + private string mobileField; + + private string hostedButtonIDField; + + private ButtonTypeType buttonTypeField; + + private bool buttonTypeFieldSpecified; + + private ButtonCodeType buttonCodeField; + + private bool buttonCodeFieldSpecified; + + private ButtonSubTypeType buttonSubTypeField; + + private bool buttonSubTypeFieldSpecified; + + private string[] buttonVarField; + + private OptionDetailsType[] optionDetailsField; + + private string[] textBoxField; + + private ButtonImageType buttonImageField; + + private bool buttonImageFieldSpecified; + + private string buttonImageURLField; + + private BuyNowTextType buyNowTextField; + + private bool buyNowTextFieldSpecified; + + private SubscribeTextType subscribeTextField; + + private bool subscribeTextFieldSpecified; + + private CountryCodeType buttonCountryField; + + private bool buttonCountryFieldSpecified; + + private string buttonLanguageField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Website { + get { + return this.websiteField; + } + set { + this.websiteField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string Mobile { + get { + return this.mobileField; + } + set { + this.mobileField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=3)] + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=4)] + public ButtonTypeType ButtonType { + get { + return this.buttonTypeField; + } + set { + this.buttonTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonTypeSpecified { + get { + return this.buttonTypeFieldSpecified; + } + set { + this.buttonTypeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=5)] + public ButtonCodeType ButtonCode { + get { + return this.buttonCodeField; + } + set { + this.buttonCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonCodeSpecified { + get { + return this.buttonCodeFieldSpecified; + } + set { + this.buttonCodeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=6)] + public ButtonSubTypeType ButtonSubType { + get { + return this.buttonSubTypeField; + } + set { + this.buttonSubTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonSubTypeSpecified { + get { + return this.buttonSubTypeFieldSpecified; + } + set { + this.buttonSubTypeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ButtonVar", Order=7)] + public string[] ButtonVar { + get { + return this.buttonVarField; + } + set { + this.buttonVarField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OptionDetails", Order=8)] + public OptionDetailsType[] OptionDetails { + get { + return this.optionDetailsField; + } + set { + this.optionDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("TextBox", Order=9)] + public string[] TextBox { + get { + return this.textBoxField; + } + set { + this.textBoxField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=10)] + public ButtonImageType ButtonImage { + get { + return this.buttonImageField; + } + set { + this.buttonImageField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonImageSpecified { + get { + return this.buttonImageFieldSpecified; + } + set { + this.buttonImageFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=11)] + public string ButtonImageURL { + get { + return this.buttonImageURLField; + } + set { + this.buttonImageURLField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=12)] + public BuyNowTextType BuyNowText { + get { + return this.buyNowTextField; + } + set { + this.buyNowTextField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BuyNowTextSpecified { + get { + return this.buyNowTextFieldSpecified; + } + set { + this.buyNowTextFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=13)] + public SubscribeTextType SubscribeText { + get { + return this.subscribeTextField; + } + set { + this.subscribeTextField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SubscribeTextSpecified { + get { + return this.subscribeTextFieldSpecified; + } + set { + this.subscribeTextFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=14)] + public CountryCodeType ButtonCountry { + get { + return this.buttonCountryField; + } + set { + this.buttonCountryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonCountrySpecified { + get { + return this.buttonCountryFieldSpecified; + } + set { + this.buttonCountryFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=15)] + public string ButtonLanguage { + get { + return this.buttonLanguageField; + } + set { + this.buttonLanguageField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ButtonTypeType { + + /// + BUYNOW, + + /// + CART, + + /// + GIFTCERTIFICATE, + + /// + SUBSCRIBE, + + /// + DONATE, + + /// + UNSUBSCRIBE, + + /// + VIEWCART, + + /// + PAYMENTPLAN, + + /// + AUTOBILLING, + + /// + PAYMENT, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ButtonCodeType { + + /// + HOSTED, + + /// + ENCRYPTED, + + /// + CLEARTEXT, + + /// + TOKEN, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ButtonSubTypeType { + + /// + PRODUCTS, + + /// + SERVICES, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class OptionDetailsType { + + private string optionNameField; + + private OptionSelectionDetailsType[] optionSelectionDetailsField; + + /// + public string OptionName { + get { + return this.optionNameField; + } + set { + this.optionNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OptionSelectionDetails")] + public OptionSelectionDetailsType[] OptionSelectionDetails { + get { + return this.optionSelectionDetailsField; + } + set { + this.optionSelectionDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class OptionSelectionDetailsType { + + private string optionSelectionField; + + private string priceField; + + private OptionTypeListType optionTypeField; + + private bool optionTypeFieldSpecified; + + private InstallmentDetailsType[] paymentPeriodField; + + /// + public string OptionSelection { + get { + return this.optionSelectionField; + } + set { + this.optionSelectionField = value; + } + } + + /// + public string Price { + get { + return this.priceField; + } + set { + this.priceField = value; + } + } + + /// + public OptionTypeListType OptionType { + get { + return this.optionTypeField; + } + set { + this.optionTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool OptionTypeSpecified { + get { + return this.optionTypeFieldSpecified; + } + set { + this.optionTypeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentPeriod")] + public InstallmentDetailsType[] PaymentPeriod { + get { + return this.paymentPeriodField; + } + set { + this.paymentPeriodField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum OptionTypeListType { + + /// + NoOptionType, + + /// + FULL, + + /// + EMI, + + /// + VARIABLE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class InstallmentDetailsType { + + private BillingPeriodType billingPeriodField; + + private bool billingPeriodFieldSpecified; + + private int billingFrequencyField; + + private bool billingFrequencyFieldSpecified; + + private int totalBillingCyclesField; + + private bool totalBillingCyclesFieldSpecified; + + private string amountField; + + private string shippingAmountField; + + private string taxAmountField; + + /// + public BillingPeriodType BillingPeriod { + get { + return this.billingPeriodField; + } + set { + this.billingPeriodField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BillingPeriodSpecified { + get { + return this.billingPeriodFieldSpecified; + } + set { + this.billingPeriodFieldSpecified = value; + } + } + + /// + public int BillingFrequency { + get { + return this.billingFrequencyField; + } + set { + this.billingFrequencyField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BillingFrequencySpecified { + get { + return this.billingFrequencyFieldSpecified; + } + set { + this.billingFrequencyFieldSpecified = value; + } + } + + /// + public int TotalBillingCycles { + get { + return this.totalBillingCyclesField; + } + set { + this.totalBillingCyclesField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TotalBillingCyclesSpecified { + get { + return this.totalBillingCyclesFieldSpecified; + } + set { + this.totalBillingCyclesFieldSpecified = value; + } + } + + /// + public string Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string ShippingAmount { + get { + return this.shippingAmountField; + } + set { + this.shippingAmountField = value; + } + } + + /// + public string TaxAmount { + get { + return this.taxAmountField; + } + set { + this.taxAmountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ButtonImageType { + + /// + REG, + + /// + SML, + + /// + CC, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BuyNowTextType { + + /// + BUYNOW, + + /// + PAYNOW, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum SubscribeTextType { + + /// + BUYNOW, + + /// + SUBSCRIBE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMManageButtonStatusResponseType : AbstractResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMUpdateButtonResponseType : AbstractResponseType { + + private string websiteField; + + private string emailField; + + private string mobileField; + + private string hostedButtonIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Website { + get { + return this.websiteField; + } + set { + this.websiteField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string Mobile { + get { + return this.mobileField; + } + set { + this.mobileField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=3)] + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMCreateButtonResponseType : AbstractResponseType { + + private string websiteField; + + private string emailField; + + private string mobileField; + + private string hostedButtonIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=0)] + public string Website { + get { + return this.websiteField; + } + set { + this.websiteField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=1)] + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=2)] + public string Mobile { + get { + return this.mobileField; + } + set { + this.mobileField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Order=3)] + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ReverseTransactionRequestDetailsType { + + private string transactionIDField; + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BillingPeriodDetailsType_Update { + + private BillingPeriodType billingPeriodField; + + private bool billingPeriodFieldSpecified; + + private int billingFrequencyField; + + private bool billingFrequencyFieldSpecified; + + private int totalBillingCyclesField; + + private bool totalBillingCyclesFieldSpecified; + + private BasicAmountType amountField; + + private BasicAmountType shippingAmountField; + + private BasicAmountType taxAmountField; + + /// + public BillingPeriodType BillingPeriod { + get { + return this.billingPeriodField; + } + set { + this.billingPeriodField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BillingPeriodSpecified { + get { + return this.billingPeriodFieldSpecified; + } + set { + this.billingPeriodFieldSpecified = value; + } + } + + /// + public int BillingFrequency { + get { + return this.billingFrequencyField; + } + set { + this.billingFrequencyField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BillingFrequencySpecified { + get { + return this.billingFrequencyFieldSpecified; + } + set { + this.billingFrequencyFieldSpecified = value; + } + } + + /// + public int TotalBillingCycles { + get { + return this.totalBillingCyclesField; + } + set { + this.totalBillingCyclesField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TotalBillingCyclesSpecified { + get { + return this.totalBillingCyclesFieldSpecified; + } + set { + this.totalBillingCyclesFieldSpecified = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public BasicAmountType ShippingAmount { + get { + return this.shippingAmountField; + } + set { + this.shippingAmountField = value; + } + } + + /// + public BasicAmountType TaxAmount { + get { + return this.taxAmountField; + } + set { + this.taxAmountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class UpdateRecurringPaymentsProfileRequestDetailsType { + + private string profileIDField; + + private string noteField; + + private string descriptionField; + + private string subscriberNameField; + + private AddressType subscriberShippingAddressField; + + private string profileReferenceField; + + private int additionalBillingCyclesField; + + private bool additionalBillingCyclesFieldSpecified; + + private BasicAmountType amountField; + + private BasicAmountType shippingAmountField; + + private BasicAmountType taxAmountField; + + private BasicAmountType outstandingBalanceField; + + private AutoBillType autoBillOutstandingAmountField; + + private bool autoBillOutstandingAmountFieldSpecified; + + private int maxFailedPaymentsField; + + private bool maxFailedPaymentsFieldSpecified; + + private CreditCardDetailsType creditCardField; + + private System.DateTime billingStartDateField; + + private bool billingStartDateFieldSpecified; + + private BillingPeriodDetailsType_Update trialPeriodField; + + private BillingPeriodDetailsType_Update paymentPeriodField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + + /// + public string SubscriberName { + get { + return this.subscriberNameField; + } + set { + this.subscriberNameField = value; + } + } + + /// + public AddressType SubscriberShippingAddress { + get { + return this.subscriberShippingAddressField; + } + set { + this.subscriberShippingAddressField = value; + } + } + + /// + public string ProfileReference { + get { + return this.profileReferenceField; + } + set { + this.profileReferenceField = value; + } + } + + /// + public int AdditionalBillingCycles { + get { + return this.additionalBillingCyclesField; + } + set { + this.additionalBillingCyclesField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AdditionalBillingCyclesSpecified { + get { + return this.additionalBillingCyclesFieldSpecified; + } + set { + this.additionalBillingCyclesFieldSpecified = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public BasicAmountType ShippingAmount { + get { + return this.shippingAmountField; + } + set { + this.shippingAmountField = value; + } + } + + /// + public BasicAmountType TaxAmount { + get { + return this.taxAmountField; + } + set { + this.taxAmountField = value; + } + } + + /// + public BasicAmountType OutstandingBalance { + get { + return this.outstandingBalanceField; + } + set { + this.outstandingBalanceField = value; + } + } + + /// + public AutoBillType AutoBillOutstandingAmount { + get { + return this.autoBillOutstandingAmountField; + } + set { + this.autoBillOutstandingAmountField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AutoBillOutstandingAmountSpecified { + get { + return this.autoBillOutstandingAmountFieldSpecified; + } + set { + this.autoBillOutstandingAmountFieldSpecified = value; + } + } + + /// + public int MaxFailedPayments { + get { + return this.maxFailedPaymentsField; + } + set { + this.maxFailedPaymentsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MaxFailedPaymentsSpecified { + get { + return this.maxFailedPaymentsFieldSpecified; + } + set { + this.maxFailedPaymentsFieldSpecified = value; + } + } + + /// + public CreditCardDetailsType CreditCard { + get { + return this.creditCardField; + } + set { + this.creditCardField = value; + } + } + + /// + public System.DateTime BillingStartDate { + get { + return this.billingStartDateField; + } + set { + this.billingStartDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BillingStartDateSpecified { + get { + return this.billingStartDateFieldSpecified; + } + set { + this.billingStartDateFieldSpecified = value; + } + } + + /// + public BillingPeriodDetailsType_Update TrialPeriod { + get { + return this.trialPeriodField; + } + set { + this.trialPeriodField = value; + } + } + + /// + public BillingPeriodDetailsType_Update PaymentPeriod { + get { + return this.paymentPeriodField; + } + set { + this.paymentPeriodField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BillOutstandingAmountRequestDetailsType { + + private string profileIDField; + + private BasicAmountType amountField; + + private string noteField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ManageRecurringPaymentsProfileStatusRequestDetailsType { + + private string profileIDField; + + private StatusChangeActionType actionField; + + private string noteField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + + /// + public StatusChangeActionType Action { + get { + return this.actionField; + } + set { + this.actionField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum StatusChangeActionType { + + /// + Cancel, + + /// + Suspend, + + /// + Reactivate, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ActivationDetailsType { + + private BasicAmountType initialAmountField; + + private FailedPaymentActionType failedInitialAmountActionField; + + private bool failedInitialAmountActionFieldSpecified; + + /// + public BasicAmountType InitialAmount { + get { + return this.initialAmountField; + } + set { + this.initialAmountField = value; + } + } + + /// + public FailedPaymentActionType FailedInitialAmountAction { + get { + return this.failedInitialAmountActionField; + } + set { + this.failedInitialAmountActionField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FailedInitialAmountActionSpecified { + get { + return this.failedInitialAmountActionFieldSpecified; + } + set { + this.failedInitialAmountActionFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum FailedPaymentActionType { + + /// + CancelOnFailure, + + /// + ContinueOnFailure, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ScheduleDetailsType { + + private string descriptionField; + + private BillingPeriodDetailsType trialPeriodField; + + private BillingPeriodDetailsType paymentPeriodField; + + private int maxFailedPaymentsField; + + private bool maxFailedPaymentsFieldSpecified; + + private ActivationDetailsType activationDetailsField; + + private AutoBillType autoBillOutstandingAmountField; + + private bool autoBillOutstandingAmountFieldSpecified; + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + + /// + public BillingPeriodDetailsType TrialPeriod { + get { + return this.trialPeriodField; + } + set { + this.trialPeriodField = value; + } + } + + /// + public BillingPeriodDetailsType PaymentPeriod { + get { + return this.paymentPeriodField; + } + set { + this.paymentPeriodField = value; + } + } + + /// + public int MaxFailedPayments { + get { + return this.maxFailedPaymentsField; + } + set { + this.maxFailedPaymentsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MaxFailedPaymentsSpecified { + get { + return this.maxFailedPaymentsFieldSpecified; + } + set { + this.maxFailedPaymentsFieldSpecified = value; + } + } + + /// + public ActivationDetailsType ActivationDetails { + get { + return this.activationDetailsField; + } + set { + this.activationDetailsField = value; + } + } + + /// + public AutoBillType AutoBillOutstandingAmount { + get { + return this.autoBillOutstandingAmountField; + } + set { + this.autoBillOutstandingAmountField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AutoBillOutstandingAmountSpecified { + get { + return this.autoBillOutstandingAmountFieldSpecified; + } + set { + this.autoBillOutstandingAmountFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class CreateRecurringPaymentsProfileRequestDetailsType { + + private string tokenField; + + private CreditCardDetailsType creditCardField; + + private RecurringPaymentsProfileDetailsType recurringPaymentsProfileDetailsField; + + private ScheduleDetailsType scheduleDetailsField; + + private PaymentDetailsItemType[] paymentDetailsItemField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + + /// + public CreditCardDetailsType CreditCard { + get { + return this.creditCardField; + } + set { + this.creditCardField = value; + } + } + + /// + public RecurringPaymentsProfileDetailsType RecurringPaymentsProfileDetails { + get { + return this.recurringPaymentsProfileDetailsField; + } + set { + this.recurringPaymentsProfileDetailsField = value; + } + } + + /// + public ScheduleDetailsType ScheduleDetails { + get { + return this.scheduleDetailsField; + } + set { + this.scheduleDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentDetailsItem")] + public PaymentDetailsItemType[] PaymentDetailsItem { + get { + return this.paymentDetailsItemField; + } + set { + this.paymentDetailsItemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoNonReferencedCreditRequestDetailsType { + + private BasicAmountType amountField; + + private BasicAmountType netAmountField; + + private BasicAmountType taxAmountField; + + private BasicAmountType shippingAmountField; + + private CreditCardDetailsType creditCardField; + + private string receiverEmailField; + + private string commentField; + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public BasicAmountType NetAmount { + get { + return this.netAmountField; + } + set { + this.netAmountField = value; + } + } + + /// + public BasicAmountType TaxAmount { + get { + return this.taxAmountField; + } + set { + this.taxAmountField = value; + } + } + + /// + public BasicAmountType ShippingAmount { + get { + return this.shippingAmountField; + } + set { + this.shippingAmountField = value; + } + } + + /// + public CreditCardDetailsType CreditCard { + get { + return this.creditCardField; + } + set { + this.creditCardField = value; + } + } + + /// + public string ReceiverEmail { + get { + return this.receiverEmailField; + } + set { + this.receiverEmailField = value; + } + } + + /// + public string Comment { + get { + return this.commentField; + } + set { + this.commentField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DeviceDetailsType { + + private string deviceIDField; + + /// + public string DeviceID { + get { + return this.deviceIDField; + } + set { + this.deviceIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SenderDetailsType { + + private DeviceDetailsType deviceDetailsField; + + /// + public DeviceDetailsType DeviceDetails { + get { + return this.deviceDetailsField; + } + set { + this.deviceDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class CreditCardNumberTypeType { + + private CreditCardTypeType creditCardTypeField; + + private bool creditCardTypeFieldSpecified; + + private string creditCardNumberField; + + /// + public CreditCardTypeType CreditCardType { + get { + return this.creditCardTypeField; + } + set { + this.creditCardTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CreditCardTypeSpecified { + get { + return this.creditCardTypeFieldSpecified; + } + set { + this.creditCardTypeFieldSpecified = value; + } + } + + /// + public string CreditCardNumber { + get { + return this.creditCardNumberField; + } + set { + this.creditCardNumberField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ReferenceCreditCardDetailsType { + + private CreditCardNumberTypeType creditCardNumberTypeField; + + private int expMonthField; + + private bool expMonthFieldSpecified; + + private int expYearField; + + private bool expYearFieldSpecified; + + private PersonNameType cardOwnerNameField; + + private AddressType billingAddressField; + + private string cVV2Field; + + private int startMonthField; + + private bool startMonthFieldSpecified; + + private int startYearField; + + private bool startYearFieldSpecified; + + private string issueNumberField; + + /// + public CreditCardNumberTypeType CreditCardNumberType { + get { + return this.creditCardNumberTypeField; + } + set { + this.creditCardNumberTypeField = value; + } + } + + /// + public int ExpMonth { + get { + return this.expMonthField; + } + set { + this.expMonthField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExpMonthSpecified { + get { + return this.expMonthFieldSpecified; + } + set { + this.expMonthFieldSpecified = value; + } + } + + /// + public int ExpYear { + get { + return this.expYearField; + } + set { + this.expYearField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ExpYearSpecified { + get { + return this.expYearFieldSpecified; + } + set { + this.expYearFieldSpecified = value; + } + } + + /// + public PersonNameType CardOwnerName { + get { + return this.cardOwnerNameField; + } + set { + this.cardOwnerNameField = value; + } + } + + /// + public AddressType BillingAddress { + get { + return this.billingAddressField; + } + set { + this.billingAddressField = value; + } + } + + /// + public string CVV2 { + get { + return this.cVV2Field; + } + set { + this.cVV2Field = value; + } + } + + /// + public int StartMonth { + get { + return this.startMonthField; + } + set { + this.startMonthField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StartMonthSpecified { + get { + return this.startMonthFieldSpecified; + } + set { + this.startMonthFieldSpecified = value; + } + } + + /// + public int StartYear { + get { + return this.startYearField; + } + set { + this.startYearField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StartYearSpecified { + get { + return this.startYearFieldSpecified; + } + set { + this.startYearFieldSpecified = value; + } + } + + /// + public string IssueNumber { + get { + return this.issueNumberField; + } + set { + this.issueNumberField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoReferenceTransactionRequestDetailsType { + + private string referenceIDField; + + private PaymentActionCodeType paymentActionField; + + private MerchantPullPaymentCodeType paymentTypeField; + + private bool paymentTypeFieldSpecified; + + private PaymentDetailsType paymentDetailsField; + + private ReferenceCreditCardDetailsType creditCardField; + + private string iPAddressField; + + private string merchantSessionIdField; + + private string reqConfirmShippingField; + + private string softDescriptorField; + + private SenderDetailsType senderDetailsField; + + private string msgSubIDField; + + /// + public string ReferenceID { + get { + return this.referenceIDField; + } + set { + this.referenceIDField = value; + } + } + + /// + public PaymentActionCodeType PaymentAction { + get { + return this.paymentActionField; + } + set { + this.paymentActionField = value; + } + } + + /// + public MerchantPullPaymentCodeType PaymentType { + get { + return this.paymentTypeField; + } + set { + this.paymentTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentTypeSpecified { + get { + return this.paymentTypeFieldSpecified; + } + set { + this.paymentTypeFieldSpecified = value; + } + } + + /// + public PaymentDetailsType PaymentDetails { + get { + return this.paymentDetailsField; + } + set { + this.paymentDetailsField = value; + } + } + + /// + public ReferenceCreditCardDetailsType CreditCard { + get { + return this.creditCardField; + } + set { + this.creditCardField = value; + } + } + + /// + public string IPAddress { + get { + return this.iPAddressField; + } + set { + this.iPAddressField = value; + } + } + + /// + public string MerchantSessionId { + get { + return this.merchantSessionIdField; + } + set { + this.merchantSessionIdField = value; + } + } + + /// + public string ReqConfirmShipping { + get { + return this.reqConfirmShippingField; + } + set { + this.reqConfirmShippingField = value; + } + } + + /// + public string SoftDescriptor { + get { + return this.softDescriptorField; + } + set { + this.softDescriptorField = value; + } + } + + /// + public SenderDetailsType SenderDetails { + get { + return this.senderDetailsField; + } + set { + this.senderDetailsField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum MerchantPullPaymentCodeType { + + /// + Any, + + /// + InstantOnly, + + /// + EcheckOnly, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SetCustomerBillingAgreementRequestDetailsType { + + private BillingAgreementDetailsType billingAgreementDetailsField; + + private string returnURLField; + + private string cancelURLField; + + private string localeCodeField; + + private string pageStyleField; + + private string cppheaderimageField; + + private string cppheaderbordercolorField; + + private string cppheaderbackcolorField; + + private string cpppayflowcolorField; + + private string buyerEmailField; + + private string reqBillingAddressField; + + /// + public BillingAgreementDetailsType BillingAgreementDetails { + get { + return this.billingAgreementDetailsField; + } + set { + this.billingAgreementDetailsField = value; + } + } + + /// + public string ReturnURL { + get { + return this.returnURLField; + } + set { + this.returnURLField = value; + } + } + + /// + public string CancelURL { + get { + return this.cancelURLField; + } + set { + this.cancelURLField = value; + } + } + + /// + public string LocaleCode { + get { + return this.localeCodeField; + } + set { + this.localeCodeField = value; + } + } + + /// + public string PageStyle { + get { + return this.pageStyleField; + } + set { + this.pageStyleField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-image")] + public string cppheaderimage { + get { + return this.cppheaderimageField; + } + set { + this.cppheaderimageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-border-color")] + public string cppheaderbordercolor { + get { + return this.cppheaderbordercolorField; + } + set { + this.cppheaderbordercolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-back-color")] + public string cppheaderbackcolor { + get { + return this.cppheaderbackcolorField; + } + set { + this.cppheaderbackcolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-payflow-color")] + public string cpppayflowcolor { + get { + return this.cpppayflowcolorField; + } + set { + this.cpppayflowcolorField = value; + } + } + + /// + public string BuyerEmail { + get { + return this.buyerEmailField; + } + set { + this.buyerEmailField = value; + } + } + + /// + public string ReqBillingAddress { + get { + return this.reqBillingAddressField; + } + set { + this.reqBillingAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BillingAgreementDetailsType { + + private BillingCodeType billingTypeField; + + private string billingAgreementDescriptionField; + + private MerchantPullPaymentCodeType paymentTypeField; + + private bool paymentTypeFieldSpecified; + + private string billingAgreementCustomField; + + /// + public BillingCodeType BillingType { + get { + return this.billingTypeField; + } + set { + this.billingTypeField = value; + } + } + + /// + public string BillingAgreementDescription { + get { + return this.billingAgreementDescriptionField; + } + set { + this.billingAgreementDescriptionField = value; + } + } + + /// + public MerchantPullPaymentCodeType PaymentType { + get { + return this.paymentTypeField; + } + set { + this.paymentTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentTypeSpecified { + get { + return this.paymentTypeFieldSpecified; + } + set { + this.paymentTypeFieldSpecified = value; + } + } + + /// + public string BillingAgreementCustom { + get { + return this.billingAgreementCustomField; + } + set { + this.billingAgreementCustomField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BillingCodeType { + + /// + None, + + /// + MerchantInitiatedBilling, + + /// + RecurringPayments, + + /// + MerchantInitiatedBillingSingleAgreement, + + /// + ChannelInitiatedBilling, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SetMobileCheckoutRequestDetailsType { + + private PhoneNumberType buyerPhoneField; + + private BasicAmountType itemAmountField; + + private BasicAmountType taxField; + + private BasicAmountType shippingField; + + private string itemNameField; + + private string itemNumberField; + + private string customField; + + private string invoiceIDField; + + private string returnURLField; + + private string cancelURLField; + + private int addressDisplayOptionsField; + + private bool addressDisplayOptionsFieldSpecified; + + private int sharePhoneField; + + private bool sharePhoneFieldSpecified; + + private AddressType shipToAddressField; + + private string buyerEmailField; + + /// + public PhoneNumberType BuyerPhone { + get { + return this.buyerPhoneField; + } + set { + this.buyerPhoneField = value; + } + } + + /// + public BasicAmountType ItemAmount { + get { + return this.itemAmountField; + } + set { + this.itemAmountField = value; + } + } + + /// + public BasicAmountType Tax { + get { + return this.taxField; + } + set { + this.taxField = value; + } + } + + /// + public BasicAmountType Shipping { + get { + return this.shippingField; + } + set { + this.shippingField = value; + } + } + + /// + public string ItemName { + get { + return this.itemNameField; + } + set { + this.itemNameField = value; + } + } + + /// + public string ItemNumber { + get { + return this.itemNumberField; + } + set { + this.itemNumberField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public string ReturnURL { + get { + return this.returnURLField; + } + set { + this.returnURLField = value; + } + } + + /// + public string CancelURL { + get { + return this.cancelURLField; + } + set { + this.cancelURLField = value; + } + } + + /// + public int AddressDisplayOptions { + get { + return this.addressDisplayOptionsField; + } + set { + this.addressDisplayOptionsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AddressDisplayOptionsSpecified { + get { + return this.addressDisplayOptionsFieldSpecified; + } + set { + this.addressDisplayOptionsFieldSpecified = value; + } + } + + /// + public int SharePhone { + get { + return this.sharePhoneField; + } + set { + this.sharePhoneField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SharePhoneSpecified { + get { + return this.sharePhoneFieldSpecified; + } + set { + this.sharePhoneFieldSpecified = value; + } + } + + /// + public AddressType ShipToAddress { + get { + return this.shipToAddressField; + } + set { + this.shipToAddressField = value; + } + } + + /// + public string BuyerEmail { + get { + return this.buyerEmailField; + } + set { + this.buyerEmailField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PhoneNumberType { + + private string countryCodeField; + + private string phoneNumberField; + + private string extensionField; + + /// + public string CountryCode { + get { + return this.countryCodeField; + } + set { + this.countryCodeField = value; + } + } + + /// + public string PhoneNumber { + get { + return this.phoneNumberField; + } + set { + this.phoneNumberField = value; + } + } + + /// + public string Extension { + get { + return this.extensionField; + } + set { + this.extensionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetMobileStatusRequestDetailsType { + + private PhoneNumberType phoneField; + + /// + public PhoneNumberType Phone { + get { + return this.phoneField; + } + set { + this.phoneField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class CreateMobilePaymentRequestDetailsType { + + private MobilePaymentCodeType paymentTypeField; + + private PaymentActionCodeType paymentActionField; + + private PhoneNumberType senderPhoneField; + + private MobileRecipientCodeType recipientTypeField; + + private string recipientEmailField; + + private PhoneNumberType recipientPhoneField; + + private BasicAmountType itemAmountField; + + private BasicAmountType taxField; + + private BasicAmountType shippingField; + + private string itemNameField; + + private string itemNumberField; + + private string noteField; + + private string customIDField; + + private string sharePhoneNumberField; + + private string shareHomeAddressField; + + /// + public MobilePaymentCodeType PaymentType { + get { + return this.paymentTypeField; + } + set { + this.paymentTypeField = value; + } + } + + /// + public PaymentActionCodeType PaymentAction { + get { + return this.paymentActionField; + } + set { + this.paymentActionField = value; + } + } + + /// + public PhoneNumberType SenderPhone { + get { + return this.senderPhoneField; + } + set { + this.senderPhoneField = value; + } + } + + /// + public MobileRecipientCodeType RecipientType { + get { + return this.recipientTypeField; + } + set { + this.recipientTypeField = value; + } + } + + /// + public string RecipientEmail { + get { + return this.recipientEmailField; + } + set { + this.recipientEmailField = value; + } + } + + /// + public PhoneNumberType RecipientPhone { + get { + return this.recipientPhoneField; + } + set { + this.recipientPhoneField = value; + } + } + + /// + public BasicAmountType ItemAmount { + get { + return this.itemAmountField; + } + set { + this.itemAmountField = value; + } + } + + /// + public BasicAmountType Tax { + get { + return this.taxField; + } + set { + this.taxField = value; + } + } + + /// + public BasicAmountType Shipping { + get { + return this.shippingField; + } + set { + this.shippingField = value; + } + } + + /// + public string ItemName { + get { + return this.itemNameField; + } + set { + this.itemNameField = value; + } + } + + /// + public string ItemNumber { + get { + return this.itemNumberField; + } + set { + this.itemNumberField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + + /// + public string CustomID { + get { + return this.customIDField; + } + set { + this.customIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string SharePhoneNumber { + get { + return this.sharePhoneNumberField; + } + set { + this.sharePhoneNumberField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string ShareHomeAddress { + get { + return this.shareHomeAddressField; + } + set { + this.shareHomeAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum MobilePaymentCodeType { + + /// + P2P, + + /// + HardGoods, + + /// + Donation, + + /// + TopUp, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum MobileRecipientCodeType { + + /// + PhoneNumber, + + /// + EmailAddress, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class TupleType { + + private string keyField; + + private string valueField; + + /// + public string Key { + get { + return this.keyField; + } + set { + this.keyField = value; + } + } + + /// + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoDirectPaymentRequestDetailsType { + + private PaymentActionCodeType paymentActionField; + + private PaymentDetailsType paymentDetailsField; + + private CreditCardDetailsType creditCardField; + + private string iPAddressField; + + private string merchantSessionIdField; + + private bool returnFMFDetailsField; + + private bool returnFMFDetailsFieldSpecified; + + /// + public PaymentActionCodeType PaymentAction { + get { + return this.paymentActionField; + } + set { + this.paymentActionField = value; + } + } + + /// + public PaymentDetailsType PaymentDetails { + get { + return this.paymentDetailsField; + } + set { + this.paymentDetailsField = value; + } + } + + /// + public CreditCardDetailsType CreditCard { + get { + return this.creditCardField; + } + set { + this.creditCardField = value; + } + } + + /// + public string IPAddress { + get { + return this.iPAddressField; + } + set { + this.iPAddressField = value; + } + } + + /// + public string MerchantSessionId { + get { + return this.merchantSessionIdField; + } + set { + this.merchantSessionIdField = value; + } + } + + /// + public bool ReturnFMFDetails { + get { + return this.returnFMFDetailsField; + } + set { + this.returnFMFDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReturnFMFDetailsSpecified { + get { + return this.returnFMFDetailsFieldSpecified; + } + set { + this.returnFMFDetailsFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class FlightDetailsType { + + private string conjuctionTicketField; + + private string exchangeTicketField; + + private string couponNumberField; + + private string serviceClassField; + + private string travelDateField; + + private string carrierCodeField; + + private string stopOverPermittedField; + + private string departureAirportField; + + private string arrivalAirportField; + + private string flightNumberField; + + private string departureTimeField; + + private string arrivalTimeField; + + private string fareBasisCodeField; + + private BasicAmountType fareField; + + private BasicAmountType taxesField; + + private BasicAmountType feeField; + + private string endorsementOrRestrictionsField; + + /// + public string ConjuctionTicket { + get { + return this.conjuctionTicketField; + } + set { + this.conjuctionTicketField = value; + } + } + + /// + public string ExchangeTicket { + get { + return this.exchangeTicketField; + } + set { + this.exchangeTicketField = value; + } + } + + /// + public string CouponNumber { + get { + return this.couponNumberField; + } + set { + this.couponNumberField = value; + } + } + + /// + public string ServiceClass { + get { + return this.serviceClassField; + } + set { + this.serviceClassField = value; + } + } + + /// + public string TravelDate { + get { + return this.travelDateField; + } + set { + this.travelDateField = value; + } + } + + /// + public string CarrierCode { + get { + return this.carrierCodeField; + } + set { + this.carrierCodeField = value; + } + } + + /// + public string StopOverPermitted { + get { + return this.stopOverPermittedField; + } + set { + this.stopOverPermittedField = value; + } + } + + /// + public string DepartureAirport { + get { + return this.departureAirportField; + } + set { + this.departureAirportField = value; + } + } + + /// + public string ArrivalAirport { + get { + return this.arrivalAirportField; + } + set { + this.arrivalAirportField = value; + } + } + + /// + public string FlightNumber { + get { + return this.flightNumberField; + } + set { + this.flightNumberField = value; + } + } + + /// + public string DepartureTime { + get { + return this.departureTimeField; + } + set { + this.departureTimeField = value; + } + } + + /// + public string ArrivalTime { + get { + return this.arrivalTimeField; + } + set { + this.arrivalTimeField = value; + } + } + + /// + public string FareBasisCode { + get { + return this.fareBasisCodeField; + } + set { + this.fareBasisCodeField = value; + } + } + + /// + public BasicAmountType Fare { + get { + return this.fareField; + } + set { + this.fareField = value; + } + } + + /// + public BasicAmountType Taxes { + get { + return this.taxesField; + } + set { + this.taxesField = value; + } + } + + /// + public BasicAmountType Fee { + get { + return this.feeField; + } + set { + this.feeField = value; + } + } + + /// + public string EndorsementOrRestrictions { + get { + return this.endorsementOrRestrictionsField; + } + set { + this.endorsementOrRestrictionsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class AirlineItineraryType { + + private string passengerNameField; + + private string issueDateField; + + private string travelAgencyNameField; + + private string travelAgencyCodeField; + + private string ticketNumberField; + + private string issuingCarrierCodeField; + + private string customerCodeField; + + private BasicAmountType totalFareField; + + private BasicAmountType totalTaxesField; + + private BasicAmountType totalFeeField; + + private string restrictedTicketField; + + private string clearingSequenceField; + + private string clearingCountField; + + private FlightDetailsType[] flightDetailsField; + + /// + public string PassengerName { + get { + return this.passengerNameField; + } + set { + this.passengerNameField = value; + } + } + + /// + public string IssueDate { + get { + return this.issueDateField; + } + set { + this.issueDateField = value; + } + } + + /// + public string TravelAgencyName { + get { + return this.travelAgencyNameField; + } + set { + this.travelAgencyNameField = value; + } + } + + /// + public string TravelAgencyCode { + get { + return this.travelAgencyCodeField; + } + set { + this.travelAgencyCodeField = value; + } + } + + /// + public string TicketNumber { + get { + return this.ticketNumberField; + } + set { + this.ticketNumberField = value; + } + } + + /// + public string IssuingCarrierCode { + get { + return this.issuingCarrierCodeField; + } + set { + this.issuingCarrierCodeField = value; + } + } + + /// + public string CustomerCode { + get { + return this.customerCodeField; + } + set { + this.customerCodeField = value; + } + } + + /// + public BasicAmountType TotalFare { + get { + return this.totalFareField; + } + set { + this.totalFareField = value; + } + } + + /// + public BasicAmountType TotalTaxes { + get { + return this.totalTaxesField; + } + set { + this.totalTaxesField = value; + } + } + + /// + public BasicAmountType TotalFee { + get { + return this.totalFeeField; + } + set { + this.totalFeeField = value; + } + } + + /// + public string RestrictedTicket { + get { + return this.restrictedTicketField; + } + set { + this.restrictedTicketField = value; + } + } + + /// + public string ClearingSequence { + get { + return this.clearingSequenceField; + } + set { + this.clearingSequenceField = value; + } + } + + /// + public string ClearingCount { + get { + return this.clearingCountField; + } + set { + this.clearingCountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("FlightDetails")] + public FlightDetailsType[] FlightDetails { + get { + return this.flightDetailsField; + } + set { + this.flightDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class EnhancedDataType { + + private AirlineItineraryType airlineItineraryField; + + /// + public AirlineItineraryType AirlineItinerary { + get { + return this.airlineItineraryField; + } + set { + this.airlineItineraryField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DoExpressCheckoutPaymentRequestDetailsType { + + private PaymentActionCodeType paymentActionField; + + private bool paymentActionFieldSpecified; + + private string tokenField; + + private string payerIDField; + + private string orderURLField; + + private PaymentDetailsType[] paymentDetailsField; + + private string promoOverrideFlagField; + + private string promoCodeField; + + private EnhancedDataType enhancedDataField; + + private string softDescriptorField; + + private UserSelectedOptionType userSelectedOptionsField; + + private string giftMessageField; + + private string giftReceiptEnableField; + + private string giftWrapNameField; + + private BasicAmountType giftWrapAmountField; + + private string buyerMarketingEmailField; + + private string surveyQuestionField; + + private string[] surveyChoiceSelectedField; + + private string buttonSourceField; + + private bool skipBACreationField; + + private bool skipBACreationFieldSpecified; + + private CoupledBucketsType[] coupledBucketsField; + + /// + public PaymentActionCodeType PaymentAction { + get { + return this.paymentActionField; + } + set { + this.paymentActionField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentActionSpecified { + get { + return this.paymentActionFieldSpecified; + } + set { + this.paymentActionFieldSpecified = value; + } + } + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + + /// + public string PayerID { + get { + return this.payerIDField; + } + set { + this.payerIDField = value; + } + } + + /// + public string OrderURL { + get { + return this.orderURLField; + } + set { + this.orderURLField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentDetails")] + public PaymentDetailsType[] PaymentDetails { + get { + return this.paymentDetailsField; + } + set { + this.paymentDetailsField = value; + } + } + + /// + public string PromoOverrideFlag { + get { + return this.promoOverrideFlagField; + } + set { + this.promoOverrideFlagField = value; + } + } + + /// + public string PromoCode { + get { + return this.promoCodeField; + } + set { + this.promoCodeField = value; + } + } + + /// + public EnhancedDataType EnhancedData { + get { + return this.enhancedDataField; + } + set { + this.enhancedDataField = value; + } + } + + /// + public string SoftDescriptor { + get { + return this.softDescriptorField; + } + set { + this.softDescriptorField = value; + } + } + + /// + public UserSelectedOptionType UserSelectedOptions { + get { + return this.userSelectedOptionsField; + } + set { + this.userSelectedOptionsField = value; + } + } + + /// + public string GiftMessage { + get { + return this.giftMessageField; + } + set { + this.giftMessageField = value; + } + } + + /// + public string GiftReceiptEnable { + get { + return this.giftReceiptEnableField; + } + set { + this.giftReceiptEnableField = value; + } + } + + /// + public string GiftWrapName { + get { + return this.giftWrapNameField; + } + set { + this.giftWrapNameField = value; + } + } + + /// + public BasicAmountType GiftWrapAmount { + get { + return this.giftWrapAmountField; + } + set { + this.giftWrapAmountField = value; + } + } + + /// + public string BuyerMarketingEmail { + get { + return this.buyerMarketingEmailField; + } + set { + this.buyerMarketingEmailField = value; + } + } + + /// + public string SurveyQuestion { + get { + return this.surveyQuestionField; + } + set { + this.surveyQuestionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("SurveyChoiceSelected")] + public string[] SurveyChoiceSelected { + get { + return this.surveyChoiceSelectedField; + } + set { + this.surveyChoiceSelectedField = value; + } + } + + /// + public string ButtonSource { + get { + return this.buttonSourceField; + } + set { + this.buttonSourceField = value; + } + } + + /// + public bool SkipBACreation { + get { + return this.skipBACreationField; + } + set { + this.skipBACreationField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SkipBACreationSpecified { + get { + return this.skipBACreationFieldSpecified; + } + set { + this.skipBACreationFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("CoupledBuckets")] + public CoupledBucketsType[] CoupledBuckets { + get { + return this.coupledBucketsField; + } + set { + this.coupledBucketsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class CoupledBucketsType { + + private CoupleType coupleTypeField; + + private bool coupleTypeFieldSpecified; + + private string coupledPaymentRequestIDField; + + private string[] paymentRequestIDField; + + /// + public CoupleType CoupleType { + get { + return this.coupleTypeField; + } + set { + this.coupleTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CoupleTypeSpecified { + get { + return this.coupleTypeFieldSpecified; + } + set { + this.coupleTypeFieldSpecified = value; + } + } + + /// + public string CoupledPaymentRequestID { + get { + return this.coupledPaymentRequestIDField; + } + set { + this.coupledPaymentRequestIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentRequestID")] + public string[] PaymentRequestID { + get { + return this.paymentRequestIDField; + } + set { + this.paymentRequestIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum CoupleType { + + /// + LifeTime, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class AuthorizationRequestType { + + private bool isRequestedField; + + /// + public bool IsRequested { + get { + return this.isRequestedField; + } + set { + this.isRequestedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class InfoSharingDirectivesType { + + private string reqBillingAddressField; + + /// + public string ReqBillingAddress { + get { + return this.reqBillingAddressField; + } + set { + this.reqBillingAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BuyerDetailType { + + private IdentificationInfoType identificationInfoField; + + /// + public IdentificationInfoType IdentificationInfo { + get { + return this.identificationInfoField; + } + set { + this.identificationInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IdentificationInfoType { + + private MobileIDInfoType mobileIDInfoField; + + private RememberMeIDInfoType rememberMeIDInfoField; + + private IdentityTokenInfoType identityTokenInfoField; + + /// + public MobileIDInfoType MobileIDInfo { + get { + return this.mobileIDInfoField; + } + set { + this.mobileIDInfoField = value; + } + } + + /// + public RememberMeIDInfoType RememberMeIDInfo { + get { + return this.rememberMeIDInfoField; + } + set { + this.rememberMeIDInfoField = value; + } + } + + /// + public IdentityTokenInfoType IdentityTokenInfo { + get { + return this.identityTokenInfoField; + } + set { + this.identityTokenInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class MobileIDInfoType { + + private string sessionTokenField; + + /// + public string SessionToken { + get { + return this.sessionTokenField; + } + set { + this.sessionTokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class RememberMeIDInfoType { + + private string externalRememberMeIDField; + + /// + public string ExternalRememberMeID { + get { + return this.externalRememberMeIDField; + } + set { + this.externalRememberMeIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IdentityTokenInfoType { + + private string accessTokenField; + + /// + public string AccessToken { + get { + return this.accessTokenField; + } + set { + this.accessTokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class PaymentDirectivesType { + + private MerchantPullPaymentCodeType paymentTypeField; + + private bool paymentTypeFieldSpecified; + + /// + public MerchantPullPaymentCodeType PaymentType { + get { + return this.paymentTypeField; + } + set { + this.paymentTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentTypeSpecified { + get { + return this.paymentTypeFieldSpecified; + } + set { + this.paymentTypeFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class OrderDetailsType { + + private string descriptionField; + + private BasicAmountType maxAmountField; + + /// + public string Description { + get { + return this.descriptionField; + } + set { + this.descriptionField = value; + } + } + + /// + public BasicAmountType MaxAmount { + get { + return this.maxAmountField; + } + set { + this.maxAmountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BillingApprovalDetailsType { + + private ApprovalTypeType approvalTypeField; + + private ApprovalSubTypeType approvalSubTypeField; + + private bool approvalSubTypeFieldSpecified; + + private OrderDetailsType orderDetailsField; + + private PaymentDirectivesType paymentDirectivesField; + + private string customField; + + /// + public ApprovalTypeType ApprovalType { + get { + return this.approvalTypeField; + } + set { + this.approvalTypeField = value; + } + } + + /// + public ApprovalSubTypeType ApprovalSubType { + get { + return this.approvalSubTypeField; + } + set { + this.approvalSubTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ApprovalSubTypeSpecified { + get { + return this.approvalSubTypeFieldSpecified; + } + set { + this.approvalSubTypeFieldSpecified = value; + } + } + + /// + public OrderDetailsType OrderDetails { + get { + return this.orderDetailsField; + } + set { + this.orderDetailsField = value; + } + } + + /// + public PaymentDirectivesType PaymentDirectives { + get { + return this.paymentDirectivesField; + } + set { + this.paymentDirectivesField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ApprovalTypeType { + + /// + BillingAgreement, + + /// + Profile, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ApprovalSubTypeType { + + /// + None, + + /// + MerchantInitiatedBilling, + + /// + MerchantInitiatedBillingSingleAgreement, + + /// + ChannelInitiatedBilling, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SetDataRequestType { + + private BillingApprovalDetailsType[] billingApprovalDetailsField; + + private BuyerDetailType buyerDetailField; + + private InfoSharingDirectivesType infoSharingDirectivesField; + + private bool retrieveShippingAddressField; + + private bool retrieveShippingAddressFieldSpecified; + + private UserChannelCodeType userChannelField; + + private bool userChannelFieldSpecified; + + private bool reqConfirmShippingField; + + private bool reqConfirmShippingFieldSpecified; + + private PaymentDetailsType[] paymentDetailsField; + + private ExternalPartnerTrackingDetailsType externalPartnerTrackingDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute("BillingApprovalDetails")] + public BillingApprovalDetailsType[] BillingApprovalDetails { + get { + return this.billingApprovalDetailsField; + } + set { + this.billingApprovalDetailsField = value; + } + } + + /// + public BuyerDetailType BuyerDetail { + get { + return this.buyerDetailField; + } + set { + this.buyerDetailField = value; + } + } + + /// + public InfoSharingDirectivesType InfoSharingDirectives { + get { + return this.infoSharingDirectivesField; + } + set { + this.infoSharingDirectivesField = value; + } + } + + /// + public bool RetrieveShippingAddress { + get { + return this.retrieveShippingAddressField; + } + set { + this.retrieveShippingAddressField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RetrieveShippingAddressSpecified { + get { + return this.retrieveShippingAddressFieldSpecified; + } + set { + this.retrieveShippingAddressFieldSpecified = value; + } + } + + /// + public UserChannelCodeType UserChannel { + get { + return this.userChannelField; + } + set { + this.userChannelField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool UserChannelSpecified { + get { + return this.userChannelFieldSpecified; + } + set { + this.userChannelFieldSpecified = value; + } + } + + /// + public bool ReqConfirmShipping { + get { + return this.reqConfirmShippingField; + } + set { + this.reqConfirmShippingField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReqConfirmShippingSpecified { + get { + return this.reqConfirmShippingFieldSpecified; + } + set { + this.reqConfirmShippingFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentDetails")] + public PaymentDetailsType[] PaymentDetails { + get { + return this.paymentDetailsField; + } + set { + this.paymentDetailsField = value; + } + } + + /// + public ExternalPartnerTrackingDetailsType ExternalPartnerTrackingDetails { + get { + return this.externalPartnerTrackingDetailsField; + } + set { + this.externalPartnerTrackingDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum UserChannelCodeType { + + /// + WEB, + + /// + MOBILE, + + /// + POS, + + /// + KIOSK, + + /// + IHSTB, + + /// + IVR, + + /// + ADMIN, + + /// + CSOPS, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ExternalPartnerTrackingDetailsType { + + private string externalPartnerSegmentIDField; + + /// + public string ExternalPartnerSegmentID { + get { + return this.externalPartnerSegmentIDField; + } + set { + this.externalPartnerSegmentIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ExecuteCheckoutOperationsRequestDetailsType { + + private string tokenField; + + private SetDataRequestType setDataRequestField; + + private AuthorizationRequestType authorizationRequestField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + + /// + public SetDataRequestType SetDataRequest { + get { + return this.setDataRequestField; + } + set { + this.setDataRequestField = value; + } + } + + /// + public AuthorizationRequestType AuthorizationRequest { + get { + return this.authorizationRequestField; + } + set { + this.authorizationRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class DisplayControlDetailsType { + + private string inContextPaymentButtonImageField; + + /// + public string InContextPaymentButtonImage { + get { + return this.inContextPaymentButtonImageField; + } + set { + this.inContextPaymentButtonImageField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class FlowControlDetailsType { + + private string errorURLField; + + private string inContextReturnURLField; + + /// + public string ErrorURL { + get { + return this.errorURLField; + } + set { + this.errorURLField = value; + } + } + + /// + public string InContextReturnURL { + get { + return this.inContextReturnURLField; + } + set { + this.inContextReturnURLField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ExternalRememberMeOwnerDetailsType { + + private string externalRememberMeOwnerIDTypeField; + + private string externalRememberMeOwnerIDField; + + /// + public string ExternalRememberMeOwnerIDType { + get { + return this.externalRememberMeOwnerIDTypeField; + } + set { + this.externalRememberMeOwnerIDTypeField = value; + } + } + + /// + public string ExternalRememberMeOwnerID { + get { + return this.externalRememberMeOwnerIDField; + } + set { + this.externalRememberMeOwnerIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ExternalRememberMeOptInDetailsType { + + private string externalRememberMeOptInField; + + private ExternalRememberMeOwnerDetailsType externalRememberMeOwnerDetailsField; + + /// + public string ExternalRememberMeOptIn { + get { + return this.externalRememberMeOptInField; + } + set { + this.externalRememberMeOptInField = value; + } + } + + /// + public ExternalRememberMeOwnerDetailsType ExternalRememberMeOwnerDetails { + get { + return this.externalRememberMeOwnerDetailsField; + } + set { + this.externalRememberMeOwnerDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveInfoType { + + private string incentiveCodeField; + + private IncentiveApplyIndicationType[] applyIndicationField; + + /// + public string IncentiveCode { + get { + return this.incentiveCodeField; + } + set { + this.incentiveCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ApplyIndication")] + public IncentiveApplyIndicationType[] ApplyIndication { + get { + return this.applyIndicationField; + } + set { + this.applyIndicationField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveApplyIndicationType { + + private string paymentRequestIDField; + + private string itemIdField; + + /// + public string PaymentRequestID { + get { + return this.paymentRequestIDField; + } + set { + this.paymentRequestIDField = value; + } + } + + /// + public string ItemId { + get { + return this.itemIdField; + } + set { + this.itemIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class ShippingOptionType { + + private string shippingOptionIsDefaultField; + + private BasicAmountType shippingOptionAmountField; + + private string shippingOptionNameField; + + /// + public string ShippingOptionIsDefault { + get { + return this.shippingOptionIsDefaultField; + } + set { + this.shippingOptionIsDefaultField = value; + } + } + + /// + public BasicAmountType ShippingOptionAmount { + get { + return this.shippingOptionAmountField; + } + set { + this.shippingOptionAmountField = value; + } + } + + /// + public string ShippingOptionName { + get { + return this.shippingOptionNameField; + } + set { + this.shippingOptionNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BuyerDetailsType { + + private string buyerIdField; + + private string buyerUserNameField; + + private System.DateTime buyerRegistrationDateField; + + private bool buyerRegistrationDateFieldSpecified; + + private TaxIdDetailsType taxIdDetailsField; + + private IdentificationInfoType identificationInfoField; + + /// + public string BuyerId { + get { + return this.buyerIdField; + } + set { + this.buyerIdField = value; + } + } + + /// + public string BuyerUserName { + get { + return this.buyerUserNameField; + } + set { + this.buyerUserNameField = value; + } + } + + /// + public System.DateTime BuyerRegistrationDate { + get { + return this.buyerRegistrationDateField; + } + set { + this.buyerRegistrationDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BuyerRegistrationDateSpecified { + get { + return this.buyerRegistrationDateFieldSpecified; + } + set { + this.buyerRegistrationDateFieldSpecified = value; + } + } + + /// + public TaxIdDetailsType TaxIdDetails { + get { + return this.taxIdDetailsField; + } + set { + this.taxIdDetailsField = value; + } + } + + /// + public IdentificationInfoType IdentificationInfo { + get { + return this.identificationInfoField; + } + set { + this.identificationInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class OtherPaymentMethodDetailsType { + + private string otherPaymentMethodIdField; + + private string otherPaymentMethodTypeField; + + private string otherPaymentMethodLabelField; + + private string otherPaymentMethodLabelDescriptionField; + + private string otherPaymentMethodLongDescriptionTitleField; + + private string otherPaymentMethodLongDescriptionField; + + private string otherPaymentMethodIconField; + + private bool otherPaymentMethodHideLabelField; + + private bool otherPaymentMethodHideLabelFieldSpecified; + + /// + public string OtherPaymentMethodId { + get { + return this.otherPaymentMethodIdField; + } + set { + this.otherPaymentMethodIdField = value; + } + } + + /// + public string OtherPaymentMethodType { + get { + return this.otherPaymentMethodTypeField; + } + set { + this.otherPaymentMethodTypeField = value; + } + } + + /// + public string OtherPaymentMethodLabel { + get { + return this.otherPaymentMethodLabelField; + } + set { + this.otherPaymentMethodLabelField = value; + } + } + + /// + public string OtherPaymentMethodLabelDescription { + get { + return this.otherPaymentMethodLabelDescriptionField; + } + set { + this.otherPaymentMethodLabelDescriptionField = value; + } + } + + /// + public string OtherPaymentMethodLongDescriptionTitle { + get { + return this.otherPaymentMethodLongDescriptionTitleField; + } + set { + this.otherPaymentMethodLongDescriptionTitleField = value; + } + } + + /// + public string OtherPaymentMethodLongDescription { + get { + return this.otherPaymentMethodLongDescriptionField; + } + set { + this.otherPaymentMethodLongDescriptionField = value; + } + } + + /// + public string OtherPaymentMethodIcon { + get { + return this.otherPaymentMethodIconField; + } + set { + this.otherPaymentMethodIconField = value; + } + } + + /// + public bool OtherPaymentMethodHideLabel { + get { + return this.otherPaymentMethodHideLabelField; + } + set { + this.otherPaymentMethodHideLabelField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool OtherPaymentMethodHideLabelSpecified { + get { + return this.otherPaymentMethodHideLabelFieldSpecified; + } + set { + this.otherPaymentMethodHideLabelFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedCheckoutDataType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class FundingSourceDetailsType { + + private string allowPushFundingField; + + private UserSelectedFundingSourceType userSelectedFundingSourceField; + + private bool userSelectedFundingSourceFieldSpecified; + + /// + public string AllowPushFunding { + get { + return this.allowPushFundingField; + } + set { + this.allowPushFundingField = value; + } + } + + /// + public UserSelectedFundingSourceType UserSelectedFundingSource { + get { + return this.userSelectedFundingSourceField; + } + set { + this.userSelectedFundingSourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool UserSelectedFundingSourceSpecified { + get { + return this.userSelectedFundingSourceFieldSpecified; + } + set { + this.userSelectedFundingSourceFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum UserSelectedFundingSourceType { + + /// + ELV, + + /// + CreditCard, + + /// + ChinaUnionPay, + + /// + BML, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SetExpressCheckoutRequestDetailsType { + + private BasicAmountType orderTotalField; + + private string returnURLField; + + private string cancelURLField; + + private string trackingImageURLField; + + private string giropaySuccessURLField; + + private string giropayCancelURLField; + + private string banktxnPendingURLField; + + private string tokenField; + + private BasicAmountType maxAmountField; + + private string orderDescriptionField; + + private string customField; + + private string invoiceIDField; + + private string reqConfirmShippingField; + + private string reqBillingAddressField; + + private AddressType billingAddressField; + + private string noShippingField; + + private string addressOverrideField; + + private string localeCodeField; + + private string pageStyleField; + + private string cppheaderimageField; + + private string cppheaderbordercolorField; + + private string cppheaderbackcolorField; + + private string cpppayflowcolorField; + + private string cppcartbordercolorField; + + private string cpplogoimageField; + + private AddressType addressField; + + private PaymentActionCodeType paymentActionField; + + private bool paymentActionFieldSpecified; + + private SolutionTypeType solutionTypeField; + + private bool solutionTypeFieldSpecified; + + private LandingPageType landingPageField; + + private bool landingPageFieldSpecified; + + private string buyerEmailField; + + private ChannelType channelTypeField; + + private bool channelTypeFieldSpecified; + + private BillingAgreementDetailsType[] billingAgreementDetailsField; + + private string[] promoCodesField; + + private string payPalCheckOutBtnTypeField; + + private ProductCategoryType productCategoryField; + + private bool productCategoryFieldSpecified; + + private ShippingServiceCodeType shippingMethodField; + + private bool shippingMethodFieldSpecified; + + private System.DateTime profileAddressChangeDateField; + + private bool profileAddressChangeDateFieldSpecified; + + private string allowNoteField; + + private FundingSourceDetailsType fundingSourceDetailsField; + + private string brandNameField; + + private string callbackURLField; + + private EnhancedCheckoutDataType enhancedCheckoutDataField; + + private OtherPaymentMethodDetailsType[] otherPaymentMethodsField; + + private BuyerDetailsType buyerDetailsField; + + private PaymentDetailsType[] paymentDetailsField; + + private ShippingOptionType[] flatRateShippingOptionsField; + + private string callbackTimeoutField; + + private string callbackVersionField; + + private string customerServiceNumberField; + + private string giftMessageEnableField; + + private string giftReceiptEnableField; + + private string giftWrapEnableField; + + private string giftWrapNameField; + + private BasicAmountType giftWrapAmountField; + + private string buyerEmailOptInEnableField; + + private string surveyEnableField; + + private string surveyQuestionField; + + private string[] surveyChoiceField; + + private TotalType totalTypeField; + + private bool totalTypeFieldSpecified; + + private string noteToBuyerField; + + private IncentiveInfoType[] incentivesField; + + private string reqInstrumentDetailsField; + + private ExternalRememberMeOptInDetailsType externalRememberMeOptInDetailsField; + + private FlowControlDetailsType flowControlDetailsField; + + private DisplayControlDetailsType displayControlDetailsField; + + private ExternalPartnerTrackingDetailsType externalPartnerTrackingDetailsField; + + private CoupledBucketsType[] coupledBucketsField; + + /// + public BasicAmountType OrderTotal { + get { + return this.orderTotalField; + } + set { + this.orderTotalField = value; + } + } + + /// + public string ReturnURL { + get { + return this.returnURLField; + } + set { + this.returnURLField = value; + } + } + + /// + public string CancelURL { + get { + return this.cancelURLField; + } + set { + this.cancelURLField = value; + } + } + + /// + public string TrackingImageURL { + get { + return this.trackingImageURLField; + } + set { + this.trackingImageURLField = value; + } + } + + /// + public string giropaySuccessURL { + get { + return this.giropaySuccessURLField; + } + set { + this.giropaySuccessURLField = value; + } + } + + /// + public string giropayCancelURL { + get { + return this.giropayCancelURLField; + } + set { + this.giropayCancelURLField = value; + } + } + + /// + public string BanktxnPendingURL { + get { + return this.banktxnPendingURLField; + } + set { + this.banktxnPendingURLField = value; + } + } + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + + /// + public BasicAmountType MaxAmount { + get { + return this.maxAmountField; + } + set { + this.maxAmountField = value; + } + } + + /// + public string OrderDescription { + get { + return this.orderDescriptionField; + } + set { + this.orderDescriptionField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public string ReqConfirmShipping { + get { + return this.reqConfirmShippingField; + } + set { + this.reqConfirmShippingField = value; + } + } + + /// + public string ReqBillingAddress { + get { + return this.reqBillingAddressField; + } + set { + this.reqBillingAddressField = value; + } + } + + /// + public AddressType BillingAddress { + get { + return this.billingAddressField; + } + set { + this.billingAddressField = value; + } + } + + /// + public string NoShipping { + get { + return this.noShippingField; + } + set { + this.noShippingField = value; + } + } + + /// + public string AddressOverride { + get { + return this.addressOverrideField; + } + set { + this.addressOverrideField = value; + } + } + + /// + public string LocaleCode { + get { + return this.localeCodeField; + } + set { + this.localeCodeField = value; + } + } + + /// + public string PageStyle { + get { + return this.pageStyleField; + } + set { + this.pageStyleField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-image")] + public string cppheaderimage { + get { + return this.cppheaderimageField; + } + set { + this.cppheaderimageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-border-color")] + public string cppheaderbordercolor { + get { + return this.cppheaderbordercolorField; + } + set { + this.cppheaderbordercolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-back-color")] + public string cppheaderbackcolor { + get { + return this.cppheaderbackcolorField; + } + set { + this.cppheaderbackcolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-payflow-color")] + public string cpppayflowcolor { + get { + return this.cpppayflowcolorField; + } + set { + this.cpppayflowcolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-cart-border-color")] + public string cppcartbordercolor { + get { + return this.cppcartbordercolorField; + } + set { + this.cppcartbordercolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-logo-image")] + public string cpplogoimage { + get { + return this.cpplogoimageField; + } + set { + this.cpplogoimageField = value; + } + } + + /// + public AddressType Address { + get { + return this.addressField; + } + set { + this.addressField = value; + } + } + + /// + public PaymentActionCodeType PaymentAction { + get { + return this.paymentActionField; + } + set { + this.paymentActionField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentActionSpecified { + get { + return this.paymentActionFieldSpecified; + } + set { + this.paymentActionFieldSpecified = value; + } + } + + /// + public SolutionTypeType SolutionType { + get { + return this.solutionTypeField; + } + set { + this.solutionTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SolutionTypeSpecified { + get { + return this.solutionTypeFieldSpecified; + } + set { + this.solutionTypeFieldSpecified = value; + } + } + + /// + public LandingPageType LandingPage { + get { + return this.landingPageField; + } + set { + this.landingPageField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool LandingPageSpecified { + get { + return this.landingPageFieldSpecified; + } + set { + this.landingPageFieldSpecified = value; + } + } + + /// + public string BuyerEmail { + get { + return this.buyerEmailField; + } + set { + this.buyerEmailField = value; + } + } + + /// + public ChannelType ChannelType { + get { + return this.channelTypeField; + } + set { + this.channelTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ChannelTypeSpecified { + get { + return this.channelTypeFieldSpecified; + } + set { + this.channelTypeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("BillingAgreementDetails")] + public BillingAgreementDetailsType[] BillingAgreementDetails { + get { + return this.billingAgreementDetailsField; + } + set { + this.billingAgreementDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PromoCodes")] + public string[] PromoCodes { + get { + return this.promoCodesField; + } + set { + this.promoCodesField = value; + } + } + + /// + public string PayPalCheckOutBtnType { + get { + return this.payPalCheckOutBtnTypeField; + } + set { + this.payPalCheckOutBtnTypeField = value; + } + } + + /// + public ProductCategoryType ProductCategory { + get { + return this.productCategoryField; + } + set { + this.productCategoryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProductCategorySpecified { + get { + return this.productCategoryFieldSpecified; + } + set { + this.productCategoryFieldSpecified = value; + } + } + + /// + public ShippingServiceCodeType ShippingMethod { + get { + return this.shippingMethodField; + } + set { + this.shippingMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ShippingMethodSpecified { + get { + return this.shippingMethodFieldSpecified; + } + set { + this.shippingMethodFieldSpecified = value; + } + } + + /// + public System.DateTime ProfileAddressChangeDate { + get { + return this.profileAddressChangeDateField; + } + set { + this.profileAddressChangeDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProfileAddressChangeDateSpecified { + get { + return this.profileAddressChangeDateFieldSpecified; + } + set { + this.profileAddressChangeDateFieldSpecified = value; + } + } + + /// + public string AllowNote { + get { + return this.allowNoteField; + } + set { + this.allowNoteField = value; + } + } + + /// + public FundingSourceDetailsType FundingSourceDetails { + get { + return this.fundingSourceDetailsField; + } + set { + this.fundingSourceDetailsField = value; + } + } + + /// + public string BrandName { + get { + return this.brandNameField; + } + set { + this.brandNameField = value; + } + } + + /// + public string CallbackURL { + get { + return this.callbackURLField; + } + set { + this.callbackURLField = value; + } + } + + /// + public EnhancedCheckoutDataType EnhancedCheckoutData { + get { + return this.enhancedCheckoutDataField; + } + set { + this.enhancedCheckoutDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OtherPaymentMethods")] + public OtherPaymentMethodDetailsType[] OtherPaymentMethods { + get { + return this.otherPaymentMethodsField; + } + set { + this.otherPaymentMethodsField = value; + } + } + + /// + public BuyerDetailsType BuyerDetails { + get { + return this.buyerDetailsField; + } + set { + this.buyerDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentDetails")] + public PaymentDetailsType[] PaymentDetails { + get { + return this.paymentDetailsField; + } + set { + this.paymentDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("FlatRateShippingOptions")] + public ShippingOptionType[] FlatRateShippingOptions { + get { + return this.flatRateShippingOptionsField; + } + set { + this.flatRateShippingOptionsField = value; + } + } + + /// + public string CallbackTimeout { + get { + return this.callbackTimeoutField; + } + set { + this.callbackTimeoutField = value; + } + } + + /// + public string CallbackVersion { + get { + return this.callbackVersionField; + } + set { + this.callbackVersionField = value; + } + } + + /// + public string CustomerServiceNumber { + get { + return this.customerServiceNumberField; + } + set { + this.customerServiceNumberField = value; + } + } + + /// + public string GiftMessageEnable { + get { + return this.giftMessageEnableField; + } + set { + this.giftMessageEnableField = value; + } + } + + /// + public string GiftReceiptEnable { + get { + return this.giftReceiptEnableField; + } + set { + this.giftReceiptEnableField = value; + } + } + + /// + public string GiftWrapEnable { + get { + return this.giftWrapEnableField; + } + set { + this.giftWrapEnableField = value; + } + } + + /// + public string GiftWrapName { + get { + return this.giftWrapNameField; + } + set { + this.giftWrapNameField = value; + } + } + + /// + public BasicAmountType GiftWrapAmount { + get { + return this.giftWrapAmountField; + } + set { + this.giftWrapAmountField = value; + } + } + + /// + public string BuyerEmailOptInEnable { + get { + return this.buyerEmailOptInEnableField; + } + set { + this.buyerEmailOptInEnableField = value; + } + } + + /// + public string SurveyEnable { + get { + return this.surveyEnableField; + } + set { + this.surveyEnableField = value; + } + } + + /// + public string SurveyQuestion { + get { + return this.surveyQuestionField; + } + set { + this.surveyQuestionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("SurveyChoice")] + public string[] SurveyChoice { + get { + return this.surveyChoiceField; + } + set { + this.surveyChoiceField = value; + } + } + + /// + public TotalType TotalType { + get { + return this.totalTypeField; + } + set { + this.totalTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TotalTypeSpecified { + get { + return this.totalTypeFieldSpecified; + } + set { + this.totalTypeFieldSpecified = value; + } + } + + /// + public string NoteToBuyer { + get { + return this.noteToBuyerField; + } + set { + this.noteToBuyerField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Incentives")] + public IncentiveInfoType[] Incentives { + get { + return this.incentivesField; + } + set { + this.incentivesField = value; + } + } + + /// + public string ReqInstrumentDetails { + get { + return this.reqInstrumentDetailsField; + } + set { + this.reqInstrumentDetailsField = value; + } + } + + /// + public ExternalRememberMeOptInDetailsType ExternalRememberMeOptInDetails { + get { + return this.externalRememberMeOptInDetailsField; + } + set { + this.externalRememberMeOptInDetailsField = value; + } + } + + /// + public FlowControlDetailsType FlowControlDetails { + get { + return this.flowControlDetailsField; + } + set { + this.flowControlDetailsField = value; + } + } + + /// + public DisplayControlDetailsType DisplayControlDetails { + get { + return this.displayControlDetailsField; + } + set { + this.displayControlDetailsField = value; + } + } + + /// + public ExternalPartnerTrackingDetailsType ExternalPartnerTrackingDetails { + get { + return this.externalPartnerTrackingDetailsField; + } + set { + this.externalPartnerTrackingDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("CoupledBuckets")] + public CoupledBucketsType[] CoupledBuckets { + get { + return this.coupledBucketsField; + } + set { + this.coupledBucketsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum SolutionTypeType { + + /// + Mark, + + /// + Sole, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum LandingPageType { + + /// + None, + + /// + Login, + + /// + Billing, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ChannelType { + + /// + Merchant, + + /// + eBayItem, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum TotalType { + + /// + Total, + + /// + EstimatedTotal, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveRequestDetailsType { + + private string requestIdField; + + private IncentiveRequestCodeType requestTypeField; + + private bool requestTypeFieldSpecified; + + private IncentiveRequestDetailLevelCodeType requestDetailLevelField; + + private bool requestDetailLevelFieldSpecified; + + /// + public string RequestId { + get { + return this.requestIdField; + } + set { + this.requestIdField = value; + } + } + + /// + public IncentiveRequestCodeType RequestType { + get { + return this.requestTypeField; + } + set { + this.requestTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RequestTypeSpecified { + get { + return this.requestTypeFieldSpecified; + } + set { + this.requestTypeFieldSpecified = value; + } + } + + /// + public IncentiveRequestDetailLevelCodeType RequestDetailLevel { + get { + return this.requestDetailLevelField; + } + set { + this.requestDetailLevelField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RequestDetailLevelSpecified { + get { + return this.requestDetailLevelFieldSpecified; + } + set { + this.requestDetailLevelFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum IncentiveRequestCodeType { + + /// + InCheckout, + + /// + PreCheckout, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum IncentiveRequestDetailLevelCodeType { + + /// + Aggregated, + + /// + Detail, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveItemType { + + private string itemIdField; + + private System.DateTime purchaseTimeField; + + private bool purchaseTimeFieldSpecified; + + private string itemCategoryListField; + + private BasicAmountType itemPriceField; + + private string itemQuantityField; + + /// + public string ItemId { + get { + return this.itemIdField; + } + set { + this.itemIdField = value; + } + } + + /// + public System.DateTime PurchaseTime { + get { + return this.purchaseTimeField; + } + set { + this.purchaseTimeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PurchaseTimeSpecified { + get { + return this.purchaseTimeFieldSpecified; + } + set { + this.purchaseTimeFieldSpecified = value; + } + } + + /// + public string ItemCategoryList { + get { + return this.itemCategoryListField; + } + set { + this.itemCategoryListField = value; + } + } + + /// + public BasicAmountType ItemPrice { + get { + return this.itemPriceField; + } + set { + this.itemPriceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string ItemQuantity { + get { + return this.itemQuantityField; + } + set { + this.itemQuantityField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class IncentiveBucketType { + + private IncentiveItemType[] itemsField; + + private string bucketIdField; + + private string sellerIdField; + + private string externalSellerIdField; + + private BasicAmountType bucketSubtotalAmtField; + + private BasicAmountType bucketShippingAmtField; + + private BasicAmountType bucketInsuranceAmtField; + + private BasicAmountType bucketSalesTaxAmtField; + + private BasicAmountType bucketTotalAmtField; + + /// + [System.Xml.Serialization.XmlElementAttribute("Items")] + public IncentiveItemType[] Items { + get { + return this.itemsField; + } + set { + this.itemsField = value; + } + } + + /// + public string BucketId { + get { + return this.bucketIdField; + } + set { + this.bucketIdField = value; + } + } + + /// + public string SellerId { + get { + return this.sellerIdField; + } + set { + this.sellerIdField = value; + } + } + + /// + public string ExternalSellerId { + get { + return this.externalSellerIdField; + } + set { + this.externalSellerIdField = value; + } + } + + /// + public BasicAmountType BucketSubtotalAmt { + get { + return this.bucketSubtotalAmtField; + } + set { + this.bucketSubtotalAmtField = value; + } + } + + /// + public BasicAmountType BucketShippingAmt { + get { + return this.bucketShippingAmtField; + } + set { + this.bucketShippingAmtField = value; + } + } + + /// + public BasicAmountType BucketInsuranceAmt { + get { + return this.bucketInsuranceAmtField; + } + set { + this.bucketInsuranceAmtField = value; + } + } + + /// + public BasicAmountType BucketSalesTaxAmt { + get { + return this.bucketSalesTaxAmtField; + } + set { + this.bucketSalesTaxAmtField = value; + } + } + + /// + public BasicAmountType BucketTotalAmt { + get { + return this.bucketTotalAmtField; + } + set { + this.bucketTotalAmtField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class GetIncentiveEvaluationRequestDetailsType { + + private string externalBuyerIdField; + + private string[] incentiveCodesField; + + private IncentiveApplyIndicationType[] applyIndicationField; + + private IncentiveBucketType[] bucketsField; + + private BasicAmountType cartTotalAmtField; + + private IncentiveRequestDetailsType requestDetailsField; + + /// + public string ExternalBuyerId { + get { + return this.externalBuyerIdField; + } + set { + this.externalBuyerIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("IncentiveCodes")] + public string[] IncentiveCodes { + get { + return this.incentiveCodesField; + } + set { + this.incentiveCodesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ApplyIndication")] + public IncentiveApplyIndicationType[] ApplyIndication { + get { + return this.applyIndicationField; + } + set { + this.applyIndicationField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Buckets")] + public IncentiveBucketType[] Buckets { + get { + return this.bucketsField; + } + set { + this.bucketsField = value; + } + } + + /// + public BasicAmountType CartTotalAmt { + get { + return this.cartTotalAmtField; + } + set { + this.cartTotalAmtField = value; + } + } + + /// + public IncentiveRequestDetailsType RequestDetails { + get { + return this.requestDetailsField; + } + set { + this.requestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SetAccessPermissionsRequestDetailsType { + + private string returnURLField; + + private string cancelURLField; + + private string logoutURLField; + + private string initFlowTypeField; + + private string skipLoginPageField; + + private string[] requiredAccessPermissionsField; + + private string[] optionalAccessPermissionsField; + + private string localeCodeField; + + private string pageStyleField; + + private string cppheaderimageField; + + private string cppheaderbordercolorField; + + private string cppheaderbackcolorField; + + private string cpppayflowcolorField; + + private string firstNameField; + + private string lastNameField; + + private AddressType addressField; + + /// + public string ReturnURL { + get { + return this.returnURLField; + } + set { + this.returnURLField = value; + } + } + + /// + public string CancelURL { + get { + return this.cancelURLField; + } + set { + this.cancelURLField = value; + } + } + + /// + public string LogoutURL { + get { + return this.logoutURLField; + } + set { + this.logoutURLField = value; + } + } + + /// + public string InitFlowType { + get { + return this.initFlowTypeField; + } + set { + this.initFlowTypeField = value; + } + } + + /// + public string SkipLoginPage { + get { + return this.skipLoginPageField; + } + set { + this.skipLoginPageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("RequiredAccessPermissions")] + public string[] RequiredAccessPermissions { + get { + return this.requiredAccessPermissionsField; + } + set { + this.requiredAccessPermissionsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OptionalAccessPermissions")] + public string[] OptionalAccessPermissions { + get { + return this.optionalAccessPermissionsField; + } + set { + this.optionalAccessPermissionsField = value; + } + } + + /// + public string LocaleCode { + get { + return this.localeCodeField; + } + set { + this.localeCodeField = value; + } + } + + /// + public string PageStyle { + get { + return this.pageStyleField; + } + set { + this.pageStyleField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-image")] + public string cppheaderimage { + get { + return this.cppheaderimageField; + } + set { + this.cppheaderimageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-border-color")] + public string cppheaderbordercolor { + get { + return this.cppheaderbordercolorField; + } + set { + this.cppheaderbordercolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-back-color")] + public string cppheaderbackcolor { + get { + return this.cppheaderbackcolorField; + } + set { + this.cppheaderbackcolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-payflow-color")] + public string cpppayflowcolor { + get { + return this.cpppayflowcolorField; + } + set { + this.cpppayflowcolorField = value; + } + } + + /// + public string FirstName { + get { + return this.firstNameField; + } + set { + this.firstNameField = value; + } + } + + /// + public string LastName { + get { + return this.lastNameField; + } + set { + this.lastNameField = value; + } + } + + /// + public AddressType Address { + get { + return this.addressField; + } + set { + this.addressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class SetAuthFlowParamRequestDetailsType { + + private string returnURLField; + + private string cancelURLField; + + private string logoutURLField; + + private string initFlowTypeField; + + private string skipLoginPageField; + + private string serviceName1Field; + + private string serviceDefReq1Field; + + private string serviceName2Field; + + private string serviceDefReq2Field; + + private string localeCodeField; + + private string pageStyleField; + + private string cppheaderimageField; + + private string cppheaderbordercolorField; + + private string cppheaderbackcolorField; + + private string cpppayflowcolorField; + + private string firstNameField; + + private string lastNameField; + + private AddressType addressField; + + /// + public string ReturnURL { + get { + return this.returnURLField; + } + set { + this.returnURLField = value; + } + } + + /// + public string CancelURL { + get { + return this.cancelURLField; + } + set { + this.cancelURLField = value; + } + } + + /// + public string LogoutURL { + get { + return this.logoutURLField; + } + set { + this.logoutURLField = value; + } + } + + /// + public string InitFlowType { + get { + return this.initFlowTypeField; + } + set { + this.initFlowTypeField = value; + } + } + + /// + public string SkipLoginPage { + get { + return this.skipLoginPageField; + } + set { + this.skipLoginPageField = value; + } + } + + /// + public string ServiceName1 { + get { + return this.serviceName1Field; + } + set { + this.serviceName1Field = value; + } + } + + /// + public string ServiceDefReq1 { + get { + return this.serviceDefReq1Field; + } + set { + this.serviceDefReq1Field = value; + } + } + + /// + public string ServiceName2 { + get { + return this.serviceName2Field; + } + set { + this.serviceName2Field = value; + } + } + + /// + public string ServiceDefReq2 { + get { + return this.serviceDefReq2Field; + } + set { + this.serviceDefReq2Field = value; + } + } + + /// + public string LocaleCode { + get { + return this.localeCodeField; + } + set { + this.localeCodeField = value; + } + } + + /// + public string PageStyle { + get { + return this.pageStyleField; + } + set { + this.pageStyleField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-image")] + public string cppheaderimage { + get { + return this.cppheaderimageField; + } + set { + this.cppheaderimageField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-border-color")] + public string cppheaderbordercolor { + get { + return this.cppheaderbordercolorField; + } + set { + this.cppheaderbordercolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-header-back-color")] + public string cppheaderbackcolor { + get { + return this.cppheaderbackcolorField; + } + set { + this.cppheaderbackcolorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("cpp-payflow-color")] + public string cpppayflowcolor { + get { + return this.cpppayflowcolorField; + } + set { + this.cpppayflowcolorField = value; + } + } + + /// + public string FirstName { + get { + return this.firstNameField; + } + set { + this.firstNameField = value; + } + } + + /// + public string LastName { + get { + return this.lastNameField; + } + set { + this.lastNameField = value; + } + } + + /// + public AddressType Address { + get { + return this.addressField; + } + set { + this.addressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BankAccountDetailsType { + + private string nameField; + + private BankAccountTypeType typeField; + + private string routingNumberField; + + private string accountNumberField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public BankAccountTypeType Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public string RoutingNumber { + get { + return this.routingNumberField; + } + set { + this.routingNumberField = value; + } + } + + /// + public string AccountNumber { + get { + return this.accountNumberField; + } + set { + this.accountNumberField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BankAccountTypeType { + + /// + Checking, + + /// + Savings, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BusinessOwnerInfoType { + + private PayerInfoType ownerField; + + private string homePhoneField; + + private string mobilePhoneField; + + private string sSNField; + + /// + public PayerInfoType Owner { + get { + return this.ownerField; + } + set { + this.ownerField = value; + } + } + + /// + public string HomePhone { + get { + return this.homePhoneField; + } + set { + this.homePhoneField = value; + } + } + + /// + public string MobilePhone { + get { + return this.mobilePhoneField; + } + set { + this.mobilePhoneField = value; + } + } + + /// + public string SSN { + get { + return this.sSNField; + } + set { + this.sSNField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class BusinessInfoType { + + private BusinessTypeType typeField; + + private bool typeFieldSpecified; + + private string nameField; + + private AddressType addressField; + + private string workPhoneField; + + private BusinessCategoryType categoryField; + + private bool categoryFieldSpecified; + + private BusinessSubCategoryType subCategoryField; + + private bool subCategoryFieldSpecified; + + private AverageTransactionPriceType averagePriceField; + + private bool averagePriceFieldSpecified; + + private AverageMonthlyVolumeType averageMonthlyVolumeField; + + private bool averageMonthlyVolumeFieldSpecified; + + private SalesVenueType salesVenueField; + + private bool salesVenueFieldSpecified; + + private string websiteField; + + private PercentageRevenueFromOnlineSalesType revenueFromOnlineSalesField; + + private bool revenueFromOnlineSalesFieldSpecified; + + private System.DateTime businessEstablishedField; + + private bool businessEstablishedFieldSpecified; + + private string customerServiceEmailField; + + private string customerServicePhoneField; + + /// + public BusinessTypeType Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TypeSpecified { + get { + return this.typeFieldSpecified; + } + set { + this.typeFieldSpecified = value; + } + } + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public AddressType Address { + get { + return this.addressField; + } + set { + this.addressField = value; + } + } + + /// + public string WorkPhone { + get { + return this.workPhoneField; + } + set { + this.workPhoneField = value; + } + } + + /// + public BusinessCategoryType Category { + get { + return this.categoryField; + } + set { + this.categoryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CategorySpecified { + get { + return this.categoryFieldSpecified; + } + set { + this.categoryFieldSpecified = value; + } + } + + /// + public BusinessSubCategoryType SubCategory { + get { + return this.subCategoryField; + } + set { + this.subCategoryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SubCategorySpecified { + get { + return this.subCategoryFieldSpecified; + } + set { + this.subCategoryFieldSpecified = value; + } + } + + /// + public AverageTransactionPriceType AveragePrice { + get { + return this.averagePriceField; + } + set { + this.averagePriceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AveragePriceSpecified { + get { + return this.averagePriceFieldSpecified; + } + set { + this.averagePriceFieldSpecified = value; + } + } + + /// + public AverageMonthlyVolumeType AverageMonthlyVolume { + get { + return this.averageMonthlyVolumeField; + } + set { + this.averageMonthlyVolumeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AverageMonthlyVolumeSpecified { + get { + return this.averageMonthlyVolumeFieldSpecified; + } + set { + this.averageMonthlyVolumeFieldSpecified = value; + } + } + + /// + public SalesVenueType SalesVenue { + get { + return this.salesVenueField; + } + set { + this.salesVenueField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SalesVenueSpecified { + get { + return this.salesVenueFieldSpecified; + } + set { + this.salesVenueFieldSpecified = value; + } + } + + /// + public string Website { + get { + return this.websiteField; + } + set { + this.websiteField = value; + } + } + + /// + public PercentageRevenueFromOnlineSalesType RevenueFromOnlineSales { + get { + return this.revenueFromOnlineSalesField; + } + set { + this.revenueFromOnlineSalesField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RevenueFromOnlineSalesSpecified { + get { + return this.revenueFromOnlineSalesFieldSpecified; + } + set { + this.revenueFromOnlineSalesFieldSpecified = value; + } + } + + /// + public System.DateTime BusinessEstablished { + get { + return this.businessEstablishedField; + } + set { + this.businessEstablishedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BusinessEstablishedSpecified { + get { + return this.businessEstablishedFieldSpecified; + } + set { + this.businessEstablishedFieldSpecified = value; + } + } + + /// + public string CustomerServiceEmail { + get { + return this.customerServiceEmailField; + } + set { + this.customerServiceEmailField = value; + } + } + + /// + public string CustomerServicePhone { + get { + return this.customerServicePhoneField; + } + set { + this.customerServicePhoneField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BusinessTypeType { + + /// + Unknown, + + /// + Individual, + + /// + Proprietorship, + + /// + Partnership, + + /// + Corporation, + + /// + Nonprofit, + + /// + Government, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BusinessCategoryType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("Category-Unspecified")] + CategoryUnspecified, + + /// + Antiques, + + /// + Arts, + + /// + Automotive, + + /// + Beauty, + + /// + Books, + + /// + Business, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Cameras-and-Photography")] + CamerasandPhotography, + + /// + Clothing, + + /// + Collectibles, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Computer-Hardware-and-Software")] + ComputerHardwareandSoftware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Culture-and-Religion")] + CultureandReligion, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Electronics-and-Telecom")] + ElectronicsandTelecom, + + /// + Entertainment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Entertainment-Memorabilia")] + EntertainmentMemorabilia, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Food-Drink-and-Nutrition")] + FoodDrinkandNutrition, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Gifts-and-Flowers")] + GiftsandFlowers, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Hobbies-Toys-and-Games")] + HobbiesToysandGames, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Home-and-Garden")] + HomeandGarden, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Internet-and-Network-Services")] + InternetandNetworkServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Media-and-Entertainment")] + MediaandEntertainment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Medical-and-Pharmaceutical")] + MedicalandPharmaceutical, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Money-Service-Businesses")] + MoneyServiceBusinesses, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Non-Profit-Political-and-Religion")] + NonProfitPoliticalandReligion, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Not-Elsewhere-Classified")] + NotElsewhereClassified, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Pets-and-Animals")] + PetsandAnimals, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Real-Estate")] + RealEstate, + + /// + Services, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Sports-and-Recreation")] + SportsandRecreation, + + /// + Travel, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Other-Categories")] + OtherCategories, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum BusinessSubCategoryType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("SubCategory-Unspecified")] + SubCategoryUnspecified, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-General")] + ANTIQUESGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Antiquities")] + ANTIQUESAntiquities, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Decorative")] + ANTIQUESDecorative, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Books-Manuscripts")] + ANTIQUESBooksManuscripts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Furniture")] + ANTIQUESFurniture, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Glass")] + ANTIQUESGlass, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-RugsCarpets")] + ANTIQUESRugsCarpets, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Pottery")] + ANTIQUESPottery, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Cultural")] + ANTIQUESCultural, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ANTIQUES-Artifacts-Grave-related-and-Native-American-Crafts")] + ANTIQUESArtifactsGraverelatedandNativeAmericanCrafts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-General")] + ARTSANDCRAFTSGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Art-Dealer-and-Galleries")] + ARTSANDCRAFTSArtDealerandGalleries, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Prints")] + ARTSANDCRAFTSPrints, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Painting")] + ARTSANDCRAFTSPainting, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Photography")] + ARTSANDCRAFTSPhotography, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Reproductions")] + ARTSANDCRAFTSReproductions, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Sculptures")] + ARTSANDCRAFTSSculptures, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Woodworking")] + ARTSANDCRAFTSWoodworking, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Art-and-Craft-Supplies")] + ARTSANDCRAFTSArtandCraftSupplies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Fabrics-and-Sewing")] + ARTSANDCRAFTSFabricsandSewing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Quilting")] + ARTSANDCRAFTSQuilting, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ARTSANDCRAFTS-Scrapbooking")] + ARTSANDCRAFTSScrapbooking, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AUTOMOTIVE-General")] + AUTOMOTIVEGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AUTOMOTIVE-Autos")] + AUTOMOTIVEAutos, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AUTOMOTIVE-Aviation")] + AUTOMOTIVEAviation, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AUTOMOTIVE-Motorcycles")] + AUTOMOTIVEMotorcycles, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AUTOMOTIVE-Parts-and-Supplies")] + AUTOMOTIVEPartsandSupplies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AUTOMOTIVE-Services")] + AUTOMOTIVEServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AUTOMOTIVE-Vintage-and-Collectible-Vehicles")] + AUTOMOTIVEVintageandCollectibleVehicles, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BEAUTY-General")] + BEAUTYGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BEAUTY-Body-Care-Personal-Hygiene")] + BEAUTYBodyCarePersonalHygiene, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BEAUTY-Fragrances-and-Perfumes")] + BEAUTYFragrancesandPerfumes, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BEAUTY-Makeup")] + BEAUTYMakeup, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-General")] + BOOKSGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-Audio-Books")] + BOOKSAudioBooks, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-Children-Books")] + BOOKSChildrenBooks, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-Computer-Books")] + BOOKSComputerBooks, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-Educational-and-Textbooks")] + BOOKSEducationalandTextbooks, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-Magazines")] + BOOKSMagazines, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-Fiction-and-Literature")] + BOOKSFictionandLiterature, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-NonFiction")] + BOOKSNonFiction, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BOOKS-Vintage-and-Collectibles")] + BOOKSVintageandCollectibles, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-General")] + BUSINESSGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Agricultural")] + BUSINESSAgricultural, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Construction")] + BUSINESSConstruction, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Educational")] + BUSINESSEducational, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Industrial")] + BUSINESSIndustrial, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Office-Supplies-and-Equipment")] + BUSINESSOfficeSuppliesandEquipment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-GeneralServices")] + BUSINESSGeneralServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Advertising")] + BUSINESSAdvertising, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Employment")] + BUSINESSEmployment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Marketing")] + BUSINESSMarketing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Meeting-Planners")] + BUSINESSMeetingPlanners, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Messaging-and-Paging-Services")] + BUSINESSMessagingandPagingServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Seminars")] + BUSINESSSeminars, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Publishing")] + BUSINESSPublishing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Shipping-and-Packaging")] + BUSINESSShippingandPackaging, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Wholesale")] + BUSINESSWholesale, + + /// + [System.Xml.Serialization.XmlEnumAttribute("BUSINESS-Industrial-Solvents")] + BUSINESSIndustrialSolvents, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CAMERASANDPHOTOGRAPHY-General")] + CAMERASANDPHOTOGRAPHYGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CAMERASANDPHOTOGRAPHY-Accessories")] + CAMERASANDPHOTOGRAPHYAccessories, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CAMERASANDPHOTOGRAPHY-Cameras")] + CAMERASANDPHOTOGRAPHYCameras, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CAMERASANDPHOTOGRAPHY-Video-Equipment")] + CAMERASANDPHOTOGRAPHYVideoEquipment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CAMERASANDPHOTOGRAPHY-Film")] + CAMERASANDPHOTOGRAPHYFilm, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CAMERASANDPHOTOGRAPHY-Supplies")] + CAMERASANDPHOTOGRAPHYSupplies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Accessories")] + CLOTHINGAccessories, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Babies-Clothing-and-Supplies")] + CLOTHINGBabiesClothingandSupplies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Childrens-Clothing")] + CLOTHINGChildrensClothing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Mens-Clothing")] + CLOTHINGMensClothing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Shoes")] + CLOTHINGShoes, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Wedding-Clothing")] + CLOTHINGWeddingClothing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Womens-Clothing")] + CLOTHINGWomensClothing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-General")] + CLOTHINGGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Jewelry")] + CLOTHINGJewelry, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Watches-and-Clocks")] + CLOTHINGWatchesandClocks, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CLOTHING-Rings")] + CLOTHINGRings, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-General")] + COLLECTIBLESGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Advertising")] + COLLECTIBLESAdvertising, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Animals")] + COLLECTIBLESAnimals, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Animation")] + COLLECTIBLESAnimation, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Coin-Operated-Banks-and-Casinos")] + COLLECTIBLESCoinOperatedBanksandCasinos, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Coins-and-Paper-Money")] + COLLECTIBLESCoinsandPaperMoney, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Comics")] + COLLECTIBLESComics, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Decorative")] + COLLECTIBLESDecorative, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Disneyana")] + COLLECTIBLESDisneyana, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Holiday")] + COLLECTIBLESHoliday, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Knives-and-Swords")] + COLLECTIBLESKnivesandSwords, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Militaria")] + COLLECTIBLESMilitaria, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Postcards-and-Paper")] + COLLECTIBLESPostcardsandPaper, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COLLECTIBLES-Stamps")] + COLLECTIBLESStamps, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-General")] + COMPUTERHARDWAREANDSOFTWAREGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Desktop-PCs")] + COMPUTERHARDWAREANDSOFTWAREDesktopPCs, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Monitors")] + COMPUTERHARDWAREANDSOFTWAREMonitors, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Hardware")] + COMPUTERHARDWAREANDSOFTWAREHardware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Peripherals")] + COMPUTERHARDWAREANDSOFTWAREPeripherals, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Laptops-Notebooks-PDAs")] + COMPUTERHARDWAREANDSOFTWARELaptopsNotebooksPDAs, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Networking-Equipment")] + COMPUTERHARDWAREANDSOFTWARENetworkingEquipment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Parts-and-Accessories")] + COMPUTERHARDWAREANDSOFTWAREPartsandAccessories, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-GeneralSoftware")] + COMPUTERHARDWAREANDSOFTWAREGeneralSoftware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Oem-Software")] + COMPUTERHARDWAREANDSOFTWAREOemSoftware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Academic-Software")] + COMPUTERHARDWAREANDSOFTWAREAcademicSoftware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Beta-Software")] + COMPUTERHARDWAREANDSOFTWAREBetaSoftware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Game-Software")] + COMPUTERHARDWAREANDSOFTWAREGameSoftware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("COMPUTERHARDWAREANDSOFTWARE-Data-Processing-Svc")] + COMPUTERHARDWAREANDSOFTWAREDataProcessingSvc, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CULTUREANDRELIGION-General")] + CULTUREANDRELIGIONGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CULTUREANDRELIGION-Christianity")] + CULTUREANDRELIGIONChristianity, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CULTUREANDRELIGION-Metaphysical")] + CULTUREANDRELIGIONMetaphysical, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CULTUREANDRELIGION-New-Age")] + CULTUREANDRELIGIONNewAge, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CULTUREANDRELIGION-Organizations")] + CULTUREANDRELIGIONOrganizations, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CULTUREANDRELIGION-Other-Faiths")] + CULTUREANDRELIGIONOtherFaiths, + + /// + [System.Xml.Serialization.XmlEnumAttribute("CULTUREANDRELIGION-Collectibles")] + CULTUREANDRELIGIONCollectibles, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-GeneralTelecom")] + ELECTRONICSANDTELECOMGeneralTelecom, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Cell-Phones-and-Pagers")] + ELECTRONICSANDTELECOMCellPhonesandPagers, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Telephone-Cards")] + ELECTRONICSANDTELECOMTelephoneCards, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Telephone-Equipment")] + ELECTRONICSANDTELECOMTelephoneEquipment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Telephone-Services")] + ELECTRONICSANDTELECOMTelephoneServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-GeneralElectronics")] + ELECTRONICSANDTELECOMGeneralElectronics, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Car-Audio-and-Electronics")] + ELECTRONICSANDTELECOMCarAudioandElectronics, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Home-Electronics")] + ELECTRONICSANDTELECOMHomeElectronics, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Home-Audio")] + ELECTRONICSANDTELECOMHomeAudio, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Gadgets-and-other-electronics")] + ELECTRONICSANDTELECOMGadgetsandotherelectronics, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Batteries")] + ELECTRONICSANDTELECOMBatteries, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-ScannersRadios")] + ELECTRONICSANDTELECOMScannersRadios, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Radar-Dectors")] + ELECTRONICSANDTELECOMRadarDectors, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Radar-Jamming-Devices")] + ELECTRONICSANDTELECOMRadarJammingDevices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Satellite-and-Cable-TV-Descramblers")] + ELECTRONICSANDTELECOMSatelliteandCableTVDescramblers, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ELECTRONICSANDTELECOM-Surveillance-Equipment")] + ELECTRONICSANDTELECOMSurveillanceEquipment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENT-General")] + ENTERTAINMENTGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENT-Movies")] + ENTERTAINMENTMovies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENT-Music")] + ENTERTAINMENTMusic, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENT-Concerts")] + ENTERTAINMENTConcerts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENT-Theater")] + ENTERTAINMENTTheater, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENT-Bootleg-Recordings")] + ENTERTAINMENTBootlegRecordings, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENT-Promotional-Items")] + ENTERTAINMENTPromotionalItems, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-General")] + ENTERTAINMENTMEMORABILIAGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Autographs")] + ENTERTAINMENTMEMORABILIAAutographs, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Limited-Editions")] + ENTERTAINMENTMEMORABILIALimitedEditions, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Movie")] + ENTERTAINMENTMEMORABILIAMovie, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Music")] + ENTERTAINMENTMEMORABILIAMusic, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Novelties")] + ENTERTAINMENTMEMORABILIANovelties, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Photos")] + ENTERTAINMENTMEMORABILIAPhotos, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Posters")] + ENTERTAINMENTMEMORABILIAPosters, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Sports-and-Fan-Shop")] + ENTERTAINMENTMEMORABILIASportsandFanShop, + + /// + [System.Xml.Serialization.XmlEnumAttribute("ENTERTAINMENTMEMORABILIA-Science-Fiction")] + ENTERTAINMENTMEMORABILIAScienceFiction, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-General")] + FOODDRINKANDNUTRITIONGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Coffee-and-Tea")] + FOODDRINKANDNUTRITIONCoffeeandTea, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Food-Products")] + FOODDRINKANDNUTRITIONFoodProducts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Gourmet-Items")] + FOODDRINKANDNUTRITIONGourmetItems, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Health-and-Nutrition")] + FOODDRINKANDNUTRITIONHealthandNutrition, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Services")] + FOODDRINKANDNUTRITIONServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Vitamins-and-Supplements")] + FOODDRINKANDNUTRITIONVitaminsandSupplements, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Weight-Management-and-Health-Products")] + FOODDRINKANDNUTRITIONWeightManagementandHealthProducts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Restaurant")] + FOODDRINKANDNUTRITIONRestaurant, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Tobacco-and-Cigars")] + FOODDRINKANDNUTRITIONTobaccoandCigars, + + /// + [System.Xml.Serialization.XmlEnumAttribute("FOODDRINKANDNUTRITION-Alcoholic-Beverages")] + FOODDRINKANDNUTRITIONAlcoholicBeverages, + + /// + [System.Xml.Serialization.XmlEnumAttribute("GIFTSANDFLOWERS-General")] + GIFTSANDFLOWERSGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("GIFTSANDFLOWERS-Flowers")] + GIFTSANDFLOWERSFlowers, + + /// + [System.Xml.Serialization.XmlEnumAttribute("GIFTSANDFLOWERS-Greeting-Cards")] + GIFTSANDFLOWERSGreetingCards, + + /// + [System.Xml.Serialization.XmlEnumAttribute("GIFTSANDFLOWERS-Humorous-Gifts-and-Novelties")] + GIFTSANDFLOWERSHumorousGiftsandNovelties, + + /// + [System.Xml.Serialization.XmlEnumAttribute("GIFTSANDFLOWERS-Personalized-Gifts")] + GIFTSANDFLOWERSPersonalizedGifts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("GIFTSANDFLOWERS-Products")] + GIFTSANDFLOWERSProducts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("GIFTSANDFLOWERS-Services")] + GIFTSANDFLOWERSServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-General")] + HOBBIESTOYSANDGAMESGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Action-Figures")] + HOBBIESTOYSANDGAMESActionFigures, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Bean-Babies")] + HOBBIESTOYSANDGAMESBeanBabies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Barbies")] + HOBBIESTOYSANDGAMESBarbies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Bears")] + HOBBIESTOYSANDGAMESBears, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Dolls")] + HOBBIESTOYSANDGAMESDolls, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Games")] + HOBBIESTOYSANDGAMESGames, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Model-Kits")] + HOBBIESTOYSANDGAMESModelKits, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Diecast-Toys-Vehicles")] + HOBBIESTOYSANDGAMESDiecastToysVehicles, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Video-Games-and-Systems")] + HOBBIESTOYSANDGAMESVideoGamesandSystems, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Vintage-and-Antique-Toys")] + HOBBIESTOYSANDGAMESVintageandAntiqueToys, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-BackupUnreleased-Games")] + HOBBIESTOYSANDGAMESBackupUnreleasedGames, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Game-copying-hardwaresoftware")] + HOBBIESTOYSANDGAMESGamecopyinghardwaresoftware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOBBIESTOYSANDGAMES-Mod-Chips")] + HOBBIESTOYSANDGAMESModChips, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-General")] + HOMEANDGARDENGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Appliances")] + HOMEANDGARDENAppliances, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Bed-and-Bath")] + HOMEANDGARDENBedandBath, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Furnishing-and-Decorating")] + HOMEANDGARDENFurnishingandDecorating, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Garden-Supplies")] + HOMEANDGARDENGardenSupplies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Hardware-and-Tools")] + HOMEANDGARDENHardwareandTools, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Household-Goods")] + HOMEANDGARDENHouseholdGoods, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Kitchenware")] + HOMEANDGARDENKitchenware, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Rugs-and-Carpets")] + HOMEANDGARDENRugsandCarpets, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Security-and-Home-Defense")] + HOMEANDGARDENSecurityandHomeDefense, + + /// + [System.Xml.Serialization.XmlEnumAttribute("HOMEANDGARDEN-Plants-and-Seeds")] + HOMEANDGARDENPlantsandSeeds, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-General")] + INTERNETANDNETWORKSERVICESGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-Bulletin-board")] + INTERNETANDNETWORKSERVICESBulletinboard, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-online-services")] + INTERNETANDNETWORKSERVICESonlineservices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-Auction-management-tools")] + INTERNETANDNETWORKSERVICESAuctionmanagementtools, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-ecommerce-development")] + INTERNETANDNETWORKSERVICESecommercedevelopment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-training-services")] + INTERNETANDNETWORKSERVICEStrainingservices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-Online-Malls")] + INTERNETANDNETWORKSERVICESOnlineMalls, + + /// + [System.Xml.Serialization.XmlEnumAttribute("INTERNETANDNETWORKSERVICES-Web-hosting-and-design")] + INTERNETANDNETWORKSERVICESWebhostinganddesign, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDIAANDENTERTAINMENT-General")] + MEDIAANDENTERTAINMENTGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDIAANDENTERTAINMENT-Concerts")] + MEDIAANDENTERTAINMENTConcerts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDIAANDENTERTAINMENT-Theater")] + MEDIAANDENTERTAINMENTTheater, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDICALANDPHARMACEUTICAL-General")] + MEDICALANDPHARMACEUTICALGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDICALANDPHARMACEUTICAL-Medical")] + MEDICALANDPHARMACEUTICALMedical, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDICALANDPHARMACEUTICAL-Dental")] + MEDICALANDPHARMACEUTICALDental, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDICALANDPHARMACEUTICAL-Opthamalic")] + MEDICALANDPHARMACEUTICALOpthamalic, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDICALANDPHARMACEUTICAL-Prescription-Drugs")] + MEDICALANDPHARMACEUTICALPrescriptionDrugs, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MEDICALANDPHARMACEUTICAL-Devices")] + MEDICALANDPHARMACEUTICALDevices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-General")] + MONEYSERVICEBUSINESSESGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Remittance")] + MONEYSERVICEBUSINESSESRemittance, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Wire-Transfer")] + MONEYSERVICEBUSINESSESWireTransfer, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Money-Orders")] + MONEYSERVICEBUSINESSESMoneyOrders, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Electronic-Cash")] + MONEYSERVICEBUSINESSESElectronicCash, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Currency-DealerExchange")] + MONEYSERVICEBUSINESSESCurrencyDealerExchange, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Check-Cashier")] + MONEYSERVICEBUSINESSESCheckCashier, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Travelers-Checks")] + MONEYSERVICEBUSINESSESTravelersChecks, + + /// + [System.Xml.Serialization.XmlEnumAttribute("MONEYSERVICEBUSINESSES-Stored-Value-Cards")] + MONEYSERVICEBUSINESSESStoredValueCards, + + /// + [System.Xml.Serialization.XmlEnumAttribute("NONPROFITPOLITICALANDRELIGION-General")] + NONPROFITPOLITICALANDRELIGIONGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("NONPROFITPOLITICALANDRELIGION-Charities")] + NONPROFITPOLITICALANDRELIGIONCharities, + + /// + [System.Xml.Serialization.XmlEnumAttribute("NONPROFITPOLITICALANDRELIGION-Political")] + NONPROFITPOLITICALANDRELIGIONPolitical, + + /// + [System.Xml.Serialization.XmlEnumAttribute("NONPROFITPOLITICALANDRELIGION-Religious")] + NONPROFITPOLITICALANDRELIGIONReligious, + + /// + [System.Xml.Serialization.XmlEnumAttribute("PETSANDANIMALS-General")] + PETSANDANIMALSGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("PETSANDANIMALS-Supplies-and-Toys")] + PETSANDANIMALSSuppliesandToys, + + /// + [System.Xml.Serialization.XmlEnumAttribute("PETSANDANIMALS-Wildlife-Products")] + PETSANDANIMALSWildlifeProducts, + + /// + [System.Xml.Serialization.XmlEnumAttribute("REALESTATE-General")] + REALESTATEGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("REALESTATE-Commercial")] + REALESTATECommercial, + + /// + [System.Xml.Serialization.XmlEnumAttribute("REALESTATE-Residential")] + REALESTATEResidential, + + /// + [System.Xml.Serialization.XmlEnumAttribute("REALESTATE-Time-Shares")] + REALESTATETimeShares, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-GeneralGovernment")] + SERVICESGeneralGovernment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Legal")] + SERVICESLegal, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Medical")] + SERVICESMedical, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Dental")] + SERVICESDental, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Vision")] + SERVICESVision, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-General")] + SERVICESGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Child-Care-Services")] + SERVICESChildCareServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Consulting")] + SERVICESConsulting, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-ImportingExporting")] + SERVICESImportingExporting, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-InsuranceDirect")] + SERVICESInsuranceDirect, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Financial-Services")] + SERVICESFinancialServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Graphic-and-Commercial-Design")] + SERVICESGraphicandCommercialDesign, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Landscaping")] + SERVICESLandscaping, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Locksmith")] + SERVICESLocksmith, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Online-Dating")] + SERVICESOnlineDating, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Event-and-Wedding-Planning")] + SERVICESEventandWeddingPlanning, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Schools-and-Colleges")] + SERVICESSchoolsandColleges, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Entertainment")] + SERVICESEntertainment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SERVICES-Aggregators")] + SERVICESAggregators, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-General")] + SPORTSANDRECREATIONGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Bicycles-and-Accessories")] + SPORTSANDRECREATIONBicyclesandAccessories, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Boating-Sailing-and-Accessories")] + SPORTSANDRECREATIONBoatingSailingandAccessories, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Camping-and-Survival")] + SPORTSANDRECREATIONCampingandSurvival, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Exercise-Equipment")] + SPORTSANDRECREATIONExerciseEquipment, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Fishing")] + SPORTSANDRECREATIONFishing, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Golf")] + SPORTSANDRECREATIONGolf, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Hunting")] + SPORTSANDRECREATIONHunting, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Paintball")] + SPORTSANDRECREATIONPaintball, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Sporting-Goods")] + SPORTSANDRECREATIONSportingGoods, + + /// + [System.Xml.Serialization.XmlEnumAttribute("SPORTSANDRECREATION-Swimming-Pools-and-Spas")] + SPORTSANDRECREATIONSwimmingPoolsandSpas, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-General")] + TRAVELGeneral, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Accommodations")] + TRAVELAccommodations, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Agencies")] + TRAVELAgencies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Airlines")] + TRAVELAirlines, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Auto-Rentals")] + TRAVELAutoRentals, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Cruises")] + TRAVELCruises, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Other-Transportation")] + TRAVELOtherTransportation, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Services")] + TRAVELServices, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Supplies")] + TRAVELSupplies, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-Tours")] + TRAVELTours, + + /// + [System.Xml.Serialization.XmlEnumAttribute("TRAVEL-AirlinesSpirit-Air")] + TRAVELAirlinesSpiritAir, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Other-SubCategories")] + OtherSubCategories, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AverageTransactionPriceType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Not-Applicable")] + AverageTransactionPriceNotApplicable, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range1")] + AverageTransactionPriceRange1, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range2")] + AverageTransactionPriceRange2, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range3")] + AverageTransactionPriceRange3, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range4")] + AverageTransactionPriceRange4, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range5")] + AverageTransactionPriceRange5, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range6")] + AverageTransactionPriceRange6, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range7")] + AverageTransactionPriceRange7, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range8")] + AverageTransactionPriceRange8, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range9")] + AverageTransactionPriceRange9, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageTransactionPrice-Range10")] + AverageTransactionPriceRange10, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum AverageMonthlyVolumeType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageMonthlyVolume-Not-Applicable")] + AverageMonthlyVolumeNotApplicable, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageMonthlyVolume-Range1")] + AverageMonthlyVolumeRange1, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageMonthlyVolume-Range2")] + AverageMonthlyVolumeRange2, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageMonthlyVolume-Range3")] + AverageMonthlyVolumeRange3, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageMonthlyVolume-Range4")] + AverageMonthlyVolumeRange4, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageMonthlyVolume-Range5")] + AverageMonthlyVolumeRange5, + + /// + [System.Xml.Serialization.XmlEnumAttribute("AverageMonthlyVolume-Range6")] + AverageMonthlyVolumeRange6, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum SalesVenueType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("Venue-Unspecified")] + VenueUnspecified, + + /// + eBay, + + /// + AnotherMarketPlace, + + /// + OwnWebsite, + + /// + Other, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PercentageRevenueFromOnlineSalesType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("PercentageRevenueFromOnlineSales-Not-Applicable")] + PercentageRevenueFromOnlineSalesNotApplicable, + + /// + [System.Xml.Serialization.XmlEnumAttribute("PercentageRevenueFromOnlineSales-Range1")] + PercentageRevenueFromOnlineSalesRange1, + + /// + [System.Xml.Serialization.XmlEnumAttribute("PercentageRevenueFromOnlineSales-Range2")] + PercentageRevenueFromOnlineSalesRange2, + + /// + [System.Xml.Serialization.XmlEnumAttribute("PercentageRevenueFromOnlineSales-Range3")] + PercentageRevenueFromOnlineSalesRange3, + + /// + [System.Xml.Serialization.XmlEnumAttribute("PercentageRevenueFromOnlineSales-Range4")] + PercentageRevenueFromOnlineSalesRange4, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class EnterBoardingRequestDetailsType { + + private string programCodeField; + + private string productListField; + + private string partnerCustomField; + + private string imageUrlField; + + private MarketingCategoryType marketingCategoryField; + + private bool marketingCategoryFieldSpecified; + + private BusinessInfoType businessInfoField; + + private BusinessOwnerInfoType ownerInfoField; + + private BankAccountDetailsType bankAccountField; + + /// + public string ProgramCode { + get { + return this.programCodeField; + } + set { + this.programCodeField = value; + } + } + + /// + public string ProductList { + get { + return this.productListField; + } + set { + this.productListField = value; + } + } + + /// + public string PartnerCustom { + get { + return this.partnerCustomField; + } + set { + this.partnerCustomField = value; + } + } + + /// + public string ImageUrl { + get { + return this.imageUrlField; + } + set { + this.imageUrlField = value; + } + } + + /// + public MarketingCategoryType MarketingCategory { + get { + return this.marketingCategoryField; + } + set { + this.marketingCategoryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MarketingCategorySpecified { + get { + return this.marketingCategoryFieldSpecified; + } + set { + this.marketingCategoryFieldSpecified = value; + } + } + + /// + public BusinessInfoType BusinessInfo { + get { + return this.businessInfoField; + } + set { + this.businessInfoField = value; + } + } + + /// + public BusinessOwnerInfoType OwnerInfo { + get { + return this.ownerInfoField; + } + set { + this.ownerInfoField = value; + } + } + + /// + public BankAccountDetailsType BankAccount { + get { + return this.bankAccountField; + } + set { + this.bankAccountField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum MarketingCategoryType { + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category-Default")] + MarketingCategoryDefault, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category1")] + MarketingCategory1, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category2")] + MarketingCategory2, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category3")] + MarketingCategory3, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category4")] + MarketingCategory4, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category5")] + MarketingCategory5, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category6")] + MarketingCategory6, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category7")] + MarketingCategory7, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category8")] + MarketingCategory8, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category9")] + MarketingCategory9, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category10")] + MarketingCategory10, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category11")] + MarketingCategory11, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category12")] + MarketingCategory12, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category13")] + MarketingCategory13, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category14")] + MarketingCategory14, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category15")] + MarketingCategory15, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category16")] + MarketingCategory16, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category17")] + MarketingCategory17, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category18")] + MarketingCategory18, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category19")] + MarketingCategory19, + + /// + [System.Xml.Serialization.XmlEnumAttribute("Marketing-Category20")] + MarketingCategory20, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class MassPayRequestItemType { + + private string receiverEmailField; + + private string receiverPhoneField; + + private string receiverIDField; + + private BasicAmountType amountField; + + private string uniqueIdField; + + private string noteField; + + /// + public string ReceiverEmail { + get { + return this.receiverEmailField; + } + set { + this.receiverEmailField = value; + } + } + + /// + public string ReceiverPhone { + get { + return this.receiverPhoneField; + } + set { + this.receiverPhoneField = value; + } + } + + /// + public string ReceiverID { + get { + return this.receiverIDField; + } + set { + this.receiverIDField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string UniqueId { + get { + return this.uniqueIdField; + } + set { + this.uniqueIdField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class MerchantPullPaymentType { + + private BasicAmountType amountField; + + private string mpIDField; + + private MerchantPullPaymentCodeType paymentTypeField; + + private bool paymentTypeFieldSpecified; + + private string memoField; + + private string emailSubjectField; + + private BasicAmountType taxField; + + private BasicAmountType shippingField; + + private BasicAmountType handlingField; + + private string itemNameField; + + private string itemNumberField; + + private string invoiceField; + + private string customField; + + private string buttonSourceField; + + private string softDescriptorField; + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string MpID { + get { + return this.mpIDField; + } + set { + this.mpIDField = value; + } + } + + /// + public MerchantPullPaymentCodeType PaymentType { + get { + return this.paymentTypeField; + } + set { + this.paymentTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PaymentTypeSpecified { + get { + return this.paymentTypeFieldSpecified; + } + set { + this.paymentTypeFieldSpecified = value; + } + } + + /// + public string Memo { + get { + return this.memoField; + } + set { + this.memoField = value; + } + } + + /// + public string EmailSubject { + get { + return this.emailSubjectField; + } + set { + this.emailSubjectField = value; + } + } + + /// + public BasicAmountType Tax { + get { + return this.taxField; + } + set { + this.taxField = value; + } + } + + /// + public BasicAmountType Shipping { + get { + return this.shippingField; + } + set { + this.shippingField = value; + } + } + + /// + public BasicAmountType Handling { + get { + return this.handlingField; + } + set { + this.handlingField = value; + } + } + + /// + public string ItemName { + get { + return this.itemNameField; + } + set { + this.itemNameField = value; + } + } + + /// + public string ItemNumber { + get { + return this.itemNumberField; + } + set { + this.itemNumberField = value; + } + } + + /// + public string Invoice { + get { + return this.invoiceField; + } + set { + this.invoiceField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string ButtonSource { + get { + return this.buttonSourceField; + } + set { + this.buttonSourceField = value; + } + } + + /// + public string SoftDescriptor { + get { + return this.softDescriptorField; + } + set { + this.softDescriptorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedCancelRecoupRequestDetailsType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedCompleteRecoupRequestDetailsType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public partial class EnhancedInitiateRecoupRequestDetailsType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public partial class MerchantStoreDetailsType { + + private string storeIDField; + + private string terminalIDField; + + /// + public string StoreID { + get { + return this.storeIDField; + } + set { + this.storeIDField = value; + } + } + + /// + public string TerminalID { + get { + return this.terminalIDField; + } + set { + this.terminalIDField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ExternalRememberMeOptOutRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ReverseTransactionRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetPalDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(UpdateRecurringPaymentsProfileRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BillOutstandingAmountRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ManageRecurringPaymentsProfileStatusRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetRecurringPaymentsProfileDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CreateRecurringPaymentsProfileRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoNonReferencedCreditRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoReferenceTransactionRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CreateBillingAgreementRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetBillingAgreementCustomerDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetCustomerBillingAgreementRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetBalanceRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoMobileCheckoutPaymentRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetMobileCheckoutRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetMobileStatusRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CreateMobilePaymentRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoUATPAuthorizationRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(UpdateAuthorizationRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoAuthorizationRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoVoidRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoReauthorizationRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoCaptureRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoCancelRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoDirectPaymentRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ManagePendingTransactionStatusRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoExpressCheckoutPaymentRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoUATPExpressCheckoutPaymentRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetExpressCheckoutDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ExecuteCheckoutOperationsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetExpressCheckoutRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetIncentiveEvaluationRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetAccessPermissionDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(UpdateAccessPermissionsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetAccessPermissionsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetAuthDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SetAuthFlowParamRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetBoardingDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(EnterBoardingRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AddressVerifyRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BAUpdateRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(MassPayRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(TransactionSearchRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BillUserRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetTransactionDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CancelRecoupRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CompleteRecoupRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(InitiateRecoupRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(RefundTransactionRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMButtonSearchRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMGetInventoryRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMSetInventoryRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMGetButtonDetailsRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMManageButtonStatusRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMUpdateButtonRequestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BMCreateButtonRequestType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public abstract partial class AbstractRequestType { + + private DetailLevelCodeType[] detailLevelField; + + private string errorLanguageField; + + private string versionField; + + private System.Xml.XmlElement anyField; + + /// + [System.Xml.Serialization.XmlElementAttribute("DetailLevel")] + public DetailLevelCodeType[] DetailLevel { + get { + return this.detailLevelField; + } + set { + this.detailLevelField = value; + } + } + + /// + public string ErrorLanguage { + get { + return this.errorLanguageField; + } + set { + this.errorLanguageField = value; + } + } + + /// + public string Version { + get { + return this.versionField; + } + set { + this.versionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum DetailLevelCodeType { + + /// + ReturnAll, + + /// + ItemReturnDescription, + + /// + ItemReturnAttributes, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ExternalRememberMeOptOutRequestType : AbstractRequestType { + + private string externalRememberMeIDField; + + private ExternalRememberMeOwnerDetailsType externalRememberMeOwnerDetailsField; + + /// + public string ExternalRememberMeID { + get { + return this.externalRememberMeIDField; + } + set { + this.externalRememberMeIDField = value; + } + } + + /// + public ExternalRememberMeOwnerDetailsType ExternalRememberMeOwnerDetails { + get { + return this.externalRememberMeOwnerDetailsField; + } + set { + this.externalRememberMeOwnerDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ReverseTransactionRequestType : AbstractRequestType { + + private ReverseTransactionRequestDetailsType reverseTransactionRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public ReverseTransactionRequestDetailsType ReverseTransactionRequestDetails { + get { + return this.reverseTransactionRequestDetailsField; + } + set { + this.reverseTransactionRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetPalDetailsRequestType : AbstractRequestType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateRecurringPaymentsProfileRequestType : AbstractRequestType { + + private UpdateRecurringPaymentsProfileRequestDetailsType updateRecurringPaymentsProfileRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public UpdateRecurringPaymentsProfileRequestDetailsType UpdateRecurringPaymentsProfileRequestDetails { + get { + return this.updateRecurringPaymentsProfileRequestDetailsField; + } + set { + this.updateRecurringPaymentsProfileRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BillOutstandingAmountRequestType : AbstractRequestType { + + private BillOutstandingAmountRequestDetailsType billOutstandingAmountRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public BillOutstandingAmountRequestDetailsType BillOutstandingAmountRequestDetails { + get { + return this.billOutstandingAmountRequestDetailsField; + } + set { + this.billOutstandingAmountRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ManageRecurringPaymentsProfileStatusRequestType : AbstractRequestType { + + private ManageRecurringPaymentsProfileStatusRequestDetailsType manageRecurringPaymentsProfileStatusRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public ManageRecurringPaymentsProfileStatusRequestDetailsType ManageRecurringPaymentsProfileStatusRequestDetails { + get { + return this.manageRecurringPaymentsProfileStatusRequestDetailsField; + } + set { + this.manageRecurringPaymentsProfileStatusRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetRecurringPaymentsProfileDetailsRequestType : AbstractRequestType { + + private string profileIDField; + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateRecurringPaymentsProfileRequestType : AbstractRequestType { + + private CreateRecurringPaymentsProfileRequestDetailsType createRecurringPaymentsProfileRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public CreateRecurringPaymentsProfileRequestDetailsType CreateRecurringPaymentsProfileRequestDetails { + get { + return this.createRecurringPaymentsProfileRequestDetailsField; + } + set { + this.createRecurringPaymentsProfileRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoNonReferencedCreditRequestType : AbstractRequestType { + + private DoNonReferencedCreditRequestDetailsType doNonReferencedCreditRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public DoNonReferencedCreditRequestDetailsType DoNonReferencedCreditRequestDetails { + get { + return this.doNonReferencedCreditRequestDetailsField; + } + set { + this.doNonReferencedCreditRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoReferenceTransactionRequestType : AbstractRequestType { + + private DoReferenceTransactionRequestDetailsType doReferenceTransactionRequestDetailsField; + + private int returnFMFDetailsField; + + private bool returnFMFDetailsFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public DoReferenceTransactionRequestDetailsType DoReferenceTransactionRequestDetails { + get { + return this.doReferenceTransactionRequestDetailsField; + } + set { + this.doReferenceTransactionRequestDetailsField = value; + } + } + + /// + public int ReturnFMFDetails { + get { + return this.returnFMFDetailsField; + } + set { + this.returnFMFDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReturnFMFDetailsSpecified { + get { + return this.returnFMFDetailsFieldSpecified; + } + set { + this.returnFMFDetailsFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateBillingAgreementRequestType : AbstractRequestType { + + private string tokenField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBillingAgreementCustomerDetailsRequestType : AbstractRequestType { + + private string tokenField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetCustomerBillingAgreementRequestType : AbstractRequestType { + + private SetCustomerBillingAgreementRequestDetailsType setCustomerBillingAgreementRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public SetCustomerBillingAgreementRequestDetailsType SetCustomerBillingAgreementRequestDetails { + get { + return this.setCustomerBillingAgreementRequestDetailsField; + } + set { + this.setCustomerBillingAgreementRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBalanceRequestType : AbstractRequestType { + + private string returnAllCurrenciesField; + + /// + public string ReturnAllCurrencies { + get { + return this.returnAllCurrenciesField; + } + set { + this.returnAllCurrenciesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoMobileCheckoutPaymentRequestType : AbstractRequestType { + + private string tokenField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetMobileCheckoutRequestType : AbstractRequestType { + + private SetMobileCheckoutRequestDetailsType setMobileCheckoutRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public SetMobileCheckoutRequestDetailsType SetMobileCheckoutRequestDetails { + get { + return this.setMobileCheckoutRequestDetailsField; + } + set { + this.setMobileCheckoutRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetMobileStatusRequestType : AbstractRequestType { + + private GetMobileStatusRequestDetailsType getMobileStatusRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public GetMobileStatusRequestDetailsType GetMobileStatusRequestDetails { + get { + return this.getMobileStatusRequestDetailsField; + } + set { + this.getMobileStatusRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateMobilePaymentRequestType : AbstractRequestType { + + private CreateMobilePaymentRequestDetailsType createMobilePaymentRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public CreateMobilePaymentRequestDetailsType CreateMobilePaymentRequestDetails { + get { + return this.createMobilePaymentRequestDetailsField; + } + set { + this.createMobilePaymentRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoUATPAuthorizationRequestType : AbstractRequestType { + + private UATPDetailsType uATPDetailsField; + + private TransactionEntityType transactionEntityField; + + private bool transactionEntityFieldSpecified; + + private BasicAmountType amountField; + + private string invoiceIDField; + + private string msgSubIDField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public UATPDetailsType UATPDetails { + get { + return this.uATPDetailsField; + } + set { + this.uATPDetailsField = value; + } + } + + /// + public TransactionEntityType TransactionEntity { + get { + return this.transactionEntityField; + } + set { + this.transactionEntityField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TransactionEntitySpecified { + get { + return this.transactionEntityFieldSpecified; + } + set { + this.transactionEntityFieldSpecified = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum TransactionEntityType { + + /// + None, + + /// + Auth, + + /// + Reauth, + + /// + Order, + + /// + Payment, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateAuthorizationRequestType : AbstractRequestType { + + private string transactionIDField; + + private AddressType shipToAddressField; + + private string iPAddressField; + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public AddressType ShipToAddress { + get { + return this.shipToAddressField; + } + set { + this.shipToAddressField = value; + } + } + + /// + public string IPAddress { + get { + return this.iPAddressField; + } + set { + this.iPAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoAuthorizationRequestType : AbstractRequestType { + + private string transactionIDField; + + private TransactionEntityType transactionEntityField; + + private bool transactionEntityFieldSpecified; + + private BasicAmountType amountField; + + private AddressType shipToAddressField; + + private PaymentDetailsItemType[] paymentDetailsItemField; + + private BasicAmountType itemTotalField; + + private BasicAmountType shippingTotalField; + + private BasicAmountType handlingTotalField; + + private BasicAmountType taxTotalField; + + private BasicAmountType insuranceTotalField; + + private BasicAmountType shippingDiscountField; + + private string orderDescriptionField; + + private string customField; + + private string msgSubIDField; + + private string iPAddressField; + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public TransactionEntityType TransactionEntity { + get { + return this.transactionEntityField; + } + set { + this.transactionEntityField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TransactionEntitySpecified { + get { + return this.transactionEntityFieldSpecified; + } + set { + this.transactionEntityFieldSpecified = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public AddressType ShipToAddress { + get { + return this.shipToAddressField; + } + set { + this.shipToAddressField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PaymentDetailsItem", Namespace="urn:ebay:apis:eBLBaseComponents")] + public PaymentDetailsItemType[] PaymentDetailsItem { + get { + return this.paymentDetailsItemField; + } + set { + this.paymentDetailsItemField = value; + } + } + + /// + public BasicAmountType ItemTotal { + get { + return this.itemTotalField; + } + set { + this.itemTotalField = value; + } + } + + /// + public BasicAmountType ShippingTotal { + get { + return this.shippingTotalField; + } + set { + this.shippingTotalField = value; + } + } + + /// + public BasicAmountType HandlingTotal { + get { + return this.handlingTotalField; + } + set { + this.handlingTotalField = value; + } + } + + /// + public BasicAmountType TaxTotal { + get { + return this.taxTotalField; + } + set { + this.taxTotalField = value; + } + } + + /// + public BasicAmountType InsuranceTotal { + get { + return this.insuranceTotalField; + } + set { + this.insuranceTotalField = value; + } + } + + /// + public BasicAmountType ShippingDiscount { + get { + return this.shippingDiscountField; + } + set { + this.shippingDiscountField = value; + } + } + + /// + public string OrderDescription { + get { + return this.orderDescriptionField; + } + set { + this.orderDescriptionField = value; + } + } + + /// + public string Custom { + get { + return this.customField; + } + set { + this.customField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + + /// + public string IPAddress { + get { + return this.iPAddressField; + } + set { + this.iPAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoVoidRequestType : AbstractRequestType { + + private string authorizationIDField; + + private string noteField; + + private string msgSubIDField; + + /// + public string AuthorizationID { + get { + return this.authorizationIDField; + } + set { + this.authorizationIDField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoReauthorizationRequestType : AbstractRequestType { + + private string authorizationIDField; + + private BasicAmountType amountField; + + private string msgSubIDField; + + /// + public string AuthorizationID { + get { + return this.authorizationIDField; + } + set { + this.authorizationIDField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoCaptureRequestType : AbstractRequestType { + + private string authorizationIDField; + + private BasicAmountType amountField; + + private CompleteCodeType completeTypeField; + + private string noteField; + + private string invoiceIDField; + + private EnhancedDataType enhancedDataField; + + private string descriptorField; + + private MerchantStoreDetailsType merchantStoreDetailsField; + + private string msgSubIDField; + + private TupleType[] merchantDataField; + + /// + public string AuthorizationID { + get { + return this.authorizationIDField; + } + set { + this.authorizationIDField = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public CompleteCodeType CompleteType { + get { + return this.completeTypeField; + } + set { + this.completeTypeField = value; + } + } + + /// + public string Note { + get { + return this.noteField; + } + set { + this.noteField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public EnhancedDataType EnhancedData { + get { + return this.enhancedDataField; + } + set { + this.enhancedDataField = value; + } + } + + /// + public string Descriptor { + get { + return this.descriptorField; + } + set { + this.descriptorField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public MerchantStoreDetailsType MerchantStoreDetails { + get { + return this.merchantStoreDetailsField; + } + set { + this.merchantStoreDetailsField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + [System.Xml.Serialization.XmlArrayItemAttribute("MerchantDataTuple", IsNullable=false)] + public TupleType[] MerchantData { + get { + return this.merchantDataField; + } + set { + this.merchantDataField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum CompleteCodeType { + + /// + NotComplete, + + /// + Complete, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoCancelRequestType : AbstractRequestType { + + private string cancelMsgSubIDField; + + private APIType aPITypeField; + + private string msgSubIDField; + + /// + public string CancelMsgSubID { + get { + return this.cancelMsgSubIDField; + } + set { + this.cancelMsgSubIDField = value; + } + } + + /// + public APIType APIType { + get { + return this.aPITypeField; + } + set { + this.aPITypeField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum APIType { + + /// + CHECKOUT_AUTHORIZATION, + + /// + CHECKOUT_SALE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoDirectPaymentRequestType : AbstractRequestType { + + private DoDirectPaymentRequestDetailsType doDirectPaymentRequestDetailsField; + + private int returnFMFDetailsField; + + private bool returnFMFDetailsFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public DoDirectPaymentRequestDetailsType DoDirectPaymentRequestDetails { + get { + return this.doDirectPaymentRequestDetailsField; + } + set { + this.doDirectPaymentRequestDetailsField = value; + } + } + + /// + public int ReturnFMFDetails { + get { + return this.returnFMFDetailsField; + } + set { + this.returnFMFDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReturnFMFDetailsSpecified { + get { + return this.returnFMFDetailsFieldSpecified; + } + set { + this.returnFMFDetailsFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ManagePendingTransactionStatusRequestType : AbstractRequestType { + + private string transactionIDField; + + private FMFPendingTransactionActionType actionField; + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public FMFPendingTransactionActionType Action { + get { + return this.actionField; + } + set { + this.actionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum FMFPendingTransactionActionType { + + /// + Accept, + + /// + Deny, + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoUATPExpressCheckoutPaymentRequestType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoExpressCheckoutPaymentRequestType : AbstractRequestType { + + private DoExpressCheckoutPaymentRequestDetailsType doExpressCheckoutPaymentRequestDetailsField; + + private int returnFMFDetailsField; + + private bool returnFMFDetailsFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public DoExpressCheckoutPaymentRequestDetailsType DoExpressCheckoutPaymentRequestDetails { + get { + return this.doExpressCheckoutPaymentRequestDetailsField; + } + set { + this.doExpressCheckoutPaymentRequestDetailsField = value; + } + } + + /// + public int ReturnFMFDetails { + get { + return this.returnFMFDetailsField; + } + set { + this.returnFMFDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReturnFMFDetailsSpecified { + get { + return this.returnFMFDetailsFieldSpecified; + } + set { + this.returnFMFDetailsFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoUATPExpressCheckoutPaymentRequestType : DoExpressCheckoutPaymentRequestType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetExpressCheckoutDetailsRequestType : AbstractRequestType { + + private string tokenField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class ExecuteCheckoutOperationsRequestType : AbstractRequestType { + + private ExecuteCheckoutOperationsRequestDetailsType executeCheckoutOperationsRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public ExecuteCheckoutOperationsRequestDetailsType ExecuteCheckoutOperationsRequestDetails { + get { + return this.executeCheckoutOperationsRequestDetailsField; + } + set { + this.executeCheckoutOperationsRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetExpressCheckoutRequestType : AbstractRequestType { + + private SetExpressCheckoutRequestDetailsType setExpressCheckoutRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public SetExpressCheckoutRequestDetailsType SetExpressCheckoutRequestDetails { + get { + return this.setExpressCheckoutRequestDetailsField; + } + set { + this.setExpressCheckoutRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetIncentiveEvaluationRequestType : AbstractRequestType { + + private GetIncentiveEvaluationRequestDetailsType getIncentiveEvaluationRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public GetIncentiveEvaluationRequestDetailsType GetIncentiveEvaluationRequestDetails { + get { + return this.getIncentiveEvaluationRequestDetailsField; + } + set { + this.getIncentiveEvaluationRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetAccessPermissionDetailsRequestType : AbstractRequestType { + + private string tokenField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateAccessPermissionsRequestType : AbstractRequestType { + + private string payerIDField; + + /// + public string PayerID { + get { + return this.payerIDField; + } + set { + this.payerIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetAccessPermissionsRequestType : AbstractRequestType { + + private SetAccessPermissionsRequestDetailsType setAccessPermissionsRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public SetAccessPermissionsRequestDetailsType SetAccessPermissionsRequestDetails { + get { + return this.setAccessPermissionsRequestDetailsField; + } + set { + this.setAccessPermissionsRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetAuthDetailsRequestType : AbstractRequestType { + + private string tokenField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetAuthFlowParamRequestType : AbstractRequestType { + + private SetAuthFlowParamRequestDetailsType setAuthFlowParamRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public SetAuthFlowParamRequestDetailsType SetAuthFlowParamRequestDetails { + get { + return this.setAuthFlowParamRequestDetailsField; + } + set { + this.setAuthFlowParamRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBoardingDetailsRequestType : AbstractRequestType { + + private string tokenField; + + /// + public string Token { + get { + return this.tokenField; + } + set { + this.tokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class EnterBoardingRequestType : AbstractRequestType { + + private EnterBoardingRequestDetailsType enterBoardingRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public EnterBoardingRequestDetailsType EnterBoardingRequestDetails { + get { + return this.enterBoardingRequestDetailsField; + } + set { + this.enterBoardingRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class AddressVerifyRequestType : AbstractRequestType { + + private string emailField; + + private string streetField; + + private string zipField; + + /// + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + public string Street { + get { + return this.streetField; + } + set { + this.streetField = value; + } + } + + /// + public string Zip { + get { + return this.zipField; + } + set { + this.zipField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BAUpdateRequestType : AbstractRequestType { + + private string referenceIDField; + + private string billingAgreementDescriptionField; + + private MerchantPullStatusCodeType billingAgreementStatusField; + + private bool billingAgreementStatusFieldSpecified; + + private string billingAgreementCustomField; + + /// + public string ReferenceID { + get { + return this.referenceIDField; + } + set { + this.referenceIDField = value; + } + } + + /// + public string BillingAgreementDescription { + get { + return this.billingAgreementDescriptionField; + } + set { + this.billingAgreementDescriptionField = value; + } + } + + /// + public MerchantPullStatusCodeType BillingAgreementStatus { + get { + return this.billingAgreementStatusField; + } + set { + this.billingAgreementStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BillingAgreementStatusSpecified { + get { + return this.billingAgreementStatusFieldSpecified; + } + set { + this.billingAgreementStatusFieldSpecified = value; + } + } + + /// + public string BillingAgreementCustom { + get { + return this.billingAgreementCustomField; + } + set { + this.billingAgreementCustomField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class MassPayRequestType : AbstractRequestType { + + private string emailSubjectField; + + private ReceiverInfoCodeType receiverTypeField; + + private bool receiverTypeFieldSpecified; + + private string buttonSourceField; + + private MassPayRequestItemType[] massPayItemField; + + /// + public string EmailSubject { + get { + return this.emailSubjectField; + } + set { + this.emailSubjectField = value; + } + } + + /// + public ReceiverInfoCodeType ReceiverType { + get { + return this.receiverTypeField; + } + set { + this.receiverTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReceiverTypeSpecified { + get { + return this.receiverTypeFieldSpecified; + } + set { + this.receiverTypeFieldSpecified = value; + } + } + + /// + public string ButtonSource { + get { + return this.buttonSourceField; + } + set { + this.buttonSourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("MassPayItem")] + public MassPayRequestItemType[] MassPayItem { + get { + return this.massPayItemField; + } + set { + this.massPayItemField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ReceiverInfoCodeType { + + /// + EmailAddress, + + /// + UserID, + + /// + PhoneNumber, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class TransactionSearchRequestType : AbstractRequestType { + + private System.DateTime startDateField; + + private System.DateTime endDateField; + + private bool endDateFieldSpecified; + + private string payerField; + + private string receiverField; + + private string receiptIDField; + + private string transactionIDField; + + private string profileIDField; + + private PersonNameType payerNameField; + + private string auctionItemNumberField; + + private string invoiceIDField; + + private string cardNumberField; + + private PaymentTransactionClassCodeType transactionClassField; + + private bool transactionClassFieldSpecified; + + private BasicAmountType amountField; + + private CurrencyCodeType currencyCodeField; + + private bool currencyCodeFieldSpecified; + + private PaymentTransactionStatusCodeType statusField; + + private bool statusFieldSpecified; + + /// + public System.DateTime StartDate { + get { + return this.startDateField; + } + set { + this.startDateField = value; + } + } + + /// + public System.DateTime EndDate { + get { + return this.endDateField; + } + set { + this.endDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool EndDateSpecified { + get { + return this.endDateFieldSpecified; + } + set { + this.endDateFieldSpecified = value; + } + } + + /// + public string Payer { + get { + return this.payerField; + } + set { + this.payerField = value; + } + } + + /// + public string Receiver { + get { + return this.receiverField; + } + set { + this.receiverField = value; + } + } + + /// + public string ReceiptID { + get { + return this.receiptIDField; + } + set { + this.receiptIDField = value; + } + } + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public string ProfileID { + get { + return this.profileIDField; + } + set { + this.profileIDField = value; + } + } + + /// + public PersonNameType PayerName { + get { + return this.payerNameField; + } + set { + this.payerNameField = value; + } + } + + /// + public string AuctionItemNumber { + get { + return this.auctionItemNumberField; + } + set { + this.auctionItemNumberField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public string CardNumber { + get { + return this.cardNumberField; + } + set { + this.cardNumberField = value; + } + } + + /// + public PaymentTransactionClassCodeType TransactionClass { + get { + return this.transactionClassField; + } + set { + this.transactionClassField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TransactionClassSpecified { + get { + return this.transactionClassFieldSpecified; + } + set { + this.transactionClassFieldSpecified = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public CurrencyCodeType CurrencyCode { + get { + return this.currencyCodeField; + } + set { + this.currencyCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CurrencyCodeSpecified { + get { + return this.currencyCodeFieldSpecified; + } + set { + this.currencyCodeFieldSpecified = value; + } + } + + /// + public PaymentTransactionStatusCodeType Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StatusSpecified { + get { + return this.statusFieldSpecified; + } + set { + this.statusFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentTransactionClassCodeType { + + /// + All, + + /// + Sent, + + /// + Received, + + /// + MassPay, + + /// + MoneyRequest, + + /// + FundsAdded, + + /// + FundsWithdrawn, + + /// + PayPalDebitCard, + + /// + Referral, + + /// + Fee, + + /// + Subscription, + + /// + Dividend, + + /// + Billpay, + + /// + Refund, + + /// + CurrencyConversions, + + /// + BalanceTransfer, + + /// + Reversal, + + /// + Shipping, + + /// + BalanceAffecting, + + /// + ECheck, + + /// + ForcedPostTransaction, + + /// + NonReferencedRefunds, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum PaymentTransactionStatusCodeType { + + /// + Pending, + + /// + Processing, + + /// + Success, + + /// + Denied, + + /// + Reversed, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BillUserRequestType : AbstractRequestType { + + private MerchantPullPaymentType merchantPullPaymentDetailsField; + + private int returnFMFDetailsField; + + private bool returnFMFDetailsFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public MerchantPullPaymentType MerchantPullPaymentDetails { + get { + return this.merchantPullPaymentDetailsField; + } + set { + this.merchantPullPaymentDetailsField = value; + } + } + + /// + public int ReturnFMFDetails { + get { + return this.returnFMFDetailsField; + } + set { + this.returnFMFDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ReturnFMFDetailsSpecified { + get { + return this.returnFMFDetailsFieldSpecified; + } + set { + this.returnFMFDetailsFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetTransactionDetailsRequestType : AbstractRequestType { + + private string transactionIDField; + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CancelRecoupRequestType : AbstractRequestType { + + private EnhancedCancelRecoupRequestDetailsType enhancedCancelRecoupRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public EnhancedCancelRecoupRequestDetailsType EnhancedCancelRecoupRequestDetails { + get { + return this.enhancedCancelRecoupRequestDetailsField; + } + set { + this.enhancedCancelRecoupRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class CompleteRecoupRequestType : AbstractRequestType { + + private EnhancedCompleteRecoupRequestDetailsType enhancedCompleteRecoupRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public EnhancedCompleteRecoupRequestDetailsType EnhancedCompleteRecoupRequestDetails { + get { + return this.enhancedCompleteRecoupRequestDetailsField; + } + set { + this.enhancedCompleteRecoupRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class InitiateRecoupRequestType : AbstractRequestType { + + private EnhancedInitiateRecoupRequestDetailsType enhancedInitiateRecoupRequestDetailsField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:EnhancedDataTypes")] + public EnhancedInitiateRecoupRequestDetailsType EnhancedInitiateRecoupRequestDetails { + get { + return this.enhancedInitiateRecoupRequestDetailsField; + } + set { + this.enhancedInitiateRecoupRequestDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class RefundTransactionRequestType : AbstractRequestType { + + private string transactionIDField; + + private string payerIDField; + + private string invoiceIDField; + + private RefundType refundTypeField; + + private bool refundTypeFieldSpecified; + + private BasicAmountType amountField; + + private string memoField; + + private System.DateTime retryUntilField; + + private bool retryUntilFieldSpecified; + + private RefundSourceCodeType refundSourceField; + + private bool refundSourceFieldSpecified; + + private bool refundAdviceField; + + private bool refundAdviceFieldSpecified; + + private MerchantStoreDetailsType merchantStoreDetailsField; + + private InvoiceItemType[] refundItemDetailsField; + + private string msgSubIDField; + + /// + public string TransactionID { + get { + return this.transactionIDField; + } + set { + this.transactionIDField = value; + } + } + + /// + public string PayerID { + get { + return this.payerIDField; + } + set { + this.payerIDField = value; + } + } + + /// + public string InvoiceID { + get { + return this.invoiceIDField; + } + set { + this.invoiceIDField = value; + } + } + + /// + public RefundType RefundType { + get { + return this.refundTypeField; + } + set { + this.refundTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RefundTypeSpecified { + get { + return this.refundTypeFieldSpecified; + } + set { + this.refundTypeFieldSpecified = value; + } + } + + /// + public BasicAmountType Amount { + get { + return this.amountField; + } + set { + this.amountField = value; + } + } + + /// + public string Memo { + get { + return this.memoField; + } + set { + this.memoField = value; + } + } + + /// + public System.DateTime RetryUntil { + get { + return this.retryUntilField; + } + set { + this.retryUntilField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RetryUntilSpecified { + get { + return this.retryUntilFieldSpecified; + } + set { + this.retryUntilFieldSpecified = value; + } + } + + /// + public RefundSourceCodeType RefundSource { + get { + return this.refundSourceField; + } + set { + this.refundSourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RefundSourceSpecified { + get { + return this.refundSourceFieldSpecified; + } + set { + this.refundSourceFieldSpecified = value; + } + } + + /// + public bool RefundAdvice { + get { + return this.refundAdviceField; + } + set { + this.refundAdviceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RefundAdviceSpecified { + get { + return this.refundAdviceFieldSpecified; + } + set { + this.refundAdviceFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public MerchantStoreDetailsType MerchantStoreDetails { + get { + return this.merchantStoreDetailsField; + } + set { + this.merchantStoreDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("RefundItemDetails", Namespace="urn:ebay:apis:eBLBaseComponents")] + public InvoiceItemType[] RefundItemDetails { + get { + return this.refundItemDetailsField; + } + set { + this.refundItemDetailsField = value; + } + } + + /// + public string MsgSubID { + get { + return this.msgSubIDField; + } + set { + this.msgSubIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum RefundType { + + /// + Other, + + /// + Full, + + /// + Partial, + + /// + ExternalDispute, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMButtonSearchRequestType : AbstractRequestType { + + private System.DateTime startDateField; + + private bool startDateFieldSpecified; + + private System.DateTime endDateField; + + private bool endDateFieldSpecified; + + /// + public System.DateTime StartDate { + get { + return this.startDateField; + } + set { + this.startDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StartDateSpecified { + get { + return this.startDateFieldSpecified; + } + set { + this.startDateFieldSpecified = value; + } + } + + /// + public System.DateTime EndDate { + get { + return this.endDateField; + } + set { + this.endDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool EndDateSpecified { + get { + return this.endDateFieldSpecified; + } + set { + this.endDateFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMGetInventoryRequestType : AbstractRequestType { + + private string hostedButtonIDField; + + /// + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMSetInventoryRequestType : AbstractRequestType { + + private string hostedButtonIDField; + + private string trackInvField; + + private string trackPnlField; + + private ItemTrackingDetailsType itemTrackingDetailsField; + + private string optionIndexField; + + private OptionTrackingDetailsType[] optionTrackingDetailsField; + + private string soldoutURLField; + + private string reuseDigitalDownloadKeysField; + + private string appendDigitalDownloadKeysField; + + private string[] digitalDownloadKeysField; + + /// + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + + /// + public string TrackInv { + get { + return this.trackInvField; + } + set { + this.trackInvField = value; + } + } + + /// + public string TrackPnl { + get { + return this.trackPnlField; + } + set { + this.trackPnlField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public ItemTrackingDetailsType ItemTrackingDetails { + get { + return this.itemTrackingDetailsField; + } + set { + this.itemTrackingDetailsField = value; + } + } + + /// + public string OptionIndex { + get { + return this.optionIndexField; + } + set { + this.optionIndexField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OptionTrackingDetails", Namespace="urn:ebay:apis:eBLBaseComponents")] + public OptionTrackingDetailsType[] OptionTrackingDetails { + get { + return this.optionTrackingDetailsField; + } + set { + this.optionTrackingDetailsField = value; + } + } + + /// + public string SoldoutURL { + get { + return this.soldoutURLField; + } + set { + this.soldoutURLField = value; + } + } + + /// + public string ReuseDigitalDownloadKeys { + get { + return this.reuseDigitalDownloadKeysField; + } + set { + this.reuseDigitalDownloadKeysField = value; + } + } + + /// + public string AppendDigitalDownloadKeys { + get { + return this.appendDigitalDownloadKeysField; + } + set { + this.appendDigitalDownloadKeysField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("DigitalDownloadKeys")] + public string[] DigitalDownloadKeys { + get { + return this.digitalDownloadKeysField; + } + set { + this.digitalDownloadKeysField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMGetButtonDetailsRequestType : AbstractRequestType { + + private string hostedButtonIDField; + + /// + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMManageButtonStatusRequestType : AbstractRequestType { + + private string hostedButtonIDField; + + private ButtonStatusType buttonStatusField; + + private bool buttonStatusFieldSpecified; + + /// + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + + /// + public ButtonStatusType ButtonStatus { + get { + return this.buttonStatusField; + } + set { + this.buttonStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonStatusSpecified { + get { + return this.buttonStatusFieldSpecified; + } + set { + this.buttonStatusFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:apis:eBLBaseComponents")] + public enum ButtonStatusType { + + /// + DELETE, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMUpdateButtonRequestType : AbstractRequestType { + + private string hostedButtonIDField; + + private ButtonTypeType buttonTypeField; + + private bool buttonTypeFieldSpecified; + + private ButtonCodeType buttonCodeField; + + private bool buttonCodeFieldSpecified; + + private ButtonSubTypeType buttonSubTypeField; + + private bool buttonSubTypeFieldSpecified; + + private string[] buttonVarField; + + private OptionDetailsType[] optionDetailsField; + + private string[] textBoxField; + + private ButtonImageType buttonImageField; + + private bool buttonImageFieldSpecified; + + private string buttonImageURLField; + + private BuyNowTextType buyNowTextField; + + private bool buyNowTextFieldSpecified; + + private SubscribeTextType subscribeTextField; + + private bool subscribeTextFieldSpecified; + + private CountryCodeType buttonCountryField; + + private bool buttonCountryFieldSpecified; + + private string buttonLanguageField; + + /// + public string HostedButtonID { + get { + return this.hostedButtonIDField; + } + set { + this.hostedButtonIDField = value; + } + } + + /// + public ButtonTypeType ButtonType { + get { + return this.buttonTypeField; + } + set { + this.buttonTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonTypeSpecified { + get { + return this.buttonTypeFieldSpecified; + } + set { + this.buttonTypeFieldSpecified = value; + } + } + + /// + public ButtonCodeType ButtonCode { + get { + return this.buttonCodeField; + } + set { + this.buttonCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonCodeSpecified { + get { + return this.buttonCodeFieldSpecified; + } + set { + this.buttonCodeFieldSpecified = value; + } + } + + /// + public ButtonSubTypeType ButtonSubType { + get { + return this.buttonSubTypeField; + } + set { + this.buttonSubTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonSubTypeSpecified { + get { + return this.buttonSubTypeFieldSpecified; + } + set { + this.buttonSubTypeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ButtonVar")] + public string[] ButtonVar { + get { + return this.buttonVarField; + } + set { + this.buttonVarField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OptionDetails")] + public OptionDetailsType[] OptionDetails { + get { + return this.optionDetailsField; + } + set { + this.optionDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("TextBox")] + public string[] TextBox { + get { + return this.textBoxField; + } + set { + this.textBoxField = value; + } + } + + /// + public ButtonImageType ButtonImage { + get { + return this.buttonImageField; + } + set { + this.buttonImageField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonImageSpecified { + get { + return this.buttonImageFieldSpecified; + } + set { + this.buttonImageFieldSpecified = value; + } + } + + /// + public string ButtonImageURL { + get { + return this.buttonImageURLField; + } + set { + this.buttonImageURLField = value; + } + } + + /// + public BuyNowTextType BuyNowText { + get { + return this.buyNowTextField; + } + set { + this.buyNowTextField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BuyNowTextSpecified { + get { + return this.buyNowTextFieldSpecified; + } + set { + this.buyNowTextFieldSpecified = value; + } + } + + /// + public SubscribeTextType SubscribeText { + get { + return this.subscribeTextField; + } + set { + this.subscribeTextField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SubscribeTextSpecified { + get { + return this.subscribeTextFieldSpecified; + } + set { + this.subscribeTextFieldSpecified = value; + } + } + + /// + public CountryCodeType ButtonCountry { + get { + return this.buttonCountryField; + } + set { + this.buttonCountryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonCountrySpecified { + get { + return this.buttonCountryFieldSpecified; + } + set { + this.buttonCountryFieldSpecified = value; + } + } + + /// + public string ButtonLanguage { + get { + return this.buttonLanguageField; + } + set { + this.buttonLanguageField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMCreateButtonRequestType : AbstractRequestType { + + private ButtonTypeType buttonTypeField; + + private bool buttonTypeFieldSpecified; + + private ButtonCodeType buttonCodeField; + + private bool buttonCodeFieldSpecified; + + private ButtonSubTypeType buttonSubTypeField; + + private bool buttonSubTypeFieldSpecified; + + private string[] buttonVarField; + + private OptionDetailsType[] optionDetailsField; + + private string[] textBoxField; + + private ButtonImageType buttonImageField; + + private bool buttonImageFieldSpecified; + + private string buttonImageURLField; + + private BuyNowTextType buyNowTextField; + + private bool buyNowTextFieldSpecified; + + private SubscribeTextType subscribeTextField; + + private bool subscribeTextFieldSpecified; + + private CountryCodeType buttonCountryField; + + private bool buttonCountryFieldSpecified; + + private string buttonLanguageField; + + /// + public ButtonTypeType ButtonType { + get { + return this.buttonTypeField; + } + set { + this.buttonTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonTypeSpecified { + get { + return this.buttonTypeFieldSpecified; + } + set { + this.buttonTypeFieldSpecified = value; + } + } + + /// + public ButtonCodeType ButtonCode { + get { + return this.buttonCodeField; + } + set { + this.buttonCodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonCodeSpecified { + get { + return this.buttonCodeFieldSpecified; + } + set { + this.buttonCodeFieldSpecified = value; + } + } + + /// + public ButtonSubTypeType ButtonSubType { + get { + return this.buttonSubTypeField; + } + set { + this.buttonSubTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonSubTypeSpecified { + get { + return this.buttonSubTypeFieldSpecified; + } + set { + this.buttonSubTypeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("ButtonVar")] + public string[] ButtonVar { + get { + return this.buttonVarField; + } + set { + this.buttonVarField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("OptionDetails")] + public OptionDetailsType[] OptionDetails { + get { + return this.optionDetailsField; + } + set { + this.optionDetailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("TextBox")] + public string[] TextBox { + get { + return this.textBoxField; + } + set { + this.textBoxField = value; + } + } + + /// + public ButtonImageType ButtonImage { + get { + return this.buttonImageField; + } + set { + this.buttonImageField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonImageSpecified { + get { + return this.buttonImageFieldSpecified; + } + set { + this.buttonImageFieldSpecified = value; + } + } + + /// + public string ButtonImageURL { + get { + return this.buttonImageURLField; + } + set { + this.buttonImageURLField = value; + } + } + + /// + public BuyNowTextType BuyNowText { + get { + return this.buyNowTextField; + } + set { + this.buyNowTextField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool BuyNowTextSpecified { + get { + return this.buyNowTextFieldSpecified; + } + set { + this.buyNowTextFieldSpecified = value; + } + } + + /// + public SubscribeTextType SubscribeText { + get { + return this.subscribeTextField; + } + set { + this.subscribeTextField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SubscribeTextSpecified { + get { + return this.subscribeTextFieldSpecified; + } + set { + this.subscribeTextFieldSpecified = value; + } + } + + /// + public CountryCodeType ButtonCountry { + get { + return this.buttonCountryField; + } + set { + this.buttonCountryField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ButtonCountrySpecified { + get { + return this.buttonCountryFieldSpecified; + } + set { + this.buttonCountryFieldSpecified = value; + } + } + + /// + public string ButtonLanguage { + get { + return this.buttonLanguageField; + } + set { + this.buttonLanguageField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class RefundTransactionReq { + + private RefundTransactionRequestType refundTransactionRequestField; + + /// + public RefundTransactionRequestType RefundTransactionRequest { + get { + return this.refundTransactionRequestField; + } + set { + this.refundTransactionRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class InitiateRecoupReq { + + private InitiateRecoupRequestType initiateRecoupRequestField; + + /// + public InitiateRecoupRequestType InitiateRecoupRequest { + get { + return this.initiateRecoupRequestField; + } + set { + this.initiateRecoupRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class CompleteRecoupReq { + + private CompleteRecoupRequestType completeRecoupRequestField; + + /// + public CompleteRecoupRequestType CompleteRecoupRequest { + get { + return this.completeRecoupRequestField; + } + set { + this.completeRecoupRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class CancelRecoupReq { + + private CancelRecoupRequestType cancelRecoupRequestField; + + /// + public CancelRecoupRequestType CancelRecoupRequest { + get { + return this.cancelRecoupRequestField; + } + set { + this.cancelRecoupRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetTransactionDetailsReq { + + private GetTransactionDetailsRequestType getTransactionDetailsRequestField; + + /// + public GetTransactionDetailsRequestType GetTransactionDetailsRequest { + get { + return this.getTransactionDetailsRequestField; + } + set { + this.getTransactionDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMCreateButtonReq { + + private BMCreateButtonRequestType bMCreateButtonRequestField; + + /// + public BMCreateButtonRequestType BMCreateButtonRequest { + get { + return this.bMCreateButtonRequestField; + } + set { + this.bMCreateButtonRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMUpdateButtonReq { + + private BMUpdateButtonRequestType bMUpdateButtonRequestField; + + /// + public BMUpdateButtonRequestType BMUpdateButtonRequest { + get { + return this.bMUpdateButtonRequestField; + } + set { + this.bMUpdateButtonRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMManageButtonStatusReq { + + private BMManageButtonStatusRequestType bMManageButtonStatusRequestField; + + /// + public BMManageButtonStatusRequestType BMManageButtonStatusRequest { + get { + return this.bMManageButtonStatusRequestField; + } + set { + this.bMManageButtonStatusRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMGetButtonDetailsReq { + + private BMGetButtonDetailsRequestType bMGetButtonDetailsRequestField; + + /// + public BMGetButtonDetailsRequestType BMGetButtonDetailsRequest { + get { + return this.bMGetButtonDetailsRequestField; + } + set { + this.bMGetButtonDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMSetInventoryReq { + + private BMSetInventoryRequestType bMSetInventoryRequestField; + + /// + public BMSetInventoryRequestType BMSetInventoryRequest { + get { + return this.bMSetInventoryRequestField; + } + set { + this.bMSetInventoryRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMGetInventoryReq { + + private BMGetInventoryRequestType bMGetInventoryRequestField; + + /// + public BMGetInventoryRequestType BMGetInventoryRequest { + get { + return this.bMGetInventoryRequestField; + } + set { + this.bMGetInventoryRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BMButtonSearchReq { + + private BMButtonSearchRequestType bMButtonSearchRequestField; + + /// + public BMButtonSearchRequestType BMButtonSearchRequest { + get { + return this.bMButtonSearchRequestField; + } + set { + this.bMButtonSearchRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BillUserReq { + + private BillUserRequestType billUserRequestField; + + /// + public BillUserRequestType BillUserRequest { + get { + return this.billUserRequestField; + } + set { + this.billUserRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class TransactionSearchReq { + + private TransactionSearchRequestType transactionSearchRequestField; + + /// + public TransactionSearchRequestType TransactionSearchRequest { + get { + return this.transactionSearchRequestField; + } + set { + this.transactionSearchRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class MassPayReq { + + private MassPayRequestType massPayRequestField; + + /// + public MassPayRequestType MassPayRequest { + get { + return this.massPayRequestField; + } + set { + this.massPayRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BillAgreementUpdateReq { + + private BAUpdateRequestType bAUpdateRequestField; + + /// + public BAUpdateRequestType BAUpdateRequest { + get { + return this.bAUpdateRequestField; + } + set { + this.bAUpdateRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class AddressVerifyReq { + + private AddressVerifyRequestType addressVerifyRequestField; + + /// + public AddressVerifyRequestType AddressVerifyRequest { + get { + return this.addressVerifyRequestField; + } + set { + this.addressVerifyRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class EnterBoardingReq { + + private EnterBoardingRequestType enterBoardingRequestField; + + /// + public EnterBoardingRequestType EnterBoardingRequest { + get { + return this.enterBoardingRequestField; + } + set { + this.enterBoardingRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBoardingDetailsReq { + + private GetBoardingDetailsRequestType getBoardingDetailsRequestField; + + /// + public GetBoardingDetailsRequestType GetBoardingDetailsRequest { + get { + return this.getBoardingDetailsRequestField; + } + set { + this.getBoardingDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateMobilePaymentReq { + + private CreateMobilePaymentRequestType createMobilePaymentRequestField; + + /// + public CreateMobilePaymentRequestType CreateMobilePaymentRequest { + get { + return this.createMobilePaymentRequestField; + } + set { + this.createMobilePaymentRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetMobileStatusReq { + + private GetMobileStatusRequestType getMobileStatusRequestField; + + /// + public GetMobileStatusRequestType GetMobileStatusRequest { + get { + return this.getMobileStatusRequestField; + } + set { + this.getMobileStatusRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetMobileCheckoutReq { + + private SetMobileCheckoutRequestType setMobileCheckoutRequestField; + + /// + public SetMobileCheckoutRequestType SetMobileCheckoutRequest { + get { + return this.setMobileCheckoutRequestField; + } + set { + this.setMobileCheckoutRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoMobileCheckoutPaymentReq { + + private DoMobileCheckoutPaymentRequestType doMobileCheckoutPaymentRequestField; + + /// + public DoMobileCheckoutPaymentRequestType DoMobileCheckoutPaymentRequest { + get { + return this.doMobileCheckoutPaymentRequestField; + } + set { + this.doMobileCheckoutPaymentRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBalanceReq { + + private GetBalanceRequestType getBalanceRequestField; + + /// + public GetBalanceRequestType GetBalanceRequest { + get { + return this.getBalanceRequestField; + } + set { + this.getBalanceRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetPalDetailsReq { + + private GetPalDetailsRequestType getPalDetailsRequestField; + + /// + public GetPalDetailsRequestType GetPalDetailsRequest { + get { + return this.getPalDetailsRequestField; + } + set { + this.getPalDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoExpressCheckoutPaymentReq { + + private DoExpressCheckoutPaymentRequestType doExpressCheckoutPaymentRequestField; + + /// + public DoExpressCheckoutPaymentRequestType DoExpressCheckoutPaymentRequest { + get { + return this.doExpressCheckoutPaymentRequestField; + } + set { + this.doExpressCheckoutPaymentRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoUATPExpressCheckoutPaymentReq { + + private DoUATPExpressCheckoutPaymentRequestType doUATPExpressCheckoutPaymentRequestField; + + /// + public DoUATPExpressCheckoutPaymentRequestType DoUATPExpressCheckoutPaymentRequest { + get { + return this.doUATPExpressCheckoutPaymentRequestField; + } + set { + this.doUATPExpressCheckoutPaymentRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetAuthFlowParamReq { + + private SetAuthFlowParamRequestType setAuthFlowParamRequestField; + + /// + public SetAuthFlowParamRequestType SetAuthFlowParamRequest { + get { + return this.setAuthFlowParamRequestField; + } + set { + this.setAuthFlowParamRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetAuthDetailsReq { + + private GetAuthDetailsRequestType getAuthDetailsRequestField; + + /// + public GetAuthDetailsRequestType GetAuthDetailsRequest { + get { + return this.getAuthDetailsRequestField; + } + set { + this.getAuthDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetAccessPermissionsReq { + + private SetAccessPermissionsRequestType setAccessPermissionsRequestField; + + /// + public SetAccessPermissionsRequestType SetAccessPermissionsRequest { + get { + return this.setAccessPermissionsRequestField; + } + set { + this.setAccessPermissionsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateAccessPermissionsReq { + + private UpdateAccessPermissionsRequestType updateAccessPermissionsRequestField; + + /// + public UpdateAccessPermissionsRequestType UpdateAccessPermissionsRequest { + get { + return this.updateAccessPermissionsRequestField; + } + set { + this.updateAccessPermissionsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetAccessPermissionDetailsReq { + + private GetAccessPermissionDetailsRequestType getAccessPermissionDetailsRequestField; + + /// + public GetAccessPermissionDetailsRequestType GetAccessPermissionDetailsRequest { + get { + return this.getAccessPermissionDetailsRequestField; + } + set { + this.getAccessPermissionDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetIncentiveEvaluationReq { + + private GetIncentiveEvaluationRequestType getIncentiveEvaluationRequestField; + + /// + public GetIncentiveEvaluationRequestType GetIncentiveEvaluationRequest { + get { + return this.getIncentiveEvaluationRequestField; + } + set { + this.getIncentiveEvaluationRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetExpressCheckoutReq { + + private SetExpressCheckoutRequestType setExpressCheckoutRequestField; + + /// + public SetExpressCheckoutRequestType SetExpressCheckoutRequest { + get { + return this.setExpressCheckoutRequestField; + } + set { + this.setExpressCheckoutRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class ExecuteCheckoutOperationsReq { + + private ExecuteCheckoutOperationsRequestType executeCheckoutOperationsRequestField; + + /// + public ExecuteCheckoutOperationsRequestType ExecuteCheckoutOperationsRequest { + get { + return this.executeCheckoutOperationsRequestField; + } + set { + this.executeCheckoutOperationsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetExpressCheckoutDetailsReq { + + private GetExpressCheckoutDetailsRequestType getExpressCheckoutDetailsRequestField; + + /// + public GetExpressCheckoutDetailsRequestType GetExpressCheckoutDetailsRequest { + get { + return this.getExpressCheckoutDetailsRequestField; + } + set { + this.getExpressCheckoutDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoDirectPaymentReq { + + private DoDirectPaymentRequestType doDirectPaymentRequestField; + + /// + public DoDirectPaymentRequestType DoDirectPaymentRequest { + get { + return this.doDirectPaymentRequestField; + } + set { + this.doDirectPaymentRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class ManagePendingTransactionStatusReq { + + private ManagePendingTransactionStatusRequestType managePendingTransactionStatusRequestField; + + /// + public ManagePendingTransactionStatusRequestType ManagePendingTransactionStatusRequest { + get { + return this.managePendingTransactionStatusRequestField; + } + set { + this.managePendingTransactionStatusRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoCancelReq { + + private DoCancelRequestType doCancelRequestField; + + /// + public DoCancelRequestType DoCancelRequest { + get { + return this.doCancelRequestField; + } + set { + this.doCancelRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoCaptureReq { + + private DoCaptureRequestType doCaptureRequestField; + + /// + public DoCaptureRequestType DoCaptureRequest { + get { + return this.doCaptureRequestField; + } + set { + this.doCaptureRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoReauthorizationReq { + + private DoReauthorizationRequestType doReauthorizationRequestField; + + /// + public DoReauthorizationRequestType DoReauthorizationRequest { + get { + return this.doReauthorizationRequestField; + } + set { + this.doReauthorizationRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoVoidReq { + + private DoVoidRequestType doVoidRequestField; + + /// + public DoVoidRequestType DoVoidRequest { + get { + return this.doVoidRequestField; + } + set { + this.doVoidRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoAuthorizationReq { + + private DoAuthorizationRequestType doAuthorizationRequestField; + + /// + public DoAuthorizationRequestType DoAuthorizationRequest { + get { + return this.doAuthorizationRequestField; + } + set { + this.doAuthorizationRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateAuthorizationReq { + + private UpdateAuthorizationRequestType updateAuthorizationRequestField; + + /// + public UpdateAuthorizationRequestType UpdateAuthorizationRequest { + get { + return this.updateAuthorizationRequestField; + } + set { + this.updateAuthorizationRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class SetCustomerBillingAgreementReq { + + private SetCustomerBillingAgreementRequestType setCustomerBillingAgreementRequestField; + + /// + public SetCustomerBillingAgreementRequestType SetCustomerBillingAgreementRequest { + get { + return this.setCustomerBillingAgreementRequestField; + } + set { + this.setCustomerBillingAgreementRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetBillingAgreementCustomerDetailsReq { + + private GetBillingAgreementCustomerDetailsRequestType getBillingAgreementCustomerDetailsRequestField; + + /// + public GetBillingAgreementCustomerDetailsRequestType GetBillingAgreementCustomerDetailsRequest { + get { + return this.getBillingAgreementCustomerDetailsRequestField; + } + set { + this.getBillingAgreementCustomerDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateBillingAgreementReq { + + private CreateBillingAgreementRequestType createBillingAgreementRequestField; + + /// + public CreateBillingAgreementRequestType CreateBillingAgreementRequest { + get { + return this.createBillingAgreementRequestField; + } + set { + this.createBillingAgreementRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoReferenceTransactionReq { + + private DoReferenceTransactionRequestType doReferenceTransactionRequestField; + + /// + public DoReferenceTransactionRequestType DoReferenceTransactionRequest { + get { + return this.doReferenceTransactionRequestField; + } + set { + this.doReferenceTransactionRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoNonReferencedCreditReq { + + private DoNonReferencedCreditRequestType doNonReferencedCreditRequestField; + + /// + public DoNonReferencedCreditRequestType DoNonReferencedCreditRequest { + get { + return this.doNonReferencedCreditRequestField; + } + set { + this.doNonReferencedCreditRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class DoUATPAuthorizationReq { + + private DoUATPAuthorizationRequestType doUATPAuthorizationRequestField; + + /// + public DoUATPAuthorizationRequestType DoUATPAuthorizationRequest { + get { + return this.doUATPAuthorizationRequestField; + } + set { + this.doUATPAuthorizationRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class CreateRecurringPaymentsProfileReq { + + private CreateRecurringPaymentsProfileRequestType createRecurringPaymentsProfileRequestField; + + /// + public CreateRecurringPaymentsProfileRequestType CreateRecurringPaymentsProfileRequest { + get { + return this.createRecurringPaymentsProfileRequestField; + } + set { + this.createRecurringPaymentsProfileRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class GetRecurringPaymentsProfileDetailsReq { + + private GetRecurringPaymentsProfileDetailsRequestType getRecurringPaymentsProfileDetailsRequestField; + + /// + public GetRecurringPaymentsProfileDetailsRequestType GetRecurringPaymentsProfileDetailsRequest { + get { + return this.getRecurringPaymentsProfileDetailsRequestField; + } + set { + this.getRecurringPaymentsProfileDetailsRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class ManageRecurringPaymentsProfileStatusReq { + + private ManageRecurringPaymentsProfileStatusRequestType manageRecurringPaymentsProfileStatusRequestField; + + /// + public ManageRecurringPaymentsProfileStatusRequestType ManageRecurringPaymentsProfileStatusRequest { + get { + return this.manageRecurringPaymentsProfileStatusRequestField; + } + set { + this.manageRecurringPaymentsProfileStatusRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class BillOutstandingAmountReq { + + private BillOutstandingAmountRequestType billOutstandingAmountRequestField; + + /// + public BillOutstandingAmountRequestType BillOutstandingAmountRequest { + get { + return this.billOutstandingAmountRequestField; + } + set { + this.billOutstandingAmountRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class UpdateRecurringPaymentsProfileReq { + + private UpdateRecurringPaymentsProfileRequestType updateRecurringPaymentsProfileRequestField; + + /// + public UpdateRecurringPaymentsProfileRequestType UpdateRecurringPaymentsProfileRequest { + get { + return this.updateRecurringPaymentsProfileRequestField; + } + set { + this.updateRecurringPaymentsProfileRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class ReverseTransactionReq { + + private ReverseTransactionRequestType reverseTransactionRequestField; + + /// + public ReverseTransactionRequestType ReverseTransactionRequest { + get { + return this.reverseTransactionRequestField; + } + set { + this.reverseTransactionRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="urn:ebay:api:PayPalAPI")] + public partial class ExternalRememberMeOptOutReq { + + private ExternalRememberMeOptOutRequestType externalRememberMeOptOutRequestField; + + /// + public ExternalRememberMeOptOutRequestType ExternalRememberMeOptOutRequest { + get { + return this.externalRememberMeOptOutRequestField; + } + set { + this.externalRememberMeOptOutRequestField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void RefundTransactionCompletedEventHandler(object sender, RefundTransactionCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class RefundTransactionCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal RefundTransactionCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public RefundTransactionResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((RefundTransactionResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void InitiateRecoupCompletedEventHandler(object sender, InitiateRecoupCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class InitiateRecoupCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal InitiateRecoupCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public InitiateRecoupResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((InitiateRecoupResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void CompleteRecoupCompletedEventHandler(object sender, CompleteRecoupCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CompleteRecoupCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CompleteRecoupCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CompleteRecoupResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CompleteRecoupResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void CancelRecoupCompletedEventHandler(object sender, CancelRecoupCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CancelRecoupCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CancelRecoupCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CancelRecoupResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CancelRecoupResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetTransactionDetailsCompletedEventHandler(object sender, GetTransactionDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetTransactionDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetTransactionDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetTransactionDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetTransactionDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BMCreateButtonCompletedEventHandler(object sender, BMCreateButtonCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BMCreateButtonCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BMCreateButtonCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BMCreateButtonResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BMCreateButtonResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BMUpdateButtonCompletedEventHandler(object sender, BMUpdateButtonCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BMUpdateButtonCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BMUpdateButtonCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BMUpdateButtonResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BMUpdateButtonResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BMManageButtonStatusCompletedEventHandler(object sender, BMManageButtonStatusCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BMManageButtonStatusCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BMManageButtonStatusCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BMManageButtonStatusResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BMManageButtonStatusResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BMGetButtonDetailsCompletedEventHandler(object sender, BMGetButtonDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BMGetButtonDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BMGetButtonDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BMGetButtonDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BMGetButtonDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BMSetInventoryCompletedEventHandler(object sender, BMSetInventoryCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BMSetInventoryCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BMSetInventoryCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BMSetInventoryResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BMSetInventoryResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BMGetInventoryCompletedEventHandler(object sender, BMGetInventoryCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BMGetInventoryCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BMGetInventoryCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BMGetInventoryResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BMGetInventoryResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BMButtonSearchCompletedEventHandler(object sender, BMButtonSearchCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BMButtonSearchCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BMButtonSearchCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BMButtonSearchResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BMButtonSearchResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BillUserCompletedEventHandler(object sender, BillUserCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BillUserCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BillUserCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BillUserResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BillUserResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void TransactionSearchCompletedEventHandler(object sender, TransactionSearchCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class TransactionSearchCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal TransactionSearchCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public TransactionSearchResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((TransactionSearchResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void MassPayCompletedEventHandler(object sender, MassPayCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class MassPayCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal MassPayCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public MassPayResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((MassPayResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BillAgreementUpdateCompletedEventHandler(object sender, BillAgreementUpdateCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BillAgreementUpdateCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BillAgreementUpdateCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BAUpdateResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BAUpdateResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void AddressVerifyCompletedEventHandler(object sender, AddressVerifyCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class AddressVerifyCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal AddressVerifyCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public AddressVerifyResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((AddressVerifyResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void EnterBoardingCompletedEventHandler(object sender, EnterBoardingCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class EnterBoardingCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal EnterBoardingCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public EnterBoardingResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((EnterBoardingResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetBoardingDetailsCompletedEventHandler(object sender, GetBoardingDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetBoardingDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetBoardingDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetBoardingDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetBoardingDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void CreateMobilePaymentCompletedEventHandler(object sender, CreateMobilePaymentCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateMobilePaymentCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateMobilePaymentCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CreateMobilePaymentResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CreateMobilePaymentResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetMobileStatusCompletedEventHandler(object sender, GetMobileStatusCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetMobileStatusCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetMobileStatusCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetMobileStatusResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetMobileStatusResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void SetMobileCheckoutCompletedEventHandler(object sender, SetMobileCheckoutCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class SetMobileCheckoutCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal SetMobileCheckoutCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public SetMobileCheckoutResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((SetMobileCheckoutResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoMobileCheckoutPaymentCompletedEventHandler(object sender, DoMobileCheckoutPaymentCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoMobileCheckoutPaymentCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoMobileCheckoutPaymentCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoMobileCheckoutPaymentResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoMobileCheckoutPaymentResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetBalanceCompletedEventHandler(object sender, GetBalanceCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetBalanceCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetBalanceCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetBalanceResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetBalanceResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetPalDetailsCompletedEventHandler(object sender, GetPalDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetPalDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetPalDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetPalDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetPalDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoExpressCheckoutPaymentCompletedEventHandler(object sender, DoExpressCheckoutPaymentCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoExpressCheckoutPaymentCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoExpressCheckoutPaymentCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoExpressCheckoutPaymentResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoExpressCheckoutPaymentResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoUATPExpressCheckoutPaymentCompletedEventHandler(object sender, DoUATPExpressCheckoutPaymentCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoUATPExpressCheckoutPaymentCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoUATPExpressCheckoutPaymentCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoUATPExpressCheckoutPaymentResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoUATPExpressCheckoutPaymentResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void SetAuthFlowParamCompletedEventHandler(object sender, SetAuthFlowParamCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class SetAuthFlowParamCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal SetAuthFlowParamCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public SetAuthFlowParamResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((SetAuthFlowParamResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetAuthDetailsCompletedEventHandler(object sender, GetAuthDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetAuthDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetAuthDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetAuthDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetAuthDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void SetAccessPermissionsCompletedEventHandler(object sender, SetAccessPermissionsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class SetAccessPermissionsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal SetAccessPermissionsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public SetAccessPermissionsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((SetAccessPermissionsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void UpdateAccessPermissionsCompletedEventHandler(object sender, UpdateAccessPermissionsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class UpdateAccessPermissionsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal UpdateAccessPermissionsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public UpdateAccessPermissionsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((UpdateAccessPermissionsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetAccessPermissionDetailsCompletedEventHandler(object sender, GetAccessPermissionDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetAccessPermissionDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetAccessPermissionDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetAccessPermissionDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetAccessPermissionDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetIncentiveEvaluationCompletedEventHandler(object sender, GetIncentiveEvaluationCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetIncentiveEvaluationCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetIncentiveEvaluationCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetIncentiveEvaluationResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetIncentiveEvaluationResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void SetExpressCheckoutCompletedEventHandler(object sender, SetExpressCheckoutCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class SetExpressCheckoutCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal SetExpressCheckoutCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public SetExpressCheckoutResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((SetExpressCheckoutResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void ExecuteCheckoutOperationsCompletedEventHandler(object sender, ExecuteCheckoutOperationsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ExecuteCheckoutOperationsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ExecuteCheckoutOperationsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ExecuteCheckoutOperationsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ExecuteCheckoutOperationsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetExpressCheckoutDetailsCompletedEventHandler(object sender, GetExpressCheckoutDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetExpressCheckoutDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetExpressCheckoutDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetExpressCheckoutDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetExpressCheckoutDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoDirectPaymentCompletedEventHandler(object sender, DoDirectPaymentCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoDirectPaymentCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoDirectPaymentCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoDirectPaymentResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoDirectPaymentResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void ManagePendingTransactionStatusCompletedEventHandler(object sender, ManagePendingTransactionStatusCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ManagePendingTransactionStatusCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ManagePendingTransactionStatusCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ManagePendingTransactionStatusResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ManagePendingTransactionStatusResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoCancelCompletedEventHandler(object sender, DoCancelCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoCancelCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoCancelCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoCancelResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoCancelResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoCaptureCompletedEventHandler(object sender, DoCaptureCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoCaptureCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoCaptureCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoCaptureResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoCaptureResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoReauthorizationCompletedEventHandler(object sender, DoReauthorizationCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoReauthorizationCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoReauthorizationCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoReauthorizationResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoReauthorizationResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoVoidCompletedEventHandler(object sender, DoVoidCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoVoidCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoVoidCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoVoidResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoVoidResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoAuthorizationCompletedEventHandler(object sender, DoAuthorizationCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoAuthorizationCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoAuthorizationCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoAuthorizationResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoAuthorizationResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void UpdateAuthorizationCompletedEventHandler(object sender, UpdateAuthorizationCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class UpdateAuthorizationCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal UpdateAuthorizationCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public UpdateAuthorizationResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((UpdateAuthorizationResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void SetCustomerBillingAgreementCompletedEventHandler(object sender, SetCustomerBillingAgreementCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class SetCustomerBillingAgreementCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal SetCustomerBillingAgreementCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public SetCustomerBillingAgreementResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((SetCustomerBillingAgreementResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetBillingAgreementCustomerDetailsCompletedEventHandler(object sender, GetBillingAgreementCustomerDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetBillingAgreementCustomerDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetBillingAgreementCustomerDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetBillingAgreementCustomerDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetBillingAgreementCustomerDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void CreateBillingAgreementCompletedEventHandler(object sender, CreateBillingAgreementCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateBillingAgreementCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateBillingAgreementCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CreateBillingAgreementResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CreateBillingAgreementResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoReferenceTransactionCompletedEventHandler(object sender, DoReferenceTransactionCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoReferenceTransactionCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoReferenceTransactionCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoReferenceTransactionResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoReferenceTransactionResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoNonReferencedCreditCompletedEventHandler(object sender, DoNonReferencedCreditCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoNonReferencedCreditCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoNonReferencedCreditCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoNonReferencedCreditResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoNonReferencedCreditResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void DoUATPAuthorizationCompletedEventHandler(object sender, DoUATPAuthorizationCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DoUATPAuthorizationCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DoUATPAuthorizationCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DoUATPAuthorizationResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DoUATPAuthorizationResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void CreateRecurringPaymentsProfileCompletedEventHandler(object sender, CreateRecurringPaymentsProfileCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateRecurringPaymentsProfileCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateRecurringPaymentsProfileCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CreateRecurringPaymentsProfileResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CreateRecurringPaymentsProfileResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void GetRecurringPaymentsProfileDetailsCompletedEventHandler(object sender, GetRecurringPaymentsProfileDetailsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetRecurringPaymentsProfileDetailsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetRecurringPaymentsProfileDetailsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetRecurringPaymentsProfileDetailsResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetRecurringPaymentsProfileDetailsResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void ManageRecurringPaymentsProfileStatusCompletedEventHandler(object sender, ManageRecurringPaymentsProfileStatusCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ManageRecurringPaymentsProfileStatusCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ManageRecurringPaymentsProfileStatusCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ManageRecurringPaymentsProfileStatusResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ManageRecurringPaymentsProfileStatusResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void BillOutstandingAmountCompletedEventHandler(object sender, BillOutstandingAmountCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BillOutstandingAmountCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BillOutstandingAmountCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BillOutstandingAmountResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BillOutstandingAmountResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void UpdateRecurringPaymentsProfileCompletedEventHandler(object sender, UpdateRecurringPaymentsProfileCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class UpdateRecurringPaymentsProfileCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal UpdateRecurringPaymentsProfileCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public UpdateRecurringPaymentsProfileResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((UpdateRecurringPaymentsProfileResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void ReverseTransactionCompletedEventHandler(object sender, ReverseTransactionCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ReverseTransactionCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ReverseTransactionCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ReverseTransactionResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ReverseTransactionResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + public delegate void ExternalRememberMeOptOutCompletedEventHandler(object sender, ExternalRememberMeOptOutCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.34209")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ExternalRememberMeOptOutCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ExternalRememberMeOptOutCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ExternalRememberMeOptOutResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ExternalRememberMeOptOutResponseType)(this.results[0])); + } + } + } +} + +#pragma warning restore 1591 \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/Reference.map b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/Reference.map new file mode 100644 index 0000000000..c502f53f31 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/Reference.map @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/RefundTransactionResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/RefundTransactionResponseType1.datasource new file mode 100644 index 0000000000..1bf4b11b85 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/RefundTransactionResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.RefundTransactionResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ReverseTransactionResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ReverseTransactionResponseType1.datasource new file mode 100644 index 0000000000..c22afccb5c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/ReverseTransactionResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.ReverseTransactionResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetAccessPermissionsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetAccessPermissionsResponseType1.datasource new file mode 100644 index 0000000000..43d8dd371f --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetAccessPermissionsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.SetAccessPermissionsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetAuthFlowParamResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetAuthFlowParamResponseType1.datasource new file mode 100644 index 0000000000..57dcc8bf6b --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetAuthFlowParamResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.SetAuthFlowParamResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetCustomerBillingAgreementResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetCustomerBillingAgreementResponseType1.datasource new file mode 100644 index 0000000000..150476a66c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetCustomerBillingAgreementResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.SetCustomerBillingAgreementResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetExpressCheckoutResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetExpressCheckoutResponseType1.datasource new file mode 100644 index 0000000000..9657280df1 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetExpressCheckoutResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.SetExpressCheckoutResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetMobileCheckoutResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetMobileCheckoutResponseType1.datasource new file mode 100644 index 0000000000..3c24c11ede --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/SetMobileCheckoutResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.SetMobileCheckoutResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/TransactionSearchResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/TransactionSearchResponseType1.datasource new file mode 100644 index 0000000000..7827822e05 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/TransactionSearchResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.TransactionSearchResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateAccessPermissionsResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateAccessPermissionsResponseType1.datasource new file mode 100644 index 0000000000..66e306887c --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateAccessPermissionsResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.UpdateAccessPermissionsResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateAuthorizationResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateAuthorizationResponseType1.datasource new file mode 100644 index 0000000000..963c2cfa18 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateAuthorizationResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.UpdateAuthorizationResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateRecurringPaymentsProfileResponseType1.datasource b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateRecurringPaymentsProfileResponseType1.datasource new file mode 100644 index 0000000000..4b83a778d4 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/UpdateRecurringPaymentsProfileResponseType1.datasource @@ -0,0 +1,10 @@ + + + + SmartStore.PayPal.PayPalSvc.UpdateRecurringPaymentsProfileResponseType, Web References.PayPalSvc.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/eBLBaseComponents.xsd b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/eBLBaseComponents.xsd new file mode 100644 index 0000000000..5c93250b0a --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/Web References/PayPalSvc/eBLBaseComponents.xsd @@ -0,0 +1,13603 @@ + + + + + + + + AccountStateCodeType + These are the possible codes to describe the state of an account of an + eBay user. + + + + + + + Amex + + + + + + + Visa + + + + + + + Mastercard + + + + + + + Reserved for internal or future use. + + + + + + + + + AckCodeType + This code identifies the acknowledgement code types that + could be used to communicate the status of processing a + (request) message to an application. This code would be used + as part of a response message that contains an application + level acknowledgement element. + + + + + + + Request processing succeeded. + + + + + + + Request processing failed. + + + + + + + Request processing completed with warning information + being included in the response message. + + + + + + + Request processing completed successful with some + with some warning information that could be useful for + the requesting application to process and/or record. + + + + + + + Request processing failed with some error and warnining + information that requesting application should process to + determine cause(s) of failure. + + + + + + + Request processing completed with Partial Success. + + + + + + + Reserved for internal or future use. + + + + + + + + + AddressOwnerCodeType + This code identifies the AddressOwner code types which indicates + who owns the user'a address. + + + + + + + PayPal owns address. + + + + + + + eBay owns address. + + + + + + + Reserved for internal or future use. + + + + + + + + + AuctionTypeCodeType - Type declaration to be used + by other schema's. This includes codes indicating the + type of auction for the listed item. + + + + + + + Unknown auction type + + + + + + + Chinese auction + + + + + + + Dutch auction + + + + + + + Live Auctions-type auction + + + + + + + Ad type auction + + + + + + + Stores Fixed-price auction (US only) + + + + + + + Personal Offer auction + + + + + + + Fixed Price item ("BIN only"). + + + + + + + Reserved for internal or future use. + + + + + + + + + BalanceCodeType + This code identifies the types of balances in an account, e.g., a PayPal + account. + + + + + + Custom Code + + + + + + Reserved for internal or future use. + + + + + + + + + BuyerPaymentMethodCodeType - Type declaration to be used + by other schema. The includes the codes for payment methods + used by buyers to pay sellers. + + + + + + + No payment method specified + + + + + + + Money order/cashiers check + + + + + + + American Express + + + + + + + Payment See Description + + + + + + + American Express + + + + + + + Personal check + + + + + + + COD + + + + + + + Visa/Mastercard + + + + + + + Other forms of payment. + Some custom method is accepted by seller + as payment method in the transaction. For + Motors vehicle items, this field refers to the + Deposit payment method. + + + + + + + PayPal + + + + + + + Discover + + + + + + + Payment on delivery acceptable payment term. + + + + + + + Direct transfer of money acceptable payment term. + + + + + + + If the seller has bank account information on file, + and MoneyXferAcceptedinCheckout = true, then + the bank account information will be displayed in + Checkout. Applicable to German site only. + + + + + + + Online Escrow paid for by seller. + + + + + + + Reserved for internal or future use. + + + + + + + + + BuyerProtectionCodeType + + + + + + + Item is ineligible (e.g., category not applicable). + + + + + + + Item is eligible per standard criteria. + + + + + + + Item marked ineligible per special criteria (e.g., seller's account closed). + + + + + + + Item marked eligible per other criteria. + + + + + + + Reserved for internal or future use. + + + + + + + + + CheckoutStatusCodeType + + + + + + + Checkout complete. + + + + + + + Checkout incomplete. No details specified. + + + + + + + Buyer requests total. + + + + + + + Seller responded to buyer's request. + + + + + + + Reserved for internal or future use. + + + + + + + + + CountryCodeType + This code list module defines the enumerated types + of standard 2-letter ISO 3166 country codes. This codelist + contains some additional country code not defined in + the ISO 3166 country code set. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOTE: APO/FPO was defined in eBay list previously + but they are not defined in ISO 3166. This country + will remain on eBay country code list for backward + compatibility. + + + + + + + NOTE: Guernsey was defined in eBay list previously + but they are not defined in ISO 3166. This country + will remain on eBay country list for backward + compatibility. + + + + + + + NOTE: Jan Mayen was defined in eBay list previously + but they are not defined in ISO 3166. This country + will remain on eBay country list for backward + compatibility. + + + + + + + NOTE: Jersey was defined in eBay list previously + but they are not defined in ISO 3166. This country + will remain on eBay country list for backward + compatibility. + + + + + + + NOTE: Tahiti was defined in eBay list previously + but they are not defined in ISO 3166. This country + will remain on eBay country list for backward + compatibility. + + + + + + + NOTE: Serbia and Montenegro was not defined in the list previously + but now an ISO 3166 code has been defined. As of 41.0 this + country is supported in PayPal PRO. + + + + + + + Reserved for internal or future use. + + + + + + + + + + + Republic of Serbia. + + + + + + + Montenegro. + + + + + + + + + ISO 4217 standard 3-letter currency code. +

    +The following currencies are supported by PayPal. +
    CodeCurrencyMaximum Transaction Amount
    AUDAustralian Dollar 12,500 AUD
    CADCanadian Dollar12,500 CAD
    EUREuro 8,000 EUR
    GBPPound Sterling 5,500 GBP
    JPYJapanese Yen1,000,000 JPY
    USD U.S. Dollar10,000 USD
    CHF Czech Koruna70,000 CHF
    SEK Swedish Krona3,50,000 SEK
    NOK Norwegian Krone4,00,000 NOK
    DKK Danish Krone3,00,000 DKK
    PLN Poland Zloty1,60,000 PLN
    HUF Hungary Forint110,00,000 HUF
    SGD Singapore Dollar80,000 SGD
    HKD HongKong Dollar3,80,000 HKD
    NZD New Zealand Dollar77,000 NZD
    CZK Czech Koruna1,20,000 CZK
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Reserved for internal or future use. + + + + +
    + + + + DepositTypeCodeType - Type declaration to be used by other schema's. + This code identifies the DepositType codes used to specify deposit + types for Motors items. If the ietm listed is not a Motors item, then always + return DepositType value to be "None". + + + + + + None + + + + + + Other Method + + + + + + + Fast Deposit. + + + + + + Reserved for internal or future use. + + + + + + + + + DetailLevelCodeType + + + + + + + Return in response message all detail levels. + + + + + + + Return item description. + + + + + + + Return attributes as part of the item. + + + + + + + + This file defines re-useable base and aggregate components of the + eBay Business Lanaguage (eBL) that would be used to compose + message payloads for eBay APIs. + + + + + + This defines if the incentive is applied on Ebay or PayPal. + + + + + + + + + + + + This defines if the incentive is applied successfully or not. + + + + + + + + + + + Represents the unique identifier for an item. To be used to specify the + elements that represents an ItemID. + + + + + + + + PaymentReasonType + This is the Payment Reason type (used by DoRT and SetEC for Refund of PI transaction, eBay return shipment, external dispute) + + + + + + + + + Identifies a BA flow for return shipment + + + + + + + + + + + Balance as of a given entry, can be 0.00. + + + + + + + Credit Amount for a detail entry, can be 0.00. + + + + + + + Date entry was posted, in GMT. + + + + + + + Debit Amount for this detail entry, can be 0.00. + + + + + + + Item number if transaction is associated with an auction or 0 + if no item is associated with an account entry. + + + + + + + Memo line for an account entry, can be empty string. + + + + + + + eBay reference number for an account entry. + + + + + + + Integer code for account details entry type. This element + element specifies an index to a table of explanations for + accounting charges. + + + + + + + + + The AdditionalAccount component represents historical data related to + accounts that the user held with a country of residency other than + the current one. eBay users can have one active account at a time. + For users who change their country of residency and modify their + eBay registration to reflect this change, the new country of residence + becomes the currently active account. Any account associated with + a previous country is treated as an additional account. Because the + currency for these additional accounts are different than the active + account, each additional account includes an indicator of the currency + for that account. Users who never change their country of residence + will not have any additional accounts. + + + + + + + + + + + + Merchandizing info for an Item. This contains a list of crosssell + or upsell items. + + + + + + + Item ID for the base item. Based on this item other items are + promoted. it is teh only tag that would show up in all calls that use promoted item type. + some are not in soap yet, such as get and ser promotion rules + + + + + + + URL for the picture of the promoted item. + + + + + + + Where to display in the list of items.currentl y even forget and set does not have to be minoccur =0 + but if we ever were to do revise promotion tems, it can be omitted + + + + + + + Promotion Price. Price at which the buyer can buy the item now. + + + + + + + + + Item Title for the promoted item. + + + + + + + + + + Merchandizing info for an Item. This contains a list of crosssell + or upsell items. + PrimaryScheme, PromotionMethod,SellerId,ItemId, ShippingDiscount + do not have be min occur 0 + + + + + + + Item ID for the base item. Based on this item other items are + promoted. + + + + + + + + + Id of the Seller who is promoting this item. + + + + + + + Shipping Discount offered or not by the seller. + + + + + + + Key of the Seller who is promoting this item. + + + + + + + Store Name for the seller. + + + + + + + + + + Includes account summary for the user. + + + + + + + + + Number of additional accounts. + + + + + + + Amount past due, 0.00 if not past due. + + + + + + + First four digits (with remainder Xed-out). This may be an empty + string depending upon the value of the payment type for the + user account (e.g, if no debit-card specified). + + + + + + + Last time/day BankAccountInfo and/or BankRoutingInfo was + modified, in GMT. This may be an empty string depending + upon the value of the payment type for the user account + (e.g, if no debit-card specified). + + + + + + + Indicates the billing cycle in which eBay sends a billing + invoice to the specified user. Possible values: + 0 = On the last day of the month. + 15 = On the 15th day of the month. + + + + + + + Expiration date for the credit card selected as payment method, + in GMT. Empty string if no credit card is on file or if account is + inactive -- even if there is a credit card on file. + + + + + + + Last four digits of user's credit card selected as payment + type. Empty string if no credit is on file. This may be an empty + string depending upon the value of the payment type for the + user account (e.g, if no debit-card specified). + + + + + + + Last date credit card or credit card expiration date was + modified, in GMT. This may be an empty string depending + upon the value of the payment type for the user account + (e.g, Empty string if no credit card is on file. + + + + + + + User's current balance. Can be 0.00, positive, or negative. + + + + + + + Amount of last payment posted, 0.00 if no payments posted. + + + + + + + Amount of last invoice. 0.00 if account not yet invoiced. + + + + + + + Date of last invoice sent by eBay to the user, in GMT. + Empty string if this account has not been invoiced yet. + + + + + + + Date of last payment by specified user to eBay, in GMT. + Empty string if no payments posted. + + + + + + + Indicates whether the account has past due amounts + outstanding. Possible values: + true = Account is past due. + false = Account is current. + + + + + + + Indicates the method the specified user selected for paying + eBay. The values for PaymentType vary for each SiteID. + + + + + + + + + Information about user used by buying applications + + + + + + + + + + Information about user used by selling applications + there are number of required elements - they will always show up for seller node + there is not such a call to do revise seller info. only added minoccur=0 to elements that will not show up in every + type of request/responce + + + + + + + + + + + + + Indicates whether the user has elected to participate + as a seller in the Merchandising Manager feature. + + + + + + + + + + + + + + + Definition of an eBay Fee type. + + + + + + + + + + + Following are the current set of eBay fee types + AuctionLengthFee + BoldFee + BuyItNowFee + CategoryFeaturedFee + FeaturedFee + FeaturedGalleryFee + FixedPriceDurationFee + GalleryFee + GiftIconFee + HighLightFee + InsertionFee + ListingDesignerFee + ListingFee + PhotoDisplayFee + PhotoFee + ReserveFee + SchedulingFee + ThirtyDaysAucFee + Instances of this type could hold one or more supported types of fee. + + + + + + + + + + + + Calculated cost of shipping, based on shipping parameters and + selected shipping service. Only returned if ShippingType = 2 + (i.e., calculated shipping rate). + + + + + + + + + Optional fees a seller might assess for the shipping of the item. + + + + + + + Describes any error message associated with the attempt + to calculate shipping rates. If there was no error, returns + "No Error" (without the quotation marks). + + + + + + + is unique identified of shipping carrier, without this element the whole node makes no sence + + + + + + + + + + + Potal/zip code from where package will be shipped. + + + + + + + Indicates an item that cannot go through the stamping machine + at the shipping service office (a value of True) and requires + special or fragile handling. Only returned if ShippingType = 2. + + + + + + + contains information about shipping fees per each shipping service chosen by the seller + + + + + + + May need to be moved into details - wait for George! The size of the package to be shipped. Possible values are: + None + Letter + Large envelope + USPS flat rate envelope + Package/thick envelope + USPS large package/oversize 1 + Very large package/oversize 2 + UPS Letter + + + + + + + Shipping weight unit of measure (major). If unit of weight is kilogram + (i.e., metric system) this would be the exact weight value in kilogram + (i.e., complete decimal number, e.g., 2.23 kg). Only returned if + ShippingType is 2. + + + + + + + Shipping weight unit of measure (minor). If unit of weight is in pounds and/or + ounces, this would be the exact weight value in ounces (i.e., complete + decimal number, e.g., 8.2 or 8.0 ounces). Only returned if ShippingType is 2. + + + + + + + + + + + Any additional shipping costs for the item. + + + + + + + + + + + + + + + Amount of the sales tax to be collected for the transaction. + Sales tax is only for US. + + + + + + + Sales tax for the transaction, expressed as a percentage. Should + be empty for items listed on international sites (hence, this is + US-only element). + + + + + + + Indicates whether shipping is included in the tax. Applicable if + ShippingType = 1 or 2. This element is used for US-only. + + + + + + + + + Specifies the shipping payment details. + + + + + + + Indicates whether the buyer edited the payment amount. + + + + + + + Calculated shipping rate details. If present, then the calculated shipping rate option was used. + + + + + + + Indicates whether the payment instructions are included (e.g., for updating the + details of a transaction). + + + + + + + Flat shipping rate details. If present, then the flat shipping rate option was used. + + + + + + + Total cost of insurance for the transaction. + + + + + + + Indicates whether buyer selected to have insurance. + + + + + + + Payment instuctions. + + + + + + + Sales tax details. Sales tax applicable for only US sites. + For non-US sites this sub-element should not be used. + + + + + + + Postal/Zip code from where the seller will ship the item. + + + + + + + + + + + URLs for item picture that are stored/hosted at eBay site. + + + + + + + Type of display for photos used for PhotoHosting slide show. + Here are display options: + None = No special Picture Services features. + SlideShow = Slideshow of multiple pictures. + SuperSize = Super-size format picture. + PicturePack = Picture Pack. + Default is 'None'. + + + + + + + This will be either "Featured" or "Gallery". + + + + + + + + + + + URLs for item picture that are stored/hosted at eBay site. + + + + + + + URL for a picture for the gallery. If the GalleryFeatured + argument is true, a value must be supplied for either + the GalleryURL or the PictureURL argument. + In either case: + (a) If a URL is provided for only PictureURL, it is used + as the Gallery thumbnail. + (b) If a URL is provided for both GalleryURL and + PictureURL, then the picture indicated in GalleryURL + is used as the thumbnail. + The image used for the Gallery thumbnail (specified + in the GalleryURL or PictureURL argument) must be + in one of the graphics formats JPEG, BMP, TIF, or GIF. + + + + + + + This will be either "Featured" or "Gallery". + + + + + + + + + + + + + + + Specific physical attribute of an item. + + + + + + + ValueList of the Attribute being described by the AttributeID. + + + + + + + + Constant name of the attribute that identifies a + physical attribute within a set of characteristics + that describe something in a formalised way. + + + + + + + + AttributeSet. + + + + + + + + + + + + + + + + Container for data on the primary category of listing. + + + + + + + + + + + + + + + CSIDList is not present if Attributes enabled. + + + + + + + + + + + + + Contains the eBay Stores-specific item attributes + department number and store location. StorefrontInfo + is shown for any item that belongs to an eBay Store + owner, regardless of whether it is fixed price or + auction type. Returned as null for international + fixed price items. + + + + + + + assumed this type is specific to add/get/revise item, then each StorefrontType nust have category id, for store details this node makes no sense to use + + + + + + + in case or revise item for example - to change store category (department) you do not need to change store URL, so it will notbe in request + + + + + + + + + Identifies the Layout and the Theme template + associated with the item. in case of revision - all data can be min occur = 0 + + + + + + + Identifies the Layout template associated with the item. + + + + + + + A value of true for OptimalPictureSize indicates that the picture + URL will be enlarged to fit description of the item. + + + + + + + Identifies the Theme template associated with the item. + + + + + + + + + Contains information about a Charity listing.in case of revision - all data can be min occur = 0 + + + + + + + + + + + + Contains the listed items price details which consists of + following information: BuyItNowPrice, ConvertedBuyItNowPrice, + ConvertedPrice, ConvertedStartPrice, CurrentPrice, MinimumToBid, + ReservePrice, and StartPrice. need to take in account get seller events when defining minoccurs = 0 + + + + + + + Number of bids placed so far against the item. Not + returned for International Fixed Price items. + + + + + + + Smallest amount a bid must be above the current high + bid. Not returned International Fixed Price items. + + + + + + + Converted current price of listed item. + + + + + + + For auction-format listings, current minimum asking price + or the current highest bid for the item if bids have been + placed. Shows minimum bid if no bids have been placed + against the item. This field does not reflect the actual current + price of the item if it's a Type=7 or Type=9 (Fixed Price) + item and the price has been revised. (See StartPrice for + revised asking price.) + + + + + + + Contains one User node representing the current high + bidder. GetItem returns a high bidder for auctions that have + ended and have a winning bidder. For Fixed Price listings, + in-progress auctions, or auction items that received no + bids, GetItem returns a HighBidder node with empty tags. + + + + + + + Applicable to ad-format items only. Indicates how many + leads to potential buyers are associated with this item. + For other item types (other than ad-format items), returns + a value of 0 (zero). + + + + + + + Minimum acceptable bid for the item. Not returned for + International Fixed Price items. + + + + + + + Number of items purchased so far. (Subtract from the value + returned in the Quantity field to calculate the number of items + remaining.) + + + + + + + Returns true if the reserve price was met or no reserve + price was specified. + + + + + + + + + + Contains the revise status information details (e.g., item properties + information). ths node contains system set data only - always output and always all data. no minccurs needed, + except for motors specific data, since it wil lnot be retruned for non motors items + + + + + + + Indicates whether the item was revised since the auction started. + + + + + + + If true, indicates that a Buy It Now Price was added for + the item. Only returned for Motors items. + + + + + + + Replaces BinLowered as of API version 305. If true, + indicates that the Buy It Now Price was lowered for the + item. Only returned for Motors items. + + + + + + + If true, indicates that the Reserve Price was lowered for + the item. Only returned for Motors items. + + + + + + + If true, indicates that the Reserve Price was removed + from the item. Only returned for eBay Motors items. + + + + + + + + + Contains the listed item details which consists of following information: . + + + + + + + + + + + + + + + + + + + + + + Converted value of the BuyItNowPrice in the currency + indicated by SiteCurrency. This value must be refreshed + every 24 hours to pick up the current conversion rates. + + + + + + + Converted value of the StartPrice field in the currency + indicated by SiteCurrency. This value must be refreshed + every 24 hours to pick up the current conversion rates. + + + + + + + Indicates the converted reserve price for a reserve auction. Returned + only if DetailLevel = 4. ReservePrice is only returned for auctions with + a reserve price where the user calling GetItem is the item's seller. + Returned as null for International Fixed Price items. For more information + on reserve price auctions, see http://pages.ebay.com/help/basics/f-format.html#1. + + + + + + + + + + + + + + + + + Indicates the new ItemID for a relisted item. When an item is + relisted, the old (expired) listing is annotated with the new + (relist) ItemID. This field only appears when the old listing is + retrieved. + + + + + + + The ItemID for the original listing (i.e., OriginalItemID specific + to Second Chance Offer items). + + + + + + + Time stamp for the start of the listing (in GMT). For regular items, + StartTime is not sent in at listing time. + + + + + + + Time stamp for the end of the listing (in GMT). + + + + + + + + + + + + + + + + Returns custom, application-specific data associated + with the item. The data in this field is stored with the item + in the items table at eBay, but is not used in any way by + eBay. Use ApplicationData to store such special information + as a part or SKU number. Maximum 32 characters in length. + + + + + + + Carries one or more instances of the AttributeSet in a list. + + + + + + + If true (1), indicates that the seller requested immediate + payment for the item. False (0) if immediate payment was + not requested. (Does not indicate whether the item is + still a candidate for puchase via immediate payment.) + Only applicable for items listed on US and UK sites in + categories that support immediate payment, when seller + has a Premier or Business PayPal account. + + + + + + + Indicates the status of the item's eligibility for the Buyer + Protection Program. Possible values: + ItemIneligible - Item is ineligible (e.g., category not applicable) + ItemEligible - Item is eligible per standard criteria + ItemMarkedIneligible - Item marked ineligible per special criteria (e.g., seller's account closed) + ItemMarkedIneligible - Item marked elegible per other criteria + Applicable for items listed to the US site and for the Parts + and Accessories category (6028) or Everything Else category + (10368) (or their subcategories) on the eBay Motors site. + + + + + + + Amount a Buyer would need to bid to take advantage + of the Buy It Now feature. Not applicable to Fixed-Price + items (Type = 7 or 9) or AdFormat-type listings. For + Fixed-Price items, see StartPrice instead. + + + + + + + Charity listing container. + + + + + + + 2-letter ISO 3166 Country Code. + + + + + + + CrossPromotions container, if applicable shows promoted items + + + + + + + 3-letter ISO Currency Code. + + + + + + + Item Description. + + + + + + + Online Escrow paid for by buyer or seller. Cannot use + with real estate auctions. Escrow is recommended for + for transactions over $500. Escrow service, + available via Escrow.com, protects both buyer and + seller by acting as a trusted third-party during the + transaction and managing the payment process + from start to finish. Also, if escrow by seller option used, + then for Motors, this means that Escrow will be + negotiated at the end of the auction. + + + + + + + If set, a generic gift icon displays in the listing's + Title. GiftIcon must be set to to be able to use + GiftServices options (e.g., GiftExpressShipping, + GiftShipToRecipient, or GiftWrap). + + + + + + + Gift service options offered by the seller of + the listed item. + + + + + + + Optional hit counter for the item's listing page. Possible + values are: + "NoHitCounter" + "HonestyStyle" + "GreenLED" + "Hidden" + + + + + + + The ID that uniquely identifies the item listing. + + + + + + + Includes listing details in terms of start and + end time of listing (in GMT) as well as other + details (e.g., orginal item for second chance, + converted start price, etc.). + + + + + + + When an item is first listed (using AddItem), a Layout template + or a Theme template (or both) can be assigned to the item. + A Layout template is assigned to a new item by specifying + the Layout template ID (in the AddItem input argument + LayoutID). Similarly, a Theme template is assigned to the + item using the ThemeID argument. + + + + + + + Describes the number of days the auction will be active. + + + + + + + Describes the types of enhancment supported + for the item's listing. + + + + + + + Describes the type of listing for the item a seller + has chosen (e.g., Chinese, Dutch, FixedPrice, etc.). + + + + + + + Indicates the geographical location of the item. + + + + + + + Needed for add item only for partners. + + + + + + + Needed for add item only for partners. + + + + + + + List of payment methods accepted by a seller from a buyer for + a (checkout) transaction. + + + + + + + Valid PayPal e-mail address if seller has chosen PayPal + as a payment method for the listed item. + + + + + + + Container for data on the primary category of listing. + + + + + + + Private auction. Not applicable to Fixed Price items. + + + + + + + Number of items being sold in the auction. + + + + + + + Region where the item is listed. See Region Table for values. + If the item is listed with a Region of 0 (zero), then this return + field denotes no region association with the item, meaning + that it is not listing the item regionally. + + + + + + + If true, creates a link from the old listing for the item to the new + relist page, which accommodates users who might still look for + the item under its old item ID. Also adds the relist ID to the old + listing's record in the eBay database, which can be returned by + calling GetItem for the old ItemId. If your application creates the + listing page for the user, you need to add the relist link option to + your application for your users. + + + + + + + Indicates the reserve price for a reserve auction. Returned + only if DetailLevel = 4. ReservePrice is only returned for + auctions with a reserve price where the user calling GetItem + is the item's seller. Returned as null for International Fixed + Price items. For more information on reserve price auctions, + see http://pages.ebay.com/help/basics/f-format.html#1. + + + + + + + Revise Status contains information about the item being + revised. + + + + + + + + Container for data on the secondary category of listing. + Secondary category is optional. + + + + + + + Item picture information for pictures hosted at eBay site. + + + + + + + Seller user. + + + + + + + Container for for selling status information (e.g., BidCount, + BidIncrement, HighBidder, MinimimumToBid, etc). + + + + + + + Specifies where the seller is willing to ship the item. + Default "SiteOnly". Valid values are: + SiteOnly (the default) + WorldWide + SitePlusRegions + WillNotShip + If SitePlusRegions is selected, then at least one + regions argument (ShipToNorthAmerica, ShipToEurope, + etc.) must also be set. + + + + + + + Contains the shipping payment related information for the + listed item. + + + + + + + Regions that seller will ship to. + + + + + + + Describes who pays for the delivery of an item (e.g., buyer + or seller). + + + + + + + eBay site on which item is listed. + + + + + + + Starting price for the item. For Type=7 or Type=9 (Fixed Price) + items, if the item price (MinimumBid) is revised, this field + returns the new price. + + + + + + + Storefront is shown for any item that + belongs to an eBay Store owner, regardless of + whether it is fixed price or auction type. Not + returned for International Fixed Price items. + + + + + + + Subtitle to use in addition to the title. Provides more keywords when buyers search in titles and descriptions. + + + + + + + Time until the the end of the listing (e.g., the amount of time left + in an active auction). + + + + + + + Name of the item as it appears for auctions. + + + + + + + Universally unique constraint tag. The UUID is unique to a category. + + + + + + + VAT info container. + + + + + + + Item picture information for pictures hosted at vendor (i.e., remote) site. + + + + + + + + + Contains information about multiple individual transations. + + + + + + + + + + Contains information about a single transaction. A transaction contains information + about the sale of a particular item. The system creates a transaction when a buyer + has made a purchase (Fixed Price items) or is the winning bidder (BIN and auction + items). A listing can be associated with one or more transactions in these cases: + Multi-Item Fixed Price Listings + Dutch Auction Listings + A listing is associated with a single transaction in these cases: + Single-Item Fixed Price Listings + Single-Item Auction Listings + + + + + + + The amount the buyer paid for the item or agreed to pay, + depending on how far into the checkout process the item is. + If the seller allowed the buyer to change the item total, the buyer + is able to change the total until the time that the transaction's + status moves to Complete. Determine whether the buyer + changed the amount by calling GetSellerTransactions or + GetSellerTransactions and comparing the AmountPaid value + to what the seller expected. For Motors items, AmountPaid is + the amount paid by the buyer for the deposit. + + + + + + + Container for buyer data. + + + + + + + Includes shipping payment data. + + + + + + + Value returned in the Transaction/AmountPaid element, converted + to the currency indicated by SiteCurrency. + + + + + + + Value returned in the Transaction/TransactionPrice element, + converted to the currency indicated by SiteCurrency. + + + + + + + For fixed-price, Stores, and BIN items indicates when the + purchase (or BIN) occurred. For all other item types indicates + when the transaction was created (the time when checkout + was initiated). + + + + + + + Deposit type for Motors items. If item is not a Motors item, + then returns a DepositType of None. Possible values: + None + Other Method + Fast Deposit + + + + + + + Item info associated with the transaction. + + + + + + + Contains the number of individual items the buyer purchased in + the transaction. + + + + + + + Shipping cost totals shown to user (for both flat and calculated + rates). + + + + + + + Container node for transaction status data. + + + + + + + Unique identifier for a transaction. Returns 0 when Type=1 + (Chinese auction). Typically, an ItemID and a TransactionID + uniquely identify a checkout transaction. + + + + + + + Unique identifier for an authorization. + + + + + + + Price of the item, before shipping and sales tax. For Motors, + TransactionPrice is the deposit amount. + + + + + + + VAT rate for the item, if the item price includes the VAT rate. + Specify the VATPercent if you want include the net price in + addition to the gross price in the listing. VAT rates vary + depending on the item and on the user's country of residence; + therefore a business seller is responsible for entering the + correct VAT rate (it will not be calculated by eBay). + + + + + + + + + + + + + + + + + + + + + + + + + + Indicates the success or failure of an eBay Online Payment for + the transaction. If the payment failed, the value returned indicates + the reason for the failure. Possible values: + 0 = No payment failure. + 3 = Buyer's eCheck bounced. + 4 = Buyer's credit card failed. + 5 = Buyer failed payment as reported by seller. + 7 = Payment from buyer to seller is in PayPal process, but has not yet been completed. + + + + + + + Indicates the current state of the checkout process for the transaction. Possible values: + 0 = Checkout complete. + 1 = Checkout incomplete. No details specified. + 2 = Buyer requests total. + 3 = Seller responded to buyer's request. + + + + + + + Indicates last date and time checkout status or incomplete state was updated + (in GMT). + + + + + + + Payment method used by the buyer. (See BuyerPaymentCodeList/Type). + + + + + + + Indicates whether the transaction process complete or incomplete. + Possible values: + 1 = Incomplete + 2 = Complete + + + + + + + + + + + + + + Feedback scores are a quantitative expression of the desirability of dealing + with that person as a Buyer or a Seller in auction transactions. Each + auction transaction can result in one feedback entry for a given user + (the Buyer can leave one feedback about the Seller and the Seller can leave + one feedback about the Buyer). That one feedback can be positive, negative, + or neutral. The aggregated feedback counts for a particular user represent + that user's overall feedback score (referred to as a "feedback rating" on the + eBay site). This rating is commonly expressed as the eBay Feedback score + for the user. + + + + + + + + + + + + + + + + + + If present, indicates whether or not the user is subject to VAT. + Users who have registered with eBay as VAT-exempt are not + subject to VAT. See Value-Added Tax (VAT). Not returned for + users whose country of residence is outside the EU. + Possible values for the user's status: + 2 = Residence in an EU country but user registered as VAT-exempt + 3 = Residence in an EU country and user not registered as VAT-exempt + + + + + + + + + + + Contains information required To list a business item. + BusinessSeller - only for add item, the RestrictedToBusiness and VATPercent for both get and add, + for revise all must be optional + + + + + + + + + + + + Contains information for Scheduling limits for the user. All dtails must be present,unless we will have revise call one day, + just in case we might let's make min occur = 0 + + + + + + + + + + + + + + + + + + + + + + + + Amount of insurance. Applicable if ShippingType is + Flat shipping rate orCalculated shipping rate. + + + + + + + Indicates whether insurance fee is required. Possible values: + Insurance not offered. + Insurance optional. + Insurance required. + Insurance included in Shipping and Handling costs. + Applicable if ShippingType is Flat shipping rate or + Calculated shipping rate. + + + + + + + + + + + + + + + + + + + + Shipping carrier for the item. Possible values are: + UPS Ground + UPS 3rd Day + UPS 2nd Day + UPS Next Day + USPS Priority + USPS Parcel + USPS Media + USPS First Class + + + + + + + + Custom categories for subdividing the items + within an eBay Store. Store owners can create + up to 12 custom categories for their stores. + (One Store category cannot be customized + and retains the value of "Other") If specified, + must be number between 0 and 12. + 0=Not an eBay Store item + 1=Other + 2=Category 1 + 3=Category 2 + ... + 11=Category 10 + 12=Category 11 + Returned as null for international fixed priced + item. + + + + + + + + URL pointing to the seller's eBay Store page. + Returned as null for International Fixed Price items. + This URL follows the format below, where "####" + is replaced by the seller's eBay Stores ID (that + uniquely identifies the eBay Store). + http://www.ebaystores.com/id=#### + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Inclusion of all supported eBay Business Language (eBL) Code Lists. + This schema definition file contains specification for: + 1) eBay Business Langauge (eBL) Abstract Request and Response Message + which will be used to construct payloads for various applications; + 2) Re-useable error components of the eBL that would be used to communicate + application-level error messages back to the client application. These application + error messages may be due to a problem detected while processing the + request message. + 3) Other utility components needed by various eBay buying, selling, and payment + applications, e.g., address type and element. + + + + + + + + Value of the application-specific error parameter. + + + + + + + + Specifies application-specific error parameter name. + + + + + + + + + + + + Error code can be used by a receiving application to debugging a response + message. These codes will need to be uniquely defined for each application. + + + + + + + SeverityCode indicates whether the error is an application + level error or if it is informational error, i.e., warning. + + + + + + + This optional element may carry additional application-specific error variables + that indicate specific information about the error condition particularly in the + cases where there are multiple instances of the ErrorType which require + additional context. + + + + + + + + + + + Error code can be used by a receiving application to debugging a SOAP response + message that contain one or more SOAP Fault detail objects, i.e., fault detail sub-elements. + These codes will need to be uniquely defined for each fault scenario. + + + + + + + Severity indicates whether the error is a serious fault + or if it is informational error, i.e., warning. + + + + + + + + + + Base type definition of request payload that can carry any type + of payload content with optional versioning information and detail level + requirements. + + + + + + + This specifies the required detail level that is needed by a client application pertaining to + a particular data component (e.g., Item, Transaction, etc.). The detail level is specified in + the DetailLevelCodeType which has all the enumerated values of the detail level for + each component. + + + + + + + This should be the standard RFC 3066 language identification tag, e.g., en_US. + + + + + + + This refers to the version of the request payload schema. + + + + + + + + + + Base type definition of a response payload that can carry any + type of payload content with following optional elements: + - timestamp of response message, + - application level acknowledgement, and + - application-level errors and warnings. + + + + + + + This value represents the date and time (GMT) when the response + was generated by a service provider (as a result of processing + of a request). + + + + + + + Application level acknowledgement code. + + + + + + + CorrelationID may be used optionally with an application + level acknowledgement. + + + + + + + + This refers to the version of the response payload schema. + + + + + + + This refers to the specific software build that was used in the deployment + for processing the request and generating the response. + + + + + + + + + + + + Country code associated with this phone number. + + + + + + + Phone number associated with this phone. + + + + + + + Extension associated with this phone number. + + + + + + + + + + + Person's name associated with this address. +
    Character length and limitations: 32 single-byte alphanumeric characters +
    +
    +
    + + + + First street address. +
    Character length and limitations: 300 single-byte alphanumeric characters +
    +
    +
    + + + + Second street address. +
    Character length and limitations: 300 single-byte alphanumeric characters +
    +
    +
    + + + + Name of city. +
    Character length and limitations: 120 single-byte alphanumeric characters
    +
    +
    + + + + State or province. +
    Character length and limitations: 120 single-byte alphanumeric characters +

    + For Canada and the USA, StateOrProvince must be the standard 2-character abbreviation of a state or province. +

    Canadian Provinces
    AlbertaAB
    British_ColumbiaBC
    ManitobaMB
    New_BrunswickNB
    NewfoundlandNF
    Northwest_TerritoriesNT
    Nova_ScotiaNS
    NunavutNU
    OntarioON
    Prince_Edward_IslandPE
    QuebecQC
    SaskatchewanSK
    YukonYK


    United States AL +
    Alabama
    AlaskaAK
    American_SamoaAS
    ArizonaAZ
    ArkansasAR
    CaliforniaCA
    ColoradoCO
    ConnecticutCT
    DelawareDE
    District_Of_ColumbiaDC
    Federated_States_Of_MicronesiaFM
    FloridaFL
    GeorgiaGA
    GuamGU
    HawaiiHI
    IdahoID
    IllinoisIL
    IndianaIN
    IowaIA
    KansasKS
    KentuckyKY
    LouisianaLA
    MaineME
    Marshall_IslandsMH
    MarylandMD
    MassachusettsMA
    MichiganMI
    MinnesotaMN
    MississippiMS
    MissouriMO
    MontanaMT
    NebraskaNE
    NevadaNV
    New_HampshireNH
    New_JerseyNJ
    New_MexicoNM
    New_YorkNY
    North_CarolinaNC
    North_DakotaND
    Northern_Mariana_IslandsMP
    OhioOH
    OklahomaOK
    OregonOR
    PalauPW
    PennsylvaniaPA
    Puerto_RicoPR
    Rhode_IslandRI
    South_CarolinaSC
    South_DakotaSD
    TennesseeTN
    TexasTX
    UtahUT
    VermontVT
    Virgin_IslandsVI
    VirginiaVA
    WashingtonWA
    West_VirginiaWV
    WisconsinWI
    WyomingWY
    Armed_Forces_AmericasAA
    Armed_ForcesAE
    Armed_Forces_PacificAP
    +
    +
    + + + + ISO 3166 standard country code +
    Character limit: Two single-byte characters.
    +
    +
    + + + + IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile or UpdateRecurringPaymentsProfile. +

    + This element should only be used in response elements and typically + should not be used in creating request messages which specify the + name of a country using the Country element (which refers to a + 2-letter country code). +
    +
    +
    + + + + Telephone number associated with this address + + + + + + + IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile, or UpdateRecurringPaymentsProfile. + + + + + + + IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile or UpdateRecurringPaymentsProfile. + + + + + + + IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile or UpdateRecurringPaymentsProfile. + + + + + + + IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile or UpdateRecurringPaymentsProfile. +

    + Only applicable to SellerPaymentAddress today. Seller's international name that is associated with the payment address. +
    +
    +
    + + + + IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile or UpdateRecurringPaymentsProfile. +

    +Only applicable to SellerPaymentAddress today. International state and city for the seller's payment address. +
    +
    +
    + + + + IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile or UpdateRecurringPaymentsProfile. +

    +Only applicable to SellerPaymentAddress today. Seller's international street address that is associated with the payment address. +
    +
    +
    + + + + Status of the address on file with PayPal. +

    IMPORTANT: Do not set this element for SetExpressCheckout, DoExpressCheckoutPayment, DoDirectPayment, CreateRecurringPaymentsProfile or UpdateRecurringPaymentsProfile. +

    +
    +
    + + + + Returns Normalization Status of the Address. Possible values are Normalized, Unnormalized, and None. + + + +
    +
    + + + + + + + + + + EscrowCodeType + These are the possible codes to describe Escrow options. + + + + + + + By Buyer + + + + + + + By Seller. + + + + + + + None. + + + + + + + Reserved for internal or future use. + + + + + + + + + FeedbackRatingStarCodeType + + + + + + + No graphic displayed + + + + + + + Yellow Star + + + + + + + Turquoise Star + + + + + + + Purple Star + + + + + + + Red Star + + + + + + + Green Star + + + + + + + Yellow Shooting Star + + + + + + + Turquoise Shooting Star + + + + + + + Purple Shooting Star + + + + + + + Red Shooting Star + + + + + + + Blue Star + + + + + + + Reserved for internal or future use. + + + + + + + + + GalleryTypeCodeType + Specifies the codes for various properties of an item. + + + + + + + Indicates whether it is a featured item. + + + + + + + Include in the gallery. + + + + + + + Reserved for internal or future use. + + + + + + + + + GeneralPaymentMethodCodeType - Type declaration to be used + by other schema. This code identifies the general types of payment means, + e.g., used by payment service provider applications. + + + + + + Custom Code + + + + + Electronic check. + + + + + ACH. + + + + + + Credit-card. + + + + + + + Pay balance. + + + + + + + Reserved for internal or future use. + + + + + + + + + GiftServicesCodeType - Type declaration to be used by other schema's. + Specifies the codes for the various Gift Services offered by sellers. If + any of the Gift Services are offered by the seller, the generic gift icon + should be used to display the item: + http://pics.ebay.com/aw/pics/gift/gift.gif + + + + + + + indicates that the seller is offering to ship the item via + an express shipping method as described in the item + description. + + + + + + + indicates that the seller is offering to ship to the gift recipient, + not the buyer, when payment clears. + + + + + + + indicates that the seller is offering to wrap the item (and + optionally include a card) as described in the item + description. + + + + + + + Reserved for internal or future use. + + + + + + + + + HitCounterCodeType + This code identifies the HitCounter codes used to specify whether + a hit counter is used for the item's listing page and, if so, what type. + + + + + + No hit counter + + + + + + Honesty Style Hit Counter + + + + + + + Green LED counter. + + + + + + Hidden counter. + + + + + + + Reserved for internal or future use. + + + + + + + + + InsuranceOptionCodeType + These are the possible codes to describe insurance option as part of shipping + service. + + + + + + + Insurance optional. + + + + + + + Insurance required. + + + + + + + Insurance not offered. + + + + + + + Insurance included in Shipping and Handling costs. + + + + + + + Reserved for internal or future use. + + + + + + + + + ListingDurationCodeType + These are the possible codes to describe the number of days the + auction will be active. Must be one of the values 3, 5, 7, or 10 + for auction and basic Fixed-Price (Type 9) listings. Must be 30, + 60, 90, 120, or GTC for Stores Fixed-Price (Type 7) listings. + Specify GTC for the Good 'Til Cancel feature (eBay Stores + items only). + + + + + + + 1 Day + + + + + + + 3 Days + + + + + + + 5 Days + + + + + + + 7 Days + + + + + + + 10 Days + + + + + + + 30 Days + + + + + + + 60 Days + + + + + + + 90 Days + + + + + + + 120 Days + + + + + + + GTC + + + + + + + Reserved for internal or future use. + + + + + + + + + ListingEnhancementsCodeType + Specifies the codes for various properties of an item. + + + + + + + Indicates whether an item will be displayed with a border + that will go around the item (e.g., for category-based search + result page or store search that brings up multiple items) + to differentiate it from the rest of list. + + + + + + + Indicates whether the bolding option was used. + + + + + + + Indicates whether it is a featured item. + + + + + + + Indicates item's listing is highlighted. + + + + + + + Indicates item's listing is home page featured. + + + + + + + Reserved for internal or future use. + + + + + + + eBay Listing Enhancements Codes + + + Code List Agency - eBay, Inc. + + + Code List Version - 1.0 + + + + + ListingTypeCodeType - Type declaration to be used + by other schema. This includes codes indicating the + type of auction for the listed item. + + + + + + + Unknown Listing Type + + + + + + + Chinese auction + + + + + + + Dutch auction + + + + + + + Live Auctions-type auction + + + + + + + Ad type auction + + + + + + + Stores Fixed-price auction (US only) + + + + + + + Personal Offer auction + + + + + + + Fixed Price item ("BIN only"). + + + + + + + Reserved for internal or future use. + + + + + + + + + MerchandizingPrefCodeType + + + + + + + OptIn + + + + + + + OptOut + + + + + + + Reserved for internal or future use. + + + + + + + + + ModifyCodeType + This code identifies the types of modification you can make on an object. + account. + + + + + + Indicate filed is to be dropped. + + + + + Indicate filed is to be modified. + + + + + + Reserved for internal or future use. + + + + + + + + + PhotoDisplayCodeType + These are types of display for photos used for PhotoHosting slide show. + + + + + + + No special Picture Services features. + + + + + + + Slideshow of multiple pictures. + + + + + + + Super-size format picture. + + + + + + + Picture Pack. + + + + + + + Reserved for internal or future use. + + + + + + + + + Cross Promotion Method. + + + + + + + Auction Item + + + + + + + Buy It Now + + + + + + + Reserved. Do not use. + + + + + + + + + Cross Promotion Method. + + + + + + + Manual Selection + + + + + + + Automatic Selection + + + + + + + Reserved. Do not use. + + + + + + + + + Cross Promotion Method. + + + + + + + Cross Sell + + + + + + + Up Sell + + + + + + + Reserved. Do not use. + + + + + + + + + Cross Promotion Context Promotion Scheme. + + + + + + + Item to Item Promotional Scheme + + + + + + + Item to Item Store Scheme + + + + + + + Store to Store Scheme + + + + + + + Reserved. Do not use. + + + + + + + + + PurchasePurposeTypeCodeType - Type declaration to be used by other + schema. This code identifies the purpose of purchases, e.g., + by a PayPal application. + + + + + + Custom Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Reserved for internal or future use. + + + + + + + + + SellerLevelCodeType + + + + + + + Bronze + + + + + + + Silver + + + + + + + Gold + + + + + + + Platinum + + + + + + + Titanium + + + + + + + None + + + + + + + Reserved for internal or future use. + + + + + + + + + SellerPaymentMethodCodeType + These are payment methods that sellers can use to pay eBay. + + + + + + + No payment method specified - some other payment method. + + + + + + + Amex + + + + + + + Visa + + + + + + + Mastercard + + + + + + + Discover + + + + + + + JCB + + + + + + + Diners + + + + + + + Reserved for internal or future use. + + + + + + + + + SeverityCodeType + This code identifies the Severity code types in terms of whether + there is an API-level error or warning that needs to be communicated + to the client. + + + + + + + Warning or informational error. + + + + + + + Application-level error. + + + + + + + Partial Success. + + + + + + + Reserved for internal or future use. + + + + + + + + + ShippingOptionCodeType + These are the possible codes to describe shipping options in terms + of where the seller is willing to ship the item. + + + + + + + Site only. + + + + + + + WorldWide. + + + + + + + SitePlusRegions. + + + + + + + WillNotShip. + + + + + + + Reserved for internal or future use. + + + + + + + + + ShippingPackageCodeType + These are the possible codes to describe shipping package options. + + + + + + + None. + + + + + + + Letter. + + + + + + + LargeEnvelope + + + + + + + USPS Large Package/Oversize 1 + + + + + + + Very Large Package/Oversize 2 + + + + + + + UPS Letter + + + + + + + USPS Flat Rate Envelope + + + + + + + Package/thick envelope + + + + + + + Reserved for internal or future use. + + + + + + + + + ShippingRatesTypeCodeType - Type declaration to be used + by other schema. The includes the codes for shipping types + supported by sellers to transport items sold to buyers. + + + + + + + Flat shipping rate. + + + + + + + Calculated shipping rate. + + + + + + + Reserved for internal or future use. + + + + + + + + + ShippingRegion CodeType + This code list module defines the enumerated types of regions for + shipping items (i.e., a seller may support shipment of an item). + + + + + + + Africa + + + + + + + Asia + + + + + + + Carribbean + + + + + + + Europe + + + + + + + LatinAmerica + + + + + + + MiddleEast + + + + + + + NorthAmerica + + + + + + + Oceania (i.e., Pacific region other than Asia) + + + + + + + SouthAmerica + + + + + + + Reserved for internal or future use. + + + + + + + + + ShippingServiceCodeType + These are the possible codes to describe insurance option as part of shipping + service. + + + + + + + UPS Ground + + + + + + + UPS 3rd Day + + + + + + + UPS 2nd Day + + + + + + + UPS Next Day. + + + + + + + USPS Priority. + + + + + + + USPS Parcel. + + + + + + + USPS Media. + + + + + + + USPS First Class + + + + + + + ShippingMethodStandard - used by merchant tool only + + + + + + + ShippingMethodExpress- used by merchant tool only + + + + + + + ShippingMethodNextDay- used by merchant tool only + + + + + + + USPS Express Mail + + + + + + + USPS Ground + + + + + + Download. + + + + + Will Call Or Pick Up. + + + + + + Reserved for internal or future use. + + + + + + + + + ShippingTermsCodeType - Type declaration to be used by other schema's. + Shipping terms code describes who pays for the shipping of an item. + These are the standard shipping terms, i.e., terms of delivery of an item. + + + + + + + Seller pays all shipping costs. + + + + + + + Buyer pays all shipping costs. + + + + + + + Reserved for internal or future use. + + + + + + + + + SiteCodeType + These are site codes that buyers and sellers can use to identify + their sites. + + + + + + + USA + + + + + + + Canada + + + + + + + United Kingdom + + + + + + + Australia + + + + + + + Austria + + + + + + + Belgium (French) + + + + + + + France + + + + + + + Germany + + + + + + + Italy + + + + + + + Belgium (Dutch) + + + + + + + Netherlands + + + + + + + Spain + + + + + + + Switzerland + + + + + + + Taiwan + + + + + + + eBay Motors + + + + + + + Hong Kong + + + + + + + Singapore + + + + + + + Reserved for internal or future use. + + + + + + + + + This is to validate input if store should be visible/invisible in the store locator. + + If Merchant wants a store to be ENABLED, input should be "E". + If Merchant wants a store to be DISABLED, input should be "D". + + If Merchant is not giving any input, it will be taken as "DISABLED" + + + + + + + + + + + UnitCodeType + + + + + + + Kilogram. + + + + + + + Pounds. + + + + + + + Ounces + + + + + + + Centimeter. + + + + + + + Inches. + + + + + + + Feet. + + + + + + + Reserved for internal or future use. + + + + + + + + + UserStatusCodeType + + + + + + + User properties have never been set. + This value should seldom, if ever, be returned + and typically represents a problem. + + + + + + + User has been suspended from selling and buying, + such as for violations of eBay terms or agreement. + + + + + + + User has completed online registration and has + properly responded to confirmation email. Most + users should fall in this category. + + + + + + + User has completed online registration, but + has either not responded to confirmation email + or has not yet been sent the confirmation email. . + + + + + + + Registered users of AuctionWeb (pre-eBay) + who never re-registered on eBay. + + + + + + + Temporary user record state indicating the + record is in the process of being changed by + eBay. Query user information again to get new + status. + + + + + + + Records for the specified user have been deleted. + + + + + + + User has completed registration and confirmation, + but is pending a verification of credit card information. + + + + + + + User's account is on hold, such as for non-payment + of amounts due eBay. User cannot sell or buy items. + + + + + + + User record has been merged with another account + record for the same user. + + + + + + + User has completed online registration and has + been sent the confirmation email, but has not yet + responded to the confirmation email. + + + + + + + User has been scheduled for account closure + (typically when a user has requested to have + their account closed.) A user in this state should + not be considered an active user. + + + + + + + User has completed the registration for + Half.com and opted to automatically also be + registered with eBay, but the registration + confirmation is still pending. + + + + + + + User has completed the registration for + Half.com and opted to automatically also be + registered with eBay, but the verification of + credit card information is still pending. + + + + + + + Passport User. User has completed the registration process, but the registration confirmation is still pending. + + + + + + + Passport User Requiring Credit Card Verification. User has completed the registration process with credit card verification, but the registration confirmation is still pending. + + + + + + + Half.com User. User has completed the registration for Half.com and opted to automatically also be registered with eBay, but the registration confirmation is still pending. + + + + + + + Reserved for internal or future use. + + + + + + + + + VATStatusCodeType + + + + + + + No VAT Tax + + + + + + + VAT Tax + + + + + + + VAT Exempt + + + + + + + Reserved for internal or future use. + + + + + + + + + Type declaration to be used by other schemas. + This is the credit card type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TransactionId - Type for a PayPal Transaction ID. + + + + + + + + AuthorizationId - Type for a PayPal Authorization ID. + + + + + + + + + + + + + + + + + + + + + + + PaymentNotificationService + For SetPaymentStatus API, this value should always be eBayCN. + + + + + + + + + + + + + BankID + The various banks supported for China postbacks. + + + + + + + + + + + + + PaymentStatus + The payment statuses supported for China postbacks. + 0 - None + 1 - Success + 2 - Pending or Suspicious + 3 - Failure + + + + + + + + + + + RefundType - Type declaration to be used by other + schema. This code identifies the types of refund transactions + supported. + + + + + + + + + + + Full Refund + + + + + Partial Refund + + + + + External Dispute + + + + + + + + Based on NRF-ARTS Specification for Units of Measure + + + + + + Each + + + + + Hours + + + + + Days + + + + + Seconds + + + + + Crate of 12 bottles of beer + + + + + 6Pack + + + + + Gallon (UK) + + + + + Gallon (US) + + + + + Litre + + + + + Inch + + + + + Foot + + + + + Millimeter + + + + + Centimeter + + + + + Meter + + + + + Square Meter + + + + + Cubic Meter + + + + + Gram + + + + + Kilogram + + + + + Kilogram + + + + + Pound + + + + + Annual + + + + + Degree Celcius + + + + + Degree Fahrenheit + + + + + RESERVED + + + + + + + + + + + + + + + Supported API Types for DoCancel operation + + + + + POS CHECKOUT AUTHORIZATION + + + + + POS CHECKOUT SALE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IncentiveRequestType + This identifies the type of request for the API call. The type of request may be used to determine whether the request is for evaluating incentives in pre-checkout or in-checkout phase. + + + + + + + + + + + IncentiveRequestDetailLevelType + This identifies the granularity of information requested by the client application. This information will be used to define the contents and details of the response. + + + + + + + + + + + IncentiveType + This identifies the type of INCENTIVE for the redemption code. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The total cost of the order to the customer. If shipping cost and tax charges are known, include them in OrderTotal; if not, OrderTotal should be the current sub-total of the order. +

    +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + URL to which the customer's browser is returned after choosing to pay with PayPal. PayPal recommends that the value of ReturnURL be the final review page on which the customer confirms the order and payment. +

    Required

    +Character length and limitations: no limit.
    +
    +
    + + + URL to which the customer is returned if he does not approve the use of PayPal to pay you. PayPal recommends that the value of CancelURL be the original page on which the customer chose to pay with PayPal. +

    Required

    +Character length and limitations: no limit +
    +
    +
    + + + Tracking URL for ebay. +

    Required

    +Character length and limitations: no limit +
    +
    +
    + + + URL to which the customer's browser is returned after paying with giropay online. +

    +Optional +

    Character length and limitations: no limit. +
    +
    +
    + + + URL to which the customer's browser is returned after fail to pay with giropay online. +

    +Optional +

    Character length and limitations: no limit. +
    +
    +
    + + + URL to which the customer's browser can be returned in the mEFT done page. +

    +Optional +

    Character length and limitations: no limit. +
    +
    +
    + + + On your first invocation of SetExpressCheckoutRequest, the value of this token is returned by SetExpressCheckoutResponse. +

    +Optional +

    +Include this element and its value only if you want to modify an existing checkout session with another invocation of SetExpressCheckoutRequest; for example, if you want the customer to edit his shipping address on PayPal. +

    +Character length and limitations: 20 single-byte characters +
    +
    +
    + + + The expected maximum total amount of the complete order, including shipping cost and tax charges. +

    +Optional +

    +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + Description of items the customer is purchasing. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + A free-form field for your own use, such as a tracking number or other value you want PayPal to return on GetExpressCheckoutDetailsResponse and DoExpressCheckoutPaymentResponse. +

    +Optional +

    Character length and limitations: 256 single-byte alphanumeric characters +
    +
    +
    + + + Your own unique invoice or tracking number. PayPal returns this value to you on DoExpressCheckoutPaymentResponse. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + The value 1 indicates that you require that the customer's shipping address on file with PayPal be a confirmed address. Any value other than 1 indicates that the customer's shipping address on file with PayPal need NOT be a confirmed address. Setting this element overrides the setting you have specified in the recipient's Merchant Account Profile. +

    +Optional +

    Character length and limitations: One single-byte numeric character. +
    +
    +
    + + + The value 1 indicates that you require that the customer's billing address on file. Setting this element overrides the setting you have specified in Admin. +

    +Optional +

    Character length and limitations: One single-byte numeric character. +
    +
    +
    + + + + The billing address for the buyer. +
    + Optional +

    + If you include the BillingAddress element, the AddressType elements are required: +

    + Name +

    + Street1 +

    + CityName +

    + CountryCode +

    Do not set set the CountryName element.
    +
    +
    + + + The value 1 indicates that on the PayPal pages, no shipping address fields should be displayed whatsoever. +

    +Optional +

    +Character length and limitations: Four single-byte numeric characters. +
    +
    +
    + + + The value 1 indicates that the PayPal pages should display the shipping address set by you in the Address element on this SetExpressCheckoutRequest, not the shipping address on file with PayPal for this customer. Displaying the PayPal street address on file does not allow the customer to edit that address. +

    +Optional +

    Character length and limitations: Four single-byte numeric characters. +
    +
    +
    + + + + Locale of pages displayed by PayPal during Express Checkout. +

    +Optional +

    +Character length and limitations: Five single-byte alphabetic characters, upper- or lowercase. +

    +Allowable values: +
    +AU or en_AU +
    +DE or de_DE +
    +FR or fr_FR +
    +GB or en_GB +
    +IT or it_IT +
    +JP or ja_JP +
    +US or en_US +
    +
    +
    + + + Sets the Custom Payment Page Style for payment pages associated with this button/link. PageStyle corresponds to the HTML variable page_style for customizing payment pages. The value is the same as the Page Style Name you chose when adding or editing the page style from the Profile subtab of the My Account tab of your PayPal account. +

    +Optional +

    Character length and limitations: 30 single-byte alphabetic characters. +
    +
    +
    + + + + A URL for the image you want to appear at the top left of the payment page. The image has a maximum size of 750 pixels wide by 90 pixels high. PayPal recommends that you provide an image that is stored on a secure (https) server. +

    +Optional +

    +Character length and limitations: 127 +
    +
    +
    + + + + Sets the border color around the header of the payment page. The border is a 2-pixel perimeter around the header space, which is 750 pixels wide by 90 pixels high. +

    +Optional +

    Character length and limitations: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + Sets the background color for the header of the payment page. +

    +Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + Sets the background color for the payment page. +

    +Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + Sets the cart gradient color for the Mini Cart on 1X flow. +

    +Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + A URL for the image you want to appear above the mini-cart. The image has a maximum size of 190 pixels wide by 60 pixels high. PayPal recommends that you provide an image that is stored on a secure (https) server. +

    +Optional +

    +Character length and limitations: 127 +
    +
    +
    + + + Customer's shipping address. +

    +Optional +

    +If you include a shipping address and set the AddressOverride element on the request, PayPal returns this same address in GetExpressCheckoutDetailsResponse. +
    +
    +
    + + + + How you want to obtain payment. +

    Required

    +Authorization indicates that this payment is a basic authorization subject to settlement with PayPal Authorization and Capture. +

    +Order indicates that this payment is is an order authorization subject to settlement with PayPal Authorization and Capture. +

    +Sale indicates that this is a final sale for which you are requesting payment. +

    +IMPORTANT: You cannot set PaymentAction to Sale or Order on SetExpressCheckoutRequest and then change PaymentAction to Authorization on the final Express Checkout API, DoExpressCheckoutPaymentRequest. +

    +Character length and limit: Up to 13 single-byte alphabetic characters +
    +
    +
    + + + + This will indicate which flow you are choosing (expresschecheckout or expresscheckout optional) +

    +Optional +

    +None +

    +Sole indicates that you are in the ExpressO flow +

    +Mark indicates that you are in the old express flow. +

    +
    +
    + + + + This indicates Which page to display for ExpressO (Billing or Login) +

    +Optional +

    +None +

    +Billing indicates that you are not a paypal account holder +

    +Login indicates that you are a paypal account holder +

    +
    +
    + + + + Email address of the buyer as entered during checkout. PayPal uses this value to pre-fill the PayPal membership sign-up portion of the PayPal login page. +

    +Optional +

    Character length and limit: 127 single-byte alphanumeric characters +
    +
    +
    + + + + + + Promo Code

    + Optional

    + List of promo codes supplied by merchant. These promo codes enable the Merchant Services Promotion Financing feature. +
    +
    +
    + + + + Default Funding option for PayLater Checkout button. + + + + + + + + + + + + + + + + + Date and time (in GMT in the format yyyy-MM-ddTHH:mm:ssZ) at which address was changed by the user. + + + + + + + The value 1 indicates that the customer may enter a note to the merchant on the PayPal page during checkout. The note is returned in the GetExpressCheckoutDetails response and the DoExpressCheckoutPayment response.
    + Optional
    + Character length and limitations: One single-byte numeric character.
    + Allowable values: 0,1 +
    +
    +
    + + + + Funding source preferences. + + + + + + + The label that needs to be displayed on the cancel links in the PayPal hosted checkout pages.
    + Optional
    + Character length and limit: 127 single-byte alphanumeric characters +
    +
    +
    + + + + URL for PayPal to use to retrieve shipping, handling, insurance, and tax details from your website.
    + Optional
    + Character length and limitations: 2048 characters.
    +
    +
    + + + + Enhanced data for different industry segments.
    + Optional
    +
    +
    + + + + List of other payment methods the user can pay with. + Optional + Refer to the OtherPaymentMethodDetailsType for more details. + + + + + + + Details about the buyer's account.
    + Optional
    + Refer to the BuyerDetailsType for more details.
    +
    +
    + + + + Information about the payment. + + + + + + + List of Fall Back Shipping options provided by merchant. + + + + + + + Information about the call back timeout override. + + + + + + + Information about the call back version. + + + + + + + Information about the Customer service number. + + + + + + + Information about the Gift message enable. + + + + + + + Information about the Gift receipt enable. + + + + + + + Information about the Gift Wrap enable. + + + + + + + Information about the Gift Wrap name. + + + + + + + Information about the Gift Wrap amount. + + + + + + + Information about the Buyer email option enable . + + + + + + + Information about the survey enable. + + + + + + + Information about the survey question. + + + + + + + Information about the survey choices for survey question. + + + + + + + + Any message the seller would like to be displayed in the Mini Cart for UX. + + + + + + + Incentive Code

    + Optional

    + List of incentive codes supplied by ebay/merchant. +
    +
    +
    + + + + Merchant specified flag which indicates whether to return Funding Instrument Details in DoEC or not. +

    Optional

    +
    +
    + + + + This element contains information that allows the merchant to request to + opt into external remember me on behalf of the buyer or to request login + bypass using external remember me. Note the opt-in details are silently + ignored if the ExternalRememberMeID is present. + + + + + + + An optional set of values related to flow-specific details. + + + + + + + An optional set of values related to display-specific details. + + + + + + + An optional set of values related to tracking for external partner. + + + + + + + Optional element that defines relationship between buckets + + + +
    +
    + + + + + + On your first invocation of ExecuteCheckoutOperationsRequest, the value of this token is returned by ExecuteCheckoutOperationsResponse. +

    + Optional +

    + Include this element and its value only if you want to modify an existing checkout session with another invocation of ExecuteCheckoutOperationsRequest; for example, if you want the customer to edit his shipping address on PayPal. +

    + Character length and limitations: 20 single-byte characters +
    +
    +
    + + + + All the Data required to initiate the checkout session is passed in this element. + + + + + + + If auto authorization is required, this should be passed in with IsRequested set to yes. + + + +
    +
    + + + + It defines the enumerated types of the user channels defined in biz/User/value_object/Channel.oml
    +
    + + + + + + + + + + +
    + + + + + + Details about Billing Agreements requested to be created. + + + + + + + Only needed if Auto Authorization is requested. The authentication session token will be passed in here. + + + + + + + Requests for specific buyer information like Billing Address to be returned through GetExpressCheckoutDetails should be specified under this. + + + + + + + The value 1 indicates that you require to retrieve the customer's shipping address on file with PayPal. Any value other than 1 indicates that no such requirement. + + + + + + + the value is required by ACS team to specify the channel which the partners are in. the channel will be used for risk assessment
    + the value is defined in biz/User/value_object/Channel.oml
    + Optional +
    +
    +
    + + + The value 1 indicates that you require that the customer's shipping address on file with PayPal be a confirmed address. Any value other than 1 indicates that the customer's shipping address on file with PayPal need NOT be a confirmed address. Setting this element overrides the setting you have specified in the recipient's Merchant Account Profile. +

    +Optional +
    +
    +
    + + + + Information about the payment. + + + + + + + An optional set of values related to tracking for external partner. + + + +
    +
    + + + + + + + + + + + + + + The Type of Approval requested - Billing Agreement or Profile + + + + + The Approval subtype - Must be MerchantInitiatedBilling for BillingAgreement ApprovalType + + + + + Description about the Order + + + + + Directives about the type of payment + + + + + Client may pass in its identification of this Billing Agreement. It used for the client's tracking purposes. + + + + + + + + + If Billing Address should be returned in GetExpressCheckoutDetails response, this parameter should be set to yes here + + + + + + + + + Description of the Order. + + + + + Expected maximum amount that the merchant may pull using DoReferenceTransaction + + + + + + + + + Type of the Payment is it Instant or Echeck or Any. + + + + + + + + + Information that is used to indentify the Buyer. This is used for auto authorization. Mandatory if Authorization is requested. + + + + + + + + + Mobile specific buyer identification. + + + + + Contains login bypass information. + + + + + Identity Access Token. + + + + + + + + + The Session token returned during buyer authentication. + + + + + + + + + + External remember-me ID returned by GetExpressCheckoutDetails on successful opt-in. The + ExternalRememberMeID is a 17-character alphanumeric (encrypted) string that identifies + the buyer's remembered login with a merchant and has meaning only to the merchant. If + present, requests that the web flow attempt bypass of login. + + + + + + + + + + Identity Access token from merchant + + + + + + + + + + Allowable values: 0,1
    + The value 1 indicates that the customer can accept push funding, and 0 means they cannot.
    + Optional
    + Character length and limitations: One single-byte numeric character.
    +
    +
    + + + + Allowable values: ELV, CreditCard, ChinaUnionPay, BML
    + This element could be used to specify the perered funding option
    + for a guest users. It has effect only if LandingPage element is set to Billing.
    + Otherwise it will be ignored. +
    +
    +
    +
    +
    + + + + + + + + + + + Only needed for AutoBill billinng type. + + + + + + + + + + + + Custom annotation field for your exclusive use. + + + + + + + + + + + The timestamped token value that was returned by SetExpressCheckoutResponse and passed on GetExpressCheckoutDetailsRequest. +

    Character length and limitations: 20 single-byte characters
    +
    +
    + + + + Information about the payer + + + + + + A free-form field for your own use, as set by you in the Custom element of SetExpressCheckoutRequest. +

    Character length and limitations: 256 single-byte alphanumeric characters
    +
    +
    + + + + Your own invoice or tracking number, as set by you in the InvoiceID element of SetExpressCheckoutRequest. +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + Payer's contact telephone number. PayPal returns a contact telephone number only if your Merchant account profile settings require that the buyer enter one. + + + + + + + + + + + + + + + Customer's billing address. +

    +Optional +

    +If you have credit card mapped in your account then billing address of the credit card is returned otherwise your primary address is returned , PayPal returns this address in GetExpressCheckoutDetailsResponse. +
    +
    +
    + + + + Text note entered by the buyer in PayPal flow. + + + + + + + Returns the status of the EC checkout session.
    + Values include 'PaymentActionNotInitiated', 'PaymentActionFailed', 'PaymentActionInProgress', 'PaymentCompleted'.
    +
    +
    + + + + PayPal may offer a discount or gift certificate to the buyer, which will be represented by a negativeamount. If the buyer has a negative balance, PayPal will add that amount to the current charges, which will be represented as a positive amount. + + + + + + + Information about the individual purchased items. + + + + + + + Information about the user selected options. + + + + + + + Information about the incentives that were applied from Ebay RYP page and PayPal RYP page. + + + + + + + Information about the Gift message. + + + + + + + Information about the Gift receipt enable. + + + + + + + Information about the Gift Wrap name. + + + + + + + Information about the Gift Wrap amount. + + + + + + + Information about the Buyer marketing email. + + + + + + + Information about the survey question. + + + + + + + Information about the survey choice selected by the user. + + + + + + + Contains payment request information about each bucket in the cart. + + + + + + + Response information resulting from opt-in operation or current login bypass status. + + + + + + + Response information resulting from opt-in operation or current login bypass status. + + + +
    +
    + + + + + + + + + + + + If Checkout session was initialized successfully, the corresponding token is returned in this element. + + + + + + + + + + + + + Status will denote whether Auto authorization was successful or not. + + + + + + + + + + + + How you want to obtain payment. +

    Required

    +Authorization indicates that this payment is a basic authorization subject to settlement with PayPal Authorization and Capture. +

    +Order indicates that this payment is is an order authorization subject to settlement with PayPal Authorization and Capture. +

    +Sale indicates that this is a final sale for which you are requesting payment. +

    +IMPORTANT: You cannot set PaymentAction to Sale on SetExpressCheckoutRequest and then change PaymentAction to Authorization on the final Express Checkout API, DoExpressCheckoutPaymentRequest. +

    +Character length and limit: Up to 13 single-byte alphabetic characters +
    +
    +
    + + + + The timestamped token value that was returned by SetExpressCheckoutResponse and passed on GetExpressCheckoutDetailsRequest. +

    Required

    +Character length and limitations: 20 single-byte characters
    +
    +
    + + + + Encrypted PayPal customer account identification number as returned by GetExpressCheckoutDetailsResponse. +

    Required

    +Character length and limitations: 127 single-byte characters. +
    +
    +
    + + + + URL on Merchant site pertaining to this invoice. +

    Optional

    +
    +
    + + + + Information about the payment +

    Required
    +
    +
    + + + + Flag to indicate if previously set promoCode shall be overriden. Value 1 indicates overriding. + + + + + + + Promotional financing code for item. Overrides any previous PromoCode setting. + + + + + + + Contains data for enhanced data like Airline Itinerary Data. + + + + + + + Soft Descriptor supported for Sale and Auth in DEC only. For Order this will be ignored. + + + + + + + Information about the user selected options. + + + + + + + Information about the Gift message. + + + + + + + Information about the Gift receipt enable. + + + + + + + Information about the Gift Wrap name. + + + + + + + Information about the Gift Wrap amount. + + + + + + + Information about the Buyer marketing email. + + + + + + + Information about the survey question. + + + + + + + Information about the survey choice selected by the user. + + + + + + An identification code for use by third-party applications to identify transactions. +

    + Optional +

    + Character length and limitations: 32 single-byte alphanumeric characters +
    +
    +
    + + + + Merchant specified flag which indicates whether to create billing agreement as part of DoEC or not. +

    Optional

    +
    +
    + + + + Optional element that defines relationship between buckets + + + +
    +
    + + + + + + The timestamped token value that was returned by SetExpressCheckoutResponse and passed on GetExpressCheckoutDetailsRequest. +

    +Character length and limitations:20 single-byte characters +
    +
    +
    + + + Information about the transaction + + + + + + + + + + + + + + + Memo entered by sender in PayPal Review Page note field. +

    + Optional +

    + Character length and limitations: 255 single-byte alphanumeric characters +
    +
    +
    + + + + Redirect back to PayPal, PayPal can host the success page. + + + + + + + Information about the user selected options. + + + + + + + Information about Coupled Payment transactions. + + + +
    +
    + + + + + The authorization identification number you specified in the request. +
    Character length and limits: 19 single-byte characters maximum +
    +
    +
    + + + Information about the transaction + + + + + + Return msgsubid back to merchant + + + + + + + Partner funding source id corresponding to the FS used in authorization. + + + +
    +
    + + + + + + How you want to obtain payment. +

    Required

    +Authorization indicates that this payment is a basic authorization subject to settlement with PayPal Authorization and Capture. +

    +Sale indicates that this is a final sale for which you are requesting payment. +

    +NOTE: Order is not allowed for Direct Payment. +

    +Character length and limit: Up to 13 single-byte alphabetic characters
    +
    +
    + + + + Information about the payment +

    Required

    +
    +
    + + + + Information about the credit card to be charged. +

    Required

    +
    +
    + + + + IP address of the payer's browser as recorded in its HTTP request to your website. PayPal records this IP addresses as a means to detect possible fraud. +

    Required

    Character length and limitations: 15 single-byte characters, including periods, in dotted-quad format: ???.???.???.??? +
    +
    +
    + + + + Your customer session identification token. PayPal records this optional session identification token as an additional means to detect possible fraud. +

    +Optional +

    Character length and limitations: 64 single-byte numeric characters
    +
    +
    + + + + + +
    +
    + + + + + Type of the payment +

    Required
    +
    +
    + + + + How you want to obtain payment. Defaults to Sale. +

    Optional

    +Authorization indicates that this payment is a basic authorization subject to settlement with PayPal Authorization and Capture. +

    +Sale indicates that this is a final sale for which you are requesting payment. +

    +
    +
    + + + Phone number of the user making the payment. +

    Required
    +
    +
    + + + Type of recipient specified, i.e., phone number or email address +

    Required
    +
    +
    + + + Email address of the recipient +

    +
    +
    + + + Phone number of the recipipent +

    Required
    +
    +
    + + + Amount of item before tax and shipping +

    +
    +
    + + + The tax charged on the transaction +Tax +

    +Optional +
    +
    +
    + + + Per-transaction shipping charge +

    +Optional +
    +
    +
    + + + Name of the item being ordered +

    +Optional +

    +Character length and limitations: 255 single-byte alphanumeric characters +
    +
    +
    + + + SKU of the item being ordered +

    +Optional +

    +Character length and limitations: 255 single-byte alphanumeric characters +
    +
    +
    + + + Memo entered by sender in PayPal Website Payments note field. +

    +Optional +

    +Character length and limitations: 255 single-byte alphanumeric characters +
    +
    +
    + + + Unique ID for the order. Required for non-P2P transactions +

    +Optional +

    +Character length and limitations: 255 single-byte alphanumeric characters +
    +
    +
    + + + Indicates whether the sender's phone number will be shared with recipient +

    +Optional +
    +
    +
    + + + Indicates whether the sender's home address will be shared with recipient +

    +Optional +
    +
    +
    +
    +
    + + + + + Phone number for status inquiry + + + + + + + + + URL to which the customer's browser is returned after choosing to login with PayPal. +

    Required

    +Character length and limitations: no limit.
    +
    +
    + + + URL to which the customer is returned if he does not approve the use of PayPal login. +

    Required

    +Character length and limitations: no limit +
    +
    +
    + + + URL to which the customer's browser is returned after user logs out from PayPal. +

    Required

    +Character length and limitations: no limit.
    +
    +
    + + + The type of the flow. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + The used to decide SkipLogin allowed or not. +

    + Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + The name of the field Merchant requires from PayPal after user's login. +

    + Optional +

    Character length and limitations: 256 single-byte alphanumeric characters +
    +
    +
    + + + Whether the field is required, opt-in or opt-out. +

    + Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + The name of the field Merchant requires from PayPal after user's login. +

    +Optional +

    Character length and limitations: 256 single-byte alphanumeric characters +
    +
    +
    + + + Whether the field is required, opt-in or opt-out. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + Locale of pages displayed by PayPal during Authentication Login. +

    +Optional +

    +Character length and limitations: Five single-byte alphabetic characters, upper- or lowercase. +

    +Allowable values: +
    +AU or en_AU +
    +DE or de_DE +
    +FR or fr_FR +
    +GB or en_GB +
    +IT or it_IT +
    +JP or ja_JP +
    +US or en_US +
    +
    +
    + + + Sets the Custom Payment Page Style for flow pages associated with this button/link. PageStyle corresponds to the HTML variable page_style for customizing flow pages. The value is the same as the Page Style Name you chose when adding or editing the page style from the Profile subtab of the My Account tab of your PayPal account. +

    +Optional +

    Character length and limitations: 30 single-byte alphabetic characters. +
    +
    +
    + + + + A URL for the image you want to appear at the top left of the flow page. The image has a maximum size of 750 pixels wide by 90 pixels high. PayPal recommends that you provide an image that is stored on a secure (https) server. +

    +Optional +

    +Character length and limitations: 127 +
    +
    +
    + + + + Sets the border color around the header of the flow page. The border is a 2-pixel perimeter around the header space, which is 750 pixels wide by 90 pixels high. +

    +Optional +

    Character length and limitations: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + Sets the background color for the header of the flow page. +

    +Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + Sets the background color for the payment page. +

    +Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + First Name of the user, this information is used if user chooses to signup with PayPal. +

    +Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + Last Name of the user, this information is used if user chooses to signup with PayPal. +

    +Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + User address, this information is used when user chooses to signup for PayPal. +

    +Optional +

    +If you include a shipping address and set the AddressOverride element on the request, PayPal returns this same address in GetExpressCheckoutDetailsResponse. +
    +
    +
    +
    +
    + + + + + The first name of the User. +

    Character length and limitations: 127 single-byte alphanumeric characters
    +
    +
    + + + The Last name of the user. +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + The email address of the user. +
    Character length and limitations: 256 single-byte alphanumeric characters. +
    +
    +
    + + + + Encrypted PayPal customer account identification number. +

    Required

    +Character length and limitations: 127 single-byte characters. +
    +
    +
    +
    +
    + + + + + URL to which the customer's browser is returned after choosing to login with PayPal. +

    Required

    + Character length and limitations: no limit. +
    +
    +
    + + + URL to which the customer is returned if he does not approve the use of PayPal login. +

    Required

    + Character length and limitations: no limit +
    +
    +
    + + + URL to which the customer's browser is returned after user logs out from PayPal. +

    Required

    + Character length and limitations: no limit. +
    +
    +
    + + + The type of the flow. +

    + Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + The used to decide SkipLogin allowed or not. +

    + Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + contains information about API Services + + + + + + + contains information about API Services + + + + + + + Locale of pages displayed by PayPal during Authentication Login. +

    + Optional +

    + Character length and limitations: Five single-byte alphabetic characters, upper- or lowercase. +

    +Allowable values: +
    +AU or en_AU +
    +DE or de_DE +
    +FR or fr_FR +
    +GB or en_GB +
    +IT or it_IT +
    +JP or ja_JP +
    +US or en_US +
    +
    +
    + + + Sets the Custom Payment Page Style for flow pages associated with this button/link. PageStyle corresponds to the HTML variable page_style for customizing flow pages. The value is the same as the Page Style Name you chose when adding or editing the page style from the Profile subtab of the My Account tab of your PayPal account. +

    + Optional +

    Character length and limitations: 30 single-byte alphabetic characters. +
    +
    +
    + + + + A URL for the image you want to appear at the top left of the flow page. The image has a maximum size of 750 pixels wide by 90 pixels high. PayPal recommends that you provide an image that is stored on a secure (https) server. +

    + Optional +

    + Character length and limitations: 127 +
    +
    +
    + + + + Sets the border color around the header of the flow page. The border is a 2-pixel perimeter around the header space, which is 750 pixels wide by 90 pixels high. +

    + Optional +

    Character length and limitations: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + Sets the background color for the header of the flow page. +

    + Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + + Sets the background color for the payment page. +

    + Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + First Name of the user, this information is used if user chooses to signup with PayPal. +

    + Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + Last Name of the user, this information is used if user chooses to signup with PayPal. +

    + Optional +

    Character length and limitation: Six character HTML hexadecimal color code in ASCII +
    +
    +
    + + + User address, this information is used when user chooses to signup for PayPal. +

    + Optional +

    + If you include a shipping address and set the AddressOverride element on the request, PayPal returns this same address in GetExpressCheckoutDetailsResponse. +
    +
    +
    +
    +
    + + + + + The first name of the User. +

    Character length and limitations: 127 single-byte alphanumeric characters
    +
    +
    + + + The Last name of the user. +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + The email address of the user. +
    Character length and limitations: 256 single-byte alphanumeric characters. +
    +
    +
    + + + + contains information about API Services + + + + + + + contains information about API Services + + + + + + + Encrypted PayPal customer account identification number. +

    Required

    + Character length and limitations: 127 single-byte characters. +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Customer's billing address. +

    Optional +
    + If you have credit card mapped in your account then billing address of the + credit card is returned otherwise your primary address is returned , PayPal + returns this address in BAUpdateResponseDetails. +
    +
    +
    +
    +
    + + + + MerchantPullPaymentResponseType + Response data from the merchant pull. + + + + + + + information about the customer + + + + + Information about the transaction + + + + + + Specific information about the preapproved payment + + + + + + + + MerchantPullInfoType + Information about the merchant pull. + + + + + + + Current status of billing agreement + + + + + + Monthly maximum payment amount + + + + + The value of the mp_custom variable that you specified in a FORM submission to PayPal during the creation or updating of a customer billing agreement + + + + + + The value of the mp_desc variable (description of goods or services) associated with the billing agreement + + + + + + Invoice value as set by BillUserRequest API call + + + + + Custom field as set by BillUserRequest API call + + + + + Note: This field is no longer used and is always empty. + + + + + + + + PaymentTransactionSearchResultType + Results from a PaymentTransaction search + + + + + + The date and time (in UTC/GMT format) the transaction occurred + + + + + The time zone of the transaction + + + + + The type of the transaction + + + + + The email address of the payer + + + + + Display name of the payer + + + + + The transaction ID of the seller + + + + + The status of the transaction + + + + + The total gross amount charged, including any profile shipping cost and taxes + + + + + The fee that PayPal charged for the transaction + + + + + The net amount of the transaction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MerchantPullPayment + Parameters to make initiate a pull payment + + + + + + + The amount to charge to the customer. +

    Required

    +Only numeric characters and a decimal separator are allowed. Limit: 10 single-byte characters, including two for decimals You must set the currencyID attribute to one of the three-character currency code for any of the supported PayPal currencies. +
    +
    +
    + + + + Preapproved Payments billing agreement identification number between the PayPal customer and you. +

    Required

    +Character limit: 19 single-byte alphanumeric characters. +

    +The format of a billing agreement identification number is the single-character prefix B, followed by a hyphen and an alphanumeric character string: +

    +B-unique_alphanumeric_string +
    +
    +
    + + + Specifies type of PayPal payment you require +

    +Optional +
    +
    +
    + + + Text entered by the customer in the Note field during enrollment +

    +Optional +
    +
    +
    + + + Subject line of confirmation email sent to recipient +

    +Optional +
    +
    +
    + + + The tax charged on the transaction +

    +Optional +
    +
    +
    + + + Per-transaction shipping charge +

    +Optional
    +
    +
    + + + Per-transaction handling charge +

    +Optional
    +
    +
    + + + Name of purchased item +

    +Optional
    +
    +
    + + + Reference number of purchased item +

    +Optional
    +
    +
    + + + Your invoice number +

    +Optional +
    +
    +
    + + + Custom annotation field for tracking or other use +

    +Optional +
    +
    +
    + + + An identification code for use by third-party applications to identify transactions. +

    +Optional +

    +Character length and limitations: 32 single-byte alphanumeric characters +
    +
    +
    + + + Passed in soft descriptor string to be appended. +

    +Optional +

    +Character length and limitations: single-byte alphanumeric characters +
    +
    +
    +
    +
    + + + + PaymentTransactionType + Information about a PayPal payment from the seller side + + + + + + Information about the recipient of the payment + + + + + Information about the payer + + + + + + This field is for holding ReferenceId for shippment sent from Merchant to the 3rd Party + + + + + + Information about the transaction + + + + + Information about an individual item in the transaction + + + + + Information about an individual Offer and Coupon information in the transaction + + + + + Information about Secondary Address + + + + + + Information about the user selected options. + + + + + + + Information about the Gift message. + + + + + + + Information about the Gift receipt. + + + + + + + Information about the Gift Wrap name. + + + + + + + Information about the Gift Wrap amount. + + + + + + + Information about the Buyer email. + + + + + + + Information about the survey question. + + + + + + + Information about the survey choice selected by the user. + + + + + + + + + ReceiverInfoType + Receiver information. + + + + + + + Email address or account ID of the payment recipient (the seller). Equivalent to Receiver if payment is sent to primary account. +
    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + Primary email address of the payment recipient (the seller). If you are the recipient of the payment and the payment is sent to your non-primary email address, the value of Receiver is still your primary email address. +
    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + Unique account ID of the payment recipient (the seller). This value is the same as the value of the recipient's referral ID. + + +
    +
    + + + + PayerInfoType + Payer information + + + + + + + Email address of payer +
    Character length and limitations: 127 single-byte characters +
    +
    +
    + + + + Unique customer ID +
    Character length and limitations: 17 single-byte characters +
    +
    +
    + + + + Status of payer's email address + + + + + + + Name of payer + + + + + + Payment sender's country of residence using standard two-character ISO 3166 country codes. +Character length and limitations: Two single-byte characters + + + + + + + Payer's business name. +
    Character length and limitations: 127 single-byte characters
    +
    +
    + + + + Payer's business address + + + + + Business contact telephone number + + + + + + Details about payer's tax info.
    + Refer to the TaxIdDetailsType for more details.
    +
    +
    + + + Holds any enhanced information about the payer + + +
    +
    + + + + InstrumentDetailsType + Promotional Instrument Information. + + + + + + + This field holds the category of the instrument only when it is promotional. Return value 1 represents BML, 2 reprasents PLCC/Cobranded. + + + + + + + This field holds the InstrumentID issued by external party corresponding to the funding source used in payment. + + + + + + + + + BMLOfferInfoType + Specific information for BML. + + + + + + + Unique identification for merchant/buyer/offer combo. + + + + + + + + + OfferDetailsType + Specific information for an offer. + + + + + + + Code used to identify the promotion offer. + + + + + + + Specific infromation for BML, Similar structure could be added for sepcific +
    promotion needs like CrossPromotions +
    +
    +
    +
    +
    + + + + PaymentInfoType + Payment information. + + + + + + A transaction identification number. +
    Character length and limits: 19 single-byte characters maximum +
    +
    +
    + + + Its Ebay transaction id. +
    EbayTransactionID will returned for immediate pay item transaction in ECA +
    +
    +
    + + + + Parent or related transaction identification number. This field is populated for the following transaction types: +

    +Reversal +
    +Capture of an authorized transaction. +
    +Reauthorization of a transaction. +
    +Capture of an order. The value of ParentTransactionID is the original OrderID. +
    +Authorization of an order. The value of ParentTransactionID is the original OrderID. +
    +Capture of an order authorization. +
    +Void of an order. The value of ParentTransactionID is the original OrderID. +

    +Character length and limits: 19 single-byte characters maximum
    +
    +
    + + + + Receipt ID +

    +Character length and limitations: 16 digits in xxxx-xxxx-xxxx-xxxx format
    +
    +
    + + + + The type of transaction +

    +cart: Transaction created via the PayPal Shopping Cart feature or by Express Checkout with multiple purchased item +

    +express-checkout: Transaction created by Express Checkout with a single purchased items +

    +send-money: Transaction created by customer from the Send Money tab on the PayPal website. +

    +web-accept: Transaction created by customer via Buy Now, Donation, or Auction Smart Logos. +

    +subscr-*: Transaction created by customer via Subscription. eot means "end of subscription term." +

    +merch-pmt: preapproved payment. +

    +mass-pay: Transaction created via MassPay. +

    +virtual-terminal: Transaction created via merchant virtual terminal. +

    +credit: Transaction created via merchant virtual terminal or API to credit a customer. +
    +
    +
    + + + + The type of payment + + + + + + The type of funding source + + + + + + eCheck latest expected clear date + + + + + + Date and time of payment + + + + + + Full amount of the customer's payment, before transaction fee is subtracted + + + + + + Transaction fee associated with the payment + + + + + Amount deposited into the account's primary balance after a currency conversion from automatic conversion through your Payment Receiving Preferences or manual conversion through manually accepting a payment. This amount is calculated after fees and taxes have been assessed. + + + + + + Amount of tax for transaction + + + + + + Exchange rate for transaction + + + + + + The status of the payment: +

    +None: No status +

    +Created: A giropay payment has been initiated. +

    +Canceled-Reversal: A reversal has been canceled. For example, you won a dispute with the customer, and the funds for the transaction that was reversed have been returned to you. +

    +Completed: The payment has been completed, and the funds have been added successfully to your account balance. +

    +Denied: You denied the payment. This happens only if the payment was previously pending because of possible reasons described for the PendingReason element. +

    +Expired: This authorization has expired and cannot be captured. +

    +Failed: The payment has failed. This happens only if the payment was made from your customer's bank account. +

    +In-Progress: The transaction is in process of authorization and capture. +

    +Partially-Refunded: The transaction has been partially refunded. +

    +Pending: The payment is pending. See "PendingReason" for more information. +

    +Refunded: You refunded the payment. +

    +Reversed: A payment was reversed due to a chargeback or other type of reversal. The funds have been removed from your account balance and returned to the buyer. The reason for the reversal is specified in the ReasonCode element. +

    +Processed: A payment has been accepted. +

    +Voided: This authorization has been voided. +

    +Completed-Funds-Held: The payment has been completed, and the funds have been added successfully to your pending balance. See the "HoldDecision" field for more information. +
    +
    +
    + + + + The reason the payment is pending: +none: No pending reason +

    +address: The payment is pending because your customer did not include a confirmed shipping address and your Payment Receiving Preferences is set such that you want to manually accept or deny each of these payments. To change your preference, go to the Preferences section of your Profile. +

    +authorization: You set PaymentAction to Authorization on SetExpressCheckoutRequest and have not yet captured funds. +

    +echeck: The payment is pending because it was made by an eCheck that has not yet cleared. +

    +intl: The payment is pending because you hold a non-U.S. account and do not have a withdrawal mechanism. You must manually accept or deny this payment from your Account Overview. +

    +multi-currency: You do not have a balance in the currency sent, and you do not have your Payment Receiving Preferences set to automatically convert and accept this payment. You must manually accept or deny this payment. +

    +unilateral: The payment is pending because it was made to an email address that is not yet registered or confirmed. +

    +upgrade: The payment is pending because it was made via credit card and you must upgrade your account to Business or Premier status in order to receive the funds. upgrade can also mean that you have reached the monthly limit for transactions on your account. +

    +verify: The payment is pending because you are not yet verified. You must verify your account before you can accept this payment. +

    +regulatory-review: This payment is pending while we make sure it meets regulatory requirements. We'll contact you again in 24-72 hours with the outcome of our review. +

    +other: The payment is pending for a reason other than those listed above. For more information, contact PayPal Customer Service. +
    +
    +
    + + + + The reason for a reversal if TransactionType is reversal: +none: No reason code +

    +chargeback: A reversal has occurred on this transaction due to a chargeback by your customer. +

    +guarantee: A reversal has occurred on this transaction due to your customer triggering a money-back guarantee. +

    +buyer-complaint: A reversal has occurred on this transaction due to a complaint about the transaction from your customer. +

    +refund: A reversal has occurred on this transaction because you have given the customer a refund. +

    +other: A reversal has occurred on this transaction due to a reason not listed above. +
    +
    +
    + + + + HoldDecision is returned in the response only if PaymentStatus is Completed-Funds-Held. The reason the funds are kept in pending balance: +newsellerpaymenthold: The seller is new. +

    +paymenthold: A hold is placed on your transaction due to a reason not listed above. +
    +
    +
    + + + + Shipping method selected by the user during check-out. + + + + + + + Protection Eligibility for this Transaction - None, SPP or ESPP + + + + + + + Protection Eligibility details for this Transaction + + + + + + + Receipt Reference Number for this Transaction + + + + + + + The type of POS transaction +

    +F: Forced post transaction. POS merchant can send transactions at a later point if connectivity is lost. +

    +S: Single call checkout, and this is to identify PayPal Lite API usage. +
    +
    +
    + + + + Amount of shipping charged on transaction + + + + + + Amount of ship handling charged on transaction + + + + + + Amount of shipping discount on transaction + + + + + + Amount of Insurance amount on transaction + + + + + + Subject as entered in the transaction + + + + + + StoreID as entered in the transaction + + + + + + TerminalID as entered in the transaction + + + + + + Details about the seller.
    + Optional
    +
    +
    + + + + Unique identifier and mandatory for each bucket in case of split payement + + + + + + + Thes are filters that could result in accept/deny/pending action. + + + + + + + This will be enhanced info for the payment: Example: UATP details + + + + + + + This will indicate the payment status for individual payment request in case of split payment + + + + + + + Type of the payment instrument. + + + + + + + Offer Details. + + + + + + + This field indicates whether the credit card number used for this transaction is in a particular bin range registered with PayPal by the merchant. + This filed is optional and will be present if merchant has a registered bin range. + The value of this field will be "true" if merchant has a registered bin range and the credit card used in the transaction is within the registered bin range. + The value of this field will be false if merchant has a registered bin range and credit card used in the transaction outside registered bin range or the transaction is not done using a credit card. + + + +
    +
    + + + + SubscriptionTermsType + Terms of a PayPal subscription. + + + + + + + + + + + SubscriptionInfoType + Information about a PayPal Subscription. + + + + + + + ID generated by PayPal for the subscriber. +Character length and limitations: no limit + + + + + + Subscription start date + + + + + + Date when the subscription modification will be effective + + + + + + Date PayPal will retry a failed subscription payment + + + + + + Username generated by PayPal and given to subscriber to access the subscription. +Character length and limitations: 64 alphanumeric single-byte characters + + + + + + Password generated by PayPal and given to subscriber to access the subscription. For security, the value of the password is hashed. +Character length and limitations: 128 alphanumeric single-byte characters + + + + + + The number of payment installments that will occur at the regular rate. +Character length and limitations: no limit + + + + + + Subscription duration and charges + + + + + + + + + + AuctionInfoType + Basic information about an auction. + + + + + + + Customer's auction ID + + + + + + Auction's close date + + + + + + + + + OptionType + PayPal item options for shopping cart. + + + + + + + + + + EbayItemPaymentDetailsItemType - Type declaration to be used by other schemas. + Information about an Ebay Payment Item. + + + + + + + Auction ItemNumber. +

    +Optional +

    +Character length and limitations: 765 single-byte characters +
    +
    +
    + + + + Auction Transaction ID. +

    +Optional +

    +Character length and limitations: 255 single-byte characters +
    +
    +
    + + + + Ebay Order ID. +

    +Optional +

    +Character length and limitations: 64 single-byte characters +
    +
    +
    + + + + Ebay Cart ID. +

    + Optional +

    + Character length and limitations: 64 single-byte characters +
    +
    +
    +
    +
    + + + + PaymentDetailsItemType + Information about a Payment Item. + + + + + + + Item name. +

    +Optional +

    +Character length and limitations: 127 single-byte characters +
    +
    +
    + + + + Item number. +

    +Optional +

    +Character length and limitations: 127 single-byte characters +
    +
    +
    + + + + Item quantity. +

    +Optional +

    +Character length and limitations: Any positive integer
    +
    +
    + + + + Item sales tax. +

    +Optional +

    Character length and limitations: any valid currency amount; currency code is set the same as for OrderTotal. +
    +
    +
    + + + + Cost of item +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Ebay specific details. +

    +Optional +
    +
    +
    + + + + Promotional financing code for item. Part of the Merchant Services Promotion Financing feature. + + + + + + + + + + + + Item description.
    + Optional
    + Character length and limitations: 127 single-byte characters +
    +
    +
    + + + + Information about the Item weight. + + + + + + + Information about the Item length. + + + + + + + Information about the Item width. + + + + + + + Information about the Item height. + + + + + + + URL for the item.
    + Optional
    + Character length and limitations: no limit. +
    +
    +
    + + + + Enhanced data for each item in the cart.
    + Optional
    +
    +
    + + + + Item category - physical or digital.
    + Optional
    +
    +
    +
    +
    + + + + PaymentItemType + Information about a Payment Item. + + + + + + + eBay Auction Transaction ID of the Item +
    Optional

    Character length and limitations: 255 single-byte characters +
    +
    +
    + + + + Item name set by you or entered by the customer. +
    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + Item number set by you. +
    +Character length and limitations: 127 single-byte alphanumeric characters
    +
    +
    + + + + Quantity set by you or entered by the customer. +
    +Character length and limitations: no limit
    +
    +
    + + + + Amount of tax charged on payment + + + + + + Amount of shipping charged on payment + + + + + + Amount of handling charged on payment + + + + + + Invoice item details + + + + + + Coupon ID Number + + + + + + Amount Value of The Coupon + + + + + + Currency of the Coupon Amount + + + + + + Amount of Discount on this Loyalty Card + + + + + + Currency of the Discount + + + + + + Cost of item + + + + + + Item options selected in PayPal shopping cart + + +
    +
    + + + + PaymentItemInfoType + Information about a PayPal item. + + + + + + + Invoice number you set in the original transaction. +

    + Character length and limitations: 127 single-byte alphanumeric characters
    +
    +
    + + + + Custom field you set in the original transaction. +

    +Character length and limitations: 127 single-byte alphanumeric characters
    +
    +
    + + + + Memo entered by your customer in PayPal Website Payments note field. +

    +Character length and limitations: 255 single-byte alphanumeric characters
    +
    +
    + + + + Amount of tax charged on transaction + + + + + + Details about the indivudal purchased item + + + + + + Information about the transaction if it was created via PayPal Subcriptions + + + + + + Information about the transaction if it was created via an auction + + +
    +
    + + + + OffersAndCouponsInfoType + Information about a Offers and Coupons. + + + + + + + Type of the incentive + + + + + + ID of the Incentive used in transaction + + + + + + Amount used on transaction + + + + + + Amount Currency + + + + + + + + PaymentDetailsType + Information about a payment. Used by DCC and Express Checkout. + + + + + + + Total of order, including shipping, handling, and tax. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +


    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,).
    +
    +
    + + + + Sum of cost of all items in this order. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Optional +

    separator must be a comma (,). +
    +
    +
    + + + + Total shipping costs for this order. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Total handling costs for this order. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Sum of tax for all items in this order. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Optional +

    Limitations: Must not exceed $10,000 USD in any currency. No currency symbol. Decimal separator must be a period (.), and the thousands separator must be a comma (,). +
    +
    +
    + + + + Description of items the customer is purchasing. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + A free-form field for your own use. +

    +Optional +

    Character length and limitations: 256 single-byte alphanumeric characters +
    +
    +
    + + + + Your own invoice or tracking number. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + + An identification code for use by third-party applications to identify transactions. +

    +Optional +

    Character length and limitations: 32 single-byte alphanumeric characters +
    +
    +
    + + + + Your URL for receiving Instant Payment Notification (IPN) about this transaction. +

    +Optional +

    If you do not specify NotifyURL in the request, the notification URL from your Merchant Profile is used, if one exists. +

    Character length and limitations: 2,048 single-byte alphanumeric characters +
    +
    +
    + + + + Address the order will be shipped to. +

    +Optional +

    +If you include the ShipToAddress element, the AddressType elements are required: +

    Name +

    +Street1 +

    +CityName +

    +CountryCode +

    Do not set set the CountryName element.
    +
    +
    + + + The value 1 indicates that this payment is associated with multiple shipping addresses. +

    + Optional +

    + Character length and limitations: Four single-byte numeric characters. +
    +
    +
    + + + + Thirdparty Fulfillment Reference Number.
    + Optional
    + Character length and limitations: 32 alphanumeric characters.
    +
    +
    + + + + + + + + + + + Date and time (in GMT in the format yyyy-MM-ddTHH:mm:ssZ) at which address was changed by the user. + + + + + + + Information about the individual purchased items + + + + + + Total shipping insurance costs for this order.
    + Optional
    +
    +
    + + + + Shipping discount for this order, specified as a negative number.
    + Optional
    +
    +
    + + + + Information about the Insurance options. + + + + + + + Allowed payment methods for this transaction. + + + + + + + Enhanced Data section to accept channel specific data.
    + Optional
    + Refer to EnhancedPaymentDataType for details.
    +
    +
    + + + + Details about the seller.
    + Optional
    +
    +
    + + + + Note to recipient/seller.
    + Optional
    + Character length and limitations: 127 single-byte alphanumeric characters.
    +
    +
    + + + + PayPal Transaction Id, returned once DoExpressCheckout is completed.
    +
    +
    + + + + How you want to obtain payment. +

    + This payment action input will be used for split payments +

    + Authorization indicates that this payment is a basic authorization subject to settlement with PayPal Authorization and Capture. +

    + Order indicates that this payment is is an order authorization subject to settlement with PayPal Authorization and Capture. +

    + Sale indicates that this is a final sale for which you are requesting payment. +

    + IMPORTANT: You cannot set PaymentAction to Sale on SetExpressCheckoutRequest and then change PaymentAction to Authorization on the final Express Checkout API, DoExpressCheckoutPaymentRequest. +

    + Character length and limit: Up to 13 single-byte alphabetic characters +
    +
    +
    + + + + Unique identifier and mandatory for the particular payment request in case of multiple payment + + + + + + + URL on Merchant site pertaining to this invoice. +

    Optional

    +
    +
    + + + + Soft Descriptor supported for Sale and Auth in DEC only. For Order this will be ignored. + + + + + + + BranchLevel is used to identify chain payment. + If BranchLevel is 0 or 1, this payment is where money moves to. + If BranchLevel greater than 1, this payment contains the actual seller info. +

    + Optional +
    +
    +
    + + + + Soft Descriptor supported for Sale and Auth in DEC only. For Order this will be ignored. + + + + + + + Flag to indicate the recurring transaction + + + + + + + Indicates the purpose of this payment like Refund + + + +
    +
    + + + + Information about the incentives that were applied from Ebay RYP page and PayPal RYP page. + + + + + + + Unique Identifier consisting of redemption code, user friendly descripotion, incentive type, campaign code, incenitve application order and site redeemed o +n. + + + + + + + Defines if the incentive has been applied on Ebay or PayPal. + + + + + + + The total discount amount for the incentive, summation of discounts up across all the buckets/items. + + + + + + + Status of incentive processing. Sussess or Error. + + + + + + + Error code if there are any errors. Zero otherwise. + + + + + + + Details of incentive application on individual bucket/item. + + + + + + + + + Details of incentive application on individual bucket/item. + + + + + + + PaymentRequestID uniquely identifies a bucket. It is the "bucket id" in the world of EC API. + + + + + + + The item id passed through by the merchant. + + + + + + + The item transaction id passed through by the merchant. + + + + + + + Discount offerred for this bucket or item. + + + + + + + SubType for coupon. + + + + + + + + + Details about the seller. + + + + + + + Unique identifier for the seller.
    + Optional
    +
    +
    + + + + The user name of the user at the marketplaces site.
    + Optional
    +
    +
    + + + + Date when the user registered with the marketplace.
    + Optional
    +
    +
    + + + + Seller Paypal Account Id contains the seller EmailId or PayerId or PhoneNo passed during the Request. + + + + + + + Unique PayPal customer account identification number (of the seller). This feild is meant for Response. This field is ignored, if passed in the Request. + + + +
    +
    + + + + Lists the Payment Methods (other than PayPal) that the use can pay with e.g. Money Order.
    + Optional.
    +
    + + + + + The identifier of the Payment Method. + + + + + + + Valid values are 'Method', 'SubMethod'. + + + + + + + The name of the Payment Method. + + + + + + + The short description of the Payment Method, goes along with the label. + + + + + + + The title for the long description. + + + + + + + The long description of the Payment Method. + + + + + + + The icon of the Payment Method. + + + + + + + If this flag is true, then OtherPaymentMethodIcon is required to have a valid value; the label will be hidden and only ICON will be shown. + + + + +
    + + + + Details about the buyer's account passed in by the merchant or partner.
    + Optional.
    +
    + + + + + The client's unique ID for this user.
    +
    +
    + + + + The user name of the user at the marketplaces site.
    +
    +
    + + + + Date when the user registered with the marketplace.
    +
    +
    + + + + Details about payer's tax info.
    + Refer to the TaxIdDetailsType for more details.
    +
    +
    + + + + Contains information that identifies the buyer. e.g. email address or the external remember me id. + + + +
    +
    + + + + Details about the payer's tax info passed in by the merchant or partner.
    + Optional.
    +
    + + + + + The payer's Tax ID type; CNPJ/CPF for BR country.
    +
    +
    + + + + The payer's Tax ID
    +
    +
    +
    +
    + + + + The Common 3DS fields. Common for both GTD and DCC API's. + + + + + + + + + + + + + + 3DS remaining fields. + + + + + + + + + + + 3DSecureInfoType + Information about 3D Secure parameters. + + + + + + + + + + + CreditCardDetailsType + Information about a Credit Card. + + + + + + + + + + + + + + + + + + + Fallback shipping options type. + + + + + + + + + + + + Information on user selected options + + + + + + + + + + + + + + + + + + + + + + + CreditCardDetailsType for DCC Reference Transaction + Information about a Credit Card. + + + + + + + + + + + + + + + + + + PaymentTransactionCodeType + This is the type of a PayPal of which matches the output from IPN + + + + + + + + + + + + + + + + + + + + + + + + + + + PaymentStatusCodeType + This is the status of a PayPal Payment which matches the output from IPN + + + + + + + + + + + + + + + + + + + + + + + + + + AddressStatusCodeType + This is the PayPal address status + + + + + + + + + + + + Normalization Status of the Address + + + + + + + + + + + + + PaymentDetailsCodeType + This is the PayPal payment details type (used by DCC and Express Checkout) + + + + + + + + + + + + + This is various actions that a merchant can take on a FMF Pending Transaction. + + + + + + + + + + + ChannelType - Type declaration to be used by other schemas. + This is the PayPal Channel type (used by Express Checkout) + + + + + + + + + + + TotalType - Type declaration for the label to be displayed + in MiniCart for UX. + + + + + + + + + + + SolutionTypeType + This is the PayPal payment Solution details type (used by Express Checkout) + + + + + + + + + + + AllowedPaymentMethodType + This is the payment Solution merchant needs to specify for Autopay (used by Express Checkout) +
    Optional +
    Default indicates that its merchant supports all funding source +
    InstantPaymentOnly indicates that its merchant only supports instant payment +
    AnyFundingSource allow all funding methods to be chosen by the buyer irrespective of merchant's profile setting +
    InstantFundingSource allow only instant funding methods, block echeck, meft, elevecheck. This will override any merchant profile setting +
    +
    + + + + + + +
    + + + + LandingPageType + This is the PayPal payment Landing Page details type (used by Express Checkout) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PendingStatusCodeType + The pending status for a PayPal Payment transaction which matches the output from IPN + + + + + + + + + + + + + + + + + + + + + + ReceiverInfoCodeType + Payee identifier type for MassPay API + + + + + + + + + + + + ReversalReasonCodeType + Reason for a reversal on a PayPal transaction which matches the output from IPN + + + + + + + + + + + + + + + POSTransactionCodeType + POS Transaction Code Type. F for Forced Post Transaction and S for Single Call Checkout + + + + + + + + + + + PaymentCodeType + This is the type of PayPal payment which matches the output from IPN. + + + + + + + + + + + + RefundSourceCodeType + This is the type of PayPal funding source that can be used for auto refund. + any - Means Merchant doesn't have any preference. PayPal can use any available funding source (Balance or eCheck) + default - Means merchant's preferred funding source as configured in his profile. (Balance or eCheck) + instant - Only Balance + echeck - Merchant prefers echeck. If PayPal balance can cover the refund amount, we will use PayPal balance. (balance or eCheck) + + + + + + + + + + + + + PayPalUserStatusCodeType + PayPal status of a user Address + + + + + + + + + + + MerchantPullPaymentCodeType + Type of Payment to be initiated by the merchant + + + + + + + + + + + + MerchantPullStatusCodeType + Status of the merchant pull + + + + + + + + + + + PaymentTransactionStatusCodeType + The status of the PayPal payment. + + + + + + + + + + + + + + PaymentTransactionClassCodeType + The Type of PayPal payment. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MatchStatusCodeType + This is the PayPal (street/zip) match code + + + + + + + + + + + + CompleteCodeType + This is the PayPal DoCapture CompleteType code + + + + + + + + + + + TransactionEntityType + This is the PayPal DoAuthorization TransactionEntityType code + + + + + + + + + + + + + + MobileRecipientCodeType + These are the accepted types of recipients for mobile-originated transactions + + + + + + + + + + + MobilePaymentCodeType + These are the accepted types of mobile payments + + + + + + + + + + + + + Custom Securiy Header. + + + + + + + + + + + + + + + + + The username is the identifier for an account. + + + + + + + Password contains the current password associated with the username. + + + + + + + Signature for Three Token authentication. + + + + + + + This field identifies an account (e.g., payment) on whose behalf the operation is being performed. + For instance one account holder may delegate the abililty to perform certain operations + to another account holder. This delegation is done through a separate mechanism. + If the base username has not been authorized by the subject the request will be rejected. + + + + + + + Authentication Session Token for authentication and authorization. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The value 1 indicates that you require that the customer's billing address on file. Setting this element overrides the setting you have specified in Admin. +

    +Optional +

    Character length and limitations: One single-byte numeric character. +
    +
    +
    +
    +
    + + + + + + + + + + Customer's billing address. +

    +Optional +

    +If you have a credit card mapped in your PayPal account, PayPal returns the billing address of the credit billing address otherwise your primary address as billing address in GetBillingAgreementCustomerDetails. +
    +
    +
    +
    +
    + + + + + Device ID

    Optional

    + Character length and limits: 256 single-byte characters
    + DeviceID length morethan 256 is truncated +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unique id for each API request to prevent duplicate payments. +

    Optional
    Character length and limits: 38 single-byte characters maximum. +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Response code from the processor when a recurring transaction is declined + + + + + + + Return msgsubid back to merchant + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Onboarding program code given to you by PayPal. +

    Required

    +Character length and limitations: 64 alphanumeric characters
    +
    +
    + + + + A list of comma-separated values that indicate the PayPal products you are implementing for this merchant: +

    +Direct Payment (dp) allows payments by credit card without requiring the customer to have a PayPal account. +

    +Express Checkout (ec) allows customers to fund transactions with their PayPal account. +

    +Authorization and Capture (auth_settle) allows merchants to verify availability of funds in a PayPal account, but capture them at a later time. +

    +Administrative APIs (admin_api) is a collection of the PayPal APIs for transaction searching, getting transaction details, refunding, and mass payments. +

    Required

    +Character length and limitations: 64 alphanumeric characters
    +
    +
    + + + + Any custom information you want to store for this partner +

    +Optional +

    +Character length and limitations: 256 alphanumeric characters
    +
    +
    + + + + The URL for the logo displayed on the PayPal Partner Welcome Page. +

    +Optional +

    +Character length and limitations: 2,048 alphanumeric characters
    +
    +
    + + + + Marketing category tha configures the graphic displayed n the PayPal Partner Welcome page. + + + + + + Information about the merchantâs business + + + + + + Information about the merchant (the business owner) + + + + + + Information about the merchant's bank account + + +
    +
    + + + + MarketingCategoryType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BusinessInfoType + + + + + + + Type of business, such as corporation or sole proprietorship + + + + + + Official name of business +

    +Character length and limitations: 75 alphanumeric characters
    +
    +
    + + + + Merchantâs business postal address + + + + + + Businessâs primary telephone number +

    +Character length and limitations: 20 alphanumeric characters
    +
    +
    + + + + Line of business, as defined in the enumerations + + + + + + Business sub-category, as defined in the enumerations + + + + + + Average transaction price, as defined by the enumerations. + AverageTransactionPrice-Not-Applicable +
    EnumerationMeaning
    AverageTransactionPrice-Range1Less than $25 USD
    AverageTransactionPrice-Range2$25 USD to $50 USD
    AverageTransactionPrice-Range3$50 USD to $100 USD
    AverageTransactionPrice-Range4$100 USD to $250 USD
    AverageTransactionPrice-Range5$250 USD to $500 USD
    AverageTransactionPrice-Range6$500 USD to $1,000 USD
    AverageTransactionPrice-Range7 $1,000 USD to $2,000 USD
    AverageTransactionPrice-Range8$2,000 USD to $5,000 USD
    AverageTransactionPrice-Range9$5,000 USD to $10,000 USD
    AverageTransactionPrice-Range10More than $10,000 USD
    +
    +
    + + + + Average monthly sales volume, as defined by the enumerations. +
    EnumerationMeaning
    AverageMonthlyVolume-Not-Applicable
    AverageMonthlyVolume-Range1Less than $1,000 USD
    AverageMonthlyVolume-Range2$1,000 USD to $5,000 USD
    AverageMonthlyVolume-Range3$5,000 USD to $25,000 USD
    AverageMonthlyVolume-Range4$25,000 USD to $100,000 USD
    AverageMonthlyVolume-Range5$100,000 USD to $1,000,000 USD
    AverageMonthlyVolume-Range6More than $1,000,000 USD
    +
    +
    + + + + Main sales venue, such as eBay + + + + + + Primary URL of business +

    Character length and limitations: 2,048 alphanumeric characters
    +
    +
    + + + + Percentage of revenue attributable to online sales, as defined by the enumerations +

    PercentageRevenueFromOnlineSales-Not-Applicable +
    EnumerationMeaning
    PercentageRevenueFromOnlineSales-Range1Less than 25%
    PercentageRevenueFromOnlineSales-Range225% to 50%
    PercentageRevenueFromOnlineSales-Range350% to 75%
    PercentageRevenueFromOnlineSales-Range475% to 100%
    +
    +
    + + + + Date the merchantâs business was established + + + + + + Email address to contact businessâs customer service +

    +Character length and limitations: 127 alphanumeric characters
    +
    +
    + + + + Telephone number to contact businessâs customer service +

    Character length and limitations: 32 alphanumeric characters
    +
    +
    +
    +
    + + + + BusinessTypeType + + + + + + + + + + + + + + + + BusinessCategoryType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BusinessSubCategoryType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AverageTransactionPriceType +

    AverageTransactionPrice-Not-Applicable +
    EnumerationMeaning
    AverageTransactionPrice-Range1Less than $25 USD
    AverageTransactionPrice-Range2$25 USD to $50 USD
    AverageTransactionPrice-Range3$50 USD to $100 USD
    AverageTransactionPrice-Range4$100 USD to $250 USD
    AverageTransactionPrice-Range5$250 USD to $500 USD
    AverageTransactionPrice-Range6$500 USD to $1,000 USD
    AverageTransactionPrice-Range7 $1,000 USD to $2,000 USD
    AverageTransactionPrice-Range8$2,000 USD to $5,000 USD
    AverageTransactionPrice-Range9$5,000 USD to $10,000 USD
    AverageTransactionPrice-Range10More than $10,000 USD
    +
    + + + + + + + + + + + + + +
    + + + + AverageMonthlyVolumeType +
    EnumerationMeaning
    AverageMonthlyVolume-Not-Applicable
    AverageMonthlyVolume-Range1Less than $1,000 USD
    AverageMonthlyVolume-Range2$1,000 USD to $5,000 USD
    AverageMonthlyVolume-Range3$5,000 USD to $25,000 USD
    AverageMonthlyVolume-Range4$25,000 USD to $100,000 USD
    AverageMonthlyVolume-Range5$100,000 USD to $1,000,000 USD
    AverageMonthlyVolume-Range6More than $1,000,000 USD
    +
    + + + + + + + + + +
    + + + + SalesVenueType + + + + + + + + + + + + + + PercentageRevenueFromOnlineSalesType +

    PercentageRevenueFromOnlineSales-Not-Applicable +
    EnumerationMeaning
    PercentageRevenueFromOnlineSales-Range1Less than 25%
    PercentageRevenueFromOnlineSales-Range225% to 50%
    PercentageRevenueFromOnlineSales-Range350% to 75%
    PercentageRevenueFromOnlineSales-Range475% to 100%
    +
    + + + + + + + +
    + + + + BusinessOwnerInfoType + + + + + + + Details about the business owner + + + + + + Business ownerâs home telephone number +

    Character length and limitations: 32 alphanumeric characters
    +
    +
    + + + + Business ownerâs mobile telephone number +

    +Character length and limitations: 32 alphanumeric characters
    +
    +
    + + + + Business ownerâs social security number +

    +Character length and limitations: 9 alphanumeric characters
    +
    +
    +
    +
    + + + + BankAccountDetailsType + + + + + + + Name of bank +

    + Character length and limitations: 192 alphanumeric characters
    +
    +
    + + + + Type of bank account: Checking or Savings + + + + + + Merchantâs bank routing number +

    +Character length and limitations: 23 alphanumeric characters
    +
    +
    + + + + Merchantâs bank account number +

    +Character length and limitations: 256 alphanumeric characters
    +
    +
    +
    +
    + + + + BankAccountTypeType + + + + + + + + + + + + + + + + Status of merchant's onboarding process: +

    + Completed +
    Cancelled +
    Pending +

    Character length and limitations: Eight alphabetic characters
    +
    +
    + + + + Date the boarding process started + + + + + + Date the merchantâs status or progress was last updated + + + + + + Reason for merchantâs cancellation of sign-up. +

    +Character length and limitations: 1,024 alphanumeric characters
    +
    +
    + + + + + + + Indicates if there is a limitation on the amount of money the business can withdraw from PayPal + + + + + + Custom information you set on the EnterBoarding API call +

    Character length and limitations: 256 alphanumeric characters
    +
    +
    + + + + Details about the owner of the account + + + + + + Merchantâs PayPal API credentials + + + + + + The APIs that this merchant has granted the business partner permission to call on his behalf. +

    + For example: +
    +SetExpressCheckout,GetExpressCheckoutDetails,DoExpressCheckoutPayment +
    +
    +
    + + + + Primary email verification status. Confirmed, Unconfirmed + + + + + + Gives VettingStatus - Pending, Cancelled, Approved, UnderReview +

    Character length and limitations: 256 alphanumeric characters
    +
    +
    + + + + Gives BankAccountVerificationStatus - Added, Confirmed +

    Character length and limitations: 256 alphanumeric characters
    +
    +
    +
    +
    + + + + Boarding Status + + + + + + + + + + + + + User Withdrawal Limit Type Type + + + + + + + + + + + + APICredentialsType + + + + + + + Merchantâs PayPal API username +Character length and limitations: 128 alphanumeric characters + + + + + + Merchantâs PayPal API password +Character length and limitations: 40 alphanumeric characters + + + + + + Merchantâs PayPal API signature, if one exists. +

    Character length and limitations: 256 alphanumeric characters
    +
    +
    + + + + Merchantâs PayPal API certificate in PEM format, if one exists +

    + The certificate consists of two parts: the private key (2,048 bytes) and the certificate proper (4,000 bytes). +


    Character length and limitations: 6,048 alphanumeric characters
    +
    +
    + + + + Merchantâs PayPal API authentication mechanism. +

    +Auth-None: no authentication mechanism on file +

    Cert: API certificate +

    Sign: API signature +

    Character length and limitations: 9 alphanumeric characters
    +
    +
    +
    +
    + + + + API Authentication Type + + + + + + + + + + + + + + The phone number of the buyer's mobile device, if available. +

    Optional
    +
    +
    + + + + Cost of this item before tax and shipping. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Required +
    +
    +
    + + + + Tax amount for this item. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Optional +
    +
    +
    + + + + Shipping amount for this item. +You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies. +

    +Optional +
    +
    +
    + + + Description of the item that the customer is purchasing. +

    +Required +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + Reference number of the item that the customer is purchasing. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + A free-form field for your own use, such as a tracking number or other value you want returned to you in IPN. +

    +Optional +

    Character length and limitations: 256 single-byte alphanumeric characters +
    +
    +
    + + + Your own unique invoice or tracking number. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + URL to which the customer's browser is returned after choosing to pay with PayPal. PayPal recommends that the value of ReturnURL be the final review page on which the customer confirms the order and payment. +

    Required

    +Character length and limitations: no limit.
    +
    +
    + + + URL to which the customer is returned if he does not approve the use of PayPal to pay you. PayPal recommends that the value of CancelURL be the original page on which the customer chose to pay with PayPal. +

    Optional

    +Character length and limitations: no limit +
    +
    +
    + + + The value 1 indicates that you require that the customer's shipping address on file with PayPal be a confirmed address. Setting this element overrides the setting you have specified in your Merchant Account Profile. +

    +Optional +
    +
    +
    + + + The value 1 indicates that you require that the customer specifies a contact phone for the transactxion. Default is 0 / none required. +

    +Optional +
    +
    +
    + + + Customer's shipping address. +

    +Optional +
    +
    +
    + + + + Email address of the buyer as entered during checkout. PayPal uses this value to pre-fill the login portion of the PayPal login page. +

    +Optional +

    Character length and limit: 127 single-byte alphanumeric characters +
    +
    +
    +
    +
    + + + + + + A free-form field for your own use, such as a tracking number or other value you want returned to you in IPN. +

    +Optional +

    Character length and limitations: 256 single-byte alphanumeric characters +
    +
    +
    + + + Your own unique invoice or tracking number. +

    +Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + Information about the payer + + + + + Information about the transaction + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + The value 'Auction' indicates that user is coming to checkout after an auction ended. A value of 'BuyItNow' indicates if the user is coming to checkout by clicking on the 'buy it now' button in a chinese auction. A value of 'FixedPriceItem' indicates that user clicked on 'Buy it now' on a fixed price item. A value of Autopay indicates autopay (or immediate pay) which is not supported at the moment. +

    + Required +
    +
    +
    + + + An item number assigned to the item in eBay database. +

    + Required +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + An Transaction id assigned to the item in eBay database. In case of Chinese auction Item Id itself indicates Transaction Id. Transaction Id in this case is Zero. +

    + Required +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + An id indicating the site on which the item was listed. +

    + Required +

    Character length and limitations: 2 alphanumeric characters +
    +
    +
    + + + Buyers ebay Id. +

    + Required +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    + + + Indicating the client type. Weather it is WAP or J2ME. A value of 'WAP' indicates WAP. A value of 'J2MEClient' indicates J2ME client. +

    + Required +
    +
    +
    + + + The phone number of the buyer's mobile device, if available. +

    Optional
    +
    +
    + + + URL to which the customer's browser is returned after choosing to pay with PayPal. PayPal recommends that the value of ReturnURL be the final review page on which the customer confirms the order and payment. +

    Optional

    + Character length and limitations: no limit. +
    +
    +
    + + + URL to which the customer is returned if he does not approve the use of PayPal to pay you. PayPal recommends that the value of CancelURL be the original page on which the customer chose to pay with PayPal. +

    Optional

    + Character length and limitations: no limit +
    +
    +
    + + + Specify quantity in case it is an immediate pay (or autopay) item. +

    + Optional +
    +
    +
    + + + Cost of this item before tax and shipping.You must set the currencyID attribute to one of the three-character currency codes for any of the supported PayPal currencies.Used only for autopay items. +

    + Optional +
    +
    +
    +
    +
    + + + + UATP Card Details Type + + + + + + UATP Card Number + + + + + UATP Card expirty month + + + + + UATP Card expirty year + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unit of meausre for billing cycle + + + + + + + Number of BillingPeriod that make up one billing cycle + + + + + + + Total billing cycles in this portion of the schedule + + + + + + + Amount to charge + + + + + + + Additional shipping amount to charge + + + + + + + Additional tax amount to charge + + + + + + + + + + + Unit of meausre for billing cycle + + + + + + + Number of BillingPeriod that make up one billing cycle + + + + + + + Total billing cycles in this portion of the schedule + + + + + + + Amount to charge + + + + + + + Additional shipping amount to charge + + + + + + + Additional tax amount to charge + + + + + + + + + + + Schedule details for the Recurring Payment + + + + + + + Trial period of this schedule + + + + + + + + + + + + The max number of payments the buyer can fail before this Recurring Payments profile is cancelled + + + + + + + + + + + + + + + + + + + + + Subscriber name - if missing, will use name in buyer's account + + + + + + + Subscriber address - if missing, will use address in buyer's account + + + + + + + When does this Profile begin billing? + + + + + + Your own unique invoice or tracking number. +

    + Optional +

    Character length and limitations: 127 single-byte alphanumeric characters +
    +
    +
    +
    +
    + + + + + + Billing Agreement token (required if Express Checkout) + + + + + + + Information about the credit card to be charged (required if Direct Payment) + + + + + + + Customer Information for this Recurring Payments + + + + + + + Schedule Information for this Recurring Payments + + + + + + + Information about the Item Details. + + + + + + + + + + + Recurring Billing Profile ID + + + + + + + Recurring Billing Profile Status + + + + + + + Transaction id from DCC initial payment + + + + + + + Response from DCC initial payment + + + + + + + Return code if DCC initial payment fails + + + + + + + + + + + Recurring Billing Profile ID + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Information about the credit card to be charged (required if Direct Payment) + + + + + + + When does this Profile begin billing? + + + + + + + Trial period of this schedule + + + + + + + + + + + + + + + + + + + + + + + Details of Risk Filter. + + + + + + + + + + + + Details of Risk Filter. + + + + + + + + + Thes are filters that could result in accept/deny/pending action. + + + + + + + + + + + + + + + + + Other + + + + + Airlines + + + + + Antiques + + + + + Art + + + + + Cameras & Photos + + + + + Cars, Boats, Vehicles & Parts + + + + + Cell Phones & Telecom + + + + + Coins & Paper Money + + + + + Collectibles + + + + + Computers & Networking + + + + + Consumer Electronics + + + + + Jewelry & Watches + + + + + Musical Instruments + + + + + Real Estate + + + + + Sports Memorabilia, Cards & Fan Shop + + + + + Stamps + + + + + Tickets + + + + + Travels + + + + + Gambling + + + + + Alcohol + + + + + Tobacco + + + + + Money Transfer + + + + + Software + + + + + + + + Enhanced Data Information. Example: AID for Airlines + + + + + + + + + + AID for Airlines + + + + + + + + + + + + + + + + + + + + + + + Details of leg information + + + + + + + + + + + + + + + + + + + + + + + + + + Authorization details + + + + + + + The status of the payment: +

    +Pending: The payment is pending. See "PendingReason" for more information. +
    +
    +
    + + + + The reason the payment is pending: +none: No pending reason +

    +address: The payment is pending because your customer did not include a confirmed shipping address and your Payment Receiving Preferences is set such that you want to manually accept or deny each of these payments. To change your preference, go to the Preferences section of your Profile. +

    +authorization: The authorization is pending at time of creation if payment is not under review +

    +echeck: The payment is pending because it was made by an eCheck that has not yet cleared. +

    +intl: The payment is pending because you hold a non-U.S. account and do not have a withdrawal mechanism. You must manually accept or deny this payment from your Account Overview. +

    +multi-currency: You do not have a balance in the currency sent, and you do not have your Payment Receiving Preferences set to automatically convert and accept this payment. You must manually accept or deny this payment. +

    +unilateral: The payment is pending because it was made to an email address that is not yet registered or confirmed. +

    +upgrade: The payment is pending because it was made via credit card and you must upgrade your account to Business or Premier status in order to receive the funds. upgrade can also mean that you have reached the monthly limit for transactions on your account. +

    +verify: The payment is pending because you are not yet verified. You must verify your account before you can accept this payment. +

    +payment_review: The payment is pending because it is under payment review. +

    +other: The payment is pending for a reason other than those listed above. For more information, contact PayPal Customer Service. +
    +
    +
    + + + + Protection Eligibility for this Transaction - None, SPP or ESPP + + + + + + + Protection Eligibility Type for this Transaction + + + +
    +
    + + + + Types of button coding + + + + + + Creates Hosted Button + + + + + Creates Encrypted Button + + + + + Creates Cleartext Button + + + + + Creates Token or temporary Button + + + + + + + + Types of buttons + + + + + + button type is BUYNOW + + + + + button type is CART + + + + + button type is GIFTCERTIFICATE + + + + + button type is SUBSCRIBE + + + + + button type is DONATE + + + + + button type is UNSUBSCRIBE + + + + + button type is VIEWCART + + + + + button type is PAYMENTPLAN + + + + + button type is AUTOBILLING + + + + + button type is PAYMENT + + + + + + + + Types of button sub types + + + + + + button subtype is PRODUCTS + + + + + button subtype is SERVICES + + + + + + + + Types of button images + + + + + + button image type is REG + + + + + button image type is SML + + + + + button image type is CC + + + + + + + + values for buynow button text + + + + + + button wording is BUYNOW + + + + + button wording is PAYNOW + + + + + + + + values for subscribe button text + + + + + + button wording is BUYNOW + + + + + button wording is SUBSCRIBE + + + + + + + + values for subscribe button text + + + + + + Changes Button Status to DELETE + + + + + + + + + + Option Number. +
    Optional
    +
    +
    + + + + Option Quantity. +
    Optional
    +
    +
    + + + + Option Select Name. +
    Optional
    +
    +
    + + + + Option Quantity Delta. +
    Optional
    +
    +
    + + + + Option Alert. +
    Optional
    +
    +
    + + + + Option Cost. +
    Optional
    +
    +
    +
    +
    + + + + + + Item Number. +
    Required
    +
    +
    + + + + Option Quantity. +
    Optional
    +
    +
    + + + + Item Quantity Delta. +
    Optional
    +
    +
    + + + + Item Alert. +
    Optional
    +
    +
    + + + + Item Cost. +
    Optional
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + Identifier of the transaction to reverse. +

    Required

    + Character length and limitations: 17 single-byte alphanumeric characters +
    +
    +
    +
    +
    + + + + + Unique transaction identifier of the reversal transaction created. +

    + Character length and limitations:17 single-byte characters +
    +
    +
    + + + Status of reversal request. +

    Required

    +
    +
    +
    +
    + + + + + + UserSelectedFundingSourceType + User Selected Funding Source (used by Express Checkout) + + + + + + + + + + + + + + + + + Physical + + + + + Digital + + + + + + + + + + + + + + + + + Details of incentive application on individual bucket. + + + + + + + Incentive redemption code. + + + + + + + Defines which bucket or item that the incentive should be applied to. + + + + + + + + + Defines which bucket or item that the incentive should be applied to. + + + + + + + The Bucket ID that the incentive is applied to. + + + + + + + The item that the incentive is applied to. + + + + + + + + + + Contains payment request information for each bucket in the cart. + + + + + + Contains the transaction id of the bucket. + + + + + + + Contains the bucket id. + + + + + + + Contains the error details. + + + + + + + + + + E-mail address or secure merchant account ID of merchant to associate with new external remember-me. + + + + + + A discriminant that tells SetEC what kind of data the ExternalRememberMeOwnerID parameter contains. + Currently, the owner must be either the API actor or omitted/none. In the future, we may allow the + owner to be a 3rd party merchant account. + Possible values are: + None, ignore the ExternalRememberMeOwnerID. An empty value for this field also signifies None. + Email, the owner ID is an email address + SecureMerchantAccountID, the owner id is a string representing the secure merchant account ID + + + + + + + When opting in to bypass login via remember me, this parameter specifies the merchant account + associated with the remembered login. Currentl, the owner must be either the API actor or omitted/none. + In the future, we may allow the owner to be a 3rd party merchant account. + If the Owner ID Type field is not present or "None", this parameter is ignored. + + + + + + + + + + This element contains information that allows the merchant to request to + opt into external remember me on behalf of the buyer or to request login + bypass using external remember me. + + + + + + 1 = opt in to external remember me. + 0 or omitted = no opt-in + Other values are invalid + + + + + + + E-mail address or secure merchant account ID of merchant to associate with new external remember-me. Currently, + the owner must be either the API actor or omitted/none. In the future, we may allow the owner to be a 3rd party + merchant account. + + + + + + + + + + An optional set of values related to flow-specific details. + + + + + + The URL to redirect to for an unpayable transaction. This field is currently used only + for the inline checkout flow. + + + + + + + The URL to redirect to after a user clicks the "Pay" or "Continue" button on the merchant's + site. This field is currently used only for the inline checkout flow. + + + + + + + + + + Response information resulting from opt-in operation or current login bypass status. + + + + + + Required field that reports status of opt-in or login bypass attempt. + 0 = Success - successful opt-in or ExternalRememberMeID specified in SetExpressCheckout + is valid. + 1 = Invalid ID - ExternalRememberMeID specified in SetExpressCheckout is invalid. + 2 = Internal Error - System error or outage during opt-in or login bypass. Can retry + opt-in or login bypass next time. Flow will force full authentication and allow buyer + to complete transaction. + -1 = None - the return value does not signify any valid remember me status. + + + + + + + Identifier returned on external-remember-me-opt-in to allow the merchant to request + bypass of PayPal login through external remember me on behalf of the buyer in future + transactions. The ExternalRememberMeID is a 17-character alphanumeric (encrypted) + string. This field has meaning only to the merchant. + + + + + + + + + + Response information resulting from opt-in operation or current login bypass status. + + + + + + Required field that reports status of opt-in or login bypass attempt. + 0 = Success, successful opt-in or RefreshToken corresponding to AccessToken specified + in SetExpressCheckout is valid (user is still opted in). + 1 = New RefreshToken was generated (user is still opted in). + 2 = Invalid ID, RefreshToken corresponding to AccessToken specified in SetExpressCheckout + is invalid (user is opted out). + -2 = Internal Error, system error or outage during opt-in or login bypass. Can retry + opt-in or login bypass next time. Flow will force full authentication and allow + buyer to complete transaction. + -1 = None, the field does not represent any valid value of the status. + + + + + + + Identifier returned on external-remember-me-opt-in to allow the merchant to request + bypass of PayPal login + + + + + + + The immutable_id is the user's unique value per merchant that should never ever change for that account. + This would be the key used to uniquely identify the user + + + + + + + + + + Contains elements that allows customization of display (user interface) elements. + + + + + + Optional URL to pay button image for the inline checkout flow. Currently applicable + only to the inline checkout flow when the FlowControlDetails/InlineReturnURL is present. + + + + + + + + + + Contains elements that allow tracking for an external partner. + + + + + + PayPal will just log this string. There will NOT be any business logic around it, nor any decisions made based on the value of the string that is passed in. + From a tracking/analytical perspective, PayPal would not infer any meaning to any specific value. + We would just segment the traffic based on the value passed (Cart and None as an example) and track different + metrics like risk/conversion etc based on these segments. + The external partner would control the value of what gets passed and we take that value as is and generate data based on it.
    + Optional
    +
    +
    +
    +
    + + + + + Store ID

    Optional

    + Character length and limits: 50 single-byte characters +
    +
    +
    + + + Terminal ID

    Optional

    + Character length and limits: 50 single-byte characters +
    +
    +
    +
    +
    + + + + + + + + + + Describes discount information + + + + + + Item name

    Optional

    + Character length and limits: 127 single-byte characters +
    +
    +
    + + + description of the discount

    Optional

    + Character length and limits: 127 single-byte characters +
    +
    +
    + + + amount discounted

    Optional

    +
    +
    + + + offer type

    Optional

    +
    +
    + + + offer ID

    Optional

    + Character length and limits: 64 single-byte characters +
    +
    +
    +
    +
    + + + + Describes an individual item for an invoice. + + + + + + a human readable item name

    Optional

    + Character length and limits: 127 single-byte characters +
    +
    +
    + + + a human readable item description

    Optional

    + Character length and limits: 127 single-byte characters +
    +
    +
    + + + + The International Article Number or + Universal Product Code (UPC) for the item. + Empty string is allowed. + Character length and limits: 17 single-byte characters + + + + + + + The Stock-Keeping Unit or other identification + code assigned to the item. + Character length and limits: 64 single-byte characters + + + + + + + A retailer could apply different return policies on different items. + Each return policy would be identified using a label or identifier. + This return policy identifier should be set here. + This identifier will be displayed next to the item in the e-Receipt. + Character length and limits: 8 single-byte characters + + + + + + + total price of this item + + + + + + + price per item quantity + + + + + + + quantity of the item (non-negative) + + + + + + + Unit of measure for the itemCount + + + + + + + discount applied to this item + + + + + + + identifies whether this item is taxable or not. + If not passed, this will be assumed to be true. + + + + + + + The tax percentage applied to the item. + This is only used for displaying in the receipt, it is not used in pricing calculations. + Note: we have totalTax at invoice level. It's up to the caller to do the calculations for setting that other element. + + + + + + + Additional fees to this item + + + + + + + identifies whether this is reimbursable or not. + If not pass, this will be assumed to be true. + + + + + + + Manufacturer part number. + + + + + + + International Standard Book Number. + Reference http://en.wikipedia.org/wiki/ISBN + Character length and limits: 32 single-byte characters + + + + + + + Price Look-Up code + Reference http://en.wikipedia.org/wiki/Price_Look-Up_code + Character length and limits: 5 single-byte characters + + + + + + + Character length and limits: 32 single-byte characters + + + + + + + Character length and limits: 32 single-byte characters + + + +
    +
    + + + + + Holds refunds payment status information + + + + + + Refund status whether it is Instant or Delayed. + + + + + + + Tells us the reason when refund payment status is Delayed. + + + + + + + + + + + Defines relationship between buckets + + + + + + Relationship Type - LifeTime (default) + + + + + + + Identifier for this relation + + + + + + + + + Defines couple relationship type between buckets + + + + + + The relation between buckets are for lifetime. Any post-transaction action on one affects other as well. + + + + + + + + + Category of payment like international shipping + + + + + + Internalnation Shipping + + + + + LocalDelivery + + + + + + + + Information about Coupled Payment transactions. + + + + + + ID received in the Coupled Payment Request + + + + + ID that uniquely identifies this CoupledPayment. Generated by PP in Response + + + + + + + + This holds single key-value pair. + + + + Key Name.
    Optional
    +
    +
    + + + Value for the above key.
    Optional
    +
    +
    +
    +
    + + + + + This holds all key-value pairs which merchants wants to pass it to the open wallet(PLCC) processor. + + + + + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/changelog.md b/src/Plugins/SmartStore.PayPal/changelog.md new file mode 100644 index 0000000000..e074479a1d --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/changelog.md @@ -0,0 +1,56 @@ +#Release Notes + +##Paypal 2.6.0.5 +###Bugfixes +* PayPal PLUS: Fixes "Cannot perform runtime binding on a null reference" when rendering the payment wall. + +##Paypal 2.6.0.4 +###Bugfixes +* PayPal PLUS: Excluding tax issue. Fixes "Transaction amount details (subtotal, tax, shipping) must add up to specified amount total". + +##Paypal 2.6.0.3 +###Bugfixes +* PayPal PLUS: Integration review through PayPal +* PayPal PLUS: Generic attribute caching problem. Fixes "Item amount must add up to specified amount subtotal (or total if amount details not specified)". + +##PayPal 2.6.0.1 +###Improvements +* Added PayPal partner attribution Id as request header + +##Paypal 2.5.0.2 +###New Features +* PayPal PLUS payment provider + +##Paypal 2.5.0.1 +###Bugfixes +* PayPal Standard: The order amount transmitted to PayPal was wrong if gift cards or reward points were applied + +##Paypal 2.2.0.4 +###New Features +* Option for API security protocol +* Option to display express checkout button in mini shopping cart +* Support for partial refunds +* Option whether IPD may change the payment status of an order +###Bugfixes +* "The request was aborted: Could not create SSL/TLS secure channel." See https://devblog.paypal.com/upcoming-security-changes-notice/ +* PayPal Express: Void and refund out of function ("The transaction id is not valid") + +##Paypal 2.2.0.3 +###New Features +* Option to add order note when order total validation fails + +##PayPal 2.2.0.2 +###Improvements +* Redirecting to payment provider performed by core instead of plugin + +##Paypal 2.2.0.1 +###New Features +* Supports order list label for new incoming IPNs + +##Paypal 1.22 +###Bugfixes +* PayPal Standard provider now using shipping rather than billing address if shipping is required + +##Paypal 1.21 +###Improvements +* Multistore configuration \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/packages.config b/src/Plugins/SmartStore.PayPal/packages.config new file mode 100644 index 0000000000..eb91eb3011 --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.PayPal/web.config b/src/Plugins/SmartStore.PayPal/web.config new file mode 100644 index 0000000000..f6daa0fb4b --- /dev/null +++ b/src/Plugins/SmartStore.PayPal/web.config @@ -0,0 +1,145 @@ + + + + +
    + + + + + + + https://api.sandbox.paypal.com/2.0/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs b/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs new file mode 100644 index 0000000000..5c5e03f8ab --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Controllers/ByTotalController.cs @@ -0,0 +1,169 @@ +using System.Web.Mvc; +using SmartStore.Core.Domain.Common; +using SmartStore.Services; +using SmartStore.Services.Directory; +using SmartStore.Services.Shipping; +using SmartStore.Shipping.Domain; +using SmartStore.Shipping.Models; +using SmartStore.Shipping.Services; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using Telerik.Web.Mvc; + +namespace SmartStore.Shipping.Controllers +{ + [AdminAuthorize] + public class ByTotalController : PluginControllerBase + { + private readonly IShippingService _shippingService; + private readonly IShippingByTotalService _shippingByTotalService; + private readonly ShippingByTotalSettings _shippingByTotalSettings; + private readonly ICountryService _countryService; + private readonly AdminAreaSettings _adminAreaSettings; + private readonly ICommonServices _services; + + public ByTotalController( + IShippingService shippingService, + IShippingByTotalService shippingByTotalService, + ShippingByTotalSettings shippingByTotalSettings, + ICountryService countryService, + AdminAreaSettings adminAreaSettings, + ICommonServices services) + { + this._shippingService = shippingService; + this._shippingByTotalService = shippingByTotalService; + this._shippingByTotalSettings = shippingByTotalSettings; + this._countryService = countryService; + this._adminAreaSettings = adminAreaSettings; + this._services = services; + } + + public ActionResult Configure() + { + var shippingMethods = _shippingService.GetAllShippingMethods(); + if (shippingMethods.Count == 0) + { + return Content(T("Admin.Configuration.Shipping.Methods.NoMethodsLoaded")); + } + + var model = new ByTotalListModel(); + var allStores = _services.StoreService.GetAllStores(); + + foreach (var sm in shippingMethods) + { + model.AvailableShippingMethods.Add(new SelectListItem { Text = sm.Name, Value = sm.Id.ToString() }); + } + + //stores + model.AvailableStores.Add(new SelectListItem { Text = "*", Value = "0" }); + foreach (var store in allStores) + { + model.AvailableStores.Add(new SelectListItem { Text = store.Name, Value = store.Id.ToString() }); + } + + //model.AvailableCountries.Add(new SelectListItem { Text = "*", Value = "0" }); + var countries = _countryService.GetAllCountries(true); + foreach (var c in countries) + { + model.AvailableCountries.Add(new SelectListItem { Text = c.Name, Value = c.Id.ToString() }); + } + + model.LimitMethodsToCreated = _shippingByTotalSettings.LimitMethodsToCreated; + model.SmallQuantityThreshold = _shippingByTotalSettings.SmallQuantityThreshold; + model.SmallQuantitySurcharge = _shippingByTotalSettings.SmallQuantitySurcharge; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; + model.GridPageSize = _adminAreaSettings.GridPageSize; + + return View(model); + } + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult RatesList(GridCommand command) + { + int totalCount; + var data = _shippingByTotalService.GetShippingByTotalModels(command.Page - 1, command.PageSize, out totalCount); + + var model = new GridModel + { + Data = data, + Total = totalCount + }; + + return new JsonResult + { + Data = model + }; + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult RateUpdate(ByTotalModel model, GridCommand command) + { + if (!ModelState.IsValid) + { + return new JsonResult { Data = T("Admin.Common.UnknownError").Text }; + } + + var shippingByTotalRecord = _shippingByTotalService.GetShippingByTotalRecordById(model.Id); + + shippingByTotalRecord.Zip = model.Zip == "*" ? null : model.Zip; + shippingByTotalRecord.From = model.From; + shippingByTotalRecord.To = model.To; + shippingByTotalRecord.UsePercentage = model.UsePercentage; + shippingByTotalRecord.ShippingChargeAmount = model.ShippingChargeAmount; + shippingByTotalRecord.ShippingChargePercentage = model.ShippingChargePercentage; + shippingByTotalRecord.BaseCharge = model.BaseCharge; + shippingByTotalRecord.MaxCharge = model.MaxCharge; + + _shippingByTotalService.UpdateShippingByTotalRecord(shippingByTotalRecord); + + return RatesList(command); + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult RateDelete(int id, GridCommand command) + { + var shippingByTotalRecord = _shippingByTotalService.GetShippingByTotalRecordById(id); + if (shippingByTotalRecord != null) + { + _shippingByTotalService.DeleteShippingByTotalRecord(shippingByTotalRecord); + } + return RatesList(command); + } + + [HttpPost] + public ActionResult AddShippingRate(ByTotalListModel model) + { + var shippingByTotalRecord = new ShippingByTotalRecord + { + StoreId = model.AddStoreId, + ShippingMethodId = model.AddShippingMethodId, + CountryId = model.AddCountryId, + StateProvinceId = model.AddStateProvinceId, + Zip = model.AddZip, + From = model.AddFrom, + To = model.AddTo, + UsePercentage = model.AddUsePercentage, + ShippingChargePercentage = (model.AddUsePercentage) ? model.AddShippingChargePercentage : 0, + ShippingChargeAmount = (model.AddUsePercentage) ? 0 : model.AddShippingChargeAmount, + BaseCharge = model.AddBaseCharge, + MaxCharge = model.AddMaxCharge + }; + _shippingByTotalService.InsertShippingByTotalRecord(shippingByTotalRecord); + + return Json(new { Result = true }); + } + + [HttpPost] + public ActionResult SaveGeneralSettings(ByTotalListModel model) + { + //save settings + _shippingByTotalSettings.LimitMethodsToCreated = model.LimitMethodsToCreated; + _shippingByTotalSettings.SmallQuantityThreshold = model.SmallQuantityThreshold; + _shippingByTotalSettings.SmallQuantitySurcharge = model.SmallQuantitySurcharge; + + _services.Settings.SaveSetting(_shippingByTotalSettings); + + return Json(new { Result = true }); + } + } +} diff --git a/src/Plugins/SmartStore.Shipping/Controllers/FixedRateController.cs b/src/Plugins/SmartStore.Shipping/Controllers/FixedRateController.cs new file mode 100644 index 0000000000..353bafe59d --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Controllers/FixedRateController.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Web.Mvc; +using SmartStore.Shipping.Models; +using SmartStore.Services.Configuration; +using SmartStore.Services.Shipping; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using Telerik.Web.Mvc; + +namespace SmartStore.Shipping.Controllers +{ + [AdminAuthorize] + public class FixedRateController : PluginControllerBase + { + private readonly IShippingService _shippingService; + private readonly ISettingService _settingService; + + public FixedRateController(IShippingService shippingServicee, ISettingService settingService) + { + this._shippingService = shippingServicee; + this._settingService = settingService; + } + + public ActionResult Configure() + { + var shippingMethods = _shippingService.GetAllShippingMethods(); + if (shippingMethods.Count == 0) + return Content(T("Admin.Configuration.Shipping.Methods.NoMethodsLoaded")); + + var tmp = new List(); + foreach (var shippingMethod in shippingMethods) + tmp.Add(new FixedRateModel() + { + ShippingMethodId = shippingMethod.Id, + ShippingMethodName = shippingMethod.Name, + Rate = GetShippingRate(shippingMethod.Id) + }); + + var gridModel = new GridModel + { + Data = tmp, + Total = tmp.Count + }; + + return View(gridModel); + } + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult Configure(GridCommand command) + { + var tmp = new List(); + foreach (var shippingMethod in _shippingService.GetAllShippingMethods()) + tmp.Add(new FixedRateModel() + { + ShippingMethodId = shippingMethod.Id, + ShippingMethodName = shippingMethod.Name, + Rate = GetShippingRate(shippingMethod.Id) + }); + + var tmp2 = tmp.ForCommand(command); + var gridModel = new GridModel + { + Data = tmp2, + Total = tmp2.Count() + }; + return new JsonResult + { + Data = gridModel + }; + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult ShippingRateUpdate(FixedRateModel model, GridCommand command) + { + int shippingMethodId = model.ShippingMethodId; + decimal rate = model.Rate; + + if (shippingMethodId != 0) + { + _settingService.SetSetting(string.Format("ShippingRateComputationMethod.FixedRate.Rate.ShippingMethodId{0}", shippingMethodId), rate); + } + + var tmp = new List(); + foreach (var shippingMethod in _shippingService.GetAllShippingMethods()) + tmp.Add(new FixedRateModel() + { + ShippingMethodId = shippingMethod.Id, + ShippingMethodName = shippingMethod.Name, + Rate = GetShippingRate(shippingMethod.Id) + }); + + var tmp2 = tmp.ForCommand(command); + var gridModel = new GridModel + { + Data = tmp2, + Total = tmp2.Count() + }; + return new JsonResult + { + Data = gridModel + }; + } + + [NonAction] + protected decimal GetShippingRate(int shippingMethodId) + { + decimal rate = this._settingService.GetSettingByKey(string.Format("ShippingRateComputationMethod.FixedRate.Rate.ShippingMethodId{0}", shippingMethodId)); + return rate; + } + } +} diff --git a/src/Plugins/SmartStore.Shipping/Data/ByTotalObjectContext.cs b/src/Plugins/SmartStore.Shipping/Data/ByTotalObjectContext.cs new file mode 100644 index 0000000000..0be8d23f05 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Data/ByTotalObjectContext.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Data.Entity; +using System.Data.Entity.Infrastructure; +using System.Data.Entity.Migrations; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Data; +using SmartStore.Data.Setup; +using SmartStore.Shipping.Data.Migrations; + +namespace SmartStore.Shipping.Data +{ + + /// + /// Object context + /// + public class ByTotalObjectContext : ObjectContextBase + { + public const string ALIASKEY = "sm_object_context_shipping_by_total"; + + static ByTotalObjectContext() + { + var initializer = new MigrateDatabaseInitializer + { + TablesToCheck = new[] { "ShippingByTotal"} + }; + Database.SetInitializer(initializer); + } + + /// + /// For tooling support, e.g. EF Migrations + /// + public ByTotalObjectContext() + : base() + { + } + + public ByTotalObjectContext(string nameOrConnectionString) + : base(nameOrConnectionString, ALIASKEY) + { + } + + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + modelBuilder.Configurations.Add(new ByTotalRecordMap()); + + //disable EdmMetadata generation + //modelBuilder.Conventions.Remove(); + base.OnModelCreating(modelBuilder); + } + + } +} diff --git a/src/Plugins/SmartStore.Shipping/Data/ByTotalRecordMap.cs b/src/Plugins/SmartStore.Shipping/Data/ByTotalRecordMap.cs new file mode 100644 index 0000000000..42db4fd8be --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Data/ByTotalRecordMap.cs @@ -0,0 +1,16 @@ +using System.Data.Entity.ModelConfiguration; +using SmartStore.Shipping.Domain; + +namespace SmartStore.Shipping.Data +{ + public class ByTotalRecordMap : EntityTypeConfiguration + { + public ByTotalRecordMap() + { + this.ToTable("ShippingByTotal"); + this.HasKey(x => x.Id); + + this.Property(x => x.Zip).IsOptional().HasMaxLength(400); + } + } +} diff --git a/src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.Designer.cs b/src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.Designer.cs similarity index 92% rename from src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.Designer.cs rename to src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.Designer.cs index f5b410f0ae..8386aa1f45 100644 --- a/src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.Designer.cs +++ b/src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.Designer.cs @@ -1,5 +1,5 @@ // -namespace SmartStore.Plugin.Shipping.ByTotal.Data.Migrations +namespace SmartStore.Shipping.Data.Migrations { using System.CodeDom.Compiler; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.cs b/src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.cs similarity index 90% rename from src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.cs rename to src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.cs index d89199f32d..6f4f55e237 100644 --- a/src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.cs +++ b/src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.cs @@ -1,4 +1,4 @@ -namespace SmartStore.Plugin.Shipping.ByTotal.Data.Migrations +namespace SmartStore.Shipping.Data.Migrations { using System; using System.Data.Entity.Migrations; @@ -9,7 +9,7 @@ public partial class Initial : DbMigration { public override void Up() { - if (DbMigrationContext.Current.SuppressInitialCreate()) + if (DbMigrationContext.Current.SuppressInitialCreate()) return; CreateTable( diff --git a/src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.resx b/src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.resx similarity index 100% rename from src/Plugins/Shipping.ByTotal/Data/Migrations/201403072202413_Initial.resx rename to src/Plugins/SmartStore.Shipping/Data/Migrations/201403072202413_Initial.resx diff --git a/src/Plugins/SmartStore.Shipping/Data/Migrations/Configuration.cs b/src/Plugins/SmartStore.Shipping/Data/Migrations/Configuration.cs new file mode 100644 index 0000000000..5a33487b47 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Data/Migrations/Configuration.cs @@ -0,0 +1,33 @@ +namespace SmartStore.Shipping.Data.Migrations +{ + using System; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using System.Linq; + + internal sealed class Configuration : DbMigrationsConfiguration + { + public Configuration() + { + AutomaticMigrationsEnabled = false; + MigrationsDirectory = @"Data\Migrations"; + ContextKey = "SmartStore.ShippingByTotal"; + } + + protected override void Seed(ByTotalObjectContext context) + { + // This method will be called after migrating to the latest version. + + // You can use the DbSet.AddOrUpdate() helper extension method + // to avoid creating duplicate seed data. E.g. + // + // context.People.AddOrUpdate( + // p => p.FullName, + // new Person { FullName = "Andrew Peters" }, + // new Person { FullName = "Brice Lambson" }, + // new Person { FullName = "Rowan Miller" } + // ); + // + } + } +} diff --git a/src/Plugins/SmartStore.Shipping/DependencyRegistrar.cs b/src/Plugins/SmartStore.Shipping/DependencyRegistrar.cs new file mode 100644 index 0000000000..f216b00c95 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/DependencyRegistrar.cs @@ -0,0 +1,41 @@ +using Autofac; +using Autofac.Core; +using Autofac.Integration.Mvc; +using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.Data; +using SmartStore.Shipping.Data; +using SmartStore.Shipping.Domain; +using SmartStore.Shipping.Services; + +namespace SmartStore.Shipping +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + + //data layer + //register named context + builder.Register(c => new ByTotalObjectContext(DataSettings.Current.DataConnectionString)) + .Named(ByTotalObjectContext.ALIASKEY) + .InstancePerRequest(); + + builder.Register(c => new ByTotalObjectContext(DataSettings.Current.DataConnectionString)) + .InstancePerRequest(); + + //override required repository with our custom context + builder.RegisterType>() + .As>() + .WithParameter(ResolvedParameter.ForNamed(ByTotalObjectContext.ALIASKEY)) + .InstancePerRequest(); + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.Shipping/Description.txt b/src/Plugins/SmartStore.Shipping/Description.txt new file mode 100644 index 0000000000..f241173e84 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Description.txt @@ -0,0 +1,9 @@ +FriendlyName: Shipping +Description: Provides shipping methods for fixed rate shipping and computation based on weight. +SystemName: SmartStore.Shipping +Group: Shipping +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 1 +FileName: SmartStore.Shipping.dll +ResourceRootKey: Plugins.SmartStore.Shipping \ No newline at end of file diff --git a/src/Plugins/Shipping.ByTotal/Domain/ShippingByTotalRecord.cs b/src/Plugins/SmartStore.Shipping/Domain/ShippingByTotalRecord.cs similarity index 97% rename from src/Plugins/Shipping.ByTotal/Domain/ShippingByTotalRecord.cs rename to src/Plugins/SmartStore.Shipping/Domain/ShippingByTotalRecord.cs index dbd767d6d9..e5ebabffe9 100644 --- a/src/Plugins/Shipping.ByTotal/Domain/ShippingByTotalRecord.cs +++ b/src/Plugins/SmartStore.Shipping/Domain/ShippingByTotalRecord.cs @@ -1,6 +1,6 @@ using SmartStore.Core; -namespace SmartStore.Plugin.Shipping.ByTotal.Domain +namespace SmartStore.Shipping.Domain { /// /// Represents a shipping by total record diff --git a/src/Plugins/SmartStore.Shipping/Localization/resources.de-de.xml b/src/Plugins/SmartStore.Shipping/Localization/resources.de-de.xml new file mode 100644 index 0000000000..259ba4ecd4 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Localization/resources.de-de.xml @@ -0,0 +1,126 @@ + + + + Versandarten + + + Stellt Versandarten für Versand mit festen Preisen und basierend auf Gewicht zur Verfügung. + + + + Versand nach Gesamtsumme + + + + + Neue Versandbedingung hinzufügen + + + Optionen + + + + Land + + + Das Bestimmungsland. Wählen Sie Stern (*), wenn das Land des Kunden bei der Auswertung keine Rolle spielen soll. + + + Region + + + Bundesland/Region/Kanton des Kunden. Wählen Sie Stern (*), wenn die Gebühr unabhängig von Region für alle Kunden im definierten Land gelten soll. + + + PLZ-(Bereich) + + + PLZ-(Bereich) des Kunden, entweder als spezifische Werte (getrennt durch Komma) oder als Muster (z.B. 4000-49999 für das PLZ-Gebiet 4). In einem Muster lassen sich auch Wildcards verwenden, wie Stern (*) oder Fragezeichen (?). Sie können auch mehrere Wildcards angeben (durch Komma getrennt). Lassen Sie das Feld leer, wenn die Gebühr unabhängig von PLZ für alle Kunden im definierten (Bundes)land gelten soll. + + + Versandart + + + Die Versandart, bei der diese Berechnungsmethode angewandt werden soll. + + + Bestellwert von + + + Die Bedingung trifft zu, wenn der Bestellwert im Warenkorb mind. diesen Wert aufweist. + + + Bestellwert bis + + + Die Bedingung trifft zu, wenn der Bestellwert im Warenkorb kleiner als dieser Wert ist. Lassen Sie das Feld leer, wenn Sie keine Obergrenze festlegen möchten. + + + Prozentual + + + Legt fest, ob die Versandgebühr prozentual vom Bestellwert berechnet werden soll. + + + Gebühr % + + + + Gebühr + + + Die Versandgebühr als absoluter Betrag + + + Kein 'Fallback' anbieten + + + Dem Kunden wird während des Checkouts kostenloser Versand als Fallback angeboten, wenn keine der festgelegten Bedingungen zutreffen. Aktivieren Sie diese Option, wenn das nicht gewünscht ist. + + + + Basisgebühr + + + Max. Gebühr + + + Ein Betrag, den die berechneten Versandkosten nicht übersteigen dürfen. + + + Mindermenge bis Bestellwert + + + Warenwert, bis zu dem ein Mindermengenzuschlag erhoben werden soll. Der Zuschlag wird ignoriert, wenn keine Versandkosten anfallen. Verwenden Sie "0", wenn kein Zuschlag erhoben werden soll. + + + Mindermengenzuschlag + + + Mindermengenzuschlag + + + Shop + + + Wird das Sternchen ausgewählt, so wird die Rate auf alle Shops angewandt. + + + + + + Versand zum Festpreis + + + + + Name der Versandart + + + Gebühr + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Shipping/Localization/resources.en-us.xml b/src/Plugins/SmartStore.Shipping/Localization/resources.en-us.xml new file mode 100644 index 0000000000..e229ab4d46 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Localization/resources.en-us.xml @@ -0,0 +1,128 @@ + + + + Shipping methods + + + Provides shipping methods for fixed rate shipping and computation based on weight. + + + + Shipping by total + + + + + + Add new record + + + Settings + + + + Country + + + If an asterisk is selected, then this shipping rate will apply to all customers, regardless of the country. + + + State / province + + + If an asterisk is selected, then this shipping rate will apply to all customers from the given country, regardless of the state / province. + + + Zip-(Range) + + + Zip/postal code (range), either as specific values (comma devided) or range pattern (e.g. 4000-4999). You can also define wildcard chars like * or ?. If zip is empty, then this shipping rate will apply to all customers from the given country or state / province, regardless of the zip code. You can also enter multiple ranges (comma devided) + + + Shipping method + + + The shipping method. + + + Order total from + + + Order total from + + + Order total to + + + Order total to + + + Use percentage + + + Check the box to use 'charge percentage' value. + + + Charge % + + + Charge percentage (of subtotal) + + + Charge + + + Charge amount + + + Limit shipping methods to configured ones + + + If you check this option, then your customers will be limited to shipping options configured here. Otherwise, they'll be able to choose any existing shipping options even if they're not configured here (zero shipping fee in this case). + + + + Base fee + + + Max. fee + + + An amount that the calculated shipping costs may not exceed. + + + Threshold for small quantities + + + Subtotal up to which a "small quantity surcharge" should be added. The surcharge will be ignored if no shipping fee is applied. Use "0" if no fee will be charged. + + + Surcharge for small quantities + + + Surcharge for small quantities + + + Store + + + If an asterisk is selected, then this shipping rate will apply to all stores. + + + + + + Fixed rate shipping + + + + + + Shipping method name + + + Rate + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Shipping/Models/ByTotalListModel.cs b/src/Plugins/SmartStore.Shipping/Models/ByTotalListModel.cs new file mode 100644 index 0000000000..848836b1af --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Models/ByTotalListModel.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Shipping.Models +{ + public class ByTotalListModel : ModelBase + { + public ByTotalListModel() + { + AvailableCountries = new List(); + AvailableStates = new List(); + AvailableShippingMethods = new List(); + AvailableStores = new List(); + } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Store")] + public int AddStoreId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Country")] + public int? AddCountryId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.StateProvince")] + public int? AddStateProvinceId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Zip")] + public string AddZip { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingMethod")] + public int AddShippingMethodId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.From")] + public decimal AddFrom { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.To")] + public decimal? AddTo { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.UsePercentage")] + public bool AddUsePercentage { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargePercentage")] + public decimal AddShippingChargePercentage { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargeAmount")] + public decimal AddShippingChargeAmount { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.BaseCharge")] + public decimal AddBaseCharge { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.MaxCharge")] + public decimal AddMaxCharge { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.MaxCharge")] + public decimal? MaxCharge { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.LimitMethodsToCreated")] + public bool LimitMethodsToCreated { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.SmallQuantityThreshold")] + public decimal SmallQuantityThreshold { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.SmallQuantitySurcharge")] + public decimal SmallQuantitySurcharge { get; set; } + + public string PrimaryStoreCurrencyCode { get; set; } + + public int GridPageSize { get; set; } + + public IList AvailableCountries { get; set; } + public IList AvailableStates { get; set; } + public IList AvailableShippingMethods { get; set; } + public IList AvailableStores { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.Shipping/Models/ByTotalModel.cs b/src/Plugins/SmartStore.Shipping/Models/ByTotalModel.cs new file mode 100644 index 0000000000..dc7a5108cc --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Models/ByTotalModel.cs @@ -0,0 +1,56 @@ +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Shipping.Models +{ + public class ByTotalModel : EntityModelBase + { + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Store")] + public int StoreId { get; set; } + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Store")] + public string StoreName { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Country")] + public int? CountryId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Country")] + public string CountryName { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.StateProvince")] + public int? StateProvinceId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.StateProvince")] + public string StateProvinceName { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.Zip")] + public string Zip { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingMethod")] + public int ShippingMethodId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingMethod")] + public string ShippingMethodName { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.From")] + public decimal From { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.To")] + public decimal? To { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.UsePercentage")] + public bool UsePercentage { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargePercentage")] + public decimal ShippingChargePercentage { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.ShippingChargeAmount")] + public decimal ShippingChargeAmount { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.BaseCharge")] + public decimal BaseCharge { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.ByTotal.Fields.MaxCharge")] + public decimal? MaxCharge { get; set; } + + } +} diff --git a/src/Plugins/SmartStore.Shipping/Models/FixedRateModel.cs b/src/Plugins/SmartStore.Shipping/Models/FixedRateModel.cs new file mode 100644 index 0000000000..f2d4fa153f --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Models/FixedRateModel.cs @@ -0,0 +1,15 @@ +using SmartStore.Web.Framework; + +namespace SmartStore.Shipping.Models +{ + public class FixedRateModel + { + public int ShippingMethodId { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.FixedRateShipping.Fields.ShippingMethodName")] + public string ShippingMethodName { get; set; } + + [SmartResourceDisplayName("Plugins.Shipping.FixedRateShipping.Fields.Rate")] + public decimal Rate { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.Shipping/Plugin.cs b/src/Plugins/SmartStore.Shipping/Plugin.cs new file mode 100644 index 0000000000..30eedb06c3 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Plugin.cs @@ -0,0 +1,80 @@ +using System; +using System.Data.Entity.Migrations; +using System.Web.Routing; +using SmartStore.Core; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Plugins; +using SmartStore.Shipping.Data; +using SmartStore.Shipping.Data.Migrations; +using SmartStore.Shipping.Services; +using SmartStore.Services.Catalog; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; +using SmartStore.Core.Logging; +using SmartStore.Services.Shipping; +using SmartStore.Services.Shipping.Tracking; + +namespace SmartStore.Shipping +{ + public class Plugin : BasePlugin + { + private readonly ILogger _logger; + private readonly ISettingService _settingService; + private readonly ILocalizationService _localizationService; + private readonly ByTotalObjectContext _objectContext; + + /// + /// Ctor + /// + /// Logger + /// /// Settings service + /// /// Localization service + public Plugin(ILogger logger, + ISettingService settingService, + ILocalizationService localizationService, + ByTotalObjectContext objectContext) + { + this._logger = logger; + this._settingService = settingService; + this._localizationService = localizationService; + this._objectContext = objectContext; + } + + /// + /// Install the plugin + /// + public override void Install() + { + var shippingByTotalSettings = new ShippingByTotalSettings() + { + LimitMethodsToCreated = false, + SmallQuantityThreshold = 0, + SmallQuantitySurcharge = 0 + }; + _settingService.SaveSetting(shippingByTotalSettings); + + _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + + _logger.Information(string.Format("Plugin installed: SystemName: {0}, Version: {1}, Description: '{2}'", PluginDescriptor.SystemName, PluginDescriptor.Version, PluginDescriptor.FriendlyName)); + } + + /// + /// Uninstall the plugin + /// + public override void Uninstall() + { + _settingService.DeleteSetting(); + + _localizationService.DeleteLocaleStringResources(PluginDescriptor.ResourceRootKey); + + var migrator = new DbMigrator(new Configuration()); + migrator.Update(DbMigrator.InitialDatabase); + + _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Shipping.FixedRateShipping", false); + + base.Uninstall(); + } + } +} diff --git a/src/Plugins/SmartStore.Shipping/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.Shipping/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..bb178026bc --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.Shipping")] diff --git a/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs new file mode 100644 index 0000000000..82ec989cf4 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Providers/ByTotalProvider.cs @@ -0,0 +1,258 @@ +using System; +using System.Web.Routing; +using SmartStore.Core; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Core.Plugins; +using SmartStore.Services.Catalog; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; +using SmartStore.Services.Shipping; +using SmartStore.Services.Shipping.Tracking; +using SmartStore.Shipping.Services; + +namespace SmartStore.Shipping +{ + [SystemName("Shipping.ByTotal")] + [FriendlyName("Shipping by total")] + [DisplayOrder(1)] + public class ByTotalProvider : IShippingRateComputationMethod, IConfigurable + { + private readonly IShippingService _shippingService; + private readonly IStoreContext _storeContext; + private readonly IShippingByTotalService _shippingByTotalService; + private readonly ShippingByTotalSettings _shippingByTotalSettings; + private readonly IPriceCalculationService _priceCalculationService; + private readonly ILogger _logger; + private readonly ISettingService _settingService; + private readonly ILocalizationService _localizationService; + + /// + /// Ctor + /// + /// Shipping service + /// ShippingByTotal service + /// ShippingByTotal settings + /// ShippingByTotal object context + /// PriceCalculation service + /// Settings service + /// Logger + public ByTotalProvider(IShippingService shippingService, + IStoreContext storeContext, + IShippingByTotalService shippingByTotalService, + ShippingByTotalSettings shippingByTotalSettings, + IPriceCalculationService priceCalculationService, + ILogger logger, + ISettingService settingService, + ILocalizationService localizationService) + { + this._shippingService = shippingService; + this._storeContext = storeContext; + this._shippingByTotalService = shippingByTotalService; + this._shippingByTotalSettings = shippingByTotalSettings; + this._priceCalculationService = priceCalculationService; + this._logger = logger; + this._settingService = settingService; + this._localizationService = localizationService; + + T = NullLocalizer.Instance; + } + + #region Properties + + public Localizer T { get; set; } + + /// + /// Gets a shipping rate computation method type + /// + public ShippingRateComputationMethodType ShippingRateComputationMethodType + { + get + { + return ShippingRateComputationMethodType.Offline; + } + } + + #endregion + + #region Utilities + + /// + /// Gets the rate for the shipping method + /// + /// the order's subtotal + /// the shipping method identifier + /// country identifier + /// state province identifier + /// Zip code + /// the rate for the shipping method + private decimal? GetRate(decimal subtotal, int shippingMethodId, int storeId, int countryId, int stateProvinceId, string zip) + { + decimal? shippingTotal = null; + + var shippingByTotalRecord = _shippingByTotalService.FindShippingByTotalRecord(shippingMethodId, storeId, countryId, subtotal, stateProvinceId, zip); + + if (shippingByTotalRecord == null) + { + if (_shippingByTotalSettings.LimitMethodsToCreated) + { + return null; + } + else + { + return decimal.Zero; + } + } + + decimal baseCharge = shippingByTotalRecord.BaseCharge; + decimal? maxCharge = shippingByTotalRecord.MaxCharge; + + if (shippingByTotalRecord.UsePercentage && shippingByTotalRecord.ShippingChargePercentage <= decimal.Zero) + { + return baseCharge; //decimal.Zero; + } + + if (!shippingByTotalRecord.UsePercentage && shippingByTotalRecord.ShippingChargeAmount <= decimal.Zero) + { + return decimal.Zero; + } + + if (shippingByTotalRecord.UsePercentage) + { + shippingTotal = Math.Round((decimal)((((float)subtotal) * ((float)shippingByTotalRecord.ShippingChargePercentage)) / 100f), 2); + shippingTotal += baseCharge; + if (maxCharge.HasValue && maxCharge > baseCharge) + { + // shipping charge should not exceed MaxCharge + shippingTotal = Math.Min(shippingTotal.Value, maxCharge.Value); + } + } + else + { + shippingTotal = shippingByTotalRecord.ShippingChargeAmount; + } + + if (shippingTotal < decimal.Zero) + { + shippingTotal = decimal.Zero; + } + + return shippingTotal; + } + + #endregion + + #region Methods + + /// + /// Gets available shipping options + /// + /// A request for getting shipping options + /// Represents a response of getting shipping rate options + public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) + { + if (getShippingOptionRequest == null) + { + throw new ArgumentNullException("getShippingOptionRequest"); + } + + var response = new GetShippingOptionResponse(); + + if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) + { + response.AddError(T("Admin.System.Warnings.NoShipmentItems")); + return response; + } + + int countryId = 0; + int stateProvinceId = 0; + string zip = null; + decimal subTotal = decimal.Zero; + int storeId = _storeContext.CurrentStore.Id; + + if (getShippingOptionRequest.ShippingAddress != null) + { + countryId = getShippingOptionRequest.ShippingAddress.CountryId ?? 0; + stateProvinceId = getShippingOptionRequest.ShippingAddress.StateProvinceId ?? 0; + zip = getShippingOptionRequest.ShippingAddress.ZipPostalCode; + } + + foreach (var shoppingCartItem in getShippingOptionRequest.Items) + { + if (shoppingCartItem.Item.IsFreeShipping || !shoppingCartItem.Item.IsShipEnabled) + { + continue; + } + subTotal += _priceCalculationService.GetSubTotal(shoppingCartItem, true); + } + + decimal sqThreshold = _shippingByTotalSettings.SmallQuantityThreshold; + decimal sqSurcharge = _shippingByTotalSettings.SmallQuantitySurcharge; + + var shippingMethods = _shippingService.GetAllShippingMethods(getShippingOptionRequest); + foreach (var shippingMethod in shippingMethods) + { + decimal? rate = GetRate(subTotal, shippingMethod.Id, storeId, countryId, stateProvinceId, zip); + if (rate.HasValue) + { + if (rate > 0 && sqThreshold > 0 && subTotal <= sqThreshold) + { + // add small quantity surcharge (Mindermengenzuschalg) + rate += sqSurcharge; + } + + var shippingOption = new ShippingOption(); + shippingOption.ShippingMethodId = shippingMethod.Id; + shippingOption.Name = shippingMethod.Name; + shippingOption.Description = shippingMethod.Description; + shippingOption.Rate = rate.Value; + response.ShippingOptions.Add(shippingOption); + } + } + + return response; + } + + /// + /// Gets fixed shipping rate (if shipping rate computation method allows it and the rate can be calculated before checkout). + /// + /// A request for getting shipping options + /// Fixed shipping rate; or null in case there's no fixed shipping rate + public decimal? GetFixedRate(GetShippingOptionRequest getShippingOptionRequest) + { + return null; + } + + /// + /// Gets a shipment tracker + /// + public IShipmentTracker ShipmentTracker + { + get + { + return null; + } + } + + public bool IsActive + { + get { return true; } + } + + /// + /// Gets a route for provider configuration + /// + /// Action name + /// Controller name + /// Route values + public void GetConfigurationRoute(out string actionName, out string controllerName, out System.Web.Routing.RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "ByTotal"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.Shipping" } }; + } + + #endregion + } +} diff --git a/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs new file mode 100644 index 0000000000..cc303cee6e --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Providers/FixedRateProvider.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Web.Routing; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Localization; +using SmartStore.Core.Plugins; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; +using SmartStore.Services.Shipping; +using SmartStore.Services.Shipping.Tracking; + +namespace SmartStore.Shipping +{ + /// + /// Fixed rate shipping computation provider + /// + [SystemName("Shipping.FixedRate")] + [FriendlyName("Fixed Rate Shipping")] + [DisplayOrder(0)] + public class FixedRateProvider : IShippingRateComputationMethod, IConfigurable + { + private readonly ISettingService _settingService; + private readonly IShippingService _shippingService; + + public FixedRateProvider(ISettingService settingService, + IShippingService shippingService) + { + this._settingService = settingService; + this._shippingService = shippingService; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + private decimal GetRate(int shippingMethodId) + { + string key = string.Format("ShippingRateComputationMethod.FixedRate.Rate.ShippingMethodId{0}", shippingMethodId); + decimal rate = this._settingService.GetSettingByKey(key); + return rate; + } + + /// + /// Gets available shipping options + /// + /// A request for getting shipping options + /// Represents a response of getting shipping rate options + public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) + { + if (getShippingOptionRequest == null) + throw new ArgumentNullException("getShippingOptionRequest"); + + var response = new GetShippingOptionResponse(); + + if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) + { + response.AddError(T("Admin.System.Warnings.NoShipmentItems")); + return response; + } + + var shippingMethods = this._shippingService.GetAllShippingMethods(getShippingOptionRequest); + foreach (var shippingMethod in shippingMethods) + { + var shippingOption = new ShippingOption(); + shippingOption.ShippingMethodId = shippingMethod.Id; + shippingOption.Name = shippingMethod.GetLocalized(x => x.Name); + shippingOption.Description = shippingMethod.GetLocalized(x => x.Description); + shippingOption.Rate = GetRate(shippingMethod.Id); + response.ShippingOptions.Add(shippingOption); + } + + return response; + } + + /// + /// Gets fixed shipping rate (if shipping rate computation method allows it and the rate can be calculated before checkout). + /// + /// A request for getting shipping options + /// Fixed shipping rate; or null in case there's no fixed shipping rate + public decimal? GetFixedRate(GetShippingOptionRequest getShippingOptionRequest) + { + if (getShippingOptionRequest == null) + throw new ArgumentNullException("getShippingOptionRequest"); + + var shippingMethods = this._shippingService.GetAllShippingMethods(getShippingOptionRequest); + + var rates = new List(); + foreach (var shippingMethod in shippingMethods) + { + decimal rate = GetRate(shippingMethod.Id); + if (!rates.Contains(rate)) + rates.Add(rate); + } + + //return default rate if all of them equal + if (rates.Count == 1) + return rates[0]; + + return null; + } + + /// + /// Gets a route for provider configuration + /// + /// Action name + /// Controller name + /// Route values + public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "FixedRate"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.Shipping" } }; + } + + /// + /// Gets a shipping rate computation method type + /// + public ShippingRateComputationMethodType ShippingRateComputationMethodType + { + get + { + return ShippingRateComputationMethodType.Offline; + } + } + + /// + /// Gets a shipment tracker + /// + public IShipmentTracker ShipmentTracker + { + get + { + //uncomment a line below to return a general shipment tracker (finds an appropriate tracker by tracking number) + //return new GeneralShipmentTracker(EngineContext.Current.Resolve()); + return null; + } + } + + public bool IsActive + { + get { return true; } + } + } +} diff --git a/src/Plugins/SmartStore.Shipping/RouteProvider.cs b/src/Plugins/SmartStore.Shipping/RouteProvider.cs new file mode 100644 index 0000000000..38dead4bf3 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/RouteProvider.cs @@ -0,0 +1,34 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.Shipping +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.Shipping.ByTotal", + "Plugins/ShippingByTotal/{action}", + new { controller = "ByTotal", action = "Configure" }, + new[] { "SmartStore.Shipping.Controllers" } + ) + .DataTokens["area"] = "SmartStore.Shipping"; + + routes.MapRoute("SmartStore.Shipping.FixedRate", + "Plugins/FixedRate/{action}", + new { controller = "FixedRate", action = "Configure" }, + new[] { "SmartStore.Shipping.Controllers" } + ) + .DataTokens["area"] = "SmartStore.Shipping"; + } + + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/Shipping.ByTotal/Services/IShippingByTotalService.cs b/src/Plugins/SmartStore.Shipping/Services/IShippingByTotalService.cs similarity index 89% rename from src/Plugins/Shipping.ByTotal/Services/IShippingByTotalService.cs rename to src/Plugins/SmartStore.Shipping/Services/IShippingByTotalService.cs index 43450965cd..77b7a16c90 100644 --- a/src/Plugins/Shipping.ByTotal/Services/IShippingByTotalService.cs +++ b/src/Plugins/SmartStore.Shipping/Services/IShippingByTotalService.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; using SmartStore.Core; -using SmartStore.Plugin.Shipping.ByTotal.Domain; -using SmartStore.Plugin.Shipping.ByTotal.Models; +using SmartStore.Shipping.Domain; +using SmartStore.Shipping.Models; -namespace SmartStore.Plugin.Shipping.ByTotal.Services +namespace SmartStore.Shipping.Services { public partial interface IShippingByTotalService { @@ -21,7 +21,7 @@ public partial interface IShippingByTotalService /// /// Get models for shipping by total records /// - IList GetShippingByTotalModels(int pageIndex, int pageSize, out int totalCount); + IList GetShippingByTotalModels(int pageIndex, int pageSize, out int totalCount); /// /// Finds the ShippingByTotalRecord by its identifier diff --git a/src/Plugins/Shipping.ByTotal/Services/ShippingByTotalService.cs b/src/Plugins/SmartStore.Shipping/Services/ShippingByTotalService.cs similarity index 91% rename from src/Plugins/Shipping.ByTotal/Services/ShippingByTotalService.cs rename to src/Plugins/SmartStore.Shipping/Services/ShippingByTotalService.cs index bade1af9e2..a24143413c 100644 --- a/src/Plugins/Shipping.ByTotal/Services/ShippingByTotalService.cs +++ b/src/Plugins/SmartStore.Shipping/Services/ShippingByTotalService.cs @@ -3,14 +3,14 @@ using System.Linq; using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Plugin.Shipping.ByTotal.Domain; -using SmartStore.Plugin.Shipping.ByTotal.Models; +using SmartStore.Shipping.Domain; +using SmartStore.Shipping.Models; using SmartStore.Services.Directory; using SmartStore.Services.Shipping; using SmartStore.Services.Stores; using SmartStore.Utilities; -namespace SmartStore.Plugin.Shipping.ByTotal.Services +namespace SmartStore.Shipping.Services { /// /// Shipping By Total Service @@ -75,14 +75,14 @@ public virtual IPagedList GetShippingByTotalRecords(int p /// /// Get models for shipping by total records /// - public virtual IList GetShippingByTotalModels(int pageIndex, int pageSize, out int totalCount) + public virtual IList GetShippingByTotalModels(int pageIndex, int pageSize, out int totalCount) { // data join would be much better but not possible here cause ShippingByTotalObjectContext cannot be shared across repositories var records = GetShippingByTotalRecords(pageIndex, pageSize); totalCount = records.TotalCount; if (records.Count <= 0) - return new List(); + return new List(); var allStores = _storeService.GetAllStores(); @@ -93,7 +93,7 @@ public virtual IList GetShippingByTotalModels(int pageInde var country = _countryService.GetCountryById(x.CountryId ?? 0); var stateProvince = _stateProvinceService.GetStateProvinceById(x.StateProvinceId ?? 0); - var model = new ShippingByTotalModel() + var model = new ByTotalModel() { Id = x.Id, StoreId = x.StoreId, @@ -212,16 +212,26 @@ private bool ZipMatches(string zip, string pattern) { return true; // catch all } - + + var patterns = pattern.Contains(",") + ? pattern.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()) + : new string[] { pattern }; + try { - var wildcard = new Wildcard(pattern); - return wildcard.IsMatch(zip); + foreach (var entry in patterns) + { + var wildcard = new Wildcard(entry); + if (wildcard.IsMatch(zip)) + return true; + } } catch { return zip.IsCaseInsensitiveEqual(pattern); } + + return false; } /// diff --git a/src/Plugins/Shipping.ByTotal/ShippingByTotalSettings.cs b/src/Plugins/SmartStore.Shipping/Settings/ShippingByTotalSettings.cs similarity index 86% rename from src/Plugins/Shipping.ByTotal/ShippingByTotalSettings.cs rename to src/Plugins/SmartStore.Shipping/Settings/ShippingByTotalSettings.cs index c6070a6f56..3ba3e94ee9 100644 --- a/src/Plugins/Shipping.ByTotal/ShippingByTotalSettings.cs +++ b/src/Plugins/SmartStore.Shipping/Settings/ShippingByTotalSettings.cs @@ -1,6 +1,6 @@ using SmartStore.Core.Configuration; -namespace SmartStore.Plugin.Shipping.ByTotal +namespace SmartStore.Shipping { public class ShippingByTotalSettings : ISettings { diff --git a/src/Plugins/SmartStore.Shipping/SmartStore.Shipping.csproj b/src/Plugins/SmartStore.Shipping/SmartStore.Shipping.csproj new file mode 100644 index 0000000000..3a9b8863dd --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/SmartStore.Shipping.csproj @@ -0,0 +1,254 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {ACC1E122-B2C8-4441-BDED-D4A77763331A} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.Shipping + SmartStore.Shipping + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.Shipping\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.Shipping\ + TRACE + prompt + 4 + false + + + true + ..\..\Presentation\SmartStore.Web\bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + ..\..\..\lib\Telerik\Telerik.Web.Mvc.dll + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + 201403072202413_Initial.cs + + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} + SmartStore.Data + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + 201403072202413_Initial.cs + + + PreserveNewest + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + PreserveNewest + + + Designer + PreserveNewest + + + Designer + PreserveNewest + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 51377 + / + http://localhost:53076/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml b/src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml new file mode 100644 index 0000000000..ae05d59b64 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Views/ByTotal/Configure.cshtml @@ -0,0 +1,331 @@ +@{ + Layout = ""; +} +@model ByTotalListModel + +@using SmartStore.Shipping.Models; +@using SmartStore.Web.Framework; +@using Telerik.Web.Mvc.UI; +@using SmartStore.Web.Framework.UI + + + + @T("Plugins.Shipping.ByTotal.AddNewRecordTitle") + + + + + + +
    + @(Html.Telerik().Grid() + .Name("shipping-bytotal-grid") + .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) + .DataBinding(dataBinding => dataBinding + .Ajax() + .Select("RatesList", "ByTotal", new RouteValueDictionary() { { "area", "SmartStore.Shipping" } }) + .Update("RateUpdate", "ByTotal", new RouteValueDictionary() { { "area", "SmartStore.Shipping" } }) + .Delete("RateDelete", "ByTotal", new RouteValueDictionary() { { "area", "SmartStore.Shipping" } }) + ) + .Columns(columns => + { + columns.Bound(x => x.StoreName).ReadOnly(); + columns.Bound(x => x.CountryName).ReadOnly(); + columns.Bound(x => x.StateProvinceName).ReadOnly(); + columns.Bound(x => x.Zip); + columns.Bound(x => x.ShippingMethodName).ReadOnly(); + columns.Bound(x => x.From) + .Format("{0:0.00}"); + columns.Bound(x => x.To) + .Format("{0:0.00}"); + columns.Bound(x => x.UsePercentage) + .Centered() + .Template(item => @Html.SymbolForBool(item.UsePercentage)) + .ClientTemplate(@Html.SymbolForBool("UsePercentage")); + columns.Bound(x => x.ShippingChargePercentage) + .Format("{0:0.00}"); + columns.Bound(x => x.ShippingChargeAmount) + .Format("{0:0.00}"); + columns.Bound(x => x.BaseCharge) + .Format("{0:0.00}"); + columns.Bound(x => x.MaxCharge) + .Format("{0:0.00}"); + columns.Command(commands => + { + commands.Edit().Localize(T); + commands.Delete().Localize(T); + }).Width(190); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .Editable(x => x.Mode(GridEditMode.InLine)) + .PreserveGridState() + .EnableCustomBinding(true)) +
    + + + +@using (Html.BeginForm()) +{ + + + {Html.SmartStore().Window() + .Name("addrecord-window") + .Title(T("Plugins.Shipping.ByTotal.AddNewRecordTitle")) + .Content( + @ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.AddStoreId) + + @Html.DropDownListFor(model => model.AddStoreId, Model.AvailableStores) + @Html.ValidationMessageFor(model => model.AddStoreId) +
    + @Html.SmartLabelFor(model => model.AddCountryId) + + @Html.DropDownListFor(model => model.AddCountryId, Model.AvailableCountries, "*") + @Html.ValidationMessageFor(model => model.AddCountryId) +
    + @Html.SmartLabelFor(model => model.AddStateProvinceId) + + @Html.DropDownListFor(model => model.AddStateProvinceId, Model.AvailableStates, "*") + @Html.ValidationMessageFor(model => model.AddStateProvinceId) +
    + @Html.SmartLabelFor(model => model.AddZip) + + @Html.EditorFor(model => model.AddZip) + @Html.ValidationMessageFor(model => model.AddZip) +
    + @Html.SmartLabelFor(model => model.AddShippingMethodId) + + @Html.DropDownListFor(model => model.AddShippingMethodId, Model.AvailableShippingMethods) + @Html.ValidationMessageFor(model => model.AddShippingMethodId) +
    + @Html.SmartLabelFor(model => model.AddFrom) + + @Html.EditorFor(model => model.AddFrom) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.AddFrom) +
    + @Html.SmartLabelFor(model => model.AddTo) + + @Html.EditorFor(model => model.AddTo) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.AddTo) +
    + @Html.SmartLabelFor(model => model.AddUsePercentage) + + @Html.EditorFor(model => model.AddUsePercentage) + @Html.ValidationMessageFor(model => model.AddUsePercentage) +
    + @Html.SmartLabelFor(model => model.AddShippingChargePercentage) + + @Html.EditorFor(model => model.AddShippingChargePercentage) + @Html.ValidationMessageFor(model => model.AddShippingChargePercentage) +
    + @Html.SmartLabelFor(model => model.AddBaseCharge) + + @Html.EditorFor(model => model.AddBaseCharge) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.AddBaseCharge) +
    + @Html.SmartLabelFor(model => model.AddMaxCharge) + + @Html.EditorFor(model => model.AddMaxCharge) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.AddMaxCharge) +
    + @Html.SmartLabelFor(model => model.AddShippingChargeAmount) + + @Html.EditorFor(model => model.AddShippingChargeAmount) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.AddShippingChargeAmount) +
    +
    ) + .FooterContent(@ + + + ) + .Modal(true) + .Visible(false) + .Render(); + } + +
    + +
    + @T("Plugins.Shipping.ByTotal.SettingsTitle") + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.SmallQuantityThreshold) + + @Html.EditorFor(model => model.SmallQuantityThreshold) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.SmallQuantityThreshold) +
    + @Html.SmartLabelFor(model => model.SmallQuantitySurcharge) + + @Html.EditorFor(model => model.SmallQuantitySurcharge) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.SmallQuantitySurcharge) +
    + @Html.SmartLabelFor(model => model.LimitMethodsToCreated) + + @Html.EditorFor(model => model.LimitMethodsToCreated) + @Html.ValidationMessageFor(model => model.LimitMethodsToCreated) +
    +   + + +
    +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.Shipping/Views/FixedRate/Configure.cshtml b/src/Plugins/SmartStore.Shipping/Views/FixedRate/Configure.cshtml new file mode 100644 index 0000000000..db753c9db9 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Views/FixedRate/Configure.cshtml @@ -0,0 +1,39 @@ +@{ + Layout = ""; +} +@model Telerik.Web.Mvc.GridModel +@using Telerik.Web.Mvc.UI; +@using System.Linq; + + + + + +
    + @(Html.Telerik().Grid(Model.Data) + .Name("Grid") + .DataKeys(keys => keys.Add(x => x.ShippingMethodId).RouteKey("ShippingMethodId")) + .Columns(columns => + { + columns.Bound(x => x.ShippingMethodName) + .ReadOnly(); + columns.Bound(x => x.Rate) + .Format("{0:0.00}") + .Width(180); + columns.Command(commands => + { + commands.Edit(); + }).Width(180); + }) + .Editable(x => + { + x.Mode(GridEditMode.InLine); + }) + .DataBinding(dataBinding => + { + dataBinding.Ajax() + .Select("Configure", "FixedRate", new RouteValueDictionary() { { "Namespaces", "SmartStore.Shipping.Controllers" }, { "area", "SmartStore.Shipping" } }) + .Update("ShippingRateUpdate", "FixedRate", new RouteValueDictionary() { { "Namespaces", "SmartStore.Shipping.Controllers" }, { "area", "SmartStore.Shipping" } }); + }) + .EnableCustomBinding(true)) +
    diff --git a/src/Plugins/SmartStore.Shipping/Views/Web.config b/src/Plugins/SmartStore.Shipping/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.Shipping/packages.config b/src/Plugins/SmartStore.Shipping/packages.config new file mode 100644 index 0000000000..1a1ea4e95b --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Shipping/web.config b/src/Plugins/SmartStore.Shipping/web.config new file mode 100644 index 0000000000..c0f82db177 --- /dev/null +++ b/src/Plugins/SmartStore.Shipping/web.config @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/Shipping.ByWeight/ByWeightShippingComputationMethod.cs b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs similarity index 81% rename from src/Plugins/Shipping.ByWeight/ByWeightShippingComputationMethod.cs rename to src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs index d4af2e8ef0..a147a1855d 100644 --- a/src/Plugins/Shipping.ByWeight/ByWeightShippingComputationMethod.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/ByWeightShippingComputationMethod.cs @@ -3,19 +3,20 @@ using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Domain.Shipping; +using SmartStore.Core.Localization; using SmartStore.Core.Plugins; -using SmartStore.Plugin.Shipping.ByWeight.Data; -using SmartStore.Plugin.Shipping.ByWeight.Data.Migrations; -using SmartStore.Plugin.Shipping.ByWeight.Services; using SmartStore.Services; using SmartStore.Services.Catalog; using SmartStore.Services.Localization; using SmartStore.Services.Shipping; using SmartStore.Services.Shipping.Tracking; +using SmartStore.ShippingByWeight.Data; +using SmartStore.ShippingByWeight.Data.Migrations; +using SmartStore.ShippingByWeight.Services; -namespace SmartStore.Plugin.Shipping.ByWeight +namespace SmartStore.ShippingByWeight { - public class ByWeightShippingComputationMethod : BasePlugin, IShippingRateComputationMethod + public class ByWeightShippingComputationMethod : BasePlugin, IShippingRateComputationMethod, IConfigurable { #region Fields @@ -27,11 +28,12 @@ public class ByWeightShippingComputationMethod : BasePlugin, IShippingRateComput private readonly ShippingByWeightObjectContext _objectContext; private readonly ILocalizationService _localizationService; private readonly IPriceFormatter _priceFormatter; - private readonly ICommonServices _commonServices; + private readonly ICommonServices _services; #endregion #region Ctor + public ByWeightShippingComputationMethod(IShippingService shippingService, IStoreContext storeContext, IShippingByWeightService shippingByWeightService, @@ -40,7 +42,7 @@ public ByWeightShippingComputationMethod(IShippingService shippingService, ShippingByWeightObjectContext objectContext, ILocalizationService localizationService, IPriceFormatter priceFormatter, - ICommonServices commonServices) + ICommonServices services) { this._shippingService = shippingService; this._storeContext = storeContext; @@ -50,17 +52,22 @@ public ByWeightShippingComputationMethod(IShippingService shippingService, this._objectContext = objectContext; this._localizationService = localizationService; this._priceFormatter = priceFormatter; - this._commonServices = commonServices; - } - #endregion + this._services = services; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + #endregion - #region Utilities + #region Utilities - private decimal? GetRate(decimal subTotal, decimal weight, int shippingMethodId, int storeId, int countryId) + private decimal? GetRate(decimal subTotal, decimal weight, int shippingMethodId, int storeId, int countryId, string zip) { decimal? shippingTotal = null; - var shippingByWeightRecord = _shippingByWeightService.FindRecord(shippingMethodId, storeId, countryId, weight); + var shippingByWeightRecord = _shippingByWeightService.FindRecord(shippingMethodId, storeId, countryId, weight, zip); if (shippingByWeightRecord == null) { if (_shippingByWeightSettings.LimitMethodsToCreated) @@ -109,47 +116,50 @@ public ByWeightShippingComputationMethod(IShippingService shippingService, /// /// Gets available shipping options /// - /// A request for getting shipping options + /// A request for getting shipping options /// Represents a response of getting shipping rate options - public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest getShippingOptionRequest) + public GetShippingOptionResponse GetShippingOptions(GetShippingOptionRequest request) { - if (getShippingOptionRequest == null) + if (request == null) throw new ArgumentNullException("getShippingOptionRequest"); var response = new GetShippingOptionResponse(); - if (getShippingOptionRequest.Items == null || getShippingOptionRequest.Items.Count == 0) + if (request.Items == null || request.Items.Count == 0) { - response.AddError("No shipment items"); - return response; - } - if (getShippingOptionRequest.ShippingAddress == null) - { - response.AddError("Shipping address is not set"); + response.AddError(T("Admin.System.Warnings.NoShipmentItems")); return response; } + + int storeId = request.StoreId > 0 ? request.StoreId : _storeContext.CurrentStore.Id; + decimal subTotal = decimal.Zero; + int countryId = 0; + string zip = null; - var storeId = _storeContext.CurrentStore.Id; - int countryId = getShippingOptionRequest.ShippingAddress.CountryId.HasValue ? getShippingOptionRequest.ShippingAddress.CountryId.Value : 0; + if (request.ShippingAddress != null) + { + countryId = request.ShippingAddress.CountryId ?? 0; + zip = request.ShippingAddress.ZipPostalCode; + } - decimal subTotal = decimal.Zero; - foreach (var shoppingCartItem in getShippingOptionRequest.Items) + foreach (var shoppingCartItem in request.Items) { if (shoppingCartItem.Item.IsFreeShipping || !shoppingCartItem.Item.IsShipEnabled) continue; subTotal += _priceCalculationService.GetSubTotal(shoppingCartItem, true); } - decimal weight = _shippingService.GetShoppingCartTotalWeight(getShippingOptionRequest.Items); + decimal weight = _shippingService.GetShoppingCartTotalWeight(request.Items); - var shippingMethods = _shippingService.GetAllShippingMethods(countryId); + var shippingMethods = _shippingService.GetAllShippingMethods(request); foreach (var shippingMethod in shippingMethods) { - var record = _shippingByWeightService.FindRecord(shippingMethod.Id, storeId, countryId, weight); + var record = _shippingByWeightService.FindRecord(shippingMethod.Id, storeId, countryId, weight, zip); - decimal? rate = GetRate(subTotal, weight, shippingMethod.Id, storeId, countryId); + decimal? rate = GetRate(subTotal, weight, shippingMethod.Id, storeId, countryId, zip); if (rate.HasValue) { var shippingOption = new ShippingOption(); + shippingOption.ShippingMethodId = shippingMethod.Id; shippingOption.Name = shippingMethod.GetLocalized(x => x.Name); if (record != null && record.SmallQuantityThreshold > subTotal) @@ -193,7 +203,7 @@ public void GetConfigurationRoute(out string actionName, out string controllerNa { actionName = "Configure"; controllerName = "ShippingByWeight"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Shipping.ByWeight.Controllers" }, { "area", "Shipping.ByWeight" } }; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.ShippingByWeight" } }; } /// @@ -214,7 +224,7 @@ public override void Uninstall() var migrator = new DbMigrator(new Configuration()); migrator.Update(DbMigrator.InitialDatabase); - _localizationService.DeletePluginStringResources(this.PluginDescriptor); + _localizationService.DeleteLocaleStringResources(PluginDescriptor.ResourceRootKey); base.Uninstall(); } @@ -248,6 +258,11 @@ public IShipmentTracker ShipmentTracker } } + public bool IsActive + { + get { return true; } + } + #endregion } } diff --git a/src/Plugins/Shipping.ByWeight/icon.png b/src/Plugins/SmartStore.ShippingByWeight/Content/icon.png similarity index 100% rename from src/Plugins/Shipping.ByWeight/icon.png rename to src/Plugins/SmartStore.ShippingByWeight/Content/icon.png diff --git a/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs b/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs new file mode 100644 index 0000000000..383d77dfa2 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Controllers/ShippingByWeightController.cs @@ -0,0 +1,175 @@ +using System.Web.Mvc; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Directory; +using SmartStore.Services; +using SmartStore.Services.Directory; +using SmartStore.Services.Shipping; +using SmartStore.ShippingByWeight.Domain; +using SmartStore.ShippingByWeight.Models; +using SmartStore.ShippingByWeight.Services; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Security; +using Telerik.Web.Mvc; + +namespace SmartStore.ShippingByWeight.Controllers +{ + + [AdminAuthorize] + public class ShippingByWeightController : PluginControllerBase + { + private readonly IShippingService _shippingService; + private readonly ICountryService _countryService; + private readonly ShippingByWeightSettings _shippingByWeightSettings; + private readonly IShippingByWeightService _shippingByWeightService; + private readonly IMeasureService _measureService; + private readonly MeasureSettings _measureSettings; + private readonly AdminAreaSettings _adminAreaSettings; + private readonly ICommonServices _services; + + public ShippingByWeightController( + IShippingService shippingService, + ICountryService countryService, + ShippingByWeightSettings shippingByWeightSettings, + IShippingByWeightService shippingByWeightService, + IMeasureService measureService, + MeasureSettings measureSettings, + AdminAreaSettings adminAreaSettings, + ICommonServices services) + { + this._shippingService = shippingService; + this._countryService = countryService; + this._shippingByWeightSettings = shippingByWeightSettings; + this._shippingByWeightService = shippingByWeightService; + this._measureService = measureService; + this._measureSettings = measureSettings; + this._adminAreaSettings = adminAreaSettings; + this._services = services; + } + + public ActionResult Configure() + { + var shippingMethods = _shippingService.GetAllShippingMethods(); + if (shippingMethods.Count == 0) + { + return Content(T("Admin.Configuration.Shipping.Methods.NoMethodsLoaded")); + } + + var model = new ShippingByWeightListModel(); + var countries = _countryService.GetAllCountries(true); + var allStores = _services.StoreService.GetAllStores(); + + foreach (var sm in shippingMethods) + { + model.AvailableShippingMethods.Add(new SelectListItem { Text = sm.Name, Value = sm.Id.ToString() }); + } + + //stores + model.AvailableStores.Add(new SelectListItem { Text = "*", Value = "0" }); + foreach (var store in allStores) + { + model.AvailableStores.Add(new SelectListItem { Text = store.Name, Value = store.Id.ToString() }); + } + + model.AvailableCountries.Add(new SelectListItem { Text = "*", Value = "0" }); + foreach (var c in countries) + { + model.AvailableCountries.Add(new SelectListItem { Text = c.Name, Value = c.Id.ToString() }); + } + + model.LimitMethodsToCreated = _shippingByWeightSettings.LimitMethodsToCreated; + model.CalculatePerWeightUnit = _shippingByWeightSettings.CalculatePerWeightUnit; + model.PrimaryStoreCurrencyCode = _services.StoreContext.CurrentStore.PrimaryStoreCurrency.CurrencyCode; + model.BaseWeightIn = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId).Name; + model.GridPageSize = _adminAreaSettings.GridPageSize; + + return View(model); + } + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult RatesList(GridCommand command) + { + int totalCount; + var data = _shippingByWeightService.GetShippingByWeightModels(command.Page - 1, command.PageSize, out totalCount); + + var model = new GridModel + { + Data = data, + Total = totalCount + }; + + return new JsonResult + { + Data = model + }; + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult RateUpdate(ShippingByWeightModel model, GridCommand command) + { + var sbw = _shippingByWeightService.GetById(model.Id); + sbw.From = model.From; + sbw.To = model.To; + sbw.UsePercentage = model.UsePercentage; + sbw.Zip = model.Zip == "*" ? null : model.Zip; + sbw.ShippingChargeAmount = model.ShippingChargeAmount; + sbw.ShippingChargePercentage = model.ShippingChargePercentage; + sbw.SmallQuantitySurcharge = model.SmallQuantitySurcharge; + sbw.SmallQuantityThreshold = model.SmallQuantityThreshold; + _shippingByWeightService.UpdateShippingByWeightRecord(sbw); + + return RatesList(command); + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult RateDelete(int id, GridCommand command) + { + var sbw = _shippingByWeightService.GetById(id); + _shippingByWeightService.DeleteShippingByWeightRecord(sbw); + + return RatesList(command); + } + + [HttpPost, ActionName("Configure")] + [FormValueRequired("addshippingbyweightrecord")] + public ActionResult AddShippingByWeightRecord(ShippingByWeightListModel model) + { + if (!ModelState.IsValid) + { + return Configure(); + } + + var sbw = new ShippingByWeightRecord() + { + StoreId = model.AddStoreId, + ShippingMethodId = model.AddShippingMethodId, + CountryId = model.AddCountryId, + Zip = model.AddZip, + //StateProvinceId = 0, + From = model.AddFrom, + To = model.AddTo, + UsePercentage = model.AddUsePercentage, + ShippingChargeAmount = model.AddShippingChargeAmount, + ShippingChargePercentage = model.AddShippingChargePercentage, + SmallQuantitySurcharge = model.SmallQuantitySurcharge, + SmallQuantityThreshold = model.SmallQuantityThreshold, + }; + _shippingByWeightService.InsertShippingByWeightRecord(sbw); + + return Configure(); + } + + [HttpPost, ActionName("Configure")] + [FormValueRequired("savegeneralsettings")] + public ActionResult SaveGeneralSettings(ShippingByWeightListModel model) + { + //save settings + _shippingByWeightSettings.LimitMethodsToCreated = model.LimitMethodsToCreated; + _shippingByWeightSettings.CalculatePerWeightUnit = model.CalculatePerWeightUnit; + _services.Settings.SaveSetting(_shippingByWeightSettings); + + return Configure(); + } + + } +} diff --git a/src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.Designer.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.Designer.cs similarity index 92% rename from src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.Designer.cs rename to src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.Designer.cs index 86822185b5..d06c8e7abc 100644 --- a/src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.Designer.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.Designer.cs @@ -1,5 +1,5 @@ // -namespace SmartStore.Plugin.Shipping.ByWeight.Data.Migrations +namespace SmartStore.ShippingByWeight.Data.Migrations { using System.CodeDom.Compiler; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.cs similarity index 95% rename from src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.cs rename to src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.cs index 9228c9e69c..3dd72e9084 100644 --- a/src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.cs @@ -1,4 +1,4 @@ -namespace SmartStore.Plugin.Shipping.ByWeight.Data.Migrations +namespace SmartStore.ShippingByWeight.Data.Migrations { using System; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.resx b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.resx similarity index 100% rename from src/Plugins/Shipping.ByWeight/Data/Migrations/201403080200108_Initial.resx rename to src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201403080200108_Initial.resx diff --git a/src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.Designer.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.Designer.cs similarity index 92% rename from src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.Designer.cs rename to src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.Designer.cs index c31d63e709..521e42a576 100644 --- a/src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.Designer.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.Designer.cs @@ -1,5 +1,5 @@ // -namespace SmartStore.Plugin.Shipping.ByWeight.Data.Migrations +namespace SmartStore.ShippingByWeight.Data.Migrations { using System.CodeDom.Compiler; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.cs similarity index 97% rename from src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.cs rename to src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.cs index 75fc09a666..e52b85492a 100644 --- a/src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.cs @@ -1,4 +1,4 @@ -namespace SmartStore.Plugin.Shipping.ByWeight.Data.Migrations +namespace SmartStore.ShippingByWeight.Data.Migrations { using System; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.resx b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.resx similarity index 100% rename from src/Plugins/Shipping.ByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.resx rename to src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201406041606037_SmallQuantitySurcharge.resx diff --git a/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.Designer.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.Designer.cs new file mode 100644 index 0000000000..f921102152 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.Designer.cs @@ -0,0 +1,29 @@ +// +namespace SmartStore.ShippingByWeight.Data.Migrations +{ + using System.CodeDom.Compiler; + using System.Data.Entity.Migrations; + using System.Data.Entity.Migrations.Infrastructure; + using System.Resources; + + [GeneratedCode("EntityFramework.Migrations", "6.1.0-30225")] + public sealed partial class ZipCode : IMigrationMetadata + { + private readonly ResourceManager Resources = new ResourceManager(typeof(ZipCode)); + + string IMigrationMetadata.Id + { + get { return "201506290747117_ZipCode"; } + } + + string IMigrationMetadata.Source + { + get { return null; } + } + + string IMigrationMetadata.Target + { + get { return Resources.GetString("Target"); } + } + } +} diff --git a/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.cs new file mode 100644 index 0000000000..e0ee37f6b9 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.cs @@ -0,0 +1,18 @@ +namespace SmartStore.ShippingByWeight.Data.Migrations +{ + using System; + using System.Data.Entity.Migrations; + + public partial class ZipCode : DbMigration + { + public override void Up() + { + AddColumn("dbo.ShippingByWeight", "Zip", c => c.String()); + } + + public override void Down() + { + DropColumn("dbo.ShippingByWeight", "Zip"); + } + } +} diff --git a/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.resx b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.resx new file mode 100644 index 0000000000..aa32749020 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/201506290747117_ZipCode.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + H4sIAAAAAAAEAM1ZzW7jNhC+F+g7CDq1QNZykksayLtInKQIuk7SKLsFeqOlsc2WPypJBfaz9dBH6it0qD/LkiVbjrPozaZmvm9mSM3Hsf/9+x//05Iz5xWUplKM3NPB0HVAhDKiYj5yEzP7cOF++vj9d/5txJfO18Lu3Nqhp9Ajd2FMfOl5OlwAJ3rAaaikljMzCCX3SCS9s+HwJ+/01AOEcBHLcfznRBjKIf2CX8dShBCbhLCJjIDpfB2fBCmq80A46JiEMHIDTpQJjFQwCBY0jjHQ69VvQOcLM7ghhrjOFaME4wqAzVyHCCENMRj15RcNgVFSzIMYFwh7WcWAdjPCNOTZXK7N901seGYT89aOBVSYaCN5T8DT87xSXt39oHq7ZSWxlrdYc7OyWaf1xArV6vcMoVSR69SpL8dMWbcdxUcXKhrrGeiJ0+F6Uh6ss8HZYDgYnjjjhJlEwUhAYhRhJ85TMmU0/AVWL/JPECORMFZNDtPDZxsLuPSkZAzKrJ5hlqd8j+l5m35e3bF0q/hk6d8Lc37mOg9ITqYMyrNTKVWa4c8gQBED0RMxBpSwGJBWv8Fe40rddxN2g4wlvl5q9VaY32lcAOB7g/vlOhOy/AxibhYjFz+6zh1dQlSs5KBfBMX+gU5GJTs5iqMwAbOQ0VsjvlOSFwg3EFJOmOs8KfyUt7cL1wlCYvH6g7/Id4PGzvQEKsQjQuZQsFxLyYCI3mBFSccLouZbcI8e/SbhFben7/3IEI39mpD0bQoSFaak34buZaFALySLjkTne+uW3GzUKIoGGyqolm79OP0DQmOtYGm2NG08VHnf1vm7uJlpxhKA6VQD7TrrIDNRbWnx23Mrs1hrupeJeiH+Xov6+xOSslRuA/mKE2RXgfGHoL8q8gzDC/UWcSyjLZmwH+O7U3tqW2wEd1RpY68cU2J3dhzxhln3nrXsR8HdvS11rVvvUuFvP5enuPPO1LajNY71DtxhUTi2lbQ+UEbeeqVoAKVXO8KI2qK1Y8kSLtr0usu7VM8qRLm4P05FQKtIleX9sVIVraKkCz1yaijkRnKNp/sjZ2pZRctW9kewklj1t9/3966pXhWo9qh/tZrit61qTatDmQrVa2cpLHowtEjdBkeLzYEsFYVrZanYNFl8r9Yh6m3Ka/Sp2m283ga7NKVuUrKX2lLTED/v57vHzEaDz0ys1MtXGqXNfaUN8LyB/sXGjILd4MJgQgSdgTbZwOKi/lzUZtP/z5zoaR2xg4bFbz6DUVvjnVNW32ve5tiVcrx16DoEpDJyiVeSvs0/cLL8sQr0lrHqkJiqQ1X0fkPV0aG3DlVT2r8Auwaqo0feNVAdn6xzoHpfusZA9Ua6fgNV8w5/yIDUYz7KJASznNpTn2VRtz14imoqm+9Vf2b1b0DT+RrC/ugqcBjBGq9BC5t7MZPFxmEBqhEVJrV9xU5DIqzjlTJ0RkKDj0PQOv3V6CthCZrc8ilE9+IxMXFirrQGPmUbP4j5Xjd/Oipuxuw/xvabPkYKGCbFFOBRXCfUnsk87rstB60Fwh6pXJYwqsBYeZqvSqQHKfYEyst3AzEIK2ovwGOGYPpRBOQVDokN++FnmJNwVVxQ2kF2b8Rm2f0bSuaKcJ1jrP3tXwee/e/g4381Mg/3bRgAAA== + + + dbo + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/Configuration.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/Configuration.cs new file mode 100644 index 0000000000..8e4c78ea05 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/Migrations/Configuration.cs @@ -0,0 +1,33 @@ +namespace SmartStore.ShippingByWeight.Data.Migrations +{ + using System; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using System.Linq; + + internal sealed class Configuration : DbMigrationsConfiguration + { + public Configuration() + { + AutomaticMigrationsEnabled = false; + MigrationsDirectory = @"Data\Migrations"; + ContextKey = "SmartStore.ShippingByWeight"; + } + + protected override void Seed(ShippingByWeightObjectContext context) + { + // This method will be called after migrating to the latest version. + + // You can use the DbSet.AddOrUpdate() helper extension method + // to avoid creating duplicate seed data. E.g. + // + // context.People.AddOrUpdate( + // p => p.FullName, + // new Person { FullName = "Andrew Peters" }, + // new Person { FullName = "Brice Lambson" }, + // new Person { FullName = "Rowan Miller" } + // ); + // + } + } +} diff --git a/src/Plugins/Shipping.ByWeight/Data/ShippingByWeightObjectContext.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/ShippingByWeightObjectContext.cs similarity index 92% rename from src/Plugins/Shipping.ByWeight/Data/ShippingByWeightObjectContext.cs rename to src/Plugins/SmartStore.ShippingByWeight/Data/ShippingByWeightObjectContext.cs index f9ad406454..9d8a94ab2a 100644 --- a/src/Plugins/Shipping.ByWeight/Data/ShippingByWeightObjectContext.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/ShippingByWeightObjectContext.cs @@ -5,9 +5,9 @@ using SmartStore.Core; using SmartStore.Data; using SmartStore.Data.Setup; -using SmartStore.Plugin.Shipping.ByWeight.Data.Migrations; +using SmartStore.ShippingByWeight.Data.Migrations; -namespace SmartStore.Plugin.Shipping.ByWeight.Data +namespace SmartStore.ShippingByWeight.Data { /// /// Object context diff --git a/src/Plugins/SmartStore.ShippingByWeight/Data/ShippingByWeightRecordMap.cs b/src/Plugins/SmartStore.ShippingByWeight/Data/ShippingByWeightRecordMap.cs new file mode 100644 index 0000000000..8f906b6226 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Data/ShippingByWeightRecordMap.cs @@ -0,0 +1,15 @@ +using System.Data.Entity.ModelConfiguration; +using SmartStore.ShippingByWeight.Domain; + +namespace SmartStore.ShippingByWeight.Data +{ + public partial class ShippingByWeightRecordMap : EntityTypeConfiguration + { + public ShippingByWeightRecordMap() + { + this.ToTable("ShippingByWeight"); + this.HasKey(x => x.Id); + this.Property(x => x.Zip).IsOptional(); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.ShippingByWeight/DependencyRegistrar.cs b/src/Plugins/SmartStore.ShippingByWeight/DependencyRegistrar.cs new file mode 100644 index 0000000000..a31d4fc131 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/DependencyRegistrar.cs @@ -0,0 +1,41 @@ +using Autofac; +using Autofac.Core; +using Autofac.Integration.Mvc; +using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.Data; +using SmartStore.ShippingByWeight.Data; +using SmartStore.ShippingByWeight.Domain; +using SmartStore.ShippingByWeight.Services; + +namespace SmartStore.ShippingByWeight +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + + // data layer + // register named context + builder.Register(c => new ShippingByWeightObjectContext(DataSettings.Current.DataConnectionString)) + .Named(ShippingByWeightObjectContext.ALIASKEY) + .InstancePerRequest(); + + builder.Register(c => new ShippingByWeightObjectContext(DataSettings.Current.DataConnectionString)) + .InstancePerRequest(); + + // override required repository with our custom context + builder.RegisterType>() + .As>() + .WithParameter(ResolvedParameter.ForNamed(ShippingByWeightObjectContext.ALIASKEY)) + .InstancePerRequest(); + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.ShippingByWeight/Description.txt b/src/Plugins/SmartStore.ShippingByWeight/Description.txt new file mode 100644 index 0000000000..218a277c2b --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Description.txt @@ -0,0 +1,8 @@ +FriendlyName: Shipping by weight +SystemName: SmartStore.ShippingByWeight +Group: Shipping +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 1 +FileName: SmartStore.ShippingByWeight.dll +ResourceRootKey: Plugins.Shipping.ByWeight \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Domain/ShippingByWeightRecord.cs b/src/Plugins/SmartStore.ShippingByWeight/Domain/ShippingByWeightRecord.cs similarity index 90% rename from src/Plugins/Shipping.ByWeight/Domain/ShippingByWeightRecord.cs rename to src/Plugins/SmartStore.ShippingByWeight/Domain/ShippingByWeightRecord.cs index 613fbd2637..b46608072d 100644 --- a/src/Plugins/Shipping.ByWeight/Domain/ShippingByWeightRecord.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Domain/ShippingByWeightRecord.cs @@ -1,6 +1,6 @@ using SmartStore.Core; -namespace SmartStore.Plugin.Shipping.ByWeight.Domain +namespace SmartStore.ShippingByWeight.Domain { /// /// Represents a shipping by weight record @@ -22,10 +22,10 @@ public partial class ShippingByWeightRecord : BaseEntity ///// //public int StateProvinceId { get; set; } - ///// - ///// Gets or sets the zip - ///// - //public string Zip { get; set; } + /// + /// Gets or sets the zip + /// + public string Zip { get; set; } /// /// Gets or sets the shipping method identifier diff --git a/src/Plugins/SmartStore.ShippingByWeight/Localization/resources.de-de.xml b/src/Plugins/SmartStore.ShippingByWeight/Localization/resources.de-de.xml new file mode 100644 index 0000000000..1cb41d9656 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Localization/resources.de-de.xml @@ -0,0 +1,94 @@ + + + + Versand nach Gewicht + + + Land + + + Das Bestimmungsland. Wählen Sie Stern (*), wenn das Land des Kunden bei der Auswertung keine Rolle spielen soll. + + + PLZ-(Bereich) + + + PLZ-(Bereich) des Kunden, entweder als spezifische Werte (getrennt durch Komma) oder als Muster (z.B. 4000-49999 für das PLZ-Gebiet 4). In einem Muster lassen sich auch Wildcards verwenden, wie Stern (*) oder Fragezeichen (?). Sie können auch mehrere Wildcards angeben (durch Komma getrennt). Lassen Sie das Feld leer, wenn die Gebühr unabhängig von PLZ für alle Kunden im definierten (Bundes)land gelten soll. + + + Versandart + + + Die Versandart, bei der diese Berechnungsmethode angewandt werden soll. + + + Warengewicht von + + + Die Bedingung trifft zu, wenn das Gesamtgewicht aller Positionen im Warenkorb mind. diesen Wert aufweist. + + + Warengewicht bis + + + Die Bedingung trifft zu, wenn das Gesamtgewicht aller Positionen im Warenkorb kleiner als dieser Wert ist. Lassen Sie das Feld leer, wenn Sie keine Obergrenze festlegen möchten. + + + Prozentual + + + Legt fest, ob die Versandgebühr prozentual vom Warenwert (NICHT Gewicht) berechnet werden soll. + + + Gebühr % + + + Prozentsatz für die Gebühr auf den Warenwert. + + + Gebühr + + + Die Versandgebühr als absoluter Betrag ODER Berechnungsfaktor, sofern die entspr. Option aktiviert wurde. + + + Kein 'Fallback' anbieten + + + Dem Kunden wird während des Checkouts kostenloser Versand als Fallback angeboten, wenn keine der festgelegten Bedingungen zutreffen. Aktivieren Sie diese Option, wenn das nicht gewünscht ist. + + + Gebühr mit Gewicht multiplizieren + + + Legt fest, ob die Gebühr mit dem Gesamt-Warengewicht multipliziert werden soll. Diese Option wird ignoriert, wenn eine prozentuale Gebühr erhoben wird. + + + Shop + + + Wird das Sternchen ausgewählt, so wird die Rate auf alle Shops angewandt. + + + Mindermengenzuschlag + + + Bestimmt den Wert des Mindermengenzuschlags. + + + Mindermenge bis Bestellwert + + + Warenwert, bis zu dem ein Mindermengenzuschlag erhoben werden soll. Der Zuschlag wird ignoriert, wenn keine Versandkosten anfallen. Verwenden Sie "0", wenn kein Zuschlag erhoben werden soll. + + + Es wird ein Mindermengenzuschlag von {0} erhoben, da Ihr Bestellwert unter {1} liegt.]]> + + + + Neue Versandbedingung hinzufügen + + + Optionen + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.ShippingByWeight/Localization/resources.en-us.xml b/src/Plugins/SmartStore.ShippingByWeight/Localization/resources.en-us.xml new file mode 100644 index 0000000000..c168a3ef5f --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Localization/resources.en-us.xml @@ -0,0 +1,96 @@ + + + Shipping by weight + + + Country + + + If an asterisk is selected, then this shipping rate will apply to all customers, regardless of the country. + + + Zip-(Range) + + + Zip/postal code (range), either as specific values (comma devided) or range pattern (e.g. 4000-4999). You can also define wildcard chars like * or ?. If zip is empty, then this shipping rate will apply to all customers from the given country or state / province, regardless of the zip code. You can also enter multiple ranges (comma devided) + + + Shipping method + + + The shipping method. + + + Order weight from + + + Order weight from. + + + Order weight to + + + Order weight to. + + + Use percentage + + + Check the box to use 'charge percentage' value. + + + Charge percentage (of subtotal) + + + Charge percentage (of subtotal). + + + Charge amount + + + Charge amount. + + + Limit shipping methods to configured ones + + + If you check this option, then your customers will be limited to shipping options configured here. Otherwise, they'll be able to choose any existing shipping options even they've not configured here (zero shipping fee in this case). + + + Calculate per weight unit + + + If you check this option, then rates are multiplied per weight unit (lb, kg, etc). This option is used for the fixed rates (without percents). + + + Store + + + If an asterisk is selected, then this shipping rate will apply to all stores. + + + + Surcharge for small quantities + + + Determines the value of the small quantity surcharge. + + + Threshold for small quantities + + + Subtotal up to which a "small quantity surcharge" should be added. The surcharge will be ignored if no shipping fee is applied. Use "0" if no fee will be charged. + + + + You're charged with a surcharge of {0} because the total of your order hasn't reached {1}.]]> + + + + + Add new record + + + Settings + + \ No newline at end of file diff --git a/src/Plugins/Shipping.ByWeight/Models/ShippingByWeightListModel.cs b/src/Plugins/SmartStore.ShippingByWeight/Models/ShippingByWeightListModel.cs similarity index 92% rename from src/Plugins/Shipping.ByWeight/Models/ShippingByWeightListModel.cs rename to src/Plugins/SmartStore.ShippingByWeight/Models/ShippingByWeightListModel.cs index e87d96734e..eb7710b070 100644 --- a/src/Plugins/Shipping.ByWeight/Models/ShippingByWeightListModel.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Models/ShippingByWeightListModel.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; -namespace SmartStore.Plugin.Shipping.ByWeight.Models +namespace SmartStore.ShippingByWeight.Models { public class ShippingByWeightListModel : ModelBase { @@ -19,6 +19,8 @@ public ShippingByWeightListModel() [SmartResourceDisplayName("Plugins.Shipping.ByWeight.Fields.Country")] public int AddCountryId { get; set; } + [SmartResourceDisplayName("Plugins.Shipping.ByWeight.Fields.Zip")] + public string AddZip { get; set; } [SmartResourceDisplayName("Plugins.Shipping.ByWeight.Fields.ShippingMethod")] public int AddShippingMethodId { get; set; } [SmartResourceDisplayName("Plugins.Shipping.ByWeight.Fields.From")] diff --git a/src/Plugins/Shipping.ByWeight/Models/ShippingByWeightModel.cs b/src/Plugins/SmartStore.ShippingByWeight/Models/ShippingByWeightModel.cs similarity index 90% rename from src/Plugins/Shipping.ByWeight/Models/ShippingByWeightModel.cs rename to src/Plugins/SmartStore.ShippingByWeight/Models/ShippingByWeightModel.cs index 2720938734..516bf71071 100644 --- a/src/Plugins/Shipping.ByWeight/Models/ShippingByWeightModel.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Models/ShippingByWeightModel.cs @@ -1,7 +1,7 @@ using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; -namespace SmartStore.Plugin.Shipping.ByWeight.Models +namespace SmartStore.ShippingByWeight.Models { public class ShippingByWeightModel : EntityModelBase { @@ -26,6 +26,9 @@ public class ShippingByWeightModel : EntityModelBase [SmartResourceDisplayName("Plugins.Shipping.ByWeight.Fields.To")] public decimal To { get; set; } + [SmartResourceDisplayName("Plugins.Shipping.ByWeight.Fields.Zip")] + public string Zip { get; set; } + [SmartResourceDisplayName("Plugins.Shipping.ByWeight.Fields.UsePercentage")] public bool UsePercentage { get; set; } diff --git a/src/Plugins/SmartStore.ShippingByWeight/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.ShippingByWeight/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..caa87d9565 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.ShippingByWeight")] diff --git a/src/Plugins/SmartStore.ShippingByWeight/RouteProvider.cs b/src/Plugins/SmartStore.ShippingByWeight/RouteProvider.cs new file mode 100644 index 0000000000..89c87cf6b2 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/RouteProvider.cs @@ -0,0 +1,27 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.ShippingByWeight +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.ShippingByWeight", + "Plugins/ShippingByWeight/{action}", + new { controller = "ShippingByWeight", action = "Configure" }, + new[] { "SmartStore.ShippingByWeight.Controllers" } + ) + .DataTokens["area"] = "SmartStore.ShippingByWeight"; + } + + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/Shipping.ByWeight/Services/IShippingByWeightService.cs b/src/Plugins/SmartStore.ShippingByWeight/Services/IShippingByWeightService.cs similarity index 79% rename from src/Plugins/Shipping.ByWeight/Services/IShippingByWeightService.cs rename to src/Plugins/SmartStore.ShippingByWeight/Services/IShippingByWeightService.cs index 9962c27a5d..76237a224a 100644 --- a/src/Plugins/Shipping.ByWeight/Services/IShippingByWeightService.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Services/IShippingByWeightService.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.Linq; using SmartStore.Core; -using SmartStore.Plugin.Shipping.ByWeight.Domain; -using SmartStore.Plugin.Shipping.ByWeight.Models; +using SmartStore.ShippingByWeight.Domain; +using SmartStore.ShippingByWeight.Models; -namespace SmartStore.Plugin.Shipping.ByWeight.Services +namespace SmartStore.ShippingByWeight.Services { public partial interface IShippingByWeightService { @@ -23,7 +23,7 @@ public partial interface IShippingByWeightService /// IList GetShippingByWeightModels(int pageIndex, int pageSize, out int totalCount); - ShippingByWeightRecord FindRecord(int shippingMethodId, int storeId, int countryId, decimal weight); + ShippingByWeightRecord FindRecord(int shippingMethodId, int storeId, int countryId, decimal weight, string zip); ShippingByWeightRecord GetById(int shippingByWeightRecordId); diff --git a/src/Plugins/Shipping.ByWeight/Services/ShippingByWeightService.cs b/src/Plugins/SmartStore.ShippingByWeight/Services/ShippingByWeightService.cs similarity index 76% rename from src/Plugins/Shipping.ByWeight/Services/ShippingByWeightService.cs rename to src/Plugins/SmartStore.ShippingByWeight/Services/ShippingByWeightService.cs index 9f70305699..f60212f80c 100644 --- a/src/Plugins/Shipping.ByWeight/Services/ShippingByWeightService.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/Services/ShippingByWeightService.cs @@ -3,13 +3,14 @@ using System.Linq; using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Plugin.Shipping.ByWeight.Domain; -using SmartStore.Plugin.Shipping.ByWeight.Models; +using SmartStore.ShippingByWeight.Domain; +using SmartStore.ShippingByWeight.Models; using SmartStore.Services.Directory; using SmartStore.Services.Shipping; using SmartStore.Services.Stores; +using SmartStore.Utilities; -namespace SmartStore.Plugin.Shipping.ByWeight.Services +namespace SmartStore.ShippingByWeight.Services { public partial class ShippingByWeightService : IShippingByWeightService { @@ -82,7 +83,7 @@ public virtual IList GetShippingByWeightModels(int pageIn var shippingMethod = _shippingService.GetShippingMethodById(x.ShippingMethodId); var country = _countryService.GetCountryById(x.CountryId); - var model = new ShippingByWeightModel() + var model = new ShippingByWeightModel { Id = x.Id, StoreId = x.StoreId, @@ -90,6 +91,7 @@ public virtual IList GetShippingByWeightModels(int pageIn CountryId = x.CountryId, From = x.From, To = x.To, + Zip = (x.Zip.HasValue() ? x.Zip : "*"), UsePercentage = x.UsePercentage, ShippingChargePercentage = x.ShippingChargePercentage, ShippingChargeAmount = x.ShippingChargeAmount, @@ -107,7 +109,7 @@ public virtual IList GetShippingByWeightModels(int pageIn return result; } - public virtual ShippingByWeightRecord FindRecord(int shippingMethodId, int storeId, int countryId, decimal weight) + public virtual ShippingByWeightRecord FindRecord(int shippingMethodId, int storeId, int countryId, decimal weight, string zip) { var existingRecords = GetShippingByWeightRecords() .Where(x => x.ShippingMethodId == shippingMethodId && weight >= x.From && weight <= x.To) @@ -147,7 +149,17 @@ public virtual ShippingByWeightRecord FindRecord(int shippingMethodId, int store } } - return matchedByCountry.FirstOrDefault(); + //filter by zip + var matchedByZip = new List(); + foreach (var sbt in matchedByCountry) + { + if ((zip.IsEmpty() && sbt.Zip.IsEmpty()) || (ZipMatches(zip, sbt.Zip))) + { + matchedByZip.Add(sbt); + } + } + + return matchedByZip.LastOrDefault(); } public virtual ShippingByWeightRecord GetById(int shippingByWeightRecordId) @@ -183,6 +195,34 @@ public virtual void UpdateShippingByWeightRecord(ShippingByWeightRecord shipping _sbwRepository.Update(shippingByWeightRecord); } + private bool ZipMatches(string zip, string pattern) + { + if (pattern.IsEmpty() || pattern == "*") + { + return true; // catch all + } + + var patterns = pattern.Contains(",") + ? pattern.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()) + : new string[] { pattern }; + + try + { + foreach (var entry in patterns) + { + var wildcard = new Wildcard(entry); + if (wildcard.IsMatch(zip)) + return true; + } + } + catch + { + return zip.IsCaseInsensitiveEqual(pattern); + } + + return false; + } + #endregion } } diff --git a/src/Plugins/Shipping.ByWeight/ShippingByWeightSettings.cs b/src/Plugins/SmartStore.ShippingByWeight/ShippingByWeightSettings.cs similarity index 83% rename from src/Plugins/Shipping.ByWeight/ShippingByWeightSettings.cs rename to src/Plugins/SmartStore.ShippingByWeight/ShippingByWeightSettings.cs index b776f28865..4d0c9050df 100644 --- a/src/Plugins/Shipping.ByWeight/ShippingByWeightSettings.cs +++ b/src/Plugins/SmartStore.ShippingByWeight/ShippingByWeightSettings.cs @@ -1,7 +1,7 @@  using SmartStore.Core.Configuration; -namespace SmartStore.Plugin.Shipping.ByWeight +namespace SmartStore.ShippingByWeight { public class ShippingByWeightSettings : ISettings { diff --git a/src/Plugins/SmartStore.ShippingByWeight/SmartStore.ShippingByWeight.csproj b/src/Plugins/SmartStore.ShippingByWeight/SmartStore.ShippingByWeight.csproj new file mode 100644 index 0000000000..990c0f2f61 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/SmartStore.ShippingByWeight.csproj @@ -0,0 +1,271 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {0793FB50-67BB-461E-B961-2F45887464CF} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.ShippingByWeight + SmartStore.ShippingByWeight + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.ShippingByWeight\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.ShippingByWeight\ + TRACE + prompt + 4 + false + + + true + ..\..\Presentation\SmartStore.Web\bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + False + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + False + ..\..\..\lib\Telerik\Telerik.Web.Mvc.dll + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + 201403080200108_Initial.cs + + + + 201406041606037_SmallQuantitySurcharge.cs + + + + 201506290747117_ZipCode.cs + + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} + SmartStore.Data + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + 201403080200108_Initial.cs + + + 201406041606037_SmallQuantitySurcharge.cs + + + PreserveNewest + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + Designer + + + Designer + PreserveNewest + + + 201506290747117_ZipCode.cs + + + + + PreserveNewest + + + + + PreserveNewest + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 51373 + / + http://localhost:53077/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.ShippingByWeight/Views/ShippingByWeight/Configure.cshtml b/src/Plugins/SmartStore.ShippingByWeight/Views/ShippingByWeight/Configure.cshtml new file mode 100644 index 0000000000..3da335400c --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Views/ShippingByWeight/Configure.cshtml @@ -0,0 +1,243 @@ +@using SmartStore.ShippingByWeight.Models; +@using SmartStore.Web.Framework; +@using Telerik.Web.Mvc.UI; +@model ShippingByWeightListModel +@{ + Layout = ""; +} + + + + + +
    + @(Html.Telerik().Grid() + .Name("Grid") + .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.StoreName).ReadOnly(); + columns.Bound(x => x.CountryName).ReadOnly(); + columns.Bound(x => x.Zip); + columns.Bound(x => x.ShippingMethodName).ReadOnly(); + columns.Bound(x => x.From) + .Format("{0:0.00}"); + columns.Bound(x => x.To) + .Format("{0:0.00}"); + columns.Bound(x => x.UsePercentage) + .Centered() + .Template(item => @Html.SymbolForBool(item.UsePercentage)) + .ClientTemplate(@Html.SymbolForBool("UsePercentage")); + columns.Bound(x => x.ShippingChargePercentage) + .Format("{0:0.00}"); + columns.Bound(x => x.ShippingChargeAmount) + .Format("{0:0.00}"); + columns.Bound(x => x.SmallQuantitySurcharge) + .Format("{0:0.00}"); + columns.Bound(x => x.SmallQuantityThreshold) + .Format("{0:0.00}"); + columns.Command(commands => + { + commands.Edit(); + commands.Delete(); + }).Width(180); + + }) + .Editable(x => + { + x.Mode(GridEditMode.InLine); + }) + .DataBinding(dataBinding => + { + dataBinding.Ajax() + .Select("RatesList", "ShippingByWeight", new RouteValueDictionary() { { "area", "SmartStore.ShippingByWeight" } }) + .Update("RateUpdate", "ShippingByWeight", new RouteValueDictionary() { { "area", "SmartStore.ShippingByWeight" } }) + .Delete("RateDelete", "ShippingByWeight", new RouteValueDictionary() { { "area", "SmartStore.ShippingByWeight" } }); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .PreserveGridState() + .EnableCustomBinding(true)) +
    +

    + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    @T("Plugins.Shipping.ByWeight.AddNewRecordTitle")
    +
    +
    + @Html.SmartLabelFor(model => model.AddStoreId) + + @Html.DropDownListFor(model => model.AddStoreId, Model.AvailableStores) + @Html.ValidationMessageFor(model => model.AddStoreId) +
    + @Html.SmartLabelFor(model => model.AddCountryId) + + @Html.DropDownListFor(model => model.AddCountryId, Model.AvailableCountries) + @Html.ValidationMessageFor(model => model.AddCountryId) +
    + @Html.SmartLabelFor(model => model.AddZip) + + @Html.EditorFor(model => model.AddZip) + @Html.ValidationMessageFor(model => model.AddZip) +
    + @Html.SmartLabelFor(model => model.AddShippingMethodId) + + @Html.DropDownListFor(model => model.AddShippingMethodId, Model.AvailableShippingMethods) + @Html.ValidationMessageFor(model => model.AddShippingMethodId) +
    + @Html.SmartLabelFor(model => model.AddFrom) + + @Html.EditorFor(model => model.AddFrom) [@Model.BaseWeightIn] + @Html.ValidationMessageFor(model => model.AddFrom) +
    + @Html.SmartLabelFor(model => model.AddTo) + + @Html.EditorFor(model => model.AddTo) [@Model.BaseWeightIn] + @Html.ValidationMessageFor(model => model.AddTo) +
    + @Html.SmartLabelFor(model => model.AddUsePercentage) + + @Html.EditorFor(model => model.AddUsePercentage) + @Html.ValidationMessageFor(model => model.AddUsePercentage) +
    + @Html.SmartLabelFor(model => model.AddShippingChargePercentage) + + @Html.EditorFor(model => model.AddShippingChargePercentage) + @Html.ValidationMessageFor(model => model.AddShippingChargePercentage) +
    + @Html.SmartLabelFor(model => model.AddShippingChargeAmount) + + @Html.EditorFor(model => model.AddShippingChargeAmount) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.AddShippingChargeAmount) +
    + @Html.SmartLabelFor(model => model.SmallQuantitySurcharge) + + @Html.EditorFor(model => model.SmallQuantitySurcharge) [@Model.PrimaryStoreCurrencyCode] + @Html.ValidationMessageFor(model => model.SmallQuantitySurcharge) +
    + @Html.SmartLabelFor(model => model.SmallQuantityThreshold) + + @Html.EditorFor(model => model.SmallQuantityThreshold) + @Html.ValidationMessageFor(model => model.SmallQuantityThreshold) +
    +   + + +
    + + + + + + + + + + + + + + + + + +
    +
    +
    @T("Plugins.Shipping.ByWeight.SettingsTitle")
    +
    +
    + @Html.SmartLabelFor(model => model.CalculatePerWeightUnit) + + @Html.EditorFor(model => model.CalculatePerWeightUnit) + @Html.ValidationMessageFor(model => model.CalculatePerWeightUnit) +
    + @Html.SmartLabelFor(model => model.LimitMethodsToCreated) + + @Html.EditorFor(model => model.LimitMethodsToCreated) + @Html.ValidationMessageFor(model => model.LimitMethodsToCreated) +
    +   + + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.ShippingByWeight/Views/Web.config b/src/Plugins/SmartStore.ShippingByWeight/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.ShippingByWeight/packages.config b/src/Plugins/SmartStore.ShippingByWeight/packages.config new file mode 100644 index 0000000000..1a1ea4e95b --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.ShippingByWeight/web.config b/src/Plugins/SmartStore.ShippingByWeight/web.config new file mode 100644 index 0000000000..c0f82db177 --- /dev/null +++ b/src/Plugins/SmartStore.ShippingByWeight/web.config @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.Tax/Controllers/TaxByRegionController.cs b/src/Plugins/SmartStore.Tax/Controllers/TaxByRegionController.cs new file mode 100644 index 0000000000..ca43d31f14 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Controllers/TaxByRegionController.cs @@ -0,0 +1,164 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Web.Mvc; +using SmartStore.Tax.Domain; +using SmartStore.Tax.Models; +using SmartStore.Tax.Services; +using SmartStore.Services.Directory; +using SmartStore.Services.Tax; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Security; +using Telerik.Web.Mvc; + +namespace SmartStore.Tax.Controllers +{ + + [AdminAuthorize] + public class TaxByRegionController : PluginControllerBase + { + private readonly ITaxCategoryService _taxCategoryService; + private readonly ICountryService _countryService; + private readonly IStateProvinceService _stateProvinceService; + private readonly ITaxRateService _taxRateService; + + public TaxByRegionController(ITaxCategoryService taxCategoryService, + ICountryService countryService, IStateProvinceService stateProvinceService, + ITaxRateService taxRateService) + { + this._taxCategoryService = taxCategoryService; + this._countryService = countryService; + this._stateProvinceService = stateProvinceService; + this._taxRateService = taxRateService; + } + + + public ActionResult Configure() + { + var taxCategories = _taxCategoryService.GetAllTaxCategories(); + if (taxCategories.Count == 0) + return Content("No tax categories can be loaded"); + + var model = new ByRegionTaxRateListModel(); + foreach (var tc in taxCategories) + model.AvailableTaxCategories.Add(new SelectListItem() { Text = tc.Name, Value = tc.Id.ToString() }); + var countries = _countryService.GetAllCountries(true); + foreach (var c in countries) + model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }); + model.AvailableStates.Add(new SelectListItem() { Text = "*", Value = "0" }); + var states = _stateProvinceService.GetStateProvincesByCountryId(countries.FirstOrDefault().Id); + if (states.Count > 0) + { + foreach (var s in states) + model.AvailableStates.Add(new SelectListItem() { Text = s.Name, Value = s.Id.ToString() }); + } + + model.TaxRates = _taxRateService.GetAllTaxRates() + .Select(x => + { + var m = new ByRegionTaxRateModel() + { + Id = x.Id, + TaxCategoryId = x.TaxCategoryId, + CountryId = x.CountryId, + StateProvinceId = x.StateProvinceId, + Zip = x.Zip, + Percentage = x.Percentage, + }; + var tc = _taxCategoryService.GetTaxCategoryById(x.TaxCategoryId); + m.TaxCategoryName = (tc != null) ? tc.Name : ""; + var c = _countryService.GetCountryById(x.CountryId); + m.CountryName = (c != null) ? c.Name : T("Common.Unavailable").Text; + var s = _stateProvinceService.GetStateProvinceById(x.StateProvinceId); + m.StateProvinceName = (s != null) ? s.Name : "*"; + m.Zip = (!String.IsNullOrEmpty(x.Zip)) ? x.Zip : "*"; + return m; + }) + .ToList(); + + return View(model); + } + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult RatesList(GridCommand command) + { + var taxRatesModel = _taxRateService.GetAllTaxRates() + .Select(x => + { + var m = new ByRegionTaxRateModel() + { + Id = x.Id, + TaxCategoryId = x.TaxCategoryId, + CountryId = x.CountryId, + StateProvinceId = x.StateProvinceId, + Zip = x.Zip, + Percentage = x.Percentage, + }; + var tc = _taxCategoryService.GetTaxCategoryById(x.TaxCategoryId); + m.TaxCategoryName = (tc != null) ? tc.Name : ""; + var c = _countryService.GetCountryById(x.CountryId); + m.CountryName = (c != null) ? c.Name : T("Common.Unavailable").Text; + var s = _stateProvinceService.GetStateProvinceById(x.StateProvinceId); + m.StateProvinceName = (s != null) ? s.Name : "*"; + m.Zip = (!String.IsNullOrEmpty(x.Zip)) ? x.Zip : "*"; + return m; + }) + .ToList(); + var model = new GridModel + { + Data = taxRatesModel, + Total = taxRatesModel.Count + }; + + return new JsonResult + { + Data = model + }; + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult RateUpdate(ByRegionTaxRateModel model, GridCommand command) + { + var taxRate = _taxRateService.GetTaxRateById(model.Id); + taxRate.Zip = model.Zip == "*" ? null : model.Zip; + taxRate.Percentage = model.Percentage; + _taxRateService.UpdateTaxRate(taxRate); + + return RatesList(command); + } + + [GridAction(EnableCustomBinding = true)] + public ActionResult RateDelete(int id, GridCommand command) + { + var taxRate = _taxRateService.GetTaxRateById(id); + _taxRateService.DeleteTaxRate(taxRate); + + return RatesList(command); + } + + [HttpPost, ActionName("Configure")] + [FormValueRequired("addtaxrate")] + public ActionResult AddTaxRate(ByRegionTaxRateListModel model) + { + if (!ModelState.IsValid) + { + return Configure(); + } + + var taxRate = new TaxRate() + { + TaxCategoryId = model.AddTaxCategoryId, + CountryId = model.AddCountryId, + StateProvinceId = model.AddStateProvinceId, + Zip = model.AddZip, + Percentage = model.AddPercentage + }; + _taxRateService.InsertTaxRate(taxRate); + + return Configure(); + } + + } +} diff --git a/src/Plugins/Tax.FixedRate/Controllers/TaxFixedRateController.cs b/src/Plugins/SmartStore.Tax/Controllers/TaxFixedRateController.cs similarity index 93% rename from src/Plugins/Tax.FixedRate/Controllers/TaxFixedRateController.cs rename to src/Plugins/SmartStore.Tax/Controllers/TaxFixedRateController.cs index 15f3d05daa..1340565989 100644 --- a/src/Plugins/Tax.FixedRate/Controllers/TaxFixedRateController.cs +++ b/src/Plugins/SmartStore.Tax/Controllers/TaxFixedRateController.cs @@ -3,22 +3,24 @@ using System.Linq; using System.Threading; using System.Web.Mvc; -using SmartStore.Plugin.Tax.FixedRate.Models; +using SmartStore.Tax.Models; using SmartStore.Services.Configuration; using SmartStore.Services.Tax; using SmartStore.Web.Framework; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; using Telerik.Web.Mvc; -namespace SmartStore.Plugin.Tax.FixedRate.Controllers +namespace SmartStore.Tax.Controllers { + [AdminAuthorize] public class TaxFixedRateController : PluginControllerBase { private readonly ITaxCategoryService _taxCategoryService; private readonly ISettingService _settingService; - public TaxFixedRateController(ITaxCategoryService taxCategoryService, ISettingService settingService) + public TaxFixedRateController(ITaxCategoryService taxCategoryService, ISettingService settingService) { this._taxCategoryService = taxCategoryService; this._settingService = settingService; diff --git a/src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.Designer.cs b/src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.Designer.cs similarity index 92% rename from src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.Designer.cs rename to src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.Designer.cs index a6b03ce3ac..491f03d88d 100644 --- a/src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.Designer.cs +++ b/src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.Designer.cs @@ -1,5 +1,5 @@ // -namespace SmartStore.Plugin.Tax.CountryStateZip.Data.Migrations +namespace SmartStore.Tax.Data.Migrations { using System.CodeDom.Compiler; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.cs b/src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.cs similarity index 93% rename from src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.cs rename to src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.cs index fafde5d97b..76934c5e24 100644 --- a/src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.cs +++ b/src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.cs @@ -1,4 +1,4 @@ -namespace SmartStore.Plugin.Tax.CountryStateZip.Data.Migrations +namespace SmartStore.Tax.Data.Migrations { using System; using System.Data.Entity.Migrations; diff --git a/src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.resx b/src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.resx similarity index 100% rename from src/Plugins/Tax.CountryStateZip/Data/Migrations/201403112350417_Initial.resx rename to src/Plugins/SmartStore.Tax/Data/Migrations/201403112350417_Initial.resx diff --git a/src/Plugins/SmartStore.Tax/Data/Migrations/Configuration.cs b/src/Plugins/SmartStore.Tax/Data/Migrations/Configuration.cs new file mode 100644 index 0000000000..465429494b --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Data/Migrations/Configuration.cs @@ -0,0 +1,33 @@ +namespace SmartStore.Tax.Data.Migrations +{ + using System; + using System.Data.Entity; + using System.Data.Entity.Migrations; + using System.Linq; + + internal sealed class Configuration : DbMigrationsConfiguration + { + public Configuration() + { + AutomaticMigrationsEnabled = false; + MigrationsDirectory = @"Data\Migrations"; + ContextKey = "SmartStore.TaxCountryStateZip"; // DO NOT CHANGE + } + + protected override void Seed(TaxRateObjectContext context) + { + // This method will be called after migrating to the latest version. + + // You can use the DbSet.AddOrUpdate() helper extension method + // to avoid creating duplicate seed data. E.g. + // + // context.People.AddOrUpdate( + // p => p.FullName, + // new Person { FullName = "Andrew Peters" }, + // new Person { FullName = "Brice Lambson" }, + // new Person { FullName = "Rowan Miller" } + // ); + // + } + } +} diff --git a/src/Plugins/Tax.CountryStateZip/Data/TaxRateMap.cs b/src/Plugins/SmartStore.Tax/Data/TaxRateMap.cs similarity index 75% rename from src/Plugins/Tax.CountryStateZip/Data/TaxRateMap.cs rename to src/Plugins/SmartStore.Tax/Data/TaxRateMap.cs index 4c9c4690eb..35ed9596cf 100644 --- a/src/Plugins/Tax.CountryStateZip/Data/TaxRateMap.cs +++ b/src/Plugins/SmartStore.Tax/Data/TaxRateMap.cs @@ -1,7 +1,7 @@ using System.Data.Entity.ModelConfiguration; -using SmartStore.Plugin.Tax.CountryStateZip.Domain; +using SmartStore.Tax.Domain; -namespace SmartStore.Plugin.Tax.CountryStateZip.Data +namespace SmartStore.Tax.Data { public partial class TaxRateMap : EntityTypeConfiguration { diff --git a/src/Plugins/Tax.CountryStateZip/Data/TaxRateObjectContext.cs b/src/Plugins/SmartStore.Tax/Data/TaxRateObjectContext.cs similarity index 91% rename from src/Plugins/Tax.CountryStateZip/Data/TaxRateObjectContext.cs rename to src/Plugins/SmartStore.Tax/Data/TaxRateObjectContext.cs index 2db1894315..82687f1426 100644 --- a/src/Plugins/Tax.CountryStateZip/Data/TaxRateObjectContext.cs +++ b/src/Plugins/SmartStore.Tax/Data/TaxRateObjectContext.cs @@ -5,9 +5,9 @@ using SmartStore.Core; using SmartStore.Data; using SmartStore.Data.Setup; -using SmartStore.Plugin.Tax.CountryStateZip.Data.Migrations; +using SmartStore.Tax.Data.Migrations; -namespace SmartStore.Plugin.Tax.CountryStateZip.Data +namespace SmartStore.Tax.Data { /// /// Object context diff --git a/src/Plugins/SmartStore.Tax/DependencyRegistrar.cs b/src/Plugins/SmartStore.Tax/DependencyRegistrar.cs new file mode 100644 index 0000000000..bc207f9625 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/DependencyRegistrar.cs @@ -0,0 +1,39 @@ +using Autofac; +using Autofac.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.Data; +using SmartStore.Tax.Data; +using SmartStore.Tax.Domain; +using SmartStore.Tax.Services; + +namespace SmartStore.Tax +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + + //register named context + builder.Register(c => new TaxRateObjectContext(DataSettings.Current.DataConnectionString)) + .Named(TaxRateObjectContext.ALIASKEY) + .InstancePerRequest(); + + builder.Register(c => new TaxRateObjectContext(DataSettings.Current.DataConnectionString)) + .InstancePerRequest(); + + //override required repository with our custom context + builder.RegisterType>() + .As>() + .WithParameter(ResolvedParameter.ForNamed(TaxRateObjectContext.ALIASKEY)) + .InstancePerRequest(); + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.Tax/Description.txt b/src/Plugins/SmartStore.Tax/Description.txt new file mode 100644 index 0000000000..ec211f9efe --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Description.txt @@ -0,0 +1,9 @@ +FriendlyName: Default Tax Providers +Description: Contains default tax providers like FixedRate, ByRegion etc. +Group: Tax +SystemName: SmartStore.Tax +Version: 2.6.0 +MinAppVersion: 2.5.0 +DisplayOrder: 0 +FileName: SmartStore.Tax.dll +ResourceRootKey: Plugins.SmartStore.Tax diff --git a/src/Plugins/Tax.CountryStateZip/Domain/TaxRate.cs b/src/Plugins/SmartStore.Tax/Domain/TaxRate.cs similarity index 93% rename from src/Plugins/Tax.CountryStateZip/Domain/TaxRate.cs rename to src/Plugins/SmartStore.Tax/Domain/TaxRate.cs index 8c491f7a2f..02c15fdd6e 100644 --- a/src/Plugins/Tax.CountryStateZip/Domain/TaxRate.cs +++ b/src/Plugins/SmartStore.Tax/Domain/TaxRate.cs @@ -1,6 +1,6 @@ using SmartStore.Core; -namespace SmartStore.Plugin.Tax.CountryStateZip.Domain +namespace SmartStore.Tax.Domain { /// /// Represents a tax rate diff --git a/src/Plugins/SmartStore.Tax/Localization/resources.de-de.xml b/src/Plugins/SmartStore.Tax/Localization/resources.de-de.xml new file mode 100644 index 0000000000..1229c24787 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Localization/resources.de-de.xml @@ -0,0 +1,63 @@ + + + + Standard Steuerberechnung + + + Stellt Standard Steuerberechnungsmodule zur Verfügung - u.A. Fester Steuersatz, Steuersatz nach Region etc. + + + + + Fester Steuersatz + + + + + Steuerklasse + + + Steuersatz + + + + + + + + Steuer nach Region + + + + + Land + + + Bundesland/Region + + + Bei Angabe des Asterisks (*) wird der Steuersatz ungeachtet der Region im gesamten Land angewandt. + + + PLZ + + + Wenn leer, wird der Steuersatz ungeachtet des PLZ-Gebietes im gesamten Land bzw. in der gesamten Region angewandt. + + + Steuerklasse + + + Prozentsatz + + + Steuersatz anlegen + + + Neuen Steuersatz hinzufügen + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Tax/Localization/resources.en-us.xml b/src/Plugins/SmartStore.Tax/Localization/resources.en-us.xml new file mode 100644 index 0000000000..86bde57c04 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Localization/resources.en-us.xml @@ -0,0 +1,64 @@ + + + + Standard Steuerberechnung + + + Stellt Standard Steuerberechnungsmodule zur Verfügung - u.A. Fester Steuersatz, Steuersatz nach Region etc. + + + + + + Fixed Tax Rate + + + + + Tax category + + + Rate + + + + + + + + Tax By Region + + + + + Country + + + State/Province + + + If an asterisk (*) is selected, this tax rate will apply to all customers from the given country, regardless of the state. + + + Zip + + + Zip/Postal code. If zip is empty, then this tax rate will apply to all customers from the given country or state, regardless of the zip code. + + + Tax category + + + Percentage + + + Add tax rate + + + Adding a new tax rate + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Tax/Models/ByRegionTaxRateListModel.cs b/src/Plugins/SmartStore.Tax/Models/ByRegionTaxRateListModel.cs new file mode 100644 index 0000000000..35cd18a325 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Models/ByRegionTaxRateListModel.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Tax.Models +{ + public class ByRegionTaxRateListModel : ModelBase + { + public ByRegionTaxRateListModel() + { + AvailableCountries = new List(); + AvailableStates = new List(); + AvailableTaxCategories = new List(); + TaxRates = new List(); + } + + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Country")] + public int AddCountryId { get; set; } + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.StateProvince")] + public int AddStateProvinceId { get; set; } + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Zip")] + public string AddZip { get; set; } + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.TaxCategory")] + public int AddTaxCategoryId { get; set; } + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Percentage")] + public decimal AddPercentage { get; set; } + public IList AvailableCountries { get; set; } + public IList AvailableStates { get; set; } + public IList AvailableTaxCategories { get; set; } + + public IList TaxRates { get; set; } + + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.Tax/Models/ByRegionTaxRateModel.cs b/src/Plugins/SmartStore.Tax/Models/ByRegionTaxRateModel.cs new file mode 100644 index 0000000000..70d4decd1e --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Models/ByRegionTaxRateModel.cs @@ -0,0 +1,29 @@ +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Tax.Models +{ + public class ByRegionTaxRateModel : EntityModelBase + { + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.TaxCategory")] + public int TaxCategoryId { get; set; } + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.TaxCategory")] + public string TaxCategoryName { get; set; } + + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Country")] + public int CountryId { get; set; } + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Country")] + public string CountryName { get; set; } + + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.StateProvince")] + public int StateProvinceId { get; set; } + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.StateProvince")] + public string StateProvinceName { get; set; } + + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Zip")] + public string Zip { get; set; } + + [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Percentage")] + public decimal Percentage { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/Tax.FixedRate/Models/FixedTaxRateModel.cs b/src/Plugins/SmartStore.Tax/Models/FixedTaxRateModel.cs similarity index 88% rename from src/Plugins/Tax.FixedRate/Models/FixedTaxRateModel.cs rename to src/Plugins/SmartStore.Tax/Models/FixedTaxRateModel.cs index 86ce8f0835..301b88e8fc 100644 --- a/src/Plugins/Tax.FixedRate/Models/FixedTaxRateModel.cs +++ b/src/Plugins/SmartStore.Tax/Models/FixedTaxRateModel.cs @@ -1,6 +1,6 @@ using SmartStore.Web.Framework; -namespace SmartStore.Plugin.Tax.FixedRate.Models +namespace SmartStore.Tax.Models { public class FixedTaxRateModel { diff --git a/src/Plugins/SmartStore.Tax/Plugin.cs b/src/Plugins/SmartStore.Tax/Plugin.cs new file mode 100644 index 0000000000..5660f7bee7 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Plugin.cs @@ -0,0 +1,48 @@ +using System; +using SmartStore.Core.Plugins; +using SmartStore.Services.Localization; +using SmartStore.Services.Configuration; +using SmartStore.Services; +using System.Data.Entity.Migrations; +using SmartStore.Tax.Data.Migrations; + +namespace SmartStore.Tax +{ + + public partial class Plugin : BasePlugin + { + private readonly ICommonServices _services; + + public Plugin(ICommonServices services) + { + this._services = services; + } + + public override void Install() + { + var settings = _services.Settings; + var loc = _services.Localization; + + // add resources + loc.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + } + + public override void Uninstall() + { + var settings = _services.Settings; + var loc = _services.Localization; + + // delete resources + loc.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); + loc.DeleteLocaleStringResources("Plugins.Tax.CountryStateZip"); + loc.DeleteLocaleStringResources("Plugins.Tax.FixedRate"); + + var migrator = new DbMigrator(new Configuration()); + migrator.Update(DbMigrator.InitialDatabase); + + base.Uninstall(); + } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.Tax/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.Tax/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b64df466e9 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.Tax")] diff --git a/src/Plugins/SmartStore.Tax/Providers/ByRegionTaxProvider.cs b/src/Plugins/SmartStore.Tax/Providers/ByRegionTaxProvider.cs new file mode 100644 index 0000000000..5752d63f6a --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Providers/ByRegionTaxProvider.cs @@ -0,0 +1,63 @@ +using System.Data.Entity.Migrations; +using System.Web.Routing; +using SmartStore.Core.Plugins; +using SmartStore.Tax.Data; +using SmartStore.Tax.Data.Migrations; +using SmartStore.Tax.Services; +using SmartStore.Services.Localization; +using SmartStore.Services.Tax; + +namespace SmartStore.Tax +{ + [SystemName("Tax.CountryStateZip")] + [FriendlyName("Tax By Region")] + [DisplayOrder(10)] + public class ByRegionTaxProvider : ITaxProvider, IConfigurable + { + private readonly ITaxRateService _taxRateService; + private readonly TaxRateObjectContext _objectContext; + private readonly ILocalizationService _localizationService; + + public ByRegionTaxProvider(ITaxRateService taxRateService, + TaxRateObjectContext objectContext, + ILocalizationService localizationService) + { + this._taxRateService = taxRateService; + this._objectContext = objectContext; + _localizationService = localizationService; + } + + /// + /// Gets tax rate + /// + /// Tax calculation request + /// Tax + public CalculateTaxResult GetTaxRate(CalculateTaxRequest calculateTaxRequest) + { + var result = new CalculateTaxResult(); + + if (calculateTaxRequest.Address == null) + { + result.Errors.Add("Address is not set"); + return result; + } + + var taxRates = _taxRateService.GetAllTaxRates(calculateTaxRequest.TaxCategoryId, + calculateTaxRequest.Address.Country != null ? calculateTaxRequest.Address.Country.Id: 0, + calculateTaxRequest.Address.StateProvince != null ? calculateTaxRequest.Address.StateProvince.Id : 0, + calculateTaxRequest.Address.ZipPostalCode); + if (taxRates.Count > 0) + result.TaxRate = taxRates[0].Percentage; + + return result; + } + + public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "TaxByRegion"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.Tax" } }; + } + + } +} diff --git a/src/Plugins/SmartStore.Tax/Providers/FixedRateTaxProvider.cs b/src/Plugins/SmartStore.Tax/Providers/FixedRateTaxProvider.cs new file mode 100644 index 0000000000..55d3ab87b7 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Providers/FixedRateTaxProvider.cs @@ -0,0 +1,46 @@ +using System.Web.Routing; +using SmartStore.Core.Plugins; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; +using SmartStore.Services.Tax; + +namespace SmartStore.Tax +{ + [SystemName("Tax.FixedRate")] + [FriendlyName("Fixed Tax Rate")] + [DisplayOrder(5)] + public class FixedRateTaxProvider : ITaxProvider, IConfigurable + { + private readonly ISettingService _settingService; + private readonly ILocalizationService _localizationService; + + public FixedRateTaxProvider(ISettingService settingService, ILocalizationService localizationService) + { + this._settingService = settingService; + _localizationService = localizationService; + } + + public CalculateTaxResult GetTaxRate(CalculateTaxRequest calculateTaxRequest) + { + var result = new CalculateTaxResult() + { + TaxRate = GetTaxRate(calculateTaxRequest.TaxCategoryId) + }; + return result; + } + + protected decimal GetTaxRate(int taxCategoryId) + { + decimal rate = this._settingService.GetSettingByKey(string.Format("Tax.TaxProvider.FixedRate.TaxCategoryId{0}", taxCategoryId)); + return rate; + } + + public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "TaxFixedRate"; + routeValues = new RouteValueDictionary() { { "area", "SmartStore.Tax" } }; + } + + } +} diff --git a/src/Plugins/SmartStore.Tax/RouteProvider.cs b/src/Plugins/SmartStore.Tax/RouteProvider.cs new file mode 100644 index 0000000000..120a251043 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/RouteProvider.cs @@ -0,0 +1,34 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.Tax +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.Tax.FixedRate", + "Plugins/SmartStore.Tax/FixedRate/{action}", + new { controller = "TaxFixedRate", action = "Configure" }, + new[] { "SmartStore.Tax.Controllers" } + ) + .DataTokens["area"] = "SmartStore.Tax"; + + routes.MapRoute("SmartStore.Tax.ByRegion", + "Plugins/SmartStore.Tax/ByRegion/{action}", + new { controller = "TaxByRegion", action = "Configure" }, + new[] { "SmartStore.Tax.Controllers" } + ) + .DataTokens["area"] = "SmartStore.Tax"; + } + + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/SmartStore.Tax/Services/Extensions.cs b/src/Plugins/SmartStore.Tax/Services/Extensions.cs new file mode 100644 index 0000000000..4ad4b1c949 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Services/Extensions.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using SmartStore.Tax.Domain; + +namespace SmartStore.Tax.Services +{ + /// + /// Extensions + /// + public static class Extensions + { + /// + /// Finds tax rate + /// + /// Source + /// Country identifier + /// Tax category identifier + /// Found tax rates + public static IList FindTaxRates(this IList source, + int countryId, int taxCategoryId) + { + var result = new List(); + foreach (TaxRate taxRate in source) + { + if (taxRate.CountryId == countryId && taxRate.TaxCategoryId == taxCategoryId) + result.Add(taxRate); + } + return result; + } + } +} diff --git a/src/Plugins/Tax.CountryStateZip/Services/ITaxRateService.cs b/src/Plugins/SmartStore.Tax/Services/ITaxRateService.cs similarity index 93% rename from src/Plugins/Tax.CountryStateZip/Services/ITaxRateService.cs rename to src/Plugins/SmartStore.Tax/Services/ITaxRateService.cs index bcf7d9239d..91d4e8b289 100644 --- a/src/Plugins/Tax.CountryStateZip/Services/ITaxRateService.cs +++ b/src/Plugins/SmartStore.Tax/Services/ITaxRateService.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using SmartStore.Plugin.Tax.CountryStateZip.Domain; +using SmartStore.Tax.Domain; -namespace SmartStore.Plugin.Tax.CountryStateZip.Services +namespace SmartStore.Tax.Services { /// /// Tax rate service interface diff --git a/src/Plugins/Tax.CountryStateZip/Services/TaxRateService.cs b/src/Plugins/SmartStore.Tax/Services/TaxRateService.cs similarity index 98% rename from src/Plugins/Tax.CountryStateZip/Services/TaxRateService.cs rename to src/Plugins/SmartStore.Tax/Services/TaxRateService.cs index 3216fa9322..be7763e63d 100644 --- a/src/Plugins/Tax.CountryStateZip/Services/TaxRateService.cs +++ b/src/Plugins/SmartStore.Tax/Services/TaxRateService.cs @@ -3,9 +3,9 @@ using System.Linq; using SmartStore.Core.Caching; using SmartStore.Core.Data; -using SmartStore.Plugin.Tax.CountryStateZip.Domain; +using SmartStore.Tax.Domain; -namespace SmartStore.Plugin.Tax.CountryStateZip.Services +namespace SmartStore.Tax.Services { /// /// Tax rate service diff --git a/src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj b/src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj new file mode 100644 index 0000000000..3f4f325f97 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/SmartStore.Tax.csproj @@ -0,0 +1,258 @@ + + + + + + False + + + False + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {94D1BEEB-64A3-4EB6-9017-D66AFAF4F2B2} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.Tax + SmartStore.Tax + v4.5.1 + 512 + + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.Tax\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.Tax\ + TRACE + prompt + 4 + false + + + true + ..\..\Presentation\SmartStore.Web\bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + + + False + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + False + ..\..\..\lib\Telerik\Telerik.Web.Mvc.dll + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + 201403112350417_Initial.cs + + + + + + + + + + + + + + + + + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} + SmartStore.Data + + + {210541AD-F659-47DA-8763-16F36C5CD2F4} + SmartStore.Services + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + 201403112350417_Initial.cs + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + + + + + + + False + True + 51143 + / + http://localhost:56865/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Tax/Views/TaxByRegion/Configure.cshtml b/src/Plugins/SmartStore.Tax/Views/TaxByRegion/Configure.cshtml new file mode 100644 index 0000000000..f3b670b3b2 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Views/TaxByRegion/Configure.cshtml @@ -0,0 +1,143 @@ +@using SmartStore.Web.Framework; +@using Telerik.Web.Mvc.UI; +@using System.Linq; +@model SmartStore.Tax.Models.ByRegionTaxRateListModel +@{ + Layout = ""; +} + + + + + +
    + @(Html.Telerik().Grid(Model.TaxRates) + .Name("Grid") + .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) + .Columns(columns => + { + columns.Bound(x => x.CountryName) + .ReadOnly(); + columns.Bound(x => x.StateProvinceName) + .ReadOnly(); + columns.Bound(x => x.Zip) + .Width(140); + columns.Bound(x => x.TaxCategoryName) + .ReadOnly(); + columns.Bound(x => x.Percentage) + .Width(140) + .Format("{0:0.00}"); + columns.Command(commands => + { + commands.Edit(); + commands.Delete(); + }).Width(180); + + }) + .Editable(x => + { + x.Mode(GridEditMode.InLine); + }) + .DataBinding(dataBinding => + { + dataBinding.Ajax() + .Select("RatesList", "TaxByRegion", new RouteValueDictionary() { { "area", "SmartStore.Tax" } }) + .Update("RateUpdate", "TaxByRegion", new RouteValueDictionary() { { "area", "SmartStore.Tax" } }) + .Delete("RateDelete", "TaxByRegion", new RouteValueDictionary() { { "area", "SmartStore.Tax" } }); + }) + .EnableCustomBinding(true)) +
    + +

    + + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    @T("Plugins.Tax.CountryStateZip.AddRecord.Hint")
    +
    +
    + @Html.SmartLabelFor(model => model.AddCountryId) + + @Html.DropDownListFor(model => model.AddCountryId, Model.AvailableCountries) + @Html.ValidationMessageFor(model => model.AddCountryId) +
    + @Html.SmartLabelFor(model => model.AddStateProvinceId) + + @Html.DropDownListFor(model => model.AddStateProvinceId, Model.AvailableStates) + @Html.ValidationMessageFor(model => model.AddStateProvinceId) +
    + @Html.SmartLabelFor(model => model.AddZip) + + @Html.EditorFor(model => model.AddZip) + @Html.ValidationMessageFor(model => model.AddZip) +
    + @Html.SmartLabelFor(model => model.AddTaxCategoryId) + + @Html.DropDownListFor(model => model.AddTaxCategoryId, Model.AvailableTaxCategories) + @Html.ValidationMessageFor(model => model.AddTaxCategoryId) +
    + @Html.SmartLabelFor(model => model.AddPercentage) + + @Html.EditorFor(model => model.AddPercentage) + @Html.ValidationMessageFor(model => model.AddPercentage) +
    +   + + +
    +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.Tax/Views/TaxFixedRate/Configure.cshtml b/src/Plugins/SmartStore.Tax/Views/TaxFixedRate/Configure.cshtml new file mode 100644 index 0000000000..76fea4dd94 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Views/TaxFixedRate/Configure.cshtml @@ -0,0 +1,41 @@ +@{ + Layout = ""; +} + +@model Telerik.Web.Mvc.GridModel +@using Telerik.Web.Mvc.UI; +@using System.Linq; + + + + + +
    + @(Html.Telerik().Grid(Model.Data) + .Name("Grid") + .DataKeys(keys => keys.Add(x => x.TaxCategoryId).RouteKey("TaxCategoryId")) + .Columns(columns => + { + columns.Bound(x => x.TaxCategoryName) + .ReadOnly(); + columns.Bound(x => x.Rate) + .Width(400) + .Format("{0:0.00}"); + columns.Command(commands => + { + commands.Edit(); + }).Width(120); + + }) + .Editable(x => + { + x.Mode(GridEditMode.InLine); + }) + .DataBinding(dataBinding => + { + dataBinding.Ajax() + .Select("Configure", "TaxFixedRate", new RouteValueDictionary() { { "area", "SmartStore.Tax" } }) + .Update("TaxRateUpdate", "TaxFixedRate", new RouteValueDictionary() { { "area", "SmartStore.Tax" } }); + }) + .EnableCustomBinding(true)) +
    diff --git a/src/Plugins/SmartStore.Tax/Views/Web.config b/src/Plugins/SmartStore.Tax/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.Tax/packages.config b/src/Plugins/SmartStore.Tax/packages.config new file mode 100644 index 0000000000..7f794ac209 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.Tax/web.config b/src/Plugins/SmartStore.Tax/web.config new file mode 100644 index 0000000000..ba87d0f098 --- /dev/null +++ b/src/Plugins/SmartStore.Tax/web.config @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/Api.WebApi/icon.png b/src/Plugins/SmartStore.WebApi/Content/icon.png similarity index 100% rename from src/Plugins/Api.WebApi/icon.png rename to src/Plugins/SmartStore.WebApi/Content/icon.png diff --git a/src/Plugins/SmartStore.WebApi/Controllers/Api/HomeController.cs b/src/Plugins/SmartStore.WebApi/Controllers/Api/HomeController.cs new file mode 100644 index 0000000000..019aa5066e --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/Api/HomeController.cs @@ -0,0 +1,10 @@ +using SmartStore.Web.Framework.WebApi.Security; +using System.Web.Http; + +namespace SmartStore.WebApi.Controllers.Api +{ + [WebApiAuthenticate] + public class HomeController : ApiController + { + } +} diff --git a/src/Plugins/SmartStore.WebApi/Controllers/Api/PaymentsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/Api/PaymentsController.cs new file mode 100644 index 0000000000..5530250f3f --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/Api/PaymentsController.cs @@ -0,0 +1,36 @@ +using SmartStore.Core.Plugins; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; +using System.Linq; +using System.Web.Http; +using System; + +namespace SmartStore.WebApi.Controllers.Api +{ + [WebApiAuthenticate(Permission = "ManagePaymentMethods")] + public class PaymentsController : ApiController + { + private readonly Lazy _providerManager; + + public PaymentsController(Lazy providerManager) + { + this._providerManager = providerManager; + } + + [WebApiQueryable(PagingOptional = true)] + public IQueryable GetMethods() + { + if (!ModelState.IsValid) + throw this.ExceptionInvalidModelState(); + + var query = _providerManager.Value + .GetAllProviders() + .Select(x => x.Metadata) + .AsQueryable(); + + return query; + } + } +} diff --git a/src/Plugins/SmartStore.WebApi/Controllers/Api/UploadsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/Api/UploadsController.cs new file mode 100644 index 0000000000..d2b92900b9 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/Api/UploadsController.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; +using System.Web.Http; +using SmartStore.Core; +using SmartStore.Core.Domain; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.IO; +using SmartStore.Services.Catalog; +using SmartStore.Services.DataExchange.Import; +using SmartStore.Services.Media; +using SmartStore.Utilities; +using SmartStore.Utilities.Threading; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; +using SmartStore.WebApi.Models.Api; + +namespace SmartStore.WebApi.Controllers.Api +{ + /// + public class UploadsController : ApiController + { + private static readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim(); + + private readonly Lazy _productService; + private readonly Lazy _pictureService; + private readonly Lazy _importProfileService; + private readonly Lazy _storeContext; + private readonly Lazy _mediaSettings; + + public UploadsController( + Lazy productService, + Lazy pictureService, + Lazy importProfileService, + Lazy storeContext, + Lazy mediaSettings) + { + _productService = productService; + _pictureService = pictureService; + _importProfileService = importProfileService; + _storeContext = storeContext; + _mediaSettings = mediaSettings; + } + + #region Utilities + + private StringContent CloneHeaderContent(string path, MultipartFileData origin) + { + var content = new StringContent(path); + + ContentDispositionHeaderValue disposition; + ContentDispositionHeaderValue.TryParse(origin.Headers.ContentDisposition.ToString(), out disposition); + + content.Headers.ContentDisposition = disposition; + + content.Headers.ContentDisposition.Name = origin.Headers.ContentDisposition.Name.ToUnquoted(); + content.Headers.ContentDisposition.FileName = Path.GetFileName(path); + + content.Headers.ContentType.MediaType = MimeTypes.MapNameToMimeType(path); + + return content; + } + + #endregion + + [HttpPost] + [WebApiAuthenticate(Permission = "ManageCatalog")] + [WebApiQueryable(PagingOptional = true)] + public async Task> ProductImages() + { + if (!Request.Content.IsMimeMultipartContent()) + { + throw this.ExceptionUnsupportedMediaType(); + } + + Product entity = null; + string identifier = null; + string tempDir = FileSystemHelper.TempDir(); + var provider = new MultipartFormDataStreamProvider(tempDir); + + try + { + await Request.Content.ReadAsMultipartAsync(provider); + } + catch (Exception exception) + { + provider.DeleteLocalFiles(); + throw this.ExceptionInternalServerError(exception); + } + + // find product entity + if (provider.FormData.AllKeys.Contains("Id")) + { + identifier = provider.FormData.GetValues("Id").FirstOrDefault(); + entity = _productService.Value.GetProductById(identifier.ToInt()); + } + else if (provider.FormData.AllKeys.Contains("Sku")) + { + identifier = provider.FormData.GetValues("Sku").FirstOrDefault(); + entity = _productService.Value.GetProductBySku(identifier); + } + else if (provider.FormData.AllKeys.Contains("Gtin")) + { + identifier = provider.FormData.GetValues("Gtin").FirstOrDefault(); + entity = _productService.Value.GetProductByGtin(identifier); + } + + if (entity == null) + { + provider.DeleteLocalFiles(); + throw this.ExceptionNotFound(WebApiGlobal.Error.EntityNotFound.FormatInvariant(identifier.NaIfEmpty())); + } + + // process images + var equalPictureId = 0; + var displayOrder = 0; + var result = new List(); + var storeUrl = _storeContext.Value.CurrentStore.Url; + var pictures = entity.ProductPictures.Select(x => x.Picture); + + if (entity.ProductPictures.Count > 0) + displayOrder = entity.ProductPictures.Max(x => x.DisplayOrder); + + foreach (var file in provider.FileData) + { + var image = new UploadImage(file.Headers); + + if (image.FileName.IsEmpty()) + image.FileName = entity.Name; + + var pictureBinary = File.ReadAllBytes(file.LocalFileName); + + if (pictureBinary != null && pictureBinary.Length > 0) + { + pictureBinary = _pictureService.Value.ValidatePicture(pictureBinary); + pictureBinary = _pictureService.Value.FindEqualPicture(pictureBinary, pictures, out equalPictureId); + + if (pictureBinary != null) + { + var seoName = _pictureService.Value.GetPictureSeName(Path.GetFileNameWithoutExtension(image.FileName)); + + var newPicture = _pictureService.Value.InsertPicture(pictureBinary, image.MediaType, seoName, true, false, false); + + if (newPicture != null) + { + _productService.Value.InsertProductPicture(new ProductPicture + { + PictureId = newPicture.Id, + ProductId = entity.Id, + DisplayOrder = ++displayOrder + }); + + image.Inserted = true; + image.Picture = newPicture; + } + } + else + { + image.Exists = true; + image.Picture = pictures.FirstOrDefault(x => x.Id == equalPictureId); + } + + if (image.Picture != null) + { + image.ImageUrl = _pictureService.Value.GetPictureUrl(image.Picture, _mediaSettings.Value.ProductDetailsPictureSize, false, storeUrl); + image.ThumbImageUrl = _pictureService.Value.GetPictureUrl(image.Picture, _mediaSettings.Value.ProductThumbPictureSize, false, storeUrl); + image.FullSizeImageUrl = _pictureService.Value.GetPictureUrl(image.Picture, 0, false, storeUrl); + } + } + + result.Add(image); + } + + provider.DeleteLocalFiles(); + return result.AsQueryable(); + } + + [HttpPost] + [WebApiAuthenticate(Permission = "ManageImports")] + [WebApiQueryable(PagingOptional = true)] + public async Task> ImportFiles() + { + if (!Request.Content.IsMimeMultipartContent()) + { + throw this.ExceptionUnsupportedMediaType(); + } + + ImportProfile profile = null; + string identifier = null; + var tempDir = FileSystemHelper.TempDir(Guid.NewGuid().ToString()); + var provider = new MultipartFormDataStreamProvider(tempDir); + + try + { + await Request.Content.ReadAsMultipartAsync(provider); + } + catch (Exception exception) + { + FileSystemHelper.ClearDirectory(tempDir, true); + throw this.ExceptionInternalServerError(exception); + } + + // find import profile + if (provider.FormData.AllKeys.Contains("Id")) + { + identifier = provider.FormData.GetValues("Id").FirstOrDefault(); + profile = _importProfileService.Value.GetImportProfileById(identifier.ToInt()); + } + else if (provider.FormData.AllKeys.Contains("Name")) + { + identifier = provider.FormData.GetValues("Name").FirstOrDefault(); + profile = _importProfileService.Value.GetImportProfileByName(identifier); + } + + if (profile == null) + { + FileSystemHelper.ClearDirectory(tempDir, true); + throw this.ExceptionNotFound(WebApiGlobal.Error.EntityNotFound.FormatInvariant(identifier.NaIfEmpty())); + } + + var deleteExisting = false; + var result = new List(); + var unzippedFiles = new List(); + var importFolder = profile.GetImportFolder(true, true); + var csvTypes = new string[] { ".csv", ".txt", ".tab" }; + + if (provider.FormData.AllKeys.Contains("deleteExisting")) + { + var strDeleteExisting = provider.FormData.GetValues("deleteExisting").FirstOrDefault(); + deleteExisting = (strDeleteExisting.HasValue() && strDeleteExisting.ToBool()); + } + + // unzip files + foreach (var file in provider.FileData) + { + var import = new UploadImportFile(file.Headers); + + if (import.FileExtension.IsCaseInsensitiveEqual(".zip")) + { + var subDir = Path.Combine(tempDir, Guid.NewGuid().ToString()); + ZipFile.ExtractToDirectory(file.LocalFileName, subDir); + FileSystemHelper.Delete(file.LocalFileName); + + foreach (var unzippedFile in Directory.GetFiles(subDir, "*.*")) + { + var content = CloneHeaderContent(unzippedFile, file); + unzippedFiles.Add(new MultipartFileData(content.Headers, unzippedFile)); + } + } + else + { + unzippedFiles.Add(new MultipartFileData(file.Headers, file.LocalFileName)); + } + } + + // copy files to import folder + if (unzippedFiles.Any()) + { + using (_rwLock.GetWriteLock()) + { + if (deleteExisting) + { + FileSystemHelper.ClearDirectory(importFolder, false); + } + + foreach (var file in unzippedFiles) + { + var import = new UploadImportFile(file.Headers); + var destPath = Path.Combine(importFolder, import.FileName); + + import.Exists = File.Exists(destPath); + + switch (profile.FileType) + { + case ImportFileType.XLSX: + import.IsSupportedByProfile = import.FileExtension.IsCaseInsensitiveEqual(".xlsx"); + break; + case ImportFileType.CSV: + import.IsSupportedByProfile = csvTypes.Contains(import.FileExtension, StringComparer.OrdinalIgnoreCase); + break; + } + + import.Inserted = FileSystemHelper.Copy(file.LocalFileName, destPath); + + result.Add(import); + } + } + } + + FileSystemHelper.ClearDirectory(tempDir, true); + return result.AsQueryable(); + } + } +} \ No newline at end of file diff --git a/src/Plugins/Api.WebApi/Controllers/OData/AddressesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/AddressesController.cs similarity index 86% rename from src/Plugins/Api.WebApi/Controllers/OData/AddressesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/AddressesController.cs index 52206b90f9..3b7e734583 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/AddressesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/AddressesController.cs @@ -12,7 +12,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCustomers")] public class AddressesController : WebApiEntityController @@ -73,14 +73,16 @@ public SingleResult
    GetAddress(int key) // navigation properties - public Country GetCountry(int key) + [WebApiQueryable] + public SingleResult GetCountry(int key) { - return GetExpandedProperty(key, x => x.Country); + return GetRelatedEntity(key, x => x.Country); } - public StateProvince GetStateProvince(int key) + [WebApiQueryable] + public SingleResult GetStateProvince(int key) { - return GetExpandedProperty(key, x => x.StateProvince); + return GetRelatedEntity(key, x => x.StateProvince); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/CategoriesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/CategoriesController.cs similarity index 89% rename from src/Plugins/Api.WebApi/Controllers/OData/CategoriesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/CategoriesController.cs index 27a8391c33..9d252befa9 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/CategoriesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/CategoriesController.cs @@ -10,7 +10,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class CategoriesController : WebApiEntityController @@ -67,9 +67,7 @@ public SingleResult GetCategory(int key) [WebApiQueryable] public IQueryable GetAppliedDiscounts(int key) { - var entity = GetExpandedEntity>(key, x => x.AppliedDiscounts); - - return entity.AppliedDiscounts.AsQueryable(); + return GetRelatedCollection(key, x => x.AppliedDiscounts); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/CountriesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/CountriesController.cs similarity index 82% rename from src/Plugins/Api.WebApi/Controllers/OData/CountriesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/CountriesController.cs index f32516700b..15f58522a4 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/CountriesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/CountriesController.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Web.Http; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCountries")] public class CountriesController : WebApiEntityController @@ -36,9 +36,7 @@ public SingleResult GetCountry(int key) [WebApiQueryable] public IQueryable GetStateProvinces(int key) { - var entity = GetExpandedEntity>(key, x => x.StateProvinces); - - return entity.StateProvinces.AsQueryable(); + return GetRelatedCollection(key, x => x.StateProvinces); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/CurrenciesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/CurrenciesController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/CurrenciesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/CurrenciesController.cs index e85826db3c..be4cff76e4 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/CurrenciesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/CurrenciesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCurrencies")] public class CurrenciesController : WebApiEntityController diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/CustomersController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/CustomersController.cs new file mode 100644 index 0000000000..c811dd60cf --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/CustomersController.cs @@ -0,0 +1,97 @@ +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; +using SmartStore.Services.Customers; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; +using System.Collections.Generic; +using System.Linq; +using System.Web.Http; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageCustomers")] + public class CustomersController : WebApiEntityController + { + protected override IQueryable GetEntitySet() + { + var query = + from x in this.Repository.Table + where !x.Deleted + select x; + + return query; + } + protected override void Insert(Customer entity) + { + Service.InsertCustomer(entity); + } + protected override void Update(Customer entity) + { + Service.UpdateCustomer(entity); + } + protected override void Delete(Customer entity) + { + Service.DeleteCustomer(entity); + } + + [WebApiQueryable] + public SingleResult GetCustomer(int key) + { + return GetSingleResult(key); + } + + // navigation properties + + [WebApiQueryable] + public SingleResult
    GetBillingAddress(int key) + { + return GetRelatedEntity(key, x => x.BillingAddress); + } + + [WebApiQueryable] + public SingleResult
    GetShippingAddress(int key) + { + return GetRelatedEntity(key, x => x.ShippingAddress); + } + + //public Language GetLanguage(int key) + //{ + // return GetExpandedProperty(key, x => x.Language); + //} + + //public Currency GetCurrency(int key) + //{ + // return GetExpandedProperty(key, x => x.Currency); + //} + + [WebApiQueryable] + public IQueryable GetOrders(int key) + { + return GetRelatedCollection(key, x => x.Orders); + } + + [WebApiQueryable] + public IQueryable GetReturnRequests(int key) + { + return GetRelatedCollection(key, x => x.ReturnRequests); + } + + [WebApiQueryable] + public IQueryable
    GetAddresses(int key) + { + return GetRelatedCollection(key, x => x.Addresses); + } + + // actions + + //[HttpGet, Queryable] + //public IQueryable GetGenericAttributes(int key) + //{ + // var query = GenericAttributes(key, "Customer"); + + // return query; + //} + } +} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/DeliveryTimesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/DeliveryTimesController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/DeliveryTimesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/DeliveryTimesController.cs index 4f99ba8b9e..a76a495298 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/DeliveryTimesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/DeliveryTimesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageDeliveryTimes")] public class DeliveryTimesController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/DiscountsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/DiscountsController.cs similarity index 83% rename from src/Plugins/Api.WebApi/Controllers/OData/DiscountsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/DiscountsController.cs index 0d1076c026..eeb0d3d448 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/DiscountsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/DiscountsController.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Web.Http; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageDiscounts")] public class DiscountsController : WebApiEntityController @@ -37,9 +37,7 @@ public SingleResult GetDiscount(int key) [WebApiQueryable] public IQueryable GetAppliedToCategories(int key) { - var entity = GetExpandedEntity>(key, x => x.AppliedToCategories); - - return entity.AppliedToCategories.AsQueryable(); + return GetRelatedCollection(key, x => x.AppliedToCategories); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/DownloadsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/DownloadsController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/DownloadsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/DownloadsController.cs index f19bbe716d..30ba4c972b 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/DownloadsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/DownloadsController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class DownloadsController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/GenericAttributesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/GenericAttributesController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/GenericAttributesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/GenericAttributesController.cs index 09825eaf79..20939a3695 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/GenericAttributesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/GenericAttributesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageMaintenance")] public class GenericAttributesController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/LanguagesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/LanguagesController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/LanguagesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/LanguagesController.cs index 2bfed90859..2ca970bebc 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/LanguagesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/LanguagesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageLanguages")] public class LanguagesController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/LocalizedPropertysController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/LocalizedPropertysController.cs similarity index 84% rename from src/Plugins/Api.WebApi/Controllers/OData/LocalizedPropertysController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/LocalizedPropertysController.cs index 78fbed9107..9f9c52edca 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/LocalizedPropertysController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/LocalizedPropertysController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageLanguages")] public class LocalizedPropertysController : WebApiEntityController @@ -31,9 +31,10 @@ public SingleResult GetLocalizedProperty(int key) // navigation properties - public Language GetLanguage(int key) + [WebApiQueryable] + public SingleResult GetLanguage(int key) { - return GetExpandedProperty(key, x => x.Language); + return GetRelatedEntity(key, x => x.Language); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ManufacturersController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ManufacturersController.cs similarity index 96% rename from src/Plugins/Api.WebApi/Controllers/OData/ManufacturersController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ManufacturersController.cs index ed981b1885..e126c6db6c 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ManufacturersController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ManufacturersController.cs @@ -8,7 +8,7 @@ using SmartStore.Web.Framework.WebApi.Security; using SmartStore.Web.Framework.WebApi.OData; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class ManufacturersController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/OrderItemsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrderItemsController.cs similarity index 78% rename from src/Plugins/Api.WebApi/Controllers/OData/OrderItemsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/OrderItemsController.cs index f26538336b..2e608f15bc 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/OrderItemsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrderItemsController.cs @@ -7,7 +7,7 @@ using System.Web.Http; using SmartStore.Core.Domain.Catalog; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageOrders")] public class OrderItemsController : WebApiEntityController @@ -41,14 +41,16 @@ public SingleResult GetOrderItem(int key) // navigation properties - public Order GetOrder(int key) + [WebApiQueryable] + public SingleResult GetOrder(int key) { - return GetExpandedProperty(key, x => x.Order); + return GetRelatedEntity(key, x => x.Order); } - public Product GetProduct(int key) + [WebApiQueryable] + public SingleResult GetProduct(int key) { - return GetExpandedProperty(key, x => x.Product); + return GetRelatedEntity(key, x => x.Product); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/OrderNotesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrderNotesController.cs similarity index 79% rename from src/Plugins/Api.WebApi/Controllers/OData/OrderNotesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/OrderNotesController.cs index efafd98de0..354204fb0e 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/OrderNotesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrderNotesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageOrders")] public class OrderNotesController : WebApiEntityController @@ -23,9 +23,10 @@ public SingleResult GetOrderNote(int key) // navigation properties - public Order GetOrder(int key) + [WebApiQueryable] + public SingleResult GetOrder(int key) { - return GetExpandedProperty(key, x => x.Order); + return GetRelatedEntity(key, x => x.Order); } } } diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs new file mode 100644 index 0000000000..f0f1c0eb9b --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/OrdersController.cs @@ -0,0 +1,206 @@ +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Services.Orders; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; +using System.Collections.Generic; +using System.Linq; +using System.Web.Http; +using System.Web.Http.OData; +using System; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageOrders")] + public class OrdersController : WebApiEntityController + { + private readonly Lazy _orderProcessingService; + + public OrdersController(Lazy orderProcessingService) + { + _orderProcessingService = orderProcessingService; + } + + protected override IQueryable GetEntitySet() + { + var query = + from x in this.Repository.Table + where !x.Deleted + select x; + + return query; + } + protected override void Insert(Order entity) + { + Service.InsertOrder(entity); + } + protected override void Update(Order entity) + { + Service.UpdateOrder(entity); + } + protected override void Delete(Order entity) + { + Service.DeleteOrder(entity); + } + + [WebApiQueryable] + public SingleResult GetOrder(int key) + { + return GetSingleResult(key); + } + + // navigation properties + + [WebApiQueryable] + public SingleResult GetCustomer(int key) + { + return GetRelatedEntity(key, x => x.Customer); + } + + [WebApiQueryable] + public SingleResult
    GetBillingAddress(int key) + { + return GetRelatedEntity(key, x => x.BillingAddress); + } + + [WebApiQueryable] + public SingleResult
    GetShippingAddress(int key) + { + return GetRelatedEntity(key, x => x.ShippingAddress); + } + + [WebApiQueryable] + public IQueryable GetOrderNotes(int key) + { + //var entity = GetEntityByKeyNotNull(key); // if ProxyCreationEnabled = true + return GetRelatedCollection(key, x => x.OrderNotes); + } + + [WebApiQueryable] + public IQueryable GetShipments(int key) + { + return GetRelatedCollection(key, x => x.Shipments); + } + + [WebApiQueryable] + public IQueryable GetOrderItems(int key) + { + return GetRelatedCollection(key, x => x.OrderItems); + } + + // actions + + [HttpPost] + public SingleResult PaymentPending(int key) + { + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, null); + + this.ProcessEntity(() => + { + order.PaymentStatus = PaymentStatus.Pending; + Service.UpdateOrder(order); + return null; + }); + + return result; + } + + [HttpPost] + public SingleResult PaymentPaid(int key, ODataActionParameters parameters) + { + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, null); + + this.ProcessEntity(() => + { + string paymentMethodName = parameters.GetValue("PaymentMethodName"); + + if (paymentMethodName != null) + { + order.PaymentMethodSystemName = paymentMethodName; + Service.UpdateOrder(order); + } + + _orderProcessingService.Value.MarkOrderAsPaid(order); + + return null; + }); + + return result; + } + + [HttpPost] + public SingleResult PaymentRefund(int key, ODataActionParameters parameters) + { + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, null); + + this.ProcessEntity(() => + { + bool online = parameters.GetValue("Online"); + + if (online) + { + var errors = _orderProcessingService.Value.Refund(order); + + if (errors.Count > 0) + return errors[0]; + } + else + { + _orderProcessingService.Value.RefundOffline(order); + } + return null; + }); + + return result; + } + + [HttpPost] + public SingleResult Cancel(int key) + { + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, "OrderItems, OrderItems.Product"); + + this.ProcessEntity(() => + { + _orderProcessingService.Value.CancelOrder(order, true); + + return null; + }); + + return result; + } + + [HttpPost] + public SingleResult AddShipment(int key, ODataActionParameters parameters) + { + var result = GetSingleResult(key); + var order = GetExpandedEntity(key, result, "OrderItems, OrderItems.Product, Shipments, Shipments.ShipmentItems"); + + this.ProcessEntity(() => + { + if (order.HasItemsToAddToShipment()) + { + var trackingNumber = parameters.GetValue("TrackingNumber"); + + var shipment = _orderProcessingService.Value.AddShipment(order, trackingNumber, null); + + if (shipment != null) + { + if (parameters.ContainsKey("SetAsShipped") && parameters.GetValue("SetAsShipped")) + _orderProcessingService.Value.Ship(shipment, true); + } + } + return null; + }); + + return result; + } + } +} diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/PaymentMethodsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/PaymentMethodsController.cs new file mode 100644 index 0000000000..ccc87cfad6 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/PaymentMethodsController.cs @@ -0,0 +1,35 @@ +using System.Web.Http; +using SmartStore.Core.Domain.Payments; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManagePaymentMethods")] + public class PaymentMethodsController : WebApiEntityController + { + protected override void Insert(PaymentMethod entity) + { + Service.InsertPaymentMethod(entity); + } + protected override void Update(PaymentMethod entity) + { + Service.UpdatePaymentMethod(entity); + } + protected override void Delete(PaymentMethod entity) + { + Service.DeletePaymentMethod(entity); + } + + [WebApiQueryable] + public SingleResult GetShippingMethod(int key) + { + return GetSingleResult(key); + } + + // navigation properties + + } +} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/PicturesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/PicturesController.cs similarity index 83% rename from src/Plugins/Api.WebApi/Controllers/OData/PicturesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/PicturesController.cs index 7ae0da7e50..9e23c2959f 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/PicturesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/PicturesController.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Web.Http; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class PicturesController : WebApiEntityController @@ -37,9 +37,7 @@ public SingleResult GetPicture(int key) [WebApiQueryable] public IQueryable GetProductPictures(int key) { - var entity = GetExpandedEntity>(key, x => x.ProductPictures); - - return entity.ProductPictures.AsQueryable(); + return GetRelatedCollection(key, x => x.ProductPictures); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ProductAttributesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductAttributesController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/ProductAttributesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ProductAttributesController.cs index e4692e2710..9b9d9803d8 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ProductAttributesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductAttributesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class ProductAttributesController : WebApiEntityController diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductBundleItemsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductBundleItemsController.cs new file mode 100644 index 0000000000..a24d207821 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductBundleItemsController.cs @@ -0,0 +1,46 @@ +using SmartStore.Core.Domain.Catalog; +using SmartStore.Services.Catalog; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; +using System.Web.Http; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageCatalog")] + public class ProductBundleItemsController : WebApiEntityController + { + protected override void Insert(ProductBundleItem entity) + { + Service.InsertBundleItem(entity); + } + protected override void Update(ProductBundleItem entity) + { + Service.UpdateBundleItem(entity); + } + protected override void Delete(ProductBundleItem entity) + { + Service.DeleteBundleItem(entity); + } + + [WebApiQueryable] + public SingleResult GetProductBundleItem(int key) + { + return GetSingleResult(key); + } + + // navigation properties + + [WebApiQueryable] + public SingleResult GetProduct(int key) + { + return GetRelatedEntity(key, x => x.Product); + } + + [WebApiQueryable] + public SingleResult GetBundleProduct(int key) + { + return GetRelatedEntity(key, x => x.BundleProduct); + } + } +} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributeCombinationsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributeCombinationsController.cs similarity index 86% rename from src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributeCombinationsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributeCombinationsController.cs index ac6b9783fa..822b0d4d62 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributeCombinationsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributeCombinationsController.cs @@ -6,7 +6,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class ProductVariantAttributeCombinationsController : WebApiEntityController @@ -32,9 +32,10 @@ public SingleResult GetProductVariantAttribu // navigation properties - public DeliveryTime GetDeliveryTime(int key) + [WebApiQueryable] + public SingleResult GetDeliveryTime(int key) { - return GetExpandedProperty(key, x => x.DeliveryTime); + return GetRelatedEntity(key, x => x.DeliveryTime); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributeValuesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributeValuesController.cs similarity index 82% rename from src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributeValuesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributeValuesController.cs index 3aecf865e0..ad1f54efe7 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributeValuesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributeValuesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class ProductVariantAttributeValuesController : WebApiEntityController @@ -31,9 +31,10 @@ public SingleResult GetProductVariantAttributeValu // navigation properties - public ProductVariantAttribute GetProductVariantAttribute(int key) + [WebApiQueryable] + public SingleResult GetProductVariantAttribute(int key) { - return GetExpandedProperty(key, x => x.ProductVariantAttribute); + return GetRelatedEntity(key, x => x.ProductVariantAttribute); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributesController.cs similarity index 75% rename from src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributesController.cs index cdd44228f1..487f636560 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ProductVariantAttributesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductVariantAttributesController.cs @@ -7,7 +7,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class ProductVariantAttributesController : WebApiEntityController @@ -33,17 +33,16 @@ public SingleResult GetProductVariantAttribute(int key) // navigation properties - public ProductAttribute GetProductAttribute(int key) + [WebApiQueryable] + public SingleResult GetProductAttribute(int key) { - return GetExpandedProperty(key, x => x.ProductAttribute); + return GetRelatedEntity(key, x => x.ProductAttribute); } [WebApiQueryable] public IQueryable GetProductVariantAttributeValues(int key) { - var entity = GetExpandedEntity>(key, x => x.ProductVariantAttributeValues); - - return entity.ProductVariantAttributeValues.AsQueryable(); + return GetRelatedCollection(key, x => x.ProductVariantAttributeValues); } } } diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs new file mode 100644 index 0000000000..df8dfd389d --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ProductsController.cs @@ -0,0 +1,396 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Web.Http; +using System.Web.Http.OData; +using System.Data.Entity; +using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Directory; +using SmartStore.Core.Domain.Discounts; +using SmartStore.Core.Domain.Media; +using SmartStore.Services.Catalog; +using SmartStore.Services.Seo; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; +using SmartStore.WebApi.Services; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageCatalog")] + public class ProductsController : WebApiEntityController + { + private readonly Lazy _workContext; + private readonly Lazy _priceCalculationService; + private readonly Lazy _urlRecordService; + private readonly Lazy _productAttributeService; + private readonly Lazy _categoryService; + private readonly Lazy _manufacturerService; + + public ProductsController( + Lazy workContext, + Lazy priceCalculationService, + Lazy urlRecordService, + Lazy productAttributeService, + Lazy categoryService, + Lazy manufacturerService) + { + _workContext = workContext; + _priceCalculationService = priceCalculationService; + _urlRecordService = urlRecordService; + _productAttributeService = productAttributeService; + _categoryService = categoryService; + _manufacturerService = manufacturerService; + } + + protected override IQueryable GetEntitySet() + { + var query = + from x in this.Repository.Table + where !x.Deleted + select x; + + return query; + } + protected override void Insert(Product entity) + { + Service.InsertProduct(entity); + + this.ProcessEntity(() => + { + _urlRecordService.Value.SaveSlug(entity, x => x.Name); + return null; + }); + } + protected override void Update(Product entity) + { + Service.UpdateProduct(entity); + + this.ProcessEntity(() => + { + _urlRecordService.Value.SaveSlug(entity, x => x.Name); + return null; + }); + } + protected override void Delete(Product entity) + { + Service.DeleteProduct(entity); + } + + [WebApiQueryable] + public SingleResult GetProduct(int key) + { + return GetSingleResult(key); + } + + // navigation properties + + public HttpResponseMessage NavigationProductCategories(int key, int relatedKey) + { + var productCategories = _categoryService.Value.GetProductCategoriesByProductId(key, true); + var productCategory = productCategories.FirstOrDefault(x => x.CategoryId == relatedKey); + + if (Request.Method == HttpMethod.Post) + { + if (productCategory == null) + { + productCategory = new ProductCategory { ProductId = key, CategoryId = relatedKey }; + + _categoryService.Value.InsertProductCategory(productCategory); + + return Request.CreateResponse(HttpStatusCode.Created, productCategory); + } + } + else if (Request.Method == HttpMethod.Delete) + { + if (productCategory != null) + _categoryService.Value.DeleteProductCategory(productCategory); + + return Request.CreateResponse(HttpStatusCode.NoContent); + } + + return Request.CreateResponseForEntity(productCategory, relatedKey); + } + + public HttpResponseMessage NavigationProductManufacturers(int key, int relatedKey) + { + var productManufacturers = _manufacturerService.Value.GetProductManufacturersByProductId(key, true); + var productManufacturer = productManufacturers.FirstOrDefault(x => x.ManufacturerId == relatedKey); + + if (Request.Method == HttpMethod.Post) + { + if (productManufacturer == null) + { + productManufacturer = new ProductManufacturer { ProductId = key, ManufacturerId = relatedKey }; + + _manufacturerService.Value.InsertProductManufacturer(productManufacturer); + + return Request.CreateResponse(HttpStatusCode.Created, productManufacturer); + } + } + else if (Request.Method == HttpMethod.Delete) + { + if (productManufacturer != null) + _manufacturerService.Value.DeleteProductManufacturer(productManufacturer); + + return Request.CreateResponse(HttpStatusCode.NoContent); + } + + return Request.CreateResponseForEntity(productManufacturer, relatedKey); + } + + [WebApiQueryable] + public SingleResult GetDeliveryTime(int key) + { + return GetRelatedEntity(key, x => x.DeliveryTime); + } + + [WebApiQueryable] + public SingleResult GetQuantityUnit(int key) + { + return GetRelatedEntity(key, x => x.QuantityUnit); + } + + [WebApiQueryable] + public SingleResult GetSampleDownload(int key) + { + return GetRelatedEntity(key, x => x.SampleDownload); + } + + [WebApiQueryable] + public IQueryable GetProductCategories(int key) + { + return GetRelatedCollection(key, x => x.ProductCategories); + } + + [WebApiQueryable] + public IQueryable GetProductManufacturers(int key) + { + return GetRelatedCollection(key, x => x.ProductManufacturers); + } + + [WebApiQueryable] + public IQueryable GetProductPictures(int key) + { + return GetRelatedCollection(key, x => x.ProductPictures); + } + + [WebApiQueryable] + public IQueryable GetProductSpecificationAttributes(int key) + { + return GetRelatedCollection(key, x => x.ProductSpecificationAttributes); + } + + [WebApiQueryable] + public IQueryable GetProductTags(int key) + { + return GetRelatedCollection(key, x => x.ProductTags); + } + + [WebApiQueryable] + public IQueryable GetTierPrices(int key) + { + return GetRelatedCollection(key, x => x.TierPrices); + } + + [WebApiQueryable] + public IQueryable GetAppliedDiscounts(int key) + { + return GetRelatedCollection(key, x => x.AppliedDiscounts); + } + + [WebApiQueryable] + public IQueryable GetProductVariantAttributes(int key) + { + return GetRelatedCollection(key, x => x.ProductVariantAttributes); + } + + [WebApiQueryable] + public IQueryable GetProductVariantAttributeCombinations(int key) + { + return GetRelatedCollection(key, x => x.ProductVariantAttributeCombinations); + } + + [WebApiQueryable] + public IQueryable GetProductBundleItems(int key) + { + return GetRelatedCollection(key, x => x.ProductBundleItems); + } + + // actions + + private decimal? CalculatePrice(int key, bool lowestPrice) + { + string requiredProperties = "TierPrices, AppliedDiscounts, ProductBundleItems"; + var entity = GetExpandedEntity(key, requiredProperties); + decimal? result = null; + + this.ProcessEntity(() => + { + if (lowestPrice) + { + if (entity.ProductType == ProductType.GroupedProduct) + { + var searchContext = new ProductSearchContext + { + OrderBy = ProductSortingEnum.Position, + Query = this.GetExpandedEntitySet(requiredProperties), + ParentGroupedProductId = entity.Id, + PageSize = int.MaxValue, + VisibleIndividuallyOnly = false + }; + + Product lowestPriceProduct; + var associatedProducts = Service.PrepareProductSearchQuery(searchContext); + + result = _priceCalculationService.Value.GetLowestPrice(entity, null, associatedProducts, out lowestPriceProduct); + } + else + { + bool displayFromMessage; + result = _priceCalculationService.Value.GetLowestPrice(entity, null, out displayFromMessage); + } + } + else + { + result = _priceCalculationService.Value.GetPreselectedPrice(entity, null); + } + return null; + }); + return result; + } + + [HttpPost] + public decimal? FinalPrice(int key) + { + return CalculatePrice(key, false); + } + + [HttpPost] + public decimal? LowestPrice(int key) + { + return CalculatePrice(key, true); + } + + [HttpPost, WebApiQueryable(PagingOptional = true)] + public IQueryable CreateAttributeCombinations(int key) + { + var entity = GetEntityByKeyNotNull(key); + + this.ProcessEntity(() => + { + _productAttributeService.Value.CreateAllProductVariantAttributeCombinations(entity); + return null; + }); + + return entity.ProductVariantAttributeCombinations.AsQueryable(); + } + + [HttpPost, WebApiQueryable(PagingOptional = true)] + public IQueryable ManageAttributes(int key, ODataActionParameters parameters) + { + var entity = GetExpandedEntity>(key, x => x.ProductVariantAttributes); + var result = new List(); + + this.ProcessEntity(() => + { + bool synchronize = parameters.GetValue("Synchronize"); + var data = (parameters["Attributes"] as IEnumerable).Where(x => x.Name.HasValue()).ToList(); + + var allAttributes = _productAttributeService.Value.GetAllProductAttributes(); + + foreach (var srcAttr in data) + { + var productAttribute = allAttributes.FirstOrDefault(x => x.Name.IsCaseInsensitiveEqual(srcAttr.Name)); + + if (productAttribute == null) + { + productAttribute = new ProductAttribute() { Name = srcAttr.Name }; + _productAttributeService.Value.InsertProductAttribute(productAttribute); + } + + var attribute = entity.ProductVariantAttributes.FirstOrDefault(x => x.ProductAttribute.Name.IsCaseInsensitiveEqual(srcAttr.Name)); + + if (attribute == null) + { + attribute = new ProductVariantAttribute() + { + ProductId = entity.Id, + ProductAttributeId = productAttribute.Id, + AttributeControlTypeId = srcAttr.ControlTypeId, + DisplayOrder = entity.ProductVariantAttributes.OrderByDescending(x => x.DisplayOrder).Select(x => x.DisplayOrder).FirstOrDefault() + 1, + IsRequired = srcAttr.IsRequired + }; + + entity.ProductVariantAttributes.Add(attribute); + Service.UpdateProduct(entity); + } + else if (synchronize) + { + if (srcAttr.Values.Count <= 0) + { + _productAttributeService.Value.DeleteProductVariantAttribute(attribute); + } + else + { + attribute.AttributeControlTypeId = srcAttr.ControlTypeId; + attribute.IsRequired = srcAttr.IsRequired; + + Service.UpdateProduct(entity); + } + } + + int maxDisplayOrder = attribute.ProductVariantAttributeValues.OrderByDescending(x => x.DisplayOrder).Select(x => x.DisplayOrder).FirstOrDefault(); + + foreach (var srcVal in srcAttr.Values.Where(x => x.Name.HasValue())) + { + var value = attribute.ProductVariantAttributeValues.FirstOrDefault(x => x.Name.IsCaseInsensitiveEqual(srcVal.Name)); + + if (value == null) + { + value = new ProductVariantAttributeValue() + { + ProductVariantAttributeId = attribute.Id, + Name = srcVal.Name, + Alias = srcVal.Alias, + ColorSquaresRgb = srcVal.ColorSquaresRgb, + PriceAdjustment = srcVal.PriceAdjustment, + WeightAdjustment = srcVal.WeightAdjustment, + IsPreSelected = srcVal.IsPreSelected, + DisplayOrder = ++maxDisplayOrder + }; + + attribute.ProductVariantAttributeValues.Add(value); + Service.UpdateProduct(entity); + } + else if (synchronize) + { + value.Alias = srcVal.Alias; + value.ColorSquaresRgb = srcVal.ColorSquaresRgb; + value.PriceAdjustment = srcVal.PriceAdjustment; + value.WeightAdjustment = srcVal.WeightAdjustment; + value.IsPreSelected = srcVal.IsPreSelected; + + Service.UpdateProduct(entity); + } + } + + if (synchronize) + { + foreach (var dstVal in attribute.ProductVariantAttributeValues.ToList()) + { + if (!srcAttr.Values.Any(x => x.Name.IsCaseInsensitiveEqual(dstVal.Name))) + _productAttributeService.Value.DeleteProductVariantAttributeValue(dstVal); + } + } + } + return null; + }); + + return entity.ProductVariantAttributes.AsQueryable(); + } + } +} diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/QuantityUnitsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/QuantityUnitsController.cs new file mode 100644 index 0000000000..11868da433 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/QuantityUnitsController.cs @@ -0,0 +1,32 @@ +using System.Web.Http; +using SmartStore.Core.Domain.Directory; +using SmartStore.Services.Directory; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageMeasures")] + public class QuantityUnitsController : WebApiEntityController + { + protected override void Insert(QuantityUnit entity) + { + Service.InsertQuantityUnit(entity); + } + protected override void Update(QuantityUnit entity) + { + Service.UpdateQuantityUnit(entity); + } + protected override void Delete(QuantityUnit entity) + { + Service.DeleteQuantityUnit(entity); + } + + [WebApiQueryable] + public SingleResult GetQuantityUnit(int key) + { + return GetSingleResult(key); + } + } +} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/RelatedProductsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/RelatedProductsController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/RelatedProductsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/RelatedProductsController.cs index d6099f15a8..d625c12022 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/RelatedProductsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/RelatedProductsController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class RelatedProductsController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ReturnRequestsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ReturnRequestsController.cs similarity index 80% rename from src/Plugins/Api.WebApi/Controllers/OData/ReturnRequestsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ReturnRequestsController.cs index 472bde6f06..fbcdd389b0 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ReturnRequestsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ReturnRequestsController.cs @@ -6,7 +6,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageReturnRequests")] public class ReturnRequestsController : WebApiEntityController @@ -24,9 +24,10 @@ public SingleResult GetReturnRequest(int key) // navigation properties - public Customer GetCustomer(int key) + [WebApiQueryable] + public SingleResult GetCustomer(int key) { - return GetExpandedProperty(key, x => x.Customer); + return GetRelatedEntity(key, x => x.Customer); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/SettingsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/SettingsController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/SettingsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/SettingsController.cs index 7107793471..0faf7e6fce 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/SettingsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/SettingsController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageSettings")] public class SettingsController : WebApiEntityController diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentItemsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentItemsController.cs new file mode 100644 index 0000000000..47fdf9982a --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentItemsController.cs @@ -0,0 +1,32 @@ +using System.Web.Http; +using SmartStore.Core.Domain.Shipping; +using SmartStore.Services.Shipping; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageOrders")] + public class ShipmentItemsController : WebApiEntityController + { + protected override void Insert(ShipmentItem entity) + { + Service.InsertShipmentItem(entity); + } + protected override void Update(ShipmentItem entity) + { + Service.UpdateShipmentItem(entity); + } + protected override void Delete(ShipmentItem entity) + { + Service.DeleteShipmentItem(entity); + } + + [WebApiQueryable] + public SingleResult GetShipmentItem(int key) + { + return GetSingleResult(key); + } + } +} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ShipmentsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentsController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/ShipmentsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentsController.cs index e026ca209d..6b34c3821d 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ShipmentsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShipmentsController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageOrders")] public class ShipmentsController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/ShippingMethodsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShippingMethodsController.cs similarity index 84% rename from src/Plugins/Api.WebApi/Controllers/OData/ShippingMethodsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/ShippingMethodsController.cs index 45fe870482..ab13899ff9 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/ShippingMethodsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/ShippingMethodsController.cs @@ -8,7 +8,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageShippingSettings")] public class ShippingMethodsController : WebApiEntityController @@ -37,9 +37,7 @@ public SingleResult GetShippingMethod(int key) [WebApiQueryable] public IQueryable GetRestrictedCountries(int key) { - var entity = GetExpandedEntity>(key, x => x.RestrictedCountries); - - return entity.RestrictedCountries.AsQueryable(); + return GetRelatedCollection(key, x => x.RestrictedCountries); } } } diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/SpecificationAttributeOptionsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/SpecificationAttributeOptionsController.cs new file mode 100644 index 0000000000..e377bb9fff --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/SpecificationAttributeOptionsController.cs @@ -0,0 +1,48 @@ +using SmartStore.Core.Domain.Catalog; +using SmartStore.Services.Catalog; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; +using System.Collections.Generic; +using System.Linq; +using System.Web.Http; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageCatalog")] + public class SpecificationAttributeOptionsController : WebApiEntityController + { + protected override void Insert(SpecificationAttributeOption entity) + { + Service.InsertSpecificationAttributeOption(entity); + } + protected override void Update(SpecificationAttributeOption entity) + { + Service.UpdateSpecificationAttributeOption(entity); + } + protected override void Delete(SpecificationAttributeOption entity) + { + Service.DeleteSpecificationAttributeOption(entity); + } + + [WebApiQueryable] + public SingleResult GetSpecificationAttributeOption(int key) + { + return GetSingleResult(key); + } + + // navigation properties + + [WebApiQueryable] + public SingleResult GetSpecificationAttribute(int key) + { + return GetRelatedEntity(key, x => x.SpecificationAttribute); + } + + [WebApiQueryable] + public IQueryable GetProductSpecificationAttributes(int key) + { + return GetRelatedCollection(key, x => x.ProductSpecificationAttributes); + } + } +} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/SpecificationAttributesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/SpecificationAttributesController.cs similarity index 82% rename from src/Plugins/Api.WebApi/Controllers/OData/SpecificationAttributesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/SpecificationAttributesController.cs index babe695d03..3990c280d8 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/SpecificationAttributesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/SpecificationAttributesController.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Web.Http; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class SpecificationAttributesController : WebApiEntityController @@ -36,9 +36,7 @@ public SingleResult GetSpecificationAttribute(int key) [WebApiQueryable] public IQueryable GetSpecificationAttributeOptions(int key) { - var entity = GetExpandedEntity>(key, x => x.SpecificationAttributeOptions); - - return entity.SpecificationAttributeOptions.AsQueryable(); + return GetRelatedCollection(key, x => x.SpecificationAttributeOptions); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/StateProvincesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/StateProvincesController.cs similarity index 84% rename from src/Plugins/Api.WebApi/Controllers/OData/StateProvincesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/StateProvincesController.cs index 7407832bdc..f01dccfec4 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/StateProvincesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/StateProvincesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCountries")] public class StateProvincesController : WebApiEntityController @@ -31,9 +31,10 @@ public SingleResult GetStateProvince(int key) // navigation properties - public Country GetCountry(int key) + [WebApiQueryable] + public SingleResult GetCountry(int key) { - return GetExpandedProperty(key, x => x.Country); + return GetRelatedEntity(key, x => x.Country); } } } diff --git a/src/Plugins/Api.WebApi/Controllers/OData/StoreMappingsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/StoreMappingsController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/StoreMappingsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/StoreMappingsController.cs index 28ad6e79bb..eab3b187b1 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/StoreMappingsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/StoreMappingsController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageStores")] public class StoreMappingsController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/StoresController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/StoresController.cs similarity index 92% rename from src/Plugins/Api.WebApi/Controllers/OData/StoresController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/StoresController.cs index e78938e6e9..b455c76487 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/StoresController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/StoresController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageStores")] public class StoresController : WebApiEntityController diff --git a/src/Plugins/SmartStore.WebApi/Controllers/OData/SyncMappingsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/SyncMappingsController.cs new file mode 100644 index 0000000000..bccd10dcaa --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/SyncMappingsController.cs @@ -0,0 +1,33 @@ +using System.Web.Http; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Domain.Stores; +using SmartStore.Services.DataExchange; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.OData; +using SmartStore.Web.Framework.WebApi.Security; + +namespace SmartStore.WebApi.Controllers.OData +{ + [WebApiAuthenticate(Permission = "ManageMaintenance")] // TODO: ManageMaintenance... really? + public class SyncMappingsController : WebApiEntityController + { + protected override void Insert(SyncMapping entity) + { + Service.InsertSyncMapping(entity); + } + protected override void Update(SyncMapping entity) + { + Service.UpdateSyncMapping(entity); + } + protected override void Delete(SyncMapping entity) + { + Service.DeleteSyncMapping(entity); + } + + [WebApiQueryable] + public SingleResult GetSyncMapping(int key) + { + return GetSingleResult(key); + } + } +} diff --git a/src/Plugins/Api.WebApi/Controllers/OData/TierPricesController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/TierPricesController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/TierPricesController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/TierPricesController.cs index e7c8144952..bceb65fc47 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/TierPricesController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/TierPricesController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageCatalog")] public class TierPricesController : WebApiEntityController diff --git a/src/Plugins/Api.WebApi/Controllers/OData/UrlRecordsController.cs b/src/Plugins/SmartStore.WebApi/Controllers/OData/UrlRecordsController.cs similarity index 93% rename from src/Plugins/Api.WebApi/Controllers/OData/UrlRecordsController.cs rename to src/Plugins/SmartStore.WebApi/Controllers/OData/UrlRecordsController.cs index 25e50aced0..c2164d7a2e 100644 --- a/src/Plugins/Api.WebApi/Controllers/OData/UrlRecordsController.cs +++ b/src/Plugins/SmartStore.WebApi/Controllers/OData/UrlRecordsController.cs @@ -5,7 +5,7 @@ using SmartStore.Web.Framework.WebApi.OData; using SmartStore.Web.Framework.WebApi.Security; -namespace SmartStore.Plugin.Api.WebApi.Controllers.OData +namespace SmartStore.WebApi.Controllers.OData { [WebApiAuthenticate(Permission = "ManageMaintenance")] public class UrlRecordsController : WebApiEntityController diff --git a/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs b/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs new file mode 100644 index 0000000000..4fb254bbff --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Controllers/WebApiController.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Core.Domain.Common; +using SmartStore.Services; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.Caching; +using SmartStore.WebApi.Models; +using SmartStore.WebApi.Security; +using SmartStore.WebApi.Services; +using Telerik.Web.Mvc; + +namespace SmartStore.WebApi.Controllers +{ + [AdminAuthorize] + public class WebApiController : PluginControllerBase + { + private readonly WebApiSettings _webApiSettings; + private readonly IWebApiPluginService _webApiPluginService; + private readonly AdminAreaSettings _adminAreaSettings; + private readonly ICommonServices _services; + + public WebApiController( + WebApiSettings settings, + IWebApiPluginService webApiPluginService, + AdminAreaSettings adminAreaSettings, + ICommonServices services) + { + _webApiSettings = settings; + _webApiPluginService = webApiPluginService; + _adminAreaSettings = adminAreaSettings; + _services = services; + } + + private bool HasPermission(bool notify = true) + { + bool hasPermission = _services.Permissions.Authorize(WebApiPermissionProvider.ManageWebApi); + + if (notify && !hasPermission) + NotifyError(_services.Localization.GetResource("Admin.AccessDenied.Description")); + + return hasPermission; + } + + private void AddButtonText() + { + ViewData["ButtonTextEnable"] = _services.Localization.GetResource("Plugins.Api.WebApi.Activate"); + ViewData["ButtonTextDisable"] = _services.Localization.GetResource("Plugins.Api.WebApi.Deactivate"); + ViewData["ButtonTextRemoveKeys"] = _services.Localization.GetResource("Plugins.Api.WebApi.RemoveKeys"); + ViewData["ButtonTextCreateKeys"] = _services.Localization.GetResource("Plugins.Api.WebApi.CreateKeys"); + } + + public ActionResult Configure() + { + if (!HasPermission(false)) + return AccessDeniedPartialView(); + + var model = new WebApiConfigModel(); + model.Copy(_webApiSettings, true); + + var odataUri = new Uri(Request.Url, + WebApiGlobal.MostRecentOdataPath.StartsWith("/") ? WebApiGlobal.MostRecentOdataPath : "/" + WebApiGlobal.MostRecentOdataPath + ); + + model.ApiOdataUrl = odataUri.AbsoluteUri.EnsureEndsWith("/"); + model.ApiOdataMetadataUrl = model.ApiOdataUrl + "$metadata"; + + model.GridPageSize = _adminAreaSettings.GridPageSize; + + AddButtonText(); + + return View(model); + } + + [HttpPost, ActionName("Configure")] + [FormValueRequired("savegeneralsettings")] + public ActionResult SaveGeneralSettings(WebApiConfigModel model) + { + if (!ModelState.IsValid) + return Configure(); + + if (!HasPermission(false)) + return AccessDeniedPartialView(); + + model.Copy(_webApiSettings, false); + _services.Settings.SaveSetting(_webApiSettings); + + WebApiCachingControllingData.Remove(); + + return Configure(); + } + + [HttpPost, GridAction(EnableCustomBinding = true)] + public ActionResult GridUserData(GridCommand command) + { + if (!HasPermission()) + return new JsonResult { Data = new GridModel { Data = new List() } }; + + var model = _webApiPluginService.GetGridModel(command.Page - 1, command.PageSize); + + AddButtonText(); + + return new JsonResult { Data = model }; + } + + [HttpPost] + public void ApiButtonCreateKeys(int customerId) + { + if (HasPermission()) + _webApiPluginService.CreateKeys(customerId); + } + + [HttpPost] + public void ApiButtonRemoveKeys(int customerId) + { + if (HasPermission()) + _webApiPluginService.RemoveKeys(customerId); + } + + [HttpPost] + public void ApiButtonEnable(int customerId) + { + if (HasPermission()) + _webApiPluginService.EnableOrDisableUser(customerId, true); + } + + [HttpPost] + public void ApiButtonDisable(int customerId) + { + if (HasPermission()) + _webApiPluginService.EnableOrDisableUser(customerId, false); + } + + } +} diff --git a/src/Plugins/SmartStore.WebApi/DependencyRegistrar.cs b/src/Plugins/SmartStore.WebApi/DependencyRegistrar.cs new file mode 100644 index 0000000000..b9316aae52 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/DependencyRegistrar.cs @@ -0,0 +1,21 @@ +using Autofac; +using Autofac.Integration.Mvc; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.WebApi.Services; + +namespace SmartStore.WebApi +{ + public class DependencyRegistrar : IDependencyRegistrar + { + public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) + { + builder.RegisterType().As().InstancePerRequest(); + } + + public int Order + { + get { return 1; } + } + } +} diff --git a/src/Plugins/SmartStore.WebApi/Description.txt b/src/Plugins/SmartStore.WebApi/Description.txt new file mode 100644 index 0000000000..646ac2fd0d --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Description.txt @@ -0,0 +1,10 @@ +FriendlyName: SmartStore.NET Web Api +SystemName: SmartStore.WebApi +Version: 2.6.0 +Group: Api +MinAppVersion: 2.5.0 +Author: SmartStore AG +DisplayOrder: 1 +FileName: SmartStore.WebApi.dll +ResourceRootKey: Plugins.Api.WebApi +Url: http://community.smartstore.com/marketplace/file/27-smartstorenet-web-api/ \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/Extensions/MiscExtensions.cs b/src/Plugins/SmartStore.WebApi/Extensions/MiscExtensions.cs new file mode 100644 index 0000000000..3e754343db --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Extensions/MiscExtensions.cs @@ -0,0 +1,44 @@ +using System.Text; +using System.Web.Mvc; + +namespace SmartStore.WebApi +{ + public static class PublicMiscExtensions + { + public static string ApiGridButtons(this HtmlHelper helper) + { + var sb = new StringBuilder(); + + sb.Append("
    \">"); + + sb.AppendFormat("", + helper.ViewData["ButtonTextRemoveKeys"]); + + sb.AppendFormat("", + helper.ViewData["ButtonTextCreateKeys"]); + + sb.AppendFormat("", + helper.ViewData["ButtonTextEnable"]); + + sb.AppendFormat("", + helper.ViewData["ButtonTextDisable"]); + + sb.Append("
    "); + + return sb.ToString(); + } + } + + internal static class MiscExtensions + { + public static string ToUnquoted(this string value) + { + if (value.HasValue() && value.Length > 1) + { + if ((value.StartsWith("\"") && value.EndsWith("\"")) || (value.StartsWith("'") && value.EndsWith("'"))) + return value.Substring(1, value.Length - 2); + } + return value; + } + } +} diff --git a/src/Plugins/SmartStore.WebApi/Localization/resources.de-de.xml b/src/Plugins/SmartStore.WebApi/Localization/resources.de-de.xml new file mode 100644 index 0000000000..650e50d1ab --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Localization/resources.de-de.xml @@ -0,0 +1,74 @@ + + + Web-API + + + + +
  • Nur registrierte Kunden (siehe Liste unten) mit einem öffentlichen und einem geheimen Schlüssel zur API haben Zugriff.
  • +
  • Sie können den Zugriff für einen Kunden durch Löschen der Schlüssel endgültig oder durch Deaktivieren zeitweise unterbinden.
  • +
  • Die Rechte der jeweiligen Kundengruppe gelten auch bei Zugriffen über die API.
  • +]]> +
    +
    + + OData API URL + + + Die URL der OData Web API. + + + OData Metadaten URL + + + Die URL der OData Metadaten. Sie beschreiben das gesamte Entitäten-Daten-Modell (EDM), auf dem die Web API basiert. + + + Anfragezeitfenster (Minuten) + + + Aus Sicherheitsgründen darf die Zeit, zu der die Anfrage an die API gesendet wurde, nicht zu weit von der aktuellen Server-Zeit abweichen. Mit dieser Einstellung legen Sie dieses Zeitfenster in Minuten fest. + + + Unautorisierte Zugriffe speichern + + + Jeder unautorisierte Zugriff wird in der Ereignisliste gespeichert. + + + Keine Zeitstempelprüfung + + + Legt fest, ob geprüft werden soll, ob der Zeitstempel der letzten Anfrage kleiner gleich der der aktuellen ist. Verhindert das Auftreten von HmacResult.TimestampOlderThanLastRequest. + + + Authentifizierung ohne MD5-Hash erlauben + + + Legt fest, ob Authentifizierungen ohne MD5 Inhalts-Hash erlaubt sind. + + + Öffentlicher Schlüssel + + + Geheimer Schlüssel + + + Letzter Zugriff + + + Für API zugelassen + + + Zulassen + + + Nicht zulassen + + + Schlüssel löschen + + + Schlüssel erstellen + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/Localization/resources.en-us.xml b/src/Plugins/SmartStore.WebApi/Localization/resources.en-us.xml new file mode 100644 index 0000000000..7aafa97635 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Localization/resources.en-us.xml @@ -0,0 +1,74 @@ + + + Web-API + + + + +
  • Only registered customers (see list below) with a public and a secret key for the API have access to it.
  • +
  • You can remove the access for a customer permanently by deleting the keys or temporary by deactivating them.
  • +
  • The rights of the respective customer group are valid for the API too.
  • +]]> +
    +
    + + OData API URL + + + URL of the OData Web API. + + + OData metadata URL + + + URL of the OData metadata. It describes the complete entity data model (EDM) the Web API is based on. + + + Request time window (minutes) + + + For security reasons should the time at which the request was sent to the API differ not too far from the current server time. With this setting, you set this time window in minutes. + + + Log unauthorized accesses + + + Each unauthorized access will be saved in the log list. + + + No timestamp validation + + + Specifies whether to validate that the timestamp of the previous request is less or equal than the one of the current. Prevents the occurrence of HmacResult.TimestampOlderThanLastRequest. + + + Allow authentification without MD5 hash + + + Specifies whether to allow authentifications without MD5 content hash. + + + Public key + + + Secret key + + + Last access + + + API enabled + + + Activate + + + Deactivate + + + Delete keys + + + Generate keys + +
    \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/Models/Api/UploadFileBase.cs b/src/Plugins/SmartStore.WebApi/Models/Api/UploadFileBase.cs new file mode 100644 index 0000000000..d0884fa6a3 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Models/Api/UploadFileBase.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using System.IO; +using System.Net.Http.Headers; +using System.Runtime.Serialization; + +namespace SmartStore.WebApi.Models.Api +{ + [DataContract] + public abstract partial class UploadFileBase + { + public UploadFileBase() + { + } + + public UploadFileBase(HttpContentHeaders headers) + { + Name = headers.ContentDisposition.Name.ToUnquoted(); + FileName = headers.ContentDisposition.FileName.ToUnquoted(); + ContentDisposition = headers.ContentDisposition.Parameters; + + if (headers.ContentType != null) + { + MediaType = headers.ContentType.MediaType.ToUnquoted(); + } + + if (FileName.HasValue()) + { + FileExtension = Path.GetExtension(FileName); + } + } + + /// + /// Unquoted name attribute of content-disposition multipart header + /// + [DataMember] + public string Name { get; set; } + + /// + /// Unquoted filename attribute of content-disposition multipart header + /// + [DataMember] + public string FileName { get; set; } + + /// + /// Extension of FileName + /// + [DataMember] + public string FileExtension { get; set; } + + /// + /// Media (mime) type of content-type multipart header + /// + [DataMember] + public string MediaType { get; set; } + + /// + /// Indicates whether the uploaded file already exist + /// + [DataMember] + public bool Exists { get; set; } + + /// + /// Indicates whether the uploaded file has been inserted + /// + [DataMember] + public bool Inserted { get; set; } + + /// + /// Raw custom parameters of the content-disposition multipart header + /// + [DataMember] + public ICollection ContentDisposition { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/Models/Api/UploadImage.cs b/src/Plugins/SmartStore.WebApi/Models/Api/UploadImage.cs new file mode 100644 index 0000000000..cca701246b --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Models/Api/UploadImage.cs @@ -0,0 +1,42 @@ +using System.Net.Http.Headers; +using System.Runtime.Serialization; +using SmartStore.Core.Domain.Media; + +namespace SmartStore.WebApi.Models.Api +{ + [DataContract] + public partial class UploadImage : UploadFileBase + { + public UploadImage() + { + } + + public UploadImage(HttpContentHeaders headers) : base(headers) + { + } + + /// + /// Url of the default size image + /// + [DataMember] + public string ImageUrl { get; set; } + + /// + /// Url of the thumbnail image + /// + [DataMember] + public string ThumbImageUrl { get; set; } + + /// + /// Url of the full size image + /// + [DataMember] + public string FullSizeImageUrl { get; set; } + + /// + /// The picture entity. Can be null. + /// + [DataMember] + public Picture Picture { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/Models/Api/UploadImportFile.cs b/src/Plugins/SmartStore.WebApi/Models/Api/UploadImportFile.cs new file mode 100644 index 0000000000..ac43524577 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Models/Api/UploadImportFile.cs @@ -0,0 +1,23 @@ +using System.Net.Http.Headers; +using System.Runtime.Serialization; + +namespace SmartStore.WebApi.Models.Api +{ + [DataContract] + public partial class UploadImportFile : UploadFileBase + { + public UploadImportFile() + { + } + + public UploadImportFile(HttpContentHeaders headers) : base(headers) + { + } + + /// + /// Whether the file type is supported by the import profile + /// + [DataMember] + public bool IsSupportedByProfile { get; set; } + } +} \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/Models/WebApiConfigModel.cs b/src/Plugins/SmartStore.WebApi/Models/WebApiConfigModel.cs new file mode 100644 index 0000000000..23882c149e --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Models/WebApiConfigModel.cs @@ -0,0 +1,47 @@ +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; +using SmartStore.Web.Framework.WebApi; + +namespace SmartStore.WebApi.Models +{ + public class WebApiConfigModel : ModelBase + { + [SmartResourceDisplayName("Plugins.Api.WebApi.ApiOdataUrl")] + public string ApiOdataUrl { get; set; } + + [SmartResourceDisplayName("Plugins.Api.WebApi.ApiOdataMetadataUrl")] + public string ApiOdataMetadataUrl { get; set; } + + [SmartResourceDisplayName("Plugins.Api.WebApi.ValidMinutePeriod")] + public int ValidMinutePeriod { get; set; } + + [SmartResourceDisplayName("Plugins.Api.WebApi.NoRequestTimestampValidation")] + public bool NoRequestTimestampValidation { get; set; } + + [SmartResourceDisplayName("Plugins.Api.WebApi.AllowEmptyMd5Hash")] + public bool AllowEmptyMd5Hash { get; set; } + + [SmartResourceDisplayName("Plugins.Api.WebApi.LogUnauthorized")] + public bool LogUnauthorized { get; set; } + + public int GridPageSize { get; set; } + + public void Copy(WebApiSettings settings, bool fromSettings) + { + if (fromSettings) + { + ValidMinutePeriod = settings.ValidMinutePeriod; + NoRequestTimestampValidation = settings.NoRequestTimestampValidation; + AllowEmptyMd5Hash = settings.AllowEmptyMd5Hash; + LogUnauthorized = settings.LogUnauthorized; + } + else + { + settings.ValidMinutePeriod = ValidMinutePeriod; + settings.NoRequestTimestampValidation = NoRequestTimestampValidation; + settings.AllowEmptyMd5Hash = AllowEmptyMd5Hash; + settings.LogUnauthorized = LogUnauthorized; + } + } + } +} diff --git a/src/Plugins/Api.WebApi/Models/WebApiUserModel.cs b/src/Plugins/SmartStore.WebApi/Models/WebApiUserModel.cs similarity index 94% rename from src/Plugins/Api.WebApi/Models/WebApiUserModel.cs rename to src/Plugins/SmartStore.WebApi/Models/WebApiUserModel.cs index 121c4e2d1e..2694f9166b 100644 --- a/src/Plugins/Api.WebApi/Models/WebApiUserModel.cs +++ b/src/Plugins/SmartStore.WebApi/Models/WebApiUserModel.cs @@ -1,8 +1,8 @@ using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; using System; +using SmartStore.Web.Framework.Modelling; -namespace SmartStore.Plugin.Api.WebApi.Models +namespace SmartStore.WebApi.Models { public class WebApiUserModel : EntityModelBase { diff --git a/src/Plugins/SmartStore.WebApi/Properties/AssemblyInfo.cs b/src/Plugins/SmartStore.WebApi/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..c0af45c817 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Properties/AssemblyInfo.cs @@ -0,0 +1,2 @@ +using System.Reflection; +[assembly: AssemblyTitle("SmartStore.WebApi")] diff --git a/src/Plugins/SmartStore.WebApi/RouteProvider.cs b/src/Plugins/SmartStore.WebApi/RouteProvider.cs new file mode 100644 index 0000000000..1ce5fb95cb --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/RouteProvider.cs @@ -0,0 +1,27 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Routing; +using SmartStore.Web.Framework.WebApi; + +namespace SmartStore.WebApi +{ + public partial class RouteProvider : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapRoute("SmartStore.WebApi.Action", + "Plugins/SmartStore.WebApi/{action}", + new { controller = "WebApi" }, + new[] { "SmartStore.WebApi.Controllers" } + ) + .DataTokens["area"] = WebApiGlobal.PluginSystemName; + } + public int Priority + { + get + { + return 0; + } + } + } +} diff --git a/src/Plugins/Api.WebApi/Scripts/smartstore.web.api.js b/src/Plugins/SmartStore.WebApi/Scripts/smartstore.web.api.js similarity index 100% rename from src/Plugins/Api.WebApi/Scripts/smartstore.web.api.js rename to src/Plugins/SmartStore.WebApi/Scripts/smartstore.web.api.js diff --git a/src/Plugins/Api.WebApi/Security/WebApiPermissionProvider.cs b/src/Plugins/SmartStore.WebApi/Security/WebApiPermissionProvider.cs similarity index 95% rename from src/Plugins/Api.WebApi/Security/WebApiPermissionProvider.cs rename to src/Plugins/SmartStore.WebApi/Security/WebApiPermissionProvider.cs index cb32c5a4be..bae7d89565 100644 --- a/src/Plugins/Api.WebApi/Security/WebApiPermissionProvider.cs +++ b/src/Plugins/SmartStore.WebApi/Security/WebApiPermissionProvider.cs @@ -3,7 +3,7 @@ using SmartStore.Services.Security; using System.Collections.Generic; -namespace SmartStore.Plugin.Api.WebApi.Security +namespace SmartStore.WebApi.Security { public partial class WebApiPermissionProvider : IPermissionProvider { diff --git a/src/Plugins/Api.WebApi/Services/IWebApiPluginService.cs b/src/Plugins/SmartStore.WebApi/Services/IWebApiPluginService.cs similarity index 80% rename from src/Plugins/Api.WebApi/Services/IWebApiPluginService.cs rename to src/Plugins/SmartStore.WebApi/Services/IWebApiPluginService.cs index 45b20fd50d..0b8092aca3 100644 --- a/src/Plugins/Api.WebApi/Services/IWebApiPluginService.cs +++ b/src/Plugins/SmartStore.WebApi/Services/IWebApiPluginService.cs @@ -1,8 +1,8 @@ using SmartStore.Core; -using SmartStore.Plugin.Api.WebApi.Models; +using SmartStore.WebApi.Models; using Telerik.Web.Mvc; -namespace SmartStore.Plugin.Api.WebApi.Services +namespace SmartStore.WebApi.Services { public partial interface IWebApiPluginService { diff --git a/src/Plugins/Api.WebApi/Services/WebApiCore.cs b/src/Plugins/SmartStore.WebApi/Services/WebApiCore.cs similarity index 94% rename from src/Plugins/Api.WebApi/Services/WebApiCore.cs rename to src/Plugins/SmartStore.WebApi/Services/WebApiCore.cs index 0759b9f7c4..838a26faa9 100644 --- a/src/Plugins/Api.WebApi/Services/WebApiCore.cs +++ b/src/Plugins/SmartStore.WebApi/Services/WebApiCore.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using SmartStore.Core.Domain.Catalog; -namespace SmartStore.Plugin.Api.WebApi.Services +namespace SmartStore.WebApi.Services { [Serializable] internal class ManageAttributeType diff --git a/src/Plugins/Api.WebApi/Services/WebApiPluginService.cs b/src/Plugins/SmartStore.WebApi/Services/WebApiPluginService.cs similarity index 84% rename from src/Plugins/Api.WebApi/Services/WebApiPluginService.cs rename to src/Plugins/SmartStore.WebApi/Services/WebApiPluginService.cs index 993098ca0a..8fb2385a8a 100644 --- a/src/Plugins/Api.WebApi/Services/WebApiPluginService.cs +++ b/src/Plugins/SmartStore.WebApi/Services/WebApiPluginService.cs @@ -1,16 +1,16 @@ -using SmartStore.Core; +using System.Linq; +using SmartStore.Core; using SmartStore.Core.Data; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; -using SmartStore.Plugin.Api.WebApi.Models; using SmartStore.Services.Common; using SmartStore.Services.Customers; -using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.Caching; using SmartStore.Web.Framework.WebApi.Security; -using System.Linq; +using SmartStore.WebApi.Models; using Telerik.Web.Mvc; -namespace SmartStore.Plugin.Api.WebApi.Services +namespace SmartStore.WebApi.Services { public class WebApiPluginService : IWebApiPluginService { @@ -40,7 +40,7 @@ from c in _customers.Table join a in ( from a in _genericAttributes.Table - where a.KeyGroup == "Customer" && a.Key == WebApiUserCacheData.Key + where a.KeyGroup == "Customer" && a.Key == WebApiCachingUserData.Key select a ) on c.Id equals a.EntityId into ga @@ -57,7 +57,7 @@ orderby a.Value descending var lst = new PagedList(query, pageIndex, pageSize); - var cacheData = WebApiCaching.UserData(); + var cacheData = WebApiCachingUserData.Data(); foreach (var itm in lst) { @@ -80,7 +80,7 @@ public GridModel GetGridModel(int pageIndex, int pageSize) { var apiUsers = GetUsers(pageIndex, pageSize); - var model = new GridModel() + var model = new GridModel { Data = apiUsers, Total = apiUsers.TotalCount @@ -94,14 +94,14 @@ public bool CreateKeys(int customerId) if (customerId != 0) { var hmac = new HmacAuthentication(); - var userData = WebApiCaching.UserData(); + var userData = WebApiCachingUserData.Data(); string key1, key2; for (int i = 0; i < 9999; ++i) { if (hmac.CreateKeys(out key1, out key2) && !userData.Exists(x => x.PublicKey.IsCaseInsensitiveEqual(key1))) { - var apiUser = new WebApiUserCacheData() + var apiUser = new WebApiUserCacheData { CustomerId = customerId, PublicKey = key1, @@ -111,17 +111,17 @@ public bool CreateKeys(int customerId) RemoveKeys(customerId); - var attribute = new GenericAttribute() + var attribute = new GenericAttribute { EntityId = customerId, KeyGroup = "Customer", - Key = WebApiUserCacheData.Key, + Key = WebApiCachingUserData.Key, Value = apiUser.ToString() }; _genericAttributeService.InsertAttribute(attribute); - WebApiCaching.Remove(WebApiUserCacheData.Key); + WebApiCachingUserData.Remove(); return true; } } @@ -134,7 +134,7 @@ public void RemoveKeys(int customerId) { var data = ( from a in _genericAttributes.Table - where a.EntityId == customerId && a.KeyGroup == "Customer" && a.Key == WebApiUserCacheData.Key + where a.EntityId == customerId && a.KeyGroup == "Customer" && a.Key == WebApiCachingUserData.Key select a).ToList(); if (data.Count > 0) @@ -142,7 +142,7 @@ from a in _genericAttributes.Table foreach (var itm in data) _genericAttributeService.DeleteAttribute(itm); - WebApiCaching.Remove(WebApiUserCacheData.Key); + WebApiCachingUserData.Remove(); } } } @@ -150,7 +150,7 @@ public void EnableOrDisableUser(int customerId, bool enable) { if (customerId != 0) { - var cacheData = WebApiCaching.UserData(); + var cacheData = WebApiCachingUserData.Data(); var apiUser = cacheData.FirstOrDefault(x => x.CustomerId == customerId); if (apiUser != null) diff --git a/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj new file mode 100644 index 0000000000..73e315200d --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/SmartStore.WebApi.csproj @@ -0,0 +1,333 @@ + + + + + + False + + + False + + + + true + bin\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + Debug + AnyCPU + {D8947A85-F0D7-4FF5-8E77-ED4EE18447C8} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + SmartStore.WebApi + SmartStore.WebApi + v4.5.1 + 512 + + + + + + + + + ..\..\ + true + + + 4.0 + true + + + + + + + + + + true + full + false + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.WebApi\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\..\Presentation\SmartStore.Web\Plugins\SmartStore.WebApi\ + TRACE + prompt + 4 + + + true + bin\EFMigrations\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + + + ..\..\packages\Autofac.WebApi.3.1.0\lib\net40\Autofac.Integration.WebApi.dll + + + ..\..\packages\AutoMapper.4.1.1\lib\net45\AutoMapper.dll + + + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll + + + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll + + + False + ..\..\packages\Microsoft.Data.Edm.5.6.1\lib\net40\Microsoft.Data.Edm.dll + + + False + ..\..\packages\Microsoft.Data.OData.5.6.1\lib\net40\Microsoft.Data.OData.dll + + + ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + False + ..\..\packages\Microsoft.AspNet.WebApi.Client.5.1.2\lib\net45\System.Net.Http.Formatting.dll + + + + + + + False + ..\..\packages\System.Spatial.5.6.1\lib\net40\System.Spatial.dll + + + + + + ..\..\packages\Microsoft.AspNet.Cors.5.1.2\lib\net45\System.Web.Cors.dll + + + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll + + + False + ..\..\packages\Microsoft.AspNet.WebApi.Core.5.1.2\lib\net45\System.Web.Http.dll + + + ..\..\packages\Microsoft.AspNet.WebApi.Cors.5.1.1\lib\net45\System.Web.Http.Cors.dll + + + ..\..\packages\Microsoft.AspNet.WebApi.OData.5.1.2\lib\net45\System.Web.Http.OData.dll + + + False + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll + + + False + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll + + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll + + + False + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll + + + + + + + ..\..\..\lib\Telerik\Telerik.Web.Mvc.dll + + + + + Properties\AssemblySharedInfo.cs + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + Designer + Always + + + Designer + Always + + + Always + + + + + {6bda8332-939f-45b7-a25e-7a797260ae59} + SmartStore.Core + + + {210541ad-f659-47da-8763-16f36c5cd2f4} + SmartStore.Services + + + {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} + SmartStore.Data + + + {75fd4163-333c-4dd5-854d-2ef294e45d94} + SmartStore.Web.Framework + + + + + PreserveNewest + + + Designer + + + PreserveNewest + + + Designer + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + False + True + 49203 + / + http://localhost:49567/ + False + True + http://www.smartstore.net + False + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/Views/Web.config b/src/Plugins/SmartStore.WebApi/Views/Web.config new file mode 100644 index 0000000000..e9d36a3c51 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Views/Web.config @@ -0,0 +1,53 @@ + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Plugins/SmartStore.WebApi/Views/WebApi/Configure.cshtml b/src/Plugins/SmartStore.WebApi/Views/WebApi/Configure.cshtml new file mode 100644 index 0000000000..9c6dbd98ef --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/Views/WebApi/Configure.cshtml @@ -0,0 +1,137 @@ +@model WebApiConfigModel +@using SmartStore.WebApi; +@using SmartStore.WebApi.Models; +@using SmartStore.Web.Framework; +@using SmartStore.Web.Framework.Plugins; +@using SmartStore.Web.Framework.WebApi; +@using SmartStore.Web.Framework.UI; +@using Telerik.Web.Mvc.UI; + +@{ + Layout = ""; + + Html.AddScriptParts(true, Url.Content("~/Plugins/SmartStore.WebApi/Scripts/smartstore.web.api.js")); +} + + + +
    + @Html.Raw(@T("Plugins.Api.WebApi.AdminInstruction")) +
    + + + + + +
    + + @(Html.Telerik().Grid() + .Name("apiuser-grid") + .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) + .Columns(c => + { + c.Bound(x => x.Id).Width(50); + c.Bound(x => x.Username); + c.Bound(x => x.Email) + .Template(x => Html.ActionLink(x.Email, "Edit", "Customer", new { id = x.Id, area = "admin" }, new { })) + .ClientTemplate("\"><#= Email #>"); + c.Bound(x => x.AdminComment); + c.Bound(x => x.PublicKey); + c.Bound(x => x.SecretKey); + c.Bound(x => x.Enabled).Width(110).Centered() + .Template(x => @Html.SymbolForBool(x.Enabled)) + .ClientTemplate(@Html.SymbolForBool("Enabled")); + c.Bound(x => x.LastRequest); + c.Template(x => @Html.ApiGridButtons()) + .Width(330) + .ClientTemplate(@Html.ApiGridButtons()); + }) + .DataBinding(dataBinding => + { + dataBinding.Ajax().Select("GridUserData", "WebApi", new { Namespaces = "SmartStore.WebApi.Controllers", area = WebApiGlobal.PluginSystemName }); + }) + .Pageable(settings => settings.PageSize(Model.GridPageSize).Position(GridPagerPosition.Both)) + .ClientEvents(events => events.OnRowDataBound("onRowDataBound_ApiUser")) + .PreserveGridState() + .EnableCustomBinding(true) + ) + +
    + +

     

    + +@using (Html.BeginForm()) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + @Html.SmartLabelFor(model => model.ApiOdataUrl) + + @Model.ApiOdataUrl +
    + @Html.SmartLabelFor(model => model.ApiOdataMetadataUrl) + + @Model.ApiOdataMetadataUrl +
    + @Html.SmartLabelFor(model => model.ValidMinutePeriod) + + @Html.EditorFor(model => model.ValidMinutePeriod) + @Html.ValidationMessageFor(model => model.ValidMinutePeriod) +
    + @Html.SmartLabelFor(model => model.NoRequestTimestampValidation) + + @Html.EditorFor(model => model.NoRequestTimestampValidation) + @Html.ValidationMessageFor(model => model.NoRequestTimestampValidation) +
    + @Html.SmartLabelFor(model => model.AllowEmptyMd5Hash) + + @Html.EditorFor(model => model.AllowEmptyMd5Hash) + @Html.ValidationMessageFor(model => model.AllowEmptyMd5Hash) +
    + @Html.SmartLabelFor(model => model.LogUnauthorized) + + @Html.EditorFor(model => model.LogUnauthorized) + @Html.ValidationMessageFor(model => model.LogUnauthorized) +
      + +
    +} diff --git a/src/Plugins/Api.WebApi/WebApiConfigurationProvider.cs b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs similarity index 88% rename from src/Plugins/Api.WebApi/WebApiConfigurationProvider.cs rename to src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs index d2a19763e5..7440806c04 100644 --- a/src/Plugins/Api.WebApi/WebApiConfigurationProvider.cs +++ b/src/Plugins/SmartStore.WebApi/WebApiConfigurationProvider.cs @@ -1,20 +1,22 @@ -using SmartStore.Core.Domain.Catalog; +using System.Web.Http.OData.Builder; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Configuration; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.DataExchange; using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Discounts; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Orders; +using SmartStore.Core.Domain.Payments; using SmartStore.Core.Domain.Seo; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Stores; using SmartStore.Web.Framework.WebApi.Configuration; -using System.Web.Http.OData.Builder; -using SmartStore.Plugin.Api.WebApi.Services; +using SmartStore.WebApi.Services; -namespace SmartStore.Plugin.Api.WebApi +namespace SmartStore.WebApi { public partial class WebApiConfigurationProvider : IWebApiConfigurationProvider { @@ -33,7 +35,14 @@ private void AddActionsToOrder(EntityTypeConfiguration config) config.Action("Cancel") .ReturnsFromEntitySet(WebApiOdataEntitySet.Orders); + + var addShipment = config.Action("AddShipment") + .ReturnsFromEntitySet(WebApiOdataEntitySet.Orders); + + addShipment.Parameter("TrackingNumber"); + addShipment.Parameter("SetAsShipped"); } + private void AddActionsToProduct(EntityTypeConfiguration config) { config.Action("FinalPrice") @@ -71,6 +80,7 @@ public void Configure(WebApiConfigurationBroadcaster configData) m.EntitySet(WebApiOdataEntitySet.OrderNotes); m.EntitySet(WebApiOdataEntitySet.Orders); m.EntitySet(WebApiOdataEntitySet.OrderItems); + m.EntitySet(WebApiOdataEntitySet.PaymentMethods); m.EntitySet(WebApiOdataEntitySet.Pictures); m.EntitySet(WebApiOdataEntitySet.ProductAttributes); m.EntitySet(WebApiOdataEntitySet.ProductBundleItems); @@ -83,10 +93,12 @@ public void Configure(WebApiConfigurationBroadcaster configData) m.EntitySet(WebApiOdataEntitySet.ProductVariantAttributes); m.EntitySet(WebApiOdataEntitySet.ProductVariantAttributeValues); m.EntitySet(WebApiOdataEntitySet.ProductVariantAttributeCombinations); + m.EntitySet(WebApiOdataEntitySet.QuantityUnits); m.EntitySet(WebApiOdataEntitySet.RelatedProducts); m.EntitySet(WebApiOdataEntitySet.ReturnRequests); m.EntitySet(WebApiOdataEntitySet.Settings); m.EntitySet(WebApiOdataEntitySet.Shipments); + m.EntitySet(WebApiOdataEntitySet.ShipmentItems); m.EntitySet(WebApiOdataEntitySet.ShippingMethods); m.EntitySet(WebApiOdataEntitySet.SpecificationAttributeOptions); m.EntitySet(WebApiOdataEntitySet.SpecificationAttributes); @@ -95,6 +107,7 @@ public void Configure(WebApiConfigurationBroadcaster configData) m.EntitySet(WebApiOdataEntitySet.StoreMappings); m.EntitySet(WebApiOdataEntitySet.TierPrices); m.EntitySet(WebApiOdataEntitySet.UrlRecords); + m.EntitySet(WebApiOdataEntitySet.SyncMappings); AddActionsToOrder(m.Entity()); AddActionsToProduct(m.Entity()); @@ -121,6 +134,7 @@ public static class WebApiOdataEntitySet public static string OrderNotes { get { return "OrderNotes"; } } public static string Orders { get { return "Orders"; } } public static string OrderItems { get { return "OrderItems"; } } + public static string PaymentMethods { get { return "PaymentMethods"; } } public static string Pictures { get { return "Pictures"; } } public static string ProductAttributes { get { return "ProductAttributes"; } } public static string ProductBundleItems { get { return "ProductBundleItems"; } } @@ -133,10 +147,12 @@ public static class WebApiOdataEntitySet public static string ProductVariantAttributes { get { return "ProductVariantAttributes"; } } public static string ProductVariantAttributeValues { get { return "ProductVariantAttributeValues"; } } public static string ProductVariantAttributeCombinations { get { return "ProductVariantAttributeCombinations"; } } + public static string QuantityUnits { get { return "QuantityUnits"; } } public static string RelatedProducts { get { return "RelatedProducts"; } } public static string ReturnRequests { get { return "ReturnRequests"; } } public static string Settings { get { return "Settings"; } } public static string Shipments { get { return "Shipments"; } } + public static string ShipmentItems { get { return "ShipmentItems"; } } public static string ShippingMethods { get { return "ShippingMethods"; } } public static string SpecificationAttributeOptions { get { return "SpecificationAttributeOptions"; } } public static string SpecificationAttributes { get { return "SpecificationAttributes"; } } @@ -145,5 +161,6 @@ public static class WebApiOdataEntitySet public static string StoreMappings { get { return "StoreMappings"; } } public static string TierPrices { get { return "TierPrices"; } } public static string UrlRecords { get { return "UrlRecords"; } } + public static string SyncMappings { get { return "SyncMappings"; } } } } diff --git a/src/Plugins/SmartStore.WebApi/WebApiPlugin.cs b/src/Plugins/SmartStore.WebApi/WebApiPlugin.cs new file mode 100644 index 0000000000..43d717c4c1 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/WebApiPlugin.cs @@ -0,0 +1,66 @@ +using System.Web.Routing; +using SmartStore.Core.Plugins; +using SmartStore.Services.Configuration; +using SmartStore.Services.Localization; +using SmartStore.Services.Security; +using SmartStore.Web.Framework.WebApi; +using SmartStore.Web.Framework.WebApi.Caching; +using SmartStore.WebApi.Security; + +namespace SmartStore.WebApi +{ + public class WebApiPlugin : BasePlugin, IConfigurable + { + private readonly IPermissionService _permissionService; + private readonly ILocalizationService _localizationService; + private readonly ISettingService _settingService; + + public WebApiPlugin(IPermissionService permissionService, ILocalizationService localizationService, ISettingService settingService) + { + _permissionService = permissionService; + _localizationService = localizationService; + _settingService = settingService; + } + + + public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) + { + actionName = "Configure"; + controllerName = "WebApi"; + routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.WebApi.Controllers" }, { "area", WebApiGlobal.PluginSystemName } }; + } + + public override void Install() + { + _permissionService.InstallPermissions(new WebApiPermissionProvider()); + + var apiSettings = new WebApiSettings + { + LogUnauthorized = true, + ValidMinutePeriod = WebApiGlobal.DefaultTimePeriodMinutes + }; + + _settingService.SaveSetting(apiSettings); + + _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); + + base.Install(); + + WebApiCachingControllingData.Remove(); + WebApiCachingUserData.Remove(); + } + + public override void Uninstall() + { + WebApiCachingControllingData.Remove(); + WebApiCachingUserData.Remove(); + + _settingService.DeleteSetting(); + + _permissionService.UninstallPermissions(new WebApiPermissionProvider()); + + base.Uninstall(); + } + + } +} diff --git a/src/Plugins/SmartStore.WebApi/changelog.md b/src/Plugins/SmartStore.WebApi/changelog.md new file mode 100644 index 0000000000..a2f7a528c8 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/changelog.md @@ -0,0 +1,55 @@ +#Release Notes + +##Web Api 2.5.0.1 +###New Features +* Option to allow authentification without MD5 content hash + +##Web Api 2.2.0.5 +###New Features +* Bridge to import framework: uploading import files to import profile directory + +##Web Api 2.2.0.4 +###New Features +* Added OData endpoint for shipment items +* Added OData action to add a shipment to an order and to set it as shipped +###Improvements +* OData actions should return SingleResult (instead of entity instance) to let expand option be recognized + +##Web Api 2.2.0.3 +###New Features +* Added OData endpoint for payment method +* #727 Option to deactivate TimestampOlderThanLastRequest validation +* #731 Allow deletion and inserting of product category and manufacturer assignments +###Improvements +* Using header timestamp as last user request date rather than API server date + +##Web Api 2.2.0.2 +###Improvements +* WebApiAuthenticate attribute can be applied on methods too +* Product image upload requires manage catalog permission + +##Web Api 2.2.0.1 +###New Features +* #652 Support for file upload and multipart mime + +##Web Api 1.32 +###New Features +* #618 Add endpoint for quantity units + +##Web Api 1.31 +###Bugfixes +* WebApiController requires more permission checks + +##Web Api 1.23 +###New Features +* #431 Add support for localized properties + +##Web Api 1.22 +###New Features +* #393 Implement OData actions for simpler working with product attributes -> added ProductsController.ManageAttributes and ProductsController.CreateAttributeCombinations + +##Web Api 1.21 +###Improvements +* #384 Inserting sluged recources like products require an URL record +###Bugfixes +* PUT implementation was incomplete \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/packages.config b/src/Plugins/SmartStore.WebApi/packages.config new file mode 100644 index 0000000000..9e4fbc38a8 --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/packages.config @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/SmartStore.WebApi/web.config b/src/Plugins/SmartStore.WebApi/web.config new file mode 100644 index 0000000000..95ed427e0a --- /dev/null +++ b/src/Plugins/SmartStore.WebApi/web.config @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Controllers/TaxCountryStateZipController.cs b/src/Plugins/Tax.CountryStateZip/Controllers/TaxCountryStateZipController.cs deleted file mode 100644 index 93fc7fca2b..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Controllers/TaxCountryStateZipController.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Web.Mvc; -using SmartStore.Plugin.Tax.CountryStateZip.Domain; -using SmartStore.Plugin.Tax.CountryStateZip.Models; -using SmartStore.Plugin.Tax.CountryStateZip.Services; -using SmartStore.Services.Directory; -using SmartStore.Services.Tax; -using SmartStore.Web.Framework.Controllers; -using Telerik.Web.Mvc; - -namespace SmartStore.Plugin.Tax.CountryStateZip.Controllers -{ - - public class TaxCountryStateZipController : PluginControllerBase - { - private readonly ITaxCategoryService _taxCategoryService; - private readonly ICountryService _countryService; - private readonly IStateProvinceService _stateProvinceService; - private readonly ITaxRateService _taxRateService; - - public TaxCountryStateZipController(ITaxCategoryService taxCategoryService, - ICountryService countryService, IStateProvinceService stateProvinceService, - ITaxRateService taxRateService) - { - this._taxCategoryService = taxCategoryService; - this._countryService = countryService; - this._stateProvinceService = stateProvinceService; - this._taxRateService = taxRateService; - } - - - public ActionResult Configure() - { - var taxCategories = _taxCategoryService.GetAllTaxCategories(); - if (taxCategories.Count == 0) - return Content("No tax categories can be loaded"); - - var model = new TaxRateListModel(); - foreach (var tc in taxCategories) - model.AvailableTaxCategories.Add(new SelectListItem() { Text = tc.Name, Value = tc.Id.ToString() }); - var countries = _countryService.GetAllCountries(true); - foreach (var c in countries) - model.AvailableCountries.Add(new SelectListItem() { Text = c.Name, Value = c.Id.ToString() }); - model.AvailableStates.Add(new SelectListItem() { Text = "*", Value = "0" }); - var states = _stateProvinceService.GetStateProvincesByCountryId(countries.FirstOrDefault().Id); - if (states.Count > 0) - { - foreach (var s in states) - model.AvailableStates.Add(new SelectListItem() { Text = s.Name, Value = s.Id.ToString() }); - } - - model.TaxRates = _taxRateService.GetAllTaxRates() - .Select(x => - { - var m = new TaxRateModel() - { - Id = x.Id, - TaxCategoryId = x.TaxCategoryId, - CountryId = x.CountryId, - StateProvinceId = x.StateProvinceId, - Zip = x.Zip, - Percentage = x.Percentage, - }; - var tc = _taxCategoryService.GetTaxCategoryById(x.TaxCategoryId); - m.TaxCategoryName = (tc != null) ? tc.Name : ""; - var c = _countryService.GetCountryById(x.CountryId); - m.CountryName = (c != null) ? c.Name : "Unavailable"; - var s = _stateProvinceService.GetStateProvinceById(x.StateProvinceId); - m.StateProvinceName = (s != null) ? s.Name : "*"; - m.Zip = (!String.IsNullOrEmpty(x.Zip)) ? x.Zip : "*"; - return m; - }) - .ToList(); - - return View(model); - } - - [HttpPost, GridAction(EnableCustomBinding = true)] - public ActionResult RatesList(GridCommand command) - { - var taxRatesModel = _taxRateService.GetAllTaxRates() - .Select(x => - { - var m = new TaxRateModel() - { - Id = x.Id, - TaxCategoryId = x.TaxCategoryId, - CountryId = x.CountryId, - StateProvinceId = x.StateProvinceId, - Zip = x.Zip, - Percentage = x.Percentage, - }; - var tc = _taxCategoryService.GetTaxCategoryById(x.TaxCategoryId); - m.TaxCategoryName = (tc != null) ? tc.Name : ""; - var c = _countryService.GetCountryById(x.CountryId); - m.CountryName = (c != null) ? c.Name : "Unavailable"; - var s = _stateProvinceService.GetStateProvinceById(x.StateProvinceId); - m.StateProvinceName = (s != null) ? s.Name : "*"; - m.Zip = (!String.IsNullOrEmpty(x.Zip)) ? x.Zip : "*"; - return m; - }) - .ToList(); - var model = new GridModel - { - Data = taxRatesModel, - Total = taxRatesModel.Count - }; - - return new JsonResult - { - Data = model - }; - } - - [GridAction(EnableCustomBinding = true)] - public ActionResult RateUpdate(TaxRateModel model, GridCommand command) - { - var taxRate = _taxRateService.GetTaxRateById(model.Id); - taxRate.Zip = model.Zip == "*" ? null : model.Zip; - taxRate.Percentage = model.Percentage; - _taxRateService.UpdateTaxRate(taxRate); - - return RatesList(command); - } - - [GridAction(EnableCustomBinding = true)] - public ActionResult RateDelete(int id, GridCommand command) - { - var taxRate = _taxRateService.GetTaxRateById(id); - _taxRateService.DeleteTaxRate(taxRate); - - return RatesList(command); - } - - [HttpPost, ActionName("Configure")] - [FormValueRequired("addtaxrate")] - public ActionResult AddTaxRate(TaxRateListModel model) - { - if (!ModelState.IsValid) - { - return Configure(); - } - - var taxRate = new TaxRate() - { - TaxCategoryId = model.AddTaxCategoryId, - CountryId = model.AddCountryId, - StateProvinceId = model.AddStateProvinceId, - Zip = model.AddZip, - Percentage = model.AddPercentage - }; - _taxRateService.InsertTaxRate(taxRate); - - return Configure(); - } - - } -} diff --git a/src/Plugins/Tax.CountryStateZip/CountryStateZipTaxProvider.cs b/src/Plugins/Tax.CountryStateZip/CountryStateZipTaxProvider.cs deleted file mode 100644 index 82b4cd6a84..0000000000 --- a/src/Plugins/Tax.CountryStateZip/CountryStateZipTaxProvider.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System.Data.Entity.Migrations; -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Plugin.Tax.CountryStateZip.Data; -using SmartStore.Plugin.Tax.CountryStateZip.Data.Migrations; -using SmartStore.Plugin.Tax.CountryStateZip.Services; -using SmartStore.Services.Localization; -using SmartStore.Services.Tax; - -namespace SmartStore.Plugin.Tax.CountryStateZip -{ - /// - /// Fixed rate tax provider - /// - public class CountryStateZipTaxProvider : BasePlugin, ITaxProvider - { - private readonly ITaxRateService _taxRateService; - private readonly TaxRateObjectContext _objectContext; - private readonly ILocalizationService _localizationService; - - public CountryStateZipTaxProvider(ITaxRateService taxRateService, - TaxRateObjectContext objectContext, - ILocalizationService localizationService) - { - this._taxRateService = taxRateService; - this._objectContext = objectContext; - _localizationService = localizationService; - } - - /// - /// Gets tax rate - /// - /// Tax calculation request - /// Tax - public CalculateTaxResult GetTaxRate(CalculateTaxRequest calculateTaxRequest) - { - var result = new CalculateTaxResult(); - - if (calculateTaxRequest.Address == null) - { - result.Errors.Add("Address is not set"); - return result; - } - - var taxRates = _taxRateService.GetAllTaxRates(calculateTaxRequest.TaxCategoryId, - calculateTaxRequest.Address.Country != null ? calculateTaxRequest.Address.Country.Id: 0, - calculateTaxRequest.Address.StateProvince != null ? calculateTaxRequest.Address.StateProvince.Id : 0, - calculateTaxRequest.Address.ZipPostalCode); - if (taxRates.Count > 0) - result.TaxRate = taxRates[0].Percentage; - - return result; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "TaxCountryStateZip"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Tax.CountryStateZip.Controllers" }, { "area", "Tax.CountryStateZip" } }; - } - - /// - /// Install plugin - /// - public override void Install() - { - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Tax.CountryStateZip", false); - - var migrator = new DbMigrator(new Configuration()); - migrator.Update(DbMigrator.InitialDatabase); - - base.Uninstall(); - } - } -} diff --git a/src/Plugins/Tax.CountryStateZip/Data/Migrations/Configuration.cs b/src/Plugins/Tax.CountryStateZip/Data/Migrations/Configuration.cs deleted file mode 100644 index 0ef5465bdc..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Data/Migrations/Configuration.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace SmartStore.Plugin.Tax.CountryStateZip.Data.Migrations -{ - using System; - using System.Data.Entity; - using System.Data.Entity.Migrations; - using System.Linq; - - internal sealed class Configuration : DbMigrationsConfiguration - { - public Configuration() - { - AutomaticMigrationsEnabled = false; - MigrationsDirectory = @"Data\Migrations"; - ContextKey = "SmartStore.TaxCountryStateZip"; - } - - protected override void Seed(TaxRateObjectContext context) - { - // This method will be called after migrating to the latest version. - - // You can use the DbSet.AddOrUpdate() helper extension method - // to avoid creating duplicate seed data. E.g. - // - // context.People.AddOrUpdate( - // p => p.FullName, - // new Person { FullName = "Andrew Peters" }, - // new Person { FullName = "Brice Lambson" }, - // new Person { FullName = "Rowan Miller" } - // ); - // - } - } -} diff --git a/src/Plugins/Tax.CountryStateZip/DependencyRegistrar.cs b/src/Plugins/Tax.CountryStateZip/DependencyRegistrar.cs deleted file mode 100644 index debacb99b7..0000000000 --- a/src/Plugins/Tax.CountryStateZip/DependencyRegistrar.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Autofac; -using Autofac.Core; -using Autofac.Integration.Mvc; -using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Infrastructure.DependencyManagement; -using SmartStore.Data; -using SmartStore.Plugin.Tax.CountryStateZip.Data; -using SmartStore.Plugin.Tax.CountryStateZip.Domain; -using SmartStore.Plugin.Tax.CountryStateZip.Services; - -namespace SmartStore.Plugin.Tax.CountryStateZip -{ - public class DependencyRegistrar : IDependencyRegistrar - { - public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) - { - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - - //register named context - builder.Register(c => new TaxRateObjectContext(DataSettings.Current.DataConnectionString)) - .Named(TaxRateObjectContext.ALIASKEY) - .InstancePerRequest(); - - builder.Register(c => new TaxRateObjectContext(DataSettings.Current.DataConnectionString)) - .InstancePerRequest(); - - //override required repository with our custom context - builder.RegisterType>() - .As>() - .WithParameter(ResolvedParameter.ForNamed(TaxRateObjectContext.ALIASKEY)) - .InstancePerRequest(); - } - - public int Order - { - get { return 1; } - } - } -} diff --git a/src/Plugins/Tax.CountryStateZip/Description.txt b/src/Plugins/Tax.CountryStateZip/Description.txt deleted file mode 100644 index 62c6b6431e..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Tax By Country & State & Zip -SystemName: Tax.CountryStateZip -Version: 1.3 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Tax.CountryStateZip.dll -ResourceRootKey: Plugins.Tax.CountryStateZip \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Localization/resources.de-de.xml b/src/Plugins/Tax.CountryStateZip/Localization/resources.de-de.xml deleted file mode 100644 index 85861f9ed7..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Localization/resources.de-de.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - Steuer nach Land & Bundesland & PLZ - - - Land - - - Das Land. - - - Bundesland - - - Bei Angabe eines Asterisks steht diese Versandart allen Kunden, ungeachtet des Bundeslandes, zur Verfügung. - - - PLZ - - - Bei Angabe eines Asterisks steht diese Versandart allen Kunden, ungeachtet der PLZ, zur Verfügung. - - - Steuerklasse - - - Die Steuerklasse. - - - Prozentsatz - - - Der Steuersatz. - - - Steuersatz anlegen - - - Neuen Steuersatz hinzufügen - - \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Localization/resources.en-us.xml b/src/Plugins/Tax.CountryStateZip/Localization/resources.en-us.xml deleted file mode 100644 index 6c678e11dd..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Localization/resources.en-us.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - Tax By Country & State & Zip - - - Country - - - The country. - - - State / province - - - If an asterisk is selected, then this tax rate will apply to all customers from the given country, regardless of the state. - - - Zip - - - Zip / postal code. If zip is empty, then this tax rate will apply to all customers from the given country or state, regardless of the zip code. - - - Tax category - - - The tax category. - - - Percentage - - - The tax rate. - - - Add tax rate - - - Adding a new tax rate - - \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Models/TaxRateListModel.cs b/src/Plugins/Tax.CountryStateZip/Models/TaxRateListModel.cs deleted file mode 100644 index 2a0175654d..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Models/TaxRateListModel.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Tax.CountryStateZip.Models -{ - public class TaxRateListModel : ModelBase - { - public TaxRateListModel() - { - AvailableCountries = new List(); - AvailableStates = new List(); - AvailableTaxCategories = new List(); - TaxRates = new List(); - } - - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Country")] - public int AddCountryId { get; set; } - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.StateProvince")] - public int AddStateProvinceId { get; set; } - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Zip")] - public string AddZip { get; set; } - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.TaxCategory")] - public int AddTaxCategoryId { get; set; } - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Percentage")] - public decimal AddPercentage { get; set; } - public IList AvailableCountries { get; set; } - public IList AvailableStates { get; set; } - public IList AvailableTaxCategories { get; set; } - - public IList TaxRates { get; set; } - - } -} \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Models/TaxRateModel.cs b/src/Plugins/Tax.CountryStateZip/Models/TaxRateModel.cs deleted file mode 100644 index 0373cfee4f..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Models/TaxRateModel.cs +++ /dev/null @@ -1,29 +0,0 @@ -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Tax.CountryStateZip.Models -{ - public class TaxRateModel : EntityModelBase - { - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.TaxCategory")] - public int TaxCategoryId { get; set; } - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.TaxCategory")] - public string TaxCategoryName { get; set; } - - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Country")] - public int CountryId { get; set; } - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Country")] - public string CountryName { get; set; } - - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.StateProvince")] - public int StateProvinceId { get; set; } - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.StateProvince")] - public string StateProvinceName { get; set; } - - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Zip")] - public string Zip { get; set; } - - [SmartResourceDisplayName("Plugins.Tax.CountryStateZip.Fields.Percentage")] - public decimal Percentage { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Notes.txt b/src/Plugins/Tax.CountryStateZip/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Properties/AssemblyInfo.cs b/src/Plugins/Tax.CountryStateZip/Properties/AssemblyInfo.cs deleted file mode 100644 index 2a08d423b5..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Tax.CountryStateZip")] diff --git a/src/Plugins/Tax.CountryStateZip/RouteProvider.cs b/src/Plugins/Tax.CountryStateZip/RouteProvider.cs deleted file mode 100644 index 6097203dd4..0000000000 --- a/src/Plugins/Tax.CountryStateZip/RouteProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Tax.CountryStateZip -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Tax.CountryStateZip.Configure", - "Plugins/TaxCountryStateZip/Configure", - new { controller = "TaxCountryStateZip", action = "Configure" }, - new[] { "SmartStore.Plugin.Tax.CountryStateZip.Controllers" } - ) - .DataTokens["area"] = "Tax.CountryStateZip"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Tax.CountryStateZip/Services/Extensions.cs b/src/Plugins/Tax.CountryStateZip/Services/Extensions.cs deleted file mode 100644 index 020e8758ff..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Services/Extensions.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using SmartStore.Plugin.Tax.CountryStateZip.Domain; - -namespace SmartStore.Plugin.Tax.CountryStateZip.Services -{ - /// - /// Extensions - /// - public static class Extensions - { - /// - /// Finds tax rate - /// - /// Source - /// Country identifier - /// Tax category identifier - /// Found tax rates - public static IList FindTaxRates(this IList source, - int countryId, int taxCategoryId) - { - var result = new List(); - foreach (TaxRate taxRate in source) - { - if (taxRate.CountryId == countryId && taxRate.TaxCategoryId == taxCategoryId) - result.Add(taxRate); - } - return result; - } - } -} diff --git a/src/Plugins/Tax.CountryStateZip/SmartStore.Plugin.Tax.CountryStateZip.csproj b/src/Plugins/Tax.CountryStateZip/SmartStore.Plugin.Tax.CountryStateZip.csproj deleted file mode 100644 index 65ca68d826..0000000000 --- a/src/Plugins/Tax.CountryStateZip/SmartStore.Plugin.Tax.CountryStateZip.csproj +++ /dev/null @@ -1,240 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {493761CB-5190-4283-8C6C-A8CEB5450CAB} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Tax.CountryStateZip - SmartStore.Plugin.Tax.CountryStateZip - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Tax.CountryStateZip\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Tax.CountryStateZip\ - TRACE - prompt - 4 - false - - - true - ..\..\Presentation\SmartStore.Web\bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll - - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll - - - False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - 201403112350417_Initial.cs - - - - - - - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {ccd7f2c9-6a2c-4cf0-8e89-076b8fc0f144} - SmartStore.Data - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - 201403112350417_Initial.cs - - - PreserveNewest - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Views/TaxCountryStateZip/Configure.cshtml b/src/Plugins/Tax.CountryStateZip/Views/TaxCountryStateZip/Configure.cshtml deleted file mode 100644 index e89a1890e7..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Views/TaxCountryStateZip/Configure.cshtml +++ /dev/null @@ -1,132 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Tax.CountryStateZip.Models.TaxRateListModel -@using SmartStore.Web.Framework; -@using Telerik.Web.Mvc.UI; -@using System.Linq; - - - - -
    - @(Html.Telerik().Grid(Model.TaxRates) - .Name("Grid") - .DataKeys(keys => keys.Add(x => x.Id).RouteKey("Id")) - .Columns(columns => - { - columns.Bound(x => x.CountryName).Width(200).ReadOnly(); - columns.Bound(x => x.StateProvinceName).Width(200).ReadOnly(); - columns.Bound(x => x.Zip).Width(100); - columns.Bound(x => x.TaxCategoryName).Width(200).ReadOnly(); - columns.Bound(x => x.Percentage).Width(100).Format("{0:G29}"); - columns.Command(commands => - { - commands.Edit(); - commands.Delete(); - }).Width(180); - - }) - .Editable(x => - { - x.Mode(GridEditMode.InLine); - }) - .DataBinding(dataBinding => - { - dataBinding.Ajax() - .Select("RatesList", "TaxCountryStateZip", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Tax.CountryStateZip.Controllers" }, { "area", "" } }) - .Update("RateUpdate", "TaxCountryStateZip", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Tax.CountryStateZip.Controllers" }, { "area", "" } }) - .Delete("RateDelete", "TaxCountryStateZip", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Tax.CountryStateZip.Controllers" }, { "area", "" } }); - }) - .EnableCustomBinding(true)) -
    -

    -

    - - -@using (Html.BeginForm()) -{ -
    -

    @T("Plugins.Tax.CountryStateZip.AddRecord.Hint")

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.AddCountryId) - - @Html.DropDownListFor(model => model.AddCountryId, Model.AvailableCountries) - @Html.ValidationMessageFor(model => model.AddCountryId) -
    - @Html.SmartLabelFor(model => model.AddStateProvinceId) - - @Html.DropDownListFor(model => model.AddStateProvinceId, Model.AvailableStates) - @Html.ValidationMessageFor(model => model.AddStateProvinceId) -
    - @Html.SmartLabelFor(model => model.AddZip) - - @Html.EditorFor(model => model.AddZip) - @Html.ValidationMessageFor(model => model.AddZip) -
    - @Html.SmartLabelFor(model => model.AddTaxCategoryId) - - @Html.DropDownListFor(model => model.AddTaxCategoryId, Model.AvailableTaxCategories) - @Html.ValidationMessageFor(model => model.AddTaxCategoryId) -
    - @Html.SmartLabelFor(model => model.AddPercentage) - - @Html.EditorFor(model => model.AddPercentage) - @Html.ValidationMessageFor(model => model.AddPercentage) -
    -   - - -
    -} \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/Views/Web.config b/src/Plugins/Tax.CountryStateZip/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Tax.CountryStateZip/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Tax.CountryStateZip/packages.config b/src/Plugins/Tax.CountryStateZip/packages.config deleted file mode 100644 index 4263d0a15c..0000000000 --- a/src/Plugins/Tax.CountryStateZip/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.CountryStateZip/web.config b/src/Plugins/Tax.CountryStateZip/web.config deleted file mode 100644 index c7103a3dae..0000000000 --- a/src/Plugins/Tax.CountryStateZip/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Tax.FixedRate/Description.txt b/src/Plugins/Tax.FixedRate/Description.txt deleted file mode 100644 index 66cc3c2190..0000000000 --- a/src/Plugins/Tax.FixedRate/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Fixed tax rate provider -SystemName: Tax.FixedRate -Version: 1.4 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Tax.FixedRate.dll -ResourceRootKey: Plugins.Tax.FixedRate \ No newline at end of file diff --git a/src/Plugins/Tax.FixedRate/FixedRateTaxProvider.cs b/src/Plugins/Tax.FixedRate/FixedRateTaxProvider.cs deleted file mode 100644 index 259fbc1c28..0000000000 --- a/src/Plugins/Tax.FixedRate/FixedRateTaxProvider.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Tax; - -namespace SmartStore.Plugin.Tax.FixedRate -{ - /// - /// Fixed rate tax provider - /// - public class FixedRateTaxProvider : BasePlugin, ITaxProvider - { - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; - - public FixedRateTaxProvider(ISettingService settingService, ILocalizationService localizationService) - { - this._settingService = settingService; - _localizationService = localizationService; - } - - /// - /// Gets tax rate - /// - /// Tax calculation request - /// Tax - public CalculateTaxResult GetTaxRate(CalculateTaxRequest calculateTaxRequest) - { - var result = new CalculateTaxResult() - { - TaxRate = GetTaxRate(calculateTaxRequest.TaxCategoryId) - }; - return result; - } - - /// - /// Gets a tax rate - /// - /// The tax category identifier - /// Tax rate - protected decimal GetTaxRate(int taxCategoryId) - { - decimal rate = this._settingService.GetSettingByKey(string.Format("Tax.TaxProvider.FixedRate.TaxCategoryId{0}", taxCategoryId)); - return rate; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "TaxFixedRate"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Tax.FixedRate.Controllers" }, { "area", "Tax.FixedRate" } }; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Tax.FixedRate", false); - - base.Uninstall(); - } - } -} diff --git a/src/Plugins/Tax.FixedRate/Localization/resources.de-de.xml b/src/Plugins/Tax.FixedRate/Localization/resources.de-de.xml deleted file mode 100644 index 4932bc5e93..0000000000 --- a/src/Plugins/Tax.FixedRate/Localization/resources.de-de.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Fester Steuersatz - - - Steuerklasse - - - Steuersatz - - \ No newline at end of file diff --git a/src/Plugins/Tax.FixedRate/Localization/resources.en-us.xml b/src/Plugins/Tax.FixedRate/Localization/resources.en-us.xml deleted file mode 100644 index 3af52c2653..0000000000 --- a/src/Plugins/Tax.FixedRate/Localization/resources.en-us.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - Fixed rate - - - Tax category - - - Rate - - \ No newline at end of file diff --git a/src/Plugins/Tax.FixedRate/Notes.txt b/src/Plugins/Tax.FixedRate/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Tax.FixedRate/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Tax.FixedRate/Properties/AssemblyInfo.cs b/src/Plugins/Tax.FixedRate/Properties/AssemblyInfo.cs deleted file mode 100644 index 990e573c12..0000000000 --- a/src/Plugins/Tax.FixedRate/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Tax.FixedRate")] diff --git a/src/Plugins/Tax.FixedRate/RouteProvider.cs b/src/Plugins/Tax.FixedRate/RouteProvider.cs deleted file mode 100644 index 14aeba34db..0000000000 --- a/src/Plugins/Tax.FixedRate/RouteProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Tax.FixedRate -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Plugin.Tax.FixedRate.Configure", - "Plugins/TaxFixedRate/Configure", - new { controller = "TaxFixedRate", action = "Configure" }, - new[] { "SmartStore.Plugin.Tax.FixedRate.Controllers" } - ) - .DataTokens["area"] = "Tax.FixedRate"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Tax.FixedRate/SmartStore.Plugin.Tax.FixedRate.csproj b/src/Plugins/Tax.FixedRate/SmartStore.Plugin.Tax.FixedRate.csproj deleted file mode 100644 index 9db21cfe66..0000000000 --- a/src/Plugins/Tax.FixedRate/SmartStore.Plugin.Tax.FixedRate.csproj +++ /dev/null @@ -1,206 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {60E882EA-9ACB-4EFE-82A0-8FB1F5884B04} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Tax.FixedRate - SmartStore.Plugin.Tax.FixedRate - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Tax.FixedRate\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Tax.FixedRate\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - PreserveNewest - - - - - PreserveNewest - - - - - PreserveNewest - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.FixedRate/Views/TaxFixedRate/Configure.cshtml b/src/Plugins/Tax.FixedRate/Views/TaxFixedRate/Configure.cshtml deleted file mode 100644 index a7553c720d..0000000000 --- a/src/Plugins/Tax.FixedRate/Views/TaxFixedRate/Configure.cshtml +++ /dev/null @@ -1,36 +0,0 @@ -@{ - Layout = ""; -} -@model Telerik.Web.Mvc.GridModel -@using Telerik.Web.Mvc.UI; -@using System.Linq; - - - - -
    - @(Html.Telerik().Grid(Model.Data) - .Name("Grid") - .DataKeys(keys => keys.Add(x => x.TaxCategoryId).RouteKey("TaxCategoryId")) - .Columns(columns => - { - columns.Bound(x => x.TaxCategoryName).Width(300).ReadOnly(); - columns.Bound(x => x.Rate).Width(100).Format("{0:G29}"); - columns.Command(commands => - { - commands.Edit(); - }).Width(100); - - }) - .Editable(x => - { - x.Mode(GridEditMode.InLine); - }) - .DataBinding(dataBinding => - { - dataBinding.Ajax() - .Select("Configure", "TaxFixedRate", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Tax.FixedRate.Controllers" }, { "area", "" } }) - .Update("TaxRateUpdate", "TaxFixedRate", new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Tax.FixedRate.Controllers" }, { "area", "" } }); - }) - .EnableCustomBinding(true)) -
    diff --git a/src/Plugins/Tax.FixedRate/Views/Web.config b/src/Plugins/Tax.FixedRate/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Tax.FixedRate/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Tax.FixedRate/packages.config b/src/Plugins/Tax.FixedRate/packages.config deleted file mode 100644 index b06b17d7d3..0000000000 --- a/src/Plugins/Tax.FixedRate/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.FixedRate/web.config b/src/Plugins/Tax.FixedRate/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Tax.FixedRate/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Tax.Free/Description.txt b/src/Plugins/Tax.Free/Description.txt deleted file mode 100644 index cd20b92036..0000000000 --- a/src/Plugins/Tax.Free/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Free tax rate provider -SystemName: Tax.Free -Version: 1.3 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Tax.Free.dll -ResourceRootKey: Plugins.Tax.Free \ No newline at end of file diff --git a/src/Plugins/Tax.Free/FreeTaxProvider.cs b/src/Plugins/Tax.Free/FreeTaxProvider.cs deleted file mode 100644 index 8f7ccf0bb9..0000000000 --- a/src/Plugins/Tax.Free/FreeTaxProvider.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Services.Localization; -using SmartStore.Services.Tax; - -namespace SmartStore.Plugin.Tax.Free -{ - /// - /// Free tax provider - /// - public class FreeTaxProvider : BasePlugin, ITaxProvider - { - - - private readonly ILocalizationService _localizationService; - - public FreeTaxProvider(ILocalizationService localizationService) - { - _localizationService = localizationService; - } - - - /// - /// Gets tax rate - /// - /// Tax calculation request - /// Tax - public CalculateTaxResult GetTaxRate(CalculateTaxRequest calculateTaxRequest) - { - var result = new CalculateTaxResult() - { - TaxRate = decimal.Zero - }; - return result; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = null; - controllerName = null; - routeValues = null; - } - - public override void Install() - { - //locales - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - //locales - this.DeletePluginLocaleResource("Plugins.Tax.FixedRate.Fields.TaxCategoryName"); - this.DeletePluginLocaleResource("Plugins.Tax.FixedRate.Fields.Rate"); - - base.Uninstall(); - } - } -} diff --git a/src/Plugins/Tax.Free/Localization/resources.de-de.xml b/src/Plugins/Tax.Free/Localization/resources.de-de.xml deleted file mode 100644 index 5617e6bf61..0000000000 --- a/src/Plugins/Tax.Free/Localization/resources.de-de.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - Steuerbefreit - - \ No newline at end of file diff --git a/src/Plugins/Tax.Free/Localization/resources.en-us.xml b/src/Plugins/Tax.Free/Localization/resources.en-us.xml deleted file mode 100644 index dc4480af3f..0000000000 --- a/src/Plugins/Tax.Free/Localization/resources.en-us.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - Free tax rate - - \ No newline at end of file diff --git a/src/Plugins/Tax.Free/Notes.txt b/src/Plugins/Tax.Free/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Tax.Free/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Tax.Free/Properties/AssemblyInfo.cs b/src/Plugins/Tax.Free/Properties/AssemblyInfo.cs deleted file mode 100644 index 383ac1e294..0000000000 --- a/src/Plugins/Tax.Free/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Tax.Free")] diff --git a/src/Plugins/Tax.Free/SmartStore.Plugin.Tax.Free.csproj b/src/Plugins/Tax.Free/SmartStore.Plugin.Tax.Free.csproj deleted file mode 100644 index d2e59f548a..0000000000 --- a/src/Plugins/Tax.Free/SmartStore.Plugin.Tax.Free.csproj +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {A999F243-C752-4430-9AF6-8FCE281C9C20} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Tax.Free - SmartStore.Plugin.Tax.Free - v4.5 - 512 - - - - - - - - - - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Tax.Free\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Tax.Free\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - - - - - web.config - - - web.config - - - web.config - - - web.config - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.Free/web.Debug.config b/src/Plugins/Tax.Free/web.Debug.config deleted file mode 100644 index 77331c88e0..0000000000 --- a/src/Plugins/Tax.Free/web.Debug.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.Free/web.EFMigrations.config b/src/Plugins/Tax.Free/web.EFMigrations.config deleted file mode 100644 index 804c7ee4c2..0000000000 --- a/src/Plugins/Tax.Free/web.EFMigrations.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.Free/web.PluginDev.config b/src/Plugins/Tax.Free/web.PluginDev.config deleted file mode 100644 index 804c7ee4c2..0000000000 --- a/src/Plugins/Tax.Free/web.PluginDev.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.Free/web.Release.config b/src/Plugins/Tax.Free/web.Release.config deleted file mode 100644 index 804c7ee4c2..0000000000 --- a/src/Plugins/Tax.Free/web.Release.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Tax.Free/web.config b/src/Plugins/Tax.Free/web.config deleted file mode 100644 index bd1f422a0a..0000000000 --- a/src/Plugins/Tax.Free/web.config +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Widgets.GoogleAnalytics/Description.txt b/src/Plugins/Widgets.GoogleAnalytics/Description.txt deleted file mode 100644 index aaada58315..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Google Analytics -SystemName: Widgets.GoogleAnalytics -Version: 1.6 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Widgets.GoogleAnalytics.dll -ResourceRootKey: Plugins.Widgets.GoogleAnalytics \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/GoogleAnalyticPlugin.cs b/src/Plugins/Widgets.GoogleAnalytics/GoogleAnalyticPlugin.cs deleted file mode 100644 index 98c07b78b6..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/GoogleAnalyticPlugin.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Services.Cms; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.Widgets.GoogleAnalytics -{ - /// - /// Live person provider - /// - public class GoogleAnalyticPlugin : BasePlugin, IWidgetPlugin - { - private readonly ISettingService _settingService; - private readonly GoogleAnalyticsSettings _googleAnalyticsSettings; - private readonly ILocalizationService _localizationService; - - public GoogleAnalyticPlugin(ISettingService settingService, - GoogleAnalyticsSettings googleAnalyticsSettings, - ILocalizationService localizationService) - { - this._settingService = settingService; - this._googleAnalyticsSettings = googleAnalyticsSettings; - _localizationService = localizationService; - } - - /// - /// Gets widget zones where this widget should be rendered - /// - /// Widget zones - public IList GetWidgetZones() - { - return !string.IsNullOrWhiteSpace(_googleAnalyticsSettings.WidgetZone) - ? new List() { _googleAnalyticsSettings.WidgetZone } - : new List() { "head_html_tag" }; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "WidgetsGoogleAnalytics"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Widgets.GoogleAnalytics.Controllers" }, { "area", "Widgets.GoogleAnalytics" } }; - } - - /// - /// Gets a route for displaying widget - /// - /// Widget zone where it's displayed - /// Action name - /// Controller name - /// Route values - public void GetDisplayWidgetRoute(string widgetZone, object model, int storeId, out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PublicInfo"; - controllerName = "WidgetsGoogleAnalytics"; - routeValues = new RouteValueDictionary() - { - {"Namespaces", "SmartStore.Plugin.Widgets.GoogleAnalytics.Controllers"}, - {"area", "Widgets.GoogleAnalytics"}, - {"widgetZone", widgetZone} - }; - } - - /// - /// Install plugin - /// - public override void Install() - { - var settings = new GoogleAnalyticsSettings() - { - GoogleId = "UA-0000000-0", - //TrackingScript = " ", - TrackingScript = @" -", - EcommerceScript = @"_gaq.push(['_addTrans', '{ORDERID}', '{SITE}', '{TOTAL}', '{TAX}', '{SHIP}', '{CITY}', '{STATEPROVINCE}', '{COUNTRY}']); -{DETAILS} -_gaq.push(['_trackTrans']); ", - EcommerceDetailScript = @"_gaq.push(['_addItem', '{ORDERID}', '{PRODUCTSKU}', '{PRODUCTNAME}', '{CATEGORYNAME}', '{UNITPRICE}', '{QUANTITY}' ]); ", - - }; - _settingService.SaveSetting(settings); - - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Widgets.GoogleAnalytics", false); - - _settingService.DeleteSetting(); - - base.Uninstall(); - } - } -} diff --git a/src/Plugins/Widgets.GoogleAnalytics/Localization/resources.de-de.xml b/src/Plugins/Widgets.GoogleAnalytics/Localization/resources.de-de.xml deleted file mode 100644 index dd63f56b5f..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Localization/resources.de-de.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - Google Analytics - - - - Google Analytics ist ein kostenloser Statistikdienst von Google. Der Dienst erfasst Statistiken über Besucher und Ecommerce-Konversion auf Ihrer Webseite

    -

    Führen Sie die folgenden Schritte aus um Google Analytics auf Ihrer Webseite einzubinden:

    -
      -
    • erstellen Sie hier einen "Google Analytics"-Account und folgen Sie dem Wizard um Ihre Webseite zuzufügen
    • -
    • Kopieren Sie die "Google Analytics"-ID in das entspechende Feld in folgendem Formular
    • -
    • Kopieren Sie den Tracking-Code in die "Tracking-Code"-Box in folgendem Formular
    • -
    • KLicken Sie den "Speichern"-Button und Google Analytics wird in Ihre Webseite integriert
    • -
    - ]]> -
    -
    - - ID - - - Geben Sie hier Ihre "Google Analytics"-ID an. - - - Tracking-Code mit {ECOMMERCE}-Zeile - - - Kopieren Sie den von Google erzeugten Tracking-Code in dieses Feld. {GOOGLEID} und {ECOMMERCE} werden automatisch ersetzt. - - - Tracking-Code für {ECOMMERCE}-Teil, mit {DETAILS}-Zeile - - - Kopieren Sie den von Google erzeugten Tracking-Code in dieses Feld. {ORDERID}, {SITE}, {TOTAL}, {TAX}, {SHIP}, {CITY}, {STATEPROVINCE}, {COUNTRY} und {DETAILS} werden automatisch ersetzt. - - - Tracking-Code für {DETAILS}-Teil - - - Kopieren Sie den von Google erzeugten Tracking-Code in dieses Feld. {ORDERID}, {PRODUCTSKU}, {PRODUCTNAME}, {CATEGORYNAME}, {UNITPRICE} und {QUANTITY} werden automatisch ersetzt. - -
    \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/Localization/resources.en-us.xml b/src/Plugins/Widgets.GoogleAnalytics/Localization/resources.en-us.xml deleted file mode 100644 index 2e97f01971..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Localization/resources.en-us.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - Google Analytics - - - - Google Analytics is a free website stats tool from Google. It keeps track of statistics - about the visitors and ecommerce conversion on your website.

    -

    Follow the next steps to enable Google Analytics integration:

    -
      -
    • Create a Google Analytics account and follow the wizard to add your website
    • -
    • Copy the Google Analytics ID into the 'ID' box below
    • -
    • Copy the tracking code from Google Analytics into the 'Tracking Code' box below
    • -
    • Click the 'Save' button below and Google Analytics will be integrated into your store
    • -
    - ]]> -
    -
    - - ID - - - Enter Google Analytics ID. - - - Tracking code with {ECOMMERCE} line - - - Paste the tracking code generated by Google Analytics here. {GOOGLEID} and {ECOMMERCE} will be dynamically replaced. - - - Tracking code for {ECOMMERCE} part, with {DETAILS} line - - - Paste the tracking code generated by Google analytics here. {ORDERID}, {SITE}, {TOTAL}, {TAX}, {SHIP}, {CITY}, {STATEPROVINCE}, {COUNTRY}, {DETAILS} will be dynamically replaced. - - - Tracking code for {DETAILS} part - - - Paste the tracking code generated by Google analytics here. {ORDERID}, {PRODUCTSKU}, {PRODUCTNAME}, {CATEGORYNAME}, {UNITPRICE}, {QUANTITY} will be dynamically replaced. - -
    \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/Models/ConfigurationModel.cs b/src/Plugins/Widgets.GoogleAnalytics/Models/ConfigurationModel.cs deleted file mode 100644 index 117cd44ea7..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Models/ConfigurationModel.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Widgets.GoogleAnalytics.Models -{ - public class ConfigurationModel : ModelBase - { - - public ConfigurationModel() - { - AvailableZones = new List(); - } - - [SmartResourceDisplayName("Admin.ContentManagement.Widgets.ChooseZone")] - public string ZoneId { get; set; } - public IList AvailableZones { get; set; } - - - [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.GoogleId")] - [AllowHtml] - public string GoogleId { get; set; } - - [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.TrackingScript")] - [AllowHtml] - //tracking code - public string TrackingScript { get; set; } - - [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.EcommerceScript")] - [AllowHtml] - public string EcommerceScript { get; set; } - - [SmartResourceDisplayName("Plugins.Widgets.GoogleAnalytics.EcommerceDetailScript")] - [AllowHtml] - public string EcommerceDetailScript { get; set; } - - } -} \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/Notes.txt b/src/Plugins/Widgets.GoogleAnalytics/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/Properties/AssemblyInfo.cs b/src/Plugins/Widgets.GoogleAnalytics/Properties/AssemblyInfo.cs deleted file mode 100644 index 2f2a908fe4..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,2 +0,0 @@ -using System.Reflection; -[assembly: AssemblyTitle("SmartStore.Plugin.Widgets.GoogleAnalytics")] diff --git a/src/Plugins/Widgets.GoogleAnalytics/RouteProvider.cs b/src/Plugins/Widgets.GoogleAnalytics/RouteProvider.cs deleted file mode 100644 index dfcf2c8691..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/RouteProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Widgets.GoogleAnalytics -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Widgets.GoogleAnalytics", - "Plugins/WidgetsGoogleAnalytics/{action}", - new { controller = "WidgetsGoogleAnalytics", action = "Configure" }, - new[] { "SmartStore.Plugin.Widgets.GoogleAnalytics.Controllers" } - ) - .DataTokens["area"] = "Widgets.GoogleAnalytics"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Widgets.GoogleAnalytics/SmartStore.Plugin.Widgets.GoogleAnalytics.csproj b/src/Plugins/Widgets.GoogleAnalytics/SmartStore.Plugin.Widgets.GoogleAnalytics.csproj deleted file mode 100644 index 666d9f43eb..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/SmartStore.Plugin.Widgets.GoogleAnalytics.csproj +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {C2B83AF5-80F6-4B8C-8628-FA7DE10C3BB5} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Widgets.GoogleAnalytics - SmartStore.Plugin.Widgets.GoogleAnalytics - v4.5 - 512 - - - - - - - - - - ..\..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Widgets.GoogleAnalytics\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Widgets.GoogleAnalytics\ - TRACE - prompt - 4 - false - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - - - - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541AD-F659-47DA-8763-16F36C5CD2F4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - - Designer - PreserveNewest - - - PreserveNewest - - - - - PreserveNewest - - - PreserveNewest - - - Designer - Always - - - Designer - Always - - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/Views/Web.config b/src/Plugins/Widgets.GoogleAnalytics/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Widgets.GoogleAnalytics/Views/WidgetsGoogleAnalytics/Configure.cshtml b/src/Plugins/Widgets.GoogleAnalytics/Views/WidgetsGoogleAnalytics/Configure.cshtml deleted file mode 100644 index eebe5ba15b..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/Views/WidgetsGoogleAnalytics/Configure.cshtml +++ /dev/null @@ -1,76 +0,0 @@ -@{ - Layout = ""; -} -@model SmartStore.Plugin.Widgets.GoogleAnalytics.Models.ConfigurationModel -@using SmartStore.Web.Framework; - -
    - @Html.Raw(@T("Plugins.Widgets.GoogleAnalytics.AdminInstruction")) -
    - -@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) - -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.ZoneId) - - @Html.DropDownListFor(model => model.ZoneId, Model.AvailableZones) - @Html.ValidationMessageFor(model => model.ZoneId) -
    - @Html.SmartLabelFor(model => model.GoogleId) - - @Html.SettingEditorFor(model => model.GoogleId) - @Html.ValidationMessageFor(model => model.GoogleId) -
    - @Html.SmartLabelFor(model => model.TrackingScript) - - @Html.SettingOverrideCheckbox(model => model.TrackingScript) - @Html.TextAreaFor(model => model.TrackingScript, new { style = "Width: 600px; Height: 200px;" }) - @Html.ValidationMessageFor(model => model.TrackingScript) -
    - @Html.SmartLabelFor(model => model.EcommerceScript) - - @Html.SettingOverrideCheckbox(model => model.EcommerceScript) - @Html.TextAreaFor(model => model.EcommerceScript, new { style = "Width: 600px; Height: 50px;" }) - @Html.ValidationMessageFor(model => model.EcommerceScript) -
    - @Html.SmartLabelFor(model => model.EcommerceDetailScript) - - @Html.SettingOverrideCheckbox(model => model.EcommerceDetailScript) - @Html.TextAreaFor(model => model.EcommerceDetailScript, new { style = "Width: 600px; Height: 50px;" }) - @Html.ValidationMessageFor(model => model.EcommerceDetailScript) -
    -   - - -
    - -} \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/packages.config b/src/Plugins/Widgets.GoogleAnalytics/packages.config deleted file mode 100644 index e36ec51261..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.GoogleAnalytics/web.config b/src/Plugins/Widgets.GoogleAnalytics/web.config deleted file mode 100644 index 8682e70c3d..0000000000 --- a/src/Plugins/Widgets.GoogleAnalytics/web.config +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/TrustedShops-rgb-Siegel_100Hpx.png b/src/Plugins/Widgets.TrustedShopsSeal/Content/images/TrustedShops-rgb-Siegel_100Hpx.png deleted file mode 100644 index 695cbb44a8..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/TrustedShops-rgb-Siegel_100Hpx.png and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_de.jpg b/src/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_de.jpg deleted file mode 100644 index 606c4f0e0f..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_de.jpg and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_en.jpg b/src/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_en.jpg deleted file mode 100644 index e78e0d3c7b..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_en.jpg and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/prepared.jpg b/src/Plugins/Widgets.TrustedShopsSeal/Content/images/prepared.jpg deleted file mode 100644 index 79dd589207..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/prepared.jpg and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_de.jpg b/src/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_de.jpg deleted file mode 100644 index 0ee9b5d400..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_de.jpg and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_en.jpg b/src/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_en.jpg deleted file mode 100644 index 1d80c18d44..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_en.jpg and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/trusted-shops-bg.jpg b/src/Plugins/Widgets.TrustedShopsSeal/Content/images/trusted-shops-bg.jpg deleted file mode 100644 index 1825563d14..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/Content/images/trusted-shops-bg.jpg and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Content/trustedshops.css b/src/Plugins/Widgets.TrustedShopsSeal/Content/trustedshops.css deleted file mode 100644 index f8a033f4db..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Content/trustedshops.css +++ /dev/null @@ -1,51 +0,0 @@ -#tsBox { - font-size: 80%; -} -#tsBox #tsInnerBox { - vertical-align: middle; - margin-top: 0px; - padding: 2px; -} -#tsBox #tsSeal { - text-align: center; - padding: 2px; -} -#tsBox #tsSeal input { - border: 0px none; -} -#tsBox #tsText { - text-align: center; - padding: 2px; -} -#tsBox #tsText a { - padding-bottom: 4px; -} - -.block-trusted-shops-seal .block-body { - background: url(images/trusted-shops-bg.jpg) no-repeat !important; -} - -.ts-info { - padding: 0 20px 20px 20px; -} -.ts-info .prepared { - background-image: url('images/prepared.jpg'); - height: 75px; - background-repeat: no-repeat; - background-position: top left; - color: white; - font: bold 13px/13px sans-serif; - text-align: right; - width: 240px; - margin-left: 11px; - padding-top: 4px; - text-transform: uppercase; -} -.ts-info .prepared span { - margin-right: 70px; - display: block; -} -.ts-info .intro { - width: 900px; - margin-bottom: 10px; -} \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Controllers/TrustedShopsSealController.cs b/src/Plugins/Widgets.TrustedShopsSeal/Controllers/TrustedShopsSealController.cs deleted file mode 100644 index f9cdbb9a25..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Controllers/TrustedShopsSealController.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Plugin.Widgets.TrustedShopsSeal.Models; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; -using SmartStore.Services.Stores; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Web.Framework.Settings; -using SmartStore.Web.Framework.UI; - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal.Controllers -{ - - public class TrustedShopsSealController : SmartController - { - private readonly IWorkContext _workContext; - private readonly IStoreContext _storeContext; - private readonly IStoreService _storeService; - private readonly ISettingService _settingService; - private readonly ILocalizationService _localizationService; - - public TrustedShopsSealController(IWorkContext workContext, - IStoreContext storeContext, IStoreService storeService, - ISettingService settingService, - ILocalizationService localizationService) - { - _workContext = workContext; - _storeContext = storeContext; - _storeService = storeService; - _settingService = settingService; - _localizationService = localizationService; - } - - public bool IsTrustedShopIdValid(ConfigurationModel model) - { - if (model.TrustedShopsId.IsNullOrEmpty()) - return false; - - if (model.IsTestMode) - { - var tsProtectionServiceSandbox = new TrustedShopsSeal.com.trustedshops.qa.TSProtectionService(); - var certStatus = new TrustedShopsSeal.com.trustedshops.qa.CertificateStatus(); - certStatus = tsProtectionServiceSandbox.checkCertificate(model.TrustedShopsId); - - return (certStatus.stateEnum == "TEST"); - } - else - { - var tsProtectionServiceLive = new TrustedShopsSeal.com.trustedshops.www.TSProtectionService(); - var certStatus = new TrustedShopsSeal.com.trustedshops.www.CertificateStatus(); - certStatus = tsProtectionServiceLive.checkCertificate(model.TrustedShopsId); - - return (certStatus.stateEnum == "PRODUCTION"); - } - } - - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure() - { - //load settings for a chosen store scope - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var trustedShopsSealSettings = _settingService.LoadSetting(storeScope); - - var model = new ConfigurationModel(); - model.TrustedShopsId = trustedShopsSealSettings.TrustedShopsId; - model.IsTestMode = trustedShopsSealSettings.IsTestMode; - model.ShopName = trustedShopsSealSettings.ShopName; - model.ShopText = trustedShopsSealSettings.ShopText; - model.WidgetZone = trustedShopsSealSettings.WidgetZone; - - model.AvailableZones.Add(new SelectListItem() { Text = "Before left side column", Value = "left_side_column_before" }); - model.AvailableZones.Add(new SelectListItem() { Text = "After left side column", Value = "left_side_column_after" }); - model.AvailableZones.Add(new SelectListItem() { Text = "Before right side column", Value = "right_side_column_before" }); - model.AvailableZones.Add(new SelectListItem() { Text = "After right side column", Value = "right_side_column_after" }); - model.AvailableZones.Add(new SelectListItem() { Text = "Homepage bottom", Value = "home_page_bottom" }); - - var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); - storeDependingSettingHelper.GetOverrideKeys(trustedShopsSealSettings, model, storeScope, _settingService); - - return View(model); - } - - [HttpPost] - [AdminAuthorize] - [ChildActionOnly] - public ActionResult Configure(ConfigurationModel model, FormCollection form) - { - if (!ModelState.IsValid) - return Configure(); - - //load settings for a chosen store scope - var storeDependingSettingHelper = new StoreDependingSettingHelper(ViewData); - var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); - var trustedShopsSealSettings = _settingService.LoadSetting(storeScope); - - bool trustedShopIdOverride = storeDependingSettingHelper.IsOverrideChecked(trustedShopsSealSettings, "TrustedShopsId", form); - bool isTrustedShopIdValid = true; - - if (trustedShopIdOverride || storeScope == 0) // do validation - { - isTrustedShopIdValid = IsTrustedShopIdValid(model); - - if (isTrustedShopIdValid) - NotifySuccess(_localizationService.GetResource("Plugins.Widgets.TrustedShopsSeal.CheckIdSuccess"), true); - else - NotifyError(_localizationService.GetResource("Plugins.Widgets.TrustedShopsSeal.CheckIdError"), true); - } - - if (isTrustedShopIdValid) //save settings - { - trustedShopsSealSettings.TrustedShopsId = model.TrustedShopsId; - trustedShopsSealSettings.IsTestMode = model.IsTestMode; - trustedShopsSealSettings.WidgetZone = model.WidgetZone; - trustedShopsSealSettings.ShopName = model.ShopName; - trustedShopsSealSettings.ShopText = model.ShopText; - - storeDependingSettingHelper.UpdateSettings(trustedShopsSealSettings, form, storeScope, _settingService); - _settingService.ClearCache(); - } - - return Configure(); - } - - [ChildActionOnly] - public ActionResult PublicInfo(string widgetZone) - { - var trustedShopsSealSettings = _settingService.LoadSetting(_storeContext.CurrentStore.Id); - - var model = new PublicInfoModel(); - model.TrustedShopsId = trustedShopsSealSettings.TrustedShopsId; - model.IsTestMode = trustedShopsSealSettings.IsTestMode; - model.ShopName = trustedShopsSealSettings.ShopName; - model.ShopText = trustedShopsSealSettings.ShopText; - - return View(model); - } - } -} \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Description.txt b/src/Plugins/Widgets.TrustedShopsSeal/Description.txt deleted file mode 100644 index 1da104ae3b..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Description.txt +++ /dev/null @@ -1,7 +0,0 @@ -FriendlyName: Trusted Shops Seal -SystemName: Widgets.TrustedShopsSeal -Version: 1.4 -MinAppVersion: 2.0.0 -DisplayOrder: 1 -FileName: SmartStore.Plugin.Widgets.TrustedShopsSeal.dll -ResourceRootKey: Plugins.Widgets.TrustedShopsSeal \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Localization/resources.de-de.xml b/src/Plugins/Widgets.TrustedShopsSeal/Localization/resources.de-de.xml deleted file mode 100644 index ac7e32e503..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Localization/resources.de-de.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - Trusted Shops Siegel - - - - - - - - - -

    Mehr Umsatz durch mehr Vertrauen!

    -

    - Das Trusted Shops Gütesiegel ist optimal, um das Vertrauen Ihrer Online-Kunden zu steigern. - Vertrauen erhöht die Bereitschaft Ihrer Kunden, bei Ihnen einzukaufen. -

    -

    Weniger Kaufabbrüche

    -

    - Sie bieten Ihren Online-Kunden ein starkes Argument: den Trusted Shops Käuferschutz. Durch diese - zusätzliche Sicherheit werden weniger Einkäufe abgebrochen. -

    - -

    Ihre Kunden werden zu Verkäufern

    -

    - Nutzen Sie unsere Kundenbewertungen als wichtiges Marketing-Tool, um das Vertrauen Ihrer Kunden - zu steigern. Lassen Sie Ihre gute Bewertung bei Google Shopping anzeigen und erhöhen Sie Ihren Traffic. -

    - - Informieren und anmelden! - - ]]> -
    -
    - - - Um das Trusted Shops Siegel auf Ihrer Seite einzubinden, finden Sie nachfolgend eine Schritt-für-Schritt Anleitung:

    -
      -
    • Registrieren Sie sich bei Trusted Shops
    • -
    • Geben Sie Ihre Trusted Shops ID in dem vorgesehenen Feld an.
    • -
    • Geben Sie optional den Namen Ihres Shops und einen beschreibenden Text an, die Im Widget angezeigt werden sollen.
    • -
    • Das Siegel wird nun in der angegebenen Widget-Zone in Ihrem Shop dargestellt.
    • -
    - ]]> -
    -
    - - - Trusted Shops - - - - Trusted Shops Id - - - Geben Sie hier Ihre Trusted Shops Id an. - - - Testmodus aktivieren - - - Testmodus aktivieren - - - Name des Shops - - - Geben Sie hier den Namen des Shops an, wie er im Widget angezeigt werden soll. - - - Beschreibender Text - - - Geben Sie hier einen beschreibenden Text an, wie er im Widget angezeigt werden soll. - - - Die Validierung Ihrer Trusted Shops ID war erfolgreich. - - - Die Validierung Ihrer Trusted Shops ID war nicht erfolgreich. - - - Bitte geben Sie Ihre Trusted Shops ID an. - - - Trusted Shops Siegel - Klicken Sie hier für eine Bestätigung. - - - ~/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_de.jpg - - - ~/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_de.jpg - - - SmartStore.NET ist bereits optimal für die Zertifizierung vorbereitet! - - -
    \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Localization/resources.en-us.xml b/src/Plugins/Widgets.TrustedShopsSeal/Localization/resources.en-us.xml deleted file mode 100644 index 9d54ea6c4d..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Localization/resources.en-us.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - Trusted Shops Seal - - - - - - - - - - -

    More trust leads to more sales!

    -

    - The Trusted Shops Seal of Approval is the optimal way to increase the trust of your online customers. - Trust increases customers' willingness to buy from you. -

    - -

    Less abandoned purchases

    -

    - Give your online customers a strong reason to buy proposing the Trusted Shops Buyer Protection. - This additional security leads to less shopping basket abandonment. -

    - -

    Your Customers become Sellers

    -

    - Use our retailer evaluation with integrated customer opinions as an important marketing tool to - increase the trust of your customers. Display your positive evaluation at Google Shopping and - increase your traffic. -

    - Apply now! - - ]]> -
    -
    - - - Please find our step by step set up guide detailed below:

    -
      -
    • Register at Trusted Shops
    • -
    • Enter your Trusted Shops ID in the assigned area below.
    • -
    • Enter the name of your shop and a descriptive text, as they should be displayed within the widget.
    • -
    • Now the seal will be display in your shop.
    • -
    - ]]> -
    -
    - - - Trusted Shops - - - - Trusted Shops Id - - - Please enter your Trusted Shops Id here. - - - Activate test mode - - - Activate test mode - - - Name of the shop - - - Please enter the name of the shop here, as it'll be shown within the widget. - - - Descriptive text - - - Please enter a descriptive text, as it'll be shown within the widget. - - - - The validation of your Trusted Shops Id was successfull. - - - The validation of your Trusted Shops Id wasn't successfull. - - - - Please enter your Trusted Shops ID. - - - - Trusted Shops Seal of Approval - click to verify. - - - - ~/Plugins/Widgets.TrustedShopsSeal/Content/images/logo_en.jpg - - - ~/Plugins/Widgets.TrustedShopsSeal/Content/images/seal_rating_en.jpg - - - SmartStore.NET is already well prepared for certification! - - -
    \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Models/ConfigurationModel.cs b/src/Plugins/Widgets.TrustedShopsSeal/Models/ConfigurationModel.cs deleted file mode 100644 index 36d05ac941..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Models/ConfigurationModel.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; -using FluentValidation.Attributes; -using SmartStore.Plugin.Widgets.TrustedShopsSeal.Validators; - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal.Models -{ - [Validator(typeof(TrustedShopsSealValidator))] - public class ConfigurationModel : ModelBase - { - public ConfigurationModel() - { - AvailableZones = new List(); - } - - [SmartResourceDisplayName("Admin.ContentManagement.Widgets.ChooseZone")] - public string WidgetZone { get; set; } - public IList AvailableZones { get; set; } - - [SmartResourceDisplayName("Plugins.Widgets.TrustedShopsSeal.TrustedShopsId")] - public string TrustedShopsId { get; set; } - - [SmartResourceDisplayName("Plugins.Widgets.TrustedShopsSeal.ShopName")] - public string ShopName { get; set; } - - [SmartResourceDisplayName("Plugins.Widgets.TrustedShopsSeal.ShopText")] - public string ShopText { get; set; } - - [SmartResourceDisplayName("Plugins.Widgets.TrustedShopsSeal.IsTestMode")] - public bool IsTestMode { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Models/PublicInfoModel.cs b/src/Plugins/Widgets.TrustedShopsSeal/Models/PublicInfoModel.cs deleted file mode 100644 index e6075ce2e6..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Models/PublicInfoModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal.Models -{ - public class PublicInfoModel : ModelBase - { - public string TrustedShopsId { get; set; } - public string ShopName { get; set; } - public string ShopText { get; set; } - public bool IsTestMode { get; set; } - } -} \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Notes.txt b/src/Plugins/Widgets.TrustedShopsSeal/Notes.txt deleted file mode 100644 index 4eead83fd3..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -'Copy local' property of the referenced assemblies are set to 'false'. -We know that they're referenced by the main web applications. So there's no need to deploy them. -It can dramatically reduce package size. - - -Set project output path to ..\..\Presentation\SmartStore.Web\Plugins\{PluginName}\ (both 'Release' and 'Debug' configurations) - - -All views should marked as embedded resources \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Properties/AssemblyInfo.cs b/src/Plugins/Widgets.TrustedShopsSeal/Properties/AssemblyInfo.cs deleted file mode 100644 index 926ebc287b..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SmartStore.Plugin.Widgets.TrustedShopsSeal")] diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Properties/Settings.Designer.cs b/src/Plugins/Widgets.TrustedShopsSeal/Properties/Settings.Designer.cs deleted file mode 100644 index 6623f778c0..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Properties/Settings.Designer.cs +++ /dev/null @@ -1,48 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.18444 -// -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. -// -//------------------------------------------------------------------------------ - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)] - [global::System.Configuration.DefaultSettingValueAttribute("https://qa.trustedshops.com:443/ts/services/TsProtection")] - public string SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_qa_TSProtectionService { - get { - return ((string)(this["SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_qa_TSProtectionServic" + - "e"])); - } - } - - [global::System.Configuration.ApplicationScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)] - [global::System.Configuration.DefaultSettingValueAttribute("https://www.trustedshops.com:443/ts/services/TsProtection")] - public string SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_www_TSProtectionService { - get { - return ((string)(this["SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_www_TSProtectionServi" + - "ce"])); - } - } - } -} diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Properties/Settings.settings b/src/Plugins/Widgets.TrustedShopsSeal/Properties/Settings.settings deleted file mode 100644 index fc106989f9..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Properties/Settings.settings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - https://qa.trustedshops.com:443/ts/services/TsProtection - - - https://www.trustedshops.com:443/ts/services/TsProtection - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/RouteProvider.cs b/src/Plugins/Widgets.TrustedShopsSeal/RouteProvider.cs deleted file mode 100644 index e236153fdd..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/RouteProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - routes.MapRoute("Widgets.TrustedShopsSeal", - "Plugins/TrustedShopsSeal/{action}", - new { controller = "TrustedShopsSeal", action = "Configure" }, - new[] { "SmartStore.Plugin.Widgets.TrustedShopsSeal.Controllers" } - ) - .DataTokens["area"] = "Widgets.TrustedShopsSeal"; - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Plugins/Widgets.TrustedShopsSeal/SmartStore.Plugin.Widgets.TrustedShopsSeal.csproj b/src/Plugins/Widgets.TrustedShopsSeal/SmartStore.Plugin.Widgets.TrustedShopsSeal.csproj deleted file mode 100644 index 9c5bb26f81..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/SmartStore.Plugin.Widgets.TrustedShopsSeal.csproj +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - False - - - False - - - - Debug - AnyCPU - {DD12934F-62E5-4A12-858A-82B2F17EA1D4} - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - SmartStore.Plugin.Widgets.TrustedShopsSeal - SmartStore.Plugin.Widgets.TrustedShopsSeal - v4.5 - 512 - ..\ - true - - - 4.0 - true - - - - - - - - true - full - false - ..\..\Presentation\SmartStore.Web\Plugins\Widgets.TrustedShopsSeal\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - ..\..\Presentation\SmartStore.Web\Plugins\Widgets.TrustedShopsSeal\ - TRACE - prompt - 4 - - - true - bin\EFMigrations\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - true - bin\ - DEBUG;TRACE - full - AnyCPU - prompt - MinimumRecommendedRules.ruleset - - - - ..\..\packages\FluentValidation.5.0.0.1\lib\Net40\FluentValidation.dll - - - - - - - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll - - - False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll - - - False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll - - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll - - - False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll - - - - - - - - - - Properties\AssemblySharedInfo.cs - - - Properties\AssemblyVersionInfo.cs - - - - True - True - Settings.settings - - - - - - - - - - True - True - Reference.map - - - True - True - Reference.map - - - - - {6bda8332-939f-45b7-a25e-7a797260ae59} - SmartStore.Core - - - {210541ad-f659-47da-8763-16f36c5cd2f4} - SmartStore.Services - - - {75fd4163-333c-4dd5-854d-2ef294e45d94} - SmartStore.Web.Framework - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - PreserveNewest - - - Always - - - Designer - Always - - - Designer - Always - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - - - PreserveNewest - - - - - PreserveNewest - - - - - - PreserveNewest - - - Reference.map - - - Reference.map - - - MSDiscoCodeGenerator - Reference.cs - - - - Reference.map - - - Reference.map - - - MSDiscoCodeGenerator - Reference.cs - - - - PreserveNewest - - - - - - - - Dynamic - Web References\com.trustedshops.qa\ - https://qa.trustedshops.com/ts/services/TsProtection%3fwsdl - - - - - Settings - SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_qa_TSProtectionService - - - Dynamic - Web References\com.trustedshops.www\ - https://www.trustedshops.com/ts/services/TsProtection%3fwsdl - - - - - Settings - SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_www_TSProtectionService - - - - - - - - - - - - True - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/TrustedShopsSealPlugin.cs b/src/Plugins/Widgets.TrustedShopsSeal/TrustedShopsSealPlugin.cs deleted file mode 100644 index 2b3d383db8..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/TrustedShopsSealPlugin.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections.Generic; -using System.Web.Routing; -using SmartStore.Core.Plugins; -using SmartStore.Services.Cms; -using SmartStore.Services.Configuration; -using SmartStore.Services.Localization; - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal -{ - /// - /// Trusted Shops seal provider - /// - public class TrustedShopsSealPlugin : BasePlugin, IWidgetPlugin - { - private readonly TrustedShopsSealSettings _trustedShopsSealSettings; - private readonly ILocalizationService _localizationService; - private readonly ISettingService _settingService; - - public TrustedShopsSealPlugin(TrustedShopsSealSettings trustedShopsSealSettings, ILocalizationService localizationService, ISettingService settingService) - { - _trustedShopsSealSettings = trustedShopsSealSettings; - _localizationService = localizationService; - _settingService = settingService; - } - - /// - /// Gets widget zones where this widget should be rendered - /// - /// Widget zones - public IList GetWidgetZones() - { - return !string.IsNullOrWhiteSpace(_trustedShopsSealSettings.WidgetZone) - ? new List() { _trustedShopsSealSettings.WidgetZone } - : new List() { "left_side_column_before" }; - } - - /// - /// Gets a route for provider configuration - /// - /// Action name - /// Controller name - /// Route values - public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "Configure"; - controllerName = "TrustedShopsSeal"; - routeValues = new RouteValueDictionary() { { "Namespaces", "SmartStore.Plugin.Widgets.TrustedShopsSeal.Controllers" }, { "area", "Widgets.TrustedShopsSeal" } }; - } - - /// - /// Gets a route for displaying widget - /// - /// Widget zone where it's displayed - /// Action name - /// Controller name - /// Route values - public void GetDisplayWidgetRoute(string widgetZone, object model, int storeId, out string actionName, out string controllerName, out RouteValueDictionary routeValues) - { - actionName = "PublicInfo"; - controllerName = "TrustedShopsSeal"; - routeValues = new RouteValueDictionary() - { - {"Namespaces", "SmartStore.Plugin.Widgets.TrustedShopsSeal.Controllers"}, - {"area", "Widgets.TrustedShopsSeal"}, - {"widgetZone", widgetZone} - }; - } - - /// - /// Install plugin - /// - public override void Install() - { - _localizationService.ImportPluginResourcesFromXml(this.PluginDescriptor); - - base.Install(); - } - - /// - /// Uninstall plugin - /// - public override void Uninstall() - { - //locales - _localizationService.DeleteLocaleStringResources(this.PluginDescriptor.ResourceRootKey); - _localizationService.DeleteLocaleStringResources("Plugins.FriendlyName.Widgets.TrustedShopsSeal", false); - - _settingService.DeleteSetting(); - - base.Uninstall(); - } - } -} diff --git a/src/Plugins/Widgets.TrustedShopsSeal/TrustedShopsSealSettings.cs b/src/Plugins/Widgets.TrustedShopsSeal/TrustedShopsSealSettings.cs deleted file mode 100644 index c8e2778628..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/TrustedShopsSealSettings.cs +++ /dev/null @@ -1,14 +0,0 @@ -using SmartStore.Core.Configuration; - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal -{ - public class TrustedShopsSealSettings : ISettings - { - public string TrustedShopsId { get; set; } - public bool IsTestMode { get; set; } - public string WidgetZone { get; set; } - public string ShopName { get; set; } - public string ShopText { get; set; } - - } -} \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Validators/TrustedShopsSealValidator.cs b/src/Plugins/Widgets.TrustedShopsSeal/Validators/TrustedShopsSealValidator.cs deleted file mode 100644 index 5114751e0e..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Validators/TrustedShopsSealValidator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using FluentValidation; -using SmartStore.Plugin.Widgets.TrustedShopsSeal.Models; -using SmartStore.Services.Localization; -using SmartStore.Web.Framework.Validators; - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal.Validators -{ - public class TrustedShopsSealValidator : AbstractValidator - { - public TrustedShopsSealValidator(ILocalizationService localize) - { - //RuleFor(x => x.TrustedShopsId).NotEmpty() - // .WithMessage(localize.GetResource("Plugins.Widgets.TrustedShopsSeal.MandatoryTrustedShopsId")); - } - } -} \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Views/TrustedShopsSeal/Configure.cshtml b/src/Plugins/Widgets.TrustedShopsSeal/Views/TrustedShopsSeal/Configure.cshtml deleted file mode 100644 index f762b3d81c..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Views/TrustedShopsSeal/Configure.cshtml +++ /dev/null @@ -1,91 +0,0 @@ -@{ - Layout = ""; - Html.AddCssFileParts(true, "~/Plugins/Widgets.TrustedShopsSeal/Content/trustedshops.css"); -} -@model SmartStore.Plugin.Widgets.TrustedShopsSeal.Models.ConfigurationModel -@using SmartStore.Web.Framework; - -
    - -
    - @Html.Raw(T("Plugins.Widgets.TrustedShopsCustomerReviews.Introduction.Headline")) -
    -
    -
    - -
    - @Html.Raw(T("Plugins.Widgets.TrustedShopsCustomerReviews.Prepared")) -
    -
    - @Html.Raw(T("Plugins.Widgets.TrustedShopsCustomerReviews.Introduction.Body")) -
    -
    - -
    - @Html.Raw(T("Plugins.Widgets.TrustedShopsSeal.AdminInstruction")) -
    - -@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) - -@using (Html.BeginForm()) -{ - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - @Html.SmartLabelFor(model => model.WidgetZone) - - @Html.SettingOverrideCheckbox(model => model.WidgetZone) - @Html.DropDownListFor(model => model.WidgetZone, Model.AvailableZones) - @Html.ValidationMessageFor(model => model.WidgetZone) -
    - @Html.SmartLabelFor(model => model.TrustedShopsId) - - @Html.SettingEditorFor(model => model.TrustedShopsId) - @Html.ValidationMessageFor(model => model.TrustedShopsId) -
    - @Html.SmartLabelFor(model => model.IsTestMode) - - @Html.SettingEditorFor(model => model.IsTestMode) - @Html.ValidationMessageFor(model => model.IsTestMode) -
    - @Html.SmartLabelFor(model => model.ShopName) - - @Html.SettingEditorFor(model => model.ShopName) - @Html.ValidationMessageFor(model => model.ShopName) -
    - @Html.SmartLabelFor(model => model.ShopText) - - @Html.SettingEditorFor(model => model.ShopText) - @Html.ValidationMessageFor(model => model.ShopText) -
    -   - - -
    -} \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Views/TrustedShopsSeal/PublicInfo.cshtml b/src/Plugins/Widgets.TrustedShopsSeal/Views/TrustedShopsSeal/PublicInfo.cshtml deleted file mode 100644 index 46237ab429..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Views/TrustedShopsSeal/PublicInfo.cshtml +++ /dev/null @@ -1,40 +0,0 @@ -@using SmartStore.Web.Framework; -@using SmartStore.Web.Framework.UI; - - -@model SmartStore.Plugin.Widgets.TrustedShopsSeal.Models.PublicInfoModel -@{ - Layout = ""; - Html.AddCssFileParts(true, "~/Plugins/Widgets.TrustedShopsSeal/Content/trustedshops.css"); -} -@using SmartStore.Web.Framework; - -
    -
    - @T("Plugins.Widgets.TrustedShopsSeal.Title") -
    -
    - -
    -
    - -
    -
    - -
    -
    - - @Model.ShopName - -
    - @Model.ShopText -
    -
    -
    -
    -
    - -
    -
    diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Views/Web.config b/src/Plugins/Widgets.TrustedShopsSeal/Views/Web.config deleted file mode 100644 index 31dc8df754..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Views/Web.config +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/CertificateStatus.datasource b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/CertificateStatus.datasource deleted file mode 100644 index 841fabd417..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/CertificateStatus.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - SmartStore.Plugin.Widgets.TrustedShopsSeal.com.trustedshops.qa.CertificateStatus, Web References.com.trustedshops.qa.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/Reference.cs b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/Reference.cs deleted file mode 100644 index 55740cc61b..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/Reference.cs +++ /dev/null @@ -1,889 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.18444 -// -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. -// -//------------------------------------------------------------------------------ - -// -// Der Quellcode wurde automatisch mit Microsoft.VSDesigner generiert. Version 4.0.30319.18444. -// -#pragma warning disable 1591 - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal.com.trustedshops.qa { - using System; - using System.Web.Services; - using System.Diagnostics; - using System.Web.Services.Protocols; - using System.Xml.Serialization; - using System.ComponentModel; - - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Web.Services.WebServiceBindingAttribute(Name="TSProtectionBinding", Namespace="http://protection.action.b2b.ts.nhp.com/")] - [System.Xml.Serialization.XmlIncludeAttribute(typeof(baseEntity))] - public partial class TSProtectionService : System.Web.Services.Protocols.SoapHttpClientProtocol { - - private System.Threading.SendOrPostCallback aliveOperationCompleted; - - private System.Threading.SendOrPostCallback checkCertificateOperationCompleted; - - private System.Threading.SendOrPostCallback checkLoginOperationCompleted; - - private System.Threading.SendOrPostCallback checkShopStatusOperationCompleted; - - private System.Threading.SendOrPostCallback getProtectionItemsOperationCompleted; - - private System.Threading.SendOrPostCallback pingOperationCompleted; - - private System.Threading.SendOrPostCallback protectWithAverageDeliveryDaysOperationCompleted; - - private bool useDefaultCredentialsSetExplicitly; - - /// - public TSProtectionService() { - this.Url = global::SmartStore.Plugin.Widgets.TrustedShopsSeal.Properties.Settings.Default.SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_qa_TSProtectionService; - if ((this.IsLocalFileSystemWebService(this.Url) == true)) { - this.UseDefaultCredentials = true; - this.useDefaultCredentialsSetExplicitly = false; - } - else { - this.useDefaultCredentialsSetExplicitly = true; - } - } - - public new string Url { - get { - return base.Url; - } - set { - if ((((this.IsLocalFileSystemWebService(base.Url) == true) - && (this.useDefaultCredentialsSetExplicitly == false)) - && (this.IsLocalFileSystemWebService(value) == false))) { - base.UseDefaultCredentials = false; - } - base.Url = value; - } - } - - public new bool UseDefaultCredentials { - get { - return base.UseDefaultCredentials; - } - set { - base.UseDefaultCredentials = value; - this.useDefaultCredentialsSetExplicitly = true; - } - } - - /// - public event aliveCompletedEventHandler aliveCompleted; - - /// - public event checkCertificateCompletedEventHandler checkCertificateCompleted; - - /// - public event checkLoginCompletedEventHandler checkLoginCompleted; - - /// - public event checkShopStatusCompletedEventHandler checkShopStatusCompleted; - - /// - public event getProtectionItemsCompletedEventHandler getProtectionItemsCompleted; - - /// - public event pingCompletedEventHandler pingCompleted; - - /// - public event protectWithAverageDeliveryDaysCompletedEventHandler protectWithAverageDeliveryDaysCompleted; - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("return")] - public int alive() { - object[] results = this.Invoke("alive", new object[0]); - return ((int)(results[0])); - } - - /// - public void aliveAsync() { - this.aliveAsync(null); - } - - /// - public void aliveAsync(object userState) { - if ((this.aliveOperationCompleted == null)) { - this.aliveOperationCompleted = new System.Threading.SendOrPostCallback(this.OnaliveOperationCompleted); - } - this.InvokeAsync("alive", new object[0], this.aliveOperationCompleted, userState); - } - - private void OnaliveOperationCompleted(object arg) { - if ((this.aliveCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.aliveCompleted(this, new aliveCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("certificateStatus")] - public CertificateStatus checkCertificate(string tsId) { - object[] results = this.Invoke("checkCertificate", new object[] { - tsId}); - return ((CertificateStatus)(results[0])); - } - - /// - public void checkCertificateAsync(string tsId) { - this.checkCertificateAsync(tsId, null); - } - - /// - public void checkCertificateAsync(string tsId, object userState) { - if ((this.checkCertificateOperationCompleted == null)) { - this.checkCertificateOperationCompleted = new System.Threading.SendOrPostCallback(this.OncheckCertificateOperationCompleted); - } - this.InvokeAsync("checkCertificate", new object[] { - tsId}, this.checkCertificateOperationCompleted, userState); - } - - private void OncheckCertificateOperationCompleted(object arg) { - if ((this.checkCertificateCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.checkCertificateCompleted(this, new checkCertificateCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("checkLogin")] - public long checkLogin(string tsId, string wsUser, string wsPassword) { - object[] results = this.Invoke("checkLogin", new object[] { - tsId, - wsUser, - wsPassword}); - return ((long)(results[0])); - } - - /// - public void checkLoginAsync(string tsId, string wsUser, string wsPassword) { - this.checkLoginAsync(tsId, wsUser, wsPassword, null); - } - - /// - public void checkLoginAsync(string tsId, string wsUser, string wsPassword, object userState) { - if ((this.checkLoginOperationCompleted == null)) { - this.checkLoginOperationCompleted = new System.Threading.SendOrPostCallback(this.OncheckLoginOperationCompleted); - } - this.InvokeAsync("checkLogin", new object[] { - tsId, - wsUser, - wsPassword}, this.checkLoginOperationCompleted, userState); - } - - private void OncheckLoginOperationCompleted(object arg) { - if ((this.checkLoginCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.checkLoginCompleted(this, new checkLoginCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("shopStatus")] - public long checkShopStatus(string tsId, string tsProductId, string wsUser, string wsPassword) { - object[] results = this.Invoke("checkShopStatus", new object[] { - tsId, - tsProductId, - wsUser, - wsPassword}); - return ((long)(results[0])); - } - - /// - public void checkShopStatusAsync(string tsId, string tsProductId, string wsUser, string wsPassword) { - this.checkShopStatusAsync(tsId, tsProductId, wsUser, wsPassword, null); - } - - /// - public void checkShopStatusAsync(string tsId, string tsProductId, string wsUser, string wsPassword, object userState) { - if ((this.checkShopStatusOperationCompleted == null)) { - this.checkShopStatusOperationCompleted = new System.Threading.SendOrPostCallback(this.OncheckShopStatusOperationCompleted); - } - this.InvokeAsync("checkShopStatus", new object[] { - tsId, - tsProductId, - wsUser, - wsPassword}, this.checkShopStatusOperationCompleted, userState); - } - - private void OncheckShopStatusOperationCompleted(object arg) { - if ((this.checkShopStatusCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.checkShopStatusCompleted(this, new checkShopStatusCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlArrayAttribute("getProtectionItems")] - [return: System.Xml.Serialization.XmlArrayItemAttribute("item", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public protectionItem[] getProtectionItems(string tsId) { - object[] results = this.Invoke("getProtectionItems", new object[] { - tsId}); - return ((protectionItem[])(results[0])); - } - - /// - public void getProtectionItemsAsync(string tsId) { - this.getProtectionItemsAsync(tsId, null); - } - - /// - public void getProtectionItemsAsync(string tsId, object userState) { - if ((this.getProtectionItemsOperationCompleted == null)) { - this.getProtectionItemsOperationCompleted = new System.Threading.SendOrPostCallback(this.OngetProtectionItemsOperationCompleted); - } - this.InvokeAsync("getProtectionItems", new object[] { - tsId}, this.getProtectionItemsOperationCompleted, userState); - } - - private void OngetProtectionItemsOperationCompleted(object arg) { - if ((this.getProtectionItemsCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.getProtectionItemsCompleted(this, new getProtectionItemsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("return")] - public int ping(int arg0) { - object[] results = this.Invoke("ping", new object[] { - arg0}); - return ((int)(results[0])); - } - - /// - public void pingAsync(int arg0) { - this.pingAsync(arg0, null); - } - - /// - public void pingAsync(int arg0, object userState) { - if ((this.pingOperationCompleted == null)) { - this.pingOperationCompleted = new System.Threading.SendOrPostCallback(this.OnpingOperationCompleted); - } - this.InvokeAsync("ping", new object[] { - arg0}, this.pingOperationCompleted, userState); - } - - private void OnpingOperationCompleted(object arg) { - if ((this.pingCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.pingCompleted(this, new pingCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("protectionNumber")] - public long protectWithAverageDeliveryDays(string tsId, string tsProductId, decimal amount, string currency, string paymentType, string buyerEmail, string shopCustomerID, string shopOrderID, System.DateTime orderDate, string wsUser, string wsPassword) { - object[] results = this.Invoke("protectWithAverageDeliveryDays", new object[] { - tsId, - tsProductId, - amount, - currency, - paymentType, - buyerEmail, - shopCustomerID, - shopOrderID, - orderDate, - wsUser, - wsPassword}); - return ((long)(results[0])); - } - - /// - public void protectWithAverageDeliveryDaysAsync(string tsId, string tsProductId, decimal amount, string currency, string paymentType, string buyerEmail, string shopCustomerID, string shopOrderID, System.DateTime orderDate, string wsUser, string wsPassword) { - this.protectWithAverageDeliveryDaysAsync(tsId, tsProductId, amount, currency, paymentType, buyerEmail, shopCustomerID, shopOrderID, orderDate, wsUser, wsPassword, null); - } - - /// - public void protectWithAverageDeliveryDaysAsync(string tsId, string tsProductId, decimal amount, string currency, string paymentType, string buyerEmail, string shopCustomerID, string shopOrderID, System.DateTime orderDate, string wsUser, string wsPassword, object userState) { - if ((this.protectWithAverageDeliveryDaysOperationCompleted == null)) { - this.protectWithAverageDeliveryDaysOperationCompleted = new System.Threading.SendOrPostCallback(this.OnprotectWithAverageDeliveryDaysOperationCompleted); - } - this.InvokeAsync("protectWithAverageDeliveryDays", new object[] { - tsId, - tsProductId, - amount, - currency, - paymentType, - buyerEmail, - shopCustomerID, - shopOrderID, - orderDate, - wsUser, - wsPassword}, this.protectWithAverageDeliveryDaysOperationCompleted, userState); - } - - private void OnprotectWithAverageDeliveryDaysOperationCompleted(object arg) { - if ((this.protectWithAverageDeliveryDaysCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.protectWithAverageDeliveryDaysCompleted(this, new protectWithAverageDeliveryDaysCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - public new void CancelAsync(object userState) { - base.CancelAsync(userState); - } - - private bool IsLocalFileSystemWebService(string url) { - if (((url == null) - || (url == string.Empty))) { - return false; - } - System.Uri wsUri = new System.Uri(url); - if (((wsUri.Port >= 1024) - && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { - return true; - } - return false; - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public partial class CertificateStatus { - - private string certificationLanguageField; - - private string stateEnumField; - - private string tsIDField; - - private string typeEnumField; - - private string urlField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string certificationLanguage { - get { - return this.certificationLanguageField; - } - set { - this.certificationLanguageField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string stateEnum { - get { - return this.stateEnumField; - } - set { - this.stateEnumField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string tsID { - get { - return this.tsIDField; - } - set { - this.tsIDField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string typeEnum { - get { - return this.typeEnumField; - } - set { - this.typeEnumField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string url { - get { - return this.urlField; - } - set { - this.urlField = value; - } - } - } - - /// - [System.Xml.Serialization.XmlIncludeAttribute(typeof(protectionItem))] - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public partial class baseEntity { - - private System.DateTime creationDateField; - - private bool creationDateFieldSpecified; - - private long idField; - - private bool idFieldSpecified; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public System.DateTime creationDate { - get { - return this.creationDateField; - } - set { - this.creationDateField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool creationDateSpecified { - get { - return this.creationDateFieldSpecified; - } - set { - this.creationDateFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public long id { - get { - return this.idField; - } - set { - this.idField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool idSpecified { - get { - return this.idFieldSpecified; - } - set { - this.idFieldSpecified = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public partial class protectionItem : baseEntity { - - private currencyEnum currencyField; - - private bool currencyFieldSpecified; - - private decimal grossFeeField; - - private bool grossFeeFieldSpecified; - - private decimal netFeeField; - - private bool netFeeFieldSpecified; - - private decimal protectedAmountDecimalField; - - private bool protectedAmountDecimalFieldSpecified; - - private int protectionDurationIntField; - - private string tsProductIDField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public currencyEnum currency { - get { - return this.currencyField; - } - set { - this.currencyField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool currencySpecified { - get { - return this.currencyFieldSpecified; - } - set { - this.currencyFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public decimal grossFee { - get { - return this.grossFeeField; - } - set { - this.grossFeeField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool grossFeeSpecified { - get { - return this.grossFeeFieldSpecified; - } - set { - this.grossFeeFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public decimal netFee { - get { - return this.netFeeField; - } - set { - this.netFeeField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool netFeeSpecified { - get { - return this.netFeeFieldSpecified; - } - set { - this.netFeeFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public decimal protectedAmountDecimal { - get { - return this.protectedAmountDecimalField; - } - set { - this.protectedAmountDecimalField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool protectedAmountDecimalSpecified { - get { - return this.protectedAmountDecimalFieldSpecified; - } - set { - this.protectedAmountDecimalFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public int protectionDurationInt { - get { - return this.protectionDurationIntField; - } - set { - this.protectionDurationIntField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string tsProductID { - get { - return this.tsProductIDField; - } - set { - this.tsProductIDField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public enum currencyEnum { - - /// - EUR, - - /// - USD, - - /// - AUD, - - /// - CAD, - - /// - CHF, - - /// - DKK, - - /// - GBP, - - /// - JPY, - - /// - NZD, - - /// - SEK, - - /// - PLN, - - /// - NOK, - - /// - BGN, - - /// - LVL, - - /// - LTL, - - /// - RON, - - /// - RUB, - - /// - TRY, - - /// - CZK, - - /// - HUF, - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void aliveCompletedEventHandler(object sender, aliveCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class aliveCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal aliveCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public int Result { - get { - this.RaiseExceptionIfNecessary(); - return ((int)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void checkCertificateCompletedEventHandler(object sender, checkCertificateCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class checkCertificateCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal checkCertificateCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public CertificateStatus Result { - get { - this.RaiseExceptionIfNecessary(); - return ((CertificateStatus)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void checkLoginCompletedEventHandler(object sender, checkLoginCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class checkLoginCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal checkLoginCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public long Result { - get { - this.RaiseExceptionIfNecessary(); - return ((long)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void checkShopStatusCompletedEventHandler(object sender, checkShopStatusCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class checkShopStatusCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal checkShopStatusCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public long Result { - get { - this.RaiseExceptionIfNecessary(); - return ((long)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void getProtectionItemsCompletedEventHandler(object sender, getProtectionItemsCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class getProtectionItemsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal getProtectionItemsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public protectionItem[] Result { - get { - this.RaiseExceptionIfNecessary(); - return ((protectionItem[])(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void pingCompletedEventHandler(object sender, pingCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class pingCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal pingCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public int Result { - get { - this.RaiseExceptionIfNecessary(); - return ((int)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void protectWithAverageDeliveryDaysCompletedEventHandler(object sender, protectWithAverageDeliveryDaysCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class protectWithAverageDeliveryDaysCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal protectWithAverageDeliveryDaysCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public long Result { - get { - this.RaiseExceptionIfNecessary(); - return ((long)(this.results[0])); - } - } - } -} - -#pragma warning restore 1591 \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/Reference.map b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/Reference.map deleted file mode 100644 index 7a2f6be3b3..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/Reference.map +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/TSProtectionService.wsdl b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/TSProtectionService.wsdl deleted file mode 100644 index 8aff737f15..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/TSProtectionService.wsdl +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/protectionItem.datasource b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/protectionItem.datasource deleted file mode 100644 index ad425868d9..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.qa/protectionItem.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - SmartStore.Plugin.Widgets.TrustedShopsSeal.com.trustedshops.qa.protectionItem, Web References.com.trustedshops.qa.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/CertificateStatus.datasource b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/CertificateStatus.datasource deleted file mode 100644 index 6b556b44cd..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/CertificateStatus.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - SmartStore.Plugin.Widgets.TrustedShopsSeal.com.trustedshops.www.CertificateStatus, Web References.com.trustedshops.www.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/Reference.cs b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/Reference.cs deleted file mode 100644 index 2de998b8d0..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/Reference.cs +++ /dev/null @@ -1,889 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.18444 -// -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. -// -//------------------------------------------------------------------------------ - -// -// Der Quellcode wurde automatisch mit Microsoft.VSDesigner generiert. Version 4.0.30319.18444. -// -#pragma warning disable 1591 - -namespace SmartStore.Plugin.Widgets.TrustedShopsSeal.com.trustedshops.www { - using System; - using System.Web.Services; - using System.Diagnostics; - using System.Web.Services.Protocols; - using System.Xml.Serialization; - using System.ComponentModel; - - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Web.Services.WebServiceBindingAttribute(Name="TSProtectionBinding", Namespace="http://protection.action.b2b.ts.nhp.com/")] - [System.Xml.Serialization.XmlIncludeAttribute(typeof(baseEntity))] - public partial class TSProtectionService : System.Web.Services.Protocols.SoapHttpClientProtocol { - - private System.Threading.SendOrPostCallback aliveOperationCompleted; - - private System.Threading.SendOrPostCallback checkCertificateOperationCompleted; - - private System.Threading.SendOrPostCallback checkLoginOperationCompleted; - - private System.Threading.SendOrPostCallback checkShopStatusOperationCompleted; - - private System.Threading.SendOrPostCallback getProtectionItemsOperationCompleted; - - private System.Threading.SendOrPostCallback pingOperationCompleted; - - private System.Threading.SendOrPostCallback protectWithAverageDeliveryDaysOperationCompleted; - - private bool useDefaultCredentialsSetExplicitly; - - /// - public TSProtectionService() { - this.Url = global::SmartStore.Plugin.Widgets.TrustedShopsSeal.Properties.Settings.Default.SmartStore_Plugin_Widgets_TrustedShopsSeal_com_trustedshops_www_TSProtectionService; - if ((this.IsLocalFileSystemWebService(this.Url) == true)) { - this.UseDefaultCredentials = true; - this.useDefaultCredentialsSetExplicitly = false; - } - else { - this.useDefaultCredentialsSetExplicitly = true; - } - } - - public new string Url { - get { - return base.Url; - } - set { - if ((((this.IsLocalFileSystemWebService(base.Url) == true) - && (this.useDefaultCredentialsSetExplicitly == false)) - && (this.IsLocalFileSystemWebService(value) == false))) { - base.UseDefaultCredentials = false; - } - base.Url = value; - } - } - - public new bool UseDefaultCredentials { - get { - return base.UseDefaultCredentials; - } - set { - base.UseDefaultCredentials = value; - this.useDefaultCredentialsSetExplicitly = true; - } - } - - /// - public event aliveCompletedEventHandler aliveCompleted; - - /// - public event checkCertificateCompletedEventHandler checkCertificateCompleted; - - /// - public event checkLoginCompletedEventHandler checkLoginCompleted; - - /// - public event checkShopStatusCompletedEventHandler checkShopStatusCompleted; - - /// - public event getProtectionItemsCompletedEventHandler getProtectionItemsCompleted; - - /// - public event pingCompletedEventHandler pingCompleted; - - /// - public event protectWithAverageDeliveryDaysCompletedEventHandler protectWithAverageDeliveryDaysCompleted; - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("return")] - public int alive() { - object[] results = this.Invoke("alive", new object[0]); - return ((int)(results[0])); - } - - /// - public void aliveAsync() { - this.aliveAsync(null); - } - - /// - public void aliveAsync(object userState) { - if ((this.aliveOperationCompleted == null)) { - this.aliveOperationCompleted = new System.Threading.SendOrPostCallback(this.OnaliveOperationCompleted); - } - this.InvokeAsync("alive", new object[0], this.aliveOperationCompleted, userState); - } - - private void OnaliveOperationCompleted(object arg) { - if ((this.aliveCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.aliveCompleted(this, new aliveCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("certificateStatus")] - public CertificateStatus checkCertificate(string tsId) { - object[] results = this.Invoke("checkCertificate", new object[] { - tsId}); - return ((CertificateStatus)(results[0])); - } - - /// - public void checkCertificateAsync(string tsId) { - this.checkCertificateAsync(tsId, null); - } - - /// - public void checkCertificateAsync(string tsId, object userState) { - if ((this.checkCertificateOperationCompleted == null)) { - this.checkCertificateOperationCompleted = new System.Threading.SendOrPostCallback(this.OncheckCertificateOperationCompleted); - } - this.InvokeAsync("checkCertificate", new object[] { - tsId}, this.checkCertificateOperationCompleted, userState); - } - - private void OncheckCertificateOperationCompleted(object arg) { - if ((this.checkCertificateCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.checkCertificateCompleted(this, new checkCertificateCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("checkLogin")] - public long checkLogin(string tsId, string wsUser, string wsPassword) { - object[] results = this.Invoke("checkLogin", new object[] { - tsId, - wsUser, - wsPassword}); - return ((long)(results[0])); - } - - /// - public void checkLoginAsync(string tsId, string wsUser, string wsPassword) { - this.checkLoginAsync(tsId, wsUser, wsPassword, null); - } - - /// - public void checkLoginAsync(string tsId, string wsUser, string wsPassword, object userState) { - if ((this.checkLoginOperationCompleted == null)) { - this.checkLoginOperationCompleted = new System.Threading.SendOrPostCallback(this.OncheckLoginOperationCompleted); - } - this.InvokeAsync("checkLogin", new object[] { - tsId, - wsUser, - wsPassword}, this.checkLoginOperationCompleted, userState); - } - - private void OncheckLoginOperationCompleted(object arg) { - if ((this.checkLoginCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.checkLoginCompleted(this, new checkLoginCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("shopStatus")] - public long checkShopStatus(string tsId, string tsProductId, string wsUser, string wsPassword) { - object[] results = this.Invoke("checkShopStatus", new object[] { - tsId, - tsProductId, - wsUser, - wsPassword}); - return ((long)(results[0])); - } - - /// - public void checkShopStatusAsync(string tsId, string tsProductId, string wsUser, string wsPassword) { - this.checkShopStatusAsync(tsId, tsProductId, wsUser, wsPassword, null); - } - - /// - public void checkShopStatusAsync(string tsId, string tsProductId, string wsUser, string wsPassword, object userState) { - if ((this.checkShopStatusOperationCompleted == null)) { - this.checkShopStatusOperationCompleted = new System.Threading.SendOrPostCallback(this.OncheckShopStatusOperationCompleted); - } - this.InvokeAsync("checkShopStatus", new object[] { - tsId, - tsProductId, - wsUser, - wsPassword}, this.checkShopStatusOperationCompleted, userState); - } - - private void OncheckShopStatusOperationCompleted(object arg) { - if ((this.checkShopStatusCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.checkShopStatusCompleted(this, new checkShopStatusCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlArrayAttribute("getProtectionItems")] - [return: System.Xml.Serialization.XmlArrayItemAttribute("item", Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public protectionItem[] getProtectionItems(string tsId) { - object[] results = this.Invoke("getProtectionItems", new object[] { - tsId}); - return ((protectionItem[])(results[0])); - } - - /// - public void getProtectionItemsAsync(string tsId) { - this.getProtectionItemsAsync(tsId, null); - } - - /// - public void getProtectionItemsAsync(string tsId, object userState) { - if ((this.getProtectionItemsOperationCompleted == null)) { - this.getProtectionItemsOperationCompleted = new System.Threading.SendOrPostCallback(this.OngetProtectionItemsOperationCompleted); - } - this.InvokeAsync("getProtectionItems", new object[] { - tsId}, this.getProtectionItemsOperationCompleted, userState); - } - - private void OngetProtectionItemsOperationCompleted(object arg) { - if ((this.getProtectionItemsCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.getProtectionItemsCompleted(this, new getProtectionItemsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("return")] - public int ping(int arg0) { - object[] results = this.Invoke("ping", new object[] { - arg0}); - return ((int)(results[0])); - } - - /// - public void pingAsync(int arg0) { - this.pingAsync(arg0, null); - } - - /// - public void pingAsync(int arg0, object userState) { - if ((this.pingOperationCompleted == null)) { - this.pingOperationCompleted = new System.Threading.SendOrPostCallback(this.OnpingOperationCompleted); - } - this.InvokeAsync("ping", new object[] { - arg0}, this.pingOperationCompleted, userState); - } - - private void OnpingOperationCompleted(object arg) { - if ((this.pingCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.pingCompleted(this, new pingCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://protection.action.b2b.ts.nhp.com/", ResponseNamespace="http://protection.action.b2b.ts.nhp.com/", Use=System.Web.Services.Description.SoapBindingUse.Literal)] - [return: System.Xml.Serialization.XmlElementAttribute("protectionNumber")] - public long protectWithAverageDeliveryDays(string tsId, string tsProductId, decimal amount, string currency, string paymentType, string buyerEmail, string shopCustomerID, string shopOrderID, System.DateTime orderDate, string wsUser, string wsPassword) { - object[] results = this.Invoke("protectWithAverageDeliveryDays", new object[] { - tsId, - tsProductId, - amount, - currency, - paymentType, - buyerEmail, - shopCustomerID, - shopOrderID, - orderDate, - wsUser, - wsPassword}); - return ((long)(results[0])); - } - - /// - public void protectWithAverageDeliveryDaysAsync(string tsId, string tsProductId, decimal amount, string currency, string paymentType, string buyerEmail, string shopCustomerID, string shopOrderID, System.DateTime orderDate, string wsUser, string wsPassword) { - this.protectWithAverageDeliveryDaysAsync(tsId, tsProductId, amount, currency, paymentType, buyerEmail, shopCustomerID, shopOrderID, orderDate, wsUser, wsPassword, null); - } - - /// - public void protectWithAverageDeliveryDaysAsync(string tsId, string tsProductId, decimal amount, string currency, string paymentType, string buyerEmail, string shopCustomerID, string shopOrderID, System.DateTime orderDate, string wsUser, string wsPassword, object userState) { - if ((this.protectWithAverageDeliveryDaysOperationCompleted == null)) { - this.protectWithAverageDeliveryDaysOperationCompleted = new System.Threading.SendOrPostCallback(this.OnprotectWithAverageDeliveryDaysOperationCompleted); - } - this.InvokeAsync("protectWithAverageDeliveryDays", new object[] { - tsId, - tsProductId, - amount, - currency, - paymentType, - buyerEmail, - shopCustomerID, - shopOrderID, - orderDate, - wsUser, - wsPassword}, this.protectWithAverageDeliveryDaysOperationCompleted, userState); - } - - private void OnprotectWithAverageDeliveryDaysOperationCompleted(object arg) { - if ((this.protectWithAverageDeliveryDaysCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.protectWithAverageDeliveryDaysCompleted(this, new protectWithAverageDeliveryDaysCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - public new void CancelAsync(object userState) { - base.CancelAsync(userState); - } - - private bool IsLocalFileSystemWebService(string url) { - if (((url == null) - || (url == string.Empty))) { - return false; - } - System.Uri wsUri = new System.Uri(url); - if (((wsUri.Port >= 1024) - && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { - return true; - } - return false; - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public partial class CertificateStatus { - - private string certificationLanguageField; - - private string stateEnumField; - - private string tsIDField; - - private string typeEnumField; - - private string urlField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string certificationLanguage { - get { - return this.certificationLanguageField; - } - set { - this.certificationLanguageField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string stateEnum { - get { - return this.stateEnumField; - } - set { - this.stateEnumField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string tsID { - get { - return this.tsIDField; - } - set { - this.tsIDField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string typeEnum { - get { - return this.typeEnumField; - } - set { - this.typeEnumField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string url { - get { - return this.urlField; - } - set { - this.urlField = value; - } - } - } - - /// - [System.Xml.Serialization.XmlIncludeAttribute(typeof(protectionItem))] - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public partial class baseEntity { - - private System.DateTime creationDateField; - - private bool creationDateFieldSpecified; - - private long idField; - - private bool idFieldSpecified; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public System.DateTime creationDate { - get { - return this.creationDateField; - } - set { - this.creationDateField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool creationDateSpecified { - get { - return this.creationDateFieldSpecified; - } - set { - this.creationDateFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public long id { - get { - return this.idField; - } - set { - this.idField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool idSpecified { - get { - return this.idFieldSpecified; - } - set { - this.idFieldSpecified = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public partial class protectionItem : baseEntity { - - private currencyEnum currencyField; - - private bool currencyFieldSpecified; - - private decimal grossFeeField; - - private bool grossFeeFieldSpecified; - - private decimal netFeeField; - - private bool netFeeFieldSpecified; - - private decimal protectedAmountDecimalField; - - private bool protectedAmountDecimalFieldSpecified; - - private int protectionDurationIntField; - - private string tsProductIDField; - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public currencyEnum currency { - get { - return this.currencyField; - } - set { - this.currencyField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool currencySpecified { - get { - return this.currencyFieldSpecified; - } - set { - this.currencyFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public decimal grossFee { - get { - return this.grossFeeField; - } - set { - this.grossFeeField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool grossFeeSpecified { - get { - return this.grossFeeFieldSpecified; - } - set { - this.grossFeeFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public decimal netFee { - get { - return this.netFeeField; - } - set { - this.netFeeField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool netFeeSpecified { - get { - return this.netFeeFieldSpecified; - } - set { - this.netFeeFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public decimal protectedAmountDecimal { - get { - return this.protectedAmountDecimalField; - } - set { - this.protectedAmountDecimalField = value; - } - } - - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - public bool protectedAmountDecimalSpecified { - get { - return this.protectedAmountDecimalFieldSpecified; - } - set { - this.protectedAmountDecimalFieldSpecified = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public int protectionDurationInt { - get { - return this.protectionDurationIntField; - } - set { - this.protectionDurationIntField = value; - } - } - - /// - [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] - public string tsProductID { - get { - return this.tsProductIDField; - } - set { - this.tsProductIDField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")] - [System.SerializableAttribute()] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://protection.action.b2b.ts.nhp.com/")] - public enum currencyEnum { - - /// - EUR, - - /// - USD, - - /// - AUD, - - /// - CAD, - - /// - CHF, - - /// - DKK, - - /// - GBP, - - /// - JPY, - - /// - NZD, - - /// - SEK, - - /// - PLN, - - /// - NOK, - - /// - BGN, - - /// - LVL, - - /// - LTL, - - /// - RON, - - /// - RUB, - - /// - TRY, - - /// - CZK, - - /// - HUF, - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void aliveCompletedEventHandler(object sender, aliveCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class aliveCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal aliveCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public int Result { - get { - this.RaiseExceptionIfNecessary(); - return ((int)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void checkCertificateCompletedEventHandler(object sender, checkCertificateCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class checkCertificateCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal checkCertificateCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public CertificateStatus Result { - get { - this.RaiseExceptionIfNecessary(); - return ((CertificateStatus)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void checkLoginCompletedEventHandler(object sender, checkLoginCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class checkLoginCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal checkLoginCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public long Result { - get { - this.RaiseExceptionIfNecessary(); - return ((long)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void checkShopStatusCompletedEventHandler(object sender, checkShopStatusCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class checkShopStatusCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal checkShopStatusCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public long Result { - get { - this.RaiseExceptionIfNecessary(); - return ((long)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void getProtectionItemsCompletedEventHandler(object sender, getProtectionItemsCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class getProtectionItemsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal getProtectionItemsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public protectionItem[] Result { - get { - this.RaiseExceptionIfNecessary(); - return ((protectionItem[])(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void pingCompletedEventHandler(object sender, pingCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class pingCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal pingCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public int Result { - get { - this.RaiseExceptionIfNecessary(); - return ((int)(this.results[0])); - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - public delegate void protectWithAverageDeliveryDaysCompletedEventHandler(object sender, protectWithAverageDeliveryDaysCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.18408")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class protectWithAverageDeliveryDaysCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal protectWithAverageDeliveryDaysCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public long Result { - get { - this.RaiseExceptionIfNecessary(); - return ((long)(this.results[0])); - } - } - } -} - -#pragma warning restore 1591 \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/Reference.map b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/Reference.map deleted file mode 100644 index 3217b43d92..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/Reference.map +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/TSProtectionService.wsdl b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/TSProtectionService.wsdl deleted file mode 100644 index 78e699a991..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/TSProtectionService.wsdl +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/protectionItem.datasource b/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/protectionItem.datasource deleted file mode 100644 index 21b08b4e3b..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/Web References/com.trustedshops.www/protectionItem.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - SmartStore.Plugin.Widgets.TrustedShopsSeal.com.trustedshops.www.protectionItem, Web References.com.trustedshops.www.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/icon.png b/src/Plugins/Widgets.TrustedShopsSeal/icon.png deleted file mode 100644 index 8cb30d4a71..0000000000 Binary files a/src/Plugins/Widgets.TrustedShopsSeal/icon.png and /dev/null differ diff --git a/src/Plugins/Widgets.TrustedShopsSeal/packages.config b/src/Plugins/Widgets.TrustedShopsSeal/packages.config deleted file mode 100644 index dbb54d0ded..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Plugins/Widgets.TrustedShopsSeal/web.config b/src/Plugins/Widgets.TrustedShopsSeal/web.config deleted file mode 100644 index 1bd02e8a8a..0000000000 --- a/src/Plugins/Widgets.TrustedShopsSeal/web.config +++ /dev/null @@ -1,51 +0,0 @@ - - - - -
    - - - - - - - - - - https://qa.trustedshops.com:443/ts/services/TsProtection - - - https://www.trustedshops.com:443/ts/services/TsProtection - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web.Framework/AppPath.cs b/src/Presentation/SmartStore.Web.Framework/AppPath.cs deleted file mode 100644 index 78fa695db3..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/AppPath.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Configuration; -using System.Web.Hosting; -using System.IO; -using SmartStore.Utilities; - -namespace SmartStore -{ - public static class AppPath - { - /// Returns physical path to temp directory - /// Name of a sub directory to be created and returned (optional) - public static string TempDir(string subDirectory = null) - { - string path = CommonHelper.GetAppSetting("sm:TempDirectory", "~/App_Data/_temp"); - path = HostingEnvironment.MapPath(path); - - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - - if (subDirectory.HasValue()) - { - path = Path.Combine(path, subDirectory); - - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - } - - return path; - } - - /// Safe way to cleanup the temp directory. Should be called via scheduled task. - public static void TempCleanup() - { - try - { - string dir = AppPath.TempDir(); - - if (!Directory.Exists(dir)) - return; - - FileInfo fi; - DateTime dtOld = DateTime.Now.Subtract(new TimeSpan(0, 5, 0, 0)); - var files = Directory.EnumerateFiles(dir); - - foreach (string file in files) - { - fi = new FileInfo(file); - - if (fi != null && fi.LastWriteTime < dtOld) - AppPath.Delete(file); - } - } - catch (Exception exc) - { - exc.Dump(); - } - } - - /// Safe way to delete a file. - public static bool Delete(string path) - { - if (path.IsNullOrEmpty()) - return true; - - bool result = true; - try - { - if (Directory.Exists(path)) - { - throw new MemberAccessException("Deleting folders cause of security reasons not possible: {0}".FormatWith(path)); - } - - System.IO.File.Delete(path); // no exception, if file doesn't exists - } - catch (Exception exc) - { - result = false; - exc.Dump(); - } - return result; - } - - /// Safe way to copy a file. - public static bool Copy(string sourcePath, string destinationPath, bool overwrite = true, bool deleteSource = false) - { - bool result = true; - try - { - System.IO.File.Copy(sourcePath, destinationPath, overwrite); - - if (deleteSource) - Delete(sourcePath); - } - catch (Exception exc) - { - result = false; - exc.Dump(); - } - return result; - } - - public static void CopyDirectory(DirectoryInfo source, DirectoryInfo target, bool overwrite = true) - { - foreach (FileInfo fi in source.GetFiles()) - { - try - { - fi.CopyTo(Path.Combine(target.ToString(), fi.Name), overwrite); - } - catch (Exception exc) - { - exc.Dump(); - } - } - - foreach (DirectoryInfo sourceSubDir in source.GetDirectories()) - { - try - { - DirectoryInfo targetSubDir = target.CreateSubdirectory(sourceSubDir.Name); - CopyDirectory(sourceSubDir, targetSubDir, overwrite); - } - catch (Exception exc) - { - exc.Dump(); - } - } - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/BundlePublisher.cs b/src/Presentation/SmartStore.Web.Framework/Bundling/BundlePublisher.cs similarity index 86% rename from src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/BundlePublisher.cs rename to src/Presentation/SmartStore.Web.Framework/Bundling/BundlePublisher.cs index f1e9fc271f..b8c831476e 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/BundlePublisher.cs +++ b/src/Presentation/SmartStore.Web.Framework/Bundling/BundlePublisher.cs @@ -3,13 +3,9 @@ using System.Linq; using System.Web.Optimization; using SmartStore.Core.Infrastructure; -using SmartStore.Core.Plugins; -namespace SmartStore.Web.Framework.Mvc.Bundles +namespace SmartStore.Web.Framework.Bundling { - /// - /// codehint: sm-add - /// public class BundlePublisher : IBundlePublisher { private readonly ITypeFinder _typeFinder; diff --git a/src/Presentation/SmartStore.Web.Framework/Bundling/IBundleProvider.cs b/src/Presentation/SmartStore.Web.Framework/Bundling/IBundleProvider.cs new file mode 100644 index 0000000000..6bd9ec5bd6 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Bundling/IBundleProvider.cs @@ -0,0 +1,11 @@ +using System.Web.Optimization; + +namespace SmartStore.Web.Framework.Bundling +{ + public interface IBundleProvider + { + void RegisterBundles(BundleCollection bundles); + + int Priority { get; } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Bundling/IBundlePublisher.cs b/src/Presentation/SmartStore.Web.Framework/Bundling/IBundlePublisher.cs new file mode 100644 index 0000000000..50859b9456 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Bundling/IBundlePublisher.cs @@ -0,0 +1,9 @@ +using System.Web.Optimization; + +namespace SmartStore.Web.Framework.Bundling +{ + public interface IBundlePublisher + { + void RegisterBundles(BundleCollection bundles); + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/AdminControllerBase.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/AdminControllerBase.cs index e6d020fb59..5d11c61de5 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/AdminControllerBase.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/AdminControllerBase.cs @@ -1,16 +1,19 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Web.Mvc; +using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Infrastructure; using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Filters; using SmartStore.Web.Framework.Localization; using SmartStore.Web.Framework.Security; -using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Theming; namespace SmartStore.Web.Framework.Controllers -{ - +{ + [AdminThemed] [RequireHttpsByConfig(SslRequirement.Yes)] [AdminValidateIpAddress] [CustomerLastActivity] @@ -21,11 +24,13 @@ public abstract class AdminControllerBase : SmartController /// Initialize controller ///
    /// Request context - protected override void Initialize(System.Web.Routing.RequestContext requestContext) + protected override void Initialize(RequestContext requestContext) { - //set work context to admin mode - EngineContext.Current.Resolve().IsAdmin = true; - + var routeData = requestContext.RouteData; + if (routeData != null && !routeData.DataTokens.ContainsKey("ParentActionViewContext")) + { + EngineContext.Current.Resolve().IsAdmin = true; + } base.Initialize(requestContext); } @@ -65,6 +70,7 @@ protected virtual void AddLocales(ILanguageService languag /// Access denied view ///
    /// Access denied view + [SuppressMessage("ReSharper", "Mvc.AreaNotResolved")] protected ActionResult AccessDeniedView() { return RedirectToAction("AccessDenied", "Security", new { pageUrl = this.Request.RawUrl, area = "Admin" }); @@ -77,6 +83,5 @@ protected ActionResult AccessDeniedPartialView() { return PartialView("~/Administration/Views/Security/AccessDenied.cshtml"); } - } } diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/CheckAffiliateAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/CheckAffiliateAttribute.cs deleted file mode 100644 index 3455c9b558..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/CheckAffiliateAttribute.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Web; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Affiliates; -using SmartStore.Services.Customers; - -namespace SmartStore.Web.Framework.Controllers -{ - public class CheckAffiliateAttribute : ActionFilterAttribute - { - - public Lazy AffiliateService { get; set; } - public Lazy WorkContext { get; set; } - public Lazy CustomerService { get; set; } - - public override void OnActionExecuting(ActionExecutingContext filterContext) - { - if (filterContext == null || filterContext.HttpContext == null) - return; - - HttpRequestBase request = filterContext.HttpContext.Request; - if (request == null) - return; - - //don't apply filter to child methods - if (filterContext.IsChildAction) - return; - - if (request.QueryString != null && request.QueryString["AffiliateId"] != null) - { - var affiliateId = Convert.ToInt32(request.QueryString["AffiliateId"]); - - if (affiliateId > 0) - { - var affiliateService = AffiliateService.Value; - var affiliate = affiliateService.GetAffiliateById(affiliateId); - if (affiliate != null && !affiliate.Deleted && affiliate.Active) - { - var workContext = WorkContext.Value; - if (workContext.CurrentCustomer != null && - workContext.CurrentCustomer.AffiliateId != affiliate.Id) - { - workContext.CurrentCustomer.AffiliateId = affiliate.Id; - var customerService = CustomerService.Value; - customerService.UpdateCustomer(workContext.CurrentCustomer); - } - } - } - } - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/ContollerExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/ContollerExtensions.cs index 564c87860c..1517db8245 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/ContollerExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/ContollerExtensions.cs @@ -7,6 +7,10 @@ using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Collections; +using System.Text; +using System; +using SmartStore.Utilities; +#pragma warning disable 1573 namespace SmartStore.Web.Framework.Controllers { @@ -16,45 +20,71 @@ public static class ContollerExtensions /// Render partial view to string ///
    /// Result - public static string RenderPartialViewToString(this Controller controller) + public static string RenderPartialViewToString(this ControllerBase controller) { - return RenderPartialViewToString(controller, null, null); + return RenderPartialViewToString(controller, null, null, null); } - /// - /// Render partial view to string - /// - /// View name - /// Result - public static string RenderPartialViewToString(this Controller controller, string viewName) + + /// + /// Render partial view to string + /// + /// + /// View name + /// Result + public static string RenderPartialViewToString(this ControllerBase controller, string viewName) { - return RenderPartialViewToString(controller, viewName, null); + return RenderPartialViewToString(controller, viewName, null, null); } - /// - /// Render partial view to string - /// - /// Model - /// Result - public static string RenderPartialViewToString(this Controller controller, object model) + + /// + /// Render partial view to string + /// + /// + /// Model + /// Result + public static string RenderPartialViewToString(this ControllerBase controller, object model) { - return RenderPartialViewToString(controller, null, model); + return RenderPartialViewToString(controller, null, model, null); } - /// - /// Render partial view to string - /// - /// View name - /// Model - /// Result - public static string RenderPartialViewToString(this Controller controller, string viewName, object model) + + /// + /// Render partial view to string + /// + /// + /// View name + /// Model + /// Result + public static string RenderPartialViewToString(this ControllerBase controller, string viewName, object model) + { + return RenderPartialViewToString(controller, viewName, model, null); + } + + /// + /// Render partial view to string + /// + /// + /// View name + /// Model + /// Additional ViewData + /// Result + public static string RenderPartialViewToString(this ControllerBase controller, string viewName, object model, object additionalViewData) { - //Original source code: http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/ - if (string.IsNullOrEmpty(viewName)) + if (viewName.IsEmpty()) viewName = controller.ControllerContext.RouteData.GetRequiredString("action"); controller.ViewData.Model = model; + if (additionalViewData != null) + { + controller.ViewData.AddRange(CommonHelper.ObjectToDictionary(additionalViewData)); + } + using (var sw = new StringWriter()) { - ViewEngineResult viewResult = System.Web.Mvc.ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName); + ViewEngineResult viewResult = System.Web.Mvc.ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName.EmptyNull()); + + ThrowIfViewNotFound(viewResult, viewName); + var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw); viewResult.View.Render(viewContext, sw); @@ -62,6 +92,90 @@ public static string RenderPartialViewToString(this Controller controller, strin } } + /// + /// Render view to string + /// + /// Result + public static string RenderViewToString(this ControllerBase controller) + { + return RenderViewToString(controller, null, null, null); + } + + /// + /// Render view to string + /// + /// Model + /// Result + public static string RenderViewToString(this ControllerBase controller, object model) + { + return RenderViewToString(controller, null, null, model); + } + + /// + /// Render view to string + /// + /// View name + /// Result + public static string RenderViewToString(this ControllerBase controller, string viewName) + { + return RenderViewToString(controller, viewName, null, null); + } + + /// + /// Render view to string + /// + /// View name + /// Model + /// Result + public static string RenderViewToString(this ControllerBase controller, string viewName, string masterName) + { + return RenderViewToString(controller, viewName, masterName, null); + } + + /// + /// Render view to string + /// + /// View name + /// Master name + /// Model + /// Result + public static string RenderViewToString(this ControllerBase controller, string viewName, string masterName, object model) + { + if (viewName.IsEmpty()) + viewName = controller.ControllerContext.RouteData.GetRequiredString("action"); + + controller.ViewData.Model = model; + + using (var sw = new StringWriter()) + { + var viewResult = System.Web.Mvc.ViewEngines.Engines.FindView(controller.ControllerContext, viewName.EmptyNull(), masterName.EmptyNull()); + + ThrowIfViewNotFound(viewResult, viewName); + + var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw); + viewResult.View.Render(viewContext, sw); + + return sw.GetStringBuilder().ToString(); + } + } + + private static void ThrowIfViewNotFound(ViewEngineResult viewResult, string viewName) + { + // if view not found, throw an exception with searched locations + if (viewResult.View == null) + { + var locations = new StringBuilder(); + locations.AppendLine(); + + foreach (string location in viewResult.SearchedLocations) + { + locations.AppendLine(location); + } + + throw new InvalidOperationException(string.Format("The view '{0}' or its master was not found, searched locations: {1}", viewName, locations)); + } + } + /// /// Get active store scope (for multi-store configuration mode) /// diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/CustomerLastActivityAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/CustomerLastActivityAttribute.cs deleted file mode 100644 index 7e5b450da5..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/CustomerLastActivityAttribute.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Customers; - -namespace SmartStore.Web.Framework.Controllers -{ - public class CustomerLastActivityAttribute : ActionFilterAttribute - { - - public Lazy WorkContext { get; set; } - public Lazy CustomerService { get; set; } - - public override void OnActionExecuting(ActionExecutingContext filterContext) - { - if (!DataSettings.DatabaseIsInstalled()) - return; - - if (filterContext == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) - return; - - //don't apply filter to child methods - if (filterContext.IsChildAction) - return; - - //only GET requests - if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) - return; - - var workContext = WorkContext.Value; - var customer = workContext.CurrentCustomer; - - //update last activity date - if (customer.LastActivityDateUtc.AddMinutes(1.0) < DateTime.UtcNow) - { - var customerService = CustomerService.Value; - customer.LastActivityDateUtc = DateTime.UtcNow; - customerService.UpdateCustomer(customer); - } - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/FormValueRequiredAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/FormValueRequiredAttribute.cs deleted file mode 100644 index 8f826791fa..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/FormValueRequiredAttribute.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Diagnostics; -using System.Reflection; -using System.Web.Mvc; - -namespace SmartStore.Web.Framework.Controllers -{ - public class FormValueRequiredAttribute : ActionMethodSelectorAttribute - { - private readonly string[] _submitButtonNames; - private readonly FormValueRequirement _requirement; - - public FormValueRequiredAttribute(params string[] submitButtonNames): - this(FormValueRequirement.Equal, submitButtonNames) - { - } - - public FormValueRequiredAttribute(FormValueRequirement requirement, params string[] submitButtonNames) - { - //at least one submit button should be found - this._submitButtonNames = submitButtonNames; - this._requirement = requirement; - } - - public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) - { - foreach (string buttonName in _submitButtonNames) - { - try - { - string value = ""; - switch (this._requirement) - { - case FormValueRequirement.Equal: - { - //do not iterate because "Invalid request" exception can be thrown - value = controllerContext.HttpContext.Request.Form[buttonName]; - } - break; - case FormValueRequirement.StartsWith: - { - foreach (var formValue in controllerContext.HttpContext.Request.Form.AllKeys) - { - if (formValue.StartsWith(buttonName, StringComparison.InvariantCultureIgnoreCase)) - { - value = controllerContext.HttpContext.Request.Form[formValue]; - break; - } - } - } - break; - } - if (!String.IsNullOrEmpty(value)) - return true; - } - catch (Exception exc) - { - //try-catch to ensure that - Debug.WriteLine(exc.Message); - } - } - return false; - } - } - - public enum FormValueRequirement - { - Equal, - StartsWith - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/LanguageSeoCodeAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/LanguageSeoCodeAttribute.cs deleted file mode 100644 index 5331550aa6..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/LanguageSeoCodeAttribute.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Web; -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Core; -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Infrastructure; -using SmartStore.Web.Framework.Localization; - -namespace SmartStore.Web.Framework.Controllers -{ - /// - /// Attribute which ensures that store URL contains a language SEO code if "SEO friendly URLs with multiple languages" setting is enabled - /// - public class LanguageSeoCodeAttribute : ActionFilterAttribute - { - - public Lazy WorkContext { get; set; } - public Lazy LocalizationSettings { get; set; } - - public override void OnActionExecuting(ActionExecutingContext filterContext) - { - if (filterContext == null || filterContext.HttpContext == null) - return; - - HttpRequestBase request = filterContext.HttpContext.Request; - if (request == null) - return; - - //don't apply filter to child methods - if (filterContext.IsChildAction) - return; - - //only GET requests - if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) - return; - - // ensure that this route is registered and localizable (LocalizedRoute in RouteProvider.cs) - if (filterContext.RouteData == null || filterContext.RouteData.Route == null || !(filterContext.RouteData.Route is LocalizedRoute)) - return; - - if (!DataSettings.DatabaseIsInstalled()) - return; - - var localizationSettings = LocalizationSettings.Value; - if (!localizationSettings.SeoFriendlyUrlsForLanguagesEnabled) - return; - - // process current URL - var workContext = WorkContext.Value; - var workingLanguage = workContext.WorkingLanguage; - var helper = new LocalizedUrlHelper(filterContext.HttpContext.Request, true); - string defaultSeoCode = workContext.GetDefaultLanguageSeoCode(); - - string seoCode; - if (helper.IsLocalizedUrl(out seoCode)) - { - if (!workContext.IsPublishedLanguage(seoCode)) - { - // language is not defined in system or not assigned to store - if (localizationSettings.InvalidLanguageRedirectBehaviour == InvalidLanguageRedirectBehaviour.ReturnHttp404) - { - filterContext.Result = new RedirectResult("~/404"); - } - else if (localizationSettings.InvalidLanguageRedirectBehaviour == InvalidLanguageRedirectBehaviour.FallbackToWorkingLanguage) - { - helper.StripSeoCode(); - filterContext.Result = new RedirectResult(helper.GetAbsolutePath(), true); - } - } - else - { - // redirect default language (if desired) - if (seoCode == defaultSeoCode && localizationSettings.DefaultLanguageRedirectBehaviour == DefaultLanguageRedirectBehaviour.StripSeoCode) - { - helper.StripSeoCode(); - filterContext.Result = new RedirectResult(helper.GetAbsolutePath(), true); - } - } - - // already localized URL, skip the rest - return; - } - - // keep default language prefixless (if desired) - if (workingLanguage.UniqueSeoCode == defaultSeoCode && (int)(localizationSettings.DefaultLanguageRedirectBehaviour) > 0) - { - return; - } - - // add language code to URL - helper.PrependSeoCode(workingLanguage.UniqueSeoCode); - filterContext.Result = new RedirectResult(helper.GetAbsolutePath()); - } - - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/PaymentControllerBase.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/PaymentControllerBase.cs index 9d779a5c1b..71b1927f2b 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/PaymentControllerBase.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/PaymentControllerBase.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Specialized; using System.Web.Mvc; using SmartStore.Services.Payments; @@ -9,5 +10,22 @@ public abstract class PaymentControllerBase : SmartController { public abstract IList ValidatePaymentForm(FormCollection form); public abstract ProcessPaymentRequest GetPaymentInfo(FormCollection form); + + public virtual string GetPaymentSummary(FormCollection form) + { + return null; + } + + protected virtual NameValueCollection GetPaymentData() + { + if (Request.RequestType.IsCaseInsensitiveEqual("POST")) + { + return Request.Form; + } + + var persisted = Session["PaymentData"] as NameValueCollection; + + return persisted ?? Request.Form; + } } } diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/PluginControllerBase.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/PluginControllerBase.cs index fe74cf8b8b..c1163aa7d6 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/PluginControllerBase.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/PluginControllerBase.cs @@ -1,30 +1,30 @@ -using System.Web.Mvc; +using System.Diagnostics.CodeAnalysis; +using System.Web.Mvc; using System.Web.Routing; using SmartStore.Core; using SmartStore.Core.Infrastructure; namespace SmartStore.Web.Framework.Controllers { - - [AdminAuthorize] public abstract partial class PluginControllerBase : SmartController { - /// - /// Initialize controller - /// - /// Request context - protected override void Initialize(RequestContext requestContext) - { - //set work context to admin mode - EngineContext.Current.Resolve().IsAdmin = true; + ///// + ///// Initialize controller + ///// + ///// Request context + //protected override void Initialize(RequestContext requestContext) + //{ + // ////set work context to admin mode + // //EngineContext.Current.Resolve().IsAdmin = true; - base.Initialize(requestContext); - } + // base.Initialize(requestContext); + //} /// /// Access denied view /// /// Access denied view + [SuppressMessage("ReSharper", "Mvc.AreaNotResolved")] protected ActionResult AccessDeniedView() { return RedirectToAction("AccessDenied", "Security", new { pageUrl = this.Request.RawUrl, area = "Admin" }); diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/PublicControllerBase.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/PublicControllerBase.cs index 1fd8d9a96d..5405872037 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/PublicControllerBase.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/PublicControllerBase.cs @@ -1,5 +1,8 @@ using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Localization; using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Seo; namespace SmartStore.Web.Framework.Controllers { @@ -8,10 +11,11 @@ namespace SmartStore.Web.Framework.Controllers [StoreIpAddress] [StoreLastVisitedPage] [CheckAffiliate] - [StoreClosedAttribute] + [StoreClosed] [PublicStoreAllowNavigation] - [LanguageSeoCodeAttribute] + [LanguageSeoCode] [RequireHttpsByConfigAttribute(SslRequirement.Retain)] + [CanonicalHostName] public abstract partial class PublicControllerBase : SmartController { } diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/RssActionResult.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/RssActionResult.cs deleted file mode 100644 index 2015b85b1b..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/RssActionResult.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.ServiceModel.Syndication; -using System.Web.Mvc; -using System.Xml; - -namespace SmartStore.Web.Framework.Controllers -{ - public class RssActionResult : ActionResult - { - public SyndicationFeed Feed { get; set; } - - public override void ExecuteResult(ControllerContext context) - { - context.HttpContext.Response.ContentType = "application/rss+xml"; - - var rssFormatter = new Rss20FeedFormatter(Feed); - using (var writer = XmlWriter.Create(context.HttpContext.Response.Output)) - { - rssFormatter.WriteTo(writer); - } - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartAsyncController.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartAsyncController.cs deleted file mode 100644 index 3c78e69e37..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartAsyncController.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Core; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Logging; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Web.Framework.Security; -using SmartStore.Web.Framework.UI; - -namespace SmartStore.Web.Framework.Controllers -{ - [SetWorkingCulture] - [CustomerLastActivity] - [StoreIpAddress] - [StoreLastVisitedPage] - [CheckAffiliate] - [StoreClosedAttribute] - [PublicStoreAllowNavigation] - [LanguageSeoCodeAttribute] - [RequireHttpsByConfigAttribute(SslRequirement.Retain)] - public abstract partial class SmartAsyncController : AsyncController - { - - protected override void Initialize(RequestContext requestContext) - { - base.Initialize(requestContext); - } - - /// - /// Log exception - /// - /// Exception - private void LogException(Exception exc) - { - var workContext = EngineContext.Current.Resolve(); - var logger = EngineContext.Current.Resolve(); - - var customer = workContext.CurrentCustomer; - logger.Error(exc.Message, exc, customer); - } - /// - /// Display success notification - /// - /// Message - /// A value indicating whether a message should be persisted for the next request - protected virtual void SuccessNotification(string message, bool persistForTheNextRequest = true) - { - AddNotification(NotifyType.Success, message, persistForTheNextRequest); - } - /// - /// Display error notification - /// - /// Message - /// A value indicating whether a message should be persisted for the next request - protected virtual void ErrorNotification(string message, bool persistForTheNextRequest = true) - { - AddNotification(NotifyType.Error, message, persistForTheNextRequest); - } - /// - /// Display error notification - /// - /// Exception - /// A value indicating whether a message should be persisted for the next request - /// A value indicating whether exception should be logged - protected virtual void ErrorNotification(Exception exception, bool persistForTheNextRequest = true, bool logException = true) - { - if (logException) - LogException(exception); - AddNotification(NotifyType.Error, exception.Message, persistForTheNextRequest); - } - /// - /// Display notification - /// - /// Notification type - /// Message - /// A value indicating whether a message should be persisted for the next request - protected virtual void AddNotification(NotifyType type, string message, bool persistForTheNextRequest) - { - string dataKey = string.Format("sm.notifications.{0}", type); - if (persistForTheNextRequest) - { - if (TempData[dataKey] == null) - TempData[dataKey] = new List(); - ((List)TempData[dataKey]).Add(message); - } - else - { - if (ViewData[dataKey] == null) - ViewData[dataKey] = new List(); - ((List)ViewData[dataKey]).Add(message); - } - } - - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs index eae03616d5..29fdb90d52 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs +++ b/src/Presentation/SmartStore.Web.Framework/Controllers/SmartController.cs @@ -1,31 +1,45 @@ using System; -using System.Collections.Generic; +using System.Text; +using System.Web; using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Core; -using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; using SmartStore.Core.Logging; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Web.Framework.Security; -using SmartStore.Web.Framework.UI; +using SmartStore.Services; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Localization; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Framework.Controllers { [SetWorkingCulture] [Notify] + [JsonNet] public abstract partial class SmartController : Controller { - private readonly Lazy _notifier; - protected SmartController() { this.Logger = NullLogger.Instance; - this._notifier = EngineContext.Current.Resolve>(); + this.T = NullLocalizer.Instance; + } + + public ILogger Logger + { + get; + set; + } + + public Localizer T + { + get; + set; } + public ICommonServices Services + { + get; + set; + } - public ILogger Logger { get; set; } - /// /// Pushes an info message to the notification queue /// @@ -33,7 +47,7 @@ protected SmartController() /// A value indicating whether the message should be persisted for the next request protected virtual void NotifyInfo(string message, bool durable = true) { - _notifier.Value.Information(message, durable); + Services.Notifier.Information(message, durable); } /// @@ -43,7 +57,7 @@ protected virtual void NotifyInfo(string message, bool durable = true) /// A value indicating whether the message should be persisted for the next request protected virtual void NotifyWarning(string message, bool durable = true) { - _notifier.Value.Warning(message, durable); + Services.Notifier.Warning(message, durable); } /// @@ -53,7 +67,7 @@ protected virtual void NotifyWarning(string message, bool durable = true) /// A value indicating whether the message should be persisted for the next request protected virtual void NotifySuccess(string message, bool durable = true) { - _notifier.Value.Success(message, durable); + Services.Notifier.Success(message, durable); } /// @@ -63,7 +77,7 @@ protected virtual void NotifySuccess(string message, bool durable = true) /// A value indicating whether the message should be persisted for the next request protected virtual void NotifyError(string message, bool durable = true) { - _notifier.Value.Error(message, durable); + Services.Notifier.Error(message, durable); } /// @@ -79,7 +93,98 @@ protected virtual void NotifyError(Exception exception, bool durable = true, boo LogException(exception); } - _notifier.Value.Error(exception.Message, durable); + Services.Notifier.Error(HttpUtility.HtmlEncode(exception.ToAllMessages()), durable); + } + + /// + /// Pushes an error message to the notification queue that the access to a resource has been denied + /// + /// A value indicating whether a message should be persisted for the next request + /// A value indicating whether the message should be logged + protected virtual void NotifyAccessDenied(bool durable = true, bool log = true) + { + var message = T("Admin.AccessDenied.Description"); + + if (log) + { + Logger.Error(message, null, Services.WorkContext.CurrentCustomer); + } + + Services.Notifier.Error(message, durable); + } + + protected ActionResult RedirectToReferrer() + { + return RedirectToReferrer(null, () => RedirectToRoute("HomePage")); + } + + protected ActionResult RedirectToReferrer(string referrer) + { + return RedirectToReferrer(referrer, () => RedirectToRoute("HomePage")); + } + + protected ActionResult RedirectToReferrer(string referrer, string fallbackUrl) + { + // addressing "Open Redirection Vulnerability" (prevent cross-domain redirects / phishing) + if (fallbackUrl.HasValue() && !Url.IsLocalUrl(fallbackUrl)) + { + fallbackUrl = null; + } + + return RedirectToReferrer( + referrer, + fallbackUrl.HasValue() ? () => Redirect(fallbackUrl) : (Func)null); + } + + protected virtual ActionResult RedirectToReferrer(string referrer, Func fallbackResult) + { + bool skipLocalCheck = false; + + if (referrer.IsEmpty() && Request.UrlReferrer != null && Request.UrlReferrer.ToString().HasValue()) + { + referrer = Request.UrlReferrer.ToString(); + if (referrer.HasValue()) + { + var domain1 = (new Uri(referrer)).GetLeftPart(UriPartial.Authority); + var domain2 = this.Request.Url.GetLeftPart(UriPartial.Authority); + if (domain1.IsCaseInsensitiveEqual(domain2)) + { + // always allow fully qualified urls from local host + skipLocalCheck = true; + } + else + { + referrer = null; + } + } + } + + // addressing "Open Redirection Vulnerability" (prevent cross-domain redirects / phishing) + if (referrer.HasValue() && !skipLocalCheck && !Url.IsLocalUrl(referrer)) + { + referrer = null; + } + + if (referrer.HasValue()) + { + return Redirect(referrer); + } + + if (fallbackResult != null) + { + return fallbackResult(); + } + + return HttpNotFound(); + } + + protected virtual ActionResult RedirectToHomePageWithError(string reason, bool durable = true) + { + string message = T("Common.RequestProcessingFailed", this.RouteData.Values["controller"], this.RouteData.Values["action"], reason.NaIfEmpty()); + + Services.Notifier.Error(message, durable); + + return RedirectToRoute("HomePage"); } /// @@ -102,11 +207,31 @@ protected override void OnException(ExceptionContext filterContext) /// Exception private void LogException(Exception exc) { - var workContext = EngineContext.Current.Resolve(); - - var customer = workContext.CurrentCustomer; + var customer = Services.WorkContext.CurrentCustomer; Logger.Error(exc.Message, exc, customer); } + ///// + ///// Creates a object that serializes the specified object to JavaScript Object Notation (JSON) format using the content type, + ///// content encoding, and the JSON request behavior. + ///// + ///// The JavaScript object graph to serialize. + ///// The content type (MIME type). + ///// The content encoding. + ///// The JSON request behavior + ///// The result object that serializes the specified object to JSON format. + ///// + ///// This overridden method internally uses the Json.NET library for serialization. + ///// + //protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) + //{ + // return new JsonNetResult(Services.DateTimeHelper) + // { + // Data = data, + // ContentType = contentType, + // ContentEncoding = contentEncoding, + // JsonRequestBehavior = behavior + // }; + //} } } diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreClosedAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/StoreClosedAttribute.cs deleted file mode 100644 index 66e2bc3446..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreClosedAttribute.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Data; -using SmartStore.Core.Domain; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Customers; - -namespace SmartStore.Web.Framework.Controllers -{ - public class StoreClosedAttribute : ActionFilterAttribute - { - private static readonly List> s_permittedRoutes = new List> - { - new Tuple("SmartStore.Web.Controllers.CustomerController", "Login"), - new Tuple("SmartStore.Web.Controllers.CustomerController", "Logout"), - new Tuple("SmartStore.Web.Controllers.CommonController", "StoreClosed"), - new Tuple("SmartStore.Web.Controllers.CommonController", "SetLanguage") - }; - - - public Lazy WorkContext { get; set; } - public Lazy StoreInformationSettings { get; set; } - - public override void OnActionExecuting(ActionExecutingContext filterContext) - { - if (filterContext == null || filterContext.HttpContext == null) - return; - - HttpRequestBase request = filterContext.HttpContext.Request; - if (request == null) - return; - - //don't apply filter to child methods - if (filterContext.IsChildAction) - return; - - string actionName = filterContext.ActionDescriptor.ActionName; - if (String.IsNullOrEmpty(actionName)) - return; - - string controllerName = filterContext.Controller.ToString(); - if (String.IsNullOrEmpty(controllerName)) - return; - - if (!DataSettings.DatabaseIsInstalled()) - return; - - var storeInformationSettings = StoreInformationSettings.Value; - if (!storeInformationSettings.StoreClosed) - return; - - if (!IsPermittedRoute(controllerName, actionName)) - { - if (storeInformationSettings.StoreClosedAllowForAdmins && WorkContext.Value.CurrentCustomer.IsAdmin()) - { - //do nothing - allow admin access - } - else - { - var storeClosedUrl = new UrlHelper(filterContext.RequestContext).RouteUrl("StoreClosed"); - filterContext.Result = new RedirectResult(storeClosedUrl); - } - } - } - - private static bool IsPermittedRoute(string controllerName, string actionName) - { - foreach (var route in s_permittedRoutes) - { - if (controllerName.IsCaseInsensitiveEqual(route.Item1) && actionName.IsCaseInsensitiveEqual(route.Item2)) - { - return true; - } - } - - return false; - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreLastVisitedPageAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Controllers/StoreLastVisitedPageAttribute.cs deleted file mode 100644 index 01185b5ad0..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreLastVisitedPageAttribute.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Common; - -namespace SmartStore.Web.Framework.Controllers -{ - public class StoreLastVisitedPageAttribute : ActionFilterAttribute - { - - public Lazy WebHelper { get; set; } - public Lazy WorkContext { get; set; } - public Lazy CustomerSettings { get; set; } - public Lazy GenericAttributeService { get; set; } - - public override void OnActionExecuting(ActionExecutingContext filterContext) - { - if (!DataSettings.DatabaseIsInstalled()) - return; - - if (filterContext == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) - return; - - //don't apply filter to child methods - if (filterContext.IsChildAction) - return; - - //only GET requests - if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) - return; - - var customerSettings = CustomerSettings.Value; - if (!customerSettings.StoreLastVisitedPage) - return; - - var webHelper = this.WebHelper.Value; - var pageUrl = webHelper.GetThisPageUrl(true); - if (!String.IsNullOrEmpty(pageUrl)) - { - var workContext = WorkContext.Value; - var genericAttributeService = GenericAttributeService.Value; - - var previousPageUrl = workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.LastVisitedPage); - if (!pageUrl.Equals(previousPageUrl)) - { - genericAttributeService.SaveAttribute(workContext.CurrentCustomer, SystemCustomerAttributeNames.LastVisitedPage, pageUrl); - } - } - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs index ba0763f24b..73a2c9bd9a 100644 --- a/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web.Framework/DependencyRegistrar.cs @@ -3,21 +3,34 @@ using System.Linq; using System.Reflection; using System.Web; +using System.Web.Mvc; using Autofac; using Autofac.Builder; using Autofac.Core; using Autofac.Integration.Mvc; using Autofac.Integration.WebApi; +using SmartStore.ComponentModel; using SmartStore.Core; using SmartStore.Core.Caching; using SmartStore.Core.Configuration; using SmartStore.Core.Data; +using SmartStore.Core.Data.Hooks; +using SmartStore.Core.Domain.DataExchange; +using SmartStore.Core.Email; using SmartStore.Core.Events; using SmartStore.Core.Fakes; using SmartStore.Core.Infrastructure; using SmartStore.Core.Infrastructure.DependencyManagement; +using SmartStore.Core.IO.Media; +using SmartStore.Core.IO.VirtualPath; +using SmartStore.Core.IO.WebSite; +using SmartStore.Core.Localization; +using SmartStore.Core.Logging; +using SmartStore.Core.Packaging; using SmartStore.Core.Plugins; +using SmartStore.Core.Themes; using SmartStore.Data; +using SmartStore.Services; using SmartStore.Services.Affiliates; using SmartStore.Services.Authentication; using SmartStore.Services.Authentication.External; @@ -27,193 +40,292 @@ using SmartStore.Services.Common; using SmartStore.Services.Configuration; using SmartStore.Services.Customers; +using SmartStore.Services.DataExchange; +using SmartStore.Services.DataExchange.Export; +using SmartStore.Services.DataExchange.Import; using SmartStore.Services.Directory; using SmartStore.Services.Discounts; -using SmartStore.Services.ExportImport; +using SmartStore.Services.Events; +using SmartStore.Services.Filter; using SmartStore.Services.Forums; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; +using SmartStore.Services.Logging; using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.News; using SmartStore.Services.Orders; using SmartStore.Services.Payments; +using SmartStore.Services.Pdf; using SmartStore.Services.Polls; using SmartStore.Services.Security; using SmartStore.Services.Seo; using SmartStore.Services.Shipping; +using SmartStore.Services.Stores; using SmartStore.Services.Tasks; using SmartStore.Services.Tax; +using SmartStore.Services.Themes; using SmartStore.Services.Topics; -using SmartStore.Web.Framework.Mvc.Routes; -using SmartStore.Web.Framework.Mvc.Bundles; -using SmartStore.Web.Framework.Themes; +using SmartStore.Utilities; +using SmartStore.Web.Framework.Bundling; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Localization; +using SmartStore.Web.Framework.Plugins; +using SmartStore.Web.Framework.Routing; +using SmartStore.Web.Framework.Theming; using SmartStore.Web.Framework.UI; -using SmartStore.Services.Filter; -using SmartStore.Core.Data.Hooks; -using SmartStore.Core.Themes; -using SmartStore.Services.Themes; -using SmartStore.Services.Stores; +using SmartStore.Web.Framework.WebApi; using SmartStore.Web.Framework.WebApi.Configuration; -using SmartStore.Services; using Module = Autofac.Module; -using SmartStore.Core.Localization; -using SmartStore.Web.Framework.Localization; -using SmartStore.Core.Email; -using SmartStore.Services.Events; -using SmartStore.Services.Logging; -using SmartStore.Core.Packaging; -using SmartStore.Core.IO.Media; -using SmartStore.Core.IO.VirtualPath; -using SmartStore.Core.IO.WebSite; -using SmartStore.Web.Framework.WebApi; +using SmartStore.Services.Catalog.Importer; +using SmartStore.Services.Customers.Importer; +using SmartStore.Services.Messages.Importer; namespace SmartStore.Web.Framework { - public class DependencyRegistrar : IDependencyRegistrar + public class DependencyRegistrar : IDependencyRegistrar { public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, bool isActiveModule) { + // plugins + var pluginFinder = new PluginFinder(); + builder.RegisterInstance(pluginFinder).As().SingleInstance(); + builder.RegisterType(); + // modules + builder.RegisterModule(new CoreModule(typeFinder)); builder.RegisterModule(new DbModule(typeFinder)); builder.RegisterModule(new CachingModule()); builder.RegisterModule(new LocalizationModule()); builder.RegisterModule(new LoggingModule()); - builder.RegisterModule(new EventModule(typeFinder)); + builder.RegisterModule(new EventModule(typeFinder, pluginFinder)); builder.RegisterModule(new MessagingModule()); builder.RegisterModule(new WebModule(typeFinder)); builder.RegisterModule(new WebApiModule(typeFinder)); builder.RegisterModule(new UiModule(typeFinder)); builder.RegisterModule(new IOModule()); builder.RegisterModule(new PackagingModule()); + builder.RegisterModule(new ProvidersModule(typeFinder, pluginFinder)); + builder.RegisterModule(new TasksModule(typeFinder)); + builder.RegisterModule(new DataExchangeModule(typeFinder)); + } + public int Order + { + get { return -100; } + } + } + + #region Modules + + public class CoreModule : Module + { + private readonly ITypeFinder _typeFinder; + + public CoreModule(ITypeFinder typeFinder) + { + _typeFinder = typeFinder; + } + + protected override void Load(ContainerBuilder builder) + { // sources builder.RegisterSource(new SettingsSource()); - // web helper - builder.RegisterType().As().InstancePerRequest(); - - // plugins - builder.RegisterType().As().SingleInstance(); // xxx (http) + // web helper + builder.RegisterType().As().InstancePerRequest(); + + // work context + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - // work context - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - // store context builder.RegisterType().As().InstancePerRequest(); - // services - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); + // services + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().Named("nocache") + .WithNullCache() + .InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As() + .WithNullCache() + .InstancePerRequest(); + builder.RegisterType().Named("nocache") + .WithNullCache() + .InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().Named("nocache").InstancePerRequest(); + + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerLifetimeScope(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); + + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithStaticCache() .InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); + builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().WithStaticCache().InstancePerRequest(); - } + } - public int Order - { - get { return -100; } - } - } + protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) + { + // Look for first settable property of type "ICommonServices" and inject + var servicesProperty = FindCommonServicesProperty(registration.Activator.LimitType); - #region Modules + if (servicesProperty == null) + return; + + var fastProperty = new FastProperty(servicesProperty); + + registration.Activated += (sender, e) => + { + if (DataSettings.DatabaseIsInstalled()) + { + var services = e.Context.Resolve(); + fastProperty.SetValue(e.Instance, services); + } + }; + } + + private static PropertyInfo FindCommonServicesProperty(Type type) + { + var prop = type + .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) + .Select(p => new + { + PropertyInfo = p, + p.PropertyType, + IndexParameters = p.GetIndexParameters(), + Accessors = p.GetAccessors(false) + }) + .Where(x => x.PropertyType == typeof(ICommonServices)) // must be ICommonServices + .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer + .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set + .Select(x => x.PropertyInfo) + .FirstOrDefault(); + + return prop; + } + + private IEnumerable> BuildLoggerInjectors(Type componentType) + { + // Look for first settable property of type "ICommonServices" + var loggerProperties = componentType + .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) + .Select(p => new + { + PropertyInfo = p, + p.PropertyType, + IndexParameters = p.GetIndexParameters(), + Accessors = p.GetAccessors(false) + }) + .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger + .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer + .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set + .Select(x => new FastProperty(x.PropertyInfo)); + + // Return an array of actions that resolve a logger and assign the property + foreach (var prop in loggerProperties) + { + yield return (ctx, instance) => + { + string component = componentType.ToString(); + var logger = ctx.Resolve(); + prop.SetValue(instance, logger); + }; + } + } + } public class DbModule : Module { @@ -283,12 +395,14 @@ protected override void Load(ContainerBuilder builder) builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>)).InstancePerRequest(); - builder.Register(c => { + builder.Register(c => + { var storeService = c.Resolve(); var aclService = c.Resolve(); return new DbQuerySettings(!aclService.HasActiveAcl, storeService.IsSingleStoreMode()); - }).InstancePerRequest(); + }) + .InstancePerRequest(); } protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) @@ -298,10 +412,15 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone if (querySettingsProperty == null) return; + var fastProperty = new FastProperty(querySettingsProperty); + registration.Activated += (sender, e) => { - var querySettings = e.Context.Resolve(); - querySettingsProperty.SetValue(e.Instance, querySettings, null); + if (DataSettings.DatabaseIsInstalled()) + { + var querySettings = e.Context.Resolve(); + fastProperty.SetValue(e.Instance, querySettings); + } }; } @@ -317,7 +436,7 @@ protected override void Load(ContainerBuilder builder) { builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); } protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) @@ -344,34 +463,30 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone private IEnumerable> BuildLoggerInjectors(Type componentType) { - if (DataSettings.DatabaseIsInstalled()) - { - // Look for settable properties of type "ILogger" - var loggerProperties = componentType - .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) - .Select(p => new - { - PropertyInfo = p, - p.PropertyType, - IndexParameters = p.GetIndexParameters(), - Accessors = p.GetAccessors(false) - }) - .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger - .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer - .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)); //must have get/set, or only set - - // Return an array of actions that resolve a logger and assign the property - foreach (var entry in loggerProperties) + // Look for settable properties of type "ILogger" + var loggerProperties = componentType + .GetProperties(BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance) + .Select(p => new { - var propertyInfo = entry.PropertyInfo; + PropertyInfo = p, + p.PropertyType, + IndexParameters = p.GetIndexParameters(), + Accessors = p.GetAccessors(false) + }) + .Where(x => x.PropertyType == typeof(ILogger)) // must be a logger + .Where(x => x.IndexParameters.Count() == 0) // must not be an indexer + .Where(x => x.Accessors.Length != 1 || x.Accessors[0].ReturnType == typeof(void)) //must have get/set, or only set + .Select(x => new FastProperty(x.PropertyInfo)); - yield return (ctx, instance) => - { - string component = componentType.ToString(); - var logger = ctx.Resolve(); - propertyInfo.SetValue(instance, logger, null); - }; - } + // Return an array of actions that resolve a logger and assign the property + foreach (var prop in loggerProperties) + { + yield return (ctx, instance) => + { + string component = componentType.ToString(); + var logger = ctx.Resolve(); + prop.SetValue(instance, logger); + }; } } } @@ -380,7 +495,7 @@ public class LocalizationModule : Module { protected override void Load(ContainerBuilder builder) { - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As() @@ -401,10 +516,15 @@ protected override void AttachToComponentRegistration(IComponentRegistry compone if (userProperty == null) return; + var fastProperty = new FastProperty(userProperty); + registration.Activated += (sender, e) => { - Localizer localizer = e.Context.Resolve().Get; - userProperty.SetValue(e.Instance, localizer, null); + if (DataSettings.DatabaseIsInstalled()) + { + Localizer localizer = e.Context.Resolve().Get; + fastProperty.SetValue(e.Instance, localizer); + } }; } @@ -418,22 +538,22 @@ public class CachingModule : Module { protected override void Load(ContainerBuilder builder) { - builder.RegisterType().As().Keyed(typeof(StaticCache)).SingleInstance(); - builder.RegisterType().As().Keyed(typeof(AspNetCache)).InstancePerRequest(); - builder.RegisterType().As().Keyed(typeof(RequestCache)).InstancePerRequest(); + builder.RegisterType().Keyed(typeof(StaticCache)).SingleInstance(); + builder.RegisterType().Keyed(typeof(AspNetCache)).SingleInstance(); + builder.RegisterType().Keyed(typeof(RequestCache)).InstancePerRequest(); - builder.RegisterType>() + builder.RegisterType>() .As() + .InstancePerRequest(); + builder.RegisterType>() .Named("static") .SingleInstance(); builder.RegisterType>() - .As() .Named("aspnet") - .InstancePerRequest(); - builder.RegisterType>() - .As() - .Named("request") - .InstancePerRequest(); + .SingleInstance(); + builder.RegisterType() + .Named("null") + .SingleInstance(); // Register resolving delegate builder.Register>(c => @@ -459,10 +579,12 @@ protected override void Load(ContainerBuilder builder) public class EventModule : Module { private readonly ITypeFinder _typeFinder; + private readonly IPluginFinder _pluginFinder; - public EventModule(ITypeFinder typeFinder) + public EventModule(ITypeFinder typeFinder, IPluginFinder pluginFinder) { _typeFinder = typeFinder; + _pluginFinder = pluginFinder; } protected override void Load(ContainerBuilder builder) @@ -478,12 +600,14 @@ protected override void Load(ContainerBuilder builder) var registration = builder.RegisterType(consumerType).As(implementedInterfaces); + var pluginDescriptor = _pluginFinder.GetPluginDescriptorByAssembly(consumerType.Assembly); var isActive = PluginManager.IsActivePluginAssembly(consumerType.Assembly); var shouldExecuteAsync = consumerType.GetAttribute(false) != null; registration.WithMetadata(m => { m.For(em => em.IsActive, isActive); m.For(em => em.ExecuteAsync, shouldExecuteAsync); + m.For(em => em.PluginDescriptor, pluginDescriptor); }); if (!shouldExecuteAsync) @@ -503,7 +627,7 @@ public class MessagingModule : Module { protected override void Load(ContainerBuilder builder) { - builder.RegisterType().As().WithRequestCache().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); @@ -529,7 +653,7 @@ protected override void Load(ContainerBuilder builder) var foundAssemblies = _typeFinder.GetAssemblies(ignoreInactivePlugins: true).ToArray(); builder.RegisterModule(new AutofacWebTypesModule()); - builder.Register(HttpContextBaseFactory).As().InstancePerRequest(); + builder.Register(HttpContextBaseFactory).As(); // register all controllers builder.RegisterControllers(foundAssemblies); @@ -537,8 +661,15 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().InstancePerRequest(); builder.RegisterFilterProvider(); + + // global exception handling + if (DataSettings.DatabaseIsInstalled()) + { + builder.RegisterType().AsActionFilterFor(); + } } static HttpContextBase HttpContextBaseFactory(IComponentContext ctx) @@ -589,11 +720,14 @@ protected override void Load(ContainerBuilder builder) // register all api controllers builder.RegisterApiControllers(foundAssemblies); - builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); } protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) { + if (!DataSettings.DatabaseIsInstalled()) + return; + var baseType = typeof(WebApiEntityController<,>); var type = registration.Activator.LimitType; Type implementingType; @@ -649,7 +783,9 @@ public UiModule(ITypeFinder typeFinder) protected override void Load(ContainerBuilder builder) { // register theming services - builder.RegisterType().As().SingleInstance(); + builder.Register(x => new DefaultThemeRegistry(x.Resolve(), null, null, true)).As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerRequest(); builder.RegisterType().As().InstancePerRequest(); @@ -659,13 +795,7 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().As>(); builder.RegisterType().As().InstancePerRequest(); - - // Register simple (code) widgets - var widgetTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true).Where(x => !typeof(IWidgetPlugin).IsAssignableFrom(x)); - foreach (var widgetType in widgetTypes) - { - builder.RegisterType(widgetType).As().Named(widgetType.FullName).InstancePerRequest(); - } + builder.RegisterType().As().InstancePerRequest(); } } @@ -690,28 +820,304 @@ protected override void Load(ContainerBuilder builder) } } - //public class PluginsModule : Module - //{ - // private readonly ITypeFinder _typeFinder; - - // public PluginsModule(ITypeFinder typeFinder) - // { - // _typeFinder = typeFinder; - // } - - // protected override void Load(ContainerBuilder builder) - // { - // // Register payment methods - // var types = _typeFinder.FindClassesOfType(typeof(IPaymentMethod)); - // foreach (var type in types) - // { - // if (PluginManager.IsActivePluginAssembly(type.Assembly)) - // { - // builder.RegisterType(type).As().Named(type.FullName).InstancePerRequest(); - // } - // } - // } - //} + public class ProvidersModule : Module + { + private readonly ITypeFinder _typeFinder; + private readonly IPluginFinder _pluginFinder; + + public ProvidersModule(ITypeFinder typeFinder, IPluginFinder pluginFinder) + { + _typeFinder = typeFinder; + _pluginFinder = pluginFinder; + } + + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerRequest(); + + if (!DataSettings.DatabaseIsInstalled()) + return; + + var providerTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true).ToList(); + + foreach (var type in providerTypes) + { + var pluginDescriptor = _pluginFinder.GetPluginDescriptorByAssembly(type.Assembly); + var groupName = ProviderTypeToKnownGroupName(type); + var systemName = GetSystemName(type, pluginDescriptor); + var friendlyName = GetFriendlyName(type, pluginDescriptor); + var displayOrder = GetDisplayOrder(type, pluginDescriptor); + var dependentWidgets = GetDependentWidgets(type); + var resPattern = (pluginDescriptor != null ? "Plugins" : "Providers") + ".{1}.{0}"; // e.g. Plugins.FriendlyName.MySystemName + var settingPattern = (pluginDescriptor != null ? "Plugins" : "Providers") + ".{0}.{1}"; // e.g. Plugins.MySystemName.DisplayOrder + var isConfigurable = typeof(IConfigurable).IsAssignableFrom(type); + var isEditable = typeof(IUserEditable).IsAssignableFrom(type); + var isHidden = GetIsHidden(type); + var exportFeature = GetExportFeature(type); + + var registration = builder.RegisterType(type).Named(systemName).InstancePerRequest().PropertiesAutowired(PropertyWiringOptions.None); + registration.WithMetadata(m => + { + m.For(em => em.PluginDescriptor, pluginDescriptor); + m.For(em => em.GroupName, groupName); + m.For(em => em.SystemName, systemName); + m.For(em => em.ResourceKeyPattern, resPattern); + m.For(em => em.SettingKeyPattern, settingPattern); + m.For(em => em.FriendlyName, friendlyName.Item1); + m.For(em => em.Description, friendlyName.Item2); + m.For(em => em.DisplayOrder, displayOrder); + m.For(em => em.DependentWidgets, dependentWidgets); + m.For(em => em.IsConfigurable, isConfigurable); + m.For(em => em.IsEditable, isEditable); + m.For(em => em.IsHidden, isHidden); + m.For(em => em.ExportFeatures, exportFeature); + }); + + // register specific provider type + RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); + RegisterAsSpecificProvider(type, systemName, registration); + } + + } + + #region Helpers + + private void RegisterAsSpecificProvider(Type implType, string systemName, IRegistrationBuilder registration) where T : IProvider + { + if (typeof(T).IsAssignableFrom(implType)) + { + try + { + registration.As().Named(systemName); + registration.WithMetadata(m => + { + m.For(em => em.ProviderType, typeof(T)); + }); + } + catch (Exception) { } + } + } + + private string GetSystemName(Type type, PluginDescriptor descriptor) + { + var attr = type.GetAttribute(false); + if (attr != null) + { + return attr.Name; + } + + if (typeof(IPlugin).IsAssignableFrom(type) && descriptor != null) + { + return descriptor.SystemName; + } + + return type.FullName; + //throw Error.Application("The 'SystemNameAttribute' must be applied to a provider type if the provider does not implement 'IPlugin' (provider type: {0}, plugin: {1})".FormatInvariant(type.FullName, descriptor != null ? descriptor.SystemName : "-")); + } + + private int GetDisplayOrder(Type type, PluginDescriptor descriptor) + { + var attr = type.GetAttribute(false); + if (attr != null) + { + return attr.DisplayOrder; + } + + if (typeof(IPlugin).IsAssignableFrom(type) && descriptor != null) + { + return descriptor.DisplayOrder; + } + + return 0; + } + + private bool GetIsHidden(Type type) + { + var attr = type.GetAttribute(false); + if (attr != null) + { + return attr.IsHidden; + } + + return false; + } + + private ExportFeatures GetExportFeature(Type type) + { + var attr = type.GetAttribute(false); + + if (attr != null) + { + return attr.Features; + } + + return ExportFeatures.None; + } + + private Tuple GetFriendlyName(Type type, PluginDescriptor descriptor) + { + string name = null; + string description = name; + + var attr = type.GetAttribute(false); + if (attr != null) + { + name = attr.Name; + description = attr.Description; + } + else if (typeof(IPlugin).IsAssignableFrom(type) && descriptor != null) + { + name = descriptor.FriendlyName; + description = descriptor.Description; + } + else + { + name = Inflector.Titleize(type.Name); + //throw Error.Application("The 'FriendlyNameAttribute' must be applied to a provider type if the provider does not implement 'IPlugin' (provider type: {0}, plugin: {1})".FormatInvariant(type.FullName, descriptor != null ? descriptor.SystemName : "-")); + } + + return new Tuple(name, description); + } + + private string[] GetDependentWidgets(Type type) + { + if (!typeof(IWidget).IsAssignableFrom(type)) + { + // don't let widgets depend on other widgets + var attr = type.GetAttribute(false); + if (attr != null) + { + return attr.WidgetSystemNames; + } + } + + return new string[] {}; + } + + private string ProviderTypeToKnownGroupName(Type implType) + { + if (typeof(ITaxProvider).IsAssignableFrom(implType)) + { + return "Tax"; + } + else if (typeof(IDiscountRequirementRule).IsAssignableFrom(implType)) + { + return "Marketing"; + } + else if (typeof(IExchangeRateProvider).IsAssignableFrom(implType)) + { + return "Payment"; + } + else if (typeof(IShippingRateComputationMethod).IsAssignableFrom(implType)) + { + return "Shipping"; + } + else if (typeof(IPaymentMethod).IsAssignableFrom(implType)) + { + return "Payment"; + } + else if (typeof(IExternalAuthenticationMethod).IsAssignableFrom(implType)) + { + return "Security"; + } + else if (typeof(IWidget).IsAssignableFrom(implType)) + { + return "CMS"; + } + else if (typeof(IExportProvider).IsAssignableFrom(implType)) + { + return "Exporting"; + } + + return null; + } + + #endregion + + } + + public class TasksModule : Module + { + private readonly ITypeFinder _typeFinder; + + public TasksModule(ITypeFinder typeFinder) + { + _typeFinder = typeFinder; + } + + protected override void Load(ContainerBuilder builder) + { + if (!DataSettings.DatabaseIsInstalled()) + return; + + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().InstancePerRequest(); + + var taskTypes = _typeFinder.FindClassesOfType(ignoreInactivePlugins: true).ToList(); + + foreach (var type in taskTypes) + { + var typeName = type.FullName; + builder.RegisterType(type).Named(typeName).Keyed(type).InstancePerRequest(); + } + + // Register resolving delegate + builder.Register>(c => + { + var cc = c.Resolve(); + return keyed => cc.ResolveKeyed(keyed); + }); + + builder.Register>(c => + { + var cc = c.Resolve(); + return named => cc.ResolveNamed(named); + }); + + } + } + + public class DataExchangeModule : Module + { + private readonly ITypeFinder _typeFinder; + + public DataExchangeModule(ITypeFinder typeFinder) + { + _typeFinder = typeFinder; + } + + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + + if (!DataSettings.DatabaseIsInstalled()) + return; + + builder.RegisterType().As().InstancePerRequest(); + builder.RegisterType().As().InstancePerRequest(); + + // IEntityImporter implementations + builder.RegisterType().Keyed(ImportEntityType.Product).InstancePerRequest(); + builder.RegisterType().Keyed(ImportEntityType.Category).InstancePerRequest(); + builder.RegisterType().Keyed(ImportEntityType.Customer).InstancePerRequest(); + builder.RegisterType().Keyed(ImportEntityType.NewsLetterSubscription).InstancePerRequest(); + + // Register resolving delegate + builder.Register>(c => + { + var cc = c.Resolve(); + return keyed => cc.ResolveKeyed(keyed); + }); + } + + } #endregion @@ -730,16 +1136,8 @@ public IEnumerable RegistrationsFor( var ts = service as TypedService; if (ts != null && typeof(ISettings).IsAssignableFrom(ts.ServiceType)) { - //var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType); - //yield return (IComponentRegistration)buildMethod.Invoke(null, null); - - // Perf with Fasterflect - yield return (IComponentRegistration)Fasterflect.TryInvokeWithValuesExtensions.TryCallMethodWithValues( - typeof(SettingsSource), - null, - "BuildRegistration", - new Type[] { ts.ServiceType }, - BindingFlags.Static | BindingFlags.NonPublic); + var buildMethod = BuildMethod.MakeGenericMethod(ts.ServiceType); + yield return (IComponentRegistration)buildMethod.Invoke(null, null); } } @@ -759,7 +1157,7 @@ public IEnumerable RegistrationsFor( //var currentStoreId = c.Resolve().GetAllStores().Count > 1 // c.Resolve().CurrentStore.Id : 0; - //although it's better to connect to your database and execute the following SQL: + ////although it's better to connect to your database and execute the following SQL: //DELETE FROM [Setting] WHERE [StoreId] > 0 return c.Resolve().LoadSetting(currentStoreId); diff --git a/src/Presentation/SmartStore.Web.Framework/Events/TabStripCreated.cs b/src/Presentation/SmartStore.Web.Framework/Events/TabStripCreated.cs index 3b4b4e6893..d86a2d5c9c 100644 --- a/src/Presentation/SmartStore.Web.Framework/Events/TabStripCreated.cs +++ b/src/Presentation/SmartStore.Web.Framework/Events/TabStripCreated.cs @@ -1,14 +1,20 @@ using System; using System.Web.Mvc; using SmartStore.Web.Framework.UI; +using System.Collections; +using System.Collections.Generic; +using SmartStore.Core.Infrastructure; +using SmartStore.Web.Framework.Localization; namespace SmartStore.Web.Framework.Events { /// - /// Admin tabstrip created event + /// Tabstrip created event /// public class TabStripCreated { + private IList _widgets; + public TabStripCreated(TabFactory itemFactory, string tabStripName, HtmlHelper html, object model = null) { this.TabStripName = tabStripName; @@ -21,5 +27,37 @@ public TabStripCreated(TabFactory itemFactory, string tabStripName, HtmlHelper h public HtmlHelper Html { get; private set; } public object Model { get; private set; } public TabFactory ItemFactory { get; private set; } + + /// + /// Renders a child action into a dynamically created special tab called 'Plugins' + /// + /// + /// Should only be called for admin tabstrips + public void AddWidget(RouteInfo routeInfo) + { + Guard.ArgumentNotNull(() => routeInfo); + + if (_widgets == null) + { + _widgets = new List(); + Html.ViewContext.ViewData["Tab.{0}.Widgets".FormatInvariant(this.TabStripName)] = _widgets; + + CreateWidgetsTab(); + } + + _widgets.Add(routeInfo); + } + + private Tab CreateWidgetsTab() + { + return ItemFactory.Add() + .Text(EngineContext.Current.Resolve().Get("Admin.Plugins")) + .Name("tab-special-plugin-widgets") + .Icon("fa fa-puzzle-piece fa-lg fa-fw") + .LinkHtmlAttributes(new { data_tab_name = "PLUGIN_WIDGETS" }) + .Content("TabWidgets", "Widget", new { area = "", model = this.Model, viewDataKey = "Tab.{0}.Widgets".FormatInvariant(this.TabStripName) }) + .Ajax(false) + .Item; + } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web.Framework/Events/ThemeTouched.cs b/src/Presentation/SmartStore.Web.Framework/Events/ThemeTouched.cs deleted file mode 100644 index 1ed43b65c2..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Events/ThemeTouched.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace SmartStore.Web.Framework.Events -{ - public class ThemeTouched - { - public ThemeTouched(string themeName) - { - Guard.ArgumentNotEmpty(() => themeName); - this.ThemeName = themeName; - } - - public string ThemeName { get; set; } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/DateTimeExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/DateTimeExtensions.cs new file mode 100644 index 0000000000..3277e60cb6 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/DateTimeExtensions.cs @@ -0,0 +1,154 @@ +using System; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; +using SmartStore.Services.Helpers; +using SmartStore.Web.Framework.Localization; + +namespace SmartStore.Web.Framework +{ + public static class DateTimeExtensions + { + /// + /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) + /// + /// Source (UTC format) + /// Formatted date and time string + public static string RelativeFormat(this DateTime source) + { + return RelativeFormat(source, string.Empty); + } + + /// + /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) + /// + /// Source (UTC format) + /// Default format string (in case relative formatting is not applied) + /// Formatted date and time string + public static string RelativeFormat(this DateTime source, string defaultFormat) + { + return RelativeFormat(source, false, defaultFormat); + } + + /// + /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) + /// + /// Source (UTC format) + /// A value indicating whether we should convet DateTime instance to user local time (in case relative formatting is not applied) + /// Default format string (in case relative formatting is not applied) + /// Formatted date and time string + public static string RelativeFormat(this DateTime source, bool convertToUserTime, string defaultFormat) + { + string result = ""; + Localizer T = EngineContext.Current.Resolve().Get; + + var ts = new TimeSpan(DateTime.UtcNow.Ticks - source.Ticks); + double delta = ts.TotalSeconds; + + if (delta > 0) + { + if (delta < 60) // 60 (seconds) + { + result = ts.Seconds == 1 ? T("Time.OneSecondAgo") : T("Time.SecondsAgo", ts.Seconds); + } + else if (delta < 120) //2 (minutes) * 60 (seconds) + { + result = T("Time.OneMinuteAgo"); + } + else if (delta < 2700) // 45 (minutes) * 60 (seconds) + { + result = String.Format(T("Time.MinutesAgo"), ts.Minutes); + } + else if (delta < 5400) // 90 (minutes) * 60 (seconds) + { + result = T("Time.OneHourAgo"); + } + else if (delta < 86400) // 24 (hours) * 60 (minutes) * 60 (seconds) + { + int hours = ts.Hours; + if (hours == 1) + hours = 2; + result = T("Time.HoursAgo", hours); + } + else if (delta < 172800) // 48 (hours) * 60 (minutes) * 60 (seconds) + { + result = T("Time.Yesterday"); + } + else if (delta < 2592000) // 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) + { + result = String.Format(T("Time.DaysAgo"), ts.Days); + } + else if (delta < 31104000) // 12 (months) * 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) + { + int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); + result = months <= 1 ? T("Time.OneMonthAgo") : T("Time.MonthsAgo", months); + } + else + { + int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); + result = years <= 1 ? T("Time.OneYearAgo") : T("Time.YearsAgo", years); + } + } + else + { + DateTime tmp1 = source; + if (convertToUserTime) + { + tmp1 = EngineContext.Current.Resolve().ConvertToUserTime(tmp1, DateTimeKind.Utc); + } + //default formatting + if (!String.IsNullOrEmpty(defaultFormat)) + { + result = tmp1.ToString(defaultFormat); + } + else + { + result = tmp1.ToString(); + } + } + return result; + } + + public static string Prettify(this TimeSpan ts) + { + Localizer T = EngineContext.Current.Resolve().Get; + double seconds = ts.TotalSeconds; + + try + { + int secsTemp = Convert.ToInt32(seconds); + string label = T("Time.SecondsAbbr"); + int remainder = 0; + string remainderLabel = ""; + + if (secsTemp > 59) + { + remainder = secsTemp % 60; + secsTemp /= 60; + label = T("Time.MinutesAbbr"); + remainderLabel = T("Time.SecondsAbbr"); + } + + if (secsTemp > 59) + { + remainder = secsTemp % 60; + secsTemp /= 60; + label = (secsTemp == 1) ? T("Time.HourAbbr") : T("Time.HoursAbbr"); + remainderLabel = T("Time.MinutesAbbr"); + } + + if (remainder == 0) + { + return string.Format("{0:#,##0.#} {1}", secsTemp, label); + } + else + { + return string.Format("{0:#,##0} {1} {2} {3}", secsTemp, label, remainder, remainderLabel); + } + } + catch + { + return "(-)"; + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs deleted file mode 100644 index 439e1ef419..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/Extensions.cs +++ /dev/null @@ -1,347 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Plugins; -using SmartStore.Services.Configuration; -using SmartStore.Services.Helpers; -using SmartStore.Services.Localization; -using Telerik.Web.Mvc; -using Telerik.Web.Mvc.Extensions; -using Telerik.Web.Mvc.UI.Fluent; - -namespace SmartStore.Web.Framework -{ - public static class Extensions - { - public static IEnumerable ForCommand(this IEnumerable current, GridCommand command) - { - var queryable = current.AsQueryable() as IQueryable; - if (command.FilterDescriptors.Any()) - { - queryable = queryable.Where(command.FilterDescriptors.AsEnumerable()).AsQueryable() as IQueryable; - } - - IList temporarySortDescriptors = new List(); - - if (!command.SortDescriptors.Any() && queryable.Provider.IsEntityFrameworkProvider()) - { - // The Entity Framework provider demands OrderBy before calling Skip. - SortDescriptor sortDescriptor = new SortDescriptor - { - Member = queryable.ElementType.FirstSortableProperty() - }; - command.SortDescriptors.Add(sortDescriptor); - temporarySortDescriptors.Add(sortDescriptor); - } - - if (command.GroupDescriptors.Any()) - { - command.GroupDescriptors.Reverse().Each(groupDescriptor => - { - SortDescriptor sortDescriptor = new SortDescriptor - { - Member = groupDescriptor.Member, - SortDirection = groupDescriptor.SortDirection - }; - - command.SortDescriptors.Insert(0, sortDescriptor); - temporarySortDescriptors.Add(sortDescriptor); - }); - } - - if (command.SortDescriptors.Any()) - { - queryable = queryable.Sort(command.SortDescriptors); - } - - return queryable as IQueryable; - } - - public static IEnumerable PagedForCommand(this IEnumerable current, GridCommand command) - { - return current.Skip((command.Page - 1) * command.PageSize).Take(command.PageSize); - } - - public static bool IsEntityFrameworkProvider(this IQueryProvider provider) - { - return provider.GetType().FullName == "System.Data.Objects.ELinq.ObjectQueryProvider"; - } - - public static bool IsLinqToObjectsProvider(this IQueryProvider provider) - { - return provider.GetType().FullName.Contains("EnumerableQuery"); - } - - public static string FirstSortableProperty(this Type type) - { - PropertyInfo firstSortableProperty = type.GetProperties().Where(property => property.PropertyType.IsPredefinedType()).FirstOrDefault(); - - if (firstSortableProperty == null) - { - throw new NotSupportedException("Cannot find property to sort by."); - } - - return firstSortableProperty.Name; - } - - internal static bool IsPredefinedType(this Type type) - { - return PredefinedTypes.Any(t => t == type); - } - - public static readonly Type[] PredefinedTypes = { - typeof(Object), - typeof(Boolean), - typeof(Char), - typeof(String), - typeof(SByte), - typeof(Byte), - typeof(Int16), - typeof(UInt16), - typeof(Int32), - typeof(UInt32), - typeof(Int64), - typeof(UInt64), - typeof(Single), - typeof(Double), - typeof(Decimal), - typeof(DateTime), - typeof(TimeSpan), - typeof(Guid), - typeof(Math), - typeof(Convert) - }; - - public static GridBoundColumnBuilder Centered(this GridBoundColumnBuilder columnBuilder) where T:class - { - return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); - } - public static GridTemplateColumnBuilder Centered(this GridTemplateColumnBuilder columnBuilder) where T : class - { - return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); - } - public static GridBoundColumnBuilder RightAlign(this GridBoundColumnBuilder columnBuilder) where T : class - { - return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); - } - public static GridTemplateColumnBuilder RightAlign(this GridTemplateColumnBuilder columnBuilder) where T : class - { - return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); - } - - public static SelectList ToSelectList(this TEnum enumObj, bool markCurrentAsSelected = true) where TEnum : struct - { - if (!typeof(TEnum).IsEnum) - throw new ArgumentException("An Enumeration type is required.", "enumObj"); - - var localizationService = EngineContext.Current.Resolve(); - var workContext = EngineContext.Current.Resolve(); - - var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum)) - select new { ID = Convert.ToInt32(enumValue), Name = enumValue.GetLocalizedEnum(localizationService, workContext) }; - object selectedValue = null; - if (markCurrentAsSelected) - selectedValue = Convert.ToInt32(enumObj); - return new SelectList(values, "ID", "Name", selectedValue); - } - - - public static string GetValueFromAppliedFilter(this IFilterDescriptor filter, string valueName, FilterOperator? filterOperator = null) - { - if (filter is CompositeFilterDescriptor) - { - foreach (IFilterDescriptor childFilter in ((CompositeFilterDescriptor)filter).FilterDescriptors) - { - var val1 = GetValueFromAppliedFilter(childFilter, valueName, filterOperator); - if (!String.IsNullOrEmpty(val1)) - return val1; - } - } - else - { - var filterDescriptor = (FilterDescriptor)filter; - if (filterDescriptor != null && - filterDescriptor.Member.Equals(valueName, StringComparison.InvariantCultureIgnoreCase)) - { - if (!filterOperator.HasValue || filterDescriptor.Operator == filterOperator.Value) - return Convert.ToString(filterDescriptor.Value); - } - } - - return ""; - } - - public static string GetValueFromAppliedFilters(this IList filters, string valueName, FilterOperator? filterOperator = null) - { - foreach (var filter in filters) - { - var val1 = GetValueFromAppliedFilter(filter, valueName, filterOperator); - if (!String.IsNullOrEmpty(val1)) - return val1; - } - return ""; - } - - /// - /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) - /// - /// Source (UTC format) - /// Formatted date and time string - public static string RelativeFormat(this DateTime source) - { - return RelativeFormat(source, string.Empty); - } - - /// - /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) - /// - /// Source (UTC format) - /// Default format string (in case relative formatting is not applied) - /// Formatted date and time string - public static string RelativeFormat(this DateTime source, string defaultFormat) - { - return RelativeFormat(source, false, defaultFormat); - } - - /// - /// Relative formatting of DateTime (e.g. 2 hours ago, a month ago) - /// - /// Source (UTC format) - /// A value indicating whether we should convet DateTime instance to user local time (in case relative formatting is not applied) - /// Default format string (in case relative formatting is not applied) - /// Formatted date and time string - public static string RelativeFormat(this DateTime source, - bool convertToUserTime, string defaultFormat) - { - string result = ""; - var localizer = EngineContext.Current.Resolve(); - - var ts = new TimeSpan(DateTime.UtcNow.Ticks - source.Ticks); - double delta = ts.TotalSeconds; - - if (delta > 0) - { - if (delta < 60) // 60 (seconds) - { - result = ts.Seconds == 1 ? localizer.GetResource("Time.OneSecondAgo") : String.Format(localizer.GetResource("Time.OneSecondAgo"), ts.Seconds); - } - else if (delta < 120) //2 (minutes) * 60 (seconds) - { - result = localizer.GetResource("Time.OneMinuteAgo"); - } - else if (delta < 2700) // 45 (minutes) * 60 (seconds) - { - result = String.Format(localizer.GetResource("Time.MinutesAgo"), ts.Minutes); - } - else if (delta < 5400) // 90 (minutes) * 60 (seconds) - { - result = localizer.GetResource("Time.OneHourAgo"); - } - else if (delta < 86400) // 24 (hours) * 60 (minutes) * 60 (seconds) - { - int hours = ts.Hours; - if (hours == 1) - hours = 2; - result = String.Format(localizer.GetResource("Time.HoursAgo"), hours); - } - else if (delta < 172800) // 48 (hours) * 60 (minutes) * 60 (seconds) - { - result = localizer.GetResource("Time.Yesterday"); - } - else if (delta < 2592000) // 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) - { - result = String.Format(localizer.GetResource("Time.DaysAgo"), ts.Days); - } - else if (delta < 31104000) // 12 (months) * 30 (days) * 24 (hours) * 60 (minutes) * 60 (seconds) - { - int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30)); - result = months <= 1 ? localizer.GetResource("Time.OneMonthAgo") : String.Format(localizer.GetResource("Time.MonthsAgo"), months); - } - else - { - int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365)); - result = years <= 1 ? localizer.GetResource("Time.OneYearAgo") : String.Format(localizer.GetResource("Time.YearsAgo"), years); - } - } - else - { - DateTime tmp1 = source; - if (convertToUserTime) - { - tmp1 = EngineContext.Current.Resolve().ConvertToUserTime(tmp1, DateTimeKind.Utc); - } - //default formatting - if (!String.IsNullOrEmpty(defaultFormat)) - { - result = tmp1.ToString(defaultFormat); - } - else - { - result = tmp1.ToString(); - } - } - return result; - } - - /// - /// Get a list of all stores - /// - /// codehint: sm-add - public static IList ToSelectListItems(this IEnumerable stores) - { - var lst = new List(); - - foreach (var store in stores) - { - lst.Add(new SelectListItem - { - Text = store.Name, - Value = store.Id.ToString() - }); - } - return lst; - } - - public static void SelectValue(this List lst, string value, string defaultValue = null) - { - if (lst != null) - { - var itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(value)); - - if (itm == null && defaultValue != null) - itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(defaultValue)); - - if (itm != null) - itm.Selected = true; - } - } - - /// - /// Determines whether a plugin is installed and activated for a particular store. - /// - public static bool IsPluginReady(this IPluginFinder pluginFinder, ISettingService settingService, string systemName, int storeId) - { - try - { - var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName(systemName); - - if (pluginDescriptor != null && pluginDescriptor.Installed) - { - if (storeId == 0 || settingService.GetSettingByKey(pluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) - return true; - } - } - catch (Exception exc) - { - exc.Dump(); - } - return false; - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs index 87333caecd..b56f183331 100644 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlExtensions.cs @@ -1,28 +1,29 @@ using System; -using System.Web; -using System.Threading; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Text; +using System.Threading; +using System.Web; using System.Web.Mvc; using System.Web.Mvc.Html; +using System.Web.Routing; using System.Web.WebPages; using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Infrastructure; using SmartStore.Services.Localization; +using SmartStore.Utilities; using SmartStore.Web.Framework.Localization; -using SmartStore.Web.Framework.Mvc; -using SmartStore.Web.Framework.UI; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Framework.Settings; -using SmartStore.Utilities; -using SmartStore.Core.Domain.Catalog; +using SmartStore.Web.Framework.UI; namespace SmartStore.Web.Framework { - public enum InputEditorType + public enum InputEditorType { TextBox, Password, Hidden, @@ -38,16 +39,14 @@ public static MvcHtmlString Hint(this HtmlHelper helper, string value) var a = new TagBuilder("a"); a.MergeAttribute("href", "#"); a.MergeAttribute("onclick", "return false;"); - a.MergeAttribute("rel", "tooltip"); + //a.MergeAttribute("rel", "tooltip"); a.MergeAttribute("title", value); a.MergeAttribute("tabindex", "-1"); a.AddCssClass("hint"); - // Create img - var img = new TagBuilder("i"); - - // Add attributes - img.MergeAttribute("class", "icon-question-sign"); + // Create img + var img = new TagBuilder("i"); + img.AddCssClass("fa fa-question-circle"); a.InnerHtml = img.ToString(); @@ -74,34 +73,12 @@ public static HelperResult LocalizedEditor(this HtmlHel var locale = helper.ViewData.Model.Locales[i]; var language = EngineContext.Current.Resolve().GetLanguageById(locale.LanguageId); x.Add().Text(language.Name) - .Content(localizedTemplate - (i). - ToHtmlString - ()) + .Content(localizedTemplate(i).ToHtmlString()) .ImageUrl("~/Content/images/flags/" + language.FlagImageFileName); } }).ToHtmlString(); writer.Write(tabStrip); writer.Write(""); - - #region OBSOLETE - //var tabStrip = helper.Telerik().TabStrip().Name(name).Items(x => - //{ - // x.Add().Text("Standard").Content(standardTemplate(helper.ViewData.Model).ToHtmlString()).Selected(true); - // for (int i = 0; i < helper.ViewData.Model.Locales.Count; i++) - // { - // var locale = helper.ViewData.Model.Locales[i]; - // var language = EngineContext.Current.Resolve().GetLanguageById(locale.LanguageId); - // x.Add().Text(language.Name) - // .Content(localizedTemplate - // (i). - // ToHtmlString - // ()) - // .ImageUrl("~/Content/images/flags/" + language.FlagImageFileName); - // } - //}).ToHtmlString(); - //writer.Write(tabStrip); - #endregion } else { @@ -149,85 +126,109 @@ public static MvcHtmlString DeleteConfirmation(this HtmlHelper helper, str return MvcHtmlString.Create(script + window); } - public static MvcHtmlString SmartLabelFor(this HtmlHelper helper, Expression> expression, bool displayHint = true, object htmlAttributes = null) + public static MvcHtmlString SmartLabel(this HtmlHelper helper, string expression, string labelText, string hint = null, object htmlAttributes = null) + { + var result = new StringBuilder(); + + var label = helper.Label(expression, labelText, htmlAttributes); + + result.Append("
    "); + { + result.Append(label); + if (hint.HasValue()) + { + result.Append(helper.Hint(hint).ToHtmlString()); + } + } + result.Append("
    "); + + return MvcHtmlString.Create(result.ToString()); + } + + public static MvcHtmlString SmartLabelFor( + this HtmlHelper helper, + Expression> expression, + bool displayHint = true, + object htmlAttributes = null) { - var result = new StringBuilder(); - var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData); - string labelText = null; - string hint = null; - - SmartResourceDisplayName resourceDisplayName; - object value = null; + var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData); + object resourceDisplayName = null; + metadata.AdditionalValues.TryGetValue("SmartResourceDisplayName", out resourceDisplayName); - if (metadata.AdditionalValues.TryGetValue("SmartResourceDisplayName", out value)) - { - resourceDisplayName = value as SmartResourceDisplayName; - if (resourceDisplayName != null) - { - // resolve label display name - labelText = resourceDisplayName.DisplayName.NullEmpty(); - if (labelText == null) - { - // take reskey as absolute fallback - labelText = resourceDisplayName.ResourceKey; - } + return SmartLabelFor(helper, expression, resourceDisplayName as SmartResourceDisplayName, metadata, displayHint, htmlAttributes); + } - // resolve hint - if (displayHint) - { - var langId = EngineContext.Current.Resolve().WorkingLanguage.Id; - hint = EngineContext.Current.Resolve() - .GetResource(resourceDisplayName.ResourceKey + ".Hint", langId, false, "", true); - } - } - } + public static MvcHtmlString SmartLabelFor( + this HtmlHelper helper, + Expression> expression, + string resourceKey, + bool displayHint = true, + object htmlAttributes = null) + { + Guard.ArgumentNotEmpty(() => resourceKey); + + var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData); + var resourceDisplayName = new SmartResourceDisplayName(resourceKey, metadata.PropertyName); - if (labelText == null) - { - labelText = metadata.PropertyName.SplitPascalCase(); - } + return SmartLabelFor(helper, expression, resourceDisplayName, metadata, displayHint, htmlAttributes); + } - var label = helper.LabelFor(expression, labelText, htmlAttributes); + private static MvcHtmlString SmartLabelFor( + this HtmlHelper helper, + Expression> expression, + SmartResourceDisplayName resourceDisplayName, + ModelMetadata metadata, + bool displayHint = true, + object htmlAttributes = null) + { + var result = new StringBuilder(); + string labelText = null; + string hint = null; - if (displayHint) - { - result.Append("
    "); - { - result.Append(label); - if (hint.HasValue()) - { - result.Append(helper.Hint(hint).ToHtmlString()); - } - } - result.Append("
    "); - } - else - { - result.Append(label); - } + if (resourceDisplayName != null) + { + // resolve label display name + labelText = resourceDisplayName.DisplayName.NullEmpty(); + if (labelText == null) + { + // take reskey as absolute fallback + labelText = resourceDisplayName.ResourceKey; + } - return MvcHtmlString.Create(result.ToString()); - } + // resolve hint + if (displayHint) + { + var langId = EngineContext.Current.Resolve().WorkingLanguage.Id; + hint = EngineContext.Current.Resolve().GetResource(resourceDisplayName.ResourceKey + ".Hint", langId, false, "", true); + } + } - public static MvcHtmlString SmartLabel(this HtmlHelper helper, string resourceKey, bool displayHint = true) - { - return null; - } + if (labelText == null) + { + labelText = metadata.PropertyName.SplitPascalCase(); + } - public static MvcHtmlString RequiredHint(this HtmlHelper helper, string additionalText = null) - { - // Create tag builder - var builder = new TagBuilder("span"); - builder.AddCssClass("required"); - var innerText = "*"; - //add additinal text if specified - if (!String.IsNullOrEmpty(additionalText)) - innerText += " " + additionalText; - builder.SetInnerText(innerText); - // Render tag - return MvcHtmlString.Create(builder.ToString()); - } + var label = helper.LabelFor(expression, labelText, htmlAttributes); + + if (displayHint) + { + result.Append("
    "); + { + result.Append(label); + if (hint.HasValue()) + { + result.Append(helper.Hint(hint).ToHtmlString()); + } + } + result.Append("
    "); + } + else + { + result.Append(label); + } + return MvcHtmlString.Create(result.ToString()); + } public static string FieldNameFor(this HtmlHelper html, Expression> expression) { @@ -268,6 +269,10 @@ public static MvcHtmlString DatePickerDropDowns(this HtmlHelper html, var yearsList = new TagBuilder("select"); yearsList.MergeAttribute("style", "width: 90px"); + daysList.Attributes.Add("data-native-menu", "false"); + monthsList.Attributes.Add("data-native-menu", "false"); + yearsList.Attributes.Add("data-native-menu", "false"); + daysList.Attributes.Add("name", dayName); monthsList.Attributes.Add("name", monthName); yearsList.Attributes.Add("name", yearName); @@ -276,6 +281,10 @@ public static MvcHtmlString DatePickerDropDowns(this HtmlHelper html, monthsList.Attributes.Add("class", "date-part"); yearsList.Attributes.Add("class", "date-part"); + daysList.Attributes.Add("data-select-min-results-for-search", "100"); + monthsList.Attributes.Add("data-select-min-results-for-search", "100"); + //yearsList.Attributes.Add("data-select-min-results-for-search", "100"); + if (disabled) { daysList.Attributes.Add("disabled", "disabled"); @@ -302,13 +311,13 @@ public static MvcHtmlString DatePickerDropDowns(this HtmlHelper html, yearLocale = "Year"; } - days.AppendFormat("", dayLocale); + days.AppendFormat("", dayLocale); for (int i = 1; i <= 31; i++) days.AppendFormat("", i, (selectedDay.HasValue && selectedDay.Value == i) ? " selected=\"selected\"" : null); - months.AppendFormat("", monthLocale); + months.AppendFormat("", monthLocale); for (int i = 1; i <= 12; i++) { months.AppendFormat("", @@ -318,7 +327,7 @@ public static MvcHtmlString DatePickerDropDowns(this HtmlHelper html, } - years.AppendFormat("", yearLocale); + years.AppendFormat("", yearLocale); if (beginYear == null) beginYear = DateTime.UtcNow.Year - 90; @@ -358,7 +367,7 @@ public static MvcHtmlString DropDownListForEnum( IDictionary attrs = null; if (htmlAttributes != null) { - attrs = CollectionHelper.ObjectToDictionary(htmlAttributes); + attrs = CommonHelper.ObjectToDictionary(htmlAttributes); } return htmlHelper.DropDownListForEnum(expression, attrs, optionLabel); @@ -409,10 +418,11 @@ public static MvcHtmlString Widget(this HtmlHelper helper, string widgetZone, ob { model = model ?? helper.ViewData.Model; var widgetSelector = EngineContext.Current.Resolve(); - var widgets = widgetSelector.GetWidgets(widgetZone, model); + var widgets = widgetSelector.GetWidgets(widgetZone, model).ToArray(); if (widgets.Any()) { - var result = helper.Action("WidgetsByZone", "Widget", new { widgets = widgets, model = model, area = "" }); + var zoneModel = new WidgetZoneModel { Widgets = widgets, WidgetZone = widgetZone, Model = model }; + var result = helper.Action("WidgetsByZone", "Widget", new { zoneModel = zoneModel, model = model, area = "" }); return result; } } @@ -437,8 +447,12 @@ public static MvcHtmlString ControlGroupFor( { return html.HiddenFor(expression); } - - var sb = new StringBuilder("
    "); + + string inputHtml = ""; + var htmlAttributes = new RouteValueDictionary(); + var dataTypeName = ModelMetadata.FromLambdaExpression(expression, html.ViewData).DataTypeName.EmptyNull(); + + var sb = new StringBuilder("
    "); if (editorType != InputEditorType.Checkbox) { @@ -448,14 +462,23 @@ public static MvcHtmlString ControlGroupFor( } sb.AppendLine("
    "); - string inputHtml = ""; - object attrs = null; + if (!required && (editorType == InputEditorType.TextBox || editorType == InputEditorType.Password)) { - attrs = new { placeholder = "Optional" /* TODO: Loc */ }; + htmlAttributes.Add("placeholder", EngineContext.Current.Resolve().GetResource("Common.Optional")); } - //var x = ModelMetadata.FromLambdaExpression(expression, html.ViewData).DisplayName; - switch (editorType) + + switch (dataTypeName) + { + case "EmailAddress": + htmlAttributes.Add("type", "email"); + break; + case "PhoneNumber": + htmlAttributes.Add("type", "tel"); + break; + } + + switch (editorType) { case InputEditorType.Checkbox: inputHtml = string.Format("", @@ -463,12 +486,13 @@ public static MvcHtmlString ControlGroupFor( ModelMetadata.FromLambdaExpression(expression, html.ViewData).DisplayName); // TBD: ist das OK so? break; case InputEditorType.Password: - inputHtml = html.PasswordFor(expression, attrs).ToString(); + inputHtml = html.PasswordFor(expression, htmlAttributes).ToString(); break; default: - inputHtml = html.TextBoxFor(expression, attrs).ToString(); + inputHtml = html.TextBoxFor(expression, htmlAttributes).ToString(); break; } + sb.AppendLine(inputHtml); sb.AppendLine(html.ValidationMessageFor(expression).ToString()); if (helpHint.HasValue()) @@ -482,16 +506,24 @@ public static MvcHtmlString ControlGroupFor( return MvcHtmlString.Create(sb.ToString()); } - public static MvcHtmlString ColorBox(this HtmlHelper html, string name, string color) + public static MvcHtmlString ColorBox(this HtmlHelper html, string name, string color) + { + return ColorBox(html, name, color, null); + } + + public static MvcHtmlString ColorBox(this HtmlHelper html, string name, string color, string defaultColor) { var sb = new StringBuilder(); - sb.AppendFormat("
    ", color); + defaultColor = defaultColor.EmptyNull(); + var isDefault = color.IsCaseInsensitiveEqual(defaultColor); + + sb.AppendFormat("", color); - sb.AppendFormat(html.TextBox(name, color, new { @class = "span2 colorval" }).ToHtmlString()); + sb.AppendFormat(html.TextBox(name, isDefault ? "" : color, new { @class = "span2 colorval", placeholder = defaultColor }).ToHtmlString()); sb.AppendFormat("", color); - sb.Append("
    "); + sb.Append(""); var bootstrapJsRoot = "~/Content/bootstrap/js/"; html.AppendScriptParts(false, @@ -562,18 +594,20 @@ public static MvcHtmlString SettingOverrideCheckbox(this HtmlHel return MvcHtmlString.Empty; } - public static MvcHtmlString SettingEditorFor(this HtmlHelper helper, - Expression> expression, string parentSelector = null) + public static MvcHtmlString SettingEditorFor(this HtmlHelper helper, + Expression> expression, + string parentSelector = null, + object additionalViewData = null) { var checkbox = helper.SettingOverrideCheckbox(expression, parentSelector); - var editor = helper.EditorFor(expression); + var editor = helper.EditorFor(expression, additionalViewData); return MvcHtmlString.Create(checkbox.ToString() + editor.ToString()); } public static MvcHtmlString CollapsedText(this HtmlHelper helper, string text) { - if (text.IsNullOrEmpty()) + if (text.IsEmpty()) return MvcHtmlString.Empty; var catalogSettings = EngineContext.Current.Resolve(); @@ -591,6 +625,126 @@ public static MvcHtmlString CollapsedText(this HtmlHelper helper, string text) return MvcHtmlString.Create(result); } - } + + public static MvcHtmlString IconForFileExtension(this HtmlHelper helper, string fileExtension, bool renderLabel = false) + { + return IconForFileExtension(helper, fileExtension, null, renderLabel); + } + + public static MvcHtmlString IconForFileExtension(this HtmlHelper helper, string fileExtension, string extraCssClasses = null, bool renderLabel = false) + { + Guard.ArgumentNotNull(() => helper); + Guard.ArgumentNotEmpty(() => fileExtension); + + var icon = "file-o"; + var ext = fileExtension; + + if (ext != null && ext.StartsWith(".")) + { + ext = ext.Substring(1); + } + + if (ext.HasValue()) + { + switch (ext.ToLowerInvariant()) + { + case "pdf": + icon = "file-pdf-o"; + break; + case "doc": + case "docx": + case "docm": + case "odt": + case "dot": + case "dotx": + case "dotm": + icon = "file-word-o"; + break; + case "xls": + case "xlsx": + case "xlsm": + case "xlsb": + case "ods": + icon = "file-excel-o"; + break; + case "csv": + case "tab": + icon = "table"; + break; + case "ppt": + case "pptx": + case "pptm": + case "ppsx": + case "odp": + case "potx": + case "pot": + case "potm": + case "pps": + case "ppsm": + icon = "file-powerpoint-o"; + break; + case "zip": + case "rar": + case "7z": + icon = "file-archive-o"; + break; + case "png": + case "jpg": + case "jpeg": + case "bmp": + case "psd": + icon = "file-image-o"; + break; + case "mp3": + case "wav": + case "ogg": + case "wma": + icon = "file-audio-o"; + break; + case "mp4": + case "mkv": + case "wmv": + case "avi": + case "asf": + case "mpg": + case "mpeg": + icon = "file-video-o"; + break; + case "txt": + icon = "file-text-o"; + break; + case "exe": + icon = "gear"; + break; + case "xml": + case "html": + case "htm": + icon = "file-code-o"; + break; + } + } + + var label = ext.NaIfEmpty().ToUpper(); + + var result = "".FormatInvariant( + icon, + extraCssClasses.HasValue() ? " " + extraCssClasses : "", + label); + + if (renderLabel) + { + if (ext.IsEmpty()) + { + result = "{0}".FormatInvariant("".NaIfEmpty()); + } + else + { + result = result + "{0}".FormatInvariant(label); + } + } + + return MvcHtmlString.Create(result); + } + } } diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlSelectListExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlSelectListExtensions.cs new file mode 100644 index 0000000000..33455155a2 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/HtmlSelectListExtensions.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Infrastructure; +using SmartStore.Services.Localization; + +namespace SmartStore.Web.Framework +{ + public static class HtmlSelectListExtensions + { + public static SelectList ToSelectList(this TEnum enumObj, bool markCurrentAsSelected = true) where TEnum : struct + { + if (!typeof(TEnum).IsEnum) + throw new ArgumentException("An Enumeration type is required.", "enumObj"); + + var localizationService = EngineContext.Current.Resolve(); + var workContext = EngineContext.Current.Resolve(); + + var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum)) + select new { ID = Convert.ToInt32(enumValue), Name = enumValue.GetLocalizedEnum(localizationService, workContext) }; + + object selectedValue = null; + if (markCurrentAsSelected) + selectedValue = Convert.ToInt32(enumObj); + + return new SelectList(values, "ID", "Name", selectedValue); + } + + /// + /// Get a list of all stores + /// + public static IList ToSelectListItems(this IEnumerable stores) + { + var lst = new List(); + + foreach (var store in stores) + { + lst.Add(new SelectListItem + { + Text = store.Name, + Value = store.Id.ToString() + }); + } + return lst; + } + + public static void SelectValue(this List lst, string value, string defaultValue = null) + { + if (lst != null) + { + var itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(value)); + + if (itm == null && defaultValue != null) + itm = lst.FirstOrDefault(i => i.Value.IsCaseInsensitiveEqual(defaultValue)); + + if (itm != null) + itm.Selected = true; + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HttpContextExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HttpContextExtensions.cs deleted file mode 100644 index 0d5761f27f..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/HttpContextExtensions.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Web; -using System.Web.Routing; -using System.IO; -using System.Web.Mvc; -using SmartStore.Services.Orders; - -namespace SmartStore -{ - public static class HttpContextExtensions - { - public static Stream ToFileStream(this HttpRequestBase request, out string fileName, out string contentType, string paramName = "qqfile") { - fileName = contentType = ""; - Stream stream = null; - - if (request[paramName].HasValue()) - { - stream = request.InputStream; - fileName = request[paramName]; - } - else - { - if (request.Files.Count > 0) - { - stream = request.Files[0].InputStream; - contentType = request.Files[0].ContentType; - fileName = Path.GetFileName(request.Files[0].FileName); - } - } - - if (contentType.IsNullOrEmpty()) - { - contentType = SmartStore.Core.IO.MimeTypes.MapNameToMimeType(fileName); - } - - return stream; - } - - public static RouteData GetRouteData(this HttpContextBase httpContext) - { - Guard.ArgumentNotNull(() => httpContext); - - var handler = httpContext.Handler as MvcHandler; - if (handler != null && handler.RequestContext != null) - { - return handler.RequestContext.RouteData; - } - - return null; - } - - public static bool TryGetRouteData(this HttpContextBase httpContext, out RouteData routeData) - { - routeData = httpContext.GetRouteData(); - return routeData != null; - } - - public static CheckoutState EnsureCheckoutState(this HttpContextBase httpContext) - { - Guard.ArgumentNotNull(() => httpContext); - - var state = httpContext.GetCheckoutState(); - - if (state != null) - return state; - - httpContext.Session.SafeSet(CheckoutState.CheckoutStateSessionKey, new CheckoutState()); - - return httpContext.GetCheckoutState(); - } - - public static CheckoutState GetCheckoutState(this HttpContextBase httpContext) - { - Guard.ArgumentNotNull(() => httpContext); - - return httpContext.Session.SafeGetValue(CheckoutState.CheckoutStateSessionKey); - } - - public static void RemoveCheckoutState(this HttpContextBase httpContext) - { - Guard.ArgumentNotNull(() => httpContext); - - httpContext.Session.SafeRemove(CheckoutState.CheckoutStateSessionKey); - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/HttpExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/HttpExtensions.cs new file mode 100644 index 0000000000..f01379faec --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/HttpExtensions.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.IO; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Services.Orders; +using SmartStore.Utilities; + +namespace SmartStore +{ + public static class HttpExtensions + { + + public static bool IsAdminArea(this HttpRequest request) + { + if (request != null) + { + return IsAdminArea(new HttpRequestWrapper(request)); + } + + return false; + } + + public static bool IsAdminArea(this HttpRequestBase request) + { + try + { + if (request != null) + { + var area = request.RequestContext.RouteData.GetAreaName(); + if (area != null) + { + return area.IsCaseInsensitiveEqual("admin"); + } + } + + return false; + } + catch + { + return false; + } + } + + public static bool IsPublicArea(this HttpRequest request) + { + if (request != null) + { + return IsPublicArea(new HttpRequestWrapper(request)); + } + + return false; + } + + public static bool IsPublicArea(this HttpRequestBase request) + { + try + { + if (request != null) + { + var area = request.RequestContext.RouteData.GetAreaName(); + return area.IsEmpty(); + } + + return false; + } + catch + { + return false; + } + } + + public static PostedFileResult ToPostedFileResult(this HttpRequestBase httpRequest) + { + if (httpRequest != null && httpRequest.Files.Count > 0) + { + return httpRequest.Files[0].ToPostedFileResult(); + } + + return null; + } + + public static PostedFileResult ToPostedFileResult(this HttpPostedFile httpFile) + { + if (httpFile != null && httpFile.ContentLength > 0) + { + return new PostedFileResult(new HttpPostedFileWrapper(httpFile)); + } + + return null; + } + + public static PostedFileResult ToPostedFileResult(this HttpPostedFileBase httpFile) + { + if (httpFile != null && httpFile.ContentLength > 0) + { + return new PostedFileResult(httpFile); + } + + return null; + } + + public static IEnumerable ToPostedFileResults(this HttpFileCollection httpFileCollection) + { + if (httpFileCollection != null && httpFileCollection.Count > 0) + { + return new HttpFileCollectionWrapper(httpFileCollection).ToPostedFileResults(); + } + + return Enumerable.Empty(); + } + + public static IEnumerable ToPostedFileResults(this HttpFileCollectionBase httpFileCollection) + { + if (httpFileCollection == null) + yield break; + + var batchId = Guid.NewGuid(); + + for (var i = 0; i < httpFileCollection.Count; i++) + { + var httpFile = httpFileCollection[i]; + var result = httpFile.ToPostedFileResult(); + if (result != null) + { + result.BatchId = batchId; + yield return result; + } + } + } + + public static RouteData GetRouteData(this HttpContextBase httpContext) + { + Guard.ArgumentNotNull(() => httpContext); + + var handler = httpContext.Handler as MvcHandler; + if (handler != null && handler.RequestContext != null) + { + return handler.RequestContext.RouteData; + } + + return null; + } + + public static bool TryGetRouteData(this HttpContextBase httpContext, out RouteData routeData) + { + routeData = httpContext.GetRouteData(); + return routeData != null; + } + + public static CheckoutState GetCheckoutState(this HttpContextBase httpContext) + { + Guard.ArgumentNotNull(() => httpContext); + + var state = httpContext.Session.SafeGetValue(CheckoutState.CheckoutStateSessionKey); + + if (state != null) + return state; + + state = new CheckoutState(); + httpContext.Session.SafeSet(CheckoutState.CheckoutStateSessionKey, state); + + return state; + } + + public static void RemoveCheckoutState(this HttpContextBase httpContext) + { + Guard.ArgumentNotNull(() => httpContext); + + httpContext.Session.SafeRemove(CheckoutState.CheckoutStateSessionKey); + } + + internal static string GetUserThemeChoiceFromCookie(this HttpContextBase context) + { + if (context == null) + return null; + + var cookie = context.Request.Cookies.Get("sm.UserThemeChoice"); + if (cookie != null) + { + return cookie.Value.NullEmpty(); + } + + return null; + } + + internal static void SetUserThemeChoiceInCookie(this HttpContextBase context, string value) + { + if (context == null) + return; + + var cookie = context.Request.Cookies.Get("sm.UserThemeChoice"); + + if (value.HasValue() && cookie == null) + { + cookie = new HttpCookie("sm.UserThemeChoice"); + cookie.HttpOnly = true; + cookie.Expires = DateTime.UtcNow.AddYears(1); + } + + if (value.HasValue()) + { + cookie.Value = value; + context.Request.Cookies.Set(cookie); + } + + if (value.IsEmpty() && cookie != null) + { + cookie.Expires = DateTime.UtcNow.AddYears(-10); + } + + if (cookie != null) + { + context.Response.SetCookie(cookie); + } + } + + internal static HttpCookie GetPreviewModeCookie(this HttpContextBase context, bool createIfMissing) + { + if (context == null) + return null; + + var cookie = context.Request.Cookies.Get("sm.PreviewModeOverrides"); + + if (cookie == null && createIfMissing) + { + cookie = new HttpCookie("sm.PreviewModeOverrides"); + cookie.HttpOnly = true; + context.Request.Cookies.Set(cookie); + } + + if (cookie != null) + { + // when cookie gets created or touched, extend its lifetime + cookie.Expires = DateTime.UtcNow.AddMinutes(20); + } + + return cookie; + } + + internal static void SetPreviewModeValue(this HttpContextBase context, string key, string value) + { + if (context == null) + return; + + var cookie = context.GetPreviewModeCookie(value.HasValue()); + if (cookie != null) + { + if (value.HasValue()) + { + cookie.Values[key] = value; + } + else + { + cookie.Values.Remove(key); + } + } + } + + public static IDisposable PreviewModeCookie(this HttpContextBase context) + { + var disposable = new ActionDisposable(() => { + var cookie = GetPreviewModeCookie(context, false); + if (cookie != null) + { + if (!cookie.HasKeys) + { + cookie.Expires = DateTime.UtcNow.AddYears(-10); + } + else + { + cookie.Expires = DateTime.UtcNow.AddMinutes(20); + } + + context.Response.SetCookie(cookie); + } + }); + + return disposable; + } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/PostedFileResult.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/PostedFileResult.cs new file mode 100644 index 0000000000..9ba2b0ed2d --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/PostedFileResult.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Web; +using SmartStore.Core.IO; + +namespace SmartStore +{ + public class PostedFileResult + { + private static readonly Regex s_ImageTypes = new Regex(@"(.*?)\.(gif|jpg|jpeg|jpe|jfif|pjpeg|pjp|png|tiff|tif|bmp|ico|svg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + private readonly HttpPostedFileBase _httpFile; + + private string _contentType; + private string _fileName; + private string _fileTitle; + private string _fileExt; + private bool? _isImage; + + public PostedFileResult(HttpPostedFileBase httpFile) + { + Guard.ArgumentNotNull(() => httpFile); + + this._httpFile = httpFile; + + this.TimeStamp = DateTime.UtcNow; + this.BatchId = Guid.NewGuid(); + } + + public HttpPostedFileBase File + { + get { return _httpFile; } + } + + public DateTime TimeStamp + { + get; + private set; + } + + public Guid BatchId + { + get; + internal set; + } + + public string FileName + { + get + { + if (_fileName == null) + { + _fileName = Path.GetFileName(_httpFile.FileName); + } + return _fileName; + } + } + + public string FileTitle + { + get + { + if (_fileTitle == null) + { + _fileTitle = Path.GetFileNameWithoutExtension(this.FileName); + } + return _fileTitle; + } + } + + public string FileExtension + { + get + { + if (_fileExt == null) + { + _fileExt = Path.GetExtension(this.FileName).EmptyNull(); + } + return _fileExt; + } + } + + public string ContentType + { + get + { + if (_contentType == null) + { + var contentType = _httpFile.ContentType; + + if (contentType == null && this.FileExtension.HasValue()) + { + contentType = MimeTypes.MapNameToMimeType(this.FileExtension); + + // ContentType is not always available. + // That's why we manually update it here + if (contentType.IsEmpty()) + { + switch (this.FileExtension.ToLowerInvariant()) + { + case ".bmp": + contentType = "image/bmp"; + break; + case ".gif": + contentType = "image/gif"; + break; + case ".jpeg": + case ".jpg": + case ".jpe": + case ".jfif": + case ".pjpeg": + case ".pjp": + contentType = "image/jpeg"; + break; + case ".png": + contentType = "image/png"; + break; + case ".tiff": + case ".tif": + contentType = "image/tiff"; + break; + case ".svg": + contentType = "image/svg+xml"; + break; + case ".ico": + contentType = "image/x-icon"; + break; + default: + break; + } + } + } + + _contentType = contentType.EmptyNull(); + } + return _contentType; + } + } + + public bool IsImage + { + get + { + if (!_isImage.HasValue) + { + _isImage = s_ImageTypes.IsMatch(FileExtension); + } + return _isImage.Value; + } + } + + public int Size + { + get { return _httpFile.ContentLength; } + } + + public Stream Stream + { + get { return _httpFile.InputStream; } + } + + public byte[] Buffer + { + get + { + return _httpFile.InputStream.ToByteArray(); + } + } + + public bool FileNameMatches(string pattern) + { + return Regex.IsMatch(_httpFile.FileName, pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline); + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/RouteExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/RouteExtensions.cs new file mode 100644 index 0000000000..f6cfa11a01 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/RouteExtensions.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.Mvc; +using System.Threading.Tasks; +using System.Web.Routing; + +// use base SmartStore Namespace to ensure the extension methods are always available +namespace SmartStore +{ + public static class RouteExtensions + { + public static string GetAreaName(this RouteData routeData) + { + object obj2; + if (routeData.DataTokens.TryGetValue("area", out obj2)) + { + return (obj2 as string); + } + return routeData.Route.GetAreaName(); + } + + public static string GetAreaName(this RouteBase route) + { + var area = route as IRouteWithArea; + if (area != null) + { + return area.Area; + } + var route2 = route as Route; + if ((route2 != null) && (route2.DataTokens != null)) + { + return (route2.DataTokens["area"] as string); + } + return null; + } + + /// + /// Generates an identifier for the given route in the form "[{area}.]{controller}.{action}" + /// + public static string GenerateRouteIdentifier(this RouteData routeData) + { + string area = routeData.GetAreaName(); + string controller = routeData.GetRequiredString("controller"); + string action = routeData.GetRequiredString("action"); + + return "{0}{1}.{2}".FormatInvariant(area.HasValue() ? area + "." : "", controller, action); + } + + public static bool IsRouteEqual(this RouteData routeData, string controller, string action) + { + if (routeData == null) + return false; + + return routeData.GetRequiredString("controller").IsCaseInsensitiveEqual(controller) && routeData.GetRequiredString("action").IsCaseInsensitiveEqual(action); + } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/TelerikExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/TelerikExtensions.cs new file mode 100644 index 0000000000..70a62d8dd7 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/TelerikExtensions.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Domain.Stores; +using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; +using SmartStore.Core.Plugins; +using SmartStore.Services.Configuration; +using SmartStore.Services.Helpers; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Localization; +using Telerik.Web.Mvc; +using Telerik.Web.Mvc.Extensions; +using Telerik.Web.Mvc.UI.Fluent; + +namespace SmartStore.Web.Framework +{ + [Serializable] + public class GridStateInfo + { + public GridState State { get; set; } + public string Path { get; set; } + } + + public static class TelerikExtensions + { + [SuppressMessage("ReSharper", "Mvc.AreaNotResolved")] + public static GridBuilder PreserveGridState(this GridBuilder builder) where T : class + { + var grid = builder.ToComponent(); + + if (!grid.DataBinding.Ajax.Enabled) + return builder; + + if (grid.Id.IsEmpty()) + throw new SmartException("A grid with preservable state must have a valid Id or Name"); + + var urlHelper = new UrlHelper(grid.ViewContext.RequestContext); + + var gridId = "GridState." + grid.Id + "__" + grid.ViewContext.RouteData.GenerateRouteIdentifier(); + + grid.AppendCssClass("grid-preservestate"); + grid.HtmlAttributes.Add("data-statepreserver-href", urlHelper.Action("SetGridState", "Common", new { area = "admin" })); + grid.HtmlAttributes.Add("data-statepreserver-key", gridId); + + // Try restore state from a previous request + var info = (GridStateInfo)grid.ViewContext.TempData[gridId]; + + if (info == null) + return builder; + + var state = info.State; + var command = GridCommand.Parse(state.Page, state.Size, state.OrderBy, state.GroupBy, state.Filter); + + if (grid.Paging.Enabled) + { + var pathChanged = !info.Path.Equals(grid.ViewContext.HttpContext.Request.RawUrl, StringComparison.OrdinalIgnoreCase); + if (!pathChanged) + { + if (command.PageSize > 0) + grid.Paging.PageSize = command.PageSize; + if (command.Page > 0) + grid.Paging.CurrentPage = command.Page; + } + } + + if (grid.Sorting.Enabled) + { + foreach (var sort in command.SortDescriptors) + { + var existingSort = grid.Sorting.OrderBy.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(sort.Member)); + if (existingSort != null) + { + grid.Sorting.OrderBy.Remove(existingSort); + } + grid.Sorting.OrderBy.Add(sort); + } + } + + if (grid.Grouping.Enabled) + { + foreach (var group in command.GroupDescriptors) + { + var existingGroup = grid.Grouping.Groups.FirstOrDefault(x => x.Member.IsCaseInsensitiveEqual(group.Member)); + if (existingGroup != null) + { + grid.Grouping.Groups.Remove(existingGroup); + } + grid.Grouping.Groups.Add(group); + } + } + + if (grid.Filtering.Enabled) + { + foreach (var filter in command.FilterDescriptors) + { + var compositeFilter = filter as CompositeFilterDescriptor; + if (compositeFilter == null) + { + compositeFilter = new CompositeFilterDescriptor { LogicalOperator = FilterCompositionLogicalOperator.And }; + compositeFilter.FilterDescriptors.Add(filter); + } + grid.Filtering.Filters.Add(compositeFilter); + } + } + + // persist again for the next request + grid.ViewContext.TempData[gridId] = info; + + return builder; + } + + public static IEnumerable ForCommand(this IEnumerable current, GridCommand command) + { + var queryable = current.AsQueryable() as IQueryable; + if (command.FilterDescriptors.Any()) + { + queryable = queryable.Where(command.FilterDescriptors.AsEnumerable()).AsQueryable() as IQueryable; + } + + IList temporarySortDescriptors = new List(); + + if (!command.SortDescriptors.Any() && queryable.Provider.IsEntityFrameworkProvider()) + { + // The Entity Framework provider demands OrderBy before calling Skip. + SortDescriptor sortDescriptor = new SortDescriptor + { + Member = GetFirstSortableProperty(queryable.ElementType) + }; + command.SortDescriptors.Add(sortDescriptor); + temporarySortDescriptors.Add(sortDescriptor); + } + + if (command.GroupDescriptors.Any()) + { + command.GroupDescriptors.Reverse().Each(groupDescriptor => + { + SortDescriptor sortDescriptor = new SortDescriptor + { + Member = groupDescriptor.Member, + SortDirection = groupDescriptor.SortDirection + }; + + command.SortDescriptors.Insert(0, sortDescriptor); + temporarySortDescriptors.Add(sortDescriptor); + }); + } + + if (command.SortDescriptors.Any()) + { + queryable = queryable.Sort(command.SortDescriptors); + } + + return queryable as IQueryable; + } + + public static IEnumerable PagedForCommand(this IEnumerable current, GridCommand command) + { + return current.Skip((command.Page - 1) * command.PageSize).Take(command.PageSize); + } + + + public static GridBoundColumnBuilder Centered(this GridBoundColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); + } + + public static GridTemplateColumnBuilder Centered(this GridTemplateColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { align = "center" }).HeaderHtmlAttributes(new { style = "text-align:center;" }); + } + + public static GridBoundColumnBuilder RightAlign(this GridBoundColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); + } + + public static GridTemplateColumnBuilder RightAlign(this GridTemplateColumnBuilder columnBuilder) where T : class + { + return columnBuilder.HtmlAttributes(new { style = "text-align:right;" }).HeaderHtmlAttributes(new { style = "text-align:right;" }); + } + + public static string GetValueFromAppliedFilter(this IFilterDescriptor filter, string valueName, FilterOperator? filterOperator = null) + { + if (filter is CompositeFilterDescriptor) + { + foreach (IFilterDescriptor childFilter in ((CompositeFilterDescriptor)filter).FilterDescriptors) + { + var val1 = GetValueFromAppliedFilter(childFilter, valueName, filterOperator); + if (!String.IsNullOrEmpty(val1)) + return val1; + } + } + else + { + var filterDescriptor = (FilterDescriptor)filter; + if (filterDescriptor != null && + filterDescriptor.Member.Equals(valueName, StringComparison.InvariantCultureIgnoreCase)) + { + if (!filterOperator.HasValue || filterDescriptor.Operator == filterOperator.Value) + return Convert.ToString(filterDescriptor.Value); + } + } + + return ""; + } + + public static string GetValueFromAppliedFilters(this IList filters, string valueName, FilterOperator? filterOperator = null) + { + foreach (var filter in filters) + { + var val1 = GetValueFromAppliedFilter(filter, valueName, filterOperator); + if (!String.IsNullOrEmpty(val1)) + return val1; + } + return ""; + } + + private static string GetFirstSortableProperty(Type type) + { + PropertyInfo firstSortableProperty = type.GetProperties().Where(property => property.PropertyType.IsPredefinedSimpleType()).FirstOrDefault(); + + if (firstSortableProperty == null) + { + throw new NotSupportedException("Cannot find property to sort by."); + } + + return firstSortableProperty.Name; + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Extensions/UrlHelperExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Extensions/UrlHelperExtensions.cs index 36cb646c33..cc1426f8fc 100644 --- a/src/Presentation/SmartStore.Web.Framework/Extensions/UrlHelperExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Extensions/UrlHelperExtensions.cs @@ -17,5 +17,16 @@ public static string LogOff(this UrlHelper urlHelper, string returnUrl) return urlHelper.Action("Logout", "Customer", new { ReturnUrl = returnUrl, area = "" }); return urlHelper.Action("Logout", "Customer", new { area = "" }); } + + public static string Referrer(this UrlHelper urlHelper, string fallbackUrl = "") + { + var request = urlHelper.RequestContext.HttpContext.Request; + if (request.UrlReferrer != null && request.UrlReferrer.ToString().HasValue()) + { + return request.UrlReferrer.ToString(); + } + + return fallbackUrl; + } } } diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/CheckAffiliateAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/CheckAffiliateAttribute.cs new file mode 100644 index 0000000000..ccbca493af --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/CheckAffiliateAttribute.cs @@ -0,0 +1,49 @@ +using System; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Services.Affiliates; +using SmartStore.Services.Customers; + +namespace SmartStore.Web.Framework.Filters +{ + public class CheckAffiliateAttribute : ActionFilterAttribute + { + public Lazy AffiliateService { get; set; } + public Lazy WorkContext { get; set; } + public Lazy CustomerService { get; set; } + + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + if (filterContext == null || filterContext.HttpContext == null) + return; + + HttpRequestBase request = filterContext.HttpContext.Request; + if (request == null) + return; + + //don't apply filter to child methods + if (filterContext.IsChildAction) + return; + + if (request.QueryString != null && request.QueryString["AffiliateId"] != null) + { + var affiliateId = Convert.ToInt32(request.QueryString["AffiliateId"]); + + if (affiliateId > 0) + { + var affiliate = AffiliateService.Value.GetAffiliateById(affiliateId); + if (affiliate != null && !affiliate.Deleted && affiliate.Active) + { + var customer = WorkContext.Value.CurrentCustomer; + if (customer != null && !customer.IsSystemAccount && customer.AffiliateId != affiliate.Id) + { + customer.AffiliateId = affiliate.Id; + CustomerService.Value.UpdateCustomer(customer); + } + } + } + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/CompressAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/CompressAttribute.cs new file mode 100644 index 0000000000..a2f0849df8 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/CompressAttribute.cs @@ -0,0 +1,34 @@ +using System.IO.Compression; +using System.Web; +using System.Web.Mvc; + +namespace SmartStore.Web.Framework.Filters +{ + public class CompressAttribute : ActionFilterAttribute + { + public bool PreferDeflate { get; set; } + + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + var response = HttpContext.Current.Response; + string acceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"].EmptyNull().ToLower(); + + if (acceptEncoding.Contains("gzip") && !(PreferDeflate && acceptEncoding.Contains("deflate"))) + { + response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); + + response.Headers.Remove("Content-Encoding"); + response.AppendHeader("Content-Encoding", "gzip"); + } + else if (acceptEncoding.Contains("deflate")) + { + response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); + + response.Headers.Remove("Content-Encoding"); + response.AppendHeader("Content-Encoding", "deflate"); + } + + //response.AppendHeader("Vary", "Content-Encoding"); + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/CustomerLastActivityAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/CustomerLastActivityAttribute.cs new file mode 100644 index 0000000000..8f9418de66 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/CustomerLastActivityAttribute.cs @@ -0,0 +1,40 @@ +using System; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Services.Customers; + +namespace SmartStore.Web.Framework.Filters +{ + public class CustomerLastActivityAttribute : ActionFilterAttribute + { + public Lazy WorkContext { get; set; } + public Lazy CustomerService { get; set; } + + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + if (!DataSettings.DatabaseIsInstalled()) + return; + + if (filterContext == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) + return; + + // don't apply filter to child methods + if (filterContext.IsChildAction) + return; + + // only GET requests + if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) + return; + + var customer = WorkContext.Value.CurrentCustomer; + + // update last activity date + if (!customer.IsSystemAccount && customer.LastActivityDateUtc.AddMinutes(1.0) < DateTime.UtcNow) + { + customer.LastActivityDateUtc = DateTime.UtcNow; + CustomerService.Value.UpdateCustomer(customer); + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/FormValueExistsAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/FormValueExistsAttribute.cs similarity index 95% rename from src/Presentation/SmartStore.Web.Framework/Controllers/FormValueExistsAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/FormValueExistsAttribute.cs index c63bb96c12..cdf11c221c 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/FormValueExistsAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/FormValueExistsAttribute.cs @@ -1,6 +1,6 @@ using System.Web.Mvc; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Filters { public class FormValueExistsAttribute : FilterAttribute, IActionFilter { diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/FormValueRequiredAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/FormValueRequiredAttribute.cs new file mode 100644 index 0000000000..c0a759a5c5 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/FormValueRequiredAttribute.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Specialized; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Web.Mvc; + +namespace SmartStore.Web.Framework.Filters +{ + + public class FormValueRequiredAttribute : ActionMethodSelectorAttribute + { + private readonly string[] _submitButtonNames; + private readonly FormValueRequirement _requirement; + private readonly FormValueRequirementRule _rule; + private readonly bool _inverse; + + public FormValueRequiredAttribute(params string[] submitButtonNames): + this(FormValueRequirement.Equal, FormValueRequirementRule.MatchAny, false, submitButtonNames) + { + } + + public FormValueRequiredAttribute(FormValueRequirement requirement, params string[] submitButtonNames) + : this(requirement, FormValueRequirementRule.MatchAny, false, submitButtonNames) + { + } + + public FormValueRequiredAttribute(FormValueRequirementRule rule, params string[] submitButtonNames) + : this(FormValueRequirement.Equal, rule, false, submitButtonNames) + { + } + + public FormValueRequiredAttribute(FormValueRequirement requirement, FormValueRequirementRule rule, params string[] submitButtonNames) + : this(requirement, rule, false, submitButtonNames) + { + } + + protected internal FormValueRequiredAttribute( + FormValueRequirement requirement, + FormValueRequirementRule rule, + bool inverse, + params string[] submitButtonNames) + { + // at least one submit button should be found (or being absent if 'inverse') + this._submitButtonNames = submitButtonNames; + this._requirement = requirement; + this._rule = rule; + this._inverse = inverse; + } + + public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo) + { + return IsValidForRequest(controllerContext.HttpContext.Request.Form); + } + + protected internal virtual bool IsValidForRequest(NameValueCollection form) + { + try + { + bool isMatch = false; + if (_rule == FormValueRequirementRule.MatchAny) + { + isMatch = _submitButtonNames.Any(x => IsMatch(form, x)); + } + else + { + isMatch = _submitButtonNames.All(x => IsMatch(form, x)); + } + return isMatch; + } + catch (Exception ex) + { + Debug.WriteLine(ex.Message); + } + + return false; + } + + private bool IsMatch(NameValueCollection form, string key) + { + string value = ""; + + if (_requirement == FormValueRequirement.Equal) + { + // do not iterate because "Invalid request" exception can be thrown + value = form[key]; + } + else + { + var firstMatch = form.AllKeys.FirstOrDefault(x => x.StartsWith(key, StringComparison.InvariantCultureIgnoreCase)); + if (firstMatch != null) + { + value = form[firstMatch]; + } + } + + if (_inverse) + { + return value.IsEmpty(); + } + + return value.HasValue(); + } + } + + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class FormValueAbsentAttribute : FormValueRequiredAttribute + { + public FormValueAbsentAttribute(params string[] submitButtonNames): + base(FormValueRequirement.Equal, FormValueRequirementRule.MatchAny, true, submitButtonNames) + { + } + + public FormValueAbsentAttribute(FormValueRequirement requirement, params string[] submitButtonNames) + : base(requirement, FormValueRequirementRule.MatchAny, true, submitButtonNames) + { + } + + public FormValueAbsentAttribute(FormValueRequirementRule rule, params string[] submitButtonNames) + : base(FormValueRequirement.Equal, rule, true, submitButtonNames) + { + } + + public FormValueAbsentAttribute(FormValueRequirement requirement, FormValueRequirementRule rule, params string[] submitButtonNames) + : base(requirement, rule, true, submitButtonNames) + { + } + } + + public enum FormValueRequirement + { + Equal, + StartsWith + } + + public enum FormValueRequirementRule + { + MatchAny, + MatchAll + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/HandleExceptionFilter.cs b/src/Presentation/SmartStore.Web.Framework/Filters/HandleExceptionFilter.cs new file mode 100644 index 0000000000..299e0faa3e --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/HandleExceptionFilter.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Runtime.InteropServices; +using System.Security; +using System.Threading; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Logging; + +namespace SmartStore.Web.Framework.Filters +{ + public class HandleExceptionFilter : IActionFilter + { + private readonly Lazy _logger; + private readonly Lazy> _exceptionFilters; + private readonly Lazy _workContext; + + public HandleExceptionFilter( + Lazy logger, + Lazy> exceptionFilters, + Lazy workContext) + { + this._logger = logger; + this._exceptionFilters = exceptionFilters; + this._workContext = workContext; + } + + public void OnActionExecuting(ActionExecutingContext filterContext) + { + } + + public void OnActionExecuted(ActionExecutedContext filterContext) + { + var descriptor = filterContext.ActionDescriptor; + + // handle server error + // don't provide custom errors if the action has some custom code to handle exceptions + if (!filterContext.ActionDescriptor.GetCustomAttributes(typeof(HandleErrorAttribute), false).Any()) + { + if (!filterContext.ExceptionHandled && filterContext.Exception != null && filterContext.HttpContext.IsCustomErrorEnabled) + { + if (ShouldHandleException(filterContext.Exception)) + { + LogException(filterContext.Exception); + + // inform exception filters of the exception that was suppressed + var exceptionContext = new ExceptionContext(filterContext.Controller.ControllerContext, filterContext.Exception); + foreach (var exceptionFilter in _exceptionFilters.Value) + { + exceptionFilter.OnException(exceptionContext); + } + + if (exceptionContext.ExceptionHandled) + { + filterContext.ExceptionHandled = true; + filterContext.Result = exceptionContext.Result; + } + else + { + if (!filterContext.IsChildAction) + { + var controllerName = descriptor.ControllerDescriptor.ControllerName; + var actionName = descriptor.ActionName; + + // if the request is AJAX return JSON data + if (filterContext.HttpContext.Request.IsAjaxRequest()) + { + filterContext.Result = new JsonResult + { + JsonRequestBehavior = JsonRequestBehavior.AllowGet, + Data = new + { + error = true, + controller = controllerName, + action = actionName, + message = filterContext.Exception.Message + } + }; + } + else + { + filterContext.Result = new ViewResult + { + ViewName = "Error", + MasterName = (string)null, + ViewData = new ViewDataDictionary(new HandleErrorInfo(filterContext.Exception, controllerName, actionName)), + TempData = filterContext.Controller.TempData + }; + } + + filterContext.ExceptionHandled = true; + + filterContext.RequestContext.HttpContext.Response.Clear(); + filterContext.RequestContext.HttpContext.Response.StatusCode = 500; + + // prevent IIS 7.0 classic mode from handling the 404/500 itself + filterContext.RequestContext.HttpContext.Response.TrySkipIisCustomErrors = true; + } + } + } + } + } + + if (filterContext.Result is HttpNotFoundResult && !filterContext.IsChildAction) + { + // handle not found (404) from within the MVC pipeline (only called when HttpNotFoundResult is returned from actions) + var requestContext = filterContext.RequestContext; + var url = requestContext.HttpContext.Request.RawUrl; + + filterContext.Result = new ViewResult + { + ViewName = "NotFound", + MasterName = (string)null, + ViewData = new ViewDataDictionary(new HandleErrorInfo(new HttpException(404, "The resource does not exist."), descriptor.ActionName, descriptor.ControllerDescriptor.ControllerName)), + TempData = filterContext.Controller.TempData + }; + requestContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; + + // prevent IIS 7.0 classic mode from handling the 404/500 itself + requestContext.HttpContext.Response.TrySkipIisCustomErrors = true; + } + } + + private bool ShouldHandleException(Exception exception) + { + return !( + exception is StackOverflowException || + exception is OutOfMemoryException || + exception is AccessViolationException || + exception is AppDomainUnloadedException || + exception is ThreadAbortException || + exception is SecurityException || + exception is SEHException); + } + + protected void LogException(Exception exception) + { + if (exception == null) + return; + + if (!DataSettings.DatabaseIsInstalled()) + return; + + //// ignore 404 HTTP errors + //var httpException = exception as HttpException; + //if (httpException != null && httpException.GetHttpCode() == 404) + // return; + + try + { + var logger = _logger.Value; + var workContext = _workContext.Value; + logger.Error(exception.Message, exception, workContext.CurrentCustomer); + } + catch + { + // don't throw new exception + } + } + + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/HandleInstallFilter.cs b/src/Presentation/SmartStore.Web.Framework/Filters/HandleInstallFilter.cs similarity index 85% rename from src/Presentation/SmartStore.Web.Framework/Controllers/HandleInstallFilter.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/HandleInstallFilter.cs index 6130edb99c..5f457e20af 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/HandleInstallFilter.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/HandleInstallFilter.cs @@ -1,17 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Web.Mvc; +using System.Web.Mvc; using System.Web.Routing; -using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; -namespace SmartStore.Web.Framework.Controllers -{ - +namespace SmartStore.Web.Framework.Filters +{ public class HandleInstallFilter : IActionFilter { - public void OnActionExecuting(ActionExecutingContext filterContext) { var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/JsonNetAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/JsonNetAttribute.cs new file mode 100644 index 0000000000..335977bd29 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/JsonNetAttribute.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net; +using System.Runtime.InteropServices; +using System.Security; +using System.Threading; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Logging; +using SmartStore.Services.Helpers; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Web.Framework.Filters +{ + public class JsonNetAttribute : ActionFilterAttribute + { + public Lazy DateTimeHelper { get; set; } + + [SuppressMessage("ReSharper", "PossibleNullReferenceException")] + public override void OnActionExecuted(ActionExecutedContext filterContext) + { + if (!DataSettings.DatabaseIsInstalled()) + return; + + if (filterContext == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) + return; + + // don't apply filter to child methods + if (filterContext.IsChildAction) + return; + + // handle JsonResult only + if (filterContext.Result.GetType() != typeof(JsonResult)) + return; + + var jsonResult = filterContext.Result as JsonResult; + + filterContext.Result = new JsonNetResult(DateTimeHelper.Value) + { + Data = jsonResult.Data, + ContentType = jsonResult.ContentType, + ContentEncoding = jsonResult.ContentEncoding, + JsonRequestBehavior = jsonResult.JsonRequestBehavior + }; + } + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/NotifyAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/NotifyAttribute.cs similarity index 88% rename from src/Presentation/SmartStore.Web.Framework/Controllers/NotifyAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/NotifyAttribute.cs index 395bcec525..9080e1d29e 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/NotifyAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/NotifyAttribute.cs @@ -1,16 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Web; -using System.Web.Http.Controllers; using System.Web.Mvc; -using SmartStore.Collections; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Localization; using SmartStore.Core.Logging; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Filters { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/ParameterBasedOnFormNameAndValueAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/ParameterBasedOnFormNameAndValueAttribute.cs similarity index 95% rename from src/Presentation/SmartStore.Web.Framework/Controllers/ParameterBasedOnFormNameAndValueAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/ParameterBasedOnFormNameAndValueAttribute.cs index 0af60e2381..710b51e048 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/ParameterBasedOnFormNameAndValueAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/ParameterBasedOnFormNameAndValueAttribute.cs @@ -1,6 +1,6 @@ using System.Web.Mvc; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Filters { public class ParameterBasedOnFormNameAndValueAttribute : FilterAttribute, IActionFilter { diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/ParameterBasedOnFormNameAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/ParameterBasedOnFormNameAttribute.cs similarity index 95% rename from src/Presentation/SmartStore.Web.Framework/Controllers/ParameterBasedOnFormNameAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/ParameterBasedOnFormNameAttribute.cs index ed45aa2672..c6b2a9f8c4 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/ParameterBasedOnFormNameAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/ParameterBasedOnFormNameAttribute.cs @@ -1,6 +1,6 @@ using System.Web.Mvc; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Filters { /// /// If form name exists, then specified "actionParameterName" will be set to "true" diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/PublicStoreAllowNavigationAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/PublicStoreAllowNavigationAttribute.cs similarity index 96% rename from src/Presentation/SmartStore.Web.Framework/Controllers/PublicStoreAllowNavigationAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/PublicStoreAllowNavigationAttribute.cs index 247e3d610f..17edc7fa99 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/PublicStoreAllowNavigationAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/PublicStoreAllowNavigationAttribute.cs @@ -3,10 +3,9 @@ using System.Web; using System.Web.Mvc; using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; using SmartStore.Services.Security; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Filters { public class PublicStoreAllowNavigationAttribute : ActionFilterAttribute { diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/StoreClosedAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/StoreClosedAttribute.cs new file mode 100644 index 0000000000..8d1a936cf4 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/StoreClosedAttribute.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain; +using SmartStore.Core.Logging; +using SmartStore.Services.Customers; +using SmartStore.Services.Localization; + +namespace SmartStore.Web.Framework.Filters +{ + public class StoreClosedAttribute : ActionFilterAttribute + { + private static readonly List> s_permittedRoutes = new List> + { + new Tuple("SmartStore.Web.Controllers.CustomerController", "Login"), + new Tuple("SmartStore.Web.Controllers.CustomerController", "Logout"), + new Tuple("SmartStore.Web.Controllers.HomeController", "StoreClosed"), + new Tuple("SmartStore.Web.Controllers.CommonController", "SetLanguage") + }; + + public Lazy Localizer { get; set; } + public Lazy Notifier { get; set; } + public Lazy WorkContext { get; set; } + public Lazy StoreInformationSettings { get; set; } + + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + if (filterContext == null || filterContext.HttpContext == null) + return; + + HttpRequestBase request = filterContext.HttpContext.Request; + if (request == null) + return; + + //don't apply filter to child methods + if (filterContext.IsChildAction) + return; + + string actionName = filterContext.ActionDescriptor.ActionName; + if (String.IsNullOrEmpty(actionName)) + return; + + string controllerName = filterContext.Controller.ToString(); + if (String.IsNullOrEmpty(controllerName)) + return; + + if (!DataSettings.DatabaseIsInstalled()) + return; + + var storeInformationSettings = StoreInformationSettings.Value; + if (!storeInformationSettings.StoreClosed) + return; + + if (!IsPermittedRoute(controllerName, actionName)) + { + if (storeInformationSettings.StoreClosedAllowForAdmins && WorkContext.Value.CurrentCustomer.IsAdmin()) + { + //do nothing - allow admin access + } + else + { + if (request.IsAjaxRequest()) + { + var storeClosedMessage = "{0} {1}".FormatCurrentUI( + Localizer.Value.GetResource("StoreClosed", 0, false), + Localizer.Value.GetResource("StoreClosed.Hint", 0, false)); + Notifier.Value.Error(storeClosedMessage); + + //filterContext.Result = new ContentResult { Content = "", ContentType = "text/html" }; + } + else + { + var storeClosedUrl = new UrlHelper(filterContext.RequestContext).RouteUrl("StoreClosed"); + filterContext.Result = new RedirectResult(storeClosedUrl); + } + + } + } + } + + private static bool IsPermittedRoute(string controllerName, string actionName) + { + foreach (var route in s_permittedRoutes) + { + if (controllerName.IsCaseInsensitiveEqual(route.Item1) && actionName.IsCaseInsensitiveEqual(route.Item2)) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreIpAddressAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/StoreIpAddressAttribute.cs similarity index 88% rename from src/Presentation/SmartStore.Web.Framework/Controllers/StoreIpAddressAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/StoreIpAddressAttribute.cs index 647e7a0c50..11b8f1eeb0 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/StoreIpAddressAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/StoreIpAddressAttribute.cs @@ -2,14 +2,12 @@ using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Core.Infrastructure; using SmartStore.Services.Customers; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Filters { public class StoreIpAddressAttribute : ActionFilterAttribute { - public Lazy WebHelper { get; set; } public Lazy WorkContext { get; set; } public Lazy CustomerService { get; set; } @@ -22,22 +20,21 @@ public override void OnActionExecuting(ActionExecutingContext filterContext) if (filterContext == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) return; - //don't apply filter to child methods if (filterContext.IsChildAction) return; - //only GET requests if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) return; var webHelper = this.WebHelper.Value; - //update IP address + // Update IP address string currentIpAddress = webHelper.GetCurrentIpAddress(); if (!String.IsNullOrEmpty(currentIpAddress)) { var workContext = WorkContext.Value; var customer = workContext.CurrentCustomer; + if (!currentIpAddress.Equals(customer.LastIpAddress, StringComparison.InvariantCultureIgnoreCase)) { var customerService = CustomerService.Value; diff --git a/src/Presentation/SmartStore.Web.Framework/Filters/StoreLastVisitedPageAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/StoreLastVisitedPageAttribute.cs new file mode 100644 index 0000000000..79decb0121 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Filters/StoreLastVisitedPageAttribute.cs @@ -0,0 +1,67 @@ +using System; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Customers; +using SmartStore.Services.Common; + +namespace SmartStore.Web.Framework.Filters +{ + public class StoreLastVisitedPageAttribute : ActionFilterAttribute + { + + public Lazy WebHelper { get; set; } + public Lazy WorkContext { get; set; } + public Lazy CustomerSettings { get; set; } + public Lazy GenericAttributeService { get; set; } + public Lazy UserAgent { get; set; } + + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + if (!DataSettings.DatabaseIsInstalled()) + return; + + if (filterContext == null || filterContext.HttpContext == null || filterContext.HttpContext.Request == null) + return; + + // don't apply filter to child methods + if (filterContext.IsChildAction) + return; + + //only GET requests + if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) + return; + + if (!CustomerSettings.Value.StoreLastVisitedPage) + return; + + var customer = WorkContext.Value.CurrentCustomer; + + if (customer == null || customer.IsSystemAccount) + return; + + var pageUrl = WebHelper.Value.GetThisPageUrl(true); + var userAgent = UserAgent.Value.RawValue; + + var genericAttributeService = GenericAttributeService.Value; + + if (pageUrl.HasValue()) + { + var previousPageUrl = customer.GetAttribute(SystemCustomerAttributeNames.LastVisitedPage); + if (!pageUrl.IsCaseInsensitiveEqual(previousPageUrl)) + { + genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastVisitedPage, pageUrl); + } + } + + if (userAgent.HasValue()) + { + var previousUserAgent = customer.GetAttribute(SystemCustomerAttributeNames.LastUserAgent); + if (!userAgent.IsCaseInsensitiveEqual(previousUserAgent)) + { + genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastUserAgent, userAgent); + } + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/UnitOfWorkAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Filters/UnitOfWorkAttribute.cs similarity index 81% rename from src/Presentation/SmartStore.Web.Framework/Controllers/UnitOfWorkAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Filters/UnitOfWorkAttribute.cs index 3125f4cb49..9a060a6294 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/UnitOfWorkAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Filters/UnitOfWorkAttribute.cs @@ -1,22 +1,15 @@ -using Autofac; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; using System.Web.Mvc; -using SmartStore.Core.Infrastructure; -using SmartStore.Data; using SmartStore.Core.Data; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Filters { - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)] public class UnitOfWorkAttribute : ActionFilterAttribute { public UnitOfWorkAttribute() - : this(null, Int32.MaxValue) + : this(null, int.MaxValue) { } @@ -26,7 +19,7 @@ public UnitOfWorkAttribute(int ordinal) } public UnitOfWorkAttribute(string alias) - : this(alias, Int32.MaxValue) + : this(alias, int.MaxValue) { } diff --git a/src/Presentation/SmartStore.Web.Framework/FrameworkCacheConsumer.cs b/src/Presentation/SmartStore.Web.Framework/FrameworkCacheConsumer.cs index 78042ee47d..42d1ac94d9 100644 --- a/src/Presentation/SmartStore.Web.Framework/FrameworkCacheConsumer.cs +++ b/src/Presentation/SmartStore.Web.Framework/FrameworkCacheConsumer.cs @@ -1,17 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using SmartStore.Core.Caching; using SmartStore.Core.Domain.Configuration; using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Domain.Stores; using SmartStore.Core.Domain.Themes; using SmartStore.Core.Events; -using SmartStore.Core.Infrastructure; using SmartStore.Core.Themes; -using SmartStore.Web.Framework.Events; namespace SmartStore.Web.Framework { @@ -23,13 +16,8 @@ public class FrameworkCacheConsumer : IConsumer>, IConsumer>, IConsumer>, - IConsumer>, - IConsumer>, - IConsumer>, - IConsumer>, - IConsumer>, IConsumer>, - IConsumer + IConsumer { /// @@ -53,8 +41,6 @@ public class FrameworkCacheConsumer : public const string CUSTOMERROLES_TAX_DISPLAY_TYPES_KEY = "sm.fw.customerroles.taxdisplaytypes-{0}-{1}"; public const string CUSTOMERROLES_TAX_DISPLAY_TYPES_PATTERN_KEY = "sm.fw.customerroles.taxdisplaytypes"; - public const string STORE_LANGUAGE_MAP_KEY = "sm.fw.storelangmap"; - private readonly ICacheManager _cacheManager; private readonly ICacheManager _aspCache; @@ -79,7 +65,7 @@ public void HandleEvent(EntityDeleted eventMessage) _aspCache.Remove(BuildThemeVarsCacheKey(eventMessage.Entity)); } - public void HandleEvent(ThemeTouched eventMessage) + public void HandleEvent(ThemeTouchedEvent eventMessage) { var cacheKey = BuildThemeVarsCacheKey(eventMessage.ThemeName, 0); _aspCache.RemoveByPattern(cacheKey); @@ -101,32 +87,6 @@ public void HandleEvent(EntityInserted eventMessage) _cacheManager.RemoveByPattern(CUSTOMERROLES_TAX_DISPLAY_TYPES_PATTERN_KEY); } - - public void HandleEvent(EntityInserted eventMessage) - { - _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); - } - - public void HandleEvent(EntityDeleted eventMessage) - { - _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); - } - - public void HandleEvent(EntityInserted eventMessage) - { - _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); - } - - public void HandleEvent(EntityUpdated eventMessage) - { - _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); - } - - public void HandleEvent(EntityDeleted eventMessage) - { - _cacheManager.Remove(STORE_LANGUAGE_MAP_KEY); - } - public void HandleEvent(EntityUpdated eventMessage) { // clear models which depend on settings diff --git a/src/Presentation/SmartStore.Web.Framework/Localization/ErrorMessageProvider.cs b/src/Presentation/SmartStore.Web.Framework/Localization/ErrorMessageProvider.cs new file mode 100644 index 0000000000..c927fc2d38 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Localization/ErrorMessageProvider.cs @@ -0,0 +1,77 @@ +using System; +using System.Globalization; +using System.Web.ModelBinding; + +namespace SmartStore.Web.Framework.Localization +{ + public class ErrorMessageProvider + { + private static string _resourceClassKey; + + public static void SetResourceClassKey(string resourceClassKey) + { + if (resourceClassKey == null) + { + throw new ArgumentNullException("resourceClassKey"); + } + + _resourceClassKey = resourceClassKey; + + ModelBinderErrorMessageProviders.ValueRequiredErrorMessageProvider = ErrorMessageProvider.DefaultValueRequiredErrorMessageProvider; + ModelBinderErrorMessageProviders.TypeConversionErrorMessageProvider = ErrorMessageProvider.DefaultTypeConversionErrorMessageProvider; + } + + private static string DefaultTypeConversionErrorMessageProvider(ModelBindingExecutionContext modelBindingExecutionContext, ModelMetadata modelMetadata, object incomingValue) + { + return GetResourceCommon(modelBindingExecutionContext, modelMetadata, incomingValue, new Func(GetValueInvalidResource)); + } + + private static string DefaultValueRequiredErrorMessageProvider(ModelBindingExecutionContext modelBindingExecutionContext, ModelMetadata modelMetadata, object incomingValue) + { + return GetResourceCommon(modelBindingExecutionContext, modelMetadata, incomingValue, new Func(GetValueRequiredResource)); + } + + private static string GetResourceCommon(ModelBindingExecutionContext modelBindingExecutionContext, ModelMetadata modelMetadata, object incomingValue, + Func resourceAccessor) + { + string displayName = modelMetadata.GetDisplayName(); + string str = resourceAccessor(modelBindingExecutionContext); + object[] objArray = new object[2]; + + objArray[0] = incomingValue; + objArray[1] = displayName; + + string str1 = string.Format(CultureInfo.CurrentCulture, str, objArray); + return str1; + } + + private static string GetUserResourceString(ModelBindingExecutionContext modelBindingExecutionContext, string resourceName, string resourceClassKey) + { + if (string.IsNullOrEmpty(resourceClassKey) || modelBindingExecutionContext == null || modelBindingExecutionContext.HttpContext == null) + { + return null; + } + else + { + return modelBindingExecutionContext.HttpContext.GetGlobalResourceObject(resourceClassKey, resourceName, CultureInfo.CurrentUICulture) as string; + } + } + + private static string GetUserResourceString(ModelBindingExecutionContext modelBindingExecutionContext, string resourceName) + { + return GetUserResourceString(modelBindingExecutionContext, resourceName, _resourceClassKey); + } + + private static string GetValueInvalidResource(ModelBindingExecutionContext modelBindingExecutionContext) + { + string userResourceString = GetUserResourceString(modelBindingExecutionContext, "PropertyValueInvalid"); + return userResourceString; + } + + private static string GetValueRequiredResource(ModelBindingExecutionContext modelBindingExecutionContext) + { + string userResourceString = GetUserResourceString(modelBindingExecutionContext, "PropertyValueRequired"); + return userResourceString; + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Localization/ILocalizedModel.cs b/src/Presentation/SmartStore.Web.Framework/Localization/ILocalizedModel.cs index 90e4795437..abde521279 100644 --- a/src/Presentation/SmartStore.Web.Framework/Localization/ILocalizedModel.cs +++ b/src/Presentation/SmartStore.Web.Framework/Localization/ILocalizedModel.cs @@ -4,14 +4,10 @@ namespace SmartStore.Web.Framework.Localization { public interface ILocalizedModel { - } + public interface ILocalizedModel : ILocalizedModel { - #region Data Members (1) - IList Locales { get; set; } - - #endregion Data Members } } diff --git a/src/Presentation/SmartStore.Web.Framework/Localization/LanguageSeoCodeAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Localization/LanguageSeoCodeAttribute.cs new file mode 100644 index 0000000000..6b4271ec47 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Localization/LanguageSeoCodeAttribute.cs @@ -0,0 +1,109 @@ +using System; +using System.Net; +using System.Web; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Localization; +using SmartStore.Services.Localization; + +namespace SmartStore.Web.Framework.Localization +{ + /// + /// Attribute which ensures that store URL contains a language SEO code if "SEO friendly URLs with multiple languages" setting is enabled + /// + public class LanguageSeoCodeAttribute : ActionFilterAttribute + { + public Lazy WorkContext { get; set; } + public Lazy LanguageService { get; set; } + public Lazy LocalizationSettings { get; set; } + + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + if (filterContext == null || filterContext.HttpContext == null) + return; + + HttpRequestBase request = filterContext.HttpContext.Request; + if (request == null) + return; + + //don't apply filter to child methods + if (filterContext.IsChildAction) + return; + + //only GET requests + if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) + return; + + // ensure that this route is registered and localizable (LocalizedRoute in RouteProvider.cs) + if (filterContext.RouteData == null || filterContext.RouteData.Route == null || !(filterContext.RouteData.Route is LocalizedRoute)) + return; + + if (!DataSettings.DatabaseIsInstalled()) + return; + + var localizationSettings = LocalizationSettings.Value; + if (!localizationSettings.SeoFriendlyUrlsForLanguagesEnabled) + return; + + // process current URL + var workContext = WorkContext.Value; + var languageService = LanguageService.Value; + var workingLanguage = workContext.WorkingLanguage; + var helper = new LocalizedUrlHelper(filterContext.HttpContext.Request, true); + string defaultSeoCode = languageService.GetDefaultLanguageSeoCode(); + + string seoCode; + if (helper.IsLocalizedUrl(out seoCode)) + { + if (!languageService.IsPublishedLanguage(seoCode)) + { + var descriptor = filterContext.ActionDescriptor; + + // language is not defined in system or not assigned to store + if (localizationSettings.InvalidLanguageRedirectBehaviour == InvalidLanguageRedirectBehaviour.ReturnHttp404) + { + filterContext.Result = new ViewResult + { + ViewName = "NotFound", + MasterName = (string)null, + ViewData = new ViewDataDictionary(new HandleErrorInfo(new HttpException(404, "The resource does not exist."), descriptor.ActionName, descriptor.ControllerDescriptor.ControllerName)), + TempData = filterContext.Controller.TempData + }; + filterContext.RouteData.Values["StripInvalidSeoCode"] = true; + filterContext.RequestContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; + filterContext.RequestContext.HttpContext.Response.TrySkipIisCustomErrors = true; + } + else if (localizationSettings.InvalidLanguageRedirectBehaviour == InvalidLanguageRedirectBehaviour.FallbackToWorkingLanguage) + { + helper.StripSeoCode(); + filterContext.Result = new RedirectResult(helper.GetAbsolutePath(), true); + } + } + else + { + // redirect default language (if desired) + if (seoCode == defaultSeoCode && localizationSettings.DefaultLanguageRedirectBehaviour == DefaultLanguageRedirectBehaviour.StripSeoCode) + { + helper.StripSeoCode(); + filterContext.Result = new RedirectResult(helper.GetAbsolutePath(), true); + } + } + + // already localized URL, skip the rest + return; + } + + // keep default language prefixless (if desired) + if (workingLanguage.UniqueSeoCode == defaultSeoCode && (int)(localizationSettings.DefaultLanguageRedirectBehaviour) > 0) + { + return; + } + + // add language code to URL + helper.PrependSeoCode(workingLanguage.UniqueSeoCode); + filterContext.Result = new RedirectResult(helper.GetAbsolutePath()); + } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedRoute.cs b/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedRoute.cs index 4bf1092777..3419e77ee1 100644 --- a/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedRoute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedRoute.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.Web; using System.Web.Mvc; using System.Web.Routing; @@ -16,6 +17,7 @@ public class LocalizedRoute : Route, ICloneable #region Fields private bool? _seoFriendlyUrlsForLanguagesEnabled; + private string _leftPart; #endregion @@ -90,6 +92,18 @@ public override RouteData GetRouteData(HttpContextBase httpContext) httpContext.RewritePath("~/" + helper.RelativePath, true); } } + + if (_leftPart == null) + { + var url = this.Url; + int idx = url.IndexOf('{'); + _leftPart = "~/" + (idx >= 0 ? url.Substring(0, idx) : url).TrimEnd('/'); + } + + // Perf + if (!httpContext.Request.AppRelativeCurrentExecutionFilePath.StartsWith(_leftPart, true, CultureInfo.InvariantCulture)) + return null; + RouteData data = base.GetRouteData(httpContext); return data; } @@ -112,7 +126,10 @@ public override VirtualPathData GetVirtualPath(RequestContext requestContext, Ro string cultureCode; if (helper.IsLocalizedUrl(out cultureCode)) { - data.VirtualPath = String.Concat(cultureCode, "/", data.VirtualPath); + if (!requestContext.RouteData.Values.ContainsKey("StripInvalidSeoCode")) + { + data.VirtualPath = String.Concat(cultureCode, "/", data.VirtualPath); + } } } return data; diff --git a/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedUrlHelper.cs b/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedUrlHelper.cs index 0a7fbd2fcc..8cf645774a 100644 --- a/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedUrlHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Localization/LocalizedUrlHelper.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Web; using System.Threading.Tasks; +using SmartStore.Core.Localization; namespace SmartStore.Web.Framework.Localization { @@ -60,13 +61,7 @@ public bool IsLocalizedUrl(out string seoCode) firstPart = firstPart.Substring(0, firstSlash); } - //int length = firstPart.Length; - //if ((length == 2 || length == 5) && RegularExpressions.IsCultureCode.IsMatch(firstPart)) - //{ - // seoCode = firstPart; - // return true; - //} - if (IsValidCulture(firstPart)) + if (LocalizationHelper.IsValidCultureCode(firstPart)) { seoCode = firstPart; return true; @@ -75,28 +70,6 @@ public bool IsLocalizedUrl(out string seoCode) return false; } - private bool IsValidCulture(string cultureName) - { - var segments = cultureName.Split('-'); - - if (segments.Length == 0) - { - return false; - } - - if (segments.Length > 2) - { - return false; - } - - if (segments.Any(s => s.Length != 2)) - { - return false; - } - - return true; - } - public string StripSeoCode() { string seoCode; diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/SetWorkingCultureAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Localization/SetWorkingCultureAttribute.cs similarity index 82% rename from src/Presentation/SmartStore.Web.Framework/Controllers/SetWorkingCultureAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Localization/SetWorkingCultureAttribute.cs index f1e3c7590f..c460525c0d 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/SetWorkingCultureAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Localization/SetWorkingCultureAttribute.cs @@ -5,18 +5,14 @@ using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Infrastructure; -using SmartStore.Web.Framework.Localization; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Localization { /// /// Attribute which determines and sets the working culture /// public class SetWorkingCultureAttribute : FilterAttribute, IAuthorizationFilter { - public Lazy WorkContext { get; set; } public void OnAuthorization(AuthorizationContext filterContext) @@ -28,9 +24,9 @@ public void OnAuthorization(AuthorizationContext filterContext) if (request == null) return; - // don't apply filter to child methods - if (filterContext.IsChildAction) - return; + // don't apply filter to child methods + if (filterContext.IsChildAction) + return; if (!DataSettings.DatabaseIsInstalled()) return; @@ -47,6 +43,7 @@ public void OnAuthorization(AuthorizationContext filterContext) { culture = new CultureInfo("en-US"); } + Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } diff --git a/src/Presentation/SmartStore.Web.Framework/Localization/SmartResourceDisplayName.cs b/src/Presentation/SmartStore.Web.Framework/Localization/SmartResourceDisplayName.cs index fe96400bbe..e64ca7c164 100644 --- a/src/Presentation/SmartStore.Web.Framework/Localization/SmartResourceDisplayName.cs +++ b/src/Presentation/SmartStore.Web.Framework/Localization/SmartResourceDisplayName.cs @@ -3,7 +3,7 @@ using SmartStore.Core; using SmartStore.Core.Infrastructure; using SmartStore.Services.Localization; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Framework { @@ -26,8 +26,7 @@ public override string DisplayName { string value = null; var langId = EngineContext.Current.Resolve().WorkingLanguage.Id; - value = EngineContext.Current.Resolve() - .GetResource(ResourceKey, langId, true, "" /* ResourceKey */, true); + value = EngineContext.Current.Resolve().GetResource(ResourceKey, langId, true, "" /* ResourceKey */, true); if (value.IsEmpty() && _callerPropertyName.HasValue()) { diff --git a/src/Presentation/SmartStore.Web.Framework/Localization/Text.cs b/src/Presentation/SmartStore.Web.Framework/Localization/Text.cs index 9e0551bc26..f96004f6f3 100644 --- a/src/Presentation/SmartStore.Web.Framework/Localization/Text.cs +++ b/src/Presentation/SmartStore.Web.Framework/Localization/Text.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using SmartStore.Core.Localization; +using SmartStore.Core.Localization; using SmartStore.Services.Localization; namespace SmartStore.Web.Framework.Localization @@ -12,20 +9,30 @@ public class Text : IText public Text(ILocalizationService localizationService) { - this._localizationService = localizationService; + _localizationService = localizationService; } public LocalizedString Get(string key, params object[] args) { - var value = _localizationService.GetResource(key); - if (string.IsNullOrEmpty(value)) + try { - return new LocalizedString(key); + var value = _localizationService.GetResource(key); + + if (string.IsNullOrEmpty(value)) + { + return new LocalizedString(key); + } + + if (args == null || args.Length == 0) + { + return new LocalizedString(value); + } + + return new LocalizedString(string.Format(value, args), key, args); } - return - new LocalizedString((args == null || args.Length == 0) - ? value - : string.Format(value, args), key, args); + catch { } + + return new LocalizedString(key); } } } diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/CommaSeparatedModelBinder.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/CommaSeparatedModelBinder.cs similarity index 98% rename from src/Presentation/SmartStore.Web.Framework/Mvc/CommaSeparatedModelBinder.cs rename to src/Presentation/SmartStore.Web.Framework/Modelling/CommaSeparatedModelBinder.cs index 0bf9c2971c..a5cdc490cd 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/CommaSeparatedModelBinder.cs +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/CommaSeparatedModelBinder.cs @@ -5,7 +5,7 @@ using System.Reflection; using System.Web.Mvc; -namespace SmartStore.Web.Framework.Mvc +namespace SmartStore.Web.Framework.Modelling { public class CommaSeparatedModelBinder : DefaultModelBinder { diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/DeleteConfirmationModel.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/DeleteConfirmationModel.cs similarity index 84% rename from src/Presentation/SmartStore.Web.Framework/Mvc/DeleteConfirmationModel.cs rename to src/Presentation/SmartStore.Web.Framework/Modelling/DeleteConfirmationModel.cs index 273c0b116b..72c947aec3 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/DeleteConfirmationModel.cs +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/DeleteConfirmationModel.cs @@ -1,4 +1,4 @@ -namespace SmartStore.Web.Framework.Mvc +namespace SmartStore.Web.Framework.Modelling { public class DeleteConfirmationModel : EntityModelBase { diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/IModelAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/IModelAttribute.cs new file mode 100644 index 0000000000..4235d75359 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/IModelAttribute.cs @@ -0,0 +1,7 @@ +namespace SmartStore.Web.Framework.Modelling +{ + public interface IModelAttribute + { + string Name { get; } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/ModelBase.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/ModelBase.cs new file mode 100644 index 0000000000..05e2f798c8 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/ModelBase.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using AutoMapper; + +namespace SmartStore.Web.Framework.Modelling +{ + public sealed class CustomPropertiesDictionary : Dictionary + { + } + + public abstract partial class ModelBase + { + protected ModelBase() + { + this.CustomProperties = new CustomPropertiesDictionary(); + } + + public virtual void BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) + { + } + + /// + /// Use this property to store any custom value for your models. + /// + [IgnoreMap] + public CustomPropertiesDictionary CustomProperties { get; set; } + } + + + public abstract partial class EntityModelBase : ModelBase + { + [SmartResourceDisplayName("Admin.Common.Entity.Fields.Id")] + public virtual int Id { get; set; } + } + + + public abstract partial class TabbableModel : EntityModelBase + { + [IgnoreMap] + public virtual string[] LoadedTabs { get; set; } + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/ModelBoundEvent.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/ModelBoundEvent.cs new file mode 100644 index 0000000000..756aceedde --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/ModelBoundEvent.cs @@ -0,0 +1,18 @@ +using System.Web.Mvc; + +namespace SmartStore.Web.Framework.Modelling +{ + public class ModelBoundEvent + { + public ModelBoundEvent(TabbableModel boundModel, object entityModel, FormCollection form) + { + this.BoundModel = boundModel; + this.EntityModel = entityModel; + this.Form = form; + } + + public TabbableModel BoundModel { get; private set; } + public object EntityModel { get; private set; } + public FormCollection Form { get; private set; } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/PictureResult.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/PictureResult.cs new file mode 100644 index 0000000000..b7374f6bab --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/PictureResult.cs @@ -0,0 +1,61 @@ +using System.IO; +using System.Web.Mvc; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Infrastructure; +using SmartStore.Services.Media; + +namespace SmartStore.Web.Framework.Modelling +{ + public class PictureResult : FileStreamResult + { + public PictureResult(Picture picture, int targetSize) + : base(GetMemoryStream(picture, targetSize), picture.MimeType) + { + + } + + static MemoryStream GetMemoryStream(Picture picture, int targetSize) + { + var localUrl = EngineContext.Current.Resolve().GetThumbLocalPath(picture, targetSize); + var fileStream = new FileStream(localUrl, FileMode.Open, FileAccess.Read, FileShare.Read); + var memoryStream = StreamToMemory(fileStream); + fileStream.Close(); + return memoryStream; + } + + static MemoryStream StreamToMemory(Stream input) + { + + byte[] buffer = new byte[1024]; + int count = 1024; + MemoryStream output; + + // build a new stream + if (input.CanSeek) + { + output = new MemoryStream((int)input.Length); + } + else + { + output = new MemoryStream(); + } + + // iterate stream and transfer to memory stream + do + { + count = input.Read(buffer, 0, count); + if (count == 0) + break; // TODO: might not be correct. Was : Exit Do + output.Write(buffer, 0, count); + } while (true); + + // rewind stream + output.Position = 0; + + // pass back + return output; + + } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/Results/JsonNetResult.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/Results/JsonNetResult.cs new file mode 100644 index 0000000000..b64e060a45 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/Results/JsonNetResult.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Mvc; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using SmartStore.Services.Helpers; + +// ReSharper disable CheckNamespace +namespace SmartStore.Web.Framework.Modelling +{ + public class JsonNetResult : JsonResult + { + private readonly IDateTimeHelper _dateTimeHelper; + private readonly JsonSerializerSettings _settings; + + public JsonNetResult(IDateTimeHelper dateTimeHelper) + : this(dateTimeHelper, null) + { + } + + public JsonNetResult(IDateTimeHelper dateTimeHelper, JsonSerializerSettings settings) + { + Guard.ArgumentNotNull(() => dateTimeHelper); + + _dateTimeHelper = dateTimeHelper; + _settings = settings; + } + + public override void ExecuteResult(ControllerContext context) + { + Guard.ArgumentNotNull(() => context); + + if (this.Data == null) + return; + + if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && context.HttpContext.Request.HttpMethod.IsCaseInsensitiveEqual("GET")) + { + throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request.To allow GET requests, set JsonRequestBehavior to AllowGet."); + } + + var response = context.HttpContext.Response; + + if (this.ContentEncoding != null) + { + response.ContentEncoding = this.ContentEncoding; + } + + response.ContentType = this.ContentType.NullEmpty() ?? "application/json"; + + var serializerSettings = _settings ?? new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Ignore, + + // Limit the object graph we'll consume to a fixed depth. This prevents stackoverflow exceptions + // from deserialization errors that might occur from deeply nested objects. + MaxDepth = 32, + + // Do not change this setting + // Setting this to None prevents Json.NET from loading malicious, unsafe, or security-sensitive types + TypeNameHandling = TypeNameHandling.None + }; + + if (_settings == null) + { + serializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; + serializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat; + + var utcDateTimeConverter = new UTCDateTimeConverter(_dateTimeHelper, new JavaScriptDateTimeConverter()); + serializerSettings.Converters.Add(utcDateTimeConverter); + } + + using (var jsonWriter = new JsonTextWriter(response.Output)) + { + jsonWriter.CloseOutput = false; + var jsonSerializer = JsonSerializer.Create(serializerSettings); + jsonSerializer.Serialize(jsonWriter, this.Data); + } + } + + class UTCDateTimeConverter : DateTimeConverterBase + { + private readonly IDateTimeHelper _dateTimeHelper; + private readonly DateTimeConverterBase _innerConverter; + + public UTCDateTimeConverter(IDateTimeHelper dateTimeHelper, DateTimeConverterBase innerConverter) + { + Guard.ArgumentNotNull(() => innerConverter); + + _dateTimeHelper = dateTimeHelper; + _innerConverter = innerConverter; + } + + public override bool CanConvert(Type objectType) + { + return _innerConverter.CanConvert(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return _innerConverter.ReadJson(reader, objectType, existingValue, serializer); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value is DateTime) + { + var d = (DateTime)value; + if (d.Kind == DateTimeKind.Unspecified) + { + // when DateTime kind is "Unspecified", it was very likely converted from UTC to + // SERVER*s preferred local time before (with DateTimeHelper.ConvertToUserTime()). + // While this works fine during server-time rendering, it can lead to wrong UTC offsets + // on the client (e.g. in AJAX mode Grids, where rendering is performed locally with JSON data). + // The issue occurs when the client's time zone is not the same as "CurrentTimeZone" (configured in the backend). + // To fix it, we have to convert the date back to UTC kind, but with the SERVER PREFERRED TIMEZONE + // in order to calculate with the correct UTC offset. Then it's up to the client to display the date + // in the CLIENT's time zone. Which is not perfect of course, because the same date would be displayed in the + // "CurrentTimeZone" if rendered on server. + // But: it fixes the issue and is way better than converting all AJAXable dates to strings on the server. + value = _dateTimeHelper.ConvertToUtcTime(d, _dateTimeHelper.CurrentTimeZone); + } + } + + _innerConverter.WriteJson(writer, value, serializer); + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/Results/RssActionResult.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/Results/RssActionResult.cs new file mode 100644 index 0000000000..ead023a777 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/Results/RssActionResult.cs @@ -0,0 +1,25 @@ +using System.ServiceModel.Syndication; +using System.Web.Mvc; +using System.Xml; + +// ReSharper disable once CheckNamespace +namespace SmartStore.Web.Framework.Modelling +{ + public class RssActionResult : ActionResult + { + public SyndicationFeed Feed { get; set; } + + public override void ExecuteResult(ControllerContext context) + { + context.HttpContext.Response.ContentType = "application/rss+xml"; + + var rssFormatter = new Rss20FeedFormatter(Feed, false); + var settings = new XmlWriterSettings { Indent = true, IndentChars = "\t", CheckCharacters = false }; + + using (var writer = XmlWriter.Create(context.HttpContext.Response.Output, settings)) + { + rssFormatter.WriteTo(writer); + } + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/XmlDownloadResult.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/Results/XmlDownloadResult.cs similarity index 93% rename from src/Presentation/SmartStore.Web.Framework/Mvc/XmlDownloadResult.cs rename to src/Presentation/SmartStore.Web.Framework/Modelling/Results/XmlDownloadResult.cs index 5a19d6cd6c..78ec6589ec 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/XmlDownloadResult.cs +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/Results/XmlDownloadResult.cs @@ -3,7 +3,8 @@ using System.Xml; using SmartStore.Utilities; -namespace SmartStore.Web.Framework.Mvc +// ReSharper disable once CheckNamespace +namespace SmartStore.Web.Framework.Modelling { public class XmlDownloadResult : ActionResult { diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/SmartMetadataProvider.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/SmartMetadataProvider.cs new file mode 100644 index 0000000000..65215447ff --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/SmartMetadataProvider.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Web.Mvc; + +namespace SmartStore.Web.Framework.Modelling +{ + /// + /// This MetadataProvider adds some functionality on top of the default CachedDataAnnotationsModelMetadataProvider. + /// It adds custom attributes (implementing IModelAttribute) to the AdditionalValues property of the model's metadata + /// so that it can be retrieved later. + /// + public class SmartMetadataProvider : CachedDataAnnotationsModelMetadataProvider + { + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + [SuppressMessage("ReSharper", "SuspiciousTypeConversion.Global")] + protected override CachedDataAnnotationsModelMetadata CreateMetadataPrototype(IEnumerable attributes, Type containerType, Type modelType, string propertyName) + { + var metadata = base.CreateMetadataPrototype(attributes, containerType, modelType, propertyName); + var attrs = attributes.OfType().ToList(); + + foreach (var attr in attrs) + { + if (metadata.AdditionalValues.ContainsKey(attr.Name)) + { + throw new SmartException("There is already an attribute with the name of '{0}' on this model.".FormatCurrent(attr.Name)); + } + metadata.AdditionalValues.Add(attr.Name, attr); + } + + return metadata; + } + + protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func modelAccessor) + { + var result = base.CreateMetadataFromPrototype(prototype, modelAccessor); + + if (prototype.AdditionalValues.Count > 0) + { + var attrs = prototype.AdditionalValues.Where(x => x.Value is IModelAttribute).ToArray(); + if (attrs.Any()) + { + result.AdditionalValues.AddRange(attrs); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web.Framework/Modelling/SmartModelBinder.cs b/src/Presentation/SmartStore.Web.Framework/Modelling/SmartModelBinder.cs new file mode 100644 index 0000000000..4bf8481d2d --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Modelling/SmartModelBinder.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; + +namespace SmartStore.Web.Framework.Modelling +{ + public class SmartModelBinder : DefaultModelBinder + { + public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) + { + var modelType = bindingContext.ModelType; + + if (bindingContext.ModelType == typeof(CustomPropertiesDictionary)) + { + return BindCustomPropertiesDictioary(controllerContext, bindingContext); + } + + var model = base.BindModel(controllerContext, bindingContext); + + if (model is ModelBase) + { + ((ModelBase)model).BindModel(controllerContext, bindingContext); + } + + return model; + } + + private CustomPropertiesDictionary BindCustomPropertiesDictioary(ControllerContext controllerContext, ModelBindingContext bindingContext) + { + var model = bindingContext.Model as CustomPropertiesDictionary ?? new CustomPropertiesDictionary(); + + var keys = GetValueProviderKeys(controllerContext, bindingContext.ModelName + "["); + if (keys.Count == 0) + { + return model; + } + + foreach (var key in keys) + { + var keyName = GetKeyName(key); + if (keyName == null || model.ContainsKey(keyName)) + continue; + + var valueBinder = this.Binders.DefaultBinder; + + var subPropertyName = GetSubPropertyName(key); + if (subPropertyName.IsCaseInsensitiveEqual("__Type__")) + continue; + + if (subPropertyName == null) + { + var simpleBindingContext = new ModelBindingContext + { + ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, GetValueType(keys, key, bindingContext.ValueProvider)), + ModelName = key, + ModelState = bindingContext.ModelState, + PropertyFilter = bindingContext.PropertyFilter, + ValueProvider = bindingContext.ValueProvider + }; + var value = valueBinder.BindModel(controllerContext, simpleBindingContext); + model[keyName] = value; + } + else + { + // Is Complex type + var modelName = key.Substring(0, key.Length - subPropertyName.Length - 1); + var valueType = GetValueType(keys, modelName, bindingContext.ValueProvider); + valueBinder = this.Binders.GetBinder(valueType); + var complexBindingContext = new ModelBindingContext + { + ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, valueType), + ModelName = key.Substring(0, key.Length - subPropertyName.Length - 1), + ModelState = bindingContext.ModelState, + PropertyFilter = bindingContext.PropertyFilter, + ValueProvider = bindingContext.ValueProvider + }; + var value = valueBinder.BindModel(controllerContext, complexBindingContext); + model[keyName] = value; + } + } + + return model; + } + + private HashSet GetValueProviderKeys(ControllerContext context, string prefix) + { + var keys = context.HttpContext.Request.Form.Keys.Cast() + .Concat(((IDictionary)context.RouteData.Values).Keys.Cast()) + .Concat(context.HttpContext.Request.QueryString.Keys.Cast()) + .Concat(context.HttpContext.Request.Files.Keys.Cast()) + .Where(x => x.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase)); + + return new HashSet(keys, StringComparer.InvariantCultureIgnoreCase); + } + + private string GetKeyName(string key) + { + int startBracket = key.IndexOf("["); + int endBracket = key.IndexOf("]", startBracket); + + if (endBracket == -1) + return null; + + return key.Substring(startBracket + 1, endBracket - startBracket - 1); + } + + private string GetSubPropertyName(string key) + { + var parts = key.Split('.'); + if (parts.Length > 1) + { + return parts[1]; + } + + return null; + } + + private Type GetValueType(HashSet keys, string prefix, IValueProvider valueProvider) + { + var typeKey = prefix + ".__Type__"; + if (keys.Contains(typeKey)) + { + var type = Type.GetType(valueProvider.GetValue(typeKey).AttemptedValue, true); + return type; + } + return typeof(object); + } + + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/IBundleProvider.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/IBundleProvider.cs deleted file mode 100644 index ae18ccbddb..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/IBundleProvider.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Web.Optimization; - -namespace SmartStore.Web.Framework.Mvc.Bundles -{ - /// - /// codehint: sm-add - /// - public interface IBundleProvider - { - void RegisterBundles(BundleCollection bundles); - - int Priority { get; } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/IBundlePublisher.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/IBundlePublisher.cs deleted file mode 100644 index e910605f06..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/Bundles/IBundlePublisher.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Web.Optimization; - -namespace SmartStore.Web.Framework.Mvc.Bundles -{ - /// - /// codehint: sm-add - /// - public interface IBundlePublisher - { - void RegisterBundles(BundleCollection bundles); - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/IModelAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/IModelAttribute.cs deleted file mode 100644 index 9e171eab4e..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/IModelAttribute.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace SmartStore.Web.Framework.Mvc -{ - public interface IModelAttribute - { - string Name { get; } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/ImageResult.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/ImageResult.cs deleted file mode 100644 index 3ec9a1307f..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/ImageResult.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.IO; -using System.Web.Mvc; -using SmartStore.Core.Domain.Media; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Media; - -namespace SmartStore.Web.Framework.Mvc -{ - public class PictureResult : FileStreamResult - { - public PictureResult(Picture picture, int targetSize) - : base( - GetMemoryStream(picture, targetSize), picture.MimeType) - { - - } - - static MemoryStream GetMemoryStream(Picture picture, int targetSize) - { - var localUrl = EngineContext.Current.Resolve().GetThumbLocalPath(picture, targetSize); - var fileStream = new FileStream(localUrl, FileMode.Open, FileAccess.Read, FileShare.Read); - var memoryStream = StreamToMemory(fileStream); - fileStream.Close(); - return memoryStream; - } - - static MemoryStream StreamToMemory(Stream input) - { - - byte[] buffer = new byte[1024]; - int count = 1024; - MemoryStream output; - - // build a new stream - if (input.CanSeek) - { - output = new MemoryStream((int)input.Length); - } - else - { - output = new MemoryStream(); - } - - // iterate stream and transfer to memory stream - do - { - count = input.Read(buffer, 0, count); - if (count == 0) - break; // TODO: might not be correct. Was : Exit Do - output.Write(buffer, 0, count); - } while (true); - - // rewind stream - output.Position = 0; - - // pass back - return output; - - } - - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/ModelBase.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/ModelBase.cs deleted file mode 100644 index 77fd5cf3dc..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/ModelBase.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Web.Mvc; - -namespace SmartStore.Web.Framework.Mvc -{ - public abstract partial class ModelBase - { - public ModelBase() - { - this.CustomProperties = new Dictionary(); - } - - public virtual void BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) - { - } - - /// - /// Use this property to store any custom value for your models. - /// - public Dictionary CustomProperties { get; set; } - } - - public abstract partial class EntityModelBase : ModelBase - { - [SmartResourceDisplayName("Admin.Common.Entity.Fields.Id")] - public virtual int Id { get; set; } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/SmartMetadataProvider.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/SmartMetadataProvider.cs deleted file mode 100644 index c75bd8b28e..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/SmartMetadataProvider.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web.Mvc; -using SmartStore.Core; - -namespace SmartStore.Web.Framework.Mvc -{ - /// - /// This MetadataProvider adds some functionality on top of the default DataAnnotationsModelMetadataProvider. - /// It adds custom attributes (implementing IModelAttribute) to the AdditionalValues property of the model's metadata - /// so that it can be retrieved later. - /// - public class SmartMetadataProvider : DataAnnotationsModelMetadataProvider - { - protected override ModelMetadata CreateMetadata(IEnumerable attributes, Type containerType, Func modelAccessor, Type modelType, string propertyName) - { - var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); - var additionalValues = attributes.OfType().ToList(); - foreach (var additionalValue in additionalValues) - { - if (metadata.AdditionalValues.ContainsKey(additionalValue.Name)) - throw new SmartException("There is already an attribute with the name of \"" + additionalValue.Name + - "\" on this model."); - metadata.AdditionalValues.Add(additionalValue.Name, additionalValue); - } - return metadata; - } - } -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/SmartModelBinder.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/SmartModelBinder.cs deleted file mode 100644 index de48da8af3..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/SmartModelBinder.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Linq; -using System.Collections; -using System.Collections.Generic; -using System.Web; -using System.Web.Mvc; -using System.ComponentModel; -using SmartStore.Utilities; - -// codehint: sm-edit (massively: added proper dictionary binding) - -namespace SmartStore.Web.Framework.Mvc -{ - public class SmartModelBinder : DefaultModelBinder - { - private readonly IModelBinder _nextBinder; - private readonly static string s_DictTypeName = typeof(IDictionary<,>).FullName; - - public SmartModelBinder() : this(null) - { - } - - public SmartModelBinder(IModelBinder nextBinder) - { - _nextBinder = nextBinder; - } - - public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) - { - Type modelType = bindingContext.ModelType; - - Type idictType = modelType.GetInterface(s_DictTypeName); - - if (idictType != null) - { - var dictInstance = this.BindDictionary(controllerContext, bindingContext, idictType); - if (dictInstance != null) - { - return dictInstance; - } - } - - if (_nextBinder != null) - { - return _nextBinder.BindModel(controllerContext, bindingContext); - } - - var model = base.BindModel(controllerContext, bindingContext); - - if (model is ModelBase) - { - ((ModelBase)model).BindModel(controllerContext, bindingContext); - } - - return model; - } - - private object BindDictionary(ControllerContext controllerContext, ModelBindingContext bindingContext, Type idictType) - { - Type modelType = bindingContext.ModelType; - object result = null; - - Type[] ga = idictType.GetGenericArguments(); - IModelBinder valueBinder = Binders.GetBinder(ga[1]); - - foreach (string key in GetValueProviderKeys(controllerContext)) - { - bool isMatch = key.StartsWith(bindingContext.ModelName + "[", StringComparison.InvariantCultureIgnoreCase); - if (isMatch) - { - int endbracket = key.IndexOf("]", bindingContext.ModelName.Length + 1); - if (endbracket == -1) - continue; - - object dictKey; - try - { - dictKey = ConvertType(key.Substring(bindingContext.ModelName.Length + 1, endbracket - bindingContext.ModelName.Length - 1), ga[0]); - } - catch (NotSupportedException) - { - continue; - } - - ModelBindingContext innerBindingContext = new ModelBindingContext() - { - ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, ga[1]), - ModelName = key.Substring(0, endbracket + 1), - ModelState = bindingContext.ModelState, - PropertyFilter = bindingContext.PropertyFilter, - ValueProvider = bindingContext.ValueProvider - }; - object newPropertyValue = valueBinder.BindModel(controllerContext, innerBindingContext); - - if (result == null) - result = CreateModel(controllerContext, bindingContext, modelType); - - if (!(bool)idictType.GetMethod("ContainsKey").Invoke(result, new object[] { dictKey })) - idictType.GetProperty("Item").SetValue(result, ((string[])newPropertyValue)[0], new object[] { dictKey }); - } - } - - return result; - } - - private object ConvertType(string stringValue, Type type) - { - return CommonHelper.GetTypeConverter(type).ConvertFrom(stringValue); - } - - private IEnumerable GetValueProviderKeys(ControllerContext context) - { - List keys = new List(); - keys.AddRange(context.HttpContext.Request.Form.Keys.Cast()); - keys.AddRange(((IDictionary)context.RouteData.Values).Keys.Cast()); - keys.AddRange(context.HttpContext.Request.QueryString.Keys.Cast()); - keys.AddRange(context.HttpContext.Request.Files.Keys.Cast()); - return keys; - } - - - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/UniversalResult.cs b/src/Presentation/SmartStore.Web.Framework/Mvc/UniversalResult.cs deleted file mode 100644 index 5ac5d40287..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/UniversalResult.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Mime; -using System.Text; -using System.Threading.Tasks; -using System.Web.Mvc; -using System.Xml; -using System.Xml.Serialization; - -namespace SmartStore.Web.Framework.Mvc -{ - /// An action method result wrapper that handles all required action results in a project. - /// codehint: sm-add - public class UniversalResult : ActionResult - { - public UniversalResult() { - } - public UniversalResult(string content, string contentType = MediaTypeNames.Text.Html) { - Content = content; - ContentType = contentType; - } - public UniversalResult(XmlDocument doc, string contentType = MediaTypeNames.Text.Xml) { - Content = doc; - ContentType = contentType; - } - // TODO: more constructors here... - - public object Content { get; set; } - public string ContentType { get; set; } - - public override void ExecuteResult(ControllerContext context) { - if (Content != null) { - string str = null; - XmlDocument xmlDoc = null; - - context.HttpContext.Response.ContentType = ContentType; - - if ((str = Content as string) != null) { - context.HttpContext.Response.Write(str); - } - else if ((xmlDoc = Content as XmlDocument) != null) { - var xs = new XmlSerializer(xmlDoc.GetType()); - xs.Serialize(context.HttpContext.Response.Output, xmlDoc); - } - // TODO: more... - } - } - } // class -} diff --git a/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfPartialViewContent.cs b/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfPartialViewContent.cs new file mode 100644 index 0000000000..fb266aa64e --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfPartialViewContent.cs @@ -0,0 +1,16 @@ +using System; +using System.Web.Mvc; +using SmartStore.Services.Pdf; + +namespace SmartStore.Web.Framework.Pdf +{ + + public class PdfPartialViewContent : PdfHtmlContent + { + public PdfPartialViewContent(string partialViewName, object model, ControllerContext controllerContext) + : base(PdfViewContent.ViewToString(partialViewName, null, model, true, controllerContext, false)) + { + } + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfRouteContent.cs b/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfRouteContent.cs new file mode 100644 index 0000000000..407ae9a490 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfRouteContent.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Services.Pdf; + +namespace SmartStore.Web.Framework.Pdf +{ + + public class PdfRouteContent : PdfUrlContent + { + public PdfRouteContent(string routeName, ControllerContext controllerContext) + : this(routeName, null, null, null, controllerContext) + { + } + + public PdfRouteContent(string routeName, RouteValueDictionary routeValues, ControllerContext controllerContext) + : this(routeName, null, null, routeValues, controllerContext) + { + } + + public PdfRouteContent(string action, string controller, ControllerContext controllerContext) + : this(null, action, controller, null, controllerContext) + { + } + + public PdfRouteContent(string action, string controller, RouteValueDictionary routeValues, ControllerContext controllerContext) + : this(null, action, controller, routeValues, controllerContext) + { + } + + protected PdfRouteContent(string routeName, string action, string controller, RouteValueDictionary routeValues, ControllerContext controllerContext) + : base(UrlHelper.GenerateUrl(routeName, action, controller, routeValues, RouteTable.Routes, controllerContext.RequestContext, true)) + { + //Guard.ArgumentNotNull(() => controllerContext); + + //if (routeName.IsEmpty() || action.IsEmpty()) + //{ + // throw Error.InvalidOperation("Either 'routeName' or 'action' must be set"); + //} + } + + + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfViewContent.cs b/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfViewContent.cs new file mode 100644 index 0000000000..46c389750e --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Pdf/Content/PdfViewContent.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; +using System.Text; +using System.Web.Mvc; +using SmartStore.Services.Pdf; +using SmartStore.Web.Framework.Controllers; + +namespace SmartStore.Web.Framework.Pdf +{ + + public class PdfViewContent : PdfHtmlContent + { + + public PdfViewContent(string viewName, object model, ControllerContext controllerContext) + : this(viewName, null, model, controllerContext) + { + } + + public PdfViewContent(string viewName, string masterName, object model, ControllerContext controllerContext) + : base(ViewToString(viewName, masterName, model, false, controllerContext, true)) + { + } + + protected internal static string ViewToString(string viewName, string masterName, object model, bool isPartial, ControllerContext context, bool throwOnError) + { + Guard.ArgumentNotNull(() => context); + + string html = null; + + try + { + html = isPartial + ? context.Controller.RenderPartialViewToString(viewName, model) + : context.Controller.RenderViewToString(viewName, masterName, model); + } + catch (Exception) + { + if (throwOnError) + { + throw; + } + else + { + return null; + } + } + + return html; + } + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/Pdf/PdfHeaderFooterVariables.cs b/src/Presentation/SmartStore.Web.Framework/Pdf/PdfHeaderFooterVariables.cs new file mode 100644 index 0000000000..854b365091 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Pdf/PdfHeaderFooterVariables.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; + +namespace SmartStore.Web.Framework.Pdf +{ + + public class PdfHeaderFooterVariables + { + + /// + /// The number of the page currently being printed + /// + public int Page { get; set; } + + /// + /// The number of the first page to be printed + /// + public int FromPage { get; set; } + + /// + /// The number of the last page to be printed + /// + public int ToPage { get; set; } + + /// + /// The URL of the page being printed + /// + public string WebPage { get; set; } + + /// + /// The name of the current section + /// + public string Section { get; set; } + + /// + /// The name of the current subsection + /// + public string SubSection { get; set; } + + /// + /// The title of the of the current page object + /// + public string Title { get; set; } + + /// + /// The title of the output document + /// + public string DocTitle { get; set; } + + /// + /// The number of the page in the current site being converted + /// + public int SitePage { get; set; } + + /// + /// The number of pages in the current site being converted + /// + public int SitePages { get; set; } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Pdf/PdfReceiptHeaderFooterModel.cs b/src/Presentation/SmartStore.Web.Framework/Pdf/PdfReceiptHeaderFooterModel.cs new file mode 100644 index 0000000000..8ccb73199e --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Pdf/PdfReceiptHeaderFooterModel.cs @@ -0,0 +1,21 @@ +using SmartStore.Core.Domain.Common; +using SmartStore.Web.Framework.Modelling; +using SmartStore.Web.Framework.Pdf; + +namespace SmartStore.Web.Framework.Pdf +{ + public partial class PdfReceiptHeaderFooterModel : ModelBase + { + public int StoreId { get; set; } + + public string StoreName { get; set; } + public string LogoUrl { get; set; } + public string StoreUrl { get; set; } + + public CompanyInformationSettings MerchantCompanyInfo { get; set; } + public BankConnectionSettings MerchantBankAccount { get; set; } + public ContactDataSettings MerchantContactData { get; set; } + + public PdfHeaderFooterVariables Variables { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web.Framework/Pdf/PdfResult.cs b/src/Presentation/SmartStore.Web.Framework/Pdf/PdfResult.cs new file mode 100644 index 0000000000..8d11030975 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Pdf/PdfResult.cs @@ -0,0 +1,62 @@ +using System.IO; +using System.Text.RegularExpressions; +using System.Web; +using System.Web.Mvc; +using System.Web.Security; +using SmartStore.Services.Pdf; + +namespace SmartStore.Web.Framework.Pdf +{ + public class PdfResult : ActionResult + { + private const string ContentType = "application/pdf"; + + public PdfResult(IPdfConverter converter, PdfConvertSettings settings) + { + Guard.ArgumentNotNull(() => converter); + + this.Converter = converter; + this.Settings = settings ?? new PdfConvertSettings(); + } + + protected IPdfConverter Converter { get; set; } + + protected PdfConvertSettings Settings { get; set; } + + /// + /// The name of the generated PDF file. + /// + public string FileName { get; set; } + + protected HttpResponseBase PrepareResponse(HttpResponseBase response) + { + response.ContentType = ContentType; + + if (FileName.HasValue()) + { + response.AddHeader("Content-Disposition", "attachment; filename=\"{0}\"".FormatCurrent(SanitizeFileName(FileName))); + } + + response.AddHeader("Content-Type", ContentType); + + return response; + } + + public override void ExecuteResult(ControllerContext context) + { + var buffer = Converter.Convert(Settings); + var response = PrepareResponse(context.HttpContext.Response); + response.OutputStream.Write(buffer, 0, buffer.Length); + } + + private static string SanitizeFileName(string name) + { + string invalidChars = Regex.Escape(new string(Path.GetInvalidPathChars()) + new string(Path.GetInvalidFileNameChars())); + string invalidCharsPattern = string.Format(@"[{0}]+", invalidChars); + + string result = Regex.Replace(name, invalidCharsPattern, "-"); + return result; + } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginCore.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginCore.cs deleted file mode 100644 index aaff4c9f36..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginCore.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Web.Mvc; -using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Logging; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Web.Framework.Plugins -{ - public class PromotionFeedSettings - { - public int ProductPictureSize { get; set; } - public int CurrencyId { get; set; } - public string StaticFileName { get; set; } - public string BuildDescription { get; set; } - public bool DescriptionToPlainText { get; set; } - public bool AdditionalImages { get; set; } - public string Availability { get; set; } - public decimal ShippingCost { get; set; } - public string ShippingTime { get; set; } - public string Brand { get; set; } - public bool UseOwnProductNo { get; set; } - public int StoreId { get; set; } - public string ExportFormat { get; set; } - public bool ConvertNetToGrossPrices { get; set; } - public int LanguageId { get; set; } - } - - - public class PromotionFeedConfigModel - { - public PromotionFeedConfigModel() - { - GeneratedFiles = new List(); - } - - public FeedPluginHelper Helper { get; set; } - public bool IsRunning { get; set; } - public string ProcessInfo { get; set; } - public string GenerateFeedUrl { get; set; } - public string GenerateFeedProgressUrl { get; set; } - public string DeleteFilesUrl { get; set; } - - [SmartResourceDisplayName("Plugins.KnownGroup.PromotionFeed")] - public List GeneratedFiles { get; set; } - public List AvailableStores { get; set; } - public List AvailableLanguages { get; set; } - } - - - public class FeedFileData : ModelBase - { - public int StoreId { get; set; } - public string StoreName { get; set; } - public string FileTempPath { get; set; } - public string FilePath { get; set; } - public string FileUrl { get; set; } - public string LogPath { get; set; } - public string LogUrl { get; set; } - public string LastWriteTime { get; set; } - } - - - public class FeedFileCreationContext - { - public FileStream Stream { get; set; } - public TraceLogger Logger { get; set; } - public Store Store { get; set; } - public int StoreCount { get; set; } - public int TotalRecords { get; set; } - public int TotalProcessed { get; set; } - public string FeedFileUrl { get; set; } - public string SecondFilePath { get; set; } - public IProgress Progress { get; set; } - - public void Report() - { - if (Progress != null) - { - Progress.Report(new FeedFileCreationProgress - { - TotalRecords = TotalRecords, - TotalProcessed = ++TotalProcessed - }); - } - } - } - - - public class FeedFileCreationProgress - { - public int TotalRecords { get; set; } - public int TotalProcessed { get; set; } - public double ProcessedPercent - { - get - { - if (TotalRecords == 0) - return 0; - - return ((double)TotalProcessed / (double)TotalRecords) * 100; - } - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs deleted file mode 100644 index e6929c992f..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/FeedPluginHelper.cs +++ /dev/null @@ -1,753 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Globalization; -using System.IO; -using System.Web; -using System.Web.Mvc; -using System.Threading; -using System.Threading.Tasks; -using Autofac; -using SmartStore.Core; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Tasks; -using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Html; -using SmartStore.Core.Logging; -using SmartStore.Core.Async; -using SmartStore.Services.Catalog; -using SmartStore.Services.Media; -using SmartStore.Services.Tasks; -using SmartStore.Services.Stores; -using SmartStore.Services.Seo; -using SmartStore.Services.Localization; -using SmartStore.Services.Tax; - -namespace SmartStore.Web.Framework.Plugins -{ - public partial class FeedPluginHelper : PluginHelper - { - private readonly string _namespace; - private ScheduleTask _scheduleTask; - private IDictionary _cachedCategories; - private IDictionary _cachedPathes; - private Func _settingsFunc; - - public FeedPluginHelper(IComponentContext componentContext, string systemName, string rootNamespace, Func settings) : - base(componentContext, systemName) - { - _namespace = rootNamespace; - _settingsFunc = settings; - } - - #region Dependencies - - private IScheduleTaskService _scheduleTaskService; - private IScheduleTaskService ScheduleTaskService - { - get { return _scheduleTaskService ?? (_scheduleTaskService = _ctx.Resolve()); } - } - - private IPictureService _pictureService; - private IPictureService PictureService - { - get { return _pictureService ?? (_pictureService = _ctx.Resolve()); } - } - - private IProductService _productService; - private IProductService ProductService - { - get { return _productService ?? (_productService = _ctx.Resolve()); } - } - - private ICategoryService _categoryService; - private ICategoryService CategoryService - { - get { return _categoryService ?? (_categoryService = _ctx.Resolve()); } - } - - private INotifier _notifier; - private INotifier Notifier - { - get { return _notifier ?? (_notifier = _ctx.Resolve()); } - } - - private ILogger _logger; - private ILogger Logger - { - get { return _logger ?? (_logger = _ctx.Resolve()); } - } - - private IUrlRecordService _urlRecordService; - private IUrlRecordService UrlRecordService - { - get { return _urlRecordService ?? (_urlRecordService = _ctx.Resolve()); } - } - - private ILanguageService _languageService; - private ILanguageService LanguageService - { - get { return _languageService ?? (_languageService = _ctx.Resolve()); } - } - - private IPriceCalculationService _priceCalculationService; - private IPriceCalculationService PriceCalculationService - { - get { return _priceCalculationService ?? (_priceCalculationService = _ctx.Resolve()); } - } - - private ITaxService _taxService; - private ITaxService TaxService - { - get { return _taxService ?? (_taxService = _ctx.Resolve()); } - } - - private IWorkContext _workContext; - private IWorkContext WorkContext - { - get { return _workContext ?? (_workContext = _ctx.Resolve()); } - } - - #endregion - - private PromotionFeedSettings BaseSettings - { - get { return _settingsFunc(); } - } - - private string ScheduleTaskType - { - get - { - return "{0}.StaticFileGenerationTask, {0}".FormatWith(_namespace); - } - } - - public ScheduleTask ScheduleTask - { - get - { - if (_scheduleTask == null) - _scheduleTask = ScheduleTaskService.GetTaskByType(ScheduleTaskType); - - return _scheduleTask; - } - } - - public string RemoveInvalidFeedChars(string input, bool isHtmlEncoded) - { - if (String.IsNullOrWhiteSpace(input)) - return input; - - //Microsoft uses a proprietary encoding (called CP-1252) for the bullet symbol and some other special characters, - //whereas most websites and data feeds use UTF-8. When you copy-paste from a Microsoft product into a website, - //some characters may appear as junk. Our system generates data feeds in the UTF-8 character encoding, - //which many shopping engines now require. - - //http://www.atensoftware.com/p90.php?q=182 - - if (isHtmlEncoded) - input = HttpUtility.HtmlDecode(input); - - input = input.Replace("¼", ""); - input = input.Replace("½", ""); - input = input.Replace("¾", ""); - - if (isHtmlEncoded) - input = HttpUtility.HtmlEncode(input); - - return input; - } - - public string BuildProductDescription(string productName, string shortDescription, string fullDescription, string manufacturer, Func updateResult = null) - { - if (BaseSettings.BuildDescription.IsCaseInsensitiveEqual(NotSpecified)) - return ""; - - string description = ""; - - if (BaseSettings.BuildDescription.IsNullOrEmpty()) - { - description = fullDescription; - - if (description.IsNullOrEmpty()) - description = shortDescription; - if (description.IsNullOrEmpty()) - description = productName; - } - else if (BaseSettings.BuildDescription.IsCaseInsensitiveEqual("short")) - { - description = shortDescription; - } - else if (BaseSettings.BuildDescription.IsCaseInsensitiveEqual("long")) - { - description = fullDescription; - } - else if (BaseSettings.BuildDescription.IsCaseInsensitiveEqual("titleAndShort")) - { - description = productName.Grow(shortDescription, " "); - } - else if (BaseSettings.BuildDescription.IsCaseInsensitiveEqual("titleAndLong")) - { - description = productName.Grow(fullDescription, " "); - } - else if (BaseSettings.BuildDescription.IsCaseInsensitiveEqual("manuAndTitleAndShort")) - { - description = manufacturer.Grow(productName, " "); - description = description.Grow(shortDescription, " "); - } - else if (BaseSettings.BuildDescription.IsCaseInsensitiveEqual("manuAndTitleAndLong")) - { - description = manufacturer.Grow(productName, " "); - description = description.Grow(fullDescription, " "); - } - - if (updateResult != null) - { - description = updateResult(description); - } - - try - { - if (BaseSettings.DescriptionToPlainText) - { - //Regex reg = new Regex("<[^>]+>", RegexOptions.IgnoreCase); - //description = HttpUtility.HtmlDecode(reg.Replace(description, "")); - - description = HtmlUtils.ConvertHtmlToPlainText(description); - description = HtmlUtils.StripTags(HttpUtility.HtmlDecode(description)); - - description = RemoveInvalidFeedChars(description, false); - } - else - { - description = RemoveInvalidFeedChars(description, true); - } - } - catch (Exception exc) - { - exc.Dump(); - } - - return description; - } - - public string GetManufacturerPartNumber(Product product) - { - if (product.ManufacturerPartNumber.HasValue()) - return product.ManufacturerPartNumber; - - if (BaseSettings.UseOwnProductNo) - return product.Sku; - - return ""; - } - - public string GetShippingCost(Product product, decimal? shippingCost = null) - { - if (product.IsFreeShipping) - return "0"; - - decimal cost = shippingCost ?? BaseSettings.ShippingCost; - - if (decimal.Compare(cost, decimal.Zero) == 0) - return ""; - - return cost.FormatInvariant(); - } - - public string GetProductDetailUrl(Store store, Product product) - { - return "{0}{1}".FormatWith(store.Url, product.GetSeName(Language.Id, UrlRecordService, LanguageService)); - } - - public decimal GetProductPrice(Product product, Currency currency) - { - decimal priceBase = PriceCalculationService.GetFinalPrice(product, null, WorkContext.CurrentCustomer, decimal.Zero, true, 1); - - if (BaseSettings.ConvertNetToGrossPrices) - { - decimal taxRate; - priceBase = TaxService.GetProductPrice(product, priceBase, true, WorkContext.CurrentCustomer, out taxRate); - } - - decimal price = ConvertFromStoreCurrency(priceBase, currency); - return price; - } - - public decimal? GetOldPrice(Product product, Currency currency) - { - if (!decimal.Equals(product.OldPrice, decimal.Zero) && !decimal.Equals(product.OldPrice, product.Price) && - !(product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing)) - { - decimal price = product.OldPrice; - - if (BaseSettings.ConvertNetToGrossPrices) - { - decimal taxRate; - price = TaxService.GetProductPrice(product, price, true, WorkContext.CurrentCustomer, out taxRate); - } - - return ConvertFromStoreCurrency(price, currency); - } - return null; - } - - public FeedFileData GetFeedFileByStore(Store store, string secondFileName = null, string extension = null) - { - if (store == null) - return null; - - string dirTemp = AppPath.TempDir(); - string ext = extension ?? BaseSettings.ExportFormat; - string dir = Path.Combine(HttpRuntime.AppDomainAppPath, "Content\\files\\exportimport"); - string fileName = "{0}_{1}".FormatWith(store.Id, BaseSettings.StaticFileName); - string logName = Path.GetFileNameWithoutExtension(fileName) + ".txt"; - - if (ext.HasValue()) - fileName = Path.GetFileNameWithoutExtension(fileName) + (ext.StartsWith(".") ? "" : ".") + ext; - - string url = "{0}content/files/exportimport/".FormatWith(store.Url.EnsureEndsWith("/")); - - if (!(url.StartsWith("http://") || url.StartsWith("https://"))) - url = "http://" + url; - - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - var feedFile = new FeedFileData() - { - StoreId = store.Id, - StoreName = store.Name, - FileTempPath = Path.Combine(dirTemp, fileName), - FilePath = Path.Combine(dir, fileName), - FileUrl = url + fileName, - LogPath = Path.Combine(dir, logName), - LogUrl = url + logName - }; - - try - { - feedFile.LastWriteTime = File.GetLastWriteTimeUtc(feedFile.FilePath).RelativeFormat(true, null); - } - catch (Exception) - { - feedFile.LastWriteTime = feedFile.LastWriteTime.NaIfEmpty(); - } - - if (secondFileName.HasValue()) - { - string fname2 = store.Id + "_" + secondFileName; - feedFile.CustomProperties.Add("SecondFileTempPath", Path.Combine(dirTemp, fname2)); - feedFile.CustomProperties.Add("SecondFilePath", Path.Combine(dir, fname2)); - feedFile.CustomProperties.Add("SecondFileUrl", url + fname2); - } - return feedFile; - } - - public List GetFeedFiles(List stores, string secondFileName = null, string extension = null) - { - var lst = new List(); - - foreach (var store in stores) - { - var feedFile = GetFeedFileByStore(store, secondFileName, extension); - - if (feedFile != null && File.Exists(feedFile.FilePath)) - lst.Add(feedFile); - } - return lst; - } - - public void StartCreatingFeeds(Func createFeed, string secondFileName = null) - { - try - { - _cachedPathes = null; - _cachedCategories = null; - - var storeService = _ctx.Resolve(); - var stores = new List(); - - if (BaseSettings.StoreId != 0) - { - var storeById = storeService.GetStoreById(BaseSettings.StoreId); - if (storeById != null) - stores.Add(storeById); - } - - if (stores.Count == 0) - { - stores.AddRange(storeService.GetAllStores()); - } - - var context = new FeedFileCreationContext() - { - StoreCount = stores.Count, - Progress = new Progress(x => - { - AsyncState.Current.Set(x, SystemName); - }) - }; - - foreach (var store in stores) - { - var feedFile = GetFeedFileByStore(store, secondFileName); - if (feedFile != null) - { - AppPath.Delete(feedFile.FileTempPath); - - if (secondFileName.HasValue()) - AppPath.Delete(feedFile.CustomProperties["SecondFileTempPath"] as string); - - using (var stream = new FileStream(feedFile.FileTempPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (var logger = new TraceLogger(feedFile.LogPath)) - { - context.Stream = stream; - context.Logger = logger; - context.Store = store; - context.FeedFileUrl = feedFile.FileUrl; - - if (secondFileName.HasValue()) - context.SecondFilePath = feedFile.CustomProperties["SecondFileTempPath"] as string; - - if (!createFeed(context)) - break; - } - - AppPath.Copy(feedFile.FileTempPath, feedFile.FilePath); - - if (secondFileName.HasValue()) - AppPath.Copy(context.SecondFilePath, feedFile.CustomProperties["SecondFilePath"] as string); - } - } - } - finally - { - AsyncState.Current.Remove(SystemName); - } - } - - public void DeleteFeedFiles(string secondFileName = null) - { - try - { - var extensions = new List() { "xml", "csv" }; - - if (!extensions.Contains(BaseSettings.ExportFormat)) - extensions.Add(BaseSettings.ExportFormat); - - var storeService = _ctx.Resolve(); - var stores = storeService.GetAllStores(); - - foreach (var store in stores) - { - foreach (var ext in extensions) - { - var feedFile = GetFeedFileByStore(store, secondFileName, ext); - if (feedFile != null) - { - AppPath.Delete(feedFile.FileTempPath); - AppPath.Delete(feedFile.FilePath); - AppPath.Delete(feedFile.LogPath); - - if (secondFileName.HasValue()) - { - AppPath.Delete(feedFile.CustomProperties["SecondFilePath"] as string); - AppPath.Delete(feedFile.CustomProperties["SecondFileTempPath"] as string); - } - } - } - } - } - catch (Exception exc) - { - Notifier.Error(exc.Message); - } - } - - public string GetMainProductImageUrl(Store store, Product product) - { - string url; - var pictureService = PictureService; - var picture = product.GetDefaultProductPicture(pictureService); - - //always use HTTP when getting image URL - if (picture != null) - url = pictureService.GetPictureUrl(picture, BaseSettings.ProductPictureSize, storeLocation: store.Url); - else - url = pictureService.GetDefaultPictureUrl(BaseSettings.ProductPictureSize, storeLocation: store.Url); - - return url; - } - - public List GetAdditionalProductImages(Store store, Product product, string mainImageUrl, int maxImages = 10) - { - var urls = new List(); - - if (BaseSettings.AdditionalImages) - { - var pictureService = PictureService; - var pics = pictureService.GetPicturesByProductId(product.Id, 0); - - foreach (var pic in pics) - { - if (pic != null) - { - string url = pictureService.GetPictureUrl(pic, BaseSettings.ProductPictureSize, storeLocation: store.Url); - - if (url.HasValue() && (mainImageUrl.IsNullOrEmpty() || !mainImageUrl.IsCaseInsensitiveEqual(url))) - { - urls.Add(url); - if (urls.Count >= maxImages) - break; - } - } - } - } - return urls; - } - - public void GetQualifiedProductsByProduct(Product product, Store store, List result) - { - result.Clear(); - - if (product.ProductType == ProductType.SimpleProduct || product.ProductType == ProductType.BundledProduct) - { - result.Add(product); - } - else if (product.ProductType == ProductType.GroupedProduct) - { - var associatedSearchContext = new ProductSearchContext() - { - OrderBy = ProductSortingEnum.CreatedOn, - PageSize = int.MaxValue, - StoreId = store.Id, - VisibleIndividuallyOnly = false, - ParentGroupedProductId = product.Id - }; - - var productService = ProductService; - - result.AddRange(productService.SearchProducts(associatedSearchContext)); - } - } - - internal string LookupCategoryPath(int id) - { - if (_cachedPathes.ContainsKey(id)) - { - return _cachedPathes[id]; - } - return null; - } - - internal void AddPathToCache(int id, string value) - { - _cachedPathes[id] = value; - } - - internal Category LookupCategory(int id) - { - if (_cachedCategories.ContainsKey(id)) - { - return _cachedCategories[id]; - } - return null; - } - - public string GetCategoryPath(Product product) - { - var categoryService = CategoryService; - - if (_cachedPathes == null) - { - _cachedPathes = new Dictionary(); - } - - if (_cachedCategories == null) - { - var allCategories = categoryService.GetAllCategories(showHidden: true, applyNavigationFilters: false); - _cachedCategories = allCategories.ToDictionary(x => x.Id); - } - - string path = categoryService.GetCategoryPath(product, null, LookupCategoryPath, AddPathToCache, (i) => LookupCategory(i) ?? categoryService.GetCategoryById(i)); - - return path; - } - - public void UpdateScheduleTask(bool enabled, int seconds) - { - var task = ScheduleTask; - if (task != null) - { - task.Enabled = enabled; - task.Seconds = seconds; - - ScheduleTaskService.UpdateTask(task); - } - } - - public void InsertScheduleTask(int minutes = 360) - { - var task = ScheduleTask; - if (task == null) - { - ScheduleTaskService.InsertTask(new ScheduleTask - { - Name = "{0} feed file generation".FormatWith(SystemName), - Seconds = minutes * 60, - Type = ScheduleTaskType, - Enabled = false, - StopOnError = false, - }); - } - } - - public void DeleteScheduleTask() - { - var task = ScheduleTask; - if (task != null) - ScheduleTaskService.DeleteTask(task); - } - - public bool RunScheduleTask() - { - if (ScheduleTask.IsRunning) - { - Notifier.Information(GetProgressInfo()); - return true; - } - - string scheduleTaskType = ScheduleTaskType; - - var task = AsyncRunner.Run(container => - { - try - { - var svc = container.Resolve(); - - var scheduleTask = svc.GetTaskByType(scheduleTaskType); - - if (scheduleTask == null) - throw new Exception("Schedule task cannot be loaded"); - - var job = new Job(scheduleTask); - job.Enabled = true; - job.Execute(container, false); - } - catch (Exception exc) - { - exc.Dump(); - - try - { - _scheduleTaskService.EnsureTaskIsNotRunning(scheduleTaskType); - } - catch (Exception) { } - } - }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); - - task.Wait(100); - - if (task.IsCompleted) - { - if (!task.IsFaulted) - { - Notifier.Success(GetResource("Admin.System.ScheduleTasks.RunNow.Completed")); - } - else - { - var exc = task.Exception.Flatten().InnerException; - Notifier.Error(exc.Message); - Logger.Error(exc.Message, exc); - } - } - else - { - Notifier.Information(GetResource("Admin.System.ScheduleTasks.RunNow.Progress")); - return true; - } - return false; - } - - public string GetProgressInfo(bool checkIfRunnning = false) - { - if (checkIfRunnning) - { - var task = ScheduleTask; - if (task != null && !task.IsRunning) - return ""; - } - - string result = GetResource("Admin.System.ScheduleTasks.RunNow.Progress"); - - try - { - var progress = AsyncState.Current.Get(SystemName); - - if (progress != null) - { - int percent = (int)progress.ProcessedPercent; - - if (percent > 0 && percent <= 100) - result = "{0}... {1}%".FormatWith(result, percent); - } - } - catch (Exception) { } - - return result; - } - - public void SetupConfigModel(PromotionFeedConfigModel model, string controller, string secondFileName = null, string[] extensions = null) - { - var storeService = _ctx.Resolve(); - var stores = storeService.GetAllStores().ToList(); - - var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext); - var routeValues = new { Namespaces = _namespace + ".Controllers"/*, area = ""*/ }; - - model.GenerateFeedUrl = urlHelper.Action("GenerateFeed", controller, routeValues); - model.GenerateFeedProgressUrl = urlHelper.Action("GenerateFeedProgress", controller, routeValues); - model.DeleteFilesUrl = urlHelper.Action("DeleteFiles", controller, routeValues); - - model.Helper = this; - model.AvailableStores = new List(); - model.AvailableStores.Add(new SelectListItem() { Text = GetResource("Admin.Common.All"), Value = "0" }); - model.AvailableStores.AddRange(stores.ToSelectListItems()); - - model.AvailableLanguages = new List(); - model.AvailableLanguages.Add(new SelectListItem() { Text = GetResource("Admin.Common.Standard"), Value = "0" }); - - foreach (var language in LanguageService.GetAllLanguages()) - { - model.AvailableLanguages.Add(new SelectListItem() - { - Text = language.Name, - Value = language.Id.ToString() - }); - } - - if (!model.IsRunning) - model.IsRunning = (ScheduleTask != null && ScheduleTask.IsRunning); - - if (model.IsRunning) - { - model.ProcessInfo = GetProgressInfo(); - } - else - { - if (extensions != null) - { - foreach (var ext in extensions) - model.GeneratedFiles.AddRange(GetFeedFiles(stores, null, ext)); - } - else - { - model.GeneratedFiles = GetFeedFiles(stores, secondFileName); - } - } - } - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginDebugViewVirtualPathProvider.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginDebugViewVirtualPathProvider.cs index 862eb9319b..4b0bba6a21 100644 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginDebugViewVirtualPathProvider.cs +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginDebugViewVirtualPathProvider.cs @@ -12,7 +12,7 @@ namespace SmartStore.Web.Framework.Plugins { public class PluginDebugViewVirtualPathProvider : VirtualPathProvider { - private readonly ConcurrentDictionary _cachedDebugViewPaths = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary _cachedDebugFilePaths = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private readonly DirectoryInfo _pluginsDebugDir; public PluginDebugViewVirtualPathProvider() @@ -34,12 +34,13 @@ public override bool FileExists(string virtualPath) public override VirtualFile GetFile(string virtualPath) { - if (!IsPluginViewPath(virtualPath)) + string appRelativePath; + if (!IsPluginPath(virtualPath, out appRelativePath)) { return Previous.GetFile(virtualPath); } - string debugPath = ResolveDebugViewPath(virtualPath); + string debugPath = ResolveDebugFilePath(appRelativePath); return debugPath != null ? new DebugPluginVirtualFile(virtualPath, debugPath) : Previous.GetFile(virtualPath); @@ -47,12 +48,13 @@ public override VirtualFile GetFile(string virtualPath) public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart) { - if (!IsPluginViewPath(virtualPath)) + string appRelativePath; + if (!IsPluginPath(virtualPath, out appRelativePath)) { return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); } - string debugPath = ResolveDebugViewPath(virtualPath); + string debugPath = ResolveDebugFilePath(appRelativePath); return debugPath != null ? new CacheDependency(debugPath) : Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart); @@ -60,28 +62,29 @@ public override CacheDependency GetCacheDependency(string virtualPath, IEnumerab public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies) { - if (!IsPluginViewPath(virtualPath)) + string appRelativePath; + if (!IsPluginPath(virtualPath, out appRelativePath)) { return Previous.GetFileHash(virtualPath, virtualPathDependencies); } - string debugPath = ResolveDebugViewPath(virtualPath); + string debugPath = ResolveDebugFilePath(appRelativePath); return debugPath != null ? File.GetLastWriteTime(debugPath).ToString() : Previous.GetFileHash(virtualPath, virtualPathDependencies); } - private string ResolveDebugViewPath(string virtualPath) + private string ResolveDebugFilePath(string appRelativePath) { - return _cachedDebugViewPaths.GetOrAdd(virtualPath, FindDebugView); + return _cachedDebugFilePaths.GetOrAdd(appRelativePath, FindDebugFile); } - private string FindDebugView(string virtualPath) + private string FindDebugFile(string appRelativePath) { if (_pluginsDebugDir == null) return null; - var unrooted = virtualPath.Substring(9); // strip "/Plugins/" + var unrooted = appRelativePath.Substring(10); // strip "~/Plugins/" string area = unrooted.Substring(0, unrooted.IndexOf('/')); var pluginDir = _pluginsDebugDir.EnumerateDirectories("*{0}*".FormatInvariant(area), SearchOption.TopDirectoryOnly).FirstOrDefault(); @@ -96,11 +99,10 @@ private string FindDebugView(string virtualPath) return null; } - private static bool IsPluginViewPath(string virtualPath) + private static bool IsPluginPath(string virtualPath, out string appRelativePath) { - var result = virtualPath.StartsWith("/Plugins/", StringComparison.InvariantCultureIgnoreCase) - && virtualPath.Contains("/Views/") - && virtualPath.EndsWith(".cshtml", StringComparison.InvariantCultureIgnoreCase); + appRelativePath = VirtualPathUtility.ToAppRelative(virtualPath); + var result = appRelativePath.StartsWith("~/Plugins/", StringComparison.InvariantCultureIgnoreCase); return result; } diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginExtensions.cs new file mode 100644 index 0000000000..0925a59f65 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginExtensions.cs @@ -0,0 +1,32 @@ +using System; +using SmartStore.Core.Plugins; +using SmartStore.Services.Configuration; + +namespace SmartStore.Web.Framework +{ + public static class PluginExtensions + { + /// + /// Determines whether a plugin is installed and activated for a particular store. + /// + public static bool IsPluginReady(this IPluginFinder pluginFinder, ISettingService settingService, string systemName, int storeId) + { + try + { + var pluginDescriptor = pluginFinder.GetPluginDescriptorBySystemName(systemName); + + if (pluginDescriptor != null && pluginDescriptor.Installed) + { + if (storeId == 0 || settingService.GetSettingByKey(pluginDescriptor.GetSettingKey("LimitedToStores")).ToIntArrayContains(storeId, true)) + return true; + } + } + catch (Exception exc) + { + exc.Dump(); + } + + return false; + } + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs deleted file mode 100644 index 1fe82b3593..0000000000 --- a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginHelper.cs +++ /dev/null @@ -1,233 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.IO; -using System.Linq; -using System.Text; -using System.Web.Mvc; -using System.Xml; -using SmartStore.Core; -using SmartStore.Core.Domain.Directory; -using SmartStore.Core.Domain.Localization; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Plugins; -using SmartStore.Services.Directory; -using SmartStore.Services.Localization; -using Autofac; -using SmartStore.Utilities; - -namespace SmartStore.Web.Framework.Plugins -{ - public partial class PluginHelper - { - protected readonly IComponentContext _ctx; - private PluginDescriptor _plugin; - private string _interfaceVersion; - private Language _language; - private int? _currencyID; - private string _currencyCode; - private Currency _euroCurrency; - private Dictionary _resMap = new Dictionary(); - - public PluginHelper(IComponentContext componentContext, string systemName) - { - SystemName = systemName; - _ctx = componentContext; - } - - public static string NotSpecified - { - get - { - return "__nospec__"; // explicitly do not set a field - } - } - - public string SystemName { get; set; } - - public PluginDescriptor Plugin - { - get - { - if (_plugin == null) - { - _plugin = _ctx.Resolve().GetPluginDescriptorBySystemName(SystemName); - } - return _plugin; - } - } - - public string InterfaceVersion - { - get - { - if (_interfaceVersion == null) - { - _interfaceVersion = "{0}_v{1}".FormatWith(CommonHelper.GetAppSetting("sm:ApplicationName"), Plugin.Version); - } - return _interfaceVersion; - } - } - - public Language Language - { - get - { - if (_language == null) - { - _language = _ctx.Resolve().WorkingLanguage; - } - return _language; - } - } - - public bool IsLanguageGerman - { - get - { - return Language.UniqueSeoCode.IsCaseInsensitiveEqual("DE"); - } - } - - public int CurrencyID - { - get - { - if (!_currencyID.HasValue) - { - _currencyID = _ctx.Resolve().PrimaryStoreCurrencyId; - } - return _currencyID ?? 1; - } - } - - public string CurrencyCode - { - get - { - try - { - if (_currencyCode == null) - { - _currencyCode = _ctx.Resolve().WorkingCurrency.CurrencyCode; - } - } - catch (Exception) - { - } - return _currencyCode ?? "EUR"; - } - } - - public Currency EuroCurrency - { - get - { - if (_euroCurrency == null) - { - _euroCurrency = _ctx.Resolve().GetCurrencyByCode("EUR"); - } - return _euroCurrency; - } - } - - public string GetResource(string keyOrShortKey) - { - string res = ""; - try - { - if (keyOrShortKey.HasValue()) - { - if (!keyOrShortKey.Contains('.')) - { - if (Plugin.ResourceRootKey.HasValue()) - { - keyOrShortKey = "{0}.{1}".FormatWith(Plugin.ResourceRootKey, keyOrShortKey); - } - else - { - keyOrShortKey = "Plugins.{0}.{1}".FormatWith(SystemName, keyOrShortKey); - } - } - - if (_resMap.ContainsKey(keyOrShortKey)) - { - return _resMap[keyOrShortKey]; - } - - res = _ctx.Resolve().GetResource(keyOrShortKey); - - if (res.IsNullOrEmpty()) - res = keyOrShortKey; - - _resMap.Add(keyOrShortKey, res); - } - } - catch (Exception exc) - { - exc.Dump(); - } - return res; - } - - public XmlDocument CreateXmlDocument(Func content) - { - XmlDocument doc = null; - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = new UTF8Encoding(false); - - using (MemoryStream ms = new MemoryStream()) - { - using (XmlWriter xw = XmlWriter.Create(ms, settings)) - { - if (content(xw)) - { - xw.Flush(); - - doc = new XmlDocument(); - doc.LoadXml(Encoding.UTF8.GetString(ms.ToArray())); - } - - xw.Close(); - ms.Close(); - return doc; - } - } - } - - public Currency GetUsedCurrency(int currencyId) - { - var currencyService = _ctx.Resolve(); - var currency = currencyService.GetCurrencyById(currencyId); - - if (currency == null || !currency.Published) - { - currency = currencyService.GetCurrencyById(CurrencyID); - } - - return currency; - } - - public decimal ConvertFromStoreCurrency(decimal price, Currency currency) - { - return _ctx.Resolve().ConvertFromPrimaryStoreCurrency(price, currency); - } - - public List AvailableCurrencies() - { - var lst = new List(); - var allCurrencies = _ctx.Resolve().GetAllCurrencies(false); - - foreach (var c in allCurrencies) - { - lst.Add(new SelectListItem() - { - Text = c.Name, - Value = c.Id.ToString() - }); - } - return lst; - } - - } -} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/PluginMediator.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginMediator.cs new file mode 100644 index 0000000000..d6dbf04906 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/PluginMediator.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Linq; +using System.Linq.Expressions; +using System.Web.Routing; +using Autofac; +using SmartStore.Core.Domain.Cms; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Localization; +using SmartStore.Core.Plugins; +using SmartStore.Services; +using SmartStore.Services.Cms; +using SmartStore.Services.Localization; +using SmartStore.Utilities; + +namespace SmartStore.Web.Framework.Plugins +{ + public class PluginMediator + { + private static readonly ConcurrentDictionary _routesCache = new ConcurrentDictionary(); + private readonly ICommonServices _services; + private readonly IComponentContext _ctx; + + public PluginMediator(ICommonServices services, IComponentContext ctx) + { + this._services = services; + this._ctx = ctx; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + public string GetLocalizedFriendlyName(ProviderMetadata metadata, int languageId = 0, bool returnDefaultValue = true) + { + return GetLocalizedValue(metadata, "FriendlyName", x => x.FriendlyName, languageId, returnDefaultValue); + } + + public string GetLocalizedDescription(ProviderMetadata metadata, int languageId = 0, bool returnDefaultValue = true) + { + return GetLocalizedValue(metadata, "Description", x => x.Description, languageId, returnDefaultValue); + } + + public string GetLocalizedValue(ProviderMetadata metadata, + string propertyName, + Expression> fallback, + int languageId = 0, + bool returnDefaultValue = true) + { + Guard.ArgumentNotNull(() => metadata); + + string systemName = metadata.SystemName; + var resourceName = metadata.ResourceKeyPattern.FormatInvariant(metadata.SystemName, propertyName); + string result = _services.Localization.GetResource(resourceName, languageId, false, "", true); + + if (result.IsEmpty() && returnDefaultValue) + result = fallback.Compile()(metadata); + + return result; + } + + public void SaveLocalizedValue(ProviderMetadata metadata, int languageId, string propertyName, string value) + { + Guard.ArgumentNotNull(() => metadata); + Guard.ArgumentIsPositive(languageId, "languageId"); + Guard.ArgumentNotEmpty(() => propertyName); + + var resourceName = metadata.ResourceKeyPattern.FormatInvariant(metadata.SystemName, propertyName); + var resource = _services.Localization.GetLocaleStringResourceByName(resourceName, languageId, false); + + if (resource != null) + { + if (value.IsEmpty()) + { + // delete + _services.Localization.DeleteLocaleStringResource(resource); + } + else + { + // update + resource.ResourceValue = value; + _services.Localization.UpdateLocaleStringResource(resource); + } + _services.Localization.ClearCache(); + } + else + { + if (value.HasValue()) + { + // insert + resource = new LocaleStringResource() + { + LanguageId = languageId, + ResourceName = resourceName, + ResourceValue = value, + }; + _services.Localization.InsertLocaleStringResource(resource); + _services.Localization.ClearCache(); + } + } + } + + public int? GetUserDisplayOrder(ProviderMetadata metadata) + { + return GetSetting(metadata, "DisplayOrder"); + } + + public T GetSetting(ProviderMetadata metadata, string propertyName) + { + var settingKey = metadata.SettingKeyPattern.FormatInvariant(metadata.SystemName, propertyName); + return _services.Settings.GetSettingByKey(settingKey); + } + + public void SetUserDisplayOrder(ProviderMetadata metadata, int displayOrder) + { + Guard.ArgumentNotNull(() => metadata); + + metadata.DisplayOrder = displayOrder; + SetSetting(metadata, "DisplayOrder", displayOrder); + } + + public void SetSetting(ProviderMetadata metadata, string propertyName, T value) + { + Guard.ArgumentNotNull(() => metadata); + Guard.ArgumentNotEmpty(() => propertyName); + + var settingKey = metadata.SettingKeyPattern.FormatInvariant(metadata.SystemName, propertyName); + + if (value != null) + { + _services.Settings.SetSetting(settingKey, value, 0, false); + } + else + { + _services.Settings.DeleteSetting(settingKey); + } + + _services.Settings.ClearCache(); + } + + public ProviderModel ToProviderModel(Provider provider, bool forEdit = false, Action, ProviderModel> enhancer = null) + { + return ToProviderModel(provider, forEdit, enhancer); + } + + public TModel ToProviderModel(Provider provider, bool forEdit = false, Action, TModel> enhancer = null) + where TModel : ProviderModel, new() + where TProvider : IProvider + { + Guard.ArgumentNotNull(() => provider); + + var metadata = provider.Metadata; + var model = new TModel(); + model.ProviderType = typeof(TProvider); + model.SystemName = metadata.SystemName; + model.FriendlyName = forEdit ? metadata.FriendlyName : GetLocalizedFriendlyName(metadata); + model.Description = forEdit ? metadata.Description : GetLocalizedDescription(metadata); + model.DisplayOrder = metadata.DisplayOrder; + model.IsEditable = metadata.IsEditable; + model.IconUrl = GetIconUrl(metadata); + model.PluginDescriptor = metadata.PluginDescriptor; + if (model.PluginDescriptor != null) + { + model.ProvidingPluginFriendlyName = model.PluginDescriptor.GetLocalizedValue(_services.Localization, "FriendlyName"); + } + + if (metadata.IsConfigurable) + { + var routeInfo = _routesCache.GetOrAdd(model.SystemName, (key) => + { + string actionName, controllerName; + RouteValueDictionary routeValues; + var configurable = (IConfigurable)provider.Value; + configurable.GetConfigurationRoute(out actionName, out controllerName, out routeValues); + + if (actionName.IsEmpty()) + { + metadata.IsConfigurable = false; + return null; + } + else + { + return new RouteInfo(actionName, controllerName, routeValues); + } + }); + + if (routeInfo != null) + { + model.ConfigurationRoute = new RouteInfo(routeInfo); + } + } + + if (enhancer != null) + { + enhancer(provider, model); + } + + model.IsConfigurable = metadata.IsConfigurable; + + return model; + } + + public string GetBrandImageUrl(ProviderMetadata metadata) + { + var plugin = metadata.PluginDescriptor; + + if (plugin != null) + { + var filesToCheck = (new string[] { "branding.{0}.png", "branding.{0}.gif", "branding.{0}.jpg", "branding.{0}.jpeg" }).Select(x => x.FormatInvariant(metadata.SystemName)); + var dir = plugin.PhysicalPath; + foreach (var file in filesToCheck) + { + if (File.Exists(Path.Combine(dir, "Content", file))) + { + return "~/Plugins/{0}/Content/{1}".FormatInvariant(plugin.SystemName, file); + } + } + + var fallback = plugin.BrandImageFileName; + if (fallback.HasValue()) + { + return "~/Plugins/{0}/Content/{1}".FormatInvariant(plugin.SystemName, fallback); + } + } + + return null; + } + + public string GetIconUrl(ProviderMetadata metadata) + { + var plugin = metadata.PluginDescriptor; + + if (plugin == null) + { + return GetDefaultIconUrl(metadata.GroupName); + } + + return GetIconUrl(plugin, metadata.SystemName); + } + + /// + /// Returns the absolute path of a plugin/provider icon + /// + /// The plugin descriptor. Used to resolve the physical path + /// Optional system name of provider. If passed, an icon with this name gets being tried to resolve first. + /// The icon's absolute path + public string GetIconUrl(PluginDescriptor plugin, string providerSystemName = null) + { + //var cacheKey = new Tuple(plugin, providerSystemName); + + if (providerSystemName.HasValue()) + { + if (File.Exists(Path.Combine(plugin.PhysicalPath, "Content", "icon-{0}.png".FormatInvariant(providerSystemName)))) + { + return "~/Plugins/{0}/Content/icon-{1}.png".FormatInvariant(plugin.SystemName, providerSystemName); + } + } + + if (File.Exists(Path.Combine(plugin.PhysicalPath, "Content", "icon.png"))) + { + return "~/Plugins/{0}/Content/icon.png".FormatInvariant(plugin.SystemName); + } + else + { + return GetDefaultIconUrl(plugin.Group); + } + } + + public string GetDefaultIconUrl(string groupName) + { + if (groupName.HasValue()) + { + string path = "~/Administration/Content/images/icon-plugin-{0}.png".FormatInvariant(groupName.ToLower()); + if (File.Exists(CommonHelper.MapPath(path, false))) + { + return path; + } + } + + return "~/Administration/Content/images/icon-plugin-default.png"; + } + + public void ActivateDependentWidgets(ProviderMetadata parent, bool activate) + { + Guard.ArgumentNotNull(() => parent); + + if (parent.DependentWidgets == null || parent.DependentWidgets.Length == 0) + return; + + foreach (var systemName in parent.DependentWidgets) + { + var widget = _ctx.ResolveOptionalNamed>(systemName); + if (widget != null) + { + var widgetSettings = _ctx.Resolve(); + + if (widget.IsWidgetActive(widgetSettings)) + { + if (!activate) + { + widgetSettings.ActiveWidgetSystemNames.Remove(systemName); + _services.Settings.SaveSetting(widgetSettings); + } + } + else + { + if (activate) + { + widgetSettings.ActiveWidgetSystemNames.Add(systemName); + _services.Settings.SaveSetting(widgetSettings); + } + } + } + } + } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/ProviderManager.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/ProviderManager.cs new file mode 100644 index 0000000000..9d2de00ebf --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/ProviderManager.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autofac; +using SmartStore.Core.Plugins; +using SmartStore.Services; + +namespace SmartStore.Web.Framework.Plugins +{ + + public partial class ProviderManager : IProviderManager + { + private readonly IComponentContext _ctx; + private readonly ICommonServices _services; + private readonly PluginMediator _pluginMediator; + + public ProviderManager(IComponentContext ctx, ICommonServices services, PluginMediator pluginMediator) + { + this._ctx = ctx; + this._services = services; + this._pluginMediator = pluginMediator; + } + + public Provider GetProvider(string systemName, int storeId = 0) where TProvider : IProvider + { + if (systemName.IsEmpty()) + return null; + + var provider = _ctx.ResolveOptionalNamed>(systemName); + if (provider != null) + { + if (storeId > 0) + { + var d = provider.Metadata.PluginDescriptor; + if (d != null && !IsActiveForStore(d, storeId)) + { + return null; + } + } + SetUserData(provider.Metadata); + return new Provider(provider); + } + return null; + } + + public Provider GetProvider(string systemName, int storeId = 0) + { + Guard.ArgumentNotEmpty(() => systemName); + + var provider = _ctx.ResolveOptionalNamed>(systemName); + if (provider != null) + { + if (storeId > 0) + { + var d = provider.Metadata.PluginDescriptor; + if (d != null && !IsActiveForStore(d, storeId)) + { + return null; + } + } + SetUserData(provider.Metadata); + return new Provider(provider); + } + return null; + } + + public IEnumerable> GetAllProviders(int storeId = 0) where TProvider : IProvider + { + var providers = _ctx.Resolve>>(); + if (storeId > 0) + { + providers = from p in providers + let d = p.Metadata.PluginDescriptor + where d == null || IsActiveForStore(d, storeId) + select p; + } + return SortProviders(providers.Select(x => new Provider(x))); + } + + public IEnumerable> GetAllProviders(int storeId = 0) + { + var providers = _ctx.Resolve>>(); + if (storeId > 0) + { + providers = from p in providers + let d = p.Metadata.PluginDescriptor + where d == null || IsActiveForStore(d, storeId) + select p; + } + return SortProviders(providers.Select(x => new Provider(x))); + } + + protected virtual IEnumerable> SortProviders(IEnumerable> providers) where TProvider : IProvider + { + foreach (var m in providers.Select(x => x.Metadata)) + { + SetUserData(m); + } + + return providers.OrderBy(x => x.Metadata.DisplayOrder).ThenBy(x => x.Metadata.FriendlyName); + } + + protected virtual void SetUserData(ProviderMetadata metadata) + { + if (!metadata.IsEditable) + return; + + var displayOrder = _pluginMediator.GetUserDisplayOrder(metadata); + var name = _pluginMediator.GetSetting(metadata, "FriendlyName"); + var description = _pluginMediator.GetSetting(metadata, "Description"); + metadata.FriendlyName = name; + metadata.Description = description; + + if (displayOrder.HasValue) + { + metadata.DisplayOrder = displayOrder.Value; + } + } + + private bool IsActiveForStore(PluginDescriptor plugin, int storeId) + { + if (storeId == 0) + { + return true; + } + + var limitedToStoresSetting = _services.Settings.GetSettingByKey(plugin.GetSettingKey("LimitedToStores")); + if (limitedToStoresSetting.IsEmpty()) + { + return true; + } + + var limitedToStores = limitedToStoresSetting.ToIntArray(); + if (limitedToStores.Length > 0) + { + var flag = limitedToStores.Contains(storeId); + return flag; + } + + return true; + } + + } + +} diff --git a/src/Presentation/SmartStore.Web.Framework/Plugins/ProviderModel.cs b/src/Presentation/SmartStore.Web.Framework/Plugins/ProviderModel.cs new file mode 100644 index 0000000000..fa02cb9798 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Plugins/ProviderModel.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Core.Plugins; +using SmartStore.Services.Payments; +using SmartStore.Web.Framework.Localization; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Web.Framework.Plugins +{ + public class ProviderModel : ModelBase, ILocalizedModel + { + private IList _locales; + + public Type ProviderType { get; set; } + + [SmartResourceDisplayName("Common.SystemName")] + public string SystemName { get; set; } + + [SmartResourceDisplayName("Common.FriendlyName")] + [AllowHtml] + public string FriendlyName { get; set; } + + [SmartResourceDisplayName("Common.Description")] + [AllowHtml] + public string Description { get; set; } + + [SmartResourceDisplayName("Common.DisplayOrder")] + public int DisplayOrder { get; set; } + + public bool IsEditable { get; set; } + + public bool IsConfigurable { get; set; } + + public RouteInfo ConfigurationRoute { get; set; } + + public PluginDescriptor PluginDescriptor { get; set; } + + [SmartResourceDisplayName("Admin.Providers.ProvidingPlugin")] + public string ProvidingPluginFriendlyName { get; set; } + + /// + /// Returns the absolute path of the provider's icon url. + /// + /// + /// The parent plugin's icon url is returned as a fallback, if provider icon cannot be resolved. + /// + public string IconUrl { get; set; } + + public IList Locales + { + get + { + if (_locales == null) + { + _locales = new List(); + } + return _locales; + } + set + { + _locales = value; + } + } + + public bool IsPaymentMethod + { + get + { + return ProviderType == typeof(IPaymentMethod); + } + } + } + + public class ProviderLocalizedModel : ILocalizedModelLocal + { + public int LanguageId { get; set; } + + [SmartResourceDisplayName("Common.FriendlyName")] + [AllowHtml] + public string FriendlyName { get; set; } + + [SmartResourceDisplayName("Common.Description")] + [AllowHtml] + public string Description { get; set; } + } + +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/GuidConstraint.cs b/src/Presentation/SmartStore.Web.Framework/Routing/GuidConstraint.cs similarity index 95% rename from src/Presentation/SmartStore.Web.Framework/Mvc/Routes/GuidConstraint.cs rename to src/Presentation/SmartStore.Web.Framework/Routing/GuidConstraint.cs index 94ce78d9ec..105fceb0b1 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/GuidConstraint.cs +++ b/src/Presentation/SmartStore.Web.Framework/Routing/GuidConstraint.cs @@ -2,7 +2,7 @@ using System.Web; using System.Web.Routing; -namespace SmartStore.Web.Framework.Mvc.Routes +namespace SmartStore.Web.Framework.Routing { public class GuidConstraint : IRouteConstraint { diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/IRouteProvider.cs b/src/Presentation/SmartStore.Web.Framework/Routing/IRouteProvider.cs similarity index 78% rename from src/Presentation/SmartStore.Web.Framework/Mvc/Routes/IRouteProvider.cs rename to src/Presentation/SmartStore.Web.Framework/Routing/IRouteProvider.cs index 52acddf5c0..164f01e62f 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/IRouteProvider.cs +++ b/src/Presentation/SmartStore.Web.Framework/Routing/IRouteProvider.cs @@ -1,6 +1,6 @@ using System.Web.Routing; -namespace SmartStore.Web.Framework.Mvc.Routes +namespace SmartStore.Web.Framework.Routing { public interface IRouteProvider { diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/IRoutePublisher.cs b/src/Presentation/SmartStore.Web.Framework/Routing/IRoutePublisher.cs similarity index 75% rename from src/Presentation/SmartStore.Web.Framework/Mvc/Routes/IRoutePublisher.cs rename to src/Presentation/SmartStore.Web.Framework/Routing/IRoutePublisher.cs index 427e6acdd5..6cda18243c 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/IRoutePublisher.cs +++ b/src/Presentation/SmartStore.Web.Framework/Routing/IRoutePublisher.cs @@ -1,6 +1,6 @@ using System.Web.Routing; -namespace SmartStore.Web.Framework.Mvc.Routes +namespace SmartStore.Web.Framework.Routing { public interface IRoutePublisher { diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/RoutePublisher.cs b/src/Presentation/SmartStore.Web.Framework/Routing/RoutePublisher.cs similarity index 89% rename from src/Presentation/SmartStore.Web.Framework/Mvc/Routes/RoutePublisher.cs rename to src/Presentation/SmartStore.Web.Framework/Routing/RoutePublisher.cs index 70301b00ab..60191958db 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/Routes/RoutePublisher.cs +++ b/src/Presentation/SmartStore.Web.Framework/Routing/RoutePublisher.cs @@ -3,10 +3,8 @@ using System.Linq; using System.Web.Routing; using SmartStore.Core.Infrastructure; -using SmartStore.Core.Plugins; -using SmartStore.Web.Framework.Localization; -namespace SmartStore.Web.Framework.Mvc.Routes +namespace SmartStore.Web.Framework.Routing { public class RoutePublisher : IRoutePublisher { diff --git a/src/Presentation/SmartStore.Web.Framework/Controllers/AdminAuthorizeAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Security/AdminAuthorizeAttribute.cs similarity index 91% rename from src/Presentation/SmartStore.Web.Framework/Controllers/AdminAuthorizeAttribute.cs rename to src/Presentation/SmartStore.Web.Framework/Security/AdminAuthorizeAttribute.cs index 3a0595f129..be10229626 100644 --- a/src/Presentation/SmartStore.Web.Framework/Controllers/AdminAuthorizeAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Security/AdminAuthorizeAttribute.cs @@ -2,15 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; -using SmartStore.Core.Infrastructure; using SmartStore.Services.Security; -namespace SmartStore.Web.Framework.Controllers +namespace SmartStore.Web.Framework.Security { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=true)] public class AdminAuthorizeAttribute : FilterAttribute, IAuthorizationFilter { - public IPermissionService PermissionService { get; set; } private void HandleUnauthorizedRequest(AuthorizationContext filterContext) @@ -50,7 +48,7 @@ public void OnAuthorization(AuthorizationContext filterContext) public virtual bool HasAdminAccess(AuthorizationContext filterContext) { - bool result = PermissionService.Authorize(StandardPermissionProvider.AccessAdminPanel); + var result = PermissionService.Authorize(StandardPermissionProvider.AccessAdminPanel); return result; } } diff --git a/src/Presentation/SmartStore.Web.Framework/Security/FilePermissionHelper.cs b/src/Presentation/SmartStore.Web.Framework/Security/FilePermissionHelper.cs index 3070f18b28..74e63cfc0b 100644 --- a/src/Presentation/SmartStore.Web.Framework/Security/FilePermissionHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Security/FilePermissionHelper.cs @@ -154,20 +154,14 @@ public static IEnumerable GetDirectoriesWrite(IWebHelper webHelper) { string rootDir = webHelper.MapPath("~/"); var dirsToCheck = new List(); - //dirsToCheck.Add(rootDir); dirsToCheck.Add(Path.Combine(rootDir, "App_Data")); - //dirsToCheck.Add(Path.Combine(rootDir, "App_Data\\files")); - //dirsToCheck.Add(Path.Combine(rootDir, "App_Data\\files\\exportimport")); dirsToCheck.Add(Path.Combine(rootDir, "bin")); dirsToCheck.Add(Path.Combine(rootDir, "content")); dirsToCheck.Add(Path.Combine(rootDir, "content\\files\\exportimport")); - //dirsToCheck.Add(Path.Combine(rootDir, "content\\images")); - //dirsToCheck.Add(Path.Combine(rootDir, "content\\images\\thumbs")); - //dirsToCheck.Add(Path.Combine(rootDir, "content\\images\\uploaded")); + dirsToCheck.Add(Path.Combine(rootDir, "Exchange")); dirsToCheck.Add(Path.Combine(rootDir, "media")); dirsToCheck.Add(Path.Combine(rootDir, "media\\thumbs")); dirsToCheck.Add(Path.Combine(rootDir, "media\\uploaded")); - //dirsToCheck.Add(Path.Combine(rootDir, "media\\exportimport")); dirsToCheck.Add(Path.Combine(rootDir, "plugins")); dirsToCheck.Add(Path.Combine(rootDir, "plugins\\bin")); return dirsToCheck; @@ -182,8 +176,8 @@ public static IEnumerable GetFilesWrite(IWebHelper webHelper) { string rootDir = webHelper.MapPath("~/"); var filesToCheck = new List(); - filesToCheck.Add(Path.Combine(rootDir, "Global.asax")); - filesToCheck.Add(Path.Combine(rootDir, "web.config")); + //filesToCheck.Add(Path.Combine(rootDir, "Global.asax")); + //filesToCheck.Add(Path.Combine(rootDir, "web.config")); filesToCheck.Add(Path.Combine(rootDir, "App_Data\\InstalledPlugins.txt")); filesToCheck.Add(Path.Combine(rootDir, "App_Data\\Settings.txt")); return filesToCheck; diff --git a/src/Presentation/SmartStore.Web.Framework/Security/RequireHttpsByConfigAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Security/RequireHttpsByConfigAttribute.cs index 1bac01ca52..626a125317 100644 --- a/src/Presentation/SmartStore.Web.Framework/Security/RequireHttpsByConfigAttribute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Security/RequireHttpsByConfigAttribute.cs @@ -10,11 +10,15 @@ namespace SmartStore.Web.Framework.Security [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class RequireHttpsByConfigAttribute : FilterAttribute, IAuthorizationFilter { - public RequireHttpsByConfigAttribute(SslRequirement sslRequirement) + public RequireHttpsByConfigAttribute(SslRequirement sslRequirement) { this.SslRequirement = sslRequirement; } + public Lazy SecuritySettings { get; set; } + public Lazy StoreContext { get; set; } + public Lazy WebHelper { get; set; } + public virtual void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) @@ -34,7 +38,7 @@ public virtual void OnAuthorization(AuthorizationContext filterContext) var currentConnectionSecured = filterContext.HttpContext.Request.IsSecureConnection(); - var securitySettings = EngineContext.Current.Resolve(); + var securitySettings = SecuritySettings.Value; if (securitySettings.ForceSslForAllPages) { // all pages are forced to be SSL no matter of the specified value @@ -47,16 +51,16 @@ public virtual void OnAuthorization(AuthorizationContext filterContext) { if (!currentConnectionSecured) { - var storeContext = EngineContext.Current.Resolve(); + var storeContext = StoreContext.Value; var currentStore = storeContext.CurrentStore; if (currentStore != null && currentStore.GetSecurityMode() > HttpSecurityMode.Unsecured) { // redirect to HTTPS version of page // string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; - var webHelper = EngineContext.Current.Resolve(); + var webHelper = WebHelper.Value; string url = webHelper.GetThisPageUrl(true, true); - filterContext.Result = new RedirectResult(url); + filterContext.Result = new RedirectResult(url, true); } } } @@ -65,12 +69,12 @@ public virtual void OnAuthorization(AuthorizationContext filterContext) { if (currentConnectionSecured) { - var webHelper = EngineContext.Current.Resolve(); + var webHelper = WebHelper.Value; // redirect to HTTP version of page // string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl; string url = webHelper.GetThisPageUrl(true, false); - filterContext.Result = new RedirectResult(url); + filterContext.Result = new RedirectResult(url, true); } } break; @@ -80,7 +84,7 @@ public virtual void OnAuthorization(AuthorizationContext filterContext) } break; default: - throw new SmartException("Not supported SslProtected parameter"); + throw new SmartException("Unsupported SslRequirement parameter"); } } diff --git a/src/Presentation/SmartStore.Web.Framework/Seo/CanonicalHostNameAttribute.cs b/src/Presentation/SmartStore.Web.Framework/Seo/CanonicalHostNameAttribute.cs new file mode 100644 index 0000000000..f683d550e1 --- /dev/null +++ b/src/Presentation/SmartStore.Web.Framework/Seo/CanonicalHostNameAttribute.cs @@ -0,0 +1,80 @@ +using System; +using System.Web.Mvc; +using SmartStore.Core; +using SmartStore.Core.Data; +using SmartStore.Core.Domain.Seo; +using SmartStore.Core.Infrastructure; + +namespace SmartStore.Web.Framework.Seo +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] + public class CanonicalHostNameAttribute : FilterAttribute, IAuthorizationFilter + { + public CanonicalHostNameAttribute() + { + } + + public Lazy SeoSettings { get; set; } + public Lazy WebHelper { get; set; } + public Lazy StoreContext { get; set; } + + public virtual void OnAuthorization(AuthorizationContext filterContext) + { + if (filterContext == null) + throw new ArgumentNullException("filterContext"); + + if (filterContext.IsChildAction) + return; + + // only redirect for GET requests + if (!String.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) + return; + + if (!DataSettings.DatabaseIsInstalled()) + return; + + var rule = SeoSettings.Value.CanonicalHostNameRule; + if (rule == CanonicalHostNameRule.NoRule) + return; + + var uri = filterContext.HttpContext.Request.Url; + + if (uri.IsLoopback) + { + // allows testing of "localtest.me" + return; + } + + var url = uri.ToString(); + var protocol = uri.Scheme.ToLower(); + var isHttps = protocol.IsCaseInsensitiveEqual("https"); + var startsWith = "{0}://www.".FormatInvariant(protocol); + var hasPrefix = url.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase); + + if (isHttps) + { + var securityMode = StoreContext.Value.CurrentStore.GetSecurityMode(); + if (securityMode == HttpSecurityMode.SharedSsl) + { + // Don't attempt to redirect when shared SSL is being used and current request is secured. + // Redirecting from http://ssl.bla.com to https://www.ssl.bla.com will most probably fail. + return; + } + } + + if (hasPrefix && rule == CanonicalHostNameRule.OmitWww) + { + url = url.Replace("://www.", "://"); + filterContext.Result = new RedirectResult(url, true); + } + + if (!hasPrefix && rule == CanonicalHostNameRule.RequireWww) + { + url = url.Replace("{0}://".FormatInvariant(protocol), startsWith); + filterContext.Result = new RedirectResult(url, true); + } + + } + + } +} diff --git a/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRoute.cs b/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRoute.cs index 73f8159ed0..6ea897dfa0 100644 --- a/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRoute.cs +++ b/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRoute.cs @@ -84,25 +84,17 @@ public override RouteData GetRouteData(HttpContextBase httpContext) if (urlRecord == null) { //no URL record found - - //var webHelper = EngineContext.Current.Resolve(); - //var response = httpContext.Response; - //response.Status = "302 Found"; - //response.RedirectLocation = webHelper.GetStoreLocation(false); - //response.End(); - //return null; - - data.Values["controller"] = "Common"; - data.Values["action"] = "PageNotFound"; - return data; + data.Values["controller"] = "Error"; + data.Values["action"] = "NotFound"; + return data; } if (!urlRecord.IsActive) { - //URL record is not active. let's find the latest one + // URL record is not active. let's find the latest one var activeSlug = urlRecordService.GetActiveSlug(urlRecord.EntityId, urlRecord.EntityName, urlRecord.LanguageId); if (!string.IsNullOrWhiteSpace(activeSlug)) { - //the active one is found + // the active one is found var webHelper = EngineContext.Current.Resolve(); var response = httpContext.Response; response.Status = "301 Moved Permanently"; @@ -112,30 +104,22 @@ public override RouteData GetRouteData(HttpContextBase httpContext) } else { - //no active slug found - - //var webHelper = EngineContext.Current.Resolve(); - //var response = httpContext.Response; - //response.Status = "302 Found"; - //response.RedirectLocation = webHelper.GetStoreLocation(false); - //response.End(); - //return null; - - data.Values["controller"] = "Common"; - data.Values["action"] = "PageNotFound"; + // no active slug found + data.Values["controller"] = "Error"; + data.Values["action"] = "NotFound"; return data; } } - //process URL + // process URL + data.Values["SeName"] = urlRecord.Slug; switch (urlRecord.EntityName.ToLowerInvariant()) { case "product": { - data.Values["controller"] = "Catalog"; - data.Values["action"] = "Product"; + data.Values["controller"] = "Product"; + data.Values["action"] = "ProductDetails"; data.Values["productid"] = urlRecord.EntityId; - data.Values["SeName"] = urlRecord.Slug; } break; case "category": @@ -143,7 +127,6 @@ public override RouteData GetRouteData(HttpContextBase httpContext) data.Values["controller"] = "Catalog"; data.Values["action"] = "Category"; data.Values["categoryid"] = urlRecord.EntityId; - data.Values["SeName"] = urlRecord.Slug; } break; case "manufacturer": @@ -151,7 +134,6 @@ public override RouteData GetRouteData(HttpContextBase httpContext) data.Values["controller"] = "Catalog"; data.Values["action"] = "Manufacturer"; data.Values["manufacturerid"] = urlRecord.EntityId; - data.Values["SeName"] = urlRecord.Slug; } break; case "newsitem": @@ -159,7 +141,6 @@ public override RouteData GetRouteData(HttpContextBase httpContext) data.Values["controller"] = "News"; data.Values["action"] = "NewsItem"; data.Values["newsItemId"] = urlRecord.EntityId; - data.Values["SeName"] = urlRecord.Slug; } break; case "blogpost": @@ -167,12 +148,11 @@ public override RouteData GetRouteData(HttpContextBase httpContext) data.Values["controller"] = "Blog"; data.Values["action"] = "BlogPost"; data.Values["blogPostId"] = urlRecord.EntityId; - data.Values["SeName"] = urlRecord.Slug; } break; default: { - throw new SmartException(string.Format("Not supported EntityName for UrlRecord: {0}", urlRecord.EntityName)); + throw new SmartException(string.Format("Unsupported EntityName for UrlRecord: {0}", urlRecord.EntityName)); } } } diff --git a/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRouteExtensions.cs b/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRouteExtensions.cs index 1a924c9be8..9029891c5f 100644 --- a/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRouteExtensions.cs +++ b/src/Presentation/SmartStore.Web.Framework/Seo/GenericPathRouteExtensions.cs @@ -6,7 +6,7 @@ namespace SmartStore.Web.Framework.Seo { public static class GenericPathRouteExtensions { - //Override for localized route + //Override for generic route public static Route MapGenericPathRoute(this RouteCollection routes, string name, string url) { return MapGenericPathRoute(routes, name, url, null /* defaults */, (object)null /* constraints */); diff --git a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingData.cs b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingData.cs index 10245ac84e..5894b7ab6f 100644 --- a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingData.cs +++ b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingData.cs @@ -2,7 +2,6 @@ namespace SmartStore.Web.Framework.Settings { - /// codehint: sm-add public class StoreDependingSettingData { public StoreDependingSettingData() diff --git a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs index cf9e3372b6..80a2d035e8 100644 --- a/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs +++ b/src/Presentation/SmartStore.Web.Framework/Settings/StoreDependingSettingHelper.cs @@ -1,12 +1,14 @@ -using System.Linq; +using System; +using System.Linq; using System.Web.Mvc; +using SmartStore.ComponentModel; +using SmartStore.Core.Infrastructure; using SmartStore.Services.Configuration; -using Fasterflect; -using System.Collections.Generic; +using SmartStore.Services.Localization; +using SmartStore.Web.Framework.Localization; namespace SmartStore.Web.Framework.Settings { - /// codehint: sm-add public class StoreDependingSettingHelper { private ViewDataDictionary _viewData; @@ -17,6 +19,7 @@ public StoreDependingSettingHelper(ViewDataDictionary viewData) } public static string ViewDataKey { get { return "StoreDependingSettingData"; } } + public StoreDependingSettingData Data { get @@ -36,16 +39,19 @@ private bool IsOverrideChecked(string settingKey, FormCollection form) } return false; } + public bool IsOverrideChecked(object settings, string name, FormCollection form) { var key = settings.GetType().Name + "." + name; return IsOverrideChecked(key, form); } + public void AddOverrideKey(object settings, string name) { var key = settings.GetType().Name + "." + name; Data.OverrideSettingKeys.Add(key); } + public void CreateViewDataObject(int activeStoreScopeConfiguration, string rootSettingClass = null) { _viewData[ViewDataKey] = new StoreDependingSettingData() @@ -55,63 +61,76 @@ public void CreateViewDataObject(int activeStoreScopeConfiguration, string rootS }; } - public void GetOverrideKeys(object settings, object model, int storeId, ISettingService settingService, bool isRootModel = true) - { - if (storeId <= 0) - return; // single store mode -> there are no overrides + public void GetOverrideKeys(object settings, object model, int storeId, ISettingService settingService, bool isRootModel = true, ILocalizedModelLocal localized = null, int? index = null) + { + if (storeId <= 0) + return; // single store mode -> there are no overrides - var data = Data; - if (data == null) - data = new StoreDependingSettingData(); + var data = Data; + if (data == null) + data = new StoreDependingSettingData(); - var settingName = settings.GetType().Name; - var properties = settings.GetType().GetProperties(); + var settingName = settings.GetType().Name; + var properties = settings.GetType().GetProperties(); + var localizedEntityService = EngineContext.Current.Resolve(); var modelType = model.GetType(); - foreach (var prop in properties) - { - var name = prop.Name; + foreach (var prop in properties) + { + var name = prop.Name; var modelProperty = modelType.GetProperty(name); - if (modelProperty == null) - continue; // setting is not configurable or missing or whatever... however we don't need the override info - - var key = settingName + "." + name; - var setting = settingService.GetSettingByKey(key, storeId: storeId); - - if (setting != null) - data.OverrideSettingKeys.Add(key); - } - - if (isRootModel) - { - data.ActiveStoreScopeConfiguration = storeId; - data.RootSettingClass = settingName; - - _viewData[ViewDataKey] = data; - } - } - public void UpdateSettings(object settings, FormCollection form, int storeId, ISettingService settingService) - { - var settingName = settings.GetType().Name; - var properties = settings.GetType().GetProperties(); - - foreach (var prop in properties) - { - var name = prop.Name; - var key = settingName + "." + name; - - if (storeId == 0 || IsOverrideChecked(key, form)) - { - dynamic value = settings.TryGetPropertyValue(name); - settingService.SetSetting(key, value == null ? "" : value, storeId, false); - } - else if (storeId > 0) - { - settingService.DeleteSetting(key, storeId); - } - } - } + if (modelProperty == null) + continue; // setting is not configurable or missing or whatever... however we don't need the override info + + var key = String.Empty; + var setting = String.Empty; + + if (localized == null) + { + key = settingName + "." + name; + setting = settingService.GetSettingByKey(key, storeId: storeId); + } + else + { + key = "Locales[" + index.ToString() + "]." + name; + setting = localizedEntityService.GetLocalizedValue(localized.LanguageId, 0, settingName, name); + } + + if (!String.IsNullOrEmpty(setting)) + data.OverrideSettingKeys.Add(key); + } + + if (isRootModel) + { + data.ActiveStoreScopeConfiguration = storeId; + data.RootSettingClass = settingName; + + _viewData[ViewDataKey] = data; + } + } + + public void UpdateSettings(object settings, FormCollection form, int storeId, ISettingService settingService, ILocalizedModelLocal localized = null) + { + var settingName = settings.GetType().Name; + var properties = FastProperty.GetProperties(localized == null ? settings.GetType() : localized.GetType()).Values; + + foreach (var prop in properties) + { + var name = prop.Name; + var key = settingName + "." + name; + + if (storeId == 0 || IsOverrideChecked(key, form)) + { + dynamic value = prop.GetValue(localized == null ? settings : localized); + settingService.SetSetting(key, value == null ? "" : value, storeId, false); + } + else if (storeId > 0) + { + settingService.DeleteSetting(key, storeId); + } + } + } } } diff --git a/src/Presentation/SmartStore.Web.Framework/Mvc/SmartDependencyResolver.cs b/src/Presentation/SmartStore.Web.Framework/SmartDependencyResolver.cs similarity index 93% rename from src/Presentation/SmartStore.Web.Framework/Mvc/SmartDependencyResolver.cs rename to src/Presentation/SmartStore.Web.Framework/SmartDependencyResolver.cs index 6ae54b1694..a38bedbe52 100644 --- a/src/Presentation/SmartStore.Web.Framework/Mvc/SmartDependencyResolver.cs +++ b/src/Presentation/SmartStore.Web.Framework/SmartDependencyResolver.cs @@ -3,7 +3,7 @@ using System.Web.Mvc; using SmartStore.Core.Infrastructure; -namespace SmartStore.Web.Framework.Mvc +namespace SmartStore.Web.Framework { public class SmartDependencyResolver : IDependencyResolver { diff --git a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj index f53587d96b..b37e9baf66 100644 --- a/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj +++ b/src/Presentation/SmartStore.Web.Framework/SmartStore.Web.Framework.csproj @@ -1,5 +1,5 @@  - + Debug AnyCPU @@ -10,7 +10,7 @@ Properties SmartStore.Web.Framework SmartStore.Web.Framework - v4.5 + v4.5.1 512 @@ -66,16 +66,22 @@ False ..\..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll - - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True - - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll + + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + True False ..\..\packages\Autofac.WebApi.3.1.0\lib\net40\Autofac.Integration.WebApi.dll + + ..\..\packages\AutoMapper.4.1.1\lib\net45\AutoMapper.dll + True + False ..\..\packages\BundleTransformer.Core.1.8.23\lib\net40\BundleTransformer.Core.dll @@ -86,23 +92,19 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll - - False - ..\..\packages\fasterflect.2.1.3\lib\net40\Fasterflect.dll - - - False - ..\..\packages\FluentValidation.5.0.0.1\lib\Net40\FluentValidation.dll + + ..\..\packages\FluentValidation.5.6.2.0\lib\Net45\FluentValidation.dll + True - - False - ..\..\packages\JavaScriptEngineSwitcher.Core.1.1.3\lib\net40\JavaScriptEngineSwitcher.Core.dll + + ..\..\packages\JavaScriptEngineSwitcher.Core.1.2.4\lib\net40\JavaScriptEngineSwitcher.Core.dll + True False @@ -120,14 +122,12 @@ True ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - False - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll - - - ..\..\packages\recaptcha.1.0.5.0\lib\.NetFramework 4.0\Recaptcha.dll + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True + @@ -137,6 +137,7 @@ ..\..\packages\Microsoft.AspNet.WebApi.Client.5.1.2\lib\net45\System.Net.Http.Formatting.dll + False @@ -150,7 +151,7 @@ False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll False @@ -168,9 +169,9 @@ False ..\..\packages\Microsoft.AspNet.WebApi.WebHost.5.1.2\lib\net45\System.Web.Http.WebHost.dll - + False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll False @@ -178,19 +179,19 @@ False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll @@ -198,7 +199,8 @@ - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll + False + ..\..\..\lib\Telerik\Telerik.Web.Mvc.dll False @@ -212,55 +214,79 @@ Properties\AssemblyVersionInfo.cs - - + + + + + + - - + - - - + + + - - + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + + + + - - - - - + + - - - - - - + + + + + + - + @@ -275,43 +301,44 @@ - - + + - + - - - + + + - - + + - - + + - - - - - - - + + + + + + + + + - + - - - - - + + + + @@ -327,7 +354,7 @@ - + @@ -355,7 +382,6 @@ - @@ -365,7 +391,8 @@ - + + @@ -375,10 +402,11 @@ - + + Designer + - {6bda8332-939f-45b7-a25e-7a797260ae59} @@ -393,6 +421,7 @@ SmartStore.Data + - - -
    -
    -
    - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/admin.less b/src/Presentation/SmartStore.Web/Administration/Content/admin.less index ef2d71dd4a..5483f5971f 100644 --- a/src/Presentation/SmartStore.Web/Administration/Content/admin.less +++ b/src/Presentation/SmartStore.Web/Administration/Content/admin.less @@ -1,4 +1,52 @@  +/* General +-------------------------------------------------------------- */ + +a:active, +a:hover { + outline: 0; +} + +.btn { + text-transform: uppercase; +} + +.dropdown-menu .fa, +.btn > .fa { + font-size: 14px; +} + +.dropdown-menu { + .border-radius(0) !important; + text-shadow: none; +} + +.dropdown-menu li > a { + padding: 8px 30px 8px 20px; + text-shadow: none; +} + +.dropdown-menu li > a > .fa { + color: #6d6d6d; +} + +.dropdown-menu li > a:hover > .fa { + color: #444; +} + +.dropdown-menu li > a:hover, +.dropdown-menu li > a:focus, +.dropdown-submenu:hover > a { + background-image: none; + filter: initial; + background-color: @dropdownLinkBackgroundHover; +} + +.alert { + padding-top: 14px; + padding-bottom: 14px; +} + /* Page -------------------------------------------------------------- */ @@ -8,6 +56,11 @@ padding: 0; } +body:not(.popup) #page { + min-width: 900px; +} + + /* Warning panel message -------------------------------------------------------------- */ @@ -36,9 +89,24 @@ } +/* Header +-------------------------------------------------------------- */ + +header { + background-color: @navbarInverseBackground; + height: 70px; + padding-bottom: 50px; +} + +.popup header { + display: none; +} + + + /* Navbar overrides -------------------------------------------------------------- */ -.navbar .nav-smart { +.navbar .nav { font-family: Tahoma, @baseFontFamily; } @@ -46,87 +114,73 @@ margin: 0; padding: 0; border: 0; - border-bottom: 1px solid #fff; - .box-shadow(0 8px 8px -8px #000 inset); + background: @navbarInverseBackground; + //background-image: none; + .box-shadow(none); .border-radius(0); } .navbar.navbar-inverse .navbar-inner .brand { margin: 0; - padding: 10px 15px 0 30px; + padding-left: 30px; } #navbar-tools { .active-tool() { - background: #444; - color: #fff; - .box-shadow(~'0px 1px 6px rgba(0,0,0, 0.3) inset, 0px 1px 0px rgba(255,255,255, .12)'); + .box-shadow(~'inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)'); } position: absolute; right: 30px; - top: 12px; + top: 10px; margin: 0; .btn, .btn-group { margin-top: 0; } - - .dropdown-menu { - .border-radius(5px); - } - - // Buttons: actions, language, help - .navbar-tools-group .btn-group { - & + .btn-group { - margin-left: 0; // override bs default; - } - &.pull-right { - float: none; // override bs default - } - - .btn { - .border-radius(0); - } - - &:first-child .btn { - .border-radius(4px 0 0 4px); - } - - &:last-child .btn { - .border-radius(0 4px 4px 0); - } + .open .navbar-tool { + .active-tool(); } + .toppad { + margin-top: 8px; + } + .navbar-tool { - color: rgba(255,255,255, .8); - border: 1px solid rgba(0,0,0, .7); - background: rgba(255,255,255, .09); - .box-shadow(~'1px 1px 0 rgba(255,255,255, .12) inset, -1px -1px 0 rgba(255,255,255, .09) inset'); - padding: 4px 8px; - margin-left: -1px; - - [class*=icon] { - font-size: 14px; - } + color: rgba(255,255,255, .87); + border: none; + background: transparent; + .box-shadow(none); + padding: 8px 6px; + .transition(color 0.1s linear); &:hover { - background-color: rgba(255,255,255, .15); color: #fff; } &:active { .active-tool(); } + + > .fa { + font-size: 20px; + } + + span { + display: inline-block; + //padding-bottom: 10px; + margin-left: 3px; + vertical-align: top; + } } - - .btn-group.open .btn.dropdown-toggle { - .active-tool(); - } +} + +#current-user { + margin-left: 20px; } #current-user span { @@ -140,50 +194,52 @@ /* Menu -------------------------------------------------------------- */ -#navbar .nav-smart > li { - .opacity(87); - .transition(opacity 0.1s linear); - - &:hover { .opacity(100); } - &:hover > a { background: rgba(255,255,255, .15) !important; } +#navbar .dropdown-menu { + margin-top: -2px; + font-family: @baseFontFamily; } -#navbar .nav-smart > li > a { +#navbar .dropdown-menu .fa { + margin-right: 6px; + font-size: 17px; + vertical-align: bottom; +} + +#navbar .nav-header { + text-shadow: none; + padding-left: 20px; +} + +#navbar .dropdown-submenu > a:after { + margin-right: -20px; +} + +#navbar .dropdown-submenu:hover > a:after { + border-left-color: #ccc; +} + +#navbar .nav > li > a { max-height: @navbarHeight - 12; min-width: 40px; max-width: 80px; height: auto; - padding: 6px !important; + padding: 12px 6px !important; text-align: center; - text-shadow: 0 -1px 0 #000; + background: transparent; background: rgba(255,255,255, 0); - //.transition(background-color 0.1s linear); - //color: #e5e5e5; - - /*&:hover { - color: #fff; - .transition(color .1s linear); - }*/ + .opacity(90); + .transition(~'opacity 0.1s linear, background-color 0.1s linear'); - .sm-icon { + .fa { position: relative; text-align: center; + vertical-align: middle; width: 22px; height: 22px; - } - - [class^="sm-icon-"], - [class*=" sm-icon-"] { - display: block; - position: relative; - text-align: center; - height: 24px; - font-size: 24px; - line-height: 24px; - font-style: normal; - font-weight: normal; - //text-shadow: none; - //color: #aaa; + font-size: 19px; + line-height: 22px; + color: #fff; + padding: 2px 0; } .navbar-label { @@ -198,43 +254,116 @@ } } +#navbar .nav > li:hover > a { + background: rgba(255,255,255, .15); + .opacity(100); +} + +.reddot { + position: absolute; + width: 10px; + height: 10px; + border-radius: 50%; + background-color: @red; + color: #fff; +} + /* SM additions -------------------------------------------------------------- */ + #ajax-busy { - position: absolute; - width: 150px; - height: 14px; - padding: 0; - background: transparent url('images/ajax-progress-2.gif') 50% 50% no-repeat; - top: 36px; - left: 34px; - visibility: hidden; - .opacity(0); - .transition(opacity 0.15s linear); + position: fixed; + opacity: 0; + left: 0; + right: 0; + top: 0; + width: 100%; + height: 3px; + z-index: 20; + background-color: #ffab40; + .transition(opacity .05s ease-in); } #ajax-busy.busy { - visibility: visible; - .opacity(100); + opacity: 1; +} +#ajax-busy.busy > .bar { + content: ""; + display: inline; + position: absolute; + width: 0; + height: 100%; + left: 50%; + text-align: center; + animation: loading 1.5s cubic-bezier(0.445, 0.05, 0.55, 0.95) infinite; + -webkit-animation: loading 1.5s cubic-bezier(0.445, 0.05, 0.55, 0.95) infinite; +} +#ajax-busy > .bar:nth-child(1) { + background-color: #fff; +} +#ajax-busy > .bar:nth-child(2) { + background-color: #3F51B5; + animation-delay: 0.5s; + -webkit-animation-delay: 0.5s; +} +#ajax-busy > .bar:nth-child(3) { + background-color: #ffab40; + animation-delay: 1s; + -webkit-animation-delay: 1s; +} +@keyframes loading { + from {left: 50%; width: 0; z-index:100;} + 50% {left: 0; width: 100%; z-index: 10;} + to {left: 0; width: 100%;} +} +@-webkit-keyframes loading { + from {left: 50%; width: 0; z-index:100;} + 50% {left: 0; width: 100%; z-index: 10;} + to {left: 0; width: 100%;} } -.ajax-loader-small { - display: inline-block; - position: relative; - width: 16px; - height: 16px; - padding: 0; - margin: 0; - background: transparent url('images/ajax_loader_small.gif') 50% 50% no-repeat; +.loading-bar { + height: 4px; + width: 100%; + position: relative; + overflow: hidden; + background-color: #ddd; +} +.loading-bar:before { + display: block; + position: absolute; + content: ""; + left: -200px; + width: 200px; + height: 4px; + background-color: #2980b9; + animation: loadingbar 2s linear infinite; + -webkit-animation: loadingbar 2s linear infinite; +} +@keyframes loadingbar { + from {left: -200px; width: 30%;} + 50% {width: 30%;} + 70% {width: 70%;} + 80% { left: 50%;} + 95% {left: 120%;} + to {left: 100%;} +} +@-webkit-keyframes loadingbar { + from {left: -200px; width: 30%;} + 50% {width: 30%;} + 70% {width: 70%;} + 80% { left: 50%;} + 95% {left: 120%;} + to {left: 100%;} } #content { position: relative; height: auto; - margin: 74px 30px 0; + margin: 0 30px; + margin-top: -50px; background-color: #fff; - padding: 15px 15px 60px 15px; - .box-shadow(~'0 0 8px #bbb'); - .border-radius(6px 6px 0 0); + padding: 15px 30px 60px 30px; + .box-shadow(~'0 0 6px rgba(0,0,0, 0.2)'); } .popup #content { @@ -259,12 +388,97 @@ td.adminData > input[type="checkbox"] { margin-top: -1px; } +.admin-config-group { + .title, + .small-title, + .head { + font-family: @headingsFontFamily; + font-weight: @headingsFontWeight; + color: inherit; + border-bottom: 1px solid #ddd; + } + .sub-title { + font-family: @baseFontFamily; + font-size: @baseFontSize; + font-weight: normal; + } + .title, + .head { + font-size: @fontSizeLarge; + padding: 12px 0; + } + .head { + margin-bottom: 12px; + } + .title { + margin: 12px 0; + } + .small-title { + margin: 2px 0; + padding: 2px 0; + } +} + /* "select2" ui tweaks for admin -------------------------------------------------------------- */ .select2-container:not(.autowidth) { - min-width: 264px; /* ensures more clean look & feel */ + min-width: 314px; /* ensures more clean look & feel */ +} + +.select2-image-item { + img { + margin-bottom: 3px; + } + span:not(.select2-icon) { + padding-left: 5px; + } + .icon-container { + float: left; + display: inline-block; + width: 16px; + min-width: 16px; + max-width: 16px; + } +} + +/* select2 with large, templated items +-------------------------------------------------------------- */ +.large-select2 { + .select2-choice { + height: 42px; + min-height: 42px; + padding-top: 4px; + + > div > b { + padding-top: 10px; + } + } +} + +.large-select2-item { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + height: 38px; + + img { + margin-right: 12px; + vertical-align: middle; + text-align: center; + max-height: 100%; + } + > div { + margin-right: 0px !important; + display: inline-block; + vertical-align: top; + line-height: normal; + } + > div > span { + display: block; + padding-bottom: 1px; + } } @@ -276,6 +490,10 @@ td.adminData > input[type="checkbox"] { &:hover { border-color: rgba(0,0,0, 0.2) } } +.t-grid .t-status-text { + color: #aaa; +} + .t-grid .table { margin-bottom: 0; } @@ -286,27 +504,43 @@ td.adminData > input[type="checkbox"] { .t-grid *:not(.btn-group) > .btn { margin: 0.2em; } + .t-grid .t-button, .t-edit-form .t-button, .t-filter-options { - padding: @paddingSmall; + padding: 2px 4px; + font-size: @fontSizeSmall; + .border-radius(2px); +} + +.t-filter-options { font-size: @fontSizeSmall; - .border-radius(@borderRadiusSmall); } + .t-grid .btn { padding: @paddingSmall; } .t-grid .btn, -.t-grid .btn [class^="icon-"] { +.t-grid .btn .fa { font-size: @fontSizeSmall; } -.t-grid .t-button [class^="icon-"], -.t-grid .t-button [class*=" icon-"] { +.t-grid .t-button .fa { margin-top: 0; } +.t-grid-toolbar .btn { + text-shadow: none; + text-decoration: none; + font-size: 13px; +} + .t-grid-filter { - margin-top: -1.6em; + margin: 0; + padding: 0; + position: absolute; + right: 4px; + top: 50%; + margin-top: -8px; } .t-link:hover { @@ -316,102 +550,39 @@ td.adminData > input[type="checkbox"] { .t-grid-header .t-header { font-size: 12px; text-transform: uppercase; + font-weight: bold !important; + padding: 0 !important; + position: relative; } .t-grid-header .t-header .t-link { - width: 100%; + margin: 0; + padding: 0.6em; } -.t-grid tbody { - - td { - padding: 6px 8px; - } - - .t-last { - .text-overflow(); - } - - .t-grid-new-row > td, - .t-grid-edit-row > td { - padding: 6px; - } - - .t-grid-edit-row .text-box, - .t-grid-edit-row .t-numerictextbox, - .t-grid-edit-row .t-datepicker { - margin: 0; - } - - .t-button { - // 64px is too wide - min-width: initial; - } - - .t-input { - width: auto; - padding-top: 2px; - padding-bottom: 2px; - } +.t-grid-pager, +.t-grid-toolbar { + background: #f7f7f7; + text-shadow: none !important; + padding-top: .4em !important; + padding-bottom: .4em !important; +} - .t-numerictextbox { - margin: 0 4px; /* let it 'breathe' */ - .t-input { - max-width: 85%; - } - } +.t-grid tbody .t-last { + .text-overflow(); } .t-grid form.t-grid-actions { margin: 0; } - - -.t-dropdown-wrap .t-input { - /* dropdown will 'jump' on hover otherwise */ - border: initial !important; -} - -.t-numerictextbox { - overflow: hidden; - position: relative; -} - -.t-numerictextbox .t-input { - width: 252px; - padding: 4px 8px 4px 2px !important; -} -.t-numerictextbox.small .t-input { - width: 80px; -} -.t-numerictextbox .t-formatted-value { - position: absolute; - padding: 4px 4px; - left: 6px; - right: 16px; - overflow: hidden; -} -.t-numerictextbox .t-arrow-up { - margin-top: 3px !important; - margin-left: -19px; -} -.t-numerictextbox .t-arrow-down { - margin-bottom: 3px !important; -} -.t-numerictextbox .t-icon { - .opacity(50); - &:hover { - .opacity(100); - } +.t-grid-edit-row .t-numerictextbox .t-arrow-up { + margin-left: -16px; } body .t-content.t-state-active { padding: 10px !important; } -body .t-tabstrip { - margin-bottom: 10px !important; -} .form-actions { overflow: hidden; @@ -429,6 +600,7 @@ body .t-tabstrip { } + /* HTML editor (tiny mce) -------------------------------------------------------------- */ @@ -438,9 +610,9 @@ body .t-tabstrip { body { - background-attachment: fixed; - //#gradient > .vertical-three-colors(#ececec, #ececec, 50%, #fff); - #gradient > .vertical-three-colors(@infoBackground, @infoBackground, 50%, #fff); + //background-attachment: fixed; + //#gradient > .vertical-three-colors(@infoBackground, @infoBackground, 50%, #fff); + background-color: #f5f5f5; } hr { border-bottom: 1px solid #CCC; @@ -451,10 +623,6 @@ label.forcheckbox { display: inline; } -a:hover { - font-weight: normal; -} - /* SECTION HEADERS */ .section-title { border-bottom: solid 3px #dfdfdf; @@ -474,8 +642,9 @@ a:hover { left: 0; top: 0; right: 0; - /*background-color: #fff;*/ - padding: 10px; + padding: 10px 30px; + .transition(background-color 0.1s linear); + .title { position: relative; @@ -485,23 +654,24 @@ a:hover { font-weight: @pageTitleFontWeight; color: @pageTitleColor; font-size: 20px; - line-height: 30px; + line-height: 32px; + height: 32px; /*vertical-align: bottom;*/ vertical-align: middle; .text-overflow(); text-shadow: none; - i { + .fa { font-size: 28px; //font-size: 32px; vertical-align: text-top; } img { - max-height: 50px; + max-height: 32px; max-width: 120px; - vertical-align: middle; - padding-bottom: 2px; + margin-right: 5px; + vertical-align: top; } a { @@ -514,28 +684,29 @@ a:hover { .options { position: absolute; - right: 15px; - top: 12px; + right: 30px; + top: 10px; &.btn-toolbar { margin: 0; } } &.sticky { position: fixed; z-index: 10; - left: 0; //89px; - top: 54px; //0; - - @c: fade(#f6f6f6, 60%); - .gradientBar(lighten(@c, 8%), @c); - border-bottom: 1px solid #dadada; + left: 30px; + right: 30px; + top: 0; + background: #f7f7f7; + + text-shadow: none; + border-bottom: 1px solid #ccc; .title { text-shadow: none; - left: 30px; + left: 5px; } .options { - right: 45px; + right: 30px; } } } @@ -562,8 +733,10 @@ a:hover { } .popup .section-header.sticky { + left: 0; + right: 0; top: 0; - .options { right: 15px } + .options { right: 30px } } /* MULTI-STORE */ @@ -608,7 +781,7 @@ table.adminContent { } td.adminTitle { padding: 4px; - width: 280px; + width: 300px; } .modal td.adminTitle { width: auto; @@ -624,11 +797,11 @@ td.adminTitle > .ctl-label { label { display: inline-block; padding-right: 20px; - margin-top: 1px; margin-bottom: 0; } a.hint { + @hintColor: #999; //#21759b position: absolute; width: 16px; height: 16px; @@ -637,30 +810,37 @@ td.adminTitle > .ctl-label { margin-top: -8px; text-decoration: none; outline: 0; - color: #21759b; - .transition(color .1s linear); - - &:hover { color: darken(#21759b, 15%) } - i { font-size: 15px } + color: @hintColor; + .transition(all .1s linear); + .opacity(0); + &:hover { + color: darken(@hintColor, 25%) + } + .fa { + font-size: 16px; + } } } +tr.adminGroup { + > td { + padding-top: 18px; + } -.admin-config-group { - margin-bottom: 20px; + label { + padding-bottom: 3px; + text-decoration: underline; + } } -.admin-config-group .title { - font-size: 1.2em; - color: #999; - margin-bottom: 5px; +td.adminTitle:hover a.hint { + .opacity(100); } - .well td.adminTitle { - width: 260px; + width: 280px; } .well.well-small td.adminTitle { - width: 270px; + width: 290px; } td.adminData { @@ -668,37 +848,82 @@ td.adminData { vertical-align: middle; } td.adminData .text-box.single-line { - width: 250px; + width: 300px; } td.adminData input[type=text].input-large, -td.adminData textarea.input-large { +td.adminData textarea.input-large, +td.adminData .control-large { width: 500px; } +td.adminData input[type=text].input-xlarge, +td.adminData textarea.input-xlarge, +td.adminData .control-xlarge { + width: 800px; +} + .t-grid .text-box.single-line { /* ... */ } td.adminData textarea { - width: 250px; + width: 300px; } td.adminData .t-combobox { - width: 256px; + width: 306px; } -tr.adminSeparator hr { - background-color: #D3D3D3; - border: medium none; - color: #D3D3D3; +tr.adminSeparator hr, +td.adminSeparator hr { + border: medium none; + background-color: #ddd; + color: #ddd; height: 1px; - margin-top: 10px; - margin-bottom: 10px; + margin-top: 12px; + margin-bottom: 12px; padding: 0; } -span.nop-tooltip { - white-space: nowrap; + +.plugin-configuration { + display: table; + width: 100%; + clear: both; + + > div { + display: table-cell; + vertical-align: top; + } + > div:first-child { + width: 80%; + } + > div:last-child { + float: right; + padding-left: 50px; + } } -/* SERVER CONTROLS */ +.admin-table { + thead th { + text-transform: uppercase; + } + th, td { + padding: 12px; + } + .disabled { + .muted(); + } + .progress-info { + min-width: 260px; + } + select, input { + margin-bottom: 0; + } + .control-large { + width: 500px; + min-width: 500px; + } +} + +/* SERVER CONTROLS */ label { padding-left: 3px; } @@ -714,6 +939,7 @@ label { } .mr8 { margin-right: 8px; } +.ml4 { margin-left: 4px; } /* MASTER HEADER */ .header-menu, @@ -741,17 +967,16 @@ a img { } legend { - font-family: 'Segoe UI SemiBold', 'Segoe UI', sans-serif; - font-weight: 600; + font-family: @headingsFontFamily; + font-weight: @headingsFontWeight; font-size: 18px; } /* MASTER CONTENT */ -#content .cph { +.cph { padding-top: 55px; } - /* WIDGETS */ .widget { position: relative; @@ -761,17 +986,19 @@ legend { overflow: hidden; } +.widget-table { + .box-shadow(1px 1px 2px rgba(0,0,0, 0.07)); +} + .widget-header { position: relative; height: 40px; line-height: 40px; border: 1px solid #d5d5d5; - .border-radius(4px 4px 0 0); .background-clip(padding-box); #gradient > .vertical(#fafafa, #e9e9e9); - [class^="icon-"], - [class*=" icon-"] { + .fa { display: inline-block; margin-left: 13px; margin-right: -2px; @@ -787,12 +1014,11 @@ legend { margin-right: 3em; font-family: inherit; - color: #888; + color: #444; font-size: 14px; line-height: 18px; font-weight: 400; - - text-shadow: 1px 1px 2px rgba(255,255,255,.5); + text-transform: uppercase; } } @@ -800,18 +1026,12 @@ legend { padding: 20px 15px 15px; background: #fff; border: 1px solid #d5d5d5; - .border-radius(5px); + position: relative; zoom: 1; } .widget-header + .widget-content { border-top: none; - -webkit-border-top-left-radius: 0; - -webkit-border-top-right-radius: 0; - -moz-border-radius-topleft: 0; - -moz-border-radius-topright: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; } .widget-nopad .widget-content { @@ -837,6 +1057,12 @@ legend { .widget-table .table { margin-bottom: 0; border: none; + table-layout: fixed; +} + +.widget-table .table td, +.widget-table .table th { + .text-overflow(); } .widget-table .table tr td:first-child { @@ -845,60 +1071,21 @@ legend { .widget-table .table tr th:first-child { border-left: none; + width: 50%; } /* DASHBOARD */ -.shortcuts { - text-align: center; -} - -.shortcuts .shortcut { - width: 28%; - display: inline-block; - padding: 12px 0; - margin: 0 .9% 1em; - vertical-align: top; - - text-decoration: none; - - background: #F3F3F3; - - border-radius: 5px; -} - -.shortcuts .shortcut .shortcut-icon { - margin-top: .25em; - margin-bottom: .25em; - - font-size: 32px; - color: #888; -} - -.shortcuts .shortcut:hover { - background: #E8E8E8; -} - -.shortcuts .shortcut:hover .shortcut-icon { - color: #666; -} - -.shortcuts .shortcut-label { - display: block; - - font-weight: 400; - color: #666; -} - .stats-today .widget-content { - #gradient > .vertical(#fafafa, #e9e9e9); + background: transparent; + border: none; + padding: 0; } .stats-today { position: relative; - text-shadow: 0 -1px 0 #fff; } .stats-today-title, @@ -912,18 +1099,16 @@ legend { .stats-today-title { position: absolute; - left: 15px; - bottom: 20px; - color: #aaa; + font-size: 50px; + font-family: @pageTitleFontFamily; + font-weight: @pageTitleFontWeight; } .stats-today-item { float: right; padding: 0 24px; text-align: center; - border-right: 1px solid #d1d1d1; - border-left: 1px solid #fff; - &.alpha { border-left: none } + border-right: 1px solid #f2f2f2; &.omega { padding-right: 0; border-right: none } } @@ -931,70 +1116,32 @@ legend { font-weight: bold; font-size: 12px; margin-bottom: 8px; - color: #999; + color: #aaa; } .stats-today-item-value { color: #333; } - -table.dashboard { - width: 100%; - margin: 0 auto; - border-collapse: collapse; +.marketplace-feed-title { + text-transform: uppercase; + font-size: 18px; + margin-bottom: 30px; + .fa { font-size: 20px; } } -table.dashboard td.maincol { - vertical-align: top; -} -table.dashboard td.splitcol { - width: 50%; - vertical-align: top; -} -table.dashboard td.rightcol { - width: 215px; - background: #f3f3f3; - padding: 10px 5px 5px; - vertical-align: top; -} -table.stats { - width: 100%; -} -table.stats td.orderaveragereport { - width: 100%; - vertical-align: top; -} -table.stats td.orderstatistics { - width: 50%; - vertical-align: top; - padding-right: 10px; -} -table.stats td.customerstatistics { - width: 50%; - vertical-align: top; - padding-left: 10px; +.marketplace-feed-item { + margin-bottom: 15px; + padding-bottom: 15px; + border-bottom: 1px solid #ddd; + &:last-child { border-bottom: none; } } -table.stats td.bestsellers { - width: 50%; - vertical-align: top; - padding-right: 10px; -} -table.stats td.bestsellers.alpha { - padding-right: 10px; -} -table.stats td.bestsellers.omega { - padding-left: 10px; -} -.statisticsTitle { - font-family: @pageTitleFontFamily; - font-weight: @pageTitleFontWeight; - color: #a1a1a1; - margin-bottom: 12px; - font-size: 20px; - line-height: 30px; + +.marketplace-feed-item-title { + margin-bottom: 4px; } + /* ORDER EDITING */ table.order-edit { width: 100%; @@ -1033,16 +1180,16 @@ table.order-edit td { font-size: 120%; vertical-align: middle; } -.system-warnings i { +.system-warnings .fa { font-size: 22px; } -.system-warnings .pass i { +.system-warnings .pass .fa { color: @green; } -.system-warnings .warning i { +.system-warnings .warning .fa { color: @yellow; } -.system-warnings .fail i { +.system-warnings .fail .fa { color: @red; } @@ -1078,75 +1225,113 @@ table.order-edit td { } -/* Plugins +/* Plugins & Providers -------------------------------------------------------------- */ -.plugins-group h3 { - font-family: 'Segoe UI Semibold', 'Segoe UI', Helvetica, Arial; - font-weight: 600; +.sortable-grip { + left: 67px; + width: 9px; +} + +.module-list, .module-item { + position: relative; +} + +.module-list > h3 { + font-family: @headingsFontFamily; + font-weight: @headingsFontWeight; color: inherit; font-size: 18px; + margin-top: 30px; } -.plugins-table { - thead > tr { - font-size: 16px; - color: #bbb; - } +.module-item { + padding: 12px 0; + border-top: 1px solid #ddd; +} +.module-item.inactive { + background-color: #fafafa; +} +.module-item.inactive .module-icon { + .opacity(50); +} - tr.uninstalled { - background-color: #fcfcfc; - } +.module-icon { + float: left; + width: 48px; + margin-left: 10px; + text-align: center; - td.cell-icon { - text-align: center; - width: 48px; - min-width: 48px; - max-width: 48px; + .icon, .fa { + max-width: 48px; + } +} - .icon { - max-width: 48px; - } - } +.module-data { + box-sizing: border-box; + margin-left: 90px; +} +.module-item:last-child .module-data { + border-bottom: none; +} - td.cell-data { - width: 50%; +.module-col { + float: left; + display: block; + box-sizing: border-box; + min-height: 1px; + position: relative; + padding: 0 15px; - .plugin-name { - font-weight: bold; - } + &:first-child { + padding-left: 0; + } +} - .attr-value { - color: #bbb; - } - } +.module-data-cols-1 .module-col { width: 100%; } +.module-data-cols-2 .module-col { width: 50%; } +.module-data-cols-3 .module-col { width: 33.3332%; } +.module-data-cols-4 .module-col { width: 25%; } - td.cell-data .plugin-data { - margin-top: 2px; - } +.module-name { + font-weight: bold; + margin-right: 5px; +} - td.cell-data .plugin-description { - margin: 4px 0; - } +.module-info { + margin-top: 3px; +} +.module-info .attr:after { + display: inline-block; + content: '\00b7'; + padding: 0 5px; +} +.module-info .attr:last-child:after { + display: none; +} +.module-info .attr-value { + color: #aaa; + //padding-right: 5px; +} - td.cell-data .plugin-actions { - margin-top: 6px; +.module-description { + margin: 4px 0; +} - [class^="icon-"] { - color: #bbb; - } +.module-actions { + margin-top: 8px; +} - a { - margin-right: 10px; - } - } +.module-actions .btn { + text-transform: none; +} - td.cell-install { - width: 50%; - vertical-align: middle; - } +table.payment-method-features td { + padding: 2px 4px; + font-size: 12px; } + /* Special icons */ .icon-active-true { color: @green; @@ -1194,39 +1379,58 @@ table.order-edit td { /* Themes */ #theme-list { - margin-top: 12px; -} -#theme-list .theme-line { - padding: 12px 0; - border-top: 1px solid #ccc; - position: relative; -} -#theme-list .theme-line.active { - background-color: #f9f9f9; -} -#theme-list .theme-line .preview-image { - width: 300px; - margin-right: 16px; -} -#theme-list .theme-line .theme-name { - font-size: 22px; - padding-bottom: 20px; -} -#theme-list .theme-line .buttons { - margin-top: 12px; - position: absolute; - bottom: 12px; -} -.theme-edit .group-name{ - h4 { - color: #aaa; - padding-left: 10px; + min-width: 820px; // 3 items in a row + max-width: 1360px; // 5 items + + .theme-item { + position: relative; + float: left; + width: 250px; + box-sizing: border-box; + margin: 0 20px 20px 0; + border: 1px solid #ccc; } - hr { - margin-top: 8px; + .theme-thumbnail-wrapper, + .theme-data { + padding: 8px; + } + .theme-thumbnail { + height: 220px; + background-size: cover; + } + .theme-data h4 { + margin-top: 0; + color: #333; + } + .theme-data h4 > small { + .smaller(); + font-weight: normal; + } + .theme-info { + font-size: 12px; + line-height: 16px; + } + .theme-buttons { + margin-top: 15px; + } + .theme-broken-badge { + position: absolute; + background-color: @red; + color: #fff; + right: 0; + bottom: 0; + padding: 8px 12px; + font-size: 20px; } } +.themevar-chain-info { + color: #bbb; + margin-left: 10px; + vertical-align: middle; +} + + .slides-title { position: relative; .headline { @@ -1270,8 +1474,8 @@ table.order-edit td { display: block; overflow: hidden; cursor: pointer; - border: 2px solid #969696; - border-radius: 5px; + border: 1px solid #969696; + border-radius: 4px; height: 14px; padding: 0; margin: 0; @@ -1280,7 +1484,6 @@ table.order-edit td { .onoffswitch-inner { width: 200%; margin-left: -100%; - .transition(all 0.3s ease-in 0s); } .onoffswitch-on, .onoffswitch-off { @@ -1289,37 +1492,36 @@ table.order-edit td { height: 15px; line-height: 15px; padding: 0; - color: white; - font-size: 11px; - font-family: Trebuchet, Arial, sans-serif; + color: #fff; + font-size: 10px; font-weight: normal; + text-align: center; + vertical-align: middle; .box-sizing(border-box); } .onoffswitch-on { - padding-left: 6px; - background-color: #6BB2ED; - color: #FFFFFF; + background-color: @orange; + color: #fff; } .onoffswitch-off { - padding-right: 3px; - background-color: #FFFFFF; - color: #969696; - text-align: right; + background-color: #fff; + color: #bbb; } .onoffswitch-switch { - width: 27px; + width: 30px; + box-sizing: border-box; margin: 0; position: absolute; top: 0; bottom: 0; - right: 29px; - background: #FFFFFF; - border: 2px solid #969696; - .border-radius(5px); - .transition(all 0.3s ease-in 0s); + right: 30px; + background: #fff; + border: 1px solid #969696; + .border-radius(4px 0 0 4px); + .transition(all 0.05s ease-in); #gradient > .vertical(#dddddd, #ffffff); } @@ -1329,6 +1531,7 @@ table.order-edit td { .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch { right: 0; + .border-radius(0 4px 4px 0); } #pnlAllFlags a.flag { min-width: 100px; @@ -1338,16 +1541,127 @@ table.order-edit td { text-decoration: none; } -#product-edit h3, -.caption-container h3 { - font-family: 'Segoe UI SemiBold', 'Segoe UI', sans-serif; - font-weight: 600; - font-size: 18px; - line-height: 36px; - color: #333; + +/* Download editor +-------------------------------------------------------------- */ + +.download-editor { + .panel-switcher-icon { + width: 13px; + } + + .filename { + line-height: 32px; + vertical-align: middle; + padding-right: 10px; + font-weight: bold; + max-width: 300px; + display: inline-block; + .ellipsis(); + } } -#product-edit h3.bordered, -.caption-container h3.bordered { - border: 0; - border-bottom: 1px solid #e5e5e5; + + +/* Scheduled tasks +-------------------------------------------------------------- */ + +.minimal-task-widget { + min-height: 26px; +} +.minimal-task-widget .task-progress { + width: 400px; +} +.minimal-task-widget .btn-cancel-task { + margin-left: 10px +} +.minimal-task-widget .btn-actions { + display: inline-block; + margin-left: 10px; +} + + + + +/* Data exchange +-------------------------------------------------------------- */ +.profile-list { + margin-bottom: 10px; + border-bottom: 1px solid #ddd; +} + +.info-profile td { + padding-top: 20px; +} + +/* Import column mapping +-------------------------------------------------------------- */ +@media (max-width: 1280px) { + #ImportColumnMappings .right-label, + .column-mapping .mapping-button-label, + .mapping-list-item .right-label { + display: none; + } +} + +.column-mapping .right-label, +.mapping-list-item .right-label { + float: right; + font-size: 0.9em; +} +.mapping-list-item { + .ellipsis(); +} + +.column-mapping { + .column-one, .column-two { + width: 42%; + } + + .select-column, .select-property, .input-default { + width: 98%; + } + + th, td, .mapping-delete, .mapping-add, .mapping-apply, .mapping-cancel { + white-space: nowrap; + padding-left: 8px; + padding-right: 8px; + } + + .select2-container .select2-choice span { + margin-right: 12px; + white-space: nowrap; + } + + .mapping-edit { + white-space: nowrap; + + .select-column, .select-property { + width: 84%; + } + .select2-container { + float: left; + display: inline-block; + min-width: 220px; + margin-right: 4px; + } + } + + .mapping-item { + .item-inner { + white-space: nowrap; + cursor: pointer; + padding: 7px 0; + + .property-icon { + display: inline-block; + margin-right: 0; + } + .left-label { + display: inline-block; + } + .right-label { + margin-right: 20px; + } + } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/LICENSE.txt b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/LICENSE.txt new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/conf.json b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/conf.json new file mode 100644 index 0000000000..c08220bdfe --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/conf.json @@ -0,0 +1,33 @@ +{ + "FILES_ROOT": "~/Media/Uploaded", + "SESSION_PATH_KEY": "", + "THUMBS_VIEW_WIDTH": "140", + "THUMBS_VIEW_HEIGHT": "120", + "PREVIEW_THUMB_WIDTH": "300", + "PREVIEW_THUMB_HEIGHT": "200", + "MAX_IMAGE_WIDTH": "0", + "MAX_IMAGE_HEIGHT": "0", + "INTEGRATION": "ckeditor", + "DIRLIST": "../../../Admin/RoxyFileManager/ProcessRequest?a=DIRLIST", + "CREATEDIR": "../../../Admin/RoxyFileManager/ProcessRequest?a=CREATEDIR", + "DELETEDIR": "../../../Admin/RoxyFileManager/ProcessRequest?a=DELETEDIR", + "MOVEDIR": "../../../Admin/RoxyFileManager/ProcessRequest?a=MOVEDIR", + "COPYDIR": "../../../Admin/RoxyFileManager/ProcessRequest?a=COPYDIR", + "RENAMEDIR": "../../../Admin/RoxyFileManager/ProcessRequest?a=RENAMEDIR", + "FILESLIST": "../../../Admin/RoxyFileManager/ProcessRequest?a=FILESLIST", + "UPLOAD": "../../../Admin/RoxyFileManager/ProcessRequest?a=UPLOAD", + "DOWNLOAD": "../../../Admin/RoxyFileManager/ProcessRequest?a=DOWNLOAD", + "DOWNLOADDIR": "../../../Admin/RoxyFileManager/ProcessRequest?a=DOWNLOADDIR", + "DELETEFILE": "../../../Admin/RoxyFileManager/ProcessRequest?a=DELETEFILE", + "MOVEFILE": "../../../Admin/RoxyFileManager/ProcessRequest?a=MOVEFILE", + "COPYFILE": "../../../Admin/RoxyFileManager/ProcessRequest?a=COPYFILE", + "RENAMEFILE": "../../../Admin/RoxyFileManager/ProcessRequest?a=RENAMEFILE", + "GENERATETHUMB": "../../../Admin/RoxyFileManager/ProcessRequest?a=GENERATETHUMB", + "DEFAULTVIEW": "list", + "FORBIDDEN_UPLOADS": "zip js jsp jsb mhtml mht xhtml xht php phtml php3 php4 php5 phps shtml jhtml pl sh py cgi exe scr dll msi vbs bat com pif cmd vxd cpl htpasswd htaccess", + "ALLOWED_UPLOADS": "", + "FILEPERMISSIONS": "0644", + "DIRPERMISSIONS": "0755", + "LANG": "auto", + "DATEFORMAT": "dd.MM.yyyy HH:mm" +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/animated-overlay.gif b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/animated-overlay.gif new file mode 100644 index 0000000000..d441f75ebf Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/animated-overlay.gif differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_flat_0_aaaaaa_40x100.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000..e1a114b4e2 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_flat_75_ffffff_40x100.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 0000000000..399d1ba7dd Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_55_fbf9ee_1x400.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 0000000000..9267153440 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_65_ffffff_1x400.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000..12902e2006 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_75_dadada_1x400.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 0000000000..c6af0909f1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_75_e6e6e6_1x400.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 0000000000..7e2dc85982 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_95_fef1ec_1x400.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 0000000000..be40bcf3c3 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 0000000000..57d294c986 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_222222_256x240.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000..c1cb1170c8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_222222_256x240.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_2e83ff_256x240.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000..84b601bf0f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_2e83ff_256x240.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_454545_256x240.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_454545_256x240.png new file mode 100644 index 0000000000..b6db1acdd4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_454545_256x240.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_888888_256x240.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_888888_256x240.png new file mode 100644 index 0000000000..feea0e2026 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_888888_256x240.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_cd0a0a_256x240.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 0000000000..ed5b6b0930 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/images/ui-icons_cd0a0a_256x240.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/jquery-ui-1.10.4.custom.css b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/jquery-ui-1.10.4.custom.css new file mode 100644 index 0000000000..4827019a8a --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/jquery-ui-1.10.4.custom.css @@ -0,0 +1,733 @@ +/*! jQuery UI - v1.10.4 - 2014-01-21 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.button.css, jquery.ui.dialog.css, jquery.ui.tooltip.css, jquery.ui.theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); +} + +.ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; +} + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-button { + display: inline-block; + position: relative; + padding: 0; + line-height: normal; + margin-right: .1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: visible; /* removes extra width in IE */ +} +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2.2em; +} +/* button elements seem to need a little more width */ +button.ui-button-icon-only { + width: 2.4em; +} +.ui-button-icons-only { + width: 3.4em; +} +button.ui-button-icons-only { + width: 3.7em; +} + +/* button text element */ +.ui-button .ui-button-text { + display: block; + line-height: normal; +} +.ui-button-text-only .ui-button-text { + padding: .4em 1em; +} +.ui-button-icon-only .ui-button-text, +.ui-button-icons-only .ui-button-text { + padding: .4em; + text-indent: -9999999px; +} +.ui-button-text-icon-primary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 1em .4em 2.1em; +} +.ui-button-text-icon-secondary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 2.1em .4em 1em; +} +.ui-button-text-icons .ui-button-text { + padding-left: 2.1em; + padding-right: 2.1em; +} +/* no icon support for input elements, provide padding by default */ +input.ui-button { + padding: .4em 1em; +} + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon, +.ui-button-text-icon-primary .ui-icon, +.ui-button-text-icon-secondary .ui-icon, +.ui-button-text-icons .ui-icon, +.ui-button-icons-only .ui-icon { + position: absolute; + top: 50%; + margin-top: -8px; +} +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} +.ui-button-text-icon-primary .ui-button-icon-primary, +.ui-button-text-icons .ui-button-icon-primary, +.ui-button-icons-only .ui-button-icon-primary { + left: .5em; +} +.ui-button-text-icon-secondary .ui-button-icon-secondary, +.ui-button-text-icons .ui-button-icon-secondary, +.ui-button-icons-only .ui-button-icon-secondary { + right: .5em; +} + +/* button sets */ +.ui-buttonset { + margin-right: 7px; +} +.ui-buttonset .ui-button { + margin-left: 0; + margin-right: -.3em; +} + +/* workarounds */ +/* reset extra padding in Firefox, see h5bp.com/l */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-dialog { + overflow: hidden; + position: absolute; + top: 0; + left: 0; + padding: .2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: .4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: .1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: .3em; + top: 50%; + width: 20px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: .5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: .5em; + padding: .3em 1em .5em .4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: .5em .4em .5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-se { + width: 12px; + height: 12px; + right: -5px; + bottom: -5px; + background-position: 16px 16px; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-tooltip { + padding: 8px; + position: absolute; + z-index: 9999; + max-width: 300px; + -webkit-box-shadow: 0 0 5px #aaa; + box-shadow: 0 0 5px #aaa; +} +body .ui-tooltip { + border-width: 2px; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: Verdana,Arial,sans-serif; + font-size: 1.1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: Verdana,Arial,sans-serif; + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #aaaaaa; + background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; + color: #222222; +} +.ui-widget-content a { + color: #222222; +} +.ui-widget-header { + border: 1px solid #aaaaaa; + background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; + color: #222222; + font-weight: bold; +} +.ui-widget-header a { + color: #222222; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #d3d3d3; + background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; + font-weight: normal; + color: #555555; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #555555; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #999999; + background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; + font-weight: normal; + color: #212121; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited, +.ui-state-focus a, +.ui-state-focus a:hover, +.ui-state-focus a:link, +.ui-state-focus a:visited { + color: #212121; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #aaaaaa; + background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; + font-weight: normal; + color: #212121; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #212121; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #fcefa1; + background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; + color: #363636; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #363636; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a; + background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; + color: #cd0a0a; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #cd0a0a; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #cd0a0a; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png); +} +.ui-widget-header .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png); +} +.ui-state-default .ui-icon { + background-image: url(images/ui-icons_888888_256x240.png); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url(images/ui-icons_454545_256x240.png); +} +.ui-state-active .ui-icon { + background-image: url(images/ui-icons_454545_256x240.png); +} +.ui-state-highlight .ui-icon { + background-image: url(images/ui-icons_2e83ff_256x240.png); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url(images/ui-icons_cd0a0a_256x240.png); +} + +/* positioning */ +.ui-icon-blank { background-position: 16px 16px; } +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 4px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; + opacity: .3; + filter: Alpha(Opacity=30); +} +.ui-widget-shadow { + margin: -8px 0 0 -8px; + padding: 8px; + background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; + opacity: .3; + filter: Alpha(Opacity=30); + border-radius: 8px; +} diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/jquery-ui-1.10.4.custom.min.css b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/jquery-ui-1.10.4.custom.min.css new file mode 100644 index 0000000000..0418dfd016 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/jquery-ui-1.10.4.custom.min.css @@ -0,0 +1,7 @@ +/*! jQuery UI - v1.10.4 - 2014-01-21 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.button.css, jquery.ui.dialog.css, jquery.ui.tooltip.css, jquery.ui.theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px +* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);border-radius:8px} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/main.css b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/main.css new file mode 100644 index 0000000000..2bd118ed06 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/main.css @@ -0,0 +1,214 @@ +/* + RoxyFileman - web based file manager. Ready to use with CKEditor, TinyMCE. + Can be easily integrated with any other WYSIWYG editor or CMS. + + Copyright (C) 2013, RoxyFileman.com - Lyubomir Arsov. All rights reserved. + For licensing, see LICENSE.txt or http://RoxyFileman.com/license + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Contact: Lyubomir Arsov, liubo (at) web-lobby.com +*/ +body{ + font-family: Verdana; + font-size: 11px; + padding:0; + margin:0; + background:#FFF; + height:100%; + width:100%; +} +a{text-decoration:none;color:#DD7700;} +ul{ + list-style:none; + margin:0; + padding:0; +} +#wraper{ + width:100%; + height:100%; +} +#wraper,#dlgNewDir,#dlgFileProp,#dlgAddFile,#menuDir, +#menuFile,#pnlRenameFile,#pnlLoadingDirs, +#pnlDirName,#pnlLoading,#pnlEmptyDir, +#pnlSearchNoFiles,#pnlFileProp, #pnlDirList ul{ + display:none; +} +.contextMenu a:hover, +#pnlFileList .selected,#pnlFileList .selected:hover, +#menuFile a:hover{ + background-color: #000099 !important; + color:#FFF; +} +#pnlDirList .selected,#pnlDirList div.selected:hover{background-color: #DFD !important;} +.dialog input,#fileUploads{width:97%;} +.filesize{font-weight:bold;margin-top:4px;display:inline-block;} +.pnlDragFile,.pnlDragDir{ + background:#FFF; + opacity:0.8; + float:left; + width:auto !important; +} +#pnlStatus{ + padding:5px; +} +.scrollPane{ + height:400px; + overflow: auto; +} +.bottomLine{background:#DDD;border-top:1px solid #CCC;} +.pale{opacity:0.5;} +/* Search and order fields */ +#txtSearch,#ddlOrder{ + border:1px solid #CCC; + border-radius:3px; +} +#txtSearch{ + padding:0 22px 0 3px; + background:url(../images/search.png) no-repeat 87px center; + width:80px; + height:20px; +} +input[type=text]::-ms-clear { display: none; } +/* END OF Search and order fields */ + +/* Directory tree */ +.pnlDirs{ + width:260px; + overflow:auto; + border-right:1px solid #DDD; +} +#pnlDirList{margin-left:4px;} +#pnlDirList ul{padding:0 0 0 20px;} +#pnlDirList .dir{ + line-height:30px; + float:left; + margin-right:5px; +} +#pnlDirList .dirPlus{ + float:left; + margin: 3px 3px 0 0; +} +#pnlDirList li,#pnlDirList div{ + float:left; + clear:both; + width:98%; +} +#pnlDirList div{padding:3px;cursor:pointer;} +#pnlLoadingDirs{margin-left:5px;} +/* END OF Directory tree */ + +/* File list */ +.pnlFiles{padding-left:4px;} +#pnlFileList .icon{float:left;margin-right:3px;} +#pnlFileList li{float:left;padding:3px;clear:both;width:98%;cursor:pointer;} +#pnlFileList li:hover,#pnlDirList li div:hover{background:#FFFFCC !important;} +#pnlFileList .size{float:right;margin-left:20px;} +#pnlFileList .time{float:right;margin-left:15px;width:130px;} +.imgPreview{max-width:300px;} +/* END OF File list */ + +/* Context menus */ +.contextMenu{ + position:absolute; + background-color:#DDD; + border:1px solid #BBB; + min-width:100px; + font-weight: bold; + z-index:1000 !important; +} +.contextMenu a{ + background-repeat:no-repeat; + background-position: 4px 6px; + padding: 5px 25px 5px 20px; + display:block; + color:#000; + text-decoration:none; +} +hr{margin:0;color:#AAA;} +/* END OF Context menus */ + +/* Buttons */ +.actions{padding:3px 0 10px 5px;} +.actions input{ + background-repeat:no-repeat; + background-position: 3px center; + padding:0 3px 0 18px; + height:22px; + font-size: 11px; + border:1px solid #CCC; + background-color: #EEE; + border-radius:3px; + margin-bottom: 3px; +} +.actions input[type=button]:hover,.actions input.selected{background-color: #DFD;cursor:pointer;} +#btnAddDir, #mnuCreateDir{background-image:url(../images/folder-add.png);} +#mnuDownloadDir{background-image:url(../images/folder-download.png);} +#btnDeleteDir,#mnuDeleteDir{background-image:url(../images/folder-delete.png);} +#btnAddFile{background-image:url(../images/file-add.png);} +#btnDeleteFile,#mnuDeleteFile{background-image:url(../images/file-delete.png);} +#btnDeleteFile{margin-right:15px;} +#btnDownloadFile,#mnuDownload{background-image:url(../images/file-download.png);} +#btnPreviewFile,#mnuPreview{background-image:url(../images/preview.png);} +#btnSelectFile,#mnuSelectFile{background-image:url(../images/select.png);} +#btnThumbView{background-image:url(../images/view-tile.png);background-position: center center;} +#btnListView{background-image:url(../images/view-list.png);background-position: center center;} +#btnRenameFile,#btnRenameDir,#mnuRenameDir,#mnuRenameFile{background-image:url(../images/rename.png);} +#mnuDirCut,#mnuFileCut{background-image:url(../images/cut.png);} +#mnuDirCopy,#mnuFileCopy{background-image:url(../images/copy.png);} +#mnuDirPaste,#mnuFilePaste{background-image:url(../images/paste.png);} + +/* END OF Buttons */ +/* File list views */ +ul#pnlFileList.thumbView li{ + /* + width:140px; + height: 140px; + */ + float:left !important; + clear:none; + margin:0 6px 6px 0; + overflow:hidden; + padding:10px; + text-align:center; + vertical-align:middle; + border: 1px solid #EEE; + border-radius: 5px; + position:relative; + background:#EEE; +} +ul#pnlFileList.thumbView .name,ul#pnlFileList.thumbView .time{display:none;} +ul#pnlFileList.thumbView .icon{ + clear:both; + float:none; + margin:0 !important; + text-align:center; + vertical-align:middle; + background-position:center center; + background-repeat:no-repeat; + /* + width:140px; + height:120px; + */ +} +ul#pnlFileList.thumbView .size{ + display:block !important; + width:95% !important; + position:absolute; + bottom:5px; + margin:0; +} +/* END OF File list views */ +div.ui-tooltip { + max-width: 90%; +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/main.min.css b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/main.min.css new file mode 100644 index 0000000000..dfaa7fa3b8 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/css/main.min.css @@ -0,0 +1 @@ +body{font-family:Verdana;font-size:11px;padding:0;margin:0;background:#FFF;height:100%;width:100%}a{text-decoration:none;color:#d70}ul{list-style:none;margin:0;padding:0}#wraper{width:100%;height:100%}#wraper,#dlgNewDir,#dlgFileProp,#dlgAddFile,#menuDir,#menuFile,#pnlRenameFile,#pnlLoadingDirs,#pnlDirName,#pnlLoading,#pnlEmptyDir,#pnlSearchNoFiles,#pnlFileProp,#pnlDirList ul{display:none}.contextMenu a:hover,#pnlFileList .selected,#pnlFileList .selected:hover,#menuFile a:hover{background-color:#009!important;color:#FFF}#pnlDirList .selected,#pnlDirList div.selected:hover{background-color:#DFD!important}.dialog input,#fileUploads{width:97%}.filesize{font-weight:bold;margin-top:4px;display:inline-block}.pnlDragFile,.pnlDragDir{background:#FFF;opacity:.8;float:left;width:auto!important}#pnlStatus{padding:5px}.scrollPane{height:400px;overflow:auto}.bottomLine{background:#DDD;border-top:1px solid #CCC}.pale{opacity:.5}#txtSearch,#ddlOrder{border:1px solid #CCC;border-radius:3px}#txtSearch{padding:0 22px 0 3px;background:url(../images/search.png) no-repeat 87px center;width:80px;height:20px}input[type=text]::-ms-clear{display:none}.pnlDirs{width:260px;overflow:auto;border-right:1px solid #DDD}#pnlDirList{margin-left:4px}#pnlDirList ul{padding:0 0 0 20px}#pnlDirList .dir{line-height:30px;float:left;margin-right:5px}#pnlDirList .dirPlus{float:left;margin:3px 3px 0 0}#pnlDirList li,#pnlDirList div{float:left;clear:both;width:98%}#pnlDirList div{padding:3px;cursor:pointer}#pnlLoadingDirs{margin-left:5px}.pnlFiles{padding-left:4px}#pnlFileList .icon{float:left;margin-right:3px}#pnlFileList li{float:left;padding:3px;clear:both;width:98%;cursor:pointer}#pnlFileList li:hover,#pnlDirList li div:hover{background:#ffc!important}#pnlFileList .size{float:right;margin-left:20px}#pnlFileList .time{float:right;margin-left:15px;width:130px}.imgPreview{max-width:300px}.contextMenu{position:absolute;background-color:#DDD;border:1px solid #BBB;min-width:100px;font-weight:bold;z-index:1000!important}.contextMenu a{background-repeat:no-repeat;background-position:4px 6px;padding:5px 25px 5px 20px;display:block;color:#000;text-decoration:none}hr{margin:0;color:#AAA}.actions{padding:3px 0 10px 5px}.actions input{background-repeat:no-repeat;background-position:3px center;padding:0 3px 0 18px;height:22px;font-size:11px;border:1px solid #CCC;background-color:#EEE;border-radius:3px;margin-bottom:3px}.actions input[type=button]:hover,.actions input.selected{background-color:#DFD;cursor:pointer}#btnAddDir,#mnuCreateDir{background-image:url(../images/folder-add.png)}#mnuDownloadDir{background-image:url(../images/folder-download.png)}#btnDeleteDir,#mnuDeleteDir{background-image:url(../images/folder-delete.png)}#btnAddFile{background-image:url(../images/file-add.png)}#btnDeleteFile,#mnuDeleteFile{background-image:url(../images/file-delete.png)}#btnDeleteFile{margin-right:15px}#btnDownloadFile,#mnuDownload{background-image:url(../images/file-download.png)}#btnPreviewFile,#mnuPreview{background-image:url(../images/preview.png)}#btnSelectFile,#mnuSelectFile{background-image:url(../images/select.png)}#btnThumbView{background-image:url(../images/view-tile.png);background-position:center center}#btnListView{background-image:url(../images/view-list.png);background-position:center center}#btnRenameFile,#btnRenameDir,#mnuRenameDir,#mnuRenameFile{background-image:url(../images/rename.png)}#mnuDirCut,#mnuFileCut{background-image:url(../images/cut.png)}#mnuDirCopy,#mnuFileCopy{background-image:url(../images/copy.png)}#mnuDirPaste,#mnuFilePaste{background-image:url(../images/paste.png)}ul#pnlFileList.thumbView li{float:left!important;clear:none;margin:0 6px 6px 0;overflow:hidden;padding:10px;text-align:center;vertical-align:middle;border:1px solid #EEE;border-radius:5px;position:relative;background:#EEE}ul#pnlFileList.thumbView .name,ul#pnlFileList.thumbView .time{display:none}ul#pnlFileList.thumbView .icon{clear:both;float:none;margin:0!important;text-align:center;vertical-align:middle;background-position:center center;background-repeat:no-repeat}ul#pnlFileList.thumbView .size{display:block!important;width:95%!important;position:absolute;bottom:5px;margin:0}div.ui-tooltip{max-width:90%} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/action-folder-paste.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/action-folder-paste.png new file mode 100644 index 0000000000..438a639c8e Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/action-folder-paste.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/action-folder-rename.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/action-folder-rename.png new file mode 100644 index 0000000000..34ec67629a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/action-folder-rename.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/arrow_down.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/arrow_down.png new file mode 100644 index 0000000000..691f6e0c7c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/arrow_down.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/arrow_up.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/arrow_up.png new file mode 100644 index 0000000000..30d005f256 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/arrow_up.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/blank.gif b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/blank.gif new file mode 100644 index 0000000000..3a46969559 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/blank.gif differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/copy.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/copy.png new file mode 100644 index 0000000000..249dcc510a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/copy.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/cut.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/cut.png new file mode 100644 index 0000000000..d2576bd7ae Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/cut.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/dir-minus.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/dir-minus.png new file mode 100644 index 0000000000..61b95f8cb7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/dir-minus.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/dir-plus.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/dir-plus.png new file mode 100644 index 0000000000..2f08324416 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/dir-plus.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-add.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-add.png new file mode 100644 index 0000000000..4fb28bf723 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-add.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-delete.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-delete.png new file mode 100644 index 0000000000..dd1c0a4f8d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-delete.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-download.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-download.png new file mode 100644 index 0000000000..e01eabbb10 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-download.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-duplicate.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-duplicate.png new file mode 100644 index 0000000000..34106e0c08 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-duplicate.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-upload.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-upload.png new file mode 100644 index 0000000000..2119894180 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/file-upload.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_3gp.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_3gp.png new file mode 100644 index 0000000000..35a05dd0a4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_3gp.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_7z.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_7z.png new file mode 100644 index 0000000000..5ed205bb95 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_7z.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ace.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ace.png new file mode 100644 index 0000000000..799604d967 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ace.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ai.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ai.png new file mode 100644 index 0000000000..078057f6f9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ai.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_aif.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_aif.png new file mode 100644 index 0000000000..02ba441724 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_aif.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_aiff.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_aiff.png new file mode 100644 index 0000000000..45f6c27ef5 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_aiff.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_amr.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_amr.png new file mode 100644 index 0000000000..4c30c8ce26 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_amr.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_asf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_asf.png new file mode 100644 index 0000000000..f65286f422 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_asf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_asx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_asx.png new file mode 100644 index 0000000000..9ac440b4c8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_asx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bat.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bat.png new file mode 100644 index 0000000000..ba72c7f896 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bat.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bin.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bin.png new file mode 100644 index 0000000000..adc7af36c7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bin.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bmp.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bmp.png new file mode 100644 index 0000000000..485cde8032 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bmp.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bup.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bup.png new file mode 100644 index 0000000000..5e25354d13 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_bup.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cab.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cab.png new file mode 100644 index 0000000000..0e19a97312 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cab.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cbr.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cbr.png new file mode 100644 index 0000000000..37d886aa04 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cbr.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cda.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cda.png new file mode 100644 index 0000000000..c50b7519c8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cda.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cdl.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cdl.png new file mode 100644 index 0000000000..cb57905683 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cdl.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cdr.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cdr.png new file mode 100644 index 0000000000..d6def9e36c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_cdr.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_chm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_chm.png new file mode 100644 index 0000000000..7a993614b7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_chm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dat.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dat.png new file mode 100644 index 0000000000..9567f6af54 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dat.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_divx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_divx.png new file mode 100644 index 0000000000..99cb983eca Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_divx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dll.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dll.png new file mode 100644 index 0000000000..7ac35c9846 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dll.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dmg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dmg.png new file mode 100644 index 0000000000..a2c644bddc Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dmg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_doc.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_doc.png new file mode 100644 index 0000000000..8738d2eb21 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_doc.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dss.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dss.png new file mode 100644 index 0000000000..d51df3c293 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dss.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dvf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dvf.png new file mode 100644 index 0000000000..62bbb95aa4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dvf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dwg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dwg.png new file mode 100644 index 0000000000..0199681774 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_dwg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_eml.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_eml.png new file mode 100644 index 0000000000..6c973fcde8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_eml.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_eps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_eps.png new file mode 100644 index 0000000000..009582ced9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_eps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_exe.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_exe.png new file mode 100644 index 0000000000..c9cec75704 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_exe.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_fla.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_fla.png new file mode 100644 index 0000000000..648b1d0735 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_fla.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_flv.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_flv.png new file mode 100644 index 0000000000..ccc1eb7f31 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_flv.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_gif.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_gif.png new file mode 100644 index 0000000000..b1aa6c3d10 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_gif.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_gz.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_gz.png new file mode 100644 index 0000000000..d4517e1c16 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_gz.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_hqx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_hqx.png new file mode 100644 index 0000000000..ae7cc0620d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_hqx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_htm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_htm.png new file mode 100644 index 0000000000..061ff46943 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_htm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_html.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_html.png new file mode 100644 index 0000000000..d86548cd52 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_html.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ifo.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ifo.png new file mode 100644 index 0000000000..89b0166a4c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ifo.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_indd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_indd.png new file mode 100644 index 0000000000..0cbaadc72b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_indd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_iso.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_iso.png new file mode 100644 index 0000000000..e8df06db98 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_iso.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jar.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jar.png new file mode 100644 index 0000000000..383aea4fa1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jar.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jpeg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jpeg.png new file mode 100644 index 0000000000..68e38ab252 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jpeg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jpg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jpg.png new file mode 100644 index 0000000000..39be8180d7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_jpg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_lnk.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_lnk.png new file mode 100644 index 0000000000..2b05f43030 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_lnk.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_log.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_log.png new file mode 100644 index 0000000000..bc99e85cf4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_log.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4a.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4a.png new file mode 100644 index 0000000000..d7c86c3c7d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4a.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4b.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4b.png new file mode 100644 index 0000000000..8a73d4e5aa Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4b.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4p.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4p.png new file mode 100644 index 0000000000..f9d90b924c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4p.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4v.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4v.png new file mode 100644 index 0000000000..c7b0b1f7e9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_m4v.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mcd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mcd.png new file mode 100644 index 0000000000..c268b87dff Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mcd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mdb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mdb.png new file mode 100644 index 0000000000..7b7b83611d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mdb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mid.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mid.png new file mode 100644 index 0000000000..4d3e482836 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mid.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mov.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mov.png new file mode 100644 index 0000000000..6a9186516f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mov.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mp2.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mp2.png new file mode 100644 index 0000000000..bbc5f049c6 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mp2.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mp4.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mp4.png new file mode 100644 index 0000000000..caa154cea3 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mp4.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mpeg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mpeg.png new file mode 100644 index 0000000000..81994a291a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mpeg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mpg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mpg.png new file mode 100644 index 0000000000..948b643180 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mpg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_msi.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_msi.png new file mode 100644 index 0000000000..97a8a3b191 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_msi.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mswmm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mswmm.png new file mode 100644 index 0000000000..d70aaa75ba Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_mswmm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ogg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ogg.png new file mode 100644 index 0000000000..a6b55f6cc2 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ogg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pdf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pdf.png new file mode 100644 index 0000000000..04423b4965 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pdf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_png.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_png.png new file mode 100644 index 0000000000..76230d3060 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_png.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pps.png new file mode 100644 index 0000000000..44a2d2c7e8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ps.png new file mode 100644 index 0000000000..0e4b20ae0f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_psd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_psd.png new file mode 100644 index 0000000000..b98ff86015 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_psd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pst.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pst.png new file mode 100644 index 0000000000..4f5f61f424 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pst.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ptb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ptb.png new file mode 100644 index 0000000000..a3568dd4d5 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ptb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pub.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pub.png new file mode 100644 index 0000000000..4a71c01b60 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_pub.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qbb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qbb.png new file mode 100644 index 0000000000..24fc0ae534 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qbb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qbw.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qbw.png new file mode 100644 index 0000000000..162b0fb9b5 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qbw.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qxd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qxd.png new file mode 100644 index 0000000000..f5e46cff8a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_qxd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ram.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ram.png new file mode 100644 index 0000000000..a55ba848a1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ram.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rar.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rar.png new file mode 100644 index 0000000000..934f18247f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rar.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rm.png new file mode 100644 index 0000000000..639e180215 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rmvb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rmvb.png new file mode 100644 index 0000000000..362ffdfce1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rmvb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rtf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rtf.png new file mode 100644 index 0000000000..cae2c95cff Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_rtf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sea.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sea.png new file mode 100644 index 0000000000..d9906e2e0d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sea.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ses.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ses.png new file mode 100644 index 0000000000..b62459b768 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ses.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sit.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sit.png new file mode 100644 index 0000000000..629270d3f1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sit.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sitx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sitx.png new file mode 100644 index 0000000000..4c7a0855e9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_sitx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ss.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ss.png new file mode 100644 index 0000000000..a3a1dbcf73 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ss.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_swf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_swf.png new file mode 100644 index 0000000000..3de371311f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_swf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tgz.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tgz.png new file mode 100644 index 0000000000..b896b27673 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tgz.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_thm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_thm.png new file mode 100644 index 0000000000..0f6bbae201 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_thm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tif.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tif.png new file mode 100644 index 0000000000..c7d4da88f7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tif.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tmp.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tmp.png new file mode 100644 index 0000000000..75e014ee90 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_tmp.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_torrent.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_torrent.png new file mode 100644 index 0000000000..6e8003c424 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_torrent.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ttf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ttf.png new file mode 100644 index 0000000000..dda399e3df Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_ttf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_txt.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_txt.png new file mode 100644 index 0000000000..1e7c12f801 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_txt.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_vcd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_vcd.png new file mode 100644 index 0000000000..d066ecbbeb Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_vcd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_vob.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_vob.png new file mode 100644 index 0000000000..2de5bed7d3 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_vob.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wav.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wav.png new file mode 100644 index 0000000000..a8d7b142d7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wav.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wma.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wma.png new file mode 100644 index 0000000000..e699f0baac Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wma.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wmv.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wmv.png new file mode 100644 index 0000000000..98001f5451 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wmv.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wps.png new file mode 100644 index 0000000000..0e7cbc05cc Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_wps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_xls.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_xls.png new file mode 100644 index 0000000000..4a394e527d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_xls.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_xpi.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_xpi.png new file mode 100644 index 0000000000..4ff58d7e42 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_xpi.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_zip.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_zip.png new file mode 100644 index 0000000000..3b1b54fd45 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/file_extension_zip.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/unknown.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/unknown.png new file mode 100644 index 0000000000..098859c245 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/big/unknown.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_3gp.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_3gp.png new file mode 100644 index 0000000000..4065bdfd90 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_3gp.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_7z.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_7z.png new file mode 100644 index 0000000000..81e33ebe16 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_7z.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ace.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ace.png new file mode 100644 index 0000000000..912abbd9be Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ace.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ai.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ai.png new file mode 100644 index 0000000000..762346076e Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ai.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_aif.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_aif.png new file mode 100644 index 0000000000..9edd1c0f4f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_aif.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_aiff.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_aiff.png new file mode 100644 index 0000000000..6bd4ab7a60 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_aiff.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_amr.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_amr.png new file mode 100644 index 0000000000..9fa593557f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_amr.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_asf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_asf.png new file mode 100644 index 0000000000..2ff894edd6 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_asf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_asx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_asx.png new file mode 100644 index 0000000000..28f610a6df Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_asx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bat.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bat.png new file mode 100644 index 0000000000..1edba7688f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bat.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bin.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bin.png new file mode 100644 index 0000000000..4c5411efb8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bin.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bmp.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bmp.png new file mode 100644 index 0000000000..42aa0026f2 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bmp.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bup.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bup.png new file mode 100644 index 0000000000..ce04201323 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_bup.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cab.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cab.png new file mode 100644 index 0000000000..74aef831b7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cab.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cbr.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cbr.png new file mode 100644 index 0000000000..9b79766cc3 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cbr.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cda.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cda.png new file mode 100644 index 0000000000..e9045442ff Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cda.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cdl.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cdl.png new file mode 100644 index 0000000000..e52bc641f1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cdl.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cdr.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cdr.png new file mode 100644 index 0000000000..277b23d0e5 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_cdr.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_chm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_chm.png new file mode 100644 index 0000000000..3d7b07c515 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_chm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dat.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dat.png new file mode 100644 index 0000000000..758a0e1c1a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dat.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_divx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_divx.png new file mode 100644 index 0000000000..204c9d0c8b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_divx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dll.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dll.png new file mode 100644 index 0000000000..49111a90be Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dll.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dmg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dmg.png new file mode 100644 index 0000000000..d8d6a81c16 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dmg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_doc.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_doc.png new file mode 100644 index 0000000000..dfd46f9ce9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_doc.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dss.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dss.png new file mode 100644 index 0000000000..4752a952c4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dss.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dvf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dvf.png new file mode 100644 index 0000000000..27e4c2358b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dvf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dwg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dwg.png new file mode 100644 index 0000000000..9dd4c903fb Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_dwg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_eml.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_eml.png new file mode 100644 index 0000000000..e6f3174fb0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_eml.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_eps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_eps.png new file mode 100644 index 0000000000..919089b353 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_eps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_exe.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_exe.png new file mode 100644 index 0000000000..09bbde7eaf Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_exe.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_fla.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_fla.png new file mode 100644 index 0000000000..81f80e9a41 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_fla.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_flv.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_flv.png new file mode 100644 index 0000000000..043623c4d8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_flv.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_gif.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_gif.png new file mode 100644 index 0000000000..efa8206090 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_gif.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_gz.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_gz.png new file mode 100644 index 0000000000..f391025d7e Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_gz.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_hqx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_hqx.png new file mode 100644 index 0000000000..e1fe0bee23 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_hqx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_htm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_htm.png new file mode 100644 index 0000000000..bcd6f0e15c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_htm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_html.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_html.png new file mode 100644 index 0000000000..a78b68e37b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_html.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ifo.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ifo.png new file mode 100644 index 0000000000..541c14efc0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ifo.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_indd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_indd.png new file mode 100644 index 0000000000..812e3c012b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_indd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_iso.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_iso.png new file mode 100644 index 0000000000..f1e060e539 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_iso.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jar.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jar.png new file mode 100644 index 0000000000..f77a21c38f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jar.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jpeg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jpeg.png new file mode 100644 index 0000000000..a69dff9948 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jpeg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jpg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jpg.png new file mode 100644 index 0000000000..6ec08d7d49 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_jpg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_lnk.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_lnk.png new file mode 100644 index 0000000000..8306dbbfcf Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_lnk.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_log.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_log.png new file mode 100644 index 0000000000..ae294cfaa0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_log.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4a.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4a.png new file mode 100644 index 0000000000..9518f75d47 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4a.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4b.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4b.png new file mode 100644 index 0000000000..f0888c7393 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4b.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4p.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4p.png new file mode 100644 index 0000000000..a7d89042a3 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4p.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4v.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4v.png new file mode 100644 index 0000000000..cf0f2cfed9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_m4v.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mcd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mcd.png new file mode 100644 index 0000000000..403ecad8be Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mcd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mdb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mdb.png new file mode 100644 index 0000000000..a74b16d60b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mdb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mid.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mid.png new file mode 100644 index 0000000000..07887a064b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mid.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mov.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mov.png new file mode 100644 index 0000000000..75075c7819 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mov.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mp2.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mp2.png new file mode 100644 index 0000000000..704a347e04 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mp2.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mp4.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mp4.png new file mode 100644 index 0000000000..ecc3d28342 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mp4.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mpeg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mpeg.png new file mode 100644 index 0000000000..6518619a22 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mpeg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mpg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mpg.png new file mode 100644 index 0000000000..d01440fe28 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mpg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_msi.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_msi.png new file mode 100644 index 0000000000..3f53d37854 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_msi.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mswmm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mswmm.png new file mode 100644 index 0000000000..f8c4fc8268 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_mswmm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ogg.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ogg.png new file mode 100644 index 0000000000..874915f710 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ogg.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pdf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pdf.png new file mode 100644 index 0000000000..ef52e6a4d8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pdf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_png.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_png.png new file mode 100644 index 0000000000..812e3c012b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_png.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pps.png new file mode 100644 index 0000000000..3964c49235 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ps.png new file mode 100644 index 0000000000..9bd9e03df4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_psd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_psd.png new file mode 100644 index 0000000000..d3f6ec562b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_psd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pst.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pst.png new file mode 100644 index 0000000000..5da647e5d0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pst.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ptb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ptb.png new file mode 100644 index 0000000000..8250def1cf Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ptb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pub.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pub.png new file mode 100644 index 0000000000..806b8ba37a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_pub.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qbb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qbb.png new file mode 100644 index 0000000000..5e4d56b863 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qbb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qbw.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qbw.png new file mode 100644 index 0000000000..7e20ff067f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qbw.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qxd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qxd.png new file mode 100644 index 0000000000..577f6efd0d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_qxd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ram.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ram.png new file mode 100644 index 0000000000..18a73cd5c0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ram.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rar.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rar.png new file mode 100644 index 0000000000..6a94dd89cd Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rar.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rm.png new file mode 100644 index 0000000000..ca0983bbd9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rmvb.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rmvb.png new file mode 100644 index 0000000000..9c533a0505 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rmvb.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rtf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rtf.png new file mode 100644 index 0000000000..a7efed7e31 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_rtf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sea.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sea.png new file mode 100644 index 0000000000..03f87f879a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sea.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ses.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ses.png new file mode 100644 index 0000000000..a85638623e Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ses.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sit.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sit.png new file mode 100644 index 0000000000..98206fc2e3 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sit.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sitx.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sitx.png new file mode 100644 index 0000000000..3c3bb4c44e Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_sitx.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ss.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ss.png new file mode 100644 index 0000000000..7d056d0241 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ss.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_swf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_swf.png new file mode 100644 index 0000000000..5650971b09 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_swf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tgz.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tgz.png new file mode 100644 index 0000000000..5253aab3d0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tgz.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_thm.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_thm.png new file mode 100644 index 0000000000..b3acbb1c8c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_thm.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tif.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tif.png new file mode 100644 index 0000000000..a284f79764 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tif.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tmp.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tmp.png new file mode 100644 index 0000000000..80c165b033 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_tmp.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_torrent.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_torrent.png new file mode 100644 index 0000000000..09de7ab1d4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_torrent.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ttf.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ttf.png new file mode 100644 index 0000000000..51a0bbb6ef Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_ttf.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_txt.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_txt.png new file mode 100644 index 0000000000..e3bed85703 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_txt.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_vcd.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_vcd.png new file mode 100644 index 0000000000..5380d08d00 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_vcd.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_vob.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_vob.png new file mode 100644 index 0000000000..5a5dde849b Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_vob.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wav.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wav.png new file mode 100644 index 0000000000..6897534d98 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wav.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wma.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wma.png new file mode 100644 index 0000000000..63f5d343b5 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wma.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wmv.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wmv.png new file mode 100644 index 0000000000..4017f86712 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wmv.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wps.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wps.png new file mode 100644 index 0000000000..69154a0218 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_wps.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_xls.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_xls.png new file mode 100644 index 0000000000..a5cb228dde Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_xls.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_xpi.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_xpi.png new file mode 100644 index 0000000000..dea5e195ad Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_xpi.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_zip.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_zip.png new file mode 100644 index 0000000000..f0756cd29c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/file_extension_zip.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/unknown.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/unknown.png new file mode 100644 index 0000000000..3ea3d5d6b5 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/filetypes/unknown.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/find.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/find.png new file mode 100644 index 0000000000..1d6f4f13fc Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/find.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-add.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-add.png new file mode 100644 index 0000000000..537184e705 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-add.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-delete.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-delete.png new file mode 100644 index 0000000000..ae496495d1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-delete.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-download.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-download.png new file mode 100644 index 0000000000..e307dec1ca Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-download.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-green.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-green.png new file mode 100644 index 0000000000..cee10d35fe Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-green.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-opened.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-opened.png new file mode 100644 index 0000000000..2a5ce8e015 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder-opened.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder.png new file mode 100644 index 0000000000..31265a4840 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/folder.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/loading-dir.gif b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/loading-dir.gif new file mode 100644 index 0000000000..bf510daca0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/loading-dir.gif differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/loading.gif b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/loading.gif new file mode 100644 index 0000000000..f5ca885452 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/loading.gif differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/paste.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/paste.png new file mode 100644 index 0000000000..468189e950 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/paste.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/preview.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/preview.png new file mode 100644 index 0000000000..ef29588dc6 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/preview.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/rename.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/rename.png new file mode 100644 index 0000000000..34ec67629a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/rename.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/search.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/search.png new file mode 100644 index 0000000000..b81b18de12 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/search.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/select.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/select.png new file mode 100644 index 0000000000..dc951d454a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/select.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/upload-big.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/upload-big.png new file mode 100644 index 0000000000..777056ea08 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/upload-big.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/view-list.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/view-list.png new file mode 100644 index 0000000000..8a08b5224d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/view-list.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/view-tile.png b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/view-tile.png new file mode 100644 index 0000000000..4a0c64e663 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/images/view-tile.png differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/index.html b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/index.html new file mode 100644 index 0000000000..9155ec4991 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/index.html @@ -0,0 +1,149 @@ + + + + + +Roxy file manager + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + +
    +
    + Loading directories...
    + +
    +
    +
      +
      +
      + + +
      + + + + + + +
      + Order by: +    + +    + +
      +
      +
      +
      + Loading files...
      + +
      +
      + This folder is empty +
      +
      + No files found +
      +
        +
        +
        +
        +    © 2013 - RoxyFileman + +
        Status bar
        +
        + + + +
        +
        + + +
        + Select files to upload
        + +
        +
        +
        + + +
        +
        + +
        +
        +
        + +
        + + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/custom.js b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/custom.js new file mode 100644 index 0000000000..13b36dad8b --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/custom.js @@ -0,0 +1,38 @@ +/* + RoxyFileman - web based file manager. Ready to use with CKEditor, TinyMCE. + Can be easily integrated with any other WYSIWYG editor or CMS. + + Copyright (C) 2013, RoxyFileman.com - Lyubomir Arsov. All rights reserved. + For licensing, see LICENSE.txt or http://RoxyFileman.com/license + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Contact: Lyubomir Arsov, liubo (at) web-lobby.com +*/ +function FileSelected(file){ + /** + * file is an object containing following properties: + * + * fullPath - path to the file - absolute from your site root + * path - directory in which the file is located - absolute from your site root + * size - size of the file in bytes + * time - timestamo of last modification + * name - file name + * ext - file extension + * width - if the file is image, this will be the width of the original image, 0 otherwise + * height - if the file is image, this will be the height of the original image, 0 otherwise + * + */ + alert(file.fullPath + "' selected.\n To integrate with CKEditor or TinyMCE change INTEGRATION setting in conf.json. For more details see the installation instructions at http:www.roxyfileman.com.\n Edit js/custom.js to setup your own implementation."); +} + diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/directory.js b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/directory.js new file mode 100644 index 0000000000..dba2a7e89e --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/directory.js @@ -0,0 +1,506 @@ +/* + RoxyFileman - web based file manager. Ready to use with CKEditor, TinyMCE. + Can be easily integrated with any other WYSIWYG editor or CMS. + + Copyright (C) 2013, RoxyFileman.com - Lyubomir Arsov. All rights reserved. + For licensing, see LICENSE.txt or http://RoxyFileman.com/license + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Contact: Lyubomir Arsov, liubo (at) web-lobby.com +*/ +function Directory(fullPath, numDirs, numFiles){ + if(!fullPath) fullPath = ''; + this.fullPath = fullPath; + this.name = RoxyUtils.GetFilename(fullPath); + if(!this.name) + this.name = 'My files'; + this.path = RoxyUtils.GetPath(fullPath); + this.dirs = (numDirs?numDirs:0); + this.files = (numFiles?numFiles:0); + this.filesList = new Array(); + + this.Show = function(){ + var html = this.GetHtml(); + var el = null; + el = $('li[data-path="'+this.path+'"]'); + if(el.length == 0) + el = $('#pnlDirList'); + else{ + if(el.children('ul').length == 0) + el.append('
          '); + el = el.children('ul'); + } + if(el){ + el.append(html); + this.SetEvents(); + } + }; + this.SetEvents = function(){ + var el = this.GetElement(); + el.draggable({helper:makeDragDir,start:startDragDir,cursorAt: { left: 10 ,top:10},delay:200}); + el = el.children('div'); + el.click(function(e){ + selectDir(this); + }); + + el.bind('contextmenu', function(e) { + e.stopPropagation(); + e.preventDefault(); + closeMenus('file'); + selectDir(this); + var t = e.pageY - $('#menuDir').height(); + if(t < 0) + t = 0; + $('#menuDir').css({ + top: t+'px', + left: e.pageX+'px' + }).show(); + + return false; + }); + + el.droppable({drop:moveObject,over:dragFileOver,out:dragFileOut}); + el = el.children('.dirPlus'); + el.click(function(e){ + e.stopPropagation(); + var d = Directory.Parse($(this).closest('li').attr('data-path')); + d.Expand(); + }); + }; + this.GetHtml = function(){ + var html = '
        • '; + html += '
          '; + html += ''+this.name+' ('+this.files+')
          '; + html += '
        • '; + + return html; + }; + this.SetStatusBar = function(){ + $('#pnlStatus').html(this.files+' '+(this.files == 1?t('file'):t('files'))); + }; + this.Select = function(){ + var el = this.GetElement(); + el.children('div').addClass('selected'); + $('#pnlDirList li[data-path!="'+this.fullPath+'"] > div').removeClass('selected'); + el.children('img.dir').prop('src', 'images/folder.png'); + this.SetStatusBar(); + var p = this.GetParent(); + while(p){ + p.Expand(true); + p = p.GetParent(); + } + this.Expand(true); + this.ListFiles(true); + }; + this.GetElement = function(){ + return $('li[data-path="'+this.fullPath+'"]'); + }; + this.IsExpanded = function(){ + var el = this.GetElement().children('ul'); + return (el && el.is(":visible")); + }; + this.IsListed = function(){ + if($('#hdDir').val() == this.fullPath) + return true; + return false; + }; + this.GetExpanded = function(el){ + var ret = new Array(); + if(!el) + el = $('#pnlDirList'); + el.children('li').each(function(){ + var path = $(this).attr('data-path'); + var d = new Directory(path); + if(d){ + if(d.IsExpanded() && path) + ret.push(path); + ret = ret.concat(d.GetExpanded(d.GetElement().children('ul'))); + } + }); + + return ret; + }; + this.RestoreExpanded = function(expandedDirs){ + for(i = 0; i < expandedDirs.length; i++){ + var d = Directory.Parse(expandedDirs[i]); + if(d) + d.Expand(true); + } + }; + this.GetParent = function(){ + return Directory.Parse(this.path); + }; + this.SetOpened = function(){ + var li = this.GetElement(); + if(li.find('li').length < 1) + li.children('div').children('.dirPlus').prop('src', 'images/blank.gif'); + else if(this.IsExpanded()) + li.children('div').children('.dirPlus').prop('src', 'images/dir-minus.png'); + else + li.children('div').children('.dirPlus').prop('src', 'images/dir-plus.png'); + }; + this.Update = function(newPath){ + var el = this.GetElement(); + if(newPath){ + this.fullPath = newPath; + this.name = RoxyUtils.GetFilename(newPath); + if(!this.name) + this.name = 'My files'; + this.path = RoxyUtils.GetPath(newPath); + } + el.attr('data-path', this.fullPath); + el.attr('data-dirs', this.dirs); + el.attr('data-files', this.files); + el.children('div').children('.name').html(this.name+' ('+this.files+')'); + this.SetOpened(); + }; + this.LoadAll = function (selectedDir) { + var expanded = this.GetExpanded(); + var dirListURL = RoxyFilemanConf.DIRLIST; + if(!dirListURL){ + alert(t('E_ActionDisabled')); + return; + } + $('#pnlLoadingDirs').show(); + $('#pnlDirList').hide(); + dirListURL = RoxyUtils.AddParam(dirListURL, 'type', RoxyUtils.GetUrlParam('type')); + + var dir = this; + $.ajax({ + url: dirListURL, + dataType: 'json', + async:true, + success: function(dirs){ + $('#pnlDirList').children('li').remove(); + for(i = 0; i < dirs.length; i++){ + var d = new Directory(dirs[i].p, dirs[i].d, dirs[i].f); + d.Show(); + } + $('#pnlLoadingDirs').hide(); + $('#pnlDirList').show(); + dir.RestoreExpanded(expanded); + var d = Directory.Parse(selectedDir); + if(d) + d.Select(); + }, + error: function(data){ + $('#pnlLoadingDirs').hide(); + $('#pnlDirList').show(); + alert(t('E_LoadingAjax')+' '+RoxyFilemanConf.DIRLIST); + } + }); + }; + this.Expand = function(show){ + var li = this.GetElement(); + var el = li.children('ul'); + if(this.IsExpanded() && !show) + el.hide(); + else + el.show(); + + this.SetOpened(); + }; + this.Create = function(newName){ + if(!newName) + return false; + else if(!RoxyFilemanConf.CREATEDIR){ + alert(t('E_ActionDisabled')); + return; + } + var url = RoxyUtils.AddParam(RoxyFilemanConf.CREATEDIR, 'd', this.fullPath); + url = RoxyUtils.AddParam(url, 'n', newName); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + item.LoadAll(RoxyUtils.MakePath(item.fullPath, newName)); + ret = true; + } + else{ + alert(data.msg); + } + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+item.name); + } + }); + return ret; + }; + this.Delete = function(){ + if(!RoxyFilemanConf.DELETEDIR){ + alert(t('E_ActionDisabled')); + return; + } + var url = RoxyUtils.AddParam(RoxyFilemanConf.DELETEDIR, 'd', this.fullPath); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + var parent = item.GetParent(); + parent.dirs--; + parent.Update(); + parent.Select(); + item.GetElement().remove(); + ret = true; + } + if(data.msg) + alert(data.msg); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+item.name); + } + }); + return ret; + }; + this.Rename = function(newName){ + if(!newName) + return false; + else if(!RoxyFilemanConf.RENAMEDIR){ + alert(t('E_ActionDisabled')); + return; + } + var url = RoxyUtils.AddParam(RoxyFilemanConf.RENAMEDIR, 'd', this.fullPath); + url = RoxyUtils.AddParam(url, 'n', newName); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + var newPath = RoxyUtils.MakePath(item.path, newName); + item.Update(newPath); + item.Select(); + ret = true; + } + if(data.msg) + alert(data.msg); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+item.name); + } + }); + return ret; + }; + this.Copy = function(newPath){ + if(!RoxyFilemanConf.COPYDIR){ + alert(t('E_ActionDisabled')); + return; + } + var url = RoxyUtils.AddParam(RoxyFilemanConf.COPYDIR, 'd', this.fullPath); + url = RoxyUtils.AddParam(url, 'n', newPath); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + var d = Directory.Parse(newPath); + if(d){ + d.LoadAll(d.fullPath); + } + ret = true; + } + if(data.msg) + alert(data.msg); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+url); + } + }); + return ret; + }; + this.Move = function(newPath){ + if(!newPath) + return false; + else if(!RoxyFilemanConf.MOVEDIR){ + alert(t('E_ActionDisabled')); + return; + } + var url = RoxyUtils.AddParam(RoxyFilemanConf.MOVEDIR, 'd', this.fullPath); + url = RoxyUtils.AddParam(url, 'n', newPath); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + item.LoadAll(RoxyUtils.MakePath(newPath, item.name)); + ret = true; + } + if(data.msg) + alert(data.msg); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+item.name); + } + }); + return ret; + }; + this.ListFiles = function(refresh){ + $('#pnlLoading').show(); + $('#pnlEmptyDir').hide(); + $('#pnlFileList').hide(); + $('#pnlSearchNoFiles').hide(); + this.LoadFiles(refresh); + }; + this.FilesLoaded = function(filesList){ + filesList = this.SortFiles(filesList); + $('#pnlFileList').html(''); + for(i = 0; i < filesList.length; i++){ + var f = filesList[i]; + f.Show(); + } + $('#hdDir').val(this.fullPath); + $('#pnlLoading').hide(); + if($('#pnlFileList').children('li').length == 0) + $('#pnlEmptyDir').show(); + this.files = $('#pnlFileList').children('li').length; + this.Update(); + this.SetStatusBar(); + filterFiles(); + switchView(); + $('#pnlFileList').show(); + }; + this.LoadFiles = function(refresh){ + if(!RoxyFilemanConf.FILESLIST){ + alert(t('E_ActionDisabled')); + return; + } + var ret = new Array(); + var fileURL = RoxyFilemanConf.FILESLIST; + fileURL = RoxyUtils.AddParam(fileURL, 'd', this.fullPath); + fileURL = RoxyUtils.AddParam(fileURL, 'type', RoxyUtils.GetUrlParam('type')); + var item = this; + if(!this.IsListed() || refresh){ + + $.ajax({ + url: fileURL, + dataType: 'json', + async:true, + success: function(files){ + for(i = 0; i < files.length; i++){ + ret.push(new File(files[i].p, files[i].s, files[i].t, files[i].w, files[i].h)); + } + item.FilesLoaded(ret); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+fileURL); + } + }); + } + else{ + $('#pnlFileList li').each(function(){ + ret.push(new File($(this).attr('data-path'), $(this).attr('data-size'), $(this).attr('data-time'), $(this).attr('data-w'), $(this).attr('data-h'))); + }); + item.FilesLoaded(ret); + } + + return ret; + }; + + this.SortByName = function(files, order){ + files.sort(function(a, b){ + var x = (order == 'desc'?0:2) + a = a.name.toLowerCase(); + b = b.name.toLowerCase(); + if(a > b) + return -1 + x; + else if(a < b) + return 1 - x; + else + return 0; + }); + + return files; + }; + this.SortBySize = function(files, order){ + files.sort(function(a, b){ + var x = (order == 'desc'?0:2) + a = parseInt(a.size); + b = parseInt(b.size); + if(a > b) + return -1 + x; + else if(a < b) + return 1 - x; + else + return 0; + }); + + return files; + }; + this.SortByTime = function(files, order){ + files.sort(function(a, b){ + var x = (order == 'desc'?0:2) + a = parseInt(a.time); + b = parseInt(b.time); + if(a > b) + return -1 + x; + else if(a < b) + return 1 - x; + else + return 0; + }); + + return files; + }; + this.SortFiles = function(files){ + var order = $('#ddlOrder').val(); + if(!order) + order = 'name'; + + switch(order){ + case 'size': + files = this.SortBySize(files, 'asc'); + break; + case 'size_desc': + files = this.SortBySize(files, 'desc'); + break; + case 'time': + files = this.SortByTime(files, 'asc'); + break; + case 'time_desc': + files = this.SortByTime(files, 'desc'); + break; + case 'name_desc': + files = this.SortByName(files, 'desc'); + break; + default: + files = this.SortByName(files, 'asc'); + } + + return files; + }; +} +Directory.Parse = function(path){ + var ret = false; + var li = $('#pnlDirList').find('li[data-path="'+path+'"]'); + if(li.length > 0) + ret = new Directory(li.attr('data-path'), li.attr('data-dirs'), li.attr('data-files')); + + return ret; +}; diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/file.js b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/file.js new file mode 100644 index 0000000000..16f6435bd7 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/file.js @@ -0,0 +1,220 @@ +/* + RoxyFileman - web based file manager. Ready to use with CKEditor, TinyMCE. + Can be easily integrated with any other WYSIWYG editor or CMS. + + Copyright (C) 2013, RoxyFileman.com - Lyubomir Arsov. All rights reserved. + For licensing, see LICENSE.txt or http://RoxyFileman.com/license + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Contact: Lyubomir Arsov, liubo (at) web-lobby.com +*/ +function File(filePath, fileSize, modTime, w, h){ + this.fullPath = filePath; + this.type = RoxyUtils.GetFileType(filePath); + this.name = RoxyUtils.GetFilename(filePath); + this.ext = RoxyUtils.GetFileExt(filePath); + this.path = RoxyUtils.GetPath(filePath); + this.icon = RoxyUtils.GetFileIcon(filePath); + this.bigIcon = this.icon.replace('filetypes', 'filetypes/big'); + this.image = filePath; + this.size = (fileSize?fileSize:RoxyUtils.GetFileSize(filePath)); + this.time = modTime; + this.width = (w? w: 0); + this.height = (h? h: 0); + this.Show = function(){ + html = '
        • '; + html += ''; + html += ''+RoxyUtils.FormatDate(new Date(this.time * 1000))+''; + html += ''+this.name+''; + html += ''+RoxyUtils.FormatFileSize(this.size)+''; + html += '
        • '; + $('#pnlFileList').append(html); + var li = $("#pnlFileList li:last"); + li.draggable({helper:makeDragFile,start:startDragFile,cursorAt: { left: 10 ,top:10},delay:200}); + li.click(function(e){ + selectFile(this); + }); + li.dblclick(function(e){ + selectFile(this); + setFile(); + }); + li.tooltip({show:{delay:700},track: true, content:tooltipContent}); + + li.bind('contextmenu', function(e) { + e.stopPropagation(); + e.preventDefault(); + closeMenus('dir'); + selectFile(this); + $(this).tooltip('close'); + var t = e.pageY - $('#menuFile').height(); + if(t < 0) + t = 0; + $('#menuFile').css({ + top: t+'px', + left: e.pageX+'px' + }).show(); + + return false; + }); + }; + this.GetElement = function(){ + return $('li[data-path="'+this.fullPath+'"]'); + }; + this.IsImage = function(){ + var ret = false; + if(this.type == 'image') + ret = true; + return ret; + }; + this.Delete = function(){ + if(!RoxyFilemanConf.DELETEFILE){ + alert(t('E_ActionDisabled')); + return; + } + var deleteUrl = RoxyUtils.AddParam(RoxyFilemanConf.DELETEFILE, 'f', this.fullPath); + var item = this; + $.ajax({ + url: deleteUrl, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + $('li[data-path="'+item.fullPath+'"]').remove(); + var d = Directory.Parse(item.path); + if(d){ + d.files--; + d.Update(); + d.SetStatusBar(); + } + } + else{ + alert(data.msg); + } + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+deleteUrl); + } + }); + }; + this.Rename = function(newName){ + if(!RoxyFilemanConf.RENAMEFILE){ + alert(t('E_ActionDisabled')); + return false; + } + if(!newName) + return false; + var url = RoxyUtils.AddParam(RoxyFilemanConf.RENAMEFILE, 'f', this.fullPath); + url = RoxyUtils.AddParam(url, 'n', newName); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + var newPath = RoxyUtils.MakePath(this.path, newName); + $('li[data-path="'+item.fullPath+'"] .icon').attr('src', RoxyUtils.GetFileIcon(newName)); + $('li[data-path="'+item.fullPath+'"] .name').text(newName); + $('li[data-path="'+newPath+'"]').attr('data-path', newPath); + ret = true; + } + if(data.msg) + alert(data.msg); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+url); + } + }); + return ret; + }; + this.Copy = function(newPath){ + if(!RoxyFilemanConf.COPYFILE){ + alert(t('E_ActionDisabled')); + return; + } + var url = RoxyUtils.AddParam(RoxyFilemanConf.COPYFILE, 'f', this.fullPath); + url = RoxyUtils.AddParam(url, 'n', newPath); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + var d = Directory.Parse(newPath); + if(d){ + d.files++; + d.Update(); + d.SetStatusBar(); + d.ListFiles(true); + } + ret = true; + } + if(data.msg) + alert(data.msg); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+url); + } + }); + return ret; + }; + this.Move = function(newPath){ + if(!RoxyFilemanConf.MOVEFILE){ + alert(t('E_ActionDisabled')); + return; + } + newFullPath = RoxyUtils.MakePath(newPath, this.name); + var url = RoxyUtils.AddParam(RoxyFilemanConf.MOVEFILE, 'f', this.fullPath); + url = RoxyUtils.AddParam(url, 'n', newFullPath); + var item = this; + var ret = false; + $.ajax({ + url: url, + dataType: 'json', + async:false, + success: function(data){ + if(data.res.toLowerCase() == 'ok'){ + $('li[data-path="'+item.fullPath+'"]').remove(); + var d = Directory.Parse(item.path); + if(d){ + d.files--; + d.Update(); + d.SetStatusBar(); + d = Directory.Parse(newPath); + d.files++; + d.Update(); + } + ret = true; + } + if(data.msg) + alert(data.msg); + }, + error: function(data){ + alert(t('E_LoadingAjax')+' '+url); + } + }); + return ret; + }; +} +File.Parse = function(path){ + var ret = false; + var li = $('#pnlFileList').find('li[data-path="'+path+'"]'); + if(li.length > 0) + ret = new File(li.attr('data-path'), li.attr('data-size'), li.attr('data-time'), li.attr('data-w'), li.attr('data-h')); + + return ret; +}; \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/fileman-modified.zip b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/fileman-modified.zip new file mode 100644 index 0000000000..a26b9d8a42 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/fileman-modified.zip differ diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/filetypes.js b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/filetypes.js new file mode 100644 index 0000000000..febec4041f --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/filetypes.js @@ -0,0 +1,120 @@ +/* + RoxyFileman - web based file manager. Ready to use with CKEditor, TinyMCE. + Can be easily integrated with any other WYSIWYG editor or CMS. + + Copyright (C) 2013, RoxyFileman.com - Lyubomir Arsov. All rights reserved. + For licensing, see LICENSE.txt or http://RoxyFileman.com/license + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Contact: Lyubomir Arsov, liubo (at) web-lobby.com +*/ +var fileTypeIcons = new Object(); +fileTypeIcons['3gp'] = 'file_extension_3gp.png'; +fileTypeIcons['7z'] = 'file_extension_7z.png'; +fileTypeIcons['ace'] = 'file_extension_ace.png'; +fileTypeIcons['ai'] = 'file_extension_ai.png'; +fileTypeIcons['aif'] = 'file_extension_aif.png'; +fileTypeIcons['aiff'] = 'file_extension_aiff.png'; +fileTypeIcons['amr'] = 'file_extension_amr.png'; +fileTypeIcons['asf'] = 'file_extension_asf.png'; +fileTypeIcons['asx'] = 'file_extension_asx.png'; +fileTypeIcons['bat'] = 'file_extension_bat.png'; +fileTypeIcons['bin'] = 'file_extension_bin.png'; +fileTypeIcons['bmp'] = 'file_extension_bmp.png'; +fileTypeIcons['bup'] = 'file_extension_bup.png'; +fileTypeIcons['cab'] = 'file_extension_cab.png'; +fileTypeIcons['cbr'] = 'file_extension_cbr.png'; +fileTypeIcons['cda'] = 'file_extension_cda.png'; +fileTypeIcons['cdl'] = 'file_extension_cdl.png'; +fileTypeIcons['cdr'] = 'file_extension_cdr.png'; +fileTypeIcons['chm'] = 'file_extension_chm.png'; +fileTypeIcons['dat'] = 'file_extension_dat.png'; +fileTypeIcons['divx'] = 'file_extension_divx.png'; +fileTypeIcons['dll'] = 'file_extension_dll.png'; +fileTypeIcons['dmg'] = 'file_extension_dmg.png'; +fileTypeIcons['doc'] = 'file_extension_doc.png'; +fileTypeIcons['dss'] = 'file_extension_dss.png'; +fileTypeIcons['dvf'] = 'file_extension_dvf.png'; +fileTypeIcons['dwg'] = 'file_extension_dwg.png'; +fileTypeIcons['eml'] = 'file_extension_eml.png'; +fileTypeIcons['eps'] = 'file_extension_eps.png'; +fileTypeIcons['exe'] = 'file_extension_exe.png'; +fileTypeIcons['fla'] = 'file_extension_fla.png'; +fileTypeIcons['flv'] = 'file_extension_flv.png'; +fileTypeIcons['gif'] = 'file_extension_gif.png'; +fileTypeIcons['gz'] = 'file_extension_gz.png'; +fileTypeIcons['hqx'] = 'file_extension_hqx.png'; +fileTypeIcons['htm'] = 'file_extension_htm.png'; +fileTypeIcons['html'] = 'file_extension_html.png'; +fileTypeIcons['ifo'] = 'file_extension_ifo.png'; +fileTypeIcons['indd'] = 'file_extension_indd.png'; +fileTypeIcons['iso'] = 'file_extension_iso.png'; +fileTypeIcons['jar'] = 'file_extension_jar.png'; +fileTypeIcons['jpeg'] = 'file_extension_jpeg.png'; +fileTypeIcons['jpg'] = 'file_extension_jpg.png'; +fileTypeIcons['lnk'] = 'file_extension_lnk.png'; +fileTypeIcons['log'] = 'file_extension_log.png'; +fileTypeIcons['m4a'] = 'file_extension_m4a.png'; +fileTypeIcons['m4b'] = 'file_extension_m4b.png'; +fileTypeIcons['m4p'] = 'file_extension_m4p.png'; +fileTypeIcons['m4v'] = 'file_extension_m4v.png'; +fileTypeIcons['mcd'] = 'file_extension_mcd.png'; +fileTypeIcons['mdb'] = 'file_extension_mdb.png'; +fileTypeIcons['mid'] = 'file_extension_mid.png'; +fileTypeIcons['mov'] = 'file_extension_mov.png'; +fileTypeIcons['mp2'] = 'file_extension_mp2.png'; +fileTypeIcons['mp4'] = 'file_extension_mp4.png'; +fileTypeIcons['mpeg'] = 'file_extension_mpeg.png'; +fileTypeIcons['mpg'] = 'file_extension_mpg.png'; +fileTypeIcons['msi'] = 'file_extension_msi.png'; +fileTypeIcons['mswmm'] = 'file_extension_mswmm.png'; +fileTypeIcons['ogg'] = 'file_extension_ogg.png'; +fileTypeIcons['pdf'] = 'file_extension_pdf.png'; +fileTypeIcons['png'] = 'file_extension_png.png'; +fileTypeIcons['pps'] = 'file_extension_pps.png'; +fileTypeIcons['ps'] = 'file_extension_ps.png'; +fileTypeIcons['psd'] = 'file_extension_psd.png'; +fileTypeIcons['pst'] = 'file_extension_pst.png'; +fileTypeIcons['ptb'] = 'file_extension_ptb.png'; +fileTypeIcons['pub'] = 'file_extension_pub.png'; +fileTypeIcons['qbb'] = 'file_extension_qbb.png'; +fileTypeIcons['qbw'] = 'file_extension_qbw.png'; +fileTypeIcons['qxd'] = 'file_extension_qxd.png'; +fileTypeIcons['ram'] = 'file_extension_ram.png'; +fileTypeIcons['rar'] = 'file_extension_rar.png'; +fileTypeIcons['rm'] = 'file_extension_rm.png'; +fileTypeIcons['rmvb'] = 'file_extension_rmvb.png'; +fileTypeIcons['rtf'] = 'file_extension_rtf.png'; +fileTypeIcons['sea'] = 'file_extension_sea.png'; +fileTypeIcons['ses'] = 'file_extension_ses.png'; +fileTypeIcons['sit'] = 'file_extension_sit.png'; +fileTypeIcons['sitx'] = 'file_extension_sitx.png'; +fileTypeIcons['ss'] = 'file_extension_ss.png'; +fileTypeIcons['swf'] = 'file_extension_swf.png'; +fileTypeIcons['tgz'] = 'file_extension_tgz.png'; +fileTypeIcons['thm'] = 'file_extension_thm.png'; +fileTypeIcons['tif'] = 'file_extension_tif.png'; +fileTypeIcons['tmp'] = 'file_extension_tmp.png'; +fileTypeIcons['torrent'] = 'file_extension_torrent.png'; +fileTypeIcons['ttf'] = 'file_extension_ttf.png'; +fileTypeIcons['txt'] = 'file_extension_txt.png'; +fileTypeIcons['vcd'] = 'file_extension_vcd.png'; +fileTypeIcons['vob'] = 'file_extension_vob.png'; +fileTypeIcons['wav'] = 'file_extension_wav.png'; +fileTypeIcons['wma'] = 'file_extension_wma.png'; +fileTypeIcons['wmv'] = 'file_extension_wmv.png'; +fileTypeIcons['wps'] = 'file_extension_wps.png'; +fileTypeIcons['xls'] = 'file_extension_xls.png'; +fileTypeIcons['xpi'] = 'file_extension_xpi.png'; +fileTypeIcons['zip'] = 'file_extension_zip.png'; diff --git a/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/jquery-1.10.2.min.js b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/jquery-1.10.2.min.js new file mode 100644 index 0000000000..da4170647d --- /dev/null +++ b/src/Presentation/SmartStore.Web/Administration/Content/filemanager/js/jquery-1.10.2.min.js @@ -0,0 +1,6 @@ +/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery-1.10.2.min.map +*/ +(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="
          ",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
          a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
          t
          ",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
          ",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t +}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/
          ","
          "],tr:[2,"","
          "],col:[2,"","
          "],td:[3,"","
          "],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
          ","
          "]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); +u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("');return b.join("")})}},fileButton:function(b,a,d){if(!(3>arguments.length)){h.call(this,a);var f=this;a.validate&&(this.validate=a.validate);var c=CKEDITOR.tools.extend({},a),e=c.onClick;c.className=(c.className?c.className+" ":"")+"cke_dialog_ui_button";c.onClick=function(c){var d= +a["for"];if(!e||e.call(this,c)!==false){b.getContentElement(d[0],d[1]).submit();this.disable()}};b.on("load",function(){b.getContentElement(a["for"][0],a["for"][1])._.buttons.push(f)});CKEDITOR.ui.dialog.button.call(this,b,c,d)}},html:function(){var b=/^\s*<[\w:]+\s+([^>]*)?>/,a=/^(\s*<[\w:]+(?:\s+[^>]*)?)((?:.|\r|\n)+)$/,d=/\/$/;return function(f,c,e){if(!(3>arguments.length)){var k=[],g=c.html;"<"!=g.charAt(0)&&(g=""+g+"");var i=c.focus;if(i){var j=this.focus;this.focus=function(){("function"== +typeof i?i:j).call(this);this.fire("focus")};c.isFocusable&&(this.isFocusable=this.isFocusable);this.keyboardFocusable=!0}CKEDITOR.ui.dialog.uiElement.call(this,f,c,k,"span",null,null,"");k=k.join("").match(b);g=g.match(a)||["","",""];d.test(g[1])&&(g[1]=g[1].slice(0,-1),g[2]="/"+g[2]);e.push([g[1]," ",k[1]||"",g[2]].join(""))}}}(),fieldset:function(b,a,d,f,c){var e=c.label;this._={children:a};CKEDITOR.ui.dialog.uiElement.call(this,b,c,f,"fieldset",null,null,function(){var a=[];e&&a.push(""+e+"");for(var b=0;ba.getChildCount()?(new CKEDITOR.dom.text(b,CKEDITOR.document)).appendTo(a):a.getChild(0).$.nodeValue=b;return this},getLabel:function(){var b= +CKEDITOR.document.getById(this._.labelId);return!b||1>b.getChildCount()?"":b.getChild(0).getText()},eventProcessors:o},!0);CKEDITOR.ui.dialog.button.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{click:function(){return!this._.disabled?this.fire("click",{dialog:this._.dialog}):!1},enable:function(){this._.disabled=!1;var b=this.getElement();b&&b.removeClass("cke_disabled")},disable:function(){this._.disabled=!0;this.getElement().addClass("cke_disabled")},isVisible:function(){return this.getElement().getFirst().isVisible()}, +isEnabled:function(){return!this._.disabled},eventProcessors:CKEDITOR.tools.extend({},CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,{onClick:function(b,a){this.on("click",function(){a.apply(this,arguments)})}},!0),accessKeyUp:function(){this.click()},accessKeyDown:function(){this.focus()},keyboardFocusable:!0},!0);CKEDITOR.ui.dialog.textInput.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return CKEDITOR.document.getById(this._.inputId)}, +focus:function(){var b=this.selectParentTab();setTimeout(function(){var a=b.getInputElement();a&&a.$.focus()},0)},select:function(){var b=this.selectParentTab();setTimeout(function(){var a=b.getInputElement();a&&(a.$.focus(),a.$.select())},0)},accessKeyUp:function(){this.select()},setValue:function(b){!b&&(b="");return CKEDITOR.ui.dialog.uiElement.prototype.setValue.apply(this,arguments)},keyboardFocusable:!0},n,!0);CKEDITOR.ui.dialog.textarea.prototype=new CKEDITOR.ui.dialog.textInput;CKEDITOR.ui.dialog.select.prototype= +CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return this._.select.getElement()},add:function(b,a,d){var f=new CKEDITOR.dom.element("option",this.getDialog().getParentEditor().document),c=this.getInputElement().$;f.$.text=b;f.$.value=void 0===a||null===a?b:a;void 0===d||null===d?CKEDITOR.env.ie?c.add(f.$):c.add(f.$,null):c.add(f.$,d);return this},remove:function(b){this.getInputElement().$.remove(b);return this},clear:function(){for(var b=this.getInputElement().$;0< +b.length;)b.remove(0);return this},keyboardFocusable:!0},n,!0);CKEDITOR.ui.dialog.checkbox.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{getInputElement:function(){return this._.checkbox.getElement()},setValue:function(b,a){this.getInputElement().$.checked=b;!a&&this.fire("change",{value:b})},getValue:function(){return this.getInputElement().$.checked},accessKeyUp:function(){this.setValue(!this.getValue())},eventProcessors:{onChange:function(b,a){if(!CKEDITOR.env.ie||8','
          + +

          + diff --git a/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/tmpFrameset.html b/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/tmpFrameset.html new file mode 100644 index 0000000000..c2d82aa402 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/tmpFrameset.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + diff --git a/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/wsc.css b/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/wsc.css new file mode 100644 index 0000000000..496d731250 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/wsc.css @@ -0,0 +1,82 @@ +/* +Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +html, body +{ + background-color: transparent; + margin: 0px; + padding: 0px; +} + +body +{ + padding: 10px; +} + +body, td, input, select, textarea +{ + font-size: 11px; + font-family: 'Microsoft Sans Serif' , Arial, Helvetica, Verdana; +} + +.midtext +{ + padding:0px; + margin:10px; +} + +.midtext p +{ + padding:0px; + margin:10px; +} + +.Button +{ + border: #737357 1px solid; + color: #3b3b1f; + background-color: #c7c78f; +} + +.PopupTabArea +{ + color: #737357; + background-color: #e3e3c7; +} + +.PopupTitleBorder +{ + border-bottom: #d5d59d 1px solid; +} +.PopupTabEmptyArea +{ + padding-left: 10px; + border-bottom: #d5d59d 1px solid; +} + +.PopupTab, .PopupTabSelected +{ + border-right: #d5d59d 1px solid; + border-top: #d5d59d 1px solid; + border-left: #d5d59d 1px solid; + padding: 3px 5px 3px 5px; + color: #737357; +} + +.PopupTab +{ + margin-top: 1px; + border-bottom: #d5d59d 1px solid; + cursor: pointer; +} + +.PopupTabSelected +{ + font-weight: bold; + cursor: default; + padding-top: 4px; + border-bottom: #f1f1e3 1px solid; + background-color: #f1f1e3; +} diff --git a/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/wsc.js b/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/wsc.js new file mode 100644 index 0000000000..b53a48cf47 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/editors/ckeditor/plugins/wsc/dialogs/wsc.js @@ -0,0 +1,74 @@ +/* + Copyright (c) 2003-2014, CKSource - Frederico Knabben. All rights reserved. + For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +(function(){function q(a){return a&&a.domId&&a.getInputElement().$?a.getInputElement():a&&a.$?a:!1}function z(a){if(!a)throw"Languages-by-groups list are required for construct selectbox";var c=[],d="",f;for(f in a)for(var g in a[f]){var h=a[f][g];"en_US"==h?d=h:c.push(h)}c.sort();d&&c.unshift(d);return{getCurrentLangGroup:function(c){a:{for(var d in a)for(var f in a[d])if(f.toUpperCase()===c.toUpperCase()){c=d;break a}c=""}return c},setLangList:function(){var c={},d;for(d in a)for(var f in a[d])c[a[d][f]]= +f;return c}()}}var e=function(){var a=function(a,b,f){var f=f||{},g=f.expires;if("number"==typeof g&&g){var h=new Date;h.setTime(h.getTime()+1E3*g);g=f.expires=h}g&&g.toUTCString&&(f.expires=g.toUTCString());var b=encodeURIComponent(b),a=a+"="+b,e;for(e in f)b=f[e],a+="; "+e,!0!==b&&(a+="="+b);document.cookie=a};return{postMessage:{init:function(a){window.addEventListener?window.addEventListener("message",a,!1):window.attachEvent("onmessage",a)},send:function(a){var b=Object.prototype.toString,f= +a.fn||null,g=a.id||"",e=a.target||window,i=a.message||{id:g};a.message&&"[object Object]"==b.call(a.message)&&(a.message.id||(a.message.id=g),i=a.message);a=window.JSON.stringify(i,f);e.postMessage(a,"*")},unbindHandler:function(a){window.removeEventListener?window.removeEventListener("message",a,!1):window.detachEvent("onmessage",a)}},hash:{create:function(){},parse:function(){}},cookie:{set:a,get:function(a){return(a=document.cookie.match(RegExp("(?:^|; )"+a.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, +"\\$1")+"=([^;]*)")))?decodeURIComponent(a[1]):void 0},remove:function(c){a(c,"",{expires:-1})}},misc:{findFocusable:function(a){var b=null;a&&(b=a.find("a[href], area[href], input, select, textarea, button, *[tabindex], *[contenteditable]"));return b},isVisible:function(a){return!(0===a.offsetWidth||0==a.offsetHeight||"none"===(document.defaultView&&document.defaultView.getComputedStyle?document.defaultView.getComputedStyle(a,null).display:a.currentStyle?a.currentStyle.display:a.style.display))}, +hasClass:function(a,b){return!(!a.className||!a.className.match(RegExp("(\\s|^)"+b+"(\\s|$)")))}}}}(),a=a||{};a.TextAreaNumber=null;a.load=!0;a.cmd={SpellTab:"spell",Thesaurus:"thes",GrammTab:"grammar"};a.dialog=null;a.optionNode=null;a.selectNode=null;a.grammerSuggest=null;a.textNode={};a.iframeMain=null;a.dataTemp="";a.div_overlay=null;a.textNodeInfo={};a.selectNode={};a.selectNodeResponce={};a.langList=null;a.langSelectbox=null;a.banner="";a.show_grammar=null;a.div_overlay_no_check=null;a.targetFromFrame= +{};a.onLoadOverlay=null;a.LocalizationComing={};a.OverlayPlace=null;a.LocalizationButton={ChangeTo:{instance:null,text:"Change to"},ChangeAll:{instance:null,text:"Change All"},IgnoreWord:{instance:null,text:"Ignore word"},IgnoreAllWords:{instance:null,text:"Ignore all words"},Options:{instance:null,text:"Options",optionsDialog:{instance:null}},AddWord:{instance:null,text:"Add word"},FinishChecking:{instance:null,text:"Finish Checking"}};a.LocalizationLabel={ChangeTo:{instance:null,text:"Change to"}, +Suggestions:{instance:null,text:"Suggestions"}};var A=function(b){var c,d;for(d in b)c=b[d].instance.getElement().getFirst()||b[d].instance.getElement(),c.setText(a.LocalizationComing[d])},B=function(b){for(var c in b){if(!b[c].instance.setLabel)break;b[c].instance.setLabel(a.LocalizationComing[c])}},j,r;a.framesetHtml=function(b){return"'}; +a.setIframe=function(b,c){var d;d=a.framesetHtml(c);var f=a.iframeNumber+"_"+c;b.getElement().setHtml(d);d=document.getElementById(f);d=d.contentWindow?d.contentWindow:d.contentDocument.document?d.contentDocument.document:d.contentDocument;d.document.open();d.document.write('iframe
          - - - - -
          - -
          Upload in progress…
          -
          - -

          - -

          - -

          JustBoil.me Images Plugin

          - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/editor_plugin.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/editor_plugin.js deleted file mode 100644 index 7595e490d7..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/editor_plugin.js +++ /dev/null @@ -1 +0,0 @@ -(function(){tinymce.PluginManager.requireLangPack('jbimages');tinymce.create('tinymce.plugins.jbImagesPlugin',{init:function(ed,url){ed.addCommand('jbImages',function(){var unixtime_ms=new Date().getTime();ed.windowManager.open({file:url+'/dialog.htm?z'+unixtime_ms,width:330+parseInt(ed.getLang('jbimages.delta_width',0)),height:155+parseInt(ed.getLang('jbimages.delta_height',0)),inline:1},{plugin_url:url})});ed.addButton('jbimages',{title:'jbimages.desc',cmd:'jbImages',image:url+'/img/jbimages-bw.gif'});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('jbimages',n.nodeName=='IMG')})},createControl:function(n,cm){return null},getInfo:function(){return{longname:'JustBoil.me Images Plugin',author:'Viktor Kuzhelnyi',authorurl:'http://justboil.me/',infourl:'http://justboil.me/',version:"2.3"}}});tinymce.PluginManager.add('jbimages',tinymce.plugins.jbImagesPlugin)})(); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/editor_plugin_src.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/editor_plugin_src.js deleted file mode 100644 index 8ebe62af1e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/editor_plugin_src.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Justboil.me - a TinyMCE image upload plugin - * jbimages/plugin.js - * - * Released under Creative Commons Attribution 3.0 Unported License - * - * License: http://creativecommons.org/licenses/by/3.0/ - * Plugin info: http://justboil.me/ - * Author: Viktor Kuzhelnyi - * - * Version: 2.3 released 23/06/2013 - */ - -(function() { - // Load plugin specific language pack - tinymce.PluginManager.requireLangPack('jbimages'); - - tinymce.create('tinymce.plugins.jbImagesPlugin', { - /** - * Initializes the plugin, this will be executed after the plugin has been created. - * This call is done before the editor instance has finished it's initialization so use the onInit event - * of the editor instance to intercept that event. - * - * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in. - * @param {string} url Absolute URL to where the plugin is located. - */ - init : function(ed, url) { - // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample'); - ed.addCommand('jbImages', function() { - var unixtime_ms = new Date().getTime(); - ed.windowManager.open({ - file : url + '/dialog.htm?z' + unixtime_ms, - width : 330 + parseInt(ed.getLang('jbimages.delta_width', 0)), - height : 155 + parseInt(ed.getLang('jbimages.delta_height', 0)), - inline : 1 - }, { - plugin_url : url // Plugin absolute URL - }); - }); - - // Register example button - ed.addButton('jbimages', { - title : 'jbimages.desc', - cmd : 'jbImages', - image : url + '/img/jbimages-bw.gif' - }); - - // Add a node change handler, selects the button in the UI when a image is selected - ed.onNodeChange.add(function(ed, cm, n) { - cm.setActive('jbimages', n.nodeName == 'IMG'); - }); - }, - - /** - * Creates control instances based in the incomming name. This method is normally not - * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons - * but you sometimes need to create more complex controls like listboxes, split buttons etc then this - * method can be used to create those. - * - * @param {String} n Name of the control to create. - * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control. - * @return {tinymce.ui.Control} New control instance or null if no control was created. - */ - createControl : function(n, cm) { - return null; - }, - - /** - * Returns information about the plugin as a name/value array. - * The current keys are longname, author, authorurl, infourl and version. - * - * @return {Object} Name/value array containing information about the plugin. - */ - getInfo : function() { - return { - longname : 'JustBoil.me Images Plugin', - author : 'Viktor Kuzhelnyi', - authorurl : 'http://justboil.me/', - infourl : 'http://justboil.me/', - version : "2.3" - }; - } - }); - - // Register plugin - tinymce.PluginManager.add('jbimages', tinymce.plugins.jbImagesPlugin); -})(); diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/img/jbimages-bw.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/img/jbimages-bw.gif deleted file mode 100644 index f8887eac25..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/img/jbimages-bw.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/img/spinner.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/img/spinner.gif deleted file mode 100644 index 0d8f4f2908..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/img/spinner.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/js/dialog-v4.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/js/dialog-v4.js deleted file mode 100644 index b7179c3f02..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/js/dialog-v4.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Justboil.me - a TinyMCE image upload plugin - * jbimages/js/dialog-v4.js - * - * Released under Creative Commons Attribution 3.0 Unported License - * - * License: http://creativecommons.org/licenses/by/3.0/ - * Plugin info: http://justboil.me/ - * Author: Viktor Kuzhelnyi - * - * Version: 2.3 released 23/06/2013 - */ - -var jbImagesDialog = { - - resized : false, - iframeOpened : false, - timeoutStore : false, - - inProgress : function() { - document.getElementById("upload_infobar").style.display = 'none'; - document.getElementById("upload_additional_info").innerHTML = ''; - document.getElementById("upload_form_container").style.display = 'none'; - document.getElementById("upload_in_progress").style.display = 'block'; - this.timeoutStore = window.setTimeout(function(){ - document.getElementById("upload_additional_info").innerHTML = 'This is taking longer than usual.' + '
          ' + 'An error may have occurred.' + '
          ' + 'View script\'s output' + ''; - // tinyMCEPopup.editor.windowManager.resizeBy(0, 30, tinyMCEPopup.id); - }, 20000); - }, - - showIframe : function() { - if (this.iframeOpened == false) - { - document.getElementById("upload_target").className = 'upload_target_visible'; - // tinyMCEPopup.editor.windowManager.resizeBy(0, 190, tinyMCEPopup.id); - this.iframeOpened = true; - } - }, - - uploadFinish : function(result) { - if (result.resultCode == 'failed') - { - window.clearTimeout(this.timeoutStore); - document.getElementById("upload_in_progress").style.display = 'none'; - document.getElementById("upload_infobar").style.display = 'block'; - document.getElementById("upload_infobar").innerHTML = result.result; - document.getElementById("upload_form_container").style.display = 'block'; - - if (this.resized == false) - { - // tinyMCEPopup.editor.windowManager.resizeBy(0, 30, tinyMCEPopup.id); - this.resized = true; - } - } - else - { - document.getElementById("upload_in_progress").style.display = 'none'; - document.getElementById("upload_infobar").style.display = 'block'; - document.getElementById("upload_infobar").innerHTML = 'Upload Complete'; - - var w = this.getWin(); - tinymce = w.tinymce; - - tinymce.EditorManager.activeEditor.insertContent(''); - - this.close(); - } - }, - - getWin : function() { - return (!window.frameElement && window.dialogArguments) || opener || parent || top; - }, - - close : function() { - var t = this; - - // To avoid domain relaxing issue in Opera - function close() { - tinymce.EditorManager.activeEditor.windowManager.close(window); - tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup - }; - - if (tinymce.isOpera) - this.getWin().setTimeout(close, 0); - else - close(); - } - -}; \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/js/dialog.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/js/dialog.js deleted file mode 100644 index f0c010af45..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/js/dialog.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Justboil.me - a TinyMCE image upload plugin - * jbimages/js/dialog.js - * - * Released under Creative Commons Attribution 3.0 Unported License - * - * License: http://creativecommons.org/licenses/by/3.0/ - * Plugin info: http://justboil.me/ - * Author: Viktor Kuzhelnyi - * - * Version: 2.3 released 23/06/2013 - */ - - tinyMCEPopup.requireLangPack(); - -var jbImagesDialog = { - - resized : false, - iframeOpened : false, - timeoutStore : false, - - init : function() { - document.getElementById("upload_target").src += '/' + tinyMCEPopup.getLang('jbimages_dlg.lang_id', 'english'); - if (navigator.userAgent.indexOf('Opera') > -1) - { - document.getElementById("close_link").style.display = 'block'; - } - }, - - inProgress : function() { - document.getElementById("upload_infobar").style.display = 'none'; - document.getElementById("upload_additional_info").innerHTML = ''; - document.getElementById("upload_form_container").style.display = 'none'; - document.getElementById("upload_in_progress").style.display = 'block'; - this.timeoutStore = window.setTimeout(function(){ - document.getElementById("upload_additional_info").innerHTML = tinyMCEPopup.getLang('jbimages_dlg.longer_than_usual', 0) + '
          ' + tinyMCEPopup.getLang('jbimages_dlg.maybe_an_error', 0) + '
          ' + tinyMCEPopup.getLang('jbimages_dlg.view_output', 0) + ''; - tinyMCEPopup.editor.windowManager.resizeBy(0, 30, tinyMCEPopup.id); - }, 20000); - }, - - showIframe : function() { - if (this.iframeOpened == false) - { - document.getElementById("upload_target").className = 'upload_target_visible'; - tinyMCEPopup.editor.windowManager.resizeBy(0, 190, tinyMCEPopup.id); - this.iframeOpened = true; - } - }, - - uploadFinish : function(result) { - if (result.resultCode == 'failed') - { - window.clearTimeout(this.timeoutStore); - document.getElementById("upload_in_progress").style.display = 'none'; - document.getElementById("upload_infobar").style.display = 'block'; - document.getElementById("upload_infobar").innerHTML = result.result; - document.getElementById("upload_form_container").style.display = 'block'; - - if (this.resized == false) - { - tinyMCEPopup.editor.windowManager.resizeBy(0, 30, tinyMCEPopup.id); - this.resized = true; - } - } - else - { - document.getElementById("upload_in_progress").style.display = 'none'; - document.getElementById("upload_infobar").style.display = 'block'; - document.getElementById("upload_infobar").innerHTML = tinyMCEPopup.getLang('jbimages_dlg.upload_complete', 0); - tinyMCEPopup.editor.execCommand('mceInsertContent', false, ''); - tinyMCEPopup.close(); - } - } - -}; - -tinyMCEPopup.onInit.add(jbImagesDialog.init, jbImagesDialog); diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/de.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/de.js deleted file mode 100644 index 536d895e9b..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/de.js +++ /dev/null @@ -1,4 +0,0 @@ - - tinyMCE.addI18n('de.jbimages',{ - desc : 'Bild hochladen' -}); diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/de_dlg.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/de_dlg.js deleted file mode 100644 index 2cfc0a6cfd..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/de_dlg.js +++ /dev/null @@ -1,13 +0,0 @@ - - tinyMCE.addI18n('de.jbimages_dlg',{ - title : 'Ein Bild vom Computer hochladen', - select_an_image : 'Bild auswhlen', - upload_in_progress : 'Bild wird hochgeladen', - upload_complete : 'Upload abgeschlossen', - upload : 'Upload', - longer_than_usual : 'Das dauert lnger als gewhnlich', - maybe_an_error : 'Es knnte zu einem Fehler gekommen sein.', - view_output : 'Ausgabe ansehen', - - lang_id : 'german' -}); diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/en.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/en.js deleted file mode 100644 index d070f816cf..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/en.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Justboil.me - a TinyMCE image upload plugin - * jbimages/langs/en.js - * - * Released under Creative Commons Attribution 3.0 Unported License - * - * License: http://creativecommons.org/licenses/by/3.0/ - * Plugin info: http://justboil.me/ - * Author: Viktor Kuzhelnyi - * - * Version: 2.3 released 23/06/2013 - */ - - tinyMCE.addI18n('en.jbimages',{ - desc : 'Upload an image' -}); diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/en_dlg.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/en_dlg.js deleted file mode 100644 index b95823057d..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/langs/en_dlg.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Justboil.me - a TinyMCE image upload plugin - * jbimages/langs/en_dlg.js - * - * Released under Creative Commons Attribution 3.0 Unported License - * - * License: http://creativecommons.org/licenses/by/3.0/ - * Plugin info: http://justboil.me/ - * Author: Viktor Kuzhelnyi - * - * Version: 2.3 released 23/06/2013 - */ - - tinyMCE.addI18n('en.jbimages_dlg',{ - title : 'Upload an image from computer', - select_an_image : 'Select an image', - upload_in_progress : 'Upload in progress', - upload_complete : 'Upload Complete', - upload : 'Upload', - longer_than_usual : 'This is taking longer than usual.', - maybe_an_error : 'An error may have occurred.', - view_output : 'View script\'s output', - - lang_id : 'english' /* php-side language files are in: ci/application/language/{lang_id}; and in ci/system/language/{lang_id} */ -}); diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/plugin.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/plugin.js deleted file mode 100644 index b5f5a47bd7..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/plugin.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Justboil.me - a TinyMCE image upload plugin - * jbimages/plugin.js - * - * Released under Creative Commons Attribution 3.0 Unported License - * - * License: http://creativecommons.org/licenses/by/3.0/ - * Plugin info: http://justboil.me/ - * Author: Viktor Kuzhelnyi - * - * Version: 2.3 released 23/06/2013 - */ - -tinymce.PluginManager.add('jbimages', function(editor, url) { - - function jbBox() { - editor.windowManager.open({ - title: 'Upload an image', - file : url + '/dialog-v4.htm', - width : 350, - height: 135, - buttons: [{ - text: 'Upload', - classes:'widget btn primary first abs-layout-item', - disabled : true, - onclick: 'close' - }, - { - text: 'Close', - onclick: 'close' - }] - }); - } - - // Add a button that opens a window - editor.addButton('jbimages', { - tooltip: 'Upload an image', - icon : 'image', - text: 'Upload', - onclick: jbBox - }); - - // Adds a menu item to the tools menu - editor.addMenuItem('jbimages', { - text: 'Upload image', - icon : 'image', - context: 'insert', - onclick: jbBox - }); -}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/plugin.min.js deleted file mode 100644 index 48a2666c99..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add('jbimages',function(editor,url){function jbBox(){editor.windowManager.open({title:'Upload an image',file:url+'/dialog-v4.htm',width:350,height:135,buttons:[{text:'Upload',classes:'widget btn primary first abs-layout-item',disabled:true,onclick:'close'},{text:'Close',onclick:'close'}]})}editor.addButton('jbimages',{tooltip:'Upload an image',icon:'image',text:'Upload',onclick:jbBox});editor.addMenuItem('jbimages',{text:'Upload image',icon:'image',context:'insert',onclick:jbBox})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/readme b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/readme deleted file mode 100644 index e3cb1ba0b2..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/jbimages/readme +++ /dev/null @@ -1,11 +0,0 @@ -|------------| -| | -| README | -| | -|------------| - - -Docs & stuff at: http://justboil.me - --- -Cheers, and have a nice day! )) \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/layer/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/layer/plugin.min.js deleted file mode 100644 index eb1ad4b68d..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/layer/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("layer",function(e){function t(e){do if(e.className&&-1!=e.className.indexOf("mceItemLayer"))return e;while(e=e.parentNode)}function n(t){var n=e.dom;tinymce.each(n.select("div,p",t),function(e){/^(absolute|relative|fixed)$/i.test(e.style.position)&&(e.hasVisual?n.addClass(e,"mceItemVisualAid"):n.removeClass(e,"mceItemVisualAid"),n.addClass(e,"mceItemLayer"))})}function i(n){var i,o,a=[],r=t(e.selection.getNode()),l=-1,s=-1;for(o=[],tinymce.walk(e.getBody(),function(e){1==e.nodeType&&/^(absolute|relative|static)$/i.test(e.style.position)&&o.push(e)},"childNodes"),i=0;il&&o[i]==r&&(l=i);if(0>n){for(i=0;i-1?(o[l].style.zIndex=a[s],o[s].style.zIndex=a[l]):a[l]>0&&(o[l].style.zIndex=a[l]-1)}else{for(i=0;ia[l]){s=i;break}s>-1?(o[l].style.zIndex=a[s],o[s].style.zIndex=a[l]):o[l].style.zIndex=a[l]+1}e.execCommand("mceRepaint")}function o(){var t=e.dom,n=t.getPos(t.getParent(e.selection.getNode(),"*")),i=e.getBody();e.dom.add(i,"div",{style:{position:"absolute",left:n.x,top:n.y>20?n.y:20,width:100,height:100},"class":"mceItemVisualAid mceItemLayer"},e.selection.getContent()||e.getLang("layer.content")),tinymce.Env.ie&&t.setHTML(i,i.innerHTML)}function a(){var n=t(e.selection.getNode());n||(n=e.dom.getParent(e.selection.getNode(),"DIV,P,IMG")),n&&("absolute"==n.style.position.toLowerCase()?(e.dom.setStyles(n,{position:"",left:"",top:"",width:"",height:""}),e.dom.removeClass(n,"mceItemVisualAid"),e.dom.removeClass(n,"mceItemLayer")):(n.style.left||(n.style.left="20px"),n.style.top||(n.style.top="20px"),n.style.width||(n.style.width=n.width?n.width+"px":"100px"),n.style.height||(n.style.height=n.height?n.height+"px":"100px"),n.style.position="absolute",e.dom.setAttrib(n,"data-mce-style",""),e.addVisual(e.getBody())),e.execCommand("mceRepaint"),e.nodeChanged())}e.addCommand("mceInsertLayer",o),e.addCommand("mceMoveForward",function(){i(1)}),e.addCommand("mceMoveBackward",function(){i(-1)}),e.addCommand("mceMakeAbsolute",function(){a()}),e.addButton("moveforward",{title:"layer.forward_desc",cmd:"mceMoveForward"}),e.addButton("movebackward",{title:"layer.backward_desc",cmd:"mceMoveBackward"}),e.addButton("absolute",{title:"layer.absolute_desc",cmd:"mceMakeAbsolute"}),e.addButton("insertlayer",{title:"layer.insertlayer_desc",cmd:"mceInsertLayer"}),e.on("init",function(){tinymce.Env.ie&&e.getDoc().execCommand("2D-Position",!1,!0)}),e.on("mouseup",function(n){var i=t(n.target);i&&e.dom.setAttrib(i,"data-mce-style","")}),e.on("mousedown",function(n){var i,o=n.target,a=e.getDoc();tinymce.Env.gecko&&(t(o)?"on"!==a.designMode&&(a.designMode="on",o=a.body,i=o.parentNode,i.removeChild(o),i.appendChild(o)):"on"==a.designMode&&(a.designMode="off"))}),e.on("NodeChange",n)}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/legacyoutput/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/legacyoutput/plugin.min.js deleted file mode 100644 index 4f6f7c1aa3..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/legacyoutput/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){e.on("AddEditor",function(e){e.editor.settings.inline_styles=!1}),e.PluginManager.add("legacyoutput",function(t){t.on("init",function(){var n="p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img",i=e.explode(t.settings.font_size_style_values),o=t.schema;t.formatter.register({alignleft:{selector:n,attributes:{align:"left"}},aligncenter:{selector:n,attributes:{align:"center"}},alignright:{selector:n,attributes:{align:"right"}},alignjustify:{selector:n,attributes:{align:"justify"}},bold:[{inline:"b",remove:"all"},{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}}],italic:[{inline:"i",remove:"all"},{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}}],underline:[{inline:"u",remove:"all"},{inline:"span",styles:{textDecoration:"underline"},exact:!0}],strikethrough:[{inline:"strike",remove:"all"},{inline:"span",styles:{textDecoration:"line-through"},exact:!0}],fontname:{inline:"font",attributes:{face:"%value"}},fontsize:{inline:"font",attributes:{size:function(t){return e.inArray(i,t.value)+1}}},forecolor:{inline:"font",attributes:{color:"%value"}},hilitecolor:{inline:"font",styles:{backgroundColor:"%value"}}}),e.each("b,i,u,strike".split(","),function(e){o.addValidElements(e+"[*]")}),o.getElementRule("font")||o.addValidElements("font[face|size|color|style]"),e.each(n.split(","),function(e){var t=o.getElementRule(e);t&&(t.attributes.align||(t.attributes.align={},t.attributesOrder.push("align")))})})})}(tinymce); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/link/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/link/plugin.min.js deleted file mode 100644 index 89cdcd13e2..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/link/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("link",function(e){function t(t){return function(){var n=e.settings.link_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(n)}}function n(t){function n(e){var t=f.find("#text");(!t.value()||e.lastControl&&t.value()==e.lastControl.text())&&t.value(e.control.text()),f.find("#href").value(e.control.value())}function l(){var n=[{text:"None",value:""}];return tinymce.each(t,function(t){n.push({text:t.text||t.title,value:e.convertURL(t.value||t.url,"href"),menu:t.menu})}),n}function i(t,n,l){var i,a=[];return tinymce.each(e.settings[t]||l,function(e){var t={text:e.text||e.title,value:e.value};a.push(t),(p[n]===e.value||!i&&e.selected)&&(i=t)}),i&&!p[n]&&(p[n]=i.value,i.selected=!0),a}function a(t){var l=[];return tinymce.each(e.dom.select("a:not([href])"),function(e){var n=e.name||e.id;n&&l.push({text:n,value:"#"+n,selected:-1!=t.indexOf("#"+n)})}),l.length?(l.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:l,onselect:n}):void 0}function r(){v&&v.value(e.convertURL(this.value(),"href")),!c&&0===p.text.length&&d&&this.parent().parent().find("#text")[0].value(this.value())}function o(e){var t=k.getContent();if(/]+>[^<]+<\/a>$/.test(t)||-1==t.indexOf("href=")))return!1;if(e){var n,l=e.childNodes;if(0===l.length)return!1;for(n=l.length-1;n>=0;n--)if(3!=l[n].nodeType)return!1}return!0}var s,u,c,f,d,h,v,x,g,m,p={},k=e.selection,y=e.dom;s=k.getNode(),u=y.getParent(s,"a[href]"),d=o(),p.text=c=u?u.innerText||u.textContent:k.getContent({format:"text"}),p.href=u?y.getAttrib(u,"href"):"",p.target=u?y.getAttrib(u,"target"):e.settings.default_link_target||null,p.rel=u?y.getAttrib(u,"rel"):null,p["class"]=u?y.getAttrib(u,"class"):null,d&&(h={name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){p.text=this.value()}}),t&&(v={type:"listbox",label:"Link list",values:l(),onselect:n,value:e.convertURL(p.href,"href"),onPostRender:function(){v=this}}),e.settings.target_list!==!1&&(g={name:"target",type:"listbox",label:"Target",values:i("target_list","target",[{text:"None",value:""},{text:"New window",value:"_blank"}])}),e.settings.rel_list&&(x={name:"rel",type:"listbox",label:"Rel",values:i("rel_list","rel",[{text:"None",value:""}])}),e.settings.link_class_list&&(m={name:"class",type:"listbox",label:"Class",values:i("link_class_list","class")}),f=e.windowManager.open({title:"Insert link",data:p,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:r,onkeyup:r},h,a(p.href),v,x,g,m],onSubmit:function(t){function n(t,n){var l=e.selection.getRng();window.setTimeout(function(){e.windowManager.confirm(t,function(t){e.selection.setRng(l),n(t)})},0)}function l(){u?(e.focus(),d&&p.text!=c&&(u.innerText=p.text),y.setAttribs(u,{href:i,target:p.target?p.target:null,rel:p.rel?p.rel:null,"class":p["class"]?p["class"]:null}),k.select(u),e.undoManager.add()):d?e.insertContent(y.createHTML("a",{href:i,target:p.target?p.target:null,rel:p.rel?p.rel:null,"class":p["class"]?p["class"]:null},y.encode(p.text))):e.execCommand("mceInsertLink",!1,{href:i,target:p.target,rel:p.rel?p.rel:null})}var i;return p=tinymce.extend(p,t.data),(i=p.href)?i.indexOf("@")>0&&-1==i.indexOf("//")&&-1==i.indexOf("mailto:")?void n("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(e){e&&(i="mailto:"+i),l()}):/^\s*www\./i.test(i)?void n("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(e){e&&(i="http://"+i),l()}):void l():void e.execCommand("unlink")}})}e.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]"}),e.addButton("unlink",{icon:"unlink",tooltip:"Remove link",cmd:"unlink",stateSelector:"a[href]"}),e.addShortcut("Ctrl+K","",t(n)),this.showDialog=n,e.addMenuItem("link",{icon:"link",text:"Insert link",shortcut:"Ctrl+K",onclick:t(n),stateSelector:"a[href]",context:"insert",prependToContext:!0})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/lists/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/lists/plugin.min.js deleted file mode 100644 index 3f1de3972e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/lists/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("lists",function(e){function t(e){return e&&/^(OL|UL)$/.test(e.nodeName)}function n(e){return e.parentNode.firstChild==e}function r(e){return e.parentNode.lastChild==e}function o(t){return t&&!!e.schema.getTextBlockElements()[t.nodeName]}function i(e){return e&&"SPAN"===e.nodeName&&"bookmark"===e.getAttribute("data-mce-type")}var a=this;e.on("init",function(){function d(e){function t(t){var r,o,i;o=e[t?"startContainer":"endContainer"],i=e[t?"startOffset":"endOffset"],1==o.nodeType&&(r=b.create("span",{"data-mce-type":"bookmark"}),o.hasChildNodes()?(i=Math.min(i,o.childNodes.length-1),t?o.insertBefore(r,o.childNodes[i]):b.insertAfter(r,o.childNodes[i])):o.appendChild(r),o=r,i=0),n[t?"startContainer":"endContainer"]=o,n[t?"startOffset":"endOffset"]=i}var n={};return t(!0),e.collapsed||t(),n}function s(e){function t(t){function n(e){for(var t=e.parentNode.firstChild,n=0;t;){if(t==e)return n;(1!=t.nodeType||"bookmark"!=t.getAttribute("data-mce-type"))&&n++,t=t.nextSibling}return-1}var r,o,i;r=i=e[t?"startContainer":"endContainer"],o=e[t?"startOffset":"endOffset"],r&&(1==r.nodeType&&(o=n(r),r=r.parentNode,b.remove(i)),e[t?"startContainer":"endContainer"]=r,e[t?"startOffset":"endOffset"]=o)}t(!0),t();var n=b.createRng();n.setStart(e.startContainer,e.startOffset),e.endContainer&&n.setEnd(e.endContainer,e.endOffset),L.setRng(n)}function f(t,n){var r,o,i,a=b.createFragment(),d=e.schema.getBlockElements();if(e.settings.forced_root_block&&(n=n||e.settings.forced_root_block),n&&(o=b.create(n),o.tagName===e.settings.forced_root_block&&b.setAttribs(o,e.settings.forced_root_block_attrs),a.appendChild(o)),t)for(;r=t.firstChild;){var s=r.nodeName;i||"SPAN"==s&&"bookmark"==r.getAttribute("data-mce-type")||(i=!0),d[s]?(a.appendChild(r),o=null):n?(o||(o=b.create(n),a.appendChild(o)),o.appendChild(r)):a.appendChild(r)}return e.settings.forced_root_block?i||tinymce.Env.ie&&!(tinymce.Env.ie>10)||o.appendChild(b.create("br",{"data-mce-bogus":"1"})):a.appendChild(b.create("br")),a}function l(){return tinymce.grep(L.getSelectedBlocks(),function(e){return"LI"==e.nodeName})}function c(e,t,n){var r,o,i=b.select('span[data-mce-type="bookmark"]',e);n=n||f(t),r=b.createRng(),r.setStartAfter(t),r.setEndAfter(e),o=r.extractContents(),b.isEmpty(o)||b.insertAfter(o,e),b.insertAfter(n,e),b.isEmpty(t.parentNode)&&(tinymce.each(i,function(e){t.parentNode.parentNode.insertBefore(e,t.parentNode)}),b.remove(t.parentNode)),b.remove(t)}function p(e){var n,r;if(n=e.nextSibling,n&&t(n)&&n.nodeName==e.nodeName){for(;r=n.firstChild;)e.appendChild(r);b.remove(n)}if(n=e.previousSibling,n&&t(n)&&n.nodeName==e.nodeName){for(;r=n.firstChild;)e.insertBefore(r,e.firstChild);b.remove(n)}}function u(e){tinymce.each(tinymce.grep(b.select("ol,ul",e)),function(e){var n,r=e.parentNode;"LI"==r.nodeName&&r.firstChild==e&&(n=r.previousSibling,n&&"LI"==n.nodeName&&(n.appendChild(e),b.isEmpty(r)&&b.remove(r))),t(r)&&(n=r.previousSibling,n&&"LI"==n.nodeName&&n.appendChild(e))})}function m(e){function o(e){b.isEmpty(e)&&b.remove(e)}var i,a=e.parentNode,d=a.parentNode;return n(e)&&r(e)?("LI"==d.nodeName?(b.insertAfter(e,d),o(d),b.remove(a)):t(d)?b.remove(a,!0):(d.insertBefore(f(e),a),b.remove(a)),!0):n(e)?("LI"==d.nodeName?(b.insertAfter(e,d),e.appendChild(a),o(d)):t(d)?d.insertBefore(e,a):(d.insertBefore(f(e),a),b.remove(e)),!0):r(e)?("LI"==d.nodeName?b.insertAfter(e,d):t(d)?b.insertAfter(e,a):(b.insertAfter(f(e),a),b.remove(e)),!0):("LI"==d.nodeName?(a=d,i=f(e,"LI")):i=t(d)?f(e,"LI"):f(e),c(a,e,i),u(a.parentNode),!0)}function h(e){function n(n,r){var o;if(t(n)){for(;o=e.lastChild.firstChild;)r.appendChild(o);b.remove(n)}}var r,o;return r=e.previousSibling,r&&t(r)?(r.appendChild(e),!0):r&&"LI"==r.nodeName&&t(r.lastChild)?(r.lastChild.appendChild(e),n(e.lastChild,r.lastChild),!0):(r=e.nextSibling,r&&t(r)?(r.insertBefore(e,r.firstChild),!0):r&&"LI"==r.nodeName&&t(e.lastChild)?!1:(r=e.previousSibling,r&&"LI"==r.nodeName?(o=b.create(e.parentNode.nodeName),r.appendChild(o),o.appendChild(e),n(e.lastChild,o),!0):!1))}function v(){var t=l();if(t.length){for(var n=d(L.getRng(!0)),r=0;r0))return n;for(var o=new tinymce.dom.TreeWalker(e.startContainer);n=o[t?"next":"prev"]();)if(3==n.nodeType&&n.data.length>0)return n}function r(e,n){var r,o,i=e.parentNode;for(t(n.lastChild)&&(o=n.lastChild),r=n.lastChild,r&&"BR"==r.nodeName&&e.hasChildNodes()&&b.remove(r);r=e.firstChild;)n.appendChild(r);o&&n.appendChild(o),b.remove(e),b.isEmpty(i)&&b.remove(i)}if(L.isCollapsed()){var o=b.getParent(L.getStart(),"LI");if(o){var i=L.getRng(!0),a=b.getParent(n(i,e),"LI");if(a&&a!=o){var f=d(i);return e?r(a,o):r(o,a),s(f),!0}if(!a&&!e&&N(o.parentNode.nodeName))return!0}}},e.addCommand("Indent",function(){return v()?void 0:!0}),e.addCommand("Outdent",function(){return C()?void 0:!0}),e.addCommand("InsertUnorderedList",function(){y("UL")}),e.addCommand("InsertOrderedList",function(){y("OL")}),e.on("keydown",function(t){9==t.keyCode&&e.dom.getParent(e.selection.getStart(),"LI")&&(t.preventDefault(),t.shiftKey?C():v())})}),e.addButton("indent",{icon:"indent",title:"Increase indent",cmd:"Indent",onPostRender:function(){var t=this;e.on("nodechange",function(){var r=e.dom.getParent(e.selection.getNode(),"LI,UL,OL");t.disabled(r&&("LI"!=r.nodeName||n(r)))})}}),e.on("keydown",function(e){e.keyCode==tinymce.util.VK.BACKSPACE?a.backspaceDelete()&&e.preventDefault():e.keyCode==tinymce.util.VK.DELETE&&a.backspaceDelete(!0)&&e.preventDefault()})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/media/moxieplayer.swf b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/media/moxieplayer.swf deleted file mode 100644 index 19c771bea5..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/media/moxieplayer.swf and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/media/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/media/plugin.min.js deleted file mode 100644 index 3306df59f5..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/media/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("media",function(e,t){function i(e){return-1!=e.indexOf(".mp3")?"audio/mpeg":-1!=e.indexOf(".wav")?"audio/wav":-1!=e.indexOf(".mp4")?"video/mp4":-1!=e.indexOf(".webm")?"video/webm":-1!=e.indexOf(".ogg")?"video/ogg":-1!=e.indexOf(".swf")?"application/x-shockwave-flash":""}function r(t){var i=e.settings.media_scripts;if(i)for(var r=0;r':"application/x-shockwave-flash"==a.source1mime?(o+='',a.poster&&(o+=''),o+=""):-1!=a.source1mime.indexOf("audio")?e.settings.audio_template_callback?o=e.settings.audio_template_callback(a):o+='":"script"==a.type?o+='':o=e.settings.video_template_callback?e.settings.video_template_callback(a):'"}return o}function n(e){var t={};return new tinymce.html.SaxParser({validate:!1,allow_conditional_comments:!0,special:"script,noscript",start:function(e,i){if(t.source1||"param"!=e||(t.source1=i.map.movie),("iframe"==e||"object"==e||"embed"==e||"video"==e||"audio"==e)&&(t.type||(t.type=e),t=tinymce.extend(i.map,t)),"script"==e){var a=r(i.map.src);if(!a)return;t={type:"script",source1:i.map.src,width:a.width,height:a.height}}"source"==e&&(t.source1?t.source2||(t.source2=i.map.src):t.source1=i.map.src),"img"!=e||t.poster||(t.poster=i.map.src)}}).parse(e),t.source1=t.source1||t.src||t.data,t.source2=t.source2||"",t.poster=t.poster||"",t}function s(t){return t.getAttribute("data-mce-object")?n(e.serializer.serialize(t,{selection:!0})):{}}function m(e,t,i){function r(e,t){var i,r,a,o;for(i in t)if(a=""+t[i],e.map[i])for(r=e.length;r--;)o=e[r],o.name==i&&(a?(e.map[i]=a,o.value=a):(delete e.map[i],e.splice(r,1)));else a&&(e.push({name:i,value:a}),e.map[i]=a)}var a,o=new tinymce.html.Writer,c=0;return new tinymce.html.SaxParser({validate:!1,allow_conditional_comments:!0,special:"script,noscript",comment:function(e){o.comment(e)},cdata:function(e){o.cdata(e)},text:function(e,t){o.text(e,t)},start:function(e,n,s){switch(e){case"video":case"object":case"embed":case"img":case"iframe":r(n,{width:t.width,height:t.height})}if(i)switch(e){case"video":r(n,{poster:t.poster,src:""}),t.source2&&r(n,{src:""});break;case"iframe":r(n,{src:t.source1});break;case"source":if(c++,2>=c&&(r(n,{src:t["source"+c],type:t["source"+c+"mime"]}),!t["source"+c]))return;break;case"img":if(!t.poster)return;a=!0}o.start(e,n,s)},end:function(e){if("video"==e&&i)for(var n=1;2>=n;n++)if(t["source"+n]){var s=[];s.map={},n>c&&(r(s,{src:t["source"+n],type:t["source"+n+"mime"]}),o.start("source",s,!0))}if(t.poster&&"object"==e&&i&&!a){var m=[];m.map={},r(m,{src:t.poster,width:t.width,height:t.height}),o.start("img",m,!0)}o.end(e)}},new tinymce.html.Schema({})).parse(e),o.getContent()}var d=[{regex:/youtu\.be\/([a-z1-9.-_]+)/,type:"iframe",w:425,h:350,url:"http://www.youtube.com/embed/$1"},{regex:/youtube\.com(.+)v=([^&]+)/,type:"iframe",w:425,h:350,url:"http://www.youtube.com/embed/$2"},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"http://player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc"},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'http://maps.google.com/maps/ms?msid=$2&output=embed"'}];e.on("ResolveName",function(e){var t;1==e.target.nodeType&&(t=e.target.getAttribute("data-mce-object"))&&(e.name=t)}),e.on("preInit",function(){var t=e.schema.getSpecialElements();tinymce.each("video audio iframe object".split(" "),function(e){t[e]=new RegExp("]*>","gi")}),e.schema.addValidElements("object[id|style|width|height|classid|codebase|*],embed[id|style|width|height|type|src|*],video[*],audio[*]");var i=e.schema.getBoolAttrs();tinymce.each("webkitallowfullscreen mozallowfullscreen allowfullscreen".split(" "),function(e){i[e]={}}),e.parser.addNodeFilter("iframe,video,audio,object,embed,script",function(t,i){for(var a,o,c,n,s,m,d,u,l=t.length;l--;)if(o=t[l],"script"!=o.name||(u=r(o.attr("src")))){for(c=new tinymce.html.Node("img",1),c.shortEnded=!0,u&&(u.width&&o.attr("width",u.width.toString()),u.height&&o.attr("height",u.height.toString())),m=o.attributes,a=m.length;a--;)n=m[a].name,s=m[a].value,"width"!==n&&"height"!==n&&"style"!==n&&(("data"==n||"src"==n)&&(s=e.convertURL(s,n)),c.attr("data-mce-p-"+n,s));d=o.firstChild&&o.firstChild.value,d&&(c.attr("data-mce-html",escape(d)),c.firstChild=null),c.attr({width:o.attr("width")||"300",height:o.attr("height")||("audio"==i?"30":"150"),style:o.attr("style"),src:tinymce.Env.transparentSrc,"data-mce-object":i,"class":"mce-object mce-object-"+i}),o.replace(c)}}),e.serializer.addAttributeFilter("data-mce-object",function(e,t){for(var i,r,a,o,c,n,s,m=e.length;m--;){for(i=e[m],s=i.attr(t),r=new tinymce.html.Node(s,1),"audio"!=s&&"script"!=s&&r.attr({width:i.attr("width"),height:i.attr("height")}),r.attr({style:i.attr("style")}),o=i.attributes,a=o.length;a--;){var d=o[a].name;0===d.indexOf("data-mce-p-")&&r.attr(d.substr(11),o[a].value)}"script"==s&&r.attr("type","text/javascript"),c=i.attr("data-mce-html"),c&&(n=new tinymce.html.Node("#text",3),n.raw=!0,n.value=unescape(c),r.append(n)),i.replace(r)}})}),e.on("ObjectSelected",function(e){var t=e.target.getAttribute("data-mce-object");("audio"==t||"script"==t)&&e.preventDefault()}),e.on("objectResized",function(e){var t,i=e.target;i.getAttribute("data-mce-object")&&(t=i.getAttribute("data-mce-html"),t&&(t=unescape(t),i.setAttribute("data-mce-html",escape(m(t,{width:e.width,height:e.height})))))}),e.addButton("media",{tooltip:"Insert/edit video",onclick:a,stateSelector:["img[data-mce-object=video]","img[data-mce-object=iframe]"]}),e.addMenuItem("media",{icon:"media",text:"Insert video",onclick:a,context:"insert",prependToContext:!0})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/nonbreaking/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/nonbreaking/plugin.min.js deleted file mode 100644 index 3df66c3e93..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/nonbreaking/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("nonbreaking",function(n){var e=n.getParam("nonbreaking_force_tab");if(n.addCommand("mceNonBreaking",function(){n.insertContent(n.plugins.visualchars&&n.plugins.visualchars.state?' ':" "),n.dom.setAttrib(n.dom.select("span.mce-nbsp"),"data-mce-bogus","1")}),n.addButton("nonbreaking",{title:"Insert nonbreaking space",cmd:"mceNonBreaking"}),n.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),e){var a=+e>1?+e:3;n.on("keydown",function(e){if(9==e.keyCode){if(e.shiftKey)return;e.preventDefault();for(var t=0;a>t;t++)n.execCommand("mceNonBreaking")}})}}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/noneditable/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/noneditable/plugin.min.js deleted file mode 100644 index aa642de8c6..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/noneditable/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("noneditable",function(e){function t(e){var t;if(1===e.nodeType){if(t=e.getAttribute(u),t&&"inherit"!==t)return t;if(t=e.contentEditable,"inherit"!==t)return t}return null}function n(e){for(var n;e;){if(n=t(e))return"false"===n?e:null;e=e.parentNode}}function r(){function r(e){for(;e;){if(e.id===g)return e;e=e.parentNode}}function a(e){var t;if(e)for(t=new f(e,e),e=t.current();e;e=t.next())if(3===e.nodeType)return e}function i(n,r){var a,i;return"false"===t(n)&&u.isBlock(n)?void s.select(n):(i=u.createRng(),"true"===t(n)&&(n.firstChild||n.appendChild(e.getDoc().createTextNode(" ")),n=n.firstChild,r=!0),a=u.create("span",{id:g,"data-mce-bogus":!0},m),r?n.parentNode.insertBefore(a,n):u.insertAfter(a,n),i.setStart(a.firstChild,1),i.collapse(!0),s.setRng(i),a)}function o(e){var t,n,i,o;if(e)t=s.getRng(!0),t.setStartBefore(e),t.setEndBefore(e),n=a(e),n&&n.nodeValue.charAt(0)==m&&(n=n.deleteData(0,1)),u.remove(e,!0),s.setRng(t);else for(i=r(s.getStart());(e=u.get(g))&&e!==o;)i!==e&&(n=a(e),n&&n.nodeValue.charAt(0)==m&&(n=n.deleteData(0,1)),u.remove(e,!0)),o=e}function l(){function e(e,n){var r,a,i,o,l;if(r=d.startContainer,a=d.startOffset,3==r.nodeType){if(l=r.nodeValue.length,a>0&&l>a||(n?a==l:0===a))return}else{if(!(a0?a-1:a;r=r.childNodes[u],r.hasChildNodes()&&(r=r.firstChild)}for(i=new f(r,e);o=i[n?"prev":"next"]();){if(3===o.nodeType&&o.nodeValue.length>0)return;if("true"===t(o))return o}return e}var r,a,l,d,u;o(),l=s.isCollapsed(),r=n(s.getStart()),a=n(s.getEnd()),(r||a)&&(d=s.getRng(!0),l?(r=r||a,(u=e(r,!0))?i(u,!0):(u=e(r,!1))?i(u,!1):s.select(r)):(d=s.getRng(!0),r&&d.setStartBefore(r),a&&d.setEndAfter(a),s.setRng(d)))}function d(a){function i(e,t){for(;e=e[t?"previousSibling":"nextSibling"];)if(3!==e.nodeType||e.nodeValue.length>0)return e}function d(e,t){s.select(e),s.collapse(t)}function g(a){function i(e){for(var t=d;t;){if(t===e)return;t=t.parentNode}u.remove(e),l()}function o(){var r,o,l=e.schema.getNonEmptyElements();for(o=new tinymce.dom.TreeWalker(d,e.getBody());(r=a?o.prev():o.next())&&!l[r.nodeName.toLowerCase()]&&!(3===r.nodeType&&tinymce.trim(r.nodeValue).length>0);)if("false"===t(r))return i(r),!0;return n(r)?!0:!1}var f,d,c,g;if(s.isCollapsed()){if(f=s.getRng(!0),d=f.startContainer,c=f.startOffset,d=r(d)||d,g=n(d))return i(g),!1;if(3==d.nodeType&&(a?c>0:ch||h>124)&&h!=c.DELETE&&h!=c.BACKSPACE){if((tinymce.isMac?a.metaKey:a.ctrlKey)&&(67==h||88==h||86==h))return;if(a.preventDefault(),h==c.LEFT||h==c.RIGHT){var y=h==c.LEFT;if(e.dom.isBlock(m)){var T=y?m.previousSibling:m.nextSibling,C=new f(T,T),b=y?C.prev():C.next();d(b,!y)}else d(m,y)}}else if(h==c.LEFT||h==c.RIGHT||h==c.BACKSPACE||h==c.DELETE){if(p=r(v)){if(h==c.LEFT||h==c.BACKSPACE)if(m=i(p,!0),m&&"false"===t(m)){if(a.preventDefault(),h!=c.LEFT)return void u.remove(m);d(m,!0)}else o(p);if(h==c.RIGHT||h==c.DELETE)if(m=i(p),m&&"false"===t(m)){if(a.preventDefault(),h!=c.RIGHT)return void u.remove(m);d(m,!1)}else o(p)}if((h==c.BACKSPACE||h==c.DELETE)&&!g(h==c.BACKSPACE))return a.preventDefault(),!1}}var u=e.dom,s=e.selection,g="mce_noneditablecaret",m="";e.on("mousedown",function(n){var r=e.selection.getNode();"false"===t(r)&&r==n.target&&l()}),e.on("mouseup keyup",l),e.on("keydown",d)}function a(t){var n=l.length,r=t.content,a=tinymce.trim(o);if("raw"!=t.format){for(;n--;)r=r.replace(l[n],function(t){var n=arguments,i=n[n.length-2];return i>0&&'"'==r.charAt(i-1)?t:''+e.dom.encode("string"==typeof n[1]?n[1]:n[0])+""});t.content=r}}var i,o,l,f=tinymce.dom.TreeWalker,d="contenteditable",u="data-mce-"+d,c=tinymce.util.VK;i=" "+tinymce.trim(e.getParam("noneditable_editable_class","mceEditable"))+" ",o=" "+tinymce.trim(e.getParam("noneditable_noneditable_class","mceNonEditable"))+" ",l=e.getParam("noneditable_regexp"),l&&!l.length&&(l=[l]),e.on("PreInit",function(){r(),l&&e.on("BeforeSetContent",a),e.parser.addAttributeFilter("class",function(e){for(var t,n,r=e.length;r--;)n=e[r],t=" "+n.attr("class")+" ",-1!==t.indexOf(i)?n.attr(u,"true"):-1!==t.indexOf(o)&&n.attr(u,"false")}),e.serializer.addAttributeFilter(u,function(e){for(var t,n=e.length;n--;)t=e[n],l&&t.attr("data-mce-content")?(t.name="#text",t.type=3,t.raw=!0,t.value=t.attr("data-mce-content")):(t.attr(d,null),t.attr(u,null))}),e.parser.addAttributeFilter(d,function(e){for(var t,n=e.length;n--;)t=e[n],t.attr(u,t.attr(d)),t.attr(d,null)})}),e.on("drop",function(e){n(e.target)&&e.preventDefault()})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/pagebreak/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/pagebreak/plugin.min.js deleted file mode 100644 index e224cb4414..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/pagebreak/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("pagebreak",function(e){var a="mce-pagebreak",t=e.getParam("pagebreak_separator",""),n=new RegExp(t.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi"),r='';e.addCommand("mcePageBreak",function(){e.settings.pagebreak_split_block?e.insertContent("

          "+r+"

          "):e.insertContent(r)}),e.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),e.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"}),e.on("ResolveName",function(t){"IMG"==t.target.nodeName&&e.dom.hasClass(t.target,a)&&(t.name="pagebreak")}),e.on("click",function(t){t=t.target,"IMG"===t.nodeName&&e.dom.hasClass(t,a)&&e.selection.select(t)}),e.on("BeforeSetContent",function(e){e.content=e.content.replace(n,r)}),e.on("PreInit",function(){e.serializer.addNodeFilter("img",function(a){for(var n,r,c=a.length;c--;)if(n=a[c],r=n.attr("class"),r&&-1!==r.indexOf("mce-pagebreak")){var o=n.parent;if(e.schema.getBlockElements()[o.name]&&e.settings.pagebreak_split_block){o.type=3,o.value=t,o.raw=!0,n.remove();continue}n.type=3,n.value=t,n.raw=!0}})})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/paste/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/paste/plugin.min.js deleted file mode 100644 index 9b71bbe960..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/paste/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e,t){"use strict";function n(e,t){for(var n,i=[],r=0;r"),t&&/^(PRE|DIV)$/.test(t.nodeName)||!a?e=n.filter(e,[[/\n/g,"
          "]]):(e=n.filter(e,[[/\n\n/g,"

          "+o],[/^(.*<\/p>)(

          )$/,o+"$1"],[/\n/g,"
          "]]),-1!=e.indexOf("

          ")&&(e=o+e)),r(e)}function o(){var t=i.dom,n=i.getBody(),r=i.dom.getViewPort(i.getWin()),a=r.y,o=20,s;if(v=i.selection.getRng(),i.inline&&(s=i.selection.getScrollContainer(),s&&(a=s.scrollTop)),v.getClientRects){var l=v.getClientRects();if(l.length)o=a+(l[0].top-t.getPos(n).y);else{o=a;var c=v.startContainer;c&&(3==c.nodeType&&c.parentNode!=n&&(c=c.parentNode),1==c.nodeType&&(o=t.getPos(c,s||n).y))}}g=t.add(i.getBody(),"div",{id:"mcepastebin",contentEditable:!0,"data-mce-bogus":"1",style:"position: absolute; top: "+o+"px;width: 10px; height: 10px; overflow: hidden; opacity: 0"},b),(e.ie||e.gecko)&&t.setStyle(g,"left","rtl"==t.getStyle(n,"direction",!0)?65535:-65535),t.bind(g,"beforedeactivate focusin focusout",function(e){e.stopPropagation()}),g.focus(),i.selection.select(g,!0)}function s(){if(g){for(var e;e=i.dom.get("mcepastebin");)i.dom.remove(e),i.dom.unbind(e);v&&i.selection.setRng(v)}y=!1,g=v=null}function l(){var e=b,t,n;for(t=i.dom.select("div[id=mcepastebin]"),n=t.length;n--;){var r=t[n].innerHTML;e==b&&(e=""),r.length>e.length&&(e=r)}return e}function c(e){var t={};if(e&&e.types){var n=e.getData("Text");n&&n.length>0&&(t["text/plain"]=n);for(var i=0;i')},t.readAsDataURL(e.getAsFile()),!0}}if(!(!i.settings.paste_data_images||"text/html"in t||"text/plain"in t)&&e.clipboardData){var a=e.clipboardData.items;if(a)for(var o=0;ol?n&&(n=n.parent.parent):(i=n,n=null)),n&&n.name==o?n.append(e):(i=i||n,n=new r(o,1),s>1&&n.attr("start",""+s),e.wrap(n)),e.name="li",t.value="";var c=t.next;c&&3==c.type&&(c.value=c.value.replace(/^\u00a0+/,"")),l>a&&i&&i.lastChild.append(n),a=l}for(var n,i,a=1,o=e.getAll("p"),s=0;s/gi,/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,[/<(\/?)s>/gi,"<$1strike>"],[/ /gi,"\xa0"],[/([\s\u00a0]*)<\/span>/gi,function(e,t){return t.length>0?t.replace(/./," ").slice(Math.floor(t.length/2)).split("").join("\xa0"):""}]]);var g=l.paste_word_valid_elements;g||(g="@[style],-strong/b,-em/i,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,-table[width],-tr,-td[colspan|rowspan|width],-th,-thead,-tfoot,-tbody,-a[href|name],sub,sup,strike,br");var v=new n({valid_elements:g}),h=new t({},v);h.addAttributeFilter("style",function(e){for(var t=e.length,n;t--;)n=e[t],n.attr("style",p(n,n.attr("style"))),"span"!=n.name||n.attributes.length||n.unwrap()}),h.addNodeFilter("a",function(e){for(var t=e.length,n,i,r;t--;)n=e[t],i=n.attr("href"),r=n.attr("name"),i&&0===i.indexOf("file://")&&(i=i.split("#")[1],i&&(i="#"+i)),i||r?n.attr({href:i,name:r}):n.unwrap()});var b=h.parse(f);d(b),c.content=new i({},v).serialize(b)}})}return s.isWordContent=o,s}),i(b,[u,c,g,l],function(e,t,n,i){return function(r){function a(e){r.on("BeforePastePreProcess",function(t){t.content=e(t.content)})}function o(e){return e=i.filter(e,[/^[\s\S]*|[\s\S]*$/g,[/\u00a0<\/span>/g,"\xa0"],/
          $/])}function s(e){if(!n.isWordContent(e))return e;var a=[];t.each(r.schema.getBlockElements(),function(e,t){a.push(t)});var o=new RegExp("(?:
           [\\s\\r\\n]+|
          )*(<\\/?("+a.join("|")+")[^>]*>)(?:
           [\\s\\r\\n]+|
          )*","g");return e=i.filter(e,[[o,"$1"]]),e=i.filter(e,[[/

          /g,"

          "],[/
          /g," "],[/

          /g,"
          "]])}function l(e){return(r.settings.paste_remove_styles||r.settings.paste_remove_styles_if_webkit!==!1)&&(e=e.replace(/ style=\"[^\"]+\"/g,"")),e}e.webkit&&(a(l),a(o)),e.ie&&a(s)}}),i(y,[P,f,g,b],function(e,t,n,i){var r;e.add("paste",function(e){function a(){"text"==s.pasteFormat?(this.active(!1),s.pasteFormat="html"):(s.pasteFormat="text",this.active(!0),r||(e.windowManager.alert("Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off."),r=!0))}var o=this,s,l=e.settings;o.clipboard=s=new t(e),o.quirks=new i(e),o.wordFilter=new n(e),e.settings.paste_as_text&&(o.clipboard.pasteFormat="text"),l.paste_preprocess&&e.on("PastePreProcess",function(e){l.paste_preprocess.call(o,o,e)}),l.paste_postprocess&&e.on("PastePostProcess",function(e){l.paste_postprocess.call(o,o,e)}),e.addCommand("mceInsertClipboardContent",function(e,t){t.content&&o.clipboard.pasteHtml(t.content),t.text&&o.clipboard.pasteText(t.text)}),e.paste_block_drop&&e.on("dragend dragover draggesture dragdrop drop drag",function(e){e.preventDefault(),e.stopPropagation()}),e.settings.paste_data_images||e.on("drop",function(e){var t=e.dataTransfer;t&&t.files&&t.files.length>0&&e.preventDefault()}),e.addButton("pastetext",{icon:"pastetext",tooltip:"Paste as text",onclick:a,active:"text"==o.clipboard.pasteFormat}),e.addMenuItem("pastetext",{text:"Paste as text",selectable:!0,active:s.pasteFormat,onclick:a})})}),o([l,f,g,b,y])}(this); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/preview/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/preview/plugin.min.js deleted file mode 100644 index 8a24058f74..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/preview/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("preview",function(e){var t=e.settings;e.addCommand("mcePreview",function(){e.windowManager.open({title:"Preview",width:parseInt(e.getParam("plugin_preview_width","650"),10),height:parseInt(e.getParam("plugin_preview_height","500"),10),html:'',buttons:{text:"Close",onclick:function(){this.parent().parent().close()}},onPostRender:function(){var i,n=this.getEl("body").firstChild.contentWindow.document,a="";tinymce.each(e.contentCSS,function(t){a+=''});var d=t.body_id||"tinymce";-1!=d.indexOf("=")&&(d=e.getParam("body_id","","hash"),d=d[e.id]||d);var r=t.body_class||"";-1!=r.indexOf("=")&&(r=e.getParam("body_class","","hash"),r=r[e.id]||""),i=""+a+""+''+e.getContent()+""+"",n.open(),n.write(i),n.close()}})}),e.addButton("preview",{title:"Preview",cmd:"mcePreview"}),e.addMenuItem("preview",{text:"Preview",cmd:"mcePreview",context:"view"})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/print/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/print/plugin.min.js deleted file mode 100644 index abc37b5fd4..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/print/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("print",function(t){t.addCommand("mcePrint",function(){t.getWin().print()}),t.addButton("print",{title:"Print",cmd:"mcePrint"}),t.addShortcut("Ctrl+P","","mcePrint"),t.addMenuItem("print",{text:"Print",cmd:"mcePrint",icon:"print",shortcut:"Ctrl+P",context:"file"})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/save/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/save/plugin.min.js deleted file mode 100644 index bd50cec41e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/save/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("save",function(e){function t(){var t,n;return t=tinymce.DOM.getParent(e.id,"form"),!e.getParam("save_enablewhendirty",!0)||e.isDirty()?(tinymce.triggerSave(),(n=e.getParam("save_onsavecallback"))?(e.execCallback("save_onsavecallback",e)&&(e.startContent=tinymce.trim(e.getContent({format:"raw"})),e.nodeChanged()),void 0):(t?(e.isNotDirty=!0,(!t.onsubmit||t.onsubmit())&&("function"==typeof t.submit?t.submit():e.windowManager.alert("Error: Form submit field collision.")),e.nodeChanged()):e.windowManager.alert("Error: No form element found."),void 0)):void 0}function n(){var t,n=tinymce.trim(e.startContent);return(t=e.getParam("save_oncancelcallback"))?(e.execCallback("save_oncancelcallback",e),void 0):(e.setContent(n),e.undoManager.clear(),e.nodeChanged(),void 0)}function i(){var t=this;e.on("nodeChange",function(){t.disabled(e.getParam("save_enablewhendirty",!0)&&!e.isDirty())})}e.addCommand("mceSave",t),e.addCommand("mceCancel",n),e.addButton("save",{icon:"save",text:"Save",cmd:"mceSave",disabled:!0,onPostRender:i}),e.addButton("cancel",{text:"Cancel",icon:!1,cmd:"mceCancel",disabled:!0,onPostRender:i}),e.addShortcut("ctrl+s","","mceSave")}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/searchreplace/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/searchreplace/plugin.min.js deleted file mode 100644 index 018303ff5b..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/searchreplace/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){function e(e,t,n,a,r){function i(e,t){if(t=t||0,!e[0])throw"findAndReplaceDOMText cannot handle zero-length matches";var n=e.index;if(t>0){var a=e[t];if(!a)throw"Invalid capture group";n+=e[0].indexOf(a),e[0]=a}return[n,n+e[0].length,[e[0]]]}function d(e){var t;if(3===e.nodeType)return e.data;if(h[e.nodeName]&&!u[e.nodeName])return"";if(t="",(u[e.nodeName]||m[e.nodeName])&&(t+="\n"),e=e.firstChild)do t+=d(e);while(e=e.nextSibling);return t}function o(e,t,n){var a,r,i,d,o=[],l=0,c=e,s=t.shift(),f=0;e:for(;;){if((u[c.nodeName]||m[c.nodeName])&&l++,3===c.nodeType&&(!r&&c.length+l>=s[1]?(r=c,d=s[1]-l):a&&o.push(c),!a&&c.length+l>s[0]&&(a=c,i=s[0]-l),l+=c.length),a&&r){if(c=n({startNode:a,startNodeIndex:i,endNode:r,endNodeIndex:d,innerNodes:o,match:s[2],matchIndex:f}),l-=r.length-d,a=null,r=null,o=[],s=t.shift(),f++,!s)break}else{if((!h[c.nodeName]||u[c.nodeName])&&c.firstChild){c=c.firstChild;continue}if(c.nextSibling){c=c.nextSibling;continue}}for(;;){if(c.nextSibling){c=c.nextSibling;break}if(c.parentNode===e)break e;c=c.parentNode}}}function l(e){var t;if("function"!=typeof e){var n=e.nodeType?e:f.createElement(e);t=function(e,t){var a=n.cloneNode(!1);return a.setAttribute("data-mce-index",t),e&&a.appendChild(f.createTextNode(e)),a}}else t=e;return function(e){var n,a,r,i=e.startNode,d=e.endNode,o=e.matchIndex;if(i===d){var l=i;r=l.parentNode,e.startNodeIndex>0&&(n=f.createTextNode(l.data.substring(0,e.startNodeIndex)),r.insertBefore(n,l));var c=t(e.match[0],o);return r.insertBefore(c,l),e.endNodeIndexh;++h){var g=e.innerNodes[h],p=t(g.data,o);g.parentNode.replaceChild(p,g),u.push(p)}var x=t(d.data.substring(0,e.endNodeIndex),o);return r=i.parentNode,r.insertBefore(n,i),r.insertBefore(s,i),r.removeChild(i),r=d.parentNode,r.insertBefore(x,d),r.insertBefore(a,d),r.removeChild(d),x}}var c,s,f,u,h,m,g=[],p=0;if(f=t.ownerDocument,u=r.getBlockElements(),h=r.getWhiteSpaceElements(),m=r.getShortEndedElements(),s=d(t)){if(e.global)for(;c=e.exec(s);)g.push(i(c,a));else c=s.match(e),g.push(i(c,a));return g.length&&(p=g.length,o(t,g,l(n))),p}}function t(t){function n(){function e(){r.statusbar.find("#next").disabled(!d(s+1).length),r.statusbar.find("#prev").disabled(!d(s-1).length)}function n(){tinymce.ui.MessageBox.alert("Could not find the specified string.",function(){r.find("#find")[0].focus()})}var a={},r=tinymce.ui.Factory.create({type:"window",layout:"flex",pack:"center",align:"center",onClose:function(){t.focus(),c.done()},onSubmit:function(t){var i,o,l,f;return t.preventDefault(),o=r.find("#case").checked(),f=r.find("#words").checked(),l=r.find("#find").value(),l.length?a.text==l&&a.caseState==o&&a.wholeWord==f?0===d(s+1).length?void n():(c.next(),void e()):(i=c.find(l,o,f),i||n(),r.statusbar.items().slice(1).disabled(0===i),e(),void(a={text:l,caseState:o,wholeWord:f})):(c.done(!1),void r.statusbar.items().slice(1).disabled(!0))},buttons:[{text:"Find",onclick:function(){r.submit()}},{text:"Replace",disabled:!0,onclick:function(){c.replace(r.find("#replace").value())||(r.statusbar.items().slice(1).disabled(!0),s=-1,a={})}},{text:"Replace all",disabled:!0,onclick:function(){c.replace(r.find("#replace").value(),!0,!0),r.statusbar.items().slice(1).disabled(!0),a={}}},{type:"spacer",flex:1},{text:"Prev",name:"prev",disabled:!0,onclick:function(){c.prev(),e()}},{text:"Next",name:"next",disabled:!0,onclick:function(){c.next(),e()}}],title:"Find and replace",items:{type:"form",padding:20,labelGap:30,spacing:10,items:[{type:"textbox",name:"find",size:40,label:"Find",value:t.selection.getNode().src},{type:"textbox",name:"replace",size:40,label:"Replace with"},{type:"checkbox",name:"case",text:"Match case",label:" "},{type:"checkbox",name:"words",text:"Whole words",label:" "}]}}).renderTo().reflow()}function a(e){var t=e.getAttribute("data-mce-index");return"number"==typeof t?""+t:t}function r(n){var a,r;return r=t.dom.create("span",{"data-mce-bogus":1}),r.className="mce-match-marker",a=t.getBody(),c.done(!1),e(n,a,r,!1,t.schema)}function i(e){var t=e.parentNode;t.insertBefore(e.firstChild,e),e.parentNode.removeChild(e)}function d(e){var n,r=[];if(n=tinymce.toArray(t.getBody().getElementsByTagName("span")),n.length)for(var i=0;is&&f[o].setAttribute("data-mce-index",m-1)}return t.undoManager.add(),s=p,n?(g=d(p+1).length>0,c.next()):(g=d(p-1).length>0,c.prev()),!r&&g},c.done=function(e){var n,r,d,o;for(r=tinymce.toArray(t.getBody().getElementsByTagName("span")),n=0;n=d.end?(i=c,a=d.end-l):r&&s.push(c),!r&&c.length+l>d.start&&(r=c,o=d.start-l),l+=c.length),r&&i){if(c=n({startNode:r,startNodeIndex:o,endNode:i,endNodeIndex:a,innerNodes:s,match:d.text,matchIndex:u}),l-=i.length-a,r=null,i=null,s=[],d=t.shift(),u++,!d)break}else{if((!k[c.nodeName]||N[c.nodeName])&&c.firstChild){c=c.firstChild;continue}if(c.nextSibling){c=c.nextSibling;continue}}for(;;){if(c.nextSibling){c=c.nextSibling;break}if(c.parentNode===e)break e;c=c.parentNode}}}function o(e){function t(t,n){var r=x[n];r.stencil||(r.stencil=e(r));var i=r.stencil.cloneNode(!1);return i.setAttribute("data-mce-index",n),t&&i.appendChild(_.doc.createTextNode(t)),i}return function n(e){var n,r,i,o=e.startNode,a=e.endNode,s=e.matchIndex,l=_.doc;if(o===a){var c=o;i=c.parentNode,e.startNodeIndex>0&&(n=l.createTextNode(c.data.substring(0,e.startNodeIndex)),i.insertBefore(n,c));var d=t(e.match,s);return i.insertBefore(d,c),e.endNodeIndexp;++p){var h=e.innerNodes[p],g=t(h.data,s);h.parentNode.replaceChild(g,h),f.push(g)}var v=t(a.data.substring(0,e.endNodeIndex),s);return i=o.parentNode,i.insertBefore(n,o),i.insertBefore(u,o),i.removeChild(o),i=a.parentNode,i.insertBefore(v,a),i.insertBefore(r,a),i.removeChild(a),v}}function a(e){var t=e.parentNode;t.insertBefore(e.firstChild,e),e.parentNode.removeChild(e)}function s(t){var n=e.getElementsByTagName("*"),r=[];t="number"==typeof t?""+t:null;for(var i=0;it&&e(x[t],t)!==!1;t++);return this}function u(t){return x.length&&i(e,x,o(t)),this}function f(e,t){if(w&&e.global)for(;C=e.exec(w);)x.push(n(C,t));return this}function p(e){var t,n=s(e?l(e):null);for(t=n.length;t--;)a(n[t]);return this}function m(e){return x[e.getAttribute("data-mce-index")]}function h(e){return s(l(e))[0]}function g(e,t,n){return x.push({start:e,end:e+t,text:w.substr(e,t),data:n}),this}function v(e){var n=s(l(e)),r=t.dom.createRng();return r.setStartBefore(n[0]),r.setEndAfter(n[n.length-1]),r}function y(e,n){var r=v(e);return r.deleteContents(),n.length>0&&r.insertNode(t.dom.doc.createTextNode(n)),r}function b(){return x.splice(0,x.length),p(),this}var C,x=[],w,_=t.dom,N,k,S;return N=t.schema.getBlockElements(),k=t.schema.getWhiteSpaceElements(),S=t.schema.getShortEndedElements(),w=r(e),{text:w,matches:x,each:d,filter:c,reset:b,matchFromElement:m,elementFromMatch:h,find:f,add:g,wrap:u,unwrap:p,replace:y,rangeFromMatch:v,indexOf:l}}}),r(c,[l,d,u,f,p,m,h],function(e,t,n,r,i,o,a){t.add("spellchecker",function(t,s){function l(){return y.textMatcher||(y.textMatcher=new e(t.getBody(),t)),y.textMatcher}function c(e,t){var r=[];return n.each(t,function(e){r.push({selectable:!0,text:e.name,data:e.value})}),r}function d(e){for(var t in e)return!1;return!0}function u(e){var o=[],a=b[e.text];n.each(a,function(n){o.push({text:n,onclick:function(){var r=l().replace(e,n);r.collapse(!1),t.selection.setRng(r),p()}})}),o.push.apply(o,[{text:"-"},{text:"Ignore",onclick:function(){m(e)}},{text:"Ignore all",onclick:function(){m(e,!0)}},{text:"Finish",onclick:h}]),x=new r({items:o,context:"contextmenu",onautohide:function(e){-1!=e.target.className.indexOf("spellchecker")&&e.preventDefault()},onhide:function(){x.remove(),x=null}}),x.renderTo(document.body);var s=l().elementFromMatch(e),c=i.DOM.getPos(t.getContentAreaContainer()),d=t.dom.getPos(s),u=t.dom.getRoot();"BODY"==u.nodeName?(d.x-=u.ownerDocument.documentElement.scrollLeft||u.scrollLeft,d.y-=u.ownerDocument.documentElement.scrollTop||u.scrollTop):(d.x-=u.scrollLeft,d.y-=u.scrollTop),c.x+=d.x,c.y+=d.y,x.moveTo(c.x,c.y+s.offsetHeight)}function f(){function e(e){return t.setProgressState(!1),d(e)?(t.windowManager.alert("No misspellings found"),void(C=!1)):(b=e,l().filter(function(t){return!!e[t.text]}).wrap(function(){return t.dom.create("span",{"class":"mce-spellchecker-word","data-mce-bogus":1})}),void t.fire("SpellcheckStart"))}function n(e,n,r){o.sendRPC({url:new a(s).toAbsolute(w.spellchecker_rpc_url),method:e,params:{lang:w.spellchecker_language||"en",words:n},success:function(e){r(e)},error:function(e,n){e="JSON Parse error."==e?"Non JSON response:"+n.responseText:"Error: "+e,t.windowManager.alert(e),t.setProgressState(!1),h()}})}var r=[],i={};if(C)return void h();h(),C=!0;var c=t.getParam("spellchecker_wordchar_pattern")||new RegExp('[^\\s!"#$%&()*+,-./:;<=>?@[\\]^_{|}`\xa7\xa9\xab\xae\xb1\xb6\xb7\xb8\xbb\xbc\xbd\xbe\xbf\xd7\xf7\xa4\u201d\u201c\u201e]+',"g");l().find(c).each(function(e){var t=e.text;if(!i[t]){if(/^\d+$/.test(t)||1==t.length)return;r.push(t),i[t]=!0}}),t.setProgressState(!0);var u=w.spellchecker_callback||n;u("spellcheck",r,e),t.focus()}function p(){t.dom.select("span.mce-spellchecker-word").length||h()}function m(e,n){t.selection.collapse(),n?l().each(function(t){t.text==e.text&&l().unwrap(t)}):l().unwrap(e),p()}function h(){l().reset(),y.textMatcher=null,C&&(C=!1,t.fire("SpellcheckEnd"))}function g(e){var t=w.spellchecker_language;e.control.items().each(function(e){e.active(e.settings.data===t)})}var v,y=this,b,C,x,w=t.settings,_=w.spellchecker_languages||"English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr_FR,German=de,Italian=it,Polish=pl,Portuguese=pt_BR,Spanish=es,Swedish=sv";v=c("Language",n.map(_.split(","),function(e){var t=e.split("=");return{name:t[0],value:t[1]}})),t.on("click",function(e){if("mce-spellchecker-word"==e.target.className){e.preventDefault();var n=l().matchFromElement(e.target);t.selection.setRng(l().rangeFromMatch(n)),u(n)}}),t.addMenuItem("spellchecker",{text:"Spellcheck",context:"tools",onclick:f,selectable:!0,onPostRender:function(){var e=this;t.on("SpellcheckStart SpellcheckEnd",function(){e.active(C)})}});var N={tooltip:"Spellcheck",onclick:f,onPostRender:function(){var e=this;t.on("SpellcheckStart SpellcheckEnd",function(){e.active(C)})}};v.length>1&&(N.type="splitbutton",N.menu=v,N.onshow=g,N.onselect=function(e){w.spellchecker_language=e.control.settings.data}),t.addButton("spellchecker",N),t.addCommand("mceSpellCheck",f),t.on("remove",function(){x&&(x.remove(),x=null)}),this.getTextMatcher=l,w.spellchecker_language=w.spellchecker_language||w.language||"en"})}),a([l,c])}(this); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/tabfocus/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/tabfocus/plugin.min.js deleted file mode 100644 index 68fe35e35a..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/tabfocus/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("tabfocus",function(e){function n(e){9!==e.keyCode||e.ctrlKey||e.altKey||e.metaKey||e.preventDefault()}function t(n){function t(n){function t(e){return"BODY"===e.nodeName||"hidden"!=e.type&&"none"!=e.style.display&&"hidden"!=e.style.visibility&&t(e.parentNode)}function r(e){return e.tabIndex||"INPUT"==e.nodeName||"TEXTAREA"==e.nodeName}function c(e){return!r(e)&&"-1"!=e.getAttribute("tabindex")&&t(e)}if(u=i.select(":input:enabled,*[tabindex]:not(iframe)"),o(u,function(n,t){return n.id==e.id?(a=t,!1):void 0}),n>0){for(d=a+1;d=0;d--)if(c(u[d]))return u[d];return null}var a,u,c,d;if(!(9!==n.keyCode||n.ctrlKey||n.altKey||n.metaKey)&&(c=r(e.getParam("tab_focus",e.getParam("tabfocus_elements",":prev,:next"))),1==c.length&&(c[1]=c[0],c[0]=":prev"),u=n.shiftKey?":prev"==c[0]?t(-1):i.get(c[0]):":next"==c[1]?t(1):i.get(c[1]))){var y=tinymce.get(u.id||u.name);u.id&&y?y.focus():window.setTimeout(function(){tinymce.Env.webkit||window.focus(),u.focus()},10),n.preventDefault()}}var i=tinymce.DOM,o=tinymce.each,r=tinymce.explode;e.on("init",function(){e.inline&&tinymce.DOM.setAttrib(e.getBody(),"tabIndex",null)}),e.on("keyup",n),tinymce.Env.gecko?e.on("keypress keydown",t):e.on("keydown",t)}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/table/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/table/plugin.min.js deleted file mode 100644 index 1e2d1d8438..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/table/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e,t){"use strict";function n(e,t){for(var n,r=[],i=0;i "+t+" tr",a);i(n,function(n,o){o+=e,i(H.select("> td, > th",n),function(e,n){var i,a,s,l;if(A[o])for(;A[o][n];)n++;for(s=r(e,"rowspan"),l=r(e,"colspan"),a=o;o+s>a;a++)for(A[a]||(A[a]=[]),i=n;n+l>i;i++)A[a][i]={part:t,real:a==o&&i==n,elm:e,rowspan:s,colspan:l}})}),e+=n.length})}function l(e,t){return e=e.cloneNode(t),e.removeAttribute("id"),e}function c(e,t){var n;return n=A[t],n?n[e]:void 0}function d(e,t,n){e&&(n=parseInt(n,10),1===n?e.removeAttribute(t,1):e.setAttribute(t,n,1))}function u(e){return e&&(H.hasClass(e.elm,"mce-item-selected")||e==L)}function f(){var e=[];return i(a.rows,function(t){i(t.cells,function(n){return H.hasClass(n,"mce-item-selected")||L&&n==L.elm?(e.push(t),!1):void 0})}),e}function p(){var e=H.createRng();e.setStartAfter(a),e.setEndAfter(a),M.setRng(e),H.remove(a)}function m(t){var r,a={};return o.settings.table_clone_elements!==!1&&(a=e.makeMap((o.settings.table_clone_elements||"strong em b i span font h1 h2 h3 h4 h5 h6 p div").toUpperCase(),/[ ,]/)),e.walk(t,function(e){var o;return 3==e.nodeType?(i(H.getParents(e.parentNode,null,t).reverse(),function(e){a[e.nodeName]&&(e=l(e,!1),r?o&&o.appendChild(e):r=o=e,o=e)}),o&&(o.innerHTML=n.ie?" ":'
          '),!1):void 0},"childNodes"),t=l(t,!1),d(t,"rowSpan",1),d(t,"colSpan",1),r?t.appendChild(r):n.ie||(t.innerHTML='
          '),t}function h(){var e=H.createRng(),t;return i(H.select("tr",a),function(e){0===e.cells.length&&H.remove(e)}),0===H.select("tr",a).length?(e.setStartBefore(a),e.setEndBefore(a),M.setRng(e),void H.remove(a)):(i(H.select("thead,tbody,tfoot",a),function(e){0===e.rows.length&&H.remove(e)}),s(),void(B&&(t=A[Math.min(A.length-1,B.y)],t&&(M.select(t[Math.min(t.length-1,B.x)].elm,!0),M.collapse(!0)))))}function g(e,t,n,r){var i,o,a,s,l;for(i=A[t][e].elm.parentNode,a=1;n>=a;a++)if(i=H.getNext(i,"tr")){for(o=e;o>=0;o--)if(l=A[t+a][o].elm,l.parentNode==i){for(s=1;r>=s;s++)H.insertAfter(m(l),l);break}if(-1==o)for(s=1;r>=s;s++)i.insertBefore(m(i.cells[0]),i.cells[0])}}function v(){i(A,function(e,t){i(e,function(e,n){var i,o,a;if(u(e)&&(e=e.elm,i=r(e,"colspan"),o=r(e,"rowspan"),i>1||o>1)){for(d(e,"rowSpan",1),d(e,"colSpan",1),a=0;i-1>a;a++)H.insertAfter(m(e),e);g(n,t,o-1,i)}})})}function y(t,n,r){var o,a,l,f,p,m,g,y,b,C,x;if(t?(o=S(t),a=o.x,l=o.y,f=a+(n-1),p=l+(r-1)):(B=P=null,i(A,function(e,t){i(e,function(e,n){u(e)&&(B||(B={x:n,y:t}),P={x:n,y:t})})}),B&&(a=B.x,l=B.y,f=P.x,p=P.y)),y=c(a,l),b=c(f,p),y&&b&&y.part==b.part){for(v(),s(),y=c(a,l).elm,d(y,"colSpan",f-a+1),d(y,"rowSpan",p-l+1),g=l;p>=g;g++)for(m=a;f>=m;m++)A[g]&&A[g][m]&&(t=A[g][m].elm,t!=y&&(C=e.grep(t.childNodes),i(C,function(e){y.appendChild(e)}),C.length&&(C=e.grep(y.childNodes),x=0,i(C,function(e){"BR"==e.nodeName&&H.getAttrib(e,"data-mce-bogus")&&x++0&&A[n-1][s]&&(h=A[n-1][s].elm,g=r(h,"rowSpan"),g>1)){d(h,"rowSpan",g+1);continue}}else if(g=r(o,"rowspan"),g>1){d(o,"rowSpan",g+1);continue}p=m(o),d(p,"colSpan",o.colSpan),f.appendChild(p),a=o}f.hasChildNodes()&&(e?c.parentNode.insertBefore(f,c):H.insertAfter(f,c))}}function C(e){var t,n;i(A,function(n){return i(n,function(n,r){return u(n)&&(t=r,e)?!1:void 0}),e?!t:void 0}),i(A,function(i,o){var a,s,l;i[t]&&(a=i[t].elm,a!=n&&(l=r(a,"colspan"),s=r(a,"rowspan"),1==l?e?(a.parentNode.insertBefore(m(a),a),g(t,o,s-1,l)):(H.insertAfter(m(a),a),g(t,o,s-1,l)):d(a,"colSpan",a.colSpan+1),n=a))})}function x(){var t=[];i(A,function(n){i(n,function(n,o){u(n)&&-1===e.inArray(t,o)&&(i(A,function(e){var t=e[o].elm,n;n=r(t,"colSpan"),n>1?d(t,"colSpan",n-1):H.remove(t)}),t.push(o))})}),h()}function w(){function e(e){var t,n,o;t=H.getNext(e,"tr"),i(e.cells,function(e){var t=r(e,"rowSpan");t>1&&(d(e,"rowSpan",t-1),n=S(e),g(n.x,n.y,1,1))}),n=S(e.cells[0]),i(A[n.y],function(e){var t;e=e.elm,e!=o&&(t=r(e,"rowSpan"),1>=t?H.remove(e):d(e,"rowSpan",t-1),o=e)})}var t;t=f(),i(t.reverse(),function(t){e(t)}),h()}function _(){var e=f();return H.remove(e),h(),e}function N(){var e=f();return i(e,function(t,n){e[n]=l(t,!0)}),e}function k(e,t){var n=f(),r=n[t?0:n.length-1],o=r.cells.length;e&&(i(A,function(e){var t;return o=0,i(e,function(e){e.real&&(o+=e.colspan),e.elm.parentNode==r&&(t=1)}),t?!1:void 0}),t||e.reverse(),i(e,function(e){var n,i=e.cells.length,a;for(n=0;i>n;n++)a=e.cells[n],d(a,"colSpan",1),d(a,"rowSpan",1);for(n=i;o>n;n++)e.appendChild(m(e.cells[i-1]));for(n=o;i>n;n++)H.remove(e.cells[n]);t?r.parentNode.insertBefore(e,r):H.insertAfter(e,r)}),H.removeClass(H.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"))}function S(e){var t;return i(A,function(n,r){return i(n,function(n,i){return n.elm==e?(t={x:i,y:r},!1):void 0}),!t}),t}function E(e){B=S(e)}function T(){var e,t;return e=t=0,i(A,function(n,r){i(n,function(n,i){var o,a;u(n)&&(n=A[r][i],i>e&&(e=i),r>t&&(t=r),n.real&&(o=n.colspan-1,a=n.rowspan-1,o&&i+o>e&&(e=i+o),a&&r+a>t&&(t=r+a)))})}),{x:e,y:t}}function R(e){var t,n,r,i,o,a,s,l,c,d;if(P=S(e),B&&P){for(t=Math.min(B.x,P.x),n=Math.min(B.y,P.y),r=Math.max(B.x,P.x),i=Math.max(B.y,P.y),o=r,a=i,d=n;a>=d;d++)e=A[d][t],e.real||t-(e.colspan-1)=c;c++)e=A[n][c],e.real||n-(e.rowspan-1)=d;d++)for(c=t;r>=c;c++)e=A[d][c],e.real&&(s=e.colspan-1,l=e.rowspan-1,s&&c+s>o&&(o=c+s),l&&d+l>a&&(a=d+l));for(H.removeClass(H.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),d=n;a>=d;d++)for(c=t;o>=c;c++)A[d][c]&&H.addClass(A[d][c].elm,"mce-item-selected")}}var A,B,P,L,M=o.selection,H=M.dom;a=a||H.getParent(M.getStart(),"table"),s(),L=H.getParent(M.getStart(),"th,td"),L&&(B=S(L),P=T(),L=c(B.x,B.y)),e.extend(this,{deleteTable:p,split:v,merge:y,insertRow:b,insertCol:C,deleteCols:x,deleteRows:w,cutRows:_,copyRows:N,pasteRows:k,getPos:S,setStartCell:E,setEndCell:R})}}),r(u,[f,d,c],function(e,t,n){function r(e,t){return parseInt(e.getAttribute(t)||1,10)}var i=n.each;return function(n){function o(){function t(t){function o(e,r){var i=e?"previousSibling":"nextSibling",o=n.dom.getParent(r,"tr"),s=o[i];if(s)return g(n,r,s,e),t.preventDefault(),!0;var d=n.dom.getParent(o,"table"),u=o.parentNode,f=u.nodeName.toLowerCase();if("tbody"===f||f===(e?"tfoot":"thead")){var p=a(e,d,u,"tbody");if(null!==p)return l(e,p,r)}return c(e,o,i,d)}function a(e,t,r,i){var o=n.dom.select(">"+i,t),a=o.indexOf(r);if(e&&0===a||!e&&a===o.length-1)return s(e,t);if(-1===a){var l="thead"===r.tagName.toLowerCase()?0:o.length-1;return o[l]}return o[a+(e?-1:1)]}function s(e,t){var r=e?"thead":"tfoot",i=n.dom.select(">"+r,t);return 0!==i.length?i[0]:null}function l(e,r,i){var o=d(r,e);return o&&g(n,i,o,e),t.preventDefault(),!0}function c(e,r,i,a){var s=a[i];if(s)return u(s),!0;var l=n.dom.getParent(a,"td,th");if(l)return o(e,l,t);var c=d(r,!e);return u(c),t.preventDefault(),!1}function d(e,t){var r=e&&e[t?"lastChild":"firstChild"];return r&&"BR"===r.nodeName?n.dom.getParent(r,"td,th"):r}function u(e){n.selection.setCursorLocation(e,0)}function f(){return b==e.UP||b==e.DOWN}function p(e){var t=e.selection.getNode(),n=e.dom.getParent(t,"tr");return null!==n}function m(e){for(var t=0,n=e;n.previousSibling;)n=n.previousSibling,t+=r(n,"colspan");return t}function h(e,t){var n=0,o=0;return i(e.children,function(e,i){return n+=r(e,"colspan"),o=i,n>t?!1:void 0}),o}function g(e,t,r,i){var o=m(n.dom.getParent(t,"td,th")),a=h(r,o),s=r.childNodes[a],l=d(s,i);u(l||s)}function v(e){var t=n.selection.getNode(),r=n.dom.getParent(t,"td,th"),i=n.dom.getParent(e,"td,th");return r&&r!==i&&y(r,i)}function y(e,t){return n.dom.getParent(e,"TABLE")===n.dom.getParent(t,"TABLE")}var b=t.keyCode;if(f()&&p(n)){var C=n.selection.getNode();setTimeout(function(){v(C)&&o(!t.shiftKey&&b===e.UP,C,t)},0)}}n.on("KeyDown",function(e){t(e)})}function a(){function e(e,t){var n=t.ownerDocument,r=n.createRange(),i;return r.setStartBefore(t),r.setEnd(e.endContainer,e.endOffset),i=n.createElement("body"),i.appendChild(r.cloneContents()),0===i.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length}n.on("KeyDown",function(t){var r,i,o=n.dom;(37==t.keyCode||38==t.keyCode)&&(r=n.selection.getRng(),i=o.getParent(r.startContainer,"table"),i&&n.getBody().firstChild==i&&e(r,i)&&(r=o.createRng(),r.setStartBefore(i),r.setEndBefore(i),n.selection.setRng(r),t.preventDefault()))})}function s(){n.on("KeyDown SetContent VisualAid",function(){var e;for(e=n.getBody().lastChild;e;e=e.previousSibling)if(3==e.nodeType){if(e.nodeValue.length>0)break}else if(1==e.nodeType&&!e.getAttribute("data-mce-bogus"))break;e&&"TABLE"==e.nodeName&&(n.settings.forced_root_block?n.dom.add(n.getBody(),n.settings.forced_root_block,n.settings.forced_root_block_attrs,t.ie&&t.ie<11?" ":'
          '):n.dom.add(n.getBody(),"br",{"data-mce-bogus":"1"}))}),n.on("PreProcess",function(e){var t=e.node.lastChild;t&&("BR"==t.nodeName||1==t.childNodes.length&&("BR"==t.firstChild.nodeName||"\xa0"==t.firstChild.nodeValue))&&t.previousSibling&&"TABLE"==t.previousSibling.nodeName&&n.dom.remove(t)})}function l(){function e(e,t,n,r){var i=3,o=e.dom.getParent(t.startContainer,"TABLE"),a,s,l;return o&&(a=o.parentNode),s=t.startContainer.nodeType==i&&0===t.startOffset&&0===t.endOffset&&r&&("TR"==n.nodeName||n==a),l=("TD"==n.nodeName||"TH"==n.nodeName)&&!r,s||l}function t(){var t=n.selection.getRng(),r=n.selection.getNode(),i=n.dom.getParent(t.startContainer,"TD,TH");if(e(n,t,r,i)){i||(i=r);for(var o=i.lastChild;o.lastChild;)o=o.lastChild;t.setEnd(o,o.nodeValue.length),n.selection.setRng(t)}}n.on("KeyDown",function(){t()}),n.on("MouseDown",function(e){2!=e.button&&t()})}function c(){n.on("keydown",function(t){if((t.keyCode==e.DELETE||t.keyCode==e.BACKSPACE)&&!t.isDefaultPrevented()){var r=n.dom.getParent(n.selection.getStart(),"table");if(r){for(var i=n.dom.select("td,th",r),o=i.length;o--;)if(!n.dom.hasClass(i[o],"mce-item-selected"))return;t.preventDefault(),n.execCommand("mceTableDelete")}}})}c(),t.webkit&&(o(),l()),t.gecko&&(a(),s()),t.ie>10&&(a(),s())}}),r(p,[l,m,c],function(e,t,n){return function(r){function i(){r.getBody().style.webkitUserSelect="",d&&(r.dom.removeClass(r.dom.select("td.mce-item-selected,th.mce-item-selected"),"mce-item-selected"),d=!1)}function o(t){var n,i,o=t.target;if(l&&(s||o!=l)&&("TD"==o.nodeName||"TH"==o.nodeName)){i=a.getParent(o,"table"),i==c&&(s||(s=new e(r,i),s.setStartCell(l),r.getBody().style.webkitUserSelect="none"),s.setEndCell(o),d=!0),n=r.selection.getSel();try{n.removeAllRanges?n.removeAllRanges():n.empty()}catch(u){}t.preventDefault()}}var a=r.dom,s,l,c,d=!0;return r.on("MouseDown",function(e){2!=e.button&&(i(),l=a.getParent(e.target,"td,th"),c=a.getParent(l,"table"))}),a.bind(r.getDoc(),"mouseover",o),r.on("remove",function(){a.unbind(r.getDoc(),"mouseover",o)}),r.on("MouseUp",function(){function e(e,r){var o=new t(e,e);do{if(3==e.nodeType&&0!==n.trim(e.nodeValue).length)return void(r?i.setStart(e,0):i.setEnd(e,e.nodeValue.length));if("BR"==e.nodeName)return void(r?i.setStartBefore(e):i.setEndBefore(e))}while(e=r?o.next():o.prev())}var i,o=r.selection,d,u,f,p,m;if(l){if(s&&(r.getBody().style.webkitUserSelect=""),d=a.select("td.mce-item-selected,th.mce-item-selected"),d.length>0){i=a.createRng(),f=d[0],m=d[d.length-1],i.setStartBefore(f),i.setEndAfter(f),e(f,1),u=new t(f,a.getParent(d[0],"table"));do if("TD"==f.nodeName||"TH"==f.nodeName){if(!a.hasClass(f,"mce-item-selected"))break;p=f}while(f=u.next());e(p),o.setRng(i)}r.nodeChanged(),l=s=c=null}}),r.on("KeyUp",function(){i()}),{clear:i}}}),r(h,[l,u,p,c,m,d,g],function(e,t,n,r,i,o,a){function s(r){function i(e){return e?e.replace(/px$/,""):""}function a(e){return/^[0-9]+$/.test(e)&&(e+="px"),e}function s(e){l("left center right".split(" "),function(t){r.formatter.remove("align"+t,{},e)})}function c(){var e=r.dom,t,n;t=e.getParent(r.selection.getStart(),"table"),n={width:i(e.getStyle(t,"width")||e.getAttrib(t,"width")),height:i(e.getStyle(t,"height")||e.getAttrib(t,"height")),cellspacing:e.getAttrib(t,"cellspacing"),cellpadding:e.getAttrib(t,"cellpadding"),border:e.getAttrib(t,"border"),caption:!!e.select("caption",t)[0]},l("left center right".split(" "),function(e){r.formatter.matchNode(t,"align"+e)&&(n.align=e)}),r.windowManager.open({title:"Table properties",items:{type:"form",layout:"grid",columns:2,data:n,defaults:{type:"textbox",maxWidth:50},items:[{label:"Width",name:"width"},{label:"Height",name:"height"},{label:"Cell spacing",name:"cellspacing"},{label:"Cell padding",name:"cellpadding"},{label:"Border",name:"border"},{label:"Caption",name:"caption",type:"checkbox"},{label:"Alignment",minWidth:90,name:"align",type:"listbox",text:"None",maxWidth:null,values:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]}]},onsubmit:function(){var n=this.toJSON(),i;r.undoManager.transact(function(){r.dom.setAttribs(t,{cellspacing:n.cellspacing,cellpadding:n.cellpadding,border:n.border}),r.dom.setStyles(t,{width:a(n.width),height:a(n.height)}),i=e.select("caption",t)[0],i&&!n.caption&&e.remove(i),!i&&n.caption&&(i=e.create("caption"),i.innerHTML=o.ie?"\xa0":'
          ',t.insertBefore(i,t.firstChild)),s(t),n.align&&r.formatter.apply("align"+n.align,{},t),r.focus(),r.addVisual()})}})}function d(e,t){r.windowManager.open({title:"Merge cells",body:[{label:"Cols",name:"cols",type:"textbox",size:10},{label:"Rows",name:"rows",type:"textbox",size:10}],onsubmit:function(){var n=this.toJSON();r.undoManager.transact(function(){e.merge(t,n.cols,n.rows)})}})}function u(){var e=r.dom,t,n,o=[];o=r.dom.select("td.mce-item-selected,th.mce-item-selected"),t=r.dom.getParent(r.selection.getStart(),"td,th"),!o.length&&t&&o.push(t),t=t||o[0],t&&(n={width:i(e.getStyle(t,"width")||e.getAttrib(t,"width")),height:i(e.getStyle(t,"height")||e.getAttrib(t,"height")),scope:e.getAttrib(t,"scope")},n.type=t.nodeName.toLowerCase(),l("left center right".split(" "),function(e){r.formatter.matchNode(t,"align"+e)&&(n.align=e)}),r.windowManager.open({title:"Cell properties",items:{type:"form",data:n,layout:"grid",columns:2,defaults:{type:"textbox",maxWidth:50},items:[{label:"Width",name:"width"},{label:"Height",name:"height"},{label:"Cell type",name:"type",type:"listbox",text:"None",minWidth:90,maxWidth:null,menu:[{text:"Cell",value:"td"},{text:"Header cell",value:"th"}]},{label:"Scope",name:"scope",type:"listbox",text:"None",minWidth:90,maxWidth:null,menu:[{text:"None",value:""},{text:"Row",value:"row"},{text:"Column",value:"col"},{text:"Row group",value:"rowgroup"},{text:"Column group",value:"colgroup"}]},{label:"Alignment",name:"align",type:"listbox",text:"None",minWidth:90,maxWidth:null,values:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]}]},onsubmit:function(){var t=this.toJSON();r.undoManager.transact(function(){l(o,function(n){r.dom.setAttrib(n,"scope",t.scope),r.dom.setStyles(n,{width:a(t.width),height:a(t.height)}),t.type&&n.nodeName.toLowerCase()!=t.type&&(n=e.rename(n,t.type)),s(n),t.align&&r.formatter.apply("align"+t.align,{},n)}),r.focus()})}}))}function f(){var e=r.dom,t,n,o,c,d=[];t=r.dom.getParent(r.selection.getStart(),"table"),n=r.dom.getParent(r.selection.getStart(),"td,th"),l(t.rows,function(t){l(t.cells,function(r){return e.hasClass(r,"mce-item-selected")||r==n?(d.push(t),!1):void 0})}),o=d[0],o&&(c={height:i(e.getStyle(o,"height")||e.getAttrib(o,"height")),scope:e.getAttrib(o,"scope")},c.type=o.parentNode.nodeName.toLowerCase(),l("left center right".split(" "),function(e){r.formatter.matchNode(o,"align"+e)&&(c.align=e)}),r.windowManager.open({title:"Row properties",items:{type:"form",data:c,columns:2,defaults:{type:"textbox"},items:[{type:"listbox",name:"type",label:"Row type",text:"None",maxWidth:null,menu:[{text:"Header",value:"thead"},{text:"Body",value:"tbody"},{text:"Footer",value:"tfoot"}]},{type:"listbox",name:"align",label:"Alignment",text:"None",maxWidth:null,menu:[{text:"None",value:""},{text:"Left",value:"left"},{text:"Center",value:"center"},{text:"Right",value:"right"}]},{label:"Height",name:"height"}]},onsubmit:function(){var t=this.toJSON(),n,i,o;r.undoManager.transact(function(){var c=t.type;l(d,function(l){r.dom.setAttrib(l,"scope",t.scope),r.dom.setStyles(l,{height:a(t.height)}),c!=l.parentNode.nodeName.toLowerCase()&&(n=e.getParent(l,"table"),i=l.parentNode,o=e.select(c,n)[0],o||(o=e.create(c),n.firstChild?n.insertBefore(o,n.firstChild):n.appendChild(o)),o.appendChild(l),i.hasChildNodes()||e.remove(i)),s(l),t.align&&r.formatter.apply("align"+t.align,{},l)}),r.focus()})}}))}function p(e){return function(){r.execCommand(e)}}function m(e,t){var n,i,a;for(a="

          ",n=0;t>n;n++){for(a+="",i=0;e>i;i++)a+="";a+=""}a+="
          "+(o.ie?" ":"
          ")+"
          ",r.insertContent(a)}function h(e,t){function n(){e.disabled(!r.dom.getParent(r.selection.getStart(),t)),r.selection.selectorChanged(t,function(t){e.disabled(!t)})}r.initialized?n():r.on("init",n)}function g(){h(this,"table")}function v(){h(this,"td,th")}function y(){var e="";e='';for(var t=0;10>t;t++){e+="";for(var n=0;10>n;n++)e+='";e+=""}return e+="
          ",e+=''}function b(e,t,n){var i=n.getEl().getElementsByTagName("table")[0],o=n.parent().rel,a,s,l,c;if(n.isRtl()||"tl-tr"==o){for(s=9;s>=0;s--)for(a=0;10>a;a++)c=i.rows[s].childNodes[a].firstChild,r.dom.toggleClass(c,"mce-active",a>=e&&t>=s),a>=e&&t>=s&&(l=c);e=9-e,i.nextSibling.innerHTML=e+" x "+(t+1)}else{for(s=0;10>s;s++)for(a=0;10>a;a++)c=i.rows[s].childNodes[a].firstChild,r.dom.toggleClass(c,"mce-active",e>=a&&t>=s),e>=a&&t>=s&&(l=c);i.nextSibling.innerHTML=e+1+" x "+(t+1)}return l.parentNode}var C,x,w=this;r.addMenuItem("inserttable",{text:"Insert table",icon:"table",context:"table",onhide:function(){var e=this.menu.items()[0].getEl().getElementsByTagName("a");r.dom.removeClass(e,"mce-active"),r.dom.addClass(e[0],"mce-active")},menu:[{type:"container",html:y(),onPostRender:function(){this.lastX=this.lastY=0},onmousemove:function(e){var t=e.target,n,r;"A"==t.nodeName&&(n=parseInt(t.getAttribute("data-mce-x"),10),r=parseInt(t.getAttribute("data-mce-y"),10),(n!==this.lastX||r!==this.lastY)&&(b(n,r,e.control),this.lastX=n,this.lastY=r))},onkeydown:function(e){var t=this.lastX,n=this.lastY,r;switch(e.keyCode){case 37:t>0&&(t--,r=!0);break;case 39:r=!0,9>t&&t++;break;case 38:r=!0,n>0&&n--;break;case 40:r=!0,9>n&&n++}r&&(e.preventDefault(),e.stopPropagation(),b(t,n,e.control).focus(),this.lastX=t,this.lastY=n)},onclick:function(e){"A"==e.target.nodeName&&(e.preventDefault(),e.stopPropagation(),this.parent().cancel(),m(this.lastX+1,this.lastY+1))}}]}),r.addMenuItem("tableprops",{text:"Table properties",context:"table",onPostRender:g,onclick:c}),r.addMenuItem("deletetable",{text:"Delete table",context:"table",onPostRender:g,cmd:"mceTableDelete"}),r.addMenuItem("cell",{separator:"before",text:"Cell",context:"table",menu:[{text:"Cell properties",onclick:p("mceTableCellProps"),onPostRender:v},{text:"Merge cells",onclick:p("mceTableMergeCells"),onPostRender:v},{text:"Split cell",onclick:p("mceTableSplitCells"),onPostRender:v}]}),r.addMenuItem("row",{text:"Row",context:"table",menu:[{text:"Insert row before",onclick:p("mceTableInsertRowBefore"),onPostRender:v},{text:"Insert row after",onclick:p("mceTableInsertRowAfter"),onPostRender:v},{text:"Delete row",onclick:p("mceTableDeleteRow"),onPostRender:v},{text:"Row properties",onclick:p("mceTableRowProps"),onPostRender:v},{text:"-"},{text:"Cut row",onclick:p("mceTableCutRow"),onPostRender:v},{text:"Copy row",onclick:p("mceTableCopyRow"),onPostRender:v},{text:"Paste row before",onclick:p("mceTablePasteRowBefore"),onPostRender:v},{text:"Paste row after",onclick:p("mceTablePasteRowAfter"),onPostRender:v}]}),r.addMenuItem("column",{text:"Column",context:"table",menu:[{text:"Insert column before",onclick:p("mceTableInsertColBefore"),onPostRender:v},{text:"Insert column after",onclick:p("mceTableInsertColAfter"),onPostRender:v},{text:"Delete column",onclick:p("mceTableDeleteCol"),onPostRender:v}]});var _=[];l("inserttable tableprops deletetable | cell row column".split(" "),function(e){_.push("|"==e?{text:"-"}:r.menuItems[e])}),r.addButton("table",{type:"menubutton",title:"Table",menu:_}),o.isIE||r.on("click",function(e){e=e.target,"TABLE"===e.nodeName&&(r.selection.select(e),r.nodeChanged())}),w.quirks=new t(r),r.on("Init",function(){C=r.windowManager,w.cellSelection=new n(r)}),l({mceTableSplitCells:function(e){e.split()},mceTableMergeCells:function(e){var t,n,i;i=r.dom.getParent(r.selection.getStart(),"th,td"),i&&(t=i.rowSpan,n=i.colSpan),r.dom.select("td.mce-item-selected,th.mce-item-selected").length?e.merge():d(e,i)},mceTableInsertRowBefore:function(e){e.insertRow(!0)},mceTableInsertRowAfter:function(e){e.insertRow()},mceTableInsertColBefore:function(e){e.insertCol(!0)},mceTableInsertColAfter:function(e){e.insertCol()},mceTableDeleteCol:function(e){e.deleteCols()},mceTableDeleteRow:function(e){e.deleteRows()},mceTableCutRow:function(e){x=e.cutRows()},mceTableCopyRow:function(e){x=e.copyRows()},mceTablePasteRowBefore:function(e){e.pasteRows(x,!0)},mceTablePasteRowAfter:function(e){e.pasteRows(x)},mceTableDelete:function(e){e.deleteTable()}},function(t,n){r.addCommand(n,function(){var n=new e(r);n&&(t(n),r.execCommand("mceRepaint"),w.cellSelection.clear())})}),l({mceInsertTable:function(){c()},mceTableRowProps:f,mceTableCellProps:u},function(e,t){r.addCommand(t,function(t,n){e(n)})})}var l=r.each;a.add("table",s)}),a([l,u,p,h])}(this); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/template/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/template/plugin.min.js deleted file mode 100644 index 91a8b5fa2d..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/template/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("template",function(e){function t(t){return function(){var a=e.settings.templates;"string"==typeof a?tinymce.util.XHR.send({url:a,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(a)}}function a(t){function a(t){function a(t){if(-1==t.indexOf("")){var a="";tinymce.each(e.contentCSS,function(t){a+=''}),t=""+a+""+""+t+""+""}t=r(t,"template_preview_replace_values");var l=n.find("iframe")[0].getEl().contentWindow.document;l.open(),l.write(t),l.close()}var c=t.control.value();c.url?tinymce.util.XHR.send({url:c.url,success:function(e){l=e,a(l)}}):(l=c.content,a(l)),n.find("#description")[0].text(t.control.value().description)}var n,l,i=[];return t&&0!==t.length?(tinymce.each(t,function(e){i.push({selected:!i.length,text:e.title,value:{url:e.url,content:e.content,description:e.description}})}),n=e.windowManager.open({title:"Insert template",layout:"flex",direction:"column",align:"stretch",padding:15,spacing:10,items:[{type:"form",flex:0,padding:0,items:[{type:"container",label:"Templates",items:{type:"listbox",label:"Templates",name:"template",values:i,onselect:a}}]},{type:"label",name:"description",label:"Description",text:" "},{type:"iframe",flex:1,border:1}],onsubmit:function(){c(!1,l)},width:e.getParam("template_popup_width",600),height:e.getParam("template_popup_height",500)}),n.find("listbox")[0].fire("select"),void 0):(e.windowManager.alert("No templates defined"),void 0)}function n(t,a){function n(e,t){if(e=""+e,e.length0&&(o=p.create("div",null),o.appendChild(s[0].cloneNode(!0))),i(p.select("*",o),function(t){c(t,e.getParam("template_cdate_classes","cdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_cdate_format",e.getLang("template.cdate_format")))),c(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_mdate_format",e.getLang("template.mdate_format")))),c(t,e.getParam("template_selected_content_classes","selcontent").replace(/\s+/g,"|"))&&(t.innerHTML=m)}),l(o),e.execCommand("mceInsertContent",!1,o.innerHTML),e.addVisual()}var i=tinymce.each;e.addCommand("mceInsertTemplate",c),e.addButton("template",{title:"Insert template",onclick:t(a)}),e.addMenuItem("template",{text:"Insert template",onclick:t(a),context:"insert"}),e.on("PreProcess",function(t){var a=e.dom;i(a.select("div",t.node),function(t){a.hasClass(t,"mceTmpl")&&(i(a.select("*",t),function(t){a.hasClass(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_mdate_format",e.getLang("template.mdate_format"))))}),l(t))})})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/textcolor/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/textcolor/plugin.min.js deleted file mode 100644 index 8f49254def..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/textcolor/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("textcolor",function(e){function t(){var t,o,r=[];for(o=e.settings.textcolor_map||["000000","Black","993300","Burnt orange","333300","Dark olive","003300","Dark green","003366","Dark azure","000080","Navy Blue","333399","Indigo","333333","Very dark gray","800000","Maroon","FF6600","Orange","808000","Olive","008000","Green","008080","Teal","0000FF","Blue","666699","Grayish blue","808080","Gray","FF0000","Red","FF9900","Amber","99CC00","Yellow green","339966","Sea green","33CCCC","Turquoise","3366FF","Royal blue","800080","Purple","999999","Medium gray","FF00FF","Magenta","FFCC00","Gold","FFFF00","Yellow","00FF00","Lime","00FFFF","Aqua","00CCFF","Sky blue","993366","Brown","C0C0C0","Silver","FF99CC","Pink","FFCC99","Peach","FFFF99","Light yellow","CCFFCC","Pale green","CCFFFF","Pale cyan","99CCFF","Light sky blue","CC99FF","Plum","FFFFFF","White"],t=0;t',a=o.length-1,c=e.settings.textcolor_rows||5,i=e.settings.textcolor_cols||8,F=0;c>F;F++){for(l+="",n=0;i>n;n++)d=F*i+n,d>a?l+="":(r=o[d],l+='
          ');l+=""}return l+=""}function r(t){var o,r=this.parent();(o=t.target.getAttribute("data-mce-color"))&&(this.lastId&&document.getElementById(this.lastId).setAttribute("aria-selected",!1),t.target.setAttribute("aria-selected",!0),this.lastId=t.target.id,r.hidePanel(),o="#"+o,r.color(o),e.execCommand(r.settings.selectcmd,!1,o))}function l(){var t=this;t._color&&e.execCommand(t.settings.selectcmd,!1,t._color)}e.addButton("forecolor",{type:"colorbutton",tooltip:"Text color",selectcmd:"ForeColor",panel:{role:"application",ariaRemember:!0,html:o,onclick:r},onclick:l}),e.addButton("backcolor",{type:"colorbutton",tooltip:"Background color",selectcmd:"HiliteColor",panel:{role:"application",ariaRemember:!0,html:o,onclick:r},onclick:l})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualblocks/css/visualblocks.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualblocks/css/visualblocks.css deleted file mode 100644 index fe6fa930a4..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualblocks/css/visualblocks.css +++ /dev/null @@ -1,128 +0,0 @@ -.mce-visualblocks p { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); -} - -.mce-visualblocks h1 { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); -} - -.mce-visualblocks h2 { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); -} - -.mce-visualblocks h3 { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); -} - -.mce-visualblocks h4 { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); -} - -.mce-visualblocks h5 { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); -} - -.mce-visualblocks h6 { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); -} - -.mce-visualblocks div { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); -} - -.mce-visualblocks section { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); -} - -.mce-visualblocks article { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); -} - -.mce-visualblocks blockquote { - padding-top: 10px; - border: 1px dashed #BBB; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); -} - -.mce-visualblocks address { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); -} - -.mce-visualblocks pre { - padding-top: 10px; - border: 1px dashed #BBB; - margin-left: 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); -} - -.mce-visualblocks figure { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); -} - -.mce-visualblocks hgroup { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); -} - -.mce-visualblocks aside { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); -} - -.mce-visualblocks figcaption { - border: 1px dashed #BBB; -} - -.mce-visualblocks ul { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==) -} - -.mce-visualblocks ol { - padding-top: 10px; - border: 1px dashed #BBB; - margin: 0 0 1em 3px; - background: transparent no-repeat url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); -} diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualblocks/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualblocks/plugin.min.js deleted file mode 100644 index cafa418736..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualblocks/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("visualblocks",function(e,t){function n(){var t=this;t.active(r),e.on("VisualBlocks",function(){t.active(e.dom.hasClass(e.getBody(),"mce-visualblocks"))})}var i,a,r;window.NodeList&&(e.addCommand("mceVisualBlocks",function(){var n,o=e.dom;i||(i=o.uniqueId(),n=o.create("link",{id:i,rel:"stylesheet",href:t+"/css/visualblocks.css"}),e.getDoc().getElementsByTagName("head")[0].appendChild(n)),e.on("PreviewFormats AfterPreviewFormats",function(t){r&&o.toggleClass(e.getBody(),"mce-visualblocks","afterpreviewformats"==t.type)}),o.toggleClass(e.getBody(),"mce-visualblocks"),r=e.dom.hasClass(e.getBody(),"mce-visualblocks"),a&&a.active(o.hasClass(e.getBody(),"mce-visualblocks")),e.fire("VisualBlocks")}),e.addButton("visualblocks",{title:"Show blocks",cmd:"mceVisualBlocks",onPostRender:n}),e.addMenuItem("visualblocks",{text:"Show blocks",cmd:"mceVisualBlocks",onPostRender:n,selectable:!0,context:"view",prependToContext:!0}),e.on("init",function(){e.settings.visualblocks_default_state&&e.execCommand("mceVisualBlocks",!1,null,{skip_focus:!0})}),e.on("remove",function(){e.dom.removeClass(e.getBody(),"mce-visualblocks")}))}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualchars/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualchars/plugin.min.js deleted file mode 100644 index 490ad137ee..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/visualchars/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("visualchars",function(e){function a(a){var t,s,i,r,c,d,l=e.getBody(),m=e.selection;if(n=!n,o.state=n,e.fire("VisualChars",{state:n}),a&&(d=m.getBookmark()),n)for(s=[],tinymce.walk(l,function(e){3==e.nodeType&&e.nodeValue&&-1!=e.nodeValue.indexOf(" ")&&s.push(e)},"childNodes"),i=0;i$1'),c=e.dom.create("div",null,r);t=c.lastChild;)e.dom.insertAfter(t,s[i]);e.dom.remove(s[i])}else for(s=e.dom.select("span.mce-nbsp",l),i=s.length-1;i>=0;i--)e.dom.remove(s[i],1);m.moveToBookmark(d)}function t(){var a=this;e.on("VisualChars",function(e){a.active(e.state)})}var n,o=this;e.addCommand("mceVisualChars",a),e.addButton("visualchars",{title:"Show invisible characters",cmd:"mceVisualChars",onPostRender:t}),e.addMenuItem("visualchars",{text:"Show invisible characters",cmd:"mceVisualChars",onPostRender:t,selectable:!0,context:"view",prependToContext:!0}),e.on("beforegetcontent",function(e){n&&"raw"!=e.format&&!e.draft&&(n=!0,a(!1))})}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/wordcount/plugin.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/wordcount/plugin.min.js deleted file mode 100644 index 1fd1518c87..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/plugins/wordcount/plugin.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.PluginManager.add("wordcount",function(e){function t(){e.theme.panel.find("#wordcount").text(["Words: {0}",a.getCount()])}var n,o,a=this;n=e.getParam("wordcount_countregex",/[\w\u2019\x27\-\u00C0-\u1FFF]+/g),o=e.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$?\x27\x22_+=\\\/\-]*/g),e.on("init",function(){var n=e.theme.panel&&e.theme.panel.find("#statusbar")[0];n&&window.setTimeout(function(){n.insert({type:"label",name:"wordcount",text:["Words: {0}",a.getCount()],classes:"wordcount",disabled:e.settings.readonly},0),e.on("setcontent beforeaddundo",t),e.on("keyup",function(e){32==e.keyCode&&t()})},0)}),a.getCount=function(){var t=e.getContent({format:"raw"}),a=0;if(t){t=t.replace(/\.\.\./g," "),t=t.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," "),t=t.replace(/(\w+)(&#?[a-z0-9]+;)+(\w+)/i,"$1$3").replace(/&.+?;/g," "),t=t.replace(o,"");var r=t.match(n);r&&(a=r.length)}return a}}); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/content.inline.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/content.inline.min.css deleted file mode 100644 index 9f194f6a64..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/content.inline.min.css +++ /dev/null @@ -1 +0,0 @@ -.mce-object{border:1px dotted #3A3A3A;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0px}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/content.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/content.min.css deleted file mode 100644 index ea08c6896f..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/content.min.css +++ /dev/null @@ -1 +0,0 @@ -body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.mce-object{border:1px dotted #3A3A3A;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0px}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/readme.md b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/readme.md deleted file mode 100644 index fa5d63946c..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/readme.md +++ /dev/null @@ -1 +0,0 @@ -Icons are generated and provided by the http://icomoon.io service. diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.eot b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.eot deleted file mode 100644 index 128a98f3d8..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.eot and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.svg b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.svg deleted file mode 100644 index fd5e3ff4d2..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.ttf b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.ttf deleted file mode 100644 index 7b50bfdae9..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.ttf and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.woff b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.woff deleted file mode 100644 index 725aaf19e2..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce-small.woff and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.eot b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.eot deleted file mode 100644 index b769c2c661..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.eot and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.svg b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.svg deleted file mode 100644 index fe4e31bf03..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.svg +++ /dev/null @@ -1,153 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.ttf b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.ttf deleted file mode 100644 index a31b584c2b..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.ttf and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.woff b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.woff deleted file mode 100644 index f0e8a34c6f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/fonts/tinymce.woff and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/anchor.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/anchor.gif deleted file mode 100644 index 606348c7f5..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/anchor.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/loader.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/loader.gif deleted file mode 100644 index c69e937232..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/loader.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/object.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/object.gif deleted file mode 100644 index cccd7f023f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/object.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/trans.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/trans.gif deleted file mode 100644 index 388486517f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/img/trans.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/skin.ie7.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/skin.ie7.min.css deleted file mode 100644 index 5ddbc66d86..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/skin.ie7.min.css +++ /dev/null @@ -1 +0,0 @@ -.mce-container,.mce-container *,.mce-widget,.mce-widget *,.mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr}.mce-widget button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.mce-tinymce{visibility:visible !important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}div.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid #9e9e9e;width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#d9d9d9}.mce-grid td div{border:1px solid #d6d6d6;width:12px;height:12px;margin:2px;cursor:pointer}.mce-grid td div:focus{border-color:#a1a1a1}.mce-grid{border-spacing:2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover,.mce-grid a:focus{border-color:#a1a1a1}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#d6d6d6;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#a1a1a1;background:#c8def4}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-toolbar-grp{padding-bottom:2px}.mce-toolbar-grp .mce-flow-layout-item{margin-bottom:0}.mce-rtl .mce-wordcount{left:0;right:auto}.mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scroll{position:relative}.mce-panel{border:0 solid #9e9e9e;background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fdfdfd, #ddd);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fdfdfd), to(#ddd));background-image:-webkit-linear-gradient(top, #fdfdfd, #ddd);background-image:-o-linear-gradient(top, #fdfdfd, #ddd);background-image:linear-gradient(to bottom, #fdfdfd, #ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd', endColorstr='#ffdddddd', GradientType=0);zoom:1}.mce-floatpanel{position:absolute;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2)}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mce-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);top:0;left:0;background:#fff;border:1px solid #9e9e9e;border:1px solid rgba(0,0,0,0.25)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px;*margin-top:0}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#9e9e9e;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mce-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#fff;height:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#fff;position:fixed;top:0;left:0;opacity:0;-webkit-transition:opacity 150ms ease-in;transition:opacity 150ms ease-in}.mce-window.mce-in{opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #c5c5c5;position:relative}.mce-window-head .mce-close{position:absolute;right:15px;top:9px;font-size:20px;font-weight:bold;line-height:20px;color:#858585;cursor:pointer;height:20px;overflow:hidden}.mce-close:hover{color:#adadad}.mce-window-head .mce-title{line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:10px}.mce-window .mce-container-body{display:block}.mce-foot{display:block;background-color:#fff;border-top:1px solid #c5c5c5;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-window.mce-fullscreen,.mce-window.mce-fullscreen .mce-foot{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-rtl .mce-window-head .mce-close{position:absolute;right:auto;left:15px}.mce-rtl .mce-window-head .mce-dragh{left:auto;right:0}.mce-rtl .mce-window-head .mce-title{direction:rtl;text-align:right}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:#fff;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-inner{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-tooltip-inner{-webkit-box-shadow:0 0 5px #000000;-moz-box-shadow:0 0 5px #000000;box-shadow:0 0 5px #000000}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-color:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-tooltip-sw{margin-left:-14px}.mce-tooltip-n .mce-tooltip-arrow{top:0px;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-btn{border:1px solid #b1b1b1;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);position:relative;text-shadow:0 1px 1px rgba(255,255,255,0.75);display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1}.mce-btn:hover,.mce-btn:focus{color:#333;background-color:#e3e3e3;background-image:-moz-linear-gradient(top, #f2f2f2, #ccc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#ccc));background-image:-webkit-linear-gradient(top, #f2f2f2, #ccc);background-image:-o-linear-gradient(top, #f2f2f2, #ccc);background-image:linear-gradient(to bottom, #f2f2f2, #ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffcccccc', GradientType=0);zoom:1}.mce-btn.mce-disabled button,.mce-btn.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn:not(.mce-disabled):active{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn button{padding:4px 10px;font-size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#333;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px #fff}.mce-primary{min-width:50px;color:#fff;border:1px solid #b1b1b1;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);zoom:1}.mce-primary:hover,.mce-primary:focus{background-color:#005fb3;background-image:-moz-linear-gradient(top, #0077b3, #003cb3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0077b3), to(#003cb3));background-image:-webkit-linear-gradient(top, #0077b3, #003cb3);background-image:-o-linear-gradient(top, #0077b3, #003cb3);background-image:linear-gradient(to bottom, #0077b3, #003cb3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0077b3', endColorstr='#ff003cb3', GradientType=0);zoom:1}.mce-primary.mce-disabled button,.mce-primary.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-primary.mce-active,.mce-primary.mce-active:hover,.mce-primary:not(.mce-disabled):active{background-color:#005299;background-image:-moz-linear-gradient(top, #069, #039);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#069), to(#039));background-image:-webkit-linear-gradient(top, #069, #039);background-image:-o-linear-gradient(top, #069, #039);background-image:linear-gradient(to bottom, #069, #039);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff006699', endColorstr='#ff003399', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-primary button,.mce-primary button i{color:#fff;text-shadow:1px 1px #333}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:1px 5px;font-size:12px;*padding-bottom:2px}.mce-btn-small i{line-height:20px;vertical-align:top;*line-height:18px}.mce-btn .mce-caret{margin-top:8px;margin-left:0}.mce-btn-small .mce-caret{margin-top:8px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #333;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#aaa}.mce-caret.mce-up{border-bottom:4px solid #333;border-top:0}.mce-rtl .mce-btn button{direction:rtl}.mce-btn-group .mce-btn{border-width:1px 0 1px 0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-btn-group .mce-first{border-left:1px solid #b1b1b1;border-left:1px solid rgba(0,0,0,0.25);-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.mce-btn-group .mce-last{border-right:1px solid #b1b1b1;border-right:1px solid rgba(0,0,0,0.1);-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.mce-btn-group .mce-first.mce-last{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0;overflow:hidden}.mce-checked i.mce-i-checkbox{color:#333;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox,.mce-checkbox.mce-focus i.mce-i-checkbox{border:1px solid rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65)}.mce-checkbox.mce-disabled .mce-label,.mce-checkbox.mce-disabled i.mce-i-checkbox{color:#acacac}.mce-rtl .mce-checkbox{direction:rtl;text-align:right}.mce-rtl i.mce-i-checkbox{margin:0 0 0 3px}.mce-colorbutton .mce-ico{position:relative}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:4px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-14px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-16px;padding-right:0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;border-left:1px solid transparent;border-right:1px solid transparent}.mce-colorbutton:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-colorbutton.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-colorbutton{direction:rtl}.mce-rtl .mce-colorbutton .mce-preview{margin-left:0;padding-right:0;padding-left:4px;margin-right:-14px}.mce-rtl .mce-colorbutton.mce-btn-small .mce-preview{margin-left:0;padding-right:0;margin-right:-17px;padding-left:0}.mce-rtl .mce-colorbutton button{padding-right:10px;padding-left:10px}.mce-rtl .mce-colorbutton .mce-open{padding-left:4px;padding-right:4px}.mce-combobox{display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);*height:32px}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:#c5c5c5;height:28px}.mce-combobox.mce-disabled input{color:#adadad}.mce-combobox.mce-has-open input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.mce-combobox .mce-btn{border-left:0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox.mce-disabled .mce-btn button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#333}.mce-path-item:hover{text-decoration:underline}.mce-path-item:focus{background:#666;color:#fff}.mce-path .mce-divider{display:inline}.mce-disabled .mce-path-item{color:#aaa}.mce-rtl .mce-path{direction:rtl}.mce-fieldset{border:0 solid #9E9E9E;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-inline .mce-flow-layout{white-space:nowrap}.mce-rtl .mce-flow-layout{text-align:right;direction:rtl}.mce-rtl .mce-flow-layout-item{margin:2px 2px 2px 0}.mce-rtl .mce-flow-layout-item.mce-last{margin-left:2px}.mce-iframe{border:0 solid #9e9e9e;width:100%;height:100%}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);border:0;overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label.mce-disabled{color:#aaa}.mce-label.mce-multiline{white-space:pre-wrap}.mce-rtl .mce-label{text-align:right;direction:rtl}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:none}.mce-menubar{border:1px solid #c4c4c4}.mce-menubar .mce-menubtn button span{color:#333}.mce-menubar .mce-caret{border-top-color:#333}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:transparent;background:#e6e6e6;filter:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-menubtn.mce-disabled span{color:#aaa}.mce-menubtn span{color:#333;margin-right:2px;line-height:20px;*line-height:16px}.mce-menubtn.mce-btn-small span{font-size:12px}.mce-menubtn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-menubtn .mce-caret{*margin-top:6px}.mce-rtl .mce-menubtn button{direction:rtl;text-align:right}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-rtl .mce-listbox .mce-caret{right:auto;left:8px}.mce-rtl .mce-listbox button{padding-right:10px;padding-left:20px}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item .mce-ico,.mce-menu-item .mce-text{color:#333}.mce-menu-item.mce-disabled .mce-text,.mce-menu-item.mce-disabled .mce-ico{color:#adadad}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text,.mce-menu-item:focus .mce-text{color:#fff}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:#fff}.mce-menu-item.mce-disabled:hover{background:#ccc}.mce-menu-shortcut{display:inline-block;color:#adadad}.mce-menu-shortcut{display:inline-block;*display:inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item:hover .mce-menu-shortcut,.mce-menu-item.mce-selected .mce-menu-shortcut,.mce-menu-item:focus .mce-menu-shortcut{color:#fff}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #333}.mce-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret,.mce-menu-item:hover .mce-caret{border-left-color:#fff}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item-normal.mce-active{background-color:#c8def4}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa}.mce-menu-item-normal.mce-active .mce-text{color:#333}.mce-menu-item-normal.mce-active:hover .mce-text,.mce-menu-item-normal.mce-active:hover .mce-ico{color:#fff}.mce-menu-item-normal.mce-active:focus .mce-text,.mce-menu-item-normal.mce-active:focus .mce-ico{color:#fff}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);zoom:1}div.mce-menu .mce-menu-item-sep,.mce-menu-item-sep:hover{border:0;padding:0;height:1px;margin:9px 1px;overflow:hidden;background:#cbcbcb;border-bottom:1px solid #fff;cursor:default;filter:none}.mce-menu.mce-rtl{direction:rtl}.mce-rtl .mce-menu-item{text-align:right;direction:rtl;padding:6px 12px 6px 15px}.mce-menu-align.mce-rtl .mce-menu-shortcut,.mce-menu-align.mce-rtl .mce-caret{right:auto;left:0}.mce-rtl .mce-menu-item .mce-caret{margin-left:6px;margin-right:0;border-right:4px solid #333;border-left:0}.mce-rtl .mce-menu-item.mce-selected .mce-caret,.mce-rtl .mce-menu-item:focus .mce-caret,.mce-rtl .mce-menu-item:hover .mce-caret{border-left-color:transparent;border-right-color:#fff}.mce-menu{position:absolute;left:0;top:0;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;margin:2px 0 0;min-width:160px;background:#fff;border:1px solid #989898;border:1px solid rgba(0,0,0,0.2);z-index:1002;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#333}.mce-spacer{visibility:hidden}.mce-splitbtn .mce-open{border-left:1px solid transparent;border-right:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-splitbtn button{padding-right:4px}.mce-splitbtn .mce-open{padding-left:4px}.mce-splitbtn .mce-open.mce-active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-splitbtn.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-splitbtn{direction:rtl;text-align:right}.mce-rtl .mce-splitbtn button{padding-right:10px;padding-left:10px}.mce-rtl .mce-splitbtn .mce-open{padding-left:4px;padding-right:4px}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #c5c5c5}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #c5c5c5;border-width:0 1px 0 0;background:#e3e3e3;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#fdfdfd}.mce-tab.mce-active{background:#fdfdfd;border-bottom-color:transparent;margin-bottom:-1px;height:14px}.mce-rtl .mce-tabs{text-align:right;direction:rtl}.mce-rtl .mce-tab{border-width:0 0 0 1px}.mce-textbox{background:#fff;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);display:inline-block;-webkit-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#333}.mce-textbox:focus,.mce-textbox.mce-focus{border-color:rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65)}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px}.mce-textbox.mce-disabled{color:#adadad}.mce-rtl .mce-textbox{text-align:right;direction:rtl}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}@font-face{font-family:'tinymce';src:url('fonts/tinymce.eot');src:url('fonts/tinymce.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce.woff') format('woff'),url('fonts/tinymce.ttf') format('truetype'),url('fonts/tinymce.svg#tinymce') format('svg');font-weight:normal;font-style:normal}@font-face{font-family:'tinymce-small';src:url('fonts/tinymce-small.eot');src:url('fonts/tinymce-small.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce-small.woff') format('woff'),url('fonts/tinymce-small.ttf') format('truetype'),url('fonts/tinymce-small.svg#tinymce') format('svg');font-weight:normal;font-style:normal}.mce-ico{font-family:'tinymce';font-style:normal;font-weight:normal;font-size:16px;line-height:16px;vertical-align:text-top;-webkit-font-smoothing:antialiased;display:inline-block;background:transparent center center;width:16px;height:16px;color:#333;-ie7-icon:' '}.mce-btn-small .mce-ico{font-family:'tinymce-small'}.mce-ico,i.mce-i-checkbox{zoom:expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = this.currentStyle['-ie7-icon'].substr(1, 1) + ' ')}.mce-i-save{-ie7-icon:"\e000"}.mce-i-newdocument{-ie7-icon:"\e001"}.mce-i-fullpage{-ie7-icon:"\e002"}.mce-i-alignleft{-ie7-icon:"\e003"}.mce-i-aligncenter{-ie7-icon:"\e004"}.mce-i-alignright{-ie7-icon:"\e005"}.mce-i-alignjustify{-ie7-icon:"\e006"}.mce-i-cut{-ie7-icon:"\e007"}.mce-i-paste{-ie7-icon:"\e008"}.mce-i-searchreplace{-ie7-icon:"\e009"}.mce-i-bullist{-ie7-icon:"\e00a"}.mce-i-numlist{-ie7-icon:"\e00b"}.mce-i-indent{-ie7-icon:"\e00c"}.mce-i-outdent{-ie7-icon:"\e00d"}.mce-i-blockquote{-ie7-icon:"\e00e"}.mce-i-undo{-ie7-icon:"\e00f"}.mce-i-redo{-ie7-icon:"\e010"}.mce-i-link{-ie7-icon:"\e011"}.mce-i-unlink{-ie7-icon:"\e012"}.mce-i-anchor{-ie7-icon:"\e013"}.mce-i-image{-ie7-icon:"\e014"}.mce-i-media{-ie7-icon:"\e015"}.mce-i-help{-ie7-icon:"\e016"}.mce-i-code{-ie7-icon:"\e017"}.mce-i-insertdatetime{-ie7-icon:"\e018"}.mce-i-preview{-ie7-icon:"\e019"}.mce-i-forecolor{-ie7-icon:"\e01a"}.mce-i-backcolor{-ie7-icon:"\e01a"}.mce-i-table{-ie7-icon:"\e01b"}.mce-i-hr{-ie7-icon:"\e01c"}.mce-i-removeformat{-ie7-icon:"\e01d"}.mce-i-subscript{-ie7-icon:"\e01e"}.mce-i-superscript{-ie7-icon:"\e01f"}.mce-i-charmap{-ie7-icon:"\e020"}.mce-i-emoticons{-ie7-icon:"\e021"}.mce-i-print{-ie7-icon:"\e022"}.mce-i-fullscreen{-ie7-icon:"\e023"}.mce-i-spellchecker{-ie7-icon:"\e024"}.mce-i-nonbreaking{-ie7-icon:"\e025"}.mce-i-template{-ie7-icon:"\e026"}.mce-i-pagebreak{-ie7-icon:"\e027"}.mce-i-restoredraft{-ie7-icon:"\e028"}.mce-i-untitled{-ie7-icon:"\e029"}.mce-i-bold{-ie7-icon:"\e02a"}.mce-i-italic{-ie7-icon:"\e02b"}.mce-i-underline{-ie7-icon:"\e02c"}.mce-i-strikethrough{-ie7-icon:"\e02d"}.mce-i-visualchars{-ie7-icon:"\e02e"}.mce-i-ltr{-ie7-icon:"\e02f"}.mce-i-rtl{-ie7-icon:"\e030"}.mce-i-copy{-ie7-icon:"\e031"}.mce-i-resize{-ie7-icon:"\e032"}.mce-i-browse{-ie7-icon:"\e034"}.mce-i-pastetext{-ie7-icon:"\e035"}.mce-i-checkbox,.mce-i-selected{-ie7-icon:"\e033"}.mce-i-selected{visibility:hidden}.mce-i-backcolor{background:#BBB} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/skin.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/skin.min.css deleted file mode 100644 index 33cd17fa8a..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/lightgray/skin.min.css +++ /dev/null @@ -1 +0,0 @@ -.mce-container,.mce-container *,.mce-widget,.mce-widget *,.mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#333;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr}.mce-widget button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.mce-tinymce{visibility:visible !important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}div.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid #9e9e9e;width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#d9d9d9}.mce-grid td div{border:1px solid #d6d6d6;width:12px;height:12px;margin:2px;cursor:pointer}.mce-grid td div:focus{border-color:#a1a1a1}.mce-grid{border-spacing:2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover,.mce-grid a:focus{border-color:#a1a1a1}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#d6d6d6;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#a1a1a1;background:#c8def4}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-toolbar-grp{padding-bottom:2px}.mce-toolbar-grp .mce-flow-layout-item{margin-bottom:0}.mce-rtl .mce-wordcount{left:0;right:auto}.mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.mce-scroll{position:relative}.mce-panel{border:0 solid #9e9e9e;background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fdfdfd, #ddd);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fdfdfd), to(#ddd));background-image:-webkit-linear-gradient(top, #fdfdfd, #ddd);background-image:-o-linear-gradient(top, #fdfdfd, #ddd);background-image:linear-gradient(to bottom, #fdfdfd, #ddd);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffdfdfd', endColorstr='#ffdddddd', GradientType=0);zoom:1}.mce-floatpanel{position:absolute;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2)}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mce-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);top:0;left:0;background:#fff;border:1px solid #9e9e9e;border:1px solid rgba(0,0,0,0.25)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px;*margin-top:0}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#9e9e9e;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mce-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#fff;height:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#fff;position:fixed;top:0;left:0;opacity:0;-webkit-transition:opacity 150ms ease-in;transition:opacity 150ms ease-in}.mce-window.mce-in{opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #c5c5c5;position:relative}.mce-window-head .mce-close{position:absolute;right:15px;top:9px;font-size:20px;font-weight:bold;line-height:20px;color:#858585;cursor:pointer;height:20px;overflow:hidden}.mce-close:hover{color:#adadad}.mce-window-head .mce-title{line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:10px}.mce-window .mce-container-body{display:block}.mce-foot{display:block;background-color:#fff;border-top:1px solid #c5c5c5;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-window.mce-fullscreen,.mce-window.mce-fullscreen .mce-foot{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-rtl .mce-window-head .mce-close{position:absolute;right:auto;left:15px}.mce-rtl .mce-window-head .mce-dragh{left:auto;right:0}.mce-rtl .mce-window-head .mce-title{direction:rtl;text-align:right}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:#fff;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-inner{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-tooltip-inner{-webkit-box-shadow:0 0 5px #000000;-moz-box-shadow:0 0 5px #000000;box-shadow:0 0 5px #000000}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-color:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-tooltip-sw{margin-left:-14px}.mce-tooltip-n .mce-tooltip-arrow{top:0px;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-btn{border:1px solid #b1b1b1;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);position:relative;text-shadow:0 1px 1px rgba(255,255,255,0.75);display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1}.mce-btn:hover,.mce-btn:focus{color:#333;background-color:#e3e3e3;background-image:-moz-linear-gradient(top, #f2f2f2, #ccc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#ccc));background-image:-webkit-linear-gradient(top, #f2f2f2, #ccc);background-image:-o-linear-gradient(top, #f2f2f2, #ccc);background-image:linear-gradient(to bottom, #f2f2f2, #ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffcccccc', GradientType=0);zoom:1}.mce-btn.mce-disabled button,.mce-btn.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn:not(.mce-disabled):active{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn button{padding:4px 10px;font-size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#333;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px #fff}.mce-primary{min-width:50px;color:#fff;border:1px solid #b1b1b1;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);zoom:1}.mce-primary:hover,.mce-primary:focus{background-color:#005fb3;background-image:-moz-linear-gradient(top, #0077b3, #003cb3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0077b3), to(#003cb3));background-image:-webkit-linear-gradient(top, #0077b3, #003cb3);background-image:-o-linear-gradient(top, #0077b3, #003cb3);background-image:linear-gradient(to bottom, #0077b3, #003cb3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0077b3', endColorstr='#ff003cb3', GradientType=0);zoom:1}.mce-primary.mce-disabled button,.mce-primary.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-primary.mce-active,.mce-primary.mce-active:hover,.mce-primary:not(.mce-disabled):active{background-color:#005299;background-image:-moz-linear-gradient(top, #069, #039);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#069), to(#039));background-image:-webkit-linear-gradient(top, #069, #039);background-image:-o-linear-gradient(top, #069, #039);background-image:linear-gradient(to bottom, #069, #039);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff006699', endColorstr='#ff003399', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-primary button,.mce-primary button i{color:#fff;text-shadow:1px 1px #333}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:1px 5px;font-size:12px;*padding-bottom:2px}.mce-btn-small i{line-height:20px;vertical-align:top;*line-height:18px}.mce-btn .mce-caret{margin-top:8px;margin-left:0}.mce-btn-small .mce-caret{margin-top:8px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #333;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#aaa}.mce-caret.mce-up{border-bottom:4px solid #333;border-top:0}.mce-rtl .mce-btn button{direction:rtl}.mce-btn-group .mce-btn{border-width:1px 0 1px 0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.mce-btn-group .mce-first{border-left:1px solid #b1b1b1;border-left:1px solid rgba(0,0,0,0.25);-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.mce-btn-group .mce-last{border-right:1px solid #b1b1b1;border-right:1px solid rgba(0,0,0,0.1);-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.mce-btn-group .mce-first.mce-last{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0;overflow:hidden}.mce-checked i.mce-i-checkbox{color:#333;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox,.mce-checkbox.mce-focus i.mce-i-checkbox{border:1px solid rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65)}.mce-checkbox.mce-disabled .mce-label,.mce-checkbox.mce-disabled i.mce-i-checkbox{color:#acacac}.mce-rtl .mce-checkbox{direction:rtl;text-align:right}.mce-rtl i.mce-i-checkbox{margin:0 0 0 3px}.mce-colorbutton .mce-ico{position:relative}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:4px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-14px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-16px;padding-right:0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;border-left:1px solid transparent;border-right:1px solid transparent}.mce-colorbutton:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-colorbutton.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-colorbutton{direction:rtl}.mce-rtl .mce-colorbutton .mce-preview{margin-left:0;padding-right:0;padding-left:4px;margin-right:-14px}.mce-rtl .mce-colorbutton.mce-btn-small .mce-preview{margin-left:0;padding-right:0;margin-right:-17px;padding-left:0}.mce-rtl .mce-colorbutton button{padding-right:10px;padding-left:10px}.mce-rtl .mce-colorbutton .mce-open{padding-left:4px;padding-right:4px}.mce-combobox{display:inline-block;*display:inline;*zoom:1;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);*height:32px}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:#c5c5c5;height:28px}.mce-combobox.mce-disabled input{color:#adadad}.mce-combobox.mce-has-open input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.mce-combobox .mce-btn{border-left:0;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox.mce-disabled .mce-btn button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#333}.mce-path-item:hover{text-decoration:underline}.mce-path-item:focus{background:#666;color:#fff}.mce-path .mce-divider{display:inline}.mce-disabled .mce-path-item{color:#aaa}.mce-rtl .mce-path{direction:rtl}.mce-fieldset{border:0 solid #9E9E9E;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-inline .mce-flow-layout{white-space:nowrap}.mce-rtl .mce-flow-layout{text-align:right;direction:rtl}.mce-rtl .mce-flow-layout-item{margin:2px 2px 2px 0}.mce-rtl .mce-flow-layout-item.mce-last{margin-left:2px}.mce-iframe{border:0 solid #9e9e9e;width:100%;height:100%}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);border:0;overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label.mce-disabled{color:#aaa}.mce-label.mce-multiline{white-space:pre-wrap}.mce-rtl .mce-label{text-align:right;direction:rtl}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:none}.mce-menubar{border:1px solid #c4c4c4}.mce-menubar .mce-menubtn button span{color:#333}.mce-menubar .mce-caret{border-top-color:#333}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:transparent;background:#e6e6e6;filter:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-menubtn.mce-disabled span{color:#aaa}.mce-menubtn span{color:#333;margin-right:2px;line-height:20px;*line-height:16px}.mce-menubtn.mce-btn-small span{font-size:12px}.mce-menubtn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-menubtn .mce-caret{*margin-top:6px}.mce-rtl .mce-menubtn button{direction:rtl;text-align:right}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-rtl .mce-listbox .mce-caret{right:auto;left:8px}.mce-rtl .mce-listbox button{padding-right:10px;padding-left:20px}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item .mce-ico,.mce-menu-item .mce-text{color:#333}.mce-menu-item.mce-disabled .mce-text,.mce-menu-item.mce-disabled .mce-ico{color:#adadad}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text,.mce-menu-item:focus .mce-text{color:#fff}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:#fff}.mce-menu-item.mce-disabled:hover{background:#ccc}.mce-menu-shortcut{display:inline-block;color:#adadad}.mce-menu-shortcut{display:inline-block;*display:inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item:hover .mce-menu-shortcut,.mce-menu-item.mce-selected .mce-menu-shortcut,.mce-menu-item:focus .mce-menu-shortcut{color:#fff}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #333}.mce-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret,.mce-menu-item:hover .mce-caret{border-left-color:#fff}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item-normal.mce-active{background-color:#c8def4}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa}.mce-menu-item-normal.mce-active .mce-text{color:#333}.mce-menu-item-normal.mce-active:hover .mce-text,.mce-menu-item-normal.mce-active:hover .mce-ico{color:#fff}.mce-menu-item-normal.mce-active:focus .mce-text,.mce-menu-item-normal.mce-active:focus .mce-ico{color:#fff}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);zoom:1}div.mce-menu .mce-menu-item-sep,.mce-menu-item-sep:hover{border:0;padding:0;height:1px;margin:9px 1px;overflow:hidden;background:#cbcbcb;border-bottom:1px solid #fff;cursor:default;filter:none}.mce-menu.mce-rtl{direction:rtl}.mce-rtl .mce-menu-item{text-align:right;direction:rtl;padding:6px 12px 6px 15px}.mce-menu-align.mce-rtl .mce-menu-shortcut,.mce-menu-align.mce-rtl .mce-caret{right:auto;left:0}.mce-rtl .mce-menu-item .mce-caret{margin-left:6px;margin-right:0;border-right:4px solid #333;border-left:0}.mce-rtl .mce-menu-item.mce-selected .mce-caret,.mce-rtl .mce-menu-item:focus .mce-caret,.mce-rtl .mce-menu-item:hover .mce-caret{border-left-color:transparent;border-right-color:#fff}.mce-menu{position:absolute;left:0;top:0;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;margin:2px 0 0;min-width:160px;background:#fff;border:1px solid #989898;border:1px solid rgba(0,0,0,0.2);z-index:1002;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#333}.mce-spacer{visibility:hidden}.mce-splitbtn .mce-open{border-left:1px solid transparent;border-right:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-splitbtn button{padding-right:4px}.mce-splitbtn .mce-open{padding-left:4px}.mce-splitbtn .mce-open.mce-active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-splitbtn.mce-btn-small .mce-open{padding:0 3px 0 3px}.mce-rtl .mce-splitbtn{direction:rtl;text-align:right}.mce-rtl .mce-splitbtn button{padding-right:10px;padding-left:10px}.mce-rtl .mce-splitbtn .mce-open{padding-left:4px;padding-right:4px}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #c5c5c5}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #c5c5c5;border-width:0 1px 0 0;background:#e3e3e3;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#fdfdfd}.mce-tab.mce-active{background:#fdfdfd;border-bottom-color:transparent;margin-bottom:-1px;height:14px}.mce-rtl .mce-tabs{text-align:right;direction:rtl}.mce-rtl .mce-tab{border-width:0 0 0 1px}.mce-textbox{background:#fff;border:1px solid #c5c5c5;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);display:inline-block;-webkit-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#333}.mce-textbox:focus,.mce-textbox.mce-focus{border-color:rgba(82,168,236,0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.65)}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px}.mce-textbox.mce-disabled{color:#adadad}.mce-rtl .mce-textbox{text-align:right;direction:rtl}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}@font-face{font-family:'tinymce';src:url('fonts/tinymce.eot');src:url('fonts/tinymce.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce.woff') format('woff'),url('fonts/tinymce.ttf') format('truetype'),url('fonts/tinymce.svg#tinymce') format('svg');font-weight:normal;font-style:normal}@font-face{font-family:'tinymce-small';src:url('fonts/tinymce-small.eot');src:url('fonts/tinymce-small.eot?#iefix') format('embedded-opentype'),url('fonts/tinymce-small.woff') format('woff'),url('fonts/tinymce-small.ttf') format('truetype'),url('fonts/tinymce-small.svg#tinymce') format('svg');font-weight:normal;font-style:normal}.mce-ico{font-family:'tinymce',Arial;font-style:normal;font-weight:normal;font-size:16px;line-height:16px;vertical-align:text-top;-webkit-font-smoothing:antialiased;display:inline-block;background:transparent center center;width:16px;height:16px;color:#333}.mce-btn-small .mce-ico{font-family:'tinymce-small',Arial}.mce-i-save:before{content:"\e000"}.mce-i-newdocument:before{content:"\e001"}.mce-i-fullpage:before{content:"\e002"}.mce-i-alignleft:before{content:"\e003"}.mce-i-aligncenter:before{content:"\e004"}.mce-i-alignright:before{content:"\e005"}.mce-i-alignjustify:before{content:"\e006"}.mce-i-cut:before{content:"\e007"}.mce-i-paste:before{content:"\e008"}.mce-i-searchreplace:before{content:"\e009"}.mce-i-bullist:before{content:"\e00a"}.mce-i-numlist:before{content:"\e00b"}.mce-i-indent:before{content:"\e00c"}.mce-i-outdent:before{content:"\e00d"}.mce-i-blockquote:before{content:"\e00e"}.mce-i-undo:before{content:"\e00f"}.mce-i-redo:before{content:"\e010"}.mce-i-link:before{content:"\e011"}.mce-i-unlink:before{content:"\e012"}.mce-i-anchor:before{content:"\e013"}.mce-i-image:before{content:"\e014"}.mce-i-media:before{content:"\e015"}.mce-i-help:before{content:"\e016"}.mce-i-code:before{content:"\e017"}.mce-i-insertdatetime:before{content:"\e018"}.mce-i-preview:before{content:"\e019"}.mce-i-forecolor:before{content:"\e01a"}.mce-i-backcolor:before{content:"\e01a"}.mce-i-table:before{content:"\e01b"}.mce-i-hr:before{content:"\e01c"}.mce-i-removeformat:before{content:"\e01d"}.mce-i-subscript:before{content:"\e01e"}.mce-i-superscript:before{content:"\e01f"}.mce-i-charmap:before{content:"\e020"}.mce-i-emoticons:before{content:"\e021"}.mce-i-print:before{content:"\e022"}.mce-i-fullscreen:before{content:"\e023"}.mce-i-spellchecker:before{content:"\e024"}.mce-i-nonbreaking:before{content:"\e025"}.mce-i-template:before{content:"\e026"}.mce-i-pagebreak:before{content:"\e027"}.mce-i-restoredraft:before{content:"\e028"}.mce-i-untitled:before{content:"\e029"}.mce-i-bold:before{content:"\e02a"}.mce-i-italic:before{content:"\e02b"}.mce-i-underline:before{content:"\e02c"}.mce-i-strikethrough:before{content:"\e02d"}.mce-i-visualchars:before{content:"\e02e"}.mce-i-visualblocks:before{content:"\e02e"}.mce-i-ltr:before{content:"\e02f"}.mce-i-rtl:before{content:"\e030"}.mce-i-copy:before{content:"\e031"}.mce-i-resize:before{content:"\e032"}.mce-i-browse:before{content:"\e034"}.mce-i-pastetext:before{content:"\e035"}.mce-i-checkbox:before,.mce-i-selected:before{content:"\e033"}.mce-i-selected{visibility:hidden}i.mce-i-backcolor{text-shadow:none;background:#bbb} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.inline.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.inline.min.css deleted file mode 100644 index 8ff8ee266f..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.inline.min.css +++ /dev/null @@ -1 +0,0 @@ -.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px!important;height:9px!important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-spellchecker-word{background:url(img/wline.gif) repeat-x bottom left;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#39f!important}.mce-edit-focus{outline:1px dotted #333} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.min.css deleted file mode 100644 index 1f057287b9..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.min.css +++ /dev/null @@ -1 +0,0 @@ -body{background-color:#fff;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;scrollbar-3dlight-color:#f0f0ee;scrollbar-arrow-color:#676662;scrollbar-base-color:#f0f0ee;scrollbar-darkshadow-color:#ddd;scrollbar-face-color:#e0e0dd;scrollbar-highlight-color:#f0f0ee;scrollbar-shadow-color:#f0f0ee;scrollbar-track-color:#f5f5f5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.mce-object{border:1px dotted #3a3a3a;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px!important;height:9px!important;border:1px dotted #3a3a3a;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-spellchecker-word{background:url(img/wline.gif) repeat-x bottom left;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#39f!important}.mce-edit-focus{outline:1px dotted #333} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.smartstore.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.smartstore.css deleted file mode 100644 index c3b1b7e1fd..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/content.smartstore.css +++ /dev/null @@ -1,5 +0,0 @@ - -.mce-content-body-smartstore { - font-family: "Segoe UI",Arial,Helvetica,sans-serif; - font-size: 13px; -} diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.eot b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.eot deleted file mode 100644 index 43a30f9925..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.eot and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.svg b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.svg deleted file mode 100644 index d338114f07..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.ttf b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.ttf deleted file mode 100644 index 841c79c182..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.ttf and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.woff b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.woff deleted file mode 100644 index ad14a2406e..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon-small.woff and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.eot b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.eot deleted file mode 100644 index eed4f8149a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.eot and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.svg b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.svg deleted file mode 100644 index 727f61af13..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.svg +++ /dev/null @@ -1,153 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.ttf b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.ttf deleted file mode 100644 index dea6e458f9..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.ttf and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.woff b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.woff deleted file mode 100644 index f17657986c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/icomoon.woff and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/readme.md b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/readme.md deleted file mode 100644 index fa5d63946c..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/fonts/readme.md +++ /dev/null @@ -1 +0,0 @@ -Icons are generated and provided by the http://icomoon.io service. diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/anchor.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/anchor.gif deleted file mode 100644 index 606348c7f5..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/anchor.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/loader.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/loader.gif deleted file mode 100644 index c69e937232..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/loader.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/object.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/object.gif deleted file mode 100644 index cccd7f023f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/object.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/trans.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/trans.gif deleted file mode 100644 index 388486517f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/trans.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/wline.gif b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/wline.gif deleted file mode 100644 index 7d0a4dbca0..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/img/wline.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.ie7.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.ie7.min.css deleted file mode 100644 index ea08c71eae..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.ie7.min.css +++ /dev/null @@ -1 +0,0 @@ -.mce-container,.mce-container *,.mce-widget,.mce-widget *{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#000;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr}.mce-widget button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.mce-container ::-webkit-scrollbar{width:8px;height:8px;-webkit-border-radius:4px}.mce-container ::-webkit-scrollbar-track,.mce-container ::-webkit-scrollbar-track-piece{background-color:transparent}.mce-container ::-webkit-scrollbar-thumb{background-color:rgba(53,57,71,0.3);width:6px;height:6px;-webkit-border-radius:4px}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.mce-tinymce{visibility:visible !important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}div.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid #ccc;width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#d9d9d9}.mce-grid td div{border:1px solid #d6d6d6;width:12px;height:12px;margin:2px;cursor:pointer}.mce-grid{border-spacing:2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover{border-color:#a1a1a1}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#d6d6d6;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#a1a1a1;background:#c8def4}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-rtl .mce-wordcount{left:0;right:auto}.mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1}.mce-scroll{position:relative}.mce-panel{border:0 solid #ccc;background-color:#fdfdfd;background-image:-moz-linear-gradient(top, #fff, #fafafa);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#fafafa));background-image:-webkit-linear-gradient(top, #fff, #fafafa);background-image:-o-linear-gradient(top, #fff, #fafafa);background-image:linear-gradient(to bottom, #fff, #fafafa);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fffafafa', GradientType=0);zoom:1}.mce-floatpanel{position:absolute;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2)}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mce-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);top:0;left:0;background:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.25)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px;*margin-top:0}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#ccc;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mce-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#fff;height:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#fff;position:fixed;top:0;left:0;opacity:0;-webkit-transition:opacity 150ms ease-in;transition:opacity 150ms ease-in}.mce-window.mce-in{opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #ccc;position:relative}.mce-window-head .mce-close{position:absolute;right:15px;top:9px;font-size:20px;font-weight:bold;line-height:20px;color:#666;cursor:pointer;height:20px;overflow:hidden}.mce-close:hover{color:#999}.mce-window-head .mce-title{line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:10px}.mce-window .mce-container-body{display:block}.mce-foot{display:block;background-color:#fff;border-top:1px solid #ccc}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-rtl .mce-window-head .mce-close{position:absolute;right:auto;left:15px}.mce-rtl .mce-window-head .mce-dragh{left:auto;right:0}.mce-rtl .mce-window-head .mce-title{direction:rtl;text-align:right}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:#fff;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-inner{-webkit-box-shadow:0 0 5px #000000;-moz-box-shadow:0 0 5px #000000;box-shadow:0 0 5px #000000}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-color:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-tooltip-sw{margin-left:-14px}.mce-tooltip-n .mce-tooltip-arrow{top:0px;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-btn{border:1px solid #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);position:relative;text-shadow:0 1px 1px rgba(255,255,255,0.75);display:inline-block;*display:inline;*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1}.mce-btn:hover,.mce-btn:focus{color:#000;background-color:#e3e3e3;background-image:-moz-linear-gradient(top, #f2f2f2, #ccc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#ccc));background-image:-webkit-linear-gradient(top, #f2f2f2, #ccc);background-image:-o-linear-gradient(top, #f2f2f2, #ccc);background-image:linear-gradient(to bottom, #f2f2f2, #ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffcccccc', GradientType=0);zoom:1}.mce-btn.mce-disabled button,.mce-btn.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn:not(.mce-disabled):active{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn button{padding:4px 10px;font-size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#000;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px #fff}.mce-primary{min-width:50px;color:#fff;border:1px solid #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);zoom:1}.mce-primary:hover,.mce-primary:focus{background-color:#005fb3;background-image:-moz-linear-gradient(top, #0077b3, #003cb3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0077b3), to(#003cb3));background-image:-webkit-linear-gradient(top, #0077b3, #003cb3);background-image:-o-linear-gradient(top, #0077b3, #003cb3);background-image:linear-gradient(to bottom, #0077b3, #003cb3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0077b3', endColorstr='#ff003cb3', GradientType=0);zoom:1}.mce-primary.mce-disabled button,.mce-primary.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-primary.mce-active,.mce-primary.mce-active:hover,.mce-primary:not(.mce-disabled):active{background-color:#005299;background-image:-moz-linear-gradient(top, #069, #039);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#069), to(#039));background-image:-webkit-linear-gradient(top, #069, #039);background-image:-o-linear-gradient(top, #069, #039);background-image:linear-gradient(to bottom, #069, #039);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff006699', endColorstr='#ff003399', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-primary button,.mce-primary button i{color:#fff;text-shadow:1px 1px #333}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:3px 5px;font-size:12px;line-height:15px}.mce-btn-small i{margin-top:0}.mce-btn .mce-caret{margin-top:8px;*margin-top:6px;margin-left:0}.mce-btn-small .mce-caret{margin-top:6px;*margin-top:4px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#aaa}.mce-caret.mce-up{border-bottom:4px solid #000;border-top:0}.mce-rtl .mce-btn button{direction:rtl}.mce-btn-group .mce-btn{border-width:1px 0 1px 0;margin:0}.mce-btn-group .mce-first{border-left:1px solid #b3b3b3;border-left:1px solid rgba(0,0,0,0.25)}.mce-btn-group .mce-last{border-right:1px solid #b3b3b3;border-right:1px solid rgba(0,0,0,0.1)}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0;overflow:hidden}.mce-checked i.mce-i-checkbox{color:#000;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox,.mce-checkbox.mce-focus i.mce-i-checkbox{border:1px solid #59a5e1;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85)}.mce-checkbox.mce-disabled .mce-label,.mce-checkbox.mce-disabled i.mce-i-checkbox{color:#999}.mce-rtl .mce-checkbox{direction:rtl;text-align:right}.mce-rtl i.mce-i-checkbox{margin:0 0 0 3px}.mce-colorbutton .mce-ico{position:relative}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:4px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-14px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-17px;padding-right:0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;border-left:1px solid transparent;border-right:1px solid transparent}.mce-colorbutton:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-rtl .mce-colorbutton{direction:rtl}.mce-rtl .mce-colorbutton .mce-preview{margin-left:0;padding-right:0;padding-left:3px;margin-right:-14px}.mce-rtl .mce-colorbutton.mce-btn-small .mce-preview{margin-left:0;padding-right:0;margin-right:-17px;padding-left:0}.mce-rtl .mce-colorbutton button{padding-right:10px;padding-left:10px}.mce-rtl .mce-colorbutton .mce-open{padding-left:4px;padding-right:4px}.mce-combobox{display:inline-block;*display:inline;*zoom:1;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);*height:32px}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:#c5c5c5;height:28px}.mce-combobox.mce-disabled input{color:#999}.mce-combobox .mce-btn{border-left:0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox.mce-disabled .mce-btn button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#000}.mce-path-item:hover{text-decoration:underline}.mce-path-item:focus{background:#666;color:#fff}.mce-path .mce-divider{display:inline}.mce-disabled .mce-path-item{color:#aaa}.mce-rtl .mce-path{direction:rtl}.mce-fieldset{border:0 solid #9E9E9E}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-inline .mce-flow-layout{white-space:nowrap}.mce-rtl .mce-flow-layout{text-align:right;direction:rtl}.mce-rtl .mce-flow-layout-item{margin:2px 2px 2px 0}.mce-rtl .mce-flow-layout-item.mce-last{margin-left:2px}.mce-iframe{border:0 solid #ccc;width:100%;height:100%}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);border:0;overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label.mce-disabled{color:#aaa}.mce-label.mce-multiline{white-space:pre-wrap}.mce-rtl .mce-label{text-align:right;direction:rtl}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:none}.mce-menubar{border:1px solid #e0e0e0}.mce-menubar .mce-menubtn button span{color:#000}.mce-menubar .mce-caret{border-top-color:#000}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:transparent;background:#e6e6e6;filter:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-menubtn.mce-disabled span{color:#aaa}.mce-menubtn span{color:#000;margin-right:2px;line-height:20px;*line-height:16px}.mce-menubtn.mce-btn-small span{font-size:12px;line-height:15px;*line-height:16px}.mce-menubtn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-rtl .mce-menubtn button{direction:rtl;text-align:right}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-rtl .mce-listbox .mce-caret{right:auto;left:8px}.mce-rtl .mce-listbox button{padding-right:10px;padding-left:20px}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item .mce-ico,.mce-menu-item .mce-text{color:#333}.mce-menu-item.mce-disabled .mce-text,.mce-menu-item.mce-disabled .mce-ico{color:#adadad}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text{color:#fff}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:#fff}.mce-menu-item.mce-disabled:hover{background:#ccc}.mce-menu-shortcut{display:inline-block;color:#adadad}.mce-menu-shortcut{display:inline-block;*display:inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item:hover .mce-menu-shortcut,.mce-menu-item.mce-selected .mce-menu-shortcut,.mce-menu-item:focus .mce-menu-shortcut{color:#fff}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #333}.mce-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret,.mce-menu-item:hover .mce-caret{border-left-color:#fff}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item-normal.mce-active{background-color:#c8def4}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa}.mce-menu-item-normal.mce-active .mce-text{color:#333}.mce-menu-item-normal.mce-active:hover .mce-text,.mce-menu-item-normal.mce-active:hover .mce-ico{color:#fff}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);zoom:1}div.mce-menu .mce-menu-item-sep,.mce-menu-item-sep:hover{border:0;padding:0;height:1px;margin:9px 1px;overflow:hidden;background:#cbcbcb;border-bottom:1px solid #fff;cursor:default;filter:none}.mce-rtl .mce-menu-item{text-align:right;direction:rtl;padding:6px 12px 6px 15px}.mce-menu-align.mce-rtl .mce-menu-shortcut,.mce-menu-align.mce-rtl .mce-caret{right:auto;left:0}.mce-rtl .mce-menu-item .mce-caret{margin-left:6px;margin-right:0;border-right:4px solid #333;border-left:0}.mce-rtl .mce-menu-item.mce-selected .mce-caret,.mce-rtl .mce-menu-item:focus .mce-caret,.mce-rtl .mce-menu-item:hover .mce-caret{border-left-color:transparent;border-right-color:#fff}.mce-menu{position:absolute;left:0;top:0;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;margin:2px 0 0;min-width:160px;background:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);z-index:1002;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#000}.mce-spacer{visibility:hidden}.mce-splitbtn .mce-open{border-left:1px solid transparent;border-right:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-splitbtn button{padding-right:4px}.mce-splitbtn .mce-open{padding-left:4px}.mce-splitbtn .mce-open.mce-active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-rtl .mce-splitbtn{direction:rtl;text-align:right}.mce-rtl .mce-splitbtn button{padding-right:10px;padding-left:10px}.mce-rtl .mce-splitbtn .mce-open{padding-left:4px;padding-right:4px}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #c5c5c5}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #c5c5c5;border-width:0 1px 0 0;background:#e3e3e3;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#fdfdfd}.mce-tab.mce-active{background:#fdfdfd;border-bottom-color:transparent;margin-bottom:-1px;height:14px}.mce-rtl .mce-tabs{text-align:right;direction:rtl}.mce-rtl .mce-tab{border-width:0 0 0 1px}.mce-textbox{background:#fff;border:1px solid #c5c5c5;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);display:inline-block;-webkit-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#000}.mce-textbox:focus,.mce-textbox.mce-focus{border-color:#59a5e1;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85)}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px}.mce-textbox.mce-disabled{color:#999}.mce-rtl .mce-textbox{text-align:right;direction:rtl}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}@font-face{font-family:'icomoon';src:url('fonts/icomoon.eot');src:url('fonts/icomoon.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon.svg#icomoon') format('svg'),url('fonts/icomoon.woff') format('woff'),url('fonts/icomoon.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'icomoon-small';src:url('fonts/icomoon-small.eot');src:url('fonts/icomoon-small.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon-small.svg#icomoon') format('svg'),url('fonts/icomoon-small.woff') format('woff'),url('fonts/icomoon-small.ttf') format('truetype');font-weight:normal;font-style:normal}.mce-ico{font-family:'icomoon';font-style:normal;font-weight:normal;font-size:16px;line-height:16px;vertical-align:text-top;-webkit-font-smoothing:antialiased;display:inline-block;background:transparent center center;width:16px;height:16px;color:#000;-ie7-icon:' '}.mce-btn-small .mce-ico{font-family:'icomoon-small'}.mce-ico,i.mce-i-checkbox{zoom:expression(this.runtimeStyle['zoom'] = '1', this.innerHTML = this.currentStyle['-ie7-icon'].substr(1, 1) + ' ')}.mce-i-save{-ie7-icon:"\e000"}.mce-i-newdocument{-ie7-icon:"\e001"}.mce-i-fullpage{-ie7-icon:"\e002"}.mce-i-alignleft{-ie7-icon:"\e003"}.mce-i-aligncenter{-ie7-icon:"\e004"}.mce-i-alignright{-ie7-icon:"\e005"}.mce-i-alignjustify{-ie7-icon:"\e006"}.mce-i-cut{-ie7-icon:"\e007"}.mce-i-paste{-ie7-icon:"\e008"}.mce-i-searchreplace{-ie7-icon:"\e009"}.mce-i-bullist{-ie7-icon:"\e00a"}.mce-i-numlist{-ie7-icon:"\e00b"}.mce-i-indent{-ie7-icon:"\e00c"}.mce-i-outdent{-ie7-icon:"\e00d"}.mce-i-blockquote{-ie7-icon:"\e00e"}.mce-i-undo{-ie7-icon:"\e00f"}.mce-i-redo{-ie7-icon:"\e010"}.mce-i-link{-ie7-icon:"\e011"}.mce-i-unlink{-ie7-icon:"\e012"}.mce-i-anchor{-ie7-icon:"\e013"}.mce-i-image{-ie7-icon:"\e014"}.mce-i-media{-ie7-icon:"\e015"}.mce-i-help{-ie7-icon:"\e016"}.mce-i-code{-ie7-icon:"\e017"}.mce-i-inserttime{-ie7-icon:"\e018"}.mce-i-preview{-ie7-icon:"\e019"}.mce-i-forecolor{-ie7-icon:"\e01a"}.mce-i-backcolor{-ie7-icon:"\e01a"}.mce-i-table{-ie7-icon:"\e01b"}.mce-i-hr{-ie7-icon:"\e01c"}.mce-i-removeformat{-ie7-icon:"\e01d"}.mce-i-subscript{-ie7-icon:"\e01e"}.mce-i-superscript{-ie7-icon:"\e01f"}.mce-i-charmap{-ie7-icon:"\e020"}.mce-i-emoticons{-ie7-icon:"\e021"}.mce-i-print{-ie7-icon:"\e022"}.mce-i-fullscreen{-ie7-icon:"\e023"}.mce-i-spellchecker{-ie7-icon:"\e024"}.mce-i-nonbreaking{-ie7-icon:"\e025"}.mce-i-template{-ie7-icon:"\e026"}.mce-i-pagebreak{-ie7-icon:"\e027"}.mce-i-restoredraft{-ie7-icon:"\e028"}.mce-i-untitled{-ie7-icon:"\e029"}.mce-i-bold{-ie7-icon:"\e02a"}.mce-i-italic{-ie7-icon:"\e02b"}.mce-i-underline{-ie7-icon:"\e02c"}.mce-i-strikethrough{-ie7-icon:"\e02d"}.mce-i-visualchars{-ie7-icon:"\e02e"}.mce-i-ltr{-ie7-icon:"\e02f"}.mce-i-rtl{-ie7-icon:"\e030"}.mce-i-copy{-ie7-icon:"\e031"}.mce-i-resize{-ie7-icon:"\e032"}.mce-i-browse{-ie7-icon:"\e034"}.mce-i-checkbox,.mce-i-selected{-ie7-icon:"\e033"}.mce-i-selected{visibility:hidden}.mce-i-backcolor{background:#BBB} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.json b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.json deleted file mode 100644 index 8a7e7da9d8..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "skin-name": "smartstore", - "preview-bg": "#eeeeee", - "text": "#000000", - "text-inverse": "#ffffff", - "text-disabled": "#aaaaaa", - "has-gradients": true, - "has-radius": false, - "has-boxshadow": true, - "btn-text": "#000000", - "btn-text-shadow": "#ffffff", - "btn-bg": "#ffffff", - "btn-bg-hlight": "#d9d9d9", - "btn-border-top": "rgba(0,0,0,0.1)", - "btn-border-right": "rgba(0,0,0,0.1)", - "btn-border-bottom": "rgba(0,0,0,0.25)", - "btn-border-left": "rgba(0,0,0,0.25)", - "btn-split-border": "#bdbdbd", - "btn-primary-text": "#ffffff", - "btn-primary-text-shadow": "#333333", - "btn-primary-bg": "#0088cc", - "btn-primary-bg-hlight": "#0044cc", - "menu-bg": "#ffffff", - "menu-border": "rgba(0,0,0,0.2)", - "menuitem-text": "#333333", - "menuitem-bg-selected": "#0088cc", - "menuitem-bg-selected-hlight": "#0077b3", - "menuitem-separator-top": "#cbcbcb", - "menuitem-separator-bottom": "#ffffff", - "menuitem-text-inverse": "#ffffff", - "menuitem-bg-active": "#c8def4", - "menuitem-text-active": "#333333", - "menuitem-preview-border-active": "#aaaaaa", - "checkbox-border": "#c5c5c5", - "checkbox-border-focus": "#59a5e1", - "panel-border": "#cccccc", - "panel-bg": "#ffffff", - "panel-bg-hlight": "#fafafa", - "textbox-bg": "#ffffff", - "textbox-border": "#c5c5c5", - "textbox-border-focus": "#59a5e1", - "window-bg": "#ffffff", - "window-border": "#cccccc", - "tab-bg": "#e3e3e3", - "tab-bg-hover": "#fdfdfd", - "tab-bg-active": "#fdfdfd", - "tab-border": "#c5c5c5", - "colorbtn-backcolor-bg": "#bbbbbb", - "grid-border": "#d6d6d6", - "grid-border-active": "#a1a1a1" -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.min.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.min.css deleted file mode 100644 index f7bf2a81cb..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.min.css +++ /dev/null @@ -1 +0,0 @@ -.mce-container,.mce-container *,.mce-widget,.mce-widget *{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:#000;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;-webkit-tap-highlight-color:transparent;line-height:normal;font-weight:normal;text-align:left;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr}.mce-widget button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.mce-container *[unselectable]{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}.mce-container ::-webkit-scrollbar{width:8px;height:8px;-webkit-border-radius:4px}.mce-container ::-webkit-scrollbar-track,.mce-container ::-webkit-scrollbar-track-piece{background-color:transparent}.mce-container ::-webkit-scrollbar-thumb{background-color:rgba(53,57,71,0.3);width:6px;height:6px;-webkit-border-radius:4px}.mce-fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.mce-fade.mce-in{opacity:1}.mce-tinymce{visibility:visible !important;position:relative}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;height:100%;z-index:100}div.mce-fullscreen{position:fixed;top:0;left:0;width:100%;height:auto}.mce-tinymce{display:block}.mce-wordcount{position:absolute;top:0;right:0;padding:8px}div.mce-edit-area{background:#FFF;filter:none}.mce-statusbar{position:relative}.mce-statusbar .mce-container-body{position:relative}.mce-fullscreen .mce-resizehandle{display:none}.mce-charmap{border-collapse:collapse}.mce-charmap td{cursor:default;border:1px solid #ccc;width:20px;height:20px;line-height:20px;text-align:center;vertical-align:middle;padding:2px}.mce-charmap td div{text-align:center}.mce-charmap td:hover{background:#d9d9d9}.mce-grid td div{border:1px solid #d6d6d6;width:12px;height:12px;margin:2px;cursor:pointer}.mce-grid{border-spacing:2px;border-collapse:separate}.mce-grid a{display:block;border:1px solid transparent}.mce-grid a:hover{border-color:#a1a1a1}.mce-grid-border{margin:0 4px 0 4px}.mce-grid-border a{border-color:#d6d6d6;width:13px;height:13px}.mce-grid-border a:hover,.mce-grid-border a.mce-active{border-color:#a1a1a1;background:#c8def4}.mce-text-center{text-align:center}div.mce-tinymce-inline{width:100%;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-rtl .mce-wordcount{left:0;right:auto}.mce-container,.mce-container-body{display:block}.mce-autoscroll{overflow:hidden}.mce-scrollbar{position:absolute;width:7px;height:100%;top:2px;right:2px;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-scrollbar-h{top:auto;right:auto;left:2px;bottom:2px;width:100%;height:7px}.mce-scrollbar-thumb{position:absolute;background-color:#000;border:1px solid #888;border-color:rgba(85,85,85,0.6);width:5px;height:100%}.mce-scrollbar-h .mce-scrollbar-thumb{width:100%;height:5px}.mce-scrollbar:hover,.mce-scrollbar.mce-active{background-color:#AAA;opacity:.6;filter:alpha(opacity=60);zoom:1}.mce-scroll{position:relative}.mce-panel{border:0 solid #ccc;background-color:#fdfdfd;background-image:-moz-linear-gradient(top, #fff, #fafafa);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#fafafa));background-image:-webkit-linear-gradient(top, #fff, #fafafa);background-image:-o-linear-gradient(top, #fff, #fafafa);background-image:linear-gradient(to bottom, #fff, #fafafa);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fffafafa', GradientType=0);zoom:1}.mce-floatpanel{position:absolute;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2)}.mce-floatpanel.mce-fixed{position:fixed}.mce-floatpanel .mce-arrow,.mce-floatpanel .mce-arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.mce-floatpanel .mce-arrow{border-width:11px}.mce-floatpanel .mce-arrow:after{border-width:10px;content:""}.mce-floatpanel.mce-popover{filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);top:0;left:0;background:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.25)}.mce-floatpanel.mce-popover.mce-bottom{margin-top:10px;*margin-top:0}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#ccc;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.mce-floatpanel.mce-popover.mce-bottom>.mce-arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.mce-floatpanel.mce-popover.mce-bottom.mce-start{margin-left:-22px}.mce-floatpanel.mce-popover.mce-bottom.mce-start>.mce-arrow{left:20px}.mce-floatpanel.mce-popover.mce-bottom.mce-end{margin-left:22px}.mce-floatpanel.mce-popover.mce-bottom.mce-end>.mce-arrow{right:10px;left:auto}.mce-fullscreen{border:0;padding:0;margin:0;overflow:hidden;background:#fff;height:100%}div.mce-fullscreen{position:fixed;top:0;left:0}#mce-modal-block{opacity:0;filter:alpha(opacity=0);zoom:1;position:fixed;left:0;top:0;width:100%;height:100%;background:#000}#mce-modal-block.mce-in{opacity:.3;filter:alpha(opacity=30);zoom:1}.mce-window-move{cursor:move}.mce-window{-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;background:#fff;position:fixed;top:0;left:0;opacity:0;-webkit-transition:opacity 150ms ease-in;transition:opacity 150ms ease-in}.mce-window.mce-in{opacity:1}.mce-window-head{padding:9px 15px;border-bottom:1px solid #ccc;position:relative}.mce-window-head .mce-close{position:absolute;right:15px;top:9px;font-size:20px;font-weight:bold;line-height:20px;color:#666;cursor:pointer;height:20px;overflow:hidden}.mce-close:hover{color:#999}.mce-window-head .mce-title{line-height:20px;font-size:20px;font-weight:bold;text-rendering:optimizelegibility;padding-right:10px}.mce-window .mce-container-body{display:block}.mce-foot{display:block;background-color:#fff;border-top:1px solid #ccc}.mce-window-head .mce-dragh{position:absolute;top:0;left:0;cursor:move;width:90%;height:100%}.mce-window iframe{width:100%;height:100%}.mce-rtl .mce-window-head .mce-close{position:absolute;right:auto;left:15px}.mce-rtl .mce-window-head .mce-dragh{left:auto;right:0}.mce-rtl .mce-window-head .mce-title{direction:rtl;text-align:right}.mce-abs-layout{position:relative}body .mce-abs-layout-item,.mce-abs-end{position:absolute}.mce-abs-end{width:1px;height:1px}.mce-container-body.mce-abs-layout{overflow:hidden}.mce-tooltip{position:absolute;padding:5px;opacity:.8;filter:alpha(opacity=80);zoom:1}.mce-tooltip-inner{font-size:11px;background-color:#000;color:#fff;max-width:200px;padding:5px 8px 4px 8px;text-align:center;white-space:normal}.mce-tooltip-inner{-webkit-box-shadow:0 0 5px #000000;-moz-box-shadow:0 0 5px #000000;box-shadow:0 0 5px #000000}.mce-tooltip-arrow{position:absolute;width:0;height:0;line-height:0;border:5px dashed #000}.mce-tooltip-arrow-n{border-bottom-color:#000}.mce-tooltip-arrow-s{border-top-color:#000}.mce-tooltip-arrow-e{border-left-color:#000}.mce-tooltip-arrow-w{border-right-color:#000}.mce-tooltip-nw,.mce-tooltip-sw{margin-left:-14px}.mce-tooltip-n .mce-tooltip-arrow{top:0px;left:50%;margin-left:-5px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-nw .mce-tooltip-arrow{top:0;left:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-ne .mce-tooltip-arrow{top:0;right:10px;border-bottom-style:solid;border-top:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-s .mce-tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-sw .mce-tooltip-arrow{bottom:0;left:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-se .mce-tooltip-arrow{bottom:0;right:10px;border-top-style:solid;border-bottom:none;border-left-color:transparent;border-right-color:transparent}.mce-tooltip-e .mce-tooltip-arrow{right:0;top:50%;margin-top:-5px;border-left-style:solid;border-right:none;border-top-color:transparent;border-bottom-color:transparent}.mce-tooltip-w .mce-tooltip-arrow{left:0;top:50%;margin-top:-5px;border-right-style:solid;border-left:none;border-top-color:transparent;border-bottom-color:transparent}.mce-btn{border:1px solid #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);position:relative;text-shadow:0 1px 1px rgba(255,255,255,0.75);display:inline-block;*display:inline;*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1}.mce-btn:hover,.mce-btn:focus{color:#000;background-color:#e3e3e3;background-image:-moz-linear-gradient(top, #f2f2f2, #ccc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#ccc));background-image:-webkit-linear-gradient(top, #f2f2f2, #ccc);background-image:-o-linear-gradient(top, #f2f2f2, #ccc);background-image:linear-gradient(to bottom, #f2f2f2, #ccc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffcccccc', GradientType=0);zoom:1}.mce-btn.mce-disabled button,.mce-btn.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-btn.mce-active,.mce-btn.mce-active:hover{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn:not(.mce-disabled):active{background-color:#d6d6d6;background-image:-moz-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#c0c0c0));background-image:-webkit-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:-o-linear-gradient(top, #e6e6e6, #c0c0c0);background-image:linear-gradient(to bottom, #e6e6e6, #c0c0c0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffc0c0c0', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-btn button{padding:4px 10px;font-size:14px;line-height:20px;*line-height:16px;cursor:pointer;color:#000;text-align:center;overflow:visible;-webkit-appearance:none}.mce-btn button::-moz-focus-inner{border:0;padding:0}.mce-btn i{text-shadow:1px 1px #fff}.mce-primary{min-width:50px;color:#fff;border:1px solid #b3b3b3;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25) rgba(0,0,0,0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #08c, #04c);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#04c));background-image:-webkit-linear-gradient(top, #08c, #04c);background-image:-o-linear-gradient(top, #08c, #04c);background-image:linear-gradient(to bottom, #08c, #04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);zoom:1}.mce-primary:hover,.mce-primary:focus{background-color:#005fb3;background-image:-moz-linear-gradient(top, #0077b3, #003cb3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0077b3), to(#003cb3));background-image:-webkit-linear-gradient(top, #0077b3, #003cb3);background-image:-o-linear-gradient(top, #0077b3, #003cb3);background-image:linear-gradient(to bottom, #0077b3, #003cb3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0077b3', endColorstr='#ff003cb3', GradientType=0);zoom:1}.mce-primary.mce-disabled button,.mce-primary.mce-disabled:hover button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-primary.mce-active,.mce-primary.mce-active:hover,.mce-primary:not(.mce-disabled):active{background-color:#005299;background-image:-moz-linear-gradient(top, #069, #039);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#069), to(#039));background-image:-webkit-linear-gradient(top, #069, #039);background-image:-o-linear-gradient(top, #069, #039);background-image:linear-gradient(to bottom, #069, #039);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff006699', endColorstr='#ff003399', GradientType=0);zoom:1;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-primary button,.mce-primary button i{color:#fff;text-shadow:1px 1px #333}.mce-btn-large button{padding:9px 14px;font-size:16px;line-height:normal}.mce-btn-large i{margin-top:2px}.mce-btn-small button{padding:3px 5px;font-size:12px;line-height:15px}.mce-btn-small i{margin-top:0}.mce-btn .mce-caret{margin-top:8px;*margin-top:6px;margin-left:0}.mce-btn-small .mce-caret{margin-top:6px;*margin-top:4px;margin-left:0}.mce-caret{display:inline-block;*display:inline;*zoom:1;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.mce-disabled .mce-caret{border-top-color:#aaa}.mce-caret.mce-up{border-bottom:4px solid #000;border-top:0}.mce-rtl .mce-btn button{direction:rtl}.mce-btn-group .mce-btn{border-width:1px 0 1px 0;margin:0}.mce-btn-group .mce-first{border-left:1px solid #b3b3b3;border-left:1px solid rgba(0,0,0,0.25)}.mce-btn-group .mce-last{border-right:1px solid #b3b3b3;border-right:1px solid rgba(0,0,0,0.1)}.mce-btn-group .mce-btn.mce-flow-layout-item{margin:0}.mce-checkbox{cursor:pointer}i.mce-i-checkbox{margin:0 3px 0 0;border:1px solid #c5c5c5;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);background-color:#f0f0f0;background-image:-moz-linear-gradient(top, #fff, #d9d9d9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#d9d9d9));background-image:-webkit-linear-gradient(top, #fff, #d9d9d9);background-image:-o-linear-gradient(top, #fff, #d9d9d9);background-image:linear-gradient(to bottom, #fff, #d9d9d9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffd9d9d9', GradientType=0);zoom:1;text-indent:-10em;*font-size:0;*line-height:0;*text-indent:0;overflow:hidden}.mce-checked i.mce-i-checkbox{color:#000;font-size:16px;line-height:16px;text-indent:0}.mce-checkbox:focus i.mce-i-checkbox,.mce-checkbox.mce-focus i.mce-i-checkbox{border:1px solid #59a5e1;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85)}.mce-checkbox.mce-disabled .mce-label,.mce-checkbox.mce-disabled i.mce-i-checkbox{color:#999}.mce-rtl .mce-checkbox{direction:rtl;text-align:right}.mce-rtl i.mce-i-checkbox{margin:0 0 0 3px}.mce-colorbutton .mce-ico{position:relative}.mce-colorbutton-grid{margin:4px}.mce-colorbutton button{padding-right:4px}.mce-colorbutton .mce-preview{padding-right:3px;display:block;position:absolute;left:50%;top:50%;margin-left:-14px;margin-top:7px;background:gray;width:13px;height:2px;overflow:hidden}.mce-colorbutton.mce-btn-small .mce-preview{margin-left:-17px;padding-right:0;width:16px}.mce-colorbutton .mce-open{padding-left:4px;border-left:1px solid transparent;border-right:1px solid transparent}.mce-colorbutton:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-rtl .mce-colorbutton{direction:rtl}.mce-rtl .mce-colorbutton .mce-preview{margin-left:0;padding-right:0;padding-left:3px;margin-right:-14px}.mce-rtl .mce-colorbutton.mce-btn-small .mce-preview{margin-left:0;padding-right:0;margin-right:-17px;padding-left:0}.mce-rtl .mce-colorbutton button{padding-right:10px;padding-left:10px}.mce-rtl .mce-colorbutton .mce-open{padding-left:4px;padding-right:4px}.mce-combobox{display:inline-block;*display:inline;*zoom:1;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);*height:32px}.mce-combobox input{border:1px solid #c5c5c5;border-right-color:#c5c5c5;height:28px}.mce-combobox.mce-disabled input{color:#999}.mce-combobox .mce-btn{border-left:0}.mce-combobox button{padding-right:8px;padding-left:8px}.mce-combobox.mce-disabled .mce-btn button{cursor:default;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:.4;filter:alpha(opacity=40);zoom:1}.mce-path{display:inline-block;*display:inline;*zoom:1;padding:8px;white-space:normal}.mce-path .mce-txt{display:inline-block;padding-right:3px}.mce-path .mce-path-body{display:inline-block}.mce-path-item{display:inline-block;*display:inline;*zoom:1;cursor:pointer;color:#000}.mce-path-item:hover{text-decoration:underline}.mce-path-item:focus{background:#666;color:#fff}.mce-path .mce-divider{display:inline}.mce-disabled .mce-path-item{color:#aaa}.mce-rtl .mce-path{direction:rtl}.mce-fieldset{border:0 solid #9E9E9E}.mce-fieldset>.mce-container-body{margin-top:-15px}.mce-fieldset-title{margin-left:5px;padding:0 5px 0 5px}.mce-fit-layout{display:inline-block;*display:inline;*zoom:1}.mce-fit-layout-item{position:absolute}.mce-flow-layout-item{display:inline-block;*display:inline;*zoom:1}.mce-flow-layout-item{margin:2px 0 2px 2px}.mce-flow-layout-item.mce-last{margin-right:2px}.mce-flow-layout{white-space:normal}.mce-tinymce-inline .mce-flow-layout{white-space:nowrap}.mce-rtl .mce-flow-layout{text-align:right;direction:rtl}.mce-rtl .mce-flow-layout-item{margin:2px 2px 2px 0}.mce-rtl .mce-flow-layout-item.mce-last{margin-left:2px}.mce-iframe{border:0 solid #ccc;width:100%;height:100%}.mce-label{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 1px rgba(255,255,255,0.75);border:0;overflow:hidden}.mce-label.mce-autoscroll{overflow:auto}.mce-label.mce-disabled{color:#aaa}.mce-label.mce-multiline{white-space:pre-wrap}.mce-rtl .mce-label{text-align:right;direction:rtl}.mce-menubar .mce-menubtn{border-color:transparent;background:transparent;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;filter:none}.mce-menubar{border:1px solid #e0e0e0}.mce-menubar .mce-menubtn button span{color:#000}.mce-menubar .mce-caret{border-top-color:#000}.mce-menubar .mce-menubtn:hover,.mce-menubar .mce-menubtn.mce-active,.mce-menubar .mce-menubtn:focus{border-color:transparent;background:#e6e6e6;filter:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.mce-menubtn.mce-disabled span{color:#aaa}.mce-menubtn span{color:#000;margin-right:2px;line-height:20px;*line-height:16px}.mce-menubtn.mce-btn-small span{font-size:12px;line-height:15px;*line-height:16px}.mce-menubtn.mce-fixed-width span{display:inline-block;overflow-x:hidden;text-overflow:ellipsis;width:90px}.mce-menubtn.mce-fixed-width.mce-btn-small span{width:70px}.mce-rtl .mce-menubtn button{direction:rtl;text-align:right}.mce-listbox button{text-align:left;padding-right:20px;position:relative}.mce-listbox .mce-caret{position:absolute;margin-top:-2px;right:8px;top:50%}.mce-rtl .mce-listbox .mce-caret{right:auto;left:8px}.mce-rtl .mce-listbox button{padding-right:10px;padding-left:20px}.mce-menu-item{display:block;padding:6px 15px 6px 12px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap;cursor:pointer;line-height:normal;border-left:4px solid transparent;margin-bottom:1px}.mce-menu-item .mce-ico,.mce-menu-item .mce-text{color:#333}.mce-menu-item.mce-disabled .mce-text,.mce-menu-item.mce-disabled .mce-ico{color:#adadad}.mce-menu-item:hover .mce-text,.mce-menu-item.mce-selected .mce-text{color:#fff}.mce-menu-item:hover .mce-ico,.mce-menu-item.mce-selected .mce-ico,.mce-menu-item:focus .mce-ico{color:#fff}.mce-menu-item.mce-disabled:hover{background:#ccc}.mce-menu-shortcut{display:inline-block;color:#adadad}.mce-menu-shortcut{display:inline-block;*display:inline;*zoom:1;padding:0 15px 0 20px}.mce-menu-item:hover .mce-menu-shortcut,.mce-menu-item.mce-selected .mce-menu-shortcut,.mce-menu-item:focus .mce-menu-shortcut{color:#fff}.mce-menu-item .mce-caret{margin-top:4px;*margin-top:3px;margin-right:6px;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:4px solid #333}.mce-menu-item.mce-selected .mce-caret,.mce-menu-item:focus .mce-caret,.mce-menu-item:hover .mce-caret{border-left-color:#fff}.mce-menu-align .mce-menu-shortcut{*margin-top:-2px}.mce-menu-align .mce-menu-shortcut,.mce-menu-align .mce-caret{position:absolute;right:0}.mce-menu-item.mce-active i{visibility:visible}.mce-menu-item-normal.mce-active{background-color:#c8def4}.mce-menu-item-preview.mce-active{border-left:5px solid #aaa}.mce-menu-item-normal.mce-active .mce-text{color:#333}.mce-menu-item-normal.mce-active:hover .mce-text,.mce-menu-item-normal.mce-active:hover .mce-ico{color:#fff}.mce-menu-item:hover,.mce-menu-item.mce-selected,.mce-menu-item:focus{text-decoration:none;color:#fff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #08c, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#0077b3));background-image:-webkit-linear-gradient(top, #08c, #0077b3);background-image:-o-linear-gradient(top, #08c, #0077b3);background-image:linear-gradient(to bottom, #08c, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);zoom:1}div.mce-menu .mce-menu-item-sep,.mce-menu-item-sep:hover{border:0;padding:0;height:1px;margin:9px 1px;overflow:hidden;background:#cbcbcb;border-bottom:1px solid #fff;cursor:default;filter:none}.mce-rtl .mce-menu-item{text-align:right;direction:rtl;padding:6px 12px 6px 15px}.mce-menu-align.mce-rtl .mce-menu-shortcut,.mce-menu-align.mce-rtl .mce-caret{right:auto;left:0}.mce-rtl .mce-menu-item .mce-caret{margin-left:6px;margin-right:0;border-right:4px solid #333;border-left:0}.mce-rtl .mce-menu-item.mce-selected .mce-caret,.mce-rtl .mce-menu-item:focus .mce-caret,.mce-rtl .mce-menu-item:hover .mce-caret{border-left-color:transparent;border-right-color:#fff}.mce-menu{position:absolute;left:0;top:0;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);background:transparent;z-index:1000;padding:5px 0 5px 0;margin:2px 0 0;min-width:160px;background:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);z-index:1002;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);max-height:400px;overflow:auto;overflow-x:hidden}.mce-menu i{display:none}.mce-menu-has-icons i{display:inline-block;*display:inline}.mce-menu-sub-tr-tl{margin:-6px 0 0 -1px}.mce-menu-sub-br-bl{margin:6px 0 0 -1px}.mce-menu-sub-tl-tr{margin:-6px 0 0 1px}.mce-menu-sub-bl-br{margin:6px 0 0 1px}.mce-container-body .mce-resizehandle{position:absolute;right:0;bottom:0;width:16px;height:16px;visibility:visible;cursor:s-resize;margin:0}.mce-container-body .mce-resizehandle-both{cursor:se-resize}i.mce-i-resize{color:#000}.mce-spacer{visibility:hidden}.mce-splitbtn .mce-open{border-left:1px solid transparent;border-right:1px solid transparent}.mce-splitbtn:hover .mce-open{border-left-color:#bdbdbd;border-right-color:#bdbdbd}.mce-splitbtn button{padding-right:4px}.mce-splitbtn .mce-open{padding-left:4px}.mce-splitbtn .mce-open.mce-active{-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05)}.mce-rtl .mce-splitbtn{direction:rtl;text-align:right}.mce-rtl .mce-splitbtn button{padding-right:10px;padding-left:10px}.mce-rtl .mce-splitbtn .mce-open{padding-left:4px;padding-right:4px}.mce-stack-layout-item{display:block}.mce-tabs{display:block;border-bottom:1px solid #c5c5c5}.mce-tab{display:inline-block;*display:inline;*zoom:1;border:1px solid #c5c5c5;border-width:0 1px 0 0;background:#e3e3e3;padding:8px;text-shadow:0 1px 1px rgba(255,255,255,0.75);height:13px;cursor:pointer}.mce-tab:hover{background:#fdfdfd}.mce-tab.mce-active{background:#fdfdfd;border-bottom-color:transparent;margin-bottom:-1px;height:14px}.mce-rtl .mce-tabs{text-align:right;direction:rtl}.mce-rtl .mce-tab{border-width:0 0 0 1px}.mce-textbox{background:#fff;border:1px solid #c5c5c5;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);display:inline-block;-webkit-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;height:28px;resize:none;padding:0 4px 0 4px;white-space:pre-wrap;*white-space:pre;color:#000}.mce-textbox:focus,.mce-textbox.mce-focus{border-color:#59a5e1;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(89, 165, 225, 0.85)}.mce-placeholder .mce-textbox{color:#aaa}.mce-textbox.mce-multiline{padding:4px}.mce-textbox.mce-disabled{color:#999}.mce-rtl .mce-textbox{text-align:right;direction:rtl}.mce-throbber{position:absolute;top:0;left:0;width:100%;height:100%;opacity:.6;filter:alpha(opacity=60);zoom:1;background:#fff url('img/loader.gif') no-repeat center center}@font-face{font-family:'tinymce';src:url('fonts/icomoon.eot');src:url('fonts/icomoon.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon.svg#icomoon') format('svg'),url('fonts/icomoon.woff') format('woff'),url('fonts/icomoon.ttf') format('truetype');font-weight:normal;font-style:normal}@font-face{font-family:'tinymce-small';src:url('fonts/icomoon-small.eot');src:url('fonts/icomoon-small.eot?#iefix') format('embedded-opentype'),url('fonts/icomoon-small.svg#icomoon') format('svg'),url('fonts/icomoon-small.woff') format('woff'),url('fonts/icomoon-small.ttf') format('truetype');font-weight:normal;font-style:normal}.mce-ico{font-family:'tinymce',Arial;font-style:normal;font-weight:normal;font-size:16px;line-height:16px;vertical-align:text-top;-webkit-font-smoothing:antialiased;display:inline-block;background:transparent center center;width:16px;height:16px;color:#000}.mce-btn-small .mce-ico{font-family:'tinymce-small',Arial}.mce-i-save:before{content:"\e000"}.mce-i-newdocument:before{content:"\e001"}.mce-i-fullpage:before{content:"\e002"}.mce-i-alignleft:before{content:"\e003"}.mce-i-aligncenter:before{content:"\e004"}.mce-i-alignright:before{content:"\e005"}.mce-i-alignjustify:before{content:"\e006"}.mce-i-cut:before{content:"\e007"}.mce-i-paste:before{content:"\e008"}.mce-i-searchreplace:before{content:"\e009"}.mce-i-bullist:before{content:"\e00a"}.mce-i-numlist:before{content:"\e00b"}.mce-i-indent:before{content:"\e00c"}.mce-i-outdent:before{content:"\e00d"}.mce-i-blockquote:before{content:"\e00e"}.mce-i-undo:before{content:"\e00f"}.mce-i-redo:before{content:"\e010"}.mce-i-link:before{content:"\e011"}.mce-i-unlink:before{content:"\e012"}.mce-i-anchor:before{content:"\e013"}.mce-i-image:before{content:"\e014"}.mce-i-media:before{content:"\e015"}.mce-i-help:before{content:"\e016"}.mce-i-code:before{content:"\e017"}.mce-i-inserttime:before{content:"\e018"}.mce-i-preview:before{content:"\e019"}.mce-i-forecolor:before{content:"\e01a"}.mce-i-backcolor:before{content:"\e01a"}.mce-i-table:before{content:"\e01b"}.mce-i-hr:before{content:"\e01c"}.mce-i-removeformat:before{content:"\e01d"}.mce-i-subscript:before{content:"\e01e"}.mce-i-superscript:before{content:"\e01f"}.mce-i-charmap:before{content:"\e020"}.mce-i-emoticons:before{content:"\e021"}.mce-i-print:before{content:"\e022"}.mce-i-fullscreen:before{content:"\e023"}.mce-i-spellchecker:before{content:"\e024"}.mce-i-nonbreaking:before{content:"\e025"}.mce-i-template:before{content:"\e026"}.mce-i-pagebreak:before{content:"\e027"}.mce-i-restoredraft:before{content:"\e028"}.mce-i-untitled:before{content:"\e029"}.mce-i-bold:before{content:"\e02a"}.mce-i-italic:before{content:"\e02b"}.mce-i-underline:before{content:"\e02c"}.mce-i-strikethrough:before{content:"\e02d"}.mce-i-visualchars:before{content:"\e02e"}.mce-i-visualblocks:before{content:"\e02e"}.mce-i-ltr:before{content:"\e02f"}.mce-i-rtl:before{content:"\e030"}.mce-i-copy:before{content:"\e031"}.mce-i-resize:before{content:"\e032"}.mce-i-browse:before{content:"\e034"}.mce-i-pastetext:before{content:"\e035"}.mce-i-checkbox:before,.mce-i-selected:before{content:"\e033"}.mce-i-selected{visibility:hidden}i.mce-i-backcolor{text-shadow:none;background:#bbb} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.smartstore.css b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.smartstore.css deleted file mode 100644 index da1ef41b12..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/skins/smartstore/skin.smartstore.css +++ /dev/null @@ -1,34 +0,0 @@ - -div.mce-fullscreen { - z-index: 10000; -} - -.mce-container, .mce-container *, .mce-widget, .mce-widget * { - font-family: "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; -} - -.mce-ico { - font-family: 'tinymce'; - font-size: 16px; -} - -.mce-btn i { - text-shadow: none; -} - -.mce-btn button { - font-size: 12px; -} - -.mce-btn > button { - opacity: .6; -} - -.mce-btn:hover > button { - opacity: 1; -} - -.mce-menubtn.mce-fixed-width span { - width: auto; -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/themes/modern/theme.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/themes/modern/theme.min.js deleted file mode 100644 index 4e770246db..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/themes/modern/theme.min.js +++ /dev/null @@ -1 +0,0 @@ -tinymce.ThemeManager.add("modern",function(e){function t(){function t(t){var i,o=[];if(t)return d(t.split(/[ ,]/),function(t){function n(){var n=e.selection;"bullist"==r&&n.selectorChanged("ul > li",function(e,n){for(var i,o=n.parents.length;o--&&(i=n.parents[o].nodeName,"OL"!=i&&"UL"!=i););t.active(e&&"UL"==i)}),"numlist"==r&&n.selectorChanged("ol > li",function(e,n){for(var i,o=n.parents.length;o--&&(i=n.parents[o].nodeName,"OL"!=i&&"UL"!=i););t.active(e&&"OL"==i)}),t.settings.stateSelector&&n.selectorChanged(t.settings.stateSelector,function(e){t.active(e)},!0),t.settings.disabledStateSelector&&n.selectorChanged(t.settings.disabledStateSelector,function(e){t.disabled(e)})}var r;"|"==t?i=null:c.has(t)?(t={type:t},u.toolbar_items_size&&(t.size=u.toolbar_items_size),o.push(t),i=null):(i||(i={type:"buttongroup",items:[]},o.push(i)),e.buttons[t]&&(r=t,t=e.buttons[r],"function"==typeof t&&(t=t()),t.type=t.type||"button",u.toolbar_items_size&&(t.size=u.toolbar_items_size),t=c.create(t),i.items.push(t),e.initialized?n():e.on("init",n)))}),n.push({type:"toolbar",layout:"flow",items:o}),!0}for(var n=[],i=1;10>i&&t(u["toolbar"+i]);i++);return n.length||t(u.toolbar||f),n}function n(){function t(t){var n;return"|"==t?{text:"|"}:n=e.menuItems[t]}function n(n){var i,o,r,a,s;if(s=tinymce.makeMap((u.removed_menuitems||"").split(/[ ,]/)),u.menu?(o=u.menu[n],a=!0):o=h[n],o){i={text:o.title},r=[],d((o.items||"").split(/[ ,]/),function(e){var n=t(e);n&&!s[e]&&r.push(t(e))}),a||d(e.menuItems,function(e){e.context==n&&("before"==e.separator&&r.push({text:"|"}),e.prependToContext?r.unshift(e):r.push(e),"after"==e.separator&&r.push({text:"|"}))});for(var l=0;l -/** - * tinymce.gzip.ashx - * - * Copyright, Moxiecode Systems AB - * Released under LGPL License. - * - * License: http://tinymce.moxiecode.com/license - * Contributing: http://tinymce.moxiecode.com/contributing - * - * This file compresses the TinyMCE JavaScript using GZip and - * enables the browser to do two requests instead of one for each .js file. - * - * It's a good idea to use the diskcache option since it reduces the servers workload. - */ - -using System; -using System.Web; -using System.IO; -using System.IO.Compression; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; - -public class Handler : IHttpHandler { - private HttpResponse Response; - private HttpRequest Request; - private HttpServerUtility Server; - - public void ProcessRequest(HttpContext context) { - this.Response = context.Response; - this.Request = context.Request; - this.Server = context.Server; - this.StreamGzipContents(); - } - - public bool IsReusable { - get { - return false; - } - } - - #region private - - private void StreamGzipContents() { - string cacheKey = "", cacheFile = "", content = "", enc, suffix, cachePath; - string[] plugins, languages, themes; - bool diskCache, supportsGzip, isJS, compress, core; - int i, x, expiresOffset; - GZipStream gzipStream; - Encoding encoding = Encoding.GetEncoding("windows-1252"); - byte[] buff; - - // Get input - plugins = GetParam("plugins", "").Split(','); - languages = GetParam("languages", "").Split(','); - themes = GetParam("themes", "").Split(','); - diskCache = GetParam("diskcache", "") == "true"; - isJS = GetParam("js", "") == "true"; - compress = GetParam("compress", "true") == "true"; - core = GetParam("core", "true") == "true"; - suffix = GetParam("suffix", ".min"); - cachePath = Server.MapPath("."); // Cache path, this is where the .gz files will be stored - expiresOffset = 10; // Cache for 10 days in browser cache - - // Custom extra javascripts to pack - string[] custom = {/* - "some custom .js file", - "some custom .js file" - */}; - - // Set response headers - Response.ContentType = "text/javascript"; - Response.Charset = "UTF-8"; - Response.Buffer = false; - - // Setup cache - Response.Cache.SetExpires(DateTime.Now.AddDays(expiresOffset)); - Response.Cache.SetCacheability(HttpCacheability.Public); - Response.Cache.SetValidUntilExpires(false); - - // Vary by all parameters and some headers - Response.Cache.VaryByHeaders["Accept-Encoding"] = true; - Response.Cache.VaryByParams["theme"] = true; - Response.Cache.VaryByParams["language"] = true; - Response.Cache.VaryByParams["plugins"] = true; - Response.Cache.VaryByParams["lang"] = true; - Response.Cache.VaryByParams["index"] = true; - - // Setup cache info - if (diskCache) { - cacheKey = GetParam("plugins", "") + GetParam("languages", "") + GetParam("themes", ""); - - for (i = 0; i < custom.Length; i++) - cacheKey += custom[i]; - - cacheKey = MD5(cacheKey); - - if (compress) - cacheFile = cachePath + "/tinymce.gzip-" + cacheKey + ".gz"; - else - cacheFile = cachePath + "/tinymce.gzip-" + cacheKey + ".js"; - } - - // Check if it supports gzip - enc = Regex.Replace("" + Request.Headers["Accept-Encoding"], @"\s+", "").ToLower(); - supportsGzip = enc.IndexOf("gzip") != -1 || Request.Headers["---------------"] != null; - enc = enc.IndexOf("x-gzip") != -1 ? "x-gzip" : "gzip"; - - // Use cached file disk cache - if (diskCache && supportsGzip && File.Exists(cacheFile)) { - Response.AppendHeader("Content-Encoding", enc); - Response.WriteFile(cacheFile); - return; - } - - // Add core - if (core) { - // Set base URL for where tinymce is loaded from - String uri = Request.Url.AbsolutePath; - uri = uri.Substring(0, uri.LastIndexOf('/')); - content += "var tinymce={base:'" + uri + "',suffix:'.min'};"; - content += GetFileContents("tinymce." + suffix + ".js"); - } - - // Add core languages - for (x = 0; x < languages.Length; x++) - content += GetFileContents("langs/" + languages[x] + ".js"); - - // Add themes - for (i = 0; i < themes.Length; i++) { - content += GetFileContents("themes/" + themes[i] + "/theme." + suffix + ".js"); - - for (x = 0; x < languages.Length; x++) - content += GetFileContents("themes/" + themes[i] + "/langs/" + languages[x] + ".js"); - } - - // Add plugins - for (i = 0; i < plugins.Length; i++) { - content += GetFileContents("plugins/" + plugins[i] + "/plugin." + suffix + ".js"); - - for (x = 0; x < languages.Length; x++) - content += GetFileContents("plugins/" + plugins[i] + "/langs/" + languages[x] + ".js"); - } - - // Add custom files - for (i = 0; i < custom.Length; i++) - content += GetFileContents(custom[i]); - - // Generate GZIP'd content - if (supportsGzip) { - if (compress) - Response.AppendHeader("Content-Encoding", enc); - - if (diskCache && cacheKey != "") { - // Gzip compress - if (compress) { - using (Stream fileStream = File.Create(cacheFile)) { - gzipStream = new GZipStream(fileStream, CompressionMode.Compress, true); - buff = encoding.GetBytes(content.ToCharArray()); - gzipStream.Write(buff, 0, buff.Length); - gzipStream.Close(); - } - } else { - using (StreamWriter sw = File.CreateText(cacheFile)) { - sw.Write(content); - } - } - - // Write to stream - Response.WriteFile(cacheFile); - } else { - gzipStream = new GZipStream(Response.OutputStream, CompressionMode.Compress, true); - buff = encoding.GetBytes(content.ToCharArray()); - gzipStream.Write(buff, 0, buff.Length); - gzipStream.Close(); - } - } else - Response.Write(content); - } - - private string GetParam(string name, string def) { - string value = !String.IsNullOrEmpty(Request.QueryString[name]) ? "" + Request.QueryString[name] : def; - - return Regex.Replace(value, @"[^0-9a-zA-Z\\-_,]+", ""); - } - - private string GetFileContents(string path) { - try { - string content; - - path = Server.MapPath(path); - - if (!File.Exists(path)) - return ""; - - StreamReader sr = new StreamReader(path); - content = sr.ReadToEnd(); - sr.Close(); - - return content; - } catch (Exception ex) { - // Ignore any errors - } - - return ""; - } - - private string MD5(string str) { - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] result = md5.ComputeHash(Encoding.ASCII.GetBytes(str)); - str = BitConverter.ToString(result); - - return str.Replace("-", ""); - } - - #endregion -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/tinymce.gzip.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/tinymce.gzip.js deleted file mode 100644 index 7a79783573..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/tinymce.gzip.js +++ /dev/null @@ -1,188 +0,0 @@ -(function () { - var tinymce, loaded = {}, urls = [], callbacks = [], loading, realInit; - - function loadScript(url, callback) { - var elm, head = document.getElementsByTagName('head')[0] || document.body; - - // Execute callback when script is loaded - function done() { - elm.parentNode.removeChild(elm); - - if (elm) { - elm.onreadystatechange = elm.onload = elm = null; - } - - callback(); - } - - function error() { - // Report the error so it's easier for people to spot loading errors - if (typeof (console) !== "undefined" && console.log) { - console.log("Failed to load: " + url); - } - } - - // Create new script element - elm = document.createElement('script'); - elm.type = 'text/javascript'; - - // Use modern onload event when it's available - if ("onload" in elm) { - elm.onload = done; - head.appendChild(elm); - - // Add src after appending it to the document seems to work better on IE 10 - elm.src = url; - } else { - elm.onreadystatechange = function () { - if (elm.src && /loaded|complete/.test(elm.readyState)) { - done(); - } - }; - - elm.src = url; - head.appendChild(elm); - } - - elm.onerror = error; - } - - function buildUrl(themes, plugins, languages) { - var url = ''; - - function getQueryPart(type, items) { - if (items) { - for (var i = items.length - 1; i >= 0; i--) { - if (loaded[type + '_' + items[i]]) { - items.splice(i, 1); - } else { - loaded[type + '_' + items[i]] = true; - } - } - - if (items.length) { - return '&' + type + 's=' + items.join(','); - } - } - - return ''; - } - - url += getQueryPart("plugin", plugins); - url += getQueryPart("theme", themes); - url += getQueryPart("language", languages); - - if (url) { - if (loaded.core) { - url += '&core=false'; - } else { - loaded.core = true; - } - - url = tinymce.baseURL + '/tinymce.gzip.ashx?js=true' + url; - } - - return url; - } - - function splitValue(value) { - if (typeof (value) == "string") { - return value.split(/[, ]/); - } - - var items = []; - - if (value) { - for (var i = 0; i < value.length; i++) { - items = items.concat(splitValue(value[i])); - } - } - - return items; - } - - function loadNext() { - var url = urls.shift(); - - if (!url) { - for (var i = 0; i < callbacks.length; i++) { - callbacks[i](); - } - - callbacks = []; - loading = false; - } else { - loadScript(url, loadNext); - } - } - - function init(settings) { - var themes = [], plugins = [], languages = []; - - themes.push(settings.theme || 'modern'); - - var pluginList = splitValue(settings.plugins); - for (var i = 0; i < pluginList.length; i++) { - plugins.push(pluginList[i]); - } - - if (settings.language) { - languages.push(settings.language); - } - - urls.push(buildUrl(themes, plugins, languages)); - - callbacks.push(function () { - if (/complete|interactive/.test(document.readyState)) { - window.tinymce.dom.Event.domLoaded = true; - } - - if (window.tinymce.init != init) { - realInit = window.tinymce.init; - window.tinymce.init = init; - } - - realInit.call(window.tinymce, settings); - }); - - if (!loading) { - loading = true; - loadNext(); - } - } - - function getBaseUrl() { - var scripts = document.getElementsByTagName('script'); - for (var i = 0; i < scripts.length; i++) { - var src = scripts[i].src; - - if (src.indexOf('tinymce.gzip.js') != -1) { - return src.substring(0, src.lastIndexOf('/')); - } - } - } - - tinymce = { - init: init, - baseURL: getBaseUrl(), - suffix: ".min" - }; - - window.tinyMCE_GZ = { - init: function (settings, callback) { - urls.push(buildUrl(splitValue(settings.themes), splitValue(settings.plugins), splitValue(settings.languages))); - - callbacks.push(function () { - window.tinymce.dom.Event.domLoaded = 1; - callback(); - }); - - if (!loading) { - loading = true; - loadNext(); - } - } - }; - - window.tinymce = window.tinyMCE = tinymce; -})(); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/tinymce.min.js b/src/Presentation/SmartStore.Web/Content/editors/tinymce4/tinymce.min.js deleted file mode 100644 index 113522642e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/editors/tinymce4/tinymce.min.js +++ /dev/null @@ -1,10 +0,0 @@ -// 4.0.18 (2014-02-27) -!function(e,t){"use strict";function n(e,t){for(var n,r=[],i=0;ir;r++)if(o=n[r],o&&o.func.call(o.scope,e)===!1&&e.preventDefault(),e.isImmediatePropagationStopped())return}var a=this,s={},l,c,u,d,f;c=o+(+new Date).toString(32),d="onmouseenter"in document.documentElement,u="onfocusin"in document.documentElement,f={mouseenter:"mouseover",mouseleave:"mouseout"},l=1,a.domLoaded=!1,a.events=s,a.bind=function(t,o,p,m){function h(e){i(n(e||_.event),g)}var g,v,y,b,C,x,w,_=window;if(t&&3!==t.nodeType&&8!==t.nodeType){for(t[c]?g=t[c]:(g=l++,t[c]=g,s[g]={}),m=m||t,o=o.split(" "),y=o.length;y--;)b=o[y],x=h,C=w=!1,"DOMContentLoaded"===b&&(b="ready"),a.domLoaded&&"ready"===b&&"complete"==t.readyState?p.call(m,n({type:b})):(d||(C=f[b],C&&(x=function(e){var t,r;if(t=e.currentTarget,r=e.relatedTarget,r&&t.contains)r=t.contains(r);else for(;r&&r!==t;)r=r.parentNode;r||(e=n(e||_.event),e.type="mouseout"===e.type?"mouseleave":"mouseenter",e.target=t,i(e,g))})),u||"focusin"!==b&&"focusout"!==b||(w=!0,C="focusin"===b?"focus":"blur",x=function(e){e=n(e||_.event),e.type="focus"===e.type?"focusin":"focusout",i(e,g)}),v=s[g][b],v?"ready"===b&&a.domLoaded?p({type:b}):v.push({func:p,scope:m}):(s[g][b]=v=[{func:p,scope:m}],v.fakeName=C,v.capture=w,v.nativeHandler=x,"ready"===b?r(t,x,a):e(t,C||b,x,w)));return t=v=0,p}},a.unbind=function(e,n,r){var i,o,l,u,d,f;if(!e||3===e.nodeType||8===e.nodeType)return a;if(i=e[c]){if(f=s[i],n){for(n=n.split(" "),l=n.length;l--;)if(d=n[l],o=f[d]){if(r)for(u=o.length;u--;)if(o[u].func===r){var p=o.nativeHandler;o=o.slice(0,u).concat(o.slice(u+1)),o.nativeHandler=p,f[d]=o}r&&0!==o.length||(delete f[d],t(e,o.fakeName||d,o.nativeHandler,o.capture))}}else{for(d in f)o=f[d],t(e,o.fakeName||d,o.nativeHandler,o.capture);f={}}for(d in f)return a;delete s[i];try{delete e[c]}catch(m){e[c]=null}}return a},a.fire=function(e,t,r){var o;if(!e||3===e.nodeType||8===e.nodeType)return a;r=n(null,r),r.type=t,r.target=e;do o=e[c],o&&i(r,o),e=e.parentNode||e.ownerDocument||e.defaultView||e.parentWindow;while(e&&!r.isPropagationStopped());return a},a.clean=function(e){var t,n,r=a.unbind;if(!e||3===e.nodeType||8===e.nodeType)return a;if(e[c]&&r(e),e.getElementsByTagName||(e=e.document),e&&e.getElementsByTagName)for(r(e),n=e.getElementsByTagName("*"),t=n.length;t--;)e=n[t],e[c]&&r(e);return a},a.destroy=function(){s={}},a.cancel=function(e){return e&&(e.preventDefault(),e.stopImmediatePropagation()),!1}}var o="mce-data-",a=/^(?:mouse|contextmenu)|click/,s={keyLocation:1,layerX:1,layerY:1,returnValue:1};return i.Event=new i,i.Event.bind(window,"ready",function(){}),i}),r(c,[],function(){function e(e){return ht.test(e+"")}function n(){var e,t=[];return e=function(n,r){return t.push(n+=" ")>_.cacheLength&&delete e[t.shift()],e[n]=r,r}}function r(e){return e[I]=!0,e}function i(e){var t=B.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t=null}}function o(e,t,n,r){var i,o,a,s,l,c,f,p,m,h;if((t?t.ownerDocument||t:F)!==B&&A(t),t=t||B,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(L&&!r){if(i=gt.exec(e))if(a=i[1]){if(9===s){if(o=t.getElementById(a),!o||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&O(t,o)&&o.id===a)return n.push(o),n}else{if(i[2])return Z.apply(n,t.getElementsByTagName(e)),n;if((a=i[3])&&z.getElementsByClassName&&t.getElementsByClassName)return Z.apply(n,t.getElementsByClassName(a)),n}if(z.qsa&&!H.test(e)){if(f=!0,p=I,m=t,h=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){for(c=u(e),(f=t.getAttribute("id"))?p=f.replace(bt,"\\$&"):t.setAttribute("id",p),p="[id='"+p+"'] ",l=c.length;l--;)c[l]=p+d(c[l]);m=mt.test(e)&&t.parentNode||t,h=c.join(",")}if(h)try{return Z.apply(n,m.querySelectorAll(h)),n}catch(g){}finally{f||t.removeAttribute("id")}}}return b(e.replace(lt,"$1"),t,n,r)}function a(e,t){var n=t&&e,r=n&&(~t.sourceIndex||G)-(~e.sourceIndex||G);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function l(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function c(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function u(e,t){var n,r,i,a,s,l,c,u=q[e+" "];if(u)return t?0:u.slice(0);for(s=e,l=[],c=_.preFilter;s;){(!n||(r=ct.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=ut.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(lt," ")}),s=s.slice(n.length));for(a in _.filter)!(r=pt[a].exec(s))||c[a]&&!(r=c[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?o.error(e):q(e,l).slice(0)}function d(e){for(var t=0,n=e.length,r="";n>t;t++)r+=e[t].value;return r}function f(e,t,n){var r=t.dir,i=n&&"parentNode"===r,o=V++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,a){var s,l,c,u=W+" "+o;if(a){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,a))return!0}else for(;t=t[r];)if(1===t.nodeType||i)if(c=t[I]||(t[I]={}),(l=c[r])&&l[0]===u){if((s=l[1])===!0||s===w)return s===!0}else if(l=c[r]=[u],l[1]=e(t,n,a)||w,l[1]===!0)return!0}}function p(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function m(e,t,n,r,i){for(var o,a=[],s=0,l=e.length,c=null!=t;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),c&&t.push(s));return a}function h(e,t,n,i,o,a){return i&&!i[I]&&(i=h(i)),o&&!o[I]&&(o=h(o,a)),r(function(r,a,s,l){var c,u,d,f=[],p=[],h=a.length,g=r||y(t||"*",s.nodeType?[s]:s,[]),v=!e||!r&&t?g:m(g,f,e,s,l),b=n?o||(r?e:h||i)?[]:a:v;if(n&&n(v,b,s,l),i)for(c=m(b,p),i(c,[],s,l),u=c.length;u--;)(d=c[u])&&(b[p[u]]=!(v[p[u]]=d));if(r){if(o||e){if(o){for(c=[],u=b.length;u--;)(d=b[u])&&c.push(v[u]=d);o(null,b=[],c,l)}for(u=b.length;u--;)(d=b[u])&&(c=o?tt.call(r,d):f[u])>-1&&(r[c]=!(a[c]=d))}}else b=m(b===a?b.splice(h,b.length):b),o?o(null,a,b,l):Z.apply(a,b)})}function g(e){for(var t,n,r,i=e.length,o=_.relative[e[0].type],a=o||_.relative[" "],s=o?1:0,l=f(function(e){return e===t},a,!0),c=f(function(e){return tt.call(t,e)>-1},a,!0),u=[function(e,n,r){return!o&&(r||n!==k)||((t=n).nodeType?l(e,n,r):c(e,n,r))}];i>s;s++)if(n=_.relative[e[s].type])u=[f(p(u),n)];else{if(n=_.filter[e[s].type].apply(null,e[s].matches),n[I]){for(r=++s;i>r&&!_.relative[e[r].type];r++);return h(s>1&&p(u),s>1&&d(e.slice(0,s-1)).replace(lt,"$1"),n,r>s&&g(e.slice(s,r)),i>r&&g(e=e.slice(r)),i>r&&d(e))}u.push(n)}return p(u)}function v(e,t){var n=0,i=t.length>0,a=e.length>0,s=function(r,s,l,c,u){var d,f,p,h=[],g=0,v="0",y=r&&[],b=null!=u,C=k,x=r||a&&_.find.TAG("*",u&&s.parentNode||s),N=W+=null==C?1:Math.random()||.1;for(b&&(k=s!==B&&s,w=n);null!=(d=x[v]);v++){if(a&&d){for(f=0;p=e[f++];)if(p(d,s,l)){c.push(d);break}b&&(W=N,w=++n)}i&&((d=!p&&d)&&g--,r&&y.push(d))}if(g+=v,i&&v!==g){for(f=0;p=t[f++];)p(y,h,s,l);if(r){if(g>0)for(;v--;)y[v]||h[v]||(h[v]=J.call(c));h=m(h)}Z.apply(c,h),b&&!r&&h.length>0&&g+t.length>1&&o.uniqueSort(c)}return b&&(W=N,k=C),y};return i?r(s):s}function y(e,t,n){for(var r=0,i=t.length;i>r;r++)o(e,t[r],n);return n}function b(e,t,n,r){var i,o,a,s,l,c=u(e);if(!r&&1===c.length){if(o=c[0]=c[0].slice(0),o.length>2&&"ID"===(a=o[0]).type&&9===t.nodeType&&L&&_.relative[o[1].type]){if(t=(_.find.ID(a.matches[0].replace(xt,wt),t)||[])[0],!t)return n;e=e.slice(o.shift().value.length)}for(i=pt.needsContext.test(e)?0:o.length;i--&&(a=o[i],!_.relative[s=a.type]);)if((l=_.find[s])&&(r=l(a.matches[0].replace(xt,wt),mt.test(o[0].type)&&t.parentNode||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Z.apply(n,r),n;break}}return S(e,c)(r,t,!L,n,mt.test(e)),n}function C(){}var x,w,_,N,E,S,k,T,R,A,B,D,L,H,M,P,O,I="sizzle"+-new Date,F=window.document,z={},W=0,V=0,U=n(),q=n(),$=n(),j=!1,K=function(){return 0},Y=typeof t,G=1<<31,X=[],J=X.pop,Q=X.push,Z=X.push,et=X.slice,tt=X.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},nt="[\\x20\\t\\r\\n\\f]",rt="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",it=rt.replace("w","w#"),ot="([*^$|!~]?=)",at="\\["+nt+"*("+rt+")"+nt+"*(?:"+ot+nt+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+it+")|)|)"+nt+"*\\]",st=":("+rt+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+at.replace(3,8)+")*)|.*)\\)|)",lt=new RegExp("^"+nt+"+|((?:^|[^\\\\])(?:\\\\.)*)"+nt+"+$","g"),ct=new RegExp("^"+nt+"*,"+nt+"*"),ut=new RegExp("^"+nt+"*([\\x20\\t\\r\\n\\f>+~])"+nt+"*"),dt=new RegExp(st),ft=new RegExp("^"+it+"$"),pt={ID:new RegExp("^#("+rt+")"),CLASS:new RegExp("^\\.("+rt+")"),NAME:new RegExp("^\\[name=['\"]?("+rt+")['\"]?\\]"),TAG:new RegExp("^("+rt.replace("w","w*")+")"),ATTR:new RegExp("^"+at),PSEUDO:new RegExp("^"+st),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+nt+"*(even|odd|(([+-]|)(\\d*)n|)"+nt+"*(?:([+-]|)"+nt+"*(\\d+)|))"+nt+"*\\)|)","i"),needsContext:new RegExp("^"+nt+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+nt+"*((?:-\\d)?\\d*)"+nt+"*\\)|)(?=[^-]|$)","i")},mt=/[\x20\t\r\n\f]*[+~]/,ht=/^[^{]+\{\s*\[native code/,gt=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,vt=/^(?:input|select|textarea|button)$/i,yt=/^h\d$/i,bt=/'|\\/g,Ct=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,xt=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,wt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320)};try{Z.apply(X=et.call(F.childNodes),F.childNodes),X[F.childNodes.length].nodeType}catch(_t){Z={apply:X.length?function(e,t){Q.apply(e,et.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}E=o.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},A=o.setDocument=function(n){var r=n?n.ownerDocument||n:F;return r!==B&&9===r.nodeType&&r.documentElement?(B=r,D=r.documentElement,L=!E(r),z.getElementsByTagName=i(function(e){return e.appendChild(r.createComment("")),!e.getElementsByTagName("*").length}),z.attributes=i(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return"boolean"!==t&&"string"!==t}),z.getElementsByClassName=i(function(e){return e.innerHTML="",e.getElementsByClassName&&e.getElementsByClassName("e").length?(e.lastChild.className="e",2===e.getElementsByClassName("e").length):!1}),z.getByName=i(function(e){e.id=I+0,e.appendChild(B.createElement("a")).setAttribute("name",I),e.appendChild(B.createElement("i")).setAttribute("name",I),D.appendChild(e);var t=r.getElementsByName&&r.getElementsByName(I).length===2+r.getElementsByName(I+0).length;return D.removeChild(e),t}),z.sortDetached=i(function(e){return e.compareDocumentPosition&&1&e.compareDocumentPosition(B.createElement("div"))}),_.attrHandle=i(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==Y&&"#"===e.firstChild.getAttribute("href")})?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},z.getByName?(_.find.ID=function(e,t){if(typeof t.getElementById!==Y&&L){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},_.filter.ID=function(e){var t=e.replace(xt,wt);return function(e){return e.getAttribute("id")===t}}):(_.find.ID=function(e,n){if(typeof n.getElementById!==Y&&L){var r=n.getElementById(e);return r?r.id===e||typeof r.getAttributeNode!==Y&&r.getAttributeNode("id").value===e?[r]:t:[]}},_.filter.ID=function(e){var t=e.replace(xt,wt);return function(e){var n=typeof e.getAttributeNode!==Y&&e.getAttributeNode("id");return n&&n.value===t}}),_.find.TAG=z.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==Y?t.getElementsByTagName(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},_.find.NAME=z.getByName&&function(e,t){return typeof t.getElementsByName!==Y?t.getElementsByName(name):void 0},_.find.CLASS=z.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==Y&&L?t.getElementsByClassName(e):void 0},M=[],H=[":focus"],(z.qsa=e(r.querySelectorAll))&&(i(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||H.push("\\["+nt+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||H.push(":checked")}),i(function(e){e.innerHTML="",e.querySelectorAll("[i^='']").length&&H.push("[*^$]="+nt+"*(?:\"\"|'')"),e.querySelectorAll(":enabled").length||H.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),H.push(",.*:")})),(z.matchesSelector=e(P=D.matchesSelector||D.mozMatchesSelector||D.webkitMatchesSelector||D.oMatchesSelector||D.msMatchesSelector))&&i(function(e){z.disconnectedMatch=P.call(e,"div"),P.call(e,"[s!='']:x"),M.push("!=",st)}),H=new RegExp(H.join("|")),M=M.length&&new RegExp(M.join("|")),O=e(D.contains)||D.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},K=D.compareDocumentPosition?function(e,t){if(e===t)return j=!0,0;var n=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return n?1&n||T&&t.compareDocumentPosition(e)===n?e===r||O(F,e)?-1:t===r||O(F,t)?1:R?tt.call(R,e)-tt.call(R,t):0:4&n?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var n,i=0,o=e.parentNode,s=t.parentNode,l=[e],c=[t];if(e===t)return j=!0,0;if(!o||!s)return e===r?-1:t===r?1:o?-1:s?1:0;if(o===s)return a(e,t);for(n=e;n=n.parentNode;)l.unshift(n);for(n=t;n=n.parentNode;)c.unshift(n);for(;l[i]===c[i];)i++;return i?a(l[i],c[i]):l[i]===F?-1:c[i]===F?1:0},B):B},o.matches=function(e,t){return o(e,null,null,t)},o.matchesSelector=function(e,t){if((e.ownerDocument||e)!==B&&A(e),t=t.replace(Ct,"='$1']"),z.matchesSelector&&L&&(!M||!M.test(t))&&!H.test(t))try{var n=P.call(e,t);if(n||z.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return o(t,B,null,[e]).length>0},o.contains=function(e,t){return(e.ownerDocument||e)!==B&&A(e),O(e,t)},o.attr=function(e,t){var n;return(e.ownerDocument||e)!==B&&A(e),L&&(t=t.toLowerCase()),(n=_.attrHandle[t])?n(e):!L||z.attributes?e.getAttribute(t):((n=e.getAttributeNode(t))||e.getAttribute(t))&&e[t]===!0?t:n&&n.specified?n.value:null},o.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},o.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!z.detectDuplicates,T=!z.sortDetached,R=!z.sortStable&&e.slice(0),e.sort(K),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return e},N=o.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=N(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=N(t);return n},_=o.selectors={cacheLength:50,createPseudo:r,match:pt,find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(xt,wt),e[3]=(e[4]||e[5]||"").replace(xt,wt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||o.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&o.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return pt.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&dt.test(n)&&(t=u(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){return"*"===e?function(){return!0}:(e=e.replace(xt,wt).toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=U[e+" "];return t||(t=new RegExp("(^|"+nt+")"+e+"("+nt+"|$)"))&&U(e,function(e){return t.test(e.className||typeof e.getAttribute!==Y&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=o.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var c,u,d,f,p,m,h=o!==a?"nextSibling":"previousSibling",g=t.parentNode,v=s&&t.nodeName.toLowerCase(),y=!l&&!s;if(g){if(o){for(;h;){for(d=t;d=d[h];)if(s?d.nodeName.toLowerCase()===v:1===d.nodeType)return!1;m=h="only"===e&&!m&&"nextSibling"}return!0}if(m=[a?g.firstChild:g.lastChild],a&&y){for(u=g[I]||(g[I]={}),c=u[e]||[],p=c[0]===W&&c[1],f=c[0]===W&&c[2],d=p&&g.childNodes[p];d=++p&&d&&d[h]||(f=p=0)||m.pop();)if(1===d.nodeType&&++f&&d===t){u[e]=[W,p,f];break}}else if(y&&(c=(t[I]||(t[I]={}))[e])&&c[0]===W)f=c[1];else for(;(d=++p&&d&&d[h]||(f=p=0)||m.pop())&&((s?d.nodeName.toLowerCase()!==v:1!==d.nodeType)||!++f||(y&&((d[I]||(d[I]={}))[e]=[W,f]),d!==t)););return f-=i,f===r||f%r===0&&f/r>=0}}},PSEUDO:function(e,t){var n,i=_.pseudos[e]||_.setFilters[e.toLowerCase()]||o.error("unsupported pseudo: "+e);return i[I]?i(t):i.length>1?(n=[e,e,"",t],_.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,n){for(var r,o=i(e,t),a=o.length;a--;)r=tt.call(e,o[a]),e[r]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:r(function(e){var t=[],n=[],i=S(e.replace(lt,"$1"));return i[I]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),!n.pop()}}),has:r(function(e){return function(t){return o(e,t).length>0}}),contains:r(function(e){return function(t){return(t.textContent||t.innerText||N(t)).indexOf(e)>-1}}),lang:r(function(e){return ft.test(e||"")||o.error("unsupported lang: "+e),e=e.replace(xt,wt).toLowerCase(),function(t){var n;do if(n=L?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(e){var t=window.location&&window.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===D},focus:function(e){return e===B.activeElement&&(!B.hasFocus||B.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!_.pseudos.empty(e)},header:function(e){return yt.test(e.nodeName)},input:function(e){return vt.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:c(function(){return[0]}),last:c(function(e,t){return[t-1]}),eq:c(function(e,t,n){return[0>n?n+t:n]}),even:c(function(e,t){for(var n=0;t>n;n+=2)e.push(n);return e}),odd:c(function(e,t){for(var n=1;t>n;n+=2)e.push(n);return e}),lt:c(function(e,t,n){for(var r=0>n?n+t:n;--r>=0;)e.push(r);return e}),gt:c(function(e,t,n){for(var r=0>n?n+t:n;++rn;n++)t[n]=e[n];return t}function f(e,t){var n;if(t.indexOf)return t.indexOf(e);for(n=t.length;n--;)if(t[n]===e)return n;return-1}function p(e,t){var n,r,i,o,a;if(e)if(n=e.length,n===o){for(r in e)if(e.hasOwnProperty(r)&&(a=e[r],t.call(a,a,r)===!1))break}else for(i=0;n>i&&(a=e[i],t.call(a,a,r)!==!1);i++);return e}function m(e,n,r){for(var i=[],o=e[n];o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!c(o).is(r));)1===o.nodeType&&i.push(o),o=o[n];return i}function h(e,t,n,r){for(var i=[];e;e=e[n])r&&e.nodeType!==r||e===t||i.push(e);return i}var g=document,v=Array.prototype.push,y=Array.prototype.slice,b=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,C=e.Event,x=l("fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom"),w=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},_=/^\s*|\s*$/g,N=function(e){return null===e||e===t?"":(""+e).replace(_,"")};return c.fn=c.prototype={constructor:c,selector:"",length:0,init:function(e,t){var n=this,r,a;if(!e)return n;if(e.nodeType)return n.context=n[0]=e,n.length=1,n;if(i(e)){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:b.exec(e),!r)return c(t||document).find(e);if(r[1])for(a=o(e).firstChild;a;)this.add(a),a=a.nextSibling;else{if(a=g.getElementById(r[2]),a.id!==r[2])return n.find(e);n.length=1,n[0]=a}}else this.add(e);return n},toArray:function(){return d(this)},add:function(e){var t=this;return w(e)?v.apply(t,e):e instanceof c?t.add(e.toArray()):v.call(t,e),t},attr:function(e,n){var i=this;if("object"==typeof e)p(e,function(e,t){i.attr(t,e)});else{if(!r(n))return i[0]&&1===i[0].nodeType?i[0].getAttribute(e):t;this.each(function(){1===this.nodeType&&this.setAttribute(e,n)})}return i},css:function(e,n){var i=this;if("object"==typeof e)p(e,function(e,t){i.css(t,e)});else{if(e=e.replace(/-(\D)/g,function(e,t){return t.toUpperCase()}),!r(n))return i[0]?i[0].style[e]:t;"number"!=typeof n||x[e]||(n+="px"),i.each(function(){var t=this.style;"opacity"===e&&this.runtimeStyle&&"undefined"==typeof this.runtimeStyle.opacity&&(t.filter=""===n?"":"alpha(opacity="+100*n+")");try{t[e]=n}catch(r){}})}return i},remove:function(){for(var e=this,t,n=this.length;n--;)t=e[n],C.clean(t),t.parentNode&&t.parentNode.removeChild(t);return this},empty:function(){for(var e=this,t,n=this.length;n--;)for(t=e[n];t.firstChild;)t.removeChild(t.firstChild);return this},html:function(e){var t=this,n;if(r(e)){for(n=t.length;n--;)t[n].innerHTML=e;return t}return t[0]?t[0].innerHTML:""},text:function(e){var t=this,n;if(r(e)){for(n=t.length;n--;)t[n].innerText=t[0].textContent=e;return t}return t[0]?t[0].innerText||t[0].textContent:""},append:function(){return a(this,arguments,function(e){1===this.nodeType&&this.appendChild(e)})},prepend:function(){return a(this,arguments,function(e){1===this.nodeType&&this.insertBefore(e,this.firstChild)})},before:function(){var e=this;return e[0]&&e[0].parentNode?a(e,arguments,function(e){this.parentNode.insertBefore(e,this.nextSibling)}):e},after:function(){var e=this;return e[0]&&e[0].parentNode?a(e,arguments,function(e){this.parentNode.insertBefore(e,this)}):e},appendTo:function(e){return c(e).append(this),this},addClass:function(e){return this.toggleClass(e,!0)},removeClass:function(e){return this.toggleClass(e,!1)},toggleClass:function(e,t){var n=this;return-1!==e.indexOf(" ")?p(e.split(" "),function(){n.toggleClass(this,t)}):n.each(function(){var n=this,r;s(n,e)!==t&&(r=n.className,t?n.className+=r?" "+e:e:n.className=N((" "+r+" ").replace(" "+e+" "," ")))}),n},hasClass:function(e){return s(this[0],e)},each:function(e){return p(this,e)},on:function(e,t){return this.each(function(){C.bind(this,e,t)})},off:function(e,t){return this.each(function(){C.unbind(this,e,t)})},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},slice:function(){return new c(y.apply(this,arguments))},eq:function(e){return-1===e?this.slice(e):this.slice(e,+e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},replaceWith:function(e){var t=this;return t[0]&&t[0].parentNode.replaceChild(c(e)[0],t[0]),t},wrap:function(e){return e=c(e)[0],this.each(function(){var t=this,n=e.cloneNode(!1);t.parentNode.insertBefore(n,t),n.appendChild(t)})},unwrap:function(){return this.each(function(){for(var e=this,t=e.firstChild,n;t;)n=t,t=t.nextSibling,e.parentNode.insertBefore(n,e)})},clone:function(){var e=[];return this.each(function(){e.push(this.cloneNode(!0))}),c(e)},find:function(e){var t,n,r=[];for(t=0,n=this.length;n>t;t++)c.find(e,this[t],r);return c(r)},push:v,sort:[].sort,splice:[].splice},u(c,{extend:u,toArray:d,inArray:f,isArray:w,each:p,trim:N,makeMap:l,find:n,expr:n.selectors,unique:n.uniqueSort,text:n.getText,isXMLDoc:n.isXML,contains:n.contains,filter:function(e,t,n){return n&&(e=":not("+e+")"),1===t.length?c.find.matchesSelector(t[0],e)?[t[0]]:[]:c.find.matches(e,t)}}),p({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return m(e,"parentNode")},parentsUntil:function(e,t){return m(e,"parentNode",t)},next:function(e){return h(e,"nextSibling",1)},prev:function(e){return h(e,"previousSibling",1)},nextNodes:function(e){return h(e,"nextSibling")},prevNodes:function(e){return h(e,"previousSibling")},children:function(e){return h(e.firstChild,"nextSibling",1)},contents:function(e){return d(("iframe"===e.nodeName?e.contentDocument||e.contentWindow.document:e).childNodes)}},function(e,t){c.fn[e]=function(n){var r=this,i;if(r.length>1)throw new Error("DomQuery only supports traverse functions on a single node.");return r[0]&&(i=t(r[0],n)),i=c(i),n&&"parentsUntil"!==e?i.filter(n):i}}),c.fn.filter=function(e){return c.filter(e)},c.fn.is=function(e){return!!e&&this.filter(e).length>0},c.fn.init.prototype=c.fn,c}),r(d,[],function(){return function(e,t){function n(e,t,n,r){function i(e){return e=parseInt(e,10).toString(16),e.length>1?e:"0"+e}return"#"+i(t)+i(n)+i(r)}var r=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,i=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,o=/\s*([^:]+):\s*([^;]+);?/g,a=/\s+$/,s,l,c={},u,d="\ufeff"; -for(e=e||{},u=("\\\" \\' \\; \\: ; : "+d).split(" "),l=0;l-1&&n||(h[e+t]=-1==l?s[0]:s.join(" "),delete h[e+"-top"+t],delete h[e+"-right"+t],delete h[e+"-bottom"+t],delete h[e+"-left"+t])}}function u(e){var t=h[e],n;if(t){for(t=t.split(" "),n=t.length;n--;)if(t[n]!==t[0])return!1;return h[e]=t[0],!0}}function d(e,t,n,r){u(t)&&u(n)&&u(r)&&(h[e]=h[t]+" "+h[n]+" "+h[r],delete h[t],delete h[n],delete h[r])}function f(e){return b=!0,c[e]}function p(e,t){return b&&(e=e.replace(/\uFEFF[0-9]/g,function(e){return c[e]})),t||(e=e.replace(/\\([\'\";:])/g,"$1")),e}function m(t,n,r,i,o,a){return(o=o||a)?(o=p(o),"'"+o.replace(/\'/g,"\\'")+"'"):(n=p(n||r||i),!e.allow_script_urls&&/(java|vb)script:/i.test(n.replace(/[\s\r\n]+/,""))?"":(C&&(n=C.call(x,n,"style")),"url('"+n.replace(/\'/g,"\\'")+"')"))}var h={},g,v,y,b,C=e.url_converter,x=e.url_converter_scope||this;if(t){for(t=t.replace(/[\u0000-\u001F]/g,""),t=t.replace(/\\[\"\';:\uFEFF]/g,f).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(e){return e.replace(/[;:]/g,f)});g=o.exec(t);){if(v=g[1].replace(a,"").toLowerCase(),y=g[2].replace(a,""),v&&y.length>0){if(!e.allow_script_urls&&("behavior"==v||/expression\s*\(/.test(y)))continue;"font-weight"===v&&"700"===y?y="bold":("color"===v||"background-color"===v)&&(y=y.toLowerCase()),y=y.replace(r,n),y=y.replace(i,m),h[v]=b?p(y,!0):y}o.lastIndex=g.index+g[0].length}s("border","",!0),s("border","-width"),s("border","-color"),s("border","-style"),s("padding",""),s("margin",""),d("border","border-width","border-style","border-color"),"medium none"===h.border&&delete h.border,"none"===h["border-image"]&&delete h["border-image"]}return h},serialize:function(e,n){function r(n){var r,o,a,l;if(r=t.styles[n])for(o=0,a=r.length;a>o;o++)n=r[o],l=e[n],l!==s&&l.length>0&&(i+=(i.length>0?" ":"")+n+": "+l+";")}var i="",o,a;if(n&&t&&t.styles)r("*"),r(n);else for(o in e)a=e[o],a!==s&&a.length>0&&(i+=(i.length>0?" ":"")+o+": "+a+";");return i}}}}),r(f,[],function(){return function(e,t){function n(e,n,r,i){var o,a;if(e){if(!i&&e[n])return e[n];if(e!=t){if(o=e[r])return o;for(a=e.parentNode;a&&a!=t;a=a.parentNode)if(o=a[r])return o}}}var r=e;this.current=function(){return r},this.next=function(e){return r=n(r,"firstChild","nextSibling",e)},this.prev=function(e){return r=n(r,"lastChild","previousSibling",e)}}}),r(p,[],function(){function e(e,n){return n?"array"==n&&g(e)?!0:typeof e==n:e!==t}function n(e){var t=[],n,r;for(n=0,r=e.length;r>n;n++)t[n]=e[n];return t}function r(e,t,n){var r;for(e=e||[],t=t||",","string"==typeof e&&(e=e.split(t)),n=n||{},r=e.length;r--;)n[e[r]]={};return n}function i(e,n,r){var i,o;if(!e)return 0;if(r=r||e,e.length!==t){for(i=0,o=e.length;o>i;i++)if(n.call(r,e[i],i,e)===!1)return 0}else for(i in e)if(e.hasOwnProperty(i)&&n.call(r,e[i],i,e)===!1)return 0;return 1}function o(e,t){var n=[];return i(e,function(e){n.push(t(e))}),n}function a(e,t){var n=[];return i(e,function(e){(!t||t(e))&&n.push(e)}),n}function s(e,t,n){var r=this,i,o,a,s,l,c=0;if(e=/^((static) )?([\w.]+)(:([\w.]+))?/.exec(e),a=e[3].match(/(^|\.)(\w+)$/i)[2],o=r.createNS(e[3].replace(/\.\w+$/,""),n),!o[a]){if("static"==e[2])return o[a]=t,void(this.onCreate&&this.onCreate(e[2],e[3],o[a]));t[a]||(t[a]=function(){},c=1),o[a]=t[a],r.extend(o[a].prototype,t),e[5]&&(i=r.resolve(e[5]).prototype,s=e[5].match(/\.(\w+)$/i)[1],l=o[a],o[a]=c?function(){return i[s].apply(this,arguments)}:function(){return this.parent=i[s],l.apply(this,arguments)},o[a].prototype[a]=o[a],r.each(i,function(e,t){o[a].prototype[t]=i[t]}),r.each(t,function(e,t){i[t]?o[a].prototype[t]=function(){return this.parent=i[t],e.apply(this,arguments)}:t!=a&&(o[a].prototype[t]=e)})),r.each(t["static"],function(e,t){o[a][t]=e})}}function l(e,t){var n,r;if(e)for(n=0,r=e.length;r>n;n++)if(e[n]===t)return n;return-1}function c(e,n){var r,i,o,a=arguments,s;for(r=1,i=a.length;i>r;r++){n=a[r];for(o in n)n.hasOwnProperty(o)&&(s=n[o],s!==t&&(e[o]=s))}return e}function u(e,t,n,r){r=r||this,e&&(n&&(e=e[n]),i(e,function(e,i){return t.call(r,e,i,n)===!1?!1:void u(e,t,n,r)}))}function d(e,t){var n,r;for(t=t||window,e=e.split("."),n=0;nn&&(t=t[e[n]],t);n++);return t}function p(t,n){return!t||e(t,"array")?t:o(t.split(n||","),h)}var m=/^\s*|\s*$/g,h=function(e){return null===e||e===t?"":(""+e).replace(m,"")},g=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)};return{trim:h,isArray:g,is:e,toArray:n,makeMap:r,each:i,map:o,grep:a,inArray:l,extend:c,create:s,walk:u,createNS:d,resolve:f,explode:p}}),r(m,[p],function(e){function t(n){function r(){return M.createDocumentFragment()}function i(e,t){_(F,e,t)}function o(e,t){_(z,e,t)}function a(e){i(e.parentNode,j(e))}function s(e){i(e.parentNode,j(e)+1)}function l(e){o(e.parentNode,j(e))}function c(e){o(e.parentNode,j(e)+1)}function u(e){e?(H[U]=H[V],H[q]=H[W]):(H[V]=H[U],H[W]=H[q]),H.collapsed=F}function d(e){a(e),c(e)}function f(e){i(e,0),o(e,1===e.nodeType?e.childNodes.length:e.nodeValue.length)}function p(e,t){var n=H[V],r=H[W],i=H[U],o=H[q],a=t.startContainer,s=t.startOffset,l=t.endContainer,c=t.endOffset;return 0===e?w(n,r,a,s):1===e?w(i,o,a,s):2===e?w(i,o,l,c):3===e?w(n,r,l,c):void 0}function m(){N(I)}function h(){return N(P)}function g(){return N(O)}function v(e){var t=this[V],r=this[W],i,o;3!==t.nodeType&&4!==t.nodeType||!t.nodeValue?(t.childNodes.length>0&&(o=t.childNodes[r]),o?t.insertBefore(e,o):3==t.nodeType?n.insertAfter(e,t):t.appendChild(e)):r?r>=t.nodeValue.length?n.insertAfter(e,t):(i=t.splitText(r),t.parentNode.insertBefore(e,i)):t.parentNode.insertBefore(e,t)}function y(e){var t=H.extractContents();H.insertNode(e),e.appendChild(t),H.selectNode(e)}function b(){return $(new t(n),{startContainer:H[V],startOffset:H[W],endContainer:H[U],endOffset:H[q],collapsed:H.collapsed,commonAncestorContainer:H.commonAncestorContainer})}function C(e,t){var n;if(3==e.nodeType)return e;if(0>t)return e;for(n=e.firstChild;n&&t>0;)--t,n=n.nextSibling;return n?n:e}function x(){return H[V]==H[U]&&H[W]==H[q]}function w(e,t,r,i){var o,a,s,l,c,u;if(e==r)return t==i?0:i>t?-1:1;for(o=r;o&&o.parentNode!=e;)o=o.parentNode;if(o){for(a=0,s=e.firstChild;s!=o&&t>a;)a++,s=s.nextSibling;return a>=t?-1:1}for(o=e;o&&o.parentNode!=r;)o=o.parentNode;if(o){for(a=0,s=r.firstChild;s!=o&&i>a;)a++,s=s.nextSibling;return i>a?-1:1}for(l=n.findCommonAncestor(e,r),c=e;c&&c.parentNode!=l;)c=c.parentNode;for(c||(c=l),u=r;u&&u.parentNode!=l;)u=u.parentNode;if(u||(u=l),c==u)return 0;for(s=l.firstChild;s;){if(s==c)return-1;if(s==u)return 1;s=s.nextSibling}}function _(e,t,r){var i,o;for(e?(H[V]=t,H[W]=r):(H[U]=t,H[q]=r),i=H[U];i.parentNode;)i=i.parentNode;for(o=H[V];o.parentNode;)o=o.parentNode;o==i?w(H[V],H[W],H[U],H[q])>0&&H.collapse(e):H.collapse(e),H.collapsed=x(),H.commonAncestorContainer=n.findCommonAncestor(H[V],H[U])}function N(e){var t,n=0,r=0,i,o,a,s,l,c;if(H[V]==H[U])return E(e);for(t=H[U],i=t.parentNode;i;t=i,i=i.parentNode){if(i==H[V])return S(t,e);++n}for(t=H[V],i=t.parentNode;i;t=i,i=i.parentNode){if(i==H[U])return k(t,e);++r}for(o=r-n,a=H[V];o>0;)a=a.parentNode,o--;for(s=H[U];0>o;)s=s.parentNode,o++;for(l=a.parentNode,c=s.parentNode;l!=c;l=l.parentNode,c=c.parentNode)a=l,s=c;return T(a,s,e)}function E(e){var t,n,i,o,a,s,l,c,u;if(e!=I&&(t=r()),H[W]==H[q])return t;if(3==H[V].nodeType){if(n=H[V].nodeValue,i=n.substring(H[W],H[q]),e!=O&&(o=H[V],c=H[W],u=H[q]-H[W],0===c&&u>=o.nodeValue.length-1?o.parentNode.removeChild(o):o.deleteData(c,u),H.collapse(F)),e==I)return;return i.length>0&&t.appendChild(M.createTextNode(i)),t}for(o=C(H[V],H[W]),a=H[q]-H[W];o&&a>0;)s=o.nextSibling,l=D(o,e),t&&t.appendChild(l),--a,o=s;return e!=O&&H.collapse(F),t}function S(e,t){var n,i,o,a,s,l;if(t!=I&&(n=r()),i=R(e,t),n&&n.appendChild(i),o=j(e),a=o-H[W],0>=a)return t!=O&&(H.setEndBefore(e),H.collapse(z)),n;for(i=e.previousSibling;a>0;)s=i.previousSibling,l=D(i,t),n&&n.insertBefore(l,n.firstChild),--a,i=s;return t!=O&&(H.setEndBefore(e),H.collapse(z)),n}function k(e,t){var n,i,o,a,s,l;for(t!=I&&(n=r()),o=A(e,t),n&&n.appendChild(o),i=j(e),++i,a=H[q]-i,o=e.nextSibling;o&&a>0;)s=o.nextSibling,l=D(o,t),n&&n.appendChild(l),--a,o=s;return t!=O&&(H.setStartAfter(e),H.collapse(F)),n}function T(e,t,n){var i,o,a,s,l,c,u,d;for(n!=I&&(o=r()),i=A(e,n),o&&o.appendChild(i),a=e.parentNode,s=j(e),l=j(t),++s,c=l-s,u=e.nextSibling;c>0;)d=u.nextSibling,i=D(u,n),o&&o.appendChild(i),u=d,--c;return i=R(t,n),o&&o.appendChild(i),n!=O&&(H.setStartAfter(e),H.collapse(F)),o}function R(e,t){var n=C(H[U],H[q]-1),r,i,o,a,s,l=n!=H[U];if(n==e)return B(n,l,z,t);for(r=n.parentNode,i=B(r,z,z,t);r;){for(;n;)o=n.previousSibling,a=B(n,l,z,t),t!=I&&i.insertBefore(a,i.firstChild),l=F,n=o;if(r==e)return i;n=r.previousSibling,r=r.parentNode,s=B(r,z,z,t),t!=I&&s.appendChild(i),i=s}}function A(e,t){var n=C(H[V],H[W]),r=n!=H[V],i,o,a,s,l;if(n==e)return B(n,r,F,t);for(i=n.parentNode,o=B(i,z,F,t);i;){for(;n;)a=n.nextSibling,s=B(n,r,F,t),t!=I&&o.appendChild(s),r=F,n=a;if(i==e)return o;n=i.nextSibling,i=i.parentNode,l=B(i,z,F,t),t!=I&&l.appendChild(o),o=l}}function B(e,t,r,i){var o,a,s,l,c;if(t)return D(e,i);if(3==e.nodeType){if(o=e.nodeValue,r?(l=H[W],a=o.substring(l),s=o.substring(0,l)):(l=H[q],a=o.substring(0,l),s=o.substring(l)),i!=O&&(e.nodeValue=s),i==I)return;return c=n.clone(e,z),c.nodeValue=a,c}if(i!=I)return n.clone(e,z)}function D(e,t){return t!=I?t==O?n.clone(e,F):e:void e.parentNode.removeChild(e)}function L(){return n.create("body",null,g()).outerText}var H=this,M=n.doc,P=0,O=1,I=2,F=!0,z=!1,W="startOffset",V="startContainer",U="endContainer",q="endOffset",$=e.extend,j=n.nodeIndex;return $(H,{startContainer:M,startOffset:0,endContainer:M,endOffset:0,collapsed:F,commonAncestorContainer:M,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:i,setEnd:o,setStartBefore:a,setStartAfter:s,setEndBefore:l,setEndAfter:c,collapse:u,selectNode:d,selectNodeContents:f,compareBoundaryPoints:p,deleteContents:m,extractContents:h,cloneContents:g,insertNode:v,surroundContents:y,cloneRange:b,toStringIE:L}),H}return t.prototype.toString=function(){return this.toStringIE()},t}),r(h,[p],function(e){function t(e){var t;return t=document.createElement("div"),t.innerHTML=e,t.textContent||t.innerText||e}function n(e,t){var n,r,i,a={};if(e){for(e=e.split(","),t=t||10,n=0;n\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,l=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,c=/[<>&\"\']/g,u=/&(#x|#)?([\w]+);/g,d={128:"\u20ac",130:"\u201a",131:"\u0192",132:"\u201e",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02c6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017d",145:"\u2018",146:"\u2019",147:"\u201c",148:"\u201d",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02dc",153:"\u2122",154:"\u0161",155:"\u203a",156:"\u0153",158:"\u017e",159:"\u0178"};o={'"':""","'":"'","<":"<",">":">","&":"&"},a={"<":"<",">":">","&":"&",""":'"',"'":"'"},i=n("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32);var f={encodeRaw:function(e,t){return e.replace(t?s:l,function(e){return o[e]||e})},encodeAllRaw:function(e){return(""+e).replace(c,function(e){return o[e]||e})},encodeNumeric:function(e,t){return e.replace(t?s:l,function(e){return e.length>1?"&#"+(1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320)+65536)+";":o[e]||"&#"+e.charCodeAt(0)+";"})},encodeNamed:function(e,t,n){return n=n||i,e.replace(t?s:l,function(e){return o[e]||n[e]||e})},getEncodeFunc:function(e,t){function a(e,n){return e.replace(n?s:l,function(e){return o[e]||t[e]||"&#"+e.charCodeAt(0)+";"||e})}function c(e,n){return f.encodeNamed(e,n,t)}return t=n(t)||i,e=r(e.replace(/\+/g,",")),e.named&&e.numeric?a:e.named?t?c:f.encodeNamed:e.numeric?f.encodeNumeric:f.encodeRaw},decode:function(e){return e.replace(u,function(e,n,r){return n?(r=parseInt(r,2===n.length?16:10),r>65535?(r-=65536,String.fromCharCode(55296+(r>>10),56320+(1023&r))):d[r]||String.fromCharCode(r)):a[e]||i[e]||t(e)})}};return f}),r(g,[],function(){var e=navigator,t=e.userAgent,n,r,i,o,a,s,l;n=window.opera&&window.opera.buildNumber,r=/WebKit/.test(t),i=!r&&!n&&/MSIE/gi.test(t)&&/Explorer/gi.test(e.appName),i=i&&/MSIE (\w+)\./.exec(t)[1],o=-1==t.indexOf("Trident/")||-1==t.indexOf("rv:")&&-1==e.appName.indexOf("Netscape")?!1:11,i=i||o,a=!r&&!o&&/Gecko/.test(t),s=-1!=t.indexOf("Mac"),l=/(iPad|iPhone)/.test(t);var c=!l||t.match(/AppleWebKit\/(\d*)/)[1]>=534;return{opera:n,webkit:r,ie:i,gecko:a,mac:s,iOS:l,contentEditable:c,transparentSrc:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",caretAfter:8!=i,range:window.getSelection&&"Range"in window,documentMode:i?document.documentMode||7:10}}),r(v,[],function(){return function(e,t){function n(t){e.getElementsByTagName("head")[0].appendChild(t)}function r(t,r,s){function l(){for(var e=v.passed,t=e.length;t--;)e[t]();v.status=2,v.passed=[],v.failed=[]}function c(){for(var e=v.failed,t=e.length;t--;)e[t]();v.status=3,v.passed=[],v.failed=[]}function u(){var e=navigator.userAgent.match(/WebKit\/(\d*)/);return!!(e&&e[1]<536)}function d(e,t){e()||((new Date).getTime()-g0)return h=e.createElement("style"),h.textContent='@import "'+t+'"',p(),void n(h);f()}n(m),m.href=t}}var i=0,o={},a;t=t||{},a=t.maxLoadTime||5e3,this.load=r}}),r(y,[c,d,l,f,m,h,g,p,v],function(e,n,r,i,o,a,s,l,c){function u(e,t){var i=this,o;i.doc=e,i.win=window,i.files={},i.counter=0,i.stdMode=!v||e.documentMode>=8,i.boxModel=!v||"CSS1Compat"==e.compatMode||i.stdMode,i.hasOuterHTML="outerHTML"in e.createElement("a"),i.styleSheetLoader=new c(e),this.boundEvents=[],i.settings=t=h({keep_values:!1,hex_colors:1},t),i.schema=t.schema,i.styles=new n({url_converter:t.url_converter,url_converter_scope:t.url_converter_scope},t.schema),i.fixDoc(e),i.events=t.ownEvents?new r(t.proxy):r.Event,o=t.schema?t.schema.getBlockElements():{},i.isBlock=function(e){if(!e)return!1;var t=e.nodeType;return t?!(1!==t||!o[e.nodeName]):!!o[e]}}var d=l.each,f=l.is,p=l.grep,m=l.trim,h=l.extend,g=s.webkit,v=s.ie,y=/^([a-z0-9],?)+$/i,b=/^[ \t\r\n]*$/,C=l.makeMap("fillOpacity fontWeight lineHeight opacity orphans widows zIndex zoom"," ");return u.prototype={root:null,props:{"for":"htmlFor","class":"className",className:"className",checked:"checked",disabled:"disabled",maxlength:"maxLength",readonly:"readOnly",selected:"selected",value:"value",id:"id",name:"name",type:"type"},fixDoc:function(e){var t=this.settings,n;if(v&&t.schema){"abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video".replace(/\w+/g,function(t){e.createElement(t)});for(n in t.schema.getCustomElements())e.createElement(n)}},clone:function(e,t){var n=this,r,i;return!v||1!==e.nodeType||t?e.cloneNode(t):(i=n.doc,t?r.firstChild:(r=i.createElement(e.nodeName),d(n.getAttribs(e),function(t){n.setAttrib(r,t.nodeName,n.getAttrib(e,t.nodeName))}),r))},getRoot:function(){var e=this;return e.get(e.settings.root_element)||e.doc.body},getViewPort:function(e){var t,n;return e=e?e:this.win,t=e.document,n=this.boxModel?t.documentElement:t.body,{x:e.pageXOffset||n.scrollLeft,y:e.pageYOffset||n.scrollTop,w:e.innerWidth||n.clientWidth,h:e.innerHeight||n.clientHeight}},getRect:function(e){var t=this,n,r;return e=t.get(e),n=t.getPos(e),r=t.getSize(e),{x:n.x,y:n.y,w:r.w,h:r.h}},getSize:function(e){var t=this,n,r;return e=t.get(e),n=t.getStyle(e,"width"),r=t.getStyle(e,"height"),-1===n.indexOf("px")&&(n=0),-1===r.indexOf("px")&&(r=0),{w:parseInt(n,10)||e.offsetWidth||e.clientWidth,h:parseInt(r,10)||e.offsetHeight||e.clientHeight}},getParent:function(e,t,n){return this.getParents(e,t,n,!1)},getParents:function(e,n,r,i){var o=this,a,s=[];for(e=o.get(e),i=i===t,r=r||("BODY"!=o.getRoot().nodeName?o.getRoot().parentNode:null),f(n,"string")&&(a=n,n="*"===n?function(e){return 1==e.nodeType}:function(e){return o.is(e,a)});e&&e!=r&&e.nodeType&&9!==e.nodeType;){if(!n||n(e)){if(!i)return e;s.push(e)}e=e.parentNode}return i?s:null},get:function(e){var t;return e&&this.doc&&"string"==typeof e&&(t=e,e=this.doc.getElementById(e),e&&e.id!==t)?this.doc.getElementsByName(t)[1]:e},getNext:function(e,t){return this._findSib(e,t,"nextSibling")},getPrev:function(e,t){return this._findSib(e,t,"previousSibling")},select:function(t,n){var r=this;return e(t,r.get(n)||r.get(r.settings.root_element)||r.doc,[])},is:function(n,r){var i;if(n.length===t){if("*"===r)return 1==n.nodeType;if(y.test(r)){for(r=r.toLowerCase().split(/,/),n=n.nodeName.toLowerCase(),i=r.length-1;i>=0;i--)if(r[i]==n)return!0;return!1}}return n.nodeType&&1!=n.nodeType?!1:e.matches(r,n.nodeType?[n]:n).length>0},add:function(e,t,n,r,i){var o=this;return this.run(e,function(e){var a;return a=f(t,"string")?o.doc.createElement(t):t,o.setAttribs(a,n),r&&(r.nodeType?a.appendChild(r):o.setHTML(a,r)),i?a:e.appendChild(a)})},create:function(e,t,n){return this.add(this.doc.createElement(e),e,t,n,1)},createHTML:function(e,t,n){var r="",i;r+="<"+e;for(i in t)t.hasOwnProperty(i)&&null!==t[i]&&(r+=" "+i+'="'+this.encode(t[i])+'"');return"undefined"!=typeof n?r+">"+n+"":r+" />"},createFragment:function(e){var t,n,r=this.doc,i;for(i=r.createElement("div"),t=r.createDocumentFragment(),e&&(i.innerHTML=e);n=i.firstChild;)t.appendChild(n);return t},remove:function(e,t){return this.run(e,function(e){var n,r=e.parentNode;if(!r)return null;if(t)for(;n=e.firstChild;)!v||3!==n.nodeType||n.nodeValue?r.insertBefore(n,e):e.removeChild(n);return r.removeChild(e)})},setStyle:function(e,t,n){return this.run(e,function(e){var r=this,i,o;if(t)if("string"==typeof t){i=e.style,t=t.replace(/-(\D)/g,function(e,t){return t.toUpperCase()}),"number"!=typeof n||C[t]||(n+="px"),"opacity"===t&&e.runtimeStyle&&"undefined"==typeof e.runtimeStyle.opacity&&(i.filter=""===n?"":"alpha(opacity="+100*n+")"),"float"==t&&(t="cssFloat"in e.style?"cssFloat":"styleFloat");try{i[t]=n}catch(a){}r.settings.update_styles&&e.removeAttribute("data-mce-style")}else for(o in t)r.setStyle(e,o,t[o])})},getStyle:function(e,n,r){if(e=this.get(e)){if(this.doc.defaultView&&r){n=n.replace(/[A-Z]/g,function(e){return"-"+e});try{return this.doc.defaultView.getComputedStyle(e,null).getPropertyValue(n)}catch(i){return null}}return n=n.replace(/-(\D)/g,function(e,t){return t.toUpperCase()}),"float"==n&&(n=v?"styleFloat":"cssFloat"),e.currentStyle&&r?e.currentStyle[n]:e.style?e.style[n]:t}},setStyles:function(e,t){this.setStyle(e,t)},css:function(e,t,n){this.setStyle(e,t,n)},removeAllAttribs:function(e){return this.run(e,function(e){var t,n=e.attributes;for(t=n.length-1;t>=0;t--)e.removeAttributeNode(n.item(t))})},setAttrib:function(e,t,n){var r=this;if(e&&t)return this.run(e,function(e){var i=r.settings,o=e.getAttribute(t);if(null!==n)switch(t){case"style":if(!f(n,"string"))return void d(n,function(t,n){r.setStyle(e,n,t)});i.keep_values&&(n?e.setAttribute("data-mce-style",n,2):e.removeAttribute("data-mce-style",2)),e.style.cssText=n;break;case"class":e.className=n||"";break;case"src":case"href":i.keep_values&&(i.url_converter&&(n=i.url_converter.call(i.url_converter_scope||r,n,t,e)),r.setAttrib(e,"data-mce-"+t,n,2));break;case"shape":e.setAttribute("data-mce-style",n)}f(n)&&null!==n&&0!==n.length?e.setAttribute(t,""+n,2):e.removeAttribute(t,2),o!=n&&i.onSetAttrib&&i.onSetAttrib({attrElm:e,attrName:t,attrValue:n})})},setAttribs:function(e,t){var n=this;return this.run(e,function(e){d(t,function(t,r){n.setAttrib(e,r,t)})})},getAttrib:function(e,t,n){var r,i=this,o;if(e=i.get(e),!e||1!==e.nodeType)return n===o?!1:n;if(f(n)||(n=""),/^(src|href|style|coords|shape)$/.test(t)&&(r=e.getAttribute("data-mce-"+t)))return r;if(v&&i.props[t]&&(r=e[i.props[t]],r=r&&r.nodeValue?r.nodeValue:r),r||(r=e.getAttribute(t,2)),/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(t))return e[i.props[t]]===!0&&""===r?t:r?t:"";if("FORM"===e.nodeName&&e.getAttributeNode(t))return e.getAttributeNode(t).nodeValue;if("style"===t&&(r=r||e.style.cssText,r&&(r=i.serializeStyle(i.parseStyle(r),e.nodeName),i.settings.keep_values&&e.setAttribute("data-mce-style",r))),g&&"class"===t&&r&&(r=r.replace(/(apple|webkit)\-[a-z\-]+/gi,"")),v)switch(t){case"rowspan":case"colspan":1===r&&(r="");break;case"size":("+0"===r||20===r||0===r)&&(r="");break;case"width":case"height":case"vspace":case"checked":case"disabled":case"readonly":0===r&&(r="");break;case"hspace":-1===r&&(r="");break;case"maxlength":case"tabindex":(32768===r||2147483647===r||"32768"===r)&&(r="");break;case"multiple":case"compact":case"noshade":case"nowrap":return 65535===r?t:n;case"shape":r=r.toLowerCase();break;default:0===t.indexOf("on")&&r&&(r=(""+r).replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/,"$1"))}return r!==o&&null!==r&&""!==r?""+r:n},getPos:function(e,t){var n=this,r=0,i=0,o,a=n.doc,s;if(e=n.get(e),t=t||a.body,e){if(t===a.body&&e.getBoundingClientRect)return s=e.getBoundingClientRect(),t=n.boxModel?a.documentElement:a.body,r=s.left+(a.documentElement.scrollLeft||a.body.scrollLeft)-t.clientLeft,i=s.top+(a.documentElement.scrollTop||a.body.scrollTop)-t.clientTop,{x:r,y:i};for(o=e;o&&o!=t&&o.nodeType;)r+=o.offsetLeft||0,i+=o.offsetTop||0,o=o.offsetParent;for(o=e.parentNode;o&&o!=t&&o.nodeType;)r-=o.scrollLeft||0,i-=o.scrollTop||0,o=o.parentNode}return{x:r,y:i}},parseStyle:function(e){return this.styles.parse(e)},serializeStyle:function(e,t){return this.styles.serialize(e,t)},addStyle:function(e){var t=this,n=t.doc,r,i;if(t!==u.DOM&&n===document){var o=u.DOM.addedStyles;if(o=o||[],o[e])return;o[e]=!0,u.DOM.addedStyles=o}i=n.getElementById("mceDefaultStyles"),i||(i=n.createElement("style"),i.id="mceDefaultStyles",i.type="text/css",r=n.getElementsByTagName("head")[0],r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i)),i.styleSheet?i.styleSheet.cssText+=e:i.appendChild(n.createTextNode(e))},loadCSS:function(e){var t=this,n=t.doc,r;return t!==u.DOM&&n===document?void u.DOM.loadCSS(e):(e||(e=""),r=n.getElementsByTagName("head")[0],void d(e.split(","),function(e){var i;t.files[e]||(t.files[e]=!0,i=t.create("link",{rel:"stylesheet",href:e}),v&&n.documentMode&&n.recalc&&(i.onload=function(){n.recalc&&n.recalc(),i.onload=null}),r.appendChild(i))}))},addClass:function(e,t){return this.run(e,function(e){var n;return t?this.hasClass(e,t)?e.className:(n=this.removeClass(e,t),e.className=n=(""!==n?n+" ":"")+t,n):0})},removeClass:function(e,t){var n=this,r;return n.run(e,function(e){var i;return n.hasClass(e,t)?(r||(r=new RegExp("(^|\\s+)"+t+"(\\s+|$)","g")),i=e.className.replace(r," "),i=m(" "!=i?i:""),e.className=i,i||(e.removeAttribute("class"),e.removeAttribute("className")),i):e.className})},hasClass:function(e,t){return e=this.get(e),e&&t?-1!==(" "+e.className+" ").indexOf(" "+t+" "):!1},toggleClass:function(e,n,r){r=r===t?!this.hasClass(e,n):r,this.hasClass(e,n)!==r&&(r?this.addClass(e,n):this.removeClass(e,n))},show:function(e){return this.setStyle(e,"display","block")},hide:function(e){return this.setStyle(e,"display","none")},isHidden:function(e){return e=this.get(e),!e||"none"==e.style.display||"none"==this.getStyle(e,"display")},uniqueId:function(e){return(e?e:"mce_")+this.counter++},setHTML:function(e,t){var n=this;return n.run(e,function(e){if(v){for(;e.firstChild;)e.removeChild(e.firstChild);try{e.innerHTML="
          "+t,e.removeChild(e.firstChild)}catch(r){var i=n.create("div");i.innerHTML="
          "+t,d(p(i.childNodes),function(t,n){n&&e.canHaveHTML&&e.appendChild(t)})}}else e.innerHTML=t;return t})},getOuterHTML:function(e){var t,n=this;return(e=n.get(e))?1===e.nodeType&&n.hasOuterHTML?e.outerHTML:(t=(e.ownerDocument||n.doc).createElement("body"),t.appendChild(e.cloneNode(!0)),t.innerHTML):null},setOuterHTML:function(e,t,n){var r=this;return r.run(e,function(e){function i(){var i,o;for(o=n.createElement("body"),o.innerHTML=t,i=o.lastChild;i;)r.insertAfter(i.cloneNode(!0),e),i=i.previousSibling;r.remove(e)}if(1==e.nodeType)if(n=n||e.ownerDocument||r.doc,v)try{1==e.nodeType&&r.hasOuterHTML?e.outerHTML=t:i()}catch(o){i()}else i()})},decode:a.decode,encode:a.encodeAllRaw,insertAfter:function(e,t){return t=this.get(t),this.run(e,function(e){var n,r;return n=t.parentNode,r=t.nextSibling,r?n.insertBefore(e,r):n.appendChild(e),e})},replace:function(e,t,n){var r=this;return r.run(t,function(t){return f(t,"array")&&(e=e.cloneNode(!0)),n&&d(p(t.childNodes),function(t){e.appendChild(t)}),t.parentNode.replaceChild(e,t)})},rename:function(e,t){var n=this,r;return e.nodeName!=t.toUpperCase()&&(r=n.create(t),d(n.getAttribs(e),function(t){n.setAttrib(r,t.nodeName,n.getAttrib(e,t.nodeName))}),n.replace(r,e,1)),r||e},findCommonAncestor:function(e,t){for(var n=e,r;n;){for(r=t;r&&n!=r;)r=r.parentNode;if(n==r)break;n=n.parentNode}return!n&&e.ownerDocument?e.ownerDocument.documentElement:n},toHex:function(e){return this.styles.toHex(l.trim(e))},run:function(e,t,n){var r=this,i;return"string"==typeof e&&(e=r.get(e)),e?(n=n||this,e.nodeType||!e.length&&0!==e.length?t.call(n,e):(i=[],d(e,function(e,o){e&&("string"==typeof e&&(e=r.get(e)),i.push(t.call(n,e,o)))}),i)):!1},getAttribs:function(e){var t;if(e=this.get(e),!e)return[];if(v){if(t=[],"OBJECT"==e.nodeName)return e.attributes;"OPTION"===e.nodeName&&this.getAttrib(e,"selected")&&t.push({specified:1,nodeName:"selected"});var n=/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi;return e.cloneNode(!1).outerHTML.replace(n,"").replace(/[\w:\-]+/gi,function(e){t.push({specified:1,nodeName:e})}),t}return e.attributes},isEmpty:function(e,t){var n=this,r,o,a,s,l,c=0;if(e=e.firstChild){s=new i(e,e.parentNode),t=t||n.schema?n.schema.getNonEmptyElements():null;do{if(a=e.nodeType,1===a){if(e.getAttribute("data-mce-bogus"))continue;if(l=e.nodeName.toLowerCase(),t&&t[l]){if("br"===l){c++;continue}return!1}for(o=n.getAttribs(e),r=e.attributes.length;r--;)if(l=e.attributes[r].nodeName,"name"===l||"data-mce-bookmark"===l)return!1}if(8==a)return!1;if(3===a&&!b.test(e.nodeValue))return!1}while(e=s.next())}return 1>=c},createRng:function(){var e=this.doc;return e.createRange?e.createRange():new o(this)},nodeIndex:function(e,t){var n=0,r,i,o;if(e)for(r=e.nodeType,e=e.previousSibling,i=e;e;e=e.previousSibling)o=e.nodeType,(!t||3!=o||o!=r&&e.nodeValue.length)&&(n++,r=o);return n},split:function(e,t,n){function r(e){function t(e){var t=e.previousSibling&&"SPAN"==e.previousSibling.nodeName,n=e.nextSibling&&"SPAN"==e.nextSibling.nodeName;return t&&n}var n,o=e.childNodes,a=e.nodeType;if(1!=a||"bookmark"!=e.getAttribute("data-mce-type")){for(n=o.length-1;n>=0;n--)r(o[n]);if(9!=a){if(3==a&&e.nodeValue.length>0){var s=m(e.nodeValue).length;if(!i.isBlock(e.parentNode)||s>0||0===s&&t(e))return}else if(1==a&&(o=e.childNodes,1==o.length&&o[0]&&1==o[0].nodeType&&"bookmark"==o[0].getAttribute("data-mce-type")&&e.parentNode.insertBefore(o[0],e),o.length||/^(br|hr|input|img)$/i.test(e.nodeName)))return;i.remove(e)}return e}}var i=this,o=i.createRng(),a,s,l;return e&&t?(o.setStart(e.parentNode,i.nodeIndex(e)),o.setEnd(t.parentNode,i.nodeIndex(t)),a=o.extractContents(),o=i.createRng(),o.setStart(t.parentNode,i.nodeIndex(t)+1),o.setEnd(e.parentNode,i.nodeIndex(e)+1),s=o.extractContents(),l=e.parentNode,l.insertBefore(r(a),e),n?l.replaceChild(n,t):l.insertBefore(t,e),l.insertBefore(r(s),e),i.remove(e),n||t):void 0},bind:function(e,t,n,r){var i=this;if(l.isArray(e)){for(var o=e.length;o--;)e[o]=i.bind(e[o],t,n,r);return e}return!i.settings.collect||e!==i.doc&&e!==i.win||i.boundEvents.push([e,t,n,r]),i.events.bind(e,t,n,r||i)},unbind:function(e,t,n){var r=this,i;if(l.isArray(e)){for(i=e.length;i--;)e[i]=r.unbind(e[i],t,n);return e}if(r.boundEvents&&(e===r.doc||e===r.win))for(i=r.boundEvents.length;i--;){var o=r.boundEvents[i];e!=o[0]||t&&t!=o[1]||n&&n!=o[2]||this.events.unbind(o[0],o[1],o[2])}return this.events.unbind(e,t,n)},fire:function(e,t,n){return this.events.fire(e,t,n)},getContentEditable:function(e){var t;return 1!=e.nodeType?null:(t=e.getAttribute("data-mce-contenteditable"),t&&"inherit"!==t?t:"inherit"!==e.contentEditable?e.contentEditable:null)},destroy:function(){var t=this;if(t.boundEvents){for(var n=t.boundEvents.length;n--;){var r=t.boundEvents[n];this.events.unbind(r[0],r[1],r[2])}t.boundEvents=null}e.setDocument&&e.setDocument(),t.win=t.doc=t.root=t.events=t.frag=null},dumpRng:function(e){return"startContainer: "+e.startContainer.nodeName+", startOffset: "+e.startOffset+", endContainer: "+e.endContainer.nodeName+", endOffset: "+e.endOffset},_findSib:function(e,t,n){var r=this,i=t;if(e)for("string"==typeof i&&(i=function(e){return r.is(e,t)}),e=e[n];e;e=e[n])if(i(e))return e;return null}},u.DOM=new u(document),u}),r(b,[y,p],function(e,t){function n(){function e(e,t){function n(){o.remove(s),a&&(a.onreadystatechange=a.onload=a=null),t() -}function i(){"undefined"!=typeof console&&console.log&&console.log("Failed to load: "+e)}var o=r,a,s;s=o.uniqueId(),a=document.createElement("script"),a.id=s,a.type="text/javascript",a.src=e,"onreadystatechange"in a?a.onreadystatechange=function(){/loaded|complete/.test(a.readyState)&&n()}:a.onload=n,a.onerror=i,(document.getElementsByTagName("head")[0]||document.body).appendChild(a)}var t=0,n=1,a=2,s={},l=[],c={},u=[],d=0,f;this.isDone=function(e){return s[e]==a},this.markDone=function(e){s[e]=a},this.add=this.load=function(e,n,r){var i=s[e];i==f&&(l.push(e),s[e]=t),n&&(c[e]||(c[e]=[]),c[e].push({func:n,scope:r||this}))},this.loadQueue=function(e,t){this.loadScripts(l,e,t)},this.loadScripts=function(t,r,l){function p(e){i(c[e],function(e){e.func.call(e.scope)}),c[e]=f}var m;u.push({func:r,scope:l||this}),(m=function(){var r=o(t);t.length=0,i(r,function(t){return s[t]==a?void p(t):void(s[t]!=n&&(s[t]=n,d++,e(t,function(){s[t]=a,d--,p(t),m()})))}),d||(i(u,function(e){e.func.call(e.scope)}),u.length=0)})()}}var r=e.DOM,i=t.each,o=t.grep;return n.ScriptLoader=new n,n}),r(C,[b,p],function(e,n){function r(){var e=this;e.items=[],e.urls={},e.lookup={}}var i=n.each;return r.prototype={get:function(e){return this.lookup[e]?this.lookup[e].instance:t},dependencies:function(e){var t;return this.lookup[e]&&(t=this.lookup[e].dependencies),t||[]},requireLangPack:function(t,n){if(r.language&&r.languageLoad!==!1){if(n&&new RegExp("([, ]|\\b)"+r.language+"([, ]|\\b)").test(n)===!1)return;e.ScriptLoader.add(this.urls[t]+"/langs/"+r.language+".js")}},add:function(e,t,n){return this.items.push(t),this.lookup[e]={instance:t,dependencies:n},t},createUrl:function(e,t){return"object"==typeof t?t:{prefix:e.prefix,resource:t,suffix:e.suffix}},addComponents:function(t,n){var r=this.urls[t];i(n,function(t){e.ScriptLoader.add(r+"/"+t)})},load:function(n,o,a,s){function l(){var r=c.dependencies(n);i(r,function(e){var n=c.createUrl(o,e);c.load(n.resource,n,t,t)}),a&&a.call(s?s:e)}var c=this,u=o;c.urls[n]||("object"==typeof o&&(u=o.prefix+o.resource+o.suffix),0!==u.indexOf("/")&&-1==u.indexOf("://")&&(u=r.baseURL+"/"+u),c.urls[n]=u.substring(0,u.lastIndexOf("/")),c.lookup[n]?l():e.ScriptLoader.add(u,l,s))}},r.PluginManager=new r,r.ThemeManager=new r,r}),r(x,[],function(){function e(e,t,n){var r,i,o=n?"lastChild":"firstChild",a=n?"prev":"next";if(e[o])return e[o];if(e!==t){if(r=e[a])return r;for(i=e.parent;i&&i!==t;i=i.parent)if(r=i[a])return r}}function t(e,t){this.name=e,this.type=t,1===t&&(this.attributes=[],this.attributes.map={})}var n=/^[ \t\r\n]*$/,r={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};return t.prototype={replace:function(e){var t=this;return e.parent&&e.remove(),t.insert(e,t),t.remove(),t},attr:function(e,t){var n=this,r,i,o;if("string"!=typeof e){for(i in e)n.attr(i,e[i]);return n}if(r=n.attributes){if(t!==o){if(null===t){if(e in r.map)for(delete r.map[e],i=r.length;i--;)if(r[i].name===e)return r=r.splice(i,1),n;return n}if(e in r.map){for(i=r.length;i--;)if(r[i].name===e){r[i].value=t;break}}else r.push({name:e,value:t});return r.map[e]=t,n}return r.map[e]}},clone:function(){var e=this,n=new t(e.name,e.type),r,i,o,a,s;if(o=e.attributes){for(s=[],s.map={},r=0,i=o.length;i>r;r++)a=o[r],"id"!==a.name&&(s[s.length]={name:a.name,value:a.value},s.map[a.name]=a.value);n.attributes=s}return n.value=e.value,n.shortEnded=e.shortEnded,n},wrap:function(e){var t=this;return t.parent.insert(e,t),e.append(t),t},unwrap:function(){var e=this,t,n;for(t=e.firstChild;t;)n=t.next,e.insert(t,e,!0),t=n;e.remove()},remove:function(){var e=this,t=e.parent,n=e.next,r=e.prev;return t&&(t.firstChild===e?(t.firstChild=n,n&&(n.prev=null)):r.next=n,t.lastChild===e?(t.lastChild=r,r&&(r.next=null)):n.prev=r,e.parent=e.next=e.prev=null),e},append:function(e){var t=this,n;return e.parent&&e.remove(),n=t.lastChild,n?(n.next=e,e.prev=n,t.lastChild=e):t.lastChild=t.firstChild=e,e.parent=t,e},insert:function(e,t,n){var r;return e.parent&&e.remove(),r=t.parent||this,n?(t===r.firstChild?r.firstChild=e:t.prev.next=e,e.prev=t.prev,e.next=t,t.prev=e):(t===r.lastChild?r.lastChild=e:t.next.prev=e,e.next=t.next,e.prev=t,t.next=e),e.parent=r,e},getAll:function(t){var n=this,r,i=[];for(r=n.firstChild;r;r=e(r,n))r.name===t&&i.push(r);return i},empty:function(){var t=this,n,r,i;if(t.firstChild){for(n=[],i=t.firstChild;i;i=e(i,t))n.push(i);for(r=n.length;r--;)i=n[r],i.parent=i.firstChild=i.lastChild=i.next=i.prev=null}return t.firstChild=t.lastChild=null,t},isEmpty:function(t){var r=this,i=r.firstChild,o,a;if(i)do{if(1===i.type){if(i.attributes.map["data-mce-bogus"])continue;if(t[i.name])return!1;for(o=i.attributes.length;o--;)if(a=i.attributes[o].name,"name"===a||0===a.indexOf("data-mce-"))return!1}if(8===i.type)return!1;if(3===i.type&&!n.test(i.value))return!1}while(i=e(i,r));return!0},walk:function(t){return e(this,null,t)}},t.create=function(e,n){var i,o;if(i=new t(e,r[e]||1),n)for(o in n)i.attr(o,n[o]);return i},t}),r(w,[p],function(e){function t(e,t){return e?e.split(t||" "):[]}function n(e){function n(e,n,r){function i(e){var t={},n,r;for(n=0,r=e.length;r>n;n++)t[e[n]]={};return t}var o,l,c,u=arguments;for(r=r||[],n=n||"","string"==typeof r&&(r=t(r)),l=3;lo;o++)i.attributes[n[o]]={},i.attributesOrder.push(n[o])}var a={},s,l,c,u,d,f,p;return r[e]?r[e]:(s=t("id accesskey class dir lang style tabindex title"),l=t("onabort onblur oncancel oncanplay oncanplaythrough onchange onclick onclose oncontextmenu oncuechange ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart onmousedown onmousemove onmouseout onmouseover onmouseup onmousewheel onpause onplay onplaying onprogress onratechange onreset onscroll onseeked onseeking onseeking onselect onshow onstalled onsubmit onsuspend ontimeupdate onvolumechange onwaiting"),c=t("address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul"),u=t("a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd label map noscript object q s samp script select small span strong sub sup textarea u var #text #comment"),"html4"!=e&&(s.push.apply(s,t("contenteditable contextmenu draggable dropzone hidden spellcheck translate")),c.push.apply(c,t("article aside details dialog figure header footer hgroup section nav")),u.push.apply(u,t("audio canvas command datalist mark meter output progress time wbr video ruby bdi keygen"))),"html5-strict"!=e&&(s.push("xml:lang"),p=t("acronym applet basefont big font strike tt"),u.push.apply(u,p),o(p,function(e){n(e,"",u)}),f=t("center dir isindex noframes"),c.push.apply(c,f),d=[].concat(c,u),o(f,function(e){n(e,"",d)})),d=d||[].concat(c,u),n("html","manifest","head body"),n("head","","base command link meta noscript script style title"),n("title hr noscript br"),n("base","href target"),n("link","href rel media hreflang type sizes hreflang"),n("meta","name http-equiv content charset"),n("style","media type scoped"),n("script","src async defer type charset"),n("body","onafterprint onbeforeprint onbeforeunload onblur onerror onfocus onhashchange onload onmessage onoffline ononline onpagehide onpageshow onpopstate onresize onscroll onstorage onunload",d),n("address dt dd div caption","",d),n("h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn","",u),n("blockquote","cite",d),n("ol","reversed start type","li"),n("ul","","li"),n("li","value",d),n("dl","","dt dd"),n("a","href target rel media hreflang type",u),n("q","cite",u),n("ins del","cite datetime",d),n("img","src alt usemap ismap width height"),n("iframe","src name width height",d),n("embed","src type width height"),n("object","data type typemustmatch name usemap form width height",d,"param"),n("param","name value"),n("map","name",d,"area"),n("area","alt coords shape href target rel media hreflang type"),n("table","border","caption colgroup thead tfoot tbody tr"+("html4"==e?" col":"")),n("colgroup","span","col"),n("col","span"),n("tbody thead tfoot","","tr"),n("tr","","td th"),n("td","colspan rowspan headers",d),n("th","colspan rowspan headers scope abbr",d),n("form","accept-charset action autocomplete enctype method name novalidate target",d),n("fieldset","disabled form name",d,"legend"),n("label","form for",u),n("input","accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate formtarget height list max maxlength min multiple name pattern readonly required size src step type value width"),n("button","disabled form formaction formenctype formmethod formnovalidate formtarget name type value","html4"==e?d:u),n("select","disabled form multiple name required size","option optgroup"),n("optgroup","disabled label","option"),n("option","disabled label selected value"),n("textarea","cols dirname disabled form maxlength name readonly required rows wrap"),n("menu","type label",d,"li"),n("noscript","",d),"html4"!=e&&(n("wbr"),n("ruby","",u,"rt rp"),n("figcaption","",d),n("mark rt rp summary bdi","",u),n("canvas","width height",d),n("video","src crossorigin poster preload autoplay mediagroup loop muted controls width height",d,"track source"),n("audio","src crossorigin preload autoplay mediagroup loop muted controls",d,"track source"),n("source","src type media"),n("track","kind src srclang label default"),n("datalist","",u,"option"),n("article section nav aside header footer","",d),n("hgroup","","h1 h2 h3 h4 h5 h6"),n("figure","",d,"figcaption"),n("time","datetime",u),n("dialog","open",d),n("command","type label icon disabled checked radiogroup command"),n("output","for form name",u),n("progress","value max",u),n("meter","value min max low high optimum",u),n("details","open",d,"summary"),n("keygen","autofocus challenge disabled form keytype name")),"html5-strict"!=e&&(i("script","language xml:space"),i("style","xml:space"),i("object","declare classid codebase codetype archive standby align border hspace vspace"),i("param","valuetype type"),i("a","charset name rev shape coords"),i("br","clear"),i("applet","codebase archive code object alt name width height align hspace vspace"),i("img","name longdesc align border hspace vspace"),i("iframe","longdesc frameborder marginwidth marginheight scrolling align"),i("font basefont","size color face"),i("input","usemap align"),i("select","onchange"),i("textarea"),i("h1 h2 h3 h4 h5 h6 div p legend caption","align"),i("ul","type compact"),i("li","type"),i("ol dl menu dir","compact"),i("pre","width xml:space"),i("hr","align noshade size width"),i("isindex","prompt"),i("table","summary width frame rules cellspacing cellpadding align bgcolor"),i("col","width align char charoff valign"),i("colgroup","width align char charoff valign"),i("thead","align char charoff valign"),i("tr","align char charoff valign bgcolor"),i("th","axis align char charoff valign nowrap bgcolor width height"),i("form","accept"),i("td","abbr axis scope align char charoff valign nowrap bgcolor width height"),i("tfoot","align char charoff valign"),i("tbody","align char charoff valign"),i("area","nohref"),i("body","background bgcolor text link vlink alink")),"html4"!=e&&(i("input button select textarea","autofocus"),i("input textarea","placeholder"),i("a","download"),i("link script img","crossorigin"),i("iframe","srcdoc sandbox seamless allowfullscreen")),o(t("a form meter progress dfn"),function(e){a[e]&&delete a[e].children[e]}),delete a.caption.children.table,r[e]=a,a)}var r={},i=e.makeMap,o=e.each,a=e.extend,s=e.explode,l=e.inArray;return function(e){function c(t,n,o){var s=e[t];return s?s=i(s,",",i(s.toUpperCase()," ")):(s=r[t],s||(s=i(n," ",i(n.toUpperCase()," ")),s=a(s,o),r[t]=s)),s}function u(e){return new RegExp("^"+e.replace(/([?+*])/g,".$1")+"$")}function d(e){var n,r,o,a,s,c,d,f,p,m,h,g,y,C,x,w,_,N,E,S=/^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)\])?$/,k=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,T=/[*?+]/;if(e)for(e=t(e,","),v["@"]&&(w=v["@"].attributes,_=v["@"].attributesOrder),n=0,r=e.length;r>n;n++)if(s=S.exec(e[n])){if(C=s[1],p=s[2],x=s[3],f=s[5],g={},y=[],c={attributes:g,attributesOrder:y},"#"===C&&(c.paddEmpty=!0),"-"===C&&(c.removeEmpty=!0),"!"===s[4]&&(c.removeEmptyAttrs=!0),w){for(N in w)g[N]=w[N];y.push.apply(y,_)}if(f)for(f=t(f,"|"),o=0,a=f.length;a>o;o++)if(s=k.exec(f[o])){if(d={},h=s[1],m=s[2].replace(/::/g,":"),C=s[3],E=s[4],"!"===h&&(c.attributesRequired=c.attributesRequired||[],c.attributesRequired.push(m),d.required=!0),"-"===h){delete g[m],y.splice(l(y,m),1);continue}C&&("="===C&&(c.attributesDefault=c.attributesDefault||[],c.attributesDefault.push({name:m,value:E}),d.defaultValue=E),":"===C&&(c.attributesForced=c.attributesForced||[],c.attributesForced.push({name:m,value:E}),d.forcedValue=E),"<"===C&&(d.validValues=i(E,"?"))),T.test(m)?(c.attributePatterns=c.attributePatterns||[],d.pattern=u(m),c.attributePatterns.push(d)):(g[m]||y.push(m),g[m]=d)}w||"@"!=p||(w=g,_=y),x&&(c.outputName=p,v[x]=c),T.test(p)?(c.pattern=u(p),b.push(c)):v[p]=c}}function f(e){v={},b=[],d(e),o(x,function(e,t){y[t]=e.children})}function p(e){var n=/^(~)?(.+)$/;e&&o(t(e,","),function(e){var t=n.exec(e),r="~"===t[1],i=r?"span":"div",s=t[2];if(y[s]=y[i],R[s]=i,r||(S[s.toUpperCase()]={},S[s]={}),!v[s]){var l=v[i];l=a({},l),delete l.removeEmptyAttrs,delete l.removeEmpty,v[s]=l}o(y,function(e){e[i]&&(e[s]=e[i])})})}function m(e){var n=/^([+\-]?)(\w+)\[([^\]]+)\]$/;e&&o(t(e,","),function(e){var r=n.exec(e),i,a;r&&(a=r[1],i=a?y[r[2]]:y[r[2]]={"#comment":{}},i=y[r[2]],o(t(r[3],"|"),function(e){"-"===a?delete i[e]:i[e]={}}))})}function h(e){var t=v[e],n;if(t)return t;for(n=b.length;n--;)if(t=b[n],t.pattern.test(e))return t}var g=this,v={},y={},b=[],C,x,w,_,N,E,S,k,T,R={},A={};e=e||{},x=n(e.schema),e.verify_html===!1&&(e.valid_elements="*[*]"),e.valid_styles&&(C={},o(e.valid_styles,function(e,t){C[t]=s(e)})),w=c("whitespace_elements","pre script noscript style textarea video audio iframe object"),_=c("self_closing_elements","colgroup dd dt li option p td tfoot th thead tr"),N=c("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr track"),E=c("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls"),k=c("non_empty_elements","td th iframe video audio object script",N),T=c("text_block_elements","h1 h2 h3 h4 h5 h6 p div address pre form blockquote center dir fieldset header footer article section hgroup aside nav figure"),S=c("block_elements","hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isindex option datalist select optgroup",T),o((e.special||"script noscript style textarea").split(" "),function(e){A[e]=new RegExp("]*>","gi")}),e.valid_elements?f(e.valid_elements):(o(x,function(e,t){v[t]={attributes:e.attributes,attributesOrder:e.attributesOrder},y[t]=e.children}),"html5"!=e.schema&&o(t("strong/b em/i"),function(e){e=t(e,"/"),v[e[1]].outputName=e[0]}),v.img.attributesDefault=[{name:"alt",value:""}],o(t("ol ul sub sup blockquote span font a table tbody tr strong em b i"),function(e){v[e]&&(v[e].removeEmpty=!0)}),o(t("p h1 h2 h3 h4 h5 h6 th td pre div address caption"),function(e){v[e].paddEmpty=!0}),o(t("span"),function(e){v[e].removeEmptyAttrs=!0})),p(e.custom_elements),m(e.valid_children),d(e.extended_valid_elements),m("+ol[ul|ol],+ul[ul|ol]"),e.invalid_elements&&o(s(e.invalid_elements),function(e){v[e]&&delete v[e]}),h("span")||d("span[!data-mce-type|*]"),g.children=y,g.styles=C,g.getBoolAttrs=function(){return E},g.getBlockElements=function(){return S},g.getTextBlockElements=function(){return T},g.getShortEndedElements=function(){return N},g.getSelfClosingElements=function(){return _},g.getNonEmptyElements=function(){return k},g.getWhiteSpaceElements=function(){return w},g.getSpecialElements=function(){return A},g.isValidChild=function(e,t){var n=y[e];return!(!n||!n[t])},g.isValid=function(e,t){var n,r,i=h(e);if(i){if(!t)return!0;if(i.attributes[t])return!0;if(n=i.attributePatterns)for(r=n.length;r--;)if(n[r].pattern.test(e))return!0}return!1},g.getElementRule=h,g.getCustomElements=function(){return R},g.addValidElements=d,g.setValidElements=f,g.addCustomElements=p,g.addValidChildren=m,g.elements=v}}),r(_,[w,h,p],function(e,t,n){var r=n.each;return function(i,o){var a=this,s=function(){};i=i||{},a.schema=o=o||new e,i.fix_self_closing!==!1&&(i.fix_self_closing=!0),r("comment cdata text start end pi doctype".split(" "),function(e){e&&(a[e]=i[e]||s)}),a.parse=function(e){function r(e){var t,n;for(t=f.length;t--&&f[t].name!==e;);if(t>=0){for(n=f.length-1;n>=t;n--)e=f[n],e.valid&&s.end(e.name);f.length=t}}function a(e,t,n,r,o){var a,s,l=/[\s\u0000-\u001F]+/g;if(t=t.toLowerCase(),n=t in C?t:F(n||r||o||""),w&&!v&&0!==t.indexOf("data-")){if(a=k[t],!a&&T){for(s=T.length;s--&&(a=T[s],!a.pattern.test(t)););-1===s&&(a=null)}if(!a)return;if(a.validValues&&!(n in a.validValues))return}if(W[t]&&!i.allow_script_urls){var c=n.replace(l,"");try{if(c=decodeURIComponent(c),V.test(c))return}catch(u){if(c=unescape(c),V.test(c))return}}p.map[t]=n,p.push({name:t,value:n})}var s=this,l,c=0,u,d,f=[],p,m,h,g,v,y,b,C,x,w,_,N,E,S,k,T,R,A,B,D,L,H,M,P,O,I=0,F=t.decode,z,W=n.makeMap("src,href"),V=/(java|vb)script:/i;for(H=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([^>]+)>)|(?:([A-Za-z0-9\\-\\:\\.]+)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g"),M=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g,b=o.getShortEndedElements(),L=i.self_closing_elements||o.getSelfClosingElements(),C=o.getBoolAttrs(),w=i.validate,y=i.remove_internals,z=i.fix_self_closing,P=o.getSpecialElements();l=H.exec(e);){if(c0&&f[f.length-1].name===u&&r(u),!w||(_=o.getElementRule(u))){if(N=!0,w&&(k=_.attributes,T=_.attributePatterns),(S=l[8])?(v=-1!==S.indexOf("data-mce-type"),v&&y&&(N=!1),p=[],p.map={},S.replace(M,a)):(p=[],p.map={}),w&&!v){if(R=_.attributesRequired,A=_.attributesDefault,B=_.attributesForced,D=_.removeEmptyAttrs,D&&!p.length&&(N=!1),B)for(m=B.length;m--;)E=B[m],g=E.name,O=E.value,"{$uid}"===O&&(O="mce_"+I++),p.map[g]=O,p.push({name:g,value:O});if(A)for(m=A.length;m--;)E=A[m],g=E.name,g in p.map||(O=E.value,"{$uid}"===O&&(O="mce_"+I++),p.map[g]=O,p.push({name:g,value:O}));if(R){for(m=R.length;m--&&!(R[m]in p.map););-1===m&&(N=!1)}p.map["data-mce-bogus"]&&(N=!1)}N&&s.start(u,p,x)}else N=!1;if(d=P[u]){d.lastIndex=c=l.index+l[0].length,(l=d.exec(e))?(N&&(h=e.substr(c,l.index-c)),c=l.index+l[0].length):(h=e.substr(c),c=e.length),N&&(h.length>0&&s.text(h,!0),s.end(u)),H.lastIndex=c;continue}x||(S&&S.indexOf("/")==S.length-1?N&&s.end(u):f.push({name:u,valid:N}))}else(u=l[1])?(">"===u.charAt(0)&&(u=" "+u),i.allow_conditional_comments||"[if"!==u.substr(0,3)||(u=" "+u),s.comment(u)):(u=l[2])?s.cdata(u):(u=l[3])?s.doctype(u):(u=l[4])&&s.pi(u,l[5]);c=l.index+l[0].length}for(c=0;m--)u=f[m],u.valid&&s.end(u.name)}}}),r(N,[x,w,_,p],function(e,t,n,r){var i=r.makeMap,o=r.each,a=r.explode,s=r.extend;return function(r,l){function c(t){var n,r,o,a,s,c,d,f,p,m,h,g,v,y;for(h=i("tr,td,th,tbody,thead,tfoot,table"),m=l.getNonEmptyElements(),g=l.getTextBlockElements(),n=0;n1){for(a.reverse(),s=c=u.filterNode(a[0].clone()),p=0;p0?(t.value=n,t=t.prev):(r=t.prev,t.remove(),t=r)}function g(e){var t,n={};for(t in e)"li"!==t&&"p"!=t&&(n[t]=e[t]);return n}var v,y,b,C,x,w,_,N,E,S,k,T,R,A=[],B,D,L,H,M,P,O,I;if(o=o||{},p={},m={},T=s(i("script,style,head,html,body,title,meta,param"),l.getBlockElements()),O=l.getNonEmptyElements(),P=l.children,k=r.validate,I="forced_root_block"in o?o.forced_root_block:r.forced_root_block,M=l.getWhiteSpaceElements(),R=/^[ \t\r\n]+/,D=/[ \t\r\n]+$/,L=/[ \t\r\n]+/g,H=/^[ \t\r\n]+$/,v=new n({validate:k,allow_script_urls:r.allow_script_urls,allow_conditional_comments:r.allow_conditional_comments,self_closing_elements:g(l.getSelfClosingElements()),cdata:function(e){b.append(u("#cdata",4)).value=e},text:function(e,t){var n;B||(e=e.replace(L," "),b.lastChild&&T[b.lastChild.name]&&(e=e.replace(R,""))),0!==e.length&&(n=u("#text",3),n.raw=!!t,b.append(n).value=e)},comment:function(e){b.append(u("#comment",8)).value=e},pi:function(e,t){b.append(u(e,7)).value=t,h(b)},doctype:function(e){var t;t=b.append(u("#doctype",10)),t.value=e,h(b)},start:function(e,t,n){var r,i,o,a,s;if(o=k?l.getElementRule(e):{}){for(r=u(o.outputName||e,1),r.attributes=t,r.shortEnded=n,b.append(r),s=P[b.name],s&&P[r.name]&&!s[r.name]&&A.push(r),i=f.length;i--;)a=f[i].name,a in t.map&&(E=m[a],E?E.push(r):m[a]=[r]);T[e]&&h(r),n||(b=r),!B&&M[e]&&(B=!0)}},end:function(t){var n,r,i,o,a;if(r=k?l.getElementRule(t):{}){if(T[t]&&!B){if(n=b.firstChild,n&&3===n.type)if(i=n.value.replace(R,""),i.length>0)n.value=i,n=n.next;else for(o=n.next,n.remove(),n=o;n&&3===n.type;)i=n.value,o=n.next,(0===i.length||H.test(i))&&(n.remove(),n=o),n=o;if(n=b.lastChild,n&&3===n.type)if(i=n.value.replace(D,""),i.length>0)n.value=i,n=n.prev;else for(o=n.prev,n.remove(),n=o;n&&3===n.type;)i=n.value,o=n.prev,(0===i.length||H.test(i))&&(n.remove(),n=o),n=o}if(B&&M[t]&&(B=!1),(r.removeEmpty||r.paddEmpty)&&b.isEmpty(O))if(r.paddEmpty)b.empty().append(new e("#text","3")).value="\xa0";else if(!b.attributes.map.name&&!b.attributes.map.id)return a=b.parent,b.empty().remove(),void(b=a);b=b.parent}}},l),y=b=new e(o.context||r.root_name,11),v.parse(t),k&&A.length&&(o.context?o.invalid=!0:c(A)),I&&("body"==y.name||o.isRootContent)&&a(),!o.invalid){for(S in p){for(E=d[S],C=p[S],_=C.length;_--;)C[_].parent||C.splice(_,1);for(x=0,w=E.length;w>x;x++)E[x](C,S,o)}for(x=0,w=f.length;w>x;x++)if(E=f[x],E.name in m){for(C=m[E.name],_=C.length;_--;)C[_].parent||C.splice(_,1);for(_=0,N=E.callbacks.length;N>_;_++)E.callbacks[_](C,E.name,o)}}return y},r.remove_trailing_brs&&u.addNodeFilter("br",function(t){var n,r=t.length,i,o=s({},l.getBlockElements()),a=l.getNonEmptyElements(),c,u,d,f,p,m;for(o.body=1,n=0;r>n;n++)if(i=t[n],c=i.parent,o[i.parent.name]&&i===c.lastChild){for(d=i.prev;d;){if(f=d.name,"span"!==f||"bookmark"!==d.attr("data-mce-type")){if("br"!==f)break;if("br"===f){i=null;break}}d=d.prev}i&&(i.remove(),c.isEmpty(a)&&(p=l.getElementRule(c.name),p&&(p.removeEmpty?c.remove():p.paddEmpty&&(c.empty().append(new e("#text",3)).value="\xa0"))))}else{for(u=i;c&&c.firstChild===u&&c.lastChild===u&&(u=c,!o[c.name]);)c=c.parent;u===c&&(m=new e("#text",3),m.value="\xa0",i.replace(m))}}),r.allow_html_in_named_anchor||u.addAttributeFilter("id,name",function(e){for(var t=e.length,n,r,i,o;t--;)if(o=e[t],"a"===o.name&&o.firstChild&&!o.attr("href")){i=o.parent,n=o.lastChild;do r=n.prev,i.insert(n,o),n=r;while(n)}})}}),r(E,[h,p],function(e,t){var n=t.makeMap;return function(t){var r=[],i,o,a,s,l;return t=t||{},i=t.indent,o=n(t.indent_before||""),a=n(t.indent_after||""),s=e.getEncodeFunc(t.entity_encoding||"raw",t.entities),l="html"==t.element_format,{start:function(e,t,n){var c,u,d,f;if(i&&o[e]&&r.length>0&&(f=r[r.length-1],f.length>0&&"\n"!==f&&r.push("\n")),r.push("<",e),t)for(c=0,u=t.length;u>c;c++)d=t[c],r.push(" ",d.name,'="',s(d.value,!0),'"');r[r.length]=!n||l?">":" />",n&&i&&a[e]&&r.length>0&&(f=r[r.length-1],f.length>0&&"\n"!==f&&r.push("\n"))},end:function(e){var t;r.push(""),i&&a[e]&&r.length>0&&(t=r[r.length-1],t.length>0&&"\n"!==t&&r.push("\n"))},text:function(e,t){e.length>0&&(r[r.length]=t?e:s(e))},cdata:function(e){r.push("")},comment:function(e){r.push("")},pi:function(e,t){t?r.push(""):r.push(""),i&&r.push("\n")},doctype:function(e){r.push("",i?"\n":"")},reset:function(){r.length=0},getContent:function(){return r.join("").replace(/\n$/,"")}}}}),r(S,[E,w],function(e,t){return function(n,r){var i=this,o=new e(n);n=n||{},n.validate="validate"in n?n.validate:!0,i.schema=r=r||new t,i.writer=o,i.serialize=function(e){function t(e){var n=i[e.type],s,l,c,u,d,f,p,m,h;if(n)n(e);else{if(s=e.name,l=e.shortEnded,c=e.attributes,a&&c&&c.length>1){for(f=[],f.map={},h=r.getElementRule(e.name),p=0,m=h.attributesOrder.length;m>p;p++)u=h.attributesOrder[p],u in c.map&&(d=c.map[u],f.map[u]=d,f.push({name:u,value:d}));for(p=0,m=c.length;m>p;p++)u=c[p].name,u in f.map||(d=c.map[u],f.map[u]=d,f.push({name:u,value:d}));c=f}if(o.start(e.name,c,l),!l){if(e=e.firstChild)do t(e);while(e=e.next);o.end(s)}}}var i,a;return a=n.validate,i={3:function(e){o.text(e.value,e.raw)},8:function(e){o.comment(e.value)},7:function(e){o.pi(e.name,e.value)},10:function(e){o.doctype(e.value)},4:function(e){o.cdata(e.value)},11:function(e){if(e=e.firstChild)do t(e);while(e=e.next)}},o.reset(),1!=e.type||n.inner?i[11](e):t(e),o.getContent()}}}),r(k,[y,N,h,S,x,w,g,p],function(e,t,n,r,i,o,a,s){var l=s.each,c=s.trim,u=e.DOM;return function(e,i){var s,d,f;return i&&(s=i.dom,d=i.schema),s=s||u,d=d||new o(e),e.entity_encoding=e.entity_encoding||"named",e.remove_trailing_brs="remove_trailing_brs"in e?e.remove_trailing_brs:!0,f=new t(e,d),f.addAttributeFilter("src,href,style",function(t,n){for(var r=t.length,i,o,a="data-mce-"+n,l=e.url_converter,c=e.url_converter_scope,u;r--;)i=t[r],o=i.attributes.map[a],o!==u?(i.attr(n,o.length>0?o:null),i.attr(a,null)):(o=i.attributes.map[n],"style"===n?o=s.serializeStyle(s.parseStyle(o),i.name):l&&(o=l.call(c,o,n,i.name)),i.attr(n,o.length>0?o:null))}),f.addAttributeFilter("class",function(e){for(var t=e.length,n,r;t--;)n=e[t],r=n.attr("class").replace(/(?:^|\s)mce-item-\w+(?!\S)/g,""),n.attr("class",r.length>0?r:null)}),f.addAttributeFilter("data-mce-type",function(e,t,n){for(var r=e.length,i;r--;)i=e[r],"bookmark"!==i.attributes.map["data-mce-type"]||n.cleanup||i.remove()}),f.addAttributeFilter("data-mce-expando",function(e,t){for(var n=e.length;n--;)e[n].attr(t,null)}),f.addNodeFilter("noscript",function(e){for(var t=e.length,r;t--;)r=e[t].firstChild,r&&(r.value=n.decode(r.value))}),f.addNodeFilter("script,style",function(e,t){function n(e){return e.replace(/()/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*(()?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}for(var r=e.length,i,o;r--;)if(i=e[r],o=i.firstChild?i.firstChild.value:"","script"===t){var a=(i.attr("type")||"text/javascript").replace(/^mce\-/,"");i.attr("type","text/javascript"===a?null:a),o.length>0&&(i.firstChild.value="// ")}else o.length>0&&(i.firstChild.value="")}),f.addNodeFilter("#comment",function(e){for(var t=e.length,n;t--;)n=e[t],0===n.value.indexOf("[CDATA[")?(n.name="#cdata",n.type=4,n.value=n.value.replace(/^\[CDATA\[|\]\]$/g,"")):0===n.value.indexOf("mce:protected ")&&(n.name="#text",n.type=3,n.raw=!0,n.value=unescape(n.value).substr(14))}),f.addNodeFilter("xml:namespace,input",function(e,t){for(var n=e.length,r;n--;)r=e[n],7===r.type?r.remove():1===r.type&&("input"!==t||"type"in r.attributes.map||r.attr("type","text"))}),e.fix_list_elements&&f.addNodeFilter("ul,ol",function(e){for(var t=e.length,n,r;t--;)n=e[t],r=n.parent,("ul"===r.name||"ol"===r.name)&&n.prev&&"li"===n.prev.name&&n.prev.append(n)}),f.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style,data-mce-selected",function(e,t){for(var n=e.length;n--;)e[n].attr(t,null)}),{schema:d,addNodeFilter:f.addNodeFilter,addAttributeFilter:f.addAttributeFilter,serialize:function(t,n){var i=this,o,u,p,m,h;return a.ie&&s.select("script,style,select,map").length>0?(h=t.innerHTML,t=t.cloneNode(!1),s.setHTML(t,h)):t=t.cloneNode(!0),o=t.ownerDocument.implementation,o.createHTMLDocument&&(u=o.createHTMLDocument(""),l("BODY"==t.nodeName?t.childNodes:[t],function(e){u.body.appendChild(u.importNode(e,!0))}),t="BODY"!=t.nodeName?u.body.firstChild:u.body,p=s.doc,s.doc=u),n=n||{},n.format=n.format||"html",n.selection&&(n.forced_root_block=""),n.no_events||(n.node=t,i.onPreProcess(n)),m=new r(e,d),n.content=m.serialize(f.parse(c(n.getInner?t.innerHTML:s.getOuterHTML(t)),n)),n.cleanup||(n.content=n.content.replace(/\uFEFF/g,"")),n.no_events||i.onPostProcess(n),p&&(s.doc=p),n.node=null,n.content},addRules:function(e){d.addValidElements(e)},setRules:function(e){d.setValidElements(e)},onPreProcess:function(e){i&&i.fire("PreProcess",e)},onPostProcess:function(e){i&&i.fire("PostProcess",e)}}}}),r(T,[],function(){function e(e){function t(t,n){var r,i=0,o,a,s,l,c,u,d=-1,f;if(r=t.duplicate(),r.collapse(n),f=r.parentElement(),f.ownerDocument===e.dom.doc){for(;"false"===f.contentEditable;)f=f.parentNode;if(!f.hasChildNodes())return{node:f,inside:1};for(s=f.children,o=s.length-1;o>=i;)if(u=Math.floor((i+o)/2),l=s[u],r.moveToElementText(l),d=r.compareEndPoints(n?"StartToStart":"EndToEnd",t),d>0)o=u-1;else{if(!(0>d))return{node:l};i=u+1}if(0>d)for(l?r.collapse(!1):(r.moveToElementText(f),r.collapse(!0),l=f,a=!0),c=0;0!==r.compareEndPoints(n?"StartToStart":"StartToEnd",t)&&0!==r.move("character",1)&&f==r.parentElement();)c++;else for(r.collapse(!0),c=0;0!==r.compareEndPoints(n?"StartToStart":"StartToEnd",t)&&0!==r.move("character",-1)&&f==r.parentElement();)c++; -return{node:l,position:d,offset:c,inside:a}}}function n(){function n(e){var n=t(o,e),r,i,s=0,l,c,u;if(r=n.node,i=n.offset,n.inside&&!r.hasChildNodes())return void a[e?"setStart":"setEnd"](r,0);if(i===c)return void a[e?"setStartBefore":"setEndAfter"](r);if(n.position<0){if(l=n.inside?r.firstChild:r.nextSibling,!l)return void a[e?"setStartAfter":"setEndAfter"](r);if(!i)return void(3==l.nodeType?a[e?"setStart":"setEnd"](l,0):a[e?"setStartBefore":"setEndBefore"](l));for(;l;){if(u=l.nodeValue,s+=u.length,s>=i){r=l,s-=i,s=u.length-s;break}l=l.nextSibling}}else{if(l=r.previousSibling,!l)return a[e?"setStartBefore":"setEndBefore"](r);if(!i)return void(3==r.nodeType?a[e?"setStart":"setEnd"](l,r.nodeValue.length):a[e?"setStartAfter":"setEndAfter"](l));for(;l;){if(s+=l.nodeValue.length,s>=i){r=l,s-=i;break}l=l.previousSibling}}a[e?"setStart":"setEnd"](r,s)}var o=e.getRng(),a=i.createRng(),s,l,c,u,d;if(s=o.item?o.item(0):o.parentElement(),s.ownerDocument!=i.doc)return a;if(l=e.isCollapsed(),o.item)return a.setStart(s.parentNode,i.nodeIndex(s)),a.setEnd(a.startContainer,a.startOffset+1),a;try{n(!0),l||n()}catch(f){if(-2147024809!=f.number)throw f;d=r.getBookmark(2),c=o.duplicate(),c.collapse(!0),s=c.parentElement(),l||(c=o.duplicate(),c.collapse(!1),u=c.parentElement(),u.innerHTML=u.innerHTML),s.innerHTML=s.innerHTML,r.moveToBookmark(d),o=e.getRng(),n(!0),l||n()}return a}var r=this,i=e.dom,o=!1;this.getBookmark=function(n){function r(e){var t,n,r,o,a=[];for(t=e.parentNode,n=i.getRoot().parentNode;t!=n&&9!==t.nodeType;){for(r=t.children,o=r.length;o--;)if(e===r[o]){a.push(o);break}e=t,t=t.parentNode}return a}function o(e){var n;return n=t(a,e),n?{position:n.position,offset:n.offset,indexes:r(n.node),inside:n.inside}:void 0}var a=e.getRng(),s={};return 2===n&&(a.item?s.start={ctrl:!0,indexes:r(a.item(0))}:(s.start=o(!0),e.isCollapsed()||(s.end=o()))),s},this.moveToBookmark=function(e){function t(e){var t,n,r,o;for(t=i.getRoot(),n=e.length-1;n>=0;n--)o=t.children,r=e[n],r<=o.length-1&&(t=o[r]);return t}function n(n){var i=e[n?"start":"end"],a,s,l,c;i&&(a=i.position>0,s=o.createTextRange(),s.moveToElementText(t(i.indexes)),c=i.offset,c!==l?(s.collapse(i.inside||a),s.moveStart("character",a?-c:c)):s.collapse(n),r.setEndPoint(n?"StartToStart":"EndToStart",s),n&&r.collapse(!0))}var r,o=i.doc.body;e.start&&(e.start.ctrl?(r=o.createControlRange(),r.addElement(t(e.start.indexes)),r.select()):(r=o.createTextRange(),n(!0),n(),r.select()))},this.addRange=function(t){function n(e){var t,n,a,d,m;a=i.create("a"),t=e?s:c,n=e?l:u,d=r.duplicate(),(t==f||t==f.documentElement)&&(t=p,n=0),3==t.nodeType?(t.parentNode.insertBefore(a,t),d.moveToElementText(a),d.moveStart("character",n),i.remove(a),r.setEndPoint(e?"StartToStart":"EndToEnd",d)):(m=t.childNodes,m.length?(n>=m.length?i.insertAfter(a,m[m.length-1]):t.insertBefore(a,m[n]),d.moveToElementText(a)):t.canHaveHTML&&(t.innerHTML="",a=t.firstChild,d.moveToElementText(a),d.collapse(o)),r.setEndPoint(e?"StartToStart":"EndToEnd",d),i.remove(a))}var r,a,s,l,c,u,d,f=e.dom.doc,p=f.body,m,h;if(s=t.startContainer,l=t.startOffset,c=t.endContainer,u=t.endOffset,r=p.createTextRange(),s==c&&1==s.nodeType){if(l==u&&!s.hasChildNodes()){if(s.canHaveHTML)return d=s.previousSibling,d&&!d.hasChildNodes()&&i.isBlock(d)?d.innerHTML="":d=null,s.innerHTML="",r.moveToElementText(s.lastChild),r.select(),i.doc.selection.clear(),s.innerHTML="",void(d&&(d.innerHTML=""));l=i.nodeIndex(s),s=s.parentNode}if(l==u-1)try{if(h=s.childNodes[l],a=p.createControlRange(),a.addElement(h),a.select(),m=e.getRng(),m.item&&h===m.item(0))return}catch(g){}}n(!0),n(),r.select()},this.getRangeAt=n}return e}),r(R,[g],function(e){return{BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(e){return e.shiftKey||e.ctrlKey||e.altKey},metaKeyPressed:function(t){return(e.mac?t.metaKey:t.ctrlKey)&&!t.altKey}}}),r(A,[R,p,g],function(e,t,n){return function(r,i){function o(e){return i.settings.object_resizing===!1?!1:/TABLE|IMG|DIV/.test(e.nodeName)?"false"===e.getAttribute("data-mce-resize")?!1:!0:!1}function a(t){var n,r;n=t.screenX-S,r=t.screenY-k,H=n*N[2]+A,M=r*N[3]+B,H=5>H?5:H,M=5>M?5:M,(e.modifierPressed(t)||"IMG"==x.nodeName&&N[2]*N[3]!==0)&&(H=Math.round(M/D),M=Math.round(H*D)),b.setStyles(w,{width:H,height:M}),N[2]<0&&w.clientWidth<=H&&b.setStyle(w,"left",T+(A-H)),N[3]<0&&w.clientHeight<=M&&b.setStyle(w,"top",R+(B-M)),L||(i.fire("ObjectResizeStart",{target:x,width:A,height:B}),L=!0)}function s(){function e(e,t){t&&(x.style[e]||!i.schema.isValid(x.nodeName.toLowerCase(),e)?b.setStyle(x,e,t):b.setAttrib(x,e,t))}L=!1,e("width",H),e("height",M),b.unbind(P,"mousemove",a),b.unbind(P,"mouseup",s),O!=P&&(b.unbind(O,"mousemove",a),b.unbind(O,"mouseup",s)),b.remove(w),I&&"TABLE"!=x.nodeName||l(x),i.fire("ObjectResized",{target:x,width:H,height:M}),i.nodeChanged()}function l(e,t,r){var l,u,d,f,p,m=i.getBody();l=b.getPos(e,m),T=l.x,R=l.y,p=e.getBoundingClientRect(),u=p.width||p.right-p.left,d=p.height||p.bottom-p.top,x!=e&&(h(),x=e,H=M=0),f=i.fire("ObjectSelected",{target:e}),o(e)&&!f.isDefaultPrevented()?C(_,function(e,o){function l(t){S=t.screenX,k=t.screenY,A=x.clientWidth,B=x.clientHeight,D=B/A,N=e,w=x.cloneNode(!0),b.addClass(w,"mce-clonedresizable"),w.contentEditable=!1,w.unSelectabe=!0,b.setStyles(w,{left:T,top:R,margin:0}),w.removeAttribute("data-mce-selected"),i.getBody().appendChild(w),b.bind(P,"mousemove",a),b.bind(P,"mouseup",s),O!=P&&(b.bind(O,"mousemove",a),b.bind(O,"mouseup",s))}var c,f;return t?void(o==t&&l(r)):(c=b.get("mceResizeHandle"+o),c?b.show(c):(f=i.getBody(),c=b.add(f,"div",{id:"mceResizeHandle"+o,"data-mce-bogus":!0,"class":"mce-resizehandle",unselectable:!0,style:"cursor:"+o+"-resize; margin:0; padding:0"}),n.ie&&(c.contentEditable=!1),b.bind(c,"mousedown",function(e){e.stopImmediatePropagation(),e.preventDefault(),l(e)})),void b.setStyles(c,{left:u*e[0]+T-c.offsetWidth/2,top:d*e[1]+R-c.offsetHeight/2}))}):c(),x.setAttribute("data-mce-selected","1")}function c(){var e,t;x&&x.removeAttribute("data-mce-selected");for(e in _)t=b.get("mceResizeHandle"+e),t&&(b.unbind(t),b.remove(t))}function u(e){function t(e,t){if(e)do if(e===t)return!0;while(e=e.parentNode)}var n;return C(b.select("img[data-mce-selected],hr[data-mce-selected]"),function(e){e.removeAttribute("data-mce-selected")}),n="mousedown"==e.type?e.target:r.getNode(),n=b.getParent(n,I?"table":"table,img,hr"),t(n,i.getBody())&&(g(),t(r.getStart(),n)&&t(r.getEnd(),n)&&(!I||n!=r.getStart()&&"IMG"!==r.getStart().nodeName))?void l(n):void c()}function d(e,t,n){e&&e.attachEvent&&e.attachEvent("on"+t,n)}function f(e,t,n){e&&e.detachEvent&&e.detachEvent("on"+t,n)}function p(e){var t=e.srcElement,n,r,o,a,s,c,u;n=t.getBoundingClientRect(),c=E.clientX-n.left,u=E.clientY-n.top;for(r in _)if(o=_[r],a=t.offsetWidth*o[0],s=t.offsetHeight*o[1],Math.abs(a-c)<8&&Math.abs(s-u)<8){N=o;break}L=!0,i.getDoc().selection.empty(),l(t,r,E)}function m(e){var t=e.srcElement;if(t!=x){if(h(),0===t.id.indexOf("mceResizeHandle"))return void(e.returnValue=!1);("IMG"==t.nodeName||"TABLE"==t.nodeName)&&(c(),x=t,d(t,"resizestart",p))}}function h(){f(x,"resizestart",p)}function g(){try{i.getDoc().execCommand("enableObjectResizing",!1,!1)}catch(e){}}function v(e){var t;if(I){t=P.body.createControlRange();try{return t.addElement(e),t.select(),!0}catch(n){}}}function y(){x=w=null,I&&(h(),f(i.getBody(),"controlselect",m))}var b=i.dom,C=t.each,x,w,_,N,E,S,k,T,R,A,B,D,L,H,M,P=i.getDoc(),O=document,I=n.ie&&n.ie<11;_={n:[.5,0,0,-1],e:[1,.5,1,0],s:[.5,1,0,1],w:[0,.5,-1,0],nw:[0,0,-1,-1],ne:[1,0,1,-1],se:[1,1,1,1],sw:[0,1,-1,1]};var F=".mce-content-body";return i.contentStyles.push(F+" div.mce-resizehandle {position: absolute;border: 1px solid black;background: #FFF;width: 5px;height: 5px;z-index: 10000}"+F+" .mce-resizehandle:hover {background: #000}"+F+" img[data-mce-selected], hr[data-mce-selected] {outline: 1px solid black;resize: none}"+F+" .mce-clonedresizable {position: absolute;"+(n.gecko?"":"outline: 1px dashed black;")+"opacity: .5;filter: alpha(opacity=50);z-index: 10000}"),i.on("init",function(){I?(i.on("ObjectResized",function(e){"TABLE"!=e.target.nodeName&&(c(),v(e.target))}),d(i.getBody(),"controlselect",m),i.on("mousedown",function(e){E=e})):(g(),n.ie>=11&&(i.on("mouseup",function(e){var t=e.target.nodeName;/^(TABLE|IMG|HR)$/.test(t)&&(i.selection.select(e.target,"TABLE"==t),i.nodeChanged())}),i.dom.bind(i.getBody(),"mscontrolselect",function(e){/^(TABLE|IMG|HR)$/.test(e.target.nodeName)&&e.preventDefault()}))),i.on("nodechange mousedown mouseup ResizeEditor",u),i.on("keydown keyup",function(e){x&&"TABLE"==x.nodeName&&u(e)})}),{isResizable:o,showResizeRect:l,hideResizeRect:c,updateResizeRect:u,controlSelect:v,destroy:y}}}),r(B,[p,f],function(e,t){function n(e){this.walk=function(t,n){function i(e){var t;return t=e[0],3===t.nodeType&&t===l&&c>=t.nodeValue.length&&e.splice(0,1),t=e[e.length-1],0===d&&e.length>0&&t===u&&3===t.nodeType&&e.splice(e.length-1,1),e}function o(e,t,n){for(var r=[];e&&e!=n;e=e[t])r.push(e);return r}function a(e,t){do{if(e.parentNode==t)return e;e=e.parentNode}while(e)}function s(e,t,r){var a=r?"nextSibling":"previousSibling";for(h=e,g=h.parentNode;h&&h!=t;h=g)g=h.parentNode,v=o(h==e?h:h[a],a),v.length&&(r||v.reverse(),n(i(v)))}var l=t.startContainer,c=t.startOffset,u=t.endContainer,d=t.endOffset,f,p,m,h,g,v,y;if(y=e.select("td.mce-item-selected,th.mce-item-selected"),y.length>0)return void r(y,function(e){n([e])});if(1==l.nodeType&&l.hasChildNodes()&&(l=l.childNodes[c]),1==u.nodeType&&u.hasChildNodes()&&(u=u.childNodes[Math.min(d-1,u.childNodes.length-1)]),l==u)return n(i([l]));for(f=e.findCommonAncestor(l,u),h=l;h;h=h.parentNode){if(h===u)return s(l,f,!0);if(h===f)break}for(h=u;h;h=h.parentNode){if(h===l)return s(u,f);if(h===f)break}p=a(l,f)||l,m=a(u,f)||u,s(l,p,!0),v=o(p==l?p:p.nextSibling,"nextSibling",m==u?m.nextSibling:m),v.length&&n(i(v)),s(u,m)},this.split=function(e){function t(e,t){return e.splitText(t)}var n=e.startContainer,r=e.startOffset,i=e.endContainer,o=e.endOffset;return n==i&&3==n.nodeType?r>0&&rr?(o-=r,n=i=t(i,o).previousSibling,o=i.nodeValue.length,r=0):o=0):(3==n.nodeType&&r>0&&r0&&o0)return c=p,u=n?p.nodeValue.length:0,void(i=!0);if(e.isBlock(p)||m[p.nodeName.toLowerCase()])return;s=p}o&&s&&(c=s,i=!0,u=0)}var c,u,d,f=e.getRoot(),p,m,h,g,v;if(c=n[(r?"start":"end")+"Container"],u=n[(r?"start":"end")+"Offset"],v=1==c.nodeType&&u===c.childNodes.length,m=e.schema.getNonEmptyElements(),g=r,1==c.nodeType&&u>c.childNodes.length-1&&(g=!1),9===c.nodeType&&(c=e.getRoot(),u=0),c===f){if(g&&(p=c.childNodes[u>0?u-1:0],p&&(h=p.nodeName.toLowerCase(),m[p.nodeName]||"TABLE"==p.nodeName)))return;if(c.hasChildNodes()&&(u=Math.min(!g&&u>0?u-1:u,c.childNodes.length-1),c=c.childNodes[u],u=0,c.hasChildNodes()&&!/TABLE/.test(c.nodeName))){p=c,d=new t(c,f);do{if(3===p.nodeType&&p.nodeValue.length>0){u=g?0:p.nodeValue.length,c=p,i=!0;break}if(m[p.nodeName.toLowerCase()]){u=e.nodeIndex(p),c=p.parentNode,"IMG"!=p.nodeName||g||u++,i=!0;break}}while(p=g?d.next():d.prev())}}o&&(3===c.nodeType&&0===u&&l(!0),1===c.nodeType&&(p=c.childNodes[u],p||(p=c.childNodes[u-1]),!p||"BR"!==p.nodeName||s(p,"A")||a(p)||a(p,!0)||l(!0,p))),g&&!o&&3===c.nodeType&&u===c.nodeValue.length&&l(!1),i&&n["set"+(r?"Start":"End")](c,u)}var i,o;return o=n.collapsed,r(!0),o||r(),i&&o&&n.collapse(!0),i}}var r=e.each;return n.compareRanges=function(e,t){if(e&&t){if(!e.item&&!e.duplicate)return e.startContainer==t.startContainer&&e.startOffset==t.startOffset;if(e.item&&t.item&&e.item(0)===t.item(0))return!0;if(e.isEqual&&t.isEqual&&t.isEqual(e))return!0}return!1},n}),r(D,[f,T,A,B,g,p],function(e,n,r,i,o,a){function s(e,t,i,o){var a=this;a.dom=e,a.win=t,a.serializer=i,a.editor=o,a.controlSelection=new r(a,o),a.win.getSelection||(a.tridentSel=new n(a))}var l=a.each,c=a.grep,u=a.trim,d=o.ie,f=o.opera;return s.prototype={setCursorLocation:function(e,t){var n=this,r=n.dom.createRng();e?(r.setStart(e,t),r.setEnd(e,t),n.setRng(r),n.collapse(!1)):(n._moveEndPoint(r,n.editor.getBody(),!0),n.setRng(r))},getContent:function(e){var n=this,r=n.getRng(),i=n.dom.create("body"),o=n.getSel(),a,s,l;return e=e||{},a=s="",e.get=!0,e.format=e.format||"html",e.selection=!0,n.editor.fire("BeforeGetContent",e),"text"==e.format?n.isCollapsed()?"":r.text||(o.toString?o.toString():""):(r.cloneContents?(l=r.cloneContents(),l&&i.appendChild(l)):r.item!==t||r.htmlText!==t?(i.innerHTML="
          "+(r.item?r.item(0).outerHTML:r.htmlText),i.removeChild(i.firstChild)):i.innerHTML=r.toString(),/^\s/.test(i.innerHTML)&&(a=" "),/\s+$/.test(i.innerHTML)&&(s=" "),e.getInner=!0,e.content=n.isCollapsed()?"":a+n.serializer.serialize(i,e)+s,n.editor.fire("GetContent",e),e.content)},setContent:function(e,t){var n=this,r=n.getRng(),i,o=n.win.document,a,s;if(t=t||{format:"html"},t.set=!0,t.selection=!0,e=t.content=e,t.no_events||n.editor.fire("BeforeSetContent",t),e=t.content,r.insertNode){e+='_',r.startContainer==o&&r.endContainer==o?o.body.innerHTML=e:(r.deleteContents(),0===o.body.childNodes.length?o.body.innerHTML=e:r.createContextualFragment?r.insertNode(r.createContextualFragment(e)):(a=o.createDocumentFragment(),s=o.createElement("div"),a.appendChild(s),s.outerHTML=e,r.insertNode(a))),i=n.dom.get("__caret"),r=o.createRange(),r.setStartBefore(i),r.setEndBefore(i),n.setRng(r),n.dom.remove("__caret");try{n.setRng(r)}catch(l){}}else r.item&&(o.execCommand("Delete",!1,null),r=n.getRng()),/^\s+/.test(e)?(r.pasteHTML('_'+e),n.dom.remove("__mce_tmp")):r.pasteHTML(e);t.no_events||n.editor.fire("SetContent",t)},getStart:function(){var e=this,t=e.getRng(),n,r,i,o;if(t.duplicate||t.item){if(t.item)return t.item(0);for(i=t.duplicate(),i.collapse(1),n=i.parentElement(),n.ownerDocument!==e.dom.doc&&(n=e.dom.getRoot()),r=o=t.parentElement();o=o.parentNode;)if(o==n){n=r;break}return n}return n=t.startContainer,1==n.nodeType&&n.hasChildNodes()&&(n=n.childNodes[Math.min(n.childNodes.length-1,t.startOffset)]),n&&3==n.nodeType?n.parentNode:n},getEnd:function(){var e=this,t=e.getRng(),n,r;return t.duplicate||t.item?t.item?t.item(0):(t=t.duplicate(),t.collapse(0),n=t.parentElement(),n.ownerDocument!==e.dom.doc&&(n=e.dom.getRoot()),n&&"BODY"==n.nodeName?n.lastChild||n:n):(n=t.endContainer,r=t.endOffset,1==n.nodeType&&n.hasChildNodes()&&(n=n.childNodes[r>0?r-1:r]),n&&3==n.nodeType?n.parentNode:n)},getBookmark:function(e,t){function n(e,t){var n=0;return l(a.select(e),function(e,r){e==t&&(n=r)}),n}function r(e){function t(t){var n,r,i,o=t?"start":"end";n=e[o+"Container"],r=e[o+"Offset"],1==n.nodeType&&"TR"==n.nodeName&&(i=n.childNodes,n=i[Math.min(t?r:r-1,i.length-1)],n&&(r=t?0:n.childNodes.length,e["set"+(t?"Start":"End")](n,r)))}return t(!0),t(),e}function i(){function e(e,n){var i=e[n?"startContainer":"endContainer"],a=e[n?"startOffset":"endOffset"],s=[],l,c,u=0;if(3==i.nodeType){if(t)for(l=i.previousSibling;l&&3==l.nodeType;l=l.previousSibling)a+=l.nodeValue.length;s.push(a)}else c=i.childNodes,a>=c.length&&c.length&&(u=1,a=Math.max(0,c.length-1)),s.push(o.dom.nodeIndex(c[a],t)+u);for(;i&&i!=r;i=i.parentNode)s.push(o.dom.nodeIndex(i,t));return s}var n=o.getRng(!0),r=a.getRoot(),i={};return i.start=e(n,!0),o.isCollapsed()||(i.end=e(n)),i}var o=this,a=o.dom,s,c,u,d,f,p,m="",h;if(2==e)return p=o.getNode(),f=p?p.nodeName:null,"IMG"==f?{name:f,index:n(f,p)}:o.tridentSel?o.tridentSel.getBookmark(e):i();if(e)return{rng:o.getRng()};if(s=o.getRng(),u=a.uniqueId(),d=o.isCollapsed(),h="overflow:hidden;line-height:0px",s.duplicate||s.item){if(s.item)return p=s.item(0),f=p.nodeName,{name:f,index:n(f,p)};c=s.duplicate();try{s.collapse(),s.pasteHTML(''+m+""),d||(c.collapse(!1),s.moveToElementText(c.parentElement()),0===s.compareEndPoints("StartToEnd",c)&&c.move("character",-1),c.pasteHTML(''+m+""))}catch(g){return null}}else{if(p=o.getNode(),f=p.nodeName,"IMG"==f)return{name:f,index:n(f,p)};c=r(s.cloneRange()),d||(c.collapse(!1),c.insertNode(a.create("span",{"data-mce-type":"bookmark",id:u+"_end",style:h},m))),s=r(s),s.collapse(!0),s.insertNode(a.create("span",{"data-mce-type":"bookmark",id:u+"_start",style:h},m))}return o.moveToBookmark({id:u,keep:1}),{id:u}},moveToBookmark:function(e){function t(t){var n=e[t?"start":"end"],r,i,o,l;if(n){for(o=n[0],i=s,r=n.length-1;r>=1;r--){if(l=i.childNodes,n[r]>l.length-1)return;i=l[n[r]]}3===i.nodeType&&(o=Math.min(n[0],i.nodeValue.length)),1===i.nodeType&&(o=Math.min(n[0],i.childNodes.length)),t?a.setStart(i,o):a.setEnd(i,o)}return!0}function n(t){var n=o.get(e.id+"_"+t),r,i,a,s,d=e.keep;if(n&&(r=n.parentNode,"start"==t?(d?(r=n.firstChild,i=1):i=o.nodeIndex(n),u=p=r,m=h=i):(d?(r=n.firstChild,i=1):i=o.nodeIndex(n),p=r,h=i),!d)){for(s=n.previousSibling,a=n.nextSibling,l(c(n.childNodes),function(e){3==e.nodeType&&(e.nodeValue=e.nodeValue.replace(/\uFEFF/g,""))});n=o.get(e.id+"_"+t);)o.remove(n,1);s&&a&&s.nodeType==a.nodeType&&3==s.nodeType&&!f&&(i=s.nodeValue.length,s.appendData(a.nodeValue),o.remove(a),"start"==t?(u=p=s,m=h=i):(p=s,h=i))}}function r(e){return!o.isBlock(e)||e.innerHTML||d||(e.innerHTML='
          '),e}var i=this,o=i.dom,a,s,u,p,m,h;if(e)if(e.start){if(a=o.createRng(),s=o.getRoot(),i.tridentSel)return i.tridentSel.moveToBookmark(e);t(!0)&&t()&&i.setRng(a)}else e.id?(n("start"),n("end"),u&&(a=o.createRng(),a.setStart(r(u),m),a.setEnd(r(p),h),i.setRng(a))):e.name?i.select(o.select(e.name)[e.index]):e.rng&&i.setRng(e.rng)},select:function(e,t){var n=this,r=n.dom,i=r.createRng(),o;if(n.lastFocusBookmark=null,e){if(!t&&n.controlSelection.controlSelect(e))return;o=r.nodeIndex(e),i.setStart(e.parentNode,o),i.setEnd(e.parentNode,o+1),t&&(n._moveEndPoint(i,e,!0),n._moveEndPoint(i,e)),n.setRng(i)}return e},isCollapsed:function(){var e=this,t=e.getRng(),n=e.getSel();return!t||t.item?!1:t.compareEndPoints?0===t.compareEndPoints("StartToEnd",t):!n||t.collapsed},collapse:function(e){var t=this,n=t.getRng(),r;n.item&&(r=n.item(0),n=t.win.document.body.createTextRange(),n.moveToElementText(r)),n.collapse(!!e),t.setRng(n)},getSel:function(){var e=this.win;return e.getSelection?e.getSelection():e.document.selection},getRng:function(e){function t(e,t,n){try{return t.compareBoundaryPoints(e,n)}catch(r){return-1}}var n=this,r,i,o,a=n.win.document,s;if(!e&&n.lastFocusBookmark){var l=n.lastFocusBookmark;return l.startContainer?(i=a.createRange(),i.setStart(l.startContainer,l.startOffset),i.setEnd(l.endContainer,l.endOffset)):i=l,i}if(e&&n.tridentSel)return n.tridentSel.getRangeAt(0);try{(r=n.getSel())&&(i=r.rangeCount>0?r.getRangeAt(0):r.createRange?r.createRange():a.createRange())}catch(c){}if(d&&i&&i.setStart&&a.selection){try{s=a.selection.createRange()}catch(c){}s&&s.item&&(o=s.item(0),i=a.createRange(),i.setStartBefore(o),i.setEndAfter(o))}return i||(i=a.createRange?a.createRange():a.body.createTextRange()),i.setStart&&9===i.startContainer.nodeType&&i.collapsed&&(o=n.dom.getRoot(),i.setStart(o,0),i.setEnd(o,0)),n.selectedRange&&n.explicitRange&&(0===t(i.START_TO_START,i,n.selectedRange)&&0===t(i.END_TO_END,i,n.selectedRange)?i=n.explicitRange:(n.selectedRange=null,n.explicitRange=null)),i},setRng:function(e,t){var n=this,r;if(e.select)try{e.select()}catch(i){}else if(n.tridentSel){if(e.cloneRange)try{return void n.tridentSel.addRange(e)}catch(i){}}else if(r=n.getSel()){n.explicitRange=e;try{r.removeAllRanges(),r.addRange(e)}catch(i){}t===!1&&r.extend&&(r.collapse(e.endContainer,e.endOffset),r.extend(e.startContainer,e.startOffset)),n.selectedRange=r.rangeCount>0?r.getRangeAt(0):null}},setNode:function(e){var t=this;return t.setContent(t.dom.getOuterHTML(e)),e},getNode:function(){function e(e,t){for(var n=e;e&&3===e.nodeType&&0===e.length;)e=t?e.nextSibling:e.previousSibling;return e||n}var t=this,n=t.getRng(),r,i=n.startContainer,o=n.endContainer,a=n.startOffset,s=n.endOffset,l=t.dom.getRoot();return n?n.setStart?(r=n.commonAncestorContainer,!n.collapsed&&(i==o&&2>s-a&&i.hasChildNodes()&&(r=i.childNodes[a]),3===i.nodeType&&3===o.nodeType&&(i=i.length===a?e(i.nextSibling,!0):i.parentNode,o=0===s?e(o.previousSibling,!1):o.parentNode,i&&i===o))?i:r&&3==r.nodeType?r.parentNode:r):(r=n.item?n.item(0):n.parentElement(),r.ownerDocument!==t.win.document&&(r=l),r):l},getSelectedBlocks:function(t,n){var r=this,i=r.dom,o,a,s=[];if(a=i.getRoot(),t=i.getParent(t||r.getStart(),i.isBlock),n=i.getParent(n||r.getEnd(),i.isBlock),t&&t!=a&&s.push(t),t&&n&&t!=n){o=t;for(var l=new e(t,a);(o=l.next())&&o!=n;)i.isBlock(o)&&s.push(o)}return n&&t!=n&&n!=a&&s.push(n),s},isForward:function(){var e=this.dom,t=this.getSel(),n,r;return t&&t.anchorNode&&t.focusNode?(n=e.createRng(),n.setStart(t.anchorNode,t.anchorOffset),n.collapse(!0),r=e.createRng(),r.setStart(t.focusNode,t.focusOffset),r.collapse(!0),n.compareBoundaryPoints(n.START_TO_START,r)<=0):!0},normalize:function(){var e=this,t=e.getRng();return!d&&new i(e.dom).normalize(t)&&e.setRng(t,e.isForward()),t},selectorChanged:function(e,t){var n=this,r;return n.selectorChangedData||(n.selectorChangedData={},r={},n.editor.on("NodeChange",function(e){var t=e.element,i=n.dom,o=i.getParents(t,null,i.getRoot()),a={};l(n.selectorChangedData,function(e,t){l(o,function(n){return i.is(n,t)?(r[t]||(l(e,function(e){e(!0,{node:n,selector:t,parents:o})}),r[t]=e),a[t]=e,!1):void 0})}),l(r,function(e,n){a[n]||(delete r[n],l(e,function(e){e(!1,{node:t,selector:n,parents:o})}))})})),n.selectorChangedData[e]||(n.selectorChangedData[e]=[]),n.selectorChangedData[e].push(t),n},getScrollContainer:function(){for(var e,t=this.dom.getRoot();t&&"BODY"!=t.nodeName;){if(t.scrollHeight>t.clientHeight){e=t;break}t=t.parentNode}return e},scrollIntoView:function(e){function t(e){for(var t=0,n=0,r=e;r&&r.nodeType;)t+=r.offsetLeft||0,n+=r.offsetTop||0,r=r.offsetParent;return{x:t,y:n}}var n,r,i=this,o=i.dom,a=o.getRoot(),s,l;if("BODY"!=a.nodeName){var c=i.getScrollContainer();if(c)return n=t(e).y-t(c).y,l=c.clientHeight,s=c.scrollTop,void((s>n||n+25>s+l)&&(c.scrollTop=s>n?n:n-l+25))}r=o.getViewPort(i.editor.getWin()),n=o.getPos(e).y,s=r.y,l=r.h,(ns+l)&&i.editor.getWin().scrollTo(0,s>n?n:n-l+25)},_moveEndPoint:function(t,n,r){var i=n,a=new e(n,i),s=this.dom.schema.getNonEmptyElements();do{if(3==n.nodeType&&0!==u(n.nodeValue).length)return void(r?t.setStart(n,0):t.setEnd(n,n.nodeValue.length));if(s[n.nodeName])return void(r?t.setStartBefore(n):"BR"==n.nodeName?t.setEndBefore(n):t.setEndAfter(n));if(o.ie&&o.ie<11&&this.dom.isBlock(n)&&this.dom.isEmpty(n))return void(r?t.setStart(n,0):t.setEnd(n,0))}while(n=r?a.next():a.prev());"BODY"==i.nodeName&&(r?t.setStart(i,0):t.setEnd(i,i.childNodes.length))},destroy:function(){this.win=null,this.controlSelection.destroy()}},s}),r(L,[f,B,p],function(e,t,n){return function(r){function i(e){return e.nodeType&&(e=e.nodeName),!!r.schema.getTextBlockElements()[e.toLowerCase()]}function o(e,t){return I.getParents(e,t,I.getRoot())}function a(e){return 1===e.nodeType&&"_mce_caret"===e.id}function s(){u({alignleft:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"left"},defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"left"}}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"center"},defaultBlock:"div"},{selector:"img",collapsed:!1,styles:{display:"block",marginLeft:"auto",marginRight:"auto"}},{selector:"table",collapsed:!1,styles:{marginLeft:"auto",marginRight:"auto"}}],alignright:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"right"},defaultBlock:"div"},{selector:"img,table",collapsed:!1,styles:{"float":"right"}}],alignjustify:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li",styles:{textAlign:"justify"},defaultBlock:"div"}],bold:[{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:!0},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:!0},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},wrap_links:!1},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},wrap_links:!1},fontname:{inline:"span",styles:{fontFamily:"%value"}},fontsize:{inline:"span",styles:{fontSize:"%value"}},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},code:{inline:"code"},link:{inline:"a",selector:"a",remove:"all",split:!0,deep:!0,onmatch:function(){return!0},onformat:function(e,t,n){et(n,function(t,n){I.setAttrib(e,n,t)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q",remove:"all",split:!0,expand:!1,block_expand:!0,deep:!0},{selector:"span",attributes:["style","class"],remove:"empty",split:!0,expand:!1,deep:!0},{selector:"*",attributes:["style","class"],split:!1,expand:!1,deep:!0}]}),et("p h1 h2 h3 h4 h5 h6 div address pre div dt dd samp".split(/\s/),function(e){u(e,{block:e,remove:"all"})}),u(r.settings.formats)}function l(){r.addShortcut("ctrl+b","bold_desc","Bold"),r.addShortcut("ctrl+i","italic_desc","Italic"),r.addShortcut("ctrl+u","underline_desc","Underline");for(var e=1;6>=e;e++)r.addShortcut("ctrl+"+e,"",["FormatBlock",!1,"h"+e]);r.addShortcut("ctrl+7","",["FormatBlock",!1,"p"]),r.addShortcut("ctrl+8","",["FormatBlock",!1,"div"]),r.addShortcut("ctrl+9","",["FormatBlock",!1,"address"])}function c(e){return e?O[e]:O}function u(e,t){e&&("string"!=typeof e?et(e,function(e,t){u(t,e)}):(t=t.length?t:[t],et(t,function(e){e.deep===X&&(e.deep=!e.selector),e.split===X&&(e.split=!e.selector||e.inline),e.remove===X&&e.selector&&!e.inline&&(e.remove="none"),e.selector&&e.inline&&(e.mixed=!0,e.block_expand=!0),"string"==typeof e.classes&&(e.classes=e.classes.split(/\s+/))}),O[e]=t))}function d(e){var t;return r.dom.getParent(e,function(e){return t=r.dom.getStyle(e,"text-decoration"),t&&"none"!==t}),t}function f(e){var t;1===e.nodeType&&e.parentNode&&1===e.parentNode.nodeType&&(t=d(e.parentNode),r.dom.getStyle(e,"color")&&t?r.dom.setStyle(e,"text-decoration",t):r.dom.getStyle(e,"textdecoration")===t&&r.dom.setStyle(e,"text-decoration",null))}function p(t,n,o){function s(e,t){t=t||h,e&&(t.onformat&&t.onformat(e,t,n,o),et(t.styles,function(t,r){I.setStyle(e,r,E(t,n))}),et(t.attributes,function(t,r){I.setAttrib(e,r,E(t,n))}),et(t.classes,function(t){t=E(t,n),I.hasClass(e,t)||I.addClass(e,t)}))}function l(){function t(t,n){var r=new e(n);for(o=r.current();o;o=r.prev())if(o.childNodes.length>1||o==t||"BR"==o.tagName)return o}var n=r.selection.getRng(),i=n.startContainer,a=n.endContainer;if(i!=a&&0===n.endOffset){var s=t(i,a),l=3==s.nodeType?s.length:s.childNodes.length;n.setEnd(s,l)}return n}function u(e,t,n,r,i){var o=[],a=-1,s,l=-1,c=-1,u;return et(e.childNodes,function(e,t){return"UL"===e.nodeName||"OL"===e.nodeName?(a=t,s=e,!1):void 0}),et(e.childNodes,function(e,n){"SPAN"===e.nodeName&&"bookmark"==I.getAttrib(e,"data-mce-type")&&(e.id==t.id+"_start"?l=n:e.id==t.id+"_end"&&(c=n))}),0>=a||a>l&&c>a?(et(tt(e.childNodes),i),0):(u=I.clone(n,K),et(tt(e.childNodes),function(e,t){(a>l&&a>t||l>a&&t>a)&&(o.push(e),e.parentNode.removeChild(e))}),a>l?e.insertBefore(u,s):l>a&&e.insertBefore(u,s.nextSibling),r.push(u),et(o,function(e){u.appendChild(e)}),u)}function d(e,r,o){var l=[],c,d,f=!0;c=h.inline||h.block,d=I.create(c),s(d),z.walk(e,function(e){function p(e){var y,C,x,_,N;return N=f,y=e.nodeName.toLowerCase(),C=e.parentNode.nodeName.toLowerCase(),1===e.nodeType&&J(e)&&(N=f,f="true"===J(e),_=!0),w(y,"br")?(v=0,void(h.block&&I.remove(e))):h.wrapper&&g(e,t,n)?void(v=0):f&&!_&&h.block&&!h.wrapper&&i(y)&&W(C,c)?(e=I.rename(e,c),s(e),l.push(e),void(v=0)):h.selector&&(et(m,function(t){"collapsed"in t&&t.collapsed!==b||I.is(e,t.selector)&&!a(e)&&(s(e,t),x=!0)}),!h.inline||x)?void(v=0):void(!f||_||!W(c,y)||!W(C,c)||!o&&3===e.nodeType&&1===e.nodeValue.length&&65279===e.nodeValue.charCodeAt(0)||a(e)||h.inline&&V(e)?"li"==y&&r?v=u(e,r,d,l,p):(v=0,et(tt(e.childNodes),p),_&&(f=N),v=0):(v||(v=I.clone(d,K),e.parentNode.insertBefore(v,e),l.push(v)),v.appendChild(e)))}var v;et(e,p)}),h.wrap_links===!1&&et(l,function(e){function t(e){var n,r,i;if("A"===e.nodeName){for(r=I.clone(d,K),l.push(r),i=tt(e.childNodes),n=0;n1||!V(e))&&0===o)return void I.remove(e,1);if(h.inline||h.wrapper){if(h.exact||1!==o||(e=i(e)),et(m,function(t){et(I.select(t.inline,e),function(e){var r;if(!D(e)){if(t.wrap_links===!1){r=e.parentNode;do if("A"===r.nodeName)return;while(r=r.parentNode)}R(t,n,e,t.exact?e:null)}})}),g(e.parentNode,t,n))return I.remove(e,1),e=0,Y;h.merge_with_parents&&I.getParent(e.parentNode,function(r){return g(r,t,n)?(I.remove(e,1),e=0,Y):void 0}),e&&h.merge_siblings!==!1&&(e=L(B(e),e),e=L(e,B(e,Y)))}})}var m=c(t),h=m[0],v,y,b=!o&&F.isCollapsed();if(h)if(o)o.nodeType?(y=I.createRng(),y.setStartBefore(o),y.setEndAfter(o),d(T(y,m),null,!0)):d(o,null,!0);else if(b&&h.inline&&!I.select("td.mce-item-selected,th.mce-item-selected").length)M("apply",t,n);else{var C=r.selection.getNode();U||!m[0].defaultBlock||I.getParent(C,I.isBlock)||p(m[0].defaultBlock),r.selection.setRng(l()),v=F.getBookmark(),d(T(F.getRng(Y),m),v),h.styles&&(h.styles.color||h.styles.textDecoration)&&(nt(C,f,"childNodes"),f(C)),F.moveToBookmark(v),P(F.getRng(Y)),r.nodeChanged()}}function m(e,t,n){function i(e){var n,r,o,a,s;if(1===e.nodeType&&J(e)&&(a=b,b="true"===J(e),s=!0),n=tt(e.childNodes),b&&!s)for(r=0,o=p.length;o>r&&!R(p[r],t,e,e);r++);if(m.deep&&n.length){for(r=0,o=n.length;o>r;r++)i(n[r]);s&&(b=a)}}function a(n){var r;return et(o(n.parentNode).reverse(),function(n){var i;r||"_start"==n.id||"_end"==n.id||(i=g(n,e,t),i&&i.split!==!1&&(r=n))}),r}function s(e,n,r,i){var o,a,s,l,c,u;if(e){for(u=e.parentNode,o=n.parentNode;o&&o!=u;o=o.parentNode){for(a=I.clone(o,K),c=0;c=0;a--){if(s=t[a].selector,!s||t[a].defaultBlock)return Y;for(i=r.length-1;i>=0;i--)if(I.is(r[i],s))return Y}return K}function C(e,t,n){var i;return G||(G={},i={},r.on("NodeChange",function(e){var t=o(e.element),n={};et(G,function(e,r){et(t,function(o){return g(o,r,{},e.similar)?(i[r]||(et(e,function(e){e(!0,{node:o,format:r,parents:t})}),i[r]=e),n[r]=e,!1):void 0})}),et(i,function(r,o){n[o]||(delete i[o],et(r,function(n){n(!1,{node:e.element,format:o,parents:t})}))})})),et(e.split(","),function(e){G[e]||(G[e]=[],G[e].similar=n),G[e].push(t)}),this}function x(e,t){return w(e,t.inline)?Y:w(e,t.block)?Y:t.selector?1==e.nodeType&&I.is(e,t.selector):void 0}function w(e,t){return e=e||"",t=t||"",e=""+(e.nodeName||e),t=""+(t.nodeName||t),e.toLowerCase()==t.toLowerCase()}function _(e,t){return N(I.getStyle(e,t),t)}function N(e,t){return("color"==t||"backgroundColor"==t)&&(e=I.toHex(e)),"fontWeight"==t&&700==e&&(e="bold"),"fontFamily"==t&&(e=e.replace(/[\'\"]/g,"").replace(/,\s+/g,",")),""+e}function E(e,t){return"string"!=typeof e?e=e(t):t&&(e=e.replace(/%(\w+)/g,function(e,n){return t[n]||e})),e}function S(e){return e&&3===e.nodeType&&/^([\t \r\n]+|)$/.test(e.nodeValue)}function k(e,t,n){var r=I.create(t,n);return e.parentNode.insertBefore(r,e),r.appendChild(e),r}function T(t,n,a){function s(e){function t(e){return"BR"==e.nodeName&&e.getAttribute("data-mce-bogus")&&!e.nextSibling}var r,i,o,a,s;if(r=i=e?g:y,a=e?"previousSibling":"nextSibling",s=I.getRoot(),3==r.nodeType&&!S(r)&&(e?v>0:br?n:r,-1===n||a||n++):(n=o.indexOf(" ",t),r=o.indexOf("\xa0",t),n=-1!==n&&(-1===r||r>n)?n:r),n}var s,l,c,u;if(3===t.nodeType){if(c=o(t,n),-1!==c)return{container:t,offset:c};u=t}for(s=new e(t,I.getParent(t,V)||r.getBody());l=s[i?"prev":"next"]();)if(3===l.nodeType){if(u=l,c=o(l),-1!==c)return{container:l,offset:c}}else if(V(l))break;return u?(n=i?0:u.length,{container:u,offset:n}):void 0}function d(e,r){var i,a,s,l;for(3==e.nodeType&&0===e.nodeValue.length&&e[r]&&(e=e[r]),i=o(e),a=0;ap?p:v],3==g.nodeType&&(v=0)),1==y.nodeType&&y.hasChildNodes()&&(p=y.childNodes.length-1,y=y.childNodes[b>p?p:b-1],3==y.nodeType&&(b=y.nodeValue.length)),g=c(g),y=c(y),(D(g.parentNode)||D(g))&&(g=D(g)?g:g.parentNode,g=g.nextSibling||g,3==g.nodeType&&(v=0)),(D(y.parentNode)||D(y))&&(y=D(y)?y:y.parentNode,y=y.previousSibling||y,3==y.nodeType&&(b=y.length)),n[0].inline&&(t.collapsed&&(h=u(g,v,!0),h&&(g=h.container,v=h.offset),h=u(y,b),h&&(y=h.container,b=h.offset)),m=l(y,b),m.node)){for(;m.node&&0===m.offset&&m.node.previousSibling;)m=l(m.node.previousSibling);m.node&&m.offset>0&&3===m.node.nodeType&&" "===m.node.nodeValue.charAt(m.offset-1)&&m.offset>1&&(y=m.node,y.splitText(m.offset-1))}return(n[0].inline||n[0].block_expand)&&(n[0].inline&&3==g.nodeType&&0!==v||(g=s(!0)),n[0].inline&&3==y.nodeType&&b!==y.nodeValue.length||(y=s())),n[0].selector&&n[0].expand!==K&&!n[0].inline&&(g=d(g,"previousSibling"),y=d(y,"nextSibling")),(n[0].block||n[0].selector)&&(g=f(g,"previousSibling"),y=f(y,"nextSibling"),n[0].block&&(V(g)||(g=s(!0)),V(y)||(y=s()))),1==g.nodeType&&(v=q(g),g=g.parentNode),1==y.nodeType&&(b=q(y)+1,y=y.parentNode),{startContainer:g,startOffset:v,endContainer:y,endOffset:b}}function R(e,t,n,r){var i,o,a;if(!x(n,e))return K;if("all"!=e.remove)for(et(e.styles,function(e,i){e=N(E(e,t),i),"number"==typeof i&&(i=e,r=0),(!r||w(_(r,i),e))&&I.setStyle(n,i,""),a=1}),a&&""===I.getAttrib(n,"style")&&(n.removeAttribute("style"),n.removeAttribute("data-mce-style")),et(e.attributes,function(e,i){var o;if(e=E(e,t),"number"==typeof i&&(i=e,r=0),!r||w(I.getAttrib(r,i),e)){if("class"==i&&(e=I.getAttrib(n,i),e&&(o="",et(e.split(/\s+/),function(e){/mce\w+/.test(e)&&(o+=(o?" ":"")+e)}),o)))return void I.setAttrib(n,i,o);"class"==i&&n.removeAttribute("className"),j.test(i)&&n.removeAttribute("data-mce-"+i),n.removeAttribute(i)}}),et(e.classes,function(e){e=E(e,t),(!r||I.hasClass(r,e))&&I.removeClass(n,e)}),o=I.getAttribs(n),i=0;ia?a:o]),3===i.nodeType&&n&&o>=i.nodeValue.length&&(i=new e(i,r.getBody()).next()||i),3!==i.nodeType||n||0!==o||(i=new e(i,r.getBody()).prev()||i),i}function M(t,n,o){function a(e){var t=I.create("span",{id:y,"data-mce-bogus":!0,style:b?"color:red":""});return e&&t.appendChild(r.getDoc().createTextNode($)),t}function s(e,t){for(;e;){if(3===e.nodeType&&e.nodeValue!==$||e.childNodes.length>1)return!1;t&&1===e.nodeType&&t.push(e),e=e.firstChild}return!0}function l(e){for(;e;){if(e.id===y)return e;e=e.parentNode}}function u(t){var n;if(t)for(n=new e(t,t),t=n.current();t;t=n.next())if(3===t.nodeType)return t}function d(e,t){var n,r;if(e)r=F.getRng(!0),s(e)?(t!==!1&&(r.setStartBefore(e),r.setEndBefore(e)),I.remove(e)):(n=u(e),n.nodeValue.charAt(0)===$&&(n=n.deleteData(0,1)),I.remove(e,1)),F.setRng(r);else if(e=l(F.getStart()),!e)for(;e=I.get(y);)d(e,!1)}function f(){var e,t,r,i,s,d,f;e=F.getRng(!0),i=e.startOffset,d=e.startContainer,f=d.nodeValue,t=l(F.getStart()),t&&(r=u(t)),f&&i>0&&i=0;p--)u.appendChild(I.clone(f[p],!1)),u=u.firstChild;u.appendChild(I.doc.createTextNode($)),u=u.firstChild;var v=I.getParent(d,i);v&&I.isEmpty(v)?d.parentNode.replaceChild(h,d):I.insertAfter(h,d),F.setCursorLocation(u,1),I.isEmpty(d)&&I.remove(d)}}function v(){var e;e=l(F.getStart()),e&&!I.isEmpty(e)&&nt(e,function(e){1!=e.nodeType||e.id===y||I.isEmpty(e)||I.setAttrib(e,"data-mce-bogus",null)},"childNodes")}var y="_mce_caret",b=r.settings.caret_debug;r._hasCaretEvents||(Z=function(){var e=[],t;if(s(l(F.getStart()),e))for(t=e.length;t--;)I.setAttrib(e[t],"data-mce-bogus","1")},Q=function(e){var t=e.keyCode;d(),(8==t||37==t||39==t)&&d(l(F.getStart())),v()},r.on("SetContent",function(e){e.selection&&v()}),r._hasCaretEvents=!0),"apply"==t?f():h()}function P(t){var n=t.startContainer,r=t.startOffset,i,o,a,s,l;if(3==n.nodeType&&r>=n.nodeValue.length&&(r=q(n),n=n.parentNode,i=!0),1==n.nodeType)for(s=n.childNodes,n=s[Math.min(r,s.length-1)],o=new e(n,I.getParent(n,I.isBlock)),(r>s.length-1||i)&&o.next(),a=o.current();a;a=o.next())if(3==a.nodeType&&!S(a))return l=I.create("a",null,$),a.parentNode.insertBefore(l,a),t.setStart(a,0),F.setRng(t),void I.remove(l)}var O={},I=r.dom,F=r.selection,z=new t(I),W=r.schema.isValidChild,V=I.isBlock,U=r.settings.forced_root_block,q=I.nodeIndex,$="\ufeff",j=/^(src|href|style)$/,K=!1,Y=!0,G,X,J=I.getContentEditable,Q,Z,et=n.each,tt=n.grep,nt=n.walk,rt=n.extend;rt(this,{get:c,register:u,apply:p,remove:m,toggle:h,match:v,matchAll:y,matchNode:g,canApply:b,formatChanged:C}),s(),l(),r.on("BeforeGetContent",function(){Z&&Z()}),r.on("mouseup keydown",function(e){Q&&Q(e)})}}),r(H,[g,p],function(e,t){var n=t.trim,r;return r=new RegExp(["]+data-mce-bogus[^>]+>[\u200b\ufeff]+<\\/span>","]+data-mce-bogus[^>]+><\\/div>",'\\s?data-mce-selected="[^"]+"'].join("|"),"gi"),function(t){function i(){return n(t.getContent({format:"raw",no_events:1}).replace(r,""))}function o(e){a.typing=!1,a.add({},e)}var a,s=0,l=[],c,u,d;return t.on("init",function(){a.add()}),t.on("BeforeExecCommand",function(e){var t=e.command;"Undo"!=t&&"Redo"!=t&&"mceRepaint"!=t&&a.beforeChange()}),t.on("ExecCommand",function(e){var t=e.command;"Undo"!=t&&"Redo"!=t&&"mceRepaint"!=t&&o(e)}),t.on("ObjectResizeStart",function(){a.beforeChange()}),t.on("SaveContent ObjectResized blur",o),t.dom.bind(t.dom.getRoot(),"dragend",o),t.on("KeyUp",function(n){var r=n.keyCode;(r>=33&&36>=r||r>=37&&40>=r||45==r||13==r||n.ctrlKey)&&(o(),t.nodeChanged()),(46==r||8==r||e.mac&&(91==r||93==r))&&t.nodeChanged(),u&&a.typing&&(t.isDirty()||(t.isNotDirty=!l[0]||i()==l[0].content,t.isNotDirty||t.fire("change",{level:l[0],lastLevel:null})),t.fire("TypingUndo"),u=!1,t.nodeChanged())}),t.on("KeyDown",function(e){var t=e.keyCode;return t>=33&&36>=t||t>=37&&40>=t||45==t?void(a.typing&&o(e)):void((16>t||t>20)&&224!=t&&91!=t&&!a.typing&&(a.beforeChange(),a.typing=!0,a.add({},e),u=!0))}),t.on("MouseDown",function(e){a.typing&&o(e)}),t.addShortcut("ctrl+z","","Undo"),t.addShortcut("ctrl+y,ctrl+shift+z","","Redo"),t.on("AddUndo Undo Redo ClearUndos MouseUp",function(e){e.isDefaultPrevented()||t.nodeChanged()}),a={data:l,typing:!1,beforeChange:function(){d||(c=t.selection.getBookmark(2,!0))},add:function(e,n){var r,o=t.settings,a;if(e=e||{},e.content=i(),d||t.removed)return null;if(t.fire("BeforeAddUndo",{level:e,originalEvent:n}).isDefaultPrevented())return null;if(a=l[s],a&&a.content==e.content)return null;if(l[s]&&(l[s].beforeBookmark=c),o.custom_undo_redo_levels&&l.length>o.custom_undo_redo_levels){for(r=0;r0&&(t.isNotDirty=!1,t.fire("change",u)),e},undo:function(){var e;return a.typing&&(a.add(),a.typing=!1),s>0&&(e=l[--s],0===s&&(t.isNotDirty=!0),t.setContent(e.content,{format:"raw"}),t.selection.moveToBookmark(e.beforeBookmark),t.fire("undo",{level:e})),e},redo:function(){var e;return s0||a.typing&&l[0]&&i()!=l[0].content},hasRedo:function(){return sD)&&(u=a.create("br"),t.parentNode.insertBefore(u,t)),l.setStartBefore(t),l.setEndBefore(t)):(l.setStartAfter(t),l.setEndAfter(t)):(l.setStart(t,0),l.setEnd(t,0));s.setRng(l),a.remove(u),s.scrollIntoView(t)}function g(e){var t=l.forced_root_block;t&&t.toLowerCase()===e.tagName.toLowerCase()&&a.setAttribs(e,l.forced_root_block_attrs)}function v(e){var t=R,n,i,o;if(e||"TABLE"==O?(n=a.create(e||F),g(n)):n=B.cloneNode(!1),o=n,l.keep_styles!==!1)do if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U|VAR|CITE|DFN|CODE|MARK|Q|SUP|SUB|SAMP)$/.test(t.nodeName)){if("_mce_caret"==t.id)continue;i=t.cloneNode(!1),a.setAttrib(i,"id",""),n.hasChildNodes()?(i.appendChild(n.firstChild),n.appendChild(i)):(o=i,n.appendChild(i))}while(t=t.parentNode);return r||(o.innerHTML='
          '),n}function y(t){var n,r,i;if(3==R.nodeType&&(t?A>0:A0)return!0}function w(){var e,t,n;R&&3==R.nodeType&&A>=R.nodeValue.length&&(r||x()||(e=a.create("br"),S.insertNode(e),S.setStartAfter(e),S.setEndAfter(e),t=!0)),e=a.create("br"),S.insertNode(e),r&&"PRE"==O&&(!D||8>D)&&e.parentNode.insertBefore(a.doc.createTextNode("\r"),e),n=a.create("span",{}," "),e.parentNode.insertBefore(n,e),s.scrollIntoView(n),a.remove(n),t?(S.setStartBefore(e),S.setEndBefore(e)):(S.setStartAfter(e),S.setEndAfter(e)),s.setRng(S),c.add()}function _(e){do 3===e.nodeType&&(e.nodeValue=e.nodeValue.replace(/^[\r\n]+/,"")),e=e.firstChild;while(e)}function N(e){var t=a.getRoot(),n,r;for(n=e;n!==t&&"false"!==a.getContentEditable(n);)"true"===a.getContentEditable(n)&&(r=n),n=n.parentNode;return n!==t?r:t}function E(e){var t;r||(e.normalize(),t=e.lastChild,(!t||/^(left|right)$/gi.test(a.getStyle(t,"float",!0)))&&a.add(e,"br"))}var S,k,T,R,A,B,D,L,H,M,P,O,I,F,z;if(S=s.getRng(!0),!o.isDefaultPrevented()){if(!S.collapsed)return void i.execCommand("Delete");if(new t(a).normalize(S),R=S.startContainer,A=S.startOffset,F=(l.force_p_newlines?"p":"")||l.forced_root_block,F=F?F.toUpperCase():"",D=a.doc.documentMode,L=o.shiftKey,1==R.nodeType&&R.hasChildNodes()&&(z=A>R.childNodes.length-1,R=R.childNodes[Math.min(A,R.childNodes.length-1)]||R,A=z&&3==R.nodeType?R.nodeValue.length:0),T=N(R)){if(c.beforeChange(),!a.isBlock(T)&&T!=a.getRoot())return void((!F||L)&&w());if((F&&!L||!F&&L)&&(R=b(R,A)),B=a.getParent(R,a.isBlock),P=B?a.getParent(B.parentNode,a.isBlock):null,O=B?B.nodeName.toUpperCase():"",I=P?P.nodeName.toUpperCase():"","LI"!=I||o.ctrlKey||(B=P,O=I),"LI"==O){if(!F&&L)return void w();if(a.isEmpty(B))return void C()}if("PRE"==O&&l.br_in_pre!==!1){if(!L)return void w()}else if(!F&&!L&&"LI"!=O||F&&L)return void w();F&&B===i.getBody()||(F=F||"P",y()?(H=/^(H[1-6]|PRE|FIGURE)$/.test(O)&&"HGROUP"!=I?v(F):v(),l.end_container_on_empty_block&&f(P)&&a.isEmpty(B)?H=a.split(P,B):a.insertAfter(H,B),h(H)):y(!0)?(H=B.parentNode.insertBefore(v(),B),p(H),h(B)):(k=S.cloneRange(),k.setEndAfter(B),M=k.extractContents(),_(M),H=M.firstChild,a.insertAfter(M,B),m(H),E(B),h(H)),a.setAttrib(H,"id",""),i.fire("NewBlock",{newBlock:H}),c.add())}}}var a=i.dom,s=i.selection,l=i.settings,c=i.undoManager,u=i.schema,d=u.getNonEmptyElements();i.on("keydown",function(e){13==e.keyCode&&o(e)!==!1&&e.preventDefault()})}}),r(P,[],function(){return function(e){function t(){var t=i.getStart(),s=e.getBody(),l,c,u,d,f,p,m,h=-16777215,g,v,y,b,C;if(C=n.forced_root_block,t&&1===t.nodeType&&C){for(;t&&t!=s;){if(a[t.nodeName])return;t=t.parentNode}if(l=i.getRng(),l.setStart){c=l.startContainer,u=l.startOffset,d=l.endContainer,f=l.endOffset;try{v=e.getDoc().activeElement===s}catch(x){}}else l.item&&(t=l.item(0),l=e.getDoc().body.createTextRange(),l.moveToElementText(t)),v=l.parentElement().ownerDocument===e.getDoc(),y=l.duplicate(),y.collapse(!0),u=-1*y.move("character",h),y.collapsed||(y=l.duplicate(),y.collapse(!1),f=-1*y.move("character",h)-u);for(t=s.firstChild,b=s.nodeName.toLowerCase();t;)if((3===t.nodeType||1==t.nodeType&&!a[t.nodeName])&&o.isValidChild(b,C.toLowerCase())){if(3===t.nodeType&&0===t.nodeValue.length){m=t,t=t.nextSibling,r.remove(m);continue}p||(p=r.create(C,e.settings.forced_root_block_attrs),t.parentNode.insertBefore(p,t),g=!0),m=t,t=t.nextSibling,p.appendChild(m)}else p=null,t=t.nextSibling;if(g&&v){if(l.setStart)l.setStart(c,u),l.setEnd(d,f),i.setRng(l);else try{l=e.getDoc().body.createTextRange(),l.moveToElementText(s),l.collapse(!0),l.moveStart("character",u),f>0&&l.moveEnd("character",f),l.select()}catch(x){}e.nodeChanged()}}}var n=e.settings,r=e.dom,i=e.selection,o=e.schema,a=o.getBlockElements();n.forced_root_block&&e.on("NodeChange",t)}}),r(O,[S,g,p],function(e,n,r){var i=r.each,o=r.extend,a=r.map,s=r.inArray,l=r.explode,c=n.gecko,u=n.ie,d=!0,f=!1;return function(r){function p(e,t,n){var r;return e=e.toLowerCase(),(r=N.exec[e])?(r(e,t,n),d):f}function m(e){var t;return e=e.toLowerCase(),(t=N.state[e])?t(e):-1}function h(e){var t;return e=e.toLowerCase(),(t=N.value[e])?t(e):f}function g(e,t){t=t||"exec",i(e,function(e,n){i(n.toLowerCase().split(","),function(n){N[t][n]=e})})}function v(e,n,i){return n===t&&(n=f),i===t&&(i=null),r.getDoc().execCommand(e,n,i)}function y(e){return S.match(e)}function b(e,n){S.toggle(e,n?{value:n}:t),r.nodeChanged()}function C(e){k=_.getBookmark(e)}function x(){_.moveToBookmark(k)}var w=r.dom,_=r.selection,N={state:{},exec:{},value:{}},E=r.settings,S=r.formatter,k;o(this,{execCommand:p,queryCommandState:m,queryCommandValue:h,addCommands:g}),g({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){r.undoManager.add()},"Cut,Copy,Paste":function(e){var t=r.getDoc(),i;try{v(e)}catch(o){i=d}if(i||!t.queryCommandSupported(e)){var a=r.translate("Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.");n.mac&&(a=a.replace(/Ctrl\+/g,"\u2318+")),r.windowManager.alert(a)}},unlink:function(){if(_.isCollapsed()){var e=_.getNode();return void("A"==e.tagName&&r.dom.remove(e,!0))}S.remove("link")},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(e){var t=e.substring(7);"full"==t&&(t="justify"),i("left,center,right,justify".split(","),function(e){t!=e&&S.remove("align"+e)}),b("align"+t),p("mceRepaint")},"InsertUnorderedList,InsertOrderedList":function(e){var t,n;v(e),t=w.getParent(_.getNode(),"ol,ul"),t&&(n=t.parentNode,/^(H[1-6]|P|ADDRESS|PRE)$/.test(n.nodeName)&&(C(),w.split(n,t),x()))},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(e){b(e)},"ForeColor,HiliteColor,FontName":function(e,t,n){b(e,n)},FontSize:function(e,t,n){var r,i;n>=1&&7>=n&&(i=l(E.font_size_style_values),r=l(E.font_size_classes),n=r?r[n-1]||n:i[n-1]||n),b(e,n)},RemoveFormat:function(e){S.remove(e)},mceBlockQuote:function(){b("blockquote")},FormatBlock:function(e,t,n){return b(n||"p")},mceCleanup:function(){var e=_.getBookmark();r.setContent(r.getContent({cleanup:d}),{cleanup:d}),_.moveToBookmark(e)},mceRemoveNode:function(e,t,n){var i=n||_.getNode();i!=r.getBody()&&(C(),r.dom.remove(i,d),x())},mceSelectNodeDepth:function(e,t,n){var i=0;w.getParent(_.getNode(),function(e){return 1==e.nodeType&&i++==n?(_.select(e),f):void 0},r.getBody())},mceSelectNode:function(e,t,n){_.select(n)},mceInsertContent:function(t,n,i){function o(e){function t(e){return r[e]&&3==r[e].nodeType}var n,r,i;return n=_.getRng(!0),r=n.startContainer,i=n.startOffset,3==r.nodeType&&(i>0?e=e.replace(/^ /," "):t("previousSibling")||(e=e.replace(/^ /," ")),i|)$/," "):t("nextSibling")||(e=e.replace(/( | )(
          |)$/," "))),e}var a,s,l,c,d,f,p,m,h,g,v;/^ | $/.test(i)&&(i=o(i)),a=r.parser,s=new e({},r.schema),v='ÈB;',f={content:i,format:"html",selection:!0},r.fire("BeforeSetContent",f),i=f.content,-1==i.indexOf("{$caret}")&&(i+="{$caret}"),i=i.replace(/\{\$caret\}/,v),m=_.getRng();var y=m.startContainer||(m.parentElement?m.parentElement():null),b=r.getBody();y===b&&_.isCollapsed()&&w.isBlock(b.firstChild)&&w.isEmpty(b.firstChild)&&(m=w.createRng(),m.setStart(b.firstChild,0),m.setEnd(b.firstChild,0),_.setRng(m)),_.isCollapsed()||r.getDoc().execCommand("Delete",!1,null),l=_.getNode();var C={context:l.nodeName.toLowerCase()};if(d=a.parse(i,C),h=d.lastChild,"mce_marker"==h.attr("id"))for(p=h,h=h.prev;h;h=h.walk(!0))if(3==h.type||!w.isBlock(h.name)){h.parent.insert(p,h,"br"===h.name);break}if(C.invalid){for(_.setContent(v),l=_.getNode(),c=r.getBody(),9==l.nodeType?l=h=c:h=l;h!==c;)l=h,h=h.parentNode;i=l==c?c.innerHTML:w.getOuterHTML(l),i=s.serialize(a.parse(i.replace(//i,function(){return s.serialize(d)}))),l==c?w.setHTML(c,i):w.setOuterHTML(l,i)}else i=s.serialize(d),h=l.firstChild,g=l.lastChild,!h||h===g&&"BR"===h.nodeName?w.setHTML(l,i):_.setContent(i);p=w.get("mce_marker"),_.scrollIntoView(p),m=w.createRng(),h=p.previousSibling,h&&3==h.nodeType?(m.setStart(h,h.nodeValue.length),u||(g=p.nextSibling,g&&3==g.nodeType&&(h.appendData(g.data),g.parentNode.removeChild(g)))):(m.setStartBefore(p),m.setEndBefore(p)),w.remove(p),_.setRng(m),r.fire("SetContent",f),r.addVisual()},mceInsertRawHTML:function(e,t,n){_.setContent("tiny_mce_marker"),r.setContent(r.getContent().replace(/tiny_mce_marker/g,function(){return n}))},mceToggleFormat:function(e,t,n){b(n)},mceSetContent:function(e,t,n){r.setContent(n)},"Indent,Outdent":function(e){var t,n,o;t=E.indentation,n=/[a-z%]+$/i.exec(t),t=parseInt(t,10),m("InsertUnorderedList")||m("InsertOrderedList")?v(e):(E.forced_root_block||w.getParent(_.getNode(),w.isBlock)||S.apply("div"),i(_.getSelectedBlocks(),function(i){if("LI"!=i.nodeName){var a=r.getParam("indent_use_margin",!1)?"margin":"padding";a+="rtl"==w.getStyle(i,"direction",!0)?"Right":"Left","outdent"==e?(o=Math.max(0,parseInt(i.style[a]||0,10)-t),w.setStyle(i,a,o?o+n:"")):(o=parseInt(i.style[a]||0,10)+t+n,w.setStyle(i,a,o))}}))},mceRepaint:function(){if(c)try{C(d),_.getSel()&&_.getSel().selectAllChildren(r.getBody()),_.collapse(d),x()}catch(e){}},InsertHorizontalRule:function(){r.execCommand("mceInsertContent",!1,"
          ")},mceToggleVisualAid:function(){r.hasVisual=!r.hasVisual,r.addVisual()},mceReplaceContent:function(e,t,n){r.execCommand("mceInsertContent",!1,n.replace(/\{\$selection\}/g,_.getContent({format:"text"})))},mceInsertLink:function(e,t,n){var r;"string"==typeof n&&(n={href:n}),r=w.getParent(_.getNode(),"a"),n.href=n.href.replace(" ","%20"),r&&n.href||S.remove("link"),n.href&&S.apply("link",n,r)},selectAll:function(){var e=w.getRoot(),t;_.getRng().setStart?(t=w.createRng(),t.setStart(e,0),t.setEnd(e,e.childNodes.length),_.setRng(t)):(t=_.getRng(),t.item||(t.moveToElementText(e),t.select()))},"delete":function(){v("Delete");var e=r.getBody();w.isEmpty(e)&&(r.setContent(""),e.firstChild&&w.isBlock(e.firstChild)?r.selection.setCursorLocation(e.firstChild,0):r.selection.setCursorLocation(e,0))},mceNewDocument:function(){r.setContent("")}}),g({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(e){var t="align"+e.substring(7),n=_.isCollapsed()?[w.getParent(_.getNode(),w.isBlock)]:_.getSelectedBlocks(),r=a(n,function(e){return!!S.matchNode(e,t)});return-1!==s(r,d)},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(e){return y(e)},mceBlockQuote:function(){return y("blockquote")},Outdent:function(){var e;if(E.inline_styles){if((e=w.getParent(_.getStart(),w.isBlock))&&parseInt(e.style.paddingLeft,10)>0)return d;if((e=w.getParent(_.getEnd(),w.isBlock))&&parseInt(e.style.paddingLeft,10)>0)return d}return m("InsertUnorderedList")||m("InsertOrderedList")||!E.inline_styles&&!!w.getParent(_.getNode(),"BLOCKQUOTE")},"InsertUnorderedList,InsertOrderedList":function(e){var t=w.getParent(_.getNode(),"ul,ol");return t&&("insertunorderedlist"===e&&"UL"===t.tagName||"insertorderedlist"===e&&"OL"===t.tagName)}},"state"),g({"FontSize,FontName":function(e){var t=0,n;return(n=w.getParent(_.getNode(),"span"))&&(t="fontsize"==e?n.style.fontSize:n.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()),t}},"value"),g({Undo:function(){r.undoManager.undo()},Redo:function(){r.undoManager.redo()}})}}),r(I,[p],function(e){function t(e,i){var o=this,a,s;if(e=r(e),i=o.settings=i||{},/^([\w\-]+):([^\/]{2})/i.test(e)||/^\s*#/.test(e))return void(o.source=e);var l=0===e.indexOf("//");0!==e.indexOf("/")||l||(e=(i.base_uri?i.base_uri.protocol||"http":"http")+"://mce_host"+e),/^[\w\-]*:?\/\//.test(e)||(s=i.base_uri?i.base_uri.path:new t(location.href).directory,e=""===i.base_uri.protocol?"//mce_host"+o.toAbsPath(s,e):(i.base_uri&&i.base_uri.protocol||"http")+"://mce_host"+o.toAbsPath(s,e)),e=e.replace(/@@/g,"(mce_at)"),e=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(e),n(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],function(t,n){var r=e[n];r&&(r=r.replace(/\(mce_at\)/g,"@@")),o[t]=r}),a=i.base_uri,a&&(o.protocol||(o.protocol=a.protocol),o.userInfo||(o.userInfo=a.userInfo),o.port||"mce_host"!==o.host||(o.port=a.port),o.host&&"mce_host"!==o.host||(o.host=a.host),o.source=""),l&&(o.protocol="")}var n=e.each,r=e.trim;return t.prototype={setPath:function(e){var t=this;e=/^(.*?)\/?(\w+)?$/.exec(e),t.path=e[0],t.directory=e[1],t.file=e[2],t.source="",t.getURI()},toRelative:function(e){var n=this,r;if("./"===e)return e;if(e=new t(e,{base_uri:n}),"mce_host"!=e.host&&n.host!=e.host&&e.host||n.port!=e.port||n.protocol!=e.protocol&&""!==e.protocol)return e.getURI();var i=n.getURI(),o=e.getURI();return i==o||"/"==i.charAt(i.length-1)&&i.substr(0,i.length-1)==o?i:(r=n.toRelPath(n.path,e.path),e.query&&(r+="?"+e.query),e.anchor&&(r+="#"+e.anchor),r)},toAbsolute:function(e,n){return e=new t(e,{base_uri:this}),e.getURI(this.host==e.host&&this.protocol==e.protocol?n:0)},toRelPath:function(e,t){var n,r=0,i="",o,a;if(e=e.substring(0,e.lastIndexOf("/")),e=e.split("/"),n=t.split("/"),e.length>=n.length)for(o=0,a=e.length;a>o;o++)if(o>=n.length||e[o]!=n[o]){r=o+1;break}if(e.lengtho;o++)if(o>=e.length||e[o]!=n[o]){r=o+1;break}if(1===r)return t;for(o=0,a=e.length-(r-1);a>o;o++)i+="../";for(o=r-1,a=n.length;a>o;o++)i+=o!=r-1?"/"+n[o]:n[o]; -return i},toAbsPath:function(e,t){var r,i=0,o=[],a,s;for(a=/\/$/.test(t)?"/":"",e=e.split("/"),t=t.split("/"),n(e,function(e){e&&o.push(e)}),e=o,r=t.length-1,o=[];r>=0;r--)0!==t[r].length&&"."!==t[r]&&(".."!==t[r]?i>0?i--:o.push(t[r]):i++);return r=e.length-i,s=0>=r?o.reverse().join("/"):e.slice(0,r).join("/")+"/"+o.reverse().join("/"),0!==s.indexOf("/")&&(s="/"+s),a&&s.lastIndexOf("/")!==s.length-1&&(s+=a),s},getURI:function(e){var t,n=this;return(!n.source||e)&&(t="",e||(t+=n.protocol?n.protocol+"://":"//",n.userInfo&&(t+=n.userInfo+"@"),n.host&&(t+=n.host),n.port&&(t+=":"+n.port)),n.path&&(t+=n.path),n.query&&(t+="?"+n.query),n.anchor&&(t+="#"+n.anchor),n.source=t),n.source}},t}),r(F,[p],function(e){function t(){}var n=e.each,r=e.extend,i,o;return t.extend=i=function(e){function t(){var e,t,n,r;if(!o&&(r=this,r.init&&r.init.apply(r,arguments),t=r.Mixins))for(e=t.length;e--;)n=t[e],n.init&&n.init.apply(r,arguments)}function a(){return this}function s(e,t){return function(){var n=this,r=n._super,i;return n._super=c[e],i=t.apply(n,arguments),n._super=r,i}}var l=this,c=l.prototype,u,d,f;o=!0,u=new l,o=!1,e.Mixins&&(n(e.Mixins,function(t){t=t;for(var n in t)"init"!==n&&(e[n]=t[n])}),c.Mixins&&(e.Mixins=c.Mixins.concat(e.Mixins))),e.Methods&&n(e.Methods.split(","),function(t){e[t]=a}),e.Properties&&n(e.Properties.split(","),function(t){var n="_"+t;e[t]=function(e){var t=this,r;return e!==r?(t[n]=e,t):t[n]}}),e.Statics&&n(e.Statics,function(e,n){t[n]=e}),e.Defaults&&c.Defaults&&(e.Defaults=r({},c.Defaults,e.Defaults));for(d in e)f=e[d],u[d]="function"==typeof f&&c[d]?s(d,f):f;return t.prototype=u,t.constructor=t,t.extend=i,t},t}),r(z,[F],function(e){function t(e){for(var t=[],n=e.length,r;n--;)r=e[n],r.__checked||(t.push(r),r.__checked=1);for(n=t.length;n--;)delete t[n].__checked;return t}var n=/^([\w\\*]+)?(?:#([\w\\]+))?(?:\.([\w\\\.]+))?(?:\[\@?([\w\\]+)([\^\$\*!~]?=)([\w\\]+)\])?(?:\:(.+))?/i,r=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,i=/^\s*|\s*$/g,o,a=e.extend({init:function(e){function t(e){return e?(e=e.toLowerCase(),function(t){return"*"===e||t.type===e}):void 0}function o(e){return e?function(t){return t._name===e}:void 0}function a(e){return e?(e=e.split("."),function(t){for(var n=e.length;n--;)if(!t.hasClass(e[n]))return!1;return!0}):void 0}function s(e,t,n){return e?function(r){var i=r[e]?r[e]():"";return t?"="===t?i===n:"*="===t?i.indexOf(n)>=0:"~="===t?(" "+i+" ").indexOf(" "+n+" ")>=0:"!="===t?i!=n:"^="===t?0===i.indexOf(n):"$="===t?i.substr(i.length-n.length)===n:!1:!!n}:void 0}function l(e){var t;return e?(e=/(?:not\((.+)\))|(.+)/i.exec(e),e[1]?(t=u(e[1],[]),function(e){return!d(e,t)}):(e=e[2],function(t,n,r){return"first"===e?0===n:"last"===e?n===r-1:"even"===e?n%2===0:"odd"===e?n%2===1:t[e]?t[e]():!1})):void 0}function c(e,r,c){function u(e){e&&r.push(e)}var d;return d=n.exec(e.replace(i,"")),u(t(d[1])),u(o(d[2])),u(a(d[3])),u(s(d[4],d[5],d[6])),u(l(d[7])),r.psuedo=!!d[7],r.direct=c,r}function u(e,t){var n=[],i,o,a;do if(r.exec(""),o=r.exec(e),o&&(e=o[3],n.push(o[1]),o[2])){i=o[3];break}while(o);for(i&&u(i,t),e=[],a=0;a"!=n[a]&&e.push(c(n[a],[],">"===n[a-1]));return t.push(e),t}var d=this.match;this._selectors=u(e,[])},match:function(e,t){var n,r,i,o,a,s,l,c,u,d,f,p,m;for(t=t||this._selectors,n=0,r=t.length;r>n;n++){for(a=t[n],o=a.length,m=e,p=0,i=o-1;i>=0;i--)for(c=a[i];m;){if(c.psuedo)for(f=m.parent().items(),u=d=f.length;u--&&f[u]!==m;);for(s=0,l=c.length;l>s;s++)if(!c[s](m,u,d)){s=l+1;break}if(s===l){p++;break}if(i===o-1)break;m=m.parent()}if(p===o)return!0}return!1},find:function(e){function n(e,t,i){var o,a,s,l,c,u=t[i];for(o=0,a=e.length;a>o;o++){for(c=e[o],s=0,l=u.length;l>s;s++)if(!u[s](c,o,a)){s=l+1;break}if(s===l)i==t.length-1?r.push(c):c.items&&n(c.items(),t,i+1);else if(u.direct)return;c.items&&n(c.items(),t,i)}}var r=[],i,s,l=this._selectors;if(e.items){for(i=0,s=l.length;s>i;i++)n(e.items(),l[i],0);s>1&&(r=t(r))}return o||(o=a.Collection),new o(r)}});return a}),r(W,[p,z,F],function(e,t,n){var r,i,o=Array.prototype.push,a=Array.prototype.slice;return i={length:0,init:function(e){e&&this.add(e)},add:function(t){var n=this;return e.isArray(t)?o.apply(n,t):t instanceof r?n.add(t.toArray()):o.call(n,t),n},set:function(e){var t=this,n=t.length,r;for(t.length=0,t.add(e),r=t.length;n>r;r++)delete t[r];return t},filter:function(e){var n=this,i,o,a=[],s,l;for("string"==typeof e?(e=new t(e),l=function(t){return e.match(t)}):l=e,i=0,o=n.length;o>i;i++)s=n[i],l(s)&&a.push(s);return new r(a)},slice:function(){return new r(a.apply(this,arguments))},eq:function(e){return-1===e?this.slice(e):this.slice(e,+e+1)},each:function(t){return e.each(this,t),this},toArray:function(){return e.toArray(this)},indexOf:function(e){for(var t=this,n=t.length;n--&&t[n]!==e;);return n},reverse:function(){return new r(e.toArray(this).reverse())},hasClass:function(e){return this[0]?this[0].hasClass(e):!1},prop:function(e,t){var n=this,r,i;return t!==r?(n.each(function(n){n[e]&&n[e](t)}),n):(i=n[0],i&&i[e]?i[e]():void 0)},exec:function(t){var n=this,r=e.toArray(arguments).slice(1);return n.each(function(e){e[t]&&e[t].apply(e,r)}),n},remove:function(){for(var e=this.length;e--;)this[e].remove();return this}},e.each("fire on off show hide addClass removeClass append prepend before after reflow".split(" "),function(t){i[t]=function(){var n=e.toArray(arguments);return this.each(function(e){t in e&&e[t].apply(e,n)}),this}}),e.each("text name disabled active selected checked visible parent value data".split(" "),function(e){i[e]=function(t){return this.prop(e,t)}}),r=n.extend(i),t.Collection=r,r}),r(V,[p,y],function(e,t){return{id:function(){return t.DOM.uniqueId()},createFragment:function(e){return t.DOM.createFragment(e)},getWindowSize:function(){return t.DOM.getViewPort()},getSize:function(e){var t,n;if(e.getBoundingClientRect){var r=e.getBoundingClientRect();t=Math.max(r.width||r.right-r.left,e.offsetWidth),n=Math.max(r.height||r.bottom-r.bottom,e.offsetHeight)}else t=e.offsetWidth,n=e.offsetHeight;return{width:t,height:n}},getPos:function(e,n){return t.DOM.getPos(e,n)},getViewPort:function(e){return t.DOM.getViewPort(e)},get:function(e){return document.getElementById(e)},addClass:function(e,n){return t.DOM.addClass(e,n)},removeClass:function(e,n){return t.DOM.removeClass(e,n)},hasClass:function(e,n){return t.DOM.hasClass(e,n)},toggleClass:function(e,n,r){return t.DOM.toggleClass(e,n,r)},css:function(e,n,r){return t.DOM.setStyle(e,n,r)},on:function(e,n,r,i){return t.DOM.bind(e,n,r,i)},off:function(e,n,r){return t.DOM.unbind(e,n,r)},fire:function(e,n,r){return t.DOM.fire(e,n,r)},innerHtml:function(e,n){t.DOM.setHTML(e,n)}}}),r(U,[F,p,W,V],function(e,t,n,r){var i=t.makeMap("focusin focusout scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave wheel keydown keypress keyup contextmenu"," "),o={},a="onmousewheel"in document,s=!1,l=e.extend({Statics:{elementIdCache:o},isRtl:function(){return l.rtl},classPrefix:"mce-",init:function(e){var n=this,i,o;if(n.settings=e=t.extend({},n.Defaults,e),n._id=e.id||r.id(),n._text=n._name="",n._width=n._height=0,n._aria={role:e.role},i=e.classes)for(i=i.split(" "),i.map={},o=i.length;o--;)i.map[i[o]]=!0;n._classes=i||[],n.visible(!0),t.each("title text width height name classes visible disabled active value".split(" "),function(t){var r=e[t],i;r!==i?n[t](r):n["_"+t]===i&&(n["_"+t]=!1)}),n.on("click",function(){return n.disabled()?!1:void 0}),e.classes&&t.each(e.classes.split(" "),function(e){n.addClass(e)}),n.settings=e,n._borderBox=n.parseBox(e.border),n._paddingBox=n.parseBox(e.padding),n._marginBox=n.parseBox(e.margin),e.hidden&&n.hide()},Properties:"parent,title,text,width,height,disabled,active,name,value",Methods:"renderHtml",getContainerElm:function(){return document.body},getParentCtrl:function(e){for(var t,n=this.getRoot().controlIdLookup;e&&n&&!(t=n[e.id]);)e=e.parentNode;return t},parseBox:function(e){var t,n=10;if(e)return"number"==typeof e?(e=e||0,{top:e,left:e,bottom:e,right:e}):(e=e.split(" "),t=e.length,1===t?e[1]=e[2]=e[3]=e[0]:2===t?(e[2]=e[0],e[3]=e[1]):3===t&&(e[3]=e[1]),{top:parseInt(e[0],n)||0,right:parseInt(e[1],n)||0,bottom:parseInt(e[2],n)||0,left:parseInt(e[3],n)||0})},borderBox:function(){return this._borderBox},paddingBox:function(){return this._paddingBox},marginBox:function(){return this._marginBox},measureBox:function(e,t){function n(t){var n=document.defaultView;return n?(t=t.replace(/[A-Z]/g,function(e){return"-"+e}),n.getComputedStyle(e,null).getPropertyValue(t)):e.currentStyle[t]}function r(e){var t=parseFloat(n(e),10);return isNaN(t)?0:t}return{top:r(t+"TopWidth"),right:r(t+"RightWidth"),bottom:r(t+"BottomWidth"),left:r(t+"LeftWidth")}},initLayoutRect:function(){var e=this,t=e.settings,n,i,o=e.getEl(),a,s,l,c,u,d,f,p;n=e._borderBox=e._borderBox||e.measureBox(o,"border"),e._paddingBox=e._paddingBox||e.measureBox(o,"padding"),e._marginBox=e._marginBox||e.measureBox(o,"margin"),p=r.getSize(o),d=t.minWidth,f=t.minHeight,l=d||p.width,c=f||p.height,a=t.width,s=t.height,u=t.autoResize,u="undefined"!=typeof u?u:!a&&!s,a=a||l,s=s||c;var m=n.left+n.right,h=n.top+n.bottom,g=t.maxWidth||65535,v=t.maxHeight||65535;return e._layoutRect=i={x:t.x||0,y:t.y||0,w:a,h:s,deltaW:m,deltaH:h,contentW:a-m,contentH:s-h,innerW:a-m,innerH:s-h,startMinWidth:d||0,startMinHeight:f||0,minW:Math.min(l,g),minH:Math.min(c,v),maxW:g,maxH:v,autoResize:u,scrollW:0},e._lastLayoutRect={},i},layoutRect:function(e){var t=this,n=t._layoutRect,r,i,o,a,s,c;return n||(n=t.initLayoutRect()),e?(o=n.deltaW,a=n.deltaH,e.x!==s&&(n.x=e.x),e.y!==s&&(n.y=e.y),e.minW!==s&&(n.minW=e.minW),e.minH!==s&&(n.minH=e.minH),i=e.w,i!==s&&(i=in.maxW?n.maxW:i,n.w=i,n.innerW=i-o),i=e.h,i!==s&&(i=in.maxH?n.maxH:i,n.h=i,n.innerH=i-a),i=e.innerW,i!==s&&(i=in.maxW-o?n.maxW-o:i,n.innerW=i,n.w=i+o),i=e.innerH,i!==s&&(i=in.maxH-a?n.maxH-a:i,n.innerH=i,n.h=i+a),e.contentW!==s&&(n.contentW=e.contentW),e.contentH!==s&&(n.contentH=e.contentH),r=t._lastLayoutRect,(r.x!==n.x||r.y!==n.y||r.w!==n.w||r.h!==n.h)&&(c=l.repaintControls,c&&c.map&&!c.map[t._id]&&(c.push(t),c.map[t._id]=!0),r.x=n.x,r.y=n.y,r.w=n.w,r.h=n.h),t):n},repaint:function(){var e=this,t,n,r,i,o=0,a=0,s,l;l=document.createRange?function(e){return e}:Math.round,t=e.getEl().style,r=e._layoutRect,s=e._lastRepaintRect||{},i=e._borderBox,o=i.left+i.right,a=i.top+i.bottom,r.x!==s.x&&(t.left=l(r.x)+"px",s.x=r.x),r.y!==s.y&&(t.top=l(r.y)+"px",s.y=r.y),r.w!==s.w&&(t.width=l(r.w-o)+"px",s.w=r.w),r.h!==s.h&&(t.height=l(r.h-a)+"px",s.h=r.h),e._hasBody&&r.innerW!==s.innerW&&(n=e.getEl("body").style,n.width=l(r.innerW)+"px",s.innerW=r.innerW),e._hasBody&&r.innerH!==s.innerH&&(n=n||e.getEl("body").style,n.height=l(r.innerH)+"px",s.innerH=r.innerH),e._lastRepaintRect=s,e.fire("repaint",{},!1)},on:function(e,t){function n(e){var t,n;return function(i){return t||r.parents().each(function(r){var i=r.settings.callbacks;return i&&(t=i[e])?(n=r,!1):void 0}),t.call(n,i)}}var r=this,o,a,s,l;if(t)for("string"==typeof t&&(t=n(t)),s=e.toLowerCase().split(" "),l=s.length;l--;)e=s[l],o=r._bindings,o||(o=r._bindings={}),a=o[e],a||(a=o[e]=[]),a.push(t),i[e]&&(r._nativeEvents?r._nativeEvents[e]=!0:r._nativeEvents={name:!0},r._rendered&&r.bindPendingEvents());return r},off:function(e,t){var n=this,r,i=n._bindings,o,a,s,l;if(i)if(e)for(s=e.toLowerCase().split(" "),r=s.length;r--;){if(e=s[r],o=i[e],!e){for(a in i)i[a].length=0;return n}if(o)if(t)for(l=o.length;l--;)o[l]===t&&o.splice(l,1);else o.length=0}else n._bindings=[];return n},fire:function(e,t,n){function r(){return!1}function i(){return!0}var o=this,a,s,l,c;if(e=e.toLowerCase(),t=t||{},t.type||(t.type=e),t.control||(t.control=o),t.preventDefault||(t.preventDefault=function(){t.isDefaultPrevented=i},t.stopPropagation=function(){t.isPropagationStopped=i},t.stopImmediatePropagation=function(){t.isImmediatePropagationStopped=i},t.isDefaultPrevented=r,t.isPropagationStopped=r,t.isImmediatePropagationStopped=r),o._bindings&&(l=o._bindings[e]))for(a=0,s=l.length;s>a&&(t.isImmediatePropagationStopped()||l[a].call(o,t)!==!1);a++);if(n!==!1)for(c=o.parent();c&&!t.isPropagationStopped();)c.fire(e,t,!1),c=c.parent();return t},hasEventListeners:function(e){return e in this._bindings},parents:function(e){var t=this,r=new n;for(t=t.parent();t;t=t.parent())r.add(t);return e&&(r=r.filter(e)),r},next:function(){var e=this.parent().items();return e[e.indexOf(this)+1]},prev:function(){var e=this.parent().items();return e[e.indexOf(this)-1]},findCommonAncestor:function(e,t){for(var n;e;){for(n=t;n&&e!=n;)n=n.parent();if(e==n)break;e=e.parent()}return e},hasClass:function(e,t){var n=this._classes[t||"control"];return e=this.classPrefix+e,n&&!!n.map[e]},addClass:function(e,t){var n=this,r,i;return e=this.classPrefix+e,r=n._classes[t||"control"],r||(r=[],r.map={},n._classes[t||"control"]=r),r.map[e]||(r.map[e]=e,r.push(e),n._rendered&&(i=n.getEl(t),i&&(i.className=r.join(" ")))),n},removeClass:function(e,t){var n=this,r,i,o;if(e=this.classPrefix+e,r=n._classes[t||"control"],r&&r.map[e])for(delete r.map[e],i=r.length;i--;)r[i]===e&&r.splice(i,1);return n._rendered&&(o=n.getEl(t),o&&(o.className=r.join(" "))),n},toggleClass:function(e,t,n){var r=this;return t?r.addClass(e,n):r.removeClass(e,n),r},classes:function(e){var t=this._classes[e||"control"];return t?t.join(" "):""},innerHtml:function(e){return r.innerHtml(this.getEl(),e),this},getEl:function(e,t){var n,i=e?this._id+"-"+e:this._id;return n=o[i]=(t===!0?null:o[i])||r.get(i)},visible:function(e){var t=this,n;return"undefined"!=typeof e?(t._visible!==e&&(t._rendered&&(t.getEl().style.display=e?"":"none"),t._visible=e,n=t.parent(),n&&(n._lastRect=null),t.fire(e?"show":"hide")),t):t._visible},show:function(){return this.visible(!0)},hide:function(){return this.visible(!1)},focus:function(){try{this.getEl().focus()}catch(e){}return this},blur:function(){return this.getEl().blur(),this},aria:function(e,t){var n=this,r=n.getEl(n.ariaTarget);return"undefined"==typeof t?n._aria[e]:(n._aria[e]=t,n._rendered&&r.setAttribute("role"==e?e:"aria-"+e,t),n)},encode:function(e,t){return t!==!1&&l.translate&&(e=l.translate(e)),(e||"").replace(/[&<>"]/g,function(e){return"&#"+e.charCodeAt(0)+";"})},before:function(e){var t=this,n=t.parent();return n&&n.insert(e,n.items().indexOf(t),!0),t},after:function(e){var t=this,n=t.parent();return n&&n.insert(e,n.items().indexOf(t)),t},remove:function(){var e=this,t=e.getEl(),n=e.parent(),i,a;if(e.items){var s=e.items().toArray();for(a=s.length;a--;)s[a].remove()}n&&n.items&&(i=[],n.items().each(function(t){t!==e&&i.push(t)}),n.items().set(i),n._lastRect=null),e._eventsRoot&&e._eventsRoot==e&&r.off(t);var l=e.getRoot().controlIdLookup;if(l&&delete l[e._id],delete o[e._id],t&&t.parentNode){var c=t.getElementsByTagName("*");for(a=c.length;a--;)delete o[c[a].id];t.parentNode.removeChild(t)}return e._rendered=!1,e},renderBefore:function(e){var t=this;return e.parentNode.insertBefore(r.createFragment(t.renderHtml()),e),t.postRender(),t},renderTo:function(e){var t=this;return e=e||t.getContainerElm(),e.appendChild(r.createFragment(t.renderHtml())),t.postRender(),t},postRender:function(){var e=this,t=e.settings,n,i,o,a,s;for(a in t)0===a.indexOf("on")&&e.on(a.substr(2),t[a]);if(e._eventsRoot){for(o=e.parent();!s&&o;o=o.parent())s=o._eventsRoot;if(s)for(a in s._nativeEvents)e._nativeEvents[a]=!0}e.bindPendingEvents(),t.style&&(n=e.getEl(),n&&(n.setAttribute("style",t.style),n.style.cssText=t.style)),e._visible||r.css(e.getEl(),"display","none"),e.settings.border&&(i=e.borderBox(),r.css(e.getEl(),{"border-top-width":i.top,"border-right-width":i.right,"border-bottom-width":i.bottom,"border-left-width":i.left}));var l=e.getRoot();l.controlIdLookup||(l.controlIdLookup={}),l.controlIdLookup[e._id]=e;for(var c in e._aria)e.aria(c,e._aria[c]);e.fire("postrender",{},!1)},scrollIntoView:function(e){function t(e,t){var n,r,i=e;for(n=r=0;i&&i!=t&&i.nodeType;)n+=i.offsetLeft||0,r+=i.offsetTop||0,i=i.offsetParent;return{x:n,y:r}}var n=this.getEl(),r=n.parentNode,i,o,a,s,l,c,u=t(n,r);return i=u.x,o=u.y,a=n.offsetWidth,s=n.offsetHeight,l=r.clientWidth,c=r.clientHeight,"end"==e?(i-=l-a,o-=c-s):"center"==e&&(i-=l/2-a/2,o-=c/2-s/2),r.scrollLeft=i,r.scrollTop=o,this},bindPendingEvents:function(){function e(e){var t=o.getParentCtrl(e.target);t&&t.fire(e.type,e)}function t(){var e=d._lastHoverCtrl;e&&(e.fire("mouseleave",{target:e.getEl()}),e.parents().each(function(e){e.fire("mouseleave",{target:e.getEl()})}),d._lastHoverCtrl=null)}function n(e){var t=o.getParentCtrl(e.target),n=d._lastHoverCtrl,r=0,i,a,s;if(t!==n){if(d._lastHoverCtrl=t,a=t.parents().toArray().reverse(),a.push(t),n){for(s=n.parents().toArray().reverse(),s.push(n),r=0;r=r;i--)n=s[i],n.fire("mouseleave",{target:n.getEl()})}for(i=r;il;l++)d=u[l]._eventsRoot;for(d||(d=u[u.length-1]||o),o._eventsRoot=d,c=l,l=0;c>l;l++)u[l]._eventsRoot=d;for(p in f){if(!f)return!1;"wheel"!==p||s?("mouseenter"===p||"mouseleave"===p?d._hasMouseEnter||(r.on(d.getEl(),"mouseleave",t),r.on(d.getEl(),"mouseover",n),d._hasMouseEnter=1):d[p]||(r.on(d.getEl(),p,e),d[p]=!0),f[p]=!1):a?r.on(o.getEl(),"mousewheel",i):r.on(o.getEl(),"DOMMouseScroll",i)}}},getRoot:function(){for(var e=this,t,n=[];e;){if(e.rootControl){t=e.rootControl;break}n.push(e),t=e,e=e.parent()}t||(t=this);for(var r=n.length;r--;)n[r].rootControl=t;return t},reflow:function(){return this.repaint(),this}});return l}),r(q,[],function(){var e={},t;return{add:function(t,n){e[t.toLowerCase()]=n},has:function(t){return!!e[t.toLowerCase()]},create:function(n,r){var i,o,a;if(!t){a=tinymce.ui;for(o in a)e[o.toLowerCase()]=a[o];t=!0}if("string"==typeof n?(r=r||{},r.type=n):(r=n,n=r.type),n=n.toLowerCase(),i=e[n],!i)throw new Error("Could not find control by type: "+n);return i=new i(r),i.type=n,i}}}),r($,[],function(){return function(e){function t(e){return e=e||b,e&&e.getAttribute("role")}function n(e){for(var n,r=e||b;r=r.parentNode;)if(n=t(r))return n}function r(e){var t=b;return t?t.getAttribute("aria-"+e):void 0}function i(e){return"INPUT"==e.tagName||"TEXTAREA"==e.tagName}function o(e){return i(e)&&!e.hidden?!0:/^(button|menuitem|checkbox|tab|menuitemcheckbox|option|gridcell)$/.test(t(e))?!0:!1}function a(e){function t(e){if(1==e.nodeType&&"none"!=e.style.display){o(e)&&n.push(e);for(var r=0;re?e=t.length-1:e>=t.length&&(e=0),t[e]&&t[e].focus(),e}function u(e,t){var n=-1,r=s();t=t||a(r.getEl());for(var i=0;i=0&&(n=t.getEl(),n&&n.parentNode.removeChild(n),n=e.getEl(),n&&n.parentNode.removeChild(n)),t.parent(this)},create:function(t){var n=this,i,a=[];return o.isArray(t)||(t=[t]),o.each(t,function(t){t&&(t instanceof e||("string"==typeof t&&(t={type:t}),i=o.extend({},n.settings.defaults,t),t.type=i.type=i.type||t.type||n.settings.defaultType||(i.defaults?i.defaults.type:null),t=r.create(i)),a.push(t))}),a},renderNew:function(){var e=this;return e.items().each(function(t,n){var r,i;t.parent(e),t._rendered||(r=e.getEl("body"),i=a.createFragment(t.renderHtml()),r.hasChildNodes()&&n<=r.childNodes.length-1?r.insertBefore(i,r.childNodes[n]):r.appendChild(i),t.postRender())}),e._layout.applyClasses(e),e._lastRect=null,e},append:function(e){return this.add(e).renderNew()},prepend:function(e){var t=this;return t.items().set(t.create(e).concat(t.items().toArray())),t.renderNew()},insert:function(e,t,n){var r=this,i,o,a;return e=r.create(e),i=r.items(),!n&&t=0&&t
          '+(e.settings.html||"")+t.renderHtml(e)+"
          "},postRender:function(){var e=this,t;return e.items().exec("postRender"),e._super(),e._layout.postRender(e),e._rendered=!0,e.settings.style&&a.css(e.getEl(),e.settings.style),e.settings.border&&(t=e.borderBox(),a.css(e.getEl(),{"border-top-width":t.top,"border-right-width":t.right,"border-bottom-width":t.bottom,"border-left-width":t.left})),e.parent()||(e.keyboardNav=new i({root:e})),e},initLayoutRect:function(){var e=this,t=e._super();return e._layout.recalc(e),t},recalc:function(){var e=this,t=e._layoutRect,n=e._lastRect;return n&&n.w==t.w&&n.h==t.h?void 0:(e._layout.recalc(e),t=e.layoutRect(),e._lastRect={x:t.x,y:t.y,w:t.w,h:t.h},!0)},reflow:function(){var t,n;if(this.visible()){for(e.repaintControls=[],e.repaintControls.map={},n=this.recalc(),t=e.repaintControls.length;t--;)e.repaintControls[t].repaint();"flow"!==this.settings.layout&&"stack"!==this.settings.layout&&this.repaint(),e.repaintControls=[]}return this}})}),r(K,[V],function(e){function t(){var e=document,t,n,r,i,o,a,s,l,c=Math.max;return t=e.documentElement,n=e.body,r=c(t.scrollWidth,n.scrollWidth),i=c(t.clientWidth,n.clientWidth),o=c(t.offsetWidth,n.offsetWidth),a=c(t.scrollHeight,n.scrollHeight),s=c(t.clientHeight,n.clientHeight),l=c(t.offsetHeight,n.offsetHeight),{width:o>r?i:r,height:l>a?s:a}}return function(n,r){function i(){return a.getElementById(r.handle||n)}var o,a=document,s,l,c,u,d,f;r=r||{},l=function(n){var l=t(),p,m;n.preventDefault(),s=n.button,p=i(),d=n.screenX,f=n.screenY,m=window.getComputedStyle?window.getComputedStyle(p,null).getPropertyValue("cursor"):p.runtimeStyle.cursor,o=a.createElement("div"),e.css(o,{position:"absolute",top:0,left:0,width:l.width,height:l.height,zIndex:2147483647,opacity:1e-4,background:"red",cursor:m}),a.body.appendChild(o),e.on(a,"mousemove",u),e.on(a,"mouseup",c),r.start(n)},u=function(e){return e.button!==s?c(e):(e.deltaX=e.screenX-d,e.deltaY=e.screenY-f,e.preventDefault(),void r.drag(e))},c=function(t){e.off(a,"mousemove",u),e.off(a,"mouseup",c),o.parentNode.removeChild(o),r.stop&&r.stop(t)},this.destroy=function(){e.off(i())},e.on(i(),"mousedown",l)}}),r(Y,[V,K],function(e,t){return{init:function(){var e=this;e.on("repaint",e.renderScroll)},renderScroll:function(){function n(){function t(t,a,s,l,c,u){var d,f,p,m,h,g,v,y,b;if(f=i.getEl("scroll"+t)){if(y=a.toLowerCase(),b=s.toLowerCase(),i.getEl("absend")&&e.css(i.getEl("absend"),y,i.layoutRect()[l]-1),!c)return void e.css(f,"display","none");e.css(f,"display","block"),d=i.getEl("body"),p=i.getEl("scroll"+t+"t"),m=d["client"+s]-2*o,m-=n&&r?f["client"+u]:0,h=d["scroll"+s],g=m/h,v={},v[y]=d["offset"+a]+o,v[b]=m,e.css(f,v),v={},v[y]=d["scroll"+a]*g,v[b]=m*g,e.css(p,v)}}var n,r,a;a=i.getEl("body"),n=a.scrollWidth>a.clientWidth,r=a.scrollHeight>a.clientHeight,t("h","Left","Width","contentW",n,"Height"),t("v","Top","Height","contentH",r,"Width")}function r(){function n(n,r,a,s,l){var c,u=i._id+"-scroll"+n,d=i.classPrefix;i.getEl().appendChild(e.createFragment('
          ')),i.draghelper=new t(u+"t",{start:function(){c=i.getEl("body")["scroll"+r],e.addClass(e.get(u),d+"active")},drag:function(e){var t,u,d,f,p=i.layoutRect();u=p.contentW>p.innerW,d=p.contentH>p.innerH,f=i.getEl("body")["client"+a]-2*o,f-=u&&d?i.getEl("scroll"+n)["client"+l]:0,t=f/i.getEl("body")["scroll"+a],i.getEl("body")["scroll"+r]=c+e["delta"+s]/t},stop:function(){e.removeClass(e.get(u),d+"active")}})}i.addClass("scroll"),n("v","Top","Height","Y","Width"),n("h","Left","Width","X","Height")}var i=this,o=2;i.settings.autoScroll&&(i._hasScroll||(i._hasScroll=!0,r(),i.on("wheel",function(e){var t=i.getEl("body");t.scrollLeft+=10*(e.deltaX||0),t.scrollTop+=10*e.deltaY,n()}),e.on(i.getEl("body"),"scroll",n)),n())}}}),r(G,[j,Y],function(e,t){return e.extend({Defaults:{layout:"fit",containerCls:"panel"},Mixins:[t],renderHtml:function(){var e=this,t=e._layout,n=e.settings.html;return e.preRender(),t.preRender(e),"undefined"==typeof n?n='
          '+t.renderHtml(e)+"
          ":("function"==typeof n&&(n=n.call(e)),e._hasBody=!1),'
          '+(e._preBodyHtml||"")+n+"
          "}})}),r(X,[V],function(e){function t(t,n,r){var i,o,a,s,l,c,u,d,f,p;return f=e.getViewPort(),o=e.getPos(n),a=o.x,s=o.y,t._fixed&&(a-=f.x,s-=f.y),i=t.getEl(),p=e.getSize(i),l=p.width,c=p.height,p=e.getSize(n),u=p.width,d=p.height,r=(r||"").split(""),"b"===r[0]&&(s+=d),"r"===r[1]&&(a+=u),"c"===r[0]&&(s+=Math.round(d/2)),"c"===r[1]&&(a+=Math.round(u/2)),"b"===r[3]&&(s-=c),"r"===r[4]&&(a-=l),"c"===r[3]&&(s-=Math.round(c/2)),"c"===r[4]&&(a-=Math.round(l/2)),{x:a,y:s,w:l,h:c}}return{testMoveRel:function(n,r){for(var i=e.getViewPort(),o=0;o0&&a.x+a.w0&&a.y+a.hi.x&&a.x+a.wi.y&&a.y+a.he?0:e+n>t?(e=t-n,0>e?0:e):e}var i=this;if(i.settings.constrainToViewport){var o=e.getViewPort(window),a=i.layoutRect();t=r(t,o.w+o.x,a.w),n=r(n,o.h+o.y,a.h)}return i._rendered?i.layoutRect({x:t,y:n}).repaint():(i.settings.x=t,i.settings.y=n),i.fire("move",{x:t,y:n}),i}}}),r(J,[V],function(e){return{resizeToContent:function(){this._layoutRect.autoResize=!0,this._lastRect=null,this.reflow()},resizeTo:function(t,n){if(1>=t||1>=n){var r=e.getWindowSize();t=1>=t?t*r.w:t,n=1>=n?n*r.h:n}return this._layoutRect.autoResize=!1,this.layoutRect({minW:t,minH:n,w:t,h:n}).reflow()},resizeBy:function(e,t){var n=this,r=n.layoutRect();return n.resizeTo(r.w+e,r.h+t)}}}),r(Q,[G,X,J,V],function(e,t,n,r){function i(e){var t;for(t=s.length;t--;)s[t]===e&&s.splice(t,1);for(t=l.length;t--;)l[t]===e&&l.splice(t,1)}var o,a,s=[],l=[],c,u=e.extend({Mixins:[t,n],init:function(e){function t(){var e,t=u.zIndex||65535,n;if(l.length)for(e=0;en&&(e.fixed(!1).layoutRect({y:e._autoFixY}).repaint(),t(!1,e._autoFixY-n)):(e._autoFixY=e.layoutRect().y,e._autoFixY'),n=n.firstChild,d.getContainerElm().appendChild(n),setTimeout(function(){r.addClass(n,i+"in"),r.addClass(d.getEl(),i+"in")},0),c=!0),l.push(d),t()}}),d.on("close hide",function(e){if(e.control==d){for(var n=l.length;n--;)l[n]===d&&l.splice(n,1);t()}}),d.on("show",function(){d.parents().each(function(e){return e._fixed?(d.fixed(!0),!1):void 0})}),e.popover&&(d._preBodyHtml='
          ',d.addClass("popover").addClass("bottom").addClass(d.isRtl()?"end":"start"))},fixed:function(e){var t=this;if(t._fixed!=e){if(t._rendered){var n=r.getViewPort();e?t.layoutRect().y-=n.y:t.layoutRect().y+=n.y}t.toggleClass("fixed",e),t._fixed=e}return t},show:function(){var e=this,t,n=e._super();for(t=s.length;t--&&s[t]!==e;);return-1===t&&s.push(e),n},hide:function(){return i(this),this._super()},hideAll:function(){u.hideAll()},close:function(){var e=this;return e.fire("close"),e.remove()},remove:function(){i(this),this._super()},postRender:function(){var e=this;return e.settings.bodyRole&&this.getEl("body").setAttribute("role",e.settings.bodyRole),e._super()}});return u.hideAll=function(){for(var e=s.length;e--;){var t=s[e];t&&t.settings.autohide&&(t.hide(),s.splice(e,1))}},u}),r(Z,[Q,G,V,K],function(e,t,n,r){var i=e.extend({modal:!0,Defaults:{border:1,layout:"flex",containerCls:"panel",role:"dialog",callbacks:{submit:function(){this.fire("submit",{data:this.toJSON()})},close:function(){this.close()}}},init:function(e){var n=this;n._super(e),n.isRtl()&&n.addClass("rtl"),n.addClass("window"),n._fixed=!0,e.buttons&&(n.statusbar=new t({layout:"flex",border:"1 0 0 0",spacing:3,padding:10,align:"center",pack:n.isRtl()?"start":"end",defaults:{type:"button"},items:e.buttons}),n.statusbar.addClass("foot"),n.statusbar.parent(n)),n.on("click",function(e){-1!=e.target.className.indexOf(n.classPrefix+"close")&&n.close() -}),n.on("cancel",function(){n.close()}),n.aria("describedby",n.describedBy||n._id+"-none"),n.aria("label",e.title),n._fullscreen=!1},recalc:function(){var e=this,t=e.statusbar,r,i,o,a;e._fullscreen&&(e.layoutRect(n.getWindowSize()),e.layoutRect().contentH=e.layoutRect().innerH),e._super(),r=e.layoutRect(),e.settings.title&&!e._fullscreen&&(i=r.headerW,i>r.w&&(o=r.x-Math.max(0,i/2),e.layoutRect({w:i,x:o}),a=!0)),t&&(t.layoutRect({w:e.layoutRect().innerW}).recalc(),i=t.layoutRect().minW+r.deltaW,i>r.w&&(o=r.x-Math.max(0,i-r.w),e.layoutRect({w:i,x:o}),a=!0)),a&&e.recalc()},initLayoutRect:function(){var e=this,t=e._super(),r=0,i;if(e.settings.title&&!e._fullscreen){i=e.getEl("head");var o=n.getSize(i);t.headerW=o.width,t.headerH=o.height,r+=t.headerH}e.statusbar&&(r+=e.statusbar.layoutRect().h),t.deltaH+=r,t.minH+=r,t.h+=r;var a=n.getWindowSize();return t.x=Math.max(0,a.w/2-t.w/2),t.y=Math.max(0,a.h/2-t.h/2),t},renderHtml:function(){var e=this,t=e._layout,n=e._id,r=e.classPrefix,i=e.settings,o="",a="",s=i.html;return e.preRender(),t.preRender(e),i.title&&(o='
          '+e.encode(i.title)+'
          '),i.url&&(s=''),"undefined"==typeof s&&(s=t.renderHtml(e)),e.statusbar&&(a=e.statusbar.renderHtml()),'
          '+o+'
          '+s+"
          "+a+"
          "},fullscreen:function(e){var t=this,r=document.documentElement,i,o=t.classPrefix,a;if(e!=t._fullscreen)if(n.on(window,"resize",function(){var e;if(t._fullscreen)if(i)t._timer||(t._timer=setTimeout(function(){var e=n.getWindowSize();t.moveTo(0,0).resizeTo(e.w,e.h),t._timer=0},50));else{e=(new Date).getTime();var r=n.getWindowSize();t.moveTo(0,0).resizeTo(r.w,r.h),(new Date).getTime()-e>50&&(i=!0)}}),a=t.layoutRect(),t._fullscreen=e,e){t._initial={x:a.x,y:a.y,w:a.w,h:a.h},t._borderBox=t.parseBox("0"),t.getEl("head").style.display="none",a.deltaH-=a.headerH+2,n.addClass(r,o+"fullscreen"),n.addClass(document.body,o+"fullscreen"),t.addClass("fullscreen");var s=n.getWindowSize();t.moveTo(0,0).resizeTo(s.w,s.h)}else t._borderBox=t.parseBox(t.settings.border),t.getEl("head").style.display="",a.deltaH+=a.headerH,n.removeClass(r,o+"fullscreen"),n.removeClass(document.body,o+"fullscreen"),t.removeClass("fullscreen"),t.moveTo(t._initial.x,t._initial.y).resizeTo(t._initial.w,t._initial.h);return t.reflow()},postRender:function(){var e=this,t;setTimeout(function(){e.addClass("in")},0),e._super(),e.statusbar&&e.statusbar.postRender(),e.focus(),this.dragHelper=new r(e._id+"-dragh",{start:function(){t={x:e.layoutRect().x,y:e.layoutRect().y}},drag:function(n){e.moveTo(t.x+n.deltaX,t.y+n.deltaY)}}),e.on("submit",function(t){t.isDefaultPrevented()||e.close()})},submit:function(){return this.fire("submit",{data:this.toJSON()})},remove:function(){var e=this,t=e.classPrefix;e.dragHelper.destroy(),e._super(),e.statusbar&&this.statusbar.remove(),e._fullscreen&&(n.removeClass(document.documentElement,t+"fullscreen"),n.removeClass(document.body,t+"fullscreen"))}});return i}),r(et,[Z],function(e){var t=e.extend({init:function(e){e={border:1,padding:20,layout:"flex",pack:"center",align:"center",containerCls:"panel",autoScroll:!0,buttons:{type:"button",text:"Ok",action:"ok"},items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200}},this._super(e)},Statics:{OK:1,OK_CANCEL:2,YES_NO:3,YES_NO_CANCEL:4,msgBox:function(n){var r,i=n.callback||function(){};switch(n.buttons){case t.OK_CANCEL:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close(),i(!0)}},{type:"button",text:"Cancel",onClick:function(e){e.control.parents()[1].close(),i(!1)}}];break;case t.YES_NO:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close(),i(!0)}}];break;case t.YES_NO_CANCEL:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close()}}];break;default:r=[{type:"button",text:"Ok",subtype:"primary",onClick:function(e){e.control.parents()[1].close(),i(!0)}}]}return new e({padding:20,x:n.x,y:n.y,minWidth:300,minHeight:100,layout:"flex",pack:"center",align:"center",buttons:r,title:n.title,role:"alertdialog",items:{type:"label",multiline:!0,maxWidth:500,maxHeight:200,text:n.text},onPostRender:function(){this.aria("describedby",this.items()[0]._id)},onClose:n.onClose,onCancel:function(){i(!1)}}).renderTo(document.body).reflow()},alert:function(e,n){return"string"==typeof e&&(e={text:e}),e.callback=n,t.msgBox(e)},confirm:function(e,n){return"string"==typeof e&&(e={text:e}),e.callback=n,e.buttons=t.OK_CANCEL,t.msgBox(e)}}});return t}),r(tt,[Z,et],function(e,t){return function(n){function r(){return o.length?o[o.length-1]:void 0}var i=this,o=[];i.windows=o,i.open=function(t,r){var i;return n.editorManager.activeEditor=n,t.title=t.title||" ",t.url=t.url||t.file,t.url&&(t.width=parseInt(t.width||320,10),t.height=parseInt(t.height||240,10)),t.body&&(t.items={defaults:t.defaults,type:t.bodyType||"form",items:t.body}),t.url||t.buttons||(t.buttons=[{text:"Ok",subtype:"primary",onclick:function(){i.find("form")[0].submit(),i.close()}},{text:"Cancel",onclick:function(){i.close()}}]),i=new e(t),o.push(i),i.on("close",function(){for(var e=o.length;e--;)o[e]===i&&o.splice(e,1);n.focus()}),t.data&&i.on("postRender",function(){this.find("*").each(function(e){var n=e.name();n in t.data&&e.value(t.data[n])})}),i.features=t||{},i.params=r||{},n.nodeChanged(),i.renderTo(document.body).reflow()},i.alert=function(e,r,i){t.alert(e,function(){r?r.call(i||this):n.focus()})},i.confirm=function(e,n,r){t.confirm(e,function(e){n.call(r||this,e)})},i.close=function(){r()&&r().close()},i.getParams=function(){return r()?r().params:null},i.setParams=function(e){r()&&(r().params=e)}}}),r(nt,[R,B,x,h,g,p],function(e,t,n,r,i,o){return function(a){function s(e,t){try{a.getDoc().execCommand(e,!1,t)}catch(n){}}function l(){var e=a.getDoc().documentMode;return e?e:6}function c(e){return e.isDefaultPrevented()}function u(){function t(e){var t=new MutationObserver(function(){});o.each(a.getBody().getElementsByTagName("*"),function(e){"SPAN"==e.tagName&&e.setAttribute("mce-data-marked",1),!e.hasAttribute("data-mce-style")&&e.hasAttribute("style")&&a.dom.setAttrib(e,"style",e.getAttribute("style"))}),t.observe(a.getDoc(),{childList:!0,attributes:!0,subtree:!0,attributeFilter:["style"]}),a.getDoc().execCommand(e?"ForwardDelete":"Delete",!1,null);var n=a.selection.getRng(),r=n.startContainer.parentNode;o.each(t.takeRecords(),function(e){if("style"==e.attributeName){var t=e.target.getAttribute("data-mce-style");t?e.target.setAttribute("style",t):e.target.removeAttribute("style")}o.each(e.addedNodes,function(e){if("SPAN"==e.nodeName&&!e.getAttribute("mce-data-marked")){var t,i;e==r&&(t=n.startOffset,i=e.firstChild),V.remove(e,!0),i&&(n.setStart(i,t),n.setEnd(i,t),a.selection.setRng(n))}})}),t.disconnect(),o.each(a.dom.select("span[mce-data-marked]"),function(e){e.removeAttribute("mce-data-marked")})}var n=a.getDoc();window.MutationObserver&&(a.on("keydown",function(n){var r=n.keyCode==W,i=e.metaKeyPressed(n);if(!c(n)&&(r||n.keyCode==z)){var o=a.selection.getRng(),s=o.startContainer,l=o.startOffset;if(!i&&o.collapsed&&3==s.nodeType&&(r?l0))return;n.preventDefault(),i&&a.selection.getSel().modify("extend",r?"forward":"backward","word"),t(r)}}),a.on("keypress",function(n){c(n)||U.isCollapsed()||!n.charCode||e.metaKeyPressed(n)||(n.preventDefault(),t(!0),a.selection.setContent(String.fromCharCode(n.charCode)))}),a.addCommand("Delete",function(){t()}),a.addCommand("ForwardDelete",function(){t(!0)}),a.on("dragstart",function(e){e.dataTransfer.setData("mce-internal",a.selection.getContent())}),a.on("drop",function(e){if(!c(e)){var r=e.dataTransfer.getData("mce-internal");r&&n.caretRangeFromPoint&&(e.preventDefault(),t(),a.selection.setRng(n.caretRangeFromPoint(e.x,e.y)),a.insertContent(r))}}),a.on("cut",function(e){!c(e)&&e.clipboardData&&(e.preventDefault(),e.clipboardData.clearData(),e.clipboardData.setData("text/html",a.selection.getContent()),e.clipboardData.setData("text/plain",a.selection.getContent({format:"text"})),t(!0))}))}function d(){function e(e){var t=V.create("body"),n=e.cloneContents();return t.appendChild(n),U.serializer.serialize(t,{format:"html"})}function n(n){if(!n.setStart){if(n.item)return!1;var r=n.duplicate();return r.moveToElementText(a.getBody()),t.compareRanges(n,r)}var i=e(n),o=V.createRng();o.selectNode(a.getBody());var s=e(o);return i===s}a.on("keydown",function(e){var t=e.keyCode,r,i;if(!c(e)&&(t==W||t==z)){if(r=a.selection.isCollapsed(),i=a.getBody(),r&&!V.isEmpty(i))return;if(!r&&!n(a.selection.getRng()))return;e.preventDefault(),a.setContent(""),i.firstChild&&V.isBlock(i.firstChild)?a.selection.setCursorLocation(i.firstChild,0):a.selection.setCursorLocation(i,0),a.nodeChanged()}})}function f(){a.on("keydown",function(t){!c(t)&&65==t.keyCode&&e.metaKeyPressed(t)&&(t.preventDefault(),a.execCommand("SelectAll"))})}function p(){a.settings.content_editable||(V.bind(a.getDoc(),"focusin",function(){U.setRng(U.getRng())}),V.bind(a.getDoc(),"mousedown",function(e){e.target==a.getDoc().documentElement&&(a.getBody().focus(),U.setRng(U.getRng()))}))}function m(){a.on("keydown",function(e){if(!c(e)&&e.keyCode===z&&U.isCollapsed()&&0===U.getRng(!0).startOffset){var t=U.getNode(),n=t.previousSibling;if("HR"==t.nodeName)return V.remove(t),void e.preventDefault();n&&n.nodeName&&"hr"===n.nodeName.toLowerCase()&&(V.remove(n),e.preventDefault())}})}function h(){window.Range.prototype.getClientRects||a.on("mousedown",function(e){if(!c(e)&&"HTML"===e.target.nodeName){var t=a.getBody();t.blur(),setTimeout(function(){t.focus()},0)}})}function g(){a.on("click",function(e){e=e.target,/^(IMG|HR)$/.test(e.nodeName)&&U.getSel().setBaseAndExtent(e,0,e,1),"A"==e.nodeName&&V.hasClass(e,"mce-item-anchor")&&U.select(e),a.nodeChanged()})}function v(){function e(){var e=V.getAttribs(U.getStart().cloneNode(!1));return function(){var t=U.getStart();t!==a.getBody()&&(V.setAttrib(t,"style",null),F(e,function(e){t.setAttributeNode(e.cloneNode(!0))}))}}function t(){return!U.isCollapsed()&&V.getParent(U.getStart(),V.isBlock)!=V.getParent(U.getEnd(),V.isBlock)}a.on("keypress",function(n){var r;return c(n)||8!=n.keyCode&&46!=n.keyCode||!t()?void 0:(r=e(),a.getDoc().execCommand("delete",!1,null),r(),n.preventDefault(),!1)}),V.bind(a.getDoc(),"cut",function(n){var r;!c(n)&&t()&&(r=e(),setTimeout(function(){r()},0))})}function y(){var e,n;a.on("selectionchange",function(){n&&(clearTimeout(n),n=0),n=window.setTimeout(function(){var n=U.getRng();e&&t.compareRanges(n,e)||(a.nodeChanged(),e=n)},50)})}function b(){document.body.setAttribute("role","application")}function C(){a.on("keydown",function(e){if(!c(e)&&e.keyCode===z&&U.isCollapsed()&&0===U.getRng(!0).startOffset){var t=U.getNode().previousSibling;if(t&&t.nodeName&&"table"===t.nodeName.toLowerCase())return e.preventDefault(),!1}})}function x(){l()>7||(s("RespectVisibilityInDesign",!0),a.contentStyles.push(".mceHideBrInPre pre br {display: none}"),V.addClass(a.getBody(),"mceHideBrInPre"),$.addNodeFilter("pre",function(e){for(var t=e.length,r,i,o,a;t--;)for(r=e[t].getAll("br"),i=r.length;i--;)o=r[i],a=o.prev,a&&3===a.type&&"\n"!=a.value.charAt(a.value-1)?a.value+="\n":o.parent.insert(new n("#text",3),o,!0).value="\n"}),j.addNodeFilter("pre",function(e){for(var t=e.length,n,r,i,o;t--;)for(n=e[t].getAll("br"),r=n.length;r--;)i=n[r],o=i.prev,o&&3==o.type&&(o.value=o.value.replace(/\r?\n$/,""))}))}function w(){V.bind(a.getBody(),"mouseup",function(){var e,t=U.getNode();"IMG"==t.nodeName&&((e=V.getStyle(t,"width"))&&(V.setAttrib(t,"width",e.replace(/[^0-9%]+/g,"")),V.setStyle(t,"width","")),(e=V.getStyle(t,"height"))&&(V.setAttrib(t,"height",e.replace(/[^0-9%]+/g,"")),V.setStyle(t,"height","")))})}function _(){a.on("keydown",function(t){var n,r,i,o,s;if(!c(t)&&t.keyCode==e.BACKSPACE&&(n=U.getRng(),r=n.startContainer,i=n.startOffset,o=V.getRoot(),s=r,n.collapsed&&0===i)){for(;s&&s.parentNode&&s.parentNode.firstChild==s&&s.parentNode!=o;)s=s.parentNode;"BLOCKQUOTE"===s.tagName&&(a.formatter.toggle("blockquote",null,s),n=V.createRng(),n.setStart(r,0),n.setEnd(r,0),U.setRng(n))}})}function N(){function e(){a._refreshContentEditable(),s("StyleWithCSS",!1),s("enableInlineTableEditing",!1),q.object_resizing||s("enableObjectResizing",!1)}q.readonly||a.on("BeforeExecCommand MouseDown",e)}function E(){function e(){F(V.select("a"),function(e){var t=e.parentNode,n=V.getRoot();if(t.lastChild===e){for(;t&&!V.isBlock(t);){if(t.parentNode.lastChild!==t||t===n)return;t=t.parentNode}V.add(t,"br",{"data-mce-bogus":1})}})}a.on("SetContent ExecCommand",function(t){("setcontent"==t.type||"mceInsertLink"===t.command)&&e()})}function S(){q.forced_root_block&&a.on("init",function(){s("DefaultParagraphSeparator",q.forced_root_block)})}function k(){a.on("Undo Redo SetContent",function(e){e.initial||a.execCommand("mceRepaint")})}function T(){a.on("keydown",function(e){var t;c(e)||e.keyCode!=z||(t=a.getDoc().selection.createRange(),t&&t.item&&(e.preventDefault(),a.undoManager.beforeChange(),V.remove(t.item(0)),a.undoManager.add()))})}function R(){var e;l()>=10&&(e="",F("p div h1 h2 h3 h4 h5 h6".split(" "),function(t,n){e+=(n>0?",":"")+t+":empty"}),a.contentStyles.push(e+"{padding-right: 1px !important}"))}function A(){l()<9&&($.addNodeFilter("noscript",function(e){for(var t=e.length,n,r;t--;)n=e[t],r=n.firstChild,r&&n.attr("data-mce-innertext",r.value)}),j.addNodeFilter("noscript",function(e){for(var t=e.length,i,o,a;t--;)i=e[t],o=e[t].firstChild,o?o.value=r.decode(o.value):(a=i.attributes.map["data-mce-innertext"],a&&(i.attr("data-mce-innertext",null),o=new n("#text",3),o.value=a,o.raw=!0,i.append(o)))}))}function B(){function e(e,t){var n=i.createTextRange();try{n.moveToPoint(e,t)}catch(r){n=null}return n}function t(t){var r;t.button?(r=e(t.x,t.y),r&&(r.compareEndPoints("StartToStart",a)>0?r.setEndPoint("StartToStart",a):r.setEndPoint("EndToEnd",a),r.select())):n()}function n(){var e=r.selection.createRange();a&&!e.item&&0===e.compareEndPoints("StartToEnd",e)&&a.select(),V.unbind(r,"mouseup",n),V.unbind(r,"mousemove",t),a=o=0}var r=V.doc,i=r.body,o,a,s;r.documentElement.unselectable=!0,V.bind(r,"mousedown contextmenu",function(i){if("HTML"===i.target.nodeName){if(o&&n(),s=r.documentElement,s.scrollHeight>s.clientHeight)return;o=1,a=e(i.x,i.y),a&&(V.bind(r,"mouseup",n),V.bind(r,"mousemove",t),V.getRoot().focus(),a.select())}})}function D(){a.on("keyup focusin",function(t){65==t.keyCode&&e.metaKeyPressed(t)||U.normalize()})}function L(){a.contentStyles.push("img:-moz-broken {-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}")}function H(){a.inline||a.on("keydown",function(){document.activeElement==document.body&&a.getWin().focus()})}function M(){a.inline||(a.contentStyles.push("body {min-height: 150px}"),a.on("click",function(e){"HTML"==e.target.nodeName&&(a.getBody().focus(),a.selection.normalize(),a.nodeChanged())}))}function P(){i.mac&&a.on("keydown",function(t){!e.metaKeyPressed(t)||37!=t.keyCode&&39!=t.keyCode||(t.preventDefault(),a.selection.getSel().modify("move",37==t.keyCode?"backward":"forward","word"))})}function O(){s("AutoUrlDetect",!1)}function I(){a.inline||a.on("init",function(){a.getDoc().designMode="on"})}var F=o.each,z=e.BACKSPACE,W=e.DELETE,V=a.dom,U=a.selection,q=a.settings,$=a.parser,j=a.serializer,K=i.gecko,Y=i.ie,G=i.webkit;C(),_(),d(),D(),G&&(u(),p(),g(),S(),i.iOS?(y(),H(),M()):f()),Y&&i.ie<11&&(m(),b(),x(),w(),T(),R(),A(),B()),i.ie>=11&&(M(),I()),i.ie&&(f(),O()),K&&(m(),h(),v(),N(),E(),k(),L(),P())}}),r(rt,[p],function(e){function t(){return!1}function n(){return!0}var r="__bindings",i=e.makeMap("focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragstart dragend dragover draggesture dragdrop drop drag"," ");return{fire:function(e,i,o){var a=this,s,l,c,u,d;if(e=e.toLowerCase(),i=i||{},i.type=e,i.target||(i.target=a),i.preventDefault||(i.preventDefault=function(){i.isDefaultPrevented=n},i.stopPropagation=function(){i.isPropagationStopped=n},i.stopImmediatePropagation=function(){i.isImmediatePropagationStopped=n},i.isDefaultPrevented=t,i.isPropagationStopped=t,i.isImmediatePropagationStopped=t),a[r]&&(s=a[r][e]))for(l=0,c=s.length;c>l&&(s[l]=u=s[l],!i.isImmediatePropagationStopped());l++)if(u.call(a,i)===!1)return i.preventDefault(),i;if(o!==!1&&a.parent)for(d=a.parent();d&&!i.isPropagationStopped();)d.fire(e,i,!1),d=d.parent();return i},on:function(e,t){var n=this,o,a,s,l;if(t===!1&&(t=function(){return!1}),t)for(s=e.toLowerCase().split(" "),l=s.length;l--;)e=s[l],o=n[r],o||(o=n[r]={}),a=o[e],a||(a=o[e]=[],n.bindNative&&i[e]&&n.bindNative(e)),a.push(t);return n},off:function(e,t){var n=this,o,a=n[r],s,l,c,u;if(a)if(e)for(c=e.toLowerCase().split(" "),o=c.length;o--;){if(e=c[o],s=a[e],!e){for(l in a)a[e].length=0;return n}if(s){if(t)for(u=s.length;u--;)s[u]===t&&s.splice(u,1);else s.length=0;!s.length&&n.unbindNative&&i[e]&&(n.unbindNative(e),delete a[e])}}else{if(n.unbindNative)for(e in a)n.unbindNative(e);n[r]=[]}return n},hasEventListeners:function(e){var t=this[r];return e=e.toLowerCase(),!(!t||!t[e]||0===t[e].length)}}}),r(it,[p,g],function(e,t){var n=e.each,r=e.explode,i={f9:120,f10:121,f11:122};return function(o){var a=this,s={};o.on("keyup keypress keydown",function(e){(e.altKey||e.ctrlKey||e.metaKey)&&n(s,function(n){var r=t.mac?e.metaKey:e.ctrlKey;if(n.ctrl==r&&n.alt==e.altKey&&n.shift==e.shiftKey)return e.keyCode==n.keyCode||e.charCode&&e.charCode==n.charCode?(e.preventDefault(),"keydown"==e.type&&n.func.call(n.scope),!0):void 0})}),a.add=function(t,a,l,c){var u;return u=l,"string"==typeof l?l=function(){o.execCommand(u,!1,null)}:e.isArray(u)&&(l=function(){o.execCommand(u[0],u[1],u[2])}),n(r(t.toLowerCase()),function(e){var t={func:l,scope:c||o,desc:o.translate(a),alt:!1,ctrl:!1,shift:!1};n(r(e,"+"),function(e){switch(e){case"alt":case"ctrl":case"shift":t[e]=!0;break;default:t.charCode=e.charCodeAt(0),t.keyCode=i[e]||e.toUpperCase().charCodeAt(0)}}),s[(t.ctrl?"ctrl":"")+","+(t.alt?"alt":"")+","+(t.shift?"shift":"")+","+t.keyCode]=t}),!0}}}),r(ot,[y,C,x,k,S,D,L,H,M,P,O,I,b,l,tt,w,N,nt,g,p,rt,it],function(e,n,r,i,o,a,s,l,c,u,d,f,p,m,h,g,v,y,b,C,x,w){function _(e,t){return"selectionchange"==t?e.getDoc():!e.inline&&/^mouse|click|contextmenu|drop/.test(t)?e.getDoc():e.getBody()}function N(e,t,r){var i=this,o,a;o=i.documentBaseUrl=r.documentBaseURL,a=r.baseURI,i.settings=t=T({id:e,theme:"modern",delta_width:0,delta_height:0,popup_css:"",plugins:"",document_base_url:o,add_form_submit_trigger:!0,submit_patch:!0,add_unload_trigger:!0,convert_urls:!0,relative_urls:!0,remove_script_host:!0,object_resizing:!0,doctype:"",visual:!0,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",forced_root_block:"p",hidden_input:!0,padd_empty_editor:!0,render_ui:!0,indentation:"30px",inline_styles:!0,convert_fonts_to_spans:!0,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",indent_after:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",validate:!0,entity_encoding:"named",url_converter:i.convertURL,url_converter_scope:i,ie7_compat:!0},t),n.language=t.language||"en",n.languageLoad=t.language_load,n.baseURL=r.baseURL,i.id=t.id=e,i.isNotDirty=!0,i.plugins={},i.documentBaseURI=new f(t.document_base_url||o,{base_uri:a}),i.baseURI=a,i.contentCSS=[],i.contentStyles=[],i.shortcuts=new w(i),i.execCommands={},i.queryStateCommands={},i.queryValueCommands={},i.loadedCSS={},i.suffix=r.suffix,i.editorManager=r,i.inline=t.inline,r.fire("SetupEditor",i),i.execCallback("setup",i)}var E=e.DOM,S=n.ThemeManager,k=n.PluginManager,T=C.extend,R=C.each,A=C.explode,B=C.inArray,D=C.trim,L=C.resolve,H=m.Event,M=b.gecko,P=b.ie;return N.prototype={render:function(){function e(){E.unbind(window,"ready",e),n.render()}function t(){var e=p.ScriptLoader;if(r.language&&"en"!=r.language&&!r.language_url&&(r.language_url=n.editorManager.baseURL+"/langs/"+r.language+".js"),r.language_url&&e.add(r.language_url),r.theme&&"function"!=typeof r.theme&&"-"!=r.theme.charAt(0)&&!S.urls[r.theme]){var t=r.theme_url;t=t?n.documentBaseURI.toAbsolute(t):"themes/"+r.theme+"/theme"+o+".js",S.load(r.theme,t)}C.isArray(r.plugins)&&(r.plugins=r.plugins.join(" ")),R(r.external_plugins,function(e,t){k.load(t,e),r.plugins+=" "+t}),R(r.plugins.split(/[ ,]/),function(e){if(e=D(e),e&&!k.urls[e])if("-"==e.charAt(0)){e=e.substr(1,e.length);var t=k.dependencies(e);R(t,function(e){var t={prefix:"plugins/",resource:e,suffix:"/plugin"+o+".js"};e=k.createUrl(t,e),k.load(e.resource,e)})}else k.load(e,{prefix:"plugins/",resource:e,suffix:"/plugin"+o+".js"})}),e.loadQueue(function(){n.removed||n.init()})}var n=this,r=n.settings,i=n.id,o=n.suffix;if(!H.domLoaded)return void E.bind(window,"ready",e);if(n.getElement()&&b.contentEditable){r.inline?n.inline=!0:(n.orgVisibility=n.getElement().style.visibility,n.getElement().style.visibility="hidden");var a=n.getElement().form||E.getParent(i,"form");a&&(n.formElement=a,r.hidden_input&&!/TEXTAREA|INPUT/i.test(n.getElement().nodeName)&&(E.insertAfter(E.create("input",{type:"hidden",name:i}),i),n.hasHiddenInput=!0),n.formEventDelegate=function(e){n.fire(e.type,e)},E.bind(a,"submit reset",n.formEventDelegate),n.on("reset",function(){n.setContent(n.startContent,{format:"raw"})}),!r.submit_patch||a.submit.nodeType||a.submit.length||a._mceOldSubmit||(a._mceOldSubmit=a.submit,a.submit=function(){return n.editorManager.triggerSave(),n.isNotDirty=!0,a._mceOldSubmit(a)})),n.windowManager=new h(n),"xml"==r.encoding&&n.on("GetContent",function(e){e.save&&(e.content=E.encode(e.content))}),r.add_form_submit_trigger&&n.on("submit",function(){n.initialized&&n.save()}),r.add_unload_trigger&&(n._beforeUnload=function(){!n.initialized||n.destroyed||n.isHidden()||n.save({format:"raw",no_events:!0,set_dirty:!1})},n.editorManager.on("BeforeUnload",n._beforeUnload)),t()}},init:function(){function e(n){var r=k.get(n),i,o;i=k.urls[n]||t.documentBaseUrl.replace(/\/$/,""),n=D(n),r&&-1===B(m,n)&&(R(k.dependencies(n),function(t){e(t)}),o=new r(t,i),t.plugins[n]=o,o.init&&(o.init(t,i),m.push(n)))}var t=this,n=t.settings,r=t.getElement(),i,o,a,s,l,c,u,d,f,p,m=[];if(t.rtl=this.editorManager.i18n.rtl,t.editorManager.add(t),n.aria_label=n.aria_label||E.getAttrib(r,"aria-label",t.getLang("aria.rich_text_area")),n.theme&&("function"!=typeof n.theme?(n.theme=n.theme.replace(/-/,""),l=S.get(n.theme),t.theme=new l(t,S.urls[n.theme]),t.theme.init&&t.theme.init(t,S.urls[n.theme]||t.documentBaseUrl.replace(/\/$/,""))):t.theme=n.theme),R(n.plugins.replace(/\-/g,"").split(/[ ,]/),e),n.render_ui&&t.theme&&(t.orgDisplay=r.style.display,"function"!=typeof n.theme?(i=n.width||r.style.width||r.offsetWidth,o=n.height||r.style.height||r.offsetHeight,a=n.min_height||100,f=/^[0-9\.]+(|px)$/i,f.test(""+i)&&(i=Math.max(parseInt(i,10)+(l.deltaWidth||0),100)),f.test(""+o)&&(o=Math.max(parseInt(o,10)+(l.deltaHeight||0),a)),l=t.theme.renderUI({targetNode:r,width:i,height:o,deltaWidth:n.delta_width,deltaHeight:n.delta_height}),n.content_editable||(E.setStyles(l.sizeContainer||l.editorContainer,{wi2dth:i,h2eight:o}),o=(l.iframeHeight||o)+("number"==typeof o?l.deltaHeight||0:""),a>o&&(o=a))):(l=n.theme(t,r),l.editorContainer.nodeType&&(l.editorContainer=l.editorContainer.id=l.editorContainer.id||t.id+"_parent"),l.iframeContainer.nodeType&&(l.iframeContainer=l.iframeContainer.id=l.iframeContainer.id||t.id+"_iframecontainer"),o=l.iframeHeight||r.offsetHeight),t.editorContainer=l.editorContainer),n.content_css&&R(A(n.content_css),function(e){t.contentCSS.push(t.documentBaseURI.toAbsolute(e))}),n.content_style&&t.contentStyles.push(n.content_style),n.content_editable)return r=s=l=null,t.initContentBody();for(t.iframeHTML=n.doctype+"",n.document_base_url!=t.documentBaseUrl&&(t.iframeHTML+=''),!b.caretAfter&&n.ie7_compat&&(t.iframeHTML+=''),t.iframeHTML+='',p=0;p',t.loadedCSS[h]=!0}u=n.body_id||"tinymce",-1!=u.indexOf("=")&&(u=t.getParam("body_id","","hash"),u=u[t.id]||u),d=n.body_class||"",-1!=d.indexOf("=")&&(d=t.getParam("body_class","","hash"),d=d[t.id]||""),t.iframeHTML+='
          ";var g='javascript:(function(){document.open();document.domain="'+document.domain+'";var ed = window.parent.tinymce.get("'+t.id+'");document.write(ed.iframeHTML);document.close();ed.initContentBody(true);})()';if(document.domain!=location.hostname&&(c=g),s=E.add(l.iframeContainer,"iframe",{id:t.id+"_ifr",src:c||'javascript:""',frameBorder:"0",allowTransparency:"true",title:t.editorManager.translate("Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help"),style:{width:"100%",height:o,display:"block"}}),P)try{t.getDoc()}catch(v){s.src=c=g}t.contentAreaContainer=l.iframeContainer,l.editorContainer&&(E.get(l.editorContainer).style.display=t.orgDisplay),E.get(t.id).style.display="none",E.setAttrib(t.id,"aria-hidden",!0),c||t.initContentBody(),r=s=l=null},initContentBody:function(t){var n=this,o=n.settings,f=E.get(n.id),p=n.getDoc(),m,h;o.inline||(n.getElement().style.visibility=n.orgVisibility),t||o.content_editable||(p.open(),p.write(n.iframeHTML),p.close()),o.content_editable&&(n.on("remove",function(){var e=this.getBody();E.removeClass(e,"mce-content-body"),E.removeClass(e,"mce-edit-focus"),E.setAttrib(e,"tabIndex",null),E.setAttrib(e,"contentEditable",null)}),E.addClass(f,"mce-content-body"),f.tabIndex=-1,n.contentDocument=p=o.content_document||document,n.contentWindow=o.content_window||window,n.bodyElement=f,o.content_document=o.content_window=null,o.root_name=f.nodeName.toLowerCase()),m=n.getBody(),m.disabled=!0,o.readonly||(n.inline&&"static"==E.getStyle(m,"position",!0)&&(m.style.position="relative"),m.contentEditable=n.getParam("content_editable_state",!0)),m.disabled=!1,n.schema=new g(o),n.dom=new e(p,{keep_values:!0,url_converter:n.convertURL,url_converter_scope:n,hex_colors:o.force_hex_style_colors,class_filter:o.class_filter,update_styles:!0,root_element:o.content_editable?n.id:null,collect:o.content_editable,schema:n.schema,onSetAttrib:function(e){n.fire("SetAttrib",e)}}),n.parser=new v(o,n.schema),n.parser.addAttributeFilter("src,href,style",function(e,t){for(var r=e.length,i,o=n.dom,a,s;r--;)i=e[r],a=i.attr(t),s="data-mce-"+t,i.attributes.map[s]||("style"===t?i.attr(s,o.serializeStyle(o.parseStyle(a),i.name)):i.attr(s,n.convertURL(a,t,i.name)))}),n.parser.addNodeFilter("script",function(e){for(var t=e.length,n;t--;)n=e[t],n.attr("type","mce-"+(n.attr("type")||"text/javascript"))}),n.parser.addNodeFilter("#cdata",function(e){for(var t=e.length,n;t--;)n=e[t],n.type=8,n.name="#comment",n.value="[CDATA["+n.value+"]]"}),n.parser.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(e){for(var t=e.length,i,o=n.schema.getNonEmptyElements();t--;)i=e[t],i.isEmpty(o)&&(i.empty().append(new r("br",1)).shortEnded=!0)}),n.serializer=new i(o,n),n.selection=new a(n.dom,n.getWin(),n.serializer,n),n.formatter=new s(n),n.undoManager=new l(n),n.forceBlocks=new u(n),n.enterKey=new c(n),n.editorCommands=new d(n),n.fire("PreInit"),o.browser_spellcheck||o.gecko_spellcheck||(p.body.spellcheck=!1,E.setAttrib(m,"spellcheck","false")),n.fire("PostRender"),n.quirks=y(n),o.directionality&&(m.dir=o.directionality),o.nowrap&&(m.style.whiteSpace="nowrap"),o.protect&&n.on("BeforeSetContent",function(e){R(o.protect,function(t){e.content=e.content.replace(t,function(e){return""})})}),n.on("SetContent",function(){n.addVisual(n.getBody())}),o.padd_empty_editor&&n.on("PostProcess",function(e){e.content=e.content.replace(/^(]*>( | |\s|\u00a0|)<\/p>[\r\n]*|
          [\r\n]*)$/,"")}),n.load({initial:!0,format:"html"}),n.startContent=n.getContent({format:"raw"}),n.initialized=!0,R(n._pendingNativeEvents,function(e){n.dom.bind(_(n,e),e,function(e){n.fire(e.type,e)})}),n.fire("init"),n.focus(!0),n.nodeChanged({initial:!0}),n.execCallback("init_instance_callback",n),n.contentStyles.length>0&&(h="",R(n.contentStyles,function(e){h+=e+"\r\n"}),n.dom.addStyle(h)),R(n.contentCSS,function(e){n.loadedCSS[e]||(n.dom.loadCSS(e),n.loadedCSS[e]=!0)}),o.auto_focus&&setTimeout(function(){var e=n.editorManager.get(o.auto_focus);e.selection.select(e.getBody(),1),e.selection.collapse(1),e.getBody().focus(),e.getWin().focus()},100),f=p=m=null},focus:function(e){var t,n=this,r=n.selection,i=n.settings.content_editable,o,a,s=n.getDoc(),l;e||(o=r.getRng(),o.item&&(a=o.item(0)),n._refreshContentEditable(),i||(b.opera||n.getBody().focus(),n.getWin().focus()),(M||i)&&(l=n.getBody(),l.setActive&&b.ie<11?l.setActive():l.focus(),i&&r.normalize()),a&&a.ownerDocument==s&&(o=s.body.createControlRange(),o.addElement(a),o.select())),n.editorManager.activeEditor!=n&&((t=n.editorManager.activeEditor)&&t.fire("deactivate",{relatedTarget:n}),n.fire("activate",{relatedTarget:t})),n.editorManager.activeEditor=n},execCallback:function(e){var t=this,n=t.settings[e],r;if(n)return t.callbackLookup&&(r=t.callbackLookup[e])&&(n=r.func,r=r.scope),"string"==typeof n&&(r=n.replace(/\.\w+$/,""),r=r?L(r):0,n=L(n),t.callbackLookup=t.callbackLookup||{},t.callbackLookup[e]={func:n,scope:r}),n.apply(r||t,Array.prototype.slice.call(arguments,1))},translate:function(e){var t=this.settings.language||"en",n=this.editorManager.i18n;return e?n.data[t+"."+e]||e.replace(/\{\#([^\}]+)\}/g,function(e,r){return n.data[t+"."+r]||"{#"+r+"}"}):""},getLang:function(e,n){return this.editorManager.i18n.data[(this.settings.language||"en")+"."+e]||(n!==t?n:"{#"+e+"}")},getParam:function(e,t,n){var r=e in this.settings?this.settings[e]:t,i;return"hash"===n?(i={},"string"==typeof r?R(r.split(r.indexOf("=")>0?/[;,](?![^=;,]*(?:[;,]|$))/:","),function(e){e=e.split("="),i[D(e[0])]=D(e.length>1?e[1]:e)}):i=r,i):r},nodeChanged:function(){var e=this,t=e.selection,n,r,i;e.initialized&&!e.settings.disable_nodechange&&(i=e.getBody(),n=t.getStart()||i,n=P&&n.ownerDocument!=e.getDoc()?e.getBody():n,"IMG"==n.nodeName&&t.isCollapsed()&&(n=n.parentNode),r=[],e.dom.getParent(n,function(e){return e===i?!0:void r.push(e)}),e.fire("NodeChange",{element:n,parents:r}))},addButton:function(e,t){var n=this;t.cmd&&(t.onclick=function(){n.execCommand(t.cmd)}),t.text||t.icon||(t.icon=e),n.buttons=n.buttons||{},t.tooltip=t.tooltip||t.title,n.buttons[e]=t},addMenuItem:function(e,t){var n=this;t.cmd&&(t.onclick=function(){n.execCommand(t.cmd)}),n.menuItems=n.menuItems||{},n.menuItems[e]=t},addCommand:function(e,t,n){this.execCommands[e]={func:t,scope:n||this}},addQueryStateHandler:function(e,t,n){this.queryStateCommands[e]={func:t,scope:n||this}},addQueryValueHandler:function(e,t,n){this.queryValueCommands[e]={func:t,scope:n||this}},addShortcut:function(e,t,n,r){this.shortcuts.add(e,t,n,r)},execCommand:function(e,t,n,r){var i=this,o=0,a;return/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(e)||r&&r.skip_focus||i.focus(),r=T({},r),r=i.fire("BeforeExecCommand",{command:e,ui:t,value:n}),r.isDefaultPrevented()?!1:(a=i.execCommands[e])&&a.func.call(a.scope,t,n)!==!0?(i.fire("ExecCommand",{command:e,ui:t,value:n}),!0):(R(i.plugins,function(r){return r.execCommand&&r.execCommand(e,t,n)?(i.fire("ExecCommand",{command:e,ui:t,value:n}),o=!0,!1):void 0 -}),o?o:i.theme&&i.theme.execCommand&&i.theme.execCommand(e,t,n)?(i.fire("ExecCommand",{command:e,ui:t,value:n}),!0):i.editorCommands.execCommand(e,t,n)?(i.fire("ExecCommand",{command:e,ui:t,value:n}),!0):(i.getDoc().execCommand(e,t,n),void i.fire("ExecCommand",{command:e,ui:t,value:n})))},queryCommandState:function(e){var t=this,n,r;if(!t._isHidden()){if((n=t.queryStateCommands[e])&&(r=n.func.call(n.scope),r!==!0))return r;if(r=t.editorCommands.queryCommandState(e),-1!==r)return r;try{return t.getDoc().queryCommandState(e)}catch(i){}}},queryCommandValue:function(e){var n=this,r,i;if(!n._isHidden()){if((r=n.queryValueCommands[e])&&(i=r.func.call(r.scope),i!==!0))return i;if(i=n.editorCommands.queryCommandValue(e),i!==t)return i;try{return n.getDoc().queryCommandValue(e)}catch(o){}}},show:function(){var e=this;E.show(e.getContainer()),E.hide(e.id),e.load(),e.fire("show")},hide:function(){var e=this,t=e.getDoc();P&&t&&!e.inline&&t.execCommand("SelectAll"),e.save(),E.hide(e.getContainer()),E.setStyle(e.id,"display",e.orgDisplay),e.fire("hide")},isHidden:function(){return!E.isHidden(this.id)},setProgressState:function(e,t){this.fire("ProgressState",{state:e,time:t})},load:function(e){var n=this,r=n.getElement(),i;return r?(e=e||{},e.load=!0,i=n.setContent(r.value!==t?r.value:r.innerHTML,e),e.element=r,e.no_events||n.fire("LoadContent",e),e.element=r=null,i):void 0},save:function(e){var t=this,n=t.getElement(),r,i;if(n&&t.initialized)return e=e||{},e.save=!0,e.element=n,r=e.content=t.getContent(e),e.no_events||t.fire("SaveContent",e),r=e.content,/TEXTAREA|INPUT/i.test(n.nodeName)?n.value=r:(t.inline||(n.innerHTML=r),(i=E.getParent(t.id,"form"))&&R(i.elements,function(e){return e.name==t.id?(e.value=r,!1):void 0})),e.element=n=null,e.set_dirty!==!1&&(t.isNotDirty=!0),r},setContent:function(e,t){var n=this,r=n.getBody(),i;return t=t||{},t.format=t.format||"html",t.set=!0,t.content=e,t.no_events||n.fire("BeforeSetContent",t),e=t.content,0===e.length||/^\s+$/.test(e)?(i=n.settings.forced_root_block,i&&n.schema.isValidChild(r.nodeName.toLowerCase(),i.toLowerCase())?(e=P&&11>P?"":'
          ',e=n.dom.createHTML(i,n.settings.forced_root_block_attrs,e)):(!P||11>P)&&(e='
          '),r.innerHTML=e,n.fire("SetContent",t)):("raw"!==t.format&&(e=new o({},n.schema).serialize(n.parser.parse(e,{isRootContent:!0}))),t.content=D(e),n.dom.setHTML(r,t.content),t.no_events||n.fire("SetContent",t)),t.content},getContent:function(e){var t=this,n,r=t.getBody();return e=e||{},e.format=e.format||"html",e.get=!0,e.getInner=!0,e.no_events||t.fire("BeforeGetContent",e),n="raw"==e.format?r.innerHTML:"text"==e.format?r.innerText||r.textContent:t.serializer.serialize(r,e),e.content="text"!=e.format?D(n):n,e.no_events||t.fire("GetContent",e),e.content},insertContent:function(e){this.execCommand("mceInsertContent",!1,e)},isDirty:function(){return!this.isNotDirty},getContainer:function(){var e=this;return e.container||(e.container=E.get(e.editorContainer||e.id+"_parent")),e.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return E.get(this.settings.content_element||this.id)},getWin:function(){var e=this,t;return e.contentWindow||(t=E.get(e.id+"_ifr"),t&&(e.contentWindow=t.contentWindow)),e.contentWindow},getDoc:function(){var e=this,t;return e.contentDocument||(t=e.getWin(),t&&(e.contentDocument=t.document)),e.contentDocument},getBody:function(){return this.bodyElement||this.getDoc().body},convertURL:function(e,t,n){var r=this,i=r.settings;return i.urlconverter_callback?r.execCallback("urlconverter_callback",e,n,!0,t):!i.convert_urls||n&&"LINK"==n.nodeName||0===e.indexOf("file:")||0===e.length?e:i.relative_urls?r.documentBaseURI.toRelative(e):e=r.documentBaseURI.toAbsolute(e,i.remove_script_host)},addVisual:function(e){var n=this,r=n.settings,i=n.dom,o;e=e||n.getBody(),n.hasVisual===t&&(n.hasVisual=r.visual),R(i.select("table,a",e),function(e){var t;switch(e.nodeName){case"TABLE":return o=r.visual_table_class||"mce-item-table",t=i.getAttrib(e,"border"),void(t&&"0"!=t||(n.hasVisual?i.addClass(e,o):i.removeClass(e,o)));case"A":return void(i.getAttrib(e,"href",!1)||(t=i.getAttrib(e,"name")||e.id,o=r.visual_anchor_class||"mce-item-anchor",t&&(n.hasVisual?i.addClass(e,o):i.removeClass(e,o))))}}),n.fire("VisualAid",{element:e,hasVisual:n.hasVisual})},remove:function(){var e=this;if(!e.removed){e.removed=1,e.hasHiddenInput&&E.remove(e.getElement().nextSibling);var t=e.getDoc();P&&t&&!e.inline&&t.execCommand("SelectAll"),e.save(),E.setStyle(e.id,"display",e.orgDisplay),e.settings.content_editable||(H.unbind(e.getWin()),H.unbind(e.getDoc()));var n=e.getContainer();H.unbind(e.getBody()),H.unbind(n),e.fire("remove"),e.editorManager.remove(e),E.remove(n),e.destroy()}},bindNative:function(e){var t=this;t.settings.readonly||(t.initialized?t.dom.bind(_(t,e),e,function(n){t.fire(e,n)}):t._pendingNativeEvents?t._pendingNativeEvents.push(e):t._pendingNativeEvents=[e])},unbindNative:function(e){var t=this;t.initialized&&t.dom.unbind(e)},destroy:function(e){var t=this,n;if(!t.destroyed){if(!e&&!t.removed)return void t.remove();e&&M&&(H.unbind(t.getDoc()),H.unbind(t.getWin()),H.unbind(t.getBody())),e||(t.editorManager.off("beforeunload",t._beforeUnload),t.theme&&t.theme.destroy&&t.theme.destroy(),t.selection.destroy(),t.dom.destroy()),n=t.formElement,n&&(n._mceOldSubmit&&(n.submit=n._mceOldSubmit,n._mceOldSubmit=null),E.unbind(n,"submit reset",t.formEventDelegate)),t.contentAreaContainer=t.formElement=t.container=null,t.settings.content_element=t.bodyElement=t.contentDocument=t.contentWindow=null,t.selection&&(t.selection=t.selection.win=t.selection.dom=t.selection.dom.doc=null),t.destroyed=1}},_refreshContentEditable:function(){var e=this,t,n;e._isHidden()&&(t=e.getBody(),n=t.parentNode,n.removeChild(t),n.appendChild(t),t.focus())},_isHidden:function(){var e;return M?(e=this.selection.getSel(),!e||!e.rangeCount||0===e.rangeCount):0}},T(N.prototype,x),N}),r(at,[],function(){var e={};return{rtl:!1,add:function(t,n){for(var r in n)e[r]=n[r];this.rtl=this.rtl||"rtl"===e._dir},translate:function(t){if("undefined"==typeof t)return t;if("string"!=typeof t&&t.raw)return t.raw;if(t.push){var n=t.slice(1);t=(e[t[0]]||t[0]).replace(/\{([^\}]+)\}/g,function(e,t){return n[t]})}return e[t]||t},data:e}}),r(st,[y,g],function(e,t){function n(r){function i(){try{return document.activeElement}catch(e){return document.body}}function o(e){return e&&e.startContainer?{startContainer:e.startContainer,startOffset:e.startOffset,endContainer:e.endContainer,endOffset:e.endOffset}:e}function a(e,t){var n;return t.startContainer?(n=e.getDoc().createRange(),n.setStart(t.startContainer,t.startOffset),n.setEnd(t.endContainer,t.endOffset)):n=t,n}function s(t){return!!e.DOM.getParent(t,n.isEditorUIElement)}function l(e,t){for(var n=t.getBody();e;){if(e==n)return!0;e=e.parentNode}}function c(n){var c=n.editor,u;c.on("init",function(){"onbeforedeactivate"in document&&t.ie<11?(c.dom.bind(c.getBody(),"beforedeactivate",function(){try{c.pendingRng=c.selection.getRng()}catch(e){}}),c.dom.bind(c.getBody(),"blur",function(){c.pendingRng&&(c.lastRng=c.pendingRng,c.selection.lastFocusBookmark=o(c.lastRng),c.pendingRng=null)})):(c.inline||t.ie>10)&&(c.on("nodechange keyup",function(){var e=document.activeElement;e&&e.id==c.id+"_ifr"&&(e=c.getBody()),l(e,c)&&(c.lastRng=c.selection.getRng())}),t.webkit&&(u=function(){var e=c.selection.getRng();e.collapsed||(c.lastRng=e)},e.DOM.bind(document,"selectionchange",u),c.on("remove",function(){e.DOM.unbind(document,"selectionchange",u)})))}),c.on("setcontent",function(){c.lastRng=null}),c.on("mousedown",function(){c.selection.lastFocusBookmark=null}),c.on("focusin",function(){var e=r.focusedEditor;c.selection.lastFocusBookmark&&(c.selection.setRng(a(c,c.selection.lastFocusBookmark)),c.selection.lastFocusBookmark=null),e!=c&&(e&&e.fire("blur",{focusedEditor:c}),r.activeEditor=c,r.focusedEditor=c,c.fire("focus",{blurredEditor:e}),c.focus(!0)),c.lastRng=null}),c.on("focusout",function(){window.setTimeout(function(){var e=r.focusedEditor;s(i())||e!=c||(c.fire("blur",{focusedEditor:null}),r.focusedEditor=null,c.selection&&(c.selection.lastFocusBookmark=null))},0)})}e.DOM.bind(document,"focusin",function(e){var t=r.activeEditor;t&&e.target.ownerDocument==document&&(t.selection&&(t.selection.lastFocusBookmark=o(t.lastRng)),s(e.target)||r.focusedEditor!=t||(t.fire("blur",{focusedEditor:null}),r.focusedEditor=null))}),r.on("AddEditor",c)}return n.isEditorUIElement=function(e){return-1!==e.className.indexOf("mce-")},n}),r(lt,[ot,y,I,g,p,rt,at,st],function(e,n,r,i,o,a,s,l){var c=n.DOM,u=o.explode,d=o.each,f=o.extend,p=0,m,h={majorVersion:"4",minorVersion:"0.18",releaseDate:"2014-02-27",editors:[],i18n:s,activeEditor:null,setup:function(){var e=this,t,n,i="",o;if(n=document.location.href.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,""),/[\/\\]$/.test(n)||(n+="/"),o=window.tinymce||window.tinyMCEPreInit)t=o.base||o.baseURL,i=o.suffix;else for(var a=document.getElementsByTagName("script"),s=0;s0&&d(u(m),function(n){c.get(n)?(l=new e(n,t,a),s.push(l),l.render(!0)):d(document.forms,function(r){d(r.elements,function(r){r.name===n&&(n="mce_editor_"+p++,c.setAttrib(r,"id",n),l=new e(n,t,a),s.push(l),l.render(1))})})});break;case"textareas":case"specific_textareas":d(c.select("textarea"),function(r){t.editor_deselector&&i(r,t.editor_deselector)||(!t.editor_selector||i(r,t.editor_selector))&&(l=new e(n(r),t,a),s.push(l),l.render(!0))})}t.oninit&&(m=h=0,d(s,function(e){h++,e.initialized?m++:e.on("init",function(){m++,m==h&&r(t,"oninit")}),m==h&&r(t,"oninit")}))}var a=this,s=[],l;a.settings=t,c.bind(window,"ready",o)},get:function(e){return e===t?this.editors:this.editors[e]},add:function(e){var t=this,n=t.editors;return n[e.id]=e,n.push(e),t.activeEditor=e,t.fire("AddEditor",{editor:e}),m||(m=function(){t.fire("BeforeUnload")},c.bind(window,"beforeunload",m)),e},createEditor:function(t,n){return this.add(new e(t,n,this))},remove:function(e){var t=this,n,r=t.editors,i,o;{if(e){if("string"==typeof e)return e=e.selector||e,void d(c.select(e),function(e){t.remove(r[e.id])});if(i=e,!r[i.id])return null;for(delete r[i.id],n=0;n=0;n--)t.remove(r[n])}},execCommand:function(t,n,r){var i=this,o=i.get(r);switch(t){case"mceAddEditor":return i.get(r)||new e(r,i.settings,i).render(),!0;case"mceRemoveEditor":return o&&o.remove(),!0;case"mceToggleEditor":return o?(o.isHidden()?o.show():o.hide(),!0):(i.execCommand("mceAddEditor",0,r),!0)}return i.activeEditor?i.activeEditor.execCommand(t,n,r):!1},triggerSave:function(){d(this.editors,function(e){e.save()})},addI18n:function(e,t){s.add(e,t)},translate:function(e){return s.translate(e)}};return f(h,a),h.setup(),window.tinymce=window.tinyMCE=h,h}),r(ct,[lt,p],function(e,t){var n=t.each,r=t.explode;e.on("AddEditor",function(e){var t=e.editor;t.on("preInit",function(){function e(e,t){n(t,function(t,n){t&&s.setStyle(e,n,t)}),s.rename(e,"span")}function i(e){s=t.dom,l.convert_fonts_to_spans&&n(s.select("font,u,strike",e.node),function(e){o[e.nodeName.toLowerCase()](s,e)})}var o,a,s,l=t.settings;l.inline_styles&&(a=r(l.font_size_legacy_values),o={font:function(t,n){e(n,{backgroundColor:n.style.backgroundColor,color:n.color,fontFamily:n.face,fontSize:a[parseInt(n.size,10)-1]})},u:function(t,n){e(n,{textDecoration:"underline"})},strike:function(t,n){e(n,{textDecoration:"line-through"})}},t.on("PreProcess SetContent",i))})})}),r(ut,[],function(){return{send:function(e){function t(){!e.async||4==n.readyState||r++>1e4?(e.success&&1e4>r&&200==n.status?e.success.call(e.success_scope,""+n.responseText,n,e):e.error&&e.error.call(e.error_scope,r>1e4?"TIMED_OUT":"GENERAL",n,e),n=null):setTimeout(t,10)}var n,r=0;if(e.scope=e.scope||this,e.success_scope=e.success_scope||e.scope,e.error_scope=e.error_scope||e.scope,e.async=e.async===!1?!1:!0,e.data=e.data||"",n=new XMLHttpRequest){if(n.overrideMimeType&&n.overrideMimeType(e.content_type),n.open(e.type||(e.data?"POST":"GET"),e.url,e.async),e.content_type&&n.setRequestHeader("Content-Type",e.content_type),n.setRequestHeader("X-Requested-With","XMLHttpRequest"),n.send(e.data),!e.async)return t();setTimeout(t,10)}}}}),r(dt,[],function(){function e(t,n){var r,i,o,a;if(n=n||'"',null===t)return"null";if(o=typeof t,"string"==o)return i="\bb t\nn\ff\rr\"\"''\\\\",n+t.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(e,t){return'"'===n&&"'"===e?e:(r=i.indexOf(t),r+1?"\\"+i.charAt(r+1):(e=t.charCodeAt().toString(16),"\\u"+"0000".substring(e.length)+e))})+n;if("object"==o){if(t.hasOwnProperty&&"[object Array]"===Object.prototype.toString.call(t)){for(r=0,i="[";r0?",":"")+e(t[r],n);return i+"]"}i="{";for(a in t)t.hasOwnProperty(a)&&(i+="function"!=typeof t[a]?(i.length>1?","+n:n)+a+n+":"+e(t[a],n):"");return i+"}"}return""+t}return{serialize:e,parse:function(e){try{return window[String.fromCharCode(101)+"val"]("("+e+")")}catch(t){}}}}),r(ft,[dt,ut,p],function(e,t,n){function r(e){this.settings=i({},e),this.count=0}var i=n.extend;return r.sendRPC=function(e){return(new r).send(e)},r.prototype={send:function(n){var r=n.error,o=n.success;n=i(this.settings,n),n.success=function(t,i){t=e.parse(t),"undefined"==typeof t&&(t={error:"JSON Parse error."}),t.error?r.call(n.error_scope||n.scope,t.error,i):o.call(n.success_scope||n.scope,t.result)},n.error=function(e,t){r&&r.call(n.error_scope||n.scope,e,t)},n.data=e.serialize({id:n.id||"c"+this.count++,method:n.method,params:n.params}),n.content_type="application/json",t.send(n)}},r}),r(pt,[y],function(e){return{callbacks:{},count:0,send:function(n){var r=this,i=e.DOM,o=n.count!==t?n.count:r.count,a="tinymce_jsonp_"+o;r.callbacks[o]=function(e){i.remove(a),delete r.callbacks[o],n.callback(e)},i.add(i.doc.body,"script",{id:a,src:n.url,type:"text/javascript"}),r.count++}}}),r(mt,[],function(){function e(){s=[];for(var e in a)s.push(e);i.length=s.length}function n(){function n(e){var n,r;return r=e!==t?u+e:i.indexOf(",",u),-1===r||r>i.length?null:(n=i.substring(u,r),u=r+1,n)}var r,i,s,u=0;if(a={},c){o.load(l),i=o.getAttribute(l)||"";do{var d=n();if(null===d)break;if(r=n(parseInt(d,32)||0),null!==r){if(d=n(),null===d)break;s=n(parseInt(d,32)||0),r&&(a[r]=s)}}while(null!==r);e()}}function r(){var t,n="";if(c){for(var r in a)t=a[r],n+=(n?",":"")+r.length.toString(32)+","+r+","+t.length.toString(32)+","+t;o.setAttribute(l,n);try{o.save(l)}catch(i){}e()}}var i,o,a,s,l,c;try{if(window.localStorage)return localStorage}catch(u){}return l="tinymce",o=document.documentElement,c=!!o.addBehavior,c&&o.addBehavior("#default#userData"),i={key:function(e){return s[e]},getItem:function(e){return e in a?a[e]:null},setItem:function(e,t){a[e]=""+t,r()},removeItem:function(e){delete a[e],r()},clear:function(){a={},r()}},n(),i}),r(ht,[y,l,b,C,p,g],function(e,t,n,r,i,o){var a=window.tinymce;return a.DOM=e.DOM,a.ScriptLoader=n.ScriptLoader,a.PluginManager=r.PluginManager,a.ThemeManager=r.ThemeManager,a.dom=a.dom||{},a.dom.Event=t.Event,i.each(i,function(e,t){a[t]=e}),i.each("isOpera isWebKit isIE isGecko isMac".split(" "),function(e){a[e]=o[e.substr(2).toLowerCase()]}),{}}),r(gt,[F,p],function(e,t){return e.extend({Defaults:{firstControlClass:"first",lastControlClass:"last"},init:function(e){this.settings=t.extend({},this.Defaults,e)},preRender:function(e){e.addClass(this.settings.containerClass,"body")},applyClasses:function(e){var t=this,n=t.settings,r,i,o;r=e.items().filter(":visible"),i=n.firstControlClass,o=n.lastControlClass,r.each(function(e){e.removeClass(i).removeClass(o),n.controlClass&&e.addClass(n.controlClass)}),r.eq(0).addClass(i),r.eq(-1).addClass(o)},renderHtml:function(e){var t=this,n=t.settings,r,i="";return r=e.items(),r.eq(0).addClass(n.firstControlClass),r.eq(-1).addClass(n.lastControlClass),r.each(function(e){n.controlClass&&e.addClass(n.controlClass),i+=e.renderHtml()}),i},recalc:function(){},postRender:function(){}})}),r(vt,[gt],function(e){return e.extend({Defaults:{containerClass:"abs-layout",controlClass:"abs-layout-item"},recalc:function(e){e.items().filter(":visible").each(function(e){var t=e.settings;e.layoutRect({x:t.x,y:t.y,w:t.w,h:t.h}),e.recalc&&e.recalc()})},renderHtml:function(e){return'
          '+this._super(e)}})}),r(yt,[U,X],function(e,t){return e.extend({Mixins:[t],Defaults:{classes:"widget tooltip tooltip-n"},text:function(e){var t=this;return"undefined"!=typeof e?(t._value=e,t._rendered&&(t.getEl().lastChild.innerHTML=t.encode(e)),t):t._value},renderHtml:function(){var e=this,t=e.classPrefix;return'"},repaint:function(){var e=this,t,n;t=e.getEl().style,n=e._layoutRect,t.left=n.x+"px",t.top=n.y+"px",t.zIndex=131070}})}),r(bt,[U,yt],function(e,t){var n,r=e.extend({init:function(e){var t=this;t._super(e),t.canFocus=!0,e.tooltip&&r.tooltips!==!1&&(t.on("mouseenter",function(n){var r=t.tooltip().moveTo(-65535);if(n.control==t){var i=r.text(e.tooltip).show().testMoveRel(t.getEl(),["bc-tc","bc-tl","bc-tr"]);r.toggleClass("tooltip-n","bc-tc"==i),r.toggleClass("tooltip-nw","bc-tl"==i),r.toggleClass("tooltip-ne","bc-tr"==i),r.moveRel(t.getEl(),i)}else r.hide()}),t.on("mouseleave mousedown click",function(){t.tooltip().hide()})),t.aria("label",e.ariaLabel||e.tooltip)},tooltip:function(){return n||(n=new t({type:"tooltip"}),n.renderTo()),n},active:function(e){var t=this,n;return e!==n&&(t.aria("pressed",e),t.toggleClass("active",e)),t._super(e)},disabled:function(e){var t=this,n;return e!==n&&(t.aria("disabled",e),t.toggleClass("disabled",e)),t._super(e)},postRender:function(){var e=this,t=e.settings;e._rendered=!0,e._super(),e.parent()||!t.width&&!t.height||(e.initLayoutRect(),e.repaint()),t.autofocus&&e.focus()},remove:function(){this._super(),n&&(n.remove(),n=null)}});return r}),r(Ct,[bt],function(e){return e.extend({Defaults:{classes:"widget btn",role:"button"},init:function(e){var t=this,n;t.on("click mousedown",function(e){e.preventDefault()}),t._super(e),n=e.size,e.subtype&&t.addClass(e.subtype),n&&t.addClass("btn-"+n)},icon:function(e){var t=this,n=t.classPrefix;if("undefined"==typeof e)return t.settings.icon;if(t.settings.icon=e,e=e?n+"ico "+n+"i-"+t.settings.icon:"",t._rendered){var r=t.getEl().firstChild,i=r.getElementsByTagName("i")[0];e?(i&&i==r.firstChild||(i=document.createElement("i"),r.insertBefore(i,r.firstChild)),i.className=e):i&&r.removeChild(i),t.text(t._text)}return t},repaint:function(){var e=this.getEl().firstChild.style;e.width=e.height="100%",this._super()},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix,r=e.settings.icon,i="";return e.settings.image&&(r="none",i=" style=\"background-image: url('"+e.settings.image+"')\""),r=e.settings.icon?n+"ico "+n+"i-"+r:"",'
          "}})}),r(xt,[j],function(e){return e.extend({Defaults:{defaultType:"button",role:"group"},renderHtml:function(){var e=this,t=e._layout;return e.addClass("btn-group"),e.preRender(),t.preRender(e),'
          '+(e.settings.html||"")+t.renderHtml(e)+"
          "}})}),r(wt,[bt],function(e){return e.extend({Defaults:{classes:"checkbox",role:"checkbox",checked:!1},init:function(e){var t=this;t._super(e),t.on("click mousedown",function(e){e.preventDefault()}),t.on("click",function(e){e.preventDefault(),t.disabled()||t.checked(!t.checked())}),t.checked(t.settings.checked)},checked:function(e){var t=this;return"undefined"!=typeof e?(e?t.addClass("checked"):t.removeClass("checked"),t._checked=e,t.aria("checked",e),t):t._checked},value:function(e){return this.checked(e)},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix;return'
          '+e.encode(e._text)+"
          "}})}),r(_t,[Ct,Q],function(e,t){return e.extend({showPanel:function(){var e=this,n=e.settings;if(e.active(!0),e.panel)e.panel.show();else{var r=n.panel;r.type&&(r={layout:"grid",items:r}),r.role=r.role||"dialog",r.popover=!0,r.autohide=!0,r.ariaRoot=!0,e.panel=new t(r).on("hide",function(){e.active(!1)}).on("cancel",function(t){t.stopPropagation(),e.focus(),e.hidePanel()}).parent(e).renderTo(e.getContainerElm()),e.panel.fire("show"),e.panel.reflow()}e.panel.moveRel(e.getEl(),n.popoverAlign||(e.isRtl()?["bc-tr","bc-tc"]:["bc-tl","bc-tc"]))},hidePanel:function(){var e=this;e.panel&&e.panel.hide()},postRender:function(){var e=this;return e.aria("haspopup",!0),e.on("click",function(t){t.control===e&&(e.panel&&e.panel.visible()?e.hidePanel():(e.showPanel(),e.panel.focus(!!t.aria)))}),e._super()}})}),r(Nt,[_t,y],function(e,t){var n=t.DOM;return e.extend({init:function(e){this._super(e),this.addClass("colorbutton")},color:function(e){return e?(this._color=e,this.getEl("preview").style.backgroundColor=e,this):this._color},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix,r=e.settings.icon?n+"ico "+n+"i-"+e.settings.icon:"",i=e.settings.image?" style=\"background-image: url('"+e.settings.image+"')\"":"";return'
          '},postRender:function(){var e=this,t=e.settings.onclick;return e.on("click",function(r){r.aria&&"down"==r.aria.key||r.control!=e||n.getParent(r.target,"."+e.classPrefix+"open")||(r.stopImmediatePropagation(),t.call(e,r))}),delete e.settings.onclick,e._super()}})}),r(Et,[bt,q,V],function(e,t,n){return e.extend({init:function(e){var t=this;t._super(e),t.addClass("combobox"),t.subinput=!0,t.ariaTarget="inp",e=t.settings,e.menu=e.menu||e.values,e.menu&&(e.icon="caret"),t.on("click",function(n){for(var r=n.target,i=t.getEl();r&&r!=i;)r.id&&-1!=r.id.indexOf("-open")&&(t.fire("action"),e.menu&&(t.showMenu(),n.aria&&t.menu.items()[0].focus())),r=r.parentNode}),t.on("keydown",function(e){"INPUT"==e.target.nodeName&&13==e.keyCode&&t.parents().reverse().each(function(n){return e.preventDefault(),t.fire("change"),n.hasEventListeners("submit")&&n.toJSON?(n.fire("submit",{data:n.toJSON()}),!1):void 0})}),e.placeholder&&(t.addClass("placeholder"),t.on("focusin",function(){t._hasOnChange||(n.on(t.getEl("inp"),"change",function(){t.fire("change")}),t._hasOnChange=!0),t.hasClass("placeholder")&&(t.getEl("inp").value="",t.removeClass("placeholder"))}),t.on("focusout",function(){0===t.value().length&&(t.getEl("inp").value=e.placeholder,t.addClass("placeholder"))}))},showMenu:function(){var e=this,n=e.settings,r;e.menu||(r=n.menu||[],r.length?r={type:"menu",items:r}:r.type=r.type||"menu",e.menu=t.create(r).parent(e).renderTo(e.getContainerElm()),e.fire("createmenu"),e.menu.reflow(),e.menu.on("cancel",function(t){t.control===e.menu&&e.focus()}),e.menu.on("show hide",function(t){t.control.items().each(function(t){t.active(t.value()==e.value())})}).fire("show"),e.menu.on("select",function(t){e.value(t.control.value())}),e.on("focusin",function(t){"INPUT"==t.target.tagName&&e.menu.hide()}),e.aria("expanded",!0)),e.menu.show(),e.menu.layoutRect({w:e.layoutRect().w}),e.menu.moveRel(e.getEl(),e.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"])},value:function(e){var t=this;return"undefined"!=typeof e?(t._value=e,t.removeClass("placeholder"),t._rendered&&(t.getEl("inp").value=e),t):t._rendered?(e=t.getEl("inp").value,e!=t.settings.placeholder?e:""):t._value},disabled:function(e){var t=this;return t._rendered&&"undefined"!=typeof e&&(t.getEl("inp").disabled=e),t._super(e)},focus:function(){this.getEl("inp").focus()},repaint:function(){var e=this,t=e.getEl(),r=e.getEl("open"),i=e.layoutRect(),o,a;o=r?i.w-n.getSize(r).width-10:i.w-10;var s=document;return s.all&&(!s.documentMode||s.documentMode<=8)&&(a=e.layoutRect().h-2+"px"),n.css(t.firstChild,{width:o,lineHeight:a}),e._super(),e},postRender:function(){var e=this;return n.on(this.getEl("inp"),"change",function(){e.fire("change")}),e._super()},remove:function(){n.off(this.getEl("inp")),this._super()},renderHtml:function(){var e=this,t=e._id,n=e.settings,r=e.classPrefix,i=n.value||n.placeholder||"",o,a,s="",l="";return"spellcheck"in n&&(l+=' spellcheck="'+n.spellcheck+'"'),n.maxLength&&(l+=' maxlength="'+n.maxLength+'"'),n.size&&(l+=' size="'+n.size+'"'),n.subtype&&(l+=' type="'+n.subtype+'"'),e.disabled()&&(l+=' disabled="disabled"'),o=n.icon,o&&"caret"!=o&&(o=r+"ico "+r+"i-"+n.icon),a=e._text,(o||a)&&(s='
          ",e.addClass("has-open")),'
          "+s+"
          "}})}),r(St,[bt],function(e){return e.extend({init:function(e){var t=this;e.delimiter||(e.delimiter="\xbb"),t._super(e),t.addClass("path"),t.canFocus=!0,t.on("click",function(e){var n,r=e.target;(n=r.getAttribute("data-index"))&&t.fire("select",{value:t.data()[n],index:n})})},focus:function(){var e=this;return e.getEl().firstChild.focus(),e},data:function(e){var t=this;return"undefined"!=typeof e?(t._data=e,t.update(),t):t._data},update:function(){this.innerHtml(this._getPathHtml())},postRender:function(){var e=this;e._super(),e.data(e.settings.data)},renderHtml:function(){var e=this;return'
          '+e._getPathHtml()+"
          "},_getPathHtml:function(){var e=this,t=e._data||[],n,r,i="",o=e.classPrefix;for(n=0,r=t.length;r>n;n++)i+=(n>0?'":"")+'
          '+t[n].name+"
          ";return i||(i='
           
          '),i}})}),r(kt,[St,lt],function(e,t){return e.extend({postRender:function(){function e(e){if(1===e.nodeType){if("BR"==e.nodeName||e.getAttribute("data-mce-bogus"))return!0;if("bookmark"===e.getAttribute("data-mce-type"))return!0}return!1}var n=this,r=t.activeEditor;return n.on("select",function(t){var n=[],i,o=r.getBody();for(r.focus(),i=r.selection.getStart();i&&i!=o;)e(i)||n.push(i),i=i.parentNode;r.selection.select(n[n.length-1-t.index]),r.nodeChanged()}),r.on("nodeChange",function(t){for(var i=[],o=t.parents,a=o.length;a--;)if(1==o[a].nodeType&&!e(o[a])){var s=r.fire("ResolveName",{name:o[a].nodeName.toLowerCase(),target:o[a]});i.push({name:s.name})}n.data(i)}),n._super()}})}),r(Tt,[j],function(e){return e.extend({Defaults:{layout:"flex",align:"center",defaults:{flex:1}},renderHtml:function(){var e=this,t=e._layout,n=e.classPrefix;return e.addClass("formitem"),t.preRender(e),'
          '+(e.settings.title?'
          '+e.settings.title+"
          ":"")+'
          '+(e.settings.html||"")+t.renderHtml(e)+"
          "}})}),r(Rt,[j,Tt],function(e,t){return e.extend({Defaults:{containerCls:"form",layout:"flex",direction:"column",align:"stretch",flex:1,padding:20,labelGap:30,spacing:10,callbacks:{submit:function(){this.submit()}}},preRender:function(){var e=this,n=e.items();n.each(function(n){var r,i=n.settings.label;i&&(r=new t({layout:"flex",autoResize:"overflow",defaults:{flex:1},items:[{type:"label",id:n._id+"-l",text:i,flex:0,forId:n._id,disabled:n.disabled()}]}),r.type="formitem",n.aria("labelledby",n._id+"-l"),"undefined"==typeof n.settings.flex&&(n.settings.flex=1),e.replace(n,r),r.add(n))})},recalcLabels:function(){var e=this,t=0,n=[],r,i;if(e.settings.labelGapCalc!==!1)for(e.items().filter("formitem").each(function(e){var r=e.items()[0],i=r.getEl().clientWidth;t=i>t?i:t,n.push(r)}),i=e.settings.labelGap||0,r=n.length;r--;)n[r].settings.minWidth=t+i},visible:function(e){var t=this._super(e);return e===!0&&this._rendered&&this.recalcLabels(),t},submit:function(){return this.fire("submit",{data:this.toJSON()})},postRender:function(){var e=this;e._super(),e.recalcLabels(),e.fromJSON(e.settings.data)}})}),r(At,[Rt],function(e){return e.extend({Defaults:{containerCls:"fieldset",layout:"flex",direction:"column",align:"stretch",flex:1,padding:"25 15 5 15",labelGap:30,spacing:10,border:1},renderHtml:function(){var e=this,t=e._layout,n=e.classPrefix;return e.preRender(),t.preRender(e),'
          '+(e.settings.title?''+e.settings.title+"":"")+'
          '+(e.settings.html||"")+t.renderHtml(e)+"
          "}})}),r(Bt,[Et],function(e){return e.extend({init:function(e){var t=this,n=tinymce.activeEditor,r;e.spellcheck=!1,r=n.settings.file_browser_callback,r&&(e.icon="browse",e.onaction=function(){r(t.getEl("inp").id,t.getEl("inp").value,e.filetype,window)}),t._super(e)}})}),r(Dt,[vt],function(e){return e.extend({recalc:function(e){var t=e.layoutRect(),n=e.paddingBox();e.items().filter(":visible").each(function(e){e.layoutRect({x:n.left,y:n.top,w:t.innerW-n.right-n.left,h:t.innerH-n.top-n.bottom}),e.recalc&&e.recalc()})}})}),r(Lt,[vt],function(e){return e.extend({recalc:function(e){var t,n,r,i,o,a,s,l,c,u,d,f,p,m,h,g,v=[],y,b,C,x,w,_,N,E,S,k,T,R,A,B,D,L,H,M,P,O,I,F,z,W,V=Math.max,U=Math.min;for(r=e.items().filter(":visible"),i=e.layoutRect(),o=e._paddingBox,a=e.settings,f=e.isRtl()?a.direction||"row-reversed":a.direction,s=a.align,l=e.isRtl()?a.pack||"end":a.pack,c=a.spacing||0,("row-reversed"==f||"column-reverse"==f)&&(r=r.set(r.toArray().reverse()),f=f.split("-")[0]),"column"==f?(S="y",N="h",E="minH",k="maxH",R="innerH",T="top",A="bottom",B="deltaH",D="contentH",I="left",M="w",L="x",H="innerW",P="minW",O="maxW",F="right",z="deltaW",W="contentW"):(S="x",N="w",E="minW",k="maxW",R="innerW",T="left",A="right",B="deltaW",D="contentW",I="top",M="h",L="y",H="innerH",P="minH",O="maxH",F="bottom",z="deltaH",W="contentH"),d=i[R]-o[T]-o[T],_=u=0,t=0,n=r.length;n>t;t++)p=r[t],m=p.layoutRect(),h=p.settings,g=h.flex,d-=n-1>t?c:0,g>0&&(u+=g,m[k]&&v.push(p),m.flex=g),d-=m[E],y=o[I]+m[P]+o[F],y>_&&(_=y); -if(x={},x[E]=0>d?i[E]-d+i[B]:i[R]-d+i[B],x[P]=_+i[z],x[D]=i[R]-d,x[W]=_,x.minW=U(x.minW,i.maxW),x.minH=U(x.minH,i.maxH),x.minW=V(x.minW,i.startMinWidth),x.minH=V(x.minH,i.startMinHeight),!i.autoResize||x.minW==i.minW&&x.minH==i.minH){for(C=d/u,t=0,n=v.length;n>t;t++)p=v[t],m=p.layoutRect(),b=m[k],y=m[E]+m.flex*C,y>b?(d-=m[k]-m[E],u-=m.flex,m.flex=0,m.maxFlexSize=b):m.maxFlexSize=0;for(C=d/u,w=o[T],x={},0===u&&("end"==l?w=d+o[T]:"center"==l?(w=Math.round(i[R]/2-(i[R]-d)/2)+o[T],0>w&&(w=o[T])):"justify"==l&&(w=o[T],c=Math.floor(d/(r.length-1)))),x[L]=o[I],t=0,n=r.length;n>t;t++)p=r[t],m=p.layoutRect(),y=m.maxFlexSize||m[E],"center"===s?x[L]=Math.round(i[H]/2-m[M]/2):"stretch"===s?(x[M]=V(m[P]||0,i[H]-o[I]-o[F]),x[L]=o[I]):"end"===s&&(x[L]=i[H]-m[M]-o.top),m.flex>0&&(y+=m.flex*C),x[N]=y,x[S]=w,p.layoutRect(x),p.recalc&&p.recalc(),w+=y+c}else if(x.w=x.minW,x.h=x.minH,e.layoutRect(x),this.recalc(e),null===e._lastRect){var q=e.parent();q&&(q._lastRect=null,q.recalc())}}})}),r(Ht,[gt],function(e){return e.extend({Defaults:{containerClass:"flow-layout",controlClass:"flow-layout-item",endClass:"break"},recalc:function(e){e.items().filter(":visible").each(function(e){e.recalc&&e.recalc()})}})}),r(Mt,[U,bt,Q,p,lt,g],function(e,t,n,r,i,o){function a(e){function t(t){function n(e){return e.replace(/%(\w+)/g,"")}var r,i,o=e.dom,a="",l,c;return c=e.settings.preview_styles,c===!1?"":(c||(c="font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow"),(t=e.formatter.get(t))?(t=t[0],r=t.block||t.inline||"span",i=o.create(r),s(t.styles,function(e,t){e=n(e),e&&o.setStyle(i,t,e)}),s(t.attributes,function(e,t){e=n(e),e&&o.setAttrib(i,t,e)}),s(t.classes,function(e){e=n(e),o.hasClass(i,e)||o.addClass(i,e)}),e.fire("PreviewFormats"),o.setStyles(i,{position:"absolute",left:-65535}),e.getBody().appendChild(i),l=o.getStyle(e.getBody(),"fontSize",!0),l=/px$/.test(l)?parseInt(l,10):0,s(c.split(" "),function(t){var n=o.getStyle(i,t,!0);if(!("background-color"==t&&/transparent|rgba\s*\([^)]+,\s*0\)/.test(n)&&(n=o.getStyle(e.getBody(),t,!0),"#ffffff"==o.toHex(n).toLowerCase())||"color"==t&&"#000000"==o.toHex(n).toLowerCase())){if("font-size"==t&&/em|%$/.test(n)){if(0===l)return;n=parseFloat(n,10)/(/%$/.test(n)?100:1),n=n*l+"px"}"border"==t&&n&&(a+="padding:0 2px;"),a+=t+":"+n+";"}}),e.fire("AfterPreviewFormats"),o.remove(i),a):void 0)}function r(t,n){return function(){var r=this;e.on("nodeChange",function(i){var o=e.formatter,a=null;s(i.parents,function(e){return s(t,function(t){return n?o.matchNode(e,n,{value:t.value})&&(a=t.value):o.matchNode(e,t.value)&&(a=t.value),a?!1:void 0}),a?!1:void 0}),r.value(a)})}}function i(e){e=e.split(";");for(var t=e.length;t--;)e[t]=e[t].split("=");return e}function o(){function n(e){var t=[];if(e)return s(e,function(e){var r={text:e.title,icon:e.icon};if(e.items)r.menu=n(e.items);else{var a=e.format||"custom"+i++;e.format||(e.name=a,o.push(e)),r.format=a}t.push(r)}),t}function r(){var t;return t=n(e.settings.style_formats_merge?e.settings.style_formats?a.concat(e.settings.style_formats):a:e.settings.style_formats||a)}var i=0,o=[],a=[{title:"Headers",items:[{title:"Header 1",format:"h1"},{title:"Header 2",format:"h2"},{title:"Header 3",format:"h3"},{title:"Header 4",format:"h4"},{title:"Header 5",format:"h5"},{title:"Header 6",format:"h6"}]},{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}];return e.on("init",function(){s(o,function(t){e.formatter.register(t.name,t)})}),{type:"menu",items:r(),onPostRender:function(t){e.fire("renderFormatsMenu",{control:t.control})},itemDefaults:{preview:!0,textStyle:function(){return this.settings.format?t(this.settings.format):void 0},onPostRender:function(){var t=this,n=this.settings.format;n&&t.parent().on("show",function(){t.disabled(!e.formatter.canApply(n)),t.active(e.formatter.match(n))})},onclick:function(){this.settings.format&&f(this.settings.format)}}}}function a(){return e.undoManager?e.undoManager.hasUndo():!1}function l(){return e.undoManager?e.undoManager.hasRedo():!1}function c(){var t=this;t.disabled(!a()),e.on("Undo Redo AddUndo TypingUndo",function(){t.disabled(!a())})}function u(){var t=this;t.disabled(!l()),e.on("Undo Redo AddUndo TypingUndo",function(){t.disabled(!l())})}function d(){var t=this;e.on("VisualAid",function(e){t.active(e.hasVisual)}),t.active(e.hasVisual)}function f(t){t.control&&(t=t.control.value()),t&&e.execCommand("mceToggleFormat",!1,t)}var p;p=o(),s({bold:"Bold",italic:"Italic",underline:"Underline",strikethrough:"Strikethrough",subscript:"Subscript",superscript:"Superscript"},function(t,n){e.addButton(n,{tooltip:t,onPostRender:function(){var t=this;e.formatter?e.formatter.formatChanged(n,function(e){t.active(e)}):e.on("init",function(){e.formatter.formatChanged(n,function(e){t.active(e)})})},onclick:function(){f(n)}})}),s({outdent:["Decrease indent","Outdent"],indent:["Increase indent","Indent"],cut:["Cut","Cut"],copy:["Copy","Copy"],paste:["Paste","Paste"],help:["Help","mceHelp"],selectall:["Select all","SelectAll"],hr:["Insert horizontal rule","InsertHorizontalRule"],removeformat:["Clear formatting","RemoveFormat"],visualaid:["Visual aids","mceToggleVisualAid"],newdocument:["New document","mceNewDocument"]},function(t,n){e.addButton(n,{tooltip:t[0],cmd:t[1]})}),s({blockquote:["Blockquote","mceBlockQuote"],numlist:["Numbered list","InsertOrderedList"],bullist:["Bullet list","InsertUnorderedList"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],alignleft:["Align left","JustifyLeft"],aligncenter:["Align center","JustifyCenter"],alignright:["Align right","JustifyRight"],alignjustify:["Justify","JustifyFull"]},function(t,n){e.addButton(n,{tooltip:t[0],cmd:t[1],onPostRender:function(){var t=this;e.formatter?e.formatter.formatChanged(n,function(e){t.active(e)}):e.on("init",function(){e.formatter.formatChanged(n,function(e){t.active(e)})})}})}),e.addButton("undo",{tooltip:"Undo",onPostRender:c,cmd:"undo"}),e.addButton("redo",{tooltip:"Redo",onPostRender:u,cmd:"redo"}),e.addMenuItem("newdocument",{text:"New document",shortcut:"Ctrl+N",icon:"newdocument",cmd:"mceNewDocument"}),e.addMenuItem("undo",{text:"Undo",icon:"undo",shortcut:"Ctrl+Z",onPostRender:c,cmd:"undo"}),e.addMenuItem("redo",{text:"Redo",icon:"redo",shortcut:"Ctrl+Y",onPostRender:u,cmd:"redo"}),e.addMenuItem("visualaid",{text:"Visual aids",selectable:!0,onPostRender:d,cmd:"mceToggleVisualAid"}),s({cut:["Cut","Cut","Ctrl+X"],copy:["Copy","Copy","Ctrl+C"],paste:["Paste","Paste","Ctrl+V"],selectall:["Select all","SelectAll","Ctrl+A"],bold:["Bold","Bold","Ctrl+B"],italic:["Italic","Italic","Ctrl+I"],underline:["Underline","Underline"],strikethrough:["Strikethrough","Strikethrough"],subscript:["Subscript","Subscript"],superscript:["Superscript","Superscript"],removeformat:["Clear formatting","RemoveFormat"]},function(t,n){e.addMenuItem(n,{text:t[0],icon:n,shortcut:t[2],cmd:t[1]})}),e.on("mousedown",function(){n.hideAll()}),e.addButton("styleselect",{type:"menubutton",text:"Formats",menu:p}),e.addButton("formatselect",function(){var n=[],o=i(e.settings.block_formats||"Paragraph=p;Address=address;Pre=pre;Header 1=h1;Header 2=h2;Header 3=h3;Header 4=h4;Header 5=h5;Header 6=h6");return s(o,function(e){n.push({text:e[0],value:e[1],textStyle:function(){return t(e[1])}})}),{type:"listbox",text:o[0][0],values:n,fixedWidth:!0,onselect:f,onPostRender:r(n)}}),e.addButton("fontselect",function(){var t="Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",n=[],o=i(e.settings.font_formats||t);return s(o,function(e){n.push({text:{raw:e[0]},value:e[1],textStyle:-1==e[1].indexOf("dings")?"font-family:"+e[1]:""})}),{type:"listbox",text:"Font Family",tooltip:"Font Family",values:n,fixedWidth:!0,onPostRender:r(n,"fontname"),onselect:function(t){t.control.settings.value&&e.execCommand("FontName",!1,t.control.settings.value)}}}),e.addButton("fontsizeselect",function(){var t=[],n="8pt 10pt 12pt 14pt 18pt 24pt 36pt",i=e.settings.fontsize_formats||n;return s(i.split(" "),function(e){t.push({text:e,value:e})}),{type:"listbox",text:"Font Sizes",tooltip:"Font Sizes",values:t,fixedWidth:!0,onPostRender:r(t,"fontsize"),onclick:function(t){t.control.settings.value&&e.execCommand("FontSize",!1,t.control.settings.value)}}}),e.addMenuItem("formats",{text:"Formats",menu:p})}var s=r.each;i.on("AddEditor",function(t){t.editor.rtl&&(e.rtl=!0),a(t.editor)}),e.translate=function(e){return i.translate(e)},t.tooltips=!o.iOS}),r(Pt,[vt],function(e){return e.extend({recalc:function(e){var t=e.settings,n,r,i,o,a,s,l,c,u,d,f,p,m,h,g,v,y,b,C,x,w,_,N=[],E=[],S,k,T,R,A,B;for(t=e.settings,i=e.items().filter(":visible"),o=e.layoutRect(),r=t.columns||Math.ceil(Math.sqrt(i.length)),n=Math.ceil(i.length/r),y=t.spacingH||t.spacing||0,b=t.spacingV||t.spacing||0,C=t.alignH||t.align,x=t.alignV||t.align,g=e._paddingBox,C&&"string"==typeof C&&(C=[C]),x&&"string"==typeof x&&(x=[x]),d=0;r>d;d++)N.push(0);for(f=0;n>f;f++)E.push(0);for(f=0;n>f;f++)for(d=0;r>d&&(u=i[f*r+d],u);d++)c=u.layoutRect(),S=c.minW,k=c.minH,N[d]=S>N[d]?S:N[d],E[f]=k>E[f]?k:E[f];for(A=o.innerW-g.left-g.right,w=0,d=0;r>d;d++)w+=N[d]+(d>0?y:0),A-=(d>0?y:0)+N[d];for(B=o.innerH-g.top-g.bottom,_=0,f=0;n>f;f++)_+=E[f]+(f>0?b:0),B-=(f>0?b:0)+E[f];if(w+=g.left+g.right,_+=g.top+g.bottom,l={},l.minW=w+(o.w-o.innerW),l.minH=_+(o.h-o.innerH),l.contentW=l.minW-o.deltaW,l.contentH=l.minH-o.deltaH,l.minW=Math.min(l.minW,o.maxW),l.minH=Math.min(l.minH,o.maxH),l.minW=Math.max(l.minW,o.startMinWidth),l.minH=Math.max(l.minH,o.startMinHeight),!o.autoResize||l.minW==o.minW&&l.minH==o.minH){o.autoResize&&(l=e.layoutRect(l),l.contentW=l.minW-o.deltaW,l.contentH=l.minH-o.deltaH);var D;D="start"==t.packV?0:B>0?Math.floor(B/n):0;var L=0,H=t.flexWidths;if(H)for(d=0;dd;d++)N[d]+=H?H[d]*M:M;for(m=g.top,f=0;n>f;f++){for(p=g.left,s=E[f]+D,d=0;r>d&&(u=i[f*r+d],u);d++)h=u.settings,c=u.layoutRect(),a=Math.max(N[d],c.startMinWidth),T=R=0,c.x=p,c.y=m,v=h.alignH||(C?C[d]||C[0]:null),"center"==v?c.x=p+a/2-c.w/2:"right"==v?c.x=p+a-c.w:"stretch"==v&&(c.w=a),v=h.alignV||(x?x[d]||x[0]:null),"center"==v?c.y=m+s/2-c.h/2:"bottom"==v?c.y=m+s-c.h:"stretch"==v&&(c.h=s),u.layoutRect(c),p+=a+y,u.recalc&&u.recalc();m+=s+b}}else if(l.w=l.minW,l.h=l.minH,e.layoutRect(l),this.recalc(e),null===e._lastRect){var P=e.parent();P&&(P._lastRect=null,P.recalc())}}})}),r(Ot,[bt],function(e){return e.extend({renderHtml:function(){var e=this;return e.addClass("iframe"),e.canFocus=!1,''},src:function(e){this.getEl().src=e},html:function(e,t){var n=this,r=this.getEl().contentWindow.document.body;return r?(r.innerHTML=e,t&&t()):setTimeout(function(){n.html(e)},0),this}})}),r(It,[bt,V],function(e,t){return e.extend({init:function(e){var t=this;t._super(e),t.addClass("widget"),t.addClass("label"),t.canFocus=!1,e.multiline&&t.addClass("autoscroll"),e.strong&&t.addClass("strong")},initLayoutRect:function(){var e=this,n=e._super();if(e.settings.multiline){var r=t.getSize(e.getEl());r.width>n.maxW&&(n.minW=n.maxW,e.addClass("multiline")),e.getEl().style.width=n.minW+"px",n.startMinH=n.h=n.minH=Math.min(n.maxH,t.getSize(e.getEl()).height)}return n},repaint:function(){var e=this;return e.settings.multiline||(e.getEl().style.lineHeight=e.layoutRect().h+"px"),e._super()},text:function(e){var t=this;return t._rendered&&e&&this.innerHtml(t.encode(e)),t._super(e)},renderHtml:function(){var e=this,t=e.settings.forId;return'"}})}),r(Ft,[j],function(e){return e.extend({Defaults:{role:"toolbar",layout:"flow"},init:function(e){var t=this;t._super(e),t.addClass("toolbar")},postRender:function(){var e=this;return e.items().addClass("toolbar-item"),e._super()}})}),r(zt,[Ft],function(e){return e.extend({Defaults:{role:"menubar",containerCls:"menubar",ariaRoot:!0,defaults:{type:"menubutton"}}})}),r(Wt,[Ct,q,zt],function(e,t,n){function r(e,t){for(;e;){if(t===e)return!0;e=e.parentNode}return!1}var i=e.extend({init:function(e){var t=this;t._renderOpen=!0,t._super(e),t.addClass("menubtn"),e.fixedWidth&&t.addClass("fixed-width"),t.aria("haspopup",!0),t.hasPopup=!0},showMenu:function(){var e=this,n=e.settings,r;return e.menu&&e.menu.visible()?e.hideMenu():(e.menu||(r=n.menu||[],r.length?r={type:"menu",items:r}:r.type=r.type||"menu",e.menu=t.create(r).parent(e).renderTo(),e.fire("createmenu"),e.menu.reflow(),e.menu.on("cancel",function(t){t.control.parent()===e.menu&&(t.stopPropagation(),e.focus(),e.hideMenu())}),e.menu.on("select",function(){e.focus()}),e.menu.on("show hide",function(t){t.control==e.menu&&e.activeMenu("show"==t.type),e.aria("expanded","show"==t.type)}).fire("show")),e.menu.show(),e.menu.layoutRect({w:e.layoutRect().w}),void e.menu.moveRel(e.getEl(),e.isRtl()?["br-tr","tr-br"]:["bl-tl","tl-bl"]))},hideMenu:function(){var e=this;e.menu&&(e.menu.items().each(function(e){e.hideMenu&&e.hideMenu()}),e.menu.hide())},activeMenu:function(e){this.toggleClass("active",e)},renderHtml:function(){var e=this,t=e._id,r=e.classPrefix,i=e.settings.icon?r+"ico "+r+"i-"+e.settings.icon:"";return e.aria("role",e.parent()instanceof n?"menuitem":"button"),'
          '},postRender:function(){var e=this;return e.on("click",function(t){t.control===e&&r(t.target,e.getEl())&&(e.showMenu(),t.aria&&e.menu.items()[0].focus())}),e.on("mouseenter",function(t){var n=t.control,r=e.parent(),o;n&&r&&n instanceof i&&n.parent()==r&&(r.items().filter("MenuButton").each(function(e){e.hideMenu&&e!=n&&(e.menu&&e.menu.visible()&&(o=!0),e.hideMenu())}),o&&(n.focus(),n.showMenu()))}),e._super()},text:function(e){var t=this,n,r;if(t._rendered)for(r=t.getEl("open").getElementsByTagName("span"),n=0;n0&&(o=n[0].text,t._value=n[0].value),e.menu=n}e.text=e.text||o||n[0].text,t._super(e),t.addClass("listbox"),t.on("select",function(n){var r=n.control;a&&(n.lastControl=a),e.multiple?r.active(!r.active()):t.value(n.control.settings.value),a=r})},value:function(e){function t(e,n){e.items().each(function(e){r=e.value()===n,r&&(i=i||e.text()),e.active(r),e.menu&&t(e.menu,n)})}var n=this,r,i,o,a;if("undefined"!=typeof e){if(n.menu)t(n.menu,e);else for(o=n.settings.menu,a=0;a'+("-"!==o?' ":"")+("-"!==o?''+o+"":"")+(l?'
          '+l+"
          ":"")+(r.menu?'
          ':"")+""},postRender:function(){var e=this,t=e.settings,n=t.textStyle;if("function"==typeof n&&(n=n.call(this)),n){var r=e.getEl("text");r&&r.setAttribute("style",n)}return e.on("mouseenter click",function(n){n.control===e&&(t.menu||"click"!==n.type?(e.showMenu(),n.aria&&e.menu.focus(!0)):(e.fire("select"),e.parent().hideAll()))}),e._super(),e},active:function(e){return"undefined"!=typeof e&&this.aria("checked",e),this._super(e)},remove:function(){this._super(),this.menu&&this.menu.remove()}})}),r(qt,[Q,Ut,p],function(e,t,n){var r=e.extend({Defaults:{defaultType:"menuitem",border:1,layout:"stack",role:"application",bodyRole:"menu",ariaRoot:!0},init:function(e){var t=this;if(e.autohide=!0,e.constrainToViewport=!0,e.itemDefaults)for(var r=e.items,i=r.length;i--;)r[i]=n.extend({},e.itemDefaults,r[i]);t._super(e),t.addClass("menu")},repaint:function(){return this.toggleClass("menu-align",!0),this._super(),this.getEl().style.height="",this.getEl("body").style.height="",this},cancel:function(){var e=this;e.hideAll(),e.fire("select")},hideAll:function(){var e=this;return this.find("menuitem").exec("hideMenu"),e._super()},preRender:function(){var e=this;return e.items().each(function(t){var n=t.settings;return n.icon||n.selectable?(e._hasIcons=!0,!1):void 0}),e._super()}});return r}),r($t,[wt],function(e){return e.extend({Defaults:{classes:"radio",role:"radio"}})}),r(jt,[bt,K],function(e,t){return e.extend({renderHtml:function(){var e=this,t=e.classPrefix;return e.addClass("resizehandle"),"both"==e.settings.direction&&e.addClass("resizehandle-both"),e.canFocus=!1,'
          '},postRender:function(){var e=this;e._super(),e.resizeDragHelper=new t(this._id,{start:function(){e.fire("ResizeStart")},drag:function(t){"both"!=e.settings.direction&&(t.deltaX=0),e.fire("Resize",t)},stop:function(){e.fire("ResizeEnd")}})},remove:function(){return this.resizeDragHelper&&this.resizeDragHelper.destroy(),this._super()}})}),r(Kt,[bt],function(e){return e.extend({renderHtml:function(){var e=this;return e.addClass("spacer"),e.canFocus=!1,'
          '}})}),r(Yt,[Wt,V],function(e,t){return e.extend({Defaults:{classes:"widget btn splitbtn",role:"button"},repaint:function(){var e=this,n=e.getEl(),r=e.layoutRect(),i,o;return e._super(),i=n.firstChild,o=n.lastChild,t.css(i,{width:r.w-t.getSize(o).width,height:r.h-2}),t.css(o,{height:r.h-2}),e},activeMenu:function(e){var n=this;t.toggleClass(n.getEl().lastChild,n.classPrefix+"active",e)},renderHtml:function(){var e=this,t=e._id,n=e.classPrefix,r=e.settings.icon?n+"ico "+n+"i-"+e.settings.icon:"";return'
          '},postRender:function(){var e=this,t=e.settings.onclick;return e.on("click",function(e){var n=e.target;if(e.control==this)for(;n;){if(e.aria&&"down"!=e.aria.key||"BUTTON"==n.nodeName&&-1==n.className.indexOf("open"))return e.stopImmediatePropagation(),void t.call(this,e);n=n.parentNode}}),delete e.settings.onclick,e._super()}})}),r(Gt,[Ht],function(e){return e.extend({Defaults:{containerClass:"stack-layout",controlClass:"stack-layout-item",endClass:"break"}})}),r(Xt,[G,V],function(e,t){return e.extend({lastIdx:0,Defaults:{layout:"absolute",defaults:{type:"panel"}},activateTab:function(e){var n;this.activeTabId&&(n=this.getEl(this.activeTabId),t.removeClass(n,this.classPrefix+"active"),n.setAttribute("aria-selected","false")),this.activeTabId="t"+e,n=this.getEl("t"+e),n.setAttribute("aria-selected","true"),t.addClass(n,this.classPrefix+"active"),e!=this.lastIdx&&(this.items()[this.lastIdx].hide(),this.lastIdx=e),this.items()[e].show().fire("showtab"),this.reflow()},renderHtml:function(){var e=this,t=e._layout,n="",r=e.classPrefix;return e.preRender(),t.preRender(e),e.items().each(function(t,i){var o=e._id+"-t"+i;t.aria("role","tabpanel"),t.aria("labelledby",o),n+='"}),'
          '+n+'
          '+t.renderHtml(e)+"
          "},postRender:function(){var e=this;e._super(),e.settings.activeTab=e.settings.activeTab||0,e.activateTab(e.settings.activeTab),this.on("click",function(t){var n=t.target.parentNode;if(t.target.parentNode.id==e._id+"-head")for(var r=n.childNodes.length;r--;)n.childNodes[r]==t.target&&e.activateTab(r)})},initLayoutRect:function(){var e=this,n,r,i;r=t.getSize(e.getEl("head")).width,r=0>r?0:r,i=0,e.items().each(function(t,n){r=Math.max(r,t.layoutRect().minW),i=Math.max(i,t.layoutRect().minH),e.settings.activeTab!=n&&t.hide()}),e.items().each(function(e){e.settings.x=0,e.settings.y=0,e.settings.w=r,e.settings.h=i,e.layoutRect({x:0,y:0,w:r,h:i})});var o=t.getSize(e.getEl("head")).height;return e.settings.minWidth=r,e.settings.minHeight=i+o,n=e._super(),n.deltaH+=o,n.innerH=n.h-n.deltaH,n}})}),r(Jt,[bt,V],function(e,t){return e.extend({init:function(e){var t=this;t._super(e),t._value=e.value||"",t.addClass("textbox"),e.multiline?t.addClass("multiline"):t.on("keydown",function(e){13==e.keyCode&&t.parents().reverse().each(function(t){return e.preventDefault(),t.hasEventListeners("submit")&&t.toJSON?(t.fire("submit",{data:t.toJSON()}),!1):void 0})})},disabled:function(e){var t=this;return t._rendered&&"undefined"!=typeof e&&(t.getEl().disabled=e),t._super(e)},value:function(e){var t=this;return"undefined"!=typeof e?(t._value=e,t._rendered&&(t.getEl().value=e),t):t._rendered?t.getEl().value:t._value},repaint:function(){var e=this,t,n,r,i=0,o=0,a;t=e.getEl().style,n=e._layoutRect,a=e._lastRepaintRect||{};var s=document;return!e.settings.multiline&&s.all&&(!s.documentMode||s.documentMode<=8)&&(t.lineHeight=n.h-o+"px"),r=e._borderBox,i=r.left+r.right+8,o=r.top+r.bottom+(e.settings.multiline?8:0),n.x!==a.x&&(t.left=n.x+"px",a.x=n.x),n.y!==a.y&&(t.top=n.y+"px",a.y=n.y),n.w!==a.w&&(t.width=n.w-i+"px",a.w=n.w),n.h!==a.h&&(t.height=n.h-o+"px",a.h=n.h),e._lastRepaintRect=a,e.fire("repaint",{},!1),e},renderHtml:function(){var e=this,t=e._id,n=e.settings,r=e.encode(e._value,!1),i="";return"spellcheck"in n&&(i+=' spellcheck="'+n.spellcheck+'"'),n.maxLength&&(i+=' maxlength="'+n.maxLength+'"'),n.size&&(i+=' size="'+n.size+'"'),n.subtype&&(i+=' type="'+n.subtype+'"'),e.disabled()&&(i+=' disabled="disabled"'),n.multiline?'":'"},postRender:function(){var e=this;return t.on(e.getEl(),"change",function(t){e.fire("change",t)}),e._super()},remove:function(){t.off(this.getEl()),this._super()}})}),r(Qt,[V],function(e){return function(t){var n=this,r;n.show=function(i){return n.hide(),r=!0,window.setTimeout(function(){r&&t.appendChild(e.createFragment('
          '))},i||0),n},n.hide=function(){var e=t.lastChild;return e&&-1!=e.className.indexOf("throbber")&&e.parentNode.removeChild(e),r=!1,n}}}),a([l,c,u,d,f,p,m,h,g,v,y,b,C,x,w,_,N,E,S,k,T,R,A,B,D,L,H,M,P,O,I,F,z,W,V,U,q,$,j,K,Y,G,X,J,Q,Z,et,tt,nt,rt,it,ot,at,st,lt,ct,ut,dt,ft,pt,mt,ht,gt,vt,yt,bt,Ct,xt,wt,_t,Nt,Et,St,kt,Tt,Rt,At,Bt,Dt,Lt,Ht,Mt,Pt,Ot,It,Ft,zt,Wt,Vt,Ut,qt,$t,jt,Kt,Yt,Gt,Xt,Jt,Qt])}(this); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/font-awesome.css b/src/Presentation/SmartStore.Web/Content/font-awesome.css new file mode 100644 index 0000000000..ba49171638 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/font-awesome.css @@ -0,0 +1,2086 @@ +/*! + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('fonts/fontawesome-webfont.eot?v=4.5.0'); + src: url('fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook-f:before, +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-feed:before, +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-desc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-asc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before, +.fa-gratipay:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: "\f1e3"; +} +.fa-tty:before { + content: "\f1e4"; +} +.fa-binoculars:before { + content: "\f1e5"; +} +.fa-plug:before { + content: "\f1e6"; +} +.fa-slideshare:before { + content: "\f1e7"; +} +.fa-twitch:before { + content: "\f1e8"; +} +.fa-yelp:before { + content: "\f1e9"; +} +.fa-newspaper-o:before { + content: "\f1ea"; +} +.fa-wifi:before { + content: "\f1eb"; +} +.fa-calculator:before { + content: "\f1ec"; +} +.fa-paypal:before { + content: "\f1ed"; +} +.fa-google-wallet:before { + content: "\f1ee"; +} +.fa-cc-visa:before { + content: "\f1f0"; +} +.fa-cc-mastercard:before { + content: "\f1f1"; +} +.fa-cc-discover:before { + content: "\f1f2"; +} +.fa-cc-amex:before { + content: "\f1f3"; +} +.fa-cc-paypal:before { + content: "\f1f4"; +} +.fa-cc-stripe:before { + content: "\f1f5"; +} +.fa-bell-slash:before { + content: "\f1f6"; +} +.fa-bell-slash-o:before { + content: "\f1f7"; +} +.fa-trash:before { + content: "\f1f8"; +} +.fa-copyright:before { + content: "\f1f9"; +} +.fa-at:before { + content: "\f1fa"; +} +.fa-eyedropper:before { + content: "\f1fb"; +} +.fa-paint-brush:before { + content: "\f1fc"; +} +.fa-birthday-cake:before { + content: "\f1fd"; +} +.fa-area-chart:before { + content: "\f1fe"; +} +.fa-pie-chart:before { + content: "\f200"; +} +.fa-line-chart:before { + content: "\f201"; +} +.fa-lastfm:before { + content: "\f202"; +} +.fa-lastfm-square:before { + content: "\f203"; +} +.fa-toggle-off:before { + content: "\f204"; +} +.fa-toggle-on:before { + content: "\f205"; +} +.fa-bicycle:before { + content: "\f206"; +} +.fa-bus:before { + content: "\f207"; +} +.fa-ioxhost:before { + content: "\f208"; +} +.fa-angellist:before { + content: "\f209"; +} +.fa-cc:before { + content: "\f20a"; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: "\f20b"; +} +.fa-meanpath:before { + content: "\f20c"; +} +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} diff --git a/src/Presentation/SmartStore.Web/Content/font-awesome.min.css b/src/Presentation/SmartStore.Web/Content/font-awesome.min.css new file mode 100644 index 0000000000..acce2ef232 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('fonts/fontawesome-webfont.eot?v=4.5.0');src:url('fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'),url('fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'),url('fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'),url('fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'),url('fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"} diff --git a/src/Presentation/SmartStore.Web/Content/fonts/FontAwesome.otf b/src/Presentation/SmartStore.Web/Content/fonts/FontAwesome.otf new file mode 100644 index 0000000000..3ed7f8b48a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/fonts/FontAwesome.otf differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.eot b/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.eot deleted file mode 100644 index e179d5fe77..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.eot and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.svg b/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.svg deleted file mode 100644 index 95f295b61e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.svg +++ /dev/null @@ -1,391 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. -9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.ttf b/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.ttf deleted file mode 100644 index 9817e5cf4e..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.ttf and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.woff b/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.woff deleted file mode 100644 index 3a60828b77..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/fonts/Fontastic.woff and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/fontastic.less b/src/Presentation/SmartStore.Web/Content/fonts/fontastic.less deleted file mode 100644 index 28f363b995..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/fontastic.less +++ /dev/null @@ -1,202 +0,0 @@ -@font-face { - font-family: 'Fontastic'; - src:url('Fontastic.eot'); - src:url('Fontastic.eot?#iefix') format('embedded-opentype'), - url('Fontastic.woff') format('woff'), - url('Fontastic.ttf') format('truetype'), - url('Fontastic.svg#Fontastic') format('svg'); - font-weight: normal; - font-style: normal; -} - -/* Use the following CSS code if you want to use data attributes for inserting your icons */ -[data-icon]:before { - font-family: 'Fontastic'; - content: attr(data-icon); - speak: none; - font-weight: normal; - -webkit-font-smoothing: antialiased; -} - -/* Use the following CSS code if you want to have a class per icon */ -[class^="sm-icon-"]:before, [class*=" sm-icon-"]:before { - font-family: 'Fontastic'; - font-style: normal; - speak: none; - font-weight: normal; - -webkit-font-smoothing: antialiased; -} -.sm-icon-database:before { - content: "\21"; -} -.sm-icon-user:before { - content: "\22"; -} -.sm-icon-cog:before { - content: "\23"; -} -.sm-icon-stats-up:before { - content: "\24"; -} -.sm-icon-gift:before { - content: "\25"; -} -.sm-icon-cube:before { - content: "\26"; -} -.sm-icon-help:before { - content: "\27"; -} -.sm-icon-loop:before { - content: "\28"; -} -.sm-icon-tag:before { - content: "\29"; -} -.sm-icon-tab:before { - content: "\2a"; -} -.sm-icon-gift-2:before { - content: "\2b"; -} -.sm-icon-home:before { - content: "\2c"; -} -.sm-icon-home-2:before { - content: "\2d"; -} -.sm-icon-earth:before { - content: "\2e"; -} -.sm-icon-database-2:before { - content: "\2f"; -} -.sm-icon-cog-2:before { - content: "\30"; -} -.sm-icon-loop-alt3:before { - content: "\31"; -} -.sm-icon-loop-alt4:before { - content: "\32"; -} -.sm-icon-loop-alt2:before { - content: "\33"; -} -.sm-icon-layers:before { - content: "\34"; -} -.sm-icon-user-2:before { - content: "\35"; -} -.sm-icon-tag-stroke:before { - content: "\36"; -} -.sm-icon-tag-fill:before { - content: "\37"; -} -.sm-icon-home-3:before { - content: "\38"; -} -.sm-icon-user-3:before { - content: "\39"; -} -.sm-icon-user-4:before { - content: "\3a"; -} -.sm-icon-users:before { - content: "\3b"; -} -.sm-icon-archive:before { - content: "\3c"; -} -.sm-icon-cog-3:before { - content: "\3d"; -} -.sm-icon-refresh:before { - content: "\3e"; -} -.sm-icon-tag-2:before { - content: "\3f"; -} -.sm-icon-tag-3:before { - content: "\40"; -} -.sm-icon-cog-4:before { - content: "\41"; -} -.sm-icon-folder:before { - content: "\42"; -} -.sm-icon-chart:before { - content: "\43"; -} -.sm-icon-cube-2:before { - content: "\44"; -} -.sm-icon-megaphone:before { - content: "\45"; -} -.sm-icon-box:before { - content: "\46"; -} -.sm-icon-layout:before { - content: "\47"; -} -.sm-icon-layout-2:before { - content: "\48"; -} -.sm-icon-layout-3:before { - content: "\49"; -} -.sm-icon-layout-4:before { - content: "\4a"; -} -.sm-icon-stats:before { - content: "\4b"; -} -.sm-icon-discout:before { - content: "\4c"; -} -.sm-icon-retweet:before { - content: "\4d"; -} -.sm-icon-tags:before { - content: "\4e"; -} -.sm-icon-users-2:before { - content: "\4f"; -} -.sm-icon-user-5:before { - content: "\50"; -} -.sm-icon-price:before { - content: "\51"; -} -.sm-icon-retweet-2:before { - content: "\52"; -} -.sm-icon-download:before { - content: "\53"; -} -.sm-icon-upload:before { - content: "\54"; -} -.sm-icon-home-4:before { - content: "\55"; -} -.sm-icon-dots-three:before { - content: "\56"; -} -.sm-icon-users-3:before { - content: "\e029"; -} -.sm-icon-user-6:before { - content: "\e028"; -} -.sm-icon-cog-5:before { - content: "\e000"; -} -.sm-icon-user-7:before { - content: "\e001"; -} diff --git a/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.eot b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000000..9b6afaedc0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.eot differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.svg b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000000..d05688e9e2 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.svg @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.ttf b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000000..26dea7951a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.ttf differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.woff b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000000..dc35ce3c2c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.woff differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.woff2 b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000000..500e517253 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/fonts/fontawesome-webfont.woff2 differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/IcoMoon Session.json b/src/Presentation/SmartStore.Web/Content/fonts/raw/IcoMoon Session.json deleted file mode 100644 index b0e4ef45ab..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/IcoMoon Session.json +++ /dev/null @@ -1 +0,0 @@ -{"share":"6", "iconsVersion":"1.4", "icomoon":"{\"selected\":[{\"idx\":\"591\",\"unicode\":\"21\"},{\"idx\":\"577\",\"unicode\":\"22\"},{\"idx\":\"563\",\"unicode\":\"23\"},{\"idx\":\"560\",\"unicode\":\"24\"},{\"idx\":\"559\",\"unicode\":\"25\"},{\"idx\":\"541\",\"unicode\":\"26\"},{\"idx\":\"497\",\"unicode\":\"27\"},{\"idx\":\"488\",\"unicode\":\"28\"},{\"idx\":\"270\",\"unicode\":\"29\"},{\"idx\":\"259\",\"unicode\":\"2b\"},{\"idx\":\"642\",\"unicode\":\"2d\"},{\"idx\":\"285\",\"unicode\":\"2e\"},{\"idx\":\"109\",\"unicode\":\"33\"},{\"idx\":\"36\",\"unicode\":\"34\"},{\"idx\":\"19\",\"unicode\":\"36\"},{\"idx\":\"816\",\"unicode\":\"3c\"},{\"idx\":\"803\",\"unicode\":\"3d\"},{\"idx\":\"788\",\"unicode\":\"3e\"},{\"idx\":\"1149\",\"unicode\":\"3f\"},{\"idx\":\"1148\",\"unicode\":\"40\"},{\"idx\":\"1065\",\"unicode\":\"43\"},{\"idx\":\"983\",\"unicode\":\"44\"},{\"idx\":\"991\",\"unicode\":\"45\"},{\"idx\":\"981\",\"unicode\":\"46\"},{\"idx\":\"962\",\"unicode\":\"47\"},{\"idx\":\"961\",\"unicode\":\"48\"},{\"idx\":\"959\",\"unicode\":\"49\"},{\"idx\":\"958\",\"unicode\":\"4a\"},{\"idx\":\"933\",\"unicode\":\"4b\"},{\"idx\":\"924\",\"unicode\":\"4c\"},{\"idx\":\"914\",\"unicode\":\"4d\"},{\"idx\":\"830\",\"unicode\":\"4e\"},{\"idx\":\"1393\",\"unicode\":\"4f\"},{\"idx\":\"1394\",\"unicode\":\"50\"},{\"idx\":\"1368\",\"unicode\":\"51\"},{\"idx\":\"1331\",\"unicode\":\"52\"},{\"idx\":\"1316\",\"unicode\":\"53\"},{\"idx\":\"1317\",\"unicode\":\"54\"},{\"idx\":\"1253\",\"unicode\":\"55\"},{\"idx\":\"1248\",\"unicode\":\"56\"},{\"idx\":\"1453\",\"unicode\":\"57\"},{\"idx\":\"1392\",\"unicode\":\"2a\"},{\"idx\":\"1367\",\"unicode\":\"2c\"},{\"idx\":\"1674\",\"unicode\":\"2f\"},{\"idx\":\"1673\",\"unicode\":\"30\"},{\"idx\":\"1362\",\"unicode\":\"31\"},{\"idx\":\"616\",\"unicode\":\"32\"},{\"idx\":\"721\",\"unicode\":\"35\"},{\"idx\":\"318\",\"unicode\":\"37\"},{\"idx\":\"255\",\"unicode\":\"38\"}],\"customIcons\":[{\"metadata\":{\"id\":\"iconic\",\"name\":\"Iconic\",\"link\":\"http://somerandomdude.com/work/iconic/\",\"author\":\"P.J. Onori\",\"authorLink\":\"http://somerandomdude.com\",\"license\":\"CC BY-SA 3.0\",\"licenseLink\":\"http://creativecommons.org/licenses/by-sa/3.0/us/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"meteocons\",\"name\":\"Meteocons\",\"link\":\"http://www.alessioatzeni.com/meteocons/\",\"author\":\"Alessio Atzeni\",\"authorLink\":\"http://www.alessioatzeni.com/\",\"license\":\"Arbitrary\",\"licenseLink\":\"http://www.alessioatzeni.com/meteocons/#about\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"broccolidry\",\"name\":\"Broccolidry\",\"link\":\"http://dribbble.com/shots/587469-Free-16px-Broccolidryiconsaniconsetitisfullof-icons\",\"author\":\"Visual Idiot\",\"authorLink\":\"http://idiot.vc/\",\"license\":\"Aribitrary\",\"licenseLink\":\"http://licence.visualidiot.com/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"icomoon\",\"name\":\"IcoMoon - Free\",\"link\":\"http://keyamoon.com/icomoon/\",\"author\":\"Keyamoon\",\"authorLink\":\"http://keyamoon.com/\",\"license\":\"CC BY-SA 3.0\",\"licenseLink\":\"http://creativecommons.org/licenses/by-sa/3.0/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"iconminia\",\"name\":\"Icon Minia\",\"link\":\"http://dribbble.com/shots/598215-Icon-Minia-139-Vector-Icons\",\"author\":\"Egemen Kapusuz\",\"authorLink\":\"https://twitter.com/#!/egemem\",\"license\":\"GPL V3\",\"licenseLink\":\"http://www.gnu.org/copyleft/gpl.html\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"ecoico\",\"name\":\"Eco Ico\",\"link\":\"http://dribbble.com/shots/665585-Eco-Ico\",\"author\":\"Matthew Skiles\",\"authorLink\":\"http://www.dvq.co.nz/\",\"license\":\"CC0\",\"licenseLink\":\"http://creativecommons.org/publicdomain/zero/1.0/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"brankic1979\",\"name\":\"Brankic1979\",\"link\":\"http://brankic1979.com/icons/\",\"author\":\"Keyamoon\",\"authorLink\":\"http://brankic1979.com\",\"license\":\"Custom\",\"licenseLink\":\"http://brankic1979.com/icons/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"cuticons\",\"name\":\"Cuticons\",\"link\":\"http://dribbble.com/shots/631056-Cuticons-You-wanted-free-icons-right\",\"author\":\"Vaibhav Bhat\",\"authorLink\":\"https://twitter.com/vabhat\",\"license\":\"CC0\",\"licenseLink\":\"http://creativecommons.org/publicdomain/zero/1.0/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"entypo\",\"name\":\"Entypo\",\"link\":\"http://www.entypo.com/\",\"author\":\"Daniel Bruce\",\"authorLink\":\"mailto:daniel@precinct.net\",\"license\":\"CC BY-SA 3.0\",\"licenseLink\":\"http://creativecommons.org/licenses/by-sa/3.0/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"typicons\",\"name\":\"Typicons\",\"link\":\"http://typicons.com/\",\"author\":\"Stephen Hutchings\",\"license\":\"CC BY-SA 3.0\",\"licenseLink\":\"http://creativecommons.org/licenses/by-sa/3.0/\",\"defaultunicode\":true},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"silkcons\",\"name\":\"Silkcons\",\"link\":\"http://dribbble.com/shots/632219-Silkcons-You-can-t-do-with-just-one-icon-set\",\"author\":\"Vaibhav Bhat\",\"authorLink\":\"https://twitter.com/vabhat\",\"license\":\"CC0\",\"licenseLink\":\"http://creativecommons.org/publicdomain/zero/1.0/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"wpzoom\",\"name\":\"WPZOOM Developer Icon Set\",\"link\":\"http://www.wpzoom.com/wpzoom/new-freebie-wpzoom-developer-icon-set-154-free-icons/\",\"author\":\"David Ferreira\",\"authorLink\":\"http://cargocollective.com/davidferreira\",\"license\":\"CC BY-SA 3.0\",\"licenseLink\":\"http://creativecommons.org/licenses/by-sa/3.0/\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]},{\"metadata\":{\"id\":\"loops105\",\"name\":\"105 Loops\",\"link\":\"http://dribbble.com/shots/707117-105-Loops-with-PSD\",\"author\":\"Pranav\",\"authorLink\":\"http://dribbble.com/pranav\",\"license\":\"Custom\",\"licenseLink\":\"http://dribbble.com/shots/707117-105-Loops-with-PSD\",\"defaultunicode\":false},\"svgs\":[\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\",\"\"]}],\"IDs\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,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,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544,545,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571,572,573,574,575,576,577,578,579,580,581,582,583,584,585,586,587,588,589,590,591,592,593,594,595,596,597,598,599,600,601,602,603,604,605,606,607,608,609,610,611,612,613,614,615,616,617,619,620,621,622,623,624,625,626,627,628,629,630,631,632,633,634,635,636,637,638,639,640,642,643,644,645,646,647,648,649,650,651,652,653,654,655,656,657,658,659,660,661,662,663,664,665,667,668,669,670,671,672,673,674,675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,782,783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,837,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,975,976,977,978,979,980,981,982,983,984,985,986,987,988,989,990,991,992,993,994,995,996,997,998,999,1000,1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1011,1012,1013,1014,1015,1016,1017,1018,1019,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1098,1099,1100,1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126,1127,1128,1129,1130,1131,1132,1133,1134,1135,1136,1137,1138,1139,1140,1141,1142,1143,1144,1145,1146,1147,1148,1149,1150,1151,1152,1153,1154,1155,1156,1157,1158,1159,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1173,1174,1175,1176,1177,1178,1179,1180,1181,1182,1183,1184,1185,1186,1187,1188,1189,1191,1192,1193,1194,1195,1196,1197,1198,1199,1200,1201,1202,1203,1204,1205,1206,1207,1208,1209,1210,1211,1212,1213,1214,1215,1216,1217,1218,1219,1220,1221,1222,1223,1224,1225,1226,1227,1228,1229,1230,1231,1232,1233,1234,1235,1236,1237,1238,1239,1240,1241,1242,1243,1244,1245,1246,1247,1248,1249,1250,1251,1252,1253,1254,1255,1256,1257,1258,1259,1260,1261,1262,1263,1264,1265,1266,1267,1268,1269,1270,1271,1272,1273,1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1285,1286,1287,1288,1289,1290,1291,1292,1293,1294,1295,1296,1297,1298,1299,1300,1301,1302,1303,1304,1305,1306,1307,1308,1309,1310,1311,1312,1313,1314,1315,1316,1317,1318,1319,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378,1379,1380,1381,1382,1383,1384,1385,1386,1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397,1398,1399,1400,1401,1402,1403,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869],\"user\":{\"email\":\"keyamoon@gmail.com\",\"newsletter\":true,\"secret\":\"29769e48fe4bab8807b024a41d770900e18015c1af12cf4ad63d2d19009e6a90aead0d2885d7a32787d7336b442a44662cdfddfa2a2b0c74445becb1f50a8998\",\"uid\":4}}","inputCache":"{\"baseline\":\"0\",\"emSize\":\"512\",\"prev_size\":\"32\",\"hdr-imported\":\"checked\",\"iconAlignment\":\"0\",\"showGrid\":\"checked\",\"fi_name\":\"Fontastic\",\"fi_id\":\"\",\"fi_link\":\"\",\"fi_author\":\"\",\"fi_authorLink\":\"\",\"fi_license\":\"\",\"fi_licenseLink\":\"\",\"include_metadata\":false,\"base64\":false,\"img-height\":\"24\",\"img-color\":\"000000\",\"include_png\":\"checked\",\"fi_class\":\"sm-icon-\",\"showCloudLinks\":false,\"hdr-iconic\":\"checked\",\"hdr-meteocons\":\"checked\",\"hdr-broccolidry\":\"checked\",\"hdr-icomoon\":\"checked\",\"hdr-iconminia\":\"checked\",\"hdr-ecoico\":\"checked\",\"hdr-brankic1979\":\"checked\",\"hdr-cuticons\":\"checked\",\"hdr-entypo\":\"checked\",\"hdr-typicons\":\"checked\",\"hdr-silkcons\":\"checked\",\"hdr-wpzoom\":\"checked\",\"hdr-loops105\":\"checked\",\"sprites-cols\":\"16\",\"include_sprites\":false}"} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.eot b/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.eot deleted file mode 100644 index e179d5fe77..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.eot and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.svg b/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.svg deleted file mode 100644 index 95f295b61e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.svg +++ /dev/null @@ -1,391 +0,0 @@ - - - - -This is a custom SVG font generated by IcoMoon. -9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.ttf b/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.ttf deleted file mode 100644 index 9817e5cf4e..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.ttf and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.woff b/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.woff deleted file mode 100644 index 3a60828b77..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/fonts/raw/fonts/Fontastic.woff and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/index.html b/src/Presentation/SmartStore.Web/Content/fonts/raw/index.html deleted file mode 100644 index e628421a3b..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/index.html +++ /dev/null @@ -1,508 +0,0 @@ - - - -Your Font/Glyphs - - - - - -
          -
          -
          -

          Your font contains the following glyphs

          -

          The generated SVG font can be imported back to IcoMoon for modification.

          -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          - - -
          -
          -
          -
          -
          -

          CSS Class Names

          -
          - - -  sm-icon-database - - - -  sm-icon-user - - - -  sm-icon-cog - - - -  sm-icon-stats-up - - - -  sm-icon-gift - - - -  sm-icon-cube - - - -  sm-icon-help - - - -  sm-icon-loop - - - -  sm-icon-tag - - - -  sm-icon-gift-2 - - - -  sm-icon-home - - - -  sm-icon-earth - - - -  sm-icon-loop-alt2 - - - -  sm-icon-layers - - - -  sm-icon-tag-stroke - - - -  sm-icon-archive - - - -  sm-icon-cog-2 - - - -  sm-icon-refresh - - - -  sm-icon-tag-2 - - - -  sm-icon-tag-3 - - - -  sm-icon-chart - - - -  sm-icon-cube-2 - - - -  sm-icon-megaphone - - - -  sm-icon-box - - - -  sm-icon-layout - - - -  sm-icon-layout-2 - - - -  sm-icon-layout-3 - - - -  sm-icon-layout-4 - - - -  sm-icon-stats - - - -  sm-icon-discout - - - -  sm-icon-retweet - - - -  sm-icon-tags - - - -  sm-icon-users - - - -  sm-icon-user-2 - - - -  sm-icon-price - - - -  sm-icon-retweet-2 - - - -  sm-icon-download - - - -  sm-icon-upload - - - -  sm-icon-home-2 - - - -  sm-icon-dots-three - - - -  sm-icon-users-2 - - - -  sm-icon-contact - - - -  sm-icon-camera - - - -  sm-icon-cart - - - -  sm-icon-bag - - - -  sm-icon-shopping - - - -  sm-icon-cart-2 - - - -  sm-icon-cart-3 - - - -  sm-icon-cart-4 - - - -  sm-icon-basket - -
          - -
          - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/license.txt b/src/Presentation/SmartStore.Web/Content/fonts/raw/license.txt deleted file mode 100644 index f963b349f2..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/license.txt +++ /dev/null @@ -1,34 +0,0 @@ -Icon Set: WPZOOM Developer Icon Set -- http://www.wpzoom.com/wpzoom/new-freebie-wpzoom-developer-icon-set-154-free-icons/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Typicons -- http://typicons.com/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Entypo -- http://www.entypo.com/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Brankic1979 -- http://brankic1979.com/icons/ -License: Custom -- http://brankic1979.com/icons/ - - -Icon Set: Eco Ico -- http://dribbble.com/shots/665585-Eco-Ico -License: CC0 -- http://creativecommons.org/publicdomain/zero/1.0/ - - -Icon Set: Icon Minia -- http://dribbble.com/shots/598215-Icon-Minia-139-Vector-Icons -License: GPL V3 -- http://www.gnu.org/copyleft/gpl.html - - -Icon Set: IcoMoon - Free -- http://keyamoon.com/icomoon/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/ - - -Icon Set: Broccolidry -- http://dribbble.com/shots/587469-Free-16px-Broccolidryiconsaniconsetitisfullof-icons -License: Aribitrary -- http://licence.visualidiot.com/ - - -Icon Set: Iconic -- http://somerandomdude.com/work/iconic/ -License: CC BY-SA 3.0 -- http://creativecommons.org/licenses/by-sa/3.0/us/ \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/lte-ie7.js b/src/Presentation/SmartStore.Web/Content/fonts/raw/lte-ie7.js deleted file mode 100644 index b109d62b28..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/lte-ie7.js +++ /dev/null @@ -1,74 +0,0 @@ -/* Use this script if you need to support IE 7 and IE 6. */ - -window.onload = function() { - function addIcon(el, entity) { - var html = el.innerHTML; - el.innerHTML = '' + entity + '' + html; - } - var icons = { - 'sm-icon-database' : '!', - 'sm-icon-user' : '"', - 'sm-icon-cog' : '#', - 'sm-icon-stats-up' : '$', - 'sm-icon-gift' : '%', - 'sm-icon-cube' : '&', - 'sm-icon-help' : ''', - 'sm-icon-loop' : '(', - 'sm-icon-tag' : ')', - 'sm-icon-gift-2' : '+', - 'sm-icon-home' : '-', - 'sm-icon-earth' : '.', - 'sm-icon-loop-alt2' : '3', - 'sm-icon-layers' : '4', - 'sm-icon-tag-stroke' : '6', - 'sm-icon-archive' : '<', - 'sm-icon-cog-2' : '=', - 'sm-icon-refresh' : '>', - 'sm-icon-tag-2' : '?', - 'sm-icon-tag-3' : '@', - 'sm-icon-chart' : 'C', - 'sm-icon-cube-2' : 'D', - 'sm-icon-megaphone' : 'E', - 'sm-icon-box' : 'F', - 'sm-icon-layout' : 'G', - 'sm-icon-layout-2' : 'H', - 'sm-icon-layout-3' : 'I', - 'sm-icon-layout-4' : 'J', - 'sm-icon-stats' : 'K', - 'sm-icon-discout' : 'L', - 'sm-icon-retweet' : 'M', - 'sm-icon-tags' : 'N', - 'sm-icon-users' : 'O', - 'sm-icon-user-2' : 'P', - 'sm-icon-price' : 'Q', - 'sm-icon-retweet-2' : 'R', - 'sm-icon-download' : 'S', - 'sm-icon-upload' : 'T', - 'sm-icon-home-2' : 'U', - 'sm-icon-dots-three' : 'V', - 'sm-icon-users-2' : 'W', - 'sm-icon-contact' : '*', - 'sm-icon-camera' : ',', - 'sm-icon-cart' : '/', - 'sm-icon-bag' : '0', - 'sm-icon-shopping' : '1', - 'sm-icon-cart-2' : '2', - 'sm-icon-cart-3' : '5', - 'sm-icon-cart-4' : '7', - 'sm-icon-basket' : '8' - }, - els = document.getElementsByTagName('*'), - i, attr, html, c, el; - for (i = 0; i < els.length; i += 1) { - el = els[i]; - attr = el.getAttribute('data-icon'); - if (attr) { - addIcon(el, attr); - } - c = el.className; - c = c.match(/sm-icon-[^\s'"]+/); - if (c && icons[c[0]]) { - addIcon(el, icons[c[0]]); - } - } -}; \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/fonts/raw/style.css b/src/Presentation/SmartStore.Web/Content/fonts/raw/style.css deleted file mode 100644 index cf8e62665b..0000000000 --- a/src/Presentation/SmartStore.Web/Content/fonts/raw/style.css +++ /dev/null @@ -1,180 +0,0 @@ -@font-face { - font-family: 'Fontastic'; - src:url('fonts/Fontastic.eot'); - src:url('fonts/Fontastic.eot?#iefix') format('embedded-opentype'), - url('fonts/Fontastic.svg#Fontastic') format('svg'), - url('fonts/Fontastic.woff') format('woff'), - url('fonts/Fontastic.ttf') format('truetype'); - font-weight: normal; - font-style: normal; -} - -/* Use the following CSS code if you want to use data attributes for inserting your icons */ -[data-icon]:before { - font-family: 'Fontastic'; - content: attr(data-icon); - speak: none; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; -} - -/* Use the following CSS code if you want to have a class per icon */ -[class^="sm-icon-"]:before, [class*=" sm-icon-"]:before { - font-family: 'Fontastic'; - font-style: normal; - speak: none; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; -} -.sm-icon-database:before { - content: "\21"; -} -.sm-icon-user:before { - content: "\22"; -} -.sm-icon-cog:before { - content: "\23"; -} -.sm-icon-stats-up:before { - content: "\24"; -} -.sm-icon-gift:before { - content: "\25"; -} -.sm-icon-cube:before { - content: "\26"; -} -.sm-icon-help:before { - content: "\27"; -} -.sm-icon-loop:before { - content: "\28"; -} -.sm-icon-tag:before { - content: "\29"; -} -.sm-icon-gift-2:before { - content: "\2b"; -} -.sm-icon-home:before { - content: "\2d"; -} -.sm-icon-earth:before { - content: "\2e"; -} -.sm-icon-loop-alt2:before { - content: "\33"; -} -.sm-icon-layers:before { - content: "\34"; -} -.sm-icon-tag-stroke:before { - content: "\36"; -} -.sm-icon-archive:before { - content: "\3c"; -} -.sm-icon-cog-2:before { - content: "\3d"; -} -.sm-icon-refresh:before { - content: "\3e"; -} -.sm-icon-tag-2:before { - content: "\3f"; -} -.sm-icon-tag-3:before { - content: "\40"; -} -.sm-icon-chart:before { - content: "\43"; -} -.sm-icon-cube-2:before { - content: "\44"; -} -.sm-icon-megaphone:before { - content: "\45"; -} -.sm-icon-box:before { - content: "\46"; -} -.sm-icon-layout:before { - content: "\47"; -} -.sm-icon-layout-2:before { - content: "\48"; -} -.sm-icon-layout-3:before { - content: "\49"; -} -.sm-icon-layout-4:before { - content: "\4a"; -} -.sm-icon-stats:before { - content: "\4b"; -} -.sm-icon-discout:before { - content: "\4c"; -} -.sm-icon-retweet:before { - content: "\4d"; -} -.sm-icon-tags:before { - content: "\4e"; -} -.sm-icon-users:before { - content: "\4f"; -} -.sm-icon-user-2:before { - content: "\50"; -} -.sm-icon-price:before { - content: "\51"; -} -.sm-icon-retweet-2:before { - content: "\52"; -} -.sm-icon-download:before { - content: "\53"; -} -.sm-icon-upload:before { - content: "\54"; -} -.sm-icon-home-2:before { - content: "\55"; -} -.sm-icon-dots-three:before { - content: "\56"; -} -.sm-icon-users-2:before { - content: "\57"; -} -.sm-icon-contact:before { - content: "\2a"; -} -.sm-icon-camera:before { - content: "\2c"; -} -.sm-icon-cart:before { - content: "\2f"; -} -.sm-icon-bag:before { - content: "\30"; -} -.sm-icon-shopping:before { - content: "\31"; -} -.sm-icon-cart-2:before { - content: "\32"; -} -.sm-icon-cart-3:before { - content: "\35"; -} -.sm-icon-cart-4:before { - content: "\37"; -} -.sm-icon-basket:before { - content: "\38"; -} diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css new file mode 100644 index 0000000000..bc6725bd86 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-custom.css @@ -0,0 +1,151 @@ + +.smartgallery-overlay, +.blueimp-gallery { + -webkit-transition: opacity 0.2s linear, transform 0.2s ease-out; + transition: opacity 0.2s linear, transform 0.2s ease-out; +} + +.smartgallery-overlay { + position: fixed; + z-index: 999998; + background: #000; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: 0; +} +.smartgallery-overlay.in { + opacity: 0.3; +} + + +.blueimp-gallery { + left: 40px; + right: 40px; + top: 40px; + bottom: 40px; + background: #fff; + border: 1px solid rgba(0,0,0, 0.25); + border-radius: 4px; + border-top-right-radius: 0; + -webkit-box-shadow: 0px 4px 20px rgba(0,0,0, 0.35); + box-shadow: 0px 4px 20px rgba(0,0,0, 0.35); + -webkit-transform: translate(0, -75px) scale(0.9, 0.9); + -moz-transform: translate(0, -75px) scale(0.9, 0.9); + -ms-transform: translate(0, -75px) scale(0.9, 0.9); + transform: translate(0, -75px) scale(0.9, 0.9); +} + +.blueimp-gallery-display { + -webkit-transform: none; + -moz-transform: none; + -ms-transform: none; + transform: none; +} + + +.blueimp-gallery > .prev, +.blueimp-gallery > .next, +.blueimp-gallery > .close { + -webkit-transition: all 0.1s ease-in-out; + transition: all 0.1s ease-in-out; +} + +.blueimp-gallery > .prev, +.blueimp-gallery > .next { + border: none; + border-radius: 0; + text-shadow: none; + font-family: initial; + background: transparent; + width: 60px; + height: 60px; + margin-top: -30px; + color: #bbb; + opacity: 1; +} +.blueimp-gallery > .prev { left: 0; } +.blueimp-gallery > .next { right: 0; } + +.blueimp-gallery > .prev:hover, +.blueimp-gallery > .next:hover { + color: #888; + background-color: #f5f5f5; +} +.blueimp-gallery > .prev:active, +.blueimp-gallery > .next:active { + background-color: #eaeaea; +} + +.blueimp-gallery > .close { + text-shadow: none; + opacity: 1 !important; + padding: 8px 12px; + padding-top: 2px; + border-bottom-left-radius: 6px; + background-color: #c5c5c5; + color: #fff; + margin: 0; + top: 0; + right: 0; +} +.blueimp-gallery > .close:hover { + background-color: #ee5f5b; +} +.blueimp-gallery > .close:active { + background-color: #ea3d38; +} + +.blueimp-gallery > .indicator { + margin: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #fff; + background-color: rgba(255,255,255, 0.5); + opacity: 0.95; + padding: 10px 0; + -webkit-transition: all 0.4s ease-in-out; + transition: all 0.4s ease-in-out; +} +.blueimp-gallery > .indicator.out { + bottom: -80px; + opacity: 0; +} + +.blueimp-gallery > .indicator > li { + position: relative; + z-index: 0; + margin: 0; + margin-left: -1px; + opacity: 1; + border: 1px solid #ccc; + box-shadow: none; + padding: 3px; + background-origin: content-box; + background-size: contain; + border-radius: 0; + width: 50px; + height: 50px; +} +.blueimp-gallery > .indicator > li:hover, +.blueimp-gallery > .indicator > li.active { + border-color: #444; +} +.blueimp-gallery > .indicator > li:hover { + z-index: 1; +} +.blueimp-gallery > .indicator > li.active { + z-index: 2; + outline: 1px solid #444; +} + +@media (max-width: 767px) { + .blueimp-gallery > .indicator > li { + width: 25px; + height: 25px; + } +} + + diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-indicator.css b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-indicator.css new file mode 100644 index 0000000000..413ff20db3 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-indicator.css @@ -0,0 +1,71 @@ +@charset "UTF-8"; +/* + * blueimp Gallery Indicator CSS 1.1.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.blueimp-gallery > .indicator { + position: absolute; + top: auto; + right: 15px; + bottom: 15px; + left: 15px; + margin: 0 40px; + padding: 0; + list-style: none; + text-align: center; + line-height: 10px; + display: none; +} +.blueimp-gallery > .indicator > li { + display: inline-block; + width: 9px; + height: 9px; + margin: 6px 3px 0 3px; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + border: 1px solid transparent; + background: #ccc; + background: rgba(255, 255, 255, 0.25) center no-repeat; + border-radius: 5px; + box-shadow: 0 0 2px #000; + opacity: 0.5; + cursor: pointer; +} +.blueimp-gallery > .indicator > li:hover, +.blueimp-gallery > .indicator > .active { + background-color: #fff; + border-color: #fff; + opacity: 1; +} +.blueimp-gallery-controls > .indicator { + display: block; + /* Fix z-index issues (controls behind slide element) on Android: */ + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -ms-transform: translateZ(0); + -o-transform: translateZ(0); + transform: translateZ(0); +} +.blueimp-gallery-single > .indicator { + display: none; +} +.blueimp-gallery > .indicator { + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* IE7 fixes */ +*+html .blueimp-gallery > .indicator > li { + display: inline; +} diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-video.css b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-video.css new file mode 100644 index 0000000000..59695647ae --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery-video.css @@ -0,0 +1,87 @@ +@charset "UTF-8"; +/* + * blueimp Gallery Video Factory CSS 1.3.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.blueimp-gallery > .slides > .slide > .video-content > img { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: auto; + width: auto; + height: auto; + max-width: 100%; + max-height: 100%; + /* Prevent artifacts in Mozilla Firefox: */ + -moz-backface-visibility: hidden; +} +.blueimp-gallery > .slides > .slide > .video-content > video { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.blueimp-gallery > .slides > .slide > .video-content > iframe { + position: absolute; + top: 100%; + left: 0; + width: 100%; + height: 100%; + border: none; +} +.blueimp-gallery > .slides > .slide > .video-playing > iframe { + top: 0; +} +.blueimp-gallery > .slides > .slide > .video-content > a { + position: absolute; + top: 50%; + right: 0; + left: 0; + margin: -64px auto 0; + width: 128px; + height: 128px; + background: url(../img/video-play.png) center no-repeat; + opacity: 0.8; + cursor: pointer; +} +.blueimp-gallery > .slides > .slide > .video-content > a:hover { + opacity: 1; +} +.blueimp-gallery > .slides > .slide > .video-playing > a, +.blueimp-gallery > .slides > .slide > .video-playing > img { + display: none; +} +.blueimp-gallery > .slides > .slide > .video-content > video { + display: none; +} +.blueimp-gallery > .slides > .slide > .video-playing > video { + display: block; +} +.blueimp-gallery > .slides > .slide > .video-loading > a { + background: url(../img/loading.gif) center no-repeat; + background-size: 64px 64px; +} + +/* Replace PNGs with SVGs for capable browsers (excluding IE<9) */ +body:last-child .blueimp-gallery > .slides > .slide > .video-content:not(.video-loading) > a { + background-image: url(../img/video-play.svg); +} + +/* IE7 fixes */ +*+html .blueimp-gallery > .slides > .slide > .video-content { + height: 100%; +} +*+html .blueimp-gallery > .slides > .slide > .video-content > a { + left: 50%; + margin-left: -64px; +} diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery.css b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery.css new file mode 100644 index 0000000000..b860d78646 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/css/blueimp-gallery.css @@ -0,0 +1,226 @@ +@charset "UTF-8"; +/* + * blueimp Gallery CSS 2.11.1 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.blueimp-gallery, +.blueimp-gallery > .slides > .slide > .slide-content { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + /* Prevent artifacts in Mozilla Firefox: */ + -moz-backface-visibility: hidden; +} +.blueimp-gallery > .slides > .slide > .slide-content { + margin: auto; + width: auto; + height: auto; + max-width: 100%; + max-height: 100%; + opacity: 1; +} +.blueimp-gallery { + position: fixed; + z-index: 999999; + overflow: hidden; + background: #000; + background: rgba(0, 0, 0, 0.9); + opacity: 0; + display: none; + direction: ltr; + -ms-touch-action: none; + touch-action: none; +} +.blueimp-gallery-carousel { + position: relative; + z-index: auto; + margin: 1em auto; + /* Set the carousel width/height ratio to 16/9: */ + padding-bottom: 56.25%; + box-shadow: 0 0 10px #000; + -ms-touch-action: pan-y; + touch-action: pan-y; +} +.blueimp-gallery-display { + display: block; + opacity: 1; +} +.blueimp-gallery > .slides { + position: relative; + height: 100%; + overflow: hidden; +} +.blueimp-gallery-carousel > .slides { + position: absolute; +} +.blueimp-gallery > .slides > .slide { + position: relative; + float: left; + height: 100%; + text-align: center; + -webkit-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000); + -moz-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000); + -ms-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000); + -o-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000); + transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000); +} +.blueimp-gallery, +.blueimp-gallery > .slides > .slide > .slide-content { + -webkit-transition: opacity 0.5s linear; + -moz-transition: opacity 0.5s linear; + -ms-transition: opacity 0.5s linear; + -o-transition: opacity 0.5s linear; + transition: opacity 0.5s linear; +} +.blueimp-gallery > .slides > .slide-loading { + background: url(../img/loading.gif) center no-repeat; + background-size: 64px 64px; +} +.blueimp-gallery > .slides > .slide-loading > .slide-content { + opacity: 0; +} +.blueimp-gallery > .slides > .slide-error { + background: url(../img/error.png) center no-repeat; +} +.blueimp-gallery > .slides > .slide-error > .slide-content { + display: none; +} +.blueimp-gallery > .prev, +.blueimp-gallery > .next { + position: absolute; + top: 50%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -23px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #fff; + text-decoration: none; + text-shadow: 0 0 2px #000; + text-align: center; + background: #222; + background: rgba(0, 0, 0, 0.5); + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + border: 3px solid #fff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + cursor: pointer; + display: none; +} +.blueimp-gallery > .next { + left: auto; + right: 15px; +} +.blueimp-gallery > .close, +.blueimp-gallery > .title { + position: absolute; + top: 15px; + left: 15px; + margin: 0 40px 0 0; + font-size: 20px; + line-height: 30px; + color: #fff; + text-shadow: 0 0 2px #000; + opacity: 0.8; + display: none; +} +.blueimp-gallery > .close { + padding: 15px; + right: 15px; + left: auto; + margin: -15px; + font-size: 30px; + text-decoration: none; + cursor: pointer; +} +.blueimp-gallery > .play-pause { + position: absolute; + right: 15px; + bottom: 15px; + width: 15px; + height: 15px; + background: url(../img/play-pause.png) 0 0 no-repeat; + cursor: pointer; + opacity: 0.5; + display: none; +} +.blueimp-gallery-playing > .play-pause { + background-position: -15px 0; +} +.blueimp-gallery > .prev:hover, +.blueimp-gallery > .next:hover, +.blueimp-gallery > .close:hover, +.blueimp-gallery > .title:hover, +.blueimp-gallery > .play-pause:hover { + color: #fff; + opacity: 1; +} +.blueimp-gallery-controls > .prev, +.blueimp-gallery-controls > .next, +.blueimp-gallery-controls > .close, +.blueimp-gallery-controls > .title, +.blueimp-gallery-controls > .play-pause { + display: block; + /* Fix z-index issues (controls behind slide element) on Android: */ + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -ms-transform: translateZ(0); + -o-transform: translateZ(0); + transform: translateZ(0); +} +.blueimp-gallery-single > .prev, +.blueimp-gallery-left > .prev, +.blueimp-gallery-single > .next, +.blueimp-gallery-right > .next, +.blueimp-gallery-single > .play-pause { + display: none; +} +.blueimp-gallery > .slides > .slide > .slide-content, +.blueimp-gallery > .prev, +.blueimp-gallery > .next, +.blueimp-gallery > .close, +.blueimp-gallery > .play-pause { + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* Replace PNGs with SVGs for capable browsers (excluding IE<9) */ +body:last-child .blueimp-gallery > .slides > .slide-error { + background-image: url(../img/error.svg); +} +body:last-child .blueimp-gallery > .play-pause { + width: 20px; + height: 20px; + background-size: 40px 20px; + background-image: url(../img/play-pause.svg); +} +body:last-child .blueimp-gallery-playing > .play-pause { + background-position: -20px 0; +} + +/* IE7 fixes */ +*+html .blueimp-gallery > .slides > .slide { + min-height: 300px; +} +*+html .blueimp-gallery > .slides > .slide > .slide-content { + position: relative; +} diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/img/error.png b/src/Presentation/SmartStore.Web/Content/image-gallery/img/error.png new file mode 100644 index 0000000000..a5577c33ab Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/image-gallery/img/error.png differ diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/img/error.svg b/src/Presentation/SmartStore.Web/Content/image-gallery/img/error.svg new file mode 100644 index 0000000000..184206a144 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/img/error.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/img/loading.gif b/src/Presentation/SmartStore.Web/Content/image-gallery/img/loading.gif new file mode 100644 index 0000000000..90f28cbdbb Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/image-gallery/img/loading.gif differ diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/img/play-pause.png b/src/Presentation/SmartStore.Web/Content/image-gallery/img/play-pause.png new file mode 100644 index 0000000000..ece6cfb9b7 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/image-gallery/img/play-pause.png differ diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/img/play-pause.svg b/src/Presentation/SmartStore.Web/Content/image-gallery/img/play-pause.svg new file mode 100644 index 0000000000..a7f1f50cd3 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/img/play-pause.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/img/video-play.png b/src/Presentation/SmartStore.Web/Content/image-gallery/img/video-play.png new file mode 100644 index 0000000000..353e3a592d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/image-gallery/img/video-play.png differ diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/img/video-play.svg b/src/Presentation/SmartStore.Web/Content/image-gallery/img/video-play.svg new file mode 100644 index 0000000000..b5ea206dde --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/img/video-play.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-fullscreen.js b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-fullscreen.js new file mode 100644 index 0000000000..eb0de11363 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-fullscreen.js @@ -0,0 +1,90 @@ +/* + * blueimp Gallery Fullscreen JS 1.2.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + './blueimp-helper', + './blueimp-gallery' + ], factory); + } else { + // Browser globals: + factory( + window.blueimp.helper || window.jQuery, + window.blueimp.Gallery + ); + } +}(function ($, Gallery) { + 'use strict'; + + $.extend(Gallery.prototype.options, { + // Defines if the gallery should open in fullscreen mode: + fullScreen: false + }); + + var initialize = Gallery.prototype.initialize, + close = Gallery.prototype.close; + + $.extend(Gallery.prototype, { + + getFullScreenElement: function () { + return document.fullscreenElement || + document.webkitFullscreenElement || + document.mozFullScreenElement || + document.msFullscreenElement; + }, + + requestFullScreen: function (element) { + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } + }, + + exitFullScreen: function () { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitCancelFullScreen) { + document.webkitCancelFullScreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } + }, + + initialize: function () { + initialize.call(this); + if (this.options.fullScreen && !this.getFullScreenElement()) { + this.requestFullScreen(this.container[0]); + } + }, + + close: function () { + if (this.getFullScreenElement() === this.container[0]) { + this.exitFullScreen(); + } + close.call(this); + } + + }); + + return Gallery; +})); diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-indicator.js b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-indicator.js new file mode 100644 index 0000000000..cd0cf7d5ea --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-indicator.js @@ -0,0 +1,153 @@ +/* + * blueimp Gallery Indicator JS 1.1.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + './blueimp-helper', + './blueimp-gallery' + ], factory); + } else { + // Browser globals: + factory( + window.blueimp.helper || window.jQuery, + window.blueimp.Gallery + ); + } +}(function ($, Gallery) { + 'use strict'; + + $.extend(Gallery.prototype.options, { + // The tag name, Id, element or querySelector of the indicator container: + indicatorContainer: 'ol', + // The class for the active indicator: + activeIndicatorClass: 'active', + // The list object property (or data attribute) with the thumbnail URL, + // used as alternative to a thumbnail child element: + thumbnailProperty: 'thumbnail', + // Defines if the gallery indicators should display a thumbnail: + thumbnailIndicators: true + }); + + var initSlides = Gallery.prototype.initSlides, + addSlide = Gallery.prototype.addSlide, + resetSlides = Gallery.prototype.resetSlides, + handleClick = Gallery.prototype.handleClick, + handleSlide = Gallery.prototype.handleSlide, + handleClose = Gallery.prototype.handleClose; + + $.extend(Gallery.prototype, { + + createIndicator: function (obj) { + var indicator = this.indicatorPrototype.cloneNode(false), + title = this.getItemProperty(obj, this.options.titleProperty), + thumbnailProperty = this.options.thumbnailProperty, + thumbnailUrl, + thumbnail; + if (this.options.thumbnailIndicators) { + thumbnail = obj.getElementsByTagName && $(obj).find('img')[0]; + if (thumbnail) { + thumbnailUrl = thumbnail.src; + } else if (thumbnailProperty) { + thumbnailUrl = this.getItemProperty(obj, thumbnailProperty); + } + if (thumbnailUrl) { + indicator.style.backgroundImage = 'url("' + thumbnailUrl + '")'; + } + } + if (title) { + indicator.title = title; + } + return indicator; + }, + + addIndicator: function (index) { + if (this.indicatorContainer.length) { + var indicator = this.createIndicator(this.list[index]); + indicator.setAttribute('data-index', index); + this.indicatorContainer[0].appendChild(indicator); + this.indicators.push(indicator); + } + }, + + setActiveIndicator: function (index) { + if (this.indicators) { + if (this.activeIndicator) { + this.activeIndicator + .removeClass(this.options.activeIndicatorClass); + } + this.activeIndicator = $(this.indicators[index]); + this.activeIndicator + .addClass(this.options.activeIndicatorClass); + } + }, + + initSlides: function (reload) { + if (!reload) { + this.indicatorContainer = this.container.find( + this.options.indicatorContainer + ); + if (this.indicatorContainer.length) { + this.indicatorPrototype = document.createElement('li'); + this.indicators = this.indicatorContainer[0].children; + } + } + initSlides.call(this, reload); + }, + + addSlide: function (index) { + addSlide.call(this, index); + this.addIndicator(index); + }, + + resetSlides: function () { + resetSlides.call(this); + this.indicatorContainer.empty(); + this.indicators = []; + }, + + handleClick: function (event) { + var target = event.target || event.srcElement, + parent = target.parentNode; + if (parent === this.indicatorContainer[0]) { + // Click on indicator element + this.preventDefault(event); + this.slide(this.getNodeIndex(target)); + } else if (parent.parentNode === this.indicatorContainer[0]) { + // Click on indicator child element + this.preventDefault(event); + this.slide(this.getNodeIndex(parent)); + } else { + return handleClick.call(this, event); + } + }, + + handleSlide: function (index) { + handleSlide.call(this, index); + this.setActiveIndicator(index); + }, + + handleClose: function () { + if (this.activeIndicator) { + this.activeIndicator + .removeClass(this.options.activeIndicatorClass); + } + handleClose.call(this); + } + + }); + + return Gallery; +})); diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-video.js b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-video.js new file mode 100644 index 0000000000..ee0343554c --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-video.js @@ -0,0 +1,171 @@ +/* + * blueimp Gallery Video Factory JS 1.1.1 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + './blueimp-helper', + './blueimp-gallery' + ], factory); + } else { + // Browser globals: + factory( + window.blueimp.helper || window.jQuery, + window.blueimp.Gallery + ); + } +}(function ($, Gallery) { + 'use strict'; + + $.extend(Gallery.prototype.options, { + // The class for video content elements: + videoContentClass: 'video-content', + // The class for video when it is loading: + videoLoadingClass: 'video-loading', + // The class for video when it is playing: + videoPlayingClass: 'video-playing', + // The list object property (or data attribute) for the video poster URL: + videoPosterProperty: 'poster', + // The list object property (or data attribute) for the video sources array: + videoSourcesProperty: 'sources' + }); + + var handleSlide = Gallery.prototype.handleSlide; + + $.extend(Gallery.prototype, { + + handleSlide: function (index) { + handleSlide.call(this, index); + if (this.playingVideo) { + this.playingVideo.pause(); + } + }, + + videoFactory: function (obj, callback, videoInterface) { + var that = this, + options = this.options, + videoContainerNode = this.elementPrototype.cloneNode(false), + videoContainer = $(videoContainerNode), + errorArgs = [{ + type: 'error', + target: videoContainerNode + }], + video = videoInterface || document.createElement('video'), + url = this.getItemProperty(obj, options.urlProperty), + type = this.getItemProperty(obj, options.typeProperty), + title = this.getItemProperty(obj, options.titleProperty), + posterUrl = this.getItemProperty(obj, options.videoPosterProperty), + posterImage, + sources = this.getItemProperty( + obj, + options.videoSourcesProperty + ), + source, + playMediaControl, + isLoading, + hasControls; + videoContainer.addClass(options.videoContentClass); + if (title) { + videoContainerNode.title = title; + } + if (video.canPlayType) { + if (url && type && video.canPlayType(type)) { + video.src = url; + } else { + while (sources && sources.length) { + source = sources.shift(); + url = this.getItemProperty(source, options.urlProperty); + type = this.getItemProperty(source, options.typeProperty); + if (url && type && video.canPlayType(type)) { + video.src = url; + break; + } + } + } + } + if (posterUrl) { + video.poster = posterUrl; + posterImage = this.imagePrototype.cloneNode(false); + $(posterImage).addClass(options.toggleClass); + posterImage.src = posterUrl; + posterImage.draggable = false; + videoContainerNode.appendChild(posterImage); + } + playMediaControl = document.createElement('a'); + playMediaControl.setAttribute('target', '_blank'); + if (!videoInterface) { + playMediaControl.setAttribute('download', title); + } + playMediaControl.href = url; + if (video.src) { + video.controls = true; + (videoInterface || $(video)) + .on('error', function () { + that.setTimeout(callback, errorArgs); + }) + .on('pause', function () { + isLoading = false; + videoContainer + .removeClass(that.options.videoLoadingClass) + .removeClass(that.options.videoPlayingClass); + if (hasControls) { + that.container.addClass(that.options.controlsClass); + } + delete that.playingVideo; + if (that.interval) { + that.play(); + } + }) + .on('playing', function () { + isLoading = false; + videoContainer + .removeClass(that.options.videoLoadingClass) + .addClass(that.options.videoPlayingClass); + if (that.container.hasClass(that.options.controlsClass)) { + hasControls = true; + that.container.removeClass(that.options.controlsClass); + } else { + hasControls = false; + } + }) + .on('play', function () { + window.clearTimeout(that.timeout); + isLoading = true; + videoContainer.addClass(that.options.videoLoadingClass); + that.playingVideo = video; + }); + $(playMediaControl).on('click', function (event) { + that.preventDefault(event); + if (isLoading) { + video.pause(); + } else { + video.play(); + } + }); + videoContainerNode.appendChild( + (videoInterface && videoInterface.element) || video + ); + } + videoContainerNode.appendChild(playMediaControl); + this.setTimeout(callback, [{ + type: 'load', + target: videoContainerNode + }]); + return videoContainerNode; + } + }); + + return Gallery; +})); diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-vimeo.js b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-vimeo.js new file mode 100644 index 0000000000..6ffff646b9 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-vimeo.js @@ -0,0 +1,215 @@ +/* + * blueimp Gallery Vimeo Video Factory JS 1.2.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document, location, $f */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + './blueimp-helper', + './blueimp-gallery-video' + ], factory); + } else { + // Browser globals: + factory( + window.blueimp.helper || window.jQuery, + window.blueimp.Gallery + ); + } +}(function ($, Gallery) { + 'use strict'; + + if (!window.postMessage) { + return Gallery; + } + + $.extend(Gallery.prototype.options, { + // The list object property (or data attribute) with the Vimeo video id: + vimeoVideoIdProperty: 'vimeo', + // The URL for the Vimeo video player, can be extended with custom parameters: + // https://developer.vimeo.com/player/embedding + vimeoPlayerUrl: '//player.vimeo.com/video/VIDEO_ID?api=1&player_id=PLAYER_ID', + // The prefix for the Vimeo video player ID: + vimeoPlayerIdPrefix: 'vimeo-player-', + // Require a click on the native Vimeo player for the initial playback: + vimeoClickToPlay: true + }); + + var textFactory = Gallery.prototype.textFactory || Gallery.prototype.imageFactory, + VimeoPlayer = function (url, videoId, playerId, clickToPlay) { + this.url = url; + this.videoId = videoId; + this.playerId = playerId; + this.clickToPlay = clickToPlay; + this.element = document.createElement('div'); + this.listeners = {}; + }, + counter = 0; + + $.extend(VimeoPlayer.prototype, { + + canPlayType: function () { + return true; + }, + + on: function (type, func) { + this.listeners[type] = func; + return this; + }, + + loadAPI: function () { + var that = this, + apiUrl = '//' + (location.protocol === 'https' ? 'secure-' : '') + + 'a.vimeocdn.com/js/froogaloop2.min.js', + scriptTags = document.getElementsByTagName('script'), + i = scriptTags.length, + scriptTag, + called, + callback = function () { + if (!called && that.playOnReady) { + that.play(); + } + called = true; + }; + while (i) { + i -= 1; + if (scriptTags[i].src === apiUrl) { + scriptTag = scriptTags[i]; + break; + } + } + if (!scriptTag) { + scriptTag = document.createElement('script'); + scriptTag.src = apiUrl; + } + $(scriptTag).on('load', callback); + scriptTags[0].parentNode.insertBefore(scriptTag, scriptTags[0]); + // Fix for cached scripts on IE 8: + if (/loaded|complete/.test(scriptTag.readyState)) { + callback(); + } + }, + + onReady: function () { + var that = this; + this.ready = true; + this.player.addEvent('play', function () { + that.hasPlayed = true; + that.onPlaying(); + }); + this.player.addEvent('pause', function () { + that.onPause(); + }); + this.player.addEvent('finish', function () { + that.onPause(); + }); + if (this.playOnReady) { + this.play(); + } + }, + + onPlaying: function () { + if (this.playStatus < 2) { + this.listeners.playing(); + this.playStatus = 2; + } + }, + + onPause: function () { + this.listeners.pause(); + delete this.playStatus; + }, + + insertIframe: function () { + var iframe = document.createElement('iframe'); + iframe.src = this.url + .replace('VIDEO_ID', this.videoId) + .replace('PLAYER_ID', this.playerId); + iframe.id = this.playerId; + this.element.parentNode.replaceChild(iframe, this.element); + this.element = iframe; + }, + + play: function () { + var that = this; + if (!this.playStatus) { + this.listeners.play(); + this.playStatus = 1; + } + if (this.ready) { + if (!this.hasPlayed && (this.clickToPlay || (window.navigator && + /iP(hone|od|ad)/.test(window.navigator.platform)))) { + // Manually trigger the playing callback if clickToPlay + // is enabled and to workaround a limitation in iOS, + // which requires synchronous user interaction to start + // the video playback: + this.onPlaying(); + } else { + this.player.api('play'); + } + } else { + this.playOnReady = true; + if (!window.$f) { + this.loadAPI(); + } else if (!this.player) { + this.insertIframe(); + this.player = $f(this.element); + this.player.addEvent('ready', function () { + that.onReady(); + }); + } + } + }, + + pause: function () { + if (this.ready) { + this.player.api('pause'); + } else if (this.playStatus) { + delete this.playOnReady; + this.listeners.pause(); + delete this.playStatus; + } + } + + }); + + $.extend(Gallery.prototype, { + + VimeoPlayer: VimeoPlayer, + + textFactory: function (obj, callback) { + var options = this.options, + videoId = this.getItemProperty(obj, options.vimeoVideoIdProperty); + if (videoId) { + if (this.getItemProperty(obj, options.urlProperty) === undefined) { + obj[options.urlProperty] = '//vimeo.com/' + videoId; + } + counter += 1; + return this.videoFactory( + obj, + callback, + new VimeoPlayer( + options.vimeoPlayerUrl, + videoId, + options.vimeoPlayerIdPrefix + counter, + options.vimeoClickToPlay + ) + ); + } + return textFactory.call(this, obj, callback); + } + + }); + + return Gallery; +})); diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-youtube.js b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-youtube.js new file mode 100644 index 0000000000..da8831daa6 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery-youtube.js @@ -0,0 +1,229 @@ +/* + * blueimp Gallery YouTube Video Factory JS 1.2.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document, YT */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + './blueimp-helper', + './blueimp-gallery-video' + ], factory); + } else { + // Browser globals: + factory( + window.blueimp.helper || window.jQuery, + window.blueimp.Gallery + ); + } +}(function ($, Gallery) { + 'use strict'; + + if (!window.postMessage) { + return Gallery; + } + + $.extend(Gallery.prototype.options, { + // The list object property (or data attribute) with the YouTube video id: + youTubeVideoIdProperty: 'youtube', + // Optional object with parameters passed to the YouTube video player: + // https://developers.google.com/youtube/player_parameters + youTubePlayerVars: { + wmode: 'transparent' + }, + // Require a click on the native YouTube player for the initial playback: + youTubeClickToPlay: true + }); + + var textFactory = Gallery.prototype.textFactory || Gallery.prototype.imageFactory, + YouTubePlayer = function (videoId, playerVars, clickToPlay) { + this.videoId = videoId; + this.playerVars = playerVars; + this.clickToPlay = clickToPlay; + this.element = document.createElement('div'); + this.listeners = {}; + }; + + $.extend(YouTubePlayer.prototype, { + + canPlayType: function () { + return true; + }, + + on: function (type, func) { + this.listeners[type] = func; + return this; + }, + + loadAPI: function () { + var that = this, + onYouTubeIframeAPIReady = window.onYouTubeIframeAPIReady, + apiUrl = '//www.youtube.com/iframe_api', + scriptTags = document.getElementsByTagName('script'), + i = scriptTags.length, + scriptTag; + window.onYouTubeIframeAPIReady = function () { + if (onYouTubeIframeAPIReady) { + onYouTubeIframeAPIReady.apply(this); + } + if (that.playOnReady) { + that.play(); + } + }; + while (i) { + i -= 1; + if (scriptTags[i].src === apiUrl) { + return; + } + } + scriptTag = document.createElement('script'); + scriptTag.src = apiUrl; + scriptTags[0].parentNode.insertBefore(scriptTag, scriptTags[0]); + }, + + onReady: function () { + this.ready = true; + if (this.playOnReady) { + this.play(); + } + }, + + onPlaying: function () { + if (this.playStatus < 2) { + this.listeners.playing(); + this.playStatus = 2; + } + }, + + onPause: function () { + Gallery.prototype.setTimeout.call( + this, + this.checkSeek, + null, + 2000 + ); + }, + + checkSeek: function () { + if (this.stateChange === YT.PlayerState.PAUSED || + this.stateChange === YT.PlayerState.ENDED) { + // check if current state change is actually paused + this.listeners.pause(); + delete this.playStatus; + } + }, + + onStateChange: function (event) { + switch (event.data) { + case YT.PlayerState.PLAYING: + this.hasPlayed = true; + this.onPlaying(); + break; + case YT.PlayerState.PAUSED: + case YT.PlayerState.ENDED: + this.onPause(); + break; + } + // Save most recent state change to this.stateChange + this.stateChange = event.data; + }, + + onError: function (event) { + this.listeners.error(event); + }, + + play: function () { + var that = this; + if (!this.playStatus) { + this.listeners.play(); + this.playStatus = 1; + } + if (this.ready) { + if (!this.hasPlayed && (this.clickToPlay || (window.navigator && + /iP(hone|od|ad)/.test(window.navigator.platform)))) { + // Manually trigger the playing callback if clickToPlay + // is enabled and to workaround a limitation in iOS, + // which requires synchronous user interaction to start + // the video playback: + this.onPlaying(); + } else { + this.player.playVideo(); + } + } else { + this.playOnReady = true; + if (!(window.YT && YT.Player)) { + this.loadAPI(); + } else if (!this.player) { + this.player = new YT.Player(this.element, { + videoId: this.videoId, + playerVars: this.playerVars, + events: { + onReady: function () { + that.onReady(); + }, + onStateChange: function (event) { + that.onStateChange(event); + }, + onError: function (event) { + that.onError(event); + } + } + }); + } + } + }, + + pause: function () { + if (this.ready) { + this.player.pauseVideo(); + } else if (this.playStatus) { + delete this.playOnReady; + this.listeners.pause(); + delete this.playStatus; + } + } + + }); + + $.extend(Gallery.prototype, { + + YouTubePlayer: YouTubePlayer, + + textFactory: function (obj, callback) { + var options = this.options, + videoId = this.getItemProperty(obj, options.youTubeVideoIdProperty); + if (videoId) { + if (this.getItemProperty(obj, options.urlProperty) === undefined) { + obj[options.urlProperty] = '//www.youtube.com/watch?v=' + videoId; + } + if (this.getItemProperty(obj, options.videoPosterProperty) === undefined) { + obj[options.videoPosterProperty] = '//img.youtube.com/vi/' + videoId + + '/maxresdefault.jpg'; + } + return this.videoFactory( + obj, + callback, + new YouTubePlayer( + videoId, + options.youTubePlayerVars, + options.youTubeClickToPlay + ) + ); + } + return textFactory.call(this, obj, callback); + } + + }); + + return Gallery; +})); diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery.js b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery.js new file mode 100644 index 0000000000..c4c9337a6b --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-gallery.js @@ -0,0 +1,1341 @@ +/* + * blueimp Gallery JS 2.14.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Swipe implementation based on + * https://github.com/bradbirdsall/Swipe + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document, DocumentTouch */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['./blueimp-helper'], factory); + } else { + // Browser globals: + window.blueimp = window.blueimp || {}; + window.blueimp.Gallery = factory( + window.blueimp.helper || window.jQuery + ); + } +}(function ($) { + 'use strict'; + + function Gallery(list, options) { + if (document.body.style.maxHeight === undefined) { + // document.body.style.maxHeight is undefined on IE6 and lower + return null; + } + if (!this || this.options !== Gallery.prototype.options) { + // Called as function instead of as constructor, + // so we simply return a new instance: + return new Gallery(list, options); + } + if (!list || !list.length) { + this.console.log( + 'blueimp Gallery: No or empty list provided as first argument.', + list + ); + return; + } + this.list = list; + this.num = list.length; + this.initOptions(options); + this.initialize(); + } + + $.extend(Gallery.prototype, { + + options: { + // The Id, element or querySelector of the gallery widget: + container: '#blueimp-gallery', + // The tag name, Id, element or querySelector of the slides container: + slidesContainer: 'div', + // The tag name, Id, element or querySelector of the title element: + titleElement: 'h3', + // The class to add when the gallery is visible: + displayClass: 'blueimp-gallery-display', + // The class to add when the gallery controls are visible: + controlsClass: 'blueimp-gallery-controls', + // The class to add when the gallery only displays one element: + singleClass: 'blueimp-gallery-single', + // The class to add when the left edge has been reached: + leftEdgeClass: 'blueimp-gallery-left', + // The class to add when the right edge has been reached: + rightEdgeClass: 'blueimp-gallery-right', + // The class to add when the automatic slideshow is active: + playingClass: 'blueimp-gallery-playing', + // The class for all slides: + slideClass: 'slide', + // The slide class for loading elements: + slideLoadingClass: 'slide-loading', + // The slide class for elements that failed to load: + slideErrorClass: 'slide-error', + // The class for the content element loaded into each slide: + slideContentClass: 'slide-content', + // The class for the "toggle" control: + toggleClass: 'toggle', + // The class for the "prev" control: + prevClass: 'prev', + // The class for the "next" control: + nextClass: 'next', + // The class for the "close" control: + closeClass: 'close', + // The class for the "play-pause" toggle control: + playPauseClass: 'play-pause', + // The list object property (or data attribute) with the object type: + typeProperty: 'type', + // The list object property (or data attribute) with the object title: + titleProperty: 'title', + // The list object property (or data attribute) with the object URL: + urlProperty: 'href', + // The gallery listens for transitionend events before triggering the + // opened and closed events, unless the following option is set to false: + displayTransition: true, + // Defines if the gallery slides are cleared from the gallery modal, + // or reused for the next gallery initialization: + clearSlides: true, + // Defines if images should be stretched to fill the available space, + // while maintaining their aspect ratio (will only be enabled for browsers + // supporting background-size="contain", which excludes IE < 9). + // Set to "cover", to make images cover all available space (requires + // support for background-size="cover", which excludes IE < 9): + stretchImages: false, + // Toggle the controls on pressing the Return key: + toggleControlsOnReturn: true, + // Toggle the automatic slideshow interval on pressing the Space key: + toggleSlideshowOnSpace: true, + // Navigate the gallery by pressing left and right on the keyboard: + enableKeyboardNavigation: true, + // Close the gallery on pressing the Esc key: + closeOnEscape: true, + // Close the gallery when clicking on an empty slide area: + closeOnSlideClick: true, + // Close the gallery by swiping up or down: + closeOnSwipeUpOrDown: true, + // Emulate touch events on mouse-pointer devices such as desktop browsers: + emulateTouchEvents: true, + // Stop touch events from bubbling up to ancestor elements of the Gallery: + stopTouchEventsPropagation: false, + // Hide the page scrollbars: + hidePageScrollbars: true, + // Stops any touches on the container from scrolling the page: + disableScroll: true, + // Carousel mode (shortcut for carousel specific options): + carousel: false, + // Allow continuous navigation, moving from last to first + // and from first to last slide: + continuous: true, + // Remove elements outside of the preload range from the DOM: + unloadElements: true, + // Start with the automatic slideshow: + startSlideshow: false, + // Delay in milliseconds between slides for the automatic slideshow: + slideshowInterval: 5000, + // The starting index as integer. + // Can also be an object of the given list, + // or an equal object with the same url property: + index: 0, + // The number of elements to load around the current index: + preloadRange: 2, + // The transition speed between slide changes in milliseconds: + transitionSpeed: 400, + // The transition speed for automatic slide changes, set to an integer + // greater 0 to override the default transition speed: + slideshowTransitionSpeed: undefined, + // The event object for which the default action will be canceled + // on Gallery initialization (e.g. the click event to open the Gallery): + event: undefined, + // Callback function executed when the Gallery is initialized. + // Is called with the gallery instance as "this" object: + onopen: undefined, + // Callback function executed when the Gallery has been initialized + // and the initialization transition has been completed. + // Is called with the gallery instance as "this" object: + onopened: undefined, + // Callback function executed on slide change. + // Is called with the gallery instance as "this" object and the + // current index and slide as arguments: + onslide: undefined, + // Callback function executed after the slide change transition. + // Is called with the gallery instance as "this" object and the + // current index and slide as arguments: + onslideend: undefined, + // Callback function executed on slide content load. + // Is called with the gallery instance as "this" object and the + // slide index and slide element as arguments: + onslidecomplete: undefined, + // Callback function executed when the Gallery is about to be closed. + // Is called with the gallery instance as "this" object: + onclose: undefined, + // Callback function executed when the Gallery has been closed + // and the closing transition has been completed. + // Is called with the gallery instance as "this" object: + onclosed: undefined + }, + + carouselOptions: { + hidePageScrollbars: false, + toggleControlsOnReturn: false, + toggleSlideshowOnSpace: false, + enableKeyboardNavigation: false, + closeOnEscape: false, + closeOnSlideClick: false, + closeOnSwipeUpOrDown: false, + disableScroll: false, + startSlideshow: true + }, + + console: window.console && typeof window.console.log === 'function' ? + window.console : + {log: function () {}}, + + // Detect touch, transition, transform and background-size support: + support: (function (element) { + var support = { + touch: window.ontouchstart !== undefined || + (window.DocumentTouch && document instanceof DocumentTouch) + }, + transitions = { + webkitTransition: { + end: 'webkitTransitionEnd', + prefix: '-webkit-' + }, + MozTransition: { + end: 'transitionend', + prefix: '-moz-' + }, + OTransition: { + end: 'otransitionend', + prefix: '-o-' + }, + transition: { + end: 'transitionend', + prefix: '' + } + }, + elementTests = function () { + var transition = support.transition, + prop, + translateZ; + document.body.appendChild(element); + if (transition) { + prop = transition.name.slice(0, -9) + 'ransform'; + if (element.style[prop] !== undefined) { + element.style[prop] = 'translateZ(0)'; + translateZ = window.getComputedStyle(element) + .getPropertyValue(transition.prefix + 'transform'); + support.transform = { + prefix: transition.prefix, + name: prop, + translate: true, + translateZ: !!translateZ && translateZ !== 'none' + }; + } + } + if (element.style.backgroundSize !== undefined) { + support.backgroundSize = {}; + element.style.backgroundSize = 'contain'; + support.backgroundSize.contain = window + .getComputedStyle(element) + .getPropertyValue('background-size') === 'contain'; + element.style.backgroundSize = 'cover'; + support.backgroundSize.cover = window + .getComputedStyle(element) + .getPropertyValue('background-size') === 'cover'; + } + document.body.removeChild(element); + }; + (function (support, transitions) { + var prop; + for (prop in transitions) { + if (transitions.hasOwnProperty(prop) && + element.style[prop] !== undefined) { + support.transition = transitions[prop]; + support.transition.name = prop; + break; + } + } + }(support, transitions)); + if (document.body) { + elementTests(); + } else { + $(document).on('DOMContentLoaded', elementTests); + } + return support; + // Test element, has to be standard HTML and must not be hidden + // for the CSS3 tests using window.getComputedStyle to be applicable: + }(document.createElement('div'))), + + requestAnimationFrame: window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame, + + initialize: function () { + this.initStartIndex(); + if (this.initWidget() === false) { + return false; + } + this.initEventListeners(); + // Load the slide at the given index: + this.onslide(this.index); + // Manually trigger the slideend event for the initial slide: + this.ontransitionend(); + // Start the automatic slideshow if applicable: + if (this.options.startSlideshow) { + this.play(); + } + }, + + slide: function (to, speed) { + window.clearTimeout(this.timeout); + var index = this.index, + direction, + naturalDirection, + diff; + if (index === to || this.num === 1) { + return; + } + if (!speed) { + speed = this.options.transitionSpeed; + } + if (this.support.transition) { + if (!this.options.continuous) { + to = this.circle(to); + } + // 1: backward, -1: forward: + direction = Math.abs(index - to) / (index - to); + // Get the actual position of the slide: + if (this.options.continuous) { + naturalDirection = direction; + direction = -this.positions[this.circle(to)] / this.slideWidth; + // If going forward but to < index, use to = slides.length + to + // If going backward but to > index, use to = -slides.length + to + if (direction !== naturalDirection) { + to = -direction * this.num + to; + } + } + diff = Math.abs(index - to) - 1; + // Move all the slides between index and to in the right direction: + while (diff) { + diff -= 1; + this.move( + this.circle((to > index ? to : index) - diff - 1), + this.slideWidth * direction, + 0 + ); + } + to = this.circle(to); + this.move(index, this.slideWidth * direction, speed); + this.move(to, 0, speed); + if (this.options.continuous) { + this.move( + this.circle(to - direction), + -(this.slideWidth * direction), + 0 + ); + } + } else { + to = this.circle(to); + this.animate(index * -this.slideWidth, to * -this.slideWidth, speed); + } + this.onslide(to); + }, + + getIndex: function () { + return this.index; + }, + + getNumber: function () { + return this.num; + }, + + prev: function () { + if (this.options.continuous || this.index) { + this.slide(this.index - 1); + } + }, + + next: function () { + if (this.options.continuous || this.index < this.num - 1) { + this.slide(this.index + 1); + } + }, + + play: function (time) { + var that = this; + window.clearTimeout(this.timeout); + this.interval = time || this.options.slideshowInterval; + if (this.elements[this.index] > 1) { + this.timeout = this.setTimeout( + (!this.requestAnimationFrame && this.slide) || function (to, speed) { + that.animationFrameId = that.requestAnimationFrame.call( + window, + function () { + that.slide(to, speed); + } + ); + }, + [this.index + 1, this.options.slideshowTransitionSpeed], + this.interval + ); + } + this.container.addClass(this.options.playingClass); + }, + + pause: function () { + window.clearTimeout(this.timeout); + this.interval = null; + this.container.removeClass(this.options.playingClass); + }, + + add: function (list) { + var i; + if (!list.concat) { + // Make a real array out of the list to add: + list = Array.prototype.slice.call(list); + } + if (!this.list.concat) { + // Make a real array out of the Gallery list: + this.list = Array.prototype.slice.call(this.list); + } + this.list = this.list.concat(list); + this.num = this.list.length; + if (this.num > 2 && this.options.continuous === null) { + this.options.continuous = true; + this.container.removeClass(this.options.leftEdgeClass); + } + this.container + .removeClass(this.options.rightEdgeClass) + .removeClass(this.options.singleClass); + for (i = this.num - list.length; i < this.num; i += 1) { + this.addSlide(i); + this.positionSlide(i); + } + this.positions.length = this.num; + this.initSlides(true); + }, + + resetSlides: function () { + this.slidesContainer.empty(); + this.slides = []; + }, + + handleClose: function () { + var options = this.options; + this.destroyEventListeners(); + // Cancel the slideshow: + this.pause(); + this.container[0].style.display = 'none'; + this.container + .removeClass(options.displayClass) + .removeClass(options.singleClass) + .removeClass(options.leftEdgeClass) + .removeClass(options.rightEdgeClass); + if (options.hidePageScrollbars) { + document.body.style.overflow = this.bodyOverflowStyle; + } + if (this.options.clearSlides) { + this.resetSlides(); + } + if (this.options.onclosed) { + this.options.onclosed.call(this); + } + }, + + close: function () { + var that = this, + closeHandler = function (event) { + if (event.target === that.container[0]) { + that.container.off( + that.support.transition.end, + closeHandler + ); + that.handleClose(); + } + }; + if (this.options.onclose) { + this.options.onclose.call(this); + } + if (this.support.transition && this.options.displayTransition) { + this.container.on( + this.support.transition.end, + closeHandler + ); + this.container.removeClass(this.options.displayClass); + } else { + this.handleClose(); + } + }, + + circle: function (index) { + // Always return a number inside of the slides index range: + return (this.num + (index % this.num)) % this.num; + }, + + move: function (index, dist, speed) { + this.translateX(index, dist, speed); + this.positions[index] = dist; + }, + + translate: function (index, x, y, speed) { + var style = this.slides[index].style, + transition = this.support.transition, + transform = this.support.transform; + style[transition.name + 'Duration'] = speed + 'ms'; + style[transform.name] = 'translate(' + x + 'px, ' + y + 'px)' + + (transform.translateZ ? ' translateZ(0)' : ''); + }, + + translateX: function (index, x, speed) { + this.translate(index, x, 0, speed); + }, + + translateY: function (index, y, speed) { + this.translate(index, 0, y, speed); + }, + + animate: function (from, to, speed) { + if (!speed) { + this.slidesContainer[0].style.left = to + 'px'; + return; + } + var that = this, + start = new Date().getTime(), + timer = window.setInterval(function () { + var timeElap = new Date().getTime() - start; + if (timeElap > speed) { + that.slidesContainer[0].style.left = to + 'px'; + that.ontransitionend(); + window.clearInterval(timer); + return; + } + that.slidesContainer[0].style.left = (((to - from) * + (Math.floor((timeElap / speed) * 100) / 100)) + + from) + 'px'; + }, 4); + }, + + preventDefault: function (event) { + if (event.preventDefault) { + event.preventDefault(); + } else { + event.returnValue = false; + } + }, + + stopPropagation: function (event) { + if (event.stopPropagation) { + event.stopPropagation(); + } else { + event.cancelBubble = true; + } + }, + + onresize: function () { + this.initSlides(true); + }, + + onmousedown: function (event) { + // Trigger on clicks of the left mouse button only + // and exclude video elements: + if (event.which && event.which === 1 && + event.target.nodeName !== 'VIDEO') { + // Preventing the default mousedown action is required + // to make touch emulation work with Firefox: + event.preventDefault(); + (event.originalEvent || event).touches = [{ + pageX: event.pageX, + pageY: event.pageY + }]; + this.ontouchstart(event); + } + }, + + onmousemove: function (event) { + if (this.touchStart) { + (event.originalEvent || event).touches = [{ + pageX: event.pageX, + pageY: event.pageY + }]; + this.ontouchmove(event); + } + }, + + onmouseup: function (event) { + if (this.touchStart) { + this.ontouchend(event); + delete this.touchStart; + } + }, + + onmouseout: function (event) { + if (this.touchStart) { + var target = event.target, + related = event.relatedTarget; + if (!related || (related !== target && + !$.contains(target, related))) { + this.onmouseup(event); + } + } + }, + + ontouchstart: function (event) { + if (this.options.stopTouchEventsPropagation) { + this.stopPropagation(event); + } + // jQuery doesn't copy touch event properties by default, + // so we have to access the originalEvent object: + var touches = (event.originalEvent || event).touches[0]; + this.touchStart = { + // Remember the initial touch coordinates: + x: touches.pageX, + y: touches.pageY, + // Store the time to determine touch duration: + time: Date.now() + }; + // Helper variable to detect scroll movement: + this.isScrolling = undefined; + // Reset delta values: + this.touchDelta = {}; + }, + + ontouchmove: function (event) { + if (this.options.stopTouchEventsPropagation) { + this.stopPropagation(event); + } + // jQuery doesn't copy touch event properties by default, + // so we have to access the originalEvent object: + var touches = (event.originalEvent || event).touches[0], + scale = (event.originalEvent || event).scale, + index = this.index, + touchDeltaX, + indices; + // Ensure this is a one touch swipe and not, e.g. a pinch: + if (touches.length > 1 || (scale && scale !== 1)) { + return; + } + if (this.options.disableScroll) { + event.preventDefault(); + } + // Measure change in x and y coordinates: + this.touchDelta = { + x: touches.pageX - this.touchStart.x, + y: touches.pageY - this.touchStart.y + }; + touchDeltaX = this.touchDelta.x; + // Detect if this is a vertical scroll movement (run only once per touch): + if (this.isScrolling === undefined) { + this.isScrolling = this.isScrolling || + Math.abs(touchDeltaX) < Math.abs(this.touchDelta.y); + } + if (!this.isScrolling) { + // Always prevent horizontal scroll: + event.preventDefault(); + // Stop the slideshow: + window.clearTimeout(this.timeout); + if (this.options.continuous) { + indices = [ + this.circle(index + 1), + index, + this.circle(index - 1) + ]; + } else { + // Increase resistance if first slide and sliding left + // or last slide and sliding right: + this.touchDelta.x = touchDeltaX = + touchDeltaX / + (((!index && touchDeltaX > 0) || + (index === this.num - 1 && touchDeltaX < 0)) ? + (Math.abs(touchDeltaX) / this.slideWidth + 1) : 1); + indices = [index]; + if (index) { + indices.push(index - 1); + } + if (index < this.num - 1) { + indices.unshift(index + 1); + } + } + while (indices.length) { + index = indices.pop(); + this.translateX(index, touchDeltaX + this.positions[index], 0); + } + } else if (this.options.closeOnSwipeUpOrDown) { + this.translateY(index, this.touchDelta.y + this.positions[index], 0); + } + }, + + ontouchend: function (event) { + if (this.options.stopTouchEventsPropagation) { + this.stopPropagation(event); + } + var index = this.index, + speed = this.options.transitionSpeed, + slideWidth = this.slideWidth, + isShortDuration = Number(Date.now() - this.touchStart.time) < 250, + // Determine if slide attempt triggers next/prev slide: + isValidSlide = (isShortDuration && Math.abs(this.touchDelta.x) > 20) || + Math.abs(this.touchDelta.x) > slideWidth / 2, + // Determine if slide attempt is past start or end: + isPastBounds = (!index && this.touchDelta.x > 0) || + (index === this.num - 1 && this.touchDelta.x < 0), + isValidClose = !isValidSlide && this.options.closeOnSwipeUpOrDown && + ((isShortDuration && Math.abs(this.touchDelta.y) > 20) || + Math.abs(this.touchDelta.y) > this.slideHeight / 2), + direction, + indexForward, + indexBackward, + distanceForward, + distanceBackward; + if (this.options.continuous) { + isPastBounds = false; + } + // Determine direction of swipe (true: right, false: left): + direction = this.touchDelta.x < 0 ? -1 : 1; + if (!this.isScrolling) { + if (isValidSlide && !isPastBounds) { + indexForward = index + direction; + indexBackward = index - direction; + distanceForward = slideWidth * direction; + distanceBackward = -slideWidth * direction; + if (this.options.continuous) { + this.move(this.circle(indexForward), distanceForward, 0); + this.move(this.circle(index - 2 * direction), distanceBackward, 0); + } else if (indexForward >= 0 && + indexForward < this.num) { + this.move(indexForward, distanceForward, 0); + } + this.move(index, this.positions[index] + distanceForward, speed); + this.move( + this.circle(indexBackward), + this.positions[this.circle(indexBackward)] + distanceForward, + speed + ); + index = this.circle(indexBackward); + this.onslide(index); + } else { + // Move back into position + if (this.options.continuous) { + this.move(this.circle(index - 1), -slideWidth, speed); + this.move(index, 0, speed); + this.move(this.circle(index + 1), slideWidth, speed); + } else { + if (index) { + this.move(index - 1, -slideWidth, speed); + } + this.move(index, 0, speed); + if (index < this.num - 1) { + this.move(index + 1, slideWidth, speed); + } + } + } + } else { + if (isValidClose) { + this.close(); + } else { + // Move back into position + this.translateY(index, 0, speed); + } + } + }, + + ontouchcancel: function (event) { + if (this.touchStart) { + this.ontouchend(event); + delete this.touchStart; + } + }, + + ontransitionend: function (event) { + var slide = this.slides[this.index]; + if (!event || slide === event.target) { + if (this.interval) { + this.play(); + } + this.setTimeout( + this.options.onslideend, + [this.index, slide] + ); + } + }, + + oncomplete: function (event) { + var target = event.target || event.srcElement, + parent = target && target.parentNode, + index; + if (!target || !parent) { + return; + } + index = this.getNodeIndex(parent); + $(parent).removeClass(this.options.slideLoadingClass); + if (event.type === 'error') { + $(parent).addClass(this.options.slideErrorClass); + this.elements[index] = 3; // Fail + } else { + this.elements[index] = 2; // Done + } + // Fix for IE7's lack of support for percentage max-height: + if (target.clientHeight > this.container[0].clientHeight) { + target.style.maxHeight = this.container[0].clientHeight; + } + if (this.interval && this.slides[this.index] === parent) { + this.play(); + } + this.setTimeout( + this.options.onslidecomplete, + [index, parent] + ); + }, + + onload: function (event) { + this.oncomplete(event); + }, + + onerror: function (event) { + this.oncomplete(event); + }, + + onkeydown: function (event) { + switch (event.which || event.keyCode) { + case 13: // Return + if (this.options.toggleControlsOnReturn) { + this.preventDefault(event); + this.toggleControls(); + } + break; + case 27: // Esc + if (this.options.closeOnEscape) { + this.close(); + } + break; + case 32: // Space + if (this.options.toggleSlideshowOnSpace) { + this.preventDefault(event); + this.toggleSlideshow(); + } + break; + case 37: // Left + if (this.options.enableKeyboardNavigation) { + this.preventDefault(event); + this.prev(); + } + break; + case 39: // Right + if (this.options.enableKeyboardNavigation) { + this.preventDefault(event); + this.next(); + } + break; + } + }, + + handleClick: function (event) { + var options = this.options, + target = event.target || event.srcElement, + parent = target.parentNode, + isTarget = function (className) { + return $(target).hasClass(className) || + $(parent).hasClass(className); + }; + if (isTarget(options.toggleClass)) { + // Click on "toggle" control + this.preventDefault(event); + this.toggleControls(); + } else if (isTarget(options.prevClass)) { + // Click on "prev" control + this.preventDefault(event); + this.prev(); + } else if (isTarget(options.nextClass)) { + // Click on "next" control + this.preventDefault(event); + this.next(); + } else if (isTarget(options.closeClass)) { + // Click on "close" control + this.preventDefault(event); + this.close(); + } else if (isTarget(options.playPauseClass)) { + // Click on "play-pause" control + this.preventDefault(event); + this.toggleSlideshow(); + } else if (parent === this.slidesContainer[0]) { + // Click on slide background + this.preventDefault(event); + if (options.closeOnSlideClick) { + this.close(); + } else { + this.toggleControls(); + } + } else if (parent.parentNode && + parent.parentNode === this.slidesContainer[0]) { + // Click on displayed element + this.preventDefault(event); + this.toggleControls(); + } + }, + + onclick: function (event) { + if (this.options.emulateTouchEvents && + this.touchDelta && (Math.abs(this.touchDelta.x) > 20 || + Math.abs(this.touchDelta.y) > 20)) { + delete this.touchDelta; + return; + } + return this.handleClick(event); + }, + + updateEdgeClasses: function (index) { + if (!index) { + this.container.addClass(this.options.leftEdgeClass); + } else { + this.container.removeClass(this.options.leftEdgeClass); + } + if (index === this.num - 1) { + this.container.addClass(this.options.rightEdgeClass); + } else { + this.container.removeClass(this.options.rightEdgeClass); + } + }, + + handleSlide: function (index) { + if (!this.options.continuous) { + this.updateEdgeClasses(index); + } + this.loadElements(index); + if (this.options.unloadElements) { + this.unloadElements(index); + } + this.setTitle(index); + }, + + onslide: function (index) { + this.index = index; + this.handleSlide(index); + this.setTimeout(this.options.onslide, [index, this.slides[index]]); + }, + + setTitle: function (index) { + var text = this.slides[index].firstChild.title, + titleElement = this.titleElement; + if (titleElement.length) { + this.titleElement.empty(); + if (text) { + titleElement[0].appendChild(document.createTextNode(text)); + } + } + }, + + setTimeout: function (func, args, wait) { + var that = this; + return func && window.setTimeout(function () { + func.apply(that, args || []); + }, wait || 0); + }, + + imageFactory: function (obj, callback) { + var that = this, + img = this.imagePrototype.cloneNode(false), + url = obj, + backgroundSize = this.options.stretchImages, + called, + element, + callbackWrapper = function (event) { + if (!called) { + event = { + type: event.type, + target: element + }; + if (!element.parentNode) { + // Fix for IE7 firing the load event for + // cached images before the element could + // be added to the DOM: + return that.setTimeout(callbackWrapper, [event]); + } + called = true; + $(img).off('load error', callbackWrapper); + if (backgroundSize) { + if (event.type === 'load') { + element.style.background = 'url("' + url + + '") center no-repeat'; + element.style.backgroundSize = backgroundSize; + } + } + callback(event); + } + }, + title; + if (typeof url !== 'string') { + url = this.getItemProperty(obj, this.options.urlProperty); + title = this.getItemProperty(obj, this.options.titleProperty); + } + if (backgroundSize === true) { + backgroundSize = 'contain'; + } + backgroundSize = this.support.backgroundSize && + this.support.backgroundSize[backgroundSize] && backgroundSize; + if (backgroundSize) { + element = this.elementPrototype.cloneNode(false); + } else { + element = img; + img.draggable = false; + } + if (title) { + element.title = title; + } + $(img).on('load error', callbackWrapper); + img.src = url; + return element; + }, + + createElement: function (obj, callback) { + var type = obj && this.getItemProperty(obj, this.options.typeProperty), + factory = (type && this[type.split('/')[0] + 'Factory']) || + this.imageFactory, + element = obj && factory.call(this, obj, callback); + if (!element) { + element = this.elementPrototype.cloneNode(false); + this.setTimeout(callback, [{ + type: 'error', + target: element + }]); + } + $(element).addClass(this.options.slideContentClass); + return element; + }, + + loadElement: function (index) { + if (!this.elements[index]) { + if (this.slides[index].firstChild) { + this.elements[index] = $(this.slides[index]) + .hasClass(this.options.slideErrorClass) ? 3 : 2; + } else { + this.elements[index] = 1; // Loading + $(this.slides[index]).addClass(this.options.slideLoadingClass); + this.slides[index].appendChild(this.createElement( + this.list[index], + this.proxyListener + )); + } + } + }, + + loadElements: function (index) { + var limit = Math.min(this.num, this.options.preloadRange * 2 + 1), + j = index, + i; + for (i = 0; i < limit; i += 1) { + // First load the current slide element (0), + // then the next one (+1), + // then the previous one (-2), + // then the next after next (+2), etc.: + j += i * (i % 2 === 0 ? -1 : 1); + // Connect the ends of the list to load slide elements for + // continuous navigation: + j = this.circle(j); + this.loadElement(j); + } + }, + + unloadElements: function (index) { + var i, + slide, + diff; + for (i in this.elements) { + if (this.elements.hasOwnProperty(i)) { + diff = Math.abs(index - i); + if (diff > this.options.preloadRange && + diff + this.options.preloadRange < this.num) { + slide = this.slides[i]; + slide.removeChild(slide.firstChild); + delete this.elements[i]; + } + } + } + }, + + addSlide: function (index) { + var slide = this.slidePrototype.cloneNode(false); + slide.setAttribute('data-index', index); + this.slidesContainer[0].appendChild(slide); + this.slides.push(slide); + }, + + positionSlide: function (index) { + var slide = this.slides[index]; + slide.style.width = this.slideWidth + 'px'; + if (this.support.transition) { + slide.style.left = (index * -this.slideWidth) + 'px'; + this.move(index, this.index > index ? -this.slideWidth : + (this.index < index ? this.slideWidth : 0), 0); + } + }, + + initSlides: function (reload) { + var clearSlides, + i; + if (!reload) { + this.positions = []; + this.positions.length = this.num; + this.elements = {}; + this.imagePrototype = document.createElement('img'); + this.elementPrototype = document.createElement('div'); + this.slidePrototype = document.createElement('div'); + $(this.slidePrototype).addClass(this.options.slideClass); + this.slides = this.slidesContainer[0].children; + clearSlides = this.options.clearSlides || + this.slides.length !== this.num; + } + this.slideWidth = this.container[0].offsetWidth; + this.slideHeight = this.container[0].offsetHeight; + this.slidesContainer[0].style.width = + (this.num * this.slideWidth) + 'px'; + if (clearSlides) { + this.resetSlides(); + } + for (i = 0; i < this.num; i += 1) { + if (clearSlides) { + this.addSlide(i); + } + this.positionSlide(i); + } + // Reposition the slides before and after the given index: + if (this.options.continuous && this.support.transition) { + this.move(this.circle(this.index - 1), -this.slideWidth, 0); + this.move(this.circle(this.index + 1), this.slideWidth, 0); + } + if (!this.support.transition) { + this.slidesContainer[0].style.left = + (this.index * -this.slideWidth) + 'px'; + } + }, + + toggleControls: function () { + var controlsClass = this.options.controlsClass; + if (this.container.hasClass(controlsClass)) { + this.container.removeClass(controlsClass); + } else { + this.container.addClass(controlsClass); + } + }, + + toggleSlideshow: function () { + if (!this.interval) { + this.play(); + } else { + this.pause(); + } + }, + + getNodeIndex: function (element) { + return parseInt(element.getAttribute('data-index'), 10); + }, + + getNestedProperty: function (obj, property) { + property.replace( + // Matches native JavaScript notation in a String, + // e.g. '["doubleQuoteProp"].dotProp[2]' + /\[(?:'([^']+)'|"([^"]+)"|(\d+))\]|(?:(?:^|\.)([^\.\[]+))/g, + function (str, singleQuoteProp, doubleQuoteProp, arrayIndex, dotProp) { + var prop = dotProp || singleQuoteProp || doubleQuoteProp || + (arrayIndex && parseInt(arrayIndex, 10)); + if (str && obj) { + obj = obj[prop]; + } + } + ); + return obj; + }, + + getDataProperty: function (obj, property) { + if (obj.getAttribute) { + var prop = obj.getAttribute('data-' + + property.replace(/([A-Z])/g, '-$1').toLowerCase()); + if (typeof prop === 'string') { + if (/^(true|false|null|-?\d+(\.\d+)?|\{[\s\S]*\}|\[[\s\S]*\])$/ + .test(prop)) { + try { + return $.parseJSON(prop); + } catch (ignore) {} + } + return prop; + } + } + }, + + getItemProperty: function (obj, property) { + var prop = obj[property]; + if (prop === undefined) { + prop = this.getDataProperty(obj, property); + if (prop === undefined) { + prop = this.getNestedProperty(obj, property); + } + } + return prop; + }, + + initStartIndex: function () { + var index = this.options.index, + urlProperty = this.options.urlProperty, + i; + // Check if the index is given as a list object: + if (index && typeof index !== 'number') { + for (i = 0; i < this.num; i += 1) { + if (this.list[i] === index || + this.getItemProperty(this.list[i], urlProperty) === + this.getItemProperty(index, urlProperty)) { + index = i; + break; + } + } + } + // Make sure the index is in the list range: + this.index = this.circle(parseInt(index, 10) || 0); + }, + + initEventListeners: function () { + var that = this, + slidesContainer = this.slidesContainer, + proxyListener = function (event) { + var type = that.support.transition && + that.support.transition.end === event.type ? + 'transitionend' : event.type; + that['on' + type](event); + }; + $(window).on('resize', proxyListener); + $(document.body).on('keydown', proxyListener); + this.container.on('click', proxyListener); + if (this.support.touch) { + slidesContainer + .on('touchstart touchmove touchend touchcancel', proxyListener); + } else if (this.options.emulateTouchEvents && + this.support.transition) { + slidesContainer + .on('mousedown mousemove mouseup mouseout', proxyListener); + } + if (this.support.transition) { + slidesContainer.on( + this.support.transition.end, + proxyListener + ); + } + this.proxyListener = proxyListener; + }, + + destroyEventListeners: function () { + var slidesContainer = this.slidesContainer, + proxyListener = this.proxyListener; + $(window).off('resize', proxyListener); + $(document.body).off('keydown', proxyListener); + this.container.off('click', proxyListener); + if (this.support.touch) { + slidesContainer + .off('touchstart touchmove touchend touchcancel', proxyListener); + } else if (this.options.emulateTouchEvents && + this.support.transition) { + slidesContainer + .off('mousedown mousemove mouseup mouseout', proxyListener); + } + if (this.support.transition) { + slidesContainer.off( + this.support.transition.end, + proxyListener + ); + } + }, + + handleOpen: function () { + if (this.options.onopened) { + this.options.onopened.call(this); + } + }, + + initWidget: function () { + var that = this, + openHandler = function (event) { + if (event.target === that.container[0]) { + that.container.off( + that.support.transition.end, + openHandler + ); + that.handleOpen(); + } + }; + this.container = $(this.options.container); + if (!this.container.length) { + this.console.log( + 'blueimp Gallery: Widget container not found.', + this.options.container + ); + return false; + } + this.slidesContainer = this.container.find( + this.options.slidesContainer + ).first(); + if (!this.slidesContainer.length) { + this.console.log( + 'blueimp Gallery: Slides container not found.', + this.options.slidesContainer + ); + return false; + } + this.titleElement = this.container.find( + this.options.titleElement + ).first(); + if (this.num === 1) { + this.container.addClass(this.options.singleClass); + } + if (this.options.onopen) { + this.options.onopen.call(this); + } + if (this.support.transition && this.options.displayTransition) { + this.container.on( + this.support.transition.end, + openHandler + ); + } else { + this.handleOpen(); + } + if (this.options.hidePageScrollbars) { + // Hide the page scrollbars: + this.bodyOverflowStyle = document.body.style.overflow; + document.body.style.overflow = 'hidden'; + } + this.container[0].style.display = 'block'; + this.initSlides(); + this.container.addClass(this.options.displayClass); + }, + + initOptions: function (options) { + // Create a copy of the prototype options: + this.options = $.extend({}, this.options); + // Check if carousel mode is enabled: + if ((options && options.carousel) || + (this.options.carousel && (!options || options.carousel !== false))) { + $.extend(this.options, this.carouselOptions); + } + // Override any given options: + $.extend(this.options, options); + if (this.num < 3) { + // 1 or 2 slides cannot be displayed continuous, + // remember the original option by setting to null instead of false: + this.options.continuous = this.options.continuous ? null : false; + } + if (!this.support.transition) { + this.options.emulateTouchEvents = false; + } + if (this.options.event) { + this.preventDefault(this.options.event); + } + } + + }); + + return Gallery; +})); diff --git a/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-helper.js b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-helper.js new file mode 100644 index 0000000000..ee178968bf --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/image-gallery/js/blueimp-helper.js @@ -0,0 +1,191 @@ +/* + * blueimp helper JS 1.2.0 + * https://github.com/blueimp/Gallery + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document */ + +(function () { + 'use strict'; + + function extend(obj1, obj2) { + var prop; + for (prop in obj2) { + if (obj2.hasOwnProperty(prop)) { + obj1[prop] = obj2[prop]; + } + } + return obj1; + } + + function Helper(query) { + if (!this || this.find !== Helper.prototype.find) { + // Called as function instead of as constructor, + // so we simply return a new instance: + return new Helper(query); + } + this.length = 0; + if (query) { + if (typeof query === 'string') { + query = this.find(query); + } + if (query.nodeType || query === query.window) { + // Single HTML element + this.length = 1; + this[0] = query; + } else { + // HTML element collection + var i = query.length; + this.length = i; + while (i) { + i -= 1; + this[i] = query[i]; + } + } + } + } + + Helper.extend = extend; + + Helper.contains = function (container, element) { + do { + element = element.parentNode; + if (element === container) { + return true; + } + } while (element); + return false; + }; + + Helper.parseJSON = function (string) { + return window.JSON && JSON.parse(string); + }; + + extend(Helper.prototype, { + + find: function (query) { + var container = this[0] || document; + if (typeof query === 'string') { + if (container.querySelectorAll) { + query = container.querySelectorAll(query); + } else if (query.charAt(0) === '#') { + query = container.getElementById(query.slice(1)); + } else { + query = container.getElementsByTagName(query); + } + } + return new Helper(query); + }, + + hasClass: function (className) { + if (!this[0]) { + return false; + } + return new RegExp('(^|\\s+)' + className + + '(\\s+|$)').test(this[0].className); + }, + + addClass: function (className) { + var i = this.length, + element; + while (i) { + i -= 1; + element = this[i]; + if (!element.className) { + element.className = className; + return this; + } + if (this.hasClass(className)) { + return this; + } + element.className += ' ' + className; + } + return this; + }, + + removeClass: function (className) { + var regexp = new RegExp('(^|\\s+)' + className + '(\\s+|$)'), + i = this.length, + element; + while (i) { + i -= 1; + element = this[i]; + element.className = element.className.replace(regexp, ' '); + } + return this; + }, + + on: function (eventName, handler) { + var eventNames = eventName.split(/\s+/), + i, + element; + while (eventNames.length) { + eventName = eventNames.shift(); + i = this.length; + while (i) { + i -= 1; + element = this[i]; + if (element.addEventListener) { + element.addEventListener(eventName, handler, false); + } else if (element.attachEvent) { + element.attachEvent('on' + eventName, handler); + } + } + } + return this; + }, + + off: function (eventName, handler) { + var eventNames = eventName.split(/\s+/), + i, + element; + while (eventNames.length) { + eventName = eventNames.shift(); + i = this.length; + while (i) { + i -= 1; + element = this[i]; + if (element.removeEventListener) { + element.removeEventListener(eventName, handler, false); + } else if (element.detachEvent) { + element.detachEvent('on' + eventName, handler); + } + } + } + return this; + }, + + empty: function () { + var i = this.length, + element; + while (i) { + i -= 1; + element = this[i]; + while (element.hasChildNodes()) { + element.removeChild(element.lastChild); + } + } + return this; + }, + + first: function () { + return new Helper(this[0]); + } + + }); + + if (typeof define === 'function' && define.amd) { + define(function () { + return Helper; + }); + } else { + window.blueimp = window.blueimp || {}; + window.blueimp.helper = Helper; + } +}()); diff --git a/src/Presentation/SmartStore.Web/Content/install/install.less b/src/Presentation/SmartStore.Web/Content/install/install.less index 950b79d0e2..bdb13586e8 100644 --- a/src/Presentation/SmartStore.Web/Content/install/install.less +++ b/src/Presentation/SmartStore.Web/Content/install/install.less @@ -8,6 +8,9 @@ * Designed and built with all the love in the world @twitter by @mdo and @fat. */ +/* Fonts (Chrome DirectWrite & FF fix) +-------------------------------------------------------------- */ + // CSS Reset @import "~/Content/bootstrap/reset.less"; @@ -29,7 +32,7 @@ @import "~/Content/bootstrap/tables.less"; // Components: common -@import "~/Content/bootstrap/font/font-awesome.less"; +//@import "~/Content/bootstrap/font/font-awesome.less"; @import "~/Content/bootstrap/dropdowns.less"; @import "~/Content/bootstrap/wells.less"; @import "~/Content/bootstrap/component-animations.less"; @@ -52,6 +55,7 @@ @import "~/Content/bootstrap/progress-bars.less"; // (MC) extra 3rd party or own components +@import "~/Content/bootstrap/custom/spinner.less"; @import "~/Content/bootstrap/custom/throbber.less"; // (MC) extra tweaks and corrections @@ -60,85 +64,135 @@ // Utility classes @import "~/Content/bootstrap/utilities.less"; // Has to be last to override when necessary -.clearfix { - *zoom: 1; - &:before, - &:after { - display: table; - content: ""; - // Fixes Opera/contenteditable bug: - // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 - line-height: 0; - } - &:after { - clear: both; - } -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} - /* INSTALL STYLES --------------------------------------------------------*/ -@installBaseColor: #29b6d9; body { - background: @installBaseColor url('images/bg.png') 50% 0% no-repeat; - background-attachment: fixed; + background: #f5f5f5; +} + +input:not([type=checkbox]):not([type=radio]), +select { + display: block; + box-sizing: border-box; + width: 100%; + height: 34px; + box-shadow: none; + border-color: #d2d2d2; +} + +textarea { + height: initial; + min-height: 34px; + box-shadow: none; + border-color: #d2d2d2; +} + +.bg-top { + position: fixed; + z-index: 0; + background: #3F51B5; + width: 100%; + height: 140px; +} + +.dropdown-menu li > a { + padding: 8px 20px 8px 12px; + > .fa { margin-right: 4px; } +} + +.help-block { + color: #a1a1a1; + margin-top: 8px; + font-size: 12px; } .install-head { - padding: 8px 0; - line-height: 40px; + position: relative; + z-index: 1; + margin: 20px 0; vertical-align: middle; } .install-panel { - margin-top: 4px; + position: relative; + z-index: 1; + margin-top: 20px; margin-bottom: 20px; padding: 30px; + padding-bottom: 0; background-color: #fff; - background-color: rgba(255,255,255, .5); - //text-shadow: 0 1px 0 rgba(255,255,255, .25); - .box-shadow(~'0 0 15px rgba(0,0,0, .15), 0 10px 6px -10px rgba(0,0,0, .4)'); - .border-radius(4px); + .box-shadow(~'0 1px 1px 0 rgba(0,0,0,.06),0 2px 5px 0 rgba(0,0,0,.2)'); + .border-radius(3px); +} + +.buttonbar { + text-align: left; + background: #fafafa; + padding: 20px 30px; + margin-left: -30px; + margin-right: -30px; + border-radius: 0 0 3px 3px; +} + +.btn-install { + font-size: 22px; + line-height: 32px; + font-weight: 600; + padding-left: 1.5em; + padding-right: 1.5em; } .install-title { margin: 0; - color: #fff; - color: lighten(@installBaseColor, 40%); - text-shadow: 0 1px 0 darken(@installBaseColor, 12%); + font-family: @pageTitleFontFamily; + font-weight: @pageTitleFontWeight; + font-size: 22px; + color: #fff; + padding-left: 8px; + vertical-align: bottom; } -.install-content { - //padding: 0 30px; +.install-intro { + font-size: 16px; + line-height: 22px; + color: #818181; + margin-bottom: 30px; +} + +.install-content fieldset { + margin-bottom: 30px; } .install-content legend { - font-family: @headingsFontFamily; - font-weight: @headingsFontWeight; + font-weight: 600; font-size: 22px; - border-bottom-color: lighten(@installBaseColor, 12%); + border-bottom-color: rgba(0,0,0, 0.1); color: @headingsColor; margin-bottom: 0; + padding-bottom: 8px; + + > .fa { + color: #717171; + margin-right: 4px; + } } .install-icon { - font-size: 32px; - line-height: 32px; - vertical-align: bottom; - margin-right: 4px; - display: none; + margin-right: 10px; +} + +.install-icon .fa-circle { + color: #f90; +} +.install-icon .fa-inverse { + font-size: 0.7em; } .form-horizontal .control-label { width: 240px; + text-align: left; } .form-horizontal .controls { @@ -150,8 +204,65 @@ label.control-label { } .field-validation-error { - color: red; + display: inline-block; + color: @red; text-shadow: none !important; + padding-top: 4px; +} + +label.control-label { + font-weight: normal; +} + + +#navbar-tools { + + .active-tool() { + .box-shadow(~'inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)'); + } + + position: absolute; + z-index: 100; + right: 0; + top: 15px; + margin: 0; + + .btn, + .btn-group { + margin-top: 0; + } + + .open .navbar-tool { + .active-tool(); + } + + .navbar-tool { + color: rgba(255,255,255, .87); + border: none; + background: transparent; + .box-shadow(none); + padding: 8px 6px; + .transition(color 0.1s linear); + + &:hover { + color: #fff; + } + + &:active { + .active-tool(); + } + + > .fa { + font-size: 20px; + } + + span { + display: inline-block; + margin-left: 3px; + vertical-align: top; + } + + } } diff --git a/src/Presentation/SmartStore.Web/Content/install/variables.custom.less b/src/Presentation/SmartStore.Web/Content/install/variables.custom.less index 537e1e2ae5..2bcad0ceeb 100644 --- a/src/Presentation/SmartStore.Web/Content/install/variables.custom.less +++ b/src/Presentation/SmartStore.Web/Content/install/variables.custom.less @@ -5,6 +5,6 @@ // Nicer page titles // ------------------------- -@pageTitleFontFamily: 'Segoe UI Light', 'Segoe UI', Arial, Helvetica, sans-serif; +@pageTitleFontFamily: 'Segoe UI', Arial, Helvetica, sans-serif; @pageTitleFontWeight: 400; @pageTitleColor: @infoText; // @linkColor; // #009fff; diff --git a/src/Presentation/SmartStore.Web/Content/install/variables.less b/src/Presentation/SmartStore.Web/Content/install/variables.less index e9195c956e..d4daaab546 100644 --- a/src/Presentation/SmartStore.Web/Content/install/variables.less +++ b/src/Presentation/SmartStore.Web/Content/install/variables.less @@ -53,8 +53,8 @@ @baseLineHeight: 18px; // 20px @altFontFamily: @serifFontFamily; -@headingsFontFamily: 'Segoe UI Semibold', 'Segoe UI', Tahoma, 'Helvetica Neue', Helvetica, Arial, 'sans-serif'; // inherit; // empty to use BS default, @baseFontFamily -@headingsFontWeight: 600 /* Semibold doesn't get bolder anyway */; //bold; // instead of browser default, bold +@headingsFontFamily: 'Segoe UI Semibold', Tahoma, 'Helvetica Neue', Helvetica, Arial, 'sans-serif'; // inherit; // empty to use BS default, @baseFontFamily +@headingsFontWeight: 400; @headingsColor: darken(@textColor, 8%); //inherit; // empty to use BS default, @textColor @@ -71,9 +71,9 @@ @paddingSmall: 2px 10px; // 26px @paddingMini: 1px 6px; // 24px -@baseBorderRadius: 0; +@baseBorderRadius: 3px; @borderRadiusLarge: 4px; -@borderRadiusSmall: 0; +@borderRadiusSmall: 2px; // Tables @@ -128,10 +128,10 @@ @dropdownLinkColor: @grayDark; -@dropdownLinkColorHover: @white; -@dropdownLinkColorActive: @dropdownLinkColor; -@dropdownLinkBackgroundActive: #666; //@linkColor; -@dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive; +@dropdownLinkColorHover: inherit; +@dropdownLinkColorActive: inherit; +@dropdownLinkBackgroundActive: #f5f5f5; +@dropdownLinkBackgroundHover: #f5f5f5; @@ -272,13 +272,13 @@ // Default 940px grid // ------------------------- -@gridColumns: 24; // 12 -@gridColumnWidth: 20px; // 60px +@gridColumns: 12; +@gridColumnWidth: 60px; @gridGutterWidth: 20px; @gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); // 1200px min -@gridColumnWidth1200: 20px; // 70px; +@gridColumnWidth1200: 70px; @gridGutterWidth1200: 30px; @gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1)); diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_flat_0_aaaaaa_40x100.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_flat_0_aaaaaa_40x100.png deleted file mode 100644 index 5b5dab2ab7..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_flat_0_aaaaaa_40x100.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_flat_75_ffffff_40x100.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_flat_75_ffffff_40x100.png deleted file mode 100644 index ac8b229af9..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_flat_75_ffffff_40x100.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_55_fbf9ee_1x400.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_55_fbf9ee_1x400.png deleted file mode 100644 index ad3d6346e0..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_55_fbf9ee_1x400.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_65_ffffff_1x400.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_65_ffffff_1x400.png deleted file mode 100644 index 42ccba269b..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_65_ffffff_1x400.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_75_dadada_1x400.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_75_dadada_1x400.png deleted file mode 100644 index 5a46b47cb1..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_75_dadada_1x400.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_75_e6e6e6_1x400.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_75_e6e6e6_1x400.png deleted file mode 100644 index 86c2baa655..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_75_e6e6e6_1x400.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_95_fef1ec_1x400.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_95_fef1ec_1x400.png deleted file mode 100644 index 4443fdc1a1..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_glass_95_fef1ec_1x400.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png deleted file mode 100644 index 7c9fa6c6ed..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-bg_highlight-soft_75_cccccc_1x100.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_222222_256x240.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_222222_256x240.png deleted file mode 100644 index ee039dc096..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_222222_256x240.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_2e83ff_256x240.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_2e83ff_256x240.png deleted file mode 100644 index 45e8928e52..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_2e83ff_256x240.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_454545_256x240.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_454545_256x240.png deleted file mode 100644 index 7ec70d11bf..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_454545_256x240.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_888888_256x240.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_888888_256x240.png deleted file mode 100644 index 5ba708c391..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_888888_256x240.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_cd0a0a_256x240.png b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_cd0a0a_256x240.png deleted file mode 100644 index 7930a55809..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/images/ui-icons_cd0a0a_256x240.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery-ui.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery-ui.css deleted file mode 100644 index e0625dc5d9..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery-ui.css +++ /dev/null @@ -1,464 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.tabs.css, jquery.ui.theme.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ - -/* Layout helpers -----------------------------------*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } -.ui-helper-clearfix:after { clear: both; } -.ui-helper-clearfix { zoom: 1; } -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } - -/* IE/Win - Fix animation bug - #4615 */ -.ui-accordion { width: 100%; } -.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } -.ui-accordion .ui-accordion-li-fix { display: inline; } -.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } -.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } -.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } -.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } -.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } -.ui-accordion .ui-accordion-content-active { display: block; } - -.ui-autocomplete { position: absolute; cursor: default; } - -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -/* - * jQuery UI Menu 1.8.24 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu#theming - */ -.ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; - float: left; -} -.ui-menu .ui-menu { - margin-top: -3px; -} -.ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; -} -.ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; -} -.ui-menu .ui-menu-item a.ui-state-hover, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} - -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } - -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } - -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } - -/* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ - -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } - -/* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -} -.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } - -.ui-progressbar { height:2em; text-align: left; overflow: hidden; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } - -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; } -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } -.ui-tabs .ui-tabs-hide { display: none !important; } - -/* Component containers -----------------------------------*/ -.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } -.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } -.ui-widget-content a { color: #222222/*{fcContent}*/; } -.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } -.ui-widget-header a { color: #222222/*{fcHeader}*/; } - -/* Interaction states -----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; } -.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } -.ui-widget :active { outline: none; } - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } -.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } -.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } -.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } -.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } -.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } -.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } -.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } -.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } -.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } -.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } - -/* positioning */ -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } -.ui-icon-triangle-1-n { background-position: 0 -16px; } -.ui-icon-triangle-1-ne { background-position: -16px -16px; } -.ui-icon-triangle-1-e { background-position: -32px -16px; } -.ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } -.ui-icon-triangle-1-sw { background-position: -80px -16px; } -.ui-icon-triangle-1-w { background-position: -96px -16px; } -.ui-icon-triangle-1-nw { background-position: -112px -16px; } -.ui-icon-triangle-2-n-s { background-position: -128px -16px; } -.ui-icon-triangle-2-e-w { background-position: -144px -16px; } -.ui-icon-arrow-1-n { background-position: 0 -32px; } -.ui-icon-arrow-1-ne { background-position: -16px -32px; } -.ui-icon-arrow-1-e { background-position: -32px -32px; } -.ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } -.ui-icon-arrow-1-sw { background-position: -80px -32px; } -.ui-icon-arrow-1-w { background-position: -96px -32px; } -.ui-icon-arrow-1-nw { background-position: -112px -32px; } -.ui-icon-arrow-2-n-s { background-position: -128px -32px; } -.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } -.ui-icon-arrow-2-e-w { background-position: -160px -32px; } -.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } -.ui-icon-arrowstop-1-n { background-position: -192px -32px; } -.ui-icon-arrowstop-1-e { background-position: -208px -32px; } -.ui-icon-arrowstop-1-s { background-position: -224px -32px; } -.ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } -.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } -.ui-icon-arrowthick-1-e { background-position: -32px -48px; } -.ui-icon-arrowthick-1-se { background-position: -48px -48px; } -.ui-icon-arrowthick-1-s { background-position: -64px -48px; } -.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } -.ui-icon-arrowthick-1-w { background-position: -96px -48px; } -.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } -.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } -.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } -.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } -.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } -.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } -.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } -.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } -.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } -.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } -.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } -.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } -.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } -.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } -.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } -.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } -.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } -.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } -.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } -.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } -.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } -.ui-icon-arrow-4 { background-position: 0 -80px; } -.ui-icon-arrow-4-diag { background-position: -16px -80px; } -.ui-icon-extlink { background-position: -32px -80px; } -.ui-icon-newwin { background-position: -48px -80px; } -.ui-icon-refresh { background-position: -64px -80px; } -.ui-icon-shuffle { background-position: -80px -80px; } -.ui-icon-transfer-e-w { background-position: -96px -80px; } -.ui-icon-transferthick-e-w { background-position: -112px -80px; } -.ui-icon-folder-collapsed { background-position: 0 -96px; } -.ui-icon-folder-open { background-position: -16px -96px; } -.ui-icon-document { background-position: -32px -96px; } -.ui-icon-document-b { background-position: -48px -96px; } -.ui-icon-note { background-position: -64px -96px; } -.ui-icon-mail-closed { background-position: -80px -96px; } -.ui-icon-mail-open { background-position: -96px -96px; } -.ui-icon-suitcase { background-position: -112px -96px; } -.ui-icon-comment { background-position: -128px -96px; } -.ui-icon-person { background-position: -144px -96px; } -.ui-icon-print { background-position: -160px -96px; } -.ui-icon-trash { background-position: -176px -96px; } -.ui-icon-locked { background-position: -192px -96px; } -.ui-icon-unlocked { background-position: -208px -96px; } -.ui-icon-bookmark { background-position: -224px -96px; } -.ui-icon-tag { background-position: -240px -96px; } -.ui-icon-home { background-position: 0 -112px; } -.ui-icon-flag { background-position: -16px -112px; } -.ui-icon-calendar { background-position: -32px -112px; } -.ui-icon-cart { background-position: -48px -112px; } -.ui-icon-pencil { background-position: -64px -112px; } -.ui-icon-clock { background-position: -80px -112px; } -.ui-icon-disk { background-position: -96px -112px; } -.ui-icon-calculator { background-position: -112px -112px; } -.ui-icon-zoomin { background-position: -128px -112px; } -.ui-icon-zoomout { background-position: -144px -112px; } -.ui-icon-search { background-position: -160px -112px; } -.ui-icon-wrench { background-position: -176px -112px; } -.ui-icon-gear { background-position: -192px -112px; } -.ui-icon-heart { background-position: -208px -112px; } -.ui-icon-star { background-position: -224px -112px; } -.ui-icon-link { background-position: -240px -112px; } -.ui-icon-cancel { background-position: 0 -128px; } -.ui-icon-plus { background-position: -16px -128px; } -.ui-icon-plusthick { background-position: -32px -128px; } -.ui-icon-minus { background-position: -48px -128px; } -.ui-icon-minusthick { background-position: -64px -128px; } -.ui-icon-close { background-position: -80px -128px; } -.ui-icon-closethick { background-position: -96px -128px; } -.ui-icon-key { background-position: -112px -128px; } -.ui-icon-lightbulb { background-position: -128px -128px; } -.ui-icon-scissors { background-position: -144px -128px; } -.ui-icon-clipboard { background-position: -160px -128px; } -.ui-icon-copy { background-position: -176px -128px; } -.ui-icon-contact { background-position: -192px -128px; } -.ui-icon-image { background-position: -208px -128px; } -.ui-icon-video { background-position: -224px -128px; } -.ui-icon-script { background-position: -240px -128px; } -.ui-icon-alert { background-position: 0 -144px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-notice { background-position: -32px -144px; } -.ui-icon-help { background-position: -48px -144px; } -.ui-icon-check { background-position: -64px -144px; } -.ui-icon-bullet { background-position: -80px -144px; } -.ui-icon-radio-off { background-position: -96px -144px; } -.ui-icon-radio-on { background-position: -112px -144px; } -.ui-icon-pin-w { background-position: -128px -144px; } -.ui-icon-pin-s { background-position: -144px -144px; } -.ui-icon-play { background-position: 0 -160px; } -.ui-icon-pause { background-position: -16px -160px; } -.ui-icon-seek-next { background-position: -32px -160px; } -.ui-icon-seek-prev { background-position: -48px -160px; } -.ui-icon-seek-end { background-position: -64px -160px; } -.ui-icon-seek-start { background-position: -80px -160px; } -/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ -.ui-icon-seek-first { background-position: -80px -160px; } -.ui-icon-stop { background-position: -96px -160px; } -.ui-icon-eject { background-position: -112px -160px; } -.ui-icon-volume-off { background-position: -128px -160px; } -.ui-icon-volume-on { background-position: -144px -160px; } -.ui-icon-power { background-position: 0 -176px; } -.ui-icon-signal-diag { background-position: -16px -176px; } -.ui-icon-signal { background-position: -32px -176px; } -.ui-icon-battery-0 { background-position: -48px -176px; } -.ui-icon-battery-1 { background-position: -64px -176px; } -.ui-icon-battery-2 { background-position: -80px -176px; } -.ui-icon-battery-3 { background-position: -96px -176px; } -.ui-icon-circle-plus { background-position: 0 -192px; } -.ui-icon-circle-minus { background-position: -16px -192px; } -.ui-icon-circle-close { background-position: -32px -192px; } -.ui-icon-circle-triangle-e { background-position: -48px -192px; } -.ui-icon-circle-triangle-s { background-position: -64px -192px; } -.ui-icon-circle-triangle-w { background-position: -80px -192px; } -.ui-icon-circle-triangle-n { background-position: -96px -192px; } -.ui-icon-circle-arrow-e { background-position: -112px -192px; } -.ui-icon-circle-arrow-s { background-position: -128px -192px; } -.ui-icon-circle-arrow-w { background-position: -144px -192px; } -.ui-icon-circle-arrow-n { background-position: -160px -192px; } -.ui-icon-circle-zoomin { background-position: -176px -192px; } -.ui-icon-circle-zoomout { background-position: -192px -192px; } -.ui-icon-circle-check { background-position: -208px -192px; } -.ui-icon-circlesmall-plus { background-position: 0 -208px; } -.ui-icon-circlesmall-minus { background-position: -16px -208px; } -.ui-icon-circlesmall-close { background-position: -32px -208px; } -.ui-icon-squaresmall-plus { background-position: -48px -208px; } -.ui-icon-squaresmall-minus { background-position: -64px -208px; } -.ui-icon-squaresmall-close { background-position: -80px -208px; } -.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } -.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } -.ui-icon-grip-solid-vertical { background-position: -32px -224px; } -.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } -.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } -.ui-icon-grip-diagonal-se { background-position: -80px -224px; } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } - -/* Overlays */ -.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } -.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery-ui.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery-ui.min.css deleted file mode 100644 index 82d19c07a3..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery-ui.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.tabs.css, jquery.ui.theme.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{position:absolute!important;clip:rect(1px);clip:rect(1px,1px,1px,1px)}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{zoom:1}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ui-accordion{width:100%}.ui-accordion .ui-accordion-header{cursor:pointer;position:relative;margin-top:1px;zoom:1}.ui-accordion .ui-accordion-li-fix{display:inline}.ui-accordion .ui-accordion-header-active{border-bottom:0!important}.ui-accordion .ui-accordion-header a{display:block;font-size:1em;padding:.5em .5em .5em .7em}.ui-accordion-icons .ui-accordion-header a{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;margin-top:-2px;position:relative;top:1px;margin-bottom:2px;overflow:auto;display:none;zoom:1}.ui-accordion .ui-accordion-content-active{display:block}.ui-autocomplete{position:absolute;cursor:default}* html .ui-autocomplete{width:1px}.ui-menu{list-style:none;padding:2px;margin:0;display:block;float:left}.ui-menu .ui-menu{margin-top:-3px}.ui-menu .ui-menu-item{margin:0;padding:0;zoom:1;float:left;clear:left;width:100%}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:.2em .4em;line-height:1.5;zoom:1}.ui-menu .ui-menu-item a.ui-state-hover,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-button{display:inline-block;position:relative;padding:0;margin-right:.1em;text-decoration:none!important;cursor:pointer;text-align:center;zoom:1;overflow:visible}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:1.4}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0em}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right}.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-cover{position:absolute;z-index:-1;filter:mask();top:-4px;left:-4px;width:200px;height:200px}.ui-dialog{position:absolute;padding:.2em;width:300px;overflow:hidden}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 16px .1em 0}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:19px;margin:-10px 0 0 0;padding:1px;height:18px}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin:1px}.ui-dialog .ui-dialog-titlebar-close:hover,.ui-dialog .ui-dialog-titlebar-close:focus{padding:0}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto;zoom:1}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin:.5em 0 0 0;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:14px;height:14px;right:3px;bottom:3px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-tabs{position:relative;padding:.2em;zoom:1}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:1px;margin:0 .2em 1px 0;border-bottom:0!important;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-selected{margin-bottom:0;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-selected a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-state-processing a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tabs .ui-tabs-hide{display:none!important}.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-widget:active{outline:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-icon{width:16px;height:16px;background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-off{background-position:-96px -144px}.ui-icon-radio-on{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;-khtml-border-top-left-radius:4px;border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;-khtml-border-top-right-radius:4px;border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;-khtml-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;-khtml-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);-moz-border-radius:8px;-khtml-border-radius:8px;-webkit-border-radius:8px;border-radius:8px} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.accordion.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.accordion.css deleted file mode 100644 index cd8f971c3a..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.accordion.css +++ /dev/null @@ -1,19 +0,0 @@ -/*! - * jQuery UI Accordion 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion#theming - */ -/* IE/Win - Fix animation bug - #4615 */ -.ui-accordion { width: 100%; } -.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } -.ui-accordion .ui-accordion-li-fix { display: inline; } -.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } -.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } -.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } -.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } -.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } -.ui-accordion .ui-accordion-content-active { display: block; } diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.accordion.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.accordion.min.css deleted file mode 100644 index 32d81b4ca0..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.accordion.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.accordion.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-accordion{width:100%}.ui-accordion .ui-accordion-header{cursor:pointer;position:relative;margin-top:1px;zoom:1}.ui-accordion .ui-accordion-li-fix{display:inline}.ui-accordion .ui-accordion-header-active{border-bottom:0!important}.ui-accordion .ui-accordion-header a{display:block;font-size:1em;padding:.5em .5em .5em .7em}.ui-accordion-icons .ui-accordion-header a{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;margin-top:-2px;position:relative;top:1px;margin-bottom:2px;overflow:auto;display:none;zoom:1}.ui-accordion .ui-accordion-content-active{display:block} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.all.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.all.css deleted file mode 100644 index e3d525c45e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.all.css +++ /dev/null @@ -1,11 +0,0 @@ -/*! - * jQuery UI CSS Framework 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming - */ -@import "jquery.ui.base.css"; -@import "jquery.ui.theme.css"; diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.autocomplete.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.autocomplete.css deleted file mode 100644 index c7eaff226e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.autocomplete.css +++ /dev/null @@ -1,53 +0,0 @@ -/*! - * jQuery UI Autocomplete 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete#theming - */ -.ui-autocomplete { position: absolute; cursor: default; } - -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -/* - * jQuery UI Menu 1.8.24 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu#theming - */ -.ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; - float: left; -} -.ui-menu .ui-menu { - margin-top: -3px; -} -.ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; -} -.ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; -} -.ui-menu .ui-menu-item a.ui-state-hover, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.autocomplete.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.autocomplete.min.css deleted file mode 100644 index 280156e968..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.autocomplete.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.autocomplete.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-autocomplete{position:absolute;cursor:default}* html .ui-autocomplete{width:1px}.ui-menu{list-style:none;padding:2px;margin:0;display:block;float:left}.ui-menu .ui-menu{margin-top:-3px}.ui-menu .ui-menu-item{margin:0;padding:0;zoom:1;float:left;clear:left;width:100%}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:.2em .4em;line-height:1.5;zoom:1}.ui-menu .ui-menu-item a.ui-state-hover,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.base.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.base.css deleted file mode 100644 index 1743811bee..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.base.css +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * jQuery UI CSS Framework 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming - */ -@import url("jquery.ui.core.css"); - -@import url("jquery.ui.accordion.css"); -@import url("jquery.ui.autocomplete.css"); -@import url("jquery.ui.button.css"); -@import url("jquery.ui.datepicker.css"); -@import url("jquery.ui.dialog.css"); -@import url("jquery.ui.progressbar.css"); -@import url("jquery.ui.resizable.css"); -@import url("jquery.ui.selectable.css"); -@import url("jquery.ui.slider.css"); -@import url("jquery.ui.tabs.css"); diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.button.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.button.css deleted file mode 100644 index 0dc98573be..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.button.css +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * jQuery UI Button 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button#theming - */ -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } - -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } - -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } - -/* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.button.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.button.min.css deleted file mode 100644 index 68d9ca0e3c..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.button.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.button.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-button{display:inline-block;position:relative;padding:0;margin-right:.1em;text-decoration:none!important;cursor:pointer;text-align:center;zoom:1;overflow:visible}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:1.4}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}button.ui-button::-moz-focus-inner{border:0;padding:0} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.core.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.core.css deleted file mode 100644 index 8b953a2b37..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.core.css +++ /dev/null @@ -1,38 +0,0 @@ -/*! - * jQuery UI CSS Framework 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - */ - -/* Layout helpers -----------------------------------*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } -.ui-helper-clearfix:after { clear: both; } -.ui-helper-clearfix { zoom: 1; } -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.core.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.core.min.css deleted file mode 100644 index f638cb9bc0..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.core.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.core.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{position:absolute!important;clip:rect(1px);clip:rect(1px,1px,1px,1px)}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{zoom:1}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.datepicker.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.datepicker.css deleted file mode 100644 index 37d3a98e3b..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.datepicker.css +++ /dev/null @@ -1,66 +0,0 @@ -/*! - * jQuery UI Datepicker 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker#theming - */ -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } - -/* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.datepicker.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.datepicker.min.css deleted file mode 100644 index 24fdceaed8..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.datepicker.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.datepicker.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0em}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right}.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-cover{position:absolute;z-index:-1;filter:mask();top:-4px;left:-4px;width:200px;height:200px} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.dialog.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.dialog.css deleted file mode 100644 index 04515f48cb..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.dialog.css +++ /dev/null @@ -1,21 +0,0 @@ -/*! - * jQuery UI Dialog 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog#theming - */ -.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.dialog.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.dialog.min.css deleted file mode 100644 index f584c1f7ec..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.dialog.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.dialog.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-dialog{position:absolute;padding:.2em;width:300px;overflow:hidden}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 16px .1em 0}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:19px;margin:-10px 0 0 0;padding:1px;height:18px}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin:1px}.ui-dialog .ui-dialog-titlebar-close:hover,.ui-dialog .ui-dialog-titlebar-close:focus{padding:0}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto;zoom:1}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin:.5em 0 0 0;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:14px;height:14px;right:3px;bottom:3px}.ui-draggable .ui-dialog-titlebar{cursor:move} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.progressbar.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.progressbar.css deleted file mode 100644 index 90bf308129..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.progressbar.css +++ /dev/null @@ -1,11 +0,0 @@ -/*! - * jQuery UI Progressbar 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar#theming - */ -.ui-progressbar { height:2em; text-align: left; overflow: hidden; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.progressbar.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.progressbar.min.css deleted file mode 100644 index fcdff9bc0c..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.progressbar.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.progressbar.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.resizable.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.resizable.css deleted file mode 100644 index d17873e72e..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.resizable.css +++ /dev/null @@ -1,20 +0,0 @@ -/*! - * jQuery UI Resizable 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizable#theming - */ -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.resizable.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.resizable.min.css deleted file mode 100644 index 08dd3cc088..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.resizable.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.resizable.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.selectable.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.selectable.css deleted file mode 100644 index 9850ee7e4c..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.selectable.css +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * jQuery UI Selectable 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectable#theming - */ -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.selectable.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.selectable.min.css deleted file mode 100644 index a0d8de9a4a..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.selectable.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.selectable.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.slider.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.slider.css deleted file mode 100644 index fbfe66585d..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.slider.css +++ /dev/null @@ -1,24 +0,0 @@ -/*! - * jQuery UI Slider 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider#theming - */ -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.slider.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.slider.min.css deleted file mode 100644 index b47e6e8fcc..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.slider.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.slider.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.tabs.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.tabs.css deleted file mode 100644 index f0bee7a209..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.tabs.css +++ /dev/null @@ -1,18 +0,0 @@ -/*! - * jQuery UI Tabs 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs#theming - */ -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } -.ui-tabs .ui-tabs-hide { display: none !important; } diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.tabs.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.tabs.min.css deleted file mode 100644 index d3304e8e77..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.tabs.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.tabs.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-tabs{position:relative;padding:.2em;zoom:1}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:1px;margin:0 .2em 1px 0;border-bottom:0!important;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-selected{margin-bottom:0;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-selected a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-state-processing a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tabs .ui-tabs-hide{display:none!important} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.theme.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.theme.css deleted file mode 100644 index b7d2f61795..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.theme.css +++ /dev/null @@ -1,247 +0,0 @@ -/*! - * jQuery UI CSS Framework 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - * - * To view and modify this theme, visit http://jqueryui.com/themeroller/ - */ - - -/* Component containers -----------------------------------*/ -.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } -.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } -.ui-widget-content a { color: #222222/*{fcContent}*/; } -.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } -.ui-widget-header a { color: #222222/*{fcHeader}*/; } - -/* Interaction states -----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; } -.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } -.ui-widget :active { outline: none; } - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } -.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } -.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } -.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } -.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } -.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } -.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } -.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } -.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } -.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } -.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } - -/* positioning */ -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } -.ui-icon-triangle-1-n { background-position: 0 -16px; } -.ui-icon-triangle-1-ne { background-position: -16px -16px; } -.ui-icon-triangle-1-e { background-position: -32px -16px; } -.ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } -.ui-icon-triangle-1-sw { background-position: -80px -16px; } -.ui-icon-triangle-1-w { background-position: -96px -16px; } -.ui-icon-triangle-1-nw { background-position: -112px -16px; } -.ui-icon-triangle-2-n-s { background-position: -128px -16px; } -.ui-icon-triangle-2-e-w { background-position: -144px -16px; } -.ui-icon-arrow-1-n { background-position: 0 -32px; } -.ui-icon-arrow-1-ne { background-position: -16px -32px; } -.ui-icon-arrow-1-e { background-position: -32px -32px; } -.ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } -.ui-icon-arrow-1-sw { background-position: -80px -32px; } -.ui-icon-arrow-1-w { background-position: -96px -32px; } -.ui-icon-arrow-1-nw { background-position: -112px -32px; } -.ui-icon-arrow-2-n-s { background-position: -128px -32px; } -.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } -.ui-icon-arrow-2-e-w { background-position: -160px -32px; } -.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } -.ui-icon-arrowstop-1-n { background-position: -192px -32px; } -.ui-icon-arrowstop-1-e { background-position: -208px -32px; } -.ui-icon-arrowstop-1-s { background-position: -224px -32px; } -.ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } -.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } -.ui-icon-arrowthick-1-e { background-position: -32px -48px; } -.ui-icon-arrowthick-1-se { background-position: -48px -48px; } -.ui-icon-arrowthick-1-s { background-position: -64px -48px; } -.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } -.ui-icon-arrowthick-1-w { background-position: -96px -48px; } -.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } -.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } -.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } -.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } -.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } -.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } -.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } -.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } -.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } -.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } -.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } -.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } -.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } -.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } -.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } -.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } -.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } -.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } -.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } -.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } -.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } -.ui-icon-arrow-4 { background-position: 0 -80px; } -.ui-icon-arrow-4-diag { background-position: -16px -80px; } -.ui-icon-extlink { background-position: -32px -80px; } -.ui-icon-newwin { background-position: -48px -80px; } -.ui-icon-refresh { background-position: -64px -80px; } -.ui-icon-shuffle { background-position: -80px -80px; } -.ui-icon-transfer-e-w { background-position: -96px -80px; } -.ui-icon-transferthick-e-w { background-position: -112px -80px; } -.ui-icon-folder-collapsed { background-position: 0 -96px; } -.ui-icon-folder-open { background-position: -16px -96px; } -.ui-icon-document { background-position: -32px -96px; } -.ui-icon-document-b { background-position: -48px -96px; } -.ui-icon-note { background-position: -64px -96px; } -.ui-icon-mail-closed { background-position: -80px -96px; } -.ui-icon-mail-open { background-position: -96px -96px; } -.ui-icon-suitcase { background-position: -112px -96px; } -.ui-icon-comment { background-position: -128px -96px; } -.ui-icon-person { background-position: -144px -96px; } -.ui-icon-print { background-position: -160px -96px; } -.ui-icon-trash { background-position: -176px -96px; } -.ui-icon-locked { background-position: -192px -96px; } -.ui-icon-unlocked { background-position: -208px -96px; } -.ui-icon-bookmark { background-position: -224px -96px; } -.ui-icon-tag { background-position: -240px -96px; } -.ui-icon-home { background-position: 0 -112px; } -.ui-icon-flag { background-position: -16px -112px; } -.ui-icon-calendar { background-position: -32px -112px; } -.ui-icon-cart { background-position: -48px -112px; } -.ui-icon-pencil { background-position: -64px -112px; } -.ui-icon-clock { background-position: -80px -112px; } -.ui-icon-disk { background-position: -96px -112px; } -.ui-icon-calculator { background-position: -112px -112px; } -.ui-icon-zoomin { background-position: -128px -112px; } -.ui-icon-zoomout { background-position: -144px -112px; } -.ui-icon-search { background-position: -160px -112px; } -.ui-icon-wrench { background-position: -176px -112px; } -.ui-icon-gear { background-position: -192px -112px; } -.ui-icon-heart { background-position: -208px -112px; } -.ui-icon-star { background-position: -224px -112px; } -.ui-icon-link { background-position: -240px -112px; } -.ui-icon-cancel { background-position: 0 -128px; } -.ui-icon-plus { background-position: -16px -128px; } -.ui-icon-plusthick { background-position: -32px -128px; } -.ui-icon-minus { background-position: -48px -128px; } -.ui-icon-minusthick { background-position: -64px -128px; } -.ui-icon-close { background-position: -80px -128px; } -.ui-icon-closethick { background-position: -96px -128px; } -.ui-icon-key { background-position: -112px -128px; } -.ui-icon-lightbulb { background-position: -128px -128px; } -.ui-icon-scissors { background-position: -144px -128px; } -.ui-icon-clipboard { background-position: -160px -128px; } -.ui-icon-copy { background-position: -176px -128px; } -.ui-icon-contact { background-position: -192px -128px; } -.ui-icon-image { background-position: -208px -128px; } -.ui-icon-video { background-position: -224px -128px; } -.ui-icon-script { background-position: -240px -128px; } -.ui-icon-alert { background-position: 0 -144px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-notice { background-position: -32px -144px; } -.ui-icon-help { background-position: -48px -144px; } -.ui-icon-check { background-position: -64px -144px; } -.ui-icon-bullet { background-position: -80px -144px; } -.ui-icon-radio-off { background-position: -96px -144px; } -.ui-icon-radio-on { background-position: -112px -144px; } -.ui-icon-pin-w { background-position: -128px -144px; } -.ui-icon-pin-s { background-position: -144px -144px; } -.ui-icon-play { background-position: 0 -160px; } -.ui-icon-pause { background-position: -16px -160px; } -.ui-icon-seek-next { background-position: -32px -160px; } -.ui-icon-seek-prev { background-position: -48px -160px; } -.ui-icon-seek-end { background-position: -64px -160px; } -.ui-icon-seek-start { background-position: -80px -160px; } -/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ -.ui-icon-seek-first { background-position: -80px -160px; } -.ui-icon-stop { background-position: -96px -160px; } -.ui-icon-eject { background-position: -112px -160px; } -.ui-icon-volume-off { background-position: -128px -160px; } -.ui-icon-volume-on { background-position: -144px -160px; } -.ui-icon-power { background-position: 0 -176px; } -.ui-icon-signal-diag { background-position: -16px -176px; } -.ui-icon-signal { background-position: -32px -176px; } -.ui-icon-battery-0 { background-position: -48px -176px; } -.ui-icon-battery-1 { background-position: -64px -176px; } -.ui-icon-battery-2 { background-position: -80px -176px; } -.ui-icon-battery-3 { background-position: -96px -176px; } -.ui-icon-circle-plus { background-position: 0 -192px; } -.ui-icon-circle-minus { background-position: -16px -192px; } -.ui-icon-circle-close { background-position: -32px -192px; } -.ui-icon-circle-triangle-e { background-position: -48px -192px; } -.ui-icon-circle-triangle-s { background-position: -64px -192px; } -.ui-icon-circle-triangle-w { background-position: -80px -192px; } -.ui-icon-circle-triangle-n { background-position: -96px -192px; } -.ui-icon-circle-arrow-e { background-position: -112px -192px; } -.ui-icon-circle-arrow-s { background-position: -128px -192px; } -.ui-icon-circle-arrow-w { background-position: -144px -192px; } -.ui-icon-circle-arrow-n { background-position: -160px -192px; } -.ui-icon-circle-zoomin { background-position: -176px -192px; } -.ui-icon-circle-zoomout { background-position: -192px -192px; } -.ui-icon-circle-check { background-position: -208px -192px; } -.ui-icon-circlesmall-plus { background-position: 0 -208px; } -.ui-icon-circlesmall-minus { background-position: -16px -208px; } -.ui-icon-circlesmall-close { background-position: -32px -208px; } -.ui-icon-squaresmall-plus { background-position: -48px -208px; } -.ui-icon-squaresmall-minus { background-position: -64px -208px; } -.ui-icon-squaresmall-close { background-position: -80px -208px; } -.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } -.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } -.ui-icon-grip-solid-vertical { background-position: -32px -224px; } -.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } -.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } -.ui-icon-grip-diagonal-se { background-position: -80px -224px; } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } - -/* Overlays */ -.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } -.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.theme.min.css b/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.theme.min.css deleted file mode 100644 index 52be52a5d7..0000000000 --- a/src/Presentation/SmartStore.Web/Content/jquery-ui/base/jquery.ui.theme.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.theme.css -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -.ui-widget{font-family:Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #aaa;background:#fff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x;color:#222}.ui-widget-content a{color:#222}.ui-widget-header{border:1px solid #aaa;background:#ccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x;color:#222;font-weight:bold}.ui-widget-header a{color:#222}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #d3d3d3;background:#e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#555}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#555;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #999;background:#dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-hover a,.ui-state-hover a:hover{color:#212121;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #aaa;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:normal;color:#212121}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#212121;text-decoration:none}.ui-widget:active{outline:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fcefa1;background:#fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x;color:#cd0a0a}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#cd0a0a}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#cd0a0a}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-icon{width:16px;height:16px;background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_888888_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_454545_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_2e83ff_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_cd0a0a_256x240.png)}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-off{background-position:-96px -144px}.ui-icon-radio-on{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;-khtml-border-top-left-radius:4px;border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;-khtml-border-top-right-radius:4px;border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;-khtml-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;-khtml-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-widget-overlay{background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30)}.ui-widget-shadow{margin:-8px 0 0 -8px;padding:8px;background:#aaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x;opacity:.3;filter:Alpha(Opacity=30);-moz-border-radius:8px;-khtml-border-radius:8px;-webkit-border-radius:8px;border-radius:8px} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.css b/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.css index aeac45f9cc..8e7e891425 100644 --- a/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.css +++ b/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.css @@ -9,21 +9,20 @@ Description: */ /* -- Notice */ .ui-pnotify { -top: 25px; -right: 25px; -position: absolute; -height: auto; -/* Ensures notices are above everything */ -z-index: 9999; + top: 25px; + right: 25px; + position: absolute; + height: auto; + /* Ensures notices are above everything */ + z-index: 9999; } /* Hides position: fixed from IE6 */ html > body .ui-pnotify { -position: fixed; + position: fixed; } .ui-pnotify .ui-pnotify-shadow { --webkit-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); --moz-box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); -box-shadow: 0px 2px 10px rgba(50, 50, 50, 0.5); + -webkit-box-shadow: 1px 1px 2px rgba(0,0,0, 0.35); + box-shadow: 1px 1px 2px rgba(0,0,0, 0.35); } .ui-pnotify-container { background-position: 0 0; @@ -32,103 +31,151 @@ height: 100%; margin: 0; } .ui-pnotify-sharp { --webkit-border-radius: 0; --moz-border-radius: 0; -border-radius: 0; + border-radius: 0; } .ui-pnotify-closer, .ui-pnotify-sticker { -float: right; -margin-left: .2em; + float: right; + margin-left: .2em; } .ui-pnotify-title { -display: block; -margin-bottom: .4em; + display: block; + margin-bottom: .4em; } .ui-pnotify-text { -display: block; + display: block; } .ui-pnotify-icon, .ui-pnotify-icon span { -display: block; -float: left; -margin-right: .2em; + display: block; + float: left; + margin-right: .2em; } /* -- History Pulldown */ .ui-pnotify-history-container { -position: absolute; -top: 0; -right: 18px; -width: 70px; -border-top: none; -padding: 0; --webkit-border-top-left-radius: 0; --moz-border-top-left-radius: 0; -border-top-left-radius: 0; --webkit-border-top-right-radius: 0; --moz-border-top-right-radius: 0; -border-top-right-radius: 0; -/* Ensures history container is above notices. */ -z-index: 10000; + position: absolute; + top: 0; + right: 18px; + width: 70px; + border-top: none; + padding: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + /* Ensures history container is above notices. */ + z-index: 10000; } .ui-pnotify-history-container .ui-pnotify-history-header { -padding: 2px; + padding: 2px; } .ui-pnotify-history-container button { -cursor: pointer; -display: block; -width: 100%; + cursor: pointer; + display: block; + width: 100%; } .ui-pnotify-history-container .ui-pnotify-history-pulldown { -display: block; -margin: 0 auto; + display: block; + margin: 0 auto; } /* Alternate stack initial positioning. */ .ui-pnotify.stack-topleft, .ui-pnotify.stack-bottomleft { -left: 25px; -right: auto; + left: 25px; + right: auto; } .ui-pnotify.stack-bottomright, .ui-pnotify.stack-bottomleft { -bottom: 25px; -top: auto; + bottom: 25px; + top: auto; } /* codehint: sm-add */ + +.ui-pnotify { + -webkit-box-shadow: 1px 1px 2px rgba(0,0,0, 0.15); + box-shadow: 1px 1px 2px rgba(0,0,0, 0.15); + border: 1px solid rgba(0,0,0, .2); + width: 500px !important; +} + .ui-pnotify-container { - padding: 8px 8px 8px 28px; + padding: 10px 10px 10px 50px !important; + margin-bottom: 0 !important; + border: none !important; + position: relative; + overflow: hidden; +} + +.ui-pnotify .ui-pnotify-shadow { + -webkit-box-shadow: none; + box-shadow: none; } .ui-pnotify-icon { position: absolute; - left: 8px; - top: 8px; -} + left: 0; + top: 0; + width: 40px; + height: 100%; + color: #fff; + background-color: #c09853; + text-align: center; + display: block; +} +.ui-pnotify-container.alert-success .ui-pnotify-icon { background-color: #468847 } +.ui-pnotify-container.alert-info .ui-pnotify-icon { background-color: #3a87ad } +.ui-pnotify-container.alert-error .ui-pnotify-icon { background-color: #b94a48 } -.ui-pnotify-icon span { - font-size: 18px; +.ui-pnotify-icon > .fa { + font-size: 16px; + line-height: 16px; + margin: 0; + color: #fff; + opacity: 0.87; + float: none; + position: relative; + top: 50%; + margin-top: -8px; } .ui-pnotify-title { - margin-bottom: 5px !important; + margin-bottom: 0 !important; +} + +.ui-pnotify .ui-pnotify-text { + padding-top: 10px; + padding-bottom: 10px; + max-height: 500px; + overflow: auto; + position: relative; } .ui-pnotify-closer, .ui-pnotify-sticker { width: 16px; - opacity: .5; - filter: alpha(50); - text-shadow: 0 1px 0 rgba(255,255,255, 1); + opacity: .35; + filter: alpha(35); + margin: 0; + padding-left: 2px; + position: relative; + top: -5px; + left: 5px; } .ui-pnotify-closer:hover, .ui-pnotify-sticker:hover { - opacity: 1; - filter: alpha(100); + opacity: .75; + filter: alpha(75); } -/* codehint: sm-add */ -.ui-pnotify.stack-bottomright { - /* These are just CSS default values to reset the pnotify CSS. */ +.ui-pnotify.stack-topcenter, +.ui-pnotify.stack-bottomcenter { + left: 50% !important; + margin-left: -250px !important; +} + +.ui-pnotify.stack-bottomcenter { + top: auto; +} + +/*.ui-pnotify.stack-bottomright { right: auto; top: auto; left: auto; bottom: auto; -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.icons.css b/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.icons.css index 65b56c7dfe..854f93a29f 100644 --- a/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.icons.css +++ b/src/Presentation/SmartStore.Web/Content/jquery.pnotify.default.icons.css @@ -9,14 +9,13 @@ Description: */ .ui-pnotify .picon { -background-color: transparent; -background-repeat: no-repeat; -background-position: center center; -width: 17px; -height: 17px; + background-color: transparent; + background-repeat: no-repeat; + background-position: center center; + width: 17px; + height: 17px; } .ui-pnotify-title { - /* codehint: sm-edit */ font-size: 15px; line-height: 20px; min-height: 20px; diff --git a/src/Presentation/SmartStore.Web/Content/print.css b/src/Presentation/SmartStore.Web/Content/print.css new file mode 100644 index 0000000000..5bb7c5a6dd --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/print.css @@ -0,0 +1,304 @@ +body { + width: 100% !important; + margin: 0; + padding: 0; + color: #000; + background: none; + font-size: 13pt; + line-height: 1.45em; + font-family: Arial, sans-serif; +} +body.screen { + font-size: 14px; +} + +/* Headings */ +h1, h2, h3, h4, h5, h6 { + page-break-after: avoid; +} +h1 { font-size: 1.5em; } +h2 { font-size: 1.3em; } +h3 { font-size: 1.2em; } +h4, +h5, +h6 { font-size: 1.1em; } + + +p, h2, h3 { orphans: 3; widows: 3; } + +code { font: 0.9em Courier, monospace; } +blockquote { margin: 1.2em; padding: 1em; font-size: 0.9em; } +hr { + box-sizing: content-box; + border: 0; + border-top: 1px solid #aaa; + margin: 10px 0; +} + +img { + max-width: 100% !important; +} +a img { border: none; } + +a:link, +a:visited { + background: transparent; + font-weight: 700; + text-decoration: underline; + color: #333; +} + +a:link[href^="http://"]:after, +a[href^="http://"]:visited:after { + content: " (" attr(href) ") "; + font-size: 0.9; +} + +abbr[title]:after { + content: " (" attr(title) ")"; +} + +/* Don't show linked images */ +a[href^="http://"] { + color: #000; +} +a[href$=".jpg"]:after, +a[href$=".jpeg"]:after, +a[href$=".gif"]:after, +a[href$=".png"]:after { + content: " (" attr(href) ") "; + display: none; +} + +/* Don't show links that are fragment identifiers, or use the `javascript:` pseudo protocol .. taken from html5boilerplate */ +a[href^="#"]:after, +a[href^="javascript:"]:after { + content: ""; +} + +img, +tr { + page-break-inside: avoid; +} + + +/* -------------------------------------------------------------- + Layout +-------------------------------------------------------------- */ + +.screen .container { + box-sizing: border-box; + width: 100%; + max-width: 1170px; + padding: 15px; + margin: 0 auto; +} + +.document:not(:last-child) { + page-break-after: always; +} + + +/* -------------------------------------------------------------- + Utils +-------------------------------------------------------------- */ + +.margin-top-10 { margin-top: 10px !important; } +.margin-top-20 { margin-top: 20px !important; } +.margin-top-30 { margin-top: 30px !important; } +.margin-top-40 { margin-top: 40px !important; } +.margin-top-50 { margin-top: 50px !important; } +.margin-top-60 { margin-top: 60px !important; } + +.margin-bottom-10 { margin-bottom: 10px !important; } +.margin-bottom-20 { margin-bottom: 20px !important; } +.margin-bottom-30 { margin-bottom: 30px !important; } +.margin-bottom-40 { margin-bottom: 40px !important; } +.margin-bottom-50 { margin-bottom: 50px !important; } +.margin-bottom-60 { margin-bottom: 60px !important; } + +.text-muted { color: #777 } +.text-left { text-align: left } +.text-center { text-align: center } +.text-right { text-align: right } + +.text-small { font-size: 0.85em; } +.text-smaller { font-size: 0.77em; } +.text-smallest { font-size: 0.69em; } + +.pull-left { float: left } +.pull-right { float: right } + +.nobr { white-space: nowrap !important } + +.clearfix:before, +.clearfix:after { + display: table; + content: " "; +} +.clearfix:after { + clear: both; +} + +/* -------------------------------------------------------------- + Tables +-------------------------------------------------------------- */ + +table { + width: 100%; + max-width: 100%; + border-spacing: 0; + border-collapse: collapse; +} + +caption { + padding-top: 8px; + padding-bottom: 8px; + text-align: left; +} + +thead { + display: table-header-group; +} + + +th, td { + vertical-align: top; + text-align: left; + line-height: 1.45em; +} + + +.table { + margin-bottom: 20px; +} + +.table tr { + border-top: 1px solid #999; +} + +.table > thead > tr { + border-bottom: 2px solid #999; +} + +.table th, +.table td { + padding: 8px; + background-color: #fff; +} + +.table > thead > tr > th { + vertical-align: bottom; +} + +.table-bordered { + border: 1px solid #999; +} +.table-bordered th, +.table-bordered td { + border-left: 1px solid #999; + border-right: 1px solid #999; +} + + +/* -------------------------------------------------------------- + Order Summary (receipts like invoice, packaging slip etc.) +-------------------------------------------------------------- */ + +.order-summary tbody td, +.order-summary tbody th { + padding-top: 12px; + padding-bottom: 12px; +} + +.order-summary > tbody > tr, +.order-summary > tfoot > tr { + border-top: none; +} + +.order-summary > tbody { + border-top: 1px solid #999; + page-break-inside: avoid; +} + +.order-summary td .attributes { + margin-left: 30px; +} + +.order-summary tr.child-row > td { + padding-top: 0; +} + +.order-summary tr.child-row > td > .associated-product { + margin-left: 30px; +} + +/* -------------------------------------------------------------- + Order address & info +-------------------------------------------------------------- */ + +.order-address { + width: 55%; + box-sizing: border-box; +} + +.order-address .header { + display: inline-block; + border-bottom: 1px solid #777; + padding-bottom: 5px; +} + +.order-info { + width: 40%; + box-sizing: border-box; + border: 1px solid #777; + padding: 10px; +} + +.order-info td { + width: 50%; +} +.order-info td.label { + font-weight: bold; +} + +/* -------------------------------------------------------------- + Order totals +-------------------------------------------------------------- */ + +.attr-caption { + font-weight: bold; +} + +.order-totals td.label { + font-weight: bold; + padding-left: 0; +} + +.order-totals td.value { + text-align: right; +} + +/* -------------------------------------------------------------- + catalog +-------------------------------------------------------------- */ + +.additional-products { + width: 45%; + float: left; + margin-top: 20px; + margin-right: 20px; + min-height: 100px; + page-break-inside: avoid; +} +.additional-products .picture { + float: left; + margin-right: 20px; + min-width: 80px; + text-align: center; +} + +.detail-picture img { + max-width: 500px !important; + /*max-height: 500px !important;*/ +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000730-apple-iphone-4s-weis.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000730-apple-iphone-4s-weis.jpg deleted file mode 100644 index c7b7632297..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000730-apple-iphone-4s-weis.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000746_apple_125.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000746_apple_125.jpeg deleted file mode 100644 index be11fa0055..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000746_apple_125.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000785-apple-iphone-5-32-gb.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000785-apple-iphone-5-32-gb.jpg deleted file mode 100644 index 9aba6b7e6a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000785-apple-iphone-5-32-gb.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000785-apple-iphone.png b/src/Presentation/SmartStore.Web/Content/samples/0000785-apple-iphone.png new file mode 100644 index 0000000000..beb92f6f5e Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/0000785-apple-iphone.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000786-apple-iphone-5-32-gb.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000786-apple-iphone-5-32-gb.jpg deleted file mode 100644 index ae87b3fb46..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000786-apple-iphone-5-32-gb.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000786-apple-iphone.png b/src/Presentation/SmartStore.Web/Content/samples/0000786-apple-iphone.png new file mode 100644 index 0000000000..b0a75e61be Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/0000786-apple-iphone.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000787-apple-iphone-5-32-gb.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000787-apple-iphone-5-32-gb.jpg deleted file mode 100644 index ff3ca9b14a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000787-apple-iphone-5-32-gb.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000787-apple-iphone.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000787-apple-iphone.jpg new file mode 100644 index 0000000000..40652847f4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/0000787-apple-iphone.jpg differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000788-apple-iphone-5-32-gb.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000788-apple-iphone-5-32-gb.jpg deleted file mode 100644 index 8dff246f75..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000788-apple-iphone-5-32-gb.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000788-apple-iphone.png b/src/Presentation/SmartStore.Web/Content/samples/0000788-apple-iphone.png new file mode 100644 index 0000000000..b1627841b2 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/0000788-apple-iphone.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000789-apple-iphone-5-32-gb.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000789-apple-iphone-5-32-gb.jpg deleted file mode 100644 index e231a0f633..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000789-apple-iphone-5-32-gb.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000789-apple-iphone.jpg b/src/Presentation/SmartStore.Web/Content/samples/0000789-apple-iphone.jpg new file mode 100644 index 0000000000..0894c2bce3 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/0000789-apple-iphone.jpg differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000898_blackberry.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000898_blackberry.jpeg deleted file mode 100644 index 50c8347334..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000898_blackberry.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000899_htc.png b/src/Presentation/SmartStore.Web/Content/samples/0000899_htc.png deleted file mode 100644 index 87c2622369..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000899_htc.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000900_lg.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000900_lg.jpeg deleted file mode 100644 index fec32fa75d..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000900_lg.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000937_best-grilling-recipes.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000937_best-grilling-recipes.jpeg deleted file mode 100644 index 6bdb6ba261..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000937_best-grilling-recipes.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000938_cooking-for-two.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000938_cooking-for-two.jpeg deleted file mode 100644 index 9b4fc2b154..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000938_cooking-for-two.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000953_dell-inspiron-one-23.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000953_dell-inspiron-one-23.jpeg deleted file mode 100644 index 82eed932cc..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000953_dell-inspiron-one-23.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000993_trekstor.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000993_trekstor.jpeg deleted file mode 100644 index 58e2073688..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000993_trekstor.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0000994_western-digital.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0000994_western-digital.jpeg deleted file mode 100644 index 68aed0358b..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0000994_western-digital.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001085_canon.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0001085_canon.jpeg deleted file mode 100644 index 247cad7f8f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001085_canon.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001086_casio.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0001086_casio.jpeg deleted file mode 100644 index 779b43dd4b..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001086_casio.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001087_panasonic.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0001087_panasonic.jpeg deleted file mode 100644 index afed07672a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001087_panasonic.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001328_certina_125.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0001328_certina_125.jpeg deleted file mode 100644 index 421ef60e3c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001328_certina_125.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001338_samsung.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0001338_samsung.jpeg deleted file mode 100644 index 10d9718d26..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001338_samsung.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001424-certina-ds-podium-big-size-herrenchronograph.jpg b/src/Presentation/SmartStore.Web/Content/samples/0001424-certina-ds-podium-big-size-herrenchronograph.jpg deleted file mode 100644 index b5a0b69bc1..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001424-certina-ds-podium-big-size-herrenchronograph.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001514_uhren.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0001514_uhren.jpeg deleted file mode 100644 index 9cdf0698ec..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001514_uhren.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/0001591_festina.jpeg b/src/Presentation/SmartStore.Web/Content/samples/0001591_festina.jpeg deleted file mode 100644 index e9ce4f5b67..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/0001591_festina.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/Dell_Logo.png b/src/Presentation/SmartStore.Web/Content/samples/Dell_Logo.png deleted file mode 100644 index 95243c36fc..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/Dell_Logo.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/acer-aspire-one.jpg b/src/Presentation/SmartStore.Web/Content/samples/acer-aspire-one.jpg deleted file mode 100644 index d895c2e894..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/acer-aspire-one.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_cell_phones.jpeg b/src/Presentation/SmartStore.Web/Content/samples/category_cell_phones.jpeg deleted file mode 100644 index 032c91c0a6..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_cell_phones.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_cellphone.png b/src/Presentation/SmartStore.Web/Content/samples/category_cellphone.png new file mode 100644 index 0000000000..bf2471f624 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_cellphone.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_computers.jpeg b/src/Presentation/SmartStore.Web/Content/samples/category_computers.jpeg deleted file mode 100644 index 5046bfbb6a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_computers.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_computers.png b/src/Presentation/SmartStore.Web/Content/samples/category_computers.png new file mode 100644 index 0000000000..f6e70dfd26 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_computers.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_desktops.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_desktops.jpg deleted file mode 100644 index e93a9d61ea..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_desktops.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_desktops.png b/src/Presentation/SmartStore.Web/Content/samples/category_desktops.png new file mode 100644 index 0000000000..4bb5505f21 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_desktops.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_digital_downloads.jpeg b/src/Presentation/SmartStore.Web/Content/samples/category_digital_downloads.jpeg deleted file mode 100644 index 4b360fe7c6..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_digital_downloads.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_digitaldownloads.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_digitaldownloads.jpg new file mode 100644 index 0000000000..06ab388542 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_digitaldownloads.jpg differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_games.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_games.jpg deleted file mode 100644 index dca41590e6..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_games.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_games.png b/src/Presentation/SmartStore.Web/Content/samples/category_games.png new file mode 100644 index 0000000000..644f53246a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_games.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_gaming.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_gaming.jpg deleted file mode 100644 index c0fb6e09f7..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_gaming.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_gaming.png b/src/Presentation/SmartStore.Web/Content/samples/category_gaming.png new file mode 100644 index 0000000000..d29055409d Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_gaming.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_gaming_accessories.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_gaming_accessories.jpg deleted file mode 100644 index d07f68ad55..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_gaming_accessories.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_gaming_accessories.png b/src/Presentation/SmartStore.Web/Content/samples/category_gaming_accessories.png new file mode 100644 index 0000000000..67dfefbf77 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_gaming_accessories.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_gift_cards.jpeg b/src/Presentation/SmartStore.Web/Content/samples/category_gift_cards.jpeg deleted file mode 100644 index 12417a7e76..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_gift_cards.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_giftcards.png b/src/Presentation/SmartStore.Web/Content/samples/category_giftcards.png new file mode 100644 index 0000000000..6acc89c44c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_giftcards.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_jeans.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_jeans.jpg deleted file mode 100644 index db3bdd0d6f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_jeans.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_jewelry.jpeg b/src/Presentation/SmartStore.Web/Content/samples/category_jewelry.jpeg deleted file mode 100644 index b67f7af988..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_jewelry.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_notebooks.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_notebooks.jpg deleted file mode 100644 index 954814bca2..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_notebooks.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_notebooks.png b/src/Presentation/SmartStore.Web/Content/samples/category_notebooks.png new file mode 100644 index 0000000000..b833828247 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_notebooks.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_shirts.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_shirts.jpg deleted file mode 100644 index c4dc7e2e53..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_shirts.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_shoes.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_shoes.jpg deleted file mode 100644 index 4fe8c731a7..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_shoes.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_software.jpg b/src/Presentation/SmartStore.Web/Content/samples/category_software.jpg deleted file mode 100644 index 6ade50cbdc..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/category_software.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/category_watches.png b/src/Presentation/SmartStore.Web/Content/samples/category_watches.png new file mode 100644 index 0000000000..1a734fd98f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/category_watches.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/iphone.png b/src/Presentation/SmartStore.Web/Content/samples/iphone.png index 2aed8ea042..d206a69510 100644 Binary files a/src/Presentation/SmartStore.Web/Content/samples/iphone.png and b/src/Presentation/SmartStore.Web/Content/samples/iphone.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-android.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-android.png new file mode 100644 index 0000000000..70af7a36c6 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-android.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-blackberry.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-blackberry.png new file mode 100644 index 0000000000..7f896ade4c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-blackberry.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-canon.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-canon.png new file mode 100644 index 0000000000..fa5abcf8ae Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-canon.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-casio.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-casio.png new file mode 100644 index 0000000000..5af767b8fd Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-casio.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-certina.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-certina.png new file mode 100644 index 0000000000..81d0e5756a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-certina.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-dell.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-dell.png new file mode 100644 index 0000000000..135bf0842c Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-dell.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/HP_Logo_2012.svg.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-hp.png similarity index 100% rename from src/Presentation/SmartStore.Web/Content/samples/HP_Logo_2012.svg.png rename to src/Presentation/SmartStore.Web/Content/samples/manufacturer-hp.png diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-htc.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-htc.png new file mode 100644 index 0000000000..902f2d0ee4 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-htc.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-lg.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-lg.png new file mode 100644 index 0000000000..b90eefa3cd Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-lg.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-microsoft.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-microsoft.png new file mode 100644 index 0000000000..b359635446 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-microsoft.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-msi.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-msi.png new file mode 100644 index 0000000000..f0d5d01bce Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-msi.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-panasonic.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-panasonic.png new file mode 100644 index 0000000000..615feb3e17 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-panasonic.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-samsung.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-samsung.png new file mode 100644 index 0000000000..11fc4c4228 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-samsung.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-trekstor.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-trekstor.png new file mode 100644 index 0000000000..3aa6598fb1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-trekstor.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer-westerndigital.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-westerndigital.png new file mode 100644 index 0000000000..3c02f36445 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer-westerndigital.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer_apple.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_apple.png new file mode 100644 index 0000000000..5c55c60676 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_apple.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer_festina.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_festina.png new file mode 100644 index 0000000000..72ed1b6d86 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_festina.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer_sony.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_sony.png new file mode 100644 index 0000000000..7e1ba52e06 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_sony.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/manufacturer_ubisoft.png b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_ubisoft.png new file mode 100644 index 0000000000..a6f27b1644 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/manufacturer_ubisoft.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/msi_logo1.jpg b/src/Presentation/SmartStore.Web/Content/samples/msi_logo1.jpg deleted file mode 100644 index abeec7a72a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/msi_logo1.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_100giftcart.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_100giftcart.jpeg deleted file mode 100644 index 231fcaca34..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_100giftcart.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_25giftcart.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_25giftcart.jpeg deleted file mode 100644 index 231fcaca34..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_25giftcart.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_50giftcart.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_50giftcart.jpeg deleted file mode 100644 index 231fcaca34..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_50giftcart.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_5giftcart.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_5giftcart.jpeg deleted file mode 100644 index 231fcaca34..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_5giftcart.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_AdidasShoe_1.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_AdidasShoe_1.jpg deleted file mode 100644 index 6523ac7b8c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_AdidasShoe_1.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_AdidasShoe_2.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_AdidasShoe_2.jpg deleted file mode 100644 index fa6ec3d4a3..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_AdidasShoe_2.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_AdobePhotoshop.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_AdobePhotoshop.jpeg deleted file mode 100644 index 0d29d67982..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_AdobePhotoshop.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_ApcUps.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_ApcUps.jpeg deleted file mode 100644 index 1323c2e9f8..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_ApcUps.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Baseball.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Baseball.jpeg deleted file mode 100644 index 33e72d4f26..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Baseball.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_BattleOfLA.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_BattleOfLA.jpeg deleted file mode 100644 index 534916f9a9..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_BattleOfLA.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_BattleOfLa_1.zip b/src/Presentation/SmartStore.Web/Content/samples/product_BattleOfLa_1.zip deleted file mode 100644 index b1111ffb63..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_BattleOfLa_1.zip and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_BestGrillingRecipes.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_BestGrillingRecipes.jpeg deleted file mode 100644 index c76f7fb3ad..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_BestGrillingRecipes.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_BestSkilletRecipes.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_BestSkilletRecipes.jpeg deleted file mode 100644 index 0bb4389d17..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_BestSkilletRecipes.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_BlackBerry.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_BlackBerry.jpeg deleted file mode 100644 index e6f5ecf335..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_BlackBerry.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamcoder.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamcoder.jpeg deleted file mode 100644 index f4b449d29f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamcoder.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_1.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_1.jpeg deleted file mode 100644 index 670adda240..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_1.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_2.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_2.jpeg deleted file mode 100644 index 34353be01a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_2.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_black.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_black.jpeg deleted file mode 100644 index 03f20f47fc..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_black.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_silver.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_silver.jpeg deleted file mode 100644 index febcc2fdeb..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_CanonCamera_silver.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Compaq.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Compaq.jpeg deleted file mode 100644 index 79dab83c58..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Compaq.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_CookingForTwo.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_CookingForTwo.jpeg deleted file mode 100644 index d365a5e5f2..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_CookingForTwo.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Corel.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Corel.jpeg deleted file mode 100644 index 38af2d8761..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Corel.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_CustomTShirt.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_CustomTShirt.jpeg deleted file mode 100644 index ae9ff4c6eb..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_CustomTShirt.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_DenimShort.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_DenimShort.jpg deleted file mode 100644 index b385b0e113..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_DenimShort.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_1.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_1.jpeg deleted file mode 100644 index af6447c685..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_1.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_2.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_2.jpeg deleted file mode 100644 index 1763c576d7..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_2.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_3.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_3.jpeg deleted file mode 100644 index a3393bdea3..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Desktops_3.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondBracelet_1.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_DiamondBracelet_1.jpg deleted file mode 100644 index db6442e572..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondBracelet_1.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondBracelet_2.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_DiamondBracelet_2.jpg deleted file mode 100644 index 1722b4d67c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondBracelet_2.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondEarrings.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_DiamondEarrings.jpg deleted file mode 100644 index 776a0e15bd..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondEarrings.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondHeart.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_DiamondHeart.jpg deleted file mode 100644 index bc4c80dfe4..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_DiamondHeart.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_EatingWell.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_EatingWell.jpeg deleted file mode 100644 index a9a6d2b352..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_EatingWell.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_EngagementRing_1.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_EngagementRing_1.jpg deleted file mode 100644 index 646382cd14..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_EngagementRing_1.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_EngagementRing_2.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_EngagementRing_2.jpg deleted file mode 100644 index 8b32814aec..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_EngagementRing_2.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Etnies.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_Etnies.jpg deleted file mode 100644 index 67198f7d85..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Etnies.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_GolfBelt.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_GolfBelt.jpeg deleted file mode 100644 index 5a8c02faa2..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_GolfBelt.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Hp506.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Hp506.jpeg deleted file mode 100644 index b28b93359c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Hp506.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion1.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion1.jpeg deleted file mode 100644 index c4ddd21a99..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion1.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion2_1.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion2_1.jpeg deleted file mode 100644 index 2817082a10..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion2_1.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion2_2.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion2_2.jpeg deleted file mode 100644 index b53aea9f6a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion2_2.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion3.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion3.jpeg deleted file mode 100644 index 33dafa51cb..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_HpPavilion3.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Kensington.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Kensington.jpeg deleted file mode 100644 index a9118d95d4..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Kensington.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_LeatherHandbag_1.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_LeatherHandbag_1.jpg deleted file mode 100644 index 2a571a81cd..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_LeatherHandbag_1.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_LeatherHandbag_2.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_LeatherHandbag_2.jpg deleted file mode 100644 index fe3ed5b1de..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_LeatherHandbag_2.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_LeviJeans_1.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_LeviJeans_1.jpg deleted file mode 100644 index 07d37b98ec..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_LeviJeans_1.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_LeviJeans_2.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_LeviJeans_2.jpg deleted file mode 100644 index 448f58f249..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_LeviJeans_2.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_MedalOfHonor.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_MedalOfHonor.jpeg deleted file mode 100644 index 431d920e87..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_MedalOfHonor.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Mouse.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Mouse.jpeg deleted file mode 100644 index 791d505799..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Mouse.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Notebooks.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Notebooks.jpeg deleted file mode 100644 index c445114c2b..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Notebooks.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace.jpeg deleted file mode 100644 index 9791bd6e5a..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace_1.zip b/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace_1.zip deleted file mode 100644 index b1111ffb63..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace_1.zip and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace_2.txt b/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace_2.txt deleted file mode 100644 index d5420f50b9..0000000000 --- a/src/Presentation/SmartStore.Web/Content/samples/product_PokerFace_2.txt +++ /dev/null @@ -1 +0,0 @@ -Example: This is a sample download \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_RockabillyPolka.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_RockabillyPolka.jpg deleted file mode 100644 index 8a082b595f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_RockabillyPolka.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_SamsungPhone_1.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_SamsungPhone_1.jpeg deleted file mode 100644 index 5867616ae1..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_SamsungPhone_1.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_SamsungPhone_2.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_SamsungPhone_2.jpeg deleted file mode 100644 index 6b3fcbcfbf..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_SamsungPhone_2.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies.jpeg deleted file mode 100644 index da8c307144..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies_1.zip b/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies_1.zip deleted file mode 100644 index b1111ffb63..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies_1.zip and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies_2.txt b/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies_2.txt deleted file mode 100644 index d5420f50b9..0000000000 --- a/src/Presentation/SmartStore.Web/Content/samples/product_SingleLadies_2.txt +++ /dev/null @@ -1 +0,0 @@ -Example: This is a sample download \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Soccer.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_Soccer.jpeg deleted file mode 100644 index 5e99314375..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Soccer.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_SonyCamcoder.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_SonyCamcoder.jpeg deleted file mode 100644 index 9e38c3497d..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_SonyCamcoder.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_Sunglasses.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_Sunglasses.jpg deleted file mode 100644 index 0a66d2726f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_Sunglasses.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_aceraspiresl1500.png b/src/Presentation/SmartStore.Web/Content/samples/product_aceraspiresl1500.png new file mode 100644 index 0000000000..000927614e Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_aceraspiresl1500.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_arrow.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_arrow.jpg deleted file mode 100644 index 1c4699a959..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_arrow.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_asuspc1000.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_asuspc1000.jpeg deleted file mode 100644 index 7e906ed097..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_asuspc1000.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_asuspc900.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_asuspc900.jpeg deleted file mode 100644 index 1265d90c40..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_asuspc900.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_bestgrillingrecipes.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_bestgrillingrecipes.jpg new file mode 100644 index 0000000000..0334788cd1 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_bestgrillingrecipes.jpg differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_certina_ds_podium_big.png b/src/Presentation/SmartStore.Web/Content/samples/product_certina_ds_podium_big.png new file mode 100644 index 0000000000..7df48d65bb Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_certina_ds_podium_big.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_cookingfortwo.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_cookingfortwo.jpg new file mode 100644 index 0000000000..437949ad2f Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_cookingfortwo.jpg differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_dellinspiron23.png b/src/Presentation/SmartStore.Web/Content/samples/product_dellinspiron23.png new file mode 100644 index 0000000000..b48ef29b6a Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_dellinspiron23.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_giftcart.png b/src/Presentation/SmartStore.Web/Content/samples/product_giftcart.png new file mode 100644 index 0000000000..a6a00b22c8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_giftcart.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_hat.jpg b/src/Presentation/SmartStore.Web/Content/samples/product_hat.jpg deleted file mode 100644 index c235aa65c7..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_hat.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_playstation3dualshock3.png b/src/Presentation/SmartStore.Web/Content/samples/product_playstation3dualshock3.png new file mode 100644 index 0000000000..2eaa94c448 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_playstation3dualshock3.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_productPanasonic.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_productPanasonic.jpeg deleted file mode 100644 index 091d8ba215..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_productPanasonic.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_sony_dualshock4_wirelesscontroller.png b/src/Presentation/SmartStore.Web/Content/samples/product_sony_dualshock4_wirelesscontroller.png new file mode 100644 index 0000000000..9172cc2186 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_sony_dualshock4_wirelesscontroller.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps3_black.png b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps3_black.png new file mode 100644 index 0000000000..f92800cca8 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps3_black.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps3_plus_game.png b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps3_plus_game.png new file mode 100644 index 0000000000..32e2c2a753 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps3_plus_game.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4.png b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4.png new file mode 100644 index 0000000000..5e0aee3a67 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4_bundle.png b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4_bundle.png new file mode 100644 index 0000000000..31bb5266a0 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4_bundle.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4_camera.png b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4_camera.png new file mode 100644 index 0000000000..403f0242d9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/product_sony_ps4_camera.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/product_wow.jpeg b/src/Presentation/SmartStore.Web/Content/samples/product_wow.jpeg deleted file mode 100644 index f17104d24d..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/product_wow.jpeg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-Dualshock3WirelessCont.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-Dualshock3WirelessCont.jpg deleted file mode 100644 index 365ce8ddde..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-Dualshock3WirelessCont.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-Dualshock4WirelessCont.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-Dualshock4WirelessCont.jpg deleted file mode 100644 index ca7a60cccb..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-Dualshock4WirelessCont.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-PS3AssassinsCreedBundle.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-PS3AssassinsCreedBundle.jpg deleted file mode 100644 index cc6a737d76..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-PS3AssassinsCreedBundle.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-PS3AssassinsCreedBundle.png b/src/Presentation/SmartStore.Web/Content/samples/sony-PS3AssassinsCreedBundle.png new file mode 100644 index 0000000000..856f154db9 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Content/samples/sony-PS3AssassinsCreedBundle.png differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-logo.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-logo.jpg deleted file mode 100644 index 2f39e83b98..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-logo.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-ps3-black.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-ps3-black.jpg deleted file mode 100644 index 466ccb335c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-ps3-black.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-ps3-plus-game.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-ps3-plus-game.jpg deleted file mode 100644 index d3550e6b34..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-ps3-plus-game.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-ps4-bundle.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-ps4-bundle.jpg deleted file mode 100644 index 115e53a71d..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-ps4-bundle.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-ps4-camera.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-ps4-camera.jpg deleted file mode 100644 index f7707e927e..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-ps4-camera.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/sony-ps4.jpg b/src/Presentation/SmartStore.Web/Content/samples/sony-ps4.jpg deleted file mode 100644 index 558034bc18..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/sony-ps4.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/samples/ubisoft-logo.jpg b/src/Presentation/SmartStore.Web/Content/samples/ubisoft-logo.jpg deleted file mode 100644 index fb4a743012..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/samples/ubisoft-logo.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/smartstore.entitypicker.css b/src/Presentation/SmartStore.Web/Content/smartstore.entitypicker.css new file mode 100644 index 0000000000..2c821195fb --- /dev/null +++ b/src/Presentation/SmartStore.Web/Content/smartstore.entitypicker.css @@ -0,0 +1,124 @@ +/* -------------------------------------------------------------- + SmartStore Component: smartstore.entitypicker.css +-------------------------------------------------------------- */ + +.entity-picker-list { + position: relative; + margin-left: -5px; + margin-right: -5px; +} + +.entity-picker-list .item-wrap { + position: relative; + box-sizing: border-box; + display: block; + float: left; + width: 33.3332%; + padding: 0 5px; +} + +.entity-picker-list .item { + position: relative; + box-sizing: border-box; + display: block; + height: 70px; + padding: 8px; + margin: 5px 0; + border-radius: 3px; +} +.entity-picker-list .item:not(.disable):hover { + cursor: pointer; +} +.entity-picker-list .item:not(.selected):hover { + background-color: #f5f5f5; +} + +.entity-picker-list .disable { + opacity: 0.4; +} + +.entity-picker-list .title { + font-weight: 400; + max-height: 36px; + overflow: hidden; + text-overflow: ellipsis; +} + +.entity-picker-list .highlight { + font-weight: 700; +} + +.entity-picker-list .summary { + color: #aaa; + font-size: 12px; + height: 18px; + line-height: 18px; + vertical-align: middle; + overflow: hidden; +} +.entity-picker-list .published { + margin-left: 1px; + margin-right: 6px; + font-size: 15px; + line-height: 18px; + vertical-align: sub; +} +.entity-picker-list .published.fa-globe { + color: inherit; +} +.entity-picker-list .published.fa-eye-slash { + color: #aaa; +} +.entity-picker-list .item.selected .published { + color: #fff; +} + +.entity-picker-list .list-footer { + clear: both; + padding: 12px; + text-align: center; +} + +.entity-picker-list .thumb, +.entity-picker-list .data { + position: relative; + box-sizing: border-box; + display: block; +} +.entity-picker-list .thumb { + display: table-cell; + width: 54px; + height: 54px; + max-width: 54px; + max-height: 54px; + padding: 2px; + text-align: center; + vertical-align: middle; +} +.entity-picker-list .item:hover .thumb, +.entity-picker-list .item.selected .thumb { + background: #fff; + box-shadow: 1px 1px 2px rgba(0,0,0, 0.1); +} +.entity-picker-list .thumb img { + max-width: 100%; + max-height: 100%; +} +.entity-picker-list .thumb + .data { + position: absolute; + left: 72px; + right: 8px; + top: 8px; + bottom: 8px; +} + +.entity-picker-list .item.selected { + background-color: #4060c0; +} +.entity-picker-list .item.selected .title { + color: #fff; +} +.entity-picker-list .item.selected .summary { + color: rgba(255,255,255, 0.6); +} + diff --git a/src/Presentation/SmartStore.Web/Content/smartstore.smartgallery.css b/src/Presentation/SmartStore.Web/Content/smartstore.smartgallery.css index 14c88cf663..3ab48b4a6b 100644 --- a/src/Presentation/SmartStore.Web/Content/smartstore.smartgallery.css +++ b/src/Presentation/SmartStore.Web/Content/smartstore.smartgallery.css @@ -9,8 +9,9 @@ } .sg-image-wrapper { + position: relative !important; width: 100%; - height: 250px; /* just to avoid page load flickering. This is overwritten per inline css anyway */ + min-height: 300px; /* just to avoid page load flickering. This is overwritten per inline css anyway */ margin-bottom: 5px; position: relative; overflow: hidden; @@ -25,22 +26,31 @@ .sg-loader { position: absolute; z-index: 10; - top: 48%; - left: 48%; - border: 1px solid #CCC; + left: 0; + top: 0; + right: 0; + bottom: 0; } - .sg-image { position: absolute; overflow: hidden; top: 0; left: 0; + height: 300px; + max-width: 100%; /*z-index: 9;*/ } +.sg-image a { + display: inline-block; + max-width: 100%; +} + .sg-image a img { border: 0; + max-height: 100%; + max-width: 100%; } .sg-image-description { @@ -68,26 +78,28 @@ width: 100%; position: relative; overflow: hidden; + opacity: 0; /* avoids flickering */ } .sg-thumbs { position: relative; overflow-x: hidden; - margin: 0; + margin: 0 auto; } .sg-thumb-list { position: relative; float: left; - width: 9000px; + width: 5000px; + height: 60px; list-style: none; margin: 0; padding: 0; } -.sg-nav.has-buttons .sg-thumb-list { - padding-left: 19px; - padding-right: 19px; +.sg-nav.has-buttons .sg-thumbs { + margin-left: 19px; + margin-right: 19px; } .sg-thumb-list li { @@ -97,41 +109,50 @@ border: 0; outline: 0; float: left; - padding: 0 2px; + padding: 0; + margin-left: -1px; +} +.sg-thumb-list li:first-child { + margin-left: 0; } .sg-thumb-list li a { + position: relative; + z-index: 0; display: block; - border: 1px solid #d5d5d5; + border: 1px solid #ddd; + background-color: #fff; outline: none; - text-align: center; - opacity: .7; - filter: Alpha(70); + overflow: hidden; -webkit-transition: all 0.1s ease-in; - -moz-transition: all 0.1s ease-in; - -ms-transition: all 0.1s ease-in; -o-transition: all 0.1s ease-in; transition: all 0.1s ease-in; - - /* TODO: dynamic */ - min-width: 52px; - min-height: 52px; + + box-sizing: border-box; + width: 60px; + height: 60px; + line-height: 52px; + text-align: center; vertical-align: middle; } .sg-thumb-list li a:hover, .sg-thumb-list li a.sg-active { - opacity: 1; - filter: Alpha(100); border-color: #999; + z-index: 1; +} + +.sg-thumb-list li a > img { + margin: 3px; + max-width: 52px; + max-height: 52px; } .sg-scroll-back, .sg-scroll-forward { position: absolute; -webkit-box-shadow: 0 0 4px rgba(0,0,0, .15); - -moz-box-shadow: 0 0 4px rgba(0,0,0, .15); box-shadow: 0 0 4px rgba(0,0,0, .15); z-index: 30; height: 100%; @@ -175,7 +196,6 @@ .zoomWindow, .zoomLens { -webkit-box-shadow: 0 0 10px rgba(0,0,0, 0.4); - -moz-box-shadow: 0 0 10px rgba(0,0,0, 0.4); box-shadow: 0 0 10px rgba(0,0,0, 0.4); display: none; } diff --git a/src/Presentation/SmartStore.Web/Content/test/logo.png b/src/Presentation/SmartStore.Web/Content/test/logo.png deleted file mode 100644 index 9c556c3eb9..0000000000 Binary files a/src/Presentation/SmartStore.Web/Content/test/logo.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Content/theme.common.less b/src/Presentation/SmartStore.Web/Content/theme.common.less deleted file mode 100644 index ea9ddb1c68..0000000000 --- a/src/Presentation/SmartStore.Web/Content/theme.common.less +++ /dev/null @@ -1,1061 +0,0 @@ - -/* Mixins -================================================ */ - -.hr() { - border-top: 1px solid #ddd; - &:first-child { - border-top: none; - } -} - - -/* General -================================================ */ - -select { - min-width: initial; -} - -legend { - color: #acacac; -} - -// required for placeholder plugin (< IE10) -input.placeholder { - color: @grayLight !important; -} - -.control-group.buttons { - padding-top: 20px; -} - -body.popup { - margin: 0; - padding: 0; - border: 0; -} - -body.print { - background: #fff !important; -} - -nav ul, nav li { - margin: 0; - padding: 0; - list-style-type: none; -} - -// Hide only visually, but have it available for screenreaders: by Jon Neal. -.hidden-accessible { - border: 0; - clip: rect(0,0,0,0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px -} - -.nobr { - white-space: nowrap !important; -} -.wrap { - white-space: normal !important; -} - -.clear { - border: medium none; - clear: both; - float: none; - font-size: 0; - height: 0; - line-height: 0; -} - - -/* Validation & Errors -================================================ */ - -.message-error { - .small(); - color: @red; -} -.message-error ul { - padding: 0px; -} -.message-error ul li { - list-style: none; -} - -.message-error, -.validation-summary-errors, -.field-validation-error, -.required { - .small(); - color: @red; -} - - -/* Shopbar -================================================ */ - -#shopbar { - overflow: visible; - position: fixed; - top: 0; - left: 0; - right: 0; - .small(); - z-index: 1000; -} - -#shopbar.sticky { - .opacity(75); - &:hover { - .opacity(100); - } -} - -#shopbar form { - margin: 0; -} - -#shopbar .form-search { - margin-right: 8px; - padding: 8px 0; -} - -#shopbar-account .shopbar-flyout-container .register { - text-align: center; -} -#shopbar-account .shopbar-flyout-container [class^="icon-"] { - font-size: 16px; -} - -.shopbar-flyout { - padding: 10px; - -webkit-transform: translateZ(0); -} - -.shopbar-button { - display: block; - text-decoration: none; - line-height: 14px; -} - -.shopbar-divider { - float: right; - height: 28px; - width: 1px; - background-color: rgba(0,0,0, .15); - margin: 8px; - padding: none; -} - -.shopbar-button-label { - position: relative; - display: inline-block; -} - -.shopbar-tool { - position: relative; - padding: 8px 0; -} - -.shopbar-tool.open .shopbar-flyout { - visibility: visible; - .opacity(100); -} - -.shopbar-tool.open .dropdown-menu { - display: block; - margin: 0; - text-shadow: none; -} - -.shopbar-tool .shopbar-button-icon { - position: relative; - display: inline-block; - margin: 2px 4px 0 0; - width: 24px; - height: 24px; - - span.label { - position: absolute; - left: -3px; - top: -3px; - font-size: 11px; - padding-top: 1px; - padding-bottom: 1px; - } -} - -.shopbar-tool [class^="sm-icon-"] { - display: inline-block; - width: 24px; - height: 24px; - font-size: 24px; - font-style: normal; - margin-top: 5px; -} - -.shopbar-button [class^="icon-"] { - font-size: 12px; -} - -.shopbar-button .sm-arrow, -.shopbar-button .sm-arrow:after { - position: absolute; - display: inline-block; - width: 0; - height: 0; - border-style: solid; - border-color: transparent; - - left: 50%; - bottom: 0; - border-top: 0; -} - -.shopbar-button .sm-arrow { - border-width: 8px; - z-index: 1002; - visibility: hidden; - margin-left: -8px; -} - -.shopbar-button .sm-arrow:after { - content: ""; - border-width: 7px; - bottom: -8px; - z-index: 1001; - margin-left: -7px; -} - -.shopbar-tool.open .sm-arrow { - visibility: visible; -} - -/* taken from bootstrap */ -.shopbar-flyout { - position: absolute; - visibility: hidden; - .opacity(0); - top: 100%; - left: 0; - z-index: @zindexDropdown; - float: left; - min-width: 320px; - max-width: 420px; - padding: 5px 0; - margin: 0; - list-style: none; - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; - - height: 50px; - min-height: 50px; - background-image: none; - background-position: 50% 50%; - background-repeat: no-repeat; - - .shopbar-tool.loading & > * { - display: none; - } - - .shopbar-tool.loaded & { - height: auto; - } - - // Dividers (basically an hr) within the dropdown - .divider { - .nav-divider(@dropdownDividerTop, @dropdownDividerBottom); - } - - // Links within the dropdown menu - a { - font-weight: normal; - line-height: @baseLineHeight; - white-space: nowrap; - } -} - -.shopbar-tool .shopbar-flyout, -.shopbar-tool .shopbar-flyout-container { - margin-top: -1px !important; -} - -// Aligns the dropdown menu to right -.pull-right .shopbar-flyout, -.pull-right .shopbar-flyout-container { - right: 0; - left: auto; -} - -#shopbar-flyout-cart { - width: 340px; -} - -#shopbar-flyout-wishlist { - width: 340px; -} - -#shopbar-flyout-account { - width: 250px; -} - -.shopbar-flyout-inner { - position: relative; - min-height: 50px; -} - -.shopbar-flyout-inner .no-items { - position: absolute; - left: 0; - right: 0; - top: 50%; - margin: -(@baseLineHeight / 2) 10px 0 10px; - text-align: center; -} - -.shopbar-flyout-inner .items { - padding: 0; - margin: 0; - .smaller(); -} - -.shopbar-flyout-inner .price { - text-align: right; -} - -.shopbar-flyout-inner .items .item { - position: relative; - padding: 8px 20px; - margin: 0; - - .picture { - display: inline-block; - text-align: center; - margin: 0; - margin-right: 4px; - width: 32px; - - img { - max-width: 32px; - max-height: 50px - } - } - - .quantity { - width: 25px; - margin-left: 5px; - .times { - font-size: .9em; - } - } - - .data { - width: 160px; - overflow: hidden; - .text-overflow(); - } - - .data .name { - /* */ - } - - .data .attributes { - white-space: initial; - line-height: 12px; - } - - &.no-thumb .data { - width: 180px; - } - - .action { - padding-left: 4px; - i { font-size: 11px } - } - - .price { - width: 70px; - } - - .remove { - position: absolute; - right: 4px; - top: 8px; - .opacity(0); - } - - &:hover .remove { - .opacity(50); - } - - .remove:hover { - .opacity(100) - } -} - -#shopbar-flyout-wishlist .shopbar-flyout-inner .items .item { - .data { width: 136px } - &.no-thumb .data { width: 176px } -} - -#shopbar-flyout-compare .shopbar-flyout-inner .items .item { - .figure { margin-right: 8px } - .data { width: 170px } -} - -.shopbar-flyout-inner .summary { - padding: 12px 20px; -} - -.shopbar-flyout-inner .buttons { - padding: 20px 20px 12px 20px; -} - -#shopbar-flyout-account .shopbar-flyout-inner { - padding: 10px 20px; -} - - -/* Header -================================================ */ - -#header { - position: relative; - padding: 46px 0 0 0; -} - -#logobar { - position: relative; - padding: 10px 0; - min-height: 50px; -} - -#logobar .brand { - float: left; - display: block; - position: relative; - text-decoration: none; - font-size: 26px; - line-height: 26px; - font-family: @headingsFontFamily; - font-weight: @headingsFontWeight; -} - -.ie8 #logobar img { - max-width: auto; -} - -#nav-home li { - float: left; -} - -#nav-home li a { - display: block; -} - -.regional-selector li { - float: left; -} - -.regional-selector li .regional-label { - display: block; -} - - -/* Navigations -================================================ */ - -.block-category-navigation.block.block-bordered .listbox { - padding-top: 0; - padding-bottom: 0; -} - -.block-category-navigation ul, -.block-account-navigation ul { - .small(); - margin: 0 0 0 0.4em; -} - -.block-category-navigation ul ul, -.block-account-navigation ul ul { - margin-left: 1.1em -} - -/* deeper hierarchy fonts are smaller */ -.block-category-navigation ul > li > ul, -.block-account-navigation ul > li > ul { .smaller() } - -.block-category-navigation ul > li > ul > li, -.block-account-navigation ul > li > ul > li { line-height: 16px } - -.block-category-navigation ul > li > ul ul, -.block-account-navigation ul > li > ul ul { font-size: 1em } - -.nav-category > ul > li, -.block-account-navigation .listbox > ul > li { - a { - display: inline-block; - padding: .3em 0; - } - - .active { - font-weight: bold; - color: inherit; - } -} - -.nav-category > ul li.expanded > a, -.block-account-navigation .listbox > ul li.expanded > a { - font-weight: bold; -} - - -/* Content -================================================ */ - -#content-wrapper, -#content-body, -#footer { - position: relative; -} - -#footer .theme-selector form { - margin: 0; -} - -.page.order-list-page .buttons .btn, -.page.address-list-page .btn { - margin: 5px 0; -} - -.page.address-list-page .address-item label { - display: inline; -} - - - -/* Data Lists -================================================ */ - -.data-list .thumbnail .caption { - padding: 4px; -} -.data-list { } -.data-list-grid { } -.data-list-grid .data-list-row, -.data-list .data-list-item { - margin-bottom: 12px; -} - - -/* Item Box -================================================ */ - -.item-box { - position: relative; - .small(); -} - -.item-box.no-border { - border-color: transparent; - .box-shadow(0 0 0 rgba(0,0,0,.0)); -} - -.item-box.product-compact { - .small(); - text-align: center; -} - -.item-box .name { - font-family: inherit; - font-weight: normal; - font-size: inherit; - line-height: inherit; - overflow: hidden; - margin-bottom: 0.3em; - margin-top: 0; -} - -.item-box .name .label.label-isnew { - font-size: 10px; - line-height: 10px; - font-weight: normal; - text-shadow: none; - text-transform: uppercase; -} - -.item-box.details .name { - margin-top: 10px; -} - -.item-box figure.picture { - position: relative; - z-index: 0; - padding: 4px; - text-align: center; - margin: 0; - min-height: 100px; -} - -.item-box figure.picture a { - display: inline-block; - position: relative; - z-index: 0; -} - -.item-box figure.picture .colors { - position: absolute; - left: 4%; - right: 4%; - bottom: 3px; - z-index: 1; - .opacity(0); - text-align: center; - line-height: 6px; - font-size: 0; - overflow: hidden; -} - -.item-box:hover figure.picture .colors { - .opacity(100); -} - -.item-box.details figure.picture .colors { - position: relative; - .opacity(50); - top: 12px; - bottom: auto; - text-align: left; -} - -.item-box figure.picture .colors > span { - display: inline-block; - width: 6px; - height: 6px; - margin-right: 3px; - border: 1px solid rgba(0,0,0,.3); - *border-color: #aaa; -} - -.item-box .data { - padding: 8px; -} - -.item-box .description a[rel=tooltip] { - color: inherit; - text-decoration: none; -} - -.item-box .buttons { - text-align: center; - margin-top: 10px; -} - - -/* Product list scroller -================================================ */ - -.product-list.scroll { - position: relative; -} - -.product-list .pl-slider { - overflow: hidden; - position: relative; -} - -.product-list.scroll .pl-row { - width: 30000px; -} - -.product-list.scroll .pl-controls { - text-align: center !important; -} - -.product-list.scroll .pl-forward, -.product-list.scroll .pl-backward { - display: inline-block; - margin-right: 5px; -} - -.product-list.scroll .pl-scroll-prev, -.product-list.scroll .pl-scroll-next{ - position: absolute; -} - - -/* Paginator -================================================ */ - -.pagination .pager-nav { - padding-left: 6px; - padding-right: 6px; - - i { - /* to apply the correct size to the icon (small, large etc.) */ - font-size: inherit; - line-height: inherit; - max-height: @baseLineHeight; - } -} -.pagination .active { - font-weight: bold -} -.pagination .shrinked span { - border-top: none; - border-bottom: none; - border-left: none; - padding-left: 4px; - padding-right: 4px -} -.pagination .pagination-summary { - display: inline-block; - font-weight: bold; - padding: 4px 1em 4px 0; -} - - -/* Blocks & Containers -================================================ */ - -.block { - margin: 12px 0 24px 0; -} - -.block.topic-html-content { - margin-top: 12px; - margin-bottom: 12px; -} - -.block .block-title, -.section-title, -fieldset > legend { - padding-bottom: 8px; - - & > * { - // probably h1-h6 - font-family: inherit; - font-weight: inherit; - color: inherit; - margin: 0; - padding: 0; - } -} - -.block .block-body { - padding: 16px 0; -} - - - -/* Ratings -================================================ */ - -.rating { - display: inline-block; - vertical-align: top; - height: 16px; - width: 80px; - padding: 2px 0; - background-image: url('images/star-off.png'); - background-repeat: repeat-x; - background-position: 0 50%; -} - -.rating > div { - height: 16px; - background-image: url('images/star-on.png'); -} - -.rating.rating-small { - height: 11px; - width: 60px; - padding: 1px 0; - background-image: url('images/star-off-12.png'); -} - -.rating.rating-small > div { - height: 11px; - background-image: url('images/star-on-12.png'); -} - - -/* Code -================================================ */ - -.csharpcode, -.csharpcode pre { font-size: small; color: #000; background-color: #fff; } -.csharpcode pre { margin: 0; } -.csharpcode .rem { color: green; } -.csharpcode .kwrd { color: #00f; } -.csharpcode .str { color: #006080; } -.csharpcode .op { color: #0000c0; } -.csharpcode .preproc { color: #c63; } -.csharpcode .asp { background-color: #ff0; } -.csharpcode .html { color: maroon; } -.csharpcode .attr { color: red; } -.csharpcode .alt { background-color: #f4f4f4; width:100%; margin:0; } -.csharpcode .lnum { color: #606060; } - - -/* File types -================================================ */ - -.file-type { - display: inline-block; - width: 16px; - min-width: 16px; - height: 16px; - min-height: 16px; - background: transparent url('images/file-type-icons.png') no-repeat 0 0; -} -.file-type-pdf { background-position: 0 0; } -.file-type-doc { background-position: -16px 0; } -.file-type-xls { background-position: -32px 0; } -.file-type-jpg { background-position: -48px 0; } -.file-type-swf { background-position: -64px 0; } -.file-type-mp3 { background-position: -80px 0; } -.file-type-mpg { background-position: -96px 0; } -.file-type-txt { background-position: -112px 0; } - - -/* Misc -================================================ */ - -.ajax-loader-small { - display: inline-block; - position: relative; - width: 16px; - height: 16px; - padding: 0; - margin: 0; - background: transparent url('images/ajax_loader_small.gif') 50% 50% no-repeat; -} - -#popup-content { - margin: 20px; -} - -.captcha-box { - margin-bottom: 12px; -} - -.simple-link-list-prepend > div { - padding-bottom: 5px; -} -.simple-link-list-append > div { - margin-top: 5px; -} -.simple-link-list h5 { - margin: 0; -} -.simple-link-list ul { - list-style-type: none; - margin: 0 0 10px 1px; -} -.simple-link-list li > * { - line-height: 16px; - vertical-align: middle; - margin-right: 4px; -} - -#terms-of-service-modal { - width: 650px; -} -#terms-of-service-modal .modal-body { - min-height: 300px; - overflow: hidden; -} -#iframe-terms-of-service { - min-height: 400px; -} -.addon-buttons { - clear: both; -} -.order-summary-content .base-price.muted { - font-size: .85em; -} - -.mini-button-icon { - font-size: 10px; - padding-right: 5px; -} -p.continued { - margin-bottom: 2px; -} - - - -/* PRODUCT BUNDLE ITEMS */ -.product-bundle { - .bundle-item-border { - border-top: 1px solid #ddd; - } -} - - .product-bundle .bundle-item { - margin-top: 10px; - padding-top: 10px; - - .bundle-item-attributes { - margin-top: 3px; - } - - .bundle-item-image { - float: left; - margin-right: 16px; - } - - .bundle-item-body { - display: table-cell; - } - - .bundle-item-name { - font-weight: bold; - } - - .bundle-item-price { - padding: 5px 0 5px 0; - - .product-price-without-discount, - .product-price-with-discount { - font-size: 1.1em; - } - - .older-price { - text-decoration: line-through; - color: #aaa; - } - - .base-price { - font-size: 0.85em; - } - } - - .bundle-item-description { - font-size: 12px; - line-height: 18px; - } - - .bundle-item-attribute-info { - font-size: 0.85em; - line-height: 1.45em; - } - - .bundle-item-footer { - clear: both; - padding-top: 13px; - } - } - -#AddToCart.bundled-product { - border-top: none !important; -} - -.attribute-value-image { - margin-right: 5px; - vertical-align: middle; -} -.attributes .attribute-value-image-checkbox { - float: left; -} -.attributes .image-has-value { - margin-left: 28px; -} - -.mb-bundle-pictures .icon-plus { - padding: 4px 10px 0 10px; -} - -.mb-bundle-pictures a, -.mb-bundle-pictures i { - float: left; -} -.mb-bundle-pictures img { - max-width: 24px; - max-height: 24px; -} -.bundle-item-overview-headline { - margin-bottom: 14px; - - .you-save { - padding-right: 180px; - } - - .bundle-item-price, - .bundle-item-price-single-units { - white-space: nowrap; - } - - .bundle-item-price { - color: @red; - font-weight: bold; - } - - .bundle-item-price-single-units { - text-decoration: line-through; - color: #aaa; - } - - .add-to-cart-button { - min-width: 120px !important; - } - - .add-to-cart { - padding-top: 0 !important; - float: right; - } -} -.bundle-item-overview-headline .form-inline { - text-align:right; -} -.bundle-item-overview .icon-plus { - padding: 0 5px; -} - -.table-order-products { - tbody.product-body:nth-child(odd) td { - background-color: @tableBackgroundAccent; - } - - .product-body { - border: none !important; - } - - .product-bundle-row td { - border: none !important; - } - - .bundle-item-indent { - padding-left: 70px; - } - - .product-body-bundle .bundle-item { - .bundle-item-image { - float: left; - margin-right: 16px; - } - - .bundle-item-body { - display: table-cell; - } - - .bundle-item-attribute-info { - font-size: 0.85em; - line-height: 1.45em; - margin-top: 2px; - } - } -} - -.table-order-items { - border-bottom: 1px solid #ddd; -} diff --git a/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.js b/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.js index 27452535b8..08a07404f4 100644 --- a/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.js +++ b/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.js @@ -3914,8 +3914,8 @@ Editableform based on Twitter Bootstrap }); //buttons - $.fn.editableform.buttons = ''+ - ''; + $.fn.editableform.buttons = ''+ + ''; //error classes $.fn.editableform.errorGroupClass = 'error'; @@ -4280,7 +4280,7 @@ Automatically shown in inline mode. /** @property tpl **/ - tpl:'
          ', + tpl:'
          ', /** @property inputclass @default 'input-small' @@ -4370,7 +4370,7 @@ Automatically shown in inline mode. if (this.isRTL){ this.picker.addClass('datepicker-rtl'); this.picker.find('.prev i, .next i') - .toggleClass('icon-arrow-left icon-arrow-right'); + .toggleClass('fa-arrow-left fa-arrow-right'); } $(document).on('mousedown', function (e) { // Clicked outside the datepicker, hide it @@ -5225,9 +5225,9 @@ Automatically shown in inline mode. }, headTemplate: ''+ ''+ - ''+ + ''+ ''+ - ''+ + '' + ''+ '', contTemplate: '', diff --git a/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.min.js b/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.min.js index e3a0a92f0c..f9b38983ee 100644 --- a/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.min.js +++ b/src/Presentation/SmartStore.Web/Content/x-editable/bootstrap-editable.min.js @@ -2,4 +2,4 @@ * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery * http://github.com/vitalets/x-editable * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ -(function(e){var t=function(t,n){this.options=e.extend({},e.fn.editableform.defaults,n),this.$div=e(t),this.options.scope||(this.options.scope=this)};t.prototype={constructor:t,initInput:function(){this.input=this.options.input,this.value=this.input.str2value(this.options.value)},initTemplate:function(){this.$form=e(e.fn.editableform.template)},initButtons:function(){this.$form.find(".editable-buttons").append(e.fn.editableform.buttons)},render:function(){this.$loading=e(e.fn.editableform.loading),this.$div.empty().append(this.$loading),this.initTemplate(),this.options.showbuttons?this.initButtons():this.$form.find(".editable-buttons").remove(),this.showLoading(),this.$div.triggerHandler("rendering"),this.initInput(),this.input.prerender(),this.$form.find("div.editable-input").append(this.input.$tpl),this.$div.append(this.$form),e.when(this.input.render()).then(e.proxy(function(){this.options.showbuttons||this.input.autosubmit(),this.$form.find(".editable-cancel").click(e.proxy(this.cancel,this)),this.input.error?(this.error(this.input.error),this.$form.find(".editable-submit").attr("disabled",!0),this.input.$input.attr("disabled",!0),this.$form.submit(function(e){e.preventDefault()})):(this.error(!1),this.input.$input.removeAttr("disabled"),this.$form.find(".editable-submit").removeAttr("disabled"),this.input.value2input(this.value),this.$form.submit(e.proxy(this.submit,this))),this.$div.triggerHandler("rendered"),this.showForm(),this.input.postrender&&this.input.postrender()},this))},cancel:function(){this.$div.triggerHandler("cancel")},showLoading:function(){var e,t;this.$form?(e=this.$form.outerWidth(),t=this.$form.outerHeight(),e&&this.$loading.width(e),t&&this.$loading.height(t),this.$form.hide()):(e=this.$loading.parent().width(),e&&this.$loading.width(e)),this.$loading.show()},showForm:function(e){this.$loading.hide(),this.$form.show(),e!==!1&&this.input.activate(),this.$div.triggerHandler("show")},error:function(t){var n=this.$form.find(".control-group"),r=this.$form.find(".editable-error-block"),i;if(t===!1)n.removeClass(e.fn.editableform.errorGroupClass),r.removeClass(e.fn.editableform.errorBlockClass).empty().hide();else{if(t){i=t.split("\n");for(var s=0;s").text(i[s]).html();t=i.join("
          ")}n.addClass(e.fn.editableform.errorGroupClass),r.addClass(e.fn.editableform.errorBlockClass).html(t).show()}},submit:function(t){t.stopPropagation(),t.preventDefault();var n,r=this.input.input2value();if(n=this.validate(r)){this.error(n),this.showForm();return}if(!this.options.savenochange&&this.input.value2str(r)==this.input.value2str(this.value)){this.$div.triggerHandler("nochange");return}e.when(this.save(r)).done(e.proxy(function(e){var t=typeof this.options.success=="function"?this.options.success.call(this.options.scope,e,r):null;if(t===!1){this.error(!1),this.showForm(!1);return}if(typeof t=="string"){this.error(t),this.showForm();return}t&&typeof t=="object"&&t.hasOwnProperty("newValue")&&(r=t.newValue),this.error(!1),this.value=r,this.$div.triggerHandler("save",{newValue:r,response:e})},this)).fail(e.proxy(function(e){this.error(typeof e=="string"?e:e.responseText||e.statusText||"Unknown error!"),this.showForm()},this))},save:function(t){var n=this.input.value2submit(t);this.options.pk=e.fn.editableutils.tryParseJson(this.options.pk,!0);var r=typeof this.options.pk=="function"?this.options.pk.call(this.options.scope):this.options.pk,i=!!(typeof this.options.url=="function"||this.options.url&&(this.options.send==="always"||this.options.send==="auto"&&r)),s;if(i)return this.showLoading(),s={name:this.options.name||"",value:n,pk:r},typeof this.options.params=="function"?s=this.options.params.call(this.options.scope,s):(this.options.params=e.fn.editableutils.tryParseJson(this.options.params,!0),e.extend(s,this.options.params)),typeof this.options.url=="function"?this.options.url.call(this.options.scope,s):e.ajax(e.extend({url:this.options.url,data:s,type:"POST"},this.options.ajaxOptions))},validate:function(e){e===undefined&&(e=this.value);if(typeof this.options.validate=="function")return this.options.validate.call(this.options.scope,e)},option:function(e,t){e in this.options&&(this.options[e]=t),e==="value"&&this.setValue(t)},setValue:function(e,t){t?this.value=this.input.str2value(e):this.value=e,this.$form&&this.$form.is(":visible")&&this.input.value2input(this.value)}},e.fn.editableform=function(n){var r=arguments;return this.each(function(){var i=e(this),s=i.data("editableform"),o=typeof n=="object"&&n;s||i.data("editableform",s=new t(this,o)),typeof n=="string"&&s[n].apply(s,Array.prototype.slice.call(r,1))})},e.fn.editableform.Constructor=t,e.fn.editableform.defaults={type:"text",url:null,params:null,name:null,pk:null,value:null,send:"auto",validate:null,success:null,ajaxOptions:null,showbuttons:!0,scope:null,savenochange:!1},e.fn.editableform.template='
          ',e.fn.editableform.loading='
          ',e.fn.editableform.buttons='',e.fn.editableform.errorGroupClass=null,e.fn.editableform.errorBlockClass="editable-error"})(window.jQuery),function(e){e.fn.editableutils={inherit:function(e,t){var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e,e.superclass=t.prototype},setCursorPosition:function(e,t){if(e.setSelectionRange)e.setSelectionRange(t,t);else if(e.createTextRange){var n=e.createTextRange();n.collapse(!0),n.moveEnd("character",t),n.moveStart("character",t),n.select()}},tryParseJson:function(e,t){if(typeof e=="string"&&e.length&&e.match(/^[\{\[].*[\}\]]$/))if(t)try{e=(new Function("return "+e))()}catch(n){}finally{return e}else e=(new Function("return "+e))();return e},sliceObj:function(t,n,r){var i,s,o={};if(!e.isArray(n)||!n.length)return o;for(var u=0;u").text(t).html()},itemsByValue:function(t,n,r){if(!n||t===null)return[];r=r||"value";var i=e.isArray(t),s=[],o=this;return e.each(n,function(n,u){u.children?s=s.concat(o.itemsByValue(t,u.children)):i?e.grep(t,function(e){return e==(u&&typeof u==="object"?u[r]:u)}).length&&s.push(u):t==(u&&typeof u==="object"?u[r]:u)&&s.push(u)}),s},createInput:function(t){var n,r,i,s=t.type;return s==="date"&&(t.mode==="inline"?e.fn.editabletypes.datefield?s="datefield":e.fn.editabletypes.dateuifield&&(s="dateuifield"):e.fn.editabletypes.date?s="date":e.fn.editabletypes.dateui&&(s="dateui"),s==="date"&&!e.fn.editabletypes.date&&(s="combodate")),s==="wysihtml5"&&!e.fn.editabletypes[s]&&(s="textarea"),typeof e.fn.editabletypes[s]=="function"?(n=e.fn.editabletypes[s],r=this.sliceObj(t,this.objectKeys(n.defaults)),i=new n(r),i):(e.error("Unknown type: "+s),!1)}}}(window.jQuery),function(e){var t=function(e,t){this.init(e,t)},n=function(e,t){this.init(e,t)};t.prototype={containerName:null,innerCss:null,init:function(n,r){this.$element=e(n),this.options=e.extend({},e.fn.editableContainer.defaults,r),this.splitOptions(),this.formOptions.scope=this.$element[0],this.initContainer(),this.$element.on("destroyed",e.proxy(function(){this.destroy()},this)),e(document).data("editable-handlers-attached")||(e(document).on("keyup.editable",function(t){t.which===27&&e(".editable-open").editableContainer("hide")}),e(document).on("click.editable",function(n){var r=e(n.target),i,s=[".editable-container",".ui-datepicker-header",".modal-backdrop",".bootstrap-wysihtml5-insert-image-modal",".bootstrap-wysihtml5-insert-link-modal"];for(i=0;i"),this.tip().is(this.innerCss)?this.tip().append(this.$form):this.tip().find(this.innerCss).append(this.$form),this.renderForm()},hide:function(e){if(!this.tip()||!this.tip().is(":visible")||!this.$element.hasClass("editable-open"))return;this.$element.removeClass("editable-open"),this.innerHide(),this.$element.triggerHandler("hidden",e)},innerShow:function(){},innerHide:function(){},toggle:function(e){this.container()&&this.tip()&&this.tip().is(":visible")?this.hide():this.show(e)},setPosition:function(){},save:function(e,t){this.$element.triggerHandler("save",t),this.hide("save")},option:function(e,t){this.options[e]=t,e in this.containerOptions?(this.containerOptions[e]=t,this.setContainerOption(e,t)):(this.formOptions[e]=t,this.$form&&this.$form.editableform("option",e,t))},setContainerOption:function(e,t){this.call("option",e,t)},destroy:function(){this.hide(),this.innerDestroy(),this.$element.off("destroyed"),this.$element.removeData("editableContainer")},innerDestroy:function(){},closeOthers:function(t){e(".editable-open").each(function(n,r){if(r===t||e(r).find(t).length)return;var i=e(r),s=i.data("editableContainer");if(!s)return;s.options.onblur==="cancel"?i.data("editableContainer").hide("onblur"):s.options.onblur==="submit"&&i.data("editableContainer").tip().find("form").submit()})},activate:function(){this.tip&&this.tip().is(":visible")&&this.$form&&this.$form.data("editableform").input.activate()}},e.fn.editableContainer=function(r){var i=arguments;return this.each(function(){var s=e(this),o="editableContainer",u=s.data(o),a=typeof r=="object"&&r,f=a.mode==="inline"?n:t;u||s.data(o,u=new f(this,a)),typeof r=="string"&&u[r].apply(u,Array.prototype.slice.call(i,1))})},e.fn.editableContainer.Popup=t,e.fn.editableContainer.Inline=n,e.fn.editableContainer.defaults={value:null,placement:"top",autohide:!0,onblur:"cancel",anim:"fast",mode:"popup"},jQuery.event.special.destroyed={remove:function(e){e.handler&&e.handler()}}}(window.jQuery),function(e){e.extend(e.fn.editableContainer.Inline.prototype,e.fn.editableContainer.Popup.prototype,{containerName:"editableform",innerCss:".editable-inline",initContainer:function(){this.$tip=e("").addClass("editable-inline"),this.options.anim||(this.options.anim=0)},splitOptions:function(){this.containerOptions={},this.formOptions=this.options},tip:function(){return this.$tip},innerShow:function(){this.$element.hide(),this.tip().insertAfter(this.$element).show()},innerHide:function(){this.$tip.hide(this.options.anim,e.proxy(function(){this.$element.show(),this.innerDestroy()},this))},innerDestroy:function(){this.tip()&&this.tip().empty().remove()}})}(window.jQuery),function(e){var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.editable.defaults,n,e.fn.editableutils.getConfigData(this.$element)),this.options.selector?this.initLive():this.init()};t.prototype={constructor:t,init:function(){var t=!1,n,r;this.options.name=this.options.name||this.$element.attr("id"),this.input=e.fn.editableutils.createInput(this.options);if(!this.input)return;this.options.value===undefined||this.options.value===null?(this.value=this.input.html2value(e.trim(this.$element.html())),t=!0):(this.options.value=e.fn.editableutils.tryParseJson(this.options.value,!0),typeof this.options.value=="string"?this.value=this.input.str2value(this.options.value):this.value=this.options.value),this.$element.addClass("editable"),this.options.toggle!=="manual"?(this.$element.addClass("editable-click"),this.$element.on(this.options.toggle+".editable",e.proxy(function(e){e.preventDefault();if(this.options.toggle==="mouseenter")this.show();else{var t=this.options.toggle!=="click";this.toggle(t)}},this))):this.$element.attr("tabindex",-1),n=!t&&this.value!==null&&this.value!==undefined,n&=this.options.autotext==="always"||this.options.autotext==="auto"&&!this.$element.text().length,e.when(n?this.render():!0).then(e.proxy(function(){this.options.disabled?this.disable():this.enable(),this.$element.triggerHandler("init",this)},this))},initLive:function(){var t=this.options.selector;this.options.selector=!1,this.options.autotext="never",this.$element.on(this.options.toggle+".editable",t,e.proxy(function(t){var n=e(t.target);n.data("editable")||n.editable(this.options).trigger(t)},this))},render:function(e){if(this.options.display===!1)return;return this.input.value2htmlFinal?this.input.value2html(this.value,this.$element[0],this.options.display,e):typeof this.options.display=="function"?this.options.display.call(this.$element[0],this.value,e):this.input.value2html(this.value,this.$element[0])},enable:function(){this.options.disabled=!1,this.$element.removeClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.options.toggle!=="manual"&&this.$element.attr("tabindex")==="-1"&&this.$element.removeAttr("tabindex")},disable:function(){this.options.disabled=!0,this.hide(),this.$element.addClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.$element.attr("tabindex",-1)},toggleDisabled:function(){this.options.disabled?this.enable():this.disable()},option:function(t,n){if(t&&typeof t=="object"){e.each(t,e.proxy(function(t,n){this.option(e.trim(t),n)},this));return}this.options[t]=n;if(t==="disabled")return n?this.disable():this.enable();t==="value"&&this.setValue(n),this.container&&this.container.option(t,n),this.input.option&&this.input.option(t,n)},handleEmpty:function(t){if(this.options.display===!1)return;this.isEmpty=t!==undefined?t:e.trim(this.$element.text())==="",this.options.disabled?this.isEmpty&&(this.$element.empty(),this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)):this.isEmpty?(this.$element.text(this.options.emptytext),this.options.emptyclass&&this.$element.addClass(this.options.emptyclass)):this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)},show:function(t){if(this.options.disabled)return;if(!this.container){var n=e.extend({},this.options,{value:this.value,input:this.input});this.$element.editableContainer(n),this.$element.on("save.internal",e.proxy(this.save,this)),this.container=this.$element.data("editableContainer")}else if(this.container.tip().is(":visible"))return;this.container.show(t)},hide:function(){this.container&&this.container.hide()},toggle:function(e){this.container&&this.container.tip().is(":visible")?this.hide():this.show(e)},save:function(e,t){if(this.options.unsavedclass){var n=!1;n=n||typeof this.options.url=="function",n=n||this.options.display===!1,n=n||t.response!==undefined,n=n||this.options.savenochange&&this.input.value2str(this.value)!==this.input.value2str(t.newValue),n?this.$element.removeClass(this.options.unsavedclass):this.$element.addClass(this.options.unsavedclass)}this.setValue(t.newValue,!1,t.response)},validate:function(){if(typeof this.options.validate=="function")return this.options.validate.call(this,this.value)},setValue:function(t,n,r){n?this.value=this.input.str2value(t):this.value=t,this.container&&this.container.option("value",this.value),e.when(this.render(r)).then(e.proxy(function(){this.handleEmpty()},this))},activate:function(){this.container&&this.container.activate()},destroy:function(){this.container&&this.container.destroy(),this.options.toggle!=="manual"&&(this.$element.removeClass("editable-click"),this.$element.off(this.options.toggle+".editable")),this.$element.off("save.internal"),this.$element.removeClass("editable"),this.$element.removeClass("editable-open"),this.$element.removeData("editable")}},e.fn.editable=function(n){var r={},i=arguments,s="editable";switch(n){case"validate":return this.each(function(){var t=e(this),n=t.data(s),i;n&&(i=n.validate())&&(r[n.options.name]=i)}),r;case"getValue":return this.each(function(){var t=e(this),n=t.data(s);n&&n.value!==undefined&&n.value!==null&&(r[n.options.name]=n.input.value2submit(n.value))}),r;case"submit":var o=arguments[1]||{},u=this,a=this.editable("validate"),f;return e.isEmptyObject(a)?(f=this.editable("getValue"),o.data&&e.extend(f,o.data),e.ajax(e.extend({url:o.url,data:f,type:"POST"},o.ajaxOptions)).success(function(e){typeof o.success=="function"&&o.success.call(u,e,o)}).error(function(){typeof o.error=="function"&&o.error.apply(u,arguments)})):typeof o.error=="function"&&o.error.call(u,a),this}return this.each(function(){var r=e(this),o=r.data(s),u=typeof n=="object"&&n;o||r.data(s,o=new t(this,u)),typeof n=="string"&&o[n].apply(o,Array.prototype.slice.call(i,1))})},e.fn.editable.defaults={type:"text",disabled:!1,toggle:"click",emptytext:"Empty",autotext:"auto",value:null,display:null,emptyclass:"editable-empty",unsavedclass:"editable-unsaved",selector:null}}(window.jQuery),function(e){e.fn.editabletypes={};var t=function(){};t.prototype={init:function(t,n,r){this.type=t,this.options=e.extend({},r,n)},prerender:function(){this.$tpl=e(this.options.tpl),this.$input=this.$tpl,this.$clear=null,this.error=null},render:function(){},value2html:function(t,n){e(n).text(t)},html2value:function(t){return e("
          ").html(t).text()},value2str:function(e){return e},str2value:function(e){return e},value2submit:function(e){return e},value2input:function(e){this.$input.val(e)},input2value:function(){return this.$input.val()},activate:function(){this.$input.is(":visible")&&this.$input.focus()},clear:function(){this.$input.val(null)},escape:function(t){return e("
          ").text(t).html()},autosubmit:function(){},setClass:function(){this.options.inputclass&&this.$input.addClass(this.options.inputclass)},setAttr:function(e){this.options[e]&&this.$input.attr(e,this.options[e])},option:function(e,t){this.options[e]=t}},t.defaults={tpl:"",inputclass:"input-medium"},e.extend(e.fn.editabletypes,{abstractinput:t})}(window.jQuery),function(e){var t=function(e){};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{render:function(){var t=e.Deferred();return this.error=null,this.onSourceReady(function(){this.renderList(),t.resolve()},function(){this.error=this.options.sourceError,t.resolve()}),t.promise()},html2value:function(e){return null},value2html:function(t,n,r,i){var s=e.Deferred(),o=function(){typeof r=="function"?r.call(n,t,this.sourceData,i):this.value2htmlFinal(t,n),s.resolve()};return t===null?o.call(this):this.onSourceReady(o,function(){s.resolve()}),s.promise()},onSourceReady:function(t,n){if(e.isArray(this.sourceData)){t.call(this);return}try{this.options.source=e.fn.editableutils.tryParseJson(this.options.source,!1)}catch(r){n.call(this);return}if(typeof this.options.source=="string"){if(this.options.sourceCache){var i=this.options.source,s;e(document).data(i)||e(document).data(i,{}),s=e(document).data(i);if(s.loading===!1&&s.sourceData){this.sourceData=s.sourceData,this.doPrepend(),t.call(this);return}if(s.loading===!0){s.callbacks.push(e.proxy(function(){this.sourceData=s.sourceData,this.doPrepend(),t.call(this)},this)),s.err_callbacks.push(e.proxy(n,this));return}s.loading=!0,s.callbacks=[],s.err_callbacks=[]}e.ajax({url:this.options.source,type:"get",cache:!1,dataType:"json",success:e.proxy(function(r){s&&(s.loading=!1),this.sourceData=this.makeArray(r),e.isArray(this.sourceData)?(s&&(s.sourceData=this.sourceData,e.each(s.callbacks,function(){this.call()})),this.doPrepend(),t.call(this)):(n.call(this),s&&e.each(s.err_callbacks,function(){this.call()}))},this),error:e.proxy(function(){n.call(this),s&&(s.loading=!1,e.each(s.err_callbacks,function(){this.call()}))},this)})}else e.isFunction(this.options.source)?this.sourceData=this.makeArray(this.options.source()):this.sourceData=this.makeArray(this.options.source),e.isArray(this.sourceData)?(this.doPrepend(),t.call(this)):n.call(this)},doPrepend:function(){if(this.options.prepend===null||this.options.prepend===undefined)return;e.isArray(this.prependData)||(this.options.prepend=e.fn.editableutils.tryParseJson(this.options.prepend,!0),typeof this.options.prepend=="string"&&(this.options.prepend={"":this.options.prepend}),typeof this.options.prepend=="function"?this.prependData=this.makeArray(this.options.prepend()):this.prependData=this.makeArray(this.options.prepend)),e.isArray(this.prependData)&&e.isArray(this.sourceData)&&(this.sourceData=this.prependData.concat(this.sourceData))},renderList:function(){},value2htmlFinal:function(e,t){},makeArray:function(t){var n,r,i=[],s,o;if(!t||typeof t=="string")return null;if(e.isArray(t)){o=function(e,t){r={value:e,text:t};if(n++>=2)return!1};for(var u=0;u1&&(s.children&&(s.children=this.makeArray(s.children)),i.push(s))):i.push({value:s,text:s})}else e.each(t,function(e,t){i.push({value:e,text:t})});return i},option:function(e,t){this.options[e]=t,e==="source"&&(this.sourceData=null),e==="prepend"&&(this.prependData=null)}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{source:null,prepend:!1,sourceError:"Error when loading list",sourceCache:!0}),e.fn.editabletypes.list=t}(window.jQuery),function(e){var t=function(e){this.init("text",e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{render:function(){this.renderClear(),this.setClass(),this.setAttr("placeholder")},activate:function(){this.$input.is(":visible")&&(this.$input.focus(),e.fn.editableutils.setCursorPosition(this.$input.get(0),this.$input.val().length),this.toggleClear&&this.toggleClear())},renderClear:function(){this.options.clear&&(this.$clear=e(''),this.$input.after(this.$clear).css("padding-right",20).keyup(e.proxy(this.toggleClear,this)).parent().css("position","relative"),this.$clear.click(e.proxy(this.clear,this)))},postrender:function(){if(this.$clear){var e=this.$input.outerHeight()||20,t=(e-this.$clear.height())/2;t<3&&(t=3),this.$clear.css({top:t,right:t})}},toggleClear:function(){if(!this.$clear)return;this.$input.val().length?this.$clear.show():this.$clear.hide()},clear:function(){this.$clear.hide(),this.$input.val("").focus()}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{tpl:'',placeholder:null,clear:!0}),e.fn.editabletypes.text=t}(window.jQuery),function(e){var t=function(e){this.init("textarea",e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.abstractinput),e.extend(t.prototype,{render:function(){this.setClass(),this.setAttr("placeholder"),this.setAttr("rows"),this.$input.keydown(function(t){t.ctrlKey&&t.which===13&&e(this).closest("form").submit()})},value2html:function(t,n){var r="",i;if(t){i=t.split("\n");for(var s=0;s").text(i[s]).html();r=i.join("
          ")}e(n).html(r)},html2value:function(t){if(!t)return"";var n=new RegExp(String.fromCharCode(10),"g"),r=t.split(//i);for(var i=0;i").html(r[i]).text();s=s.replace(n,""),r[i]=s}return r.join("\n")},activate:function(){e.fn.editabletypes.text.prototype.activate.call(this)}}),t.defaults=e.extend({},e.fn.editabletypes.abstractinput.defaults,{tpl:"",inputclass:"input-large",placeholder:null,rows:7}),e.fn.editabletypes.textarea=t}(window.jQuery),function(e){var t=function(e){this.init("select",e,t.defaults)};e.fn.editableutils.inherit(t,e.fn.editabletypes.list),e.extend(t.prototype,{renderList:function(){this.$input.empty();var t=function(n,r){if(e.isArray(r))for(var i=0;i",{label:r[i].text}),r[i].children)):n.append(e("
          /// True - use desktop version; false - use version for mobile devices /// Action result + [HttpPost] public ActionResult ChangeDevice(bool dontUseMobileVersion) { - _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, - SystemCustomerAttributeNames.DontUseMobileVersion, dontUseMobileVersion, _storeContext.CurrentStore.Id); + _genericAttributeService.Value.SaveAttribute( + _services.WorkContext.CurrentCustomer, + SystemCustomerAttributeNames.DontUseMobileVersion, + dontUseMobileVersion, + _services.StoreContext.CurrentStore.Id); - string returnurl = _webHelper.GetUrlReferrer(); - if (String.IsNullOrEmpty(returnurl)) - returnurl = Url.RouteUrl("HomePage"); - return Redirect(returnurl); + return RedirectToReferrer(); } + [ChildActionOnly] public ActionResult ChangeDeviceBlock() { - if (!_mobileDeviceHelper.MobileDevicesSupported()) + if (!_mobileDeviceHelper.Value.MobileDevicesSupported()) //mobile devices support is disabled return Content(""); - if (!_mobileDeviceHelper.IsMobileDevice()) + if (!_mobileDeviceHelper.Value.IsMobileDevice()) //request is made by a desktop computer return Content(""); @@ -974,65 +816,56 @@ public ActionResult RobotsTextFile() { "/bin/", "/Content/files/", - "/Content/files/exportimport/", - "/country/getstatesbycountryid", - "/install", - "/setproductreviewhelpfulness", + "/Content/files/ExportImport/", + "/Exchange/", + "/Country/GetStatesByCountryId", + "/Install", + "/Product/SetReviewHelpfulness", }; var localizableDisallowPaths = new List() { - "/addproducttocart/catalog/", - "/addproducttocart/details/", - "/boards/forumwatch", - "/boards/postedit", - "/boards/postdelete", - "/boards/postcreate", - "/boards/topicedit", - "/boards/topicdelete", - "/boards/topiccreate", - "/boards/topicmove", - "/boards/topicwatch", - "/cart", - "/checkout", - "/checkout/billingaddress", - "/checkout/completed", - "/checkout/confirm", - "/checkout/shippingaddress", - "/checkout/shippingmethod", - "/checkout/paymentinfo", - "/checkout/paymentmethod", - "/clearcomparelist", - "/compareproducts", - "/customer/avatar", - "/customer/activation", - "/customer/addresses", - "/customer/backinstocksubscriptions", - "/customer/changepassword", - "/customer/checkusernameavailability", - "/customer/downloadableproducts", - "/customer/forumsubscriptions", - "/customer/info", - "/customer/orders", - "/customer/returnrequests", - "/customer/rewardpoints", - "/deletepm", - "/emailwishlist", - "/inboxupdate", - "/newsletter/subscriptionactivation", - "/onepagecheckout", - "/orderdetails", - "/passwordrecovery/confirm", - "/poll/vote", - "/privatemessages", - "/returnrequest", - "/sendpm", - "/sentupdate", - "/subscribenewsletter", - "/topic/authenticate", - "/viewpm", - "/wishlist", - "/productaskquestion", - "/productemailafriend" + "/Boards/ForumWatch", + "/Boards/PostEdit", + "/Boards/PostDelete", + "/Boards/PostCreate", + "/Boards/TopicEdit", + "/Boards/TopicDelete", + "/Boards/TopicCreate", + "/Boards/TopicMove", + "/Boards/TopicWatch", + "/Cart", + "/Checkout", + "/Product/ClearCompareList", + "/CompareProducts", + "/Customer/Avatar", + "/Customer/Activation", + "/Customer/Addresses", + "/Customer/BackInStockSubscriptions", + "/Customer/ChangePassword", + "/Customer/CheckUsernameAvailability", + "/Customer/DownloadableProducts", + "/Customer/ForumSubscriptions", + "/Customer/DeleteForumSubscriptions", + "/Customer/Info", + "/Customer/Orders", + "/Customer/ReturnRequests", + "/Customer/RewardPoints", + "/PrivateMessages", + "/Newsletter/SubscriptionActivation", + "/Order", + "/PasswordRecovery", + "/Poll/Vote", + "/ReturnRequest", + "/Newsletter/Subscribe", + "/Topic/Authenticate", + "/Wishlist", + "/Product/AskQuestion", + "/Product/EmailAFriend", + "/Search", + "/Config", + "/Settings", + "/Login", + "/Register" }; @@ -1040,12 +873,15 @@ public ActionResult RobotsTextFile() var sb = new StringBuilder(); sb.Append("User-agent: *"); sb.Append(newLine); + sb.AppendFormat("Sitemap: {0}", Url.RouteUrl("SitemapSEO", (object)null, _securitySettings.Value.ForceSslForAllPages ? "https" : "http")); + sb.AppendLine(); + + var disallows = disallowPaths.Concat(localizableDisallowPaths); - var disallows = disallowPaths.Concat(localizableDisallowPaths); if (_localizationSettings.SeoFriendlyUrlsForLanguagesEnabled) { // URLs are localizable. Append SEO code - foreach (var language in _languageService.GetAllLanguages(storeId: _storeContext.CurrentStore.Id)) + foreach (var language in _languageService.Value.GetAllLanguages(storeId: _services.StoreContext.CurrentStore.Id)) { disallows = disallows.Concat(localizableDisallowPaths.Select(x => "/{0}{1}".FormatInvariant(language.UniqueSeoCode, x))); } @@ -1056,6 +892,9 @@ public ActionResult RobotsTextFile() // append extra disallows disallows = disallows.Concat(seoSettings.ExtraRobotsDisallows.Select(x => x.Trim())); + // Append all lowercase variants (at least Google is case sensitive) + disallows = disallows.Concat(GetLowerCaseVariants(disallows)); + foreach (var disallow in disallows) { sb.AppendFormat("Disallow: {0}", disallow); @@ -1067,33 +906,44 @@ public ActionResult RobotsTextFile() return null; } + private IEnumerable GetLowerCaseVariants(IEnumerable disallows) + { + var other = new List(); + foreach (var item in disallows) + { + var lower = item.ToLower(); + if (lower != item) + { + other.Add(lower); + } + } + + return other; + } + public ActionResult GenericUrl() { - //seems that no entity was found - return RedirectToRoute("HomePage"); + // seems that no entity was found + return HttpNotFound(); } - /// - /// codehint: sm-add - /// - /// [ChildActionOnly] public ActionResult AccountDropdown() { - var customer = _workContext.CurrentCustomer; + var customer = _services.WorkContext.CurrentCustomer; var unreadMessageCount = GetUnreadPrivateMessages(); var unreadMessage = string.Empty; var alertMessage = string.Empty; if (unreadMessageCount > 0) { - unreadMessage = T("PrivateMessages.TotalUnread", unreadMessageCount); + unreadMessage = unreadMessageCount.ToString(); //notifications here if (_forumSettings.ShowAlertForPM && - !customer.GetAttribute(SystemCustomerAttributeNames.NotifiedAboutNewPrivateMessages, _storeContext.CurrentStore.Id)) + !customer.GetAttribute(SystemCustomerAttributeNames.NotifiedAboutNewPrivateMessages, _services.StoreContext.CurrentStore.Id)) { - _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.NotifiedAboutNewPrivateMessages, true, _storeContext.CurrentStore.Id); + _genericAttributeService.Value.SaveAttribute(customer, SystemCustomerAttributeNames.NotifiedAboutNewPrivateMessages, true, _services.StoreContext.CurrentStore.Id); alertMessage = T("PrivateMessages.YouHaveUnreadPM", unreadMessageCount); } } @@ -1101,11 +951,11 @@ public ActionResult AccountDropdown() var model = new AccountDropdownModel { IsAuthenticated = customer.IsRegistered(), - DisplayAdminLink = _permissionService.Authorize(StandardPermissionProvider.AccessAdminPanel), - ShoppingCartEnabled = _permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart), - ShoppingCartItems = customer.CountProductsInCart(ShoppingCartType.ShoppingCart, _storeContext.CurrentStore.Id), - WishlistEnabled = _permissionService.Authorize(StandardPermissionProvider.EnableWishlist), - WishlistItems = customer.CountProductsInCart(ShoppingCartType.Wishlist, _storeContext.CurrentStore.Id), + DisplayAdminLink = _services.Permissions.Authorize(StandardPermissionProvider.AccessAdminPanel), + ShoppingCartEnabled = _services.Permissions.Authorize(StandardPermissionProvider.EnableShoppingCart), + ShoppingCartItems = customer.CountProductsInCart(ShoppingCartType.ShoppingCart, _services.StoreContext.CurrentStore.Id), + WishlistEnabled = _services.Permissions.Authorize(StandardPermissionProvider.EnableWishlist), + WishlistItems = customer.CountProductsInCart(ShoppingCartType.Wishlist, _services.StoreContext.CurrentStore.Id), AllowPrivateMessages = _forumSettings.AllowPrivateMessages, UnreadPrivateMessages = unreadMessage, AlertMessage = alertMessage @@ -1114,12 +964,213 @@ public ActionResult AccountDropdown() return PartialView(model); } - //store is closed - public ActionResult StoreClosed() - { - return View(); - } + [OverrideActionFilters, OverrideAuthorization] + public ActionResult PdfReceiptHeader(PdfHeaderFooterVariables vars, int storeId = 0, bool isPartial = false) + { + var model = PreparePdfReceiptHeaderFooterModel(storeId); + model.Variables = vars; - #endregion - } + ViewBag.IsPartial = isPartial; + + if (isPartial) + return PartialView(model); + return View(model); + } + + [OverrideActionFilters, OverrideAuthorization] + public ActionResult PdfReceiptFooter(PdfHeaderFooterVariables vars, int storeId = 0, bool isPartial = false) + { + var model = PreparePdfReceiptHeaderFooterModel(storeId); + model.Variables = vars; + + ViewBag.IsPartial = isPartial; + + if (isPartial) + return PartialView(model); + return View(model); + } + + protected PdfReceiptHeaderFooterModel PreparePdfReceiptHeaderFooterModel(int storeId) + { + return _services.Cache.Get("PdfReceiptHeaderFooterModel-{0}".FormatInvariant(storeId), () => + { + var model = new PdfReceiptHeaderFooterModel { StoreId = storeId }; + var store = _services.StoreService.GetStoreById(model.StoreId) ?? _services.StoreContext.CurrentStore; + + var companyInfoSettings = _services.Settings.LoadSetting(store.Id); + var bankSettings = _services.Settings.LoadSetting(store.Id); + var contactSettings = _services.Settings.LoadSetting(store.Id); + var pdfSettings = _services.Settings.LoadSetting(store.Id); + + model.StoreName = store.Name; + model.StoreUrl = store.Url; + + var logoPicture = _pictureService.Value.GetPictureById(pdfSettings.LogoPictureId); + if (logoPicture == null) + { + logoPicture = _pictureService.Value.GetPictureById(store.LogoPictureId); + } + + if (logoPicture != null) + { + model.LogoUrl = _pictureService.Value.GetPictureUrl(logoPicture, showDefaultPicture: false); + } + + model.MerchantCompanyInfo = companyInfoSettings; + model.MerchantBankAccount = bankSettings; + model.MerchantContactData = contactSettings; + + return model; + }, 1 /* 1 min. (just for the duration of pdf processing) */); + } + + #endregion + + #region Entity Picker + + public ActionResult EntityPicker(EntityPickerModel model) + { + model.PageSize = 48; // _commonSettings.EntityPickerPageSize; + model.AllString = T("Admin.Common.All"); + + if (model.Entity.IsCaseInsensitiveEqual("product")) + { + var allCategories = _categoryService.Value.GetAllCategories(showHidden: true); + var mappedCategories = allCategories.ToDictionary(x => x.Id); + + model.AvailableCategories = allCategories + .Select(x => new SelectListItem { Text = x.GetCategoryNameWithPrefix(_categoryService.Value, mappedCategories), Value = x.Id.ToString() }) + .ToList(); + + model.AvailableManufacturers = _manufacturerService.Value.GetAllManufacturers(true) + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + model.AvailableStores = _services.StoreService.GetAllStores() + .Select(x => new SelectListItem { Text = x.Name, Value = x.Id.ToString() }) + .ToList(); + + model.AvailableProductTypes = ProductType.SimpleProduct.ToSelectList(false).ToList(); + } + + return PartialView(model); + } + + [HttpPost] + public ActionResult EntityPicker(EntityPickerModel model, FormCollection form) + { + model.PageSize = 48; // _commonSettings.EntityPickerPageSize; + model.PublishedString = T("Common.Published"); + model.UnpublishedString = T("Common.Unpublished"); + + try + { + var disableIf = model.DisableIf.SplitSafe(",").Select(x => x.ToLower().Trim()).ToList(); + var disableIds = model.DisableIds.SplitSafe(",").Select(x => x.ToInt()).ToList(); + + using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, proxyCreation: true, validateOnSave: false, forceNoTracking: true)) + { + if (model.Entity.IsCaseInsensitiveEqual("product")) + { + #region Product + + model.SearchTerm = model.ProductName.TrimSafe(); + + var hasPermission = _services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog); + var storeLocation = _services.WebHelper.GetStoreLocation(false); + var disableIfNotSimpleProduct = disableIf.Contains("notsimpleproduct"); + var labelTextGrouped = T("Admin.Catalog.Products.ProductType.GroupedProduct.Label").Text; + var labelTextBundled = T("Admin.Catalog.Products.ProductType.BundledProduct.Label").Text; + var sku = T("Products.Sku").Text; + + var searchContext = new ProductSearchContext + { + CategoryIds = (model.CategoryId == 0 ? null : new List { model.CategoryId }), + ManufacturerId = model.ManufacturerId, + StoreId = model.StoreId, + Keywords = model.SearchTerm, + ProductType = model.ProductTypeId > 0 ? (ProductType?)model.ProductTypeId : null, + SearchSku = !_catalogSettings.SuppressSkuSearch, + ShowHidden = hasPermission + }; + + var query = _productService.Value.PrepareProductSearchQuery(searchContext, x => new { x.Id, x.Sku, x.Name, x.Published, x.ProductTypeId }); + + query = from x in query + group x by x.Id into grp + orderby grp.Key + select grp.FirstOrDefault(); + + var products = query + .OrderBy(x => x.Name) + .Skip(model.PageIndex * model.PageSize) + .Take(model.PageSize) + .ToList(); + + var productIds = products.Select(x => x.Id).ToArray(); + var pictures = _productService.Value.GetProductPicturesByProductIds(productIds, true); + + model.SearchResult = products + .Select(x => + { + var item = new EntityPickerModel.SearchResultModel + { + Id = x.Id, + ReturnValue = (model.ReturnField.IsCaseInsensitiveEqual("sku") ? x.Sku : x.Id.ToString()), + Title = x.Name, + Summary = x.Sku, + SummaryTitle = "{0}: {1}".FormatInvariant(sku, x.Sku.NaIfEmpty()), + Published = (hasPermission ? x.Published : (bool?)null) + }; + + if (disableIfNotSimpleProduct) + { + item.Disable = (x.ProductTypeId != (int)ProductType.SimpleProduct); + } + + if (!item.Disable && disableIds.Contains(x.Id)) + { + item.Disable = true; + } + + if (x.ProductTypeId == (int)ProductType.GroupedProduct) + { + item.LabelText = labelTextGrouped; + item.LabelClassName = "label-success"; + } + else if (x.ProductTypeId == (int)ProductType.BundledProduct) + { + item.LabelText = labelTextBundled; + item.LabelClassName = "label-info"; + } + + var productPicture = pictures.FirstOrDefault(y => y.Key == x.Id); + if (productPicture.Value != null) + { + var picture = productPicture.Value.FirstOrDefault(); + if (picture != null) + { + item.ImageUrl = _pictureService.Value.GetPictureUrl(picture.Picture, _mediaSettings.Value.ProductThumbPictureSizeOnProductDetailsPage, + !_catalogSettings.HideProductDefaultPictures, storeLocation); + } + } + + return item; + }) + .ToList(); + + #endregion + } + } + } + catch (Exception exception) + { + NotifyError(exception.ToAllMessages()); + } + + return PartialView("EntityPickerList", model); + } + + #endregion + } } diff --git a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs index 56ed9a9085..a72b4fc872 100644 --- a/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/CustomerController.cs @@ -4,15 +4,16 @@ using System.Web; using System.Web.Mvc; using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Forums; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Logging; using SmartStore.Services.Authentication; using SmartStore.Services.Authentication.External; using SmartStore.Services.Catalog; @@ -27,17 +28,18 @@ using SmartStore.Services.Orders; using SmartStore.Services.Seo; using SmartStore.Services.Tax; -using SmartStore.Web.Extensions; +using SmartStore.Utilities; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Plugins; using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.UI.Captcha; using SmartStore.Web.Models.Common; using SmartStore.Web.Models.Customer; -using SmartStore.Core.Logging; namespace SmartStore.Web.Controllers { - public partial class CustomerController : PublicControllerBase + public partial class CustomerController : PublicControllerBase { #region Fields @@ -74,12 +76,14 @@ public partial class CustomerController : PublicControllerBase private readonly IDownloadService _downloadService; private readonly IWebHelper _webHelper; private readonly ICustomerActivityService _customerActivityService; + private readonly IProductAttributeParser _productAttributeParser; private readonly MediaSettings _mediaSettings; private readonly IWorkflowMessageService _workflowMessageService; private readonly LocalizationSettings _localizationSettings; private readonly CaptchaSettings _captchaSettings; private readonly ExternalAuthenticationSettings _externalAuthenticationSettings; + private readonly PluginMediator _pluginMediator; #endregion @@ -105,9 +109,12 @@ public CustomerController(IAuthenticationService authenticationService, IOpenAuthenticationService openAuthenticationService, IBackInStockSubscriptionService backInStockSubscriptionService, IDownloadService downloadService, IWebHelper webHelper, - ICustomerActivityService customerActivityService, MediaSettings mediaSettings, + ICustomerActivityService customerActivityService, + IProductAttributeParser productAttributeParser, + MediaSettings mediaSettings, IWorkflowMessageService workflowMessageService, LocalizationSettings localizationSettings, - CaptchaSettings captchaSettings, ExternalAuthenticationSettings externalAuthenticationSettings) + CaptchaSettings captchaSettings, ExternalAuthenticationSettings externalAuthenticationSettings, + PluginMediator pluginMediator) { this._authenticationService = authenticationService; this._dateTimeHelper = dateTimeHelper; @@ -142,12 +149,14 @@ public CustomerController(IAuthenticationService authenticationService, this._downloadService = downloadService; this._webHelper = webHelper; this._customerActivityService = customerActivityService; + this._productAttributeParser = productAttributeParser; this._mediaSettings = mediaSettings; this._workflowMessageService = workflowMessageService; this._localizationSettings = localizationSettings; this._captchaSettings = captchaSettings; this._externalAuthenticationSettings = externalAuthenticationSettings; + this._pluginMediator = pluginMediator; } #endregion @@ -237,6 +246,7 @@ protected void PrepareCustomerInfoModel(CustomerInfoModel model, Customer custom model.StateProvinceId = customer.GetAttribute(SystemCustomerAttributeNames.StateProvinceId); model.Phone = customer.GetAttribute(SystemCustomerAttributeNames.Phone); model.Fax = customer.GetAttribute(SystemCustomerAttributeNames.Fax); + model.CustomerNumber = customer.GetAttribute(SystemCustomerAttributeNames.CustomerNumber); //newsletter var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(customer.Email, _storeContext.CurrentStore.Id); @@ -307,6 +317,19 @@ protected void PrepareCustomerInfoModel(CustomerInfoModel model, Customer custom model.AllowUsersToChangeUsernames = _customerSettings.AllowUsersToChangeUsernames; model.CheckUsernameAvailabilityEnabled = _customerSettings.CheckUsernameAvailabilityEnabled; model.SignatureEnabled = _forumSettings.ForumsEnabled && _forumSettings.SignaturesEnabled; + model.DisplayCustomerNumber = _customerSettings.CustomerNumberMethod != CustomerNumberMethod.Disabled + && _customerSettings.CustomerNumberVisibility != CustomerNumberVisibility.None; + + if (_customerSettings.CustomerNumberMethod != CustomerNumberMethod.Disabled + && (_customerSettings.CustomerNumberVisibility == CustomerNumberVisibility.Editable + || (_customerSettings.CustomerNumberVisibility == CustomerNumberVisibility.EditableIfEmpty && String.IsNullOrEmpty(model.CustomerNumber)))) + { + model.CustomerNumberEnabled = true; + } + else + { + model.CustomerNumberEnabled = false; + } //external authentication foreach (var ear in _openAuthenticationService.GetExternalIdentifiersFor(customer)) @@ -320,47 +343,55 @@ protected void PrepareCustomerInfoModel(CustomerInfoModel model, Customer custom Id = ear.Id, Email = ear.Email, ExternalIdentifier = ear.ExternalIdentifier, - AuthMethodName = authMethod.GetLocalizedValue(_localizationService, "FriendlyName", _workContext.WorkingLanguage.Id) + AuthMethodName = _pluginMediator.GetLocalizedFriendlyName(authMethod.Metadata, _workContext.WorkingLanguage.Id) }); } - model.NavigationModel = GetCustomerNavigationModel(customer); model.NavigationModel.SelectedTab = CustomerNavigationEnum.Info; } [NonAction] - protected CustomerOrderListModel PrepareCustomerOrderListModel(Customer customer) + protected CustomerOrderListModel PrepareCustomerOrderListModel(Customer customer, int pageIndex) { if (customer == null) throw new ArgumentNullException("customer"); - var model = new CustomerOrderListModel(); + var storeScope = (_orderSettings.DisplayOrdersOfAllStores ? 0 : _storeContext.CurrentStore.Id); + + var model = new CustomerOrderListModel(); model.NavigationModel = GetCustomerNavigationModel(customer); model.NavigationModel.SelectedTab = CustomerNavigationEnum.Orders; - var orders = _orderService.SearchOrders(_storeContext.CurrentStore.Id, customer.Id, - null, null, null, null, null, null, null, null, 0, int.MaxValue); - foreach (var order in orders) - { - var orderModel = new CustomerOrderListModel.OrderDetailsModel() - { - Id = order.Id, - OrderNumber = order.GetOrderNumber(), - CreatedOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc), - OrderStatus = order.OrderStatus.GetLocalizedEnum(_localizationService, _workContext), - IsReturnRequestAllowed = _orderProcessingService.IsReturnRequestAllowed(order) - }; - var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate); - orderModel.OrderTotal = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage); - model.Orders.Add(orderModel); - } + var orders = _orderService.SearchOrders(storeScope, customer.Id, null, null, null, null, null, null, null, null, pageIndex, _orderSettings.OrderListPageSize); + + var orderModels = orders + .Select(x => + { + var orderModel = new CustomerOrderListModel.OrderDetailsModel + { + Id = x.Id, + OrderNumber = x.GetOrderNumber(), + CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOnUtc, DateTimeKind.Utc), + OrderStatus = x.OrderStatus.GetLocalizedEnum(_localizationService, _workContext), + IsReturnRequestAllowed = _orderProcessingService.IsReturnRequestAllowed(x) + }; + + var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(x.OrderTotal, x.CurrencyRate); + orderModel.OrderTotal = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, x.CustomerCurrencyCode, false, _workContext.WorkingLanguage); + + return orderModel; + }) + .ToList(); + + model.Orders = new PagedList(orderModels, orders.PageIndex, orders.PageSize, orders.TotalCount); + + + var recurringPayments = _orderService.SearchRecurringPayments(_storeContext.CurrentStore.Id, customer.Id, 0, null); - var recurringPayments = _orderService.SearchRecurringPayments(_storeContext.CurrentStore.Id, - customer.Id, 0, null); foreach (var recurringPayment in recurringPayments) { - var recurringPaymentModel = new CustomerOrderListModel.RecurringOrderModel() + var recurringPaymentModel = new CustomerOrderListModel.RecurringOrderModel { Id = recurringPayment.Id, StartDate = _dateTimeHelper.ConvertToUserTime(recurringPayment.StartDateUtc, DateTimeKind.Utc).ToString(), @@ -390,7 +421,6 @@ public ActionResult Login(bool? checkoutAsGuest) model.CheckoutAsGuest = checkoutAsGuest.HasValue ? checkoutAsGuest.Value : false; model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnLoginPage; - // codehint: sm-add if (_customerSettings.PrefillLoginUsername.HasValue()) { if (model.UsernamesEnabled) @@ -437,10 +467,7 @@ public ActionResult Login(LoginModel model, string returnUrl, bool captchaValid) //activity log _customerActivityService.InsertActivity("PublicStore.Login", _localizationService.GetResource("ActivityLog.PublicStore.Login"), customer); - if (!String.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)) - return Redirect(returnUrl); - else - return RedirectToRoute("HomePage"); + return RedirectToReferrer(returnUrl); } else { @@ -466,6 +493,7 @@ public ActionResult Register() foreach (var tzi in _dateTimeHelper.GetSystemTimeZones()) model.AvailableTimeZones.Add(new SelectListItem() { Text = tzi.DisplayName, Value = tzi.Id, Selected = (tzi.Id == _dateTimeHelper.DefaultStoreTimeZone.Id) }); model.DisplayVatNumber = _taxSettings.EuVatEnabled; + model.VatRequired = _taxSettings.VatRequired; //form fields model.GenderEnabled = _customerSettings.GenderEnabled; model.DateOfBirthEnabled = _customerSettings.DateOfBirthEnabled; @@ -526,15 +554,15 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha if (_workContext.CurrentCustomer.IsRegistered()) { - //Already registered customer. + // Already registered customer. _authenticationService.SignOut(); - //Save a new record + // Save a new record _workContext.CurrentCustomer = _customerService.InsertGuestCustomer(); } var customer = _workContext.CurrentCustomer; - //validate CAPTCHA + // validate CAPTCHA if (_captchaSettings.Enabled && _captchaSettings.ShowOnRegistrationPage && !captchaValid) { ModelState.AddModelError("", _localizationService.GetResource("Common.WrongCaptcha")); @@ -553,12 +581,12 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha var registrationResult = _customerRegistrationService.RegisterCustomer(registrationRequest); if (registrationResult.Success) { - //properties + // properties if (_dateTimeSettings.AllowCustomersToSetTimeZone) { _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.TimeZoneId, model.TimeZoneId); } - //VAT number + // VAT number if (_taxSettings.EuVatEnabled) { _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.VatNumber, model.VatNumber); @@ -569,12 +597,12 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.VatNumberStatusId, (int)vatNumberStatus); - //send VAT number admin notification + // send VAT number admin notification if (!String.IsNullOrEmpty(model.VatNumber) && _taxSettings.EuVatEmailAdminWhenNewVatSubmitted) _workflowMessageService.SendNewVatSubmittedStoreOwnerNotification(customer, model.VatNumber, vatAddress, _localizationSettings.DefaultAdminLanguageId); } - //form fields + // form fields if (_customerSettings.GenderEnabled) _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Gender, model.Gender); _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, model.FirstName); @@ -607,11 +635,13 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Phone, model.Phone); if (_customerSettings.FaxEnabled) _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Fax, model.Fax); + if (_customerSettings.CustomerNumberMethod == CustomerNumberMethod.AutomaticallySet && String.IsNullOrEmpty(customer.GetAttribute(SystemCustomerAttributeNames.CustomerNumber))) + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CustomerNumber, customer.Id); - //newsletter + // newsletter if (_customerSettings.NewsletterEnabled) { - //save newsletter value + // save newsletter value var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(model.Email, _storeContext.CurrentStore.Id); if (newsletter != null) { @@ -630,7 +660,7 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha { if (model.Newsletter) { - _newsLetterSubscriptionService.InsertNewsLetterSubscription(new NewsLetterSubscription() + _newsLetterSubscriptionService.InsertNewsLetterSubscription(new NewsLetterSubscription { NewsLetterSubscriptionGuid = Guid.NewGuid(), Email = model.Email, @@ -690,11 +720,10 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha { case UserRegistrationType.EmailValidation: { - //email validation message + // email validation message _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.AccountActivationToken, Guid.NewGuid().ToString()); _workflowMessageService.SendCustomerEmailValidationMessage(customer, _workContext.WorkingLanguage.Id); - //result return RedirectToRoute("RegisterResult", new { resultId = (int)UserRegistrationType.EmailValidation }); } case UserRegistrationType.AdminApproval: @@ -703,8 +732,8 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha } case UserRegistrationType.Standard: { - //send customer welcome message - _workflowMessageService.SendCustomerWelcomeMessage(customer, _workContext.WorkingLanguage.Id); + // send customer welcome message + _workflowMessageService.SendCustomerWelcomeMessage(customer, _workContext.WorkingLanguage.Id); var redirectUrl = Url.RouteUrl("RegisterResult", new { resultId = (int)UserRegistrationType.Standard }); if (!String.IsNullOrEmpty(returnUrl)) @@ -729,6 +758,7 @@ public ActionResult Register(RegisterModel model, string returnUrl, bool captcha foreach (var tzi in _dateTimeHelper.GetSystemTimeZones()) model.AvailableTimeZones.Add(new SelectListItem() { Text = tzi.DisplayName, Value = tzi.Id, Selected = (tzi.Id == _dateTimeHelper.DefaultStoreTimeZone.Id) }); model.DisplayVatNumber = _taxSettings.EuVatEnabled; + model.VatRequired = _taxSettings.VatRequired; //form fields model.GenderEnabled = _customerSettings.GenderEnabled; model.DateOfBirthEnabled = _customerSettings.DateOfBirthEnabled; @@ -799,10 +829,8 @@ public ActionResult RegisterResult(int resultId) default: break; } - var model = new RegisterResultModel() - { - Result = resultText - }; + + var model = new RegisterResultModel { Result = resultText }; return View(model); } @@ -872,14 +900,14 @@ public ActionResult AccountActivation(string token, string email) { var customer = _customerService.GetCustomerByEmail(email); if (customer == null) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Email"); var cToken = customer.GetAttribute(SystemCustomerAttributeNames.AccountActivationToken); if (String.IsNullOrEmpty(cToken)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (!cToken.Equals(token, StringComparison.InvariantCultureIgnoreCase)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); //activate user account customer.Active = true; @@ -887,8 +915,8 @@ public ActionResult AccountActivation(string token, string email) _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.AccountActivationToken, ""); //send welcome message _workflowMessageService.SendCustomerWelcomeMessage(customer, _workContext.WorkingLanguage.Id); - - var model = new AccountActivationModel(); + + var model = new AccountActivationModel(); model.Result = _localizationService.GetResource("Account.AccountActivation.Activated"); return View(model); } @@ -950,8 +978,7 @@ public ActionResult Info(CustomerInfoModel model) if (ModelState.IsValid) { //username - if (_customerSettings.UsernamesEnabled && - this._customerSettings.AllowUsersToChangeUsernames) + if (_customerSettings.UsernamesEnabled && _customerSettings.AllowUsersToChangeUsernames) { if (!customer.Username.Equals(model.Username.Trim(), StringComparison.InvariantCultureIgnoreCase)) { @@ -1000,9 +1027,28 @@ public ActionResult Info(CustomerInfoModel model) //form fields if (_customerSettings.GenderEnabled) + { _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Gender, model.Gender); + } + + if (_customerSettings.CustomerNumberMethod != CustomerNumberMethod.Disabled) + { + var customerNumbers = _genericAttributeService.GetAttributes(SystemCustomerAttributeNames.CustomerNumber, "customer"); + var currentCustomerNumber = customer.GetAttribute(SystemCustomerAttributeNames.CustomerNumber); + + if (model.CustomerNumber != currentCustomerNumber && customerNumbers.Where(x => x.Value == model.CustomerNumber).Any()) + { + NotifyError("Common.CustomerNumberAlreadyExists"); + } + else + { + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.CustomerNumber, model.CustomerNumber); + } + } + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, model.FirstName); _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.LastName, model.LastName); + if (_customerSettings.DateOfBirthEnabled) { DateTime? dateOfBirth = null; @@ -1035,40 +1081,15 @@ public ActionResult Info(CustomerInfoModel model) //newsletter if (_customerSettings.NewsletterEnabled) { - //save newsletter value - var newsletter = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(customer.Email, _storeContext.CurrentStore.Id); - if (newsletter != null) - { - if (model.Newsletter) - { - newsletter.Active = true; - _newsLetterSubscriptionService.UpdateNewsLetterSubscription(newsletter); - } - else - { - _newsLetterSubscriptionService.DeleteNewsLetterSubscription(newsletter); - } - } - else - { - if (model.Newsletter) - { - _newsLetterSubscriptionService.InsertNewsLetterSubscription(new NewsLetterSubscription() - { - NewsLetterSubscriptionGuid = Guid.NewGuid(), - Email = customer.Email, - Active = true, - CreatedOnUtc = DateTime.UtcNow, - StoreId = _storeContext.CurrentStore.Id - }); - } - } + _newsLetterSubscriptionService.AddNewsLetterSubscriptionFor(model.Newsletter, customer.Email, _storeContext.CurrentStore.Id); } - if (_forumSettings.ForumsEnabled && _forumSettings.SignaturesEnabled) - _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Signature, model.Signature); + if (_forumSettings.ForumsEnabled && _forumSettings.SignaturesEnabled) + { + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.Signature, model.Signature); + } - return RedirectToRoute("CustomerInfo"); + return RedirectToAction("Info"); } } catch (Exception exc) @@ -1108,15 +1129,18 @@ public ActionResult Addresses() } [RequireHttpsByConfigAttribute(SslRequirement.Yes)] - public ActionResult AddressDelete(int addressId) + public ActionResult AddressDelete(int id) { - if (!IsCurrentUserRegistered()) + if (id < 1) + return HttpNotFound(); + + if (!IsCurrentUserRegistered()) return new HttpUnauthorizedResult(); var customer = _workContext.CurrentCustomer; //find address (ensure that it belongs to the current customer) - var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault(); + var address = customer.Addresses.Where(a => a.Id == id).FirstOrDefault(); if (address != null) { customer.RemoveAddress(address); @@ -1125,7 +1149,7 @@ public ActionResult AddressDelete(int addressId) _addressService.DeleteAddress(address); } - return RedirectToRoute("CustomerAddresses"); + return RedirectToAction("Addresses"); } [RequireHttpsByConfigAttribute(SslRequirement.Yes)] @@ -1166,7 +1190,7 @@ public ActionResult AddressAdd(CustomerAddressEditModel model) customer.Addresses.Add(address); _customerService.UpdateCustomer(customer); - return RedirectToRoute("CustomerAddresses"); + return RedirectToAction("Addresses"); } @@ -1180,17 +1204,20 @@ public ActionResult AddressAdd(CustomerAddressEditModel model) } [RequireHttpsByConfigAttribute(SslRequirement.Yes)] - public ActionResult AddressEdit(int addressId) + public ActionResult AddressEdit(int id) { - if (!IsCurrentUserRegistered()) + if (id < 1) + return HttpNotFound(); + + if (!IsCurrentUserRegistered()) return new HttpUnauthorizedResult(); var customer = _workContext.CurrentCustomer; //find address (ensure that it belongs to the current customer) - var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault(); + var address = customer.Addresses.Where(a => a.Id == id).FirstOrDefault(); if (address == null) //address is not found - return RedirectToRoute("CustomerAddresses"); + return RedirectToAction("Addresses"); var model = new CustomerAddressEditModel(); model.NavigationModel = GetCustomerNavigationModel(customer); @@ -1202,24 +1229,23 @@ public ActionResult AddressEdit(int addressId) } [HttpPost] - public ActionResult AddressEdit(CustomerAddressEditModel model, int addressId) + public ActionResult AddressEdit(CustomerAddressEditModel model, int id) { if (!IsCurrentUserRegistered()) return new HttpUnauthorizedResult(); var customer = _workContext.CurrentCustomer; //find address (ensure that it belongs to the current customer) - var address = customer.Addresses.Where(a => a.Id == addressId).FirstOrDefault(); + var address = customer.Addresses.Where(a => a.Id == id).FirstOrDefault(); if (address == null) //address is not found - return RedirectToRoute("CustomerAddresses"); + return RedirectToAction("Addresses"); if (ModelState.IsValid) { address = model.Address.ToEntity(address); _addressService.UpdateAddress(address); - - return RedirectToRoute("CustomerAddresses"); + return RedirectToAction("Addresses"); } //If we got this far, something failed, redisplay form @@ -1235,13 +1261,13 @@ public ActionResult AddressEdit(CustomerAddressEditModel model, int addressId) #region Orders [RequireHttpsByConfigAttribute(SslRequirement.Yes)] - public ActionResult Orders() + public ActionResult Orders(int? page) { if (!IsCurrentUserRegistered()) return new HttpUnauthorizedResult(); - var customer = _workContext.CurrentCustomer; - var model = PrepareCustomerOrderListModel(customer); + var model = PrepareCustomerOrderListModel(_workContext.CurrentCustomer, Math.Max((page ?? 0) - 1, 0)); + return View(model); } @@ -1254,14 +1280,18 @@ public ActionResult CancelRecurringPayment(FormCollection form) //get recurring payment identifier int recurringPaymentId = 0; - foreach (var formValue in form.AllKeys) - if (formValue.StartsWith("cancelRecurringPayment", StringComparison.InvariantCultureIgnoreCase)) - recurringPaymentId = Convert.ToInt32(formValue.Substring("cancelRecurringPayment".Length)); + foreach (var formValue in form.AllKeys) + { + if (formValue.StartsWith("cancelRecurringPayment", StringComparison.InvariantCultureIgnoreCase)) + { + recurringPaymentId = Convert.ToInt32(formValue.Substring("cancelRecurringPayment".Length)); + } + } var recurringPayment = _orderService.GetRecurringPaymentById(recurringPaymentId); if (recurringPayment == null) { - return RedirectToRoute("CustomerOrders"); + return RedirectToAction("Orders"); } var customer = _workContext.CurrentCustomer; @@ -1269,16 +1299,14 @@ public ActionResult CancelRecurringPayment(FormCollection form) { var errors = _orderProcessingService.CancelRecurringPayment(recurringPayment); - var model = PrepareCustomerOrderListModel(customer); + var model = PrepareCustomerOrderListModel(customer, 0); model.CancelRecurringPaymentErrors = errors; return View(model); } - else - { - return RedirectToRoute("CustomerOrders"); - } - } + + return RedirectToAction("Orders"); + } #endregion @@ -1304,8 +1332,9 @@ public ActionResult ReturnRequests() if (orderItem != null) { var product = orderItem.Product; + var attributeQueryData = new List>(); - var itemModel = new CustomerReturnRequestsModel.ReturnRequestModel() + var itemModel = new CustomerReturnRequestsModel.ReturnRequestModel { Id = returnRequest.Id, ReturnRequestStatus = returnRequest.ReturnRequestStatus.GetLocalizedEnum(_localizationService, _workContext), @@ -1316,8 +1345,22 @@ public ActionResult ReturnRequests() ReturnAction = returnRequest.RequestedAction, ReturnReason = returnRequest.ReasonForReturn, Comments = returnRequest.CustomerComments, - CreatedOn = _dateTimeHelper.ConvertToUserTime(returnRequest.CreatedOnUtc, DateTimeKind.Utc), + CreatedOn = _dateTimeHelper.ConvertToUserTime(returnRequest.CreatedOnUtc, DateTimeKind.Utc) }; + + if (orderItem.Product.ProductType != ProductType.BundledProduct) + { + _productAttributeParser.DeserializeQueryData(attributeQueryData, orderItem.AttributesXml, orderItem.ProductId); + } + else if (orderItem.Product.BundlePerItemPricing && orderItem.BundleData.HasValue()) + { + var bundleData = orderItem.GetBundleData(); + + bundleData.ForEach(x => _productAttributeParser.DeserializeQueryData(attributeQueryData, x.AttributesXml, x.ProductId, x.BundleItemId)); + } + + itemModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(attributeQueryData, itemModel.ProductSeName); + model.Items.Add(itemModel); } } @@ -1340,11 +1383,12 @@ public ActionResult DownloadableProducts() var model = new CustomerDownloadableProductsModel(); model.NavigationModel = GetCustomerNavigationModel(customer); model.NavigationModel.SelectedTab = CustomerNavigationEnum.DownloadableProducts; - var items = _orderService.GetAllOrderItems(null, customer.Id, null, null, - null, null, null, true); + + var items = _orderService.GetAllOrderItems(null, customer.Id, null, null, null, null, null, true); + foreach (var item in items) { - var itemModel = new CustomerDownloadableProductsModel.DownloadableProductsModel() + var itemModel = new CustomerDownloadableProductsModel.DownloadableProductsModel { OrderItemGuid = item.OrderItemGuid, OrderId = item.OrderId, @@ -1354,6 +1398,9 @@ public ActionResult DownloadableProducts() ProductAttributes = item.AttributeDescription, ProductId = item.ProductId }; + + itemModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(item.AttributesXml, item.ProductId, itemModel.ProductSeName); + model.Items.Add(itemModel); if (_downloadService.IsDownloadAllowed(item)) @@ -1366,19 +1413,22 @@ public ActionResult DownloadableProducts() return View(model); } - public ActionResult UserAgreement(Guid orderItemId) + public ActionResult UserAgreement(Guid id /* orderItemId */) { - var orderItem = _orderService.GetOrderItemByGuid(orderItemId); + if (id == Guid.Empty) + return HttpNotFound(); + + var orderItem = _orderService.GetOrderItemByGuid(id); if (orderItem == null) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Guid"); var product = orderItem.Product; if (product == null || !product.HasUserAgreement) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Product"); var model = new UserAgreementModel(); model.UserAgreementText = product.UserAgreementText; - model.OrderItemGuid = orderItemId; + model.OrderItemGuid = id; return View(model); } @@ -1394,7 +1444,7 @@ public ActionResult RewardPoints() return new HttpUnauthorizedResult(); if (!_rewardPointsSettings.Enabled) - return RedirectToRoute("CustomerInfo"); + return RedirectToAction("Info"); var customer = _workContext.CurrentCustomer; @@ -1482,11 +1532,12 @@ public ActionResult Avatar() return new HttpUnauthorizedResult(); if (!_customerSettings.AllowCustomersToUploadAvatars) - return RedirectToRoute("CustomerInfo"); + return RedirectToAction("Info"); var customer = _workContext.CurrentCustomer; var model = new CustomerAvatarModel(); + model.MaxFileSize = Prettifier.BytesToString(_customerSettings.AvatarMaximumSizeBytes); model.NavigationModel = GetCustomerNavigationModel(customer); model.NavigationModel.SelectedTab = CustomerNavigationEnum.Avatar; model.AvatarUrl = _pictureService.GetPictureUrl( @@ -1504,43 +1555,47 @@ public ActionResult UploadAvatar(CustomerAvatarModel model, HttpPostedFileBase u return new HttpUnauthorizedResult(); if (!_customerSettings.AllowCustomersToUploadAvatars) - return RedirectToRoute("CustomerInfo"); + return RedirectToAction("Info"); var customer = _workContext.CurrentCustomer; + model.MaxFileSize = Prettifier.BytesToString(_customerSettings.AvatarMaximumSizeBytes); model.NavigationModel = GetCustomerNavigationModel(customer); model.NavigationModel.SelectedTab = CustomerNavigationEnum.Avatar; - if (ModelState.IsValid) { try { var customerAvatar = _pictureService.GetPictureById(customer.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId)); - if ((uploadedFile != null) && (!String.IsNullOrEmpty(uploadedFile.FileName))) - { - int avatarMaxSize = _customerSettings.AvatarMaximumSizeBytes; - if (uploadedFile.ContentLength > avatarMaxSize) - throw new SmartException(string.Format(_localizationService.GetResource("Account.Avatar.MaximumUploadedFileSize"), avatarMaxSize)); - byte[] customerPictureBinary = uploadedFile.GetPictureBits(); - if (customerAvatar != null) - customerAvatar = _pictureService.UpdatePicture(customerAvatar.Id, customerPictureBinary, uploadedFile.ContentType, null, true); - else - customerAvatar = _pictureService.InsertPicture(customerPictureBinary, uploadedFile.ContentType, null, true); - } + if ((uploadedFile != null) && (!String.IsNullOrEmpty(uploadedFile.FileName))) + { + var avatarMaxSize = _customerSettings.AvatarMaximumSizeBytes; + + if (uploadedFile.ContentLength > avatarMaxSize) + throw new SmartException(T("Account.Avatar.MaximumUploadedFileSize", Prettifier.BytesToString(avatarMaxSize))); + + byte[] customerPictureBinary = uploadedFile.InputStream.ToByteArray(); + + if (customerAvatar != null) + customerAvatar = _pictureService.UpdatePicture(customerAvatar.Id, customerPictureBinary, uploadedFile.ContentType, null, true); + else + customerAvatar = _pictureService.InsertPicture(customerPictureBinary, uploadedFile.ContentType, null, true, false); + } + else if (customerAvatar != null) + { + _pictureService.DeletePicture(customerAvatar); + customerAvatar = null; + } - int customerAvatarId = 0; - if (customerAvatar != null) - customerAvatarId = customerAvatar.Id; + var customerAvatarId = (customerAvatar != null ? customerAvatar.Id : 0); _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.AvatarPictureId, customerAvatarId); - model.AvatarUrl = _pictureService.GetPictureUrl( - customer.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId), - _mediaSettings.AvatarPictureSize, - false); - return View(model); + model.AvatarUrl = _pictureService.GetPictureUrl(customerAvatarId, _mediaSettings.AvatarPictureSize, false); + + return View(model); } catch (Exception exc) { @@ -1548,12 +1603,9 @@ public ActionResult UploadAvatar(CustomerAvatarModel model, HttpPostedFileBase u } } - //If we got this far, something failed, redisplay form - model.AvatarUrl = _pictureService.GetPictureUrl( - customer.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId), - _mediaSettings.AvatarPictureSize, - false); + model.AvatarUrl = _pictureService.GetPictureUrl(customer.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId), _mediaSettings.AvatarPictureSize, false); + return View(model); } @@ -1565,7 +1617,7 @@ public ActionResult RemoveAvatar(CustomerAvatarModel model, HttpPostedFileBase u return new HttpUnauthorizedResult(); if (!_customerSettings.AllowCustomersToUploadAvatars) - return RedirectToRoute("CustomerInfo"); + return RedirectToAction("Info"); var customer = _workContext.CurrentCustomer; @@ -1575,9 +1627,10 @@ public ActionResult RemoveAvatar(CustomerAvatarModel model, HttpPostedFileBase u var customerAvatar = _pictureService.GetPictureById(customer.GetAttribute(SystemCustomerAttributeNames.AvatarPictureId)); if (customerAvatar != null) _pictureService.DeletePicture(customerAvatar); + _genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.AvatarPictureId, 0); - return RedirectToRoute("CustomerAvatar"); + return RedirectToAction("Avatar"); } #endregion @@ -1624,14 +1677,14 @@ public ActionResult PasswordRecoveryConfirm(string token, string email) { var customer = _customerService.GetCustomerByEmail(email); if (customer == null ) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Email"); var cPrt = customer.GetAttribute(SystemCustomerAttributeNames.PasswordRecoveryToken); if (String.IsNullOrEmpty(cPrt)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (!cPrt.Equals(token, StringComparison.InvariantCultureIgnoreCase)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); var model = new PasswordRecoveryConfirmModel(); return View(model); @@ -1643,14 +1696,14 @@ public ActionResult PasswordRecoveryConfirmPOST(string token, string email, Pass { var customer = _customerService.GetCustomerByEmail(email); if (customer == null) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Email"); var cPrt = customer.GetAttribute(SystemCustomerAttributeNames.PasswordRecoveryToken); if (String.IsNullOrEmpty(cPrt)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (!cPrt.Equals(token, StringComparison.InvariantCultureIgnoreCase)) - return RedirectToRoute("HomePage"); + return RedirectToHomePageWithError("Token"); if (ModelState.IsValid) { @@ -1683,7 +1736,7 @@ public ActionResult ForumSubscriptions(int? page) { if (!_forumSettings.AllowCustomersToManageSubscriptions) { - return RedirectToRoute("CustomerInfo"); + return RedirectToAction("Info"); } int pageIndex = 0; @@ -1725,12 +1778,12 @@ public ActionResult ForumSubscriptions(int? page) var forum = _forumService.GetForumById(forumId); if (forum != null) { - title = forum.Name; + title = forum.GetLocalized(x => x.Name); slug = forum.GetSeName(); } } - model.ForumSubscriptions.Add(new ForumSubscriptionModel() + model.ForumSubscriptions.Add(new ForumSubscriptionModel { Id = forumSubscription.Id, ForumTopicId = forumTopicId, @@ -1767,18 +1820,21 @@ public ActionResult ForumSubscriptionsPOST(FormCollection formCollection) } } - return RedirectToRoute("CustomerForumSubscriptions"); + return RedirectToAction("ForumSubscriptions"); } - public ActionResult DeleteForumSubscription(int subscriptionId) + public ActionResult DeleteForumSubscription(int id) { - var forumSubscription = _forumService.GetSubscriptionById(subscriptionId); + if (id < 1) + return HttpNotFound(); + + var forumSubscription = _forumService.GetSubscriptionById(id); if (forumSubscription != null && forumSubscription.CustomerId == _workContext.CurrentCustomer.Id) { _forumService.DeleteSubscription(forumSubscription); } - return RedirectToRoute("CustomerForumSubscriptions"); + return RedirectToAction("ForumSubscriptions"); } #endregion @@ -1789,7 +1845,7 @@ public ActionResult BackInStockSubscriptions(int? page) { if (_customerSettings.HideBackInStockSubscriptionsTab) { - return RedirectToRoute("CustomerInfo"); + return RedirectToAction("Info"); } int pageIndex = 0; @@ -1851,18 +1907,18 @@ public ActionResult BackInStockSubscriptionsPOST(FormCollection formCollection) } } - return RedirectToRoute("CustomerBackInStockSubscriptions"); + return RedirectToAction("BackInStockSubscriptions"); } - public ActionResult DeleteBackInStockSubscription(int subscriptionId) + public ActionResult DeleteBackInStockSubscription(int id /* subscriptionId */) { - var subscription = _backInStockSubscriptionService.GetSubscriptionById(subscriptionId); + var subscription = _backInStockSubscriptionService.GetSubscriptionById(id); if (subscription != null && subscription.CustomerId == _workContext.CurrentCustomer.Id) { _backInStockSubscriptionService.DeleteSubscription(subscription); } - return RedirectToRoute("CustomerBackInStockSubscriptions"); + return RedirectToAction("BackInStockSubscriptions"); } #endregion diff --git a/src/Presentation/SmartStore.Web/Controllers/DownloadController.cs b/src/Presentation/SmartStore.Web/Controllers/DownloadController.cs index 9dd010736f..857b877aa3 100644 --- a/src/Presentation/SmartStore.Web/Controllers/DownloadController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/DownloadController.cs @@ -1,7 +1,11 @@ using System; +using System.Web; using System.Web.Mvc; using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Html; using SmartStore.Services.Catalog; using SmartStore.Services.Media; using SmartStore.Services.Orders; @@ -9,7 +13,7 @@ namespace SmartStore.Web.Controllers { - public partial class DownloadController : PublicControllerBase + public partial class DownloadController : PublicControllerBase { private readonly IDownloadService _downloadService; private readonly IProductService _productService; @@ -18,8 +22,12 @@ public partial class DownloadController : PublicControllerBase private readonly CustomerSettings _customerSettings; - public DownloadController(IDownloadService downloadService, IProductService productService, - IOrderService orderService, IWorkContext workContext, CustomerSettings customerSettings) + public DownloadController( + IDownloadService downloadService, + IProductService productService, + IOrderService orderService, + IWorkContext workContext, + CustomerSettings customerSettings) { this._downloadService = downloadService; this._productService = productService; @@ -27,45 +35,56 @@ public DownloadController(IDownloadService downloadService, IProductService prod this._workContext = workContext; this._customerSettings = customerSettings; } - - public ActionResult Sample(int productId) + + private ActionResult GetFileContentResultFor(Download download, Product product) + { + if (download.DownloadBinary == null) + { + return Content(T("Common.Download.NoDataAvailable")); + } + + var id = (product != null ? product.Id : download.Id); + var fileName = !String.IsNullOrWhiteSpace(download.Filename) ? download.Filename : id.ToString(); + var contentType = !String.IsNullOrWhiteSpace(download.ContentType) ? download.ContentType : "application/octet-stream"; + + return new FileContentResult(download.DownloadBinary, contentType) + { + FileDownloadName = fileName + download.Extension + }; + } + + public ActionResult Sample(int id /* productId */) { - var product = _productService.GetProductById(productId); + var product = _productService.GetProductById(id); if (product == null) - return RedirectToRoute("HomePage"); + return HttpNotFound(); - if (!product.HasSampleDownload) - return Content("Product variant doesn't have a sample download."); + if (!product.HasSampleDownload) + return Content(T("Common.Download.HasNoSample")); var download = _downloadService.GetDownloadById(product.SampleDownloadId.GetValueOrDefault()); if (download == null) - return Content("Sample download is not available any more."); + return Content(T("Common.Download.SampleNotAvailable")); if (download.UseDownloadUrl) - { return new RedirectResult(download.DownloadUrl); - } - else - { - if (download.DownloadBinary == null) - return Content("Download data is not available any more."); - string fileName = !String.IsNullOrWhiteSpace(download.Filename) ? download.Filename : product.Id.ToString(); - string contentType = !String.IsNullOrWhiteSpace(download.ContentType) ? download.ContentType : "application/octet-stream"; - return new FileContentResult(download.DownloadBinary, contentType) { FileDownloadName = fileName + download.Extension }; - } + return GetFileContentResultFor(download, product); } - public ActionResult GetDownload(Guid orderItemId, bool agree = false) + public ActionResult GetDownload(Guid id /* orderItemId */, bool agree = false) { - var orderItem = _orderService.GetOrderItemByGuid(orderItemId); + if (id == Guid.Empty) + return HttpNotFound(); + + var orderItem = _orderService.GetOrderItemByGuid(id); if (orderItem == null) - return RedirectToRoute("HomePage"); + return HttpNotFound(); var order = orderItem.Order; var product = orderItem.Product; if (!_downloadService.IsDownloadAllowed(orderItem)) - return Content("Downloads are not allowed"); + return Content(T("Common.Download.NotAllowed")); if (_customerSettings.DownloadableProductsValidateUser) { @@ -73,59 +92,52 @@ public ActionResult GetDownload(Guid orderItemId, bool agree = false) return new HttpUnauthorizedResult(); if (order.CustomerId != _workContext.CurrentCustomer.Id) - return Content("This is not your order"); + return Content(T("Account.CustomerOrders.NotYourOrder")); } var download = _downloadService.GetDownloadById(product.DownloadId); if (download == null) - return Content("Download is not available any more."); - - if (product.HasUserAgreement) - { - if (!agree) - return RedirectToRoute("DownloadUserAgreement", new { orderItemId = orderItemId }); - } + return Content(T("Common.Download.NoDataAvailable")); + if (product.HasUserAgreement && !agree) + return RedirectToAction("UserAgreement", "Customer", new { id = id }); if (!product.UnlimitedDownloads && orderItem.DownloadCount >= product.MaxNumberOfDownloads) - return Content(string.Format("You have reached maximum number of downloads {0}", product.MaxNumberOfDownloads)); + return Content(T("Common.Download.MaxNumberReached", product.MaxNumberOfDownloads)); - if (download.UseDownloadUrl) { - //increase download orderItem.DownloadCount++; _orderService.UpdateOrder(order); - //return result return new RedirectResult(download.DownloadUrl); } else { if (download.DownloadBinary == null) - return Content("Download data is not available any more."); + return Content(T("Common.Download.NoDataAvailable")); - //increase download orderItem.DownloadCount++; _orderService.UpdateOrder(order); - //return result - string fileName = !String.IsNullOrWhiteSpace(download.Filename) ? download.Filename : product.Id.ToString(); - string contentType = !String.IsNullOrWhiteSpace(download.ContentType) ? download.ContentType : "application/octet-stream"; - return new FileContentResult(download.DownloadBinary, contentType) { FileDownloadName = fileName + download.Extension }; + return GetFileContentResultFor(download, product); } } - public ActionResult GetLicense(Guid orderItemId) + public ActionResult GetLicense(Guid id /* orderItemId */) { - var orderItem = _orderService.GetOrderItemByGuid(orderItemId); + if (id == Guid.Empty) + return HttpNotFound(); + + var orderItem = _orderService.GetOrderItemByGuid(id); if (orderItem == null) - return RedirectToRoute("HomePage"); + return HttpNotFound(); var order = orderItem.Order; var product = orderItem.Product; + if (!_downloadService.IsLicenseDownloadAllowed(orderItem)) - return Content("Downloads are not allowed"); + return Content(T("Common.Download.NotAllowed")); if (_customerSettings.DownloadableProductsValidateUser) { @@ -133,52 +145,49 @@ public ActionResult GetLicense(Guid orderItemId) return new HttpUnauthorizedResult(); if (order.CustomerId != _workContext.CurrentCustomer.Id) - return Content("This is not your order"); + return Content(T("Account.CustomerOrders.NotYourOrder")); } var download = _downloadService.GetDownloadById(orderItem.LicenseDownloadId.HasValue ? orderItem.LicenseDownloadId.Value : 0); if (download == null) - return Content("Download is not available any more."); + return Content(T("Common.Download.NotAvailable")); if (download.UseDownloadUrl) - { - //return result return new RedirectResult(download.DownloadUrl); - } - else - { - if (download.DownloadBinary == null) - return Content("Download data is not available any more."); - - //return result - string fileName = !String.IsNullOrWhiteSpace(download.Filename) ? download.Filename : product.Id.ToString(); - string contentType = !String.IsNullOrWhiteSpace(download.ContentType) ? download.ContentType : "application/octet-stream"; - return new FileContentResult(download.DownloadBinary, contentType) { FileDownloadName = fileName + download.Extension }; - } - } + + return GetFileContentResultFor(download, product); + } public ActionResult GetFileUpload(Guid downloadId) { var download = _downloadService.GetDownloadByGuid(downloadId); if (download == null) - return Content("Download is not available any more."); + return Content(T("Common.Download.NotAvailable")); if (download.UseDownloadUrl) - { - //return result return new RedirectResult(download.DownloadUrl); - } - else - { - if (download.DownloadBinary == null) - return Content("Download data is not available any more."); - //return result - string fileName = !String.IsNullOrWhiteSpace(download.Filename) ? download.Filename : downloadId.ToString(); - string contentType = !String.IsNullOrWhiteSpace(download.ContentType) ? download.ContentType : "application/octet-stream"; - return new FileContentResult(download.DownloadBinary, contentType) { FileDownloadName = fileName + download.Extension }; - } - } + return GetFileContentResultFor(download, null); + } + + public ActionResult GetUserAgreement(int productId, bool? asPlainText) + { + var product = _productService.GetProductById(productId); + if (product == null) + return Content(T("Products.NotFound", productId)); + + if (!product.IsDownload || !product.HasUserAgreement || product.UserAgreementText.IsEmpty()) + return Content(T("DownloadableProducts.HasNoUserAgreement")); + + if (asPlainText ?? false) + { + var agreement = HtmlUtils.ConvertHtmlToPlainText(product.UserAgreementText); + agreement = HtmlUtils.StripTags(HttpUtility.HtmlDecode(agreement)); + + return Content(agreement); + } - } + return Content(product.UserAgreementText); + } + } } diff --git a/src/Presentation/SmartStore.Web/Controllers/ErrorController.cs b/src/Presentation/SmartStore.Web/Controllers/ErrorController.cs new file mode 100644 index 0000000000..c78a18fbc9 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Controllers/ErrorController.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using SmartStore.Web.Infrastructure; + +namespace SmartStore.Web.Controllers +{ + // Keep this very simple: no dependencies at all! + public class ErrorController : Controller + { + + [MapLegacyRoutes] + public ActionResult NotFound() + { + return HttpNotFound(); + } + + public ActionResult Index() + { + this.Response.StatusCode = 500; + this.Response.TrySkipIisCustomErrors = true; + + return View("Error"); + } + + //public ActionResult DoThrow() + //{ + // throw Error.Application("This error was thrown on purpose for testing reasons."); + //} + + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Controllers/ExternalAuthenticationController.cs b/src/Presentation/SmartStore.Web/Controllers/ExternalAuthenticationController.cs index c8a5cd2a9f..3fc35cd8db 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ExternalAuthenticationController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ExternalAuthenticationController.cs @@ -31,10 +31,10 @@ public ExternalAuthenticationController(IOpenAuthenticationService openAuthentic #region Methods - public RedirectResult RemoveParameterAssociation(string returnUrl) + public ActionResult RemoveParameterAssociation(string returnUrl) { ExternalAuthorizerHelper.RemoveParameters(); - return Redirect(returnUrl); + return RedirectToReferrer(returnUrl); } [ChildActionOnly] @@ -43,15 +43,14 @@ public ActionResult ExternalMethods() //model var model = new List(); - foreach (var eam in _openAuthenticationService - .LoadActiveExternalAuthenticationMethods(_storeContext.CurrentStore.Id)) + foreach (var eam in _openAuthenticationService.LoadActiveExternalAuthenticationMethods(_storeContext.CurrentStore.Id)) { var eamModel = new ExternalAuthenticationMethodModel(); string actionName; string controllerName; RouteValueDictionary routeValues; - eam.GetPublicInfoRoute(out actionName, out controllerName, out routeValues); + eam.Value.GetPublicInfoRoute(out actionName, out controllerName, out routeValues); eamModel.ActionName = actionName; eamModel.ControllerName = controllerName; eamModel.RouteValues = routeValues; diff --git a/src/Presentation/SmartStore.Web/Controllers/FilterController.cs b/src/Presentation/SmartStore.Web/Controllers/FilterController.cs index 8bdb1422cc..e122492826 100644 --- a/src/Presentation/SmartStore.Web/Controllers/FilterController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/FilterController.cs @@ -1,62 +1,44 @@ using System.Collections.Generic; using System.Linq; -using System.Linq.Dynamic; using System.Web.Mvc; -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Filter; -using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; +using SmartStore.Services.Filter; using SmartStore.Web.Models.Filter; -using SmartStore.Web.Framework.Mvc; -using System.Net.Mime; -using SmartStore.Web.Models.Catalog; -using System; -using SmartStore.Services.Catalog; -using SmartStore.Services.Security; -using System.Diagnostics; -using SmartStore.Web.Infrastructure.Cache; -using SmartStore.Core; -using SmartStore.Services.Localization; -using SmartStore.Core.Domain.Tax; -using SmartStore.Services.Directory; -using SmartStore.Core.Domain.Directory; -using SmartStore.Services.Tax; -using SmartStore.Services.Media; -using SmartStore.Core.Domain.Media; -using SmartStore.Web.Models.Media; -using SmartStore.Core.Caching; -using SmartStore.Services.Seo; -using SmartStore.Web.Framework.Controllers; namespace SmartStore.Web.Controllers { - /// codehint: sm-add - public partial class FilterController : Controller // not BaseController cause of performance + public partial class FilterController : Controller // not BaseController cause of performance { private readonly IFilterService _filterService; + private readonly CatalogSettings _catalogSettings; - public FilterController(IFilterService filterService) + public FilterController(IFilterService filterService, CatalogSettings catalogSettings) { _filterService = filterService; + _catalogSettings = catalogSettings; + } + + private bool IsShowAllText(ICollection criteriaGroup) + { + if (criteriaGroup.Any(c => c.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutPrice))) + return false; + + return (criteriaGroup.Count >= _catalogSettings.MaxFilterItemsToDisplay || criteriaGroup.Any(c => !c.IsInactive)); } public ActionResult Products(string filter, int categoryID, string path, int? pagesize, int? orderby, string viewmode) { - var context = new FilterProductContext() - { - Filter = filter, - ParentCategoryID = categoryID, - CategoryIds = new List { categoryID }, - Path = path, - PageSize = pagesize ?? 12, - ViewMode = viewmode, - OrderBy = orderby, - Criteria = _filterService.Deserialize(filter) - }; + var context = _filterService.CreateFilterProductContext(filter, categoryID, path, pagesize, orderby, viewmode); _filterService.ProductFilterable(context); - return PartialView(new ProductFilterModel { Context = context }); + return PartialView(new ProductFilterModel + { + Context = context, + IsShowAllText = IsShowAllText(context.Criteria), + MaxFilterItemsToDisplay = _catalogSettings.MaxFilterItemsToDisplay, + ExpandAllFilterGroups = _catalogSettings.ExpandAllFilterCriteria + }); } [HttpPost] @@ -65,12 +47,12 @@ public ActionResult Products(string active, string inactive, int categoryID, int // TODO: needed later for ajax based filtering... see example below //System.Threading.Thread.Sleep(3000); - var context = new FilterProductContext() + var context = new FilterProductContext { ParentCategoryID = categoryID, CategoryIds = new List { categoryID }, Criteria = _filterService.Deserialize(active), - OrderBy = orderby + OrderBy = orderby, }; context.Criteria.AddRange(_filterService.Deserialize(inactive)); @@ -96,22 +78,17 @@ public ActionResult Products(string active, string inactive, int categoryID, int public ActionResult ProductsMultiSelect(string filter, int categoryID, string path, int? pagesize, int? orderby, string viewmode, string filterMultiSelect) { - var context = new FilterProductContext() - { - Filter = filter, - ParentCategoryID = categoryID, - CategoryIds = new List { categoryID }, - Path = path, - PageSize = pagesize ?? 12, - ViewMode = viewmode, - OrderBy = orderby, - Criteria = _filterService.Deserialize(filter) - }; + var context = _filterService.CreateFilterProductContext(filter, categoryID, path, pagesize, orderby, viewmode); _filterService.ProductFilterableMultiSelect(context, filterMultiSelect); - return PartialView(new ProductFilterModel { Context = context }); + return PartialView(new ProductFilterModel + { + Context = context, + IsShowAllText = IsShowAllText(context.Criteria), + MaxFilterItemsToDisplay = _catalogSettings.MaxFilterItemsToDisplay, + ExpandAllFilterGroups = _catalogSettings.ExpandAllFilterCriteria + }); } - - } // class + } } diff --git a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs index 31a0557946..58e6eb4ace 100644 --- a/src/Presentation/SmartStore.Web/Controllers/HomeController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/HomeController.cs @@ -1,23 +1,77 @@ -using System.Web.Mvc; -using SmartStore.Web.Framework.Security; -using SmartStore.Core.Domain.Cms; -using SmartStore.Services.Configuration; +using System; +using System.Collections.Generic; using System.Linq; -using System; +using System.Web.Mvc; using SmartStore.Core; -using SmartStore.Services.Media; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Cms; +using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Messages; using SmartStore.Core.Infrastructure; +using SmartStore.Core.Localization; +using SmartStore.Services; +using SmartStore.Services.Catalog; +using SmartStore.Services.Customers; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; +using SmartStore.Services.Messages; +using SmartStore.Services.Seo; +using SmartStore.Services.Topics; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.UI.Captcha; +using SmartStore.Web.Infrastructure.Cache; +using SmartStore.Web.Models.Catalog; +using SmartStore.Web.Models.Common; +using SmartStore.Web.Models.Topics; namespace SmartStore.Web.Controllers { public partial class HomeController : PublicControllerBase - { + { + #region Fields + + private readonly ICommonServices _services; + private readonly Lazy _categoryService; + private readonly Lazy _productService; + private readonly Lazy _manufacturerService; + private readonly Lazy _topicService; + private readonly Lazy _queuedEmailService; + private readonly Lazy _emailAccountService; + private readonly Lazy _sitemapGenerator; + private readonly Lazy _captchaSettings; + private readonly Lazy _commonSettings; + private readonly Lazy _customerSettings; + + #endregion - #region Constructors + #region Constructors - public HomeController() + public HomeController( + ICommonServices services, + Lazy categoryService, + Lazy productService, + Lazy manufacturerService, + Lazy topicService, + Lazy queuedEmailService, + Lazy emailAccountService, + Lazy sitemapGenerator, + Lazy captchaSettings, + Lazy commonSettings, + Lazy customerSettings) { + this._services = services; + this._categoryService = categoryService; + this._productService = productService; + this._manufacturerService = manufacturerService; + this._topicService = topicService; + this._queuedEmailService = queuedEmailService; + this._emailAccountService = emailAccountService; + this._sitemapGenerator = sitemapGenerator; + this._captchaSettings = captchaSettings; + this._commonSettings = commonSettings; + this._customerSettings = customerSettings; } #endregion @@ -25,28 +79,26 @@ public HomeController() [RequireHttpsByConfigAttribute(SslRequirement.No)] public ActionResult Index() { - return View(); + return View(); } [ChildActionOnly] public ActionResult ContentSlider() { - var workContext = EngineContext.Current.Resolve(); - var storeContext = EngineContext.Current.Resolve(); - var pictureService = EngineContext.Current.Resolve(); - var model = EngineContext.Current.Resolve(); + var pictureService = EngineContext.Current.Resolve(); + var settings = _services.Settings.LoadSetting(); - model.BackgroundPictureUrl = pictureService.GetPictureUrl(model.BackgroundPictureId, 0, false); - - var slides = model.Slides + settings.BackgroundPictureUrl = pictureService.GetPictureUrl(settings.BackgroundPictureId, 0, false); + + var slides = settings.Slides .Where(s => - s.LanguageCulture == workContext.WorkingLanguage.LanguageCulture && - (!s.LimitedToStores || (s.SelectedStoreIds != null && s.SelectedStoreIds.Contains(storeContext.CurrentStore.Id))) + s.LanguageCulture == _services.WorkContext.WorkingLanguage.LanguageCulture && + (!s.LimitedToStores || (s.SelectedStoreIds != null && s.SelectedStoreIds.Contains(_services.StoreContext.CurrentStore.Id))) ) .OrderBy(s => s.DisplayOrder); - foreach (ContentSliderSlideSettings slide in slides) + foreach (var slide in slides) { slide.PictureUrl = pictureService.GetPictureUrl(slide.PictureId, 0, false); slide.Button1.Url = CheckButtonUrl(slide.Button1.Url); @@ -54,40 +106,205 @@ public ActionResult ContentSlider() slide.Button3.Url = CheckButtonUrl(slide.Button3.Url); } - model.Slides = slides.ToList(); + settings.Slides = slides.ToList(); - return PartialView(model); + return PartialView(settings); } + public ActionResult StoreClosed() + { + return View(); + } + + [RequireHttpsByConfigAttribute(SslRequirement.No)] + public ActionResult ContactUs() + { + var model = new ContactUsModel() + { + Email = _services.WorkContext.CurrentCustomer.Email, + FullName = _services.WorkContext.CurrentCustomer.GetFullName(), + DisplayCaptcha = _captchaSettings.Value.Enabled && _captchaSettings.Value.ShowOnContactUsPage, + DisplayPrivacyAgreement = _customerSettings.Value.DisplayPrivacyAgreementOnContactUs + + }; + + return View(model); + } + + [HttpPost, ActionName("ContactUs")] + [CaptchaValidator] + public ActionResult ContactUsSend(ContactUsModel model, bool captchaValid) + { + //validate CAPTCHA + if (_captchaSettings.Value.Enabled && _captchaSettings.Value.ShowOnContactUsPage && !captchaValid) + { + ModelState.AddModelError("", T("Common.WrongCaptcha")); + } + + if (ModelState.IsValid) + { + string email = model.Email.Trim(); + string fullName = model.FullName; + string subject = T("ContactUs.EmailSubject", _services.StoreContext.CurrentStore.Name); + + var emailAccount = _emailAccountService.Value.GetDefaultEmailAccount(); + + string from = null; + string fromName = null; + string body = Core.Html.HtmlUtils.FormatText(model.Enquiry, false, true, false, false, false, false); + //required for some SMTP servers + if (_commonSettings.Value.UseSystemEmailForContactUsForm) + { + from = emailAccount.Email; + fromName = emailAccount.DisplayName; + body = string.Format("From: {0} - {1}

          {2}", + Server.HtmlEncode(fullName), + Server.HtmlEncode(email), body); + } + else + { + from = email; + fromName = fullName; + } + _queuedEmailService.Value.InsertQueuedEmail(new QueuedEmail + { + From = from, + FromName = fromName, + To = emailAccount.Email, + ToName = emailAccount.DisplayName, + Priority = 5, + Subject = subject, + Body = body, + CreatedOnUtc = DateTime.UtcNow, + EmailAccountId = emailAccount.Id, + ReplyTo = email, + ReplyToName = fullName + }); + + model.SuccessfullySent = true; + model.Result = T("ContactUs.YourEnquiryHasBeenSent"); + + //activity log + _services.CustomerActivity.InsertActivity("PublicStore.ContactUs", T("ActivityLog.PublicStore.ContactUs")); + + return View(model); + } + + model.DisplayCaptcha = _captchaSettings.Value.Enabled && _captchaSettings.Value.ShowOnContactUsPage; + return View(model); + } + + [RequireHttpsByConfigAttribute(SslRequirement.No)] + public ActionResult SitemapSeo() + { + if (!_commonSettings.Value.SitemapEnabled) + return HttpNotFound(); + + var roleIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); + string cacheKey = ModelCacheEventConsumer.SITEMAP_XML_MODEL_KEY.FormatInvariant(_services.WorkContext.WorkingLanguage.Id, string.Join(",", roleIds), _services.StoreContext.CurrentStore.Id); + var sitemap = _services.Cache.Get(cacheKey, () => + { + return _sitemapGenerator.Value.Generate(this.Url); + }, 120); + + return Content(sitemap, "text/xml"); + } + + [RequireHttpsByConfigAttribute(SslRequirement.No)] + public ActionResult Sitemap() + { + if (!_commonSettings.Value.SitemapEnabled) + return HttpNotFound(); + + var roleIds = _services.WorkContext.CurrentCustomer.CustomerRoles.Where(x => x.Active).Select(x => x.Id).ToList(); + string cacheKey = ModelCacheEventConsumer.SITEMAP_PAGE_MODEL_KEY.FormatInvariant(_services.WorkContext.WorkingLanguage.Id, string.Join(",", roleIds), _services.StoreContext.CurrentStore.Id); + + var result = _services.Cache.Get(cacheKey, () => + { + var model = new SitemapModel(); + if (_commonSettings.Value.SitemapIncludeCategories) + { + var categories = _categoryService.Value.GetAllCategories(); + model.Categories = categories.Select(x => x.ToModel()).ToList(); + } + + if (_commonSettings.Value.SitemapIncludeManufacturers) + { + var manufacturers = _manufacturerService.Value.GetAllManufacturers(); + model.Manufacturers = manufacturers.Select(x => x.ToModel()).ToList(); + } + + if (_commonSettings.Value.SitemapIncludeProducts) + { + //limit product to 200 until paging is supported on this page + IList filterableSpecificationAttributeOptionIds = null; + + var productSearchContext = new ProductSearchContext(); + + productSearchContext.OrderBy = ProductSortingEnum.Position; + productSearchContext.PageSize = 200; + productSearchContext.FilterableSpecificationAttributeOptionIds = filterableSpecificationAttributeOptionIds; + productSearchContext.StoreId = _services.StoreContext.CurrentStoreIdIfMultiStoreMode; + productSearchContext.VisibleIndividuallyOnly = true; + + var products = _productService.Value.SearchProducts(productSearchContext); + + model.Products = products.Select(product => new ProductOverviewModel() + { + Id = product.Id, + Name = product.GetLocalized(x => x.Name).EmptyNull(), + ShortDescription = product.GetLocalized(x => x.ShortDescription), + SeName = product.GetSeName(), + }).ToList(); + } + if (_commonSettings.Value.SitemapIncludeTopics) + { + var topics = _topicService.Value.GetAllTopics(_services.StoreContext.CurrentStore.Id) + .ToList() + .FindAll(t => t.IncludeInSitemap); + + model.Topics = topics.Select(topic => new TopicModel() + { + Id = topic.Id, + SystemName = topic.SystemName, + IncludeInSitemap = topic.IncludeInSitemap, + IsPasswordProtected = topic.IsPasswordProtected, + Title = topic.GetLocalized(x => x.Title), + }) + .ToList(); + } + return model; + }); + + return View(result); + } + #region helper functions private string CheckButtonUrl(string url) { if (!String.IsNullOrEmpty(url)) { - if (url.StartsWith("//") || url.StartsWith("http://")) + if (url.StartsWith("//") || url.StartsWith("/") || url.StartsWith("http://") || url.StartsWith("https://")) { // //www.domain.de/dir // http://www.domain.de/dir // nothing needs to be done + return url; } else if (url.StartsWith("~/")) { // ~/directory - url = Url.Content(url); - } - else if (url.StartsWith("/")) - { - // /directory - url = Url.Content("~" + url); + return Url.Content(url); } else { // directory - url = Url.Content("~/" + url); + return Url.Content("~/" + url); } } - return url; + + return url.EmptyNull(); } #endregion helper functions diff --git a/src/Presentation/SmartStore.Web/Controllers/InstallController.cs b/src/Presentation/SmartStore.Web/Controllers/InstallController.cs index 88ebc57777..7c5a919eb0 100644 --- a/src/Presentation/SmartStore.Web/Controllers/InstallController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/InstallController.cs @@ -1,35 +1,33 @@ using System; using System.Collections.Generic; +using System.Data.Entity; using System.Data.SqlClient; using System.Linq; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; -using System.Web; -using System.Web.Caching; using System.Web.Hosting; using System.Web.Mvc; -using System.ComponentModel.Composition; +using System.Web.SessionState; +using Autofac; using SmartStore.Core; -using SmartStore.Core.Caching; +using SmartStore.Core.Async; using SmartStore.Core.Data; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Infrastructure; using SmartStore.Core.Plugins; +using SmartStore.Data; +using SmartStore.Data.Setup; using SmartStore.Services.Security; +using SmartStore.Utilities; using SmartStore.Web.Framework.Security; using SmartStore.Web.Infrastructure.Installation; using SmartStore.Web.Models.Install; -using SmartStore.Core.Async; -using System.Data.Entity; -using SmartStore.Data; -using SmartStore.Data.Setup; -using System.Configuration; -using SmartStore.Utilities; namespace SmartStore.Web.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public partial class InstallController : Controller { #region Fields @@ -143,7 +141,7 @@ protected string CreateDatabase(string connectionString, string collation) protected string CreateConnectionString( bool trustedConnection, string serverName, string databaseName, - string userName, string password, int timeout = 15 /* codehint: sm-edit (was 0) */) + string userName, string password, int timeout = 15) { var builder = new SqlConnectionStringBuilder(); builder.IntegratedSecurity = trustedConnection; @@ -155,9 +153,8 @@ protected string CreateConnectionString( builder.Password = password; } builder.PersistSecurityInfo = false; - builder.MultipleActiveResultSets = true; + //builder.MultipleActiveResultSets = true; - // codehint: sm-add builder.UserInstance = false; builder.Pooling = true; builder.MinPoolSize = 1; @@ -180,10 +177,10 @@ public ActionResult Index() if (DataSettings.DatabaseIsInstalled()) return RedirectToRoute("HomePage"); - //set page timeout to 5 minutes - this.Server.ScriptTimeout = 300; + // set page timeout to 10 minutes + this.Server.ScriptTimeout = 600; - var model = new InstallModel() + var model = new InstallModel { AdminEmail = _locService.GetResource("AdminEmailValue"), //AdminPassword = "admin", @@ -198,26 +195,34 @@ public ActionResult Index() Collation = "SQL_Latin1_General_CP1_CI_AS", }; - foreach (var lang in _locService.GetAvailableLanguages()) + var curLanguage = _locService.GetCurrentLanguage(); + var availableLanguages = _locService.GetAvailableLanguages(); + + foreach (var lang in availableLanguages) { - model.AvailableLanguages.Add(new SelectListItem() + model.AvailableLanguages.Add(new SelectListItem { Value = Url.Action("ChangeLanguage", "Install", new { language = lang.Code}), Text = lang.Name, - Selected = _locService.GetCurrentLanguage().Code == lang.Code, + Selected = curLanguage.Code == lang.Code, }); } foreach (var lang in _locService.GetAvailableAppLanguages()) { - model.AvailableAppLanguages.Add(new SelectListItem() + model.AvailableAppLanguages.Add(new SelectListItem { Value = lang.Culture, Text = lang.Name, - Selected = lang.Culture == Thread.CurrentThread.CurrentCulture.IetfLanguageTag // TODO (?) + Selected = lang.UniqueSeoCode.IsCaseInsensitiveEqual(curLanguage.Code) }); } + if (!model.AvailableAppLanguages.Any(x => x.Selected)) + { + model.AvailableAppLanguages.FirstOrDefault(x => x.Value.IsCaseInsensitiveEqual("en")).Selected = true; + } + model.AvailableMediaStorages.Add(new SelectListItem { Value = "db", Text = _locService.GetResource("MediaStorage.DB"), Selected = true }); model.AvailableMediaStorages.Add(new SelectListItem { Value = "fs", Text = _locService.GetResource("MediaStorage.FS") }); @@ -233,18 +238,20 @@ public JsonResult Progress() [HttpPost] public async Task Install(InstallModel model) { - var result = await InstallCore(model); - return Json(result); + var t = AsyncRunner.Run( + (c, ct, state) => InstallCore(c, (InstallModel)state), + model, + CancellationToken.None, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); + + return Json(await t); } [NonAction] - protected virtual Task InstallCore(InstallModel model) + protected virtual InstallationResult InstallCore(ILifetimeScope scope, InstallModel model) { - var tcs = new TaskCompletionSource(); - var t = tcs.Task; - var scope = EngineContext.Current.ContainerManager.Scope(); - UpdateResult(x => { x.ProgressMessage = _locService.GetResource("Progress.CheckingRequirements"); @@ -253,12 +260,11 @@ protected virtual Task InstallCore(InstallModel model) if (DataSettings.DatabaseIsInstalled()) { - tcs.SetResult(UpdateResult(x => + return UpdateResult(x => { x.Success = true; x.RedirectUrl = Url.Action("Index", "Home"); - })); - return t; + }); } //set page timeout to 5 minutes @@ -327,7 +333,7 @@ protected virtual Task InstallCore(InstallModel model) //and the configured application pool identity on IIS 7.5) that is used if the application is not impersonating. //If the application is impersonating via , //the identity will be the anonymous user (typically IUSR_MACHINENAME) or the authenticated request user. - var webHelper = EngineContext.Current.ContainerManager.Resolve(scope: scope); + var webHelper = scope.Resolve(); //validate permissions var dirsToCheck = FilePermissionHelper.GetDirectoriesWrite(webHelper); foreach (string dir in dirsToCheck) @@ -349,13 +355,12 @@ protected virtual Task InstallCore(InstallModel model) if (GetInstallResult().HasErrors) { - tcs.SetResult(UpdateResult(x => + return UpdateResult(x => { x.Completed = true; x.Success = false; x.RedirectUrl = null; - })); - return t; + }); } else { @@ -397,14 +402,13 @@ protected virtual Task InstallCore(InstallModel model) var errorCreatingDatabase = CreateDatabase(connectionString, collation); if (errorCreatingDatabase.HasValue()) { - tcs.SetResult(UpdateResult(x => + return UpdateResult(x => { x.Errors.Add(errorCreatingDatabase); x.Completed = true; x.Success = false; x.RedirectUrl = null; - })); - return t; + }); } else { @@ -421,14 +425,13 @@ protected virtual Task InstallCore(InstallModel model) //check whether database exists if (!SqlServerDatabaseExists(connectionString)) { - tcs.SetResult(UpdateResult(x => + return UpdateResult(x => { x.Errors.Add(_locService.GetResource("DatabaseNotExists")); x.Completed = true; x.Success = false; x.RedirectUrl = null; - })); - return t; + }); } } } @@ -452,12 +455,13 @@ protected virtual Task InstallCore(InstallModel model) // save settings var dataProvider = model.DataProvider; var settings = DataSettings.Current; + settings.AppVersion = SmartStoreVersion.Version; settings.DataProvider = dataProvider; settings.DataConnectionString = connectionString; settings.Save(); // init data provider - var dataProviderInstance = EngineContext.Current.ContainerManager.Resolve(scope: scope); + var dataProviderInstance = scope.Resolve(); // Although obsolete we have no other chance than using this here. // Delegating this to DbConfiguration is not possible during installation. @@ -469,14 +473,13 @@ protected virtual Task InstallCore(InstallModel model) var lazyLanguage = _locService.GetAppLanguage(model.PrimaryLanguage); if (lazyLanguage == null) { - tcs.SetResult(UpdateResult(x => + return UpdateResult(x => { - x.Errors.Add(string.Format("The install language '{0}' is not registered", model.PrimaryLanguage)); + x.Errors.Add(_locService.GetResource("Install.LanguageNotRegistered").FormatInvariant(model.PrimaryLanguage)); x.Completed = true; x.Success = false; x.RedirectUrl = null; - })); - return t; + }); } // create the DataContext @@ -514,7 +517,7 @@ protected virtual Task InstallCore(InstallModel model) // install plugins PluginManager.MarkAllPluginsAsUninstalled(); - var pluginFinder = EngineContext.Current.ContainerManager.Resolve(scope: scope); + var pluginFinder = scope.Resolve(); var plugins = pluginFinder.GetPlugins(false) //.ToList() .OrderBy(x => x.PluginDescriptor.Group) @@ -537,7 +540,7 @@ protected virtual Task InstallCore(InstallModel model) var pluginsCount = plugins.Count; var idx = 0; - using (var dbScope = new DbContextScope(autoDetectChanges: false)) { + using (var dbScope = new DbContextScope(autoDetectChanges: false, hooksEnabled: false)) { foreach (var plugin in plugins) { try @@ -565,17 +568,16 @@ protected virtual Task InstallCore(InstallModel model) foreach (var providerType in permissionProviders) { dynamic provider = Activator.CreateInstance(providerType); - EngineContext.Current.ContainerManager.Resolve(scope: scope).InstallPermissions(provider); + scope.Resolve().InstallPermissions(provider); } // SUCCESS: Redirect to home page - tcs.SetResult(UpdateResult(x => + return UpdateResult(x => { x.Completed = true; x.Success = true; x.RedirectUrl = Url.Action("Index", "Home"); - })); - return t; + }); } catch (Exception exception) { @@ -604,14 +606,13 @@ protected virtual Task InstallCore(InstallModel model) msg += " (" + realException.Message + ")"; } - tcs.SetResult(UpdateResult(x => + return UpdateResult(x => { x.Errors.Add(string.Format(_locService.GetResource("SetupFailed"), msg)); x.Success = false; x.Completed = true; x.RedirectUrl = null; - })); - return t; + }); } finally { diff --git a/src/Presentation/SmartStore.Web/Controllers/KeepAliveController.cs b/src/Presentation/SmartStore.Web/Controllers/KeepAliveController.cs deleted file mode 100644 index 3093193eb9..0000000000 --- a/src/Presentation/SmartStore.Web/Controllers/KeepAliveController.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Web.Mvc; - -namespace SmartStore.Web.Controllers -{ - public partial class KeepAliveController : Controller - { - public ActionResult Index() - { - return Content("I am alive!"); - } - } -} diff --git a/src/Presentation/SmartStore.Web/Controllers/NewsController.cs b/src/Presentation/SmartStore.Web/Controllers/NewsController.cs index f43052ea69..b285065191 100644 --- a/src/Presentation/SmartStore.Web/Controllers/NewsController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/NewsController.cs @@ -5,23 +5,24 @@ using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Caching; -using SmartStore.Core.Domain; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Media; using SmartStore.Core.Domain.News; +using SmartStore.Core.Logging; using SmartStore.Services.Common; using SmartStore.Services.Customers; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; -using SmartStore.Core.Logging; using SmartStore.Services.Media; using SmartStore.Services.Messages; using SmartStore.Services.News; using SmartStore.Services.Seo; using SmartStore.Services.Stores; -using SmartStore.Web.Framework; +using SmartStore.Utilities; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.UI.Captcha; using SmartStore.Web.Infrastructure.Cache; @@ -46,6 +47,7 @@ public partial class NewsController : PublicControllerBase private readonly ICacheManager _cacheManager; private readonly ICustomerActivityService _customerActivityService; private readonly IStoreMappingService _storeMappingService; + private readonly ILanguageService _languageService; private readonly MediaSettings _mediaSettings; private readonly NewsSettings _newsSettings; @@ -64,6 +66,7 @@ public NewsController(INewsService newsService, IWorkflowMessageService workflowMessageService, IWebHelper webHelper, ICacheManager cacheManager, ICustomerActivityService customerActivityService, IStoreMappingService storeMappingService, + ILanguageService languageService, MediaSettings mediaSettings, NewsSettings newsSettings, LocalizationSettings localizationSettings, CustomerSettings customerSettings, CaptchaSettings captchaSettings) @@ -80,6 +83,7 @@ public NewsController(INewsService newsService, this._cacheManager = cacheManager; this._customerActivityService = customerActivityService; this._storeMappingService = storeMappingService; + this._languageService = languageService; this._mediaSettings = mediaSettings; this._newsSettings = newsSettings; @@ -110,7 +114,7 @@ protected void PrepareNewsItemModel(NewsItemModel model, NewsItem newsItem, bool model.Short = newsItem.Short; model.Full = newsItem.Full; model.AllowComments = newsItem.AllowComments; - model.AvatarPictureSize = _mediaSettings.AvatarPictureSize; // codehint: sm-add + model.AvatarPictureSize = _mediaSettings.AvatarPictureSize; model.CreatedOn = _dateTimeHelper.ConvertToUserTime(newsItem.CreatedOnUtc, DateTimeKind.Utc); model.NumberOfComments = newsItem.ApprovedCommentCount; model.AddNewComment.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnNewsCommentPage; @@ -182,7 +186,7 @@ public ActionResult HomePageNews() public ActionResult List(NewsPagingFilteringModel command) { if (!_newsSettings.Enabled) - return RedirectToRoute("HomePage"); + return HttpNotFound(); var model = new NewsItemListModel(); model.WorkingLanguageId = _workContext.WorkingLanguage.Id; @@ -208,33 +212,49 @@ public ActionResult List(NewsPagingFilteringModel command) return View(model); } + [ActionName("rss"), Compress] public ActionResult ListRss(int languageId) { - var feed = new SyndicationFeed( - string.Format("{0}: News", _storeContext.CurrentStore.Name), - "News", - new Uri(_webHelper.GetStoreLocation(false)), - "NewsRSS", - DateTime.UtcNow); + DateTime? maxAge = null; + var protocol = _webHelper.IsCurrentConnectionSecured() ? "https" : "http"; + var selfLink = Url.Action("rss", "News", new { languageId = languageId }, protocol); + var newsLink = Url.RouteUrl("NewsArchive", null, protocol); - if (!_newsSettings.Enabled) - return new RssActionResult() { Feed = feed }; + var title = "{0} - News".FormatInvariant(_storeContext.CurrentStore.Name); - var items = new List(); - var newsItems = _newsService.GetAllNews(languageId, _storeContext.CurrentStore.Id, 0, int.MaxValue); - foreach (var n in newsItems) - { - string newsUrl = Url.RouteUrl("NewsItem", new { SeName = n.GetSeName(n.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); - items.Add(new SyndicationItem(n.Title, n.Short, new Uri(newsUrl), String.Format("Blog:{0}", n.Id), n.CreatedOnUtc)); - } - feed.Items = items; - return new RssActionResult() { Feed = feed }; + if (_newsSettings.MaxAgeInDays > 0) + maxAge = DateTime.UtcNow.Subtract(new TimeSpan(_newsSettings.MaxAgeInDays, 0, 0, 0)); + + var language = _languageService.GetLanguageById(languageId); + var feed = new SmartSyndicationFeed(new Uri(newsLink), title); + + feed.AddNamespaces(true); + feed.Init(selfLink, language); + + if (!_newsSettings.Enabled) + return new RssActionResult { Feed = feed }; + + var items = new List(); + var newsItems = _newsService.GetAllNews(languageId, _storeContext.CurrentStore.Id, 0, int.MaxValue, false, maxAge); + + foreach (var news in newsItems) + { + var newsUrl = Url.RouteUrl("NewsItem", new { SeName = news.GetSeName(news.LanguageId, ensureTwoPublishedLanguages: false) }, "http"); + + var item = feed.CreateItem(news.Title, news.Short, newsUrl, news.CreatedOnUtc, news.Full); + + items.Add(item); + } + + feed.Items = items; + + return new RssActionResult { Feed = feed }; } public ActionResult NewsItem(int newsItemId) { if (!_newsSettings.Enabled) - return RedirectToRoute("HomePage"); + return HttpNotFound(); var newsItem = _newsService.GetNewsById(newsItemId); if (newsItem == null || @@ -243,7 +263,7 @@ public ActionResult NewsItem(int newsItemId) (newsItem.EndDateUtc.HasValue && newsItem.EndDateUtc.Value <= DateTime.UtcNow) || //Store mapping !_storeMappingService.Authorize(newsItem)) - return RedirectToRoute("HomePage"); + return HttpNotFound(); var model = new NewsItemModel(); PrepareNewsItemModel(model, newsItem, true); @@ -257,11 +277,11 @@ public ActionResult NewsItem(int newsItemId) public ActionResult NewsCommentAdd(int newsItemId, NewsItemModel model, bool captchaValid) { if (!_newsSettings.Enabled) - return RedirectToRoute("HomePage"); + return HttpNotFound(); var newsItem = _newsService.GetNewsById(newsItemId); if (newsItem == null || !newsItem.Published || !newsItem.AllowComments) - return RedirectToRoute("HomePage"); + return HttpNotFound(); //validate CAPTCHA if (_captchaSettings.Enabled && _captchaSettings.ShowOnNewsCommentPage && !captchaValid) @@ -299,13 +319,11 @@ public ActionResult NewsCommentAdd(int newsItemId, NewsItemModel model, bool cap //activity log _customerActivityService.InsertActivity("PublicStore.AddNewsComment", _localizationService.GetResource("ActivityLog.PublicStore.AddNewsComment")); - //The text boxes should be cleared after a comment has been posted - //That' why we reload the page - TempData["sm.news.addcomment.result"] = _localizationService.GetResource("News.Comments.SuccessfullyAdded"); + NotifySuccess(T("News.Comments.SuccessfullyAdded")); + return RedirectToRoute("NewsItem", new { SeName = newsItem.GetSeName(newsItem.LanguageId, ensureTwoPublishedLanguages: false) }); } - //If we got this far, something failed, redisplay form PrepareNewsItemModel(model, newsItem, true); return View(model); @@ -318,7 +336,8 @@ public ActionResult RssHeaderLink() return Content(""); string link = string.Format("", - Url.RouteUrl("NewsRSS", new { languageId = _workContext.WorkingLanguage.Id }, _webHelper.IsCurrentConnectionSecured() ? "https" : "http"), _storeContext.CurrentStore.Name); + Url.Action("rss", null, new { languageId = _workContext.WorkingLanguage.Id }, _webHelper.IsCurrentConnectionSecured() ? "https" : "http"), + _storeContext.CurrentStore.Name); return Content(link); } diff --git a/src/Presentation/SmartStore.Web/Controllers/NewsletterController.cs b/src/Presentation/SmartStore.Web/Controllers/NewsletterController.cs index cc900c4550..d41e2a40b0 100644 --- a/src/Presentation/SmartStore.Web/Controllers/NewsletterController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/NewsletterController.cs @@ -3,16 +3,14 @@ using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Messages; -using SmartStore.Services.Localization; using SmartStore.Services.Messages; -using SmartStore.Web.Models.Newsletter; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Models.Newsletter; namespace SmartStore.Web.Controllers { - public partial class NewsletterController : PublicControllerBase + public partial class NewsletterController : PublicControllerBase { - private readonly ILocalizationService _localizationService; private readonly IWorkContext _workContext; private readonly INewsLetterSubscriptionService _newsLetterSubscriptionService; private readonly IWorkflowMessageService _workflowMessageService; @@ -20,12 +18,13 @@ public partial class NewsletterController : PublicControllerBase private readonly CustomerSettings _customerSettings; - public NewsletterController(ILocalizationService localizationService, - IWorkContext workContext, INewsLetterSubscriptionService newsLetterSubscriptionService, - IWorkflowMessageService workflowMessageService, CustomerSettings customerSettings, + public NewsletterController( + IWorkContext workContext, + INewsLetterSubscriptionService newsLetterSubscriptionService, + IWorkflowMessageService workflowMessageService, + CustomerSettings customerSettings, IStoreContext storeContext) { - this._localizationService = localizationService; this._workContext = workContext; this._newsLetterSubscriptionService = newsLetterSubscriptionService; this._workflowMessageService = workflowMessageService; @@ -44,59 +43,62 @@ public ActionResult NewsletterBox() [HttpPost] [ValidateInput(false)] - public ActionResult SubscribeNewsletter(bool subscribe, string email) + public ActionResult Subscribe(bool subscribe, string email) { string result; - bool success = false; + var success = false; if (!email.IsEmail()) - result = _localizationService.GetResource("Newsletter.Email.Wrong"); - else - { - //subscribe/unsubscribe - email = email.Trim(); - - var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(email, _storeContext.CurrentStore.Id); - if (subscription != null) - { - if (subscribe) - { - if (!subscription.Active) - { - _workflowMessageService.SendNewsLetterSubscriptionActivationMessage(subscription, _workContext.WorkingLanguage.Id); - } - result = _localizationService.GetResource("Newsletter.SubscribeEmailSent"); - } - else - { - if (subscription.Active) - { - _workflowMessageService.SendNewsLetterSubscriptionDeactivationMessage(subscription, _workContext.WorkingLanguage.Id); - } - result = _localizationService.GetResource("Newsletter.UnsubscribeEmailSent"); - } - } - else if (subscribe) - { - subscription = new NewsLetterSubscription() - { - NewsLetterSubscriptionGuid = Guid.NewGuid(), - Email = email, - Active = false, - CreatedOnUtc = DateTime.UtcNow, + { + result = T("Newsletter.Email.Wrong"); + } + else + { + //subscribe/unsubscribe + email = email.Trim(); + + var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByEmail(email, _storeContext.CurrentStore.Id); + if (subscription != null) + { + if (subscribe) + { + if (!subscription.Active) + { + _workflowMessageService.SendNewsLetterSubscriptionActivationMessage(subscription, _workContext.WorkingLanguage.Id); + } + result = T("Newsletter.SubscribeEmailSent"); + } + else + { + if (subscription.Active) + { + _workflowMessageService.SendNewsLetterSubscriptionDeactivationMessage(subscription, _workContext.WorkingLanguage.Id); + } + result = T("Newsletter.UnsubscribeEmailSent"); + } + } + else if (subscribe) + { + subscription = new NewsLetterSubscription + { + NewsLetterSubscriptionGuid = Guid.NewGuid(), + Email = email, + Active = false, + CreatedOnUtc = DateTime.UtcNow, StoreId = _storeContext.CurrentStore.Id - }; - _newsLetterSubscriptionService.InsertNewsLetterSubscription(subscription); - _workflowMessageService.SendNewsLetterSubscriptionActivationMessage(subscription, _workContext.WorkingLanguage.Id); - - result = _localizationService.GetResource("Newsletter.SubscribeEmailSent"); - } - else - { - result = _localizationService.GetResource("Newsletter.UnsubscribeEmailSent"); - } - success = true; - } + }; + + _newsLetterSubscriptionService.InsertNewsLetterSubscription(subscription); + _workflowMessageService.SendNewsLetterSubscriptionActivationMessage(subscription, _workContext.WorkingLanguage.Id); + + result = T("Newsletter.SubscribeEmailSent"); + } + else + { + result = T("Newsletter.UnsubscribeEmailSent"); + } + success = true; + } return Json(new { @@ -106,27 +108,28 @@ public ActionResult SubscribeNewsletter(bool subscribe, string email) } public ActionResult SubscriptionActivation(Guid token, bool active) - { - var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByGuid(token); - if (subscription == null) - return RedirectToRoute("HomePage"); + { + var subscription = _newsLetterSubscriptionService.GetNewsLetterSubscriptionByGuid(token); + if (subscription == null) + { + return HttpNotFound(); + } var model = new SubscriptionActivationModel(); - if (active) - { - subscription.Active = active; - _newsLetterSubscriptionService.UpdateNewsLetterSubscription(subscription); - } - else - _newsLetterSubscriptionService.DeleteNewsLetterSubscription(subscription); - - if (active) - model.Result = _localizationService.GetResource("Newsletter.ResultActivated"); - else - model.Result = _localizationService.GetResource("Newsletter.ResultDeactivated"); - - return View(model); + if (active) + { + subscription.Active = active; + _newsLetterSubscriptionService.UpdateNewsLetterSubscription(subscription); + } + else + { + _newsLetterSubscriptionService.DeleteNewsLetterSubscription(subscription); + } + + model.Result = T(active ? "Newsletter.ResultActivated" : "Newsletter.ResultDeactivated"); + + return View(model); } } } diff --git a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs index 409218d52f..448a1983d3 100644 --- a/src/Presentation/SmartStore.Web/Controllers/OrderController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/OrderController.cs @@ -1,27 +1,32 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Net.Mime; using System.Web.Mvc; -using SmartStore.Core; +using System.Web.Routing; +using SmartStore.Core.Data; using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Common; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Tax; using SmartStore.Core.Html; +using SmartStore.Services; using SmartStore.Services.Catalog; -using SmartStore.Services.Common; using SmartStore.Services.Directory; using SmartStore.Services.Helpers; using SmartStore.Services.Localization; +using SmartStore.Services.Media; using SmartStore.Services.Orders; using SmartStore.Services.Payments; +using SmartStore.Services.Pdf; +using SmartStore.Services.Security; using SmartStore.Services.Seo; using SmartStore.Services.Shipping; -using SmartStore.Web.Extensions; +using SmartStore.Services.Stores; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Pdf; +using SmartStore.Web.Framework.Plugins; using SmartStore.Web.Framework.Security; using SmartStore.Web.Models.Order; @@ -33,70 +38,66 @@ public partial class OrderController : PublicControllerBase private readonly IOrderService _orderService; private readonly IShipmentService _shipmentService; - private readonly IWorkContext _workContext; private readonly ICurrencyService _currencyService; private readonly IPriceFormatter _priceFormatter; private readonly IOrderProcessingService _orderProcessingService; private readonly IDateTimeHelper _dateTimeHelper; private readonly IPaymentService _paymentService; - private readonly ILocalizationService _localizationService; - private readonly IPdfService _pdfService; + private readonly IPdfConverter _pdfConverter; private readonly IShippingService _shippingService; private readonly ICountryService _countryService; - private readonly IWebHelper _webHelper; private readonly IProductService _productService; private readonly IProductAttributeFormatter _productAttributeFormatter; + private readonly IProductAttributeParser _productAttributeParser; + private readonly IStoreService _storeService; + private readonly ICheckoutAttributeFormatter _checkoutAttributeFormatter; + private readonly PluginMediator _pluginMediator; + private readonly ICommonServices _services; + private readonly IQuantityUnitService _quantityUnitService; - private readonly OrderSettings _orderSettings; - private readonly TaxSettings _taxSettings; - private readonly CatalogSettings _catalogSettings; - private readonly PdfSettings _pdfSettings; - private readonly ShippingSettings _shippingSettings; - private readonly AddressSettings _addressSettings; - - private readonly ICheckoutAttributeFormatter _checkoutAttributeFormatter; //codehint: sm-add #endregion #region Constructors - public OrderController(IOrderService orderService, - IShipmentService shipmentService, IWorkContext workContext, - ICurrencyService currencyService, IPriceFormatter priceFormatter, - IOrderProcessingService orderProcessingService, IDateTimeHelper dateTimeHelper, - IPaymentService paymentService, ILocalizationService localizationService, - IPdfService pdfService, IShippingService shippingService, - ICountryService countryService, IWebHelper webHelper, - CatalogSettings catalogSettings, OrderSettings orderSettings, - TaxSettings taxSettings, PdfSettings pdfSettings, - ShippingSettings shippingSettings, AddressSettings addressSettings, + public OrderController( + IOrderService orderService, + IShipmentService shipmentService, + ICurrencyService currencyService, + IPriceFormatter priceFormatter, + IOrderProcessingService orderProcessingService, + IDateTimeHelper dateTimeHelper, + IPaymentService paymentService, + IPdfConverter pdfConverter, + IShippingService shippingService, + ICountryService countryService, ICheckoutAttributeFormatter checkoutAttributeFormatter, + IStoreService storeService, IProductService productService, - IProductAttributeFormatter productAttributeFormatter) + IProductAttributeFormatter productAttributeFormatter, + IProductAttributeParser productAttributeParser, + Lazy pictureService, + PluginMediator pluginMediator, + ICommonServices services, + IQuantityUnitService quantityUnitService) { this._orderService = orderService; this._shipmentService = shipmentService; - this._workContext = workContext; this._currencyService = currencyService; this._priceFormatter = priceFormatter; this._orderProcessingService = orderProcessingService; this._dateTimeHelper = dateTimeHelper; this._paymentService = paymentService; - this._localizationService = localizationService; - this._pdfService = pdfService; + this._pdfConverter = pdfConverter; this._shippingService = shippingService; this._countryService = countryService; - this._webHelper = webHelper; this._productService = productService; this._productAttributeFormatter = productAttributeFormatter; - - this._catalogSettings = catalogSettings; - this._orderSettings = orderSettings; - this._taxSettings = taxSettings; - this._pdfSettings = pdfSettings; - this._shippingSettings = shippingSettings; - this._addressSettings = addressSettings; - - this._checkoutAttributeFormatter = checkoutAttributeFormatter; //codehint: sm-add + this._productAttributeParser = productAttributeParser; + this._storeService = storeService; + this._checkoutAttributeFormatter = checkoutAttributeFormatter; + this._pluginMediator = pluginMediator; + this._services = services; + this._quantityUnitService = quantityUnitService; } #endregion @@ -104,26 +105,40 @@ public OrderController(IOrderService orderService, #region Utilities [NonAction] - protected OrderDetailsModel PrepareOrderDetailsModel(Order order) + protected OrderDetailsModel PrepareOrderDetailsModel(Order order) { if (order == null) - throw new ArgumentNullException("order"); - var model = new OrderDetailsModel(); + throw new ArgumentNullException("order"); + + var store = _storeService.GetStoreById(order.StoreId) ?? _services.StoreContext.CurrentStore; + var language = _services.WorkContext.WorkingLanguage; + + var orderSettings = _services.Settings.LoadSetting(store.Id); + var catalogSettings = _services.Settings.LoadSetting(store.Id); + var taxSettings = _services.Settings.LoadSetting(store.Id); + var pdfSettings = _services.Settings.LoadSetting(store.Id); + var addressSettings = _services.Settings.LoadSetting(store.Id); + var companyInfoSettings = _services.Settings.LoadSetting(store.Id); + var model = new OrderDetailsModel(); + + model.MerchantCompanyInfo = companyInfoSettings; model.Id = order.Id; + model.StoreId = order.StoreId; model.OrderNumber = order.GetOrderNumber(); model.CreatedOn = _dateTimeHelper.ConvertToUserTime(order.CreatedOnUtc, DateTimeKind.Utc); - model.OrderStatus = order.OrderStatus.GetLocalizedEnum(_localizationService, _workContext); - model.IsReOrderAllowed = _orderSettings.IsReOrderAllowed; + model.OrderStatus = order.OrderStatus.GetLocalizedEnum(_services.Localization, _services.WorkContext); + model.IsReOrderAllowed = orderSettings.IsReOrderAllowed; model.IsReturnRequestAllowed = _orderProcessingService.IsReturnRequestAllowed(order); - model.DisplayPdfInvoice = _pdfSettings.Enabled; + model.DisplayPdfInvoice = pdfSettings.Enabled; + model.RenderOrderNotes = pdfSettings.RenderOrderNotes; //shipping info - model.ShippingStatus = order.ShippingStatus.GetLocalizedEnum(_localizationService, _workContext); + model.ShippingStatus = order.ShippingStatus.GetLocalizedEnum(_services.Localization, _services.WorkContext); if (order.ShippingStatus != ShippingStatus.ShippingNotRequired) { model.IsShippable = true; - model.ShippingAddress.PrepareModel(order.ShippingAddress, false, _addressSettings); + model.ShippingAddress.PrepareModel(order.ShippingAddress, false, addressSettings); model.ShippingMethod = order.ShippingMethod; @@ -131,7 +146,7 @@ protected OrderDetailsModel PrepareOrderDetailsModel(Order order) var shipments = order.Shipments.Where(x => x.ShippedDateUtc.HasValue).OrderBy(x => x.CreatedOnUtc).ToList(); foreach (var shipment in shipments) { - var shipmentModel = new OrderDetailsModel.ShipmentBriefModel() + var shipmentModel = new OrderDetailsModel.ShipmentBriefModel { Id = shipment.Id, TrackingNumber = shipment.TrackingNumber, @@ -146,133 +161,162 @@ protected OrderDetailsModel PrepareOrderDetailsModel(Order order) //billing info - model.BillingAddress.PrepareModel(order.BillingAddress, false, _addressSettings); + model.BillingAddress.PrepareModel(order.BillingAddress, false, addressSettings); //VAT number model.VatNumber = order.VatNumber; //payment method var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(order.PaymentMethodSystemName); - model.PaymentMethod = paymentMethod != null ? paymentMethod.GetLocalizedValue(_localizationService, "FriendlyName", _workContext.WorkingLanguage.Id) : order.PaymentMethodSystemName; + model.PaymentMethod = paymentMethod != null ? _pluginMediator.GetLocalizedFriendlyName(paymentMethod.Metadata) : order.PaymentMethodSystemName; model.CanRePostProcessPayment = _paymentService.CanRePostProcessPayment(order); //purchase order number (we have to find a better to inject this information because it's related to a certain plugin) - if (paymentMethod != null && paymentMethod.PluginDescriptor.SystemName.Equals("Payments.PurchaseOrder", StringComparison.InvariantCultureIgnoreCase)) + if (paymentMethod != null && paymentMethod.Metadata.SystemName.Equals("SmartStore.PurchaseOrderNumber", StringComparison.InvariantCultureIgnoreCase)) { model.DisplayPurchaseOrderNumber = true; model.PurchaseOrderNumber = order.PurchaseOrderNumber; } - //totals) + // totals switch (order.CustomerTaxDisplayType) { case TaxDisplayType.ExcludingTax: { //order subtotal - var orderSubtotalExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate); - model.OrderSubtotal = _priceFormatter.FormatPrice(orderSubtotalExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, false); - //discount (applied to order subtotal) - var orderSubTotalDiscountExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountExclTax, order.CurrencyRate); - if (orderSubTotalDiscountExclTaxInCustomerCurrency > decimal.Zero) - model.OrderSubTotalDiscount = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, false); - //order shipping - var orderShippingExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingExclTax, order.CurrencyRate); - model.OrderShipping = _priceFormatter.FormatShippingPrice(orderShippingExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, false); + var orderSubtotalExclTax = _currencyService.ConvertCurrency(order.OrderSubtotalExclTax, order.CurrencyRate); + model.OrderSubtotal = _priceFormatter.FormatPrice(orderSubtotalExclTax, true, order.CustomerCurrencyCode, language, false, false); + + //discount (applied to order subtotal) + var orderSubTotalDiscountExclTax = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountExclTax, order.CurrencyRate); + if (orderSubTotalDiscountExclTax > decimal.Zero) + { + model.OrderSubTotalDiscount = _priceFormatter.FormatPrice(-orderSubTotalDiscountExclTax, true, order.CustomerCurrencyCode, language, false, false); + } + + //order shipping + var orderShippingExclTax = _currencyService.ConvertCurrency(order.OrderShippingExclTax, order.CurrencyRate); + model.OrderShipping = _priceFormatter.FormatShippingPrice(orderShippingExclTax, true, order.CustomerCurrencyCode, language, false, false); + //payment method additional fee - var paymentMethodAdditionalFeeExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeExclTax, order.CurrencyRate); - if (paymentMethodAdditionalFeeExclTaxInCustomerCurrency > decimal.Zero) - model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, false); + var paymentMethodAdditionalFeeExclTax = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeExclTax, order.CurrencyRate); + if (paymentMethodAdditionalFeeExclTax != decimal.Zero) + { + model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeExclTax, true, order.CustomerCurrencyCode, + language, false, false); + } } break; + case TaxDisplayType.IncludingTax: { //order subtotal - var orderSubtotalInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate); - model.OrderSubtotal = _priceFormatter.FormatPrice(orderSubtotalInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, true); - //discount (applied to order subtotal) - var orderSubTotalDiscountInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountInclTax, order.CurrencyRate); - if (orderSubTotalDiscountInclTaxInCustomerCurrency > decimal.Zero) - model.OrderSubTotalDiscount = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, true); + var orderSubtotalInclTax = _currencyService.ConvertCurrency(order.OrderSubtotalInclTax, order.CurrencyRate); + model.OrderSubtotal = _priceFormatter.FormatPrice(orderSubtotalInclTax, true, order.CustomerCurrencyCode, language, true, false); + + //discount (applied to order subtotal) + var orderSubTotalDiscountInclTax = _currencyService.ConvertCurrency(order.OrderSubTotalDiscountInclTax, order.CurrencyRate); + if (orderSubTotalDiscountInclTax > decimal.Zero) + { + model.OrderSubTotalDiscount = _priceFormatter.FormatPrice(-orderSubTotalDiscountInclTax, true, order.CustomerCurrencyCode, language, true, false); + } + //order shipping - var orderShippingInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderShippingInclTax, order.CurrencyRate); - model.OrderShipping = _priceFormatter.FormatShippingPrice(orderShippingInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, true); - //payment method additional fee - var paymentMethodAdditionalFeeInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeInclTax, order.CurrencyRate); - if (paymentMethodAdditionalFeeInclTaxInCustomerCurrency > decimal.Zero) - model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, true); + var orderShippingInclTax = _currencyService.ConvertCurrency(order.OrderShippingInclTax, order.CurrencyRate); + model.OrderShipping = _priceFormatter.FormatShippingPrice(orderShippingInclTax, true, order.CustomerCurrencyCode, language, true, false); + + //payment method additional fee + var paymentMethodAdditionalFeeInclTax = _currencyService.ConvertCurrency(order.PaymentMethodAdditionalFeeInclTax, order.CurrencyRate); + if (paymentMethodAdditionalFeeInclTax != decimal.Zero) + { + model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeInclTax, true, order.CustomerCurrencyCode, + language, true, false); + } } break; } //tax - bool displayTax = true; - bool displayTaxRates = true; - if (_taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax) + var displayTax = true; + var displayTaxRates = true; + + if (taxSettings.HideTaxInOrderSummary && order.CustomerTaxDisplayType == TaxDisplayType.IncludingTax) { displayTax = false; displayTaxRates = false; } else { - if (order.OrderTax == 0 && _taxSettings.HideZeroTax) + if (order.OrderTax == 0 && taxSettings.HideZeroTax) { displayTax = false; displayTaxRates = false; } else { - displayTaxRates = _taxSettings.DisplayTaxRates && order.TaxRatesDictionary.Count > 0; + displayTaxRates = taxSettings.DisplayTaxRates && order.TaxRatesDictionary.Count > 0; displayTax = !displayTaxRates; var orderTaxInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTax, order.CurrencyRate); - //TODO pass languageId to _priceFormatter.FormatPrice - model.Tax = _priceFormatter.FormatPrice(orderTaxInCustomerCurrency, true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage); + model.Tax = _priceFormatter.FormatPrice(orderTaxInCustomerCurrency, true, order.CustomerCurrencyCode, false, language); foreach (var tr in order.TaxRatesDictionary) { - model.TaxRates.Add(new OrderDetailsModel.TaxRate() + var rate = _priceFormatter.FormatTaxRate(tr.Key); + //var labelKey = "ShoppingCart.Totals.TaxRateLine" + (_services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax ? "Incl" : "Excl"); + var labelKey = (_services.WorkContext.TaxDisplayType == TaxDisplayType.IncludingTax ? "ShoppingCart.Totals.TaxRateLineIncl" : "ShoppingCart.Totals.TaxRateLineExcl"); + + model.TaxRates.Add(new OrderDetailsModel.TaxRate { - Rate = _priceFormatter.FormatTaxRate(tr.Key), - //TODO pass languageId to _priceFormatter.FormatPrice - Value = _priceFormatter.FormatPrice(_currencyService.ConvertCurrency(tr.Value, order.CurrencyRate), true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage), + Rate = rate, + Label = T(labelKey).Text.FormatCurrent(rate), + Value = _priceFormatter.FormatPrice(_currencyService.ConvertCurrency(tr.Value, order.CurrencyRate), true, order.CustomerCurrencyCode, false, language), }); } } } + model.DisplayTaxRates = displayTaxRates; model.DisplayTax = displayTax; //discount (applied to order total) var orderDiscountInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderDiscount, order.CurrencyRate); - if (orderDiscountInCustomerCurrency > decimal.Zero) - model.OrderTotalDiscount = _priceFormatter.FormatPrice(-orderDiscountInCustomerCurrency, true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage); - + if (orderDiscountInCustomerCurrency > decimal.Zero) + { + model.OrderTotalDiscount = _priceFormatter.FormatPrice(-orderDiscountInCustomerCurrency, true, order.CustomerCurrencyCode, false, language); + } //gift cards foreach (var gcuh in order.GiftCardUsageHistory) { - model.GiftCards.Add(new OrderDetailsModel.GiftCard() - { - CouponCode = gcuh.GiftCard.GiftCardCouponCode, - Amount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(gcuh.UsedValue, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage), - }); - } + var remainingAmountBase = gcuh.GiftCard.GetGiftCardRemainingAmount(); + var remainingAmount = _currencyService.ConvertCurrency(remainingAmountBase, order.CurrencyRate); + + var gcModel = new OrderDetailsModel.GiftCard + { + CouponCode = gcuh.GiftCard.GiftCardCouponCode, + Amount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(gcuh.UsedValue, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, language), + Remaining = _priceFormatter.FormatPrice(remainingAmount, true, false) + }; + + model.GiftCards.Add(gcModel); + } //reward points if (order.RedeemedRewardPointsEntry != null) { model.RedeemedRewardPoints = -order.RedeemedRewardPointsEntry.Points; - model.RedeemedRewardPointsAmount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(order.RedeemedRewardPointsEntry.UsedAmount, order.CurrencyRate)), true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage); + model.RedeemedRewardPointsAmount = _priceFormatter.FormatPrice(-(_currencyService.ConvertCurrency(order.RedeemedRewardPointsEntry.UsedAmount, order.CurrencyRate)), + true, order.CustomerCurrencyCode, false, language); } //total var orderTotalInCustomerCurrency = _currencyService.ConvertCurrency(order.OrderTotal, order.CurrencyRate); - model.OrderTotal = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, _workContext.WorkingLanguage); + model.OrderTotal = _priceFormatter.FormatPrice(orderTotalInCustomerCurrency, true, order.CustomerCurrencyCode, false, language); //checkout attributes - //codehint: sm-edit model.CheckoutAttributeInfo = HtmlUtils.ConvertPlainTextToTable(HtmlUtils.ConvertHtmlToPlainText(order.CheckoutAttributeDescription)); //order notes @@ -281,7 +325,7 @@ protected OrderDetailsModel PrepareOrderDetailsModel(Order order) .OrderByDescending(on => on.CreatedOnUtc) .ToList()) { - model.OrderNotes.Add(new OrderDetailsModel.OrderNote() + model.OrderNotes.Add(new OrderDetailsModel.OrderNote { Note = orderNote.FormatOrderNoteText(), CreatedOn = _dateTimeHelper.ConvertToUserTime(orderNote.CreatedOnUtc, DateTimeKind.Utc) @@ -290,7 +334,7 @@ protected OrderDetailsModel PrepareOrderDetailsModel(Order order) //purchased products - model.ShowSku = _catalogSettings.ShowProductSku; + model.ShowSku = catalogSettings.ShowProductSku; var orderItems = _orderService.GetAllOrderItems(order.Id, null, null, null, null, null, null); foreach (var orderItem in orderItems) @@ -311,48 +355,59 @@ protected ShipmentDetailsModel PrepareShipmentDetailsModel(Shipment shipment) var order = shipment.Order; if (order == null) - throw new Exception("order cannot be loaded"); - var model = new ShipmentDetailsModel(); - - model.Id = shipment.Id; + throw new SmartException(T("Order.NotFound", shipment.OrderId)); + + var store = _storeService.GetStoreById(order.StoreId) ?? _services.StoreContext.CurrentStore; + var catalogSettings = _services.Settings.LoadSetting(store.Id); + var shippingSettings = _services.Settings.LoadSetting(store.Id); + + var model = new ShipmentDetailsModel + { + Id = shipment.Id, + TrackingNumber = shipment.TrackingNumber + }; + if (shipment.ShippedDateUtc.HasValue) model.ShippedDate = _dateTimeHelper.ConvertToUserTime(shipment.ShippedDateUtc.Value, DateTimeKind.Utc); + if (shipment.DeliveryDateUtc.HasValue) model.DeliveryDate = _dateTimeHelper.ConvertToUserTime(shipment.DeliveryDateUtc.Value, DateTimeKind.Utc); - //tracking number and shipment information - model.TrackingNumber = shipment.TrackingNumber; var srcm = _shippingService.LoadShippingRateComputationMethodBySystemName(order.ShippingRateComputationMethodSystemName); - if (srcm != null && - srcm.PluginDescriptor.Installed && - srcm.IsShippingRateComputationMethodActive(_shippingSettings)) + + if (srcm != null && srcm.IsShippingRateComputationMethodActive(shippingSettings)) { - var shipmentTracker = srcm.ShipmentTracker; + var shipmentTracker = srcm.Value.ShipmentTracker; if (shipmentTracker != null) { model.TrackingNumberUrl = shipmentTracker.GetUrl(shipment.TrackingNumber); - if (_shippingSettings.DisplayShipmentEventsToCustomers) + if (shippingSettings.DisplayShipmentEventsToCustomers) { var shipmentEvents = shipmentTracker.GetShipmentEvents(shipment.TrackingNumber); - if (shipmentEvents != null) - foreach (var shipmentEvent in shipmentEvents) - { - var shipmentStatusEventModel = new ShipmentDetailsModel.ShipmentStatusEventModel(); - var shipmentEventCountry = _countryService.GetCountryByTwoLetterIsoCode(shipmentEvent.CountryCode); - shipmentStatusEventModel.Country = shipmentEventCountry != null - ? shipmentEventCountry.GetLocalized(x => x.Name) - : shipmentEvent.CountryCode; - shipmentStatusEventModel.Date = shipmentEvent.Date; - shipmentStatusEventModel.EventName = shipmentEvent.EventName; - shipmentStatusEventModel.Location = shipmentEvent.Location; - model.ShipmentStatusEvents.Add(shipmentStatusEventModel); - } + if (shipmentEvents != null) + { + foreach (var shipmentEvent in shipmentEvents) + { + var shipmentEventCountry = _countryService.GetCountryByTwoLetterIsoCode(shipmentEvent.CountryCode); + + var shipmentStatusEventModel = new ShipmentDetailsModel.ShipmentStatusEventModel + { + Country = (shipmentEventCountry != null ? shipmentEventCountry.GetLocalized(x => x.Name) : shipmentEvent.CountryCode), + Date = shipmentEvent.Date, + EventName = shipmentEvent.EventName, + Location = shipmentEvent.Location + }; + + model.ShipmentStatusEvents.Add(shipmentStatusEventModel); + } + } } } } //products in this shipment - model.ShowSku = _catalogSettings.ShowProductSku; + model.ShowSku = catalogSettings.ShowProductSku; + foreach (var shipmentItem in shipment.ShipmentItems) { var orderItem = _orderService.GetOrderItemById(shipmentItem.OrderItemId); @@ -360,7 +415,10 @@ protected ShipmentDetailsModel PrepareShipmentDetailsModel(Shipment shipment) continue; orderItem.Product.MergeWithCombination(orderItem.AttributesXml); - var shipmentItemModel = new ShipmentDetailsModel.ShipmentItemModel() + + var attributeQueryData = new List>(); + + var shipmentItemModel = new ShipmentDetailsModel.ShipmentItemModel { Id = shipmentItem.Id, Sku = orderItem.Product.Sku, @@ -369,12 +427,25 @@ protected ShipmentDetailsModel PrepareShipmentDetailsModel(Shipment shipment) ProductSeName = orderItem.Product.GetSeName(), AttributeInfo = orderItem.AttributeDescription, QuantityOrdered = orderItem.Quantity, - QuantityShipped = shipmentItem.Quantity, + QuantityShipped = shipmentItem.Quantity }; + + if (orderItem.Product.ProductType != ProductType.BundledProduct) + { + _productAttributeParser.DeserializeQueryData(attributeQueryData, orderItem.AttributesXml, orderItem.ProductId); + } + else if (orderItem.Product.BundlePerItemPricing && orderItem.BundleData.HasValue()) + { + var bundleData = orderItem.GetBundleData(); + + bundleData.ForEach(x => _productAttributeParser.DeserializeQueryData(attributeQueryData, x.AttributesXml, x.ProductId, x.BundleItemId)); + } + + shipmentItemModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(attributeQueryData, shipmentItemModel.ProductSeName); + model.Items.Add(shipmentItemModel); } - //order details model model.Order = PrepareOrderDetailsModel(order); return model; @@ -382,9 +453,11 @@ protected ShipmentDetailsModel PrepareShipmentDetailsModel(Shipment shipment) private OrderDetailsModel.OrderItemModel PrepareOrderItemModel(Order order, OrderItem orderItem) { + var attributeQueryData = new List>(); + orderItem.Product.MergeWithCombination(orderItem.AttributesXml); - var model = new OrderDetailsModel.OrderItemModel() + var model = new OrderDetailsModel.OrderItemModel { Id = orderItem.Id, Sku = orderItem.Product.Sku, @@ -396,6 +469,14 @@ private OrderDetailsModel.OrderItemModel PrepareOrderItemModel(Order order, Orde AttributeInfo = orderItem.AttributeDescription }; + if (orderItem.Product.ProductType != ProductType.BundledProduct) + { + _productAttributeParser.DeserializeQueryData(attributeQueryData, orderItem.AttributesXml, orderItem.ProductId); + } + + var quantityUnit = _quantityUnitService.GetQuantityUnitById(orderItem.Product.QuantityUnitId); + model.QuantityUnit = (quantityUnit == null ? "" : quantityUnit.GetLocalized(x => x.Name)); + if (orderItem.Product.ProductType == ProductType.BundledProduct && orderItem.BundleData.HasValue()) { var bundleData = orderItem.GetBundleData(); @@ -405,7 +486,7 @@ private OrderDetailsModel.OrderItemModel PrepareOrderItemModel(Order order, Orde foreach (var bundleItem in bundleData) { - var bundleItemModel = new OrderDetailsModel.BundleItemModel() + var bundleItemModel = new OrderDetailsModel.BundleItemModel { Sku = bundleItem.Sku, ProductName = bundleItem.ProductName, @@ -416,10 +497,17 @@ private OrderDetailsModel.OrderItemModel PrepareOrderItemModel(Order order, Orde AttributeInfo = bundleItem.AttributesInfo }; + bundleItemModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(bundleItem.AttributesXml, bundleItem.ProductId, bundleItemModel.ProductSeName); + + if (orderItem.Product.BundlePerItemPricing) + { + _productAttributeParser.DeserializeQueryData(attributeQueryData, bundleItem.AttributesXml, bundleItem.ProductId, bundleItem.BundleItemId); + } + if (model.BundlePerItemShoppingCart) { decimal priceWithDiscount = _currencyService.ConvertCurrency(bundleItem.PriceWithDiscount, order.CurrencyRate); - bundleItemModel.PriceWithDiscount = _priceFormatter.FormatPrice(priceWithDiscount, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, false); + bundleItemModel.PriceWithDiscount = _priceFormatter.FormatPrice(priceWithDiscount, true, order.CustomerCurrencyCode, _services.WorkContext.WorkingLanguage, false, false); } model.BundleItems.Add(bundleItemModel); @@ -432,22 +520,26 @@ private OrderDetailsModel.OrderItemModel PrepareOrderItemModel(Order order, Orde case TaxDisplayType.ExcludingTax: { var unitPriceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.UnitPriceExclTax, order.CurrencyRate); - model.UnitPrice = _priceFormatter.FormatPrice(unitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, false); + model.UnitPrice = _priceFormatter.FormatPrice(unitPriceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _services.WorkContext.WorkingLanguage, false, false); var priceExclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.PriceExclTax, order.CurrencyRate); - model.SubTotal = _priceFormatter.FormatPrice(priceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, false); + model.SubTotal = _priceFormatter.FormatPrice(priceExclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _services.WorkContext.WorkingLanguage, false, false); } break; + case TaxDisplayType.IncludingTax: { var unitPriceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.UnitPriceInclTax, order.CurrencyRate); - model.UnitPrice = _priceFormatter.FormatPrice(unitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, true); + model.UnitPrice = _priceFormatter.FormatPrice(unitPriceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _services.WorkContext.WorkingLanguage, true, false); var priceInclTaxInCustomerCurrency = _currencyService.ConvertCurrency(orderItem.PriceInclTax, order.CurrencyRate); - model.SubTotal = _priceFormatter.FormatPrice(priceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _workContext.WorkingLanguage, true); + model.SubTotal = _priceFormatter.FormatPrice(priceInclTaxInCustomerCurrency, true, order.CustomerCurrencyCode, _services.WorkContext.WorkingLanguage, true, false); } break; } + + model.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(attributeQueryData, model.ProductSeName); + return model; } @@ -456,47 +548,121 @@ private OrderDetailsModel.OrderItemModel PrepareOrderItemModel(Order order, Orde #region Order details [RequireHttpsByConfigAttribute(SslRequirement.Yes)] - public ActionResult Details(int orderId) + public ActionResult Details(int id) { - var order = _orderService.GetOrderById(orderId); - if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) - return new HttpUnauthorizedResult(); + var order = _orderService.GetOrderById(id); + + if (IsNonExistentOrder(order)) + return HttpNotFound(); + + if (IsUnauthorizedOrder(order)) + return new HttpUnauthorizedResult(); var model = PrepareOrderDetailsModel(order); return View(model); } - [RequireHttpsByConfigAttribute(SslRequirement.Yes)] - public ActionResult PrintOrderDetails(int orderId) - { - var order = _orderService.GetOrderById(orderId); - if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) - return new HttpUnauthorizedResult(); + [RequireHttpsByConfigAttribute(SslRequirement.Yes)] + public ActionResult Print(int id, bool pdf = false) + { + var order = _orderService.GetOrderById(id); - var model = PrepareOrderDetailsModel(order); - model.PrintMode = true; + if (IsNonExistentOrder(order)) + return HttpNotFound(); - return View("Details", model); - } + if (IsUnauthorizedOrder(order)) + return new HttpUnauthorizedResult(); - public ActionResult GetPdfInvoice(int orderId) - { - var order = _orderService.GetOrderById(orderId); - if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) - return new HttpUnauthorizedResult(); + var model = PrepareOrderDetailsModel(order); + var fileName = T("Order.PdfInvoiceFileName", order.Id); - var orders = new List(); - orders.Add(order); + return PrintCore(new List { model }, pdf, fileName); + } - return File(_pdfService.PrintOrdersToPdf(orders), MediaTypeNames.Application.Pdf, "order-{0}.pdf".FormatWith(order.Id)); - } + [AdminAuthorize] + public ActionResult PrintMany(string ids = null, bool pdf = false) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageOrders)) + return new HttpUnauthorizedResult(); + + const int maxOrders = 500; + IList orders = null; + int totalCount = 0; + + using (var scope = new DbContextScope(_services.DbContext, autoDetectChanges: false, forceNoTracking: true)) + { + if (ids != null) + { + orders = _orderService.GetOrdersByIds(ids.ToIntArray()); + totalCount = orders.Count; + } + else + { + var pagedOrders = _orderService.SearchOrders(0, 0, null, null, null, null, null, null, null, null, 0, 1); + totalCount = pagedOrders.TotalCount; + + if (totalCount > 0 && totalCount <= maxOrders) + { + orders = _orderService.SearchOrders(0, 0, null, null, null, null, null, null, null, null, 0, int.MaxValue); + } + } + } + + if (totalCount == 0) + { + NotifyInfo(T("Admin.Common.ExportNoData")); + return RedirectToReferrer(); + } + + if (totalCount > maxOrders) + { + NotifyWarning(T("Admin.Common.ExportToPdf.TooManyItems")); + return RedirectToReferrer(); + } + + var listModel = orders.Select(x => PrepareOrderDetailsModel(x)).ToList(); - public ActionResult ReOrder(int orderId) + return PrintCore(listModel, pdf, "orders.pdf"); + } + + [NonAction] + private ActionResult PrintCore(List model, bool pdf, string pdfFileName) + { + ViewBag.PdfMode = pdf; + var viewName = "Details.Print"; + + if (pdf) + { + // TODO: (mc) this is bad for multi-document processing, where orders can originate from different stores. + var storeId = model[0].StoreId; + var routeValues = new RouteValueDictionary { { "storeId", storeId } }; + var pdfSettings = _services.Settings.LoadSetting(storeId); + + var settings = new PdfConvertSettings + { + Size = pdfSettings.LetterPageSizeEnabled ? PdfPageSize.Letter : PdfPageSize.A4, + Margins = new PdfPageMargins { Top = 35, Bottom = 35 }, + Page = new PdfViewContent(viewName, model, this.ControllerContext), + Header = new PdfRouteContent("PdfReceiptHeader", "Common", routeValues, this.ControllerContext), + Footer = new PdfRouteContent("PdfReceiptFooter", "Common", routeValues, this.ControllerContext) + }; + + return new PdfResult(_pdfConverter, settings) { FileName = pdfFileName }; + } + + return View(viewName, model); + } + + public ActionResult ReOrder(int id) { - var order = _orderService.GetOrderById(orderId); - if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) - return new HttpUnauthorizedResult(); + var order = _orderService.GetOrderById(id); + + if (IsNonExistentOrder(order)) + return HttpNotFound(); + + if (IsUnauthorizedOrder(order)) + return new HttpUnauthorizedResult(); _orderProcessingService.ReOrder(order); return RedirectToRoute("ShoppingCart"); @@ -504,49 +670,82 @@ public ActionResult ReOrder(int orderId) [HttpPost, ActionName("Details")] [FormValueRequired("repost-payment")] - public ActionResult RePostPayment(int orderId) + public ActionResult RePostPayment(int id) { - var order = _orderService.GetOrderById(orderId); - if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) - return new HttpUnauthorizedResult(); + var order = _orderService.GetOrderById(id); - if (!_paymentService.CanRePostProcessPayment(order)) - return RedirectToRoute("OrderDetails", new { orderId = orderId }); + if (IsNonExistentOrder(order)) + return HttpNotFound(); - var postProcessPaymentRequest = new PostProcessPaymentRequest() - { - Order = order - }; - _paymentService.PostProcessPayment(postProcessPaymentRequest); + if (IsUnauthorizedOrder(order)) + return new HttpUnauthorizedResult(); - if (_webHelper.IsRequestBeingRedirected || _webHelper.IsPostBeingDone) - { - //redirection or POST has been done in PostProcessPayment - return Content("Redirected"); - } - else - { - //if no redirection has been done (to a third-party payment page) - //theoretically it's not possible - return RedirectToRoute("OrderDetails", new { orderId = orderId }); - } + try + { + if (_paymentService.CanRePostProcessPayment(order)) + { + var postProcessPaymentRequest = new PostProcessPaymentRequest + { + Order = order, + IsRePostProcessPayment = true + }; + + _paymentService.PostProcessPayment(postProcessPaymentRequest); + + if (postProcessPaymentRequest.RedirectUrl.HasValue()) + { + return Redirect(postProcessPaymentRequest.RedirectUrl); + } + } + } + catch (Exception exception) + { + NotifyError(exception); + } + + return RedirectToAction("Details", "Order", new { id = order.Id }); } [RequireHttpsByConfigAttribute(SslRequirement.Yes)] - public ActionResult ShipmentDetails(int shipmentId) + public ActionResult ShipmentDetails(int id /* shipmentId */) { - var shipment = _shipmentService.GetShipmentById(shipmentId); + var shipment = _shipmentService.GetShipmentById(id); if (shipment == null) - return new HttpUnauthorizedResult(); + return HttpNotFound(); var order = shipment.Order; - if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) + + if (IsNonExistentOrder(order)) + return HttpNotFound(); + + if (IsUnauthorizedOrder(order)) return new HttpUnauthorizedResult(); var model = PrepareShipmentDetailsModel(shipment); return View(model); } + + private bool IsNonExistentOrder(Order order) + { + var flag = order == null || order.Deleted; + + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageOrders)) + { + flag = flag || (order.StoreId != 0 && order.StoreId != _services.StoreContext.CurrentStore.Id); + } + + return flag; + } + + private bool IsUnauthorizedOrder(Order order) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.ManageOrders)) + return order == null || order.CustomerId != _services.WorkContext.CurrentCustomer.Id; + else + return order == null; + } + #endregion } } diff --git a/src/Presentation/SmartStore.Web/Controllers/PollController.cs b/src/Presentation/SmartStore.Web/Controllers/PollController.cs index c7734a23e4..1919207834 100644 --- a/src/Presentation/SmartStore.Web/Controllers/PollController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/PollController.cs @@ -6,7 +6,6 @@ using SmartStore.Core.Caching; using SmartStore.Core.Domain.Polls; using SmartStore.Services.Customers; -using SmartStore.Services.Localization; using SmartStore.Services.Polls; using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Infrastructure.Cache; @@ -14,11 +13,10 @@ namespace SmartStore.Web.Controllers { - public partial class PollController : PublicControllerBase + public partial class PollController : PublicControllerBase { #region Fields - private readonly ILocalizationService _localizationService; private readonly IWorkContext _workContext; private readonly IPollService _pollService; private readonly IWebHelper _webHelper; @@ -29,12 +27,13 @@ public partial class PollController : PublicControllerBase #region Constructors - public PollController(ILocalizationService localizationService, - IWorkContext workContext, IPollService pollService, - IWebHelper webHelper, ICacheManager cacheManager, + public PollController( + IWorkContext workContext, + IPollService pollService, + IWebHelper webHelper, + ICacheManager cacheManager, IStoreContext storeContext) { - this._localizationService = localizationService; this._workContext = workContext; this._pollService = pollService; this._webHelper = webHelper; @@ -49,18 +48,23 @@ public PollController(ILocalizationService localizationService, [NonAction] protected PollModel PreparePollModel(Poll poll, bool setAlreadyVotedProperty) { - var model = new PollModel() + var model = new PollModel { Id = poll.Id, AlreadyVoted = setAlreadyVotedProperty && _pollService.AlreadyVoted(poll.Id, _workContext.CurrentCustomer.Id), Name = poll.Name }; + var answers = poll.PollAnswers.OrderBy(x => x.DisplayOrder); - foreach (var answer in answers) - model.TotalVotes += answer.NumberOfVotes; + + foreach (var answer in answers) + { + model.TotalVotes += answer.NumberOfVotes; + } + foreach (var pa in answers) { - model.Answers.Add(new PollAnswerModel() + model.Answers.Add(new PollAnswerModel { Id = pa.Id, Name = pa.Name, @@ -88,10 +92,11 @@ public ActionResult PollBlock(string systemKeyword) var poll = _pollService.GetPollBySystemKeyword(systemKeyword, _workContext.WorkingLanguage.Id); if (poll == null) - return new PollModel() { Id = 0 }; //we do not cache nulls. that's why let's return an empty record (ID = 0) + return new PollModel { Id = 0 }; //we do not cache nulls. that's why let's return an empty record (ID = 0) return PreparePollModel(poll, false); }); + if (cachedModel == null || cachedModel.Id == 0) return Content(""); @@ -108,30 +113,29 @@ public ActionResult PollBlock(string systemKeyword) public ActionResult Vote(int pollAnswerId) { var pollAnswer = _pollService.GetPollAnswerById(pollAnswerId); - if (pollAnswer == null) - return Json(new - { - error = "No poll answer found with the specified id", - }); + + if (pollAnswer == null) + { + return Json(new { error = T("Polls.AnswerNotFound", pollAnswerId).Text }); + } var poll = pollAnswer.Poll; - if (!poll.Published) - return Json(new - { - error = "Poll is not available", - }); - if (_workContext.CurrentCustomer.IsGuest() && !poll.AllowGuestsToVote) - return Json(new - { - error = _localizationService.GetResource("Polls.OnlyRegisteredUsersVote"), - }); + if (!poll.Published) + { + return Json(new { error = T("Polls.NotAvailable").Text }); + } + + if (_workContext.CurrentCustomer.IsGuest() && !poll.AllowGuestsToVote) + { + return Json(new { error = T("Polls.OnlyRegisteredUsersVote").Text }); + } bool alreadyVoted = _pollService.AlreadyVoted(poll.Id, _workContext.CurrentCustomer.Id); if (!alreadyVoted) { //vote - pollAnswer.PollVotingRecords.Add(new PollVotingRecord() + pollAnswer.PollVotingRecords.Add(new PollVotingRecord { PollAnswerId = pollAnswer.Id, CustomerId = _workContext.CurrentCustomer.Id, @@ -140,8 +144,10 @@ public ActionResult Vote(int pollAnswerId) CreatedOnUtc = DateTime.UtcNow, UpdatedOnUtc = DateTime.UtcNow, }); + //update totals pollAnswer.NumberOfVotes = pollAnswer.PollVotingRecords.Count; + _pollService.UpdatePoll(poll); } @@ -161,19 +167,24 @@ public ActionResult HomePagePolls() .Select(x => PreparePollModel(x, false)) .ToList(); }); + //"AlreadyVoted" property of "PollModel" object depends on the current customer. Let's update it. //But first we need to clone the cached model (the updated one should not be cached) var model = new List(); + foreach (var p in cachedModel) { - var pollModel = (PollModel) p.Clone(); + var pollModel = (PollModel)p.Clone(); pollModel.AlreadyVoted = _pollService.AlreadyVoted(pollModel.Id, _workContext.CurrentCustomer.Id); model.Add(pollModel); } + + if (model.Count == 0) + return Content(""); + return PartialView(model); } #endregion - } } diff --git a/src/Presentation/SmartStore.Web/Controllers/PrivateMessagesController.cs b/src/Presentation/SmartStore.Web/Controllers/PrivateMessagesController.cs index f6e5c7287c..8171bf6d4f 100644 --- a/src/Presentation/SmartStore.Web/Controllers/PrivateMessagesController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/PrivateMessagesController.cs @@ -4,19 +4,19 @@ using SmartStore.Core; using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Forums; +using SmartStore.Core.Logging; using SmartStore.Services.Customers; using SmartStore.Services.Forums; using SmartStore.Services.Helpers; -using SmartStore.Services.Localization; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; using SmartStore.Web.Framework.Security; using SmartStore.Web.Models.Common; using SmartStore.Web.Models.PrivateMessages; -using SmartStore.Core.Logging; namespace SmartStore.Web.Controllers { - [RequireHttpsByConfigAttribute(SslRequirement.Yes)] + [RequireHttpsByConfigAttribute(SslRequirement.Yes)] public partial class PrivateMessagesController : PublicControllerBase { #region Fields @@ -24,7 +24,6 @@ public partial class PrivateMessagesController : PublicControllerBase private readonly IForumService _forumService; private readonly ICustomerService _customerService; private readonly ICustomerActivityService _customerActivityService; - private readonly ILocalizationService _localizationService; private readonly IWorkContext _workContext; private readonly IStoreContext _storeContext; private readonly IDateTimeHelper _dateTimeHelper; @@ -36,16 +35,17 @@ public partial class PrivateMessagesController : PublicControllerBase #region Constructors public PrivateMessagesController(IForumService forumService, - ICustomerService customerService, ICustomerActivityService customerActivityService, - ILocalizationService localizationService, - IWorkContext workContext, IStoreContext storeContext, + ICustomerService customerService, + ICustomerActivityService customerActivityService, + IWorkContext workContext, + IStoreContext storeContext, IDateTimeHelper dateTimeHelper, - ForumSettings forumSettings, CustomerSettings customerSettings) + ForumSettings forumSettings, + CustomerSettings customerSettings) { this._forumService = forumService; this._customerService = customerService; this._customerActivityService = customerActivityService; - this._localizationService = localizationService; this._workContext = workContext; this._storeContext = storeContext; this._dateTimeHelper = dateTimeHelper; @@ -71,7 +71,7 @@ public ActionResult Index(int? page, string tab) { if (!AllowPrivateMessages()) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } if (_workContext.CurrentCustomer.IsGuest()) @@ -102,7 +102,7 @@ public ActionResult Index(int? page, string tab) break; } - var model = new PrivateMessageIndexModel() + var model = new PrivateMessageIndexModel { InboxPage = inboxPage, SentItemsPage = sentItemsPage, @@ -130,7 +130,7 @@ public ActionResult Inbox(int page, string tab) foreach (var pm in list) { - inbox.Add(new PrivateMessageModel() + inbox.Add(new PrivateMessageModel { Id = pm.Id, FromCustomerId = pm.FromCustomer.Id, @@ -146,13 +146,11 @@ public ActionResult Inbox(int page, string tab) }); } - // codehint: sm-edit ViewData["PagerRouteValues"] = new PrivateMessageRouteValues { page = page, tab = tab }; var model = new PrivateMessageListModel(list) { Messages = inbox - // codehint: sm-delete }; return PartialView(model); @@ -176,7 +174,7 @@ public ActionResult SentItems(int page, string tab) foreach (var pm in list) { - sentItems.Add(new PrivateMessageModel() + sentItems.Add(new PrivateMessageModel { Id = pm.Id, FromCustomerId = pm.FromCustomer.Id, @@ -192,13 +190,11 @@ public ActionResult SentItems(int page, string tab) }); } - // codehint: sm-edit ViewData["PagerRouteValues"] = new PrivateMessageRouteValues { page = page, tab = tab }; var model = new PrivateMessageListModel(list) { Messages = sentItems - // codehint: sm-delete }; return PartialView(model); @@ -230,8 +226,8 @@ public ActionResult DeleteInboxPM(FormCollection formCollection) } } } - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } [HttpPost, FormValueRequired("mark-unread"), ActionName("InboxUpdate")] public ActionResult MarkUnread(FormCollection formCollection) @@ -259,7 +255,7 @@ public ActionResult MarkUnread(FormCollection formCollection) } } } - return RedirectToRoute("PrivateMessages"); + return RedirectToAction("Index"); } //updates sent items (deletes PrivateMessages) @@ -293,11 +289,11 @@ public ActionResult DeleteSentPM(FormCollection formCollection) return RedirectToRoute("PrivateMessages", new { tab = "sent" }); } - public ActionResult SendPM(int toCustomerId, int? replyToMessageId) + public ActionResult Send(int id /* toCustomerId */, int? replyToMessageId) { if (!AllowPrivateMessages()) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } if (_workContext.CurrentCustomer.IsGuest()) @@ -305,12 +301,12 @@ public ActionResult SendPM(int toCustomerId, int? replyToMessageId) return new HttpUnauthorizedResult(); } - var customerTo = _customerService.GetCustomerById(toCustomerId); + var customerTo = _customerService.GetCustomerById(id); if (customerTo == null || customerTo.IsGuest()) { - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } var model = new SendPrivateMessageModel(); model.ToCustomerId = customerTo.Id; @@ -322,8 +318,8 @@ public ActionResult SendPM(int toCustomerId, int? replyToMessageId) var replyToPM = _forumService.GetPrivateMessageById(replyToMessageId.Value); if (replyToPM == null) { - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } if (replyToPM.ToCustomerId == _workContext.CurrentCustomer.Id || replyToPM.FromCustomerId == _workContext.CurrentCustomer.Id) { @@ -332,18 +328,18 @@ public ActionResult SendPM(int toCustomerId, int? replyToMessageId) } else { - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } } - return View(model); + return View(model); } [HttpPost] - public ActionResult SendPM(SendPrivateMessageModel model) + public ActionResult Send(SendPrivateMessageModel model) { if (!AllowPrivateMessages()) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } if (_workContext.CurrentCustomer.IsGuest()) @@ -361,8 +357,8 @@ public ActionResult SendPM(SendPrivateMessageModel model) } else { - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } } else { @@ -371,8 +367,8 @@ public ActionResult SendPM(SendPrivateMessageModel model) if (toCustomer == null || toCustomer.IsGuest()) { - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } model.ToCustomerId = toCustomer.Id; model.CustomerToName = toCustomer.FormatUserName(); model.AllowViewingToProfile = _customerSettings.AllowViewingProfiles && !toCustomer.IsGuest(); @@ -411,9 +407,9 @@ public ActionResult SendPM(SendPrivateMessageModel model) _forumService.InsertPrivateMessage(privateMessage); //activity log - _customerActivityService.InsertActivity("PublicStore.SendPM", _localizationService.GetResource("ActivityLog.PublicStore.SendPM"), toCustomer.Email); + _customerActivityService.InsertActivity("PublicStore.SendPM", T("ActivityLog.PublicStore.SendPM", toCustomer.Email)); - return RedirectToRoute("PrivateMessages", new { tab = "sent" }); + return RedirectToAction("Index", new { tab = "sent" }); } catch (Exception ex) { @@ -424,11 +420,11 @@ public ActionResult SendPM(SendPrivateMessageModel model) return View(model); } - public ActionResult ViewPM(int privateMessageId) + public ActionResult View(int id /* privateMessageId */) { if (!AllowPrivateMessages()) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } if (_workContext.CurrentCustomer.IsGuest()) @@ -436,13 +432,13 @@ public ActionResult ViewPM(int privateMessageId) return new HttpUnauthorizedResult(); } - var pm = _forumService.GetPrivateMessageById(privateMessageId); + var pm = _forumService.GetPrivateMessageById(id); if (pm != null) { if (pm.ToCustomerId != _workContext.CurrentCustomer.Id && pm.FromCustomerId != _workContext.CurrentCustomer.Id) { - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } if (!pm.IsRead && pm.ToCustomerId == _workContext.CurrentCustomer.Id) { @@ -452,10 +448,10 @@ public ActionResult ViewPM(int privateMessageId) } else { - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } - var model = new PrivateMessageModel() + var model = new PrivateMessageModel { Id = pm.Id, FromCustomerId = pm.FromCustomer.Id, @@ -473,11 +469,11 @@ public ActionResult ViewPM(int privateMessageId) return View(model); } - public ActionResult DeletePM(int privateMessageId) + public ActionResult Delete(int id /* privateMessageId */) { if (!AllowPrivateMessages()) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } if (_workContext.CurrentCustomer.IsGuest()) @@ -485,7 +481,7 @@ public ActionResult DeletePM(int privateMessageId) return new HttpUnauthorizedResult(); } - var pm = _forumService.GetPrivateMessageById(privateMessageId); + var pm = _forumService.GetPrivateMessageById(id); if (pm != null) { if (pm.FromCustomerId == _workContext.CurrentCustomer.Id) @@ -500,8 +496,8 @@ public ActionResult DeletePM(int privateMessageId) _forumService.UpdatePrivateMessage(pm); } } - return RedirectToRoute("PrivateMessages"); - } + return RedirectToAction("Index"); + } #endregion } diff --git a/src/Presentation/SmartStore.Web/Controllers/ProductController.cs b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs new file mode 100644 index 0000000000..79497418a9 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Controllers/ProductController.cs @@ -0,0 +1,1142 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Web.Mvc; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Localization; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Orders; +using SmartStore.Services; +using SmartStore.Services.Catalog; +using SmartStore.Services.Common; +using SmartStore.Services.Customers; +using SmartStore.Services.Directory; +using SmartStore.Services.Localization; +using SmartStore.Services.Media; +using SmartStore.Services.Messages; +using SmartStore.Services.Orders; +using SmartStore.Services.Security; +using SmartStore.Services.Seo; +using SmartStore.Services.Stores; +using SmartStore.Services.Tax; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.UI.Captcha; +using SmartStore.Web.Infrastructure.Cache; +using SmartStore.Web.Models.Catalog; + +namespace SmartStore.Web.Controllers +{ + public partial class ProductController : PublicControllerBase + { + #region Fields + + private readonly ICommonServices _services; + private readonly IManufacturerService _manufacturerService; + private readonly IProductService _productService; + private readonly IProductAttributeService _productAttributeService; + private readonly IProductAttributeParser _productAttributeParser; + private readonly ITaxService _taxService; + private readonly ICurrencyService _currencyService; + private readonly IPictureService _pictureService; + private readonly IPriceCalculationService _priceCalculationService; + private readonly IPriceFormatter _priceFormatter; + private readonly ICustomerContentService _customerContentService; + private readonly ICustomerService _customerService; + private readonly IShoppingCartService _shoppingCartService; + private readonly IRecentlyViewedProductsService _recentlyViewedProductsService; + private readonly IWorkflowMessageService _workflowMessageService; + private readonly IProductTagService _productTagService; + private readonly IOrderReportService _orderReportService; + private readonly IBackInStockSubscriptionService _backInStockSubscriptionService; + private readonly IAclService _aclService; + private readonly IStoreMappingService _storeMappingService; + private readonly MediaSettings _mediaSettings; + private readonly CatalogSettings _catalogSettings; + private readonly ShoppingCartSettings _shoppingCartSettings; + private readonly LocalizationSettings _localizationSettings; + private readonly CaptchaSettings _captchaSettings; + private readonly CatalogHelper _helper; + private readonly IDownloadService _downloadService; + private readonly ILocalizationService _localizationService; + + #endregion + + #region Constructors + + public ProductController( + ICommonServices services, + IManufacturerService manufacturerService, + IProductService productService, + IProductAttributeService productAttributeService, + IProductAttributeParser productAttributeParser, + ITaxService taxService, + ICurrencyService currencyService, + IPictureService pictureService, + IPriceCalculationService priceCalculationService, + IPriceFormatter priceFormatter, + ICustomerContentService customerContentService, + ICustomerService customerService, + IShoppingCartService shoppingCartService, + IRecentlyViewedProductsService recentlyViewedProductsService, + IWorkflowMessageService workflowMessageService, + IProductTagService productTagService, + IOrderReportService orderReportService, + IBackInStockSubscriptionService backInStockSubscriptionService, + IAclService aclService, + IStoreMappingService storeMappingService, + MediaSettings mediaSettings, + CatalogSettings catalogSettings, + ShoppingCartSettings shoppingCartSettings, + LocalizationSettings localizationSettings, + CaptchaSettings captchaSettings, + CatalogHelper helper, + IDownloadService downloadService, + ILocalizationService localizationService) + { + this._services = services; + this._manufacturerService = manufacturerService; + this._productService = productService; + this._productAttributeService = productAttributeService; + this._productAttributeParser = productAttributeParser; + this._taxService = taxService; + this._currencyService = currencyService; + this._pictureService = pictureService; + this._priceCalculationService = priceCalculationService; + this._priceFormatter = priceFormatter; + this._customerContentService = customerContentService; + this._customerService = customerService; + this._shoppingCartService = shoppingCartService; + this._recentlyViewedProductsService = recentlyViewedProductsService; + this._workflowMessageService = workflowMessageService; + this._productTagService = productTagService; + this._orderReportService = orderReportService; + this._backInStockSubscriptionService = backInStockSubscriptionService; + this._aclService = aclService; + this._storeMappingService = storeMappingService; + this._mediaSettings = mediaSettings; + this._catalogSettings = catalogSettings; + this._shoppingCartSettings = shoppingCartSettings; + this._localizationSettings = localizationSettings; + this._captchaSettings = captchaSettings; + this._helper = helper; + this._downloadService = downloadService; + this._localizationService = localizationService; + } + + #endregion + + #region Products + + [RequireHttpsByConfigAttribute(SslRequirement.No)] + public ActionResult ProductDetails(int productId, string attributes) + { + var product = _productService.GetProductById(productId); + if (product == null || product.Deleted) + return HttpNotFound(); + + //Is published? + //Check whether the current user has a "Manage catalog" permission + //It allows him to preview a product before publishing + if (!product.Published && !_services.Permissions.Authorize(StandardPermissionProvider.ManageCatalog)) + return HttpNotFound(); + + //ACL (access control list) + if (!_aclService.Authorize(product)) + return HttpNotFound(); + + //Store mapping + if (!_storeMappingService.Authorize(product)) + return HttpNotFound(); + + //visible individually? + if (!product.VisibleIndividually) + { + //is this one an associated products? + var parentGroupedProduct = _productService.GetProductById(product.ParentGroupedProductId); + if (parentGroupedProduct != null) + { + return RedirectToRoute("Product", new { SeName = parentGroupedProduct.GetSeName() }); + } + else + { + return HttpNotFound(); + } + } + + var selectedAttributes = new NameValueCollection(); + + // get selected attributes from query string + selectedAttributes.GetSelectedAttributes( + Request.QueryString, + _productAttributeParser.DeserializeQueryData(attributes), + product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing ? 0 : product.Id); + + // prepare the view model + var model = _helper.PrepareProductDetailsPageModel(product, selectedAttributes: selectedAttributes, queryData: Request.QueryString); + + //save as recently viewed + _recentlyViewedProductsService.AddProductToRecentlyViewedList(product.Id); + + //activity log + _services.CustomerActivity.InsertActivity("PublicStore.ViewProduct", T("ActivityLog.PublicStore.ViewProduct"), product.Name); + + return View(model.ProductTemplateViewPath, model); + } + + //add product to cart using HTTP POST + //currently we use this method only for mobile device version + //desktop version uses AJAX version of this method (see ShoppingCartController) + // TODO: This should be handled by ShoppingCartController + [HttpPost, ActionName("ProductDetails")] + [ValidateInput(false)] + public ActionResult AddProductToCart(int productId, FormCollection form) + { + var parentProductId = productId; + var cartType = ShoppingCartType.ShoppingCart; + + foreach (string formKey in form.AllKeys) + { + if (formKey.StartsWith("addtocartbutton-")) + { + cartType = ShoppingCartType.ShoppingCart; + int.TryParse(formKey.Replace("addtocartbutton-", ""), out productId); + } + else if (formKey.StartsWith("addtowishlistbutton-")) + { + cartType = ShoppingCartType.Wishlist; + int.TryParse(formKey.Replace("addtowishlistbutton-", ""), out productId); + } + } + + var product = _productService.GetProductById(productId); + if (product == null || product.Deleted || !product.Published) + return RedirectToRoute("HomePage"); + + var parentProduct = (parentProductId == productId ? product : _productService.GetProductById(parentProductId)); + + decimal customerEnteredPrice = decimal.Zero; + decimal customerEnteredPriceConverted = decimal.Zero; + + if (product.CustomerEntersPrice) + { + foreach (string formKey in form.AllKeys) + { + if (formKey.Equals(string.Format("addtocart_{0}.CustomerEnteredPrice", productId), StringComparison.InvariantCultureIgnoreCase)) + { + if (decimal.TryParse(form[formKey], out customerEnteredPrice)) + customerEnteredPriceConverted = _currencyService.ConvertToPrimaryStoreCurrency(customerEnteredPrice, _services.WorkContext.WorkingCurrency); + break; + } + } + } + + int quantity = 1; + + foreach (string formKey in form.AllKeys) + { + if (formKey.Equals(string.Format("addtocart_{0}.AddToCart.EnteredQuantity", productId), StringComparison.InvariantCultureIgnoreCase)) + { + int.TryParse(form[formKey], out quantity); + break; + } + } + + var addToCartContext = new AddToCartContext + { + Product = product, + AttributeForm = form, + CartType = cartType, + CustomerEnteredPrice = customerEnteredPrice, + Quantity = quantity, + AddRequiredProducts = true + }; + + _shoppingCartService.AddToCart(addToCartContext); + + if (addToCartContext.Warnings.Count == 0) + { + switch (cartType) + { + case ShoppingCartType.Wishlist: + { + if (_shoppingCartSettings.DisplayWishlistAfterAddingProduct) + { + //redirect to the wishlist page + return RedirectToRoute("Wishlist"); + } + else + { + //redisplay the page with "Product has been added to the wishlist" notification message + var model = _helper.PrepareProductDetailsPageModel(parentProduct); + this.NotifySuccess(T("Products.ProductHasBeenAddedToTheWishlist"), false); + + //activity log + _services.CustomerActivity.InsertActivity("PublicStore.AddToWishlist", + T("ActivityLog.PublicStore.AddToWishlist"), product.Name); + + return View(model.ProductTemplateViewPath, model); + } + } + case ShoppingCartType.ShoppingCart: + default: + { + if (_shoppingCartSettings.DisplayCartAfterAddingProduct) + { + //redirect to the shopping cart page + return RedirectToRoute("ShoppingCart"); + } + else + { + //redisplay the page with "Product has been added to the cart" notification message + var model = _helper.PrepareProductDetailsPageModel(parentProduct); + this.NotifySuccess(T("Products.ProductHasBeenAddedToTheCart"), false); + + //activity log + _services.CustomerActivity.InsertActivity("PublicStore.AddToShoppingCart", + T("ActivityLog.PublicStore.AddToShoppingCart"), product.Name); + + return View(model.ProductTemplateViewPath, model); + } + } + } + } + else + { + //Errors + foreach (string error in addToCartContext.Warnings) + { + this.NotifyError(error); + } + //If we got this far, something failed, redisplay form + var model = _helper.PrepareProductDetailsPageModel(parentProduct); + + return View(model.ProductTemplateViewPath, model); + } + } + + [ChildActionOnly] + public ActionResult ProductManufacturers(int productId, bool preparePictureModel = false) + { + var cacheKey = string.Format(ModelCacheEventConsumer.PRODUCT_MANUFACTURERS_MODEL_KEY, + productId, + !_catalogSettings.HideManufacturerDefaultPictures, + _services.WorkContext.WorkingLanguage.Id, + _services.StoreContext.CurrentStore.Id); + + var cacheModel = _services.Cache.Get(cacheKey, () => + { + var model = _manufacturerService.GetProductManufacturersByProductId(productId) + .Select(x => + { + var m = x.Manufacturer.ToModel(); + if (preparePictureModel) + { + m.PictureModel.ImageUrl = _pictureService.GetPictureUrl(x.Manufacturer.PictureId.GetValueOrDefault(), 0, !_catalogSettings.HideManufacturerDefaultPictures); + + var picture = _pictureService.GetPictureUrl(x.Manufacturer.PictureId.GetValueOrDefault()); + if (picture != null) + { + m.PictureModel.PictureId = x.Manufacturer.PictureId.GetValueOrDefault(); + m.PictureModel.Title = string.Format(T("Media.Product.ImageLinkTitleFormat"), m.Name); + m.PictureModel.AlternateText = string.Format(T("Media.Product.ImageAlternateTextFormat"), m.Name); + } + } + return m; + }) + .ToList(); + return model; + }); + + if (cacheModel.Count == 0) + return Content(""); + + return PartialView(cacheModel); + } + + [ChildActionOnly] + public ActionResult ReviewOverview(int id) + { + var product = _productService.GetProductById(id); + if (product == null) + throw new ArgumentException(T("Products.NotFound", id)); + + var model = new ProductReviewOverviewModel() + { + ProductId = product.Id, + RatingSum = product.ApprovedRatingSum, + TotalReviews = product.ApprovedTotalReviews, + AllowCustomerReviews = product.AllowCustomerReviews + }; + return PartialView(model); + } + + [ChildActionOnly] + public ActionResult ProductSpecifications(int productId) + { + var product = _productService.GetProductById(productId); + if (product == null) + throw new ArgumentException(T("Products.NotFound", productId)); + + var model = _helper.PrepareProductSpecificationModel(product); + + if (model.Count == 0) + return Content(""); + + return PartialView(model); + } + + [ChildActionOnly] + public ActionResult ProductDetailReviews(int productId) + { + var product = _productService.GetProductById(productId); + if (product == null || !product.AllowCustomerReviews) + return Content(""); + + var model = new ProductReviewsModel(); + _helper.PrepareProductReviewsModel(model, product); + + return PartialView(model); + } + + [ChildActionOnly] + public ActionResult ProductTierPrices(int productId) + { + if (!_services.Permissions.Authorize(StandardPermissionProvider.DisplayPrices)) + return Content(""); //hide prices + + var product = _productService.GetProductById(productId); + if (product == null) + throw new ArgumentException(T("Products.NotFound", productId)); + + if (!product.HasTierPrices) + return Content(""); //no tier prices + + var model = product.TierPrices + .OrderBy(x => x.Quantity) + .FilterByStore(_services.StoreContext.CurrentStore.Id) + .FilterForCustomer(_services.WorkContext.CurrentCustomer) + .ToList() + .RemoveDuplicatedQuantities() + .Select(tierPrice => + { + var m = new ProductDetailsModel.TierPriceModel() + { + Quantity = tierPrice.Quantity, + }; + decimal taxRate = decimal.Zero; + decimal priceBase = _taxService.GetProductPrice(product, _priceCalculationService.GetFinalPrice(product, _services.WorkContext.CurrentCustomer, decimal.Zero, _catalogSettings.DisplayTierPricesWithDiscounts, tierPrice.Quantity), out taxRate); + decimal price = _currencyService.ConvertFromPrimaryStoreCurrency(priceBase, _services.WorkContext.WorkingCurrency); + m.Price = _priceFormatter.FormatPrice(price, true, false); + return m; + }) + .ToList(); + + return PartialView(model); + } + + [ChildActionOnly] + public ActionResult RelatedProducts(int productId, int? productThumbPictureSize) + { + var products = new List(); + var relatedProducts = _productService.GetRelatedProductsByProductId1(productId); + foreach (var product in _productService.GetProductsByIds(relatedProducts.Select(x => x.ProductId2).ToArray())) + { + //ensure has ACL permission and appropriate store mapping + if (_aclService.Authorize(product) && _storeMappingService.Authorize(product)) + products.Add(product); + } + + if (products.Count == 0) + return Content(""); + + var model = _helper.PrepareProductOverviewModels(products, true, true, productThumbPictureSize, false, false, false, false, true).ToList(); + + return PartialView(model); + } + + [ChildActionOnly] + public ActionResult ProductsAlsoPurchased(int productId, int? productThumbPictureSize) + { + if (!_catalogSettings.ProductsAlsoPurchasedEnabled) + return Content(""); + + // load and cache report + var productIds = _services.Cache.Get(string.Format(ModelCacheEventConsumer.PRODUCTS_ALSO_PURCHASED_IDS_KEY, productId, _services.StoreContext.CurrentStore.Id), () => + { + return _orderReportService.GetAlsoPurchasedProductsIds(_services.StoreContext.CurrentStore.Id, productId, _catalogSettings.ProductsAlsoPurchasedNumber); + }); + + // load products + var products = _productService.GetProductsByIds(productIds); + + // ACL and store mapping + products = products.Where(p => _aclService.Authorize(p) && _storeMappingService.Authorize(p)).ToList(); + + if (products.Count == 0) + return Content(""); + + // prepare model + var model = _helper.PrepareProductOverviewModels(products, true, true, productThumbPictureSize, false, false, false, false, true).ToList(); + + return PartialView(model); + } + + [ChildActionOnly] + public ActionResult ShareButton() + { + if (_catalogSettings.ShowShareButton && !String.IsNullOrEmpty(_catalogSettings.PageShareCode)) + { + var shareCode = _catalogSettings.PageShareCode; + if (_services.WebHelper.IsCurrentConnectionSecured()) + { + //need to change the addthis link to be https linked when the page is, so that the page doesnt ask about mixed mode when viewed in https... + shareCode = shareCode.Replace("http://", "https://"); + } + + return PartialView("ShareButton", shareCode); + } + + return Content(""); + } + + [ChildActionOnly] + public ActionResult CrossSellProducts(int? productThumbPictureSize) + { + var cart = _services.WorkContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, _services.StoreContext.CurrentStore.Id); + + var products = _productService.GetCrosssellProductsByShoppingCart(cart, _shoppingCartSettings.CrossSellsNumber); + //ACL and store mapping + products = products.Where(p => _aclService.Authorize(p) && _storeMappingService.Authorize(p)).ToList(); + + + //Cross-sell products are dispalyed on the shopping cart page. + //We know that the entire shopping cart page is not refresh + //even if "ShoppingCartSettings.DisplayCartAfterAddingProduct" setting is enabled. + //That's why we force page refresh (redirect) in this case + var model = _helper.PrepareProductOverviewModels(products, + productThumbPictureSize: productThumbPictureSize, forceRedirectionAfterAddingToCart: true) + .ToList(); + + return PartialView(model); + } + + [ActionName("BackInStockSubscribe")] + public ActionResult BackInStockSubscribePopup(int id /* productId */) + { + var product = _productService.GetProductById(id); + if (product == null || product.Deleted) + throw new ArgumentException(T("Products.NotFound", id)); + + var model = new BackInStockSubscribeModel(); + model.ProductId = product.Id; + model.ProductName = product.GetLocalized(x => x.Name); + model.ProductSeName = product.GetSeName(); + model.IsCurrentCustomerRegistered = _services.WorkContext.CurrentCustomer.IsRegistered(); + model.MaximumBackInStockSubscriptions = _catalogSettings.MaximumBackInStockSubscriptions; + model.CurrentNumberOfBackInStockSubscriptions = _backInStockSubscriptionService + .GetAllSubscriptionsByCustomerId(_services.WorkContext.CurrentCustomer.Id, _services.StoreContext.CurrentStore.Id, 0, 1) + .TotalCount; + if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock && + product.BackorderMode == BackorderMode.NoBackorders && + product.AllowBackInStockSubscriptions && + product.StockQuantity <= 0) + { + //out of stock + model.SubscriptionAllowed = true; + model.AlreadySubscribed = _backInStockSubscriptionService + .FindSubscription(_services.WorkContext.CurrentCustomer.Id, product.Id, _services.StoreContext.CurrentStore.Id) != null; + } + return View("BackInStockSubscribePopup", model); + } + + [HttpPost, ActionName("BackInStockSubscribe")] + public ActionResult BackInStockSubscribePopupPOST(int id /* productId */) + { + var product = _productService.GetProductById(id); + if (product == null || product.Deleted) + throw new ArgumentException(T("Products.NotFound", id)); + + if (!_services.WorkContext.CurrentCustomer.IsRegistered()) + return Content(T("BackInStockSubscriptions.OnlyRegistered")); + + if (product.ManageInventoryMethod == ManageInventoryMethod.ManageStock && + product.BackorderMode == BackorderMode.NoBackorders && + product.AllowBackInStockSubscriptions && + product.StockQuantity <= 0) + { + //out of stock + var subscription = _backInStockSubscriptionService + .FindSubscription(_services.WorkContext.CurrentCustomer.Id, product.Id, _services.StoreContext.CurrentStore.Id); + if (subscription != null) + { + //unsubscribe + _backInStockSubscriptionService.DeleteSubscription(subscription); + return Content("Unsubscribed"); + } + else + { + if (_backInStockSubscriptionService + .GetAllSubscriptionsByCustomerId(_services.WorkContext.CurrentCustomer.Id, _services.StoreContext.CurrentStore.Id, 0, 1) + .TotalCount >= _catalogSettings.MaximumBackInStockSubscriptions) + return Content(string.Format(T("BackInStockSubscriptions.MaxSubscriptions"), _catalogSettings.MaximumBackInStockSubscriptions)); + + //subscribe + subscription = new BackInStockSubscription() + { + Customer = _services.WorkContext.CurrentCustomer, + Product = product, + StoreId = _services.StoreContext.CurrentStore.Id, + CreatedOnUtc = DateTime.UtcNow + }; + _backInStockSubscriptionService.InsertSubscription(subscription); + return Content("Subscribed"); + } + + } + else + { + return Content(T("BackInStockSubscriptions.NotAllowed")); + } + } + + [HttpPost] + public ActionResult UpdateProductDetails(int productId, string itemType, int bundleItemId, FormCollection form) + { + int quantity = 1; + int galleryStartIndex = -1; + string galleryHtml = null; + string dynamicThumbUrl = null; + bool isAssociated = itemType.IsCaseInsensitiveEqual("associateditem"); + var pictureModel = new ProductDetailsPictureModel(); + var m = new ProductDetailsModel(); + var product = _productService.GetProductById(productId); + var bItem = _productService.GetBundleItemById(bundleItemId); + IList bundleItems = null; + ProductBundleItemData bundleItem = (bItem == null ? null : new ProductBundleItemData(bItem)); + + var warnings = new List(); + var attributes = _productAttributeService.GetProductVariantAttributesByProductId(productId); + + string attributeXml = form.CreateSelectedAttributesXml(productId, attributes, _productAttributeParser, + _localizationService, _downloadService, _catalogSettings, this.Request, warnings, true); + + var areAllAttributesForCombinationSelected = _shoppingCartService.AreAllAttributesForCombinationSelected(attributeXml, product); + + // quantity required for tier prices + string quantityKey = form.AllKeys.FirstOrDefault(k => k.EndsWith("EnteredQuantity")); + if (quantityKey.HasValue()) + int.TryParse(form[quantityKey], out quantity); + + if (product.ProductType == ProductType.BundledProduct && product.BundlePerItemPricing) + { + bundleItems = _productService.GetBundleItems(product.Id); + if (form.Count > 0) + { + // may add elements to form if they are preselected by bundle item filter + foreach (var itemData in bundleItems) + { + var unused = _helper.PrepareProductDetailsPageModel(itemData.Item.Product, false, itemData, null, form); + } + } + } + + // get merged model data + _helper.PrepareProductDetailModel(m, product, isAssociated, bundleItem, bundleItems, form, quantity); + + if (bundleItem != null) // update bundle item thumbnail + { + if (!bundleItem.Item.HideThumbnail) + { + var picture = m.GetAssignedPicture(_pictureService, null, bundleItem.Item.ProductId); + dynamicThumbUrl = _pictureService.GetPictureUrl(picture, _mediaSettings.BundledProductPictureSize, false); + } + } + else if (isAssociated) // update associated product thumbnail + { + var picture = m.GetAssignedPicture(_pictureService, null, productId); + dynamicThumbUrl = _pictureService.GetPictureUrl(picture, _mediaSettings.AssociatedProductPictureSize, false); + } + else if (product.ProductType != ProductType.BundledProduct) // update image gallery + { + var pictures = _pictureService.GetPicturesByProductId(productId); + + if (pictures.Count <= _catalogSettings.DisplayAllImagesNumber) // all pictures rendered... only index is required + { + var picture = m.GetAssignedPicture(_pictureService, pictures); + galleryStartIndex = (picture == null ? 0 : pictures.IndexOf(picture)); + } + else + { + var allCombinationPictureIds = _productAttributeService.GetAllProductVariantAttributeCombinationPictureIds(product.Id); + + _helper.PrepareProductDetailsPictureModel( + pictureModel, + pictures, + product.GetLocalized(x => x.Name), + allCombinationPictureIds, + false, + bundleItem, + m.SelectedCombination); + + galleryStartIndex = pictureModel.GalleryStartIndex; + galleryHtml = this.RenderPartialViewToString("_PictureGallery", pictureModel); + } + } + + #region data object + + object data = new + { + Delivery = new + { + Id = 0, + Name = m.DeliveryTimeName, + Color = m.DeliveryTimeHexValue, + DisplayAccordingToStock = m.DisplayDeliveryTimeAccordingToStock + }, + Measure = new + { + Weight = new { Value = m.WeightValue, Text = m.Weight }, + Height = new { Value = product.Height, Text = m.Height }, + Width = new { Value = product.Width, Text = m.Width }, + Length = new { Value = product.Length, Text = m.Length } + }, + Number = new + { + Sku = new { Value = m.Sku, Show = m.ShowSku }, + Gtin = new { Value = m.Gtin, Show = m.ShowGtin }, + Mpn = new { Value = m.ManufacturerPartNumber, Show = m.ShowManufacturerPartNumber } + }, + Price = new + { + Base = new + { + Enabled = m.IsBasePriceEnabled, + Info = m.BasePriceInfo + }, + Old = new + { + Value = decimal.Zero, + Text = m.ProductPrice.OldPrice + }, + WithoutDiscount = new + { + Value = m.ProductPrice.PriceValue, + Text = m.ProductPrice.Price + }, + WithDiscount = new + { + Value = m.ProductPrice.PriceWithDiscountValue, + Text = m.ProductPrice.PriceWithDiscount + } + }, + Stock = new + { + Quantity = new + { + Value = product.StockQuantity, + Show = areAllAttributesForCombinationSelected ? product.DisplayStockQuantity : false + }, + Availability = new + { + Text = m.StockAvailability, + Show = areAllAttributesForCombinationSelected ? product.DisplayStockAvailability : false, + Available = m.IsAvailable + } + }, + + DynamicThumblUrl = dynamicThumbUrl, + GalleryStartIndex = galleryStartIndex, + GalleryHtml = galleryHtml + }; + + #endregion + + return new JsonResult { Data = data }; + } + + #endregion + + + #region Product tags + + [ChildActionOnly] + public ActionResult ProductTags(int productId) + { + var product = _productService.GetProductById(productId); + if (product == null) + throw new ArgumentException(T("Products.NotFound", productId)); + + var cacheKey = string.Format(ModelCacheEventConsumer.PRODUCTTAG_BY_PRODUCT_MODEL_KEY, product.Id, _services.WorkContext.WorkingLanguage.Id, _services.StoreContext.CurrentStore.Id); + var cacheModel = _services.Cache.Get(cacheKey, () => + { + var model = product.ProductTags + //filter by store + .Where(x => _productTagService.GetProductCount(x.Id, _services.StoreContext.CurrentStore.Id) > 0) + .Select(x => + { + var ptModel = new ProductTagModel() + { + Id = x.Id, + Name = x.GetLocalized(y => y.Name), + SeName = x.GetSeName(), + ProductCount = _productTagService.GetProductCount(x.Id, _services.StoreContext.CurrentStore.Id) + }; + return ptModel; + }) + .ToList(); + return model; + }); + + return PartialView(cacheModel); + } + + #endregion + + + #region Product reviews + + [ActionName("Reviews")] + [RequireHttpsByConfigAttribute(SslRequirement.No)] + public ActionResult Reviews(int id) + { + var product = _productService.GetProductById(id); + if (product == null || product.Deleted || !product.Published || !product.AllowCustomerReviews) + return HttpNotFound(); + + var model = new ProductReviewsModel(); + _helper.PrepareProductReviewsModel(model, product); + //only registered users can leave reviews + if (_services.WorkContext.CurrentCustomer.IsGuest() && !_catalogSettings.AllowAnonymousUsersToReviewProduct) + ModelState.AddModelError("", T("Reviews.OnlyRegisteredUsersCanWriteReviews")); + //default value + model.AddProductReview.Rating = _catalogSettings.DefaultProductRatingValue; + return View(model); + } + + [HttpPost, ActionName("Reviews")] + [FormValueRequired("add-review")] + [CaptchaValidator] + public ActionResult ReviewsAdd(int id, ProductReviewsModel model, bool captchaValid) + { + var product = _productService.GetProductById(id); + if (product == null || product.Deleted || !product.Published || !product.AllowCustomerReviews) + return HttpNotFound(); + + //validate CAPTCHA + if (_captchaSettings.Enabled && _captchaSettings.ShowOnProductReviewPage && !captchaValid) + { + ModelState.AddModelError("", T("Common.WrongCaptcha")); + } + + if (_services.WorkContext.CurrentCustomer.IsGuest() && !_catalogSettings.AllowAnonymousUsersToReviewProduct) + { + ModelState.AddModelError("", T("Reviews.OnlyRegisteredUsersCanWriteReviews")); + } + + if (ModelState.IsValid) + { + //save review + int rating = model.AddProductReview.Rating; + if (rating < 1 || rating > 5) + rating = _catalogSettings.DefaultProductRatingValue; + + bool isApproved = !_catalogSettings.ProductReviewsMustBeApproved; + var customer = _services.WorkContext.CurrentCustomer; + + var productReview = new ProductReview() + { + ProductId = product.Id, + CustomerId = customer.Id, + IpAddress = _services.WebHelper.GetCurrentIpAddress(), + Title = model.AddProductReview.Title, + ReviewText = model.AddProductReview.ReviewText, + Rating = rating, + HelpfulYesTotal = 0, + HelpfulNoTotal = 0, + IsApproved = isApproved, + CreatedOnUtc = DateTime.UtcNow, + UpdatedOnUtc = DateTime.UtcNow, + }; + _customerContentService.InsertCustomerContent(productReview); + + //update product totals + _productService.UpdateProductReviewTotals(product); + + //notify store owner + if (_catalogSettings.NotifyStoreOwnerAboutNewProductReviews) + _workflowMessageService.SendProductReviewNotificationMessage(productReview, _localizationSettings.DefaultAdminLanguageId); + + //activity log + _services.CustomerActivity.InsertActivity("PublicStore.AddProductReview", T("ActivityLog.PublicStore.AddProductReview"), product.Name); + + if (isApproved) + _customerService.RewardPointsForProductReview(customer, product, true); + + _helper.PrepareProductReviewsModel(model, product); + model.AddProductReview.Title = null; + model.AddProductReview.ReviewText = null; + + model.AddProductReview.SuccessfullyAdded = true; + if (!isApproved) + model.AddProductReview.Result = T("Reviews.SeeAfterApproving"); + else + model.AddProductReview.Result = T("Reviews.SuccessfullyAdded"); + + return View(model); + } + + //If we got this far, something failed, redisplay form + _helper.PrepareProductReviewsModel(model, product); + return View(model); + } + + [HttpPost] + public ActionResult SetReviewHelpfulness(int productReviewId, bool washelpful) + { + var productReview = _customerContentService.GetCustomerContentById(productReviewId) as ProductReview; + if (productReview == null) + throw new ArgumentException(T("Reviews.NotFound", productReviewId)); + + if (_services.WorkContext.CurrentCustomer.IsGuest() && !_catalogSettings.AllowAnonymousUsersToReviewProduct) + { + return Json(new + { + Success = false, + Result = T("Reviews.Helpfulness.OnlyRegistered").Text, + TotalYes = productReview.HelpfulYesTotal, + TotalNo = productReview.HelpfulNoTotal + }); + } + + //customers aren't allowed to vote for their own reviews + if (productReview.CustomerId == _services.WorkContext.CurrentCustomer.Id) + { + return Json(new + { + Success = false, + Result = T("Reviews.Helpfulness.YourOwnReview").Text, + TotalYes = productReview.HelpfulYesTotal, + TotalNo = productReview.HelpfulNoTotal + }); + } + + //delete previous helpfulness + var oldPrh = (from prh in productReview.ProductReviewHelpfulnessEntries + where prh.CustomerId == _services.WorkContext.CurrentCustomer.Id + select prh).FirstOrDefault(); + if (oldPrh != null) + _customerContentService.DeleteCustomerContent(oldPrh); + + //insert new helpfulness + var newPrh = new ProductReviewHelpfulness() + { + ProductReviewId = productReview.Id, + CustomerId = _services.WorkContext.CurrentCustomer.Id, + IpAddress = _services.WebHelper.GetCurrentIpAddress(), + WasHelpful = washelpful, + IsApproved = true, //always approved + CreatedOnUtc = DateTime.UtcNow, + UpdatedOnUtc = DateTime.UtcNow, + }; + _customerContentService.InsertCustomerContent(newPrh); + + //new totals + int helpfulYesTotal = (from prh in productReview.ProductReviewHelpfulnessEntries + where prh.WasHelpful + select prh).Count(); + int helpfulNoTotal = (from prh in productReview.ProductReviewHelpfulnessEntries + where !prh.WasHelpful + select prh).Count(); + + productReview.HelpfulYesTotal = helpfulYesTotal; + productReview.HelpfulNoTotal = helpfulNoTotal; + _customerContentService.UpdateCustomerContent(productReview); + + return Json(new + { + Success = true, + Result = T("Reviews.Helpfulness.SuccessfullyVoted").Text, + TotalYes = productReview.HelpfulYesTotal, + TotalNo = productReview.HelpfulNoTotal + }); + } + + #endregion + + + #region Ask product question + + [ChildActionOnly] + public ActionResult AskQuestionButton(int id) + { + if (!_catalogSettings.AskQuestionEnabled) + return Content(""); + var model = new ProductAskQuestionModel() + { + Id = id + }; + + return PartialView(model); + } + + [RequireHttpsByConfigAttribute(SslRequirement.No)] + public ActionResult AskQuestion(int id) + { + var product = _productService.GetProductById(id); + if (product == null || product.Deleted || !product.Published || !_catalogSettings.AskQuestionEnabled) + return HttpNotFound(); + + var customer = _services.WorkContext.CurrentCustomer; + + var model = new ProductAskQuestionModel(); + model.Id = product.Id; + model.ProductName = product.GetLocalized(x => x.Name); + model.ProductSeName = product.GetSeName(); + model.SenderEmail = customer.Email; + model.SenderName = customer.GetFullName(); + model.SenderPhone = customer.GetAttribute(SystemCustomerAttributeNames.Phone); + model.Question = T("Products.AskQuestion.Question.Text").Text.FormatCurrentUI(model.ProductName); + model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnAskQuestionPage; + + return View(model); + } + + [HttpPost, ActionName("AskQuestion")] + [CaptchaValidator] + public ActionResult AskQuestionSend(ProductAskQuestionModel model, bool captchaValid) + { + var product = _productService.GetProductById(model.Id); + if (product == null || product.Deleted || !product.Published || !_catalogSettings.AskQuestionEnabled) + return HttpNotFound(); + + // validate CAPTCHA + if (_captchaSettings.Enabled && _captchaSettings.ShowOnAskQuestionPage && !captchaValid) + { + ModelState.AddModelError("", T("Common.WrongCaptcha")); + } + + if (ModelState.IsValid) + { + // email + var result = _workflowMessageService.SendProductQuestionMessage( + _services.WorkContext.CurrentCustomer, + _services.WorkContext.WorkingLanguage.Id, + product, + model.SenderEmail, + model.SenderName, + model.SenderPhone, + Core.Html.HtmlUtils.FormatText(model.Question, false, true, false, false, false, false)); + + if (result > 0) + { + this.NotifySuccess(T("Products.AskQuestion.Sent"), true); + return RedirectToRoute("Product", new { SeName = product.GetSeName() }); + } + else + { + ModelState.AddModelError("", T("Common.Error.SendMail")); + } + } + + // If we got this far, something failed, redisplay form + var customer = _services.WorkContext.CurrentCustomer; + model.Id = product.Id; + model.ProductName = product.GetLocalized(x => x.Name); + model.ProductSeName = product.GetSeName(); + model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnAskQuestionPage; + return View(model); + } + + #endregion + + + #region Email a friend + + [ChildActionOnly] + public ActionResult EmailAFriendButton(int id) + { + if (!_catalogSettings.EmailAFriendEnabled) + return Content(""); + var model = new ProductEmailAFriendModel() + { + ProductId = id + }; + + return PartialView(model); + } + + [RequireHttpsByConfigAttribute(SslRequirement.No)] + public ActionResult EmailAFriend(int id) + { + var product = _productService.GetProductById(id); + if (product == null || product.Deleted || !product.Published || !_catalogSettings.EmailAFriendEnabled) + return HttpNotFound(); + + var model = new ProductEmailAFriendModel(); + model.ProductId = product.Id; + model.ProductName = product.GetLocalized(x => x.Name); + model.ProductSeName = product.GetSeName(); + model.YourEmailAddress = _services.WorkContext.CurrentCustomer.Email; + model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnEmailProductToFriendPage; + return View(model); + } + + [HttpPost, ActionName("EmailAFriend")] + [CaptchaValidator] + public ActionResult EmailAFriendSend(ProductEmailAFriendModel model, int id, bool captchaValid) + { + var product = _productService.GetProductById(id); + if (product == null || product.Deleted || !product.Published || !_catalogSettings.EmailAFriendEnabled) + return HttpNotFound(); + + //validate CAPTCHA + if (_captchaSettings.Enabled && _captchaSettings.ShowOnEmailProductToFriendPage && !captchaValid) + { + ModelState.AddModelError("", T("Common.WrongCaptcha")); + } + + //check whether the current customer is guest and ia allowed to email a friend + if (_services.WorkContext.CurrentCustomer.IsGuest() && !_catalogSettings.AllowAnonymousUsersToEmailAFriend) + { + ModelState.AddModelError("", T("Products.EmailAFriend.OnlyRegisteredUsers")); + } + + if (ModelState.IsValid) + { + //email + _workflowMessageService.SendProductEmailAFriendMessage(_services.WorkContext.CurrentCustomer, + _services.WorkContext.WorkingLanguage.Id, product, + model.YourEmailAddress, model.FriendEmail, + Core.Html.HtmlUtils.FormatText(model.PersonalMessage, false, true, false, false, false, false)); + + model.ProductId = product.Id; + model.ProductName = product.GetLocalized(x => x.Name); + model.ProductSeName = product.GetSeName(); + + //model.SuccessfullySent = true; + //model.Result = T("Products.EmailAFriend.SuccessfullySent"); + + //return View(model); + + NotifySuccess(T("Products.EmailAFriend.SuccessfullySent")); + + return RedirectToRoute("Product", new { SeName = model.ProductSeName }); + } + + //If we got this far, something failed, redisplay form + model.ProductId = product.Id; + model.ProductName = product.GetLocalized(x => x.Name); + model.ProductSeName = product.GetSeName(); + model.DisplayCaptcha = _captchaSettings.Enabled && _captchaSettings.ShowOnEmailProductToFriendPage; + return View(model); + } + + #endregion + + } +} diff --git a/src/Presentation/SmartStore.Web/Controllers/ProfileController.cs b/src/Presentation/SmartStore.Web/Controllers/ProfileController.cs index 8a4881ba0a..6f79a4ebcc 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ProfileController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ProfileController.cs @@ -65,7 +65,7 @@ public ActionResult Index(int? id, int? page) var customer = _customerService.GetCustomerById(customerId); if (!_customerSettings.AllowViewingProfiles || (customer == null || customer.IsGuest())) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } bool pagingPosts = false; @@ -99,7 +99,7 @@ public ActionResult Info(int customerProfileId) var customer = _customerService.GetCustomerById(customerProfileId); if (customer == null) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } //avatar @@ -204,7 +204,7 @@ public ActionResult Posts(int customerProfileId, int page) var customer = _customerService.GetCustomerById(customerProfileId); if (customer == null) { - return RedirectToRoute("HomePage"); + return HttpNotFound(); } if (page > 0) @@ -240,12 +240,10 @@ public ActionResult Posts(int customerProfileId, int page) }); } - // codehint: sm-edit ViewData["PagerRouteValues"] = new RouteValues { page = page, id = customerProfileId }; var model = new ProfilePostsModel(list) { - // codehint: sm-delete Posts = latestPosts, }; diff --git a/src/Presentation/SmartStore.Web/Controllers/ReturnRequestController.cs b/src/Presentation/SmartStore.Web/Controllers/ReturnRequestController.cs index 0328870008..d7b5e454d6 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ReturnRequestController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ReturnRequestController.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Core; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Tax; @@ -11,9 +13,9 @@ using SmartStore.Services.Messages; using SmartStore.Services.Orders; using SmartStore.Services.Seo; +using SmartStore.Web.Framework.Controllers; using SmartStore.Web.Framework.Security; using SmartStore.Web.Models.Order; -using SmartStore.Web.Framework.Controllers; namespace SmartStore.Web.Controllers { @@ -30,6 +32,7 @@ public partial class ReturnRequestController : PublicControllerBase private readonly ILocalizationService _localizationService; private readonly ICustomerService _customerService; private readonly IWorkflowMessageService _workflowMessageService; + private readonly IProductAttributeParser _productAttributeParser; private readonly LocalizationSettings _localizationSettings; private readonly OrderSettings _orderSettings; @@ -38,13 +41,15 @@ public partial class ReturnRequestController : PublicControllerBase #region Constructors - public ReturnRequestController(IOrderService orderService, + public ReturnRequestController( + IOrderService orderService, IWorkContext workContext, IStoreContext storeContext, ICurrencyService currencyService, IPriceFormatter priceFormatter, IOrderProcessingService orderProcessingService, ILocalizationService localizationService, ICustomerService customerService, IWorkflowMessageService workflowMessageService, + IProductAttributeParser productAttributeParser, LocalizationSettings localizationSettings, OrderSettings orderSettings) { @@ -57,6 +62,7 @@ public ReturnRequestController(IOrderService orderService, this._localizationService = localizationService; this._customerService = customerService; this._workflowMessageService = workflowMessageService; + this._productAttributeParser = productAttributeParser; this._localizationSettings = localizationSettings; this._orderSettings = orderSettings; @@ -77,42 +83,50 @@ protected SubmitReturnRequestModel PrepareReturnRequestModel(SubmitReturnRequest model.OrderId = order.Id; + string returnRequestReasons = _orderSettings.GetLocalized(x => x.ReturnRequestReasons, order.CustomerLanguageId, true, false); + string returnRequestActions = _orderSettings.GetLocalized(x => x.ReturnRequestActions, order.CustomerLanguageId, true, false); + //return reasons - if (_orderSettings.ReturnRequestReasons != null) - foreach (var rrr in _orderSettings.ReturnRequestReasons) - { - model.AvailableReturnReasons.Add(new SelectListItem() - { - Text = rrr, - Value = rrr - }); - } + foreach (var rrr in returnRequestReasons.SplitSafe(",")) + { + model.AvailableReturnReasons.Add(new SelectListItem() { Text = rrr, Value = rrr }); + } //return actions - if (_orderSettings.ReturnRequestActions != null) - foreach (var rra in _orderSettings.ReturnRequestActions) - { - model.AvailableReturnActions.Add(new SelectListItem() - { - Text = rra, - Value = rra - }); - } + foreach (var rra in returnRequestActions.SplitSafe(",")) + { + model.AvailableReturnActions.Add(new SelectListItem() { Text = rra, Value = rra }); + } //products var orderItems = _orderService.GetAllOrderItems(order.Id, null, null, null, null, null, null); + foreach (var orderItem in orderItems) { - var orderItemModel = new SubmitReturnRequestModel.OrderItemModel() + var attributeQueryData = new List>(); + + var orderItemModel = new SubmitReturnRequestModel.OrderItemModel { Id = orderItem.Id, ProductId = orderItem.Product.Id, ProductName = orderItem.Product.GetLocalized(x => x.Name), - ProductSeName = orderItem.Product.GetSeName(), + ProductSeName = orderItem.Product.GetSeName(), AttributeInfo = orderItem.AttributeDescription, Quantity = orderItem.Quantity }; - model.Items.Add(orderItemModel); + + if (orderItem.Product.ProductType != ProductType.BundledProduct) + { + _productAttributeParser.DeserializeQueryData(attributeQueryData, orderItem.AttributesXml, orderItem.ProductId); + } + else if (orderItem.Product.BundlePerItemPricing && orderItem.BundleData.HasValue()) + { + var bundleData = orderItem.GetBundleData(); + + bundleData.ForEach(x => _productAttributeParser.DeserializeQueryData(attributeQueryData, x.AttributesXml, x.ProductId, x.BundleItemId)); + } + + orderItemModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes(attributeQueryData, orderItemModel.ProductSeName); //unit price switch (order.CustomerTaxDisplayType) @@ -130,6 +144,8 @@ protected SubmitReturnRequestModel PrepareReturnRequestModel(SubmitReturnRequest } break; } + + model.Items.Add(orderItemModel); } return model; @@ -140,9 +156,9 @@ protected SubmitReturnRequestModel PrepareReturnRequestModel(SubmitReturnRequest #region Return requests [RequireHttpsByConfigAttribute(SslRequirement.Yes)] - public ActionResult ReturnRequest(int orderId) + public ActionResult ReturnRequest(int id /* orderId */) { - var order = _orderService.GetOrderById(orderId); + var order = _orderService.GetOrderById(id); if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) return new HttpUnauthorizedResult(); @@ -154,11 +170,11 @@ public ActionResult ReturnRequest(int orderId) return View(model); } - [HttpPost, ActionName("ReturnRequest")] + [HttpPost, ActionName("ReturnRequest")] [ValidateInput(false)] - public ActionResult ReturnRequestSubmit(int orderId, SubmitReturnRequestModel model, FormCollection form) + public ActionResult ReturnRequestSubmit(int id /* orderId */, SubmitReturnRequestModel model, FormCollection form) { - var order = _orderService.GetOrderById(orderId); + var order = _orderService.GetOrderById(id); if (order == null || order.Deleted || _workContext.CurrentCustomer.Id != order.CustomerId) return new HttpUnauthorizedResult(); diff --git a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs index ac9f0b1632..e4ff2cb6a7 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ShoppingCartController.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; using System.Web; using System.Web.Mvc; @@ -18,6 +17,7 @@ using SmartStore.Core.Domain.Shipping; using SmartStore.Core.Domain.Tax; using SmartStore.Core.Html; +using SmartStore.Core.Logging; using SmartStore.Services.Catalog; using SmartStore.Services.Common; using SmartStore.Services.Customers; @@ -32,14 +32,15 @@ using SmartStore.Services.Seo; using SmartStore.Services.Shipping; using SmartStore.Services.Tax; -using SmartStore.Web.Extensions; +using SmartStore.Services.Topics; using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Plugins; using SmartStore.Web.Framework.Security; using SmartStore.Web.Framework.UI.Captcha; using SmartStore.Web.Infrastructure.Cache; using SmartStore.Web.Models.Media; using SmartStore.Web.Models.ShoppingCart; -using SmartStore.Core.Logging; namespace SmartStore.Web.Controllers { @@ -81,7 +82,6 @@ public partial class ShoppingCartController : PublicControllerBase private readonly IGenericAttributeService _genericAttributeService; private readonly IDeliveryTimeService _deliveryTimeService; private readonly HttpContextBase _httpContext; - private readonly MediaSettings _mediaSettings; private readonly ShoppingCartSettings _shoppingCartSettings; private readonly CatalogSettings _catalogSettings; @@ -90,12 +90,17 @@ public partial class ShoppingCartController : PublicControllerBase private readonly TaxSettings _taxSettings; private readonly CaptchaSettings _captchaSettings; private readonly AddressSettings _addressSettings; + private readonly PluginMediator _pluginMediator; + private readonly IQuantityUnitService _quantityUnitService; + private readonly Lazy _topicService; + private readonly IMeasureService _measureService; + private readonly MeasureSettings _measureSettings; - #endregion + #endregion - #region Constructors + #region Constructors - public ShoppingCartController(IProductService productService, + public ShoppingCartController(IProductService productService, IWorkContext workContext, IStoreContext storeContext, IShoppingCartService shoppingCartService, IPictureService pictureService, ILocalizationService localizationService, @@ -119,7 +124,10 @@ public ShoppingCartController(IProductService productService, CatalogSettings catalogSettings, OrderSettings orderSettings, ShippingSettings shippingSettings, TaxSettings taxSettings, CaptchaSettings captchaSettings, AddressSettings addressSettings, - HttpContextBase httpContext) + HttpContextBase httpContext, PluginMediator pluginMediator, + IQuantityUnitService quantityUnitService, + Lazy topicService, + IMeasureService measureService, MeasureSettings measureSettings) { this._productService = productService; this._workContext = workContext; @@ -155,7 +163,6 @@ public ShoppingCartController(IProductService productService, this._genericAttributeService = genericAttributeService; this._deliveryTimeService = deliveryTimeService; this._httpContext = httpContext; - this._mediaSettings = mediaSettings; this._shoppingCartSettings = shoppingCartSettings; this._catalogSettings = catalogSettings; @@ -164,6 +171,11 @@ public ShoppingCartController(IProductService productService, this._taxSettings = taxSettings; this._captchaSettings = captchaSettings; this._addressSettings = addressSettings; + this._pluginMediator = pluginMediator; + this._quantityUnitService = quantityUnitService; + this._topicService = topicService; + this._measureService = measureService; + this._measureSettings = measureSettings; } #endregion @@ -171,7 +183,7 @@ public ShoppingCartController(IProductService productService, #region Utilities [NonAction] - protected PictureModel PrepareCartItemPictureModel(Product product, int pictureSize, bool showDefaultPicture, string productName, string attributesXml) + protected PictureModel PrepareCartItemPictureModel(Product product, int pictureSize, string productName, string attributesXml) { if (product == null) throw new ArgumentNullException("product"); @@ -202,10 +214,10 @@ protected PictureModel PrepareCartItemPictureModel(Product product, int pictureS picture = _pictureService.GetPicturesByProductId(product.ParentGroupedProductId, 1).FirstOrDefault(); } - return new PictureModel() + return new PictureModel { PictureId = picture != null ? picture.Id : 0, - ImageUrl = _pictureService.GetPictureUrl(picture, pictureSize, showDefaultPicture), + ImageUrl = _pictureService.GetPictureUrl(picture, pictureSize, !_catalogSettings.HideProductDefaultPictures), Title = string.Format(_localizationService.GetResource("Media.Product.ImageLinkTitleFormat"), productName), AlternateText = string.Format(_localizationService.GetResource("Media.Product.ImageAlternateTextFormat"), productName), }; @@ -220,7 +232,7 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org product.MergeWithCombination(item.AttributesXml); - var model = new ShoppingCartModel.ShoppingCartItemModel() + var model = new ShoppingCartModel.ShoppingCartItemModel { Id = item.Id, Sku = product.Sku, @@ -232,16 +244,22 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org IsShipEnabled = product.IsShipEnabled, ShortDesc = product.GetLocalized(x => x.ShortDescription), ProductType = product.ProductType, - BasePrice = product.GetBasePriceInfo(_localizationService, _priceFormatter) + BasePrice = product.GetBasePriceInfo(_localizationService, _priceFormatter, _currencyService, _taxService, _priceCalculationService, _workContext.WorkingCurrency), + Weight = product.Weight, + IsDownload = product.IsDownload, + HasUserAgreement = product.HasUserAgreement, + IsEsd = product.IsEsd }; + model.ProductUrl = GetProductUrlWithAttributes(sci, model.ProductSeName); + if (item.BundleItem != null) { model.BundlePerItemPricing = item.BundleItem.BundleProduct.BundlePerItemPricing; model.BundlePerItemShoppingCart = item.BundleItem.BundleProduct.BundlePerItemShoppingCart; model.AttributeInfo = _productAttributeFormatter.FormatAttributes(product, item.AttributesXml, _workContext.CurrentCustomer, - renderPrices: false, renderGiftCardAttributes: true, allowHyperlinks: false); + renderPrices: false, renderGiftCardAttributes: true, allowHyperlinks: true); string bundleItemName = item.BundleItem.GetLocalized(x => x.Name); if (bundleItemName.HasValue()) @@ -267,15 +285,32 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org else { model.AttributeInfo = _productAttributeFormatter.FormatAttributes(product, item.AttributesXml); + + var selectedAttributeValues = _productAttributeParser.ParseProductVariantAttributeValues(item.AttributesXml).ToList(); + if (selectedAttributeValues != null) + { + foreach (var attributeValue in selectedAttributeValues) + model.Weight = decimal.Add(model.Weight, attributeValue.WeightAdjustment); + } } - var deliveryTime = _deliveryTimeService.GetDeliveryTimeById(product.DeliveryTimeId.GetValueOrDefault()); - if (deliveryTime != null) + if (product.DisplayDeliveryTimeAccordingToStock(_catalogSettings)) { - model.DeliveryTimeName = deliveryTime.GetLocalized(x => x.Name); - model.DeliveryTimeHexValue = deliveryTime.ColorHexValue; + var deliveryTime = _deliveryTimeService.GetDeliveryTime(product); + if (deliveryTime != null) + { + model.DeliveryTimeName = deliveryTime.GetLocalized(x => x.Name); + model.DeliveryTimeHexValue = deliveryTime.ColorHexValue; + } } + //if show measure Unit + if (product.QuantityUnitId != null) + { + var quantityUnit = _quantityUnitService.GetQuantityUnitById(product.QuantityUnitId); + if(quantityUnit != null) + model.QuantityUnit = quantityUnit.GetLocalized(x => x.Name); + } //allowed quantities var allowedQuantities = product.ParseAllowedQuatities(); @@ -346,23 +381,33 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org decimal shoppingCartItemDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartItemDiscountBase, _workContext.WorkingCurrency); model.Discount = _priceFormatter.FormatPrice(shoppingCartItemDiscount); } + + model.BasePrice = product.GetBasePriceInfo( + _localizationService, + _priceFormatter, + _currencyService, + _taxService, + _priceCalculationService, + _workContext.WorkingCurrency, + (product.Price - _priceCalculationService.GetUnitPrice(sci, true)) * (-1) + ); } //picture if (item.BundleItem != null) { if (_shoppingCartSettings.ShowProductBundleImagesOnShoppingCart) - model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbBundleItemPictureSize, true, model.ProductName, item.AttributesXml); + model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbBundleItemPictureSize, model.ProductName, item.AttributesXml); } else { if (_shoppingCartSettings.ShowProductImagesOnShoppingCart) - model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbPictureSize, true, model.ProductName, item.AttributesXml); + model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbPictureSize, model.ProductName, item.AttributesXml); } //item warnings var itemWarnings = _shoppingCartService.GetShoppingCartItemWarnings(_workContext.CurrentCustomer, item.ShoppingCartType, product, item.StoreId, - item.AttributesXml, item.CustomerEnteredPrice, item.Quantity, false, childItems: sci.ChildItems); + item.AttributesXml, item.CustomerEnteredPrice, item.Quantity, false, bundleItem: item.BundleItem, childItems: sci.ChildItems); foreach (var warning in itemWarnings) { @@ -381,6 +426,7 @@ private ShoppingCartModel.ShoppingCartItemModel PrepareShoppingCartItemModel(Org return model; } + private WishlistModel.ShoppingCartItemModel PrepareWishlistCartItemModel(OrganizedShoppingCartItem sci) { var item = sci.Item; @@ -388,7 +434,7 @@ private WishlistModel.ShoppingCartItemModel PrepareWishlistCartItemModel(Organiz product.MergeWithCombination(item.AttributesXml); - var model = new WishlistModel.ShoppingCartItemModel() + var model = new WishlistModel.ShoppingCartItemModel { Id = item.Id, Sku = product.Sku, @@ -401,6 +447,8 @@ private WishlistModel.ShoppingCartItemModel PrepareWishlistCartItemModel(Organiz VisibleIndividually = product.VisibleIndividually }; + model.ProductUrl = GetProductUrlWithAttributes(sci, model.ProductSeName); + if (item.BundleItem != null) { model.BundlePerItemPricing = item.BundleItem.BundleProduct.BundlePerItemPricing; @@ -438,7 +486,7 @@ private WishlistModel.ShoppingCartItemModel PrepareWishlistCartItemModel(Organiz var allowedQuantities = product.ParseAllowedQuatities(); foreach (var qty in allowedQuantities) { - model.AllowedQuantities.Add(new SelectListItem() + model.AllowedQuantities.Add(new SelectListItem { Text = qty.ToString(), Value = qty.ToString(), @@ -497,12 +545,12 @@ private WishlistModel.ShoppingCartItemModel PrepareWishlistCartItemModel(Organiz if (item.BundleItem != null) { if (_shoppingCartSettings.ShowProductBundleImagesOnShoppingCart) - model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbBundleItemPictureSize, true, model.ProductName, item.AttributesXml); + model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbBundleItemPictureSize, model.ProductName, item.AttributesXml); } else { if (_shoppingCartSettings.ShowProductImagesOnShoppingCart) - model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbPictureSize, true, model.ProductName, item.AttributesXml); + model.Picture = PrepareCartItemPictureModel(product, _mediaSettings.CartThumbPictureSize, model.ProductName, item.AttributesXml); } //item warnings @@ -531,22 +579,23 @@ private void PrepareButtonPaymentMethodModel(ButtonPaymentMethodModel model, ILi { model.Items.Clear(); + var paymentTypes = new PaymentMethodType[] { PaymentMethodType.Button, PaymentMethodType.StandardAndButton }; + var boundPaymentMethods = _paymentService - .LoadActivePaymentMethods(_workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id) - .Where(pm => pm.PaymentMethodType == PaymentMethodType.Button || pm.PaymentMethodType == PaymentMethodType.StandardAndButton) + .LoadActivePaymentMethods(_workContext.CurrentCustomer, cart, _storeContext.CurrentStore.Id, paymentTypes, false) .ToList(); foreach (var pm in boundPaymentMethods) { - if (cart.IsRecurring() && pm.RecurringPaymentType == RecurringPaymentType.NotSupported) + if (cart.IsRecurring() && pm.Value.RecurringPaymentType == RecurringPaymentType.NotSupported) continue; string actionName; string controllerName; RouteValueDictionary routeValues; - pm.GetPaymentInfoRoute(out actionName, out controllerName, out routeValues); + pm.Value.GetPaymentInfoRoute(out actionName, out controllerName, out routeValues); - model.Items.Add(new ButtonPaymentMethodModel.ButtonPaymentMethodItem() + model.Items.Add(new ButtonPaymentMethodModel.ButtonPaymentMethodItem { ActionName = actionName, ControllerName = controllerName, @@ -555,270 +604,301 @@ private void PrepareButtonPaymentMethodModel(ButtonPaymentMethodModel model, ILi } } - /// - /// Prepare shopping cart model - /// - /// Model instance - /// Shopping cart - /// A value indicating whether cart is editable - /// A value indicating whether we should validate checkout attributes when preparing the model - /// A value indicating whether we should prepare "Estimate shipping" model - /// A value indicating whether we should prefill "Estimate shipping" model with the default customer address - /// A value indicating whether we should prepare review data (such as billing/shipping address, payment or shipping data entered during checkout) - /// Model - [NonAction] - protected void PrepareShoppingCartModel(ShoppingCartModel model, - IList cart, bool isEditable = true, - bool validateCheckoutAttributes = false, - bool prepareEstimateShippingIfEnabled = true, bool setEstimateShippingDefaultAddress = true, - bool prepareAndDisplayOrderReviewData = false) - { - if (cart == null) - throw new ArgumentNullException("cart"); + /// + /// Prepare shopping cart model + /// + /// Model instance + /// Shopping cart + /// A value indicating whether cart is editable + /// A value indicating whether we should validate checkout attributes when preparing the model + /// A value indicating whether we should prepare "Estimate shipping" model + /// A value indicating whether we should prefill "Estimate shipping" model with the default customer address + /// A value indicating whether we should prepare review data (such as billing/shipping address, payment or shipping data entered during checkout) + /// Model + [NonAction] + protected void PrepareShoppingCartModel(ShoppingCartModel model, + IList cart, bool isEditable = true, + bool validateCheckoutAttributes = false, + bool prepareEstimateShippingIfEnabled = true, bool setEstimateShippingDefaultAddress = true, + bool prepareAndDisplayOrderReviewData = false) + { + if (cart == null) + throw new ArgumentNullException("cart"); - if (model == null) - throw new ArgumentNullException("model"); + if (model == null) + throw new ArgumentNullException("model"); - if (cart.Count == 0) - return; + if (cart.Count == 0) + return; - #region Simple properties + #region Simple properties - model.MediaDimensions = _mediaSettings.CartThumbPictureSize; + model.MediaDimensions = _mediaSettings.CartThumbPictureSize; model.BundleThumbSize = _mediaSettings.CartThumbBundleItemPictureSize; - model.DisplayDeliveryTime = _shoppingCartSettings.ShowDeliveryTimes; - model.DisplayShortDesc = _shoppingCartSettings.ShowShortDesc; - model.DisplayBasePrice = _shoppingCartSettings.ShowBasePrice; - model.IsEditable = isEditable; - model.ShowProductImages = _shoppingCartSettings.ShowProductImagesOnShoppingCart; + model.DisplayDeliveryTime = _shoppingCartSettings.ShowDeliveryTimes; + model.DisplayShortDesc = _shoppingCartSettings.ShowShortDesc; + model.DisplayBasePrice = _shoppingCartSettings.ShowBasePrice; + model.DisplayWeight = _shoppingCartSettings.ShowWeight; + model.IsEditable = isEditable; + model.ShowProductImages = _shoppingCartSettings.ShowProductImagesOnShoppingCart; model.ShowProductBundleImages = _shoppingCartSettings.ShowProductBundleImagesOnShoppingCart; - model.ShowSku = _catalogSettings.ShowProductSku; + model.ShowSku = _catalogSettings.ShowProductSku; + + var measure = _measureService.GetMeasureWeightById(_measureSettings.BaseWeightId); + if(measure != null) + { + model.MeasureUnitName = measure.Name; + } + + var checkoutAttributesXml = _workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); - model.CheckoutAttributeInfo = HtmlUtils.ConvertPlainTextToTable(HtmlUtils.ConvertHtmlToPlainText( + model.CheckoutAttributeInfo = HtmlUtils.ConvertPlainTextToTable(HtmlUtils.ConvertHtmlToPlainText( _checkoutAttributeFormatter.FormatAttributes(checkoutAttributesXml, _workContext.CurrentCustomer) )); - //model.CheckoutAttributeInfo = _checkoutAttributeFormatter.FormatAttributes(_workContext.CurrentCustomer.CheckoutAttributes, _workContext.CurrentCustomer); - //model.CheckoutAttributeInfo = _checkoutAttributeFormatter.FormatAttributes(_workContext.CurrentCustomer.CheckoutAttributes, _workContext.CurrentCustomer, "", false); - bool minOrderSubtotalAmountOk = _orderProcessingService.ValidateMinOrderSubtotalAmount(cart); - if (!minOrderSubtotalAmountOk) - { - decimal minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency); - model.MinOrderSubtotalWarning = string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"), _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false)); - } - model.TermsOfServiceEnabled = _orderSettings.TermsOfServiceEnabled; + //model.CheckoutAttributeInfo = _checkoutAttributeFormatter.FormatAttributes(_workContext.CurrentCustomer.CheckoutAttributes, _workContext.CurrentCustomer); + //model.CheckoutAttributeInfo = _checkoutAttributeFormatter.FormatAttributes(_workContext.CurrentCustomer.CheckoutAttributes, _workContext.CurrentCustomer, "", false); + + bool minOrderSubtotalAmountOk = _orderProcessingService.ValidateMinOrderSubtotalAmount(cart); + if (!minOrderSubtotalAmountOk) + { + decimal minOrderSubtotalAmount = _currencyService.ConvertFromPrimaryStoreCurrency(_orderSettings.MinOrderSubtotalAmount, _workContext.WorkingCurrency); + model.MinOrderSubtotalWarning = string.Format(_localizationService.GetResource("Checkout.MinOrderSubtotalAmount"), _priceFormatter.FormatPrice(minOrderSubtotalAmount, true, false)); + } + model.TermsOfServiceEnabled = _orderSettings.TermsOfServiceEnabled; - //gift card and gift card boxes - model.DiscountBox.Display = _shoppingCartSettings.ShowDiscountBox; + //gift card and gift card boxes + model.DiscountBox.Display = _shoppingCartSettings.ShowDiscountBox; var discountCouponCode = _workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.DiscountCouponCode); var discount = _discountService.GetDiscountByCouponCode(discountCouponCode); - if (discount != null && - discount.RequiresCouponCode && - _discountService.IsDiscountValid(discount, _workContext.CurrentCustomer)) - model.DiscountBox.CurrentCode = discount.CouponCode; - model.GiftCardBox.Display = _shoppingCartSettings.ShowGiftCardBox; + if (discount != null && discount.RequiresCouponCode && _discountService.IsDiscountValid(discount, _workContext.CurrentCustomer)) + { + model.DiscountBox.CurrentCode = discount.CouponCode; + } - //cart warnings - var cartWarnings = _shoppingCartService.GetShoppingCartWarnings(cart, checkoutAttributesXml, validateCheckoutAttributes); - foreach (var warning in cartWarnings) - model.Warnings.Add(warning); + model.GiftCardBox.Display = _shoppingCartSettings.ShowGiftCardBox; + model.DisplayCommentBox = _shoppingCartSettings.ShowCommentBox; + model.NewsLetterSubscription = _shoppingCartSettings.NewsLetterSubscription; + model.ThirdPartyEmailHandOver = _shoppingCartSettings.ThirdPartyEmailHandOver; + model.DisplayEsdRevocationWaiverBox = _shoppingCartSettings.ShowEsdRevocationWaiverBox; - #endregion + if (_shoppingCartSettings.ThirdPartyEmailHandOver != CheckoutThirdPartyEmailHandOver.None) + { + model.ThirdPartyEmailHandOverLabel = _shoppingCartSettings.GetLocalized(x => x.ThirdPartyEmailHandOverLabel, _workContext.WorkingLanguage.Id, true, false); - #region Checkout attributes + if (model.ThirdPartyEmailHandOverLabel.IsEmpty()) + model.ThirdPartyEmailHandOverLabel = T("Admin.Configuration.Settings.ShoppingCart.ThirdPartyEmailHandOverLabel.Default"); + } - var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(); - if (!cart.RequiresShipping()) - { - //remove attributes which require shippable products - checkoutAttributes = checkoutAttributes.RemoveShippableAttributes(); - } - foreach (var attribute in checkoutAttributes) - { - var caModel = new ShoppingCartModel.CheckoutAttributeModel() - { - Id = attribute.Id, - Name = attribute.GetLocalized(x => x.Name), - TextPrompt = attribute.GetLocalized(x => x.TextPrompt), - IsRequired = attribute.IsRequired, - AttributeControlType = attribute.AttributeControlType - }; + //cart warnings + var cartWarnings = _shoppingCartService.GetShoppingCartWarnings(cart, checkoutAttributesXml, validateCheckoutAttributes); + foreach (var warning in cartWarnings) + { + model.Warnings.Add(warning); + } - if (attribute.ShouldHaveValues()) - { - //values - var caValues = _checkoutAttributeService.GetCheckoutAttributeValues(attribute.Id); - foreach (var caValue in caValues) - { - var pvaValueModel = new ShoppingCartModel.CheckoutAttributeValueModel() - { - Id = caValue.Id, - Name = caValue.GetLocalized(x => x.Name), - IsPreSelected = caValue.IsPreSelected - }; - caModel.Values.Add(pvaValueModel); - - //display price if allowed - if (_permissionService.Authorize(StandardPermissionProvider.DisplayPrices)) - { - decimal priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(caValue); - decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); - if (priceAdjustmentBase > decimal.Zero) - pvaValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment); - else if (priceAdjustmentBase < decimal.Zero) - pvaValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment); - } - } - } + #endregion + #region Checkout attributes + var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(_storeContext.CurrentStore.Id); + if (!cart.RequiresShipping()) + { + //remove attributes which require shippable products + checkoutAttributes = checkoutAttributes.RemoveShippableAttributes(); + } + foreach (var attribute in checkoutAttributes) + { + var caModel = new ShoppingCartModel.CheckoutAttributeModel() + { + Id = attribute.Id, + Name = attribute.GetLocalized(x => x.Name), + TextPrompt = attribute.GetLocalized(x => x.TextPrompt), + IsRequired = attribute.IsRequired, + AttributeControlType = attribute.AttributeControlType + }; + + if (attribute.ShouldHaveValues()) + { + //values + var caValues = _checkoutAttributeService.GetCheckoutAttributeValues(attribute.Id); + foreach (var caValue in caValues) + { + var pvaValueModel = new ShoppingCartModel.CheckoutAttributeValueModel() + { + Id = caValue.Id, + Name = caValue.GetLocalized(x => x.Name), + IsPreSelected = caValue.IsPreSelected + }; + caModel.Values.Add(pvaValueModel); + + //display price if allowed + if (_permissionService.Authorize(StandardPermissionProvider.DisplayPrices)) + { + decimal priceAdjustmentBase = _taxService.GetCheckoutAttributePrice(caValue); + decimal priceAdjustment = _currencyService.ConvertFromPrimaryStoreCurrency(priceAdjustmentBase, _workContext.WorkingCurrency); + if (priceAdjustmentBase > decimal.Zero) + pvaValueModel.PriceAdjustment = "+" + _priceFormatter.FormatPrice(priceAdjustment); + else if (priceAdjustmentBase < decimal.Zero) + pvaValueModel.PriceAdjustment = "-" + _priceFormatter.FormatPrice(-priceAdjustment); + } + } + } - //set already selected attributes - string selectedCheckoutAttributes = _workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); - switch (attribute.AttributeControlType) - { - case AttributeControlType.DropdownList: - case AttributeControlType.RadioList: - case AttributeControlType.ColorSquares: - case AttributeControlType.Checkboxes: - { - if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) - { - //clear default selection - foreach (var item in caModel.Values) - item.IsPreSelected = false; - - //select new values - var selectedCaValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(selectedCheckoutAttributes); - foreach (var caValue in selectedCaValues) - foreach (var item in caModel.Values) - if (caValue.Id == item.Id) - item.IsPreSelected = true; - } - } - break; - case AttributeControlType.TextBox: - case AttributeControlType.MultilineTextbox: - { - if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) - { - var enteredText = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); - if (enteredText.Count > 0) - caModel.DefaultValue = enteredText[0]; - } - } - break; - case AttributeControlType.Datepicker: - { - //keep in mind my that the code below works only in the current culture - var selectedDateStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); - if (selectedDateStr.Count > 0) - { - DateTime selectedDate; - if (DateTime.TryParseExact(selectedDateStr[0], "D", CultureInfo.CurrentCulture, - DateTimeStyles.None, out selectedDate)) - { - //successfully parsed - caModel.SelectedDay = selectedDate.Day; - caModel.SelectedMonth = selectedDate.Month; - caModel.SelectedYear = selectedDate.Year; - } - } - } - break; - default: - break; - } - model.CheckoutAttributes.Add(caModel); - } + //set already selected attributes + string selectedCheckoutAttributes = _workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.CheckoutAttributes, _genericAttributeService); + switch (attribute.AttributeControlType) + { + case AttributeControlType.DropdownList: + case AttributeControlType.RadioList: + case AttributeControlType.ColorSquares: + case AttributeControlType.Checkboxes: + { + if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) + { + //clear default selection + foreach (var item in caModel.Values) + item.IsPreSelected = false; + + //select new values + var selectedCaValues = _checkoutAttributeParser.ParseCheckoutAttributeValues(selectedCheckoutAttributes); + foreach (var caValue in selectedCaValues) + foreach (var item in caModel.Values) + if (caValue.Id == item.Id) + item.IsPreSelected = true; + } + } + break; + case AttributeControlType.TextBox: + case AttributeControlType.MultilineTextbox: + { + if (!String.IsNullOrEmpty(selectedCheckoutAttributes)) + { + var enteredText = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); + if (enteredText.Count > 0) + caModel.DefaultValue = enteredText[0]; + } + } + break; + case AttributeControlType.Datepicker: + { + //keep in mind my that the code below works only in the current culture + var selectedDateStr = _checkoutAttributeParser.ParseValues(selectedCheckoutAttributes, attribute.Id); + if (selectedDateStr.Count > 0) + { + DateTime selectedDate; + if (DateTime.TryParseExact(selectedDateStr[0], "D", CultureInfo.CurrentCulture, + DateTimeStyles.None, out selectedDate)) + { + //successfully parsed + caModel.SelectedDay = selectedDate.Day; + caModel.SelectedMonth = selectedDate.Month; + caModel.SelectedYear = selectedDate.Year; + } + } - #endregion + } + break; + default: + break; + } - #region Estimate shipping + model.CheckoutAttributes.Add(caModel); + } - if (prepareEstimateShippingIfEnabled) - { - model.EstimateShipping.Enabled = cart.Count > 0 && cart.RequiresShipping() && _shippingSettings.EstimateShippingEnabled; - if (model.EstimateShipping.Enabled) - { - //countries - int? defaultEstimateCountryId = (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) ? _workContext.CurrentCustomer.ShippingAddress.CountryId : model.EstimateShipping.CountryId; - //model.EstimateShipping.AvailableCountries.Add(new SelectListItem() { Text = _localizationService.GetResource("Address.SelectCountry"), Value = "0" }); - foreach (var c in _countryService.GetAllCountriesForShipping()) - model.EstimateShipping.AvailableCountries.Add(new SelectListItem() - { - Text = c.GetLocalized(x => x.Name), - Value = c.Id.ToString(), - Selected = c.Id == defaultEstimateCountryId - }); - //states - int? defaultEstimateStateId = (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) ? _workContext.CurrentCustomer.ShippingAddress.StateProvinceId : model.EstimateShipping.StateProvinceId; - var states = defaultEstimateCountryId.HasValue ? _stateProvinceService.GetStateProvincesByCountryId(defaultEstimateCountryId.Value).ToList() : new List(); - if (states.Count > 0) - foreach (var s in states) - model.EstimateShipping.AvailableStates.Add(new SelectListItem() - { - Text = s.GetLocalized(x => x.Name), - Value = s.Id.ToString(), - Selected = s.Id == defaultEstimateStateId - }); - else - model.EstimateShipping.AvailableStates.Add(new SelectListItem() { Text = _localizationService.GetResource("Address.OtherNonUS"), Value = "0" }); + #endregion - if (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) - model.EstimateShipping.ZipPostalCode = _workContext.CurrentCustomer.ShippingAddress.ZipPostalCode; - } - } + #region Estimate shipping - #endregion + if (prepareEstimateShippingIfEnabled) + { + model.EstimateShipping.Enabled = cart.Count > 0 && cart.RequiresShipping() && _shippingSettings.EstimateShippingEnabled; + if (model.EstimateShipping.Enabled) + { + //countries + int? defaultEstimateCountryId = (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) ? _workContext.CurrentCustomer.ShippingAddress.CountryId : model.EstimateShipping.CountryId; + //model.EstimateShipping.AvailableCountries.Add(new SelectListItem() { Text = _localizationService.GetResource("Address.SelectCountry"), Value = "0" }); + foreach (var c in _countryService.GetAllCountriesForShipping()) + model.EstimateShipping.AvailableCountries.Add(new SelectListItem() + { + Text = c.GetLocalized(x => x.Name), + Value = c.Id.ToString(), + Selected = c.Id == defaultEstimateCountryId + }); + //states + int? defaultEstimateStateId = (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) ? _workContext.CurrentCustomer.ShippingAddress.StateProvinceId : model.EstimateShipping.StateProvinceId; + var states = defaultEstimateCountryId.HasValue ? _stateProvinceService.GetStateProvincesByCountryId(defaultEstimateCountryId.Value).ToList() : new List(); + if (states.Count > 0) + foreach (var s in states) + model.EstimateShipping.AvailableStates.Add(new SelectListItem() + { + Text = s.GetLocalized(x => x.Name), + Value = s.Id.ToString(), + Selected = s.Id == defaultEstimateStateId + }); + else + model.EstimateShipping.AvailableStates.Add(new SelectListItem() { Text = _localizationService.GetResource("Address.OtherNonUS"), Value = "0" }); + + if (setEstimateShippingDefaultAddress && _workContext.CurrentCustomer.ShippingAddress != null) + model.EstimateShipping.ZipPostalCode = _workContext.CurrentCustomer.ShippingAddress.ZipPostalCode; + } + } - #region Cart items + #endregion - foreach (var sci in cart) - { + #region Cart items + + foreach (var sci in cart) + { var shoppingCartItemModel = PrepareShoppingCartItemModel(sci); model.Items.Add(shoppingCartItemModel); - } + } - #endregion + #endregion - #region Order review data + #region Order review data - if (prepareAndDisplayOrderReviewData) - { - model.OrderReviewData.Display = true; + if (prepareAndDisplayOrderReviewData) + { + model.OrderReviewData.Display = true; - //billing info - var billingAddress = _workContext.CurrentCustomer.BillingAddress; - if (billingAddress != null) - model.OrderReviewData.BillingAddress.PrepareModel(billingAddress, false, _addressSettings); - - //shipping info - if (cart.RequiresShipping()) - { - model.OrderReviewData.IsShippable = true; + //billing info + var billingAddress = _workContext.CurrentCustomer.BillingAddress; + if (billingAddress != null) + model.OrderReviewData.BillingAddress.PrepareModel(billingAddress, false, _addressSettings); + + //shipping info + if (cart.RequiresShipping()) + { + model.OrderReviewData.IsShippable = true; + + var shippingAddress = _workContext.CurrentCustomer.ShippingAddress; + if (shippingAddress != null) + model.OrderReviewData.ShippingAddress.PrepareModel(shippingAddress, false, _addressSettings); - var shippingAddress = _workContext.CurrentCustomer.ShippingAddress; - if (shippingAddress != null) - model.OrderReviewData.ShippingAddress.PrepareModel(shippingAddress, false, _addressSettings); - - //selected shipping method + //selected shipping method var shippingOption = _workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.SelectedShippingOption, _storeContext.CurrentStore.Id); - if (shippingOption != null) - model.OrderReviewData.ShippingMethod = shippingOption.Name; - } - //payment info + if (shippingOption != null) + model.OrderReviewData.ShippingMethod = shippingOption.Name; + } + + //payment info var selectedPaymentMethodSystemName = _workContext.CurrentCustomer.GetAttribute( SystemCustomerAttributeNames.SelectedPaymentMethod, _storeContext.CurrentStore.Id); + + var checkoutState = _httpContext.GetCheckoutState(); var paymentMethod = _paymentService.LoadPaymentMethodBySystemName(selectedPaymentMethodSystemName); - model.OrderReviewData.PaymentMethod = paymentMethod != null ? paymentMethod.GetLocalizedValue(_localizationService, "FriendlyName", _workContext.WorkingLanguage.Id) : ""; - } - #endregion + + model.OrderReviewData.PaymentMethod = paymentMethod != null ? _pluginMediator.GetLocalizedFriendlyName(paymentMethod.Metadata) : ""; + model.OrderReviewData.PaymentSummary = checkoutState.PaymentSummary; + model.OrderReviewData.IsPaymentSelectionSkipped = checkoutState.IsPaymentSelectionSkipped; + } + #endregion PrepareButtonPaymentMethodModel(model.ButtonPaymentMethods, cart); - } + } [NonAction] protected void PrepareWishlistModel(WishlistModel model, IList cart, bool isEditable = true) @@ -843,6 +923,7 @@ protected void PrepareWishlistModel(WishlistModel model, IList x.Item.Id) .Take(_shoppingCartSettings.MiniShoppingCartProductNumber) .ToList()) { - var cartItemModel = new MiniShoppingCartModel.ShoppingCartItemModel() + var item = sci.Item; + var product = sci.Item.Product; + + var cartItemModel = new MiniShoppingCartModel.ShoppingCartItemModel { - Id = sci.Item.Id, - ProductId = sci.Item.Product.Id, - ProductName = sci.Item.Product.GetLocalized(x => x.Name), - ProductSeName = sci.Item.Product.GetSeName(), - Quantity = sci.Item.Quantity, + Id = item.Id, + ProductId = product.Id, + ProductName = product.GetLocalized(x => x.Name), + ProductSeName = product.GetSeName(), + Quantity = item.Quantity, AttributeInfo = _productAttributeFormatter.FormatAttributes( - sci.Item.Product, - sci.Item.AttributesXml, + product, + item.AttributesXml, null, serapator: ", ", renderPrices: false, @@ -936,42 +1019,49 @@ protected MiniShoppingCartModel PrepareMiniShoppingCartModel() allowHyperlinks: false) }; - if (sci.Item.Product.ProductType == ProductType.BundledProduct) - { - var bundleItems = _productService.GetBundleItems(sci.Item.Product.Id); - foreach (var bundleItem in bundleItems) - { - var bundleItemModel = new MiniShoppingCartModel.ShoppingCartItemBundleItem(); - bundleItemModel.ProductName = bundleItem.Item.Product.GetLocalized(x => x.Name); - var bundlePic = _pictureService.GetPicturesByProductId(bundleItem.Item.ProductId).FirstOrDefault(); - if(bundlePic != null) - bundleItemModel.PictureUrl = _pictureService.GetPictureUrl(bundlePic.Id, 32); + cartItemModel.ProductUrl = GetProductUrlWithAttributes(sci, cartItemModel.ProductSeName); - bundleItemModel.ProductSeName = bundleItem.Item.Product.GetSeName(); + if (sci.ChildItems != null && _shoppingCartSettings.ShowProductBundleImagesOnShoppingCart) + { + foreach (var childItem in sci.ChildItems.Where(x => x.Item.Id != item.Id && x.Item.BundleItem != null && !x.Item.BundleItem.HideThumbnail)) + { + var bundleItemModel = new MiniShoppingCartModel.ShoppingCartItemBundleItem + { + ProductName = childItem.Item.Product.GetLocalized(x => x.Name), + ProductSeName = childItem.Item.Product.GetSeName(), + }; - if (!bundleItem.Item.HideThumbnail) - cartItemModel.BundleItems.Add(bundleItemModel); - } - } + bundleItemModel.ProductUrl = _productAttributeParser.GetProductUrlWithAttributes( + childItem.Item.AttributesXml, childItem.Item.ProductId, bundleItemModel.ProductSeName); + + var itemPicture = _pictureService.GetPicturesByProductId(childItem.Item.ProductId, 1).FirstOrDefault(); + if (itemPicture != null) + bundleItemModel.PictureUrl = _pictureService.GetPictureUrl(itemPicture.Id, 32); + + cartItemModel.BundleItems.Add(bundleItemModel); + } + } //unit prices - if (sci.Item.Product.CallForPrice) + if (product.CallForPrice) { cartItemModel.UnitPrice = _localizationService.GetResource("Products.CallForPrice"); } else { + product.MergeWithCombination(item.AttributesXml); + decimal taxRate = decimal.Zero; - decimal shoppingCartUnitPriceWithDiscountBase = _taxService.GetProductPrice(sci.Item.Product, _priceCalculationService.GetUnitPrice(sci, true), out taxRate); + decimal shoppingCartUnitPriceWithDiscountBase = _taxService.GetProductPrice(product, _priceCalculationService.GetUnitPrice(sci, true), out taxRate); decimal shoppingCartUnitPriceWithDiscount = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartUnitPriceWithDiscountBase, _workContext.WorkingCurrency); + cartItemModel.UnitPrice = _priceFormatter.FormatPrice(shoppingCartUnitPriceWithDiscount); } //picture if (_shoppingCartSettings.ShowProductImagesInMiniShoppingCart) { - cartItemModel.Picture = PrepareCartItemPictureModel(sci.Item.Product, - _mediaSettings.MiniCartThumbPictureSize, true, cartItemModel.ProductName, sci.Item.AttributesXml); + cartItemModel.Picture = PrepareCartItemPictureModel(product, _mediaSettings.MiniCartThumbPictureSize, cartItemModel.ProductName, item.AttributesXml); } model.Items.Add(cartItemModel); @@ -985,15 +1075,18 @@ protected MiniShoppingCartModel PrepareMiniShoppingCartModel() protected void ParseAndSaveCheckoutAttributes(List cart, FormCollection form) { string selectedAttributes = ""; - var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(); + var checkoutAttributes = _checkoutAttributeService.GetAllCheckoutAttributes(_storeContext.CurrentStore.Id); + if (!cart.RequiresShipping()) { //remove attributes which require shippable products checkoutAttributes = checkoutAttributes.RemoveShippableAttributes(); } + foreach (var attribute in checkoutAttributes) { string controlId = string.Format("checkout_attribute_{0}", attribute.Id); + switch (attribute.AttributeControlType) { case AttributeControlType.DropdownList: @@ -1003,13 +1096,13 @@ protected void ParseAndSaveCheckoutAttributes(List ca var rblAttributes = form[controlId]; if (!String.IsNullOrEmpty(rblAttributes)) { - int selectedAttributeId = int.Parse(rblAttributes); + var selectedAttributeId = rblAttributes.SplitSafe(",").SafeGet(0).ToInt(); if (selectedAttributeId > 0) - selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, - attribute, selectedAttributeId.ToString()); + selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, attribute, selectedAttributeId.ToString()); } } break; + case AttributeControlType.Checkboxes: { var cblAttributes = form[controlId]; @@ -1017,14 +1110,14 @@ protected void ParseAndSaveCheckoutAttributes(List ca { foreach (var item in cblAttributes.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { - int selectedAttributeId = int.Parse(item); - if (selectedAttributeId > 0) - selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, - attribute, selectedAttributeId.ToString()); + var selectedAttributeId = item.SplitSafe(",").SafeGet(0).ToInt(); + if (selectedAttributeId > 0) + selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, attribute, selectedAttributeId.ToString()); } } } break; + case AttributeControlType.TextBox: case AttributeControlType.MultilineTextbox: { @@ -1032,36 +1125,38 @@ protected void ParseAndSaveCheckoutAttributes(List ca if (!String.IsNullOrEmpty(txtAttribute)) { string enteredText = txtAttribute.Trim(); - selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, - attribute, enteredText); + selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, attribute, enteredText); } } break; + case AttributeControlType.Datepicker: { var date = form[controlId + "_day"]; var month = form[controlId + "_month"]; var year = form[controlId + "_year"]; DateTime? selectedDate = null; + try { selectedDate = new DateTime(Int32.Parse(year), Int32.Parse(month), Int32.Parse(date)); } catch { } + if (selectedDate.HasValue) { - selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, - attribute, selectedDate.Value.ToString("D")); + selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, attribute, selectedDate.Value.ToString("D")); } } break; + case AttributeControlType.FileUpload: { - var httpPostedFile = this.Request.Files[controlId]; - if ((httpPostedFile != null) && (!String.IsNullOrEmpty(httpPostedFile.FileName))) + var postedFile = this.Request.Files[controlId].ToPostedFileResult(); + if (postedFile != null && postedFile.FileName.HasValue()) { int fileMaxSize = _catalogSettings.FileUploadMaximumSizeBytes; - if (httpPostedFile.ContentLength > fileMaxSize) + if (postedFile.Size > fileMaxSize) { //TODO display warning //warnings.Add(string.Format(_localizationService.GetResource("ShoppingCart.MaximumUploadedFileSize"), (int)(fileMaxSize / 1024))); @@ -1069,25 +1164,25 @@ protected void ParseAndSaveCheckoutAttributes(List ca else { //save an uploaded file - var download = new Download() + var download = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = false, DownloadUrl = "", - DownloadBinary = httpPostedFile.GetDownloadBits(), - ContentType = httpPostedFile.ContentType, - Filename = System.IO.Path.GetFileNameWithoutExtension(httpPostedFile.FileName), - Extension = System.IO.Path.GetExtension(httpPostedFile.FileName), + DownloadBinary = postedFile.Buffer, + ContentType = postedFile.ContentType, + Filename = postedFile.FileTitle, + Extension = postedFile.FileExtension, IsNew = true }; _downloadService.InsertDownload(download); //save attribute - selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, - attribute, download.DownloadGuid.ToString()); + selectedAttributes = _checkoutAttributeParser.AddCheckoutAttribute(selectedAttributes, attribute, download.DownloadGuid.ToString()); } } } break; + default: break; } @@ -1097,6 +1192,27 @@ protected void ParseAndSaveCheckoutAttributes(List ca _genericAttributeService.SaveAttribute(_workContext.CurrentCustomer, SystemCustomerAttributeNames.CheckoutAttributes, selectedAttributes); } + private string GetProductUrlWithAttributes(OrganizedShoppingCartItem cartItem, string productSeName) + { + var attributeQueryData = new List>(); + var product = cartItem.Item.Product; + + if (product.ProductType != ProductType.BundledProduct) + { + _productAttributeParser.DeserializeQueryData(attributeQueryData, cartItem.Item.AttributesXml, product.Id); + } + else if (cartItem.ChildItems != null && product.BundlePerItemPricing) + { + foreach (var childItem in cartItem.ChildItems.Where(x => x.Item.Id != cartItem.Item.Id)) + { + _productAttributeParser.DeserializeQueryData(attributeQueryData, childItem.Item.AttributesXml, childItem.Item.ProductId, childItem.BundleItemData.Item.Id); + } + } + + var url = _productAttributeParser.GetProductUrlWithAttributes(attributeQueryData, productSeName); + return url; + } + #endregion #region Shopping cart @@ -1104,7 +1220,7 @@ protected void ParseAndSaveCheckoutAttributes(List ca //add product to cart using AJAX //currently we use this method on catalog pages (category/manufacturer/etc) [HttpPost] - public ActionResult AddProductToCart_Catalog(int productId, bool forceredirection = false) + public ActionResult AddProductSimple(int productId, bool forceredirection = false) { //current we support only ShoppingCartType.ShoppingCart const ShoppingCartType shoppingCartType = ShoppingCartType.ShoppingCart; @@ -1112,16 +1228,15 @@ public ActionResult AddProductToCart_Catalog(int productId, bool forceredirectio var product = _productService.GetProductById(productId); if (product == null) { - //no product found return Json(new { success = false, - message = "No product found with the specified ID" + message = T("Products.NotFound", productId) }); } - // filter out product types that cannot be add to cart - if (product.ProductType == ProductType.GroupedProduct) + // filter out cases where a product cannot be added to cart + if (product.ProductType == ProductType.GroupedProduct || product.CustomerEntersPrice || product.IsGiftCard) { return Json(new { @@ -1129,15 +1244,6 @@ public ActionResult AddProductToCart_Catalog(int productId, bool forceredirectio }); } - if (product.CustomerEntersPrice) - { - //cannot be added to the cart (requires a customer to enter price) - return Json(new - { - redirect = Url.RouteUrl("Product", new { SeName = product.GetSeName() }), - }); - } - //quantity to add var qtyToAdd = product.OrderMinimumQuantity > 0 ? product.OrderMinimumQuantity : 1; @@ -1175,9 +1281,17 @@ public ActionResult AddProductToCart_Catalog(int productId, bool forceredirectio } //now let's try adding product to the cart (now including product attribute validation, etc) - _shoppingCartService.AddToCart(addToCartWarnings, product, null, shoppingCartType, decimal.Zero, qtyToAdd, true); + var addToCartContext = new AddToCartContext + { + Product = product, + CartType = shoppingCartType, + Quantity = qtyToAdd, + AddRequiredProducts = true + }; - if (addToCartWarnings.Count > 0) + _shoppingCartService.AddToCart(addToCartContext); + + if (addToCartContext.Warnings.Count > 0) { //cannot be added to the cart //but we do not display attribute and gift card warnings here. let's do it on the product details page @@ -1212,7 +1326,7 @@ public ActionResult AddProductToCart_Catalog(int productId, bool forceredirectio //currently we use this method on the product details pages [HttpPost] [ValidateInput(false)] - public ActionResult AddProductToCart_Details(int productId, int shoppingCartTypeId, FormCollection form) + public ActionResult AddProduct(int productId, int shoppingCartTypeId, FormCollection form) { var product = _productService.GetProductById(productId); if (product == null) @@ -1242,7 +1356,6 @@ public ActionResult AddProductToCart_Details(int productId, int shoppingCartType #region Quantity - // codehint: sm-edit int quantity = 1; string key1 = "addtocart_{0}.EnteredQuantity".FormatWith(productId); string key2 = "addtocart_{0}.AddToCart.EnteredQuantity".FormatWith(productId); @@ -1256,20 +1369,29 @@ public ActionResult AddProductToCart_Details(int productId, int shoppingCartType //save item var cartType = (ShoppingCartType)shoppingCartTypeId; - var addToCartWarnings = new List(); - _shoppingCartService.AddToCart(addToCartWarnings, product, form, cartType, customerEnteredPriceConverted, quantity, true); + var addToCartContext = new AddToCartContext + { + Product = product, + AttributeForm = form, + CartType = cartType, + CustomerEnteredPrice = customerEnteredPriceConverted, + Quantity = quantity, + AddRequiredProducts = true + }; + + _shoppingCartService.AddToCart(addToCartContext); #region Return result - if (addToCartWarnings.Count > 0) + if (addToCartContext.Warnings.Count > 0) { //cannot be added to the cart/wishlist //let's display warnings return Json(new { success = false, - message = addToCartWarnings.ToArray() + message = addToCartContext.Warnings.ToArray() }); } @@ -1336,86 +1458,62 @@ public ActionResult UploadFileProductAttribute(int productId, int productAttribu { success = false, downloadGuid = Guid.Empty, - }, "text/plain"); + }); } - //ensure that this attribute belong to this product and has "file upload" type + + // ensure that this attribute belong to this product and has "file upload" type var pva = _productAttributeService .GetProductVariantAttributesByProductId(productId) .Where(pa => pa.ProductAttributeId == productAttributeId) .FirstOrDefault(); + if (pva == null || pva.AttributeControlType != AttributeControlType.FileUpload) { return Json(new { success = false, downloadGuid = Guid.Empty, - }, "text/plain"); - } - - //we process it distinct ways based on a browser - //find more info here http://stackoverflow.com/questions/4884920/mvc3-valums-ajax-file-upload - Stream stream = null; - var fileName = ""; - var contentType = ""; - if (String.IsNullOrEmpty(Request["qqfile"])) - { - // IE - HttpPostedFileBase httpPostedFile = Request.Files[0]; - if (httpPostedFile == null) - throw new ArgumentException("No file uploaded"); - stream = httpPostedFile.InputStream; - fileName = Path.GetFileName(httpPostedFile.FileName); - contentType = httpPostedFile.ContentType; - } - else - { - //Webkit, Mozilla - stream = Request.InputStream; - fileName = Request["qqfile"]; + }); } - var fileBinary = new byte[stream.Length]; - stream.Read(fileBinary, 0, fileBinary.Length); - - var fileExtension = Path.GetExtension(fileName); - if (!String.IsNullOrEmpty(fileExtension)) - fileExtension = fileExtension.ToLowerInvariant(); + var postedFile = Request.ToPostedFileResult(); + if (postedFile == null) + { + throw new ArgumentException(T("Common.NoFileUploaded")); + } int fileMaxSize = _catalogSettings.FileUploadMaximumSizeBytes; - if (fileBinary.Length > fileMaxSize) + if (postedFile.Size > fileMaxSize) { - //when returning JSON the mime-type must be set to text/plain - //otherwise some browsers will pop-up a "Save As" dialog. return Json(new { success = false, message = string.Format(_localizationService.GetResource("ShoppingCart.MaximumUploadedFileSize"), (int)(fileMaxSize / 1024)), downloadGuid = Guid.Empty, - }, "text/plain"); + }); } - var download = new Download() + var download = new Download { DownloadGuid = Guid.NewGuid(), UseDownloadUrl = false, DownloadUrl = "", - DownloadBinary = fileBinary, - ContentType = contentType, - //we store filename without extension for downloads - Filename = Path.GetFileNameWithoutExtension(fileName), - Extension = fileExtension, - IsNew = true + DownloadBinary = postedFile.Buffer, + ContentType = postedFile.ContentType, + // we store filename without extension for downloads + Filename = postedFile.FileTitle, + Extension = postedFile.FileExtension, + IsNew = true, + IsTransient = true }; _downloadService.InsertDownload(download); - //when returning JSON the mime-type must be set to text/plain - //otherwise some browsers will pop-up a "Save As" dialog. return Json(new { success = true, message = _localizationService.GetResource("ShoppingCart.FileUploaded"), downloadGuid = download.DownloadGuid, - }, "text/plain"); + }); } @@ -1650,14 +1748,7 @@ public ActionResult DeleteCartItem(int cartItemId, bool? wishlistItem) public ActionResult ContinueShopping() { string returnUrl = _workContext.CurrentCustomer.GetAttribute(SystemCustomerAttributeNames.LastContinueShoppingPage, _storeContext.CurrentStore.Id); - if (!String.IsNullOrEmpty(returnUrl)) - { - return Redirect(returnUrl); - } - else - { - return RedirectToRoute("HomePage"); - } + return RedirectToReferrer(returnUrl); } [ValidateInput(false)] @@ -1686,7 +1777,7 @@ public ActionResult StartCheckout(FormCollection form) { if (_orderSettings.AnonymousCheckoutAllowed) { - return RedirectToRoute("LoginCheckoutAsGuest", new {returnUrl = Url.RouteUrl("ShoppingCart")}); + return RedirectToAction("Login", "Customer", new { checkoutAsGuest = true, returnUrl = Url.RouteUrl("ShoppingCart") }); } else { @@ -1695,7 +1786,7 @@ public ActionResult StartCheckout(FormCollection form) } else { - return RedirectToRoute("Checkout"); + return RedirectToRoute("Checkout"); } } @@ -1775,7 +1866,8 @@ public ActionResult ApplyGiftCard(string giftcardcouponcode, FormCollection form [FormValueRequired("estimateshipping")] public ActionResult GetEstimateShipping(EstimateShippingModel shippingModel, FormCollection form) { - var cart = _workContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, _storeContext.CurrentStore.Id); + var store = _storeContext.CurrentStore; + var cart = _workContext.CurrentCustomer.GetCartItems(ShoppingCartType.ShoppingCart, store.Id); //parse and save checkout attributes ParseAndSaveCheckoutAttributes(cart, form); @@ -1784,11 +1876,17 @@ public ActionResult GetEstimateShipping(EstimateShippingModel shippingModel, For model.EstimateShipping.CountryId = shippingModel.CountryId; model.EstimateShipping.StateProvinceId = shippingModel.StateProvinceId; model.EstimateShipping.ZipPostalCode = shippingModel.ZipPostalCode; + PrepareShoppingCartModel(model, cart, setEstimateShippingDefaultAddress: false); if (cart.RequiresShipping()) { - var address = new Address() + if (_topicService.Value.GetTopicBySystemName("ShippingInfo", store.Id) != null) + { + model.EstimateShipping.ShippingInfoUrl = Url.RouteUrl("Topic", new { SystemName = "shippinginfo" }); + } + + var address = new Address { CountryId = shippingModel.CountryId, Country = shippingModel.CountryId.HasValue ? _countryService.GetCountryById(shippingModel.CountryId.Value) : null, @@ -1796,12 +1894,15 @@ public ActionResult GetEstimateShipping(EstimateShippingModel shippingModel, For StateProvince = shippingModel.StateProvinceId.HasValue ? _stateProvinceService.GetStateProvinceById(shippingModel.StateProvinceId.Value) : null, ZipPostalCode = shippingModel.ZipPostalCode, }; - GetShippingOptionResponse getShippingOptionResponse = _shippingService - .GetShippingOptions(cart, address, "", _storeContext.CurrentStore.Id); + + var getShippingOptionResponse = _shippingService.GetShippingOptions(cart, address, "", store.Id); + if (!getShippingOptionResponse.Success) { - foreach (var error in getShippingOptionResponse.Errors) - model.EstimateShipping.Warnings.Add(error); + foreach (var error in getShippingOptionResponse.Errors) + { + model.EstimateShipping.Warnings.Add(error); + } } else { @@ -1811,12 +1912,13 @@ public ActionResult GetEstimateShipping(EstimateShippingModel shippingModel, For foreach (var shippingOption in getShippingOptionResponse.ShippingOptions) { - var soModel = new EstimateShippingModel.ShippingOptionModel() + var soModel = new EstimateShippingModel.ShippingOptionModel { + ShippingMethodId = shippingOption.ShippingMethodId, Name = shippingOption.Name, - Description = shippingOption.Description, - + Description = shippingOption.Description }; + //calculate discounted and taxed rate Discount appliedDiscount = null; decimal shippingTotal = _orderTotalCalculationService.AdjustShippingRate( @@ -1825,12 +1927,13 @@ public ActionResult GetEstimateShipping(EstimateShippingModel shippingModel, For decimal rateBase = _taxService.GetShippingPrice(shippingTotal, _workContext.CurrentCustomer); decimal rate = _currencyService.ConvertFromPrimaryStoreCurrency(rateBase, _workContext.WorkingCurrency); soModel.Price = _priceFormatter.FormatShippingPrice(rate, false /*true*/); + model.EstimateShipping.ShippingOptions.Add(soModel); } } else { - model.EstimateShipping.Warnings.Add(_localizationService.GetResource("Checkout.ShippingIsNotAllowed")); + model.EstimateShipping.Warnings.Add(T("Checkout.ShippingIsNotAllowed")); } } } @@ -1847,7 +1950,16 @@ public ActionResult OrderTotals(bool isEditable) model.IsEditable = isEditable; if (cart.Count > 0) - { + { + + //weight + model.Weight = decimal.Zero; + + foreach (var sci in cart) + { + model.Weight += sci.Item.Product.Weight * sci.Item.Quantity; + } + //subtotal decimal subtotalBase = decimal.Zero; decimal orderSubTotalDiscountAmountBase = decimal.Zero; @@ -1896,7 +2008,7 @@ public ActionResult OrderTotals(bool isEditable) decimal paymentMethodAdditionalFee = _paymentService.GetAdditionalHandlingFee(cart, paymentMethodSystemName); decimal paymentMethodAdditionalFeeWithTaxBase = _taxService.GetPaymentMethodAdditionalFee(paymentMethodAdditionalFee, _workContext.CurrentCustomer); - if (paymentMethodAdditionalFeeWithTaxBase > decimal.Zero) + if (paymentMethodAdditionalFeeWithTaxBase != decimal.Zero) { decimal paymentMethodAdditionalFeeWithTax = _currencyService.ConvertFromPrimaryStoreCurrency(paymentMethodAdditionalFeeWithTaxBase, _workContext.WorkingCurrency); model.PaymentMethodAdditionalFee = _priceFormatter.FormatPaymentMethodAdditionalFee(paymentMethodAdditionalFeeWithTax, true); @@ -1925,14 +2037,17 @@ public ActionResult OrderTotals(bool isEditable) { displayTaxRates = _taxSettings.DisplayTaxRates && taxRates.Count > 0; displayTax = !displayTaxRates; - - model.Tax = _priceFormatter.FormatPrice(shoppingCartTax, false /*true*/, false); + + model.Tax = _priceFormatter.FormatPrice(shoppingCartTax, true, false); foreach (var tr in taxRates) { - model.TaxRates.Add(new OrderTotalsModel.TaxRate() + var rate = _priceFormatter.FormatTaxRate(tr.Key); + var labelKey = "ShoppingCart.Totals.TaxRateLine" + (_workContext.TaxDisplayType == TaxDisplayType.IncludingTax ? "Incl" : "Excl"); + model.TaxRates.Add(new OrderTotalsModel.TaxRate() { - Rate = _priceFormatter.FormatTaxRate(tr.Key), - Value = _priceFormatter.FormatPrice(_currencyService.ConvertFromPrimaryStoreCurrency(tr.Value, _workContext.WorkingCurrency), false /*true*/, false), + Rate = rate, + Value = _priceFormatter.FormatPrice(_currencyService.ConvertFromPrimaryStoreCurrency(tr.Value, _workContext.WorkingCurrency), true, false), + Label = _localizationService.GetResource(labelKey).FormatCurrent(rate) }); } } @@ -1940,6 +2055,8 @@ public ActionResult OrderTotals(bool isEditable) model.DisplayTaxRates = displayTaxRates; model.DisplayTax = displayTax; + model.DisplayWeight = _shoppingCartSettings.ShowWeight; + //total decimal orderTotalDiscountAmountBase = decimal.Zero; Discount orderTotalAppliedDiscount = null; @@ -1954,14 +2071,14 @@ public ActionResult OrderTotals(bool isEditable) if (shoppingCartTotalBase.HasValue) { decimal shoppingCartTotal = _currencyService.ConvertFromPrimaryStoreCurrency(shoppingCartTotalBase.Value, _workContext.WorkingCurrency); - model.OrderTotal = _priceFormatter.FormatPrice(shoppingCartTotal, false /*true*/, false); + model.OrderTotal = _priceFormatter.FormatPrice(shoppingCartTotal, true, false); } //discount if (orderTotalDiscountAmountBase > decimal.Zero) { decimal orderTotalDiscountAmount = _currencyService.ConvertFromPrimaryStoreCurrency(orderTotalDiscountAmountBase, _workContext.WorkingCurrency); - model.OrderTotalDiscount = _priceFormatter.FormatPrice(-orderTotalDiscountAmount, false /*true*/, false); + model.OrderTotalDiscount = _priceFormatter.FormatPrice(-orderTotalDiscountAmount, true, false); model.AllowRemovingOrderTotalDiscount = orderTotalAppliedDiscount != null && orderTotalAppliedDiscount.RequiresCouponCode && !String.IsNullOrEmpty(orderTotalAppliedDiscount.CouponCode) && model.IsEditable; } @@ -1977,11 +2094,11 @@ public ActionResult OrderTotals(bool isEditable) CouponCode = appliedGiftCard.GiftCard.GiftCardCouponCode, }; decimal amountCanBeUsed = _currencyService.ConvertFromPrimaryStoreCurrency(appliedGiftCard.AmountCanBeUsed, _workContext.WorkingCurrency); - gcModel.Amount = _priceFormatter.FormatPrice(-amountCanBeUsed, false /*true*/, false); + gcModel.Amount = _priceFormatter.FormatPrice(-amountCanBeUsed, true, false); decimal remainingAmountBase = appliedGiftCard.GiftCard.GetGiftCardRemainingAmount() - appliedGiftCard.AmountCanBeUsed; decimal remainingAmount = _currencyService.ConvertFromPrimaryStoreCurrency(remainingAmountBase, _workContext.WorkingCurrency); - gcModel.Remaining = _priceFormatter.FormatPrice(remainingAmount, false /*true*/, false); + gcModel.Remaining = _priceFormatter.FormatPrice(remainingAmount, true, false); model.GiftCards.Add(gcModel); } @@ -1992,7 +2109,7 @@ public ActionResult OrderTotals(bool isEditable) { decimal redeemedRewardPointsAmountInCustomerCurrency = _currencyService.ConvertFromPrimaryStoreCurrency(redeemedRewardPointsAmount, _workContext.WorkingCurrency); model.RedeemedRewardPoints = redeemedRewardPoints; - model.RedeemedRewardPointsAmount = _priceFormatter.FormatPrice(-redeemedRewardPointsAmountInCustomerCurrency, false /*true*/, false); + model.RedeemedRewardPointsAmount = _priceFormatter.FormatPrice(-redeemedRewardPointsAmountInCustomerCurrency, true, false); } } @@ -2511,15 +2628,11 @@ public ActionResult EmailWishlistSend(WishlistEmailAFriendModel model, bool capt return View(model); } - /// - /// codehint: sm-add - /// - /// public ActionResult FlyoutWishlist() { Customer customer = _workContext.CurrentCustomer; - var cart = customer.GetCartItems(ShoppingCartType.Wishlist, _storeContext.CurrentStore.Id, true); + var cart = customer.GetCartItems(ShoppingCartType.Wishlist, _storeContext.CurrentStore.Id); var model = new WishlistModel(); PrepareWishlistModel(model, cart, true); @@ -2545,7 +2658,7 @@ public ActionResult FlyoutWishlist() } }); - model.IgnoredProductsCount = Math.Max(0, cart.Count - _shoppingCartSettings.MiniShoppingCartProductNumber); // codehint: sm-add; + model.IgnoredProductsCount = Math.Max(0, cart.Count - _shoppingCartSettings.MiniShoppingCartProductNumber); model.ThumbSize = _mediaSettings.MiniCartThumbPictureSize; return PartialView(model); diff --git a/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs new file mode 100644 index 0000000000..68c94b3fe7 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.SessionState; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Services.Tasks; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Services.Security; +using SmartStore.Services; +using SmartStore.Collections; + +namespace SmartStore.Web.Controllers +{ + + [SessionState(SessionStateBehavior.ReadOnly)] + public class TaskSchedulerController : Controller + { + private readonly ITaskScheduler _taskScheduler; + private readonly IScheduleTaskService _scheduledTaskService; + private readonly ITaskExecutor _taskExecutor; + private readonly ICommonServices _services; + + public TaskSchedulerController( + ITaskScheduler taskScheduler, + IScheduleTaskService scheduledTaskService, + ITaskExecutor taskExecutor, + ICommonServices services) + { + this._taskScheduler = taskScheduler; + this._scheduledTaskService = scheduledTaskService; + this._taskExecutor = taskExecutor; + this._services = services; + } + + [HttpPost] + public ActionResult Sweep() + { + if (!_taskScheduler.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) + return new HttpUnauthorizedResult(); + + var pendingTasks = _scheduledTaskService.GetPendingTasks(); + var prevTaskStart = DateTime.UtcNow; + var count = 0; + + for (var i = 0; i < pendingTasks.Count; i++) + { + var task = pendingTasks[i]; + + if (i > 0) + { + // Maybe a subsequent Sweep call or another machine in a webfarm executed + // successive tasks already. + // To be able to determine this, we need to reload the entity from the database. + // The TaskExecutor will exit when the task should be in running state then. + _services.DbContext.ReloadEntity(task); + } + + if (task.IsPending) + { + prevTaskStart = DateTime.UtcNow; + _taskExecutor.Execute(task); + count++; + } + } + + return Content("{0} of {1} pending tasks executed".FormatInvariant(count, pendingTasks.Count)); + } + + [HttpPost] + public ActionResult Execute(int id /* taskId */) + { + if (!_taskScheduler.VerifyAuthToken(Request.Headers["X-AUTH-TOKEN"])) + return new HttpUnauthorizedResult(); + + var task = _scheduledTaskService.GetTaskById(id); + if (task == null) + return HttpNotFound(); + + _taskExecutor.Execute(task, QueryString.Current.ToDictionary()); + + return Content("Task '{0}' executed".FormatCurrent(task.Name)); + } + + public ContentResult Noop() + { + return Content("noop"); + } + + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Controllers/ThemeController.cs b/src/Presentation/SmartStore.Web/Controllers/ThemeController.cs index 14a44d4640..92e8cde656 100644 --- a/src/Presentation/SmartStore.Web/Controllers/ThemeController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/ThemeController.cs @@ -1,13 +1,10 @@ -using System; -using System.Linq; -using System.Web.Mvc; -using System.Web.Routing; +using System.Web.Mvc; using SmartStore.Core; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Services.Configuration; using SmartStore.Core.Themes; -using SmartStore.Services.Security; using SmartStore.Services.Themes; +using SmartStore.Web.Framework.Controllers; +using SmartStore.Web.Framework.Security; +using SmartStore.Web.Framework.Theming; namespace SmartStore.Web.Controllers { @@ -18,16 +15,23 @@ public partial class ThemeController : PublicControllerBase private readonly IThemeRegistry _themeRegistry; private readonly IThemeVariablesService _themeVarService; + private readonly IThemeContext _themeContext; + private readonly IStoreContext _storeContext; #endregion #region Constructors - public ThemeController(IThemeRegistry themeRegistry, IThemeVariablesService themeVarService) + public ThemeController( + IThemeRegistry themeRegistry, + IThemeVariablesService themeVarService, + IThemeContext themeContext, + IStoreContext storeContext) { - //this._permissionService = permissionService; this._themeRegistry = themeRegistry; this._themeVarService = themeVarService; + this._themeContext = themeContext; + this._storeContext = storeContext; } #endregion  @@ -35,14 +39,19 @@ public ThemeController(IThemeRegistry themeRegistry, IThemeVariablesService them #region Methods [ChildActionOnly] - public ActionResult ConfigureTheme(string theme, int StoreId) + public ActionResult ConfigureTheme(string theme, int storeId) { if (theme.HasValue()) { - this.ControllerContext.RouteData.DataTokens["ThemeOverride"] = theme; + _themeContext.SetRequestTheme(theme); } - var model = TempData["OverriddenThemeVars"] ?? _themeVarService.GetThemeVariables(theme, StoreId); + if (storeId > 0) + { + _storeContext.SetRequestStore(storeId); + } + + var model = TempData["OverriddenThemeVars"] ?? _themeVarService.GetThemeVariables(theme, storeId); return View(model); } diff --git a/src/Presentation/SmartStore.Web/Controllers/TopicController.cs b/src/Presentation/SmartStore.Web/Controllers/TopicController.cs index 2b9ef19cdb..7c4be750a3 100644 --- a/src/Presentation/SmartStore.Web/Controllers/TopicController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/TopicController.cs @@ -48,6 +48,12 @@ protected TopicModel PrepareTopicModel(string systemName) if (topic == null) return null; + var titleTag = "h3"; + if(topic.TitleTag != null) + titleTag = topic.TitleTag; + else if (!topic.RenderAsWidget) + titleTag = "h1"; + var model = new TopicModel() { Id = topic.Id, @@ -59,7 +65,9 @@ protected TopicModel PrepareTopicModel(string systemName) MetaKeywords = topic.GetLocalized(x => x.MetaKeywords), MetaDescription = topic.GetLocalized(x => x.MetaDescription), MetaTitle = topic.GetLocalized(x => x.MetaTitle), - }; + TitleTag = titleTag, + RenderAsWidget = topic.RenderAsWidget + }; return model; } @@ -72,8 +80,9 @@ public ActionResult TopicDetails(string systemName) var cacheKey = string.Format(ModelCacheEventConsumer.TOPIC_MODEL_KEY, systemName, _workContext.WorkingLanguage.Id, _storeContext.CurrentStore.Id); var cacheModel = _cacheManager.Get(cacheKey, () => PrepareTopicModel(systemName)); - if (cacheModel == null) - return RedirectToRoute("HomePage"); + if (cacheModel == null || (cacheModel.RenderAsWidget && !cacheModel.IncludeInSitemap)) + return HttpNotFound(); + return View("TopicDetails", cacheModel); } @@ -83,7 +92,7 @@ public ActionResult TopicDetailsPopup(string systemName) var cacheModel = _cacheManager.Get(cacheKey, () => PrepareTopicModel(systemName)); if (cacheModel == null) - return RedirectToRoute("HomePage"); + return HttpNotFound(); ViewBag.IsPopup = true; return View("TopicDetails", cacheModel); diff --git a/src/Presentation/SmartStore.Web/Controllers/WidgetController.cs b/src/Presentation/SmartStore.Web/Controllers/WidgetController.cs index 180440df34..74461e92ef 100644 --- a/src/Presentation/SmartStore.Web/Controllers/WidgetController.cs +++ b/src/Presentation/SmartStore.Web/Controllers/WidgetController.cs @@ -9,10 +9,16 @@ namespace SmartStore.Web.Controllers public partial class WidgetController : PublicControllerBase { [ChildActionOnly] - public ActionResult WidgetsByZone(IEnumerable widgets) + public ActionResult WidgetsByZone(WidgetZoneModel zoneModel) { - return PartialView(widgets); + return PartialView(zoneModel); } + [ChildActionOnly] + public ActionResult TabWidgets(object model, string viewDataKey) + { + var widgets = this.ControllerContext.ParentActionViewContext.ViewData[viewDataKey]; + return PartialView(widgets); + } } } diff --git a/src/Presentation/SmartStore.Web/ErrorPage.htm b/src/Presentation/SmartStore.Web/ErrorPage.htm deleted file mode 100644 index 77a735556c..0000000000 --- a/src/Presentation/SmartStore.Web/ErrorPage.htm +++ /dev/null @@ -1,47 +0,0 @@ - - - - Error - - - -
          - -

          - We're sorry, an internal error has occurred. -

          -

          - Our supporting staff has been notified of this error and will address the issue shortly. - We apologize for the inconvenience. -

          - Please try clicking your browsers 'back' button or try reloading the home page. - If you continue to receive this message, please try again in a little while. -

          - -

          - Thank you for your patience. -

          - -
          - - diff --git a/src/Presentation/SmartStore.Web/Content/Images/Thumbs/placeholder.txt b/src/Presentation/SmartStore.Web/Exchange/placeholder similarity index 100% rename from src/Presentation/SmartStore.Web/Content/Images/Thumbs/placeholder.txt rename to src/Presentation/SmartStore.Web/Exchange/placeholder diff --git a/src/Presentation/SmartStore.Web/Extensions/EditorExtensions.cs b/src/Presentation/SmartStore.Web/Extensions/EditorExtensions.cs index 54e1c7406b..a621ced06d 100644 --- a/src/Presentation/SmartStore.Web/Extensions/EditorExtensions.cs +++ b/src/Presentation/SmartStore.Web/Extensions/EditorExtensions.cs @@ -4,7 +4,7 @@ using SmartStore.Core; using SmartStore.Core.Infrastructure; -namespace SmartStore.Web.Extensions +namespace SmartStore.Web { public static class EditorExtensions { diff --git a/src/Presentation/SmartStore.Web/Extensions/MappingExtensions.cs b/src/Presentation/SmartStore.Web/Extensions/MappingExtensions.cs index 49a7cdedee..fcd098d40b 100644 --- a/src/Presentation/SmartStore.Web/Extensions/MappingExtensions.cs +++ b/src/Presentation/SmartStore.Web/Extensions/MappingExtensions.cs @@ -11,7 +11,7 @@ using SmartStore.Web.Models.Catalog; using SmartStore.Web.Models.Common; -namespace SmartStore.Web.Extensions +namespace SmartStore.Web { public static class MappingExtensions { @@ -21,11 +21,13 @@ public static CategoryModel ToModel(this Category entity) if (entity == null) return null; - var model = new CategoryModel() + var model = new CategoryModel { Id = entity.Id, Name = entity.GetLocalized(x => x.Name), + FullName = entity.GetLocalized(x => x.FullName), Description = entity.GetLocalized(x => x.Description), + BottomDescription = entity.GetLocalized(x => x.BottomDescription), MetaKeywords = entity.GetLocalized(x => x.MetaKeywords), MetaDescription = entity.GetLocalized(x => x.MetaDescription), MetaTitle = entity.GetLocalized(x => x.MetaTitle), @@ -82,6 +84,7 @@ public static void PrepareModel(this AddressModel model, model.FirstName = address.FirstName; model.LastName = address.LastName; model.Email = address.Email; + model.EmailMatch = address.Email; model.Company = address.Company; model.CountryId = address.CountryId; model.CountryName = address.Country != null @@ -149,6 +152,7 @@ public static void PrepareModel(this AddressModel model, } //form fields + model.ValidateEmailAddress = addressSettings.ValidateEmailAddress; model.CompanyEnabled = addressSettings.CompanyEnabled; model.CompanyRequired = addressSettings.CompanyRequired; model.StreetAddressEnabled = addressSettings.StreetAddressEnabled; diff --git a/src/Presentation/SmartStore.Web/Extensions/PagerHtmlExtension.cs b/src/Presentation/SmartStore.Web/Extensions/PagerHtmlExtension.cs deleted file mode 100644 index dcbf598d86..0000000000 --- a/src/Presentation/SmartStore.Web/Extensions/PagerHtmlExtension.cs +++ /dev/null @@ -1,66 +0,0 @@ -//using System; -//using System.Text; -//using System.Web.Mvc; -//using System.Web.Mvc.Html; -//using SmartStore.Core.Infrastructure; -//using SmartStore.Services.Localization; -//using SmartStore.Web.Framework.UI.Paging; -//using SmartStore.Web.Models.Boards; -//using SmartStore.Web.Models.Common; - -//namespace SmartStore.Web.Extensions -//{ -// public static class PagerHtmlExtension -// { -// //we have two pagers: -// //The first one can have custom routes -// //The second one just adds query string parameter -// // codehint: sm-delete -// public static MvcHtmlString ForumTopicSmallPager(this HtmlHelper html, ForumTopicRowModel model) -// { -// var localizationService= EngineContext.Current.Resolve(); - -// var forumTopicId = model.Id; -// var forumTopicSlug = model.SeName; -// var totalPages = model.TotalPostPages; - -// if (totalPages > 0) -// { -// var links = new StringBuilder(); - -// if (totalPages <= 4) -// { -// for (int x = 1; x <= totalPages; x++) -// { -// links.Append(html.RouteLink(x.ToString(), "TopicSlugPaged", new { id = forumTopicId, page = (x), slug = forumTopicSlug }, new { title = String.Format(localizationService.GetResource("Pager.PageLinkTitle"), x.ToString()) })); -// if (x < totalPages) -// { -// links.Append(", "); -// } -// } -// } -// else -// { -// links.Append(html.RouteLink("1", "TopicSlugPaged", new { id = forumTopicId, page = (1), slug = forumTopicSlug }, new { title = String.Format(localizationService.GetResource("Pager.PageLinkTitle"), 1) })); -// links.Append(" ... "); - -// for (int x = (totalPages - 2); x <= totalPages; x++) -// { -// links.Append(html.RouteLink(x.ToString(), "TopicSlugPaged", new { id = forumTopicId, page = (x), slug = forumTopicSlug }, new { title = String.Format(localizationService.GetResource("Pager.PageLinkTitle"), x.ToString()) })); - -// if (x < totalPages) -// { -// links.Append(", "); -// } -// } -// } - -// // Inserts the topic page links into the localized string ([Go to page: {0}]) -// return MvcHtmlString.Create(String.Format(localizationService.GetResource("Forum.Topics.GotoPostPager"), links.ToString())); -// } -// return MvcHtmlString.Create(string.Empty); -// } - -// // codehint: sm-delete -// } -//} diff --git a/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs b/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs index 946ee78400..18356aa3cb 100644 --- a/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs +++ b/src/Presentation/SmartStore.Web/Extensions/ProductDetailsExtensions.cs @@ -7,34 +7,36 @@ using SmartStore.Core.Domain.Media; using SmartStore.Services.Media; -namespace SmartStore.Web.Extensions +namespace SmartStore.Web { public static class ProductDetailsExtensions { + public static string UpdateProductDetailsUrl(this ProductDetailsModel model, string itemType = null) { var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext); - string url = urlHelper.Action("UpdateProductDetails", "Catalog", new + string url = urlHelper.Action("UpdateProductDetails", "Product", new { productId = model.Id, bundleItemId = model.BundleItem.Id, - itemType = itemType, - area = "admin" + itemType = itemType }); return url; } + public static bool RenderBundleTitle(this ProductDetailsModel model) { return model.BundleTitleText.HasValue() && model.BundledItems.Where(x => x.BundleItem.Visible).Count() > 0; } + public static Picture GetAssignedPicture(this ProductDetailsModel model, IPictureService pictureService, IList pictures, int productId = 0) { - if (model != null && model.CombinationSelected != null) + if (model != null && model.SelectedCombination != null) { Picture picture = null; - var combiAssignedImages = model.CombinationSelected.GetAssignedPictureIds(); + var combiAssignedImages = model.SelectedCombination.GetAssignedPictureIds(); if (combiAssignedImages.Length > 0) { @@ -52,6 +54,7 @@ public static Picture GetAssignedPicture(this ProductDetailsModel model, IPictur } return null; } + public static string GetAttributeValueInfo(this ProductDetailsModel.ProductVariantAttributeValueModel model) { string result = ""; @@ -78,6 +81,7 @@ public static bool ShouldBeRendered(this ProductDetailsModel.ProductVariantAttri return true; } } + public static bool ShouldBeRendered(this IEnumerable variantAttributes) { if (variantAttributes != null) diff --git a/src/Presentation/SmartStore.Web/FileNotFound.htm b/src/Presentation/SmartStore.Web/FileNotFound.htm deleted file mode 100644 index f0f33982f2..0000000000 --- a/src/Presentation/SmartStore.Web/FileNotFound.htm +++ /dev/null @@ -1,46 +0,0 @@ - - - - File not found - - - -
          - -

          - Page not found -

          -

          - We're sorry, we can't find that page. - It's possible you typed the address incorrectly or the page you were - looking for has been moved or no longer exists. - Please go to our home page and try again. -

          - -

          - Thank you you for your patience. -

          - -
          - - diff --git a/src/Presentation/SmartStore.Web/Global.asax.cs b/src/Presentation/SmartStore.Web/Global.asax.cs index 0a9bf6bfa1..4297e54186 100644 --- a/src/Presentation/SmartStore.Web/Global.asax.cs +++ b/src/Presentation/SmartStore.Web/Global.asax.cs @@ -1,45 +1,34 @@ using System; -using System.Globalization; using System.Linq; -using System.Threading; +using System.Web; using System.Web.Hosting; using System.Web.Mvc; +using System.Web.Optimization; using System.Web.Routing; +using System.Web.Security; using System.Web.WebPages; -using System.Web.Optimization; using FluentValidation.Mvc; using SmartStore.Core; using SmartStore.Core.Data; -using SmartStore.Core.Domain; +using SmartStore.Core.Events; using SmartStore.Core.Infrastructure; -using SmartStore.Core.Logging; +using SmartStore.Services.Customers; using SmartStore.Services.Tasks; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; -using SmartStore.Web.Framework.Mvc.Bundles; -using SmartStore.Web.Framework.Mvc.Routes; -using SmartStore.Web.Framework.Themes; -using SmartStore.Core.Events; -using System.Web; -using SmartStore.Core.Domain.Themes; -using SmartStore.Core.Infrastructure.DependencyManagement; -using Autofac; -using Autofac.Integration.Mvc; -using System.IO; -using System.Diagnostics; +using SmartStore.Web.Framework.Bundling; +using SmartStore.Web.Framework.Filters; +using SmartStore.Web.Framework.Localization; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Framework.Plugins; -using SmartStore.Web.Framework.Controllers; -using SmartStore.Web.Framework.Validators; - +using SmartStore.Web.Framework.Routing; +using SmartStore.Web.Framework.Theming; +using SmartStore.Web.Framework.Validators; namespace SmartStore.Web { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 - public class MvcApplication : System.Web.HttpApplication { - public static void RegisterGlobalFilters(GlobalFilterCollection filters) { var eventPublisher = EngineContext.Current.Resolve(); @@ -50,23 +39,14 @@ public static void RegisterGlobalFilters(GlobalFilterCollection filters) public static void RegisterRoutes(RouteCollection routes, bool databaseInstalled = true) { - routes.IgnoreRoute("favicon.ico"); + //routes.IgnoreRoute("favicon.ico"); routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); + routes.IgnoreRoute("{resource}.ashx/{*pathInfo}"); routes.IgnoreRoute(".db/{*virtualpath}"); - if (databaseInstalled) - { - // register custom routes (plugins, etc) - var routePublisher = EngineContext.Current.Resolve(); - routePublisher.RegisterRoutes(routes); - } - - routes.MapRoute( - "Default", // Route name - "{controller}/{action}/{id}", // URL with parameters - new { controller = "Home", action = "Index", id = UrlParameter.Optional }, - new[] { "SmartStore.Web.Controllers" } - ); + // register routes (core, admin, plugins, etc) + var routePublisher = EngineContext.Current.Resolve(); + routePublisher.RegisterRoutes(routes); } public static void RegisterBundles(BundleCollection bundles) @@ -110,19 +90,24 @@ protected void Application_Start() // Routes RegisterRoutes(RouteTable.Routes, installed); + // localize MVC resources + ClientDataTypeModelValidatorProvider.ResourceClassKey = "MvcLocalization"; + DefaultModelBinder.ResourceClassKey = "MvcLocalization"; + ErrorMessageProvider.SetResourceClassKey("MvcLocalization"); + if (installed) { // register our themeable razor view engine we use ViewEngines.Engines.Add(new ThemeableRazorViewEngine()); // Global filters - RegisterGlobalFilters(GlobalFilters.Filters); + RegisterGlobalFilters(GlobalFilters.Filters); // Bundles RegisterBundles(BundleTable.Bundles); - // register virtual path provider for theme variables - HostingEnvironment.RegisterVirtualPathProvider(new ThemeVarsVirtualPathProvider(HostingEnvironment.VirtualPathProvider)); + // register virtual path provider for theming (file inheritance & variables handling) + HostingEnvironment.RegisterVirtualPathProvider(new ThemingVirtualPathProvider(HostingEnvironment.VirtualPathProvider)); BundleTable.VirtualPathProvider = HostingEnvironment.VirtualPathProvider; // register plugin debug view virtual path provider @@ -131,9 +116,8 @@ protected void Application_Start() HostingEnvironment.RegisterVirtualPathProvider(new PluginDebugViewVirtualPathProvider()); } - // start scheduled tasks - TaskManager.Instance.Initialize(); - TaskManager.Instance.Start(); + // "throw-away" filter for task scheduler initialization (the filter removes itself when processed) + GlobalFilters.Filters.Add(new InitializeSchedulerFilter()); } else { @@ -151,7 +135,7 @@ public override string GetVaryByCustomString(HttpContext context, string custom) if (DataSettings.DatabaseIsInstalled()) { - custom = custom.ToLower(); + custom = custom.ToLowerInvariant(); switch (custom) { @@ -172,43 +156,24 @@ public override string GetVaryByCustomString(HttpContext context, string custom) if (result.HasValue()) { return result; - } + } return base.GetVaryByCustomString(context, custom); } - - protected void Application_AuthenticateRequest(object sender, EventArgs e) - { - // [...] - } - - protected void Application_Error(Object sender, EventArgs e) - { - //disable compression (if enabled). More info - http://stackoverflow.com/questions/3960707/asp-net-mvc-weird-characters-in-error-page - //log error - LogException(Server.GetLastError()); - } - - protected void LogException(Exception exc) - { - if (exc == null) - return; - - if (!DataSettings.DatabaseIsInstalled()) - return; - - try - { - var logger = EngineContext.Current.Resolve(); - var workContext = EngineContext.Current.Resolve(); - logger.Error(exc.Message, exc, workContext.CurrentCustomer); - } - catch (Exception) - { - //don't throw new exception if occurs - } - } - - } + public void AnonymousIdentification_Creating(object sender, AnonymousIdentificationEventArgs args) + { + try + { + var customerService = EngineContext.Current.Resolve(); + var customer = customerService.FindGuestCustomerByClientIdent(maxAgeSeconds: 180); + if (customer != null) + { + // We found our anonymous visitor: don't let ASP.NET create a new id. + args.AnonymousID = customer.CustomerGuid.ToString(); + } + } + catch { } + } + } } diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Cache/ModelCacheEventConsumer.cs b/src/Presentation/SmartStore.Web/Infrastructure/Cache/ModelCacheEventConsumer.cs index bc18eb23c1..c17e051277 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Cache/ModelCacheEventConsumer.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Cache/ModelCacheEventConsumer.cs @@ -40,7 +40,7 @@ public partial class ModelCacheEventConsumer: IConsumer>, IConsumer>, //categories - IConsumer>, // codehint: sm-add + IConsumer>, IConsumer>, IConsumer>, //product categories @@ -122,15 +122,16 @@ public partial class ModelCacheEventConsumer: IConsumer>, IConsumer> { - /// - /// Key for ManufacturerNavigationModel caching - /// - /// - /// {0} : current manufacturer id - /// {1} : language id - /// {2} : current store ID - /// - public const string MANUFACTURER_NAVIGATION_MODEL_KEY = "sm.pres.manufacturer.navigation-{0}-{1}-{2}"; + /// + /// Key for ManufacturerNavigationModel caching + /// + /// + /// {0} : current manufacturer id + /// {1} : value indicating whether a default picture is displayed in case if no real picture exists + /// {2} : language id + /// {3} : current store ID + /// + public const string MANUFACTURER_NAVIGATION_MODEL_KEY = "sm.pres.manufacturer.navigation-{0}-{1}-{2}-{3}"; public const string MANUFACTURER_NAVIGATION_PATTERN_KEY = "sm.pres.manufacturer.navigation"; /// @@ -178,18 +179,6 @@ public partial class ModelCacheEventConsumer: public const string CATEGORY_HAS_FEATURED_PRODUCTS_KEY = "sm.pres.category.hasfeaturedproducts-{0}-{1}-{2}"; public const string CATEGORY_HAS_FEATURED_PRODUCTS_PATTERN_KEY = "sm.pres.category.hasfeaturedproducts"; - /// - /// Key for ProductBreadcrumbModel caching - /// - /// - /// {0} : product id - /// {1} : language id - /// {2} : comma separated list of customer roles - /// {3} : current store id - /// - public const string PRODUCT_BREADCRUMB_MODEL_KEY = "sm.pres.product.breadcrumb-{0}-{1}-{2}-{3}"; - public const string PRODUCT_BREADCRUMB_PATTERN_KEY = "sm.pres.product.breadcrumb"; - /// /// Key for ProductTagModel caching /// @@ -211,15 +200,16 @@ public partial class ModelCacheEventConsumer: public const string PRODUCTTAG_POPULAR_MODEL_KEY = "sm.pres.producttag.popular-{0}-{1}"; public const string PRODUCTTAG_POPULAR_PATTERN_KEY = "sm.pres.producttag.popular"; - /// - /// Key for ProductManufacturers model caching - /// - /// - /// {0} : product id - /// {1} : language id - /// {2} : current store ID - /// - public const string PRODUCT_MANUFACTURERS_MODEL_KEY = "sm.pres.product.manufacturers-{0}-{1}-{2}"; + /// + /// Key for ProductManufacturers model caching + /// + /// + /// {0} : product id + /// {1} : value indicating whether a default picture is displayed in case if no real picture exists + /// {2} : language id + /// {3} : current store ID + /// + public const string PRODUCT_MANUFACTURERS_MODEL_KEY = "sm.pres.product.manufacturers-{0}-{1}-{2}-{3}"; public const string PRODUCT_MANUFACTURERS_PATTERN_KEY = "sm.pres.product.manufacturers"; /// @@ -253,17 +243,6 @@ public partial class ModelCacheEventConsumer: public const string TOPIC_WIDGET_PATTERN_KEY = "sm.pres.topic.widget"; public const string TOPIC_WIDGET_ALL_MODEL_KEY = "sm.pres.topic.widget-all-{0}-{1}"; - /// - /// Key for TopicWidget by zone caching - /// - /// - /// {0} : widget zone - /// {1} : store id - /// {2} : language id - /// - public const string TOPIC_WIDGET_BYZONE_PATTERN_KEY = "sm.pres.topic.widget-byzone"; - public const string TOPIC_WIDGET_BYZONE_MODEL_KEY = "sm.pres.topic.widget-byzone-{0}-{1}-{2}"; - /// /// Key for CategoryTemplate caching /// @@ -453,6 +432,27 @@ public partial class ModelCacheEventConsumer: public const string SHOPHEADER_MODEL_KEY = "sm.pres.shopheader-{0}"; public const string SHOPHEADER_MODEL_PATTERN_KEY = "sm.pres.shopheader"; + /// + /// Key for sitemap + /// + /// + /// {0} : language id + /// {1} : current user roles + /// {2} : current store id + /// + public const string SITEMAP_PAGE_MODEL_KEY = "sm.pres.sitemap.page-{0}-{1}-{2}"; + + /// + /// Key for seo sitemap + /// + /// + /// {0} : language id + /// {1} : current user roles + /// {2} : current store id + /// + public const string SITEMAP_XML_MODEL_KEY = "sm.pres.sitemap.xml-{0}-{1}-{2}"; + public const string SITEMAP_PATTERN_KEY = "sm.pres.sitemap"; + private readonly ICacheManager _cacheManager; public ModelCacheEventConsumer(Func cache) @@ -467,7 +467,6 @@ public void HandleEvent(EntityInserted eventMessage) _cacheManager.RemoveByPattern(MANUFACTURER_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_SPECS_PATTERN_KEY); _cacheManager.RemoveByPattern(TOPIC_PATTERN_KEY); - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_MANUFACTURERS_PATTERN_KEY); _cacheManager.RemoveByPattern(STATEPROVINCES_PATTERN_KEY); @@ -480,8 +479,6 @@ public void HandleEvent(EntityUpdated eventMessage) _cacheManager.RemoveByPattern(MANUFACTURER_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_SPECS_PATTERN_KEY); _cacheManager.RemoveByPattern(TOPIC_PATTERN_KEY); - _cacheManager.RemoveByPattern(TOPIC_WIDGET_BYZONE_PATTERN_KEY); - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_MANUFACTURERS_PATTERN_KEY); _cacheManager.RemoveByPattern(STATEPROVINCES_PATTERN_KEY); @@ -494,8 +491,6 @@ public void HandleEvent(EntityDeleted eventMessage) _cacheManager.RemoveByPattern(MANUFACTURER_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_SPECS_PATTERN_KEY); _cacheManager.RemoveByPattern(TOPIC_PATTERN_KEY); - _cacheManager.RemoveByPattern(TOPIC_WIDGET_BYZONE_PATTERN_KEY); - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_MANUFACTURERS_PATTERN_KEY); _cacheManager.RemoveByPattern(STATEPROVINCES_PATTERN_KEY); @@ -527,6 +522,7 @@ public void HandleEvent(EntityUpdated eventMessage) _cacheManager.RemoveByPattern(HOMEPAGE_BESTSELLERS_IDS_PATTERN_KEY); //depends on CatalogSettings.NumberOfBestsellersOnHomepage _cacheManager.RemoveByPattern(BLOG_PATTERN_KEY); //depends on BlogSettings.NumberOfTags _cacheManager.RemoveByPattern(NEWS_PATTERN_KEY); //depends on NewsSettings.MainPageNewsCount + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); //depends on sitemap settings } //manufacturers @@ -534,18 +530,21 @@ public void HandleEvent(EntityInserted eventMessage) { _cacheManager.RemoveByPattern(MANUFACTURER_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_MANUFACTURERS_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityUpdated eventMessage) { _cacheManager.RemoveByPattern(MANUFACTURER_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_MANUFACTURERS_PATTERN_KEY); _cacheManager.RemoveByPattern(MANUFACTURER_PICTURE_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityDeleted eventMessage) { _cacheManager.RemoveByPattern(MANUFACTURER_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_MANUFACTURERS_PATTERN_KEY); _cacheManager.RemoveByPattern(MANUFACTURER_PICTURE_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } //product manufacturers @@ -570,38 +569,36 @@ public void HandleEvent(EntityInserted eventMessage) { _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_CHILD_IDENTIFIERS_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityUpdated eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_PICTURE_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_CHILD_IDENTIFIERS_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityDeleted eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_PICTURE_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_CHILD_IDENTIFIERS_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } //product categories public void HandleEvent(EntityInserted eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_HAS_FEATURED_PRODUCTS_PATTERN_KEY); } public void HandleEvent(EntityUpdated eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_HAS_FEATURED_PRODUCTS_PATTERN_KEY); } public void HandleEvent(EntityDeleted eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_HAS_FEATURED_PRODUCTS_PATTERN_KEY); } @@ -610,15 +607,16 @@ public void HandleEvent(EntityDeleted eventMessage) public void HandleEvent(EntityInserted eventMessage) { _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityUpdated eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCT_DEFAULTPICTURE_PATTERN_KEY); _cacheManager.RemoveByPattern(CART_PICTURE_PATTERN_KEY); _cacheManager.RemoveByPattern(HOMEPAGE_BESTSELLERS_IDS_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCTS_ALSO_PURCHASED_IDS_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityDeleted eventMessage) { @@ -626,6 +624,7 @@ public void HandleEvent(EntityDeleted eventMessage) _cacheManager.RemoveByPattern(PRODUCT_DEFAULTPICTURE_PATTERN_KEY); _cacheManager.RemoveByPattern(HOMEPAGE_BESTSELLERS_IDS_PATTERN_KEY); _cacheManager.RemoveByPattern(PRODUCTS_ALSO_PURCHASED_IDS_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } //product tags @@ -689,16 +688,19 @@ public void HandleEvent(EntityDeleted eventMessag public void HandleEvent(EntityInserted eventMessage) { _cacheManager.RemoveByPattern(TOPIC_WIDGET_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityUpdated eventMessage) { _cacheManager.RemoveByPattern(TOPIC_PATTERN_KEY); _cacheManager.RemoveByPattern(TOPIC_WIDGET_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } public void HandleEvent(EntityDeleted eventMessage) { _cacheManager.RemoveByPattern(TOPIC_PATTERN_KEY); _cacheManager.RemoveByPattern(TOPIC_WIDGET_PATTERN_KEY); + _cacheManager.RemoveByPattern(SITEMAP_PATTERN_KEY); } //Category templates @@ -873,13 +875,11 @@ public void HandleEvent(EntityDeleted eventMessage) //customer roles public void HandleEvent(EntityUpdated eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_CHILD_IDENTIFIERS_PATTERN_KEY); } public void HandleEvent(EntityDeleted eventMessage) { - _cacheManager.RemoveByPattern(PRODUCT_BREADCRUMB_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_NAVIGATION_PATTERN_KEY); _cacheManager.RemoveByPattern(CATEGORY_CHILD_IDENTIFIERS_PATTERN_KEY); } diff --git a/src/Presentation/SmartStore.Web/Infrastructure/DefaultBundles.cs b/src/Presentation/SmartStore.Web/Infrastructure/DefaultBundles.cs new file mode 100644 index 0000000000..d64c2a3d2f --- /dev/null +++ b/src/Presentation/SmartStore.Web/Infrastructure/DefaultBundles.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Optimization; +using BundleTransformer.Core.Bundles; +using SmartStore.Web.Framework.Bundling; + +namespace SmartStore.Web.Infrastructure +{ + public class DefaultBundles : IBundleProvider + { + public void RegisterBundles(BundleCollection bundles) + { + /* Image Gallery + -----------------------------------------------------*/ + bundles.Add(new CustomScriptBundle("~/bundles/image-gallery").Include( + "~/Content/image-gallery/js/blueimp-gallery.js", + //"~/Content/image-gallery/js/blueimp-gallery-fullscreen.js", + "~/Content/image-gallery/js/blueimp-gallery-indicator.js", + "~/Scripts/jquery.elevatezoom.js", + "~/Scripts/smartstore.smartgallery.js")); + + bundles.Add(new CustomStyleBundle("~/css/image-gallery").Include( + "~/Content/smartstore.smartgallery.css", + "~/Content/image-gallery/css/blueimp-gallery.css", + "~/Content/image-gallery/css/blueimp-gallery-indicator.css", + "~/Content/image-gallery/css/blueimp-gallery-custom.css")); + + + /* sequence js + -----------------------------------------------------*/ + bundles.Add(new CustomScriptBundle("~/bundles/sequencejs").Include( + "~/Scripts/jquery.backgroundpos.js", + "~/Scripts/jquery.sequence.js", + "~/Scripts/jquery.sequence.custom.js")); + + + /* File Upload + -----------------------------------------------------*/ + bundles.Add(new CustomScriptBundle("~/bundles/fileupload").Include( + "~/Scripts/jquery-ui/widget.js", + "~/Content/fileupload/jquery.iframe-transport.js", + "~/Content/fileupload/jquery.fileupload.js", + "~/Content/fileupload/jquery.fileupload-single-ui.js")); + + bundles.Add(new CustomStyleBundle("~/css/fileupload").Include( + "~/Content/fileupload/jquery.fileupload-single-ui.css")); + + } + + public int Priority + { + get { return 0; } + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Infrastructure/DefaultWidgetSelector.cs b/src/Presentation/SmartStore.Web/Infrastructure/DefaultWidgetSelector.cs index 7feb99b355..48ce046bc7 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/DefaultWidgetSelector.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/DefaultWidgetSelector.cs @@ -8,6 +8,7 @@ using SmartStore.Core.Caching; using SmartStore.Core.Data; using SmartStore.Core.Infrastructure; +using SmartStore.Services; using SmartStore.Services.Cms; using SmartStore.Services.Localization; using SmartStore.Services.Topics; @@ -29,12 +30,8 @@ public partial class DefaultWidgetSelector : IWidgetSelector private readonly ICacheManager _cacheManager; private readonly IWorkContext _workContext; private readonly IDbContext _dbContext; - private readonly Lazy> _simpleWidgets; private readonly IWidgetProvider _widgetProvider; - - private static ConcurrentDictionary> s_simpleWidgetsMap; - private static bool? s_hasSimpleWidgets; - private static readonly object _lock = new object(); + private readonly ICommonServices _services; #endregion @@ -45,8 +42,8 @@ public DefaultWidgetSelector( ICacheManager cacheManager, IWorkContext workContext, IDbContext dbContext, - Lazy> simpleWidgets, - IWidgetProvider widgetProvider) + IWidgetProvider widgetProvider, + ICommonServices services) { this._widgetService = widgetService; this._topicService = topicService; @@ -54,12 +51,12 @@ public DefaultWidgetSelector( this._cacheManager = cacheManager; this._workContext = workContext; this._dbContext = dbContext; - this._simpleWidgets = simpleWidgets; this._widgetProvider = widgetProvider; + this._services = services; } public virtual IEnumerable GetWidgets(string widgetZone, object model) - { + { string actionName; string controllerName; RouteValueDictionary routeValues; @@ -70,14 +67,17 @@ public virtual IEnumerable GetWidgets(string widgetZone, object var widgets = _widgetService.LoadActiveWidgetsByWidgetZone(widgetZone, storeId); foreach (var widget in widgets) { - widget.GetDisplayWidgetRoute(widgetZone, model, storeId, out actionName, out controllerName, out routeValues); + widget.Value.GetDisplayWidgetRoute(widgetZone, model, storeId, out actionName, out controllerName, out routeValues); - yield return new WidgetRouteInfo - { - ActionName = actionName, - ControllerName = controllerName, - RouteValues = routeValues - }; + if (actionName.HasValue() && controllerName.HasValue()) + { + yield return new WidgetRouteInfo + { + ActionName = actionName, + ControllerName = controllerName, + RouteValues = routeValues + }; + } } #endregion @@ -86,62 +86,115 @@ public virtual IEnumerable GetWidgets(string widgetZone, object // add special "topic widgets" to the list var allTopicsCacheKey = string.Format(ModelCacheEventConsumer.TOPIC_WIDGET_ALL_MODEL_KEY, storeId, _workContext.WorkingLanguage.Id); - var topicWidgets = _cacheManager.Get(allTopicsCacheKey, () => + // get topic widgets from STATIC cache + var topicWidgets = _services.Cache.Get(allTopicsCacheKey, () => { - var allTopicWidgets = _topicService.GetAllTopics(storeId).Where(x => x.RenderAsWidget).ToList(); - var stubs = allTopicWidgets - .Select(t => new TopicWidgetStub - { - Id = t.Id, - Bordered = t.WidgetBordered, - ShowTitle = t.WidgetShowTitle, - SystemName = t.SystemName.SanitizeHtmlId(), - Title = t.GetLocalized(x => t.Title), - Body = t.GetLocalized(x => t.Body), - WidgetZones = t.GetWidgetZones().ToArray(), - Priority = t.Priority - }) - .ToList(); - return stubs; + using (var scope = new DbContextScope(forceNoTracking: true)) + { + var allTopicWidgets = _topicService.GetAllTopics(storeId).Where(x => x.RenderAsWidget).ToList(); + var stubs = allTopicWidgets + .Select(t => new TopicWidgetStub + { + Id = t.Id, + Bordered = t.WidgetBordered, + WrapContent = !t.WidgetWrapContent.HasValue || t.WidgetWrapContent.Value, + ShowTitle = t.WidgetShowTitle, + SystemName = t.SystemName.SanitizeHtmlId(), + Title = t.GetLocalized(x => t.Title), + TitleTag = t.TitleTag, + Body = t.GetLocalized(x => t.Body), + WidgetZones = t.GetWidgetZones().ToArray(), + Priority = t.Priority + }) + .OrderBy(t => t.Priority) + .ToList(); + return stubs; + } }); - var byZoneTopicsCacheKey = string.Format(ModelCacheEventConsumer.TOPIC_WIDGET_BYZONE_MODEL_KEY, widgetZone, _storeContext.CurrentStore.Id, _workContext.WorkingLanguage.Id); - var topicsByZone = _cacheManager.Get(byZoneTopicsCacheKey, () => + var byZoneTopicsCacheKey = "SmartStore.TopicWidgets.ZoneMapped"; + // save widgets to zones map in request cache + var topicsByZone = _cacheManager.Get(byZoneTopicsCacheKey, () => { - var result = from t in topicWidgets - where t.WidgetZones.Contains(widgetZone, StringComparer.InvariantCultureIgnoreCase) - orderby t.Priority - select new WidgetRouteInfo - { - ControllerName = "Topic", - ActionName = "TopicWidget", - RouteValues = new RouteValueDictionary() - { - {"Namespaces", "SmartStore.Web.Controllers"}, - {"area", null}, - {"widgetZone", widgetZone}, - {"model", new TopicWidgetModel - { - Id = t.Id, - SystemName = t.SystemName, - ShowTitle = t.ShowTitle, - IsBordered = t.Bordered, - Title = t.Title, - Html = t.Body - } } - } - }; + var map = new Multimap(); - return result.ToList(); - }); + foreach (var widget in topicWidgets) + { + var zones = widget.WidgetZones; + if (zones != null && zones.Any()) + { + foreach (var zone in zones.Select(x => x.ToLower())) + { + var routeInfo = new WidgetRouteInfo + { + ControllerName = "Topic", + ActionName = "TopicWidget", + RouteValues = new RouteValueDictionary() + { + {"Namespaces", "SmartStore.Web.Controllers"}, + {"area", null}, + {"widgetZone", zone}, + {"model", new TopicWidgetModel + { + Id = widget.Id, + SystemName = widget.SystemName, + WrapContent = widget.WrapContent, + ShowTitle = widget.ShowTitle, + IsBordered = widget.Bordered, + Title = String.IsNullOrEmpty(widget.Title) ? "div" : widget.Title, + TitleTag = widget.TitleTag ?? "h3", + Html = widget.Body + } } + } + }; + map.Add(zone, routeInfo); + } + } + } - foreach (var topicWidget in topicsByZone) - { - yield return topicWidget; - } + return map; + + #region Obsolete + //var result = from t in topicWidgets + // where t.WidgetZones.Contains(widgetZone, StringComparer.InvariantCultureIgnoreCase) + // orderby t.Priority + // select new WidgetRouteInfo + // { + // ControllerName = "Topic", + // ActionName = "TopicWidget", + // RouteValues = new RouteValueDictionary() + // { + // {"Namespaces", "SmartStore.Web.Controllers"}, + // {"area", null}, + // {"widgetZone", widgetZone}, + // {"model", new TopicWidgetModel + // { + // Id = t.Id, + // SystemName = t.SystemName, + // ShowTitle = t.ShowTitle, + // IsBordered = t.Bordered, + // Title = t.Title, + // Html = t.Body + // } } + // } + // }; + + //return result.ToList(); + #endregion + }); + + if (topicsByZone.ContainsKey(widgetZone.ToLower())) + { + var zoneWidgets = topicsByZone[widgetZone.ToLower()]; + foreach (var topicWidget in zoneWidgets) + { + yield return topicWidget; + } + } #endregion + #region Request scoped widgets (provided by IWidgetProvider) var requestScopedWidgets = _widgetProvider.GetWidgets(widgetZone); @@ -154,97 +207,6 @@ orderby t.Priority } #endregion - - #region Simple Widgets - - if (s_hasSimpleWidgets.HasValue && s_hasSimpleWidgets.Value == false) - { - yield break; - } - - if (!s_hasSimpleWidgets.HasValue) - { - InitSimpleWidgetsMap(_simpleWidgets.Value); - if (s_hasSimpleWidgets.Value == false) - { - yield break; - } - } - - if (s_simpleWidgetsMap.ContainsKey(widgetZone)) - { - var widgetNames = s_simpleWidgetsMap[widgetZone]; - foreach (var widgetName in widgetNames) - { - // Simple widgets has been registered with their type full names before - var simpleWidget = EngineContext.Current.Resolve(widgetName); - if (simpleWidget != null) - { - simpleWidget.GetDisplayWidgetRoute(widgetZone, model, storeId, out actionName, out controllerName, out routeValues); - - yield return new WidgetRouteInfo - { - ActionName = actionName, - ControllerName = controllerName, - RouteValues = routeValues - }; - } - } - } - - #endregion - } - - #region Simple Widgets - - private static void InitSimpleWidgetsMap(IEnumerable widgets) - { - lock (_lock) - { - if (!s_hasSimpleWidgets.HasValue) // double check - { - if (!widgets.Any()) - { - s_hasSimpleWidgets = false; - return; - } - - var map = new Multimap(); - - foreach (var widget in widgets) - { - var zones = widget.GetWidgetZones(); - if (zones != null & zones.Any()) - { - foreach (var zone in zones.Select(x => x.ToLower())) - { - int ordinal = 0; - var ordered = widget as IOrdered; - if (ordered != null) - { - ordinal = ordered.Ordinal; - } - map.Add(zone, new SimpleWidgetStub { Widget = widget, Ordinal = ordinal }); - } - } - } - - var orderedMap = from x in map - select new KeyValuePair>( - x.Key, - x.Value.OrderBy(w => w.Ordinal).Select(w => w.Widget.GetType().FullName)); - - s_simpleWidgetsMap = new ConcurrentDictionary>(orderedMap.ToList(), StringComparer.InvariantCultureIgnoreCase); - - s_hasSimpleWidgets = s_simpleWidgetsMap.Count > 0; - } - } - } - - class SimpleWidgetStub - { - public IWidget Widget { get; set; } - public int Ordinal { get; set; } } class TopicWidgetStub @@ -252,15 +214,15 @@ class TopicWidgetStub public int Id { get; set; } public string[] WidgetZones { get; set; } public string SystemName { get; set; } + public bool WrapContent { get; set; } public bool ShowTitle { get; set; } public bool Bordered { get; set; } public string Title { get; set; } + public string TitleTag { get; set; } public string Body { get; set; } public int Priority { get; set; } } - #endregion - } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Infrastructure/DependencyRegistrar.cs b/src/Presentation/SmartStore.Web/Infrastructure/DependencyRegistrar.cs index 8895154853..64e3eab915 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/DependencyRegistrar.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/DependencyRegistrar.cs @@ -26,7 +26,9 @@ public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, b builder.RegisterType().WithStaticCache(); builder.RegisterType().WithStaticCache(); - builder.RegisterType().As().WithStaticCache().InstancePerRequest(); + builder.RegisterType().InstancePerRequest(); + + builder.RegisterType().As().InstancePerRequest(); // installation localization service builder.RegisterType().As().InstancePerRequest(); diff --git a/src/Presentation/SmartStore.Web/Infrastructure/GenericUrlRouteProvider.cs b/src/Presentation/SmartStore.Web/Infrastructure/GenericUrlRouteProvider.cs deleted file mode 100644 index 458f5bd37f..0000000000 --- a/src/Presentation/SmartStore.Web/Infrastructure/GenericUrlRouteProvider.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Localization; -using SmartStore.Web.Framework.Mvc.Routes; -using SmartStore.Web.Framework.Seo; - -namespace SmartStore.Web.Infrastructure -{ - public partial class GenericUrlRouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - //generic URLs - routes.MapGenericPathRoute("GenericUrl", - "{generic_se_name}", - new { controller = "Common", action = "GenericUrl" }, - new[] { "SmartStore.Web.Controllers" }); - - //define this routes to use in UI views (in case if you want to customize some of them later) - routes.MapLocalizedRoute("Product", - "{SeName}", - new { controller = "Catalog", action = "Product" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("Category", - "{SeName}", - new { controller = "Catalog", action = "Category" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("Manufacturer", - "{SeName}", - new { controller = "Catalog", action = "Manufacturer" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("NewsItem", - "{SeName}", - new { controller = "News", action = "NewsItem" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("BlogPost", - "{SeName}", - new { controller = "Blog", action = "BlogPost" }, - new[] { "SmartStore.Web.Controllers" }); - - //the last route. it's used when none of registered routes could be used for the current request - //but it this case we cannot process non-registered routes (/controller/action) - //routes.MapLocalizedRoute( - // "PageNotFound-Wildchar", - // "{*url}", - // new { controller = "Common", action = "PageNotFound" }, - // new[] { "SmartStore.Web.Controllers" }); - - } - - public int Priority - { - get - { - //it should be the last route - //we do not set it to -int.MaxValue so it could be overriden (if required) - return -1000000; - } - } - } -} diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs index be36a712b0..3896e5c829 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/DeDESeedData.cs @@ -1,35 +1,28 @@ using System; -using System.Linq; -using System.Linq.Expressions; using System.Collections.Generic; -using System.IO; -using SmartStore.Core; +using System.Linq; using SmartStore.Core.Configuration; -using SmartStore.Core.Domain; using SmartStore.Core.Domain.Blogs; +using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Cms; using SmartStore.Core.Domain.Common; +using SmartStore.Core.Domain.Customers; using SmartStore.Core.Domain.Directory; using SmartStore.Core.Domain.Discounts; -using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.Forums; using SmartStore.Core.Domain.Localization; using SmartStore.Core.Domain.Logging; +using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Messages; using SmartStore.Core.Domain.News; +using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Polls; -using SmartStore.Core.Domain.Tax; -using SmartStore.Core.Domain.Topics; using SmartStore.Core.Domain.Seo; -using SmartStore.Core.Domain.Orders; using SmartStore.Core.Domain.Shipping; -using SmartStore.Core.Domain.Tasks; -using SmartStore.Core.Domain.Payments; -using SmartStore.Core.Infrastructure; -using SmartStore.Core.Data; -using SmartStore.Core.Domain.Customers; -using SmartStore.Core.Domain.Catalog; using SmartStore.Core.Domain.Stores; -using SmartStore.Core.Domain.Media; +using SmartStore.Core.Domain.Tasks; +using SmartStore.Core.Domain.Tax; +using SmartStore.Core.Domain.Topics; using SmartStore.Data.Setup; namespace SmartStore.Web.Infrastructure.Installation @@ -46,14 +39,18 @@ protected override void Alter(Customer entity) { base.Alter(entity); - if (entity.SystemName == "builtin@search-engine-record.com") + if (entity.SystemName == SystemCustomerNames.SearchEngine) { - entity.AdminComment = "System Gastkonto für Suchmaschinenanfragen."; + entity.AdminComment = "System-Gastkonto für Suchmaschinenanfragen."; } - else if (entity.SystemName == "builtin@background-task-record.com") + else if (entity.SystemName == SystemCustomerNames.BackgroundTask) { - entity.AdminComment = "System Konto für geplante Aufgaben."; + entity.AdminComment = "Systemkonto für geplante Aufgaben."; } + else if (entity.SystemName == SystemCustomerNames.PdfConverter) + { + entity.AdminComment = "Systemkonto für den PDF-Konverter."; + } } protected override void Alter(IList entities) @@ -135,7 +132,7 @@ protected override void Alter(IList entities) { base.Alter(entities); - string cssString = @""; + string cssString = @""; string templateHeader = cssString + "
          "; string templateFooter = "
          "; @@ -261,7 +258,7 @@ protected override void Alter(IList entities) .Alter("ReturnRequestStatusChanged.CustomerNotification", x => { x.Subject = "%Store.Name%. Rücksendung - Status-Änderung"; - x.Body = templateHeader + "

          %Store.Name% 

          Hallo %Customer.FullName%,

          der Status Ihrer Rücksendung #%ReturnRequest.ID% wurde aktualisiert.

          Mit freundlichen Grüßen,

          Ihr %Store.Name% - Team

          " + templateFooter; + x.Body = templateHeader + "

          %Store.Name% 

          Hallo %Customer.FullName%,

          der Status Ihrer Rücksendung #%ReturnRequest.ID% wurde aktualisiert: %ReturnRequest.Status%

          Mit freundlichen Grüßen,

          Ihr %Store.Name% - Team

          " + templateFooter; }) .Alter("Service.EmailAFriend", x => { @@ -286,7 +283,7 @@ protected override void Alter(IList entities) .Alter("Product.AskQuestion", x => { x.Subject = "%Store.Name% - Frage zu '%Product.Name%' von %ProductQuestion.SenderName%"; - x.Body = templateHeader + "

          %ProductQuestion.Message%

          %ProductQuestion.Message%

          ID: %Product.ID%
          SKU: %Product.Sku%
          Email: %ProductQuestion.SenderEmail%
          Name: %ProductQuestion.SenderName%
          Telefon: %ProductQuestion.SenderPhone%

          " + templateFooter; + x.Body = templateHeader + "

          %ProductQuestion.Message%

          ID: %Product.ID%
          SKU: %Product.Sku%
          Email: %ProductQuestion.SenderEmail%
          Name: %ProductQuestion.SenderName%
          Telefon: %ProductQuestion.SenderPhone%

          " + templateFooter; }) @@ -367,8 +364,7 @@ protected override void Alter(IList entities) protected override void Alter(Address entity) { base.Alter(entity); - string addressThreeLetterIsoCode = "DEU"; - var cCountry = base.DbContext.Set().Where(x => x.ThreeLetterIsoCode == addressThreeLetterIsoCode); + var cCountry = base.DbContext.Set().Where(x => x.ThreeLetterIsoCode == "DEU"); entity.FirstName = "Max"; entity.LastName ="Mustermann"; @@ -617,7 +613,7 @@ protected override void Alter(IList entities) }); x.StateProvinces.Add(new StateProvince() { - Name = "Tiral", + Name = "Tirol", Abbreviation = "T", Published = true, DisplayOrder = 1, @@ -2044,11 +2040,6 @@ protected override void Alter(IList entities) x.Title = "Versand und Rücksendungen"; x.Body = "

          Informationen zu Versand und Rücksendungen. Sie können diese in der Admin-Seite zu bearbeiten.

          "; }) - .Alter("PageNotFound", x => - { - x.Title = ""; - x.Body = "

          Die von Ihnen angeforderte Seite wurde nicht gefunden, und wir haben eine Vermutung, warum:

          • Wenn Sie die URL direkt eingetippt haben, stellen Sie sicher, dass die Schreibweise korrekt ist.
          • Die Seite existiert nicht mehr.

          "; - }) .Alter("Imprint", x => { x.Title = "Impressum"; @@ -2114,12 +2105,6 @@ protected override void Alter(IList settings) x.BaseWeightId = base.DbContext.Set().Where(m => m.SystemKeyword == "kg").Single().Id; }) - .Alter(x => - { - x.PrimaryStoreCurrencyId = base.DbContext.Set().Where(c => c.CurrencyCode == "EUR").Single().Id; - x.PrimaryExchangeRateCurrencyId = base.DbContext.Set().Where(c => c.CurrencyCode == "EUR").Single().Id; - }) - .Alter(x => { x.DefaultTitle = "Mein Shop"; @@ -2127,8 +2112,8 @@ protected override void Alter(IList settings) .Alter(x => { - x.ReturnRequestActions = new List() { "Reparatur", "Ersatz", "Gutschein" }; - x.ReturnRequestReasons = new List() { "Falschen Artikel erhalten", "Falsch bestellt", "Ware fehlerhaft bzw. defekt" }; + x.ReturnRequestActions = "Reparatur,Ersatz,Gutschein"; + x.ReturnRequestReasons = "Falschen Artikel erhalten,Falsch bestellt,Ware fehlerhaft bzw. defekt"; x.NumberOfDaysReturnRequestAvailable = 14; }) @@ -2180,7 +2165,7 @@ protected override void Alter(IList settings) Published = true, Text = "mehr...", Type = "btn-primary", - Url = "~/apple-iphone-5-32-gb", + Url = "~/apple-iphone-6", }, Button2 = new ContentSliderButtonSettings @@ -2188,7 +2173,7 @@ protected override void Alter(IList settings) Published = true, Text = "Jetzt Kaufen", Type = "btn-danger", - Url = "~/apple-iphone-5-32-gb" + Url = "~/apple-iphone-6" }, Button3 = new ContentSliderButtonSettings { @@ -2527,30 +2512,38 @@ protected override void Alter(IList entities) { base.Alter(entities); - entities.WithKey(x => x.Name) - .Alter("Send emails", x => + entities.WithKey(x => x.Type) + .Alter("SmartStore.Services.Messages.QueuedMessagesSendTask, SmartStore.Services", x => { x.Name = "E-Mail senden"; }) - .Alter("Keep alive", x => - { - x.Name = "Keep alive"; - }) - .Alter("Delete guests", x => + .Alter("SmartStore.Services.Messages.QueuedMessagesClearTask, SmartStore.Services", x => + { + x.Name = "E-Mail Queue bereinigen"; + }) + .Alter("SmartStore.Services.Media.TransientMediaClearTask, SmartStore.Services", x => + { + x.Name = "Temporäre Uploads bereinigen"; + }) + .Alter("SmartStore.Services.Customers.DeleteGuestsTask, SmartStore.Services", x => { x.Name = "Gastbenutzer löschen"; }) - .Alter("Clear cache", x => + .Alter("SmartStore.Services.Caching.ClearCacheTask, SmartStore.Services", x => { x.Name = "Cache bereinigen"; }) - .Alter("Send emails", x => + .Alter("SmartStore.Services.Messages.QueuedMessagesSendTask, SmartStore.Services", x => { x.Name = "E-Mail senden"; }) - .Alter("Update currency exchange rates", x => + .Alter("SmartStore.Services.Directory.UpdateExchangeRateTask, SmartStore.Services", x => { x.Name = "Wechselkurse aktualisieren"; + }) + .Alter("SmartStore.Services.Common.TempFileCleanupTask, SmartStore.Services", x => + { + x.Name = "Temporäre Dateien bereinigen"; }); } @@ -2929,12 +2922,21 @@ protected override void Alter(IList entities) .Alter("Game", x => { x.Name = "Spiel"; + }) + .Alter("iPhone color", x => + { + x.Name = "Farbe"; + }) + .Alter("Memory capacity", x => + { + x.Name = "Speicherkapazität"; }); } protected override void Alter(IList entities) { base.Alter(entities); + entities.WithKey(x => x.ProductAttribute.Alias) .Alter("Color", x => @@ -2942,6 +2944,11 @@ protected override void Alter(IList entities) x.ProductVariantAttributeValues.First(v => v.Alias == "black").Name = "Schwarz"; x.ProductVariantAttributeValues.First(v => v.Alias == "white").Name = "Weiß"; }) + .Alter("iPhone color", x => + { + x.ProductVariantAttributeValues.First(v => v.Alias == "silver").Name = "Silber"; + x.ProductVariantAttributeValues.First(v => v.Alias == "spacegray").Name = "Space-Grau"; + }) .Alter("Game", x => { x.ProductVariantAttributeValues.First(v => v.Alias == "Prince of Persia \"The Forgotten Sands\"").Name = "Prince of Persia \"Die vergessene Zeit\""; @@ -3049,24 +3056,18 @@ protected override void Alter(IList entities) #region variables string ps3FullDescription = "
          Prozessortyp Cell Processor 
          Arbeitsspeicher (RAM)nbsp;256 MB 
          Grafikchipsatz nVidia RSX 
          Taktfrequenz 3.200 MHz 
          Abmessungen 290 x 60 x 230 mm 
          Gewicht 2.100 g 
          Speichermedium Blu-ray 
          Stromverbrauch in Betrieb 190 Watt 
          Plattform Playstation 3 (PS3) 
          Akku-Laufzeit 0 h 
          Anschlüsse 2x USB 2.0, AV-Ausgang, digitaler optischer Ausgang (SPDIF), HDMI 
          Soundmodi AAC, Dolby igital, Dolby Digital Plus, Dolby TrueHD, DTS, DTS-HD, LPCM 7.1-Kanal 
          Unterstützte Auflösungen 576i, 576p, 720p, 1080i, 1080p Full HD 
          Serie Sony Playstation 3 
          Veröffentlichungsjahr 2012 
          Mitgelieferte Hardware Dual Shock 3-Controller 
          Farbe schwarz 
          USK-Freigabe 0 Jahre 
          PEGI-Freigabe 3 Jahre 
          RAM-Typ XDR-DRAM 
          Controller-Akku-Laufzeit 30 h 
          WLAN-Standard IEEE 802.11 b/g 
          LAN-Standard Gigabit Ethernet (10/100/1000 Mbit/s) 
          Daten-Kommunikation Bluetooth 2.0 + EDR, Netzwerk (Ethernet), WLAN (Wi-Fi) 
          Controller-Eigenschaften Beschleunigungssensor, Lagesensor (Gyrosensor), Headset-nschluss, Vibration 
          Spielsteuerungen Bewegungssteuerung, Controller 
          Spielfunktionen Community, Kindersicherung, Plattformübergreifendes Spielen, Remote Gaming, Sony PlayStation Network, Sony PlayStation Plus, Streaming (DLNA), Streaming (PlayStation Now/Gaikai) 
          Marketplace Sony PlayStation Store 
          Internetfunktionen Chat, Video Chat, Voice Chat, Webbrowser 
          Multimedia-Funktionen Audio-CD-Wiedergabe, Blu-ray-Wiedergabe, DVD-Wiedergabe, Internet-Radio, Video-Wiedergabe 
          Streaming-ienste Animax, Lovefilm, Maxdome, Mubi, Music on Demand, Sony Music Unlimited, Sony Video Unlimited, TuneIn, VidZone, Video on Demand, Watchever, YouTube 
          Ausstattungonlinefähig/eingebautes Netzteil/3D-Ready
          Sonstigesbis zu 7 kabellose lageempfindliche Controller (Bluetooth) / PSP-Connectivity / keine Abwärtskompatibilität zu PlayStation 2-Spielen / Herunterladen von Filmen von Hollywood Studios aus dem Playstation Network, übertragbar auf PSP / Toploader-Laufwerk / Cross-Plattform-Funktionen (PS3 und PS Vita): Remote Play (Zugriff auf kompatible Inhalte auf PS3), Cross Buy (Spiel für anderes System kostenlos oder günstiger (online) dazukaufen), Cross-Goods (In-Game-Objekte für beide Systeme), Cross-Save (gespeichertes Spiel auf anderem System weiterspielen), Cross-Controller (PS Vita als Controller), Cross-Play (PSV vs. PS3), PlayStation Network-Konto erforderlich / 256 MB GDDR3 Grafikspeicher 
          "; - string ps4FullDescription = "
          • PlayStation 4, die neueste Generation des Entertainment Systems, definiert reichhaltiges und beeindruckendes Gameplay, völlig neu.
          • Den Kern der PS4 bilden ein leistungsstarker, eigens entwickelter Chip mit acht x86-Kernen (64 bit) sowie ein hochmoderner optimierter Grafikprozessor.
          • Ein neuer, hochsensibler SIXAXIS-Sensor ermöglicht mit dem DualShock 4 Wireless Controller eine erstklassige Bewegungssteuerung.
          • Der DualShock 4 bietet als Neuerungen ein Touchpad, eine Share-Taste, einen eingebauten Lautsprecher und einen Headset-Anschluss.
          • PS4 integriert Zweitbildschirme, darunter PS Vita, Smartphones und Tablets, damit Spieler ihre Lieblingsinhalte überall hin mitnehmen können.
          "; #endregion variables entities.WithKey(x => x.MetaTitle) + # region category Gift Cards -.Alter("$5 Virtual Gift Card", x => + .Alter("$5 Virtual Gift Card", x => { x.Name = "5 € Geschenkgutschein"; x.ShortDescription = "5 € Geschenkgutschein. Eine ideale Geschenkidee."; x.FullDescription = "

          Wenn in letzter Minute mal wieder ein Geschenk fehlt oder man nicht weiß, was man schenken soll, dann bietet sich der Kauf eines Geschenkgutscheins an.

          "; - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Geschenkgutscheine").Single(), - DisplayOrder = 1, - }); }) .Alter("$25 Virtual Gift Card", x => @@ -3074,12 +3075,6 @@ protected override void Alter(IList entities) x.Name = "25 € Geschenkgutschein"; x.ShortDescription = "25 € Geschenkgutschein. Eine ideale Geschenkidee."; x.FullDescription = "

          Wenn in letzter Minute mal wieder ein Geschenk fehlt oder man nicht weiß, was man schenken soll, dann bietet sich der Kauf eines Geschenkgutscheins an.

          "; - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Geschenkgutscheine").Single(), - DisplayOrder = 1, - }); }) .Alter("$50 Virtual Gift Card", x => @@ -3087,12 +3082,6 @@ protected override void Alter(IList entities) x.Name = "50 € Geschenkgutschein"; x.ShortDescription = "50 € Geschenkgutschein. Eine ideale Geschenkidee."; x.FullDescription = "

          Wenn in letzter Minute mal wieder ein Geschenk fehlt oder man nicht weiß, was man schenken soll, dann bietet sich der Kauf eines Geschenkgutscheins an.

          "; - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Geschenkgutscheine").Single(), - DisplayOrder = 1, - }); }) #endregion @@ -3100,7 +3089,7 @@ protected override void Alter(IList entities) #region Bücher #region SPIEGEL-Bestseller -.Alter("Überman: The novel", x => + .Alter("Überman: The novel", x => { x.Name = "Überman: Der Roman"; x.ShortDescription = "Gebundene Ausgabe"; @@ -3118,28 +3107,15 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "SPIEGEL-Bestseller").Single(), - DisplayOrder = 1, - }); }) #endregion SPIEGEL-Bestseller #region Kochen & Genießen -.Alter("Best Grilling Recipes", x => + .Alter("Best Grilling Recipes", x => { x.ShortDescription = "Mehr als 100 regionale Favoriten Grill-Rezepte getestet und und für den Freiluft-Koch perfektioniert"; - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Kochen und Genießen").Single(), - DisplayOrder = 1, - }); x.Price = 16.99M; x.DeliveryTime = base.DbContext.Set().Where(dt => dt.DisplayOrder == 0).Single(); x.TaxCategoryId = base.DbContext.Set().Where(tc => tc.Name == TaxNameBooks).Single().Id; @@ -3174,19 +3150,12 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Kochen und Genießen").Single(), - DisplayOrder = 1, - }); }) #endregion Kochen & Genießen #region Books : cars and motorcycles -.Alter("Car of superlatives", x => + .Alter("Car of superlatives", x => { x.Name = "Autos der Superlative: Die Stärksten, die Ersten, die Schönsten, Die Schnellsten"; x.ShortDescription = "Gebundene Ausgabe"; @@ -3204,13 +3173,6 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Bücher").Single(), - DisplayOrder = 1, - }); }) .Alter("Picture Atlas Motorcycles", x => @@ -3231,13 +3193,6 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Bücher").Single(), - DisplayOrder = 1, - }); }) .Alter("The Car Book", x => @@ -3258,13 +3213,6 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Bücher").Single(), - DisplayOrder = 1, - }); }) .Alter("Fast Cars", x => @@ -3285,13 +3233,6 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Bücher").Single(), - DisplayOrder = 1, - }); }) .Alter("Motorcycle Adventures", x => @@ -3312,13 +3253,6 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Bücher").Single(), - DisplayOrder = 1, - }); }) #endregion Books : cars and motorcycles @@ -3330,7 +3264,7 @@ protected override void Alter(IList entities) #region computer-desktops #region Dell Inspiron One 23 -.Alter("Dell Inspiron One 23", x => + .Alter("Dell Inspiron One 23", x => { x.ShortDescription = "Dieser 58 cm (23'')-All-in-One-PC mit Full HD, Windows 8 und leistungsstarken Intel® Core™ Prozessoren der dritten Generation ermöglicht eine praktische Interaktion mit einem Touchscreen."; x.FullDescription = "

          Extrem leistungsstarker All-in-One PC mit Windows 8, Intel® Core™ i7 Prozessor, riesiger 2TB Festplatte und Blu-Ray Laufwerk.

          Intel® Core™ i7-3770S Prozessor ( 3,1 GHz, 6 MB Cache) Windows 8 64bit , Deutsch
          8 GB1 DDR3 SDRAM bei 1600 MHz
          2 TB-Serial ATA-Festplatte (7.200 U/min)
          1GB AMD Radeon HD 7650

          "; @@ -3347,18 +3281,11 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Desktop Computer").Single(), - DisplayOrder = 1, - }); }) #endregion Dell Inspiron One 23 #region Dell Optiplex 3010 DT Base -.Alter("Dell Optiplex 3010 DT Base", x => + .Alter("Dell Optiplex 3010 DT Base", x => { x.ShortDescription = "SONDERANGEBOT: Zusätzliche 50 € Rabatt auf alle Dell OptiPlex Desktops ab einem Wert von 549 €. Online-Coupon: W8DWQ0ZRKTM1, gültig bis 4.12.2013"; x.FullDescription = "

          Ebenfalls im Lieferumfang dieses Systems enthalten

          1 Jahr Basis-Service - Vor-Ort-Service am nächsten Arbeitstag - kein Upgrade ausgewählt Keine Asset-Tag erforderlich

          Die folgenden Optionen sind in Ihren Auftrag aufgenommene Standardauswahlen.
          German (QWERTZ) Dell KB212-B QuietKey USB Keyboard Black
          X11301001
          WINDOWS LIVE
          OptiPlex™ Bestellung - Deutschland
          OptiPlex™ Intel® Core™ i3 Aufkleber
          Optische Software nicht erforderlich, Betriebssystemsoftware ausreichend

          "; @@ -3375,27 +3302,18 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Desktop Computer").Single(), - DisplayOrder = 1, - }); }) #endregion Dell Optiplex 3010 DT Base - #endregion computer-desktops #region Notebooks #region Acer Aspire One 8.9 -.Alter("Acer Aspire One 8.9", x => + .Alter("Acer Aspire One 8.9", x => { x.Name = "Acer Aspire One 8.9\" Mini-Notebook Case - (Schwarz)"; x.ShortDescription = "Acer definiert mit dem Aspire One mobile Konnektivität neu, dem revolutionären Spaß und Power Netbook in der zierlichen 8.9\" Größe. "; - x.FullDescription = "

          Von der Betätigung des Powerknopfes an, ist das Aspire One in nur wenigen Sekunden betriebsbereit. Sobald an, ist die Arbeit sehr einfach: ein Heimarbeitsplatz der die heute benötigten vier Bereiche abdeckt, verbunden bleiben, arbeiten, spielen und Ihr Leben unterwegs organisieren. Und der Aspire One ist etwas Besonderes, Sie können alles so individualisieren das es für Sie das Richtige ist. Schnell, einfach und unbeschreiblich schick. Ihr Style ist Ihre Unterschrift. Es ist Ihre Identität, Ihre Persönlichkeit und Ihre Visitenkarte. Ihr Style zeigt Ihrer Umwelt wie Sie sind und wie Sie Ihr Leben leben, online und offline. Das alles benötigen Sie, um Sie selbst zu sein. Ihr Style kommt in verschiedenen Farben, jede mit einem individuellen Charakter. Kleiner als ein durchschnittliches Tagebuch, das Aspire One bringt Freiheit in Ihre Hände.

          Allgemein
          Betriebssystem: Microsoft Windows XP Home Edition, Linux Linpus Lite
          Herstellergarantie: 1 Jahr Garantie
          Systemtyp: Netbook
          MPN: LU.S080B.069, LU.S050B.081, LU.S040B.079, LU.S090B.079, LU.S040B.198, LU.S040A.048, LU.S050A.050, LU.S050B.080, LU.S040B.078, 099915639, LU.S050A.074, LU.S360A.203, LU.S450B.030, LU.S050B.159
          Speicher
          RAM: 1 GB ( 1 x 512 MB + 512 MB (integriert) ), 1 GB
          Max. unterstützter RAM-Speicher: 1.5 GB
          Technologie: DDR2 SDRAM
          Geschwindigkeit: 533 MHz
          Formfaktor: SO DIMM 200-polig
          Anz. Steckplätze: 1
          Leere Steckplätze: 0, 1
          Display
          Typ: 22.6 cm ( 8.9\" )
          Auflösung: 1024 x 600 ( WSVGA )
          Breitwand: Ja
          LCD-Hintergrundbeleuchtung: LED-Hintergrundbeleuchtung
          Farbunterstützung: 262.144 Farben, 24 Bit (16,7 Millionen Farben)
          Besonderheiten: CrystalBrite
          Batterie
          Betriebszeit: Bis zu 7 Stunden, Bis zu 3 Stunden
          Kapazität: 2600 mAh, 2200 mAh
          Technologie: 6 Zellen Lithium-Ionen, 3 Zellen Lithium-Ionen, Lithium-Ionen
          Herstellergarantie
          Service & Support:
          Reisegarantie - 1 Jahr, Begrenzte Garantie - 1 Jahr, Internationale Garantie - 1 Jahr
          Begrenzte Garantie - 1 Jahr, Reisegarantie - 1 Jahr
          Begrenzte Garantie - 1 Jahr, Begrenzte Garantie - 1 Jahr
          Reisegarantie - 1 Jahr
          Navigation
          Empfänger: GPS

          "; - + x.FullDescription = "

          Von der Betätigung des Powerknopfes an, ist das Aspire One in nur wenigen Sekunden betriebsbereit. Sobald an, ist die Arbeit sehr einfach: ein Heimarbeitsplatz der die heute benötigten vier Bereiche abdeckt, verbunden bleiben, arbeiten, spielen und Ihr Leben unterwegs organisieren. Und der Aspire One ist etwas Besonderes, Sie können alles so individualisieren das es für Sie das Richtige ist. Schnell, einfach und unbeschreiblich schick. Ihr Style ist Ihre Unterschrift. Es ist Ihre Identität, Ihre Persönlichkeit und Ihre Visitenkarte. Ihr Style zeigt Ihrer Umwelt wie Sie sind und wie Sie Ihr Leben leben, online und offline. Das alles benötigen Sie, um Sie selbst zu sein. Ihr Style kommt in verschiedenen Farben, jede mit einem individuellen Charakter. Kleiner als ein durchschnittliches Tagebuch, das Aspire One bringt Freiheit in Ihre Hände.

          Allgemein
          Betriebssystem: Microsoft Windows XP Home Edition, Linux Linpus Lite
          Herstellergarantie: 1 Jahr Garantie
          Systemtyp: Netbook
          MPN: LU.S080B.069, LU.S050B.081, LU.S040B.079, LU.S090B.079, LU.S040B.198, LU.S040A.048, LU.S050A.050, LU.S050B.080, LU.S040B.078, 099915639, LU.S050A.074, LU.S360A.203, LU.S450B.030, LU.S050B.159
          Speicher
          RAM: 1 GB ( 1 x 512 MB + 512 MB (integriert) ), 1 GB
          Max. unterstützter RAM-Speicher: 1.5 GB
          Technologie: DDR2 SDRAM
          Geschwindigkeit: 533 MHz
          Formfaktor: SO DIMM 200-polig
          Anz. Steckplätze: 1
          Leere Steckplätze: 0, 1
          Display
          Typ: 22.6 cm ( 8.9\" )
          Auflösung: 1024 x 600 ( WSVGA )
          Breitwand: Ja
          LCD-Hintergrundbeleuchtung: LED-Hintergrundbeleuchtung
          Farbunterstützung: 262.144 Farben, 24 Bit (16,7 Millionen Farben)
          Besonderheiten: CrystalBrite
          Batterie
          Betriebszeit: Bis zu 7 Stunden, Bis zu 3 Stunden
          Kapazität: 2600 mAh, 2200 mAh
          Technologie: 6 Zellen Lithium-Ionen, 3 Zellen Lithium-Ionen, Lithium-Ionen
          Herstellergarantie
          Service & Support:
          Reisegarantie - 1 Jahr, Begrenzte Garantie - 1 Jahr, Internationale Garantie - 1 Jahr
          Begrenzte Garantie - 1 Jahr, Reisegarantie - 1 Jahr
          Begrenzte Garantie - 1 Jahr, Begrenzte Garantie - 1 Jahr
          Reisegarantie - 1 Jahr
          Navigation
          Empfänger: GPS

          "; x.Price = 210.60M; x.DeliveryTime = base.DbContext.Set().Where(dt => dt.DisplayOrder == 0).Single(); x.TaxCategoryId = base.DbContext.Set().Where(tc => tc.Name == "Normal").Single().Id; @@ -3409,27 +3327,21 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Notebook").Single(), - DisplayOrder = 1, - }); }) #endregion Acer Aspire One 8.9 #endregion Notebooks - #endregion computer #region SmartPhones - #region Apple iPhone 5 32 GB -.Alter("Apple iPhone 5 32 GB", x => + + #region Apple iPhone + + .Alter("Apple iPhone 6", x => { - x.ShortDescription = "Apple iPhone 5 32 GB Simlock frei Neu Schwarz/Graphit"; - x.FullDescription = "

          Neues Design.
          Mit 7,6 mm und 112 g2 hat das iPhone 5 ein bemerkenswert dünnes und leichtes Design. Es ist aus eloxiertem Aluminium gefertigt. Die abgeschrägten Kanten wurden präzise mit einem Diamanten geschnitten.

          Brillantes 4\" Retina Display.
          Jetzt siehst du alles noch lebendiger und detailreicher. Und obwohl das Display größer ist, hat es die gleiche Breite wie das iPhone 4S und lässt sich daher ebenso leicht mit einer Hand bedienen.

          Leistungsstarker A6 Chip.
          Verglichen mit dem A5 Chip hat er die bis zu doppelte CPU- und Grafikleistung. Und trotz seiner Geschwindigkeit hat das iPhone 5 eine fantastische Batterielaufzeit.

          "; + x.ShortDescription = "Apple iPhone 6 Simlock frei Neu"; + x.FullDescription = "

          Das iPhone 6 ist nicht einfach nur größer. Es ist wirklich in allem besser. Es ist länger und breiter, aber deutlich dünner. Leistungsstärker, aber unglaublich energieeffizient. Seine glatte Oberfläche aus Metall schließt nahtlos an das neue Retina HD Display an. So entsteht eine durchgehende Form, in der Hardware und Software in perfekter Einheit zusammenarbeiten – für eine neue iPhone Generation, die nach allen Maßstäben besser ist.

          Das iPhone 6 kommt mit einem A8 Chip auf Basis einer 64 Bit Desktoparchitektur der zweiten Generation. Seine unglaubliche Leistung wird durch einen M8 Motion Coprozessor erweitert, der Aktivität mit fortschrittlichen Sensoren ermittelt, darunter auch ein neues Barometer.

          Mit keiner anderen Kamera werden von so vielen Menschen so viele Fotos gemacht wie mit dem iPhone. Jetzt hat die iSight Kamera einen neuen Sensor mit Focus Pixels und neue Videofunktionen wie 1080p HD Videos mit 60 Bildern pro Sekunde, Zeitlupenvideos mit 240 Bildern pro Sekunde und Zeitraffervideo.

          • Abmessungen (HxBxT) 138.1 x 67 x 6.9 Millimeter
          • Gewicht 129 Gramm
          • Strahlungswert (SAR-Wert) unbekannt
          • Erscheinungstermin 09/2014
          • Betriebssystem Apple iOS
          • Systemversion 8.0
          • Netzstandards GSM1800 GSM1900 GSM850 GSM900W-CDMA (UMTS)
          • Flugzeugmodus ja
          • Akku-Typ Li-Ionen
          • Akkuleistung 1810 mAh
          • max. Bereitschaftszeit 250 Stunden
          • max. Sprechzeit 840 Minuten

          "; x.Price = 579.00M; x.DeliveryTime = base.DbContext.Set().Where(dt => dt.DisplayOrder == 0).Single(); x.TaxCategoryId = base.DbContext.Set().Where(tc => tc.Name == "Normal").Single().Id; @@ -3443,75 +3355,33 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Smartphones").Single(), - DisplayOrder = 1, - }); x.ProductReviews.Clear(); - //x.ProductReviews.Add(new ProductReview() - //{ - // Rating = 5, - // Title = "Das original ist immer noch das Beste!!!", - // IsApproved = true, - // ReviewText = "

          Das iPhone 5 ist das beste iPhone aller Zeiten. Es hat alle Funktionen die ein Smartphone braucht, und ist dabei noch schön handlich." - //}); - }) - #endregion Apple iPhone 5 32 GB + #endregion Apple iPhone + #endregion SmartPhones #region Instant Downloads - #region Antonio Vivildi: then spring -.Alter("Antonio Vivaldi: spring", x => + + #region Antonio Vivildi: then spring + + .Alter("Antonio Vivaldi: spring", x => { x.Name = "Antonio Vivaldi: Der Frühling"; x.ShortDescription = "MP3, 320 kbit/s"; x.FullDescription = "

          Antonio Vivaldi: Der Frühling

          Antonio Lucio Vivaldi (* 4. März 1678 in Venedig; † 28. Juli 1741 in Wien) war ein venezianischer Komponist und Violinist im Barock.

          Die vier Jahreszeiten (italienisch Le quattro stagioni) heißt das wohl bekannteste Werk Antonio Vivaldis. Es handelt sich um vier Violinkonzerte mit außermusikalischen Programmen; jedes Konzert porträtiert eine Jahreszeit. Dazu ist den einzelnen Konzerten jeweils ein – vermutlich von Vivaldi selbst geschriebenes – Sonett vorangestellt; fortlaufende Buchstaben vor den einzelnen Zeilen und an den entsprechenden Stellen in der Partitur ordnen die verbale Beschreibung der Musik zu.

          Vivaldi hatte bereits zuvor immer wieder mit außermusikalischen Programmen experimentiert, die sich häufig in seinen Titeln niederschlagen; die genaue Ausdeutung von Einzelstellen der Partitur ist aber für ihn ungewöhnlich. Seine Erfahrung als virtuoser Geiger erlaubte ihm den Zugriff auf besonders wirkungsvolle Spieltechniken; als Opernkomponist hatte er einen starken Sinn für Effekte entwickelt; beides kam ihm hier zugute.

          Wie der Titel bereits nahelegt, werden vor allem Naturerscheinungen imitiert – sanfte Winde, heftige Stürme und Gewitter sind Elemente, die in allen vier Konzerten auftreten. Hinzu kommen verschiedene Vogelstimmen und sogar ein Hund, weiter menschliche Betätigungen wie etwa die Jagd, ein Bauerntanz, das Schlittschuhlaufen einschließlich Stolpern und Hinfallen bis hin zum schweren Schlaf eines Betrunkenen.

          Das Werk stammt aus dem Jahre 1725 und ist in zwei Druckausgaben erhalten, die offenbar mehr oder weniger zeitgleich in Amsterdam und Paris erschienen.


          "; - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Musik kaufen & sofort herunterladen").Single(), - DisplayOrder = 1, - }); x.ProductReviews.Clear(); - //x.ProductReviews.Add(new ProductReview() - //{ - // Rating = 5, - // Title = "Das original ist immer noch das Beste!!!", - // IsApproved = true, - // ReviewText = "

          Das iPhone 5 ist das beste iPhone aller Zeiten. Es hat alle Funktionen die ein Smartphone braucht, und ist dabei noch schön handlich." - //}); - - }) #endregion Antonio Vivildi: then spring #region Beethoven für Elise -.Alter("Ludwig van Beethoven: Für Elise", x => + .Alter("Ludwig van Beethoven: Für Elise", x => { x.Name = "Ludwig van Beethoven: Für Elise"; x.ShortDescription = "Ludwig van Beethoven: Für Elise. Eine von Beethovens populärsten Kompositionen."; x.FullDescription = "

          Die früheste, 1973 bekannt gewordene Fassung der „Kernmelodie“[5] notierte Beethoven 1808 in ein Skizzenbuch zur Pastorale. Einige aus dem Skizzenbuch herausgelöste Seiten bilden heute das Autograph Mus. ms. autograph. Beethoven Landsberg 10 der Staatsbibliothek Preußischer Kulturbesitz in Berlin. Die Melodie, die eindeutig als Kern des Klavierstückes WoO 59 zu erkennen ist,[2] befindet sich in den Zeilen 6 und 7 der Seite 149. Es handelt sich um eine einstimmige, sechzehntaktige Melodie, die sich besonders bei den Auftakten des Mittelteiles und bei den Schlusswendungen der Takte 7 und 15 sowie durch das Fehlen des zweitaktigen Orgelpunktes auf E von späteren Fassungen unterscheidet.[2] Diese Melodie nahm Beethoven 1810 wieder auf, modifizierte sie und fügte ihr weitere Teile hinzu. Das geschah in Beethovens Handschrift BH 116[6] und vermutlich auch in dem Autograph, das zu Babette Bredl gelangte und von Ludwig Nohl abgeschrieben und 1867 erstmals veröffentlicht wurde.[7][8]

          In BH 116 lassen sich drei Arbeitsphasen erkennen: eine erste Niederschrift im Jahre 1810, Korrekturen daran von 1810 und eine Bearbeitung aus dem Jahre 1822. Die Bearbeitung von 1822 hatte das Ziel, das Klavierstück in eine für eine Veröffentlichung taugliche Fassung zu bringen. Es sollte als No 12 den Schluss eines Zyklus von Bagatellen bilden. Dieser Plan wurde allerdings nicht ausgeführt.[9] 1822 überschrieb Beethoven das Klavierstück mit „molto grazioso“. Er verschob die Begleitfiguren des A-Teils in der linken Hand um ein Sechzehntel nach rechts und entlastete dabei den Taktanfang. Außerdem führte er die Begleitfigur teilweise in eine tiefere Lage und weitete damit den Klang aus.[10] Im Teil B kehrte Beethoven zu einer melodisch und rhythmisch komplizierteren, 1810 verworfenen Fassung zurück. Den vermutlichen Gesamtaufbau des Klavierstückes ließ er nicht völlig unangetastet und fügte vier bisher ungenutzte Takte als Überleitung zum Teil B ein. Vier 1822 notierte Einleitungstakte, die zum A-Teil passen, strich er dagegen wieder.[11] Bei der Anweisung für die Reprise des letztmals wiederkehrenden Teiles A schrieb er „una corda“ vor, was sich auf diesen Teil selbst beziehen kann oder nur auf den neu entworfenen, dreitaktigen, wahrscheinlich akkordisch gedachten, aber nur einstimmig notierten Schluss.[12] Eine vollständige Fassung als Resultat der Bearbeitung von 1822 stellte Beethoven nicht her.[13][14]

          "; - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Musik kaufen & sofort herunterladen").Single(), - DisplayOrder = 1, - }); x.ProductReviews.Clear(); - //x.ProductReviews.Add(new ProductReview() - //{ - // Rating = 5, - // Title = "Das original ist immer noch das Beste!!!", - // IsApproved = true, - // ReviewText = "

          Das iPhone 5 ist das beste iPhone aller Zeiten. Es hat alle Funktionen die ein Smartphone braucht, und ist dabei noch schön handlich." - //}); - - }) #endregion Beethoven für Elise @@ -3519,8 +3389,9 @@ protected override void Alter(IList entities) #endregion Instant Downloads #region watches + #region Certina DS Podium Big Size -.Alter("Certina DS Podium Big Size", x => + .Alter("Certina DS Podium Big Size", x => { x.Name = "Certina DS Podium Big Size Herrenchronograph"; x.ShortDescription = "C001.617.26.037.00"; @@ -3538,18 +3409,12 @@ protected override void Alter(IList entities) x.CreatedOnUtc = DateTime.UtcNow; x.UpdatedOnUtc = DateTime.UtcNow; x.IsShipEnabled = true; - - x.ProductCategories.Clear(); - x.ProductCategories.Add(new ProductCategory() - { - Category = base.DbContext.Set().Where(c => c.Name == "Uhren").Single(), - DisplayOrder = 1, - }); x.ProductReviews.Clear(); }) #endregion Certina DS Podium Big Size - #endregion watches + + #endregion watches #region gaming @@ -3696,6 +3561,33 @@ protected override void Alter(IList entities) }); } + protected override void Alter(IList entities) + { + base.Alter(entities); + + entities.WithKey(x => x.DisplayOrder) + .Alter(0, x => + { + x.Name = "Stück"; + x.Description = "Stück"; + }) + .Alter(1, x => + { + x.Name = "Schachtel"; + x.Description = "Schachtel"; + }) + .Alter(2, x => + { + x.Name = "Paket"; + x.Description = "Paket"; + }) + .Alter(3, x => + { + x.Name = "Palette"; + x.Description = "Palette"; + }); + } + protected override void Alter(IList entities) { base.Alter(entities); @@ -3812,7 +3704,7 @@ protected override void Alter(IList entities) base.Alter(entities); entities.WithKey(x => x.MetaTitle) - .Alter("smartstore.net new release!", x => + .Alter("SmartStore.NET new release!", x => { x.Title = "SmartStore.NET - das clevere Shopsystem!"; x.Short = "SmartStore.NET ist die neue dynamische E-Commerce Lösung von SmartStore. SmartStore.NET bietet alle Funktionen und Möglichkeiten, um schnell und einfach einen leistungsfähigen und funktional kompletten Online-Shop zu erstellen."; diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/IInstallationLocalizationService.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/IInstallationLocalizationService.cs index bf0a388f5f..c6908ccc5a 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/IInstallationLocalizationService.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/IInstallationLocalizationService.cs @@ -18,7 +18,6 @@ public partial interface IInstallationLocalizationService IList GetAvailableLanguages(); - // codehint: sm-add IEnumerable GetAvailableAppLanguages(); Lazy GetAppLanguage(string culture); } diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs index 1a641fb43c..4e964cc565 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallDataSeeder.cs @@ -31,6 +31,7 @@ using SmartStore.Data.Migrations; using SmartStore.Services.Stores; using SmartStore.Core.Domain.Orders; +using SmartStore.Web.Framework; namespace SmartStore.Web.Infrastructure.Installation { @@ -84,7 +85,7 @@ private void PopulateTaxCategories() foreach (var id in taxIds) { decimal rate = 0; - if (_data.FixedTaxRates.HasItems() && _data.FixedTaxRates.Length > i) + if (_data.FixedTaxRates.Any() && _data.FixedTaxRates.Length > i) { rate = _data.FixedTaxRates[i]; } @@ -131,73 +132,9 @@ private void PopulateLocaleResources() // already without AutoDetectChanges(), so it's fast. } - ExecutePendingResourceMigrations(locPath); + MigratorUtils.ExecutePendingResourceMigrations(locPath, _ctx); } - private void ExecutePendingResourceMigrations(string resPath) - { - string headPath = Path.Combine(resPath, "head.txt"); - if (!File.Exists(headPath)) - return; - - string resHead = File.ReadAllText(headPath); - if (!MigratorUtils.IsValidMigrationId(resHead)) - return; - - var migrator = new DbMigrator(new MigrationsConfiguration()); - var migrations = GetPendingResourceMigrations(migrator, resHead); - - foreach (var id in migrations) - { - if (MigratorUtils.IsAutomaticMigration(id)) - continue; - - if (!MigratorUtils.IsValidMigrationId(id)) - continue; - - // Resolve and instantiate the DbMigration instance from the assembly - var migration = MigratorUtils.CreateMigrationInstanceByMigrationId(id, migrator.Configuration); - - var provider = migration as ILocaleResourcesProvider; - if (provider == null) - continue; - - var builder = new LocaleResourcesBuilder(); - provider.MigrateLocaleResources(builder); - - var resEntries = builder.Build(); - var resMigrator = new LocaleResourcesMigrator(_ctx); - resMigrator.Migrate(resEntries); - } - } - - private IEnumerable GetPendingResourceMigrations(DbMigrator migrator, string resHead) - { - var local = migrator.GetLocalMigrations(); - var atHead = false; - - if (local.Last().IsCaseInsensitiveEqual(resHead)) - yield break; - - foreach (var id in local) - { - if (!atHead) - { - if (!id.IsCaseInsensitiveEqual(resHead)) - { - continue; - } - else - { - atHead = true; - continue; - } - } - - yield return id; - } - } - private void PopulateCurrencies() { SaveRange(_data.Currencies().Where(x => x != null)); @@ -219,7 +156,7 @@ private void PopulateCustomersAndUsers(string defaultUserEmail, string defaultUs SaveRange(customerRoles.Where(x => x != null)); //admin user - var adminUser = new Customer() + var adminUser = new Customer { CustomerGuid = Guid.NewGuid(), Email = defaultUserEmail, @@ -232,9 +169,11 @@ private void PopulateCustomersAndUsers(string defaultUserEmail, string defaultUs LastActivityDateUtc = DateTime.UtcNow, }; - adminUser.Addresses.Add(_data.AdminAddress()); - adminUser.BillingAddress = _data.AdminAddress(); - adminUser.ShippingAddress = _data.AdminAddress(); + var adminAddress = _data.AdminAddress(); + + adminUser.Addresses.Add(adminAddress); + adminUser.BillingAddress = adminAddress; + adminUser.ShippingAddress = adminAddress; adminUser.CustomerRoles.Add(customerRoles.SingleOrDefault(x => x.SystemName == SystemCustomerRoleNames.Administrators)); adminUser.CustomerRoles.Add(customerRoles.SingleOrDefault(x => x.SystemName == SystemCustomerRoleNames.ForumModerators)); adminUser.CustomerRoles.Add(customerRoles.SingleOrDefault(x => x.SystemName == SystemCustomerRoleNames.Registered)); @@ -245,7 +184,7 @@ private void PopulateCustomersAndUsers(string defaultUserEmail, string defaultUs this.GenericAttributeService.SaveAttribute(adminUser, SystemCustomerAttributeNames.LastName, adminUser.Addresses.FirstOrDefault().LastName); _ctx.SaveChanges(); - // search engine (crawler) built-in user + // Built-in user for search engines (crawlers) var customer = _data.SearchEngineUser(); customer.CustomerRoles.Add(customerRoles.SingleOrDefault(x => x.SystemName == SystemCustomerRoleNames.Guests)); Save(customer); @@ -254,6 +193,11 @@ private void PopulateCustomersAndUsers(string defaultUserEmail, string defaultUs customer = _data.BackgroundTaskUser(); customer.CustomerRoles.Add(customerRoles.SingleOrDefault(x => x.SystemName == SystemCustomerRoleNames.Guests)); Save(customer); + + // Built-in user for the PDF converter + customer = _data.PdfConverterUser(); + customer.CustomerRoles.Add(customerRoles.SingleOrDefault(x => x.SystemName == SystemCustomerRoleNames.Guests)); + Save(customer); } private void HashDefaultCustomerPassword(string defaultUserEmail, string defaultUserPassword) @@ -532,7 +476,8 @@ protected IPictureService PictureService NullEventPublisher.Instance, mediaSettings, new ImageResizerService(), - new ImageCache(mediaSettings, webHelper, null, null)); + new ImageCache(mediaSettings, webHelper, null, null), + new Notifier()); } return _pictureService; @@ -552,6 +497,8 @@ protected ILocalizationService LocalizationService rsResources.AutoCommitEnabled = false; var storeMappingService = new StoreMappingService(NullCache.Instance, null, null, null); + var storeService = new StoreService(NullCache.Instance, new EfRepository(_ctx), NullEventPublisher.Instance); + var storeContext = new WebStoreContext(storeService, new WebHelper(null), null); var locSettings = new LocalizationSettings(); @@ -561,7 +508,9 @@ protected ILocalizationService LocalizationService this.SettingService, locSettings, NullEventPublisher.Instance, - storeMappingService); + storeMappingService, + storeService, + storeContext); _locService = new LocalizationService( NullCache.Instance, @@ -590,6 +539,7 @@ public virtual void Seed(SmartObjectContext context) _ctx.Configuration.AutoDetectChangesEnabled = false; _ctx.Configuration.ValidateOnSaveEnabled = false; + _ctx.HooksEnabled = false; _config.ProgressMessageCallback("Progress.CreatingRequiredData"); @@ -600,12 +550,12 @@ public virtual void Seed(SmartObjectContext context) }); Populate("PopulatePictures", _data.Pictures()); + Populate("PopulateCurrencies", PopulateCurrencies); Populate("PopulateStores", PopulateStores); Populate("InstallLanguages", () => PopulateLanguage(_config.Language)); Populate("PopulateMeasureDimensions", _data.MeasureDimensions()); Populate("PopulateMeasureWeights", _data.MeasureWeights()); Populate("PopulateTaxCategories", PopulateTaxCategories); - Populate("PopulateCurrencies", PopulateCurrencies); Populate("PopulateCountriesAndStates", PopulateCountriesAndStates); Populate("PopulateShippingMethods", PopulateShippingMethods); Populate("PopulateDeliveryTimes", _data.DeliveryTimes()); @@ -665,9 +615,11 @@ private void SetModified(TEntity entity) private string ValidateSeName(TEntity entity, string name) where TEntity : BaseEntity, ISlugSupported { + var seoSettings = new SeoSettings { LoadAllUrlAliasesOnStartup = false }; + if (_urlRecordService == null) { - _urlRecordService = new UrlRecordService(NullCache.Instance, new EfRepository(_ctx) { AutoCommitEnabled = false }); + _urlRecordService = new UrlRecordService(NullCache.Instance, new EfRepository(_ctx) { AutoCommitEnabled = false }, seoSettings); } return entity.ValidateSeName("", name, true, _urlRecordService, new SeoSettings()); diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallationLocalizationService.cs b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallationLocalizationService.cs index 06d2e26f86..04ba8b6e49 100644 --- a/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallationLocalizationService.cs +++ b/src/Presentation/SmartStore.Web/Infrastructure/Installation/InstallationLocalizationService.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Web; using System.Xml; using SmartStore.Core; @@ -37,7 +38,7 @@ public string GetResource(string resourceName) .Select(r => r.Value) .FirstOrDefault(); if (String.IsNullOrEmpty(resourceValue)) - //return name + // return name return resourceName; return resourceValue; @@ -52,35 +53,55 @@ public virtual InstallationLanguage GetCurrentLanguage() if (cookie != null && !String.IsNullOrEmpty(cookie.Value)) cookieLanguageCode = cookie.Value; - //ensure it's available (it could be delete since the previous installation) + // ensure it's available (it could be deleted since the previous installation) var availableLanguages = GetAvailableLanguages(); var language = availableLanguages .Where(l => l.Code.Equals(cookieLanguageCode, StringComparison.InvariantCultureIgnoreCase)) - //.Where(l => l.Code.Equals("en", StringComparison.InvariantCultureIgnoreCase)) .FirstOrDefault(); if (language != null) return language; - //if we got here, the language code is not found. let's return the default one - language = availableLanguages - .Where(l => l.IsDefault) - .FirstOrDefault(); + // try to resolve install language from CurrentCulture + language = availableLanguages.Where(MatchLanguageByCurrentCulture).FirstOrDefault(); + if (language != null) + return language; + + // if we got here, the language code is not found. let's return the default one + language = availableLanguages.Where(l => l.IsDefault).FirstOrDefault(); if (language != null) return language; - //return any available language + // return any available language language = availableLanguages.FirstOrDefault(); return language; } + private bool MatchLanguageByCurrentCulture(InstallationLanguage language) + { + var curCulture = Thread.CurrentThread.CurrentUICulture; + + if (language.Code.IsCaseInsensitiveEqual(curCulture.IetfLanguageTag)) + return true; + + curCulture = curCulture.Parent; + if (curCulture != null) + { + return language.Code.IsCaseInsensitiveEqual(curCulture.IetfLanguageTag); + } + + return false; + } + public virtual void SaveCurrentLanguage(string languageCode) { var httpContext = EngineContext.Current.Resolve(); var cookie = new HttpCookie(LanguageCookieName); + cookie.HttpOnly = true; cookie.Value = languageCode; cookie.Expires = DateTime.Now.AddHours(24); + httpContext.Response.Cookies.Remove(LanguageCookieName); httpContext.Response.Cookies.Add(cookie); } @@ -131,7 +152,7 @@ public virtual IList GetAvailableLanguages() var isRightToLeft = isRightToLeftAttribute != null ? Convert.ToBoolean(isRightToLeftAttribute.InnerText.Trim()) : false; //create language - var language = new InstallationLanguage() + var language = new InstallationLanguage { Code = languageCode, Name = languageName, diff --git a/src/Presentation/SmartStore.Web/Infrastructure/RouteProvider.cs b/src/Presentation/SmartStore.Web/Infrastructure/RouteProvider.cs deleted file mode 100644 index bacb7e2f06..0000000000 --- a/src/Presentation/SmartStore.Web/Infrastructure/RouteProvider.cs +++ /dev/null @@ -1,671 +0,0 @@ -using System.Web.Mvc; -using System.Web.Routing; -using SmartStore.Web.Framework.Localization; -using SmartStore.Web.Framework.Mvc.Routes; - -namespace SmartStore.Web.Infrastructure -{ - public partial class RouteProvider : IRouteProvider - { - public void RegisterRoutes(RouteCollection routes) - { - //home page - routes.MapLocalizedRoute("HomePage", - "", - new { controller = "Home", action = "Index"}, - new[] { "SmartStore.Web.Controllers" }); - - - //install - routes.MapRoute("Installation", - "install", - new { controller = "Install", action = "Index" }, - new[] { "SmartStore.Web.Controllers" }); - - //products - routes.MapLocalizedRoute("RecentlyViewedProducts", - "recentlyviewedproducts/", - new { controller = "Catalog", action = "RecentlyViewedProducts" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("RecentlyAddedProducts", - "newproducts/", - new { controller = "Catalog", action = "RecentlyAddedProducts" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("RecentlyAddedProductsRSS", - "newproducts/rss", - new { controller = "Catalog", action = "RecentlyAddedProductsRss" }, - new[] { "SmartStore.Web.Controllers" }); - - //comparing products - routes.MapLocalizedRoute("AddProductToCompare", - "compareproducts/add/{productId}", - new { controller = "Catalog", action = "AddProductToCompareList" }, - new { productId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CompareProducts", - "compareproducts/", - new { controller = "Catalog", action = "CompareProducts" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("RemoveProductFromCompareList", - "compareproducts/remove/{productId}", - new { controller = "Catalog", action = "RemoveProductFromCompareList"}, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ClearCompareList", - "clearcomparelist/", - new { controller = "Catalog", action = "ClearCompareList" }, - new[] { "SmartStore.Web.Controllers" }); - - // product email a friend - routes.MapLocalizedRoute("ProductEmailAFriend", - "productemailafriend/{productId}", - new { controller = "Catalog", action = "ProductEmailAFriend" }, - new { productId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - // ask product question form - routes.MapLocalizedRoute("ProductAskQuestion", - "productaskquestion/{productId}", - new { controller = "Catalog", action = "ProductAskQuestion" }, - new { productId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - //catalog - routes.MapLocalizedRoute("ManufacturerList", - "manufacturer/all/", - new { controller = "Catalog", action = "ManufacturerAll" }, - new[] { "SmartStore.Web.Controllers" }); - //downloads - routes.MapRoute("GetSampleDownload", - "download/sample/{productid}", - new { controller = "Download", action = "Sample"}, - new { productid = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapRoute("GetDownload", - "download/getdownload/{orderItemId}/{agree}", - new { controller = "Download", action = "GetDownload", agree = UrlParameter.Optional }, - new { orderItemId = new GuidConstraint(false) }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapRoute("GetLicense", - "download/getlicense/{orderItemId}/", - new { controller = "Download", action = "GetLicense" }, - new { orderItemId = new GuidConstraint(false) }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("DownloadUserAgreement", - "customer/useragreement/{orderItemId}", - new { controller = "Customer", action = "UserAgreement" }, - new { orderItemId = new GuidConstraint(false) }, - new[] { "SmartStore.Web.Controllers" }); - - //reviews - routes.MapLocalizedRoute("ProductReviews", - "productreviews/{productId}", - new { controller = "Catalog", action = "ProductReviews" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapRoute("SetProductReviewHelpfulness", - "setproductreviewhelpfulness", - new { controller = "Catalog", action = "SetProductReviewHelpfulness" }, - new[] { "SmartStore.Web.Controllers" }); - - //back in stock notifications - routes.MapLocalizedRoute("BackInStockSubscribePopup", - "backinstocksubscribe/{productId}", - new { controller = "Catalog", action = "BackInStockSubscribePopup" }, - new { productId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("DeleteBackInStockSubscription", - "backinstocksubscribe/delete/{subscriptionId}", - new { controller = "Customer", action = "DeleteBackInStockSubscription" }, - new { subscriptionId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - //login, register - routes.MapLocalizedRoute("Login", - "login/", - new { controller = "Customer", action = "Login" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("LoginCheckoutAsGuest", - "login/checkoutasguest", - new { controller = "Customer", action = "Login", checkoutAsGuest = true }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("Register", - "register/", - new { controller = "Customer", action = "Register" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("Logout", - "logout/", - new { controller = "Customer", action = "Logout" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("RegisterResult", - "registerresult/{resultId}", - new { controller = "Customer", action = "RegisterResult" }, - new { resultId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckUsernameAvailability", - "customer/checkusernameavailability", - new { controller = "Customer", action = "CheckUsernameAvailability" }, - new[] { "SmartStore.Web.Controllers" }); - - //shopping cart - routes.MapLocalizedRoute("ShoppingCart", - "cart/", - new { controller = "ShoppingCart", action = "Cart" }, - new[] { "SmartStore.Web.Controllers" }); - //wishlist - routes.MapLocalizedRoute("Wishlist", - "wishlist/{customerGuid}", - new { controller = "ShoppingCart", action = "Wishlist", customerGuid = UrlParameter.Optional }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("EmailWishlist", - "emailwishlist", - new { controller = "ShoppingCart", action = "EmailWishlist" }, - new[] { "SmartStore.Web.Controllers" }); - //add product to cart (without any attributes and options). used on catalog pages. - routes.MapLocalizedRoute("AddProductToCart-Catalog", - "addproducttocart/catalog/{productId}", - new { controller = "ShoppingCart", action = "AddProductToCart_Catalog" }, - new { productId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - //add product to cart (with attributes and options). used on the product details pages. - routes.MapLocalizedRoute("AddProductToCart-Details", - "addproducttocart/details/{productId}/{shoppingCartTypeId}", - new { controller = "ShoppingCart", action = "AddProductToCart_Details" }, - new { productId = @"\d+", shoppingCartTypeId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - //product attributes with "upload file" type - routes.MapLocalizedRoute("UploadFileProductAttribute", - "uploadfileproductattribute/{productId}/{productAttributeId}", - new { controller = "ShoppingCart", action = "UploadFileProductAttribute" }, - new { productId = @"\d+", productAttributeId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - //checkout - routes.MapLocalizedRoute("Checkout", - "checkout/", - new { controller = "Checkout", action = "Index" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutOnePage", - "onepagecheckout/", - new { controller = "Checkout", action = "OnePageCheckout" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutShippingAddress", - "checkout/shippingaddress", - new { controller = "Checkout", action = "ShippingAddress" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutSelectShippingAddress", - "checkout/selectshippingaddress", - new { controller = "Checkout", action = "SelectShippingAddress" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutBillingAddress", - "checkout/billingaddress", - new { controller = "Checkout", action = "BillingAddress" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutSelectBillingAddress", - "checkout/selectbillingaddress", - new { controller = "Checkout", action = "SelectBillingAddress" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutShippingMethod", - "checkout/shippingmethod", - new { controller = "Checkout", action = "ShippingMethod" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutPaymentMethod", - "checkout/paymentmethod", - new { controller = "Checkout", action = "PaymentMethod" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutPaymentInfo", - "checkout/paymentinfo", - new { controller = "Checkout", action = "PaymentInfo" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutConfirm", - "checkout/confirm", - new { controller = "Checkout", action = "Confirm" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CheckoutCompleted", - "checkout/completed", - new { controller = "Checkout", action = "Completed" }, - new[] { "SmartStore.Web.Controllers" }); - - //orders - routes.MapLocalizedRoute("OrderDetails", - "orderdetails/{orderId}", - new { controller = "Order", action = "Details" }, - new { orderId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ShipmentDetails", - "orderdetails/shipment/{shipmentId}", - new { controller = "Order", action = "ShipmentDetails" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ReturnRequest", - "returnrequest/{orderId}", - new { controller = "ReturnRequest", action = "ReturnRequest" }, - new { orderId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ReOrder", - "reorder/{orderId}", - new { controller = "Order", action = "ReOrder" }, - new { orderId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("GetOrderPdfInvoice", - "orderdetails/pdf/{orderId}", - new { controller = "Order", action = "GetPdfInvoice" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("PrintOrderDetails", - "orderdetails/print/{orderId}", - new { controller = "Order", action = "PrintOrderDetails" }, - new[] { "SmartStore.Web.Controllers" }); - - - //contact us - routes.MapLocalizedRoute("ContactUs", - "contactus", - new { controller = "Common", action = "ContactUs" }, - new[] { "SmartStore.Web.Controllers" }); - - //store closed - routes.MapLocalizedRoute("StoreClosed", - "storeclosed", - new { controller = "Common", action = "StoreClosed" }, - new[] { "SmartStore.Web.Controllers" }); - - //passwordrecovery - routes.MapLocalizedRoute("PasswordRecovery", - "passwordrecovery", - new { controller = "Customer", action = "PasswordRecovery" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("PasswordRecoveryConfirm", - "passwordrecovery/confirm", - new { controller = "Customer", action = "PasswordRecoveryConfirm" }, - new[] { "SmartStore.Web.Controllers" }); - - //newsletters - routes.MapLocalizedRoute("NewsletterActivation", - "newsletter/subscriptionactivation/{token}/{active}", - new { controller = "Newsletter", action = "SubscriptionActivation" }, - new { token = new GuidConstraint(false) }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("SubscribeNewsletter", - "subscribenewsletter", - new { controller = "Newsletter", action = "SubscribeNewsletter" }, - new[] { "SmartStore.Web.Controllers" }); - - - - //customer - routes.MapLocalizedRoute("CustomerMyAccount", - "customer/myaccount", - new { controller = "Customer", action = "MyAccount" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerInfo", - "customer/info", - new { controller = "Customer", action = "Info" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerAddresses", - "customer/addresses", - new { controller = "Customer", action = "Addresses" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerOrders", - "customer/orders", - new { controller = "Customer", action = "Orders" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerReturnRequests", - "customer/returnrequests", - new { controller = "Customer", action = "ReturnRequests" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerDownloadableProducts", - "customer/downloadableproducts", - new { controller = "Customer", action = "DownloadableProducts" }, - new[] { "SmartStore.Web.Controllers" }); - - - routes.MapLocalizedRoute("CustomerBackInStockSubscriptions", - "customer/backinstocksubscriptions", - new { controller = "Customer", action = "BackInStockSubscriptions" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerBackInStockSubscriptionsPaged", - "customer/backinstocksubscriptions/{page}", - new { controller = "Customer", action = "BackInStockSubscriptions", page = UrlParameter.Optional }, - new { page = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("CustomerRewardPoints", - "customer/rewardpoints", - new { controller = "Customer", action = "RewardPoints" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerChangePassword", - "customer/changepassword", - new { controller = "Customer", action = "ChangePassword" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerAvatar", - "customer/avatar", - new { controller = "Customer", action = "Avatar" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("AccountActivation", - "customer/activation", - new { controller = "Customer", action = "AccountActivation" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerProfile", - "profile/{id}", - new { controller = "Profile", action = "Index" }, - new { id = @"\d+"}, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerProfilePaged", - "profile/{id}/page/{page}", - new { controller = "Profile", action = "Index"}, - new { id = @"\d+", page = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerForumSubscriptions", - "customer/forumsubscriptions", - new { controller = "Customer", action = "ForumSubscriptions"}, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerForumSubscriptionsPaged", - "customer/forumsubscriptions/{page}", - new { controller = "Customer", action = "ForumSubscriptions", page = UrlParameter.Optional }, - new { page = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("DeleteForumSubscription", - "customer/forumsubscriptions/delete/{subscriptionId}", - new { controller = "Customer", action = "DeleteForumSubscription" }, - new { subscriptionId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - //addresses - routes.MapLocalizedRoute("CustomerAddressDelete", - "customer/addressdelete/{addressId}", - new { controller = "Customer", action = "AddressDelete" }, - new { addressId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerAddressEdit", - "customer/addressedit/{addressId}", - new { controller = "Customer", action = "AddressEdit" }, - new { addressId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("CustomerAddressAdd", - "customer/addressadd", - new { controller = "Customer", action = "AddressAdd" }, - new[] { "SmartStore.Web.Controllers" }); - - - - //blog - routes.MapLocalizedRoute("Blog", - "blog", - new { controller = "Blog", action = "List" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("BlogByTag", - "blog/tag/{tag}", - new { controller = "Blog", action = "BlogByTag" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("BlogByMonth", - "blog/month/{month}", - new { controller = "Blog", action = "BlogByMonth" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("BlogRSS", - "blog/rss/{languageId}", - new { controller = "Blog", action = "ListRss" }, - new { languageId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - //forum - routes.MapLocalizedRoute("Boards", - "boards", - new { controller = "Boards", action = "Index" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ActiveDiscussions", - "boards/activediscussions", - new { controller = "Boards", action = "ActiveDiscussions" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ActiveDiscussionsRSS", - "boards/activediscussionsrss", - new { controller = "Boards", action = "ActiveDiscussionsRSS" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("PostEdit", - "boards/postedit/{id}", - new { controller = "Boards", action = "PostEdit" }, - new { id = @"\d+"}, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("PostDelete", - "boards/postdelete/{id}", - new { controller = "Boards", action = "PostDelete" }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("PostCreate", - "boards/postcreate/{id}", - new { controller = "Boards", action = "PostCreate"}, - new { id = @"\d+"}, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("PostCreateQuote", - "boards/postcreate/{id}/{quote}", - new { controller = "Boards", action = "PostCreate"}, - new { id = @"\d+", quote = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicEdit", - "boards/topicedit/{id}", - new { controller = "Boards", action = "TopicEdit"}, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicDelete", - "boards/topicdelete/{id}", - new { controller = "Boards", action = "TopicDelete"}, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicCreate", - "boards/topiccreate/{id}", - new { controller = "Boards", action = "TopicCreate" }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicMove", - "boards/topicmove/{id}", - new { controller = "Boards", action = "TopicMove" }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicWatch", - "boards/topicwatch/{id}", - new { controller = "Boards", action = "TopicWatch" }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicSlug", - "boards/topic/{id}/{slug}", - new { controller = "Boards", action = "Topic", slug = UrlParameter.Optional }, - new { id = @"\d+"}, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicSlugPaged", - "boards/topic/{id}/{slug}/page/{page}", - new { controller = "Boards", action = "Topic", slug = UrlParameter.Optional, page = UrlParameter.Optional }, - new { id = @"\d+", page = @"\d+"}, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ForumWatch", - "boards/forumwatch/{id}", - new { controller = "Boards", action = "ForumWatch" }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ForumRSS", - "boards/forumrss/{id}", - new { controller = "Boards", action = "ForumRSS" }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ForumSlug", - "boards/forum/{id}/{slug}", - new { controller = "Boards", action = "Forum", slug = UrlParameter.Optional }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ForumSlugPaged", - "boards/forum/{id}/{slug}/page/{page}", - new { controller = "Boards", action = "Forum", slug = UrlParameter.Optional, page = UrlParameter.Optional }, - new { id = @"\d+", page = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ForumGroupSlug", - "boards/forumgroup/{id}/{slug}", - new { controller = "Boards", action = "ForumGroup", slug = UrlParameter.Optional }, - new { id = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("Search", - "boards/search", - new { controller = "Boards", action = "Search" }, - new[] { "SmartStore.Web.Controllers" }); - - - //private messages - routes.MapLocalizedRoute("PrivateMessages", - "privatemessages/{tab}", - new { controller = "PrivateMessages", action = "Index", tab = UrlParameter.Optional }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("PrivateMessagesPaged", - "privatemessages/{tab}/page/{page}", - new { controller = "PrivateMessages", action = "Index", tab = UrlParameter.Optional }, - new { page = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("PrivateMessagesInbox", - "inboxupdate", - new { controller = "PrivateMessages", action = "InboxUpdate" }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("PrivateMessagesSent", - "sentupdate", - new { controller = "PrivateMessages", action = "SentUpdate" }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("SendPM", - "sendpm/{toCustomerId}", - new { controller = "PrivateMessages", action = "SendPM" }, - new { toCustomerId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("SendPMReply", - "sendpm/{toCustomerId}/{replyToMessageId}", - new { controller = "PrivateMessages", action = "SendPM" }, - new { toCustomerId = @"\d+", replyToMessageId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("ViewPM", - "viewpm/{privateMessageId}", - new { controller = "PrivateMessages", action = "ViewPM" }, - new { privateMessageId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - routes.MapLocalizedRoute("DeletePM", - "deletepm/{privateMessageId}", - new { controller = "PrivateMessages", action = "DeletePM" }, - new { privateMessageId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - //news - routes.MapLocalizedRoute("NewsArchive", - "news", - new { controller = "News", action = "List" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("NewsRSS", - "news/rss/{languageId}", - new { controller = "News", action = "ListRss" }, - new { languageId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - - //topics - routes.MapLocalizedRoute("Topic", - "t/{SystemName}", - new { controller = "Topic", action = "TopicDetails" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicPopup", - "t-popup/{SystemName}", - new { controller = "Topic", action = "TopicDetailsPopup" }, - new[] { "SmartStore.Web.Controllers" }); - //sitemaps - routes.MapLocalizedRoute("Sitemap", - "sitemap", - new { controller = "Common", action = "Sitemap" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("SitemapSEO", - "sitemapseo", - new { controller = "Common", action = "SitemapSeo" }, - new[] { "SmartStore.Web.Controllers" }); - - //product tags - routes.MapLocalizedRoute("ProductsByTag", - "producttag/{productTagId}/{SeName}", - new { controller = "Catalog", action = "ProductsByTag", SeName = UrlParameter.Optional }, - new { productTagId = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ProductTagsAll", - "producttag/all/", - new { controller = "Catalog", action = "ProductTagsAll" }, - new[] { "SmartStore.Web.Controllers" }); - - //product search - routes.MapLocalizedRoute("ProductSearch", - "search/", - new { controller = "Catalog", action = "Search" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ProductSearchAutoComplete", - "catalog/searchtermautocomplete", - new { controller = "Catalog", action = "SearchTermAutoComplete" }, - new[] { "SmartStore.Web.Controllers" }); - - //config - routes.MapLocalizedRoute("Config", - "config", - new { controller = "Common", action = "Config" }, - new[] { "SmartStore.Web.Controllers" }); - - //some AJAX links - routes.MapRoute("GetStatesByCountryId", - "country/getstatesbycountryid/", - new { controller = "Country", action = "GetStatesByCountryId" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ChangeDevice", - "changedevice/{dontusemobileversion}", - new { controller = "Common", action = "ChangeDevice" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ChangeCurrency", - "changecurrency/{customercurrency}", - new { controller = "Common", action = "CurrencySelected" }, - new { customercurrency = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapRoute("ChangeLanguage", - "changelanguage/{langid}", - new { controller = "Common", action = "SetLanguage" }, - new { langid = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ChangeTaxType", - "changetaxtype/{customertaxtype}", - new { controller = "Common", action = "TaxTypeSelected" }, - new { customertaxtype = @"\d+" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("PollVote", - "poll/vote", - new { controller = "Poll", action = "Vote" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("TopicAuthenticate", - "topic/authenticate", - new { controller = "Topic", action = "Authenticate" }, - new[] { "SmartStore.Web.Controllers" }); - // codehint: sm-add - routes.MapLocalizedRoute("ProductFilters", - "filter/", - new { controller = "Filter", action = "Products" }, - new[] { "SmartStore.Web.Controllers" }); - routes.MapLocalizedRoute("ProductsMultiSelect", - "filter/productsmultiselect", - new { controller = "Filter", action = "ProductsMultiSelect" }, - new[] { "SmartStore.Web.Controllers" }); - - //robots.txt - routes.MapRoute("robots.txt", - "robots.txt", - new { controller = "Common", action = "RobotsTextFile" }, - new[] { "SmartStore.Web.Controllers" }); - - //page not found - routes.MapLocalizedRoute("PageNotFound", - "404", - new { controller = "Common", action = "PageNotFound" }, - new[] { "SmartStore.Web.Controllers" }); - } - - public int Priority - { - get - { - return 0; - } - } - } -} diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Routes/1_StoreRoutes.cs b/src/Presentation/SmartStore.Web/Infrastructure/Routes/1_StoreRoutes.cs new file mode 100644 index 0000000000..d5d5d1413d --- /dev/null +++ b/src/Presentation/SmartStore.Web/Infrastructure/Routes/1_StoreRoutes.cs @@ -0,0 +1,335 @@ +using System; +using System.Web.Mvc; +using System.Web.Mvc.Routing.Constraints; +using System.Web.Routing; +using SmartStore.Web.Framework.Localization; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.Web.Infrastructure +{ + public partial class StoreRoutes : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + var idConstraint = new MinRouteConstraint(1); + + /* Common + ----------------------------------------*/ + + routes.MapLocalizedRoute("HomePage", + "", + new { controller = "Home", action = "Index"}, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("Register", + "register/", + new { controller = "Customer", action = "Register" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("Login", + "login/", + new { controller = "Customer", action = "Login" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("Logout", + "logout/", + new { controller = "Customer", action = "Logout" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ContactUs", + "contactus", + new { controller = "Home", action = "ContactUs" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ShoppingCart", + "cart/", + new { controller = "ShoppingCart", action = "Cart" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("Wishlist", + "wishlist/{customerGuid}", + new { controller = "ShoppingCart", action = "Wishlist", customerGuid = UrlParameter.Optional }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("MyAccount", + "customer/myaccount", + new { controller = "Customer", action = "MyAccount" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("Topic", + "t/{SystemName}", + new { controller = "Topic", action = "TopicDetails" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("TopicPopup", + "t-popup/{SystemName}", + new { controller = "Topic", action = "TopicDetailsPopup" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ProductSearch", + "search/", + new { controller = "Catalog", action = "Search" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ProductSearchAutoComplete", + "catalog/searchtermautocomplete", + new { controller = "Catalog", action = "SearchTermAutoComplete" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ChangeDevice", + "changedevice/{dontusemobileversion}", + new { controller = "Common", action = "ChangeDevice" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ChangeCurrency", + "changecurrency/{customercurrency}", + new { controller = "Common", action = "CurrencySelected" }, + new { customercurrency = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapRoute("ChangeLanguage", + "changelanguage/{langid}", + new { controller = "Common", action = "SetLanguage" }, + new { langid = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ChangeTaxType", + "changetaxtype/{customertaxtype}", + new { controller = "Common", action = "TaxTypeSelected" }, + new { customertaxtype = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + /* Catalog + ----------------------------------------*/ + + routes.MapLocalizedRoute("ManufacturerList", + "manufacturer/all/", + new { controller = "Catalog", action = "ManufacturerAll" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ProductsByTag", + "producttag/{productTagId}/{SeName}", + new { controller = "Catalog", action = "ProductsByTag", SeName = UrlParameter.Optional }, + new { productTagId = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ProductTagsAll", + "producttag/all/", + new { controller = "Catalog", action = "ProductTagsAll" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("RecentlyViewedProducts", + "recentlyviewedproducts/", + new { controller = "Catalog", action = "RecentlyViewedProducts" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("RecentlyAddedProducts", + "newproducts/", + new { controller = "Catalog", action = "RecentlyAddedProducts" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("RecentlyAddedProductsRSS", + "newproducts/rss", + new { controller = "Catalog", action = "RecentlyAddedProductsRss" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("CompareProducts", + "compareproducts/", + new { controller = "Catalog", action = "CompareProducts" }, + new[] { "SmartStore.Web.Controllers" }); + + + /* Shopping Cart + ----------------------------------------*/ + + // add product to cart (without any attributes and options). used on catalog pages. + routes.MapLocalizedRoute("AddProductToCartSimple", + "cart/addproductsimple/{productId}", + new { controller = "ShoppingCart", action = "AddProductSimple" }, + new { productId = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + // add product to cart (with attributes and options). used on the product details pages. + routes.MapLocalizedRoute("AddProductToCart", + "cart/addproduct/{productId}/{shoppingCartTypeId}", + new { controller = "ShoppingCart", action = "AddProduct" }, + new { productId = idConstraint, shoppingCartTypeId = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + + /* Checkout + ----------------------------------------*/ + + routes.MapLocalizedRoute("Checkout", + "checkout/", + new { controller = "Checkout", action = "Index" }, + new[] { "SmartStore.Web.Controllers" }); + + + /* Newsletter + ----------------------------------------*/ + + routes.MapLocalizedRoute("NewsletterActivation", + "newsletter/subscriptionactivation/{token}/{active}", + new { controller = "Newsletter", action = "SubscriptionActivation" }, + new { token = new GuidConstraint(false) }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("SubscribeNewsletter", // COMPAT: subscribenewsletter >> newsletter/subscribe + "Newsletter/Subscribe", + new { controller = "Newsletter", action = "Subscribe" }, + new[] { "SmartStore.Web.Controllers" }); + + + /* Customer + ----------------------------------------*/ + + routes.MapLocalizedRoute("AccountActivation", + "customer/activation", + new { controller = "Customer", action = "AccountActivation" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("CustomerProfile", + "profile/{id}", + new { controller = "Profile", action = "Index", id = UrlParameter.Optional }, + new { id = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + + /* Blog + ----------------------------------------*/ + + routes.MapLocalizedRoute("Blog", + "blog", + new { controller = "Blog", action = "List" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("BlogByTag", + "blog/tag/{tag}", + new { controller = "Blog", action = "BlogByTag" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("BlogByMonth", + "blog/month/{month}", + new { controller = "Blog", action = "BlogByMonth" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("BlogRSS", + "blog/rss/{languageId}", + new { controller = "Blog", action = "ListRss" }, + new { languageId = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + + /* Boards + ----------------------------------------*/ + + routes.MapLocalizedRoute("Boards", + "boards", + new { controller = "Boards", action = "Index" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("BoardPostCreate", + "boards/postcreate/{id}/{quote}", + new { controller = "Boards", action = "PostCreate", quote = UrlParameter.Optional }, + new { id = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("TopicSlug", + "boards/topic/{id}/{slug}", + new { controller = "Boards", action = "Topic", slug = UrlParameter.Optional }, + new { id = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("TopicSlugPaged", + "boards/topic/{id}/{slug}/page/{page}", + new { controller = "Boards", action = "Topic" }, + new { id = idConstraint, page = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ForumSlug", + "boards/forum/{id}/{slug}", + new { controller = "Boards", action = "Forum", slug = UrlParameter.Optional }, + new { id = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ForumSlugPaged", + "boards/forum/{id}/{slug}/page/{page}", + new { controller = "Boards", action = "Forum" }, + new { id = idConstraint, page = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("ForumGroupSlug", + "boards/forumgroup/{id}/{slug}", + new { controller = "Boards", action = "ForumGroup", slug = UrlParameter.Optional }, + new { id = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("BoardSearch", + "boards/search", + new { controller = "Boards", action = "Search" }, + new[] { "SmartStore.Web.Controllers" }); + + + /* Misc + ----------------------------------------*/ + + routes.MapLocalizedRoute("RegisterResult", + "registerresult/{resultId}", + new { controller = "Customer", action = "RegisterResult" }, + new { resultId = idConstraint }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("PrivateMessages", + "privatemessages/{tab}", + new { controller = "PrivateMessages", action = "Index", tab = UrlParameter.Optional }, + new { tab = @"inbox|sent" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("NewsArchive", + "news", + new { controller = "News", action = "List" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("NewsRss", + "news/rss/{languageId}", + new { controller = "News", action = "rss", languageId = UrlParameter.Optional }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("Sitemap", + "sitemap", + new { controller = "Home", action = "Sitemap" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("SitemapSEO", + "sitemap.xml", + new { controller = "Home", action = "SitemapSeo" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("StoreClosed", + "storeclosed", + new { controller = "Home", action = "StoreClosed" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapRoute("robots.txt", + "robots.txt", + new { controller = "Common", action = "RobotsTextFile" }, + new[] { "SmartStore.Web.Controllers" }); + + routes.MapLocalizedRoute("Settings", + "settings", + new { controller = "Common", action = "Settings" }, + new[] { "SmartStore.Web.Controllers" }); + + } + + public int Priority + { + get + { + return 0; + } + } + } + +} diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Routes/2_DefaultRoutes.cs b/src/Presentation/SmartStore.Web/Infrastructure/Routes/2_DefaultRoutes.cs new file mode 100644 index 0000000000..352c05e1fb --- /dev/null +++ b/src/Presentation/SmartStore.Web/Infrastructure/Routes/2_DefaultRoutes.cs @@ -0,0 +1,74 @@ +using System; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using System.Reflection; +using System.Linq; +using SmartStore.Web.Controllers; +using SmartStore.Web.Framework.Localization; +using SmartStore.Web.Framework.Seo; +using System.Collections.Generic; +using SmartStore.Web.Framework.Routing; + +namespace SmartStore.Web.Infrastructure +{ + public partial class GeneralRoutes : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + routes.MapLocalizedRoute( + "Default_Localized", + "{controller}/{action}/{id}", + new { controller = "Home", action = "Index", id = UrlParameter.Optional }, + new { controller = new IsKnownController() }, + new[] { "SmartStore.Web.Controllers" } + ); + + routes.MapRoute( + "Default", + "{controller}/{action}/{id}", + new { controller = "Home", action = "Index", id = UrlParameter.Optional }, + new { controller = new IsKnownController() }, + new[] { "SmartStore.Web.Controllers" } + ); + } + + public int Priority + { + get { return -999; } + } + } + + internal class IsKnownController : IRouteConstraint + { + private readonly static HashSet s_knownControllers = new HashSet(StringComparer.InvariantCultureIgnoreCase); + + static IsKnownController() + { + var assembly = typeof(HomeController).Assembly; + var controllerTypes = from t in assembly.GetExportedTypes() + where typeof(IController).IsAssignableFrom(t) && t.Namespace == "SmartStore.Web.Controllers" + select t; + + foreach (var type in controllerTypes) + { + var name = type.Name.Substring(0, type.Name.Length - 10); + s_knownControllers.Add(name); + } + } + + public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) + { + object value; + if (values.TryGetValue(parameterName, out value)) + { + var requestedController = Convert.ToString(value); + if (s_knownControllers.Contains(requestedController)) + { + return true; + } + } + return false; + } + } +} diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Routes/3_GenericRoutes.cs b/src/Presentation/SmartStore.Web/Infrastructure/Routes/3_GenericRoutes.cs new file mode 100644 index 0000000000..a3abdc0415 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Infrastructure/Routes/3_GenericRoutes.cs @@ -0,0 +1,57 @@ +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Web.Framework.Localization; +using SmartStore.Web.Framework.Routing; +using SmartStore.Web.Framework.Seo; + +namespace SmartStore.Web.Infrastructure +{ + public partial class SeoRoutes : IRouteProvider + { + public void RegisterRoutes(RouteCollection routes) + { + //generic URLs + routes.MapGenericPathRoute("GenericUrl", + "{*generic_se_name}", + new { controller = "Common", action = "GenericUrl" }, + new[] { "SmartStore.Web.Controllers" }); + + // Routes solely needed for URL creation, NOT for route matching. + routes.MapLocalizedRoute("Product", + "{SeName}", + new { controller = "Product", action = "Product" }, + new[] { "SmartStore.Web.Controllers" }); + routes.MapLocalizedRoute("Category", + "{SeName}", + new { controller = "Catalog", action = "Category" }, + new[] { "SmartStore.Web.Controllers" }); + routes.MapLocalizedRoute("Manufacturer", + "{SeName}", + new { controller = "Catalog", action = "Manufacturer" }, + new[] { "SmartStore.Web.Controllers" }); + routes.MapLocalizedRoute("NewsItem", + "{SeName}", + new { controller = "News", action = "NewsItem" }, + new[] { "SmartStore.Web.Controllers" }); + routes.MapLocalizedRoute("BlogPost", + "{SeName}", + new { controller = "Blog", action = "BlogPost" }, + new[] { "SmartStore.Web.Controllers" }); + + // TODO: actually this one's never reached, because the "GenericUrl" route + // at the top handles this. + routes.MapLocalizedRoute("PageNotFound", + "{*path}", + new { controller = "Error", action = "NotFound" }, + new[] { "SmartStore.Web.Controllers" }); + } + + public int Priority + { + get + { + return int.MinValue; + } + } + } +} diff --git a/src/Presentation/SmartStore.Web/Infrastructure/Routes/MapLegacyRoutesAttribute.cs b/src/Presentation/SmartStore.Web/Infrastructure/Routes/MapLegacyRoutesAttribute.cs new file mode 100644 index 0000000000..fe86cdef07 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Infrastructure/Routes/MapLegacyRoutesAttribute.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using SmartStore.Core.Data; +using SmartStore.Utilities; + +namespace SmartStore.Web.Infrastructure +{ + + public sealed class MapLegacyRoutesAttribute : ActionFilterAttribute + { + private static readonly IList s_mappedRoutes = new List(); + + static MapLegacyRoutesAttribute() + { + AddLegacyRoute(@"/productreviews/(?\d+)$", "/product/reviews/${id}", "GET"); + AddLegacyRoute("/sitemapseo$", "/sitemap.xml", "GET"); + AddLegacyRoute("/config$", "/settings", "GET"); + } + + private static void AddLegacyRoute(string path, string newPath, string verb = ".*") + { + var rgPath = new Regex(path, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline); + var rgVerb = new Regex(verb, RegexOptions.CultureInvariant | RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase); + + s_mappedRoutes.Add(new MappedRoute { LegacyPath = rgPath, NewPath = newPath, HttpMethod = rgVerb }); + } + + public override void OnActionExecuted(ActionExecutedContext filterContext) + { + if (!DataSettings.DatabaseIsInstalled()) + return; + + if (filterContext.IsChildAction) + return; + + if (!CommonHelper.GetAppSetting("sm:EnableLegacyRoutesMapping")) + return; + + var mappedPath = GetMappedPath(filterContext.HttpContext.Request); + if (mappedPath != null) + { + filterContext.Result = new RedirectResult(mappedPath, true); + } + } + + private string GetMappedPath(HttpRequestBase request) + { + var path = request.AppRelativeCurrentExecutionFilePath.TrimStart('~').TrimEnd('/'); + var method = request.HttpMethod.EmptyNull(); + + foreach (var route in s_mappedRoutes) + { + if (route.LegacyPath.IsMatch(path) && route.HttpMethod.IsMatch(method)) + { + var newPath = route.LegacyPath.Replace(path, route.NewPath); + return newPath; + } + } + + return null; + } + + private class MappedRoute + { + public Regex LegacyPath { get; set; } + public string NewPath { get; set; } + public Regex HttpMethod { get; set; } + } + + } + +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Media/Thumbs/placeholder.txt b/src/Presentation/SmartStore.Web/Media/Thumbs/placeholder.txt index 5f282702bb..0eaf54c3d7 100644 --- a/src/Presentation/SmartStore.Web/Media/Thumbs/placeholder.txt +++ b/src/Presentation/SmartStore.Web/Media/Thumbs/placeholder.txt @@ -1 +1 @@ - \ No newline at end of file +placeholder file \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Media/Uploaded/placeholder.txt b/src/Presentation/SmartStore.Web/Media/Uploaded/placeholder.txt index 5f282702bb..0eaf54c3d7 100644 --- a/src/Presentation/SmartStore.Web/Media/Uploaded/placeholder.txt +++ b/src/Presentation/SmartStore.Web/Media/Uploaded/placeholder.txt @@ -1 +1 @@ - \ No newline at end of file +placeholder file \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Media/default-avatar.jpg b/src/Presentation/SmartStore.Web/Media/default-avatar.jpg deleted file mode 100644 index 3f8947a5e9..0000000000 Binary files a/src/Presentation/SmartStore.Web/Media/default-avatar.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Media/default-image.jpg b/src/Presentation/SmartStore.Web/Media/default-image.jpg deleted file mode 100644 index d38c8a446c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Media/default-image.jpg and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/AddBlogCommentModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/AddBlogCommentModel.cs index 642bb76372..e3208d7ab0 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/AddBlogCommentModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/AddBlogCommentModel.cs @@ -1,6 +1,6 @@ using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Blogs { diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/BlogCommentModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/BlogCommentModel.cs index d7144cb6e0..9de84ec882 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/BlogCommentModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/BlogCommentModel.cs @@ -1,5 +1,5 @@ using System; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Blogs { diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPagingFilteringModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPagingFilteringModel.cs index 052b5938fe..90292d014a 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPagingFilteringModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPagingFilteringModel.cs @@ -1,11 +1,9 @@ using System; -// codehint: sm-delete using SmartStore.Core; namespace SmartStore.Web.Models.Blogs { - // codehint: sm-edit (formerly inherited BasePageableModel) - public partial class BlogPagingFilteringModel : PagedListBase // BasePageableModel + public partial class BlogPagingFilteringModel : PagedListBase { #region Methods diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostListModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostListModel.cs index de22f36422..7487110110 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostListModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostListModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Blogs { diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostModel.cs index 745c2cb1e0..7c8df3e2d6 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostModel.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using FluentValidation.Attributes; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Blogs; namespace SmartStore.Web.Models.Blogs @@ -36,7 +36,6 @@ public BlogPostModel() public IList Comments { get; set; } public AddBlogCommentModel AddNewComment { get; set; } - // codehint: sm-add public int AvatarPictureSize { get; set; } public bool AllowCustomersToUploadAvatars { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagListModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagListModel.cs index 613df18752..7db54f132a 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagListModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagListModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Blogs { diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagModel.cs index f774e346f7..ddab728568 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostTagModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Blogs { diff --git a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostYearMonthModel.cs b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostYearMonthModel.cs index 54b7ed1cfe..89ea5f646d 100644 --- a/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostYearMonthModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Blogs/BlogPostYearMonthModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Blogs { diff --git a/src/Presentation/SmartStore.Web/Models/Boards/TopicMoveModel.cs b/src/Presentation/SmartStore.Web/Models/Boards/TopicMoveModel.cs index 034fddec45..c88dc4c6b4 100644 --- a/src/Presentation/SmartStore.Web/Models/Boards/TopicMoveModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Boards/TopicMoveModel.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Web.Mvc; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Boards { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/AddToCompareListModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/AddToCompareListModel.cs index 1bffb79e6e..d493b61c51 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/AddToCompareListModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/AddToCompareListModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/BackInStockSubscribeModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/BackInStockSubscribeModel.cs index 7bcac2f0ba..d403abbf0d 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/BackInStockSubscribeModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/BackInStockSubscribeModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/CatalogPagingFilteringModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/CatalogPagingFilteringModel.cs index 0ab878ee0b..39e3c6be9d 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/CatalogPagingFilteringModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/CatalogPagingFilteringModel.cs @@ -2,19 +2,16 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Web.Mvc; using SmartStore.Core; using SmartStore.Core.Domain.Catalog; using SmartStore.Services.Catalog; using SmartStore.Services.Localization; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; -// codehint: sm-delete +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { - // codehint: sm-edit (formerly inherited BasePageableModel) - public partial class CatalogPagingFilteringModel : PagingFilteringModel //BasePageableModel + + public partial class CatalogPagingFilteringModel : PagingFilteringModel { #region Constructors @@ -74,7 +71,7 @@ protected virtual IList GetPriceRangeList(string priceRangesStr) { string[] fromTo = str1.Trim().Split(new char[] { '-' }); - if (fromTo.Length > 1) { // codehint: sm-edit + if (fromTo.Length > 1) { decimal? from = null; if (!String.IsNullOrEmpty(fromTo[0]) && !String.IsNullOrEmpty(fromTo[0].Trim())) from = decimal.Parse(fromTo[0].Trim(), new CultureInfo("en-US")); diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/CategoryModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/CategoryModel.cs index 8489645561..a09f815652 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/CategoryModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/CategoryModel.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Core.Domain.Catalog; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Framework.UI; using SmartStore.Web.Models.Media; @@ -18,7 +19,9 @@ public CategoryModel() } public string Name { get; set; } + public string FullName { get; set; } public string Description { get; set; } + public string BottomDescription { get; set; } public string MetaKeywords { get; set; } public string MetaDescription { get; set; } public string MetaTitle { get; set; } @@ -30,6 +33,9 @@ public CategoryModel() public bool DisplayCategoryBreadcrumb { get; set; } public IList CategoryBreadcrumb { get; set; } + + public bool DisplayFilter { get; set; } + public SubCategoryDisplayType SubCategoryDisplayType { get; set; } public IList SubCategories { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/CompareProductsModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/CompareProductsModel.cs index f7661c0956..1b58526ad5 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/CompareProductsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/CompareProductsModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/HomePageBestsellersModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/HomePageBestsellersModel.cs index 3178fc0182..1f6bb34c0e 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/HomePageBestsellersModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/HomePageBestsellersModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/HomePageProductsModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/HomePageProductsModel.cs index 3e206bdae4..e4a7303d2a 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/HomePageProductsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/HomePageProductsModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerModel.cs index 4c9521ba7f..7f8452ad4d 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Media; namespace SmartStore.Web.Models.Catalog diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs index dcbefd212d..a27b37ba7f 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerNavigationModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { @@ -13,6 +13,10 @@ public ManufacturerNavigationModel() public IList Manufacturers { get; set; } public int TotalManufacturers { get; set; } + + public bool DisplayManufacturers { get; set; } + + public bool DisplayImages { get; set; } } public partial class ManufacturerBriefInfoModel : EntityModelBase @@ -20,7 +24,9 @@ public partial class ManufacturerBriefInfoModel : EntityModelBase public string Name { get; set; } public string SeName { get; set; } - + + public string PictureUrl { get; set; } + public bool IsActive { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerOverviewModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerOverviewModel.cs index 3715363b32..523526d25e 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerOverviewModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ManufacturerOverviewModel.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Media; namespace SmartStore.Web.Models.Catalog diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/NavigationModelBuiltEvent.cs b/src/Presentation/SmartStore.Web/Models/Catalog/NavigationModelBuiltEvent.cs index 4ba7c59c8b..633a453b1f 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/NavigationModelBuiltEvent.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/NavigationModelBuiltEvent.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using SmartStore.Collections; +using SmartStore.Collections; using SmartStore.Web.Framework.UI; namespace SmartStore.Web.Models.Catalog diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/PagingFilteringModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/PagingFilteringModel.cs index 7879fa6639..b5a339879c 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/PagingFilteringModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/PagingFilteringModel.cs @@ -1,15 +1,11 @@ -// codehint: sm-delete -using System.Collections.Generic; +using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Core; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { - - // codehint: sm-add (whole file) - public partial class ListOptionItem : ModelBase { public string Text { get; set; } @@ -28,13 +24,11 @@ public SelectListItem ToSelectListItem() } } - // codehint: sm-add public partial class PagingFilteringModel : PagedListBase { public PagingFilteringModel() { - // codehint: sm-edit (SelectListItem > ListOptionItem) this.AvailableSortOptions = new List(); this.AvailableViewModes = new List(); this.PageSizeOptions = new List(); diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/PopularProductTagsModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/PopularProductTagsModel.cs index 0efd6badc8..65d46aa59e 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/PopularProductTagsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/PopularProductTagsModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductAskQuestionModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductAskQuestionModel.cs index 58ac5c011d..c8e8facd98 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductAskQuestionModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductAskQuestionModel.cs @@ -1,16 +1,14 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Catalog; namespace SmartStore.Web.Models.Catalog { [Validator(typeof(ProductAskQuestionValidator))] - public partial class ProductAskQuestionModel : ModelBase + public partial class ProductAskQuestionModel : EntityModelBase { - public int ProductId { get; set; } - public string ProductName { get; set; } public string ProductSeName { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductDetailsModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductDetailsModel.cs index fee7452ca8..ab13510f40 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductDetailsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductDetailsModel.cs @@ -2,9 +2,8 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Core.Domain.Catalog; -using SmartStore.Core.Domain.Directory; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Framework.UI; using SmartStore.Web.Models.Media; @@ -16,14 +15,11 @@ public partial class ProductDetailsModel : EntityModelBase public ProductDetailsModel() { - //codehint: sm-edit - //Manufacturers = new List(); Manufacturers = new List(); GiftCard = new GiftCardModel(); ProductPrice = new ProductPriceModel(); AddToCart = new AddToCartModel(); ProductVariantAttributes = new List(); - Combinations = new List(); AssociatedProducts = new List(); BundledItems = new List(); BundleItem = new ProductBundleItemModel(); @@ -90,8 +86,9 @@ public ProductDetailsPictureModel DetailsPictureModel public int ThumbDimensions { get; set; } public string DeliveryTimeName { get; set; } public string DeliveryTimeHexValue { get; set; } - public bool DisplayDeliveryTime { get; set; } + public string QuantityUnitName { get; set; } + public bool DisplayProductReviews { get; set; } public bool IsShipEnabled { get; set; } public bool DisplayDeliveryTimeAccordingToStock { get; set; } public bool IsBasePriceEnabled { get; set; } @@ -101,8 +98,7 @@ public ProductDetailsPictureModel DetailsPictureModel public bool BundlePerItemPricing { get; set; } public bool BundlePerItemShoppingCart { get; set; } - public IList Combinations { get; set; } - public ProductVariantAttributeCombination CombinationSelected { get; set; } + public ProductVariantAttributeCombination SelectedCombination { get; set; } public IList Manufacturers { get; set; } public int ReviewCount { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductEmailAFriendModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductEmailAFriendModel.cs index fe12f24f7c..77054abb8e 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductEmailAFriendModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductEmailAFriendModel.cs @@ -1,7 +1,7 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Catalog; namespace SmartStore.Web.Models.Catalog diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs index ebd1f187e3..74d7baecc8 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductOverviewModel.cs @@ -1,8 +1,6 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; using SmartStore.Web.Models.Media; -using SmartStore.Core; -using SmartStore.Core.Domain.Directory; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { @@ -22,7 +20,7 @@ public ProductOverviewModel() public string Name { get; set; } public string ShortDescription { get; set; } - public string FullDescription { get; set; } + public string FullDescription { get; set; } public string SeName { get; set; } public int ThumbDimension { get; set; } @@ -42,6 +40,7 @@ public ProductOverviewModel() public int TotalReviews { get; set; } public bool ShowReviews { get; set; } public bool ShowDeliveryTimes { get; set; } + public bool InvisibleDeliveryTime { get; set; } public string DeliveryTimeName { get; set; } public string DeliveryTimeHexValue { get; set; } @@ -50,7 +49,10 @@ public ProductOverviewModel() public string StockAvailablity { get; set; } public bool DisplayBasePrice { get; set; } public string BasePriceInfo { get; set; } - public int ProductMinPriceId { get; set; } + ///

          + /// For internal use + /// + public int MinPriceProductId { get; set; } public bool CompareEnabled { get; set; } public bool IsNew { get; set; } public bool HideBuyButtonInLists { get; set; } @@ -83,6 +85,8 @@ public partial class ProductPriceModel : ModelBase public bool AvailableForPreOrder { get; set; } public bool ForceRedirectionAfterAddingToCart { get; set; } + + public bool CallForPrice { get; set; } } public partial class ColorAttributeModel : ModelBase diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductReviewModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductReviewModel.cs index 17dd5e7a27..0118abf688 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductReviewModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductReviewModel.cs @@ -2,7 +2,7 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Catalog; namespace SmartStore.Web.Models.Catalog diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductSpecificationModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductSpecificationModel.cs index 1b4b0c98fb..c6436eb6af 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductSpecificationModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductSpecificationModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductTagModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductTagModel.cs index 155f168818..926a87fa0e 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductTagModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductTagModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/ProductsByTagModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/ProductsByTagModel.cs index a5c5afc51e..4c312cc1d8 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/ProductsByTagModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/ProductsByTagModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/RecentlyAddedProductsModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/RecentlyAddedProductsModel.cs index 5ac18739f5..7c3ef212be 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/RecentlyAddedProductsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/RecentlyAddedProductsModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/SearchBoxModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/SearchBoxModel.cs index 6bcc77a21d..4d784901ee 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/SearchBoxModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/SearchBoxModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/SearchModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/SearchModel.cs index 4c3d9e96cb..91904e47fc 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/SearchModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/SearchModel.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Catalog { diff --git a/src/Presentation/SmartStore.Web/Models/Catalog/SearchPagingFilteringModel.cs b/src/Presentation/SmartStore.Web/Models/Catalog/SearchPagingFilteringModel.cs index 54591c656a..086054f61f 100644 --- a/src/Presentation/SmartStore.Web/Models/Catalog/SearchPagingFilteringModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Catalog/SearchPagingFilteringModel.cs @@ -1,14 +1,6 @@ -// codehint: sm-delete -using System.Collections.Generic; -using System.Web.Mvc; -using SmartStore.Core; -using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Web.Models.Catalog +namespace SmartStore.Web.Models.Catalog { - // codehint: sm-edit - public partial class SearchPagingFilteringModel : PagingFilteringModel // BasePageableModel + public partial class SearchPagingFilteringModel : PagingFilteringModel { } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutBillingAddressModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutBillingAddressModel.cs index d5e592dca5..bde0e52a42 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutBillingAddressModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutBillingAddressModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Checkout diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutCompletedModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutCompletedModel.cs index 3920514ded..370be66071 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutCompletedModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutCompletedModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Checkout { diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutConfirmModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutConfirmModel.cs index b553051c80..2239a2e298 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutConfirmModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutConfirmModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Checkout { @@ -17,6 +17,7 @@ public CheckoutConfirmModel() public IList Warnings { get; set; } public bool ShowConfirmOrderLegalHint { get; set; } + public bool ShowEsdRevocationWaiverBox { get; set; } public bool BypassPaymentMethodInfo { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentInfoModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentInfoModel.cs index e08675e71a..2c23a55607 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentInfoModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentInfoModel.cs @@ -1,5 +1,5 @@ using System.Web.Routing; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Checkout { diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs index 37bab3bee2..b3eba49ab3 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutPaymentMethodModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Checkout { @@ -10,7 +10,7 @@ public CheckoutPaymentMethodModel() PaymentMethods = new List(); } - public IList PaymentMethods { get; set; } + public List PaymentMethods { get; set; } public bool DisplayRewardPoints { get; set; } public int RewardPointsBalance { get; set; } @@ -24,10 +24,14 @@ public partial class PaymentMethodModel : ModelBase public string PaymentMethodSystemName { get; set; } public string Name { get; set; } public string Description { get; set; } + public string FullDescription { get; set; } public string BrandUrl { get; set; } public string Fee { get; set; } public bool Selected { get; set; } + public RouteInfo PaymentInfoRoute { get; set; } + public bool RequiresInteraction { get; set; } } + #endregion } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutProgressModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutProgressModel.cs index 8974f5773d..5ef7e38f32 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutProgressModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutProgressModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Checkout { diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingAddressModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingAddressModel.cs index 5a4cac101f..eae1a17753 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingAddressModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingAddressModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Checkout diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs index 4b5c2c52e9..a1104b942f 100644 --- a/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Checkout/CheckoutShippingMethodModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Checkout { @@ -19,11 +19,13 @@ public CheckoutShippingMethodModel() public partial class ShippingMethodModel : ModelBase { + public int ShippingMethodId { get; set; } public string ShippingRateComputationMethodSystemName { get; set; } public string Name { get; set; } - public string BrandUrl { get; set; } // codehint: sm-add + public string BrandUrl { get; set; } public string Description { get; set; } public string Fee { get; set; } + public decimal FeeRaw { get; set; } public bool Selected { get; set; } } #endregion diff --git a/src/Presentation/SmartStore.Web/Models/Checkout/OnePageCheckoutModel.cs b/src/Presentation/SmartStore.Web/Models/Checkout/OnePageCheckoutModel.cs deleted file mode 100644 index 21ce124538..0000000000 --- a/src/Presentation/SmartStore.Web/Models/Checkout/OnePageCheckoutModel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using SmartStore.Web.Framework.Mvc; - -namespace SmartStore.Web.Models.Checkout -{ - public partial class OnePageCheckoutModel : ModelBase - { - public bool ShippingRequired { get; set; } - } -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/CheckoutBillingAddressModel.cs b/src/Presentation/SmartStore.Web/Models/CheckoutBillingAddressModel.cs new file mode 100644 index 0000000000..d07e120dff --- /dev/null +++ b/src/Presentation/SmartStore.Web/Models/CheckoutBillingAddressModel.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using SmartStore.Web.Framework.Modelling; +using SmartStore.Web.Models.Common; + +namespace SmartStore.Web.Models.Checkout +{ + public partial class CheckoutBillingAddressModel2 : ModelBase + { + public CheckoutBillingAddressModel2() + { + ExistingAddresses = new List(); + NewAddress = new AddressModel(); + } + + public IList ExistingAddresses { get; set; } + + public AddressModel NewAddress { get; set; } + + /// + /// Used on one-page checkout page + /// + public bool NewAddressPreselected { get; set; } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Common/AccountDropdownModel.cs b/src/Presentation/SmartStore.Web/Models/Common/AccountDropdownModel.cs index 445ff6fc39..46686d6cf9 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/AccountDropdownModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/AccountDropdownModel.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/AddressModel.cs b/src/Presentation/SmartStore.Web/Models/Common/AddressModel.cs index 470c877bbc..a393eb0873 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/AddressModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/AddressModel.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Common; namespace SmartStore.Web.Models.Common { - [Validator(typeof(AddressValidator))] + [Validator(typeof(AddressValidator))] public partial class AddressModel : EntityModelBase { public AddressModel() @@ -19,71 +20,82 @@ public AddressModel() [SmartResourceDisplayName("Address.Fields.FirstName")] [AllowHtml] public string FirstName { get; set; } + [SmartResourceDisplayName("Address.Fields.LastName")] [AllowHtml] public string LastName { get; set; } + [SmartResourceDisplayName("Address.Fields.Email")] [AllowHtml] - public string Email { get; set; } + [DataType(DataType.EmailAddress)] + public string Email { get; set; } + [SmartResourceDisplayName("Address.Fields.EmailMatch")] + [DataType(DataType.EmailAddress)] + public string EmailMatch { get; set; } + public bool ValidateEmailAddress { get; set; } - public bool CompanyEnabled { get; set; } - public bool CompanyRequired { get; set; } [SmartResourceDisplayName("Address.Fields.Company")] [AllowHtml] public string Company { get; set; } + public bool CompanyEnabled { get; set; } + public bool CompanyRequired { get; set; } - public bool CountryEnabled { get; set; } [SmartResourceDisplayName("Address.Fields.Country")] public int? CountryId { get; set; } + [SmartResourceDisplayName("Address.Fields.Country")] [AllowHtml] public string CountryName { get; set; } + public bool CountryEnabled { get; set; } - public bool StateProvinceEnabled { get; set; } [SmartResourceDisplayName("Address.Fields.StateProvince")] public int? StateProvinceId { get; set; } + public bool StateProvinceEnabled { get; set; } + [SmartResourceDisplayName("Address.Fields.StateProvince")] [AllowHtml] public string StateProvinceName { get; set; } - public bool CityEnabled { get; set; } - public bool CityRequired { get; set; } [SmartResourceDisplayName("Address.Fields.City")] [AllowHtml] public string City { get; set; } + public bool CityEnabled { get; set; } + public bool CityRequired { get; set; } - public bool StreetAddressEnabled { get; set; } - public bool StreetAddressRequired { get; set; } [SmartResourceDisplayName("Address.Fields.Address1")] [AllowHtml] public string Address1 { get; set; } + public bool StreetAddressEnabled { get; set; } + public bool StreetAddressRequired { get; set; } - public bool StreetAddress2Enabled { get; set; } - public bool StreetAddress2Required { get; set; } [SmartResourceDisplayName("Address.Fields.Address2")] [AllowHtml] public string Address2 { get; set; } + public bool StreetAddress2Enabled { get; set; } + public bool StreetAddress2Required { get; set; } - public bool ZipPostalCodeEnabled { get; set; } - public bool ZipPostalCodeRequired { get; set; } [SmartResourceDisplayName("Address.Fields.ZipPostalCode")] [AllowHtml] public string ZipPostalCode { get; set; } + public bool ZipPostalCodeEnabled { get; set; } + public bool ZipPostalCodeRequired { get; set; } - public bool PhoneEnabled { get; set; } - public bool PhoneRequired { get; set; } [SmartResourceDisplayName("Address.Fields.PhoneNumber")] [AllowHtml] - public string PhoneNumber { get; set; } + [DataType(DataType.PhoneNumber)] + public string PhoneNumber { get; set; } + public bool PhoneEnabled { get; set; } + public bool PhoneRequired { get; set; } - public bool FaxEnabled { get; set; } - public bool FaxRequired { get; set; } [SmartResourceDisplayName("Address.Fields.FaxNumber")] [AllowHtml] - public string FaxNumber { get; set; } + [DataType(DataType.PhoneNumber)] + public string FaxNumber { get; set; } + public bool FaxEnabled { get; set; } + public bool FaxRequired { get; set; } public IList AvailableCountries { get; set; } public IList AvailableStates { get; set; } } -} \ No newline at end of file +} diff --git a/src/Presentation/SmartStore.Web/Models/Common/CompareDropdownModel.cs b/src/Presentation/SmartStore.Web/Models/Common/CompareDropdownModel.cs index 8e4c279077..d8d32376fc 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/CompareDropdownModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/CompareDropdownModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/ContactUsModel.cs b/src/Presentation/SmartStore.Web/Models/Common/ContactUsModel.cs index 4965525cea..db9ab838bc 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/ContactUsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/ContactUsModel.cs @@ -1,17 +1,24 @@ -using System.Web.Mvc; +using System.ComponentModel.DataAnnotations; +using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Common; namespace SmartStore.Web.Models.Common { - [Validator(typeof(ContactUsValidator))] + [Validator(typeof(ContactUsValidator))] public partial class ContactUsModel : ModelBase { + [SmartResourceDisplayName("ContactUs.PrivacyAgreement")] + public bool PrivacyAgreement { get; set; } + + public bool DisplayPrivacyAgreement { get; set; } + [AllowHtml] [SmartResourceDisplayName("ContactUs.Email")] - public string Email { get; set; } + [DataType(DataType.EmailAddress)] + public string Email { get; set; } [AllowHtml] [SmartResourceDisplayName("ContactUs.Enquiry")] diff --git a/src/Presentation/SmartStore.Web/Models/Common/CurrencyModel.cs b/src/Presentation/SmartStore.Web/Models/Common/CurrencyModel.cs index 730a2ee0fb..f9048e5d37 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/CurrencyModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/CurrencyModel.cs @@ -1,12 +1,10 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { public partial class CurrencyModel : EntityModelBase { public string Name { get; set; } - - // codehint: sm-add public string ISOCode { get; set; } public string Symbol { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/Common/CurrencySelectorModel.cs b/src/Presentation/SmartStore.Web/Models/Common/CurrencySelectorModel.cs index 7c5b6e0bab..ec2ff8e876 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/CurrencySelectorModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/CurrencySelectorModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/EntityPickerModel.cs b/src/Presentation/SmartStore.Web/Models/Common/EntityPickerModel.cs new file mode 100644 index 0000000000..c83422b7f2 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Models/Common/EntityPickerModel.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Web.Mvc; +using SmartStore.Web.Framework; +using SmartStore.Web.Framework.Modelling; + +namespace SmartStore.Web.Models.Common +{ + public class EntityPickerModel : ModelBase + { + public string AllString { get; set; } + public string PublishedString { get; set; } + public string UnpublishedString { get; set; } + + public string Entity { get; set; } + public bool HighligtSearchTerm { get; set; } + public string DisableIf { get; set; } + public string DisableIds { get; set; } + public string SearchTerm { get; set; } + public string ReturnField { get; set; } + public int MaxReturnValues { get; set; } + public int PageIndex { get; set; } + public int PageSize { get; set; } + + public List SearchResult { get; set; } + + #region Products + + [SmartResourceDisplayName("Admin.Catalog.Products.List.SearchProductName")] + public string ProductName { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Products.List.SearchCategory")] + public int CategoryId { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Products.List.SearchManufacturer")] + public int ManufacturerId { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Products.List.SearchStore")] + public int StoreId { get; set; } + + [SmartResourceDisplayName("Admin.Catalog.Products.List.SearchProductType")] + public int ProductTypeId { get; set; } + + public IList AvailableCategories { get; set; } + public IList AvailableManufacturers { get; set; } + public IList AvailableStores { get; set; } + public IList AvailableProductTypes { get; set; } + + #endregion + + public class SearchResultModel : EntityModelBase + { + public string ReturnValue { get; set; } + public string Title { get; set; } + public string Summary { get; set; } + public string SummaryTitle { get; set; } + public bool? Published { get; set; } + public bool Disable { get; set; } + public string ImageUrl { get; set; } + public string LabelText { get; set; } + public string LabelClassName { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Common/FooterModel.cs b/src/Presentation/SmartStore.Web/Models/Common/FooterModel.cs index 67aea71c20..a6911f9e67 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/FooterModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/FooterModel.cs @@ -1,15 +1,10 @@ -using SmartStore.Web.Framework.Mvc; -using System.Collections.Generic; +using System.Collections.Generic; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { public partial class FooterModel : ModelBase { - public FooterModel() - { - Topics = new Dictionary(); - } - public string StoreName { get; set; } public string LegalInfo { get; set; } @@ -20,7 +15,6 @@ public FooterModel() public bool HideNewsletterBlock { get; set; } public bool BlogEnabled { get; set; } public bool ForumEnabled { get; set; } - public Dictionary Topics { get; set; } public bool ShowSocialLinks { get; set; } public string FacebookLink { get; set; } @@ -28,5 +22,7 @@ public FooterModel() public string TwitterLink { get; set; } public string PinterestLink { get; set; } public string YoutubeLink { get; set; } - } + + public Dictionary TopicPageUrls { get; set; } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Common/HeaderLinksModel.cs b/src/Presentation/SmartStore.Web/Models/Common/HeaderLinksModel.cs index f1eb44279c..a3a794535d 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/HeaderLinksModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/HeaderLinksModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/InfoBlockModel.cs b/src/Presentation/SmartStore.Web/Models/Common/InfoBlockModel.cs index 872c97d1d6..5678d3938b 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/InfoBlockModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/InfoBlockModel.cs @@ -1,4 +1,5 @@ -using SmartStore.Web.Framework.Mvc; +using System.Collections.Generic; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { @@ -11,5 +12,7 @@ public partial class InfoBlockModel : ModelBase public bool SitemapEnabled { get; set; } public bool ForumEnabled { get; set; } public bool AllowPrivateMessages { get; set; } - } + + public Dictionary TopicPageUrls { get; set; } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Common/LanguageModel.cs b/src/Presentation/SmartStore.Web/Models/Common/LanguageModel.cs index 91dbfd530b..fa5d5a0590 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/LanguageModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/LanguageModel.cs @@ -1,16 +1,13 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { public partial class LanguageModel : EntityModelBase { public string Name { get; set; } - // codehint: sm-add public string ISOCode { get; set; } public string SeoCode { get; set; } public string NativeName { get; set; } - public string ReturnUrl { get; set; } - public string FlagImageFileName { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/Common/LanguageSelectorModel.cs b/src/Presentation/SmartStore.Web/Models/Common/LanguageSelectorModel.cs index 0b26742a2c..a869b91166 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/LanguageSelectorModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/LanguageSelectorModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/MenuModel.cs b/src/Presentation/SmartStore.Web/Models/Common/MenuModel.cs index 17680fb249..c906dc18ea 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/MenuModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/MenuModel.cs @@ -1,9 +1,10 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { public partial class MenuModel : ModelBase { + public bool NewsEnabled { get; set; } public bool BlogEnabled { get; set; } public bool RecentlyAddedProductsEnabled { get; set; } public bool ForumEnabled { get; set; } @@ -12,8 +13,11 @@ public partial class MenuModel : ModelBase public int UnreadPrivateMessages { get; set; } public bool IsAuthenticated { get; set; } - public bool DisplayAdminLink { get; set; } + public bool DisplayLoginLink { get; set; } + public bool DisplayAdminLink { get; set; } public bool IsCustomerImpersonated { get; set; } public string CustomerEmailUsername { get; set; } - } + + public bool HasContactUsPage { get; set; } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Common/PagerModel.cs b/src/Presentation/SmartStore.Web/Models/Common/PagerModel.cs index bc416d03be..a55ba04714 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/PagerModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/PagerModel.cs @@ -1,10 +1,5 @@ -using SmartStore.Core.Infrastructure; -using SmartStore.Services.Localization; - -namespace SmartStore.Web.Models.Common +namespace SmartStore.Web.Models.Common { - //codehint: sm-delete (whole PagerModel class) - #region Classes /// diff --git a/src/Presentation/SmartStore.Web/Models/Common/PaymentInfoModel.cs b/src/Presentation/SmartStore.Web/Models/Common/PaymentInfoModel.cs index 3a8460e97f..f550571863 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/PaymentInfoModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/PaymentInfoModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Catalog; using SmartStore.Web.Models.Topics; diff --git a/src/Presentation/SmartStore.Web/Models/Common/ShipmentInfoModel.cs b/src/Presentation/SmartStore.Web/Models/Common/ShipmentInfoModel.cs index b36a289de5..0567d5606a 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/ShipmentInfoModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/ShipmentInfoModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Catalog; using SmartStore.Web.Models.Topics; diff --git a/src/Presentation/SmartStore.Web/Models/Common/ShopBarModel.cs b/src/Presentation/SmartStore.Web/Models/Common/ShopBarModel.cs index 85a41134de..e517dc9c6c 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/ShopBarModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/ShopBarModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/ShopHeaderModel.cs b/src/Presentation/SmartStore.Web/Models/Common/ShopHeaderModel.cs index 4aa61f8404..f52360b057 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/ShopHeaderModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/ShopHeaderModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/ShopLogoModel.cs b/src/Presentation/SmartStore.Web/Models/Common/ShopLogoModel.cs index 34daebea13..10e4f6e8a4 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/ShopLogoModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/ShopLogoModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/SitemapModel.cs b/src/Presentation/SmartStore.Web/Models/Common/SitemapModel.cs index e32142a5ab..0f24e7c67b 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/SitemapModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/SitemapModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Catalog; using SmartStore.Web.Models.Topics; diff --git a/src/Presentation/SmartStore.Web/Models/Common/StoreThemeModel.cs b/src/Presentation/SmartStore.Web/Models/Common/StoreThemeModel.cs index d7472f77f8..e2d777357f 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/StoreThemeModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/StoreThemeModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/StoreThemeSelectorModel.cs b/src/Presentation/SmartStore.Web/Models/Common/StoreThemeSelectorModel.cs index f842b79886..51f428e3b9 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/StoreThemeSelectorModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/StoreThemeSelectorModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Common/TaxTypeSelectorModel.cs b/src/Presentation/SmartStore.Web/Models/Common/TaxTypeSelectorModel.cs index 12e6fb41ea..a28efcbc24 100644 --- a/src/Presentation/SmartStore.Web/Models/Common/TaxTypeSelectorModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Common/TaxTypeSelectorModel.cs @@ -1,5 +1,5 @@ using SmartStore.Core.Domain.Tax; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Common { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/AccountActivationModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/AccountActivationModel.cs index 1405143edc..16596efe64 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/AccountActivationModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/AccountActivationModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/BackInStockSubscriptionModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/BackInStockSubscriptionModel.cs index 7709196b2a..2248c1942a 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/BackInStockSubscriptionModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/BackInStockSubscriptionModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/ChangePasswordModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/ChangePasswordModel.cs index 4c7eacc63f..cb580e2105 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/ChangePasswordModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/ChangePasswordModel.cs @@ -2,7 +2,7 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Customer; namespace SmartStore.Web.Models.Customer diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressEditModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressEditModel.cs index e5805e1d0d..370286d602 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressEditModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressEditModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Customer diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressListModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressListModel.cs index 6c405db530..761ad41556 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressListModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerAddressListModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Customer diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerAvatarModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerAvatarModel.cs index f7cf9f5ff9..2aeedc3e16 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerAvatarModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerAvatarModel.cs @@ -1,10 +1,11 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { public partial class CustomerAvatarModel : ModelBase { public string AvatarUrl { get; set; } + public string MaxFileSize { get; set; } public CustomerNavigationModel NavigationModel { get; set; } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerBackInStockSubscriptionsModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerBackInStockSubscriptionsModel.cs index c85eada465..1087058c29 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerBackInStockSubscriptionsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerBackInStockSubscriptionsModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using SmartStore.Core; -using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerDownloadableProductsModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerDownloadableProductsModel.cs index 346e102504..77fffc7a39 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerDownloadableProductsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerDownloadableProductsModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { @@ -15,6 +15,7 @@ public CustomerDownloadableProductsModel() public CustomerNavigationModel NavigationModel { get; set; } #region Nested classes + public partial class DownloadableProductsModel : ModelBase { public Guid OrderItemGuid { get; set; } @@ -24,6 +25,7 @@ public partial class DownloadableProductsModel : ModelBase public int ProductId { get; set; } public string ProductName { get; set; } public string ProductSeName { get; set; } + public string ProductUrl { get; set; } public string ProductAttributes { get; set; } public int DownloadId { get; set; } @@ -31,6 +33,7 @@ public partial class DownloadableProductsModel : ModelBase public DateTime CreatedOn { get; set; } } + #endregion } diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerForumSubscriptionsModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerForumSubscriptionsModel.cs index d1d741cb24..bab1809345 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerForumSubscriptionsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerForumSubscriptionsModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using SmartStore.Core; -using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs index ed98738e60..80e9ddafef 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerInfoModel.cs @@ -1,13 +1,14 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Customer; namespace SmartStore.Web.Models.Customer { - [Validator(typeof(CustomerInfoValidator))] + [Validator(typeof(CustomerInfoValidator))] public partial class CustomerInfoModel : ModelBase { public CustomerInfoModel() @@ -20,7 +21,14 @@ public CustomerInfoModel() [SmartResourceDisplayName("Account.Fields.Email")] [AllowHtml] - public string Email { get; set; } + [DataType(DataType.EmailAddress)] + public string Email { get; set; } + + [SmartResourceDisplayName("Account.Fields.CustomerNumber")] + [AllowHtml] + public string CustomerNumber { get; set; } + public bool CustomerNumberEnabled { get; set; } + public bool DisplayCustomerNumber { get; set; } public bool CheckUsernameAvailabilityEnabled { get; set; } public bool AllowUsersToChangeUsernames { get; set; } @@ -94,13 +102,15 @@ public CustomerInfoModel() public bool PhoneRequired { get; set; } [SmartResourceDisplayName("Account.Fields.Phone")] [AllowHtml] - public string Phone { get; set; } + [DataType(DataType.PhoneNumber)] + public string Phone { get; set; } public bool FaxEnabled { get; set; } public bool FaxRequired { get; set; } [SmartResourceDisplayName("Account.Fields.Fax")] [AllowHtml] - public string Fax { get; set; } + [DataType(DataType.PhoneNumber)] + public string Fax { get; set; } public bool NewsletterEnabled { get; set; } [SmartResourceDisplayName("Account.Fields.Newsletter")] diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerNavigationModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerNavigationModel.cs index 533025a128..aea5297338 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerNavigationModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerNavigationModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerOrderListModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerOrderListModel.cs index c3e278616e..eebb536d65 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerOrderListModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerOrderListModel.cs @@ -1,19 +1,19 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Core; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { - public partial class CustomerOrderListModel : ModelBase + public partial class CustomerOrderListModel : ModelBase { public CustomerOrderListModel() { - Orders = new List(); - RecurringOrders = new List(); - CancelRecurringPaymentErrors = new List(); + RecurringOrders = new List(); + CancelRecurringPaymentErrors = new List(); } - public IList Orders { get; set; } + public PagedList Orders { get; set; } public IList RecurringOrders { get; set; } public IList CancelRecurringPaymentErrors { get; set; } @@ -21,6 +21,7 @@ public CustomerOrderListModel() #region Nested classes + public partial class OrderDetailsModel : EntityModelBase { public string OrderNumber { get; set; } @@ -29,6 +30,7 @@ public partial class OrderDetailsModel : EntityModelBase public string OrderStatus { get; set; } public DateTime CreatedOn { get; set; } } + public partial class RecurringOrderModel : EntityModelBase { public string StartDate { get; set; } @@ -39,6 +41,7 @@ public partial class RecurringOrderModel : EntityModelBase public int InitialOrderId { get; set; } public bool CanCancel { get; set; } } + #endregion } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerReturnRequestsModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerReturnRequestsModel.cs index d41eb9aefa..0e302ec53e 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerReturnRequestsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerReturnRequestsModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { @@ -15,12 +15,14 @@ public CustomerReturnRequestsModel() public CustomerNavigationModel NavigationModel { get; set; } #region Nested classes + public partial class ReturnRequestModel : EntityModelBase { public string ReturnRequestStatus { get; set; } public int ProductId { get; set; } public string ProductName { get; set; } public string ProductSeName { get; set; } + public string ProductUrl { get; set; } public int Quantity { get; set; } public string ReturnReason { get; set; } @@ -29,6 +31,7 @@ public partial class ReturnRequestModel : EntityModelBase public DateTime CreatedOn { get; set; } } + #endregion } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Customer/CustomerRewardPointsModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/CustomerRewardPointsModel.cs index dd49358347..c37089ddae 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/CustomerRewardPointsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/CustomerRewardPointsModel.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { @@ -28,7 +28,7 @@ public partial class RewardPointsHistoryModel : EntityModelBase [SmartResourceDisplayName("RewardPoints.Fields.Message")] public string Message { get; set; } - [SmartResourceDisplayName("RewardPoints.Fields.Date")] + [SmartResourceDisplayName("Common.CreatedOn")] public DateTime CreatedOn { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/Customer/ExternalAuthenticationMethodModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/ExternalAuthenticationMethodModel.cs index d85169b975..c9a81bc26b 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/ExternalAuthenticationMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/ExternalAuthenticationMethodModel.cs @@ -1,5 +1,5 @@ using System.Web.Routing; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/ForumSubscriptionModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/ForumSubscriptionModel.cs index 499092c518..a899d2cb22 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/ForumSubscriptionModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/ForumSubscriptionModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/LoginModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/LoginModel.cs index 12f55b6a38..c99aaf03e2 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/LoginModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/LoginModel.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Customer/PasswordRecoveryConfirmModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/PasswordRecoveryConfirmModel.cs index ed22787350..a31e5d72c1 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/PasswordRecoveryConfirmModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/PasswordRecoveryConfirmModel.cs @@ -2,7 +2,7 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Customer; namespace SmartStore.Web.Models.Customer diff --git a/src/Presentation/SmartStore.Web/Models/Customer/PaswordRecoveryModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/PaswordRecoveryModel.cs index cea324b284..b8581117d4 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/PaswordRecoveryModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/PaswordRecoveryModel.cs @@ -1,17 +1,19 @@ -using System.Web.Mvc; +using System.ComponentModel.DataAnnotations; +using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Customer; namespace SmartStore.Web.Models.Customer { - [Validator(typeof(PasswordRecoveryValidator))] + [Validator(typeof(PasswordRecoveryValidator))] public partial class PasswordRecoveryModel : ModelBase { [AllowHtml] [SmartResourceDisplayName("Account.PasswordRecovery.Email")] - public string Email { get; set; } + [DataType(DataType.EmailAddress)] + public string Email { get; set; } public string Result { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/Customer/RegisterModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/RegisterModel.cs index 2a9e1b44a4..4d1a445e2d 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/RegisterModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/RegisterModel.cs @@ -3,7 +3,7 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Customer; namespace SmartStore.Web.Models.Customer @@ -20,7 +20,8 @@ public RegisterModel() [SmartResourceDisplayName("Account.Fields.Email")] [AllowHtml] - public string Email { get; set; } + [DataType(DataType.EmailAddress)] + public string Email { get; set; } public bool UsernamesEnabled { get; set; } [SmartResourceDisplayName("Account.Fields.Username")] @@ -104,13 +105,15 @@ public RegisterModel() public bool PhoneRequired { get; set; } [SmartResourceDisplayName("Account.Fields.Phone")] [AllowHtml] - public string Phone { get; set; } + [DataType(DataType.PhoneNumber)] + public string Phone { get; set; } public bool FaxEnabled { get; set; } public bool FaxRequired { get; set; } [SmartResourceDisplayName("Account.Fields.Fax")] [AllowHtml] - public string Fax { get; set; } + [DataType(DataType.PhoneNumber)] + public string Fax { get; set; } public bool NewsletterEnabled { get; set; } [SmartResourceDisplayName("Account.Fields.Newsletter")] @@ -127,6 +130,7 @@ public RegisterModel() public string VatNumber { get; set; } public string VatNumberStatusNote { get; set; } public bool DisplayVatNumber { get; set; } + public bool VatRequired { get; set; } public bool DisplayCaptcha { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/Customer/RegisterResultModel.cs b/src/Presentation/SmartStore.Web/Models/Customer/RegisterResultModel.cs index 6942031829..9330b13339 100644 --- a/src/Presentation/SmartStore.Web/Models/Customer/RegisterResultModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Customer/RegisterResultModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Customer { diff --git a/src/Presentation/SmartStore.Web/Models/Filter/ProductFilterModel.cs b/src/Presentation/SmartStore.Web/Models/Filter/ProductFilterModel.cs index 9a285c5384..a53bd91670 100644 --- a/src/Presentation/SmartStore.Web/Models/Filter/ProductFilterModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Filter/ProductFilterModel.cs @@ -1,14 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using SmartStore.Web.Framework.Mvc; -using SmartStore.Services.Filter; +using SmartStore.Services.Filter; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Filter { public partial class ProductFilterModel : ModelBase { public FilterProductContext Context { get; set; } - } // class + + public bool IsShowAllText { get; set; } + + public int MaxFilterItemsToDisplay { get; set; } + + public bool ExpandAllFilterGroups { get; set; } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Install/InstallModel.cs b/src/Presentation/SmartStore.Web/Models/Install/InstallModel.cs index c0556266fa..c50cac8d06 100644 --- a/src/Presentation/SmartStore.Web/Models/Install/InstallModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Install/InstallModel.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.Web.Mvc; using FluentValidation.Attributes; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.Install; namespace SmartStore.Web.Models.Install @@ -13,7 +13,6 @@ public partial class InstallModel : ModelBase public InstallModel() { this.AvailableLanguages = new List(); - // codehint: sm-add this.AvailableAppLanguages = new List(); this.AvailableMediaStorages = new List(); } @@ -53,7 +52,6 @@ public InstallModel() public List AvailableLanguages { get; set; } - // codehint: sm-add public string PrimaryLanguage { get; set; } public List AvailableAppLanguages { get; set; } public string MediaStorage { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/Media/PictureModel.cs b/src/Presentation/SmartStore.Web/Models/Media/PictureModel.cs index 8c4b4c48d6..352676256c 100644 --- a/src/Presentation/SmartStore.Web/Models/Media/PictureModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Media/PictureModel.cs @@ -1,13 +1,12 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Media { public partial class PictureModel : ModelBase { - // codehint: sm-add public int PictureId { get; set; } - public string ThumbImageUrl { get; set; } // codehint: sm-add + public string ThumbImageUrl { get; set; } public string ImageUrl { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/News/AddNewsCommentModel.cs b/src/Presentation/SmartStore.Web/Models/News/AddNewsCommentModel.cs index a990d4ba86..8fd2495661 100644 --- a/src/Presentation/SmartStore.Web/Models/News/AddNewsCommentModel.cs +++ b/src/Presentation/SmartStore.Web/Models/News/AddNewsCommentModel.cs @@ -1,6 +1,6 @@ using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.News { diff --git a/src/Presentation/SmartStore.Web/Models/News/HomePageNewsItemsModel.cs b/src/Presentation/SmartStore.Web/Models/News/HomePageNewsItemsModel.cs index 4439f524f3..2462025a1d 100644 --- a/src/Presentation/SmartStore.Web/Models/News/HomePageNewsItemsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/News/HomePageNewsItemsModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.News { diff --git a/src/Presentation/SmartStore.Web/Models/News/NewsCommentModel.cs b/src/Presentation/SmartStore.Web/Models/News/NewsCommentModel.cs index d6ca5c0f54..0be2e50419 100644 --- a/src/Presentation/SmartStore.Web/Models/News/NewsCommentModel.cs +++ b/src/Presentation/SmartStore.Web/Models/News/NewsCommentModel.cs @@ -1,5 +1,5 @@ using System; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.News { diff --git a/src/Presentation/SmartStore.Web/Models/News/NewsItemListModel.cs b/src/Presentation/SmartStore.Web/Models/News/NewsItemListModel.cs index ca2afa0f8e..ff5ba23165 100644 --- a/src/Presentation/SmartStore.Web/Models/News/NewsItemListModel.cs +++ b/src/Presentation/SmartStore.Web/Models/News/NewsItemListModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.News { diff --git a/src/Presentation/SmartStore.Web/Models/News/NewsItemModel.cs b/src/Presentation/SmartStore.Web/Models/News/NewsItemModel.cs index 3e4eb262e4..3870d06898 100644 --- a/src/Presentation/SmartStore.Web/Models/News/NewsItemModel.cs +++ b/src/Presentation/SmartStore.Web/Models/News/NewsItemModel.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using FluentValidation.Attributes; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.News; namespace SmartStore.Web.Models.News @@ -34,7 +34,6 @@ public NewsItemModel() public IList Comments { get; set; } public AddNewsCommentModel AddNewComment { get; set; } - // codehint: sm-add public int AvatarPictureSize { get; set; } public bool AllowCustomersToUploadAvatars { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Models/News/NewsPagingFilteringModel.cs b/src/Presentation/SmartStore.Web/Models/News/NewsPagingFilteringModel.cs index 326dc22682..e5ffffbacd 100644 --- a/src/Presentation/SmartStore.Web/Models/News/NewsPagingFilteringModel.cs +++ b/src/Presentation/SmartStore.Web/Models/News/NewsPagingFilteringModel.cs @@ -1,9 +1,7 @@ using SmartStore.Core; -// codehint: sm-delete namespace SmartStore.Web.Models.News { - // codehint: sm-edit public partial class NewsPagingFilteringModel : PagedListBase { } diff --git a/src/Presentation/SmartStore.Web/Models/Newsletter/NewsletterBoxModel.cs b/src/Presentation/SmartStore.Web/Models/Newsletter/NewsletterBoxModel.cs index d74ee82698..d0a54a2571 100644 --- a/src/Presentation/SmartStore.Web/Models/Newsletter/NewsletterBoxModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Newsletter/NewsletterBoxModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Newsletter { diff --git a/src/Presentation/SmartStore.Web/Models/Newsletter/SubscriptionActivationModel.cs b/src/Presentation/SmartStore.Web/Models/Newsletter/SubscriptionActivationModel.cs index 3494a8dbdf..582c127a29 100644 --- a/src/Presentation/SmartStore.Web/Models/Newsletter/SubscriptionActivationModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Newsletter/SubscriptionActivationModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Newsletter { diff --git a/src/Presentation/SmartStore.Web/Models/Order/OrderDetailsModel.cs b/src/Presentation/SmartStore.Web/Models/Order/OrderDetailsModel.cs index 3c28a7be82..c4b4773f3a 100644 --- a/src/Presentation/SmartStore.Web/Models/Order/OrderDetailsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Order/OrderDetailsModel.cs @@ -1,16 +1,20 @@ using System; using System.Collections.Generic; using SmartStore.Core.Domain.Catalog; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Core.Domain.Common; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Order { - public partial class OrderDetailsModel : EntityModelBase + + public partial class OrderDetailsModel : EntityModelBase { public OrderDetailsModel() { - TaxRates = new List(); + MerchantCompanyInfo = new CompanyInformationSettings(); + + TaxRates = new List(); GiftCards = new List(); Items = new List(); OrderNotes = new List(); @@ -20,9 +24,13 @@ public OrderDetailsModel() ShippingAddress = new AddressModel(); } + public int StoreId { get; set; } + + public CompanyInformationSettings MerchantCompanyInfo { get; set; } + public string OrderNumber { get; set; } - public bool PrintMode { get; set; } public bool DisplayPdfInvoice { get; set; } + public bool RenderOrderNotes { get; set; } public DateTime CreatedOn { get; set; } @@ -81,12 +89,13 @@ public OrderItemModel() public int ProductId { get; set; } public string ProductName { get; set; } public string ProductSeName { get; set; } + public string ProductUrl { get; set; } public ProductType ProductType { get; set; } public string UnitPrice { get; set; } public string SubTotal { get; set; } public int Quantity { get; set; } + public string QuantityUnit { get; set; } public string AttributeInfo { get; set; } - public bool BundlePerItemPricing { get; set; } public bool BundlePerItemShoppingCart { get; set; } @@ -98,6 +107,7 @@ public partial class BundleItemModel : ModelBase public string Sku { get; set; } public string ProductName { get; set; } public string ProductSeName { get; set; } + public string ProductUrl { get; set; } public bool VisibleIndividually { get; set; } public int Quantity { get; set; } public int DisplayOrder { get; set; } @@ -109,13 +119,15 @@ public partial class TaxRate : ModelBase { public string Rate { get; set; } public string Value { get; set; } + public string Label { get; set; } } public partial class GiftCard : ModelBase { public string CouponCode { get; set; } public string Amount { get; set; } - } + public string Remaining { get; set; } + } public partial class OrderNote : ModelBase { diff --git a/src/Presentation/SmartStore.Web/Models/Order/ShipmentDetailsModel.cs b/src/Presentation/SmartStore.Web/Models/Order/ShipmentDetailsModel.cs index 1ffdd4270e..c935a596f1 100644 --- a/src/Presentation/SmartStore.Web/Models/Order/ShipmentDetailsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Order/ShipmentDetailsModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Order { @@ -30,6 +30,7 @@ public partial class ShipmentItemModel : EntityModelBase public int ProductId { get; set; } public string ProductName { get; set; } public string ProductSeName { get; set; } + public string ProductUrl { get; set; } public string AttributeInfo { get; set; } public int QuantityOrdered { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/Order/SubmitReturnRequestModel.cs b/src/Presentation/SmartStore.Web/Models/Order/SubmitReturnRequestModel.cs index 7592a3c785..5e5e837a55 100644 --- a/src/Presentation/SmartStore.Web/Models/Order/SubmitReturnRequestModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Order/SubmitReturnRequestModel.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Order { @@ -44,6 +44,8 @@ public partial class OrderItemModel : EntityModelBase public string ProductSeName { get; set; } + public string ProductUrl { get; set; } + public string AttributeInfo { get; set; } public string UnitPrice { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/Polls/PollModel.cs b/src/Presentation/SmartStore.Web/Models/Polls/PollModel.cs index 0475127251..f4fa173939 100644 --- a/src/Presentation/SmartStore.Web/Models/Polls/PollModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Polls/PollModel.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Polls { diff --git a/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageListModel.cs b/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageListModel.cs index 07e7275191..ebe3930685 100644 --- a/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageListModel.cs +++ b/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageListModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using SmartStore.Core; -using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.PrivateMessages { diff --git a/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageModel.cs b/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageModel.cs index a383d89518..f30fc6ea1f 100644 --- a/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageModel.cs +++ b/src/Presentation/SmartStore.Web/Models/PrivateMessages/PrivateMessageModel.cs @@ -1,6 +1,6 @@ using System; using FluentValidation.Attributes; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.PrivateMessages; namespace SmartStore.Web.Models.PrivateMessages diff --git a/src/Presentation/SmartStore.Web/Models/PrivateMessages/SendPrivateMessageModel.cs b/src/Presentation/SmartStore.Web/Models/PrivateMessages/SendPrivateMessageModel.cs index da8fdf3241..0736872b33 100644 --- a/src/Presentation/SmartStore.Web/Models/PrivateMessages/SendPrivateMessageModel.cs +++ b/src/Presentation/SmartStore.Web/Models/PrivateMessages/SendPrivateMessageModel.cs @@ -1,6 +1,6 @@ using System.Web.Mvc; using FluentValidation.Attributes; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.PrivateMessages; namespace SmartStore.Web.Models.PrivateMessages diff --git a/src/Presentation/SmartStore.Web/Models/Profile/ProfilePostsModel.cs b/src/Presentation/SmartStore.Web/Models/Profile/ProfilePostsModel.cs index 6c8b5fb70e..be4da001b8 100644 --- a/src/Presentation/SmartStore.Web/Models/Profile/ProfilePostsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Profile/ProfilePostsModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using SmartStore.Core; -using SmartStore.Web.Models.Common; namespace SmartStore.Web.Models.Profile { diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/ButtonPaymentMethodModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/ButtonPaymentMethodModel.cs index 8949d991a4..1282a50501 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/ButtonPaymentMethodModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/ButtonPaymentMethodModel.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Web.Routing; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.ShoppingCart { diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs index aed18dadf1..d0f241a1e1 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/EstimateShippingModel.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.ShoppingCart { @@ -18,6 +18,8 @@ public EstimateShippingModel() public bool Enabled { get; set; } + public string ShippingInfoUrl { get; set; } + public IList ShippingOptions { get; set; } public IList Warnings { get; set; } @@ -36,6 +38,8 @@ public EstimateShippingModel() public partial class ShippingOptionModel : ModelBase { + public int ShippingMethodId { get; set; } + public string Name { get; set; } public string Description { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/MiniShoppingCartModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/MiniShoppingCartModel.cs index d7093304de..6f69774664 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/MiniShoppingCartModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/MiniShoppingCartModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; -using SmartStore.Core.Domain.Catalog; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Media; namespace SmartStore.Web.Models.ShoppingCart @@ -40,6 +39,8 @@ public ShoppingCartItemModel() public string ProductSeName { get; set; } + public string ProductUrl { get; set; } + public int Quantity { get; set; } public string UnitPrice { get; set; } @@ -57,6 +58,7 @@ public partial class ShoppingCartItemBundleItem : ModelBase public string PictureUrl { get; set; } public string ProductName { get; set; } public string ProductSeName { get; set; } + public string ProductUrl { get; set; } } #endregion diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/OrderTotalsModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/OrderTotalsModel.cs index 79c95caef2..b1f0826ee6 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/OrderTotalsModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/OrderTotalsModel.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.ShoppingCart { @@ -27,8 +27,8 @@ public OrderTotalsModel() public IList TaxRates { get; set; } public bool DisplayTax { get; set; } public bool DisplayTaxRates { get; set; } - - + public bool DisplayWeight { get; set; } + public IList GiftCards { get; set; } public string OrderTotalDiscount { get; set; } @@ -36,6 +36,7 @@ public OrderTotalsModel() public int RedeemedRewardPoints { get; set; } public string RedeemedRewardPointsAmount { get; set; } public string OrderTotal { get; set; } + public decimal Weight { get; set; } #region Nested classes @@ -43,6 +44,7 @@ public partial class TaxRate: ModelBase { public string Rate { get; set; } public string Value { get; set; } + public string Label { get; set; } } public partial class GiftCard : EntityModelBase diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/ShoppingCartModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/ShoppingCartModel.cs index 468d1fd680..e8c08f9810 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/ShoppingCartModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/ShoppingCartModel.cs @@ -1,7 +1,8 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Core.Domain.Catalog; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Core.Domain.Orders; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Common; using SmartStore.Web.Models.Media; @@ -43,13 +44,27 @@ public ShoppingCartModel() public int BundleThumbSize { get; set; } public bool DisplayDeliveryTime { get; set; } public bool DisplayShortDesc { get; set; } + public bool DisplayWeight { get; set; } public bool DisplayBasePrice { get; set; } public ButtonPaymentMethodModel ButtonPaymentMethods { get; set; } + public bool DisplayCommentBox { get; set; } + public string CustomerComment { get; set; } + public string MeasureUnitName { get; set; } + + public CheckoutNewsLetterSubscription NewsLetterSubscription { get; set; } + public bool? SubscribeToNewsLetter { get; set; } + + public CheckoutThirdPartyEmailHandOver ThirdPartyEmailHandOver { get; set; } + public string ThirdPartyEmailHandOverLabel { get; set; } + public bool? AcceptThirdPartyEmailHandOver { get; set; } + + public bool DisplayEsdRevocationWaiverBox { get; set; } + #region Nested Classes - public partial class ShoppingCartItemModel : EntityModelBase + public partial class ShoppingCartItemModel : EntityModelBase { public ShoppingCartItemModel() { @@ -69,6 +84,8 @@ public ShoppingCartItemModel() public string ProductSeName { get; set; } + public string ProductUrl { get; set; } + public bool VisibleIndividually { get; set; } public ProductType ProductType { get; set; } @@ -88,16 +105,25 @@ public ShoppingCartItemModel() public IList Warnings { get; set; } + public decimal Weight { get; set; } + public bool IsShipEnabled { get; set; } + public string QuantityUnit { get; set; } + public string DeliveryTimeName { get; set; } public string DeliveryTimeHexValue { get; set; } public string ShortDesc { get; set; } - + public string BasePrice { get; set; } + public bool IsDownload { get; set; } + public bool HasUserAgreement { get; set; } + + public bool IsEsd { get; set; } + public bool BundlePerItemPricing { get; set; } public bool BundlePerItemShoppingCart { get; set; } public BundleItemModel BundleItem { get; set; } @@ -182,6 +208,9 @@ public OrderReviewDataModel() public string ShippingMethod { get; set; } public string PaymentMethod { get; set; } + public string PaymentSummary { get; set; } + + public bool IsPaymentSelectionSkipped { get; set; } } #endregion } diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistEmailAFriendModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistEmailAFriendModel.cs index aa515a6d0b..4c87a4991b 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistEmailAFriendModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistEmailAFriendModel.cs @@ -1,7 +1,7 @@ using System.Web.Mvc; using FluentValidation.Attributes; using SmartStore.Web.Framework; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Validators.ShoppingCart; namespace SmartStore.Web.Models.ShoppingCart diff --git a/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistModel.cs b/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistModel.cs index a38cc246df..2ceba4c312 100644 --- a/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistModel.cs +++ b/src/Presentation/SmartStore.Web/Models/ShoppingCart/WishlistModel.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Web.Mvc; using SmartStore.Core.Domain.Catalog; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; using SmartStore.Web.Models.Media; namespace SmartStore.Web.Models.ShoppingCart @@ -32,12 +32,12 @@ public WishlistModel() public IList Warnings { get; set; } - // codehint: sm-add public int ThumbSize { get; set; } public int BundleThumbSize { get; set; } public int IgnoredProductsCount { get; set; } public bool DisplayShortDesc { get; set; } public bool ShowProductBundleImages { get; set; } + public bool ShowItemsFromWishlistToCartButton { get; set; } #region Nested Classes @@ -51,6 +51,7 @@ public ShoppingCartItemModel() ChildItems = new List(); BundleItem = new BundleItemModel(); } + public string Sku { get; set; } public PictureModel Picture {get;set;} @@ -61,6 +62,8 @@ public ShoppingCartItemModel() public string ProductSeName { get; set; } + public string ProductUrl { get; set; } + public bool VisibleIndividually { get; set; } public ProductType ProductType { get; set; } diff --git a/src/Presentation/SmartStore.Web/Models/Topics/TopicModel.cs b/src/Presentation/SmartStore.Web/Models/Topics/TopicModel.cs index ebe43c7fad..96548a4559 100644 --- a/src/Presentation/SmartStore.Web/Models/Topics/TopicModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Topics/TopicModel.cs @@ -1,4 +1,4 @@ -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Topics { @@ -19,5 +19,9 @@ public partial class TopicModel : EntityModelBase public string MetaDescription { get; set; } public string MetaTitle { get; set; } - } + + public string TitleTag { get; set; } + + public bool RenderAsWidget { get; set; } + } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Models/Topics/TopicWidgetModel.cs b/src/Presentation/SmartStore.Web/Models/Topics/TopicWidgetModel.cs index 1339a1bd25..07d465763c 100644 --- a/src/Presentation/SmartStore.Web/Models/Topics/TopicWidgetModel.cs +++ b/src/Presentation/SmartStore.Web/Models/Topics/TopicWidgetModel.cs @@ -1,5 +1,4 @@ -using System.Web.Routing; -using SmartStore.Web.Framework.Mvc; +using SmartStore.Web.Framework.Modelling; namespace SmartStore.Web.Models.Topics { @@ -8,7 +7,9 @@ public partial class TopicWidgetModel : EntityModelBase public string SystemName { get; set; } public string Title { get; set; } public string Html { get; set; } - + public string TitleTag { get; set; } + + public bool WrapContent { get; set; } public bool ShowTitle { get; set; } public bool IsBordered { get; set; } } diff --git a/src/Presentation/SmartStore.Web/Scripts/2012.2.607/jquery.validate.min.js b/src/Presentation/SmartStore.Web/Scripts/2012.2.607/jquery.validate.min.js deleted file mode 100644 index 7ab1d85b29..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/2012.2.607/jquery.validate.min.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * jQuery Validation Plugin 1.8.0 - * - * http://bassistance.de/jquery-plugins/jquery-plugin-validation/ - * http://docs.jquery.com/Plugins/Validation - * - * Copyright (c) 2006 - 2011 Jörn Zaefferer - * - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - */ -(function(c){c.extend(c.fn,{validate:function(a){if(this.length){var b=c.data(this[0],"validator");if(b)return b;b=new c.validator(a,this[0]);c.data(this[0],"validator",b);if(b.settings.onsubmit){this.find("input, button").filter(".cancel").click(function(){b.cancelSubmit=true});b.settings.submitHandler&&this.find("input, button").filter(":submit").click(function(){b.submitButton=this});this.submit(function(d){function e(){if(b.settings.submitHandler){if(b.submitButton)var f=c("").attr("name", -b.submitButton.name).val(b.submitButton.value).appendTo(b.currentForm);b.settings.submitHandler.call(b,b.currentForm);b.submitButton&&f.remove();return false}return true}b.settings.debug&&d.preventDefault();if(b.cancelSubmit){b.cancelSubmit=false;return e()}if(b.form()){if(b.pendingRequest){b.formSubmitted=true;return false}return e()}else{b.focusInvalid();return false}})}return b}else a&&a.debug&&window.console&&console.warn("nothing selected, can't validate, returning nothing")},valid:function(){if(c(this[0]).is("form"))return this.validate().form(); -else{var a=true,b=c(this[0].form).validate();this.each(function(){a&=b.element(this)});return a}},removeAttrs:function(a){var b={},d=this;c.each(a.split(/\s/),function(e,f){b[f]=d.attr(f);d.removeAttr(f)});return b},rules:function(a,b){var d=this[0];if(a){var e=c.data(d.form,"validator").settings,f=e.rules,g=c.validator.staticRules(d);switch(a){case "add":c.extend(g,c.validator.normalizeRule(b));f[d.name]=g;if(b.messages)e.messages[d.name]=c.extend(e.messages[d.name],b.messages);break;case "remove":if(!b){delete f[d.name]; -return g}var h={};c.each(b.split(/\s/),function(j,i){h[i]=g[i];delete g[i]});return h}}d=c.validator.normalizeRules(c.extend({},c.validator.metadataRules(d),c.validator.classRules(d),c.validator.attributeRules(d),c.validator.staticRules(d)),d);if(d.required){e=d.required;delete d.required;d=c.extend({required:e},d)}return d}});c.extend(c.expr[":"],{blank:function(a){return!c.trim(""+a.value)},filled:function(a){return!!c.trim(""+a.value)},unchecked:function(a){return!a.checked}});c.validator=function(a, -b){this.settings=c.extend(true,{},c.validator.defaults,a);this.currentForm=b;this.init()};c.validator.format=function(a,b){if(arguments.length==1)return function(){var d=c.makeArray(arguments);d.unshift(a);return c.validator.format.apply(this,d)};if(arguments.length>2&&b.constructor!=Array)b=c.makeArray(arguments).slice(1);if(b.constructor!=Array)b=[b];c.each(b,function(d,e){a=a.replace(RegExp("\\{"+d+"\\}","g"),e)});return a};c.extend(c.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error", -validClass:"valid",errorElement:"label",focusInvalid:true,errorContainer:c([]),errorLabelContainer:c([]),onsubmit:true,ignore:[],ignoreTitle:false,onfocusin:function(a){this.lastActive=a;if(this.settings.focusCleanup&&!this.blockFocusCleanup){this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass);this.addWrapper(this.errorsFor(a)).hide()}},onfocusout:function(a){if(!this.checkable(a)&&(a.name in this.submitted||!this.optional(a)))this.element(a)}, -onkeyup:function(a){if(a.name in this.submitted||a==this.lastElement)this.element(a)},onclick:function(a){if(a.name in this.submitted)this.element(a);else a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(a,b,d){c(a).addClass(b).removeClass(d)},unhighlight:function(a,b,d){c(a).removeClass(b).addClass(d)}},setDefaults:function(a){c.extend(c.validator.defaults,a)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.", -url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",accept:"Please enter a value with a valid extension.",maxlength:c.validator.format("Please enter no more than {0} characters."),minlength:c.validator.format("Please enter at least {0} characters."),rangelength:c.validator.format("Please enter a value between {0} and {1} characters long."), -range:c.validator.format("Please enter a value between {0} and {1}."),max:c.validator.format("Please enter a value less than or equal to {0}."),min:c.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:false,prototype:{init:function(){function a(e){var f=c.data(this[0].form,"validator");e="on"+e.type.replace(/^validate/,"");f.settings[e]&&f.settings[e].call(f,this[0])}this.labelContainer=c(this.settings.errorLabelContainer);this.errorContext=this.labelContainer.length&& -this.labelContainer||c(this.currentForm);this.containers=c(this.settings.errorContainer).add(this.settings.errorLabelContainer);this.submitted={};this.valueCache={};this.pendingRequest=0;this.pending={};this.invalid={};this.reset();var b=this.groups={};c.each(this.settings.groups,function(e,f){c.each(f.split(/\s/),function(g,h){b[h]=e})});var d=this.settings.rules;c.each(d,function(e,f){d[e]=c.validator.normalizeRule(f)});c(this.currentForm).validateDelegate(":text, :password, :file, select, textarea", -"focusin focusout keyup",a).validateDelegate(":radio, :checkbox, select, option","click",a);this.settings.invalidHandler&&c(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){this.checkForm();c.extend(this.submitted,this.errorMap);this.invalid=c.extend({},this.errorMap);this.valid()||c(this.currentForm).triggerHandler("invalid-form",[this]);this.showErrors();return this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]); -return this.valid()},element:function(a){this.lastElement=a=this.clean(a);this.prepareElement(a);this.currentElements=c(a);var b=this.check(a);if(b)delete this.invalid[a.name];else this.invalid[a.name]=true;if(!this.numberOfInvalids())this.toHide=this.toHide.add(this.containers);this.showErrors();return b},showErrors:function(a){if(a){c.extend(this.errorMap,a);this.errorList=[];for(var b in a)this.errorList.push({message:a[b],element:this.findByName(b)[0]});this.successList=c.grep(this.successList, -function(d){return!(d.name in a)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){c.fn.resetForm&&c(this.currentForm).resetForm();this.submitted={};this.prepareForm();this.hideErrors();this.elements().removeClass(this.settings.errorClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b=0,d;for(d in a)b++;return b},hideErrors:function(){this.addWrapper(this.toHide).hide()}, -valid:function(){return this.size()==0},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{c(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(a){}},findLastActive:function(){var a=this.lastActive;return a&&c.grep(this.errorList,function(b){return b.element.name==a.name}).length==1&&a},elements:function(){var a=this,b={};return c([]).add(this.currentForm.elements).filter(":input").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){!this.name&& -a.settings.debug&&window.console&&console.error("%o has no name assigned",this);if(this.name in b||!a.objectLength(c(this).rules()))return false;return b[this.name]=true})},clean:function(a){return c(a)[0]},errors:function(){return c(this.settings.errorElement+"."+this.settings.errorClass,this.errorContext)},reset:function(){this.successList=[];this.errorList=[];this.errorMap={};this.toShow=c([]);this.toHide=c([]);this.currentElements=c([])},prepareForm:function(){this.reset();this.toHide=this.errors().add(this.containers)}, -prepareElement:function(a){this.reset();this.toHide=this.errorsFor(a)},check:function(a){a=this.clean(a);if(this.checkable(a))a=this.findByName(a.name).not(this.settings.ignore)[0];var b=c(a).rules(),d=false,e;for(e in b){var f={method:e,parameters:b[e]};try{var g=c.validator.methods[e].call(this,a.value.replace(/\r/g,""),a,f.parameters);if(g=="dependency-mismatch")d=true;else{d=false;if(g=="pending"){this.toHide=this.toHide.not(this.errorsFor(a));return}if(!g){this.formatAndAdd(a,f);return false}}}catch(h){this.settings.debug&& -window.console&&console.log("exception occured when checking element "+a.id+", check the '"+f.method+"' method",h);throw h;}}if(!d){this.objectLength(b)&&this.successList.push(a);return true}},customMetaMessage:function(a,b){if(c.metadata){var d=this.settings.meta?c(a).metadata()[this.settings.meta]:c(a).metadata();return d&&d.messages&&d.messages[b]}},customMessage:function(a,b){var d=this.settings.messages[a];return d&&(d.constructor==String?d:d[b])},findDefined:function(){for(var a=0;aWarning: No message defined for "+a.name+"")},formatAndAdd:function(a,b){var d=this.defaultMessage(a,b.method),e=/\$?\{(\d+)\}/g;if(typeof d=="function")d=d.call(this,b.parameters,a);else if(e.test(d))d=jQuery.format(d.replace(e,"{$1}"),b.parameters);this.errorList.push({message:d, -element:a});this.errorMap[a.name]=d;this.submitted[a.name]=d},addWrapper:function(a){if(this.settings.wrapper)a=a.add(a.parent(this.settings.wrapper));return a},defaultShowErrors:function(){for(var a=0;this.errorList[a];a++){var b=this.errorList[a];this.settings.highlight&&this.settings.highlight.call(this,b.element,this.settings.errorClass,this.settings.validClass);this.showLabel(b.element,b.message)}if(this.errorList.length)this.toShow=this.toShow.add(this.containers);if(this.settings.success)for(a= -0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight){a=0;for(b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass)}this.toHide=this.toHide.not(this.toShow);this.hideErrors();this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return c(this.errorList).map(function(){return this.element})},showLabel:function(a, -b){var d=this.errorsFor(a);if(d.length){d.removeClass().addClass(this.settings.errorClass);d.attr("generated")&&d.html(b)}else{d=c("<"+this.settings.errorElement+"/>").attr({"for":this.idOrName(a),generated:true}).addClass(this.settings.errorClass).html(b||"");if(this.settings.wrapper)d=d.hide().show().wrap("<"+this.settings.wrapper+"/>").parent();this.labelContainer.append(d).length||(this.settings.errorPlacement?this.settings.errorPlacement(d,c(a)):d.insertAfter(a))}if(!b&&this.settings.success){d.text(""); -typeof this.settings.success=="string"?d.addClass(this.settings.success):this.settings.success(d)}this.toShow=this.toShow.add(d)},errorsFor:function(a){var b=this.idOrName(a);return this.errors().filter(function(){return c(this).attr("for")==b})},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(a){var b=this.currentForm;return c(document.getElementsByName(a)).map(function(d,e){return e.form== -b&&e.name==a&&e||null})},getLength:function(a,b){switch(b.nodeName.toLowerCase()){case "select":return c("option:selected",b).length;case "input":if(this.checkable(b))return this.findByName(b.name).filter(":checked").length}return a.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):true},dependTypes:{"boolean":function(a){return a},string:function(a,b){return!!c(a,b.form).length},"function":function(a,b){return a(b)}},optional:function(a){return!c.validator.methods.required.call(this, -c.trim(a.value),a)&&"dependency-mismatch"},startRequest:function(a){if(!this.pending[a.name]){this.pendingRequest++;this.pending[a.name]=true}},stopRequest:function(a,b){this.pendingRequest--;if(this.pendingRequest<0)this.pendingRequest=0;delete this.pending[a.name];if(b&&this.pendingRequest==0&&this.formSubmitted&&this.form()){c(this.currentForm).submit();this.formSubmitted=false}else if(!b&&this.pendingRequest==0&&this.formSubmitted){c(this.currentForm).triggerHandler("invalid-form",[this]);this.formSubmitted= -false}},previousValue:function(a){return c.data(a,"previousValue")||c.data(a,"previousValue",{old:null,valid:true,message:this.defaultMessage(a,"remote")})}},classRuleSettings:{required:{required:true},email:{email:true},url:{url:true},date:{date:true},dateISO:{dateISO:true},dateDE:{dateDE:true},number:{number:true},numberDE:{numberDE:true},digits:{digits:true},creditcard:{creditcard:true}},addClassRules:function(a,b){a.constructor==String?this.classRuleSettings[a]=b:c.extend(this.classRuleSettings, -a)},classRules:function(a){var b={};(a=c(a).attr("class"))&&c.each(a.split(" "),function(){this in c.validator.classRuleSettings&&c.extend(b,c.validator.classRuleSettings[this])});return b},attributeRules:function(a){var b={};a=c(a);for(var d in c.validator.methods){var e=a.attr(d);if(e)b[d]=e}b.maxlength&&/-1|2147483647|524288/.test(b.maxlength)&&delete b.maxlength;return b},metadataRules:function(a){if(!c.metadata)return{};var b=c.data(a.form,"validator").settings.meta;return b?c(a).metadata()[b]: -c(a).metadata()},staticRules:function(a){var b={},d=c.data(a.form,"validator");if(d.settings.rules)b=c.validator.normalizeRule(d.settings.rules[a.name])||{};return b},normalizeRules:function(a,b){c.each(a,function(d,e){if(e===false)delete a[d];else if(e.param||e.depends){var f=true;switch(typeof e.depends){case "string":f=!!c(e.depends,b.form).length;break;case "function":f=e.depends.call(b,b)}if(f)a[d]=e.param!==undefined?e.param:true;else delete a[d]}});c.each(a,function(d,e){a[d]=c.isFunction(e)? -e(b):e});c.each(["minlength","maxlength","min","max"],function(){if(a[this])a[this]=Number(a[this])});c.each(["rangelength","range"],function(){if(a[this])a[this]=[Number(a[this][0]),Number(a[this][1])]});if(c.validator.autoCreateRanges){if(a.min&&a.max){a.range=[a.min,a.max];delete a.min;delete a.max}if(a.minlength&&a.maxlength){a.rangelength=[a.minlength,a.maxlength];delete a.minlength;delete a.maxlength}}a.messages&&delete a.messages;return a},normalizeRule:function(a){if(typeof a=="string"){var b= -{};c.each(a.split(/\s/),function(){b[this]=true});a=b}return a},addMethod:function(a,b,d){c.validator.methods[a]=b;c.validator.messages[a]=d!=undefined?d:c.validator.messages[a];b.length<3&&c.validator.addClassRules(a,c.validator.normalizeRule(a))},methods:{required:function(a,b,d){if(!this.depend(d,b))return"dependency-mismatch";switch(b.nodeName.toLowerCase()){case "select":return(a=c(b).val())&&a.length>0;case "input":if(this.checkable(b))return this.getLength(a,b)>0;default:return c.trim(a).length> -0}},remote:function(a,b,d){if(this.optional(b))return"dependency-mismatch";var e=this.previousValue(b);this.settings.messages[b.name]||(this.settings.messages[b.name]={});e.originalMessage=this.settings.messages[b.name].remote;this.settings.messages[b.name].remote=e.message;d=typeof d=="string"&&{url:d}||d;if(this.pending[b.name])return"pending";if(e.old===a)return e.valid;e.old=a;var f=this;this.startRequest(b);var g={};g[b.name]=a;c.ajax(c.extend(true,{url:d,mode:"abort",port:"validate"+b.name, -dataType:"json",data:g,success:function(h){f.settings.messages[b.name].remote=e.originalMessage;var j=h===true;if(j){var i=f.formSubmitted;f.prepareElement(b);f.formSubmitted=i;f.successList.push(b);f.showErrors()}else{i={};h=h||f.defaultMessage(b,"remote");i[b.name]=e.message=c.isFunction(h)?h(a):h;f.showErrors(i)}e.valid=j;f.stopRequest(b,j)}},d));return"pending"},minlength:function(a,b,d){return this.optional(b)||this.getLength(c.trim(a),b)>=d},maxlength:function(a,b,d){return this.optional(b)|| -this.getLength(c.trim(a),b)<=d},rangelength:function(a,b,d){a=this.getLength(c.trim(a),b);return this.optional(b)||a>=d[0]&&a<=d[1]},min:function(a,b,d){return this.optional(b)||a>=d},max:function(a,b,d){return this.optional(b)||a<=d},range:function(a,b,d){return this.optional(b)||a>=d[0]&&a<=d[1]},email:function(a,b){return this.optional(b)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(a)}, -url:function(a,b){return this.optional(b)||/^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(a)}, -date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a))},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(a)},number:function(a,b){return this.optional(b)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9-]+/.test(a))return false;var d=0,e=0,f=false;a=a.replace(/\D/g,"");for(var g=a.length-1;g>= -0;g--){e=a.charAt(g);e=parseInt(e,10);if(f)if((e*=2)>9)e-=9;d+=e;f=!f}return d%10==0},accept:function(a,b,d){d=typeof d=="string"?d.replace(/,/g,"|"):"png|jpe?g|gif";return this.optional(b)||a.match(RegExp(".("+d+")$","i"))},equalTo:function(a,b,d){d=c(d).unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){c(b).valid()});return a==d.val()}}});c.format=c.validator.format})(jQuery); -(function(c){var a={};if(c.ajaxPrefilter)c.ajaxPrefilter(function(d,e,f){e=d.port;if(d.mode=="abort"){a[e]&&a[e].abort();a[e]=f}});else{var b=c.ajax;c.ajax=function(d){var e=("port"in d?d:c.ajaxSettings).port;if(("mode"in d?d:c.ajaxSettings).mode=="abort"){a[e]&&a[e].abort();return a[e]=b.apply(this,arguments)}return b.apply(this,arguments)}}})(jQuery); -(function(c){!jQuery.event.special.focusin&&!jQuery.event.special.focusout&&document.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.handle.call(this,e)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)},handler:function(e){arguments[0]=c.event.fix(e);arguments[0].type=b;return c.event.handle.apply(this,arguments)}}});c.extend(c.fn,{validateDelegate:function(a, -b,d){return this.bind(b,function(e){var f=c(e.target);if(f.is(a))return d.apply(f,arguments)})}})})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/2012.2.607/telerik.all.min.js b/src/Presentation/SmartStore.Web/Scripts/2012.2.607/telerik.all.min.js deleted file mode 100644 index 5a8467552b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/2012.2.607/telerik.all.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(a){try{if(document.execCommand){document.execCommand("BackgroundImageCache",false,true)}}catch(x){}var r=/\d/;var aC=/\s+/;var aB=parseInt(a.browser.version.substring(0,5).replace(".",""));var H=a.browser.mozilla&&aB>=180&&aB<=191;var s=/d{1,4}|M{1,4}|yy(?:yy)?|([Hhmstf])\1*|"[^"]*"|'[^']*'/g;var W=(navigator.userAgent.search(/like\sMac\sOS\sX;.*Mobile\/\S+/)!=-1);var X=(navigator.userAgent.search(/4_1\slike\sMac\sOS\sX;.*Mobile\/\S+/)!=-1);var aA=(function(){var e=new a.Event("triggerHandlerTest");a("
          ").triggerHandler(e);return !e.isDefaultPrevented()})();var b=a.telerik={create:function(aF,aG){var e=aG.name;var aE=a.extend({},a.fn[e].defaults,aG.options);return aF.each(function(){var aH=a(this);aE=a.meta?a.extend({},aE,aH.data()):aE;if(!aH.data(e)){var aI=aG.init(this,aE);aH.data(e,aI);b.trigger(this,"load");if(aG.success){aG.success(aI)}}})},toJson:function(e){function aF(aG){return"["+a.map(aG,aE).join(",")+"]"}function aE(aH){var aI=[];for(var aG in aH){var aJ=aH[aG];if(a.isArray(aJ)){aI.push('"'+aG+'":'+aF(aJ))}else{if(typeof aJ!="object"){aI.push('"'+aG+'":"'+(aJ==null?"":aJ)+'"')}else{aI.push('"'+aG+'":'+aE(aJ))}}}return"{"+aI.join(",")+"}"}if(a.isArray(e)){return aF(e)}else{return aE(e)}},delegate:function(e,aE){return function(aF){aE.apply(e,[aF,this])}},stop:function(aE,e){return function(aF){aF.stopPropagation();aE.apply(e||this,arguments)}},stopAll:function(aE,e){return function(aF){aF.preventDefault();aF.stopPropagation();aE.apply(e||this,arguments)}},bind:function(aE,aF){var e=a(aE.element?aE.element:aE);a.each(aF,function(aG){if(a.isFunction(this)){e.bind(aG,this)}})},preventDefault:function(aE){aE.preventDefault()},hover:function(){a(this).addClass("t-state-hover")},leave:function(){a(this).removeClass("t-state-hover")},buttonHover:function(){a(this).addClass("t-button-hover")},buttonLeave:function(){a(this).removeClass("t-button-hover")},stringBuilder:function(){this.buffer=[]},ajaxError:function(e,aE,aH,aG){var aF=this.trigger(e,aE,{XMLHttpRequest:aH,textStatus:aG});if(!aF){if(aG=="error"&&aH.status!="0"){alert("Error! The requested URL returned "+aH.status+" - "+aH.statusText)}if(aG=="timeout"){alert("Error! Server timeout.")}}return aF},trigger:function(aF,aG,aE){aE=a.extend(aE||{},new a.Event(aG));if(aA){a(aF).triggerHandler(aE)}else{aE.stopPropagation();a(aF).trigger(aE)}return aE.isDefaultPrevented()},getType:function(e){if(e instanceof Date){return"date"}if(typeof e==="number"){return"number"}return"object"},formatString:function(){var aJ=arguments[0];for(var aF=0,aG=arguments.length-1;aF-1;aF--){if(aG.substr(aF,aE)==e){return aF}}return -1},caretPos:function(e){var aE=-1;if(document.selection){aE=Math.abs(e.document.selection.createRange().moveStart("character",-e.value.length))}else{if(e.selectionStart!==undefined){aE=e.selectionStart}}return aE},encode:function(e){return e.replace(/&/g,"&").replace(//g,">").replace(/\u00a0/g," ").replace(/'/g,"'")},formatters:{},fx:{},cultureInfo:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbrDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDays:["Su","Mo","Tu","We","Th","Fr","Sa"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],abbrMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],longTime:"h:mm:ss tt",longDate:"dddd, MMMM dd, yyyy",shortDate:"M/d/yyyy",shortTime:"h:mm tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",generalDateShortTime:"M/d/yyyy h:mm tt",generalDateTime:"M/d/yyyy h:mm:ss tt",sortableDateTime:"yyyy'-'MM'-'ddTHH':'mm':'ss",universalSortableDateTime:"yyyy'-'MM'-'dd HH':'mm':'ss'Z'",monthYear:"MMMM, yyyy",monthDay:"MMMM dd",today:"today",tomorrow:"tomorrow",yesterday:"yesterday",next:"next",last:"last",year:"year",month:"month",week:"week",day:"day",am:"AM",pm:"PM",dateSeparator:"/",timeSeparator:":",firstDayOfWeek:0,currencydecimaldigits:2,currencydecimalseparator:".",currencygroupseparator:",",currencygroupsize:3,currencynegative:0,currencypositive:0,currencysymbol:"$",numericdecimaldigits:2,numericdecimalseparator:".",numericgroupseparator:",",numericgroupsize:3,numericnegative:1,percentdecimaldigits:2,percentdecimalseparator:".",percentgroupseparator:",",percentgroupsize:3,percentnegative:0,percentpositive:0,percentsymbol:"%"},patterns:{numeric:{negative:["(n)","-n","- n","n-","n -"]},currency:{positive:["*n","n*","* n","n *"],negative:["(*n)","-*n","*-n","*n-","(n*)","-n*","n-*","n*-","-n *","-* n","n *-","* n-","* -n","n- *","(* n)","(n *)"]},percent:{positive:["n *","n*","*n"],negative:["-n *","-n*","-*n"]}}};var F,V;if(Array.prototype.filter!==undefined){F=function(e,aE){return e.filter(aE)}}else{F=function(e,aG){var aH=[],aF=e.length;for(var aE=0;aE
            ').string()).addClass("t-popup t-group").hide();this.$element.delegate(".t-reset > .t-item","mouseenter",b.hover).delegate(".t-reset > .t-item","mouseleave",b.leave).delegate(".t-reset > .t-item","click",a.proxy(function(aE){if(this.onClick){this.onClick(a.extend(aE,{item:a(aE.target).closest(".t-item")[0]}))}},this));this.$element.tScrollable()};b.dropDown.prototype={_html:function(aE,aJ){var aH=new b.stringBuilder();if(aE){for(var aI=0,aK=aE.length;aI').cat(aG.html).cat("")}}return aH.string()},open:function(aF){if(this.onOpen){this.onOpen()}if(this.isOpened()||!this.$items){return}var e=this.$element,aG;if(!e.parent()[0]){e.hide().appendTo(document.body)}if(e[0].style.width==""){aG=aF.outerWidth?aF.outerWidth-2:0}else{aG=parseInt(this.attr?a("")[0].style.width:(a.browser.msie&&a.browser.version>8?e.outerWidth():e[0].style.width))}e.css("overflowY","auto").css("width",aG);var aE=aF.offset;aE.top+=aF.outerHeight;if(W){if(!document.body.scrollLeft&&!X){aE.left-=window.pageXOffset}if(!document.body.scrollTop&&!X){aE.top-=window.pageYOffset}}b.fx._wrap(e).css(a.extend({position:"absolute",zIndex:aF.zIndex},aE));if(H){e.css("overflow","hidden")}e.parent().show();b.fx.play(this.effects,e,{direction:"bottom"},a.proxy(function(){e.css("overflow","auto");if(a.browser.msie&&a.browser.version>8){var aI=e.css("height");if(aI=="auto"||aI!="100%"){e.css({height:"100%",boxSizing:"border-box"})}}var aH=this.$items.filter(".t-state-selected");if(aH.length){this.scrollTo(aH[0])}},this))},close:function(aG){if(!this.isOpened()){return}var aE=this.$element;var aF=this.$items;if(H){aE.css("overflow","hidden")}b.fx.rewind(this.effects,aE,{direction:"bottom"},function(){if(H){aE.css("overflow","auto")}if(aF){aF.removeClass("t-state-hover")}if(aE.parent(".t-animation-container")[0]){aE.parent().hide()}})},dataBind:function(aG,aJ){aG=aG||[];var e=this.$element;if(e[0].style.height=="100%"){e.css("height","auto")}var aH=e[0].style.height,aI=aH&&aH!="auto"?aH:"200px",aF=e.find("> ul");aF[0].innerHTML=this._html(aG,aJ);var aE=this.$items=aF.children();e.css("height",aE.length>10?aI:"auto")},highlight:function(e){return a(e).addClass("t-state-selected").siblings().removeClass("t-state-selected").end().index()},isOpened:function(){return this.$element.is(":visible")},scrollTo:function(aH){if(!aH){return}var aJ=aH.offsetTop;var aI=aH.offsetHeight;var aE=this.$element[0];var aG=aE.scrollTop;var aF=aE.clientHeight;var e=aJ+aI;aE.scrollTop=aG>aJ?aJ:e>(aG+aF)?e-aF:aG}};b.datetime=function(){if(arguments.length==0){this.value=new Date()}else{if(arguments.length==1){this.value=new Date(arguments[0])}else{if(arguments.length==3){this.value=new Date(arguments[0],arguments[1],arguments[2])}else{if(arguments.length==6){this.value=new Date(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5])}else{this.value=new Date(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6])}}}}return this};a.extend(b.datetime,{msPerMinute:60000,msPerDay:86400000,add:function(e,aI,aE){var aG=e.timeOffset();var aF=new b.datetime(e.time()+aI);var aH=aF.timeOffset()-aG;if(aE){return aF}return new b.datetime(aF.time()+aH*b.datetime.msPerMinute)},subtract:function(e,aE){aE=new b.datetime(aE).toDate();var aF=e.time()-aE;var aG=e.timeOffset()-aE.timeOffset();return aF-(aG*b.datetime.msPerMinute)},firstDayOfMonth:function(e){return new b.datetime(0).hours(e.hours()).minutes(e.minutes()).seconds(e.seconds()).milliseconds(e.milliseconds()).year(e.year(),e.month(),1)},dst:function(){var aF=new b.datetime(),e=new b.datetime(aF.year(),aF.month(),aF.date(),0,0,0),aE=new b.datetime(aF.year(),aF.month(),aF.date(),12,0,0);return -1*(e.timeOffset()-aE.timeOffset())},firstVisibleDay:function(e){var aE=b.cultureInfo.firstDayOfWeek;var aF=new b.datetime(e.year(),e.month(),0,e.hours(),e.minutes(),e.seconds(),e.milliseconds());while(aF.day()!=aE){b.datetime.modify(aF,-1*b.datetime.msPerDay)}return aF},modify:function(e,aH){var aF=e.timeOffset();var aE=new b.datetime(e.time()+aH);var aG=aE.timeOffset()-aF;e.time(aE.time()+aG*b.datetime.msPerMinute)},pad:function(e){if(e<10){return"0"+e}return e},standardFormat:function(e){var aE=b.cultureInfo;var aF={d:aE.shortDate,D:aE.longDate,F:aE.fullDateTime,g:aE.generalDateShortTime,G:aE.generalDateTime,m:aE.monthDay,M:aE.monthDay,s:aE.sortableDateTime,t:aE.shortTime,T:aE.longTime,u:aE.universalSortableDateTime,y:aE.monthYear,Y:aE.monthYear};return aF[e]},format:function(aE,aI){var aK=b.cultureInfo;var e=aE.getDate();var aG=aE.getDay();var aM=aE.getMonth();var aP=aE.getFullYear();var aJ=aE.getHours();var aL=aE.getMinutes();var aO=aE.getSeconds();var aH=aE.getMilliseconds();var aN=b.datetime.pad;var aF={d:e,dd:aN(e),ddd:aK.abbrDays[aG],dddd:aK.days[aG],M:aM+1,MM:aN(aM+1),MMM:aK.abbrMonths[aM],MMMM:aK.months[aM],yy:aN(aP%100),yyyy:aP,h:aJ%12||12,hh:aN(aJ%12||12),H:aJ,HH:aN(aJ),m:aL,mm:aN(aL),s:aO,ss:aN(aO),f:Math.floor(aH/100),ff:Math.floor(aH/10),fff:aH,tt:aJ<12?aK.am:aK.pm};aI=aI||"G";aI=b.datetime.standardFormat(aI)?b.datetime.standardFormat(aI):aI;return aI.replace(s,function(aQ){return aQ in aF?aF[aQ]:aQ.slice(1,aQ.length-1)})},parse:function(aE){var aF=aE.value;var e=aE.format;if(aF&&aF.value){return aF}e=b.datetime.standardFormat(e)?b.datetime.standardFormat(e):e;if(r.test(aF)){return b.datetime.parseMachineDate({value:aF,format:e,shortYearCutOff:aE.shortYearCutOff,baseDate:aE.baseDate,AM:b.cultureInfo.am,PM:b.cultureInfo.pm})}return b.datetime.parseByToken?b.datetime.parseByToken(aF,aE.today):null},parseMachineDate:function(aZ){var e=aZ.AM,a0=aZ.PM,a4=aZ.value,aL=aZ.format,aE=aZ.baseDate,a2=aZ.shortYearCutOff||30,a6=null,aX=null,aJ=null,aP=0,aW=0,a1=0,aV=0,aQ,aR,aS=false,aU=function(a7){return(aM+131)){return null}break;case"M":aG=aT("M");aX=aG<=1?aO(2):aN(b.cultureInfo[aG==3?"months":"abbrMonths"]);if(aX===null||(aX<1||aX>12)){return null}aX-=1;break;case"y":aG=aT("y");a6=aO(aG<=1?2:4);if(a6<0||a6.toString().length<=aG){return null}break;case"H":aG=aT("H");aP=aY(aO(2));if(aP===null||(aP<0||aP>23)){return null}break;case"h":aT("h");aP=aY(aO(2));if(aP==12){aP=0}if(aP===null||(aP<0||aP>11)){return null}break;case"m":aT("m");aW=aY(aO(2));if(aW===null||(aW<0||aW>59)){return null}break;case"s":aT("s");a1=aY(aO(2));if(a1===null||(a1<0||a1>59)){return null}break;case"f":aG=aT("f");aV=aY(aO(aG<=0?1:aG+1));if(aV===null||(aV<0||aV>999)){return null}break;case"t":aG=aT("t");e=aG>0?e:"a";a0=aG>0?a0:"p";var a3=a4.substr(aH).toLowerCase();aQ=a3.indexOf(e.toLowerCase())!=-1;aR=a3.indexOf(a0.toLowerCase())!=-1;aH+=aR?a0.length:aQ?e.length:0;break;case"'":aF();aS=true;break;default:if(!aF()){return null}}}}var aI=new b.datetime();if(a6!==null&&a6<100){a6+=aI.year()-aI.year()%100+(a6<=a2?0:-100)}aP=(aR&&aP<12)?aP+12:aP==12&&aQ?0:aP;if(aE==undefined){if(a6===null){a6=aI.year()}if(aJ===null){aJ=1}aI=new b.datetime(a6,aX,aJ,aP,aW,a1,aV)}else{aI=new b.datetime(a6!==null?a6:aE.year(),aX!==null?aX:aE.month(),aJ!==null?aJ:aE.date(),aP,aW,a1,aV)}return aI}});b.datetime.prototype={year:function(){if(arguments.length==0){return this.value.getFullYear()}else{if(arguments.length==1){this.value.setFullYear(arguments[0])}else{this.value.setFullYear(arguments[0],arguments[1],arguments[2])}}return this},timeOffset:function(){return this.value.getTimezoneOffset()},day:function(){return this.value.getDay()},toDate:function(){return this.value},addMonth:function(e){this.month(this.month()+e)},addYear:function(e){this.year(this.year()+e)}};a.each(["Month","Date","Hours","Minutes","Seconds","Milliseconds","Time"],function(e,aE){b.datetime.prototype[aE.toLowerCase()]=function(){if(arguments.length==1){this.value["set"+aE](arguments[0])}else{return this.value["get"+aE]()}return this}});var p=/[0#?]/;var au=/n|p|c/i;function aq(aF,aE){var e=Math.pow(10,aE||0);return Math.round(aF*e)/e}function ap(e){return e.split("").reverse().join("")}function O(aM,aH,e){var aI=0,aJ=0,aG=aH.length,aN=aM.length,aE=new b.stringBuilder();while(aI=0){if(aH.charAt(aI).match(p)){aE.cat(aM.charAt(aJ++))}else{aE.cat(aH.charAt(aI))}aI++}aE.catIf(aM.substring(aJ),aJ-1){aO=aK.indexOf("0")}if(aO>-1){var aF=aK.slice(0,aO),aL=aK.slice(aO,aK.length);aK=aF.replace(/#/g,"")+aL.replace(/#/g,"0")}else{aK=aK.replace(/#/g,"")}if(aK.indexOf(",")==0){aK=aK.replace(/,/g,"")}return e?aK:ap(aK)}b.formatNumber=function(aU,aI,aG,a4,aJ,aK,aY,aS,a8,aM){if(!aI){return aU}var a9,aF,aT,bb,a5=aU<0;aI=aI.split(":");aI=aI.length>1?aI[1].replace("}",""):aI[0];var aL=p.test(aI)&&!au.test(aI);if(aL){aI=aI.split(";");aF=aI[0];aT=aI[1];bb=aI[2];aI=(a5&&aT?aT:aF).indexOf("%")!=-1?"p":"n"}switch(aI.toLowerCase().charAt(0)){case"d":return Math.round(aU).toString();case"c":a9="currency";break;case"n":a9="numeric";break;case"p":a9="percent";if(!aM){aU=Math.abs(aU)*100}break;default:return aU.toString()}var aR=aI.match(r);if(aR){aG=parseInt(aR[0],10)}var bc=function(bg,bd,bf){for(var be=bg.length;be1?a7[1]:"",aO=b.lastIndexOf(a1,"0"),aN=b.lastIndexOf(a1,"#");aG=(aN>aO?aN:aO)+1}var a3=aq(aU,aG);aU=isFinite(a3)?a3:aU;if(aU.toString().toLowerCase().indexOf("e")>-1){aU=aU.toFixed(aG)}var a6=aU.toString().split(".");aP=a6[0];aP=a5?aP.replace("-",""):aP;a0=a6.length>1?a6[1]:"";if(aH){if(!a5){a0=bc(a0,aH,false);aP+=a0.slice(0,aH);a0=a0.substr(aH)}else{aP=bc(aP,aH+1,true);a0=aP.slice(aH,aP.length)+a0;aP=aP.slice(0,aH)}}var a2=a0.length;if(aG<1||(aL&&aO==-1&&a2===0)){a0=""}else{a0=a2>aG?a0.slice(0,aG):bc(a0,aG,false)}var aZ;if(aL){if(aP==0){aP=""}aP=O(ap(aP),ap(aQ),true).replace(/,/g,"");aP=aQ.indexOf(",")!=-1?e(aP,aJ,aK):aP;a0=a0&&a1?O(a0,a1):"";aZ=aU===0&&bb?bb:(a5&&!aT?"-":"")+aP+(a0.length>0?a4+a0:"")}else{aP=e(aP,aJ,aK);aX=aX[a9];var aW=a5?aX.negative[aS]:a8?aX.positive[aY]:null;var aV=aP+(a0.length>0?a4+a0:"");aZ=aW?aW.replace("n",aV).replace("*",a8):aV}return aZ};a.extend(b.formatters,{date:b.datetime.format,number:b.formatNumber});b.scripts=[];var S=[];function ao(aE,e){var aG=b.scripts;aE=a.grep(aE,function(aH){aH=aH.toLowerCase().replace(".min","");if(aH.indexOf("jquery-")>-1||(aH.indexOf("jquery.validate")>-1&&a.fn.validate)||aH.indexOf("telerik.common")>-1){return false}var aJ=false;for(var aI=0;aI-1){aJ=true;break}}return !aJ});var aF=function(aH){if(aH){a.ajax({url:aH,dataType:"script",cache:!a.browser.msie,success:function(){aF(aE.shift())}})}else{e();S.shift();if(S.length){S[0]()}}};aF(aE.shift())}b.load=function(aE,e){S.push(function(){ao(aE,e)});if(S.length==1){ao(aE,e)}};b.stringBuilder.prototype={cat:function(e){this.buffer.push(e);return this},rep:function(aF,e){for(var aE=0;aE');this._verticalScrollbar=this._horizontalScrollbar.clone();this._scrollbars=this._horizontalScrollbar.add(this._verticalScrollbar);this._startProxy=a.proxy(this._start,this);this._stopProxy=a.proxy(this._stop,this);this._dragProxy=a.proxy(this._drag,this);this._create()}b.touchLocation=function(aE){return{idx:0,x:aE.pageX,y:aE.pageY}};b.eventTarget=function(aE){return aE.target};b.eventCurrentTarget=function(aE){return aE.currentTarget};if(b.isTouch){b.touchLocation=function(aF,aG){var aE=aF.changedTouches||aF.originalEvent.changedTouches;if(aG){var aH=null;y(aE,function(e,aI){if(aG==aI.identifier){aH={idx:aI.identifier,x:aI.pageX,y:aI.pageY}}});return aH}else{if(aF.type in {touchstart:{},touchmove:{},touchend:{},touchcancel:{}}){return{idx:aE[0].identifier,x:aE[0].pageX,y:aE[0].pageY}}else{return{idx:0,x:aF.pageX,y:aF.pageY}}}};b.eventTarget=function(aE){var aF="originalEvent" in aE?aE.originalEvent.changedTouches:"changedTouches" in aE?aE.changedTouches:null;return aF?document.elementFromPoint(aF[0].clientX,aF[0].clientY):null};b.eventCurrentTarget=b.eventTarget}b.zoomLevel=function(){return b.isTouch?(document.documentElement.clientWidth/window.innerWidth):1};ar.prototype={_create:function(){this.wrapper.css("overflow","hidden").bind(av,a.proxy(this._wait,this))},_wait:function(aE){var aF=b.touchLocation(aE);this.start={x:aF.x+this.wrapper.scrollLeft(),y:aF.y+this.wrapper.scrollTop()};a(document).bind(Z,this._startProxy).bind(z,this._stopProxy)},_start:function(aF){var aE=b.touchLocation(aF);this._dragged=false;if(this.start.x-aE.x>10||this.start.y-aE.y>10){aF.preventDefault();this._dragged=true;a(document).unbind(Z,this._startProxy).bind(Z,this._dragProxy);var aK=this.wrapper.innerWidth(),aG=this.wrapper.innerHeight(),aH=this.wrapper.offset(),aJ=this.wrapper.attr("scrollWidth"),aI=this.wrapper.attr("scrollHeight");if(aJ>aK){this._horizontalScrollbar.appendTo(document.body).css({width:Math.floor((aK/aJ)*aK),left:this.wrapper.scrollLeft()+aH.left+parseInt(this.wrapper.css("borderLeftWidth")),top:aH.top+this.wrapper.innerHeight()+parseInt(this.wrapper.css("borderTopWidth"))-this._horizontalScrollbar.outerHeight()})}if(aI>aG){this._verticalScrollbar.appendTo(document.body).css({height:Math.floor((aG/aI)*aG),top:this.wrapper.scrollTop()+aH.top+parseInt(this.wrapper.css("borderTopWidth")),left:aH.left+this.wrapper.innerWidth()+parseInt(this.wrapper.css("borderLeftWidth"))-this._verticalScrollbar.outerWidth()})}this._scrollbars.stop().fadeTo(200,0.5)}},_drag:function(aF){if(!this._dragged){aF.preventDefault()}var aE=b.touchLocation(aF),aI=this.wrapper.offset(),aJ=aI.left+parseInt(this.wrapper.css("borderLeftWidth")),aK=aI.top+parseInt(this.wrapper.css("borderTopWidth")),aG=this.start.x-aE.x,aM=this.start.y-aE.y,aH=Math.max(aJ,aJ+aG),aL=Math.max(aK,aK+aM);aH=Math.min(aJ+this.wrapper.innerWidth()-this._horizontalScrollbar.outerWidth()-this._horizontalScrollbar.outerHeight(),aH);aL=Math.min(aK+this.wrapper.innerHeight()-this._verticalScrollbar.outerHeight()-this._verticalScrollbar.outerWidth(),aL);this._horizontalScrollbar.css("left",aH);this._verticalScrollbar.css("top",aL);this.wrapper.scrollLeft(aG).scrollTop(aM)},_stop:function(){a(document).unbind(Z,this._startProxy).unbind(Z,this._dragProxy).unbind(z,this._stopProxy);this._scrollbars.stop().fadeTo(400,0)}};var ag=function(aE,aG,aF){if(aG.length==0&&aF){aF();return null}var e=aE.list.length;return function(){if(--e==0&&aF){aF()}}};a.extend(b.fx,{_wrap:function(e){if(!e.parent().hasClass("t-animation-container")){e.wrap(a("
            ").addClass("t-animation-container").css({width:e.outerWidth(),height:e.outerHeight()}))}return e.parent()},play:function(aF,aK,aJ,aG){var e=ag(aF,aK,aG);if(e===null){return}aK.stop(false,true);for(var aH=0,aI=aF.list.length;aH=0;aH--){var aE=aJ.data("effect-"+aH)||new b.fx[aF.list[aH].name](aJ);aE.rewind(a.extend(aF.list[aH],{openDuration:aF.openDuration,closeDuration:aF.closeDuration},aI),e);aJ.data("effect-"+aH,null)}}});b.fx.toggle=function(e){this.element=e.stop(false,true)};b.fx.toggle.prototype={play:function(aE,e){this.element.show();if(e){e()}},rewind:function(aE,e){this.element.hide();if(e){e()}}};b.fx.toggle.defaults=function(){return{list:[{name:"toggle"}]}};b.fx.slide=function(e){this.element=e;this.animationContainer=b.fx._wrap(e)};b.fx.slide.prototype={play:function(aJ,aH){var aF=this.animationContainer;this.element.css("display","block").stop();aF.css({display:"block",overflow:"hidden"});var aK=this.element.outerWidth();var aI=this.element.outerHeight();var e=aJ.direction=="bottom"?"marginTop":"marginLeft";var aE=aJ.direction=="bottom"?-aI:-aK;aF.css({width:aK,height:aI});var aG={};aG[e]=0;this.element.css("width",this.element.width()).each(function(){this.style.cssText=this.style.cssText}).css(e,aE).animate(aG,{queue:false,duration:aJ.openDuration,easing:"linear",complete:function(){aF.css("overflow","");if(aH){aH()}}})},rewind:function(aG,aF){var aE=this.animationContainer;this.element.stop(false,true);aE.css({overflow:"hidden"});var e;switch(aG.direction){case"bottom":e={marginTop:-this.element.outerHeight()};break;case"right":e={marginLeft:-this.element.outerWidth()};break}this.element.animate(e,{queue:false,duration:aG.closeDuration,easing:"linear",complete:function(){aE.css({display:"none",overflow:""});if(aF){aF()}}})}};b.fx.slide.defaults=function(){return{list:[{name:"slide"}],openDuration:"fast",closeDuration:"fast"}};b.fx.property=function(e){this.element=e};b.fx.property.prototype={_animate:function(aH,aE,aI,aF){var aJ={overflow:"hidden"},aG={},e=this.element;a.each(aH,function(aK,aL){var aM;switch(aL){case"height":case"width":aM=e[aL]();break;case"opacity":aM=1;break;default:aM=e.css(aL);break}aJ[aL]=aI?aM:0;aG[aL]=aI?0:aM});e.css(aJ).show().animate(aG,{queue:false,duration:aE,easing:"linear",complete:function(){if(aI){e.hide()}a.each(aG,function(aK){aG[aK]=""});e.css(a.extend({overflow:""},aG));if(aF){aF()}}})},play:function(aE,e){this._animate(aE.properties,aE.openDuration,false,e)},rewind:function(aE,e){this._animate(aE.properties,aE.closeDuration,true,e)}};b.fx.property.defaults=function(){return{list:[{name:"property",properties:arguments}],openDuration:"fast",closeDuration:"fast"}};a(document).ready(function(){if(a.browser.msie&&typeof(Sys)!="undefined"&&typeof(Sys.Mvc)!="undefined"&&typeof(Sys.Mvc.FormContext)!="undefined"){var e=function(aE,aF){return a.grep(aE.getElementsByTagName("*"),function(aG){return aG.name==aF})};if(Sys.Mvc.FormContext){Sys.Mvc.FormContext.$F=Sys.Mvc.FormContext._getFormElementsWithName=e}}});var E=a.extend,aj=a.proxy,ax=a.type,Q=a.isFunction,R=a.isPlainObject,P=a.isEmptyObject,y=a.each,aa=a.noop;function C(){this._isPrevented=false}C.prototype={preventDefault:function(){this._isPrevented=true},isDefaultPrevented:function(){return this._isPrevented}};function j(){}j.extend=function(aF){var e=function(){},aI=this,aG=aF&&aF.init?aF.init:function(){aI.apply(this,arguments)},aH;e.prototype=aI.prototype;aH=aG.fn=aG.prototype=E(new e,aF);for(var aE in aH){if(typeof aH[aE]==="object"){aH[aE]=E(true,{},e.prototype[aE],aF[aE])}}aH.constructor=aG;aG.extend=aI.extend;return aG};a.telerik.Class=j;var ad=j.extend({init:function(){this._events={}},bind:function(e,aG){var aJ=this,aH,aE=a.isArray(e)?e:[e],aI,aF;for(aH=0,aI=aE.length;aHaG?1:(aFaG?-1:0)}},create:function(e){return k[e.dir.toLowerCase()](e.field)},combine:function(e){return function(aE,aF){var aI=e[0](aE,aF),aG,aH;for(aG=1,aH=e.length;aG",aH,aI,aJ)},gte:function(aH,aI,aJ){return aE(">=",aH,aI,aJ)},lt:function(aH,aI,aJ){return aE("<",aH,aI,aJ)},lte:function(aH,aI,aJ){return aE("<=",aH,aI,aJ)},startswith:function(aH,aI,aJ){if(aJ){aH="("+aH+" || '').toLowerCase()";if(aI){aI=aI.toLowerCase()}}if(aI){aI=aF(aI)}return aH+".lastIndexOf('"+aI+"', 0) == 0"},endswith:function(aH,aI,aJ){if(aJ){aH="("+aH+" || '').toLowerCase()";if(aI){aI=aI.toLowerCase()}}if(aI){aI=aF(aI)}return aH+".lastIndexOf('"+aI+"') == "+aH+".length - "+(aI||"").length},contains:function(aH,aI,aJ){if(aJ){aH="("+aH+" || '').toLowerCase()";if(aI){aI=aI.toLowerCase()}}if(aI){aI=aF(aI)}return aH+".indexOf('"+aI+"') >= 0"},doesnotcontain:function(aH,aI,aJ){if(aJ){aH="("+aH+" || '').toLowerCase()";if(aI){aI=aI.toLowerCase()}}if(aI){aI=aF(aI)}return aH+".indexOf('"+aI+"') == -1"}}})();var ak=function(e){return new ak.fn.init(e)};var ae={"==":"eq",equals:"eq",isequalto:"eq",equalto:"eq",equal:"eq","!=":"neq",ne:"neq",notequals:"neq",isnotequalto:"neq",notequalto:"neq",notequal:"neq","<":"lt",islessthan:"lt",lessthan:"lt",less:"lt","<=":"lte",le:"lte",islessthanorequalto:"lte",lessthanequal:"lte",">":"gt",isgreaterthan:"gt",greaterthan:"gt",greater:"gt",">=":"gte",isgreaterthanorequalto:"gte",greaterthanequal:"gte",ge:"gte",substringof:"contains",notsubstringof:"doesnotcontain"};function ac(e){var aG,aH,aE,aI,aF=e.filters;if(aF){for(aG=0,aH=aF.length;aG0){aE=aF[0];aG=aG.groupBy(aE).select(function(aJ){var aI=new ak(e).filter([{field:aJ.field,operator:"eq",value:aJ.value}]);return{field:aJ.field,value:aJ.value,items:aF.length>1?new ak(aJ.items).group(aF.slice(1),aI.toArray()).toArray():aJ.items,hasSubgroups:aF.length>1,aggregates:aI.aggregate(aE.aggregates)}})}return aG},groupBy:function(aG){if(P(aG)||!this.data.length){return new ak([])}var aH=aG.field,aO=this.sort(aH,aG.dir||"asc").toArray(),e=c(aH),aL,aJ=e.get(aO[0],aH),aE={},aI={field:aH,value:aJ,items:[]},aF,aK,aM,aN=[aI];for(aK=0,aM=aO.length;aKaG){aE=aG}return aE}};ak.fn.init.prototype=ak.fn;var ax=a.type,az="UPDATED",ah="PRISTINE",n="CREATED",w="DESTROYED";function A(aE,aG){if(aE===aG){return true}var aF=ax(aE),aH=ax(aG),e;if(aF!==aH){return false}if(aF==="date"){return aE.getTime()===aG.getTime()}if(aF!=="object"&&aF!=="array"){return false}for(e in aE){if(!A(aE[e],aG[e])){return false}}return true}var D=function(e,aE){e=e||"";if(e&&e.charAt(0)!=="["){e="."+e}if(aE){e=aD(e.split("."))}else{e="d"+e}return e},I=function(e,aE){return new Function("d","return "+D(e,aE))},at=function(e){return new Function("d,value","d."+e+"=value")},c=function(e){return{get:I(e),set:at(e)}};var aD=function(aI){var aJ="d",aF,aE,aG,aH,e=1;for(aE=0,aG=aI.length;aE=0){aK._data[aL]=aM}}});aK._idMap(aK._data)},_syncError:function(aE,e){this.error({data:aE})},_send:function(e,aG,aH){var aK=this,aF,aI=aK._promises,aJ=aj(aK._syncSuccess,aK,e),aE=aj(aK._syncError,aK,e);if(e.length==0){return}if(aH==="multiple"){for(aF=0,length=e.length;aF0,aF=aI._models;aI._total=aI._deserializer.total(e);if(aI._aggregates&&aI.options.serverAggregates){aI._aggregateResult=aI._deserializer.aggregates(e)}if(aE){e=aI._deserializer.groups(e)}else{e=aI._deserializer.data(e)}aI._data=e;a.each(aJ,function(){var aK=aI.id(this);a.each(e,function(){if(aK===aI.id(this)){delete aF[aK]}})});if(aI.options.serverPaging!==true){aG.page=aI._page;aG.pageSize=aI._pageSize}if(aI.options.serverSorting!==true){aG.sort=aI._sort}if(aI.options.serverFiltering!==true){aG.filter=aI._filter}if(aI.options.serverGrouping!==true){aG.group=aI._group}if(aI.options.serverAggregates!==true){aG.aggregates=aI._aggregates;aI._aggregateResult=g(e,aG)}aH=ai(e,aG);aI._view=aH.data;if(aH.total!==undefined&&!aI.options.serverFiltering){aI._total=aH.total}aI._idMap(e);aI.trigger(h)},changes:function(e){var aF=this,aE=aF._models[e];if(aE&&aE.state===Y.UPDATED){return aE.changes()}},hasChanges:function(e){var aG=this,aE,aF=aG._models,e;if(e===undefined){for(e in aF){if(aF[e].state!==Y.PRISTINE){return true}}return false}aE=aF[e];return !!aE&&aE.state===Y.UPDATED},at:function(e){return this._data[e]},data:function(e){if(e!==undefined){this._data=e}else{return this._data}},view:function(){return this._view},query:function(e){var aG=this,e=e,aF,aE=aG.options.serverSorting||aG.options.serverPaging||aG.options.serverFiltering||aG.options.serverGrouping||aG.options.serverAggregates;if(e!==undefined){aG._pageSize=e.pageSize;aG._page=e.page;aG._sort=e.sort;aG._filter=e.filter;aG._group=e.group;aG._aggregates=e.aggregates;if(e.sort){aG._sort=e.sort=ak.expandSort(e.sort)}if(e.filter){aG._filter=e.filter=ab(e.filter)}if(e.group){aG._group=e.group=ak.expandGroup(e.group)}if(e.aggregates){aG._aggregates=e.aggregates=ak.expandAggregates(e.aggregates)}}if(aE||(aG._data===undefined||aG._data.length==0)){aG.read(e)}else{aF=ai(aG._data,e);if(aF.total!==undefined&&!aG.options.serverFiltering){aG._total=aF.total}aG._view=aF.data;aG._aggregateResult=g(aG._data,e);aG.trigger(h)}},fetch:function(){var e=this;e.query({page:e.page(),pageSize:e.pageSize(),sort:e.sort(),filter:e.filter(),group:e.group(),aggregate:e.aggregate()})},page:function(aE){var e=this;if(aE!==undefined){aE=Math.max(Math.min(Math.max(aE,1),e._totalPages()),1);e.query({page:aE,pageSize:e.pageSize(),sort:e.sort(),filter:e.filter(),group:e.group(),aggregates:e.aggregate()});return}return e._page},pageSize:function(aE){var e=this;if(aE!==undefined){e.query({page:e.page(),pageSize:aE,sort:e.sort(),filter:e.filter(),group:e.group(),aggregates:e.aggregate()});return}return e._pageSize},sort:function(aE){var e=this;if(aE!==undefined){e.query({page:e.page(),pageSize:e.pageSize(),sort:aE,filter:e.filter(),group:e.group(),aggregates:e.aggregate()});return}return this._sort},filter:function(aE){var e=this;if(aE!==undefined){e.query({page:e.page(),pageSize:e.pageSize(),sort:e.sort(),filter:aE,group:e.group(),aggregates:e.aggregate()});return}return e._filter},group:function(aE){var e=this;if(aE!==undefined){e.query({page:e.page(),pageSize:e.pageSize(),sort:e.sort(),filter:e.filter(),group:aE,aggregates:e.aggregate()});return}return e._group},total:function(){return this._total},aggregate:function(aE){var e=this;if(aE!==undefined){e.query({page:e.page(),pageSize:e.pageSize(),sort:e.sort(),filter:aE,group:e.group(),aggregates:aE});return}return e._aggregates},aggregates:function(){return this._aggregateResult},_totalPages:function(){var aE=this,e=aE.pageSize()||aE.total();return Math.ceil((aE.total()||0)/e)}});q.create=function(aG){aG=a.isArray(aG)?{data:aG}:aG;var aE=aG||{},e=aE.data,aF=aE.fields,aI=aE.table,aH=aE.select;if(aF){if(!e){if(aI){e=N(aI,aF)}else{if(aH){e=M(aH,aF)}}}else{if(aH){am(e,aH,aF)}}}aE.data=e;return aE instanceof q?aE:new q(aE)};function M(aK,aE){var aI=a(aK)[0].children,aH,aG,e=[],aJ,aF;for(aH=0,aG=aI.length;aH";if(aN||aN===0){aK+=aN}aK+="";aL.push(aK)}aM.html(aL.join(""))}function N(aO,aJ){var aP=a(aO)[0].tBodies[0],aN=aP?aP.rows:[],aM,aL,aI,aH=aJ.length,aF=[],aE,aK,e,aG;for(aM=0,aL=aN.length;aM",render:function(aH,e){var aF,aG,aE="";for(aF=0,aG=e.length;aF/g,">")}a.telerik.template=a.proxy(aw.compile,aw);a.telerik.htmlEncode=K;var l=ad.extend({init:function(e,aE){var aF=this;ad.fn.init.call(aF);aF.element=a(e);aF.options=E(true,{},aF.options,aE)}});a.telerik.Component=l;function t(e){var aE=1,aF=arguments.length;for(aE=1;aE0){cm=new bk(cl,ck)}else{if(co.length>0){cm=new cd(co,ck)}else{cm=new J(X,ck)}}return cm},_supportsSVG:bM,_attachEvents:function(){var X=this,Y=X.element;Y.bind(U,bq(X._click,X));Y.bind(a5,bq(X._mouseOver,X))},_getPoint:function(ci){var X=this,ck=X._model,ch=X._eventCoordinates(ci),cm=ci.target.id,Y=ck.idMap[cm],cj=ck.idMapMetadata[cm],cl;if(Y){if(Y.getNearestPoint&&cj){cl=Y.getNearestPoint(ch.x,ch.y,cj.seriesIx)}else{cl=Y}}return cl},_eventCoordinates:function(X){var Y=this.element,ch=Y.offset(),ci=parseInt(Y.css("paddingLeft"),10),cj=parseInt(Y.css("paddingTop"),10),ck=a(window);return{x:X.clientX-ch.left-ci+ck.scrollLeft(),y:X.clientY-ch.top-cj+ck.scrollTop()}},_click:function(Y){var X=this,ch=X._getPoint(Y);if(ch){X.trigger(bE,{value:ch.value,category:ch.category,series:ch.series,dataItem:ch.dataItem,element:a(Y.target)})}},_mouseOver:function(Y){var X=this,cj=X._tooltip,ch=X._highlight,ck,ci;if(!ch||ch.element===Y.target){return}ci=X._getPoint(Y);if(ci){X._activePoint=ci;ck=af({},X.options.tooltip,ci.options.tooltip);if(ck.visible){cj.show(ci)}ch.show(ci);a(am.body).bind(a4,bq(X._mouseMove,X))}},_mouseMove:function(ch){var X=this,cm=X._tooltip,ci=X._highlight,Y=X._eventCoordinates(ch),ck=X._activePoint,cn,cj,cl;if(X._plotArea.box.containsPoint(Y.x,Y.y)){if(ck&&(ck.series.type===aT||ck.series.type===l)){cj=ck.owner;cl=cj.getNearestPoint(Y.x,Y.y,ck.seriesIx);if(cl&&cl!=ck){X._activePoint=cl;cn=af({},X.options.tooltip,ck.options.tooltip);if(cn.visible){cm.show(cl)}ci.show(cl)}}}else{a(am.body).unbind(a4);delete X._activePoint;cm.hide();ci.hide()}},_onDataChanged:function(){var X=this,ck=X.options,cl=ck.series,cm,cn=cl.length,ch=X.dataSource.view(),ci=(X.dataSource.group()||[]).length>0,cj=[],Y;for(cm=0;cm=X.x1&&Y<=X.x2&&ch>=X.y1&&ch<=X.y2},points:function(){var X=this;return[new bn(X.x1,X.y1),new bn(X.x2,X.y1),new bn(X.x2,X.y2),new bn(X.x1,X.y2)]}});var bu=S.extend({init:function(Y,ch,ci,ck,X){var cj=this;cj.c=Y;cj.ir=ch;cj.r=ci;cj.startAngle=ck;cj.angle=X},clone:function(){var X=this;return new bu(X.c,X.ir,X.r,X.startAngle,X.angle)},middle:function(){return this.startAngle+this.angle/2},radius:function(Y,X){var ch=this;if(X){ch.ir=Y}else{ch.r=Y}return ch},point:function(X,ci){var cl=this,cj=X*al,Y=a0.cos(cj),ch=a0.sin(cj),ck=ci?cl.ir:cl.r,cm=cl.c.x-(Y*ck),cn=cl.c.y-(ch*ck);return new bn(cm,cn)},getBBox:function(){var ck=this,cl=ck.startAngle,Y=cl+ck.angle,cm=a1,cn=a3,co=a1,cp=a3,cj,X,ci;function ch(cr,cs,cq){return(cr>=cl&&cr<=Y)}X=aC([cl,Y,0,90,180,270],ch);for(ci=0;ci0){ct=az(cs.padding);ct.left+=cr*2;co.pad(ct);ck.children.unshift(cu.createRect(co,{stroke:X.width?X.color:"",strokeWidth:X.width,dashType:X.dashType,fill:cs.background}))}return[ck]},verticalLayout:function(cr){var cl=this,cq=cl.options,X=cl.children,Y=X.length,cj=X[0].box.clone(),co,cp,cm=az(cq.margin),cn=cl.markerSize()*2,ci,ch;for(ch=1;chcs-co){ck.box=new E(X.x1,X.y2,X.x1+ck.box.width(),X.y2+ck.box.height());Y=ck.box.width()+co;cl=ck.box.y1}else{ck.box.alignTo(ch[cj-1].box,bt);ck.box.y2=cl+ck.box.height();ck.box.y1=cl;ck.box.translate(co,0)}X.wrap(ck.box)}cp=(ct.width()-X.width()+co)/2;if(cr.position===bW){cq=ct.y1+cn.top;X.y2=ct.y1+X.height()+cn.top+cn.bottom;X.y1=ct.y1}else{cq=ct.y2-X.height()-cn.bottom;X.y1=ct.y2-X.height()-cn.top-cn.bottom;X.y2=ct.y2}cm.translateChildren(cp+cr.offsetX,cq+cr.offsetY);X.x1=ct.x1;X.x2=ct.x2;cm.box=X},customLayout:function(cm){var cj=this,cl=cj.options,X=cj.children,Y=X.length,ci=X[0].box.clone(),ck=cj.markerSize()*2,ch;for(ch=1;ch0){return X[0].box.height()/2}else{return 0}}});var o=Q.extend({init:function(Y){var X=this;Q.fn.init.call(X,Y);if(!X.options.visible){X.options=af({},X.options,{labels:{visible:false},line:{visible:false},margin:0,majorTickSize:0,minorTickSize:0})}X.createLabels();X.createTitle()},options:{labels:{visible:true,rotation:0,mirror:false,step:1},line:{width:1,color:C,visible:true},title:{visible:true,position:N},majorTickType:bd,majorTickSize:4,minorTickType:a6,minorTickSize:3,axisCrossingValue:0,minorGridLines:{visible:false,width:1,color:C},margin:5,visible:true},createLabels:function(){var Y=this,cm=Y.options,X=cm.isVertical?bt:N,cj=af({},cm.labels,{align:X,zIndex:cm.zIndex}),cn=cj.step;Y.labels=[];if(cj.visible){var ck=Y.getLabelsCount(),cl,ci,ch;for(ch=0;ch0){X+=cj}ch.min=av(Y,cj);ch.max=M(X,cj);if(ck){cn=ak(ck.min)||ak(ck.max);if(cn){if(ck.min===ck.max){if(ck.min>0){ck.min=0}else{ck.max=1}}}if(ck.majorUnit){ch.min=av(ch.min,ck.majorUnit);ch.max=M(ch.max,ck.majorUnit)}else{if(cn){ck=af(ch,ck);ch.majorUnit=n(ck.min,ck.max)}}}return af(ch,ck)},range:function(){var X=this.options;return{min:X.min,max:X.max}},reflow:function(X){this.reflowAxis(X)},getViewElements:function(cl){var X=this,ck=X.options,ch=ck.line,Y=Q.fn.getViewElements.call(X,cl),ci=X.lineBox(),cj;if(ch.width>0&&ch.visible){cj={strokeWidth:ch.width,stroke:ch.color,dashType:ch.dashType,zIndex:ck.zIndex};if(ck.isVertical){Y.push(cl.createLine(ci.x1,ci.y1,ci.x1,ci.y2,cj))}else{Y.push(cl.createLine(ci.x1,ci.y1,ci.x2,ci.y1,cj))}f(Y,X.renderTicks(cl));f(Y,X.renderPlotBands(cl))}return Y},autoAxisMax:function(ci,ch){if(ci==0&&ch==0){return 1}var X;if(ci<=0&&ch<=0){ch=ci==ch?0:ch;var Y=a0.abs((ch-ci)/ch);if(Y>cg){return 0}X=ch-((ci-ch)/2)}else{ci=ci==ch?0:ci;X=ch}return X},autoAxisMin:function(ci,ch){if(ci==0&&ch==0){return 0}var X;if(ci>=0&&ch>=0){ci=ci==ch?0:ci;var Y=(ch-ci)/ch;if(Y>cg){return 0}X=ci-((ch-ci)/2)}else{ch=ci==ch?0:ch;X=ci}return X},getDivisions:function(ch){var X=this.options,Y=X.max-X.min;return a0.floor(bx(Y/ch,ab))+1},getTickPositions:function(cu){var X=this,cm=X.options,cj=cm.isVertical,cq=cm.reverse,ck=X.lineBox(),cl=cj?ck.height():ck.width(),cp=cm.max-cm.min,cr=cl/cp,ct=cu*cr,ch=X.getDivisions(cu),Y=(cj?-1:1)*(cq?-1:1),cs=Y===1?1:2,cn=ck[(cj?ce:cb)+cs],co=[],ci;for(ci=0;ci1){cm=cj[0].box[ck]()/2;ch=aQ(cj).box[ck]()/2}if(ci){return new E(Y.x1,Y.y1+cm,Y.x1,Y.y2-ch)}else{return new E(Y.x1+cm,Y.y1,Y.x2-ch,Y.y1)}},getSlot:function(X,ch){var Y=this,cn=Y.options,cq=cn.reverse,cj=cn.isVertical,ct=cj?ce:cb,ck=Y.lineBox(),cm=ck[ct+(cq?2:1)],cl=cj?ck.height():ck.width(),ci=cq?-1:1,cs=ci*(cl/(cn.max-cn.min)),X=ak(X)?X:cn.axisCrossingValue,ch=ak(ch)?ch:cn.axisCrossingValue,X=a0.max(a0.min(X,cn.max),cn.min),ch=a0.max(a0.min(ch,cn.max),cn.min),co,cp,cr=new E(ck.x1,ck.y1,ck.x1,ck.y1);if(cj){co=cn.max-a0.max(X,ch);cp=cn.max-a0.min(X,ch)}else{co=a0.min(X,ch)-cn.min;cp=a0.max(X,ch)-cn.min}cr[ct+1]=cm+cs*(cq?cp:co);cr[ct+2]=cm+cs*(cq?co:cp);return cr},getLabelsCount:function(){return this.getDivisions(this.options.majorUnit)},getLabelText:function(X){var Y=this.options;return bx(Y.min+(X*Y.majorUnit),ai)}});var L=o.extend({options:{categories:[],isVertical:false,majorGridLines:{visible:false,width:1,color:C},zIndex:1},range:function(){return{min:0,max:this.options.categories.length}},reflow:function(X){this.reflowAxis(X,bb)},getViewElements:function(cl){var X=this,ck=X.options,ch=ck.line,ci=X.lineBox(),Y=Q.fn.getViewElements.call(X,cl),cj;if(ch.width>0&&ch.visible){cj={strokeWidth:ch.width,stroke:ch.color,dashType:ch.dashType,zIndex:ch.zIndex};Y.push(cl.createLine(ci.x1,ci.y1,ci.x2,ci.y2,cj));f(Y,X.renderTicks(cl));f(Y,X.renderPlotBands(cl))}return Y},getTickPositions:function(ci){var X=this,cj=X.options,ch=cj.isVertical,cm=ch?X.box.height():X.box.width(),cn=cm/ci,ck=ch?X.box.y1:X.box.x1,cl=[],Y;for(Y=0;Y0||(ch==ct&&Y==ch)){cn=cm+(cr*cs)}cq[cu+1]=co?cn:cm;cq[cu+2]=co?cm:cn;return cq},getLabelsCount:function(){return this.options.categories.length},getLabelText:function(X){var Y=this.options;return ak(Y.categories[X])?Y.categories[X]:""}});var W=Q.extend({init:function(Y){var X=this;Q.fn.init.call(X,Y)},options:{isVertical:false,gap:0,spacing:0},reflow:function(Y){var cj=this,co=cj.options,cn=co.isVertical,X=cn?ce:cb,ci=cj.children,cl=co.gap,cs=co.spacing,ck=ci.length,cq=ck+cl+(cs*(ck-1)),cr=(cn?Y.height():Y.width())/cq,cp=Y[X+1]+cr*(cl/2),ch,cm;for(cm=0;cm0?{stroke:X.getBorderColor(),strokeWidth:cl.border.width,dashType:cl.border.dashType}:{},ch=X.box,cm=af({id:cl.id,fill:cl.color,fillOpacity:cl.opacity,strokeOpacity:cl.opacity,isVertical:cl.isVertical,aboveAxis:cl.aboveAxis,stackBase:cl.stackBase,animation:cl.animation},Y),ci=[],ck=X.children[0];if(cl.overlay){cm.overlay=af({rotation:cj?0:90},cl.overlay)}ci.push(cn.createRect(ch,cm));f(ci,Q.fn.getViewElements.call(X,cn));X.registerId(cl.id);if(ck){X.registerId(ck.options.id)}return ci},getOutlineElement:function(cj,ch){var X=this,Y=X.box,ci=X.options.id+bc;X.registerId(ci);ch=af({},ch,{id:ci});return cj.createRect(Y,ch)},getBorderColor:function(){var X=this,ci=X.options,ch=ci.color,Y=ci.border.color;if(!ak(Y)){Y=new Z(ch).brightness(s).toHex()}return Y},tooltipAnchor:function(cl,ck){var Y=this,cj=Y.options,ch=Y.box,ci=cj.isVertical,X=cj.aboveAxis,cm,cn;if(ci){cm=ch.x2+bU;cn=X?ch.y1:ch.y2-ck}else{if(cj.isStacked){cm=ch.x2-cl;cn=ch.y1-ck-bU}else{cm=ch.x2+bU;cn=ch.y1}}return new bn(cm,cn)},formatPointValue:function(X){var Y=this;return Y.owner.formatPointValue(Y.value,X)}});var I=Q.extend({init:function(ch,Y){var X=this;Q.fn.init.call(X,Y);X.plotArea=ch;X.valueAxisRanges={};X.points=[];X.categoryPoints=[];X.seriesPoints=[];X.render()},options:{series:[],invertAxes:false,isStacked:false},render:function(){var X=this;X.traverseDataPoints(bq(X.addValue,X))},addValue:function(cn,X,Y,ck,cl){var ci=this,cj,ch=ci.categoryPoints[Y],cm=ci.seriesPoints[cl];if(!ch){ci.categoryPoints[Y]=ch=[]}if(!cm){ci.seriesPoints[cl]=cm=[]}ci.updateRange(cn,Y,ck);cj=ci.createPoint(cn,X,Y,ck,cl);if(cj){cj.category=X;cj.series=ck;cj.seriesIx=cl;cj.owner=ci;cj.dataItem=ck.dataItems?ck.dataItems[Y]:{value:cn}}ci.points.push(cj);cm.push(cj);ch.push(cj)},updateRange:function(ck,ch,cj){var ci=this,X=cj.axis||bp,Y=ci.valueAxisRanges[X];if(ak(ck)){Y=ci.valueAxisRanges[X]=Y||{min:a1,max:a3};Y.min=a0.min(Y.min,ck);Y.max=a0.max(Y.max,ck)}},seriesValueAxis:function(X){return this.plotArea.namedValueAxes[(X||{}).axis||bp]},reflow:function(cp){var ci=this,cl=ci.options,ck=cl.invertAxes,cm=ci.plotArea,co=0,ch=ci.categorySlots=[],cj=ci.points,Y=cm.categoryAxis,cq,X,cn;ci.traverseDataPoints(function(cz,cs,ct,cv){cq=ci.seriesValueAxis(cv);X=cq.options.axisCrossingValue;cn=cj[co++];if(cn&&cn.plotValue){cz=cn.plotValue}var cu=Y.getSlot(ct),cA=cq.getSlot(cz),cx=ck?cA:cu,cy=ck?cu:cA,cw=new E(cx.x1,cy.y1,cx.x2,cy.y2),cr=cq.options.reverse?cz=X;if(cn){cn.options.aboveAxis=cr;cn.reflow(cw)}if(!ch[ct]){ch[ct]=cu}});ci.reflowCategories(ch);ci.box=cp},reflowCategories:function(){},traverseDataPoints:function(X){var ci=this,cm=ci.options,cn=cm.series,Y=ci.plotArea.options.categoryAxis.categories||[],cj=K(cn),ch,co,cp,ck,cl;for(ch=0;ch0){cp.append(X)}else{cn.append(X)}}else{ck.append(X)}return X},updateRange:function(cl,X,ci){var Y=this,ch=Y.options.isStacked,ck=Y._categoryTotalsPos,cj=Y._categoryTotalsNeg;if(ak(cl)){if(ch){aI(cl>0?ck:cj,X,cl)}else{I.fn.updateRange.apply(Y,arguments)}}},computeAxisRanges:function(){var Y=this,ch=Y.options.isStacked,X;if(ch){X=Y.options.series[0].axis||bp;Y.valueAxisRanges[X]={min:bI(Y._categoryTotalsNeg.concat(0)),max:bH(Y._categoryTotalsPos.concat(0))}}},seriesValueAxis:function(ch){var X=this,Y=X.options;return I.fn.seriesValueAxis.call(X,Y.isStacked?X.options.series[0]:ch)},reflowCategories:function(X){var Y=this,ch=Y.children,ci=ch.length,cj;for(cj=0;cj1){cj.push(X.createSegment(b1(),cs,ci,Y,cq))}ci=[]}}}if(ci.length>1){cj.push(X.createSegment(b1(),cs,ci,Y,cq))}}return cj},createSegment:function(X,cj,Y,ch,ci){this.registerId(X,{seriesIx:ci});return cj.createPolyline(Y,false,{id:X,stroke:ch.color,strokeWidth:ch.width,strokeOpacity:ch.opacity,fill:"",dashType:ch.dashType})},getNearestPoint:function(cs,ct,cr){var Y=this,cj=Y.options.invertAxes,X=cj?ce:cb,cq=cj?ct:cs,co=Y.seriesPoints[cr],cl=a1,cp=co.length,ch,cm,cn,ck,ci;for(ci=0;ci0){cr=cs[cj-1].clone().points.reverse();line.points=cn.concat(cr)}}else{if(cn.length>1){ci=cn[0];cl=aQ(cn);if(ck){cn.unshift(new bn(ch,ci.y));cn.push(new bn(ch,cl.y))}else{cn.unshift(new bn(ci.x,ch));cn.push(new bn(cl.x,ch))}}}co.push(line)}return co},createSegment:function(Y,ck,ch,ci,cj){var X=af({},{color:ci.color,opacity:ci.opacity},ci.line);this.registerId(Y,{seriesIx:cj});return ck.createPolyline(ch,true,{id:Y,stroke:X.color,strokeWidth:X.width,strokeOpacity:X.opacity,dashType:X.dashType,fillOpacity:ci.opacity,fill:ci.color,seriesIx:cj,stack:ci.stack})}});var bB=Q.extend({init:function(ch,Y){var X=this;Q.fn.init.call(X,Y);X.plotArea=ch;X.xAxisRanges={};X.yAxisRanges={};X.points=[];X.seriesPoints=[];X.render()},options:{series:[],tooltip:{format:"{0}, {1}"},labels:{format:"{0}, {1}"}},render:function(){var X=this;X.traverseDataPoints(bq(X.addValue,X))},addValue:function(ck,Y){var X=this,ch,ci=Y.seriesIx,cj=X.seriesPoints[ci];X.updateRange(ck,Y.series);ch=X.createPoint(ck,Y.series,ci);if(ch){aq(ch,Y)}X.points.push(ch);cj.push(ch)},updateRange:function(ch,Y){var X=this,ci=ch.x,cl=ch.y,cj=Y.xAxis||bp,cm=Y.yAxis||bp,ck=X.xAxisRanges[cj],cn=X.yAxisRanges[cm];if(ak(ci)&&ci!==null){ck=X.xAxisRanges[cj]=ck||{min:a1,max:a3};ck.min=a0.min(ck.min,ci);ck.max=a0.max(ck.max,ci)}if(ak(cl)&&cl!==null){cn=X.yAxisRanges[cm]=cn||{min:a1,max:a3};cn.min=a0.min(cn.min,cl);cn.max=a0.max(cn.max,cl)}},createPoint:function(cj,ch,ci){var X=this,Y,ck=cj.x,cl=cj.y;if(!ak(ck)||ck===null||!ak(cl)||cl===null){return null}Y=new aY(cj,af({markers:{border:{color:ch.color},opacity:ch.opacity},tooltip:{format:X.options.tooltip.format},labels:{format:X.options.labels.format}},ch));X.append(Y);return Y},seriesAxes:function(Y){var X=this.plotArea,ch=Y.xAxis||bp,ci=Y.yAxis||bp;return{x:X.namedXAxes[ch],y:X.namedYAxes[ci]}},reflow:function(cl){var X=this,ch=X.plotArea,Y=X.points,cj=0,ci,ck;X.traverseDataPoints(function(cq,cm){ci=Y[cj++];ck=X.seriesAxes(cm.series);var co=ck.x.getSlot(cq.x,cq.x),cp=ck.y.getSlot(cq.y,cq.y),cn=new E(co.x1,cp.y1,co.x2,cp.y2);if(ci){ci.reflow(cn)}});X.box=cl},getViewElements:function(ci){var X=this,Y=Q.fn.getViewElements.call(X,ci),ch=ci.createGroup({animation:{type:V}});ch.children=Y;return[ch]},traverseDataPoints:function(X){var Y=this,ck=Y.options,cn=ck.series,cp=Y.seriesPoints,cm=0,co,ch,ci,cj,cq,cl;for(co=0;co=cn.c.x){cp=cl.x+ck;Y.orientation=bt}else{cp=cl.x-ck;Y.orientation=aR}Y.reflow(new E(cp,cl.y-ch,cl.x,cl.y))}}}},getViewElements:function(cm){var cl=this,ck=cl.sector,ci=cl.options,Y=ci.border||{},X=Y.width>0?{stroke:Y.color,strokeWidth:Y.width,dashType:Y.dashType}:{},ch=[],cj=ci.overlay;if(cj){cj=af({},ci.overlay,{r:ck.r,cx:ck.c.x,cy:ck.c.y})}if(cl.value!==0){ch.push(cm.createSector(ck,af({id:ci.id,fill:ci.color,overlay:cj,fillOpacity:ci.opacity,strokeOpacity:ci.opacity,animation:af(ci.animation,{delay:cl.categoryIx*bg})},X)))}f(ch,Q.fn.getViewElements.call(cl,cm));return ch},getOutlineElement:function(cl,ci){var ck=this,ch=ck.options.highlight||{},X=ch.border||{},cj=ck.options.id+bc,Y;ck.registerId(cj);ci=af({},ci,{id:cj});if(ck.value!==0){Y=cl.createSector(ck.sector,af({},ci,{fill:ch.color,fillOpacity:ch.opacity,strokeOpacity:X.opacity,strokeWidth:X.width,stroke:X.color}))}return Y},tooltipAnchor:function(ck,cj){var cl=ck/2,X=cj/2,Y=a0.sqrt((cl*cl)+(X*X)),ch=this.sector.clone().expand(Y+bU),ci=ch.point(ch.middle());return new bn(ci.x-cl,ci.y-X)},formatPointValue:function(X){var Y=this;return Y.owner.formatPointValue(Y.value,X)}});var bj=Q.extend({init:function(ch,Y){var X=this;Q.fn.init.call(X,Y);X.plotArea=ch;X.segments=[];X.seriesPoints=[];X.render()},options:{startAngle:90,padding:60,connectors:{width:1,color:"#939393",padding:4}},render:function(){var X=this;X.traverseDataPoints(bq(X.addValue,X))},traverseDataPoints:function(ch){var ci=this,cs=ci.options,cj=ci.plotArea.options.seriesColors||[],cv=cs.startAngle,ck=cj.length,ct=cs.series,cp,cm,cn,cl,cu,X,co,Y,cx,cq,cw,cr;for(cu=0;cucm/2-cv?cm/2-cv:cp.padding,cn=new E(X.x1,X.y1,X.x1+cm,X.y1+cm),co=cn.center(),Y=X.center(),cu=ch.segments,ci=cu.length,cl=[],cr=[],ck,ct,cs,cj;cn.translate(Y.x-co.x,Y.y-co.y);for(cj=0;cj0){cl.sort(ch.labelComparator(true));ch.leftLabelsReflow(cl)}if(cr.length>0){cr.sort(ch.labelComparator(false));ch.rightLabelsReflow(cr)}ch.box=cn},leftLabelsReflow:function(ch){var X=this,Y=X.distanceBetweenLabels(ch);X.distributeLabels(Y,ch)},rightLabelsReflow:function(ch){var X=this,Y=X.distanceBetweenLabels(ch);X.distributeLabels(Y,ch)},distanceBetweenLabels:function(cl){var X=this,cp=X.segments[0],co=cp.sector,cj=cl[0].box,cn,Y=cl.length-1,ci=[],ch,cm=co.r+cp.options.labels.distance,ck;ch=bx(cj.y1-(co.c.y-cm-cj.height()-cj.height()/2));ci.push(ch);for(ck=0;ck0&&(ck>=0||cm0){var ch=a0.min(ci[cj],X);X-=ch;ci[cj]-=ch;ci[Y]+=ch}return X},reflowLabels:function(cj,co){var ci=this,cs=ci.segments,cr=cs[0],cq=cr.sector,cp=co.length,cn=cr.options.labels,cm=cn.distance,ch=cq.c.y-(cq.r+cm)-co[0].box.height(),cl,Y,X,ck;cj[0]+=2;for(ck=0;ckcu.c.x){cz=cu.c.x-cu.r-cy;if(cv.options.labels.align!==aa){if(cz>cr.x){ct.push(new bn(cz,cA.y))}else{ct.push(new bn(cA.x-cy*2,cA.y))}}else{ct.push(new bn(cz,cA.y))}ct.push(new bn(cr.x,cn.y))}else{cm.y=cn.y;ct.push(cm)}}ct.push(cn);cj=cB.createPolyline(ct,false,{id:b1(),stroke:ck.color,strokeWidth:ck.width,animation:{type:au,delay:cv.categoryIx*bg}});cq.push(cj);cv.registerId(cj.options.id,cx)}cv.registerId(cp.options.id,cx)}cv.registerId(cv.options.id,cx)}f(cq,Q.fn.getViewElements.call(ci,cB));return cq},labelComparator:function(X){X=(X)?-1:1;return function(Y,ch){Y=(Y.parent.sector.middle()+270)%360;ch=(ch.parent.sector.middle()+270)%360;return(Y-ch)*X}},hAlignLabel:function(ci,ck,cm,cn,ch){var X=ck.c.x,Y=ck.c.y,cj=ck.r,cl=a0.min(a0.abs(Y-cm),a0.abs(Y-cn));if(cl>cj){return ci}else{return X+a0.sqrt((cj*cj)-(cl*cl))*(ch?1:-1)}},pointInCircle:function(Y,X,ch){return bJ(X.x-Y.x)+bJ(X.y-Y.y)0){ch.reflowAxes();ch.box=ch.axisBox()}ch.reflowCharts()},axisCrossingValues:function(X,Y){var ck=X.options,ch=[].concat(ck.axisCrossingValue),cl=Y.length-ch.length,ci=ch[0]||0,cj;for(cj=0;cj0){ch.invertAxes=aH(ci[0].type,[r,b5,b4])}bm.fn.init.call(ch,ci,Y)},options:{categoryAxis:{categories:[]},valueAxis:{}},render:function(){var X=this,Y=X.series;X.createBarChart(aC(Y,function(ch){return aH(ch.type,[r,aa])}));X.createLineChart(aC(Y,function(ch){return aH(ch.type,[aT,b5])}));X.createAreaChart(aC(Y,function(ch){return aH(ch.type,[l,b4])}));X.createAxes()},appendChart:function(ch){var cj=this,ci=cj.options,ck=ch.options.series,X=ci.categoryAxis.categories,Y=a0.max(0,K(ck)-X.length);f(X,new Array(Y));cj.valueAxisRangeTracker.update(ch.valueAxisRanges);bm.fn.appendChart.call(cj,ch)},createBarChart:function(cj){if(cj.length===0){return}var ci=this,ch=ci.options,Y=cj[0],X=new x(ci,{series:cj,invertAxes:ci.invertAxes,isStacked:Y.stack,gap:Y.gap,spacing:Y.spacing});ci.appendChart(X)},createLineChart:function(cj){if(cj.length===0){return}var ci=this,ch=ci.options,X=cj[0],Y=new aW(ci,{invertAxes:ci.invertAxes,isStacked:X.stack,series:cj});ci.appendChart(Y)},createAreaChart:function(cj){if(cj.length===0){return}var ci=this,ch=ci.options,Y=cj[0],X=new m(ci,{invertAxes:ci.invertAxes,isStacked:Y.stack,series:cj});ci.appendChart(X)},createAxes:function(){var cm=this,cl=cm.options,co,cj=cm.invertAxes,ch=cl.categoryAxis.categories.length,ci=new L(af({isVertical:cj,axisCrossingValue:cj?ch:0},cl.categoryAxis)),X,Y,ck=cm.namedValueAxes,cp=[].concat(cl.valueAxis),cn;an(cp,function(){Y=this.name||bp;co=cm.valueAxisRangeTracker.query(Y);X=ck[Y]=new a9(co.min,co.max,af({isVertical:!cj},this));cm.axes.push(X);cm.append(X)});cn=ck[bp]||cm.axes[0];cm.axisX=cj?cn:ci;cm.axisY=cj?ci:cn;cm.categoryAxis=ci;cm.axes.push(ci);cm.append(cm.categoryAxis)}});var p=S.extend({init:function(X){var Y=this;Y.axisRanges={},Y.axisOptions=[].concat(X),Y.defaultRange={min:0,max:1}},update:function(cj){var co=this,ci=co.axisRanges,ch=co.axisOptions,cn,ck,cl,X,Y,cm=ch.length;if(!cj){return}for(cl=0;cl0){X.appendChart(new bB(X,{series:Y}))}},createScatterLineChart:function(Y){var X=this;if(Y.length>0){X.appendChart(new bC(X,{series:Y}))}},createXYAxis:function(ck,ci){var cl=this,Y=ck.name||bp,cj=ci?cl.namedYAxes:cl.namedXAxes,ch=ci?cl.yAxisRanges:cl.xAxisRanges,cn=ci?cl.yAxisRangeTracker:cl.xAxisRangeTracker,cm=cn.query(Y),ck=af({},ck,{isVertical:ci}),X=new a9(cm.min,cm.max,ck);cj[Y]=X;cl.append(X);cl.axes.push(X)},createAxes:function(){var Y=this,X=Y.options,ch=[].concat(X.xAxis),ci=[].concat(X.yAxis);an(ch,function(){Y.createXYAxis(this,false)});an(ci,function(){Y.createXYAxis(this,true)});Y.axisX=Y.namedXAxes.primary||Y.namedXAxes[ch[0].name];Y.axisY=Y.namedYAxes.primary||Y.namedYAxes[ci[0].name]}});var bk=bm.extend({render:function(){var X=this,Y=X.series;X.createPieChart(Y)},createPieChart:function(ci){var ch=this,X=ci[0],Y=new bj(ch,{series:ci,padding:X.padding,startAngle:X.startAngle,connectors:X.connectors});ch.appendChart(Y)},addToLegend:function(X){var cj=this,ci=cj.options,ck=X.segments,Y=ck.length,ch;for(ch=0;ch
            ")}ch.element=a(ch.template(ch.options)).appendTo(X)},options:{background:C,color:b8,border:{width:3},opacity:1,animation:{duration:bT}},show:function(X){var Y=this;Y.point=X;Y.showTimeout=setTimeout(bq(Y._show,Y),bV)},_show:function(){var cn=this,cl=cn.point,ci=cn.element,ck=cn.options,Y=cn.chartPadding,X,cm,ch,co,cp,cj;if(!cl){return}ch=cl.value.toString();co=af({},cn.options,cl.options.tooltip);if(co.template){cm=A(co.template);ch=cm({value:cl.value,category:cl.category,series:cl.series,dataItem:cl.dataItem,percentage:cl.percentage})}else{if(co.format){ch=cl.formatPointValue(co.format)}}ci.html(ch);X=cl.tooltipAnchor(ci.outerWidth(),ci.outerHeight());cp=bx(X.y+Y.top)+"px";cj=bx(X.x+Y.left)+"px";if(!cn.visible){cn.element.css({top:cp,left:cj})}cn.element.css({backgroundColor:co.background,borderColor:co.border.color||cl.options.color,color:co.color,opacity:co.opacity,borderWidth:co.border.width}).stop(true,true).show().animate({left:cj,top:cp},ck.animation.duration);cn.visible=true},hide:function(){var X=this;clearTimeout(X.showTimeout);if(X.visible){X.element.fadeOut();X.point=null;X.visible=false}}});function M(Y,X){return bx(a0.ceil(Y/X)*X,ai)}function av(Y,X){return bx(a0.floor(Y/X)*X,ai)}function bx(ch,Y){var X=a0.pow(10,Y||0);return a0.round(ch*X)/X}function a2(cu,cr,cp){var cs=ay(cr),ch=cu+cs+cp,Y=a2.cache[ch];if(Y){return Y}var cl=a2.measureBox,X=a2.baselineMarker.cloneNode(false);if(!cl){cl=a2.measureBox=a("
            ").appendTo(am.body)[0]}for(var ct in cr){cl.style[ct]=cr[ct]}cl.innerHTML=cu;cl.appendChild(X);var cq={width:cl.offsetWidth-z,height:cl.offsetHeight,baseline:X.offsetTop+z};if(cp){var cv=cq.width,ck=cq.height,ci=cv/2,cj=ck/2,cm=bw(0,0,ci,cj,cp),cn=bw(cv,0,ci,cj,cp),co=bw(cv,ck,ci,cj,cp);r4=bw(0,ck,ci,cj,cp);cq.normalWidth=cv;cq.normalHeight=ck;cq.width=a0.max(cm.x,cn.x,co.x,r4.x)-a0.min(cm.x,cn.x,co.x,r4.x);cq.height=a0.max(cm.y,cn.y,co.y,r4.y)-a0.min(cm.y,cn.y,co.y,r4.y)}a2.cache[ch]=cq;return cq}a2.cache={};a2.baselineMarker=a("
            ")[0];function ay(ch){var X=[];for(var Y in ch){X.push(Y+ch[Y])}return X.sort().join(" ")}function bw(cj,ck,Y,ch,X){var ci=X*al;return{x:Y+(cj-Y)*a0.cos(ci)+(ck-ch)*a0.sin(ci),y:ch-(cj-Y)*a0.sin(ci)+(ck-ch)*a0.cos(ci)}}function F(cn,cp){if(cn.x1==cp.x1&&cn.y1==cp.y1&&cn.x2==cp.x2&&cn.y2==cp.y2){return cp}var X=a0.min(cn.x1,cp.x1),Y=a0.max(cn.x1,cp.x1),ch=a0.min(cn.x2,cp.x2),ci=a0.max(cn.x2,cp.x2),cj=a0.min(cn.y1,cp.y1),ck=a0.max(cn.y1,cp.y1),cl=a0.min(cn.y2,cp.y2),cm=a0.max(cn.y2,cp.y2),co=[];co[0]=new E(Y,cj,ch,ck);co[1]=new E(X,ck,Y,cl);co[2]=new E(ch,ck,ci,cl);co[3]=new E(Y,cl,ch,cm);if(cn.x1==X&&cn.y1==cj||cp.x1==X&&cp.y1==cj){co[4]=new E(X,cj,Y,ck);co[5]=new E(ch,cl,ci,cm)}else{co[4]=new E(ch,cj,ci,ck);co[5]=new E(X,cl,Y,cm)}return a.grep(co,function(cq){return cq.height()>0&&cq.width()>0})[0]}function bI(X){return bG(X).min}function bH(X){return bG(X).max}function bG(X){var cj=a1,ci=a3,Y,ch=X.length,ck;for(Y=0;Y1?ci:ci[0]})}function h(X,Y){g(X,Y);k(X,Y)}function aI(Y,X,ch){Y[X]=(Y[X]||0)+ch}function ak(X){return typeof X!==b0}var b1=(function(){var X=1;return function(){X=((X>>>1)^(-(X&1)&3489660929))>>>0;return aG+X.toString(16)}})();var Z=function(cm){var Y=this,ch=Z.formats,cl,ck,cj,ci,X;if(arguments.length===1){cm=Y.resolveColor(cm);for(ci=0;ci255)?255:X)},padDigit:function(X){return(X.length===1)?"0"+X:X},brightness:function(ch){var X=this,Y=a0.round;X.r=Y(X.normalizeByte(X.r*ch));X.g=Y(X.normalizeByte(X.g*ch));X.b=Y(X.normalizeByte(X.b*ch));return X}};Z.formats=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,process:function(X){return[parseInt(X[1],10),parseInt(X[2],10),parseInt(X[3],10)]}},{re:/^(\w{2})(\w{2})(\w{2})$/,process:function(X){return[parseInt(X[1],16),parseInt(X[2],16),parseInt(X[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,process:function(X){return[parseInt(X[1]+X[1],16),parseInt(X[2]+X[2],16),parseInt(X[3]+X[3],16)]}}];Z.namedColors={aqua:"00ffff",azure:"f0ffff",beige:"f5f5dc",black:"000000",blue:"0000ff",brown:"a52a2a",coral:"ff7f50",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgray:"a9a9a9",darkgreen:"006400",darkorange:"ff8c00",darkred:"8b0000",dimgray:"696969",fuchsia:"ff00ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lightblue:"add8e6",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumblue:"0000cd",navy:"000080",olive:"808000",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",pink:"ffc0cb",plum:"dda0dd",purple:"800080",red:"ff0000",royalblue:"4169e1",salmon:"fa8072",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",steelblue:"4682b4",tan:"d2b48c",teal:"008080",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"};P.Gradients={glass:{type:aV,rotation:0,stops:[{offset:0,color:b8,opacity:0},{offset:0.1,color:b8,opacity:0},{offset:0.25,color:b8,opacity:0.3},{offset:0.92,color:b8,opacity:0},{offset:1,color:b8,opacity:0}]},sharpBevel:{type:br,stops:[{offset:0,color:b8,opacity:0.55},{offset:0.65,color:b8,opacity:0},{offset:0.95,color:b8,opacity:0},{offset:0.95,color:b8,opacity:0.25}]},roundedBevel:{type:br,stops:[{offset:0.33,color:b8,opacity:0.06},{offset:0.83,color:b8,opacity:0.2},{offset:0.95,color:b8,opacity:0}]}};function b2(X,ci,cj){var Y,ch=X.length;for(Y=0;Y#= d.renderDefinitions() ##= d.renderContent() #")}},options:{width:n,height:m,idPrefix:""},renderTo:function(W){var X=this,Y;X.setupAnimations();x(W,X.render());Y=W.firstChild;X.alignToScreen(Y);X.playAnimations();return Y},renderDefinitions:function(){var X=this,W=U.fn.renderDefinitions.call(X);return W.length>0?""+W+"":""},renderElement:function(X){var W=p.createElement("div"),X;x(W,""+X.render()+"");X=W.firstChild.firstChild;return X},createGroup:function(W){return this.decorate(new H(W))},createText:function(W,X){return this.decorate(new O(W,X))},createRect:function(W,X){return this.decorate(new I(W.points(),true,X))},createLine:function(X,Z,Y,aa,W){return this.decorate(new I([new v(X,Z),new v(Y,aa)],false,W))},createPolyline:function(Y,W,X){return this.decorate(new I(Y,W,X))},createCircle:function(W,Y,X){return this.decorate(new D(W,Y,X))},createSector:function(X,W){return this.decorate(new N(X,W))},createGradient:function(W){if(W.type===w){return new M(W)}else{return new J(W)}},alignToScreen:function(Y){try{var W=Y.getScreenCTM?Y.getScreenCTM():null}catch(X){}if(W){var Z=-W.e%1,ab=-W.f%1,aa=Y.style;if(Z!==0||ab!==0){aa.left=Z+"px";aa.top=ab+"px"}}}});P.fromModel=function(W){var X=new P(W.options);[].push.apply(X.children,W.getViewElements(X));return X};var O=V.extend({init:function(W,X){var Y=this;V.fn.init.call(Y,X);Y.content=W;Y.template=O.template;if(!Y.template){Y.template=O.template=Q("#= d.content #")}},options:{x:0,y:0,baseline:0,font:l,size:{width:0,height:0},fillOpacity:1},refresh:function(W){var X=this.options;a(W).attr({"fill-opacity":X.fillOpacity})},clone:function(){var W=this;return new O(W.content,k({},W.options))},renderRotation:function(){var ae=this,aa=ae.options,ad=aa.size,W=z(aa.x+ad.normalWidth/2,j),X=z(aa.y+ad.normalHeight/2,j),ab=z(aa.x+ad.width/2,j),ac=z(aa.y+ad.height/2,j),Y=z(ab-W,j),Z=z(ac-X,j);return"transform='translate("+Y+","+Z+") rotate("+aa.rotation+","+W+","+X+")'"}});var L=V.extend({init:function(W){var X=this;V.fn.init.call(X,W);X.template=L.template;if(!X.template){X.template=L.template=Q("")}},options:{fill:"",fillOpacity:1,strokeOpacity:1},refresh:function(W){var X=this.options;a(W).attr({d:this.renderPoints(),"fill-opacity":X.fillOpacity,"stroke-opacity":X.strokeOpacity})},clone:function(){var W=this;return new L(k({},W.options))},renderPoints:function(){},renderDashType:function(){var X=this,W=X.options;return y(W.dashType,W.strokeWidth)},renderLinecap:function(){var W=this.options.dashType;return(W&&W!="solid")?"butt":"square"},renderFill:function(){var W=this.options.fill;if(W&&W!==R){return W}return t}});var I=L.extend({init:function(Z,W,Y){var X=this;L.fn.init.call(X,Y);X.points=Z;X.closed=W},renderPoints:function(){var Z=this,aa=Z.points,Y,W=aa.length,X=aa[0],ab="M"+Z._print(X);for(Y=1;Y180,ac=s.max(W.r,0),X=W.c.x,Y=W.c.y,aa=W.point(af),ad=W.point(Z);return ae.pathTemplate({firstPoint:aa,secondPoint:ad,isReflexAngle:ab,r:ac,cx:X,cy:Y})}});var D=V.extend({init:function(W,Z,Y){var X=this;V.fn.init.call(X,Y);X.center=W;X.radius=Z;X.template=D.template;if(!X.template){X.template=D.template=Q("")}},options:{fill:"",fillOpacity:1,strokeOpacity:1}});var H=V.extend({init:function(X){var W=this;V.fn.init.call(W,X);W.template=H.template;if(!W.template){W.template=H.template=Q('#= d.renderContent() #')}}});var F=V.extend({init:function(X){var W=this;V.fn.init.call(W,X);W.template=F.template;if(!W.template){W.template=F.template=Q('#= d.renderContent() #')}}});var J=V.extend({init:function(X){var W=this;V.fn.init.call(W,X);W.template=J.template;W.stopTemplate=J.stopTemplate;if(!W.template){W.template=J.template=Q(" #= d.renderStops() #");W.stopTemplate=J.stopTemplate=Q("")}},options:{id:"",rotation:0},renderStops:function(){var X=this,ab=X.options.stops,ac=X.stopTemplate,Y,Z=ab.length,W,aa="";for(Y=0;Y#= d.renderStops() #");W.stopTemplate=M.stopTemplate=Q("")}},options:{id:"",rotation:0},renderStops:function(){var X=this,ab=X.options.stops,ac=X.stopTemplate,Z=ab.length,W,aa="",Y;for(Y=0;Y",X=p.createElement("div"),W=typeof DOMParser!=S;X.innerHTML=Y;if(W&&X.firstChild.namespaceURI!=C){x=function(aa,ad){var ac=new DOMParser(),Z=ac.parseFromString(ad,"text/xml"),ab=p.adoptNode(Z.documentElement);aa.innerHTML="";aa.appendChild(ab)}}})();k(f,{SVGView:P,SVGText:O,SVGPath:L,SVGLine:I,SVGSector:N,SVGCircle:D,SVGGroup:H,SVGClipPath:F,SVGLinearGradient:J,SVGRadialGradient:M,SVGOverlayDecorator:K,SVGGradientDecorator:G,SVGClipAnimationDecorator:E})})(jQuery);(function(){var a=jQuery,b=a.telerik,k=b.Class,j=b.chart.Chart,m=j.Color,h=j.Box2D,y=j.Point2D,c=j.BarAnimationDecorator,x=j.PieAnimationDecorator,t=j.FadeAnimationDecorator,s=j.ExpandAnimation,G=j.ViewBase,H=j.ViewElement,n=j.deepExtend,D=j.template,F=j.uniqueId,A=j.rotatePoint,B=j.round,C=j.supportsSVG,r=document,v=Math;var d="#000",l=j.CLIP,q=j.DEFAULT_WIDTH,p=j.DEFAULT_HEIGHT,o=j.DEFAULT_FONT,w="object",z="radial",E="transparent";var W=G.extend({init:function(X){var Y=this;G.fn.init.call(Y,X);Y.decorators.push(new Q(Y),new M(Y),new c(Y),new x(Y),new J(Y));if(!u()){Y.decorators.push(new t(Y))}Y.template=W.template;if(!Y.template){Y.template=W.template=D("
            #= d.renderContent() #
            ")}},options:{width:q,height:p},renderTo:function(X){var Y=this;if(r.namespaces){r.namespaces.add("kvml","urn:schemas-microsoft-com:vml","#default#VML")}Y.setupAnimations();X.innerHTML=Y.render();Y.playAnimations();return X.firstChild},renderElement:function(Y){var X=r.createElement("div"),Y;X.style.display="none";r.body.appendChild(X);X.innerHTML=Y.render();Y=X.firstChild;r.body.removeChild(X);return Y},createText:function(X,Y){return this.decorate((Y&&Y.rotation)?new S(X,Y):new V(X,Y))},createRect:function(X,Y){return this.decorate(new O(X.points(),true,Y))},createLine:function(Y,aa,Z,ab,X){return this.decorate(new O([new y(Y,aa),new y(Z,ab)],false,X))},createPolyline:function(Z,X,Y){return this.decorate(new O(Z,X,Y))},createCircle:function(X,Z,Y){return this.decorate(new I(X,Z,Y))},createSector:function(Y,X){return this.decorate(new T(Y,X))},createGroup:function(X){return this.decorate(new N(X))},createGradient:function(X){return new P(X)}});W.fromModel=function(X){var Y=new W(X.options);[].push.apply(Y.children,X.getViewElements(Y));return Y};var V=H.extend({init:function(X,Y){var Z=this;H.fn.init.call(Z,Y);Z.content=X;Z.template=V.template;if(!Z.template){Z.template=V.template=D("#= d.content #")}},options:{x:0,y:0,font:o,color:d,fillOpacity:1},refresh:function(X){a(X).css("visibility",this.renderVisibility())},clone:function(){var X=this;return new V(X.content,n({},X.options))},renderVisibility:function(){return this.options.fillOpacity>0?"visible":"hidden"}});var S=H.extend({init:function(X,Y){var Z=this;H.fn.init.call(Z,Y);Z.content=X;Z.template=S.template;if(!Z.template){Z.template=S.template=D("#= d.renderPath() #")}},options:{x:0,y:0,font:o,color:d,size:{width:0,height:0}},renderPath:function(){var ae=this,ab=ae.options,af=ab.size.width,aa=ab.size.height,Y=ab.x+af/2,Z=ab.y+aa/2,X=-ab.rotation,ac=A(ab.x,Z,Y,Z,X),ad=A(ab.x+af,Z,Y,Z,X);return""}});var U=H.extend({init:function(X){var Y=this;H.fn.init.call(Y,X);Y.template=U.template;if(!Y.template){Y.template=U.template=D('')}}});var L=H.extend({init:function(X){var Y=this;H.fn.init.call(Y,X);Y.template=L.template;if(!Y.template){Y.template=L.template=D('')}},isEnabled:function(){var X=this.options.fill;return !!X&&X.toLowerCase()!==E}});var R=H.extend({init:function(X){var Y=this;H.fn.init.call(Y,X);Y.template=R.template;if(!Y.template){Y.template=R.template=D("#= d.fill.render() + d.stroke.render() #")}Y.stroke=new U(Y.options);Y.fill=new L(Y.options)},options:{fill:"",fillOpacity:1,strokeOpacity:1},render:function(){var X=this;X.fill.options.fillOpacity=X.options.fillOpacity;X.stroke.options.strokeOpacity=X.options.strokeOpacity;return H.fn.render.call(X)},renderPoints:function(){},refresh:function(X){var ac=this,aa=ac.options,Z=a(X),ab=Z[0].parentNode;if(ab){Z.find("path")[0].v=this.renderPoints();try{Z.find("fill")[0].opacity=aa.fillOpacity;Z.find("stroke")[0].opacity=aa.strokeOpacity}catch(Y){}ab.style.cssText=ab.style.cssText}}});var O=R.extend({init:function(aa,X,Z){var Y=this;R.fn.init.call(Y,Z);Y.points=aa;Y.closed=X},renderPoints:function(){var Z=this,aa=Z.points,Y,X=aa.length,ab="m "+Z._print(aa[0]);if(X>1){ab+=" l ";for(Y=1;Y#= d.fill.render() + d.stroke.render() #")}Y.stroke=new U(Y.options);Y.fill=new L(Y.options)},options:{fill:""}});var N=H.extend({init:function(Y){var X=this;H.fn.init.call(X,Y);X.template=N.template;if(!X.template){X.template=N.template=D("
            #= d.renderContent() #
            ")}}});var K=H.extend({init:function(X,Z){var Y=this;H.fn.init.call(Y,Z);Y.template=K.template;Y.clipTemplate=K.clipTemplate;if(!Y.template){Y.template=K.template=D("
            #= d.renderContent() #
            ");Y.clipTemplate=K.clipTemplate=D("rect(#= d.points[0].y #px #= d.points[1].x #px #= d.points[2].y #px #= d.points[0].x #px)")}Y.box=X;Y.points=X.points()},clone:function(){var X=this;return new K(X.box,n({},X.options))},refresh:function(X){X.style.clip=this._renderClip()},_renderClip:function(){return this.clipTemplate(this)}});var P=H.extend({init:function(Y){var X=this;H.fn.init.call(X,Y);X.template=P.template;if(!X.template){X.template=P.template=D("")}},options:{rotation:0,opacity:1},renderColors:function(){var Y=this,ab=Y.options,ae=ab.stops,X,Z,aa=ae.length,ac=[],ad=v.round;for(Z=0;Z
            '].join(" "))}this.render=function(){f.wrap(p()).hide();var q=a('
            ').insertBefore(f);this.text({builder:g,text:n,id:k,name:m}).appendTo(q);a('select').appendTo(q);if(l){g.buffer=[];a(g.cat('").string()).insertAfter(q)}};this.text=function(q){return a(['',q.text||" ",""].join(""))}},initialize:function(){this.previousValue=this.value();b.bind(this,{dataBinding:this.onDataBinding,dataBound:this.onDataBound,error:this.onError,open:this.onOpen,close:this.onClose,valueChange:this.onChange,load:this.onLoad})},common:function(){this.open=function(){if(!this.loader.isAjax()&&(!this.data||this.data.length==0)){return}var f=this.$wrapper||this.$element,g=this.dropDown,h=g.$element.css("z-index");var j={offset:f.offset(),outerHeight:f.outerHeight(),outerWidth:f.outerWidth(),zIndex:h&&h!="auto"?h:b.getElementZIndex(f[0])};if(g.$items){g.open(j)}else{this.fill(function(){g.open(j)})}};this.close=function(){this.dropDown.close()};this.dataBind=function(f,o){this.data=f=(f||[]);var k=-1,m=f.length,n=this.placeholder;if(n&&f[0]&&f[0].Text!==n){var g=[{Text:n,Value:""}];for(var j=0;j-1&&f0&&t.length0){g.filters[l](g,h,t);var k=g.filteredDataIndexes;if((k&&k.length>0)||(l==0&&g.selectedIndex!=-1)){p=false}}if(p){var q={};q[g.queryString.text]=t;g.loader.ajaxRequest(function(w){var y=g.trigger;var x=g.dropDown;if(w&&w.length==0){x.close();x.dataBind();return}g.data=w;b.trigger(g.element,"dataBound");g.filters[l](g,w,t);var v=x.$items;if(v.length>0){if(!x.isOpened()){y.open()}g.filtering.autoFill(g,v.first().text())}else{y.close()}},{data:q})}}else{p=false;g.filters[l](g,g.data,t)}if(!p){var f=j.$items;if(!f){return}var n=f.length,r=g.selectedIndex;var o=l==0?r!=-1?f[r].innerText||f[r].textContent:"":f.length>0?f.first().text():"";this.autoFill(g,o);if(n==0){u.close()}else{if(!j.isOpened()){u.open()}}}};this.multiple=function(f){return f}},filters:function(){this.filters=[function f(h,j,m){if(!j||j.length==0){return}var k=h.dropDown;var g=k.$items;if(!g||g.length==0||h.loader.isAjax()){k.dataBind(j,h.encoded);g=k.$items}for(var l=0,o=j.length;l .t-dropdown-wrap .t-icon").addClass("t-loading")},this),100)},this.hideBusy=function(){clearTimeout(this.busyTimeout);this.component.$wrapper.find("> .t-dropdown-wrap .t-icon").removeClass("t-loading")}},trigger:function(f){this.component=f;this.change=function(){var g=f.previousValue;var h=f.value();if(g==undefined||h!=g){b.trigger(f.element,"valueChange",{value:h});f._oldIndex=f.selectedIndex}else{if(f.selectedIndex!==f._oldIndex){b.trigger(f.element,"valueChange",{value:h});f._oldIndex=f.selectedIndex}}f.previousValue=f.value()};this.open=function(){var g=f.dropDown;if((g.$items&&g.$items.length>0)&&!g.isOpened()&&!b.trigger(f.element,"open")){f.open()}};this.close=function(){var g=f.dropDown;if((g.$element.is(":animated")||g.isOpened())&&!b.trigger(f.element,"close")){f.close()}}},retrieveData:function(l){var j=[];var g=a(l).find("option");for(var h=0,k=g.length;h]*)("+n.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)",g?"ig":"i");j.filteredDataIndexes=l;j.selectedIndex=-1;j.dropDown.onItemCreate=function(o){if(n){o.html=o.html.replace(m,"$1")}};j.dropDown.dataBind(a.map(l,function(p,o){return k[p]}),j.encoded);var h=j.dropDown.$items;h.removeClass("t-state-selected");b.list.highlightFirstOnFilter(j,h)}}function d(g,f,k){if(!g||!f){return null}var l=k.length;k=k.toLowerCase();for(var h=0,j=g.length;h .t-dropdown-wrap > .t-input");if(!this.$wrapper.attr("tabIndex")){this.$wrapper.attr("tabIndex",0)}this.dropDown=new b.dropDown({attr:this.dropDownAttr,effects:this.effects,onClick:a.proxy(function(t){this.select(t.item);this.trigger.change();this.trigger.close();this.$wrapper.focus()},this)});this.dropDown.$element.css("direction",this.$wrapper.closest(".t-rtl").length?"rtl":"");var s=function(v){var t="class",u=f.attr(t);if((v.attrName&&v.attrName=="class")||(v.propertyName&&v.propertyName=="className")){var w=f.prev(".t-dropdown-wrap");var x=/\b(t-state-[\w]+)\b/.exec(w.attr(t));if(!(x&&x[0])){x=""}else{x=x[0]}if(u!=w.attr(t)){w.attr(t,u).addClass("t-dropdown-wrap "+x)}}};if(a.browser.msie){l.attachEvent("onpropertychange",s)}else{f.bind("DOMAttrModified",s)}this.fill=function(t,w){function x(z){var C,D=z.selectedValue||z.value();if(D){C=function(E){return D==(E.Value||E.Text)}}else{var y=z.dropDown.$items,A=z.index,B=y.filter(".t-state-selected").length;C=A!=-1&&A0?B-1:0}z.select(C);z._oldIndex=z.selectedIndex}var u=this.dropDown,v=this.loader;if(!u.$items&&!v.ajaxError){if(v.isAjax()){w=w||{};v.ajaxRequest(function(y){this.dataBind(y,true);x(this);b.trigger(this.element,"dataBound");this.trigger.change();if(t){t()}},w)}else{this.dataBind(this.data);x(this);if(t){t()}}}};this.enable=function(){var t=this.$wrapper.removeClass("t-state-disabled");if(!t.data("events")){this.$wrapper.removeClass("t-state-disabled").bind({keydown:a.proxy(n,this),keypress:a.proxy(o,this),click:a.proxy(function(v){var w=this.trigger;var u=this.dropDown;this.$wrapper.focus();if(u.isOpened()){w.close()}else{if(!u.$items){this.fill(w.open)}else{w.open()}}},this),focus:a.proxy(function(){this.$wrapper.find(".t-dropdown-wrap").addClass("t-state-focused").removeClass("t-state-default")},this),blur:a.proxy(function(){this.$wrapper.find(".t-dropdown-wrap").addClass("t-state-default").removeClass("t-state-focused")},this)})}f.removeAttr("disabled")};this.disable=function(){f.attr("disabled","disabled");this.$wrapper.addClass("t-state-disabled").unbind()};this.reload=function(){this.dropDown.$items=null;if(arguments.length){this.fill(arguments[0],arguments[1])}else{this.fill()}};this.select=function(u){var t=this.highlight(u);if(t!=-1){this.selectedIndex=t;b.list.updateTextAndValue(this,this.data[t].Text,this.data[t].Value)}return t};this.text=function(t){if(t!==undefined){if(this.encoded){t=b.encode(t)}this.$text.html(t&&t.replace(e,"")?t:" ")}else{return this.$text.html()}};this.value=function(u){if(u!==undefined){u=u+"";var t=this.select(function(v){return u===(v.Value+"")});if(t==-1){t=this.select(function(v){return u==v.Text})}if(t!=-1){this.previousValue=this.$element.val();this._oldIndex=this.selectedIndex}}else{return this.$element.val()}};b.list.common.call(this);b.list.initialize.call(this);a(document.documentElement).bind("mousedown",a.proxy(function(u){var t=this.dropDown.$element;var v=t&&t.parent().length>0;if(a.contains(this.$wrapper[0],u.target)||(v&&a.contains(t.parent()[0],u.target))){return}this.trigger.change();this.trigger.close()},this));this[this.enabled?"enable":"disable"]();function q(){clearTimeout(this.timeout);this.timeout=setTimeout(a.proxy(function(){j=""},this),this.delay)}function n(y){var B=this.trigger;var x=this.dropDown;var A=y.keyCode||y.which;if(y.altKey&&(A==38||A==40)){var w=A==38?B.close:B.open;if(!x.$items){this.fill(w)}else{w()}return}if(A>34&&A<41){y.preventDefault();if(!x.$items){this.fill();return}var u=x.$items,v=a(u[this.selectedIndex]);var t=(A==35)?u.last():(A==36)?u.first():(A==37||A==38)?v.prev():(A==39||A==40)?v.next():[];if(t.length){var z=t[0];this.select(z);x.scrollTo(z);if(!x.isOpened()){B.change()}}}if(A==8){a.proxy(q,this)();y.preventDefault();j=j.slice(0,-1)}if(A==9||A==13||A==27){B.change();B.close()}}function o(u){var t=this.dropDown;var v=u.keyCode||u.charCode;if(v==0||a.inArray(v,b.list.keycodes)!=-1||u.ctrlKey||u.altKey||u.shiftKey){return}if(!t.$items){this.fill(a.proxy(function(){h(v)},this));return}h(v)}var h=a.proxy(function h(v){var t=this.dropDown;var w=j;w+=String.fromCharCode(v);if(w){var u=d(this.data,t.$items,w);if(u){this.select(u);t.scrollTo(u)}j=w}a.proxy(q,this)()},this);if(r.cascadeTo){var k=a("#"+r.cascadeTo).attr("disabled","disabled");k.bind("load",function(){if(r.value()){r.$element.trigger("valueChange")}});r.$element.bind("valueChange",a.proxy(function(){var u=k.data("tDropDownList");if(u){var v=[],t={};t[r.$element.attr("name")]=r.value();if(u.loader.isAjax()){if(r.placeholder){v[0]={Text:r.placeholder,Value:""}}u.dataBind(v)}u.select(0);u.disable();if(r.value()===""&&r.placeholder){u.$element.trigger("valueChange");return}u.reload(function(){var w=v[0]?1:0;if(u.data[w]){u.enable()}},{data:t})}},r))}};a.fn.tDropDownList=function(f){return b.create(this,{name:"tDropDownList",init:function(g,h){return new b.dropDownList(g,h)},options:f})};a.fn.tDropDownList.defaults={effects:b.fx.slide.defaults(),accessible:false,index:0,delay:500,encoded:true}})(jQuery);(function(a){var b=a.telerik;b.scripts.push("telerik.autocomplete.js");b.autocomplete=function(d,f){a.extend(this,f);var c=this.$element=a(d).addClass("t-widget t-autocomplete t-input").attr("autocomplete","off").bind("paste",a.proxy(function(j){g(this)},this));this.$text=c;this.element=d;this.trigger=new b.list.trigger(this);this.trigger.change=function(){var k=this.component.text();var j=this.component.previousValue;if(j==undefined||k!=j){b.trigger(this.component.element,"valueChange",{value:k})}this.component.previousValue=k};this.loader=new b.list.loader(this);this.loader.showBusy=function(){this.busyTimeout=setTimeout(a.proxy(function(){this.component.$element.addClass("t-loading")},this),100)};this.loader.hideBusy=function(){clearTimeout(this.busyTimeout);this.component.$element.removeClass("t-loading")};this.filtering=new b.list.filtering(this);this.filtering.autoFill=function(j,n){if(j.autoFill&&(j.lastKeyCode!=8&&j.lastKeyCode!=46)){var m=j.$text[0],v=m.value,r=j.separator,k=b.caretPos(m),q=j.multiple;var o=q&&r?b.lastIndexOf(v.substring(0,k),r):-1;var t=o!=-1?o+r.length:0;var l=v.substring(t,k);var p=n.toLowerCase().indexOf(l.toLowerCase());if(p!=-1){var u=n.substring(p+l.length);if(q){var s=v.split(r),w=h(m,r);s[w]=l+u;m.value=s.join(r)+(j.multiple&&w!=0&&w==s.length-1?r:"")}else{m.value=l+u}b.list.selection(m,k,k+u.length)}}};this.enable=function(){c.removeClass("t-state-disabled").removeAttr("disabled")};this.disable=function(){c.addClass("t-state-disabled").attr("disabled","disabled")};this.filtering.multiple=a.proxy(function(j){if(this.multiple){j=j.split(this.separator);j=j[h(this.$text[0],this.separator)]}return j},this);this.dropDown=new b.dropDown({attr:this.dropDownAttr,effects:this.effects,onClick:a.proxy(function(j){this.select(j.item);this.trigger.change();this.trigger.close()},this)});this.dropDown.$element.css("direction",c.closest(".t-rtl").length?"rtl":"");this.fill=function(j){function l(s){var r=s.highlightFirst?k.$items.first():null;if(r){r.addClass("t-state-selected")}}var m=this.loader;var k=this.dropDown;var n=this.minChars;var p=this.text();var q=p.length;if(!k.$items&&!m.ajaxError){if((m.isAjax()||this.onDataBinding)&&q>=n){var o={};o[this.queryString.text]=p;m.ajaxRequest(function(r){this.dataBind(r,true);l(this);b.trigger(this.element,"dataBound");this.trigger.change();if(j){j()}},{data:o})}else{this.dataBind(this.data,true);l(this);if(j){j()}}}};this.text=function(){if(arguments.length>0){this.previousValue=arguments[0]}return this.$text.val.apply(this.$text,arguments)};this.value=function(){return this.text.apply(this,arguments)};this.select=function(n){var m=this.highlight(n);if(m==-1){return m}var l=this.filteredDataIndexes;var o=(l&&l.length)>0?l[m]:m;var n=this.data[o];var k=n.Text?n.Text:n;var q=k;if(this.multiple){var j=this.$element;var p=this.separator;var r=h(j[0],p);q=j.val().split(p);q[r]=k;q=q.join(p)+(r==q.length-1?p:"")}this.$text.val(q)};b.list.common.call(this);b.list.filters.call(this);b.list.initialize.call(this);this.dataBind=function(j,k){this.data=j=(j||[]);this.dropDown.dataBind(j,this.encoded);if(!k){this.$text.val("")}};c.bind({focus:a.proxy(function(j){j.stopPropagation()},this),keydown:a.proxy(e,this),keypress:a.proxy(function(j){var k=j.keyCode||j.charCode;if(k==0||a.inArray(k,b.list.keycodes)!=-1||j.ctrlKey){return true}},this)});a(document.documentElement).bind("mousedown",a.proxy(function(k){var j=this.dropDown.$element.parent();var l=j.length;if((!l&&d!==k.target)||(l&&!a.contains(d,k.target)&&!a.contains(j[0],k.target))){this.trigger.change();this.trigger.close()}},this));function h(j,k){return j.value.substring(0,b.caretPos(j)).split(k).length-1}function g(j){clearTimeout(j.timeout);j.timeout=setTimeout(function(){j.filtering.filter(j)},j.delay)}function e(p){var u=this.trigger;var o=this.dropDown;var r=p.keyCode||p.which;this.lastKeyCode=r;if(!p.shiftKey&&r>36&&r<41&&r!=37&&r!=39){p.preventDefault();if(o.isOpened()){if(!o.$items){this.fill()}var l=o.$items;var m=l.filter(".t-state-selected:first");var k=[];if(r==38){var t=m.prev();k=t.length?t:l.last()}else{if(r==40){var s=m.next();k=s.length?s:l.first()}}if(k.length){var q=k[0];this.highlight(q);o.scrollTo(q);this.filtering.autoFill(this,k.text())}}return}if(r==8||r==46){var j=this.$element;if(j.val()!=""){g(this)}setTimeout(a.proxy(function(){if(j.val()==""){u.close()}},this),0);return}if(r==13){if(o.isOpened()){p.preventDefault()}if(o.$items){var n=o.$items.filter(".t-state-selected:first");if(n.length>0){this.select(n[0])}}u.change();u.close();b.list.moveToEnd(this.element);return}if(r==27||r==9){clearTimeout(this.timeout);u.change();u.close();return}g(this)}};a.fn.tAutoComplete=function(c){return b.create(this,{name:"tAutoComplete",init:function(d,e){return new b.autocomplete(d,e)},options:c})};a.fn.tAutoComplete.defaults={encoded:true,effects:b.fx.slide.defaults(),filter:1,delay:200,minChars:1,cache:true,autoFill:false,highlightFirst:false,queryString:{text:"text"},multiple:false,separator:", "}})(jQuery);(function(a){var b=a.telerik,e=/{0:?/,c=/{0:?(\S|\s)*}/;b.scripts.push("telerik.calendar.js");function d(h,g,f){var j=new b.datetime();if(h){j=new b.datetime(h)}if(g>j.value){j=new b.datetime(g)}else{if(f').cat('').cat(this.currentView.title(this.viewedMonth)).cat("").cat('=0).cat('">');a(".t-header",this.element).html(g.string());a(".t-nav-next:not(.t-state-disabled)",f).live("click",a.proxy(this.navigateToFuture,this));a(".t-nav-prev:not(.t-state-disabled)",f).live("click",a.proxy(this.navigateToPast,this));a(".t-nav-fast:not(.t-state-disabled)",f).live("click",a.proxy(this.navigateUp,this));a(".t-link.t-state-disabled",f).live("click",b.preventDefault);a("td:not(.t-state-disabled):has(.t-link)",f).live("mouseenter",b.hover).live("mouseleave",b.leave).live("click",a.proxy(this.navigateDown,this));b.bind(this,{change:this.onChange,load:this.onLoad});this._footer(this.todayFormat)}});b.calendar.prototype={stopAnimation:false,updateSelection:function(){var g=b.datetime.firstDayOfMonth(this.viewedMonth).toDate();var h=new b.datetime(g).date(32).date(0).toDate();if(this.selectedDate===null||!b.calendar.isInRange(this.selectedDate,g,h)){var k=d(this.selectedDate,this.minDate,this.maxDate);this.goToView(0,k)}var j=this;var f=a(".t-content td:not(.t-other-month)",this.element).removeClass("t-state-selected");if(this.selectedDate!==null){f.filter(function(){return(parseInt(a(this).text(),10)==j.selectedDate.getDate())}).addClass("t-state-selected")}},value:function(){if(arguments.length==0){return this.selectedDate}if(arguments.length==1){this.selectedDate=arguments[0]===null?null:new Date(arguments[0].value?arguments[0].value:arguments[0])}else{if(arguments.length>1){this.selectedDate=new Date(arguments[0],arguments[1],arguments[2])}}this.updateSelection();return this},overlay:function(g){if(!g){return a(".t-overlay",this.element).remove()}var f=a("
            ").addClass("t-overlay").css({opacity:0,width:this.element.offsetWidth,height:this.element.offsetHeight,position:"absolute",top:0,left:0,zIndex:3,backgroundColor:"#fff"});a(this.element).find(".t-header").after(f)},goToView:function(j,h){if(j<0||b.calendar.views.length<=j){return}var g=new b.datetime(this.minDate);var f=new b.datetime(this.maxDate);if(typeof h!="undefined"){h=h.value?h:new b.datetime(h);this.viewedMonth=b.datetime.firstDayOfMonth(h)}this.currentView=b.calendar.views[j];a(".t-nav-prev",this.element).toggleClass("t-state-disabled",this.currentView.compare(h,g,false)<=0);a(".t-nav-next",this.element).toggleClass("t-state-disabled",this.currentView.compare(h,f,true)>=0);a(".t-nav-fast",this.element).html(this.currentView.title(h)).toggleClass("t-state-disabled",j==b.calendar.views.length-1);a(".t-content",this.element).html(this.currentView.body(h,g,f,this.selectedDate?new b.datetime(this.selectedDate):null,this.urlFormat,this.dates)).toggleClass("t-meta-view",j==1||j==2);return this},navigateVertically:function(w,v,t,u){v=new b.datetime(v);this.viewedMonth=b.datetime.firstDayOfMonth(v);this.currentView=b.calendar.views[w];this.overlay(true);var l=new b.datetime(this.minDate);var h=new b.datetime(this.maxDate);var n=a(".t-content",this.element);var r=n.outerWidth();var p=n.outerHeight();var o=n.css("font-size");var q=n.css("line-height");if(q==="normal"){q=parseInt(o)*1.5}n.find("td").removeClass("t-state-hover");a(".t-nav-fast",this.element).html(this.currentView.title(v)).toggleClass("t-state-disabled",w==b.calendar.views.length-1);a(".t-nav-prev",this.element).toggleClass("t-state-disabled",this.currentView.compare(this.viewedMonth,l,false)<=0);a(".t-nav-next",this.element).toggleClass("t-state-disabled",this.currentView.compare(this.viewedMonth,h,true)>=0);var m=a('
            ').html(this.currentView.body(v,l,h,this.selectedDate?new b.datetime(this.selectedDate):null,this.urlFormat,this.dates)).toggleClass("t-meta-view",w==1||w==2);var k=this;var j={fontSize:o,lineHeight:q,top:0,left:0,width:r,height:p,opacity:1};var s;if(t){s=b.fx._wrap(n).css({overflow:"hidden",position:"relative"});m.wrap(a("
            ").addClass("t-animation-container").css(a.extend({position:"absolute",zIndex:1,fontSize:1,lineHeight:1,width:u.outerWidth(),height:u.outerHeight(),opacity:0},u.position()))).parent().insertAfter(n);if(!this.stopAnimation){m.parent().animate({fontSize:o,lineHeight:q,top:0,left:0,width:r,height:p,opacity:1},"normal",function(){a(k.element).find(".t-header").after(m);s.remove();k.overlay(false)})}else{n.remove();a(k.element).find(".t-header").after(m);s.remove();k.overlay(false)}}else{m.insertBefore(n);s=b.fx._wrap(m).css({overflow:"hidden",position:"relative"});var g;if(w!=0){g=b.calendar.views[w].verticalDate(this.viewedMonth)}var f={top:(Math.floor(g/4)*p)/3,left:((g%4)*r)/4};n.wrap(a("
            ").addClass("t-animation-container").css(a.extend({position:"absolute"},j))).parent().insertAfter(m);if(!this.stopAnimation){n.parent().animate(a.extend({fontSize:1,lineHeight:1,width:48,height:54,opacity:0},f),"normal",function(){a(k.element).find(".t-header").after(m);s.remove();k.overlay(false)})}else{n.remove();a(k.element).find(".t-header").after(m);s.remove();k.overlay(false)}}b.trigger(this.element,"navigate",{direction:t})},navigateHorizontally:function(o,n,g){n=new b.datetime(n);var k=new b.datetime(this.minDate);var h=new b.datetime(this.maxDate);this.viewedMonth=b.datetime.firstDayOfMonth(b.calendar.fitDateToRange(n,k,h));this.currentView=b.calendar.views[o];a(".t-nav-fast",this.element).html(this.currentView.title(n)).toggleClass("t-state-disabled",o==b.calendar.views.length-1);a(".t-nav-prev",this.element).toggleClass("t-state-disabled",this.currentView.compare(this.viewedMonth,k,false)<=0);a(".t-nav-next",this.element).toggleClass("t-state-disabled",this.currentView.compare(this.viewedMonth,h,true)>=0);this.overlay(true);var l=a('
            ').html(this.currentView.body(n,k,h,this.selectedDate?new b.datetime(this.selectedDate):null,this.urlFormat,this.dates)).toggleClass("t-meta-view",o==1||o==2);var m=a(".t-content",this.element);var p=m.outerWidth();m.add(l).css({width:p,"float":"left"});var f=b.fx._wrap(m).css({position:"relative",width:p*2,"float":"left",left:(g?0:-200)});l[g?"insertAfter":"insertBefore"](m);var j=this;if(!this.stopAnimation){f.animate({left:(g?-200:0)},"normal",function(){a(j.element).find(".t-header").after(l);f.remove();j.overlay(false)})}else{m.remove();a(j.element).find(".t-header").after(l);f.remove();j.overlay(false)}b.trigger(this.element,"navigate",{direction:g})},navigateUp:function(g){if(g){g.preventDefault()}var f=this.currentView.index;this.navigateVertically(f+1,this.viewedMonth.toDate(),false)},navigateDown:function(k,o,p){var f=a(a(k.target).hasClass("t-input")?o:k.target);var g=f.text();var h=p||this.currentView.index;var l=f.attr("href");if(l&&(l.charAt(l.length-1)=="#")){k.preventDefault()}if(h==0){var j=parseInt(g,10);var m=this.viewedMonth.month();if(f.parent().hasClass("t-other-month")){m+=(j<15?1:-1)}var n=new Date(this.viewedMonth.year(),m,j);if(!this.selectedDate||(this.selectedDate>n||n>this.selectedDate)){if(b.trigger(this.element,"change",{previousDate:this.selectedDate,date:n})){return this}this.selectedDate=n}this.updateSelection()}else{if(h!=0){b.calendar.views[h].verticalDate(this.viewedMonth,g)}this.viewedMonth=b.calendar.fitDateToRange(this.viewedMonth,new b.datetime(this.minDate),new b.datetime(this.maxDate));this.navigateVertically(h-1,this.viewedMonth.toDate(),true,f.add(f.parent()).filter("td"))}},navigateToPast:function(g){if(g){g.preventDefault()}var f=this.currentView.index;if(f==0){this.viewedMonth.date(1).date(-1)}else{this.viewedMonth.addYear(-Math.pow(10,f-1))}this.navigateHorizontally(f,this.viewedMonth.toDate(),false)},navigateToFuture:function(g){if(g){g.preventDefault()}var f=this.currentView.index;if(f==0){this.viewedMonth.date(32).date(1)}else{this.viewedMonth.addYear(Math.pow(10,f-1))}this.navigateHorizontally(f,this.viewedMonth.toDate(),true)},_footer:function(g){var j=this,f=j.footer,k=new Date(),h=a.telerik.datetime.format(k,g||"d");if(!f){j.footer=f=a('');a(j.element).append(f);f.find("a").click(function(l){l.preventDefault();if(!j.selectedDate||(j.selectedDate>k||k>j.selectedDate)){if(!b.trigger(j.element,"change",{previousDate:j.selectedDate,date:k})){j.selectedDate=k;j.updateSelection()}}})}f.find("a").attr("title",h).html(h);f.toggle(!!g)}};a.fn.tCalendar=function(f){return b.create(this,{name:"tCalendar",init:function(g,h){return new b.calendar(g,h)},options:f})};a.fn.tCalendar.defaults={selectedDate:null,minDate:new Date(1899,11,31),maxDate:new Date(2100,0,1)};a.extend(b.calendar,{views:[{index:0,title:function(f){return new b.stringBuilder().cat(b.cultureInfo.months[f.month()]).cat(" ").cat(f.year()).string()},body:function(x,q,p,s,w,j){var n=(new b.stringBuilder()).cat("");var m=b.cultureInfo.firstDayOfWeek,l=b.cultureInfo.days,f=b.cultureInfo.abbrDays,u=b.cultureInfo.shortestDays;l=l.slice(m).concat(l.slice(0,m));f=f.slice(m).concat(f.slice(0,m));u=u.slice(m).concat(u.slice(0,m));for(var o=0;o<7;o++){n.cat('').cat(u[o]).cat("")}n.cat("");var h=b.datetime.firstVisibleDay(x);var r=x.month();var t=s===null?false:x.year()==s.year();var g;for(var y=0;y<6;y++){n.cat("");for(var k=0;k<7;k++){g=h.month()!=r?"t-other-month":(t&&h.month()==s.month()&&h.date()==s.date())?" t-state-selected":"";n.cat("");if(b.calendar.isInRange(h.toDate(),q.toDate(),p.toDate())){n.cat('').cat(h.date()).cat("")}else{n.cat(" ")}n.cat("");b.datetime.modify(h,b.datetime.msPerDay)}n.cat("")}n.cat("");return n.string()},compare:function(f,j){var m;var g=f.month();var h=f.year();var k=j.month();var l=j.year();if(h>l){m=1}else{if(hk?1:-1}}return m},firstLastDay:function(g,h,f){return h?b.datetime.firstDayOfMonth(g):new b.datetime(g.year(),g.month()+1,0)},navCheck:function(f,g,h){if(h){return new b.datetime(g.year(),g.month()+1,g.date()).value-f.value<=0}else{return this.compare(f,g)===-1}}},{index:1,title:function(f){return f.year()},body:function(h,g,f){return b.calendar.metaView(true,h,function(){var l=[];var m=0;var j=11;if(g.year()==f.year()){m=g.month();j=f.month()}else{if(h.year()==g.year()){m=g.month()}else{if(h.year()==f.year()){j=f.month()}}}for(var k=0;k<12;k++){if(k>=m&&k<=j){l.push(b.cultureInfo.abbrMonths[k])}else{l.push(" ")}}return l})},compare:function(f,g){return f.year()>g.year()?1:f.year()=l&&n+j<=k?n+j:" ")}return m})},compare:function(g,h,f){var l=g.year();var k=(l-l%10);var j=(l-l%10+9);return b.calendar.check(k,j,h,f)},verticalDate:function(g,f){if(!f){return g.year()%10+1}g.year(f)},firstLastDay:function(f,g){return new b.datetime(f.year()-f.year()%10+(g?0:9),0,1)},navCheck:function(f,g,h){var j=this.compare(g,f,h);return h?j==-1:j==1}},{index:3,title:function(g){var f=g.year()-g.year()%100;return f+"-"+(f+99)},body:function(h,g,f){return b.calendar.metaView(false,h,function(){var j=h.year()-h.year()%100;var m=[];for(var l=-1;l<11;l++){var k=j+l*10;if((k+10)>=g.year()&&k<=f.year()){m.push(k+"-
            "+(k+9)+" ")}else{m.push(" 
             ")}}return m})},compare:function(g,h,f){var l=g.year();var k=(l-l%100);var j=(l-l%100+99);return b.calendar.check(k,j,h,f)},verticalDate:function(g,f){if(!f){return Math.ceil(g.year()/10)%10+1}g.year(f.substring(0,f.indexOf("-")))},firstLastDay:function(f,g){return g?new b.datetime(f.year()-(f.year()%100),0,1):new b.datetime(f.year()-(f.year()%100)+99,0,1)},navCheck:function(f,g,h){var j=this.compare(g,f,h);return h?j==-1:j==1}}],check:function(j,k,h,g){var f=function(l){return lh.year()?1:0};return g?f(k):f(j)},html:function(l,j,h,g,k,f){l=l||new b.datetime();h=h||new b.datetime(a.fn.tCalendar.defaults.minDate);g=g||new b.datetime(a.fn.tCalendar.defaults.maxDate);return new b.stringBuilder().cat('
            ').cat('").cat('').cat(b.calendar.views[0].body(l,h,g,j,k,f)).cat("
            ").string()},metaView:function(k,m,g){var h=new b.stringBuilder();var f=g();h.cat("");for(var j=0,l=f.length;j",j>0&&j%4==0).cat("");if(f[j]!==" "&&f[j]!==" 
             "){h.cat('').cat(f[j]).cat("")}else{h.cat(f[j])}h.cat("")}h.cat("");return h.string()},isInRange:function(g,l,j){if(!g){return false}var f=new Date(g.getFullYear(),g.getMonth(),g.getDate());var k=new Date(l.getFullYear(),l.getMonth(),l.getDate());var h=new Date(j.getFullYear(),j.getMonth(),j.getDate());return k-f<=0&&h-f>=0},fitDateToRange:function(f,h,g){if(f.valueg.value){f=new b.datetime(g.value)}return f},isInCollection:function(f,g){var j=g[f.year()];if(j){var h=j[f.month()];if(h&&a.inArray(f.date(),h)!=-1){return true}}return false},findTarget:function(k,n,g,l){k=k.value?k:new b.datetime(k);var j=function(p,q){return a.grep(p,function(r){return a(r).children().eq(0).text().indexOf(q)>-1})[0]};var m=l?"last":"first";var h=a(".t-content:"+m+" td:has(> .t-link)",g).removeClass("t-state-focus");var f;if(n==0){f=a(j(h.filter(":not(.t-other-month)"),k.date()))}else{if(n==1){f=a(j(h,b.cultureInfo.abbrMonths[k.month()]))}else{if(n==2||n==3){var o=k.year();f=a(j(h,n==2?o:o-(o%10)));if(f.length==0&&n==3){f=a(j(h,o-(o%10)+99))}}}}return f},focusDate:function(g,j,f,h){b.calendar.findTarget(g,j,f,h).addClass("t-state-focus")},formatUrl:function(j,f){var h=j.match(c);if(h){h=h[0];var g=h==="{0}"?b.cultureInfo.generalDateTime:h.replace(e,"").replace("}","");return j.replace(h,b.datetime.format(f.toDate(),g))}return j}})})(jQuery);(function(a){var b=a.telerik;b.scripts.push("telerik.combobox.js");b.combobox=function(j,p){if(p&&p.enabled===undefined){p.enabled=!a(j).is("[disabled]")}a.extend(this,p);var m=j.nodeName.toLowerCase()=="input"&&j.type.toLowerCase()=="text";var l=j.nodeName.toLowerCase()=="select";if((m||l)&&!a(j).parent().hasClass("t-combobox")){if(l&&!this.data){this.data=b.list.retrieveData(j)}var k=new b.list.htmlBuilder(j,"t-combobox",l);k.text=function(v){var u=v.builder;u.buffer=[];return a(u.cat('").string())};k.render();if(l){j=j.previousSibling}}this.element=j;var r=this;var d=this.$element=a(j).closest("form").bind("reset",function(){setTimeout(function(){r.value(j.value)})}).end();this.loader=new b.list.loader(this);this.trigger=new b.list.trigger(this);var g=this.$wrapper=d.closest(".t-combobox");var e=this.$wrapper.find(".t-select");var f=this.$text=this.$wrapper.find("> .t-dropdown-wrap > .t-input").attr("autocomplete","off").bind("paste",a.proxy(function(u){setTimeout(a.proxy(function(){this.$element.val(u.target.value);q(this)},this),0)},this));var t=function(w){var u="class",v=d.attr(u)||"";if((w.attrName&&w.attrName==u)||(w.propertyName&&w.propertyName=="className")){if(v!=f.attr(u)){f.attr(u,v).addClass("t-input")}}};if(a.browser.msie){j.attachEvent("onpropertychange",t)}else{d.bind("DOMAttrModified",t)}d.closest("form").bind("reset",a.proxy(function(u){var v=this;window.setTimeout(function(){if(d.val()!=""){v.value(d.val())}else{v.highlight(0);v.selectedIndex=0}},1)},this));this.filtering=new b.list.filtering(this);this.filtering.autoFill=function(u,y){if(u.autoFill&&(u.lastKeyCode!=8&&u.lastKeyCode!=46)){var x=u.$text[0];var v=b.caretPos(x);var w=x.value.substring(0,v);var z=y.toLowerCase().indexOf(w.toLowerCase());if(z!=-1){var A=y.substring(z+w.length);x.value=w+A;b.list.selection(x,v,v+A.length)}}};this.dropDown=new b.dropDown({attr:this.dropDownAttr,effects:this.effects,onOpen:a.proxy(function(){var u=this.data;var v=this.dropDown;if(u.length==0){return}var x=this.$text.val();var w=this.selectedIndex;if(w!=-1&&this.isFiltered){if(x==u[w].Text){this.filteredDataIndexes=[];v.onItemCreate=null;if(this.filter){v.dataBind(this.data,this.encoded)}this.select(v.$items[w])}else{this.filters[this.filter](this,this.data,x)}this.isFiltered=false}},this),onClick:a.proxy(function(u){this.select(u.item);this.trigger.change();this.trigger.close();f.focus()},this)});this.dropDown.$element.css("direction",g.closest(".t-rtl").length?"rtl":"");this.enable=function(){g.removeClass("t-state-disabled");f.removeAttr("disabled");d.removeAttr("disabled");if(!e.data("events")){e.bind("click",a.proxy(s,this))}};this.disable=function(){g.addClass("t-state-disabled");f.attr("disabled","disabled");d.attr("disabled","disabled");e.unbind("click")};this[this.enabled?"enable":"disable"]();this.fill=function(u,z,w){function D(G){var K=G.selectedValue||G.value();if(K){G.value(K);return}var E=v.$items;var I=G.index;var F=E.filter(".t-state-selected");var J=F.length;var H=I!=-1&&I0?F[J-1]:null;if(H){G.select(H)}else{G.selectedIndex=-1;if(G.highlightFirst){G.highlight(E[0])}}G._oldIndex=G.selectedIndex}var x=this.loader;var v=this.dropDown;var y=this.minChars;var B=this.text();var C=B.length;if(!v.$items&&!x.ajaxError){if((x.isAjax()||this.onDataBinding)&&C>=y){z=z||{};var A=a.extend({},z);if(w){B=""}A[this.queryString.text]=B;x.ajaxRequest(function(E){this.dataBind(E,true);D(this);b.trigger(this.element,"dataBound");this.trigger.change();if(u){u()}},{data:A})}else{this.dataBind(this.data,true);D(this);if(u){u()}}}};this.reload=function(){this.dropDown.$items=null;if(arguments.length){this.fill(arguments[0],arguments[1])}else{this.fill()}};this.select=function(x){var w=this.highlight(x);if(w!=-1){var v=this.filteredDataIndexes;this.selectedIndex=(v&&v.length)>0?v[w]:w;var u=this.data[this.selectedIndex];b.list.updateTextAndValue(this,u.Text,u.Value)}return w};this.text=function(){return this.$text.val.apply(this.$text,arguments)};this.value=function(){if(arguments.length){var v=arguments[0];var u=this.select(function(w){return v==(w.Value||w.Text)});if(u==-1){this.selectedIndex=u;this.$element.val(v);this.text(v)}this.previousValue=this.$element.val();this._oldIndex=this.selectedIndex}else{return this.$element.val()}};b.list.common.call(this);b.list.filters.call(this);b.list.initialize.call(this);a(document.documentElement).bind("mousedown",a.proxy(function(w){var u=this.dropDown.$element;var x=u&&u.parent().length>0;if(a.contains(this.$wrapper[0],w.target)||(x&&a.contains(u.parent()[0],w.target))){return}if(this._textChanged){this._textChanged=false;var v=c(this.data,this.$text.val(),this.ignoreCase);if(v){this.selectedIndex=v.index;this.text(v.dataItem.Text);this.$element.val(v.dataItem.Value||v.dataItem.Text)}else{this.selectedIndex=-1;this.$element.val(this.$text.val())}}this.trigger.change();this.trigger.close()},this));this.$text.bind({keydown:a.proxy(n,this),keypress:a.proxy(o,this),focus:a.proxy(function(w){if(this.openOnFocus){var x=this.trigger;var v=this.dropDown;if(!v.$items){this.fill(x.open)}else{x.open()}}var u=this.$text;clearTimeout(this.selectTextTimeout);this.selectTextTimeout=window.setTimeout(function(){b.list.selection(u[0],0,u.val().length)},130)},this),blur:a.proxy(function(){clearTimeout(this.selectTextTimeout)},this)});function s(v){var u=this.dropDown,w=this.trigger;this.loader.ajaxError=false;if(!u.isOpened()){if(!u.$items){this.fill(w.open,{},true)}else{w.open()}f[0].focus()}else{w.close()}}function q(u){clearTimeout(u.timeout);u.timeout=setTimeout(function(){u.filtering.filter(u)},u.delay)}function n(z){var C=this.trigger;var y=this.dropDown;var A=z.keyCode||z.which;this.lastKeyCode=A;if(z.altKey){if(A==38||A==40){var w=A==38?C.close:C.open;if(!y.$items){this.fill(w)}else{w()}}return}if(!z.shiftKey&&(A==38||A==40)){z.preventDefault();var B=a.proxy(function(){var E=y.$items,F=E.filter(".t-state-selected:first");var D=F.length==0||E.length==1||this.selectedIndex==-1?E.first():(A==38)?F.prev():(A==40)?F.next():[];if(D.length){var G=D[0];this.select(G);y.scrollTo(G);if(!y.isOpened()){C.change()}}},this);if(!y.$items){if(this.index!=-1||this.value()||this.selectedValue){B=null}this.fill(B);return}B();return}if(A==8||A==46||(z.ctrlKey&&A==88)){var v=this.$text;if(v.val()!=""){q(this)}setTimeout(a.proxy(function(){if(v.val()==""){this.selectedIndex=-1;this.$element.val("")}else{this.$element.val(this.$text.val())}},this),0);return}if(A==13){if(y.isOpened()){z.preventDefault();var u=y.$items.filter(".t-state-selected:first");if(u.length>0){this.select(u[0])}else{this.$element.val(this.$text.val())}C.change();C.close();b.list.moveToEnd(this.$text[0])}return}if(A==27||A==9){clearTimeout(this.timeout);var x;if(this.selectedIndex!==undefined&&this.selectedIndex>-1&&this.data[this.selectedIndex].Text===this.$text.val()){x={dataItem:this.data[this.selectedIndex],index:this.selectedIndex}}else{x=c(this.data,this.$text.val(),this.ignoreCase)}if(x){this.selectedIndex=x.index;this.text(x.dataItem.Text);this.$element.val(x.dataItem.Value||x.dataItem.Text)}else{this.selectedIndex=-1;this.$element.val(this.$text.val())}C.change();C.close();if(A==27){this.$text.blur()}return}q(this)}function o(u){this._textChanged=true;var v=u.keyCode||u.charCode;if(!u.shiftKey&&(v==0||a.inArray(v,b.list.keycodes)!=-1||u.ctrlKey)){return true}setTimeout(a.proxy(function(){this.$element.val(this.$text.val())},this),0)}if(r.cascadeTo){var h=a("#"+r.cascadeTo).attr("disabled","disabled");h.bind("load",function(){if(r.selectedValue||r.value()){r.$element.trigger("valueChange")}});r.$element.bind("valueChange",a.proxy(function(){var u=h.data("tComboBox");if(u){var w=[],v={};v[r.$element.attr("name")]=r.value();if(u.loader.isAjax()){if(r.placeholder){w[0]={Text:r.placeholder,Value:""}}u.dataBind(w)}u.select(0);u.disable();if((r.selectedValue||r.value())===""&&r.placeholder){u.$element.trigger("valueChange");return}u.reload(function(){var x=w[0]?1:0;if(u.data[x]){u.enable()}else{u.value("")}},v)}},r))}};function c(d,h,g){if(!h){return}if(d){for(var f=0,j=d.length;f0?1:-1)*v))%v):0)+(n?(j==b.cultureInfo.next?1:-1)*v:0))};var r=a.inArray(n||j,b.cultureInfo[p]);if(p.toLowerCase().indexOf("day")>-1){s=(r==0?7:r)-o.day();t(7,true)}else{s=r-o.month();t(12,false)}};var h=function(){var s=function(u){var t;switch(n){case"year":t=u==1?1:0;break;case"month":t=u==2?1:0;break;case"week":t=u==3?7:0;break;case"day":t=u==3?1:0;break}return t};var r=(j==b.cultureInfo.next?1:-1);o.year(o.year()+s(1)*r,o.month()+s(2)*r,o.date()+s(3)*r)};a.each(["today","tomorrow","yesterday","next","last"],function(r,s){if(j!==null){return}j=k(b.cultureInfo[s])});if(j!==null){l+=j.length;if(/[^\s\d]\s+[^\s\d]/i.test(q)){l++;a.each(["year","month","week","day"],function(r,s){if(n!==null){return}n=k(b.cultureInfo[s])});p=null;if(n===null){n=m()}if(n===null){return null}}else{switch(j){case b.cultureInfo.today:break;case b.cultureInfo.tomorrow:o.date(o.date()+1);break;case b.cultureInfo.yesterday:o.date(o.date()-1);break;default:o=null;break}return o}}else{j=m();if(j!=null){g();return o}else{return null}}if(p!==null){g()}else{h()}return o};function c(g,k,j,h){if(k){g=new Date(k)}if(j>g){g=new Date(j)}else{if(h')}b.fx._wrap(f).css("display","none");if(a.browser.msie&&a.browser.version<=6){a('').prependTo(f).height(f.height())}}return f},_getCalendar:function(){return f.data("tCalendar")},_reassignSharedCalendar:function(){var g=this._getCalendar();if(f.data("associatedDateView")!=this){f.stop(true,true);this.focusedValue=c(this.focusedValue,this.selectedValue,this.minValue,this.maxValue);g.minDate=this.minValue;g.maxDate=this.maxValue;g.selectedValue=this.selectedValue;g.goToView(0,this.focusedValue);g._footer(this.todayFormat);f.unbind("change").bind("change",a.proxy(function(h){var k=this.selectedValue;var j=new b.datetime(h.date);if(k!==null){j.hours(k.getHours()).minutes(k.getMinutes()).seconds(k.getSeconds()).milliseconds(k.getMilliseconds())}this.onChange(j.toDate())},this)).unbind("navigate").bind("navigate",a.proxy(function(h){var j=this.focusedValue;var k=g.viewedMonth;var l=g.currentView.index;j.setFullYear(k.year(),k.month(),j.getDate());b.calendar.focusDate(j,l,f,h.direction)},this)).data("associatedDateView",this);g.value(this.selectedValue);b.calendar.focusDate(this.focusedValue,g.currentView.index,f)}},open:function(k){if(this.isOpened()){return}this._reassignSharedCalendar();var j=this.isRtl;var g=this.$calendar;elementPosition=k.offset;elementPosition.top+=k.outerHeight;if(d){if(!document.body.scrollLeft&&!e){elementPosition.left-=window.pageXOffset}if(!document.body.scrollTop&&!e){elementPosition.top-=window.pageYOffset}}if(j){elementPosition.left-=(f.outerWidth()||f.parent().outerWidth())-k.outerWidth}b.fx._wrap(f).css(a.extend({position:"absolute",direction:j?"rtl":"",display:f.is(":visible")?"":"none"},elementPosition));var h=this._getCalendar();var l=h.currentView.index;if(!f.is(":visible")&&h.viewedMonth.value-this.focusedValue!=0){h.goToView(l,this.focusedValue).value(this.selectedValue)}b.calendar.focusDate(this.focusedValue,h.currentView.index,f);b.fx._wrap(g).css("zIndex",k.zIndex).show();b.fx.play(this.effects,g,{direction:"bottom"})},close:function(){if(this.isOpened()){b.fx.rewind(this.effects,this.$calendar,{direction:"bottom"},function(){if(f){b.fx._wrap(f).hide()}})}},isOpened:function(){return f&&f.data("associatedDateView")==this&&f.is(":visible")},value:function(j){if(j===undefined){return this.selectedValue}var h=j===null;var g=this._getCalendar();if(!h){j=j.value?new Date(j.value):j}g.value(j);this.selectedValue=j;if(h){j=new Date()}this.focusedValue=new Date(j);b.calendar.focusDate(j,g.currentView.index,f)},navigate:function(m){if(this.isOpened()&&a(".t-overlay",f).length>0){return}var n;var o=false;var g=this.$calendar;var j=this._getCalendar();var s=j.viewedMonth;var k=j.currentView;var t=k.index;var l=new b.datetime(this.focusedValue);var p=function(u,w,v){if(!a(u,g).hasClass("t-state-disabled")){if("navigateUp"==w){t+=1}n=v||false;j[w]();return true}else{return false}};var q=function(){var u=b.calendar.findTarget(l,t,g,false)[0];j.navigateDown(m,u,t);t=t==0?0:t-1;n=true};var r=function(u,x,w){var v=!w?-1:1;if(!p(u,x,w)){return false}if(t==0){l.addMonth(v)}else{l.addYear(v*(t==1?1:t==2?10:100))}return true};var h=b.datepicker.adjustDate;if(g.is(":visible")&&!m.shiftKey){o=true;switch(m.keyCode){case 37:if(m.ctrlKey){if(!r(".t-nav-prev","navigateToPast")){return}}else{h(t,l,-1,-1);if(k.navCheck(l,s,false)){if(!p(".t-nav-prev","navigateToPast")){return}}}break;case 38:if(m.ctrlKey){p(".t-nav-fast","navigateUp")}else{h(t,l,-7,-4);if(k.navCheck(l,s,false)){if(!p(".t-nav-prev","navigateToPast")){return}}}break;case 39:if(m.ctrlKey){if(!r(".t-nav-next","navigateToFuture",true)){return}}else{h(t,l,1,1);if(k.navCheck(l,s,true)){if(!p(".t-nav-next","navigateToFuture",true)){return}}}break;case 40:if(m.ctrlKey){q()}else{h(t,l,7,4);if(k.navCheck(l,s,true)){if(!p(".t-nav-next","navigateToFuture",true)){return}}}break;case 33:if(!r(".t-nav-prev","navigateToPast")){return}break;case 34:if(!r(".t-nav-next","navigateToFuture",true)){return}break;case 35:l=b.calendar.views[t].firstLastDay(l,false,j);break;case 36:l=b.calendar.views[t].firstLastDay(l,true,j);break;case 13:m.stopPropagation();if(t==0){this.onChange(this.focusedValue)}else{q()}break;default:o=false;break}}if(o){m.preventDefault();l=b.calendar.fitDateToRange(l,new b.datetime(this.minValue),new b.datetime(this.maxValue));b.calendar.focusDate(l.toDate(),t,g,n);this.focusedValue=l.toDate()}}};a.each(["min","max"],a.proxy(function(g,h){b.dateView.prototype[h]=function(k){var j=h+"Value";if(k===undefined){return this[j]}this[j]=new Date(k.value?k.value:k);if(f.data("associatedDateView")===this){f.data("associatedDateView",null);this._reassignSharedCalendar()}}},this));b.datepicker=function(k,l){a.extend(this,l);if(k.nodeName.toLowerCase()!=="input"&&k.type.toLowerCase()!=="text"){throw"Target element is not a INPUT"}this.element=k;var g=this.$element=a(k).addClass("t-input").attr("autocomplete","off").bind({keydown:a.proxy(this._keydown,this),focus:a.proxy(function(o){if(this.openOnFocus){this._open()}this.$element.removeClass("t-state-error")},this),blur:a.proxy(function(o){this._bluring=setTimeout(a.proxy(function(){if(g.val()&&this.parse(g.val())===null){this.$element.addClass("t-state-error")}if(!this.dateView.isOpened()&&this.dateView===this.dateView.$calendar.data("associatedDateView")){this._update(g.val())}},this),100)},this)});if(!g.parent().hasClass("t-picker-wrap")){g.wrap('
            ');if(l.showButton){var h=new b.stringBuilder(),m=l.buttonTitle;a(h.cat('').cat('').string()).insertAfter(g)}}this.dateView=new b.dateView({todayFormat:this.todayFormat,selectedValue:this.selectedValue,minValue:this.minValue,maxValue:this.maxValue,effects:this.effects,isRtl:g.closest(".t-rtl").length,onChange:a.proxy(function(o){this._update(o);this._close()},this)});this.dateView.$calendar.bind("mousedown",function(o){o.preventDefault()}).bind("click",a.proxy(function(o){o.stopPropagation();clearTimeout(this._bluring);if(this.dateView!==this.dateView.$calendar.data("associatedDateView")){return}if(o.target.parentNode.className.indexOf("t-state-selected")!=-1){this._close()}},this));this.inputValue=g.val();var n=this.selectedValue||this.inputValue;if(n){this._value(this.parse(n))}var j=this.enabled?a.proxy(this._togglePopup,this):b.preventDefault;this.$wrapper=g.closest(".t-datepicker").find(".t-icon").bind("click",j).end();a(document.documentElement).bind("mousedown",a.proxy(function(p){var q=this.$element.val();if(q!=this.inputValue){this._update(q)}if(!f){return}var o=f.data("associatedDateView");if(!o||o!=this.dateView){return}if(!a.contains(this.$wrapper[0],p.target)&&!a.contains(f[0],p.target)){this._close()}},this));b.bind(this,{open:this.onOpen,close:this.onClose,valueChange:this.onChange,load:this.onLoad})};b.datepicker.prototype={_togglePopup:function(){if(this.dateView.isOpened()){this._close()}else{this.element.focus();this._open()}},_close:function(){if(!f.is(":animated")&&this.dateView.isOpened()){this._trigger("close")}},_open:function(){if(!this.dateView.isOpened()){this._trigger("open")}},_trigger:function(g){if(!b.trigger(this.element,g)){this[g]()}},_update:function(l){l=this.parse(l);if(l!=null){if(l-this.minValue<=0){l=this.minValue}else{if(l-this.maxValue>=0){l=this.maxValue}}}var k=this.selectedValue,h=k?b.datetime.format(k,this.format):"",j=l?b.datetime.format(l,this.format):"";this._value(l);if(j!=h){var g={previousValue:k,value:l,previousDate:k,date:l};if(b.trigger(this.element,"valueChange",g)){this._value(k)}}},_keydown:function(g){var h=g.keyCode;if(h==9||(h==13&&this.inputValue!=this.$element.val())){this._update(this.$element.val());this._close()}else{if(h==27){this._close()}else{if(g.altKey){if(h==40){this._open()}else{if(h==38){this._close()}}}else{this.dateView.navigate(g)}}}},enable:function(){this.$element.attr("disabled",false);this.$wrapper.removeClass("t-state-disabled").find(".t-icon").unbind("click").bind("click",a.proxy(this._togglePopup,this))},disable:function(g){this.$element.attr("disabled",true);this.$wrapper.addClass("t-state-disabled").find(".t-icon").unbind("click").bind("click",b.preventDefault)},_value:function(j){var h=this.$element.val();var g=j===null;this.selectedValue=j;this.dateView.value(j);if(!g){h=b.datetime.format(j,this.format)}this.inputValue=h;this.$element.toggleClass("t-state-error",g&&h!="").val(h)},value:function(h){if(h===undefined){return this.selectedValue}var g=this.parse(h);g=b.datepicker.isInRange(g,this.minValue,this.maxValue)?g:null;if(g===null){this.$element.removeClass("t-state-error").val("")}this._value(g);return this},showPopup:function(){this.open()},hidePopup:function(){this.close()},open:function(){var g=this.$element;this.dateView.open({offset:g.offset(),outerHeight:g.outerHeight(),outerWidth:g.outerWidth(),zIndex:b.getElementZIndex(g[0])})},close:function(){this.dateView.close()},parse:function(j,g){if(j===null||j.getDate){return j}var h=b.datetime.parse({value:j,format:g||this.format,shortYearCutOff:this.shortYearCutOff});return h!=null?h.toDate():null}};a.each(["min","max"],a.proxy(function(g,h){b.datepicker.prototype[h]=function(m){var l=h+"Value";if(m===undefined){return this[l]}var k=this.parse(m);if(k!==null){var j=this[l];this[l]=k;if(this.minValue>this.maxValue){this[l]=j;return}this.dateView[h](k)}}},this));a.extend(b.datepicker,{adjustDate:function(k,g,h,j){if(k==0){b.datetime.modify(g,b.datetime.msPerDay*h)}else{if(k==1){g.addMonth(j)}else{g.addYear((k==2?j:10*j))}}},isInRange:function(g,j,h){if(!g){return false}return j-g<=0&&h-g>=0}});a.fn.tDatePicker=function(g){return b.create(this,{name:"tDatePicker",init:function(h,j){return new b.datepicker(h,j)},options:g})};a.fn.tDatePicker.defaults={effects:b.fx.slide.defaults(),selectedValue:null,format:b.cultureInfo.shortDate,minValue:new Date(1899,11,31),maxValue:new Date(2100,0,1),shortYearCutOff:30,showButton:true,buttonTitle:"Open the calendar",enabled:true,openOnFocus:false}})(jQuery);(function(a){var b=a.telerik;b.scripts.push("telerik.timepicker.js");b.timeView=function(d){a.extend(this,d);var c=this.dropDown=new b.dropDown({attr:this.dropDownAttr,effects:this.effects,onClick:function(f){var g=f.item;d.onChange(g.innerText||g.textContent)}});c.$element.addClass("t-time-popup").css("direction",this.isRtl?"rtl":"")};b.timeView.prototype={_ensureItems:function(){if(!this.dropDown.$items){if(this.dates){this.dataBind(this.dates)}else{this.bind()}}},open:function(c){this._ensureItems();this.dropDown.open(c)},close:function(){this.dropDown.close()},dataBind:function(d){if(!d){return}var m=this.minValue;var l=this.maxValue;var c=[];var f=this.format;var g=b.datetime.format;var j=b.timeView.isInRange;var e;for(var h=0,k=d.length;hj?j+h:j;f=g>f?f+h:f;return g-f==0||j>=g&&j<=f},getTimeMilliseconds:function(c){c=c.value?c:new b.datetime(c);return((c.hours()*60)+c.minutes())*b.datetime.msPerMinute+c.seconds()*1000+c.milliseconds()}});b.timepicker=function(f,g){a.extend(this,g);if(f.nodeName.toLowerCase()!=="input"&&f.type.toLowerCase()!=="text"){throw"Target element is not a INPUT"}this.element=f;var c=this.$element=a(f).addClass("t-input").attr("autocomplete","off").bind({keydown:a.proxy(this._keydown,this),focus:a.proxy(function(k){if(this.openOnFocus){this._open()}this.$element.removeClass("t-state-error")},this),blur:a.proxy(function(k){this._bluring=setTimeout(a.proxy(function(){if(c.val()&&this.parse(c.val())===null){this.$element.addClass("t-state-error")}this._update(c.val())},this),100)},this)});if(!c.parent().hasClass("t-picker-wrap")){c.wrap('
            ');if(g.showButton){var d=new b.stringBuilder(),h=g.buttonTitle;a(d.cat('').cat('').string()).insertAfter(c)}}this.timeView=new b.timeView({dates:this.dates,effects:this.effects,dropDownAttr:this.dropDownAttr,format:this.format,interval:this.interval,isRtl:c.closest(".t-rtl").length,minValue:this.minValue,maxValue:this.maxValue,onNavigateWithOpenPopup:a.proxy(function(k){this.$element.val(k)},this),onChange:a.proxy(function(k){clearTimeout(this._bluring);if(k!=this.inputValue){this._update(k)}this._close();window.setTimeout(function(){c.focus()},1)},this)});this.inputValue=c.val();var j=this.selectedValue||this.inputValue;if(j){this._value(this.parse(j))}var e=this.enabled?a.proxy(this._togglePopup,this):b.preventDefault;this.$wrapper=c.closest(".t-timepicker").find(".t-icon").bind("click",e).end();a(document.documentElement).bind("mousedown",a.proxy(function(l){var n=this.$element.val();if(n!=this.inputValue){this._update(n)}var k=this.timeView.dropDown.$element;var m=k&&k.parent().length>0;if(!m||a.contains(this.$wrapper[0],l.target)||a.contains(k.parent()[0],l.target)){return}this._close()},this));b.bind(this,{open:this.onOpen,close:this.onClose,valueChange:this.onChange,load:this.onLoad})};b.timepicker.prototype={_close:function(){var c=this.timeView.dropDown;if(!c.$element.is(":animated")&&c.isOpened()){this._trigger("close")}},_open:function(){if(!this.timeView.isOpened()){this._trigger("open")}},_trigger:function(c){if(!b.trigger(this.element,c)){this[c]()}},_togglePopup:function(){if(this.timeView.isOpened()){this._close()}else{this.element.focus();this._open()}},_update:function(m){var j=this.minValue,g=this.maxValue,m=this.parse(m),l=this.selectedValue;if(m!=null&&!b.timeView.isInRange(m,j,g)){var e=b.timeView.getTimeMilliseconds,k=e(m),h=Math.abs(e(j)-k),f=Math.abs(e(g)-k);m=new Date(h').string()}b.datetimepicker=function(e,f){a.extend(this,f);if(e.nodeName.toLowerCase()!=="input"&&e.type.toLowerCase()!=="text"){throw"Target element is not a INPUT"}this.element=e;var d=this.$element=a(e).addClass("t-input").attr("autocomplete","off").bind({keydown:a.proxy(this._keydown,this),focus:a.proxy(function(j){this.$element.removeClass("t-state-error")},this),blur:a.proxy(function(j){this._bluring=setTimeout(a.proxy(function(){if(d.val()&&this.parse(d.val())===null){this.$element.addClass("t-state-error")}if(!this.dateView.isOpened()&&this.dateView===this.dateView.$calendar.data("associatedDateView")){this._update(d.val())}},this),100)},this)});if(!d.parent().hasClass("t-picker-wrap")){d.wrap('
            ');if(f.showCalendarButton||f.showTimeButton){a(new b.stringBuilder().cat('').catIf(c("calendar",f.calendarButtonTitle),f.showCalendarButton).cat(c("clock",f.timeButtonTitle),f.showTimeButton).cat("").string()).insertAfter(d)}}this.$wrapper=d.closest(".t-datetimepicker").find(".t-icon-clock").bind("click",this.enabled?a.proxy(this._toggleTimeView,this):b.preventDefault).end().find(".t-icon-calendar").bind("click",this.enabled?a.proxy(this._toggleDateView,this):b.preventDefault).end();this.timeView=new b.timeView({dates:this.dates,effects:this.effects,dropDownAttr:this.dropDownAttr,format:this.timeFormat,interval:this.interval,isRtl:d.closest(".t-rtl").length,minValue:this.startTimeValue,maxValue:this.endTimeValue,onNavigateWithOpenPopup:a.proxy(function(k){var j=this.parse(k,this.timeFormat);this.$element.val(b.datetime.format(j,this.format))},this),onChange:a.proxy(function(j){clearTimeout(this._bluring);this._update(this.parse(j,this.timeFormat));this._close("time");window.setTimeout(function(){d.focus()},1)},this)});this.dateView=new b.dateView({todayFormat:this.todayFormat,selectedValue:this.selectedValue,minValue:this.minValue,maxValue:this.maxValue,effects:this.effects,isRtl:d.closest(".t-rtl").length,onChange:a.proxy(function(j){this._update(j);this._close("date")},this)});this.dateView.$calendar.bind("click",a.proxy(function(j){j.stopPropagation();clearTimeout(this._bluring);if(this.dateView!==this.dateView.$calendar.data("associatedDateView")){return}if(j.target.parentNode.className.indexOf("t-state-selected")!=-1){this._close("date")}window.setTimeout(function(){d.focus()},1)},this));this.inputValue=d.val();var h=this.selectedValue||this.inputValue;if(h){var g=this.parse(h);this.dateView.selectedValue=g;this._value(this.parse(h))}a(document.documentElement).bind("mousedown",a.proxy(function(m){var p=this.$element.val();if(p!=this.inputValue){this._update(p)}var j=this.dateView.$calendar;if(!j){return}var k=this.timeView.dropDown.$element;var n=k&&k.parent().length>0;var l=j.data("associatedDateView");var o=m.target;if(a.contains(this.$wrapper[0],o)||(l&&l==this.dateView&&a.contains(j[0],o))||(n&&a.contains(k.parent()[0],o))){return}this._close("date");this._close("time")},this));b.bind(this,{open:this.onOpen,close:this.onClose,valueChange:this.onChange,load:this.onLoad})};b.datetimepicker.prototype={_update:function(h){h=this.parse(h);if(h!=null){if(h-this.minValue<=0){h=this.minValue}else{if(h-this.maxValue>=0){h=this.maxValue}}}var g=this.selectedValue,e=g?b.datetime.format(g,this.format):"",f=h?b.datetime.format(h,this.format):"";this._value(h);if(f!=e){var d={previousValue:g,value:h};if(b.trigger(this.element,"valueChange",d)){this._value(g)}}},_value:function(f){var e=this.$element.val();var d=f===null;this.selectedValue=f;this.timeView.value(d?null:b.datetime.format(f,this.timeFormat));this.dateView.value(f);if(!d){e=b.datetime.format(f,this.format)}this.inputValue=e;this.$element.toggleClass("t-state-error",d&&e!="").val(e)},_open:function(d){if(!this[d=="time"?"timeView":"dateView"].isOpened()){this._trigger(d,"open")}},_close:function(f){var d=this.dateView;var e=this.timeView.dropDown;if((f=="time"&&!e.$element.is(":animated")&&e.isOpened())||(!d.$calendar.is(":animated")&&d.isOpened())){this._trigger(f,"close")}},_trigger:function(e,d){if(!b.trigger(this.element,d,{popup:e})){this[d](e)}},_keydown:function(d){var g=d.keyCode,f=this.dateView.isOpened();if(g==9||g==27||(g==13&&this.inputValue!=this.$element.val())){this._update(this.$element.val());this._close("date");this._close("time");return}if(d.altKey){if(g==40){this._close(f?"date":"time");this._open(f?"time":"date")}else{if(g==38){this._close(f?"date":"time")}}return}if(f){this.dateView.navigate(d);return}if(this.timeView.isOpened()&&(g===38||g===40)){this.timeView.navigate(d);return}},_toggleDateView:function(){if(this.dateView.isOpened()){this._close("date")}else{this.element.focus();this._open("date");this._close("time")}},_toggleTimeView:function(){if(this.timeView.isOpened()){this._close("time")}else{this.element.focus();this._open("time");this._close("date")}},enable:function(){this.$element.attr("disabled",false);this.$wrapper.removeClass("t-state-disabled").find(".t-icon-clock").unbind("click").bind("click",a.proxy(this._toggleTimeView,this)).end().find(".t-icon-calendar").unbind("click").bind("click",a.proxy(this._toggleDateView,this))},disable:function(d){this.$element.attr("disabled",true);this.$wrapper.addClass("t-state-disabled").find(".t-icon").unbind("click").bind("click",b.preventDefault)},open:function(e){var d=this.$element;var f={offset:d.offset(),outerHeight:d.outerHeight(),outerWidth:d.outerWidth(),zIndex:b.getElementZIndex(d[0])};this[e=="time"?"timeView":"dateView"].open(f)},close:function(d){this[d=="time"?"timeView":"dateView"].close()},value:function(e){if(e===undefined){return this.selectedValue}var d=this.parse(e);d=b.datepicker.isInRange(d,this.minValue,this.maxValue)?d:null;if(d===null){this.$element.removeClass("t-state-error").val("")}this._value(d);return this},parse:function(f,d){if(f===null||f.getDate){return f}d=d||this.format;var e=b.datetime.parse({AM:b.cultureInfo.am,PM:b.cultureInfo.pm,value:f,format:d,baseDate:this.selectedValue?new b.datetime(this.selectedValue):new b.datetime()});return e!=null?e.toDate():null}};a.each(["min","max"],a.proxy(function(d,e){b.datetimepicker.prototype[e]=function(j){var h=e+"Value";if(j===undefined){return this[h]}var g=this.parse(j);if(g!==null){var f=this[h];this[h]=g;if(this.minValue>this.maxValue){this[h]=f;return}this.dateView[e](g)}}},this));a.each(["startTime","endTime"],a.proxy(function(d,e){b.datetimepicker.prototype[e]=function(h){var g=e+"Value";if(h===undefined){return this[g]}var f=this.parse(h,b.cultureInfo.shortTime);if(f!==null){this[g]=f;e=="startTime"?this.timeView.min(f):this.timeView.max(f)}}},this));a.fn.tDateTimePicker=function(d){a.fn.tDateTimePicker.defaults.timeFormat=b.cultureInfo.shortTime;return b.create(this,{name:"tDateTimePicker",init:function(e,f){return new b.datetimepicker(e,f)},options:d})};a.fn.tDateTimePicker.defaults={effects:b.fx.slide.defaults(),selectedValue:null,format:b.cultureInfo.generalDateTime,focusedDate:new b.datetime(),minValue:new Date(1899,11,31),maxValue:new Date(2100,0,1),startTimeValue:new b.datetime().hours(0).minutes(0).seconds(0).toDate(),endTimeValue:new b.datetime().hours(0).minutes(0).seconds(0).toDate(),calendarButtonTitle:"Open the calendar",timeButtonTitle:"Open the time view",showCalendarButton:true,showTimeButton:true,shortYearCutOff:30,enabled:true,interval:30}})(jQuery);(function(a){var b=a.telerik,n=function(){},e={},g={},c={},j={owner:[null]},m=b.isTouch?"touchend":"mouseup",k=b.isTouch?"touchstart":"mousedown",l=b.isTouch?"touchmove":"mousemove",f={scope:"default",drop:n,over:n,out:n,owner:document.body},d={distance:5,cursorAt:{left:10,top:b.isTouch?-40/b.zoomLevel():10},scope:"default",start:n,drag:n,stop:n,destroy:n,owner:document.body,cue:function(){return a("")}};b.scripts.push("telerik.draganddrop.js");function o(q){var r=0,p;for(p in q){q.hasOwnProperty(p)&&r++}return r}function h(p,r){var q={owner:[null]};a.each(r,function(){var t=this,s=t.owner;if(s&&a.contains(s,p)){q=a.extend(q,t);q.selector&&(q.owner=a(p).closest(q.selector)[0]);return false}});return q}b.droppable=function(p){a.extend(this,f,p);a(this.owner).delegate(this.selector,"mouseenter",a.proxy(this._over,this)).delegate(this.selector,m,a.proxy(this._drop,this)).delegate(this.selector,"mouseleave",a.proxy(this._out,this));if(!(this.scope in g)){g[this.scope]=[this]}else{g[this.scope].push(this)}};b.droppable.prototype={_over:function(p){this._raise(p,this.over)},_out:function(p){this._raise(p,this.out)},_drop:function(p){this._raise(p,a.proxy(function(q){this.drop(q);q.destroy(q)},this))},_raise:function(r,p){var q=e[this.scope],s=a(b.eventCurrentTarget(r)).closest(this.selector);if(q){p(a.extend(r,q,{$droppable:s}))}}};b.dragCue=function(p){return a('
            ').html(p).prepend('').appendTo(document.body)};b.dragCueStatus=function(p,q){p.find(".t-drag-status").attr("class","t-icon t-drag-status").addClass(q)};b.draggable=function(p){a.extend(this,d,p);a(this.owner).delegate(this.selector,k,a.proxy(this._wait,this)).delegate(this.selector,"dragstart",b.preventDefault);this._startProxy=a.proxy(this._start,this);this._destroyProxy=a.proxy(this._destroy,this);this._stopProxy=a.proxy(this._stop,this);this._dragProxy=a.proxy(this._drag,this)};b.draggable.get=function(p){return e[p]};b.draggable.prototype={_raise:function(r,p){var q=e[this.scope];if(q){return p(a.extend(r,q))}},_startDrag:function(r,q){r=a(r);this.$target=r;if(q){this._startPosition=q}else{var p=r.offset();this._startPosition={x:p.left,y:p.top}}a(document).bind(l+"."+this.scope,this._startProxy).bind(m+"."+this.scope,this._destroyProxy)},_wait:function(p){if(b.isTouch){p.stopImmediatePropagation()}this._startDrag(p.currentTarget,b.touchLocation(p));a(document.documentElement).trigger(k,p);if(!b.isTouch){return false}},_start:function(r){var s=b.touchLocation(r),t=this._startPosition.x-s.x,u=this._startPosition.y-s.y;var q=Math.sqrt((t*t)+(u*u));if(q>=this.distance){if(b.isTouch){r.stopImmediatePropagation();r.preventDefault()}var p=c[this.selector];if(!p){p=c[this.selector]=this.cue({$draggable:this.$target})}a(document).unbind("."+this.scope).bind(l+"."+this.scope,this._dragProxy).bind(m+"."+this.scope,this._stopProxy).bind("keydown."+this.scope,this._stopProxy).bind("selectstart."+this.scope,false);e[this.scope]={$cue:p.css({position:"absolute",left:s.x+this.cursorAt.left,top:s.y+this.cursorAt.top}),$draggable:this.$target,destroy:this._destroyProxy};if(this._raise(r,this.start)===false){this._destroy(r)}}},_drag:function(s){if(b.isTouch){s.stopImmediatePropagation()}var v=b.touchLocation(s);if(b.isTouch&&o(g)){var r=b.eventTarget(s);if(r){var q=g[this.scope],w=h(r,q),t=w.owner,u=j.owner,p=u!=t;if(p){if(u!=null&&"_out" in j){j._out(s)}if(t&&a.contains(t,r)&&"_over" in w){w._over(s)}j=w}}}this._raise(s,this.drag);e[this.scope].$cue.css({left:v.x+this.cursorAt.left,top:v.y+this.cursorAt.top})},_stop:function(s){if(b.isTouch){s.stopImmediatePropagation()}if(s.type==m||s.keyCode==27){a(document).unbind("."+this.scope)}if(b.isTouch&&o(g)){var r=b.eventTarget(s);if(r){var q=g[this.scope],t=h(r,q);if(t.owner&&"_drop" in t){j={owner:[null]};t._drop(s)}}}if(this._raise(s,this.stop)===false){this._destroy(s)}else{var p=e[this.scope];if(p){p.$cue.animate(p.$draggable.offset(),"fast",this._destroyProxy)}}},_destroy:function(p){a(document).unbind("."+this.scope);this._raise(p,this.destroy);e[this.scope]=null;c[this.selector]=null}}})(jQuery);(function(a,e){var b=a.telerik;b.scripts.push("telerik.window.js");function d(f){return f&&!(/^([a-z]+:)?\/\//i).test(f)}function c(f){if(a.browser.msie&&a.browser.version<7){f.find(".t-resize-e,.t-resize-w").css("height",f.height()).end().find(".t-resize-n,.t-resize-s").css("width",f.width()).end().find(".t-overlay").css({width:f.width(),height:f.height()})}}b.fx.zoom=function(f){this.element=f};b.fx.zoom.prototype={play:function(j,g){var f=this.element.show();var k=f.find("> .t-window-content");var h={width:k.width(),height:k.height(),left:parseInt(f.css("left"))||0,top:parseInt(f.css("top"))||0};f.css({left:h.left+20,top:h.top+20}).animate({left:h.left,top:h.top},j.openDuration);k.css({width:h.width-40,height:h.height-40}).animate({width:h.width,height:h.height},j.openDuration,function(){if(g){g()}})},rewind:function(j,g){var f=this.element;var k=f.find("> .t-window-content");var h={width:k.width(),height:k.height(),left:parseInt(f.css("left")),top:parseInt(f.css("top"))};k.animate({width:h.width-40,height:h.height-40},j.closeDuration);f.animate({left:h.left+20,top:h.top+20},j.closeDuration,function(){f.css({left:h.left,top:h.top}).hide();setTimeout(function(){k.css({width:h.width,height:h.height})},0);if(g){g()}})}};b.fx.zoom.defaults=function(){return{list:[{name:"zoom"}],openDuration:"fast",closeDuration:"fast"}};b.window=function(g,l){this.element=g;var f=a(g),j=a.extend({},l);delete j.title;delete j.content;a.extend(this,j);if(!f.is(".t-window")){f.addClass("t-widget t-window");b.window.create(g,l)}if(!f.is("body")){var k;if(f.is(":visible")){k=f.offset();f.css({top:k.top,left:k.left})}else{f.css({visibility:"hidden",display:""});k=f.offset();f.css({top:k.top,left:k.left}).css({visibility:"visible",display:"none"})}var h=f.find("iframe").map(function(n){var o=this.getAttribute("src");this.src="";return o});f.toggleClass("t-rtl",f.closest(".t-rtl").length>0).appendTo(document.body).find("iframe").each(function(n){this.src=h[n]})}this.bringToTop();f.find(".t-window-titlebar").andSelf().bind("mousedown",a.proxy(this.bringToTop,this));if(this.modal&&f.is(":visible")){this.overlay(true).css({opacity:0.5,zIndex:parseInt(f.css("zIndex"),10)-1})}var m=".t-window-titlebar .t-link";f.delegate(m,"mouseenter",b.hover).delegate(m,"mouseleave",b.leave).delegate(m,"click",a.proxy(this.windowActionHandler,this));if(this.resizable){f.delegate(".t-window-titlebar","dblclick",a.proxy(this.toggleMaximization,this)).append(b.window.getResizeHandlesHtml());c(f);(function(q){function o(s){var r=a(q.element);q.initialCursorPosition=r.offset();q.resizeDirection=/t-resize-([nesw]+)/gi.exec(s.$draggable[0].className)[1];q.resizeElement=r.find("> .t-window-content");q.initialSize={width:q.resizeElement.width(),height:q.resizeElement.height()};q.outlineSize={left:q.resizeElement.outerWidth()-q.resizeElement.width()+r.outerWidth()-r.width(),top:q.resizeElement.outerHeight()-q.resizeElement.height()+r.outerHeight()-r.height()+r.find("> .t-window-titlebar").outerHeight()};a('
            ').appendTo(q.element);r.find(".t-resize-handle").not(s.$draggable).hide();a(document.body).css("cursor",s.$draggable.css("cursor"))}function n(s){var r=a(q.element);var t={e:function(){var u=b.touchLocation(s),v=u.x-q.initialCursorPosition.left-q.outlineSize.left;q.resizeElement.width((vq.maxWidth)?q.maxWidth:v))},s:function(){var v=b.touchLocation(s),u=v.y-q.initialCursorPosition.top-q.outlineSize.top;q.resizeElement.height((uq.maxHeight)?q.maxHeight:u))},w:function(){var u=b.touchLocation(s),w=q.initialCursorPosition.left+q.initialSize.width;r.css("left",u.x>(w-q.minWidth)?w-q.minWidth:u.x<(w-q.maxWidth)?w-q.maxWidth:u.x);var v=w-u.x;q.resizeElement.width((vq.maxWidth)?q.maxWidth:v))},n:function(){var v=b.touchLocation(s),w=q.initialCursorPosition.top+q.initialSize.height;r.css("top",v.y>(w-q.minHeight)?w-q.minHeight:v.y<(w-q.maxHeight)?w-q.maxHeight:v.y);var u=w-v.y;q.resizeElement.height((uq.maxHeight)?q.maxHeight:u))}};a.each(q.resizeDirection.split(""),function(){t[this]()});c(r);if(a.browser.msie&&parseInt(a.browser.version)>=9){r[0].style.cssText=r[0].style.cssText}b.trigger(q.element,"resize")}function p(s){var r=a(q.element);r.find(".t-overlay").remove().end().find(".t-resize-handle").not(s.$draggable).show();a(document.body).css("cursor","");if(s.keyCode==27){c(r);r.css(q.initialCursorPosition);q.resizeElement.css(q.initialSize)}return false}new b.draggable({owner:q.element,selector:".t-resize-handle",scope:q.element.id+"-resizing",distance:0,start:o,drag:n,stop:p})})(this)}if(this.draggable){(function(q){function o(t){var r=a(q.element),u=b.touchLocation(t);q.initialWindowPosition=r.position();b.trigger(g,"dragStart");q.startPosition={left:u.x-q.initialWindowPosition.left,top:u.y-q.initialWindowPosition.top};var s=r.find(".t-window-actions");if(s.length>0){if(q.isRtl==e){q.isRtl=a(q.element).closest(".t-rtl").length>0}q.minLeftPosition=s.outerWidth()+parseInt(s.css(q.isRtl?"left":"right"),10)-r.outerWidth()}else{q.minLeftPosition=20-r.outerWidth()}a(".t-resize-handle",q.element).hide();a('
            ').appendTo(q.element);a(document.body).css("cursor",t.$draggable.css("cursor"))}function n(s){var t=b.touchLocation(s),r={left:Math.max(t.x-q.startPosition.left,q.minLeftPosition),top:Math.max(t.y-q.startPosition.top,0)};a(q.element).css(r)}function p(r){a(q.element).find(".t-resize-handle").show().end().find(".t-overlay").remove();a(document.body).css("cursor","");if(r.keyCode==27){r.$draggable.closest(".t-window").css(q.initialWindowPosition)}b.trigger(g,"dragEnd");return false}new b.draggable({owner:q.element,selector:".t-window-titlebar",scope:q.element.id+"-moving",start:o,drag:n,stop:p})})(this)}b.bind(this,{open:this.onOpen,activated:this.onActivate,close:this.onClose,refresh:this.onRefresh,resize:this.onResize,error:this.onError,load:this.onLoad,dragStart:this.onDragStart,dragEnd:this.onDragEnd});a(window).resize(a.proxy(this.onDocumentResize,this));if(d(this.contentUrl)){this.ajaxRequest()}};b.window.prototype={overlay:function(h){var g=a("body > .t-overlay"),f=this.element;if(g.length==0){g=a('
            ').toggle(h).insertBefore(f)}else{g.insertBefore(f).toggle(h)}this.positionOverlay(g);return g},positionOverlay:function(g){var f=a(document);if(a.browser.msie&&a.browser.version<7){g.css({width:f.width()-21,height:f.height(),position:"absolute"})}else{if((/ipad/gi).test(navigator.appVersion)){g.css({width:f.width(),height:f.height(),position:"absolute"})}}},overlayOnClose:function(g){var f=this;var j=a(".t-window").filter(function(){var p=a(this);return this!==f.element&&p.is(":visible")&&p.data("tWindow").modal});var o=f.modal&&j.length==0;var m=f.modal?f.overlay(true):a(e);if(o){if(f.effects.list.length>0&&f.effects.list[0].name!="toggle"){m.fadeOut(f.effects.closeDuration,function(){if(g){m.remove()}})}else{if(g){m.remove()}else{m.hide()}}}else{if(j.length>0){var n=parseInt(a(".t-overlay").css("zIndex"),10);var h=0;var l;j.each(function(q,p){var r=parseInt(a(p).css("zIndex"),10);if(r>=h){h=r;l=a(p)}});var k=l.data("tWindow");k.overlay(true).css("zIndex",h-1)}}},windowActionHandler:function(h){var f=a(h.target).closest(".t-link").find(".t-icon"),g=this;a.each({"t-close":this.close,"t-maximize":this.maximize,"t-restore":this.restore,"t-refresh":this.refresh},function(j,k){if(f.hasClass(j)){h.preventDefault();k.call(g);return false}})},center:function(){var f=a(this.element),g=a(window);f.css({left:g.scrollLeft()+Math.max(0,(g.width()-f.width())/2),top:g.scrollTop()+Math.max(0,(g.height()-f.height())/2)});return this},title:function(g){var f=a(".t-window-titlebar > .t-window-title",this.element);if(!g){return f.text()}f.text(g);return this},content:function(g){var f=a("> .t-window-content",this.element);if(!g){return f.html()}f.html(g);return this},bringToTop:function(){var j=0,h=this,g=h.element,f=a(".t-window");if(f.filter(":visible").length==1&&a(g).is(":visible")){return}f.each(function(){var k=a(this);var l=k.css("zIndex");if(!isNaN(l)){j=Math.max(parseInt(l,10),j)}if(this!=g&&k.find(".t-window-content > iframe").length>0){k.find(".t-window-content").append("
            ")}});a(g).css("zIndex",j+2).find(".t-window-content > .t-overlay").remove();return h},open:function(g){var f=a(this.element);this.bringToTop();if(!b.trigger(this.element,"open")){if(this.modal){var h=this.overlay(false).css("zIndex",parseInt(f.css("zIndex"),10)-1);if(this.effects.list.length>0&&this.effects.list[0].name!="toggle"){h.css("opacity",0).show().animate({opacity:0.5},this.effects.openDuration)}else{h.css("opacity",0.5).show()}}if(!f.is(":visible")){b.fx.play(this.effects,f,{},function(){b.trigger(f[0],"activated")})}}if(this.isMaximized){this._documentScrollTop=a(document).scrollTop();a("html, body").css("overflow","hidden")}return this},close:function(){var f=a(this.element);if(f.is(":visible")){if(!b.trigger(this.element,"close")){this.overlayOnClose();b.fx.rewind(this.effects,f,null,function(){f.hide()})}}if(this.isMaximized){a("html, body").css("overflow","");if(this._documentScrollTop&&this._documentScrollTop>0){a(document).scrollTop(this._documentScrollTop)}}return this},toggleMaximization:function(f){if(f&&a(f.target).closest(".t-link").length>0){return}this[this.isMaximized?"restore":"maximize"]()},restore:function(){if(!this.isMaximized){return}a(this.element).css({position:"absolute",left:this.restorationSettings.left,top:this.restorationSettings.top}).find("> .t-window-content").css({width:this.restorationSettings.width,height:this.restorationSettings.height}).end().find(".t-resize-handle").show().end().find(".t-window-titlebar .t-restore").addClass("t-maximize").removeClass("t-restore");a("html, body").css("overflow","");if(this._documentScrollTop&&this._documentScrollTop>0){a(document).scrollTop(this._documentScrollTop)}this.isMaximized=false;b.trigger(this.element,"resize");return this},maximize:function(g){if(this.isMaximized){return}var f=a(this.element),h=f.find("> .t-window-content");this.restorationSettings={left:f.position().left,top:f.position().top,width:h.width(),height:h.height()};f.css({left:0,top:0,position:"fixed"}).find(".t-resize-handle").hide().end().find(".t-window-titlebar .t-maximize").addClass("t-restore").removeClass("t-maximize");this._documentScrollTop=a(document).scrollTop();a("html, body").css("overflow","hidden");this.isMaximized=true;this.onDocumentResize();return this},onDocumentResize:function(){if(!this.isMaximized){return}var f=a(this.element),g=f.find("> .t-window-content");g.css({width:a(window).width()-(g.outerWidth()-g.width()+f.outerWidth()-f.width()),height:a(window).height()-(g.outerHeight()-g.height()+f.outerHeight()-f.height()+f.find("> .t-window-titlebar").outerHeight())});c(f);b.trigger(f,"resize")},refresh:function(){if(d(this.contentUrl)){this.ajaxRequest()}else{var f=a(this.element).find("> .t-window-content > iframe")[0];if(f){f.src=f.src}}return this},ajaxRequest:function(h,f){var g=setTimeout(function(){a(".t-refresh",this.element).addClass("t-loading")},100);a.ajax({type:"GET",url:h||this.contentUrl,dataType:"html",data:f||{},cache:false,error:a.proxy(function(k,j){if(b.ajaxError(this.element,"error",k,j)){return}},this),complete:function(){clearTimeout(g);a(".t-refresh",this.element).removeClass("t-loading")},success:a.proxy(function(j,k){a(".t-window-content",this.element).html(j);b.trigger(this.element,"refresh")},this)})},destroy:function(){a(this.element).remove();this.overlayOnClose(true)}};a.extend(b.window,{create:function(){var g,h,f;if(a.isPlainObject(arguments[0])){h=arguments[0]}else{g=arguments[0];h=a.extend({html:g.innerHTML},arguments[1])}h=a.extend({title:"",html:"",actions:["Close"],visible:true},h);f=h.contentUrl;var j=new b.stringBuilder().catIf('
            ',!g).cat('
            ').cat(' ').cat(h.title).cat("").cat('
            ');a.map(h.actions,function(k){j.cat('').cat('').cat(k).cat("")});j.cat("
            ").cat('
            ').catIf(h.html,!f||(f&&d(f))).catIf('',f&&!d(f)).cat("
            ").catIf("
            ",!g);if(g){a(g).css("display",h.visible?"":"none").html(j.string())}else{delete h.title;return a(j.string()).css("display",h.visible?"":"none").appendTo(document.body).eq(0).tWindow(h)}},getResizeHandlesHtml:function(){var f=new b.stringBuilder();a.each("n e s w se sw ne nw".split(" "),function(g,h){f.cat('
            ')});return f.string()}});a.fn.tWindow=function(f){return b.create(this,{name:"tWindow",init:function(g,h){return new b.window(g,h)},success:function(h){var j=h.element,g=a(j);if(g.is(":visible")){b.trigger(j,"open");b.trigger(j,"activated")}},options:f})};a.fn.tWindow.defaults={effects:{list:[{name:"zoom"},{name:"property",properties:["opacity"]}],openDuration:"fast",closeDuration:"fast"},modal:false,resizable:true,draggable:true,minWidth:50,minHeight:50}})(jQuery);(function(a,p){var b=a.telerik,k=a.telerik.query;b.scripts.push("telerik.imagebrowser.js");b.imageBrowser=function(v,z){this.element=v;this.wrapper=a(v);var w=z.filter||"*.png,*.gif,*.jpg,*.jpeg";var y=z.localization;this.wrapper.append('
            select
            ').append(o(y,z.uploadUrl,z.createDirectoryUrl,z.deleteFileUrl||z.deleteDirectoryUrl)).append('
              ');var s=this.wrapper.find(".t-breadcrumbs");var x=this.wrapper.find(".t-tiles");var A=this.wrapper.find(".t-search-wrap");if(z.uploadUrl){this.wrapper.find(".t-upload input").tUpload({async:{saveUrl:z.uploadUrl,autoUpload:true},multiple:false,onUpload:function(B){var D=new RegExp(("("+w.split(",").join(")|(")+")").replace(/\*\./g,".*."),"i");var C=B.files[0].name;if(D.test(C)){B.data={path:s.val()};x.trigger("t:upload",[{name:C},function(){B.preventDefault()}])}else{B.preventDefault();alert(b.formatString(y.invalidFileType,C,w))}},onError:function(B){B.preventDefault();x.trigger("t:error",[B.files[0]]);var C=B.XMLHttpRequest;if(b.ajaxError(z.element,"error",C,C.statusText)){return}},onSuccess:function(B){x.trigger("t:completeFile",[a.extend(B.response,{path:s.val()})])}})}new b.searchBox(A[0]);new b.fileListView(x[0],{thumbnailUrl:z.thumbUrl,localization:y});var u=new b.dropDown({effects:b.fx.slide.defaults(),onClick:function(B){a(v).find(".t-tiles-arrange a span:first").html(a(B.item).text());u.close();s.trigger("t:change")}});var q=[{Text:y.orderByName,Value:"name"},{Text:y.orderBySize,Value:"size"}];u.dataBind(q);this.wrapper.find(".t-tiles-arrange a").click(function(C){C.preventDefault();var B=a(this);u.open({offset:B.offset(),outerHeight:B.outerHeight(),outerWidth:B.outerWidth(),zIndex:b.getElementZIndex(this)})}).end().delegate(".t-button:not(.t-state-disabled):has(.t-delete)","click",function(){var B=x.find(".t-state-selected");if(B.length&&confirm(b.formatString(y.deleteFile,B.find("strong").text()))){a.ajax({type:"POST",url:B.data("kind")=="f"?z.deleteFileUrl:z.deleteDirectoryUrl,data:{path:B.data("url")},error:function(D,C){if(b.ajaxError(z.element,"error",D,C)){return}},success:function(){x.trigger("t:delete");a(v).find(".t-delete").parent().addClass("t-state-disabled")}})}}).delegate(".t-button:not(.t-state-disabled):has(.t-addfolder)","click",function(){x.trigger("t:createDirectory",[function(B){a.ajax({type:"POST",url:z.createDirectoryUrl,data:{path:s.val(),name:B},error:function(D,C){x.trigger("t:errorDirectory",{name:B});if(b.ajaxError(z.element,"error",D,C)){return}},success:function(){x.trigger("t:completeDirectory",{path:s.val(),name:B})}})}])});a(document.documentElement).bind("mousedown",function(B){var C=u.$element[0];if(!a.contains(C,B.target)){u.close()}});var t=new b.dataSource({error:function(D,C){var B=b.trigger(z.element,"error",{XMLHttpRequest:D,textStatus:C});if(!B){if(C=="error"){if(D.status=="404"){alert(z.localization.directoryNotFound)}else{if(D.status!="0"){alert("Error! The requested URL returned "+D.status+" - "+D.statusText)}}}else{if(C=="timeout"){alert("Error! Server timeout.")}}}},url:z.selectUrl,callback:function(C){a(v).find(".t-delete").parent().addClass("t-state-disabled");if(!s.val()){new b.breadcrumbs(s[0],{path:C.Path,roots:C.ContentPaths})}s.val(C.Path).trigger("t:refresh");var B=a(v).find(".t-tiles-arrange a span:first").text();var E=a.map(q,function(F){if(F.Text==B){return F.Value}})[0];var D=A.val();x.trigger("t:refresh",[C,E,D])}});A.bind("t:change",function(){s.trigger("t:change")});t.get({path:""});x.bind("t:select",function(B){if(B.kind=="d"){t.get({path:B.url})}else{z.apply(B)}}).bind("t:change",function(B){var C=a(v).find(".t-delete").parent().addClass("t-state-disabled");if(B.kind=="f"){var D=B.url;if(z.imageUrl){D=z.imageUrl+"?path="+D}a(v).parent().find("#t-editor-image-url").val(D)}if((B.kind=="f"&&z.deleteFileUrl)||(B.kind=="d"&&z.deleteDirectoryUrl)){C.removeClass("t-state-disabled")}});s.bind("t:change",function(){var B=a(this).val();if(!B.match(/\/$/)){B=B+"/"}t.get({path:B})})};function o(v,u,s,t){var x=!u?"":'
              '+v.uploadFile+'
              ',q=!s?"":'',w=!t?"":' ';return'
              '+x+q+w+'
              '+v.orderBy+' '+v.orderByName+'
              '}b.fileInfoReader=function(q){this._thumbnailUrl=q.thumbnailUrl||""};b.fileInfoReader.prototype={read:function(s,q){return q[s]||q[(s.charAt(0).toUpperCase()+s.substring(1))]},directories:function(q){return this.read("directories",q)},files:function(q){return this.read("files",q)},thumbUrl:function(s,q){return this._thumbnailUrl+"/?path="+s+encodeURIComponent(q)},size:function(q){var t=this.read("size",q);if(!t){return""}var s=" bytes";if(t>=1073741824){s=" GB";t/=1073741824}else{if(t>=1048576){s=" MB";t/=1048576}else{if(t>=1024){s=" KB";t/=1024}}}return Math.round(t*100)/100+s},name:function(q){return this.read("name",q)},path:function(q){return this.read("path",q)},concatPaths:function(s,q){if(s===p||!s.match(/\/$/)){s=(s||"")+"/"}return s+encodeURIComponent(q)}};b.fileListView=function(q,s){this.element=q;this.wrapper=a(q);this._localization=s.localization;this._reader=s.reader||new b.fileInfoReader({thumbnailUrl:s.thumbnailUrl});this._pageSize=s.pageSize||20;this.wrapper.bind({"t:refresh":a.proxy(this._refresh,this),"t:upload":a.proxy(this._upload,this),"t:completeDirectory":a.proxy(this._completeDirectory,this),"t:delete":a.proxy(this._delete,this),"t:errorFile":a.proxy(this._errorFile,this),"t:errorDirectory":a.proxy(this._errorDirectory,this),"t:createDirectory":a.proxy(this._createDirectory,this),scroll:a.proxy(this._scroll,this)}).delegate("li[data-url]:not(.t-tile-empty)","click",a.proxy(this._click,this)).delegate("li[data-url]:not(.t-tile-empty)","dblclick",a.proxy(this._dblclick,this))};function g(q){return'
            • '+q.name+"
            • "}function d(q){return'
            • '+q+"
            • "}function e(q){return'
            • '+q.name+''+q.size+"";"
            • "}function c(q){return'
            • '+q.name+"
            • "}function h(q){return'
            • '}function f(t){var q=a(t);var s=a("",{alt:q.data("filename")}).hide().bind("load",function(){a(this).prev().remove().end().addClass("t-image").fadeIn()});q.find(".t-loading").after(s);s.attr("src",q.data("thumburl"));t.loaded=true}if(a.browser.msie&&parseFloat(a.browser.version)<8){var j=function(q){return q.offsetTop}}else{var j=function(q){return q.offsetTop-a(q).height()}}var l=/(\:|\^|\$|\/|\.|\+|\||\(|\)|\[|\]|\{|\}|\\)/g,n=/\*/g,m=/\?/g;function r(q){return new RegExp(q.replace(l,"\\$1").replace(n,".*").replace(m,".?"),"ig")}b.fileListView.prototype={bindTo:function(q,w,u){this._filter=u;var x=this._reader;this.wrapper.empty();var s=k(this._reader.directories(q)||[]);var t=k(this._reader.files(q)||[]);if(u){var z=function(A){return r(u).test(x.name(A))};s=s.where(z);t=t.where(z)}var y=function(A){return x[w](A)};this._data=this._process(this._reader.path(q),s.orderBy(y),t.orderBy(y));var v=this._data.select(function(A){return A.kind=="f"?e(A):c(A)}).toArray().join("");this.wrapper.append(v);this._tiles=this.wrapper.find("li[data-kind=f]");this._scroll();this._asEmpty()},_asEmpty:function(){if(!this._data.any()&&!this._filter){this.wrapper.append(d(this._localization.emptyFolder))}},_completeFile:function(q,u){var t=this._reader.name(q);var v=this._reader.path(q);var s=a(e({kind:"f",thumbUrl:this._reader.thumbUrl(v,t),url:this._reader.concatPaths(v,t),name:t,size:this._reader.size(q)}));this.wrapper.find("li").eq(this.fileIndex(u)).replaceWith(s);f(s[0]);s.click()},_completeDirectory:function(s,q){var u=this._reader.name(q);var v=this._reader.path(q);var t=a(c({kind:"d",url:this._reader.concatPaths(v,u),name:u}));this.wrapper.find("li").eq(this.directoryIndex(u)).replaceWith(t)},_delete:function(){var s=this.wrapper.find(".t-state-selected");if(s.length){var q=this._data.toArray();q.splice(s.index(),1);this._data=k(q);s.remove();this._scroll();this._asEmpty()}},_scroll:function(q){clearTimeout(this._timeout);this._timeout=setTimeout(a.proxy(function(){var s=this.wrapper.outerHeight();var u=this.wrapper.scrollTop();var t=u+s;this._tiles.each(function(){var w=j(this);var v=w+this.offsetHeight;if((w>=u&&w=u&&vt){return false}});this._tiles=this._tiles.filter(function(){return !this.loaded})},this),250)},_upload:function(s,u,y){var v=u.name;var t=this.fileIndex(v);if(t>-1&&!confirm(b.formatString(this._localization.overwriteFile,v))){y()}else{this.wrapper.find(".t-tile-empty").remove();var x=a(g(u));if(t>-1){x.data("existing",true);this.wrapper.find("li").eq(t).replaceWith(x)}else{var w=this.wrapper.find("li[data-kind=f]:first");if(w.length){w.before(x)}else{this.wrapper.append(x)}var q=this._data.toArray();q.splice(x.index(),0,{name:v,kind:"f"})}this.wrapper.scrollTop(x.attr("offsetTop")-this.element.offsetHeight);this.wrapper.one("t:completeFile",a.proxy(function(z,A){this._completeFile(A,v)},this))}},_nameDirectory:function(){var u="New folder";var s=this._data.where(function(v){return v.kind=="d"&&v.name.indexOf(u)>-1}).select(function(v){return v.name}).toArray();if(a.inArray(u,s)>-1){var t=2;do{var q=u+" ("+t+")";t++}while(a.inArray(q,s)>-1);u=q}return u},_createDirectory:function(t,q){var x=this._nameDirectory();var w=a(h(x));var u=this.wrapper.find("li[data-kind=f]:first");if(u.length){u.before(w)}else{this.wrapper.append(w)}var s=this._data.toArray();var v=w.addClass("t-state-selected").siblings().removeClass("t-state-selected").end().find("input").keydown(function(y){if(y.keyCode==13){this.blur()}}).blur(a.proxy(function(y){var z=a.trim(y.target.value);if(!z||this._data.any(function(A){return A.kind=="d"&&A.name.toLowerCase()==z.toLowerCase()})){z=this._nameDirectory()}s.splice(w.index(),0,{name:z,kind:"d"});a(y.target).replaceWith(""+z+"");q(z)},this));setTimeout(function(){v.select()});this.wrapper.find(".t-tile-empty").remove();this.wrapper.scrollTop(w.attr("offsetTop")-this.element.offsetHeight)},_errorFile:function(q,s){var t=this.fileIndex(s.name);if(t>-1){var u=this.wrapper.find("li").eq(t);if(u.data("existing")){var v=a(e(this._data.toArray()[t]));u.replaceWith(v);f(v[0])}else{u.remove();this._data.toArray().splice(t,1)}this._asEmpty()}},_errorDirectory:function(s,q){var t=this.directoryIndex(q.name);if(t>-1){this.wrapper.find("li").eq(t).remove();this._data.toArray().splice(t,1);this._asEmpty()}},fileIndex:function(q){return this._index("f",q)},directoryIndex:function(q){return this._index("d",q)},_index:function(s,t){var u=-1,q=this._data?this._data.toArray():[];t=t.toLowerCase();a.each(q,function(v,w){if(w.kind==s&&w.name.toLowerCase()==t){u=v;return false}});return u},_raise:function(s,t){var q=a(s.currentTarget);b.trigger(this.wrapper,t,{kind:q.data("kind"),url:q.data("url")})},_click:function(q){a(q.currentTarget).addClass("t-state-selected").siblings().removeClass("t-state-selected");this._raise(q,"t:change")},_dblclick:function(q){if(document.selection&&document.selection.empty){document.selection.empty()}this._raise(q,"t:select")},_refresh:function(s,q,u,t){this.bindTo(q,u,t)},_process:function(t,q,s){var u=this._reader;var q=q.select(function(v){return{url:u.concatPaths(t,u.name(v)),name:u.name(v),kind:"d"}});var s=s.select(function(v){var w=u.name(v);return{url:u.concatPaths(t,w),name:w,kind:"f",thumbUrl:u.thumbUrl(t,w),size:u.size(v)}});return q.concat(s)}};b.dataSource=function(q){this._url=q.url;this._callback=q.callback;this._error=q.error};b.dataSource.prototype={_complete:function(q){if(this._callback){this._callback(q)}},get:function(q){a.ajax({type:"POST",url:this._url,data:q,success:a.proxy(this._complete,this),error:this._error})}};b.breadcrumbs=function(s,t){this.element=s;this.wrapper=a(s);this._gap=t.gap||50;this._initPaths(t.path);var q=new b.dropDown({effects:b.fx.slide.defaults(),onClick:a.proxy(function(u){var v=a(u.item).text();q.close();this._initPaths(v);a(s).val(v).trigger("t:change")},this)});q.dataBind(t.roots);this.wrapper.delegate("input","focus",a.proxy(this._focus,this)).delegate("input","blur",a.proxy(this._blur,this)).delegate("input","keydown",a.proxy(function(u){if(u.keyCode==13){this._blur()}},this)).delegate("a:not(.t-first)","click",b.stopAll(this._click,this)).delegate(".t-select","click",function(){var u=a(s);q.open({offset:u.offset(),outerHeight:u.outerHeight(),outerWidth:u.outerWidth(),zIndex:b.getElementZIndex(this)})}).bind("t:refresh",a.proxy(this.refresh,this));a(document.documentElement).bind("mousedown",function(u){var v=q.$element[0];if(!a.contains(v,u.target)){q.close()}});this.value(t.path)};b.breadcrumbs.prototype={_initPaths:function(q){this._basePath=(q||"").replace(/\/{2,}/g,"/").replace(/\/$/,"");q=this._basePath.split("/");q.pop();this._root=q.join("/")},_html:function(){var q=this._basePath.split("/").length-1;var s=this.value();if(s===p||!s.match(/^\//)){s="/"+(s||"")}return'
              '+a.map(s.split("/"),function(u,t){if(u&&t>=q){return''+u+""}}).join('>')+'
              select
              '},_path:function(q){return this._root+"/"+a.map(q,function(s){return a(s).text()}).join("/")},_update:function(s){s=s.charAt(0)==="/"?s:"/"+s;var q=this.value()!=s;this.value(s);if(q){this.wrapper.trigger("t:change")}},value:function(q){if(q!==p){this.wrapper.val(q.replace(/\/{2,}/g,"/"));this.refresh()}else{return this.wrapper.val()}},_click:function(q){this._update(this._path(a(q.target).prevAll("a").andSelf()))},refresh:function(){this.wrapper.empty().append(this._html());var s=this.wrapper.width()-this._gap;var q=this.wrapper.find("a");q.each(function(u){var t=a(this);if(t.parent().width()>s){if(u==q.length-1){t.width(s)}else{t.prev().andSelf().hide()}}})},_focus:function(){var q=this.wrapper.find(".t-breadcrumbs-wrap").hide().end().find("input").val(this.value());setTimeout(function(){q.select()})},_blur:function(){var q=this.wrapper.find("input").val().replace(/\/{2,}/g,"/");if(!q||q.toLowerCase().indexOf(this._basePath.toLowerCase())<0){q=this._basePath}this._update(q)}};b.searchBox=function(q){this.element=q;this.wrapper=a(q);this.wrapper.delegate("input","focus",a.proxy(this._focus,this)).delegate("input","blur",a.proxy(this._blur,this)).delegate("input","keydown",a.proxy(function(s){if(s.keyCode==13){this._blur()}},this)).delegate("a","click",b.stopAll(this._click,this));this._render()};b.searchBox.prototype={_render:function(){var q='search';this.wrapper.empty().append(a(q))},_focus:function(){this.wrapper.find("label").hide()},_blur:function(){this._update(this.wrapper.find("input").val());if(this.value()==""){this.wrapper.find("label").show()}},_update:function(s){var q=this.value()!=s;this.value(s);if(q){this.wrapper.trigger("t:change")}},value:function(q){if(q!==p){this.wrapper.val(q)}else{return this.wrapper.val()}},_click:function(){this._blur()}}})(jQuery);(function(a){var v,b=a.telerik,q=/\.([^\.]+)$/;b.scripts.push("telerik.upload.js");b.upload=function(x,y){a.extend(this,y);this.element=x;this.name=x.name;var w=a(x);this.wrapper=w.closest(".t-upload");if(this.wrapper.length==0){this.wrapper=this._wrapInput(w)}this._setActiveInput(w);this.toggle(this.enabled);w.closest("form").bind({submit:a.proxy(this._onParentFormSubmit,this),reset:a.proxy(this._onParentFormReset,this)});if(this.async.saveUrl!=v){this._module=this._getSupportsFormData()?new d(this):new m(this)}else{this._module=new t(this)}if(this._getSupportsDrop()){this._setupDropZone()}this.wrapper.delegate(".t-upload-action","click",a.proxy(this._onFileAction,this)).delegate(".t-upload-selected","click",a.proxy(this._onUploadSelected,this)).delegate(".t-file","t:progress",a.proxy(this._onFileProgress,this)).delegate(".t-file","t:upload-success",a.proxy(this._onUploadSuccess,this)).delegate(".t-file","t:upload-error",a.proxy(this._onUploadError,this));b.bind(this.wrapper,{load:this.onLoad,select:this.onSelect,upload:this.onUpload,success:this.onSuccess,error:this.onError,complete:this.onComplete,cancel:this.onCancel,remove:this.onRemove});var z=a(this.wrapper).data("tUpload",this);a(x).bind("load",function(){b.trigger(z,"load")})};b.upload.prototype={enable:function(){this.toggle(true)},disable:function(){this.toggle(false)},toggle:function(w){w=typeof w==="undefined"?w:!w;this.wrapper.toggleClass("t-state-disabled",w)},_addInput:function(w){w.insertAfter(this.element).data("tUpload",this);a(this.element).hide().removeAttr("id");this._setActiveInput(w)},_setActiveInput:function(w){var x=this.wrapper;this.element=w;w.attr("multiple",this._getSupportsMultiple()?this.multiple:false).attr("autocomplete","off").click(function(y){if(x.hasClass("t-state-disabled")){y.preventDefault()}}).change(a.proxy(this._onInputChange,this))},_onInputChange:function(w){var z=this,x=a(w.target),y=b.trigger(z.wrapper,"select",{files:l(x)});if(y){z._addInput(x.clone().val(""));x.remove()}else{x.trigger("t:select")}},_onDrop:function(y){var x=y.originalEvent.dataTransfer,w=x.files;r(y);if(w.length>0){var z=b.trigger(this.wrapper,"select",{files:e(w)});if(!z){a(".t-dropzone",this.wrapper).trigger("t:select",[w])}}},_enqueueFile:function(A,w){var z=a(".t-upload-files",this.wrapper);if(z.length==0){z=a("
                ").appendTo(this.wrapper);if(!this.showFileList){z.hide()}}var x=a(".t-file",z);var y=a("
              • "+A+"
              • ").appendTo(z).data(w);if(!this.multiple){x.trigger("t:remove")}return y},_removeFileEntry:function(x){var y=x.closest(".t-upload-files"),w;x.remove();w=a(".t-file",y);if(w.find("> .t-fail").length===w.length){this._hideUploadButton()}if(w.length==0){y.remove()}},_setFileAction:function(y,w){var x={remove:"t-delete",cancel:"t-cancel",retry:"t-retry"};if(!x.hasOwnProperty(w)){return}this._clearFileAction(y);y.append(this._renderAction(x[w],this.localization[w]).addClass("t-upload-action"))},_setFileState:function(x,z){var A={uploading:{cssClass:"t-loading",text:this.localization.statusUploading},uploaded:{cssClass:"t-success",text:this.localization.statusUploaded},failed:{cssClass:"t-fail",text:this.localization.statusFailed}};var w=A[z];if(w){var y=x.children(".t-icon").text(w.text);y[0].className="t-icon "+w.cssClass}},_renderAction:function(w,x){if(w!=""){return a("")}else{return a("")}},_clearFileAction:function(w){w.find(".t-upload-action").remove()},_onFileAction:function(x){if(!this.wrapper.hasClass("t-state-disabled")){var w=a(x.target).closest(".t-upload-action"),A=w.find(".t-icon"),z=w.closest(".t-file"),y={files:z.data("fileNames")};if(A.hasClass("t-delete")){if(!b.trigger(this.wrapper,"remove",y)){z.trigger("t:remove",y.data)}}else{if(A.hasClass("t-cancel")){b.trigger(this.wrapper,"cancel",y);z.trigger("t:cancel");this._checkAllComplete()}else{if(A.hasClass("t-retry")){z.trigger("t:retry")}}}}return false},_onUploadSelected:function(){this.wrapper.trigger("t:saveSelected");return false},_onFileProgress:function(w,x){var y=a(".t-progress-status",w.target);if(y.length==0){y=a("").appendTo(a(".t-filename",w.target)).find(".t-progress-status")}y.width(x+"%")},_onUploadSuccess:function(w,y,z){var x=g(w);this._setFileState(x,"uploaded");b.trigger(this.wrapper,"success",{files:x.data("fileNames"),response:y,operation:"upload",XMLHttpRequest:z});if(this._supportsRemove()){this._setFileAction(x,"remove")}else{this._clearFileAction(x)}this._checkAllComplete()},_onUploadError:function(w,z){var x=g(w);this._setFileState(x,"failed");this._setFileAction(x,"retry");var y=b.trigger(this.wrapper,"error",{operation:"upload",files:x.data("fileNames"),XMLHttpRequest:z});o("Server response: "+z.responseText);if(!y){this._alert("Error! Upload failed. Unexpected server response - see console.")}this._checkAllComplete()},_showUploadButton:function(){var w=a(".t-upload-selected",this.wrapper);if(w.length==0){w=this._renderAction("",this.localization.uploadSelectedFiles).addClass("t-upload-selected")}this.wrapper.append(w)},_hideUploadButton:function(){a(".t-upload-selected",this.wrapper).remove()},_onParentFormSubmit:function(){var y=this,w=y.element;w.trigger("t:abort");if(!w.value){var x=a(w);x.attr("disabled","disabled");window.setTimeout(function(){x.removeAttr("disabled")},0)}},_onParentFormReset:function(){a(".t-upload-files",this.wrapper).remove()},_getSupportsFormData:function(){return typeof(FormData)!="undefined"},_getSupportsMultiple:function(){return !a.browser.opera},_getSupportsDrop:function(){var z=this._getUserAgent().toLowerCase(),w=/chrome/.test(z),x=!w&&/safari/.test(z),y=x&&/windows/.test(z);return !y&&this._getSupportsFormData()&&(this.async.saveUrl!=v)},_getUserAgent:function(){return navigator.userAgent},_setupDropZone:function(){a(".t-upload-button",this.wrapper).wrap("
                ");var w=a(".t-dropzone",this.wrapper).append(a(""+this.localization.dropFilesHere+"")).bind({dragenter:r,dragover:function(x){x.preventDefault()},drop:a.proxy(this._onDrop,this)});c(w,function(){w.addClass("t-dropzone-hovered")},function(){w.removeClass("t-dropzone-hovered")});c(a(document),function(){w.addClass("t-dropzone-active")},function(){w.removeClass("t-dropzone-active")})},_supportsRemove:function(){return this.async.removeUrl!=v},_submitRemove:function(x,w,z,y){var A=a.extend(w,f());A.fileNames=x;a.ajax({type:"POST",dataType:"json",url:this.async.removeUrl,traditional:true,data:A,success:z,error:y})},_alert:function(w){alert(w)},_wrapInput:function(w){w.wrap("
                ");w.closest(".t-button").append(""+this.localization.select+"");return w.closest(".t-upload")},_checkAllComplete:function(){if(a(".t-file .t-icon.t-loading",this.wrapper).length==0){b.trigger(this.wrapper,"complete")}}};a.fn.tUpload=function(w){return b.create(this,{name:"tUpload",init:function(x,y){return new b.upload(x,y)},options:w})};a.fn.tUpload.defaults={enabled:true,multiple:true,showFileList:true,async:{},localization:{select:"Select...",cancel:"Cancel",retry:"Retry",remove:"Remove",uploadSelectedFiles:"Upload files",dropFilesHere:"drop files here to upload",statusUploading:"uploading",statusUploaded:"uploaded",statusFailed:"failed"}};var t=function(w){this.name="syncUploadModule";this.element=w.wrapper;this.upload=w;this.element.bind("t:select",a.proxy(this.onSelect,this)).bind("t:remove",a.proxy(this.onRemove,this)).closest("form").attr("enctype","multipart/form-data").attr("encoding","multipart/form-data")};t.prototype={onSelect:function(w){var z=this.upload;var y=a(w.target);z._addInput(y.clone().val(""));var x=z._enqueueFile(k(y),{relatedInput:y,fileNames:l(y)});z._setFileAction(x,"remove")},onRemove:function(w){var x=g(w);x.data("relatedInput").remove();this.upload._removeFileEntry(x)}};var m=function(w){this.name="iframeUploadModule";this.element=w.wrapper;this.upload=w;this.iframes=[];this.element.bind("t:select",a.proxy(this.onSelect,this)).bind("t:cancel",a.proxy(this.onCancel,this)).bind("t:retry",a.proxy(this.onRetry,this)).bind("t:remove",a.proxy(this.onRemove,this)).bind("t:saveSelected",a.proxy(this.onSaveSelected,this)).bind("t:abort",a.proxy(this.onAbort,this))};b.upload._frameId=0;m.prototype={onSelect:function(w){var z=this.upload,y=a(w.target);var x=this.prepareUpload(y);if(z.async.autoUpload){this.performUpload(x)}else{if(z._supportsRemove()){this.upload._setFileAction(x,"remove")}z._showUploadButton()}},prepareUpload:function(B){var C=this.upload;var w=a(C.element);var A=C.async.saveField||B.attr("name");C._addInput(B.clone().val(""));B.attr("name",A);var z=this.createFrame(C.name+"_"+b.upload._frameId++);this.registerFrame(z);var y=this.createForm(C.async.saveUrl,z.attr("name")).append(w);var x=C._enqueueFile(k(B),{frame:z,relatedInput:w,fileNames:l(B)});z.data({form:y,file:x});return x},performUpload:function(y){var x={files:y.data("fileNames")},A=y.data("frame"),C=this.upload;if(!b.trigger(C.wrapper,"upload",x)){C._hideUploadButton();A.appendTo(document.body);var z=A.data("form").appendTo(document.body);x.data=a.extend({},x.data,f());for(var B in x.data){var w=z.find("input[name='"+B+"']");if(w.length==0){w=a("",{type:"hidden",name:B}).prependTo(z)}w.val(x.data[B])}C._setFileAction(y,"cancel");C._setFileState(y,"uploading");A.one("load",a.proxy(this.onIframeLoad,this));z[0].submit()}else{C._removeFileEntry(A.data("file"));this.cleanupFrame(A);this.unregisterFrame(A)}},onSaveSelected:function(w){var x=this;a(".t-file",this.element).each(function(){var y=a(this),z=n(y);if(!z){x.performUpload(y)}})},onIframeLoad:function(w){var x=a(w.target);try{var y=x.contents().text()}catch(w){y="Error trying to get server response: "+w}this.processResponse(x,y)},processResponse:function(y,A){var x=y.data("file"),z=this,w={responseText:A};u(A,function(B){a.extend(w,{statusText:"OK",status:"200"});x.trigger("t:upload-success",[B,w]);z.cleanupFrame(y);z.unregisterFrame(y)},function(){a.extend(w,{statusText:"error",status:"500"});x.trigger("t:upload-error",[w])})},onCancel:function(w){var x=a(w.target).data("frame");this.stopFrameSubmit(x);this.cleanupFrame(x);this.unregisterFrame(x);this.upload._removeFileEntry(x.data("file"))},onRetry:function(w){var x=g(w);this.performUpload(x)},onRemove:function(x,w){var y=g(x);var z=y.data("frame");if(z){this.unregisterFrame(z);this.upload._removeFileEntry(y);this.cleanupFrame(z)}else{p(y,this.upload,w)}},onAbort:function(){var w=this.element,x=this;a.each(this.iframes,function(){a("input",this.data("form")).appendTo(w);x.stopFrameSubmit(this[0]);this.data("form").remove();this.remove()});this.iframes=[]},createFrame:function(w){return a("")}},font:{start:function(bl){bg.push('')},end:function(bj){bg.push("")}}};function bd(bv){var bz=[],bm=bv.attributes,bA=a.trim;if(y.is(bv,"iframe")){var bj=a(bv);if(bj.attr("originalsrc")!=""){bj.attr("src",bj.attr("originalsrc"));bj.removeAttr("originalsrc")}}if(y.is(bv,"img")){var bC=bv.style.width,bq=bv.style.height,bj=a(bv);if(bC){bj.attr("width",parseInt(bC));y.unstyle(bv,{width:undefined})}if(bq){bj.attr("height",parseInt(bq));y.unstyle(bv,{height:undefined})}}for(var br=0,bs=bm.length;brbE.nodeName?1:bD.nodeName=0){bB=y.toHex(bB)}if(bx.indexOf("font")>=0){bB=bB.replace(aI,"'")}bg.push(bx);bg.push(":");bg.push(bB);bg.push(";")}}}else{if(bl=="src"||bl=="href"){bg.push(bv.getAttribute(bl,2))}else{bg.push(F[bl]?bl:bn)}}bg.push('"')}}function bf(bk,bl){for(var bj=bk.firstChild;bj;bj=bj.nextSibling){be(bj,bl)}}function be(bk,bo){var bl=bk.nodeType;if(bl==1){var bp=y.name(bk);if(bp==""||(bk.attributes._moz_dirty&&y.is(bk,"br"))){return}var bj=bi[bp];if(bj){bj.start(bk);bf(bk);bj.end(bk);return}bg.push("<");bg.push(bp);bd(bk);if(A[bp]){bg.push(" />")}else{bg.push(">");bf(bk,bo||y.is(bk,"pre"));bg.push("")}}else{if(bl==3){var bq=bk.nodeValue;if(!bo&&a.support.leadingWhitespace){var bm=bk.parentNode;var bn=bk.previousSibling;if(!bn){bn=(y.isInline(bm)?bm:bk).previousSibling}if(!bn||bn.innerHTML==""||y.isBlock(bn)){bq=bq.replace(/^[\r\n\v\f\t ]+/,"")}bq=bq.replace(/ +/," ")}bg.push(y.encode(bq))}else{if(bl==4){bg.push("")}else{if(bl==8){if(bk.data.indexOf("[CDATA[")<0){bg.push("")}else{bg.push("")}}}}}}bf(bh);bg=bg.join("");if(bg.replace(n,"").replace(C,"")==""){return""}return bg}var aX=0,aW=1,D=2,E=3;function x(bd){var be=bd.startContainer;return be.nodeType==9?be:be.ownerDocument}function aR(bd){if(a.browser.msie&&a.browser.version<9){return new ba(bd.document)}return bd.getSelection()}function aQ(be){var bd=x(be);return aP(bd)}function aP(bd){return aR(bc(bd))}function bc(bd){return bd.defaultView||bd.parentWindow}function aU(bf,bd,bg){function be(bj){var bi=bf.cloneRange();bi.collapse(bj);bi[bj?"setStartBefore":"setEndAfter"](bd);var bh=bi.extractContents();if(bg){bh=y.trim(bh)}y[bj?"insertBefore":"insertAfter"](bh,bd)}be(true);be(false)}function aS(be){var bd=aL.image(be);if(bd){be.setStartAfter(bd);be.setEndAfter(bd)}var bf=aQ(be);bf.removeAllRanges();bf.addRange(be)}function a9(bd){a.extend(this,{ownerDocument:bd,startContainer:bd,endContainer:bd,commonAncestorContainer:bd,startOffset:0,endOffset:0,collapsed:true})}a9.prototype={setStart:function(bd,be){this.startContainer=bd;this.startOffset=be;a7(this);J(this,true)},setEnd:function(bd,be){this.endContainer=bd;this.endOffset=be;a7(this);J(this,false)},setStartBefore:function(bd){this.setStart(bd.parentNode,H(bd))},setStartAfter:function(bd){this.setStart(bd.parentNode,H(bd)+1)},setEndBefore:function(bd){this.setEnd(bd.parentNode,H(bd))},setEndAfter:function(bd){this.setEnd(bd.parentNode,H(bd)+1)},selectNode:function(bd){this.setStartBefore(bd);this.setEndAfter(bd)},selectNodeContents:function(bd){this.setStart(bd,0);this.setEnd(bd,bd[bd.nodeType===1?"childNodes":"nodeValue"].length)},collapse:function(bd){if(bd){this.setEnd(this.startContainer,this.startOffset)}else{this.setStart(this.endContainer,this.endOffset)}},deleteContents:function(){var be=this.cloneRange();if(this.startContainer!=this.commonAncestorContainer){this.setStartAfter(G(this.commonAncestorContainer,this.startContainer))}this.collapse(true);(function bd(bf){while(bf.next()){bf.hasPartialSubtree()?bd(bf.getSubtreeIterator()):bf.remove()}})(new aK(be))},cloneContents:function(){var be=x(this);return(function bd(bg){for(var bh,bf=be.createDocumentFragment();bh=bg.next();){bh=bh.cloneNode(!bg.hasPartialSubtree());if(bg.hasPartialSubtree()){bh.appendChild(bd(bg.getSubtreeIterator()))}bf.appendChild(bh)}return bf})(new aK(this))},extractContents:function(){var bf=this.cloneRange();if(this.startContainer!=this.commonAncestorContainer){this.setStartAfter(G(this.commonAncestorContainer,this.startContainer))}this.collapse(true);var bg=this;var bd=x(this);return(function be(bi){for(var bj,bh=bd.createDocumentFragment();bj=bi.next();){bi.hasPartialSubtree()?bj=bj.cloneNode(false):bi.remove(bg.originalRange);if(bi.hasPartialSubtree()){bj.appendChild(be(bi.getSubtreeIterator()))}bh.appendChild(bj)}return bh})(new aK(bf))},insertNode:function(bd){if(an(this.startContainer)){if(this.startOffset!=this.startContainer.nodeValue.length){aV(this.startContainer,this.startOffset)}y.insertAfter(bd,this.startContainer)}else{y.insertAt(this.startContainer,bd,this.startOffset)}this.setStart(this.startContainer,this.startOffset)},cloneRange:function(){return a.extend(new a9(this.ownerDocument),{startContainer:this.startContainer,endContainer:this.endContainer,commonAncestorContainer:this.commonAncestorContainer,startOffset:this.startOffset,endOffset:this.endOffset,collapsed:this.collapsed,originalRange:this})},toString:function(){var be=this.startContainer.nodeName,bd=this.endContainer.nodeName;return[be=="#text"?this.startContainer.nodeValue:be,"(",this.startOffset,") : ",bd=="#text"?this.endContainer.nodeValue:bd,"(",this.endOffset,")"].join("")}};function r(bi,be,bk,bg){if(bi==be){return bg-bk}var bd=be;while(bd&&bd.parentNode!=bi){bd=bd.parentNode}if(bd){return H(bd)-bk}bd=bi;while(bd&&bd.parentNode!=be){bd=bd.parentNode}if(bd){return bg-H(bd)-1}var bh=y.commonAncestor(bi,be);var bj=bi;while(bj&&bj.parentNode!=bh){bj=bj.parentNode}if(!bj){bj=bh}var bf=be;while(bf&&bf.parentNode!=bh){bf=bf.parentNode}if(!bf){bf=bh}if(bj==bf){return 0}return H(bf)-H(bj)}function J(be,bf){function bd(bh){try{return r(bh.startContainer,bh.endContainer,bh.startOffset,bh.endOffset)<0}catch(bg){return true}}if(bd(be)){if(bf){be.commonAncestorContainer=be.endContainer=be.startContainer;be.endOffset=be.startOffset}else{be.commonAncestorContainer=be.startContainer=be.endContainer;be.startOffset=be.endOffset}be.collapsed=true}}function a7(be){be.collapsed=be.startContainer==be.endContainer&&be.startOffset==be.endOffset;var bd=be.startContainer;while(bd&&bd!=be.endContainer&&!al(bd,be.endContainer)){bd=bd.parentNode}be.commonAncestorContainer=bd}function t(bd){if(a.browser.msie&&a.browser.version<9){return new a9(bd)}return bd.createRange()}function aK(bd){a.extend(this,{range:bd,_current:null,_next:null,_end:null});if(bd.collapsed){return}var be=bd.commonAncestorContainer;this._next=bd.startContainer==be&&!an(bd.startContainer)?bd.startContainer.childNodes[bd.startOffset]:G(be,bd.startContainer);this._end=bd.endContainer==be&&!an(bd.endContainer)?bd.endContainer.childNodes[bd.endOffset]:G(be,bd.endContainer).nextSibling}aK.prototype={hasNext:function(){return !!this._next},next:function(){var bd=this._current=this._next;this._next=this._current&&this._current.nextSibling!=this._end?this._current.nextSibling:null;if(an(this._current)){if(this.range.endContainer==this._current){(bd=bd.cloneNode(true)).deleteData(this.range.endOffset,bd.length-this.range.endOffset)}if(this.range.startContainer==this._current){(bd=bd.cloneNode(true)).deleteData(0,this.range.startOffset)}}return bd},traverse:function(bd){function bf(){this._current=this._next;this._next=this._current&&this._current.nextSibling!=this._end?this._current.nextSibling:null;return this._current}var be;while(be=bf.call(this)){if(this.hasPartialSubtree()){this.getSubtreeIterator().traverse(bd)}else{bd(be)}}return be},remove:function(bi){var bg=this.range.startContainer==this._current;var bf=this.range.endContainer==this._current;if(an(this._current)&&(bg||bf)){var bk=bg?this.range.startOffset:0;var be=bf?this.range.endOffset:this._current.length;var bd=be-bk;if(bi&&(bg||bf)){if(this._current==bi.startContainer&&bk<=bi.startOffset){bi.startOffset-=bd}if(this._current==bi.endContainer&&be<=bi.endOffset){bi.endOffset-=bd}}this._current.deleteData(bk,bd)}else{var bj=this._current.parentNode;if(bi&&(this.range.startContainer==bj||this.range.endContainer==bj)){var bh=H(this._current);if(bj==bi.startContainer&&bh<=bi.startOffset){bi.startOffset-=1}if(bj==bi.endContainer&&bh0&&be.previousSibling);bd.setEndPoint(bh?"EndToStart":"EndToEnd",bj);var bi=be.nextSibling;if(!bi){bi=be.previousSibling;if(bi&&an(bi)){bg.setEnd(bi,bi.nodeValue.length);y.remove(be)}else{bg.selectNodeContents(bf);y.remove(be);bg.endOffset-=1}return}y.remove(be);if(an(bi)){bg[bh?"setStart":"setEnd"](bi,bd.text.length)}else{bg[bh?"setStartBefore":"setEndBefore"](bi)}}function aJ(bd){this.enumerate=function(){var be=[];function bf(bg){if(y.is(bg,"img")||(bg.nodeType==3&&!y.isWhitespace(bg))){be.push(bg)}else{bg=bg.firstChild;while(bg){bf(bg);bg=bg.nextSibling}}}new aK(bd).traverse(bf);return be}}function a1(bd){return new aJ(bd).enumerate()}function l(bh){var be=[];for(var bf=0,bg=bh.length;bf'}bi.selectNodeContents(be)}}bi.collapse(true)};this.add=function(bf,be){if(be&&bf.collapsed){this.addCaret(bf);bf=aL.expand(bf)}var bg=bf.cloneRange();bg.collapse(false);this.end=y.create(x(bf),"span",{className:"t-marker"});bg.insertNode(this.end);bg=bf.cloneRange();bg.collapse(true);this.start=this.end.cloneNode(true);bg.insertNode(this.start);bf.setStartBefore(this.start);bf.setEndAfter(this.end);aC(bf.commonAncestorContainer);return bf};this.remove=function(bl){var bo=this.start,bg=this.end;aC(bl.commonAncestorContainer);while(!bo.nextSibling&&bo.parentNode){bo=bo.parentNode}while(!bg.previousSibling&&bg.parentNode){bg=bg.parentNode}var bn=(bo.previousSibling&&bo.previousSibling.nodeType==3)&&(bo.nextSibling&&bo.nextSibling.nodeType==3);var bm=(bg.previousSibling&&bg.previousSibling.nodeType==3)&&(bg.nextSibling&&bg.nextSibling.nodeType==3);bo=bo.nextSibling;bg=bg.previousSibling;var be=false;var bf=false;if(bo==this.end){bf=!!this.start.previousSibling;bo=bg=this.start.previousSibling||this.end.nextSibling;be=true}y.remove(this.start);y.remove(this.end);if(bo==null||bg==null){bl.selectNodeContents(bl.commonAncestorContainer);bl.collapse(true);return}var bq=be?an(bo)?bo.nodeValue.length:bo.childNodes.length:0;var bi=an(bg)?bg.nodeValue.length:bg.childNodes.length;if(bo.nodeType==3){while(bo.previousSibling&&bo.previousSibling.nodeType==3){bo=bo.previousSibling;bq+=bo.nodeValue.length}}if(bg.nodeType==3){while(bg.previousSibling&&bg.previousSibling.nodeType==3){bg=bg.previousSibling;bi+=bg.nodeValue.length}}var bp=H(bo),br=bo.parentNode;var bh=H(bg),bj=bg.parentNode;for(var bs=bo;bs.previousSibling;bs=bs.previousSibling){if(bs.nodeType==3&&bs.previousSibling.nodeType==3){bp--}}for(var bk=bg;bk.previousSibling;bk=bk.previousSibling){if(bk.nodeType==3&&bk.previousSibling.nodeType==3){bh--}}aC(br);if(bo.nodeType==3){bo=br.childNodes[bp]}aC(bj);if(bg.nodeType==3){bg=bj.childNodes[bh]}if(be){if(bo.nodeType==3){bl.setStart(bo,bq)}else{bl[bf?"setStartAfter":"setStartBefore"](bo)}bl.collapse(true)}else{if(bo.nodeType==3){bl.setStart(bo,bq)}else{bl.setStartBefore(bo)}if(bg.nodeType==3){bl.setEnd(bg,bi)}else{bl.setEndAfter(bg)}}if(bd){this.removeCaret(bl)}}}var m=/[\u0009-\u000d]|\u0020|\u00a0|\ufeff|\.|,|;|:|!|\(|\)|\?/;var aL={nodes:function(be){var bd=a1(be);if(!bd.length){be.selectNodeContents(be.commonAncestorContainer);bd=a1(be);if(!bd.length){bd=y.significantChildNodes(be.commonAncestorContainer)}}return bd},image:function(be){var bd=[];new aK(be).traverse(function(bf){if(y.is(bf,"img")){bd.push(bf)}});if(bd.length==1){return bd[0]}},expand:function(bh){var bi=bh.cloneRange();var bj=bi.startContainer.childNodes[bi.startOffset==0?0:bi.startOffset-1];var bf=bi.endContainer.childNodes[bi.endOffset];if(!an(bj)||!an(bf)){return bi}var be=bj.nodeValue;var bd=bf.nodeValue;if(be==""||bd==""){return bi}var bk=be.split("").reverse().join("").search(m);var bg=bd.search(m);if(bk==0||bg==0){return bi}bg=bg==-1?bd.length:bg;bk=bk==-1?0:be.length-bk;bi.setStart(bj,bk);bi.setEnd(bf,bg);return bi},isExpandable:function(bi){var bh=bi.startContainer;var bf=x(bi);if(bh==bf||bh==bf.body){return false}var bj=bi.cloneRange();var bl=bh.nodeValue;if(!bl){return false}var be=bl.substring(0,bj.startOffset);var bd=bl.substring(bj.startOffset);var bk=0,bg=0;if(be!=""){bk=be.split("").reverse().join("").search(m)}if(bd!=""){bg=bd.search(m)}return bk!=0&&bg!=0}};function q(be){var bf=new aM(be.range);var bd=new az();this.formatter=be.formatter;this.getRange=function(){return bf.toRange()};this.lockRange=function(bg){return bd.add(this.getRange(),bg)};this.releaseRange=function(bg){bd.remove(bg);aS(bg)};this.undo=function(){bf.body.innerHTML=bf.html;aS(bf.toRange())};this.redo=function(){this.exec()};this.exec=function(){var bg=this.lockRange(true);this.formatter.editor=this.editor;this.formatter.toggle(bg);this.releaseRange(bg)}}function S(bf,be){var bd=bf.body;this.redo=function(){bd.innerHTML=be.html;aS(be.toRange())};this.undo=function(){bd.innerHTML=bf.html;aS(bf.toRange())}}function aj(bd){q.call(this,bd);this.managesUndoRedo=true;this.exec=function(){var be=this.editor;var bf=be.getRange();var bg=new aM(bf);be.clipboard.paste(bd.value||"");be.undoRedoStack.push(new S(bg,new aM(be.getRange())));be.focus()}}function ak(){a2.call(this);var bd,be="";this.command=function(bf){return new aj(bf)};this.update=function(bf,bh){var bg=bf.data("tSelectBox");bg.close();bg.value(be)};this.init=function(bf,bg){bd=bg.editor;be=bd.localization.insertHtml;bf.tSelectBox({data:bd.insertHtml||[],title:be,onItemCreate:function(bh){bh.html=''+bh.dataItem.Text+""},onChange:function(bh){a2.exec(bd,"insertHtml",bh.value)},highlightFirst:false}).find(".t-input").html(bd.localization.insertHtml)}}function a4(){var be=[],bd=-1;this.push=function(bf){be=be.slice(0,bd+1);bd=be.push(bf)-1};this.undo=function(){if(this.canUndo()){be[bd--].undo()}};this.redo=function(){if(this.canRedo()){be[++bd].redo()}};this.canUndo=function(){return bd>=0};this.canRedo=function(){return bd!=be.length-1}}function a3(bd){this.keydown=function(be){var bg=bd.keyboard;var bf=bg.isTypingKey(be);if(bf&&!bg.typingInProgress()){var bh=bd.getRange();this.startRestorePoint=new aM(bh);bg.startTyping(a.proxy(function(){bd.selectionRestorePoint=this.endRestorePoint=new aM(bd.getRange());bd.undoRedoStack.push(new S(this.startRestorePoint,this.endRestorePoint))},this));return true}return false};this.keyup=function(be){var bf=bd.keyboard;if(bf.typingInProgress()){bf.endTyping();return true}return false}}function a0(bd){var be=false;this.createUndoCommand=function(){this.endRestorePoint=new aM(bd.getRange());bd.undoRedoStack.push(new S(this.startRestorePoint,this.endRestorePoint));this.startRestorePoint=this.endRestorePoint};this.changed=function(){if(this.startRestorePoint){return this.startRestorePoint.html!=bd.body.innerHTML}return false};this.keydown=function(bf){var bg=bd.keyboard;if(bg.isModifierKey(bf)){if(bg.typingInProgress()){bg.endTyping(true)}this.startRestorePoint=new aM(bd.getRange());return true}if(bg.isSystem(bf)){be=true;if(this.changed()){be=false;this.createUndoCommand()}return true}return false};this.keyup=function(bf){if(be&&this.changed()){be=false;this.createUndoCommand(bf);return true}return false}}function ao(bd){var bj=false;var bi;var bg;function be(bk){return(bk>=48&&bk<=90)||(bk>=96&&bk<=111)||(bk>=186&&bk<=192)||(bk>=219&&bk<=222)}this.toolFromShortcut=function(bo,bk){var bl=String.fromCharCode(bk.keyCode);for(var bn in bo){var bm=bo[bn];if((bm.key==bl||bm.key==bk.keyCode)&&!!bm.ctrl==bk.ctrlKey&&!!bm.alt==bk.altKey&&!!bm.shift==bk.shiftKey){return bn}}};this.isTypingKey=function(bk){var bl=bk.keyCode;return(be(bl)&&!bk.ctrlKey&&!bk.altKey)||bl==32||bl==13||bl==8||(bl==46&&!bk.shiftKey&&!bk.ctrlKey&&!bk.altKey)};this.isModifierKey=function(bk){var bl=bk.keyCode;return(bl==17&&!bk.shiftKey&&!bk.altKey)||(bl==16&&!bk.ctrlKey&&!bk.altKey)||(bl==18&&!bk.ctrlKey&&!bk.shiftKey)};this.isSystem=function(bk){return bk.keyCode==46&&bk.ctrlKey&&!bk.altKey&&!bk.shiftKey};this.startTyping=function(bk){bg=bk;bj=true};function bh(){bj=false;if(bg){bg()}}this.endTyping=function(bk){this.clearTimeout();if(bk){bh()}else{bi=window.setTimeout(bh,1000)}};this.typingInProgress=function(){return bj};this.clearTimeout=function(){window.clearTimeout(bi)};function bf(bk,bm){for(var bl=0;bl(\s| )*)+(<\/?(div|p|li|col|t))/ig,"$3");bn=bn.replace(/<(a|span)[^>]*><\/\1>/ig,"")}bn=bn.replace(/^
              • $/g,"li>
              ");var bi=bg(bn);var bs=be.getRange();bs.deleteContents();if(bs.startContainer==be.document){bs.selectNodeContents(be.body)}var bq=new az();var bj=bq.addCaret(bs);var br=bh(bi,bj);var bt=false;if(!/body|td/.test(y.name(br))&&(bi||y.isInline(br))){bs.selectNode(bj);aU(bs,br,true);bt=true}var bl=bf(bn);if(bl.firstChild&&bl.firstChild.className==="t-paste-container"){var bm=[];for(bo=0,bp=bl.childNodes.length;bo"))}bs.insertNode(bl);br=bh(bi,bj);if(bt){while(bj.parentNode!=br){y.unwrap(bj.parentNode)}y.unwrap(bj.parentNode)}aC(bs.commonAncestorContainer);bj.style.display="inline";y.scrollTo(bj);bq.removeCaret(bs);aS(bs)}}function v(){this.applicable=function(bd){return/<(b|i|u|)>/i.test(bd)};this.clean=function(bd){return bd.replace(/<(\/?)b>/gi,"<$1strong>").replace(/<(\/?)>/gi,"<$1em>").replace(//gi,'').replace(/<\/u>/gi,"")}}function aT(){this.applicable=function(bd){return/=0;bf--){bd=bi[bf];bg=bd.parentNode;if(y.is(bg,"span")&&bg.childNodes.length==1){bg.style.cssText=a.trim(bg.style.cssText+bd.style.cssText);while(bd.firstChild){bg.appendChild(bd.firstChild)}bg.removeChild(bd)}}return bh.innerHTML}}function aA(){var bf=[/<\?xml[^>]*>/gi,"",//g,"",/"/g,"'",/(?:
               [\s\r\n]+|
              )*(<\/?(h[1-6]|hr|p|div|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|address|pre|form|blockquote|dl|dt|dd|dir|fieldset)[^>]*>)(?:
               [\s\r\n]+|
              )*/g,"$1",/

              /g,"

              ",/
              ( )+\s+/ig," ",/]*)>(\s| )+]*>(\s| )*<\/tr>/gi,"",/]*>(\s| )*<\/tbody>/gi,"",/]*>(\s| )*<\/table>/gi,"",/

              /g,"
              ",/^\s*( )+/gi,"",/( |]*>)+\s*$/gi,"",/mso-[^;"]*;?/ig,"",/<(\/?)b(\s[^>]*)?>/ig,"<$1strong$2>",/<(\/?)i(\s[^>]*)?>/ig,"<$1em$2>",/<\/?(meta|link|style|o:|v:|x:)[^>]*>((?:.|\n)*?<\/(meta|link|style|o:|v:|x:)[^>]*>)?/ig,"",/style=(["|'])\s*\1/g,""];this.applicable=function(bh){return/class="?Mso|style="[^"]*mso-/i.test(bh)};function be(bh){if(/^[\u2022\u00b7\u00a7\u00d8o]\u00a0+/.test(bh)){return"ul"}if(/^\s*\w+[\.\)]\u00a0{2,}/.test(bh)){return"ol"}}function bd(bj){var bt=y.create(document,"div",{innerHTML:bj});var bh=a(g.join(","),bt);var bm=-1,bn,bo={ul:{},ol:{}},bp=bt;for(var bk=0;bk]*>/g,"").replace(/ /g,"\u00a0");var bu=be(bj);if(!bu||y.name(bs)!="p"){if(bs.innerHTML==""){y.remove(bs)}else{bo={ul:{},ol:{}};bp=bt;bm=-1}continue}var br=parseFloat(bs.style.marginLeft||0);var bq=bo[bu][br];if(br>bm||!bq){bq=y.create(document,bu);if(bp==bt){y.insertBefore(bq,bs)}else{bp.appendChild(bq)}bo[bu][br]=bq}if(bn!=bu){for(var bl in bo){for(var bi in bo[bl]){if(a.contains(bq,bo[bl][bi])){delete bo[bl][bi]}}}}y.remove(bs.firstChild);bp=y.create(document,"li",{innerHTML:bs.innerHTML});bq.appendChild(bp);y.remove(bs);bm=br;bn=bu}return bt.innerHTML}function bg(bh){return bh.replace(/]*)>\s*<\/a>/ig,function(bi,bj){if(!bj||bj.indexOf("href")<0){return""}return bi})}this.clean=function(bh){for(var bi=0,bj=bf.length;bi]*"?/ig,"");return bh}}function af(bd){function be(bj){var bk=0,bf=0,bg=0,bi=bj.parentNode;for(var bh=bi.firstChild;bh;bh=bh.nextSibling){if(bh!=bj){if(bh.className=="t-marker"){bg++}else{if(bh.nodeType==3){bk++}else{bf++}}}}if(bg>1&&bi.firstChild.className=="t-marker"&&bi.lastChild.className=="t-marker"){return 0}else{return bf+bk}}this.findSuitable=function(bg,bf){if(!bf&&be(bg)>0){return null}return y.parentOfType(bg,bd[0].tags)};this.findFormat=function(bi){for(var bg=0;bg0){this.activate(bj,bi)}};this.apply=function(bn){var bj=[];for(var bk=0,bl=bn.length;bk0){for(var bj=0,bk=bl.length;bj1){var bj=bk.pop();var bi=bk[bk.length-1];if(bj.previousSibling&&bj.previousSibling.className=="t-marker"){bi.appendChild(bj.previousSibling)}if(bj.tagName==bi.tagName&&bj.previousSibling==bi&&bj.style.cssText==bi.style.cssText){while(bj.firstChild){bi.appendChild(bj.firstChild)}y.remove(bj)}}}}function W(bd,bg){af.call(this,bd);function bf(bq){var bi=bq.attributes,bu=a.trim;if(!bi){return}for(var bm=0,bn=bi.length;bm=0?y.toHex(bv):bv}}}}return}function be(bk){var bh=a(an(bk)?bk.parentNode:bk);var bl=bh.parents().andSelf();for(var bi=0,bj=bl.length;bi'+bk.dataItem.Text+"
              "},highlightFirst:false});bh.data(bg).value("inherit")}}function p(be){a2.call(this,be);var bd=[{tags:["span"]}];this.update=function(bf){bf.data("tColorPicker").close()};this.command=function(bf){return new P(a.extend(bf,{formatter:function(){var bg={};bg[be.domAttr]=bf.value;return new X(bd,{style:bg},be.cssAttr)}}))};this.willDelayExecution=ai;this.init=function(bf,bh){var bg=bh.editor;bf.tColorPicker({selectedColor:"#000000",onChange:function(bi){a2.exec(bg,be.name,bi.value)}})}}function aY(){a2.call(this);var be=[{tags:["span"]}],bd=new W(be,"className");this.command=function(bf){return new P(a.extend(bf,{formatter:function(){return new X(be,{className:bf.value})}}))};this.update=function(bf,bh){var bg=bf.data("tSelectBox");bg.close();bg.value(bd.getFormat(bh))};this.init=function(bf,bh){var bg=bh.editor;bf.tSelectBox({data:bg.style,title:bg.localization.style,onItemCreate:function(bi){var bj=y.inlineStyle(bg.document,"span",{className:bi.dataItem.Value});bi.html=''+bi.html+""},onChange:function(bi){a2.exec(bg,"style",bi.value)}})}}function h(be){function bd(bi,bg){for(var bh=0;bh'+bh.dataItem.Text+""},onChange:function(bh){a2.exec(bf,"formatBlock",bh.value)},highlightFirst:false})}}function aG(bd){q.call(this,bd);this.exec=function(){var bq=this.getRange(),bg=x(bq),bo,bp,bm,bh=a.browser.msie?"":'
              ',bn,bl,bk,bj,br,be="p,h1,h2,h3,h4,h5,h6".split(","),bt=y.parentOfType(bq.startContainer,be),bi=y.parentOfType(bq.endContainer,be),bs=(bt&&!bi)||(!bt&&bi);bq.deleteContents();bl=y.create(bg,"a");bq.insertNode(bl);aC(bl.parentNode);bk=y.parentOfType(bl,["li"]);bj=y.parentOfType(bl,"h1,h2,h3,h4,h5,h6".split(","));if(bk){br=bq.cloneRange();br.selectNode(bk);if(a1(br).length==0){bn=y.create(bg,"p");if(bk.nextSibling){aU(br,bk.parentNode)}y.insertAfter(bn,bk.parentNode);y.remove(bk.parentNode.childNodes.length==1?bk.parentNode:bk);bn.innerHTML=bh;bm=bn}}else{if(bj&&!bl.nextSibling){bn=y.create(bg,"p");y.insertAfter(bn,bj);bn.innerHTML=bh;y.remove(bl);bm=bn}}if(!bm){if(!(bk||bj)){new j([{tags:["p"]}]).apply([bl])}bq.selectNode(bl);bo=y.parentOfType(bl,[bk?"li":bj?y.name(bj):"p"]);aU(bq,bo,bs);bp=bo.previousSibling;if(y.is(bp,"li")&&bp.firstChild&&!y.is(bp.firstChild,"br")){bp=bp.firstChild}bm=bo.nextSibling;if(y.is(bm,"li")&&bm.firstChild&&!y.is(bm.firstChild,"br")){bm=bm.firstChild}y.remove(bo);function bf(bu){if(bu.firstChild&&y.is(bu.firstChild,"br")){y.remove(bu.firstChild)}if(an(bu)&&bu.nodeValue==""){bu=bu.parentNode}if(bu&&!y.is(bu,"img")){while(bu.firstChild&&bu.firstChild.nodeType==1){bu=bu.firstChild}if(bu.innerHTML==""){bu.innerHTML=bh}}}bf(bp);bf(bm);aC(bp)}aC(bm);if(y.is(bm,"img")){bq.setStartBefore(bm)}else{bq.selectNodeContents(bm)}bq.collapse(true);y.scrollTo(bm);aS(bq)}}function aB(bd){q.call(this,bd);this.exec=function(){var bg=this.getRange();bg.deleteContents();var be=y.create(x(bg),"br");bg.insertNode(be);aC(be.parentNode);if(!a.browser.msie&&(!be.nextSibling||y.isWhitespace(be.nextSibling))){var bf=be.cloneNode(true);bf.setAttribute("_moz_dirty","");y.insertAfter(bf,be)}bg.setStartAfter(be);bg.collapse(true);aS(bg)}}function au(bd){var be=[bd=="ul"?"ol":"ul",bd];h.call(this,[{tags:be}]);this.isFormatted=function(bi){var bg=[],bf;for(var bh=0;bh1){y.insertAfter(bh[bh.length-1],bd);y.insertAfter(bh[1],bd);y[bi.length>0?"insertBefore":"insertAfter"](bh[0],bd)}}else{var bg=new ag([{tags:["a"]}],be);bg.finder=this.finder;bg.apply(bi)}}}function a5(bd){bd.formatter={toggle:function(be){new ag([{tags:["a"]}]).remove(a1(be))}};q.call(this,bd)}function ap(bf){q.call(this,bf);var bd;this.async=true;var be=new ar();this.exec=function(){var bn=this.getRange();var bj=bn.collapsed;bn=this.lockRange(true);var bm=a1(bn);var bl=null;var bo=this;function bh(bq){var br=a("#t-editor-link-url",bk.element).val();if(br&&br!="http://"){bd={href:br};var bu=a("#t-editor-link-title",bk.element).val();if(bu){bd.title=bu}var bt=a("#t-editor-link-text",bk.element).val();if(bt!==bl){bd.innerHTML=bt||br}var bs=a("#t-editor-link-target",bk.element).is(":checked");if(bs){bd.target="_blank"}be.apply(bn,bd)}bi(bq);if(bo.change){bo.change()}}function bi(bq){bq.preventDefault();bk.destroy();bc(x(bn)).focus();bo.releaseRange(bn)}var bg=bm.length?be.finder.findSuitable(bm[0]):null;var bp=bm.length<=1||(bm.length==2&&bj);var bk=b.window.create(a.extend({},this.editor.dialogOptions,{title:"Insert link",html:new a.telerik.stringBuilder().cat('
              ').cat("
                ").cat('
              1. ').catIf('
              2. ',bp).cat('
              3. ').cat('
              4. ').cat("
              ").cat('
              ').cat('').cat(" or ").cat('Close').cat("
              ").cat("
              ").string(),onClose:bi})).hide().find(".t-dialog-insert").click(bh).end().find(".t-dialog-close").click(bi).end().find(".t-form-text-row input").keydown(function(bq){if(bq.keyCode==13){bh(bq)}else{if(bq.keyCode==27){bi(bq)}}}).end().find("#t-editor-link-url").val(bg?bg.getAttribute("href",2):"http://").end().find("#t-editor-link-text").val(bm.length>0?(bm.length==1?bm[0].nodeValue:bm[0].nodeValue+bm[1].nodeValue):"").end().find("#t-editor-link-title").val(bg?bg.title:"").end().find("#t-editor-link-target").attr("checked",bg?bg.target=="_blank":false).end().show().data("tWindow").center();if(bp&&bm.length>0){bl=a("#t-editor-link-text",bk.element).val()}a("#t-editor-link-url",bk.element).focus().select()},this.redo=function(){var bg=this.lockRange(true);be.apply(bg,bd);this.releaseRange(bg)}}function a6(bf){a2.call(this,a.extend(bf,{command:a5}));var be=new af([{tags:["a"]}]),bd=this.init;this.init=function(bg,bh){bd.call(this,bg,bh);bg.addClass("t-state-disabled")};this.update=function(bg,bh){bg.toggleClass("t-state-disabled",!be.isFormatted(bh)).removeClass("t-state-hover")}}function Y(bf){q.call(this,bf);this.async=true;var bd;function be(bg,bh){if(bd.src&&bd.src!="http://"){if(!bg){bg=y.create(x(bh),"img",bd);bg.onload=bg.onerror=function(){bg.removeAttribute("complete");bg.removeAttribute("width");bg.removeAttribute("height")};bh.deleteContents();bh.insertNode(bg);bh.setStartAfter(bg);bh.setEndAfter(bg);aS(bh);return true}else{y.attr(bg,bd)}}return false}this.redo=function(){var bg=this.lockRange();if(!be(aL.image(bg),bg)){this.releaseRange(bg)}};this.exec=function(){var bn=this.lockRange();var bh=false;var bm=aL.image(bn);var bo=this;function bi(bq){bd={src:a("#t-editor-image-url",bk.element).val(),alt:a("#t-editor-image-title",bk.element).val()};bh=be(bm,bn);bj(bq);if(bo.change){bo.change()}}function bj(bq){bq.preventDefault();bk.destroy();bc(x(bn)).focus();if(!bh){bo.releaseRange(bn)}}var bl=this.editor.fileBrowser;var bp=bl&&bl.selectUrl!==undefined;function bg(){if(bp){new b.imageBrowser(a(this).find(".t-image-browser"),a.extend(bl,{apply:bi,element:bo.editor.element,localization:bo.editor.localization}))}}var bk=b.window.create(a.extend({width:750},this.editor.dialogOptions,{title:"Insert image",html:new a.telerik.stringBuilder().cat('
              ').catIf('
              ',bp).cat("
                ").cat('
              1. ').cat('
              2. ').cat("
              ").cat('
              ').cat('').cat(" or ").cat('Close').cat("
              ").cat("
              ").string(),onClose:bj,onActivate:bg})).hide().find(".t-dialog-insert").click(bi).end().find(".t-dialog-close").click(bj).end().find(".t-form-text-row input").keydown(function(bq){if(bq.keyCode==13){bi(bq)}else{if(bq.keyCode==27){bj(bq)}}}).end().toggleClass("t-imagebrowser",bp).find("#t-editor-image-url").val(bm?bm.getAttribute("src",2):"http://").end().find("#t-editor-image-title").val(bm?bm.alt:"").end().show().data("tWindow").center();a("#t-editor-image-url",bk.element).focus().select()}}b.selectbox=function(bg,bi){var bk;var bd=a(bg).attr("tabIndex",0);var be=bd.find(".t-input");var bf=this.dropDown=new b.dropDown({effects:b.fx.slide.defaults(),onItemCreate:bi.onItemCreate,onClick:function(bm){bj(bi.data[a(bm.item).index()].Value);bi.onChange({value:bk})}});function bh(){if(!bf.$items){bf.dataBind(bi.data)}}function bl(bm){be.html(bm?bm:" ")}function bj(bo){bh();var bn=-1;for(var bm=0,bp=bi.data.length;bm0?"rtl":"");a(document.documentElement).bind("mousedown",a.proxy(function(bn){var bm=bf.$element;var bo=bm&&bm.parent().length>0;if(bo&&!a.contains(bg,bn.target)&&!a.contains(bm.parent()[0],bn.target)){bf.close()}},this))};a.fn.tSelectBox=function(bd){return b.create(this,{name:"tSelectBox",init:function(be,bf){return new b.selectbox(be,bf)},options:bd})};a.fn.tSelectBox.defaults={effects:b.fx.slide.defaults()};b.colorpicker=function(be,bf){var bg=this;bg.element=be;var bd=a(be);a.extend(bg,bf);bd.attr("tabIndex",0).click(a.proxy(bg.click,bg)).keydown(function(bh){var bj=bg.popup(),bl,bi,bk;if(bh.keyCode==40){if(!bj.is(":visible")){bg.open()}else{bl=bj.find(".t-state-selected");if(bl[0]){bi=bl.next()}else{bi=bj.find("li:first")}if(bi[0]){bl.removeClass("t-state-selected");bi.addClass("t-state-selected")}}bh.preventDefault()}else{if(bh.keyCode==38){if(bj.is(":visible")){bl=bj.find(".t-state-selected");bk=bl.prev();if(bk[0]){bl.removeClass("t-state-selected");bk.addClass("t-state-selected")}}bh.preventDefault()}else{if(bh.keyCode==9||bh.keyCode==39||bh.keyCode==37){bg.close()}else{if(bh.keyCode==13){bj.find(".t-state-selected").click();bh.preventDefault()}}}}}).find("*").attr("unselectable","on");if(a.browser.msie){bd.focus(function(){bd.css("outline","1px dotted #000")}).blur(function(){bd.css("outline","")})}if(bg.selectedColor){bd.find(".t-selected-color").css("background-color",this.selectedColor)}a(be.ownerDocument.documentElement).bind("mousedown",a.proxy(function(bh){if(!a(bh.target).closest(".t-colorpicker-popup").length){this.close()}},bg));b.bind(bg,{change:bg.onChange,load:bg.onLoad})};b.colorpicker.prototype={select:function(bd){if(bd){bd=y.toHex(bd);if(!b.trigger(this.element,"change",{value:bd})){this.value(bd);this.close()}}else{b.trigger(this.element,"change",{value:this.selectedColor})}},open:function(){var be=this.popup();var bd=a(this.element);var bf=bd.offset();bf.top+=bd.outerHeight();if(bd.closest(".t-rtl").length){bf.left-=be.outerWidth()-bd.outerWidth()}var bg="auto";bd.parents().andSelf().each(function(){bg=a(this).css("zIndex");if(Number(bg)){bg=Number(bg)+1;return false}});b.fx._wrap(be).css(a.extend({position:"absolute",zIndex:bg},bf));be.find(".t-item").bind("click",a.proxy(function(bi){var bh=a(bi.currentTarget,bi.target.ownerDocument).find("div").css("background-color");this.select(bh)},this));b.fx.play(this.effects,be,{direction:"bottom"})},close:function(){if(!this.$popup){return}b.fx.rewind(this.effects,this.$popup,{direction:"bottom"},a.proxy(function(){if(this.$popup){y.remove(this.$popup[0].parentNode);this.$popup=null}},this))},toggle:function(){if(!this.$popup||!this.$popup.is(":visible")){this.open()}else{this.close()}},click:function(bd){if(a(bd.target).closest(".t-tool-icon").length>0){this.select()}else{this.toggle()}},value:function(bd){if(!bd){return this.selectedColor}bd=y.toHex(bd);this.selectedColor=bd;a(".t-selected-color",this.element).css("background-color",bd)},popup:function(){if(!this.$popup){this.$popup=a(b.colorpicker.buildPopup(this)).hide().appendTo(document.body).find("*").attr("unselectable","on").end()}return this.$popup}};a.extend(b.colorpicker,{buildPopup:function(bd){var bg=new b.stringBuilder();bg.cat('
              ').cat('
                ');var bf=bd.data;var be=(bd.value()||"").substring(1);for(var bh=0,bi=bf.length;bh
                ')}bg.cat("
              ");return bg.string()}});a.fn.tColorPicker=function(bd){return b.create(this,{name:"tColorPicker",init:function(be,bf){return new b.colorpicker(be,bf)},options:bd})};a.fn.tColorPicker.defaults={data:"000000,7f7f7f,880015,ed1c24,ff7f27,fff200,22b14c,00a2e8,3f48cc,a349a4,ffffff,c3c3c3,b97a57,ffaec9,ffc90e,efe4b0,b5e61d,99d9ea,7092be,c8bfe7".split(","),selectedColor:null,effects:b.fx.slide.defaults()};function Z(bd,bf){var be=y.name(bd)!="td"?"marginLeft":"paddingLeft";if(bf===undefined){return bd.style[be]||0}else{if(bf>0){bd.style[be]=bf+"px"}else{bd.style[be]="";if(bd.style.cssText==""){bd.removeAttribute("style")}}}}function ab(){var bd=new h([{tags:g}]);this.apply=function(bm){var bh=bd.findSuitable(bm);if(bh.length){var bp=[];for(var bj=0;bj1||Z(bk[bg].parentNode)))||(y.ofType(bk[bg],["ul","ol"])&&bi>0)}if(bh){bf.removeClass("t-state-disabled");return}}bf.addClass("t-state-disabled").removeClass("t-state-hover")}}function aH(bd){this.editor=bd;this.formats=[]}aH.prototype={apply:function(bj){if(!this.hasPending()){return}var bh=new az();bh.addCaret(bj);var bd=bj.startContainer.childNodes[bj.startOffset];var bk=bd.previousSibling;if(!bk.nodeValue){bk=bk.previousSibling}bj.setStart(bk,bk.nodeValue.length-1);bh.add(bj);if(a1(bj).length==0){bh.remove(bj);bj.collapse(true);this.editor.selectRange(bj);return}var bl=bh.end.previousSibling.previousSibling;var bi,bf=this.formats;for(var bg=0;bg0},isPending:function(bd){return !!this.getPending(bd)},getPending:function(bd){var be=this.formats;for(var bf=0;bf
               or Close
              ",indent:function(bd){return bd.replace(/<\/(p|li|ul|ol|h[1-6]|table|tr|td|th)>/ig,"\n").replace(/<(ul|ol)([^>]*)>
            • \n/ig,"
              \n").replace(/\n$/,"")}});function s(bd,bh){bd.hide();var bg=a("")}},font:{start:function(bk){bf.push('')},end:function(bi){bf.push("")}}};function bc(bu){var by=[],bl=bu.attributes,bz=a.trim;if(x.is(bu,"iframe")){var bi=a(bu);if(bi.attr("originalsrc")!=""){bi.attr("src",bi.attr("originalsrc"));bi.removeAttr("originalsrc")}}if(x.is(bu,"img")){var bB=bu.style.width,bp=bu.style.height,bi=a(bu);if(bB){bi.attr("width",parseInt(bB));x.unstyle(bu,{width:undefined})}if(bp){bi.attr("height",parseInt(bp));x.unstyle(bu,{height:undefined})}}for(var bq=0,br=bl.length;bqbD.nodeName?1:bC.nodeName=0){bA=x.toHex(bA)}if(bw.indexOf("font")>=0){bA=bA.replace(aH,"'")}bf.push(bw);bf.push(":");bf.push(bA);bf.push(";")}}}else{if(bk=="src"||bk=="href"){bf.push(bu.getAttribute(bk,2))}else{bf.push(E[bk]?bk:bm)}}bf.push('"')}}function be(bj,bk){for(var bi=bj.firstChild;bi;bi=bi.nextSibling){bd(bi,bk)}}function bd(bj,bn){var bk=bj.nodeType;if(bk==1){var bo=x.name(bj);if(bo==""||(bj.attributes._moz_dirty&&x.is(bj,"br"))){return}var bi=bh[bo];if(bi){bi.start(bj);be(bj);bi.end(bj);return}bf.push("<");bf.push(bo);bc(bj);if(z[bo]){bf.push(" />")}else{bf.push(">");be(bj,bn||x.is(bj,"pre"));bf.push("")}}else{if(bk==3){var bp=bj.nodeValue;if(!bn&&a.support.leadingWhitespace){var bl=bj.parentNode;var bm=bj.previousSibling;if(!bm){bm=(x.isInline(bl)?bl:bj).previousSibling}if(!bm||bm.innerHTML==""||x.isBlock(bm)){bp=bp.replace(/^[\r\n\v\f\t ]+/,"")}bp=bp.replace(/ +/," ")}bf.push(x.encode(bp))}else{if(bk==4){bf.push("")}else{if(bk==8){if(bj.data.indexOf("[CDATA[")<0){bf.push("")}else{bf.push("")}}}}}}be(bg);bf=bf.join("");if(bf.replace(m,"").replace(B,"")==""){return""}return bf}var aW=0,aV=1,C=2,D=3;function w(bc){var bd=bc.startContainer;return bd.nodeType==9?bd:bd.ownerDocument}function aQ(bc){if(a.browser.msie&&a.browser.version<9){return new a9(bc.document)}return bc.getSelection()}function aP(bd){var bc=w(bd);return aO(bc)}function aO(bc){return aQ(bb(bc))}function bb(bc){return bc.defaultView||bc.parentWindow}function aT(be,bc,bf){function bd(bi){var bh=be.cloneRange();bh.collapse(bi);bh[bi?"setStartBefore":"setEndAfter"](bc);var bg=bh.extractContents();if(bf){bg=x.trim(bg)}x[bi?"insertBefore":"insertAfter"](bg,bc)}bd(true);bd(false)}function aR(bd){var bc=aK.image(bd);if(bc){bd.setStartAfter(bc);bd.setEndAfter(bc)}var be=aP(bd);be.removeAllRanges();be.addRange(bd)}function a8(bc){a.extend(this,{ownerDocument:bc,startContainer:bc,endContainer:bc,commonAncestorContainer:bc,startOffset:0,endOffset:0,collapsed:true})}a8.prototype={setStart:function(bc,bd){this.startContainer=bc;this.startOffset=bd;a6(this);I(this,true)},setEnd:function(bc,bd){this.endContainer=bc;this.endOffset=bd;a6(this);I(this,false)},setStartBefore:function(bc){this.setStart(bc.parentNode,G(bc))},setStartAfter:function(bc){this.setStart(bc.parentNode,G(bc)+1)},setEndBefore:function(bc){this.setEnd(bc.parentNode,G(bc))},setEndAfter:function(bc){this.setEnd(bc.parentNode,G(bc)+1)},selectNode:function(bc){this.setStartBefore(bc);this.setEndAfter(bc)},selectNodeContents:function(bc){this.setStart(bc,0);this.setEnd(bc,bc[bc.nodeType===1?"childNodes":"nodeValue"].length)},collapse:function(bc){if(bc){this.setEnd(this.startContainer,this.startOffset)}else{this.setStart(this.endContainer,this.endOffset)}},deleteContents:function(){var bd=this.cloneRange();if(this.startContainer!=this.commonAncestorContainer){this.setStartAfter(F(this.commonAncestorContainer,this.startContainer))}this.collapse(true);(function bc(be){while(be.next()){be.hasPartialSubtree()?bc(be.getSubtreeIterator()):be.remove()}})(new aJ(bd))},cloneContents:function(){var bd=w(this);return(function bc(bf){for(var bg,be=bd.createDocumentFragment();bg=bf.next();){bg=bg.cloneNode(!bf.hasPartialSubtree());if(bf.hasPartialSubtree()){bg.appendChild(bc(bf.getSubtreeIterator()))}be.appendChild(bg)}return be})(new aJ(this))},extractContents:function(){var be=this.cloneRange();if(this.startContainer!=this.commonAncestorContainer){this.setStartAfter(F(this.commonAncestorContainer,this.startContainer))}this.collapse(true);var bf=this;var bc=w(this);return(function bd(bh){for(var bi,bg=bc.createDocumentFragment();bi=bh.next();){bh.hasPartialSubtree()?bi=bi.cloneNode(false):bh.remove(bf.originalRange);if(bh.hasPartialSubtree()){bi.appendChild(bd(bh.getSubtreeIterator()))}bg.appendChild(bi)}return bg})(new aJ(be))},insertNode:function(bc){if(am(this.startContainer)){if(this.startOffset!=this.startContainer.nodeValue.length){aU(this.startContainer,this.startOffset)}x.insertAfter(bc,this.startContainer)}else{x.insertAt(this.startContainer,bc,this.startOffset)}this.setStart(this.startContainer,this.startOffset)},cloneRange:function(){return a.extend(new a8(this.ownerDocument),{startContainer:this.startContainer,endContainer:this.endContainer,commonAncestorContainer:this.commonAncestorContainer,startOffset:this.startOffset,endOffset:this.endOffset,collapsed:this.collapsed,originalRange:this})},toString:function(){var bd=this.startContainer.nodeName,bc=this.endContainer.nodeName;return[bd=="#text"?this.startContainer.nodeValue:bd,"(",this.startOffset,") : ",bc=="#text"?this.endContainer.nodeValue:bc,"(",this.endOffset,")"].join("")}};function q(bh,bd,bj,bf){if(bh==bd){return bf-bj}var bc=bd;while(bc&&bc.parentNode!=bh){bc=bc.parentNode}if(bc){return G(bc)-bj}bc=bh;while(bc&&bc.parentNode!=bd){bc=bc.parentNode}if(bc){return bf-G(bc)-1}var bg=x.commonAncestor(bh,bd);var bi=bh;while(bi&&bi.parentNode!=bg){bi=bi.parentNode}if(!bi){bi=bg}var be=bd;while(be&&be.parentNode!=bg){be=be.parentNode}if(!be){be=bg}if(bi==be){return 0}return G(be)-G(bi)}function I(bd,be){function bc(bg){try{return q(bg.startContainer,bg.endContainer,bg.startOffset,bg.endOffset)<0}catch(bf){return true}}if(bc(bd)){if(be){bd.commonAncestorContainer=bd.endContainer=bd.startContainer;bd.endOffset=bd.startOffset}else{bd.commonAncestorContainer=bd.startContainer=bd.endContainer;bd.startOffset=bd.endOffset}bd.collapsed=true}}function a6(bd){bd.collapsed=bd.startContainer==bd.endContainer&&bd.startOffset==bd.endOffset;var bc=bd.startContainer;while(bc&&bc!=bd.endContainer&&!ak(bc,bd.endContainer)){bc=bc.parentNode}bd.commonAncestorContainer=bc}function s(bc){if(a.browser.msie&&a.browser.version<9){return new a8(bc)}return bc.createRange()}function aJ(bc){a.extend(this,{range:bc,_current:null,_next:null,_end:null});if(bc.collapsed){return}var bd=bc.commonAncestorContainer;this._next=bc.startContainer==bd&&!am(bc.startContainer)?bc.startContainer.childNodes[bc.startOffset]:F(bd,bc.startContainer);this._end=bc.endContainer==bd&&!am(bc.endContainer)?bc.endContainer.childNodes[bc.endOffset]:F(bd,bc.endContainer).nextSibling}aJ.prototype={hasNext:function(){return !!this._next},next:function(){var bc=this._current=this._next;this._next=this._current&&this._current.nextSibling!=this._end?this._current.nextSibling:null;if(am(this._current)){if(this.range.endContainer==this._current){(bc=bc.cloneNode(true)).deleteData(this.range.endOffset,bc.length-this.range.endOffset)}if(this.range.startContainer==this._current){(bc=bc.cloneNode(true)).deleteData(0,this.range.startOffset)}}return bc},traverse:function(bc){function be(){this._current=this._next;this._next=this._current&&this._current.nextSibling!=this._end?this._current.nextSibling:null;return this._current}var bd;while(bd=be.call(this)){if(this.hasPartialSubtree()){this.getSubtreeIterator().traverse(bc)}else{bc(bd)}}return bd},remove:function(bh){var bf=this.range.startContainer==this._current;var be=this.range.endContainer==this._current;if(am(this._current)&&(bf||be)){var bj=bf?this.range.startOffset:0;var bd=be?this.range.endOffset:this._current.length;var bc=bd-bj;if(bh&&(bf||be)){if(this._current==bh.startContainer&&bj<=bh.startOffset){bh.startOffset-=bc}if(this._current==bh.endContainer&&bd<=bh.endOffset){bh.endOffset-=bc}}this._current.deleteData(bj,bc)}else{var bi=this._current.parentNode;if(bh&&(this.range.startContainer==bi||this.range.endContainer==bi)){var bg=G(this._current);if(bi==bh.startContainer&&bg<=bh.startOffset){bh.startOffset-=1}if(bi==bh.endContainer&&bg0&&bd.previousSibling);bc.setEndPoint(bg?"EndToStart":"EndToEnd",bi);var bh=bd.nextSibling;if(!bh){bh=bd.previousSibling;if(bh&&am(bh)){bf.setEnd(bh,bh.nodeValue.length);x.remove(bd)}else{bf.selectNodeContents(be);x.remove(bd);bf.endOffset-=1}return}x.remove(bd);if(am(bh)){bf[bg?"setStart":"setEnd"](bh,bc.text.length)}else{bf[bg?"setStartBefore":"setEndBefore"](bh)}}function aI(bc){this.enumerate=function(){var bd=[];function be(bf){if(x.is(bf,"img")||(bf.nodeType==3&&!x.isWhitespace(bf))){bd.push(bf)}else{bf=bf.firstChild;while(bf){be(bf);bf=bf.nextSibling}}}new aJ(bc).traverse(be);return bd}}function a0(bc){return new aI(bc).enumerate()}function k(bg){var bd=[];for(var be=0,bf=bg.length;be'}bh.selectNodeContents(bd)}}bh.collapse(true)};this.add=function(be,bd){if(bd&&be.collapsed){this.addCaret(be);be=aK.expand(be)}var bf=be.cloneRange();bf.collapse(false);this.end=x.create(w(be),"span",{className:"t-marker"});bf.insertNode(this.end);bf=be.cloneRange();bf.collapse(true);this.start=this.end.cloneNode(true);bf.insertNode(this.start);be.setStartBefore(this.start);be.setEndAfter(this.end);aB(be.commonAncestorContainer);return be};this.remove=function(bk){var bn=this.start,bf=this.end;aB(bk.commonAncestorContainer);while(!bn.nextSibling&&bn.parentNode){bn=bn.parentNode}while(!bf.previousSibling&&bf.parentNode){bf=bf.parentNode}var bm=(bn.previousSibling&&bn.previousSibling.nodeType==3)&&(bn.nextSibling&&bn.nextSibling.nodeType==3);var bl=(bf.previousSibling&&bf.previousSibling.nodeType==3)&&(bf.nextSibling&&bf.nextSibling.nodeType==3);bn=bn.nextSibling;bf=bf.previousSibling;var bd=false;var be=false;if(bn==this.end){be=!!this.start.previousSibling;bn=bf=this.start.previousSibling||this.end.nextSibling;bd=true}x.remove(this.start);x.remove(this.end);if(bn==null||bf==null){bk.selectNodeContents(bk.commonAncestorContainer);bk.collapse(true);return}var bp=bd?am(bn)?bn.nodeValue.length:bn.childNodes.length:0;var bh=am(bf)?bf.nodeValue.length:bf.childNodes.length;if(bn.nodeType==3){while(bn.previousSibling&&bn.previousSibling.nodeType==3){bn=bn.previousSibling;bp+=bn.nodeValue.length}}if(bf.nodeType==3){while(bf.previousSibling&&bf.previousSibling.nodeType==3){bf=bf.previousSibling;bh+=bf.nodeValue.length}}var bo=G(bn),bq=bn.parentNode;var bg=G(bf),bi=bf.parentNode;for(var br=bn;br.previousSibling;br=br.previousSibling){if(br.nodeType==3&&br.previousSibling.nodeType==3){bo--}}for(var bj=bf;bj.previousSibling;bj=bj.previousSibling){if(bj.nodeType==3&&bj.previousSibling.nodeType==3){bg--}}aB(bq);if(bn.nodeType==3){bn=bq.childNodes[bo]}aB(bi);if(bf.nodeType==3){bf=bi.childNodes[bg]}if(bd){if(bn.nodeType==3){bk.setStart(bn,bp)}else{bk[be?"setStartAfter":"setStartBefore"](bn)}bk.collapse(true)}else{if(bn.nodeType==3){bk.setStart(bn,bp)}else{bk.setStartBefore(bn)}if(bf.nodeType==3){bk.setEnd(bf,bh)}else{bk.setEndAfter(bf)}}if(bc){this.removeCaret(bk)}}}var l=/[\u0009-\u000d]|\u0020|\u00a0|\ufeff|\.|,|;|:|!|\(|\)|\?/;var aK={nodes:function(bd){var bc=a0(bd);if(!bc.length){bd.selectNodeContents(bd.commonAncestorContainer);bc=a0(bd);if(!bc.length){bc=x.significantChildNodes(bd.commonAncestorContainer)}}return bc},image:function(bd){var bc=[];new aJ(bd).traverse(function(be){if(x.is(be,"img")){bc.push(be)}});if(bc.length==1){return bc[0]}},expand:function(bg){var bh=bg.cloneRange();var bi=bh.startContainer.childNodes[bh.startOffset==0?0:bh.startOffset-1];var be=bh.endContainer.childNodes[bh.endOffset];if(!am(bi)||!am(be)){return bh}var bd=bi.nodeValue;var bc=be.nodeValue;if(bd==""||bc==""){return bh}var bj=bd.split("").reverse().join("").search(l);var bf=bc.search(l);if(bj==0||bf==0){return bh}bf=bf==-1?bc.length:bf;bj=bj==-1?0:bd.length-bj;bh.setStart(bi,bj);bh.setEnd(be,bf);return bh},isExpandable:function(bh){var bg=bh.startContainer;var be=w(bh);if(bg==be||bg==be.body){return false}var bi=bh.cloneRange();var bk=bg.nodeValue;if(!bk){return false}var bd=bk.substring(0,bi.startOffset);var bc=bk.substring(bi.startOffset);var bj=0,bf=0;if(bd!=""){bj=bd.split("").reverse().join("").search(l)}if(bc!=""){bf=bc.search(l)}return bj!=0&&bf!=0}};function p(bd){var be=new aL(bd.range);var bc=new ay();this.formatter=bd.formatter;this.getRange=function(){return be.toRange()};this.lockRange=function(bf){return bc.add(this.getRange(),bf)};this.releaseRange=function(bf){bc.remove(bf);aR(bf)};this.undo=function(){be.body.innerHTML=be.html;aR(be.toRange())};this.redo=function(){this.exec()};this.exec=function(){var bf=this.lockRange(true);this.formatter.editor=this.editor;this.formatter.toggle(bf);this.releaseRange(bf)}}function R(be,bd){var bc=be.body;this.redo=function(){bc.innerHTML=bd.html;aR(bd.toRange())};this.undo=function(){bc.innerHTML=be.html;aR(be.toRange())}}function ai(bc){p.call(this,bc);this.managesUndoRedo=true;this.exec=function(){var bd=this.editor;var be=bd.getRange();var bf=new aL(be);bd.clipboard.paste(bc.value||"");bd.undoRedoStack.push(new R(bf,new aL(bd.getRange())));bd.focus()}}function aj(){a1.call(this);var bc,bd="";this.command=function(be){return new ai(be)};this.update=function(be,bg){var bf=be.data("tSelectBox");bf.close();bf.value(bd)};this.init=function(be,bf){bc=bf.editor;bd=bc.localization.insertHtml;be.tSelectBox({data:bc.insertHtml||[],title:bd,onItemCreate:function(bg){bg.html=''+bg.dataItem.Text+""},onChange:function(bg){a1.exec(bc,"insertHtml",bg.value)},highlightFirst:false}).find(".t-input").html(bc.localization.insertHtml)}}function a3(){var bd=[],bc=-1;this.push=function(be){bd=bd.slice(0,bc+1);bc=bd.push(be)-1};this.undo=function(){if(this.canUndo()){bd[bc--].undo()}};this.redo=function(){if(this.canRedo()){bd[++bc].redo()}};this.canUndo=function(){return bc>=0};this.canRedo=function(){return bc!=bd.length-1}}function a2(bc){this.keydown=function(bd){var bf=bc.keyboard;var be=bf.isTypingKey(bd);if(be&&!bf.typingInProgress()){var bg=bc.getRange();this.startRestorePoint=new aL(bg);bf.startTyping(a.proxy(function(){bc.selectionRestorePoint=this.endRestorePoint=new aL(bc.getRange());bc.undoRedoStack.push(new R(this.startRestorePoint,this.endRestorePoint))},this));return true}return false};this.keyup=function(bd){var be=bc.keyboard;if(be.typingInProgress()){be.endTyping();return true}return false}}function aZ(bc){var bd=false;this.createUndoCommand=function(){this.endRestorePoint=new aL(bc.getRange());bc.undoRedoStack.push(new R(this.startRestorePoint,this.endRestorePoint));this.startRestorePoint=this.endRestorePoint};this.changed=function(){if(this.startRestorePoint){return this.startRestorePoint.html!=bc.body.innerHTML}return false};this.keydown=function(be){var bf=bc.keyboard;if(bf.isModifierKey(be)){if(bf.typingInProgress()){bf.endTyping(true)}this.startRestorePoint=new aL(bc.getRange());return true}if(bf.isSystem(be)){bd=true;if(this.changed()){bd=false;this.createUndoCommand()}return true}return false};this.keyup=function(be){if(bd&&this.changed()){bd=false;this.createUndoCommand(be);return true}return false}}function an(bc){var bi=false;var bh;var bf;function bd(bj){return(bj>=48&&bj<=90)||(bj>=96&&bj<=111)||(bj>=186&&bj<=192)||(bj>=219&&bj<=222)}this.toolFromShortcut=function(bn,bj){var bk=String.fromCharCode(bj.keyCode);for(var bm in bn){var bl=bn[bm];if((bl.key==bk||bl.key==bj.keyCode)&&!!bl.ctrl==bj.ctrlKey&&!!bl.alt==bj.altKey&&!!bl.shift==bj.shiftKey){return bm}}};this.isTypingKey=function(bj){var bk=bj.keyCode;return(bd(bk)&&!bj.ctrlKey&&!bj.altKey)||bk==32||bk==13||bk==8||(bk==46&&!bj.shiftKey&&!bj.ctrlKey&&!bj.altKey)};this.isModifierKey=function(bj){var bk=bj.keyCode;return(bk==17&&!bj.shiftKey&&!bj.altKey)||(bk==16&&!bj.ctrlKey&&!bj.altKey)||(bk==18&&!bj.ctrlKey&&!bj.shiftKey)};this.isSystem=function(bj){return bj.keyCode==46&&bj.ctrlKey&&!bj.altKey&&!bj.shiftKey};this.startTyping=function(bj){bf=bj;bi=true};function bg(){bi=false;if(bf){bf()}}this.endTyping=function(bj){this.clearTimeout();if(bj){bg()}else{bh=window.setTimeout(bg,1000)}};this.typingInProgress=function(){return bi};this.clearTimeout=function(){window.clearTimeout(bh)};function be(bj,bl){for(var bk=0;bk(\s| )*)+(<\/?(div|p|li|col|t))/ig,"$3");bm=bm.replace(/<(a|span)[^>]*><\/\1>/ig,"")}bm=bm.replace(/^
            • $/g,"li>");var bh=bf(bm);var br=bd.getRange();br.deleteContents();if(br.startContainer==bd.document){br.selectNodeContents(bd.body)}var bp=new ay();var bi=bp.addCaret(br);var bq=bg(bh,bi);var bs=false;if(!/body|td/.test(x.name(bq))&&(bh||x.isInline(bq))){br.selectNode(bi);aT(br,bq,true);bs=true}var bk=be(bm);if(bk.firstChild&&bk.firstChild.className==="t-paste-container"){var bl=[];for(bn=0,bo=bk.childNodes.length;bn"))}br.insertNode(bk);bq=bg(bh,bi);if(bs){while(bi.parentNode!=bq){x.unwrap(bi.parentNode)}x.unwrap(bi.parentNode)}aB(br.commonAncestorContainer);bi.style.display="inline";x.scrollTo(bi);bp.removeCaret(br);aR(br)}}function u(){this.applicable=function(bc){return/<(b|i|u|)>/i.test(bc)};this.clean=function(bc){return bc.replace(/<(\/?)b>/gi,"<$1strong>").replace(/<(\/?)>/gi,"<$1em>").replace(//gi,'').replace(/<\/u>/gi,"")}}function aS(){this.applicable=function(bc){return/=0;be--){bc=bh[be];bf=bc.parentNode;if(x.is(bf,"span")&&bf.childNodes.length==1){bf.style.cssText=a.trim(bf.style.cssText+bc.style.cssText);while(bc.firstChild){bf.appendChild(bc.firstChild)}bf.removeChild(bc)}}return bg.innerHTML}}function az(){var be=[/<\?xml[^>]*>/gi,"",//g,"",/"/g,"'",/(?:
               [\s\r\n]+|
              )*(<\/?(h[1-6]|hr|p|div|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|address|pre|form|blockquote|dl|dt|dd|dir|fieldset)[^>]*>)(?:
               [\s\r\n]+|
              )*/g,"$1",/

              /g,"

              ",/
              ( )+\s+/ig," ",/]*)>(\s| )+]*>(\s| )*<\/tr>/gi,"",/]*>(\s| )*<\/tbody>/gi,"",/]*>(\s| )*<\/table>/gi,"",/

              /g,"
              ",/^\s*( )+/gi,"",/( |]*>)+\s*$/gi,"",/mso-[^;"]*;?/ig,"",/<(\/?)b(\s[^>]*)?>/ig,"<$1strong$2>",/<(\/?)i(\s[^>]*)?>/ig,"<$1em$2>",/<\/?(meta|link|style|o:|v:|x:)[^>]*>((?:.|\n)*?<\/(meta|link|style|o:|v:|x:)[^>]*>)?/ig,"",/style=(["|'])\s*\1/g,""];this.applicable=function(bg){return/class="?Mso|style="[^"]*mso-/i.test(bg)};function bd(bg){if(/^[\u2022\u00b7\u00a7\u00d8o]\u00a0+/.test(bg)){return"ul"}if(/^\s*\w+[\.\)]\u00a0{2,}/.test(bg)){return"ol"}}function bc(bi){var bs=x.create(document,"div",{innerHTML:bi});var bg=a(g.join(","),bs);var bl=-1,bm,bn={ul:{},ol:{}},bo=bs;for(var bj=0;bj]*>/g,"").replace(/ /g,"\u00a0");var bt=bd(bi);if(!bt||x.name(br)!="p"){if(br.innerHTML==""){x.remove(br)}else{bn={ul:{},ol:{}};bo=bs;bl=-1}continue}var bq=parseFloat(br.style.marginLeft||0);var bp=bn[bt][bq];if(bq>bl||!bp){bp=x.create(document,bt);if(bo==bs){x.insertBefore(bp,br)}else{bo.appendChild(bp)}bn[bt][bq]=bp}if(bm!=bt){for(var bk in bn){for(var bh in bn[bk]){if(a.contains(bp,bn[bk][bh])){delete bn[bk][bh]}}}}x.remove(br.firstChild);bo=x.create(document,"li",{innerHTML:br.innerHTML});bp.appendChild(bo);x.remove(br);bl=bq;bm=bt}return bs.innerHTML}function bf(bg){return bg.replace(/]*)>\s*<\/a>/ig,function(bh,bi){if(!bi||bi.indexOf("href")<0){return""}return bh})}this.clean=function(bg){for(var bh=0,bi=be.length;bh]*"?/ig,"");return bg}}function ae(bc){function bd(bi){var bj=0,be=0,bf=0,bh=bi.parentNode;for(var bg=bh.firstChild;bg;bg=bg.nextSibling){if(bg!=bi){if(bg.className=="t-marker"){bf++}else{if(bg.nodeType==3){bj++}else{be++}}}}if(bf>1&&bh.firstChild.className=="t-marker"&&bh.lastChild.className=="t-marker"){return 0}else{return be+bj}}this.findSuitable=function(bf,be){if(!be&&bd(bf)>0){return null}return x.parentOfType(bf,bc[0].tags)};this.findFormat=function(bh){for(var bf=0;bf0){this.activate(bi,bh)}};this.apply=function(bm){var bi=[];for(var bj=0,bk=bm.length;bj0){for(var bi=0,bj=bk.length;bi1){var bi=bj.pop();var bh=bj[bj.length-1];if(bi.previousSibling&&bi.previousSibling.className=="t-marker"){bh.appendChild(bi.previousSibling)}if(bi.tagName==bh.tagName&&bi.previousSibling==bh&&bi.style.cssText==bh.style.cssText){while(bi.firstChild){bh.appendChild(bi.firstChild)}x.remove(bi)}}}}function V(bc,bf){ae.call(this,bc);function be(bp){var bh=bp.attributes,bt=a.trim;if(!bh){return}for(var bl=0,bm=bh.length;bl=0?x.toHex(bu):bu}}}}return}function bd(bj){var bg=a(am(bj)?bj.parentNode:bj);var bk=bg.parents().andSelf();for(var bh=0,bi=bk.length;bh'+bj.dataItem.Text+"
              "},highlightFirst:false});bg.data(bf).value("inherit")}}function o(bd){a1.call(this,bd);var bc=[{tags:["span"]}];this.update=function(be){be.data("tColorPicker").close()};this.command=function(be){return new O(a.extend(be,{formatter:function(){var bf={};bf[bd.domAttr]=be.value;return new W(bc,{style:bf},bd.cssAttr)}}))};this.willDelayExecution=ah;this.init=function(be,bg){var bf=bg.editor;be.tColorPicker({selectedColor:"#000000",onChange:function(bh){a1.exec(bf,bd.name,bh.value)}})}}function aX(){a1.call(this);var bd=[{tags:["span"]}],bc=new V(bd,"className");this.command=function(be){return new O(a.extend(be,{formatter:function(){return new W(bd,{className:be.value})}}))};this.update=function(be,bg){var bf=be.data("tSelectBox");bf.close();bf.value(bc.getFormat(bg))};this.init=function(be,bg){var bf=bg.editor;be.tSelectBox({data:bf.style,title:bf.localization.style,onItemCreate:function(bh){var bi=x.inlineStyle(bf.document,"span",{className:bh.dataItem.Value});bh.html=''+bh.html+""},onChange:function(bh){a1.exec(bf,"style",bh.value)}})}}function h(bd){function bc(bh,bf){for(var bg=0;bg'+bg.dataItem.Text+""},onChange:function(bg){a1.exec(be,"formatBlock",bg.value)},highlightFirst:false})}}function aF(bc){p.call(this,bc);this.exec=function(){var bp=this.getRange(),bf=w(bp),bn,bo,bl,bg=a.browser.msie?"":'
              ',bm,bk,bj,bi,bq,bd="p,h1,h2,h3,h4,h5,h6".split(","),bs=x.parentOfType(bp.startContainer,bd),bh=x.parentOfType(bp.endContainer,bd),br=(bs&&!bh)||(!bs&&bh);bp.deleteContents();bk=x.create(bf,"a");bp.insertNode(bk);aB(bk.parentNode);bj=x.parentOfType(bk,["li"]);bi=x.parentOfType(bk,"h1,h2,h3,h4,h5,h6".split(","));if(bj){bq=bp.cloneRange();bq.selectNode(bj);if(a0(bq).length==0){bm=x.create(bf,"p");if(bj.nextSibling){aT(bq,bj.parentNode)}x.insertAfter(bm,bj.parentNode);x.remove(bj.parentNode.childNodes.length==1?bj.parentNode:bj);bm.innerHTML=bg;bl=bm}}else{if(bi&&!bk.nextSibling){bm=x.create(bf,"p");x.insertAfter(bm,bi);bm.innerHTML=bg;x.remove(bk);bl=bm}}if(!bl){if(!(bj||bi)){new i([{tags:["p"]}]).apply([bk])}bp.selectNode(bk);bn=x.parentOfType(bk,[bj?"li":bi?x.name(bi):"p"]);aT(bp,bn,br);bo=bn.previousSibling;if(x.is(bo,"li")&&bo.firstChild&&!x.is(bo.firstChild,"br")){bo=bo.firstChild}bl=bn.nextSibling;if(x.is(bl,"li")&&bl.firstChild&&!x.is(bl.firstChild,"br")){bl=bl.firstChild}x.remove(bn);function be(bt){if(bt.firstChild&&x.is(bt.firstChild,"br")){x.remove(bt.firstChild)}if(am(bt)&&bt.nodeValue==""){bt=bt.parentNode}if(bt&&!x.is(bt,"img")){while(bt.firstChild&&bt.firstChild.nodeType==1){bt=bt.firstChild}if(bt.innerHTML==""){bt.innerHTML=bg}}}be(bo);be(bl);aB(bo)}aB(bl);if(x.is(bl,"img")){bp.setStartBefore(bl)}else{bp.selectNodeContents(bl)}bp.collapse(true);x.scrollTo(bl);aR(bp)}}function aA(bc){p.call(this,bc);this.exec=function(){var bf=this.getRange();bf.deleteContents();var bd=x.create(w(bf),"br");bf.insertNode(bd);aB(bd.parentNode);if(!a.browser.msie&&(!bd.nextSibling||x.isWhitespace(bd.nextSibling))){var be=bd.cloneNode(true);be.setAttribute("_moz_dirty","");x.insertAfter(be,bd)}bf.setStartAfter(bd);bf.collapse(true);aR(bf)}}function at(bc){var bd=[bc=="ul"?"ol":"ul",bc];h.call(this,[{tags:bd}]);this.isFormatted=function(bh){var bf=[],be;for(var bg=0;bg1){x.insertAfter(bg[bg.length-1],bc);x.insertAfter(bg[1],bc);x[bh.length>0?"insertBefore":"insertAfter"](bg[0],bc)}}else{var bf=new af([{tags:["a"]}],bd);bf.finder=this.finder;bf.apply(bh)}}}function a4(bc){bc.formatter={toggle:function(bd){new af([{tags:["a"]}]).remove(a0(bd))}};p.call(this,bc)}function ao(be){p.call(this,be);var bc;this.async=true;var bd=new aq();this.exec=function(){var bm=this.getRange();var bi=bm.collapsed;bm=this.lockRange(true);var bl=a0(bm);var bk=null;var bn=this;function bg(bp){var bq=a("#t-editor-link-url",bj.element).val();if(bq&&bq!="http://"){bc={href:bq};var bt=a("#t-editor-link-title",bj.element).val();if(bt){bc.title=bt}var bs=a("#t-editor-link-text",bj.element).val();if(bs!==bk){bc.innerHTML=bs||bq}var br=a("#t-editor-link-target",bj.element).is(":checked");if(br){bc.target="_blank"}bd.apply(bm,bc)}bh(bp);if(bn.change){bn.change()}}function bh(bp){bp.preventDefault();bj.destroy();bb(w(bm)).focus();bn.releaseRange(bm)}var bf=bl.length?bd.finder.findSuitable(bl[0]):null;var bo=bl.length<=1||(bl.length==2&&bi);var bj=b.window.create(a.extend({},this.editor.dialogOptions,{title:"Insert link",html:new a.telerik.stringBuilder().cat('
              ').cat("
                ").cat('
              1. ').catIf('
              2. ',bo).cat('
              3. ').cat('
              4. ').cat("
              ").cat('
              ').cat('').cat(" or ").cat('Close').cat("
              ").cat("
              ").string(),onClose:bh})).hide().find(".t-dialog-insert").click(bg).end().find(".t-dialog-close").click(bh).end().find(".t-form-text-row input").keydown(function(bp){if(bp.keyCode==13){bg(bp)}else{if(bp.keyCode==27){bh(bp)}}}).end().find("#t-editor-link-url").val(bf?bf.getAttribute("href",2):"http://").end().find("#t-editor-link-text").val(bl.length>0?(bl.length==1?bl[0].nodeValue:bl[0].nodeValue+bl[1].nodeValue):"").end().find("#t-editor-link-title").val(bf?bf.title:"").end().find("#t-editor-link-target").attr("checked",bf?bf.target=="_blank":false).end().show().data("tWindow").center();if(bo&&bl.length>0){bk=a("#t-editor-link-text",bj.element).val()}a("#t-editor-link-url",bj.element).focus().select()},this.redo=function(){var bf=this.lockRange(true);bd.apply(bf,bc);this.releaseRange(bf)}}function a5(be){a1.call(this,a.extend(be,{command:a4}));var bd=new ae([{tags:["a"]}]),bc=this.init;this.init=function(bf,bg){bc.call(this,bf,bg);bf.addClass("t-state-disabled")};this.update=function(bf,bg){bf.toggleClass("t-state-disabled",!bd.isFormatted(bg)).removeClass("t-state-hover")}}function X(be){p.call(this,be);this.async=true;var bc;function bd(bf,bg){if(bc.src&&bc.src!="http://"){if(!bf){bf=x.create(w(bg),"img",bc);bf.onload=bf.onerror=function(){bf.removeAttribute("complete");bf.removeAttribute("width");bf.removeAttribute("height")};bg.deleteContents();bg.insertNode(bf);bg.setStartAfter(bf);bg.setEndAfter(bf);aR(bg);return true}else{x.attr(bf,bc)}}return false}this.redo=function(){var bf=this.lockRange();if(!bd(aK.image(bf),bf)){this.releaseRange(bf)}};this.exec=function(){var bm=this.lockRange();var bg=false;var bl=aK.image(bm);var bn=this;function bh(bp){bc={src:a("#t-editor-image-url",bj.element).val(),alt:a("#t-editor-image-title",bj.element).val()};bg=bd(bl,bm);bi(bp);if(bn.change){bn.change()}}function bi(bp){bp.preventDefault();bj.destroy();bb(w(bm)).focus();if(!bg){bn.releaseRange(bm)}}var bk=this.editor.fileBrowser;var bo=bk&&bk.selectUrl!==undefined;function bf(){if(bo){new b.imageBrowser(a(this).find(".t-image-browser"),a.extend(bk,{apply:bh,element:bn.editor.element,localization:bn.editor.localization}))}}var bj=b.window.create(a.extend({width:750},this.editor.dialogOptions,{title:"Insert image",html:new a.telerik.stringBuilder().cat('
              ').catIf('
              ',bo).cat("
                ").cat('
              1. ').cat('
              2. ').cat("
              ").cat('
              ').cat('').cat(" or ").cat('Close').cat("
              ").cat("
              ").string(),onClose:bi,onActivate:bf})).hide().find(".t-dialog-insert").click(bh).end().find(".t-dialog-close").click(bi).end().find(".t-form-text-row input").keydown(function(bp){if(bp.keyCode==13){bh(bp)}else{if(bp.keyCode==27){bi(bp)}}}).end().toggleClass("t-imagebrowser",bo).find("#t-editor-image-url").val(bl?bl.getAttribute("src",2):"http://").end().find("#t-editor-image-title").val(bl?bl.alt:"").end().show().data("tWindow").center();a("#t-editor-image-url",bj.element).focus().select()}}b.selectbox=function(bf,bh){var bj;var bc=a(bf).attr("tabIndex",0);var bd=bc.find(".t-input");var be=this.dropDown=new b.dropDown({effects:b.fx.slide.defaults(),onItemCreate:bh.onItemCreate,onClick:function(bl){bi(bh.data[a(bl.item).index()].Value);bh.onChange({value:bj})}});function bg(){if(!be.$items){be.dataBind(bh.data)}}function bk(bl){bd.html(bl?bl:" ")}function bi(bn){bg();var bm=-1;for(var bl=0,bo=bh.data.length;bl0?"rtl":"");a(document.documentElement).bind("mousedown",a.proxy(function(bm){var bl=be.$element;var bn=bl&&bl.parent().length>0;if(bn&&!a.contains(bf,bm.target)&&!a.contains(bl.parent()[0],bm.target)){be.close()}},this))};a.fn.tSelectBox=function(bc){return b.create(this,{name:"tSelectBox",init:function(bd,be){return new b.selectbox(bd,be)},options:bc})};a.fn.tSelectBox.defaults={effects:b.fx.slide.defaults()};b.colorpicker=function(bd,be){var bf=this;bf.element=bd;var bc=a(bd);a.extend(bf,be);bc.attr("tabIndex",0).click(a.proxy(bf.click,bf)).keydown(function(bg){var bi=bf.popup(),bk,bh,bj;if(bg.keyCode==40){if(!bi.is(":visible")){bf.open()}else{bk=bi.find(".t-state-selected");if(bk[0]){bh=bk.next()}else{bh=bi.find("li:first")}if(bh[0]){bk.removeClass("t-state-selected");bh.addClass("t-state-selected")}}bg.preventDefault()}else{if(bg.keyCode==38){if(bi.is(":visible")){bk=bi.find(".t-state-selected");bj=bk.prev();if(bj[0]){bk.removeClass("t-state-selected");bj.addClass("t-state-selected")}}bg.preventDefault()}else{if(bg.keyCode==9||bg.keyCode==39||bg.keyCode==37){bf.close()}else{if(bg.keyCode==13){bi.find(".t-state-selected").click();bg.preventDefault()}}}}}).find("*").attr("unselectable","on");if(a.browser.msie){bc.focus(function(){bc.css("outline","1px dotted #000")}).blur(function(){bc.css("outline","")})}if(bf.selectedColor){bc.find(".t-selected-color").css("background-color",this.selectedColor)}a(bd.ownerDocument.documentElement).bind("mousedown",a.proxy(function(bg){if(!a(bg.target).closest(".t-colorpicker-popup").length){this.close()}},bf));b.bind(bf,{change:bf.onChange,load:bf.onLoad})};b.colorpicker.prototype={select:function(bc){if(bc){bc=x.toHex(bc);if(!b.trigger(this.element,"change",{value:bc})){this.value(bc);this.close()}}else{b.trigger(this.element,"change",{value:this.selectedColor})}},open:function(){var bd=this.popup();var bc=a(this.element);var be=bc.offset();be.top+=bc.outerHeight();if(bc.closest(".t-rtl").length){be.left-=bd.outerWidth()-bc.outerWidth()}var bf="auto";bc.parents().andSelf().each(function(){bf=a(this).css("zIndex");if(Number(bf)){bf=Number(bf)+1;return false}});b.fx._wrap(bd).css(a.extend({position:"absolute",zIndex:bf},be));bd.find(".t-item").bind("click",a.proxy(function(bh){var bg=a(bh.currentTarget,bh.target.ownerDocument).find("div").css("background-color");this.select(bg)},this));b.fx.play(this.effects,bd,{direction:"bottom"})},close:function(){if(!this.$popup){return}b.fx.rewind(this.effects,this.$popup,{direction:"bottom"},a.proxy(function(){if(this.$popup){x.remove(this.$popup[0].parentNode);this.$popup=null}},this))},toggle:function(){if(!this.$popup||!this.$popup.is(":visible")){this.open()}else{this.close()}},click:function(bc){if(a(bc.target).closest(".t-tool-icon").length>0){this.select()}else{this.toggle()}},value:function(bc){if(!bc){return this.selectedColor}bc=x.toHex(bc);this.selectedColor=bc;a(".t-selected-color",this.element).css("background-color",bc)},popup:function(){if(!this.$popup){this.$popup=a(b.colorpicker.buildPopup(this)).hide().appendTo(document.body).find("*").attr("unselectable","on").end()}return this.$popup}};a.extend(b.colorpicker,{buildPopup:function(bc){var bf=new b.stringBuilder();bf.cat('
              ').cat('
                ');var be=bc.data;var bd=(bc.value()||"").substring(1);for(var bg=0,bh=be.length;bg
                ')}bf.cat("
              ");return bf.string()}});a.fn.tColorPicker=function(bc){return b.create(this,{name:"tColorPicker",init:function(bd,be){return new b.colorpicker(bd,be)},options:bc})};a.fn.tColorPicker.defaults={data:"000000,7f7f7f,880015,ed1c24,ff7f27,fff200,22b14c,00a2e8,3f48cc,a349a4,ffffff,c3c3c3,b97a57,ffaec9,ffc90e,efe4b0,b5e61d,99d9ea,7092be,c8bfe7".split(","),selectedColor:null,effects:b.fx.slide.defaults()};function Y(bc,be){var bd=x.name(bc)!="td"?"marginLeft":"paddingLeft";if(be===undefined){return bc.style[bd]||0}else{if(be>0){bc.style[bd]=be+"px"}else{bc.style[bd]="";if(bc.style.cssText==""){bc.removeAttribute("style")}}}}function aa(){var bc=new h([{tags:g}]);this.apply=function(bl){var bg=bc.findSuitable(bl);if(bg.length){var bo=[];for(var bi=0;bi1||Y(bj[bf].parentNode)))||(x.ofType(bj[bf],["ul","ol"])&&bh>0)}if(bg){be.removeClass("t-state-disabled");return}}be.addClass("t-state-disabled").removeClass("t-state-hover")}}function aG(bc){this.editor=bc;this.formats=[]}aG.prototype={apply:function(bi){if(!this.hasPending()){return}var bg=new ay();bg.addCaret(bi);var bc=bi.startContainer.childNodes[bi.startOffset];var bj=bc.previousSibling;if(!bj.nodeValue){bj=bj.previousSibling}bi.setStart(bj,bj.nodeValue.length-1);bg.add(bi);if(a0(bi).length==0){bg.remove(bi);bi.collapse(true);this.editor.selectRange(bi);return}var bk=bg.end.previousSibling.previousSibling;var bh,be=this.formats;for(var bf=0;bf0},isPending:function(bc){return !!this.getPending(bc)},getPending:function(bc){var bd=this.formats;for(var be=0;be
               or Close
            • ",indent:function(bc){return bc.replace(/<\/(p|li|ul|ol|h[1-6]|table|tr|td|th)>/ig,"\n").replace(/<(ul|ol)([^>]*)>
            • \n/ig,"
              \n").replace(/\n$/,"")}});function r(bc,bg){bc.hide();var bf=a("',f&&!d(f)).cat("
            • ").catIf("
              ",!g);if(g){a(g).css("display",h.visible?"":"none").html(i.string())}else{delete h.title;return a(i.string()).css("display",h.visible?"":"none").appendTo(document.body).eq(0).tWindow(h)}},getResizeHandlesHtml:function(){var f=new b.stringBuilder();a.each("n e s w se sw ne nw".split(" "),function(g,h){f.cat('
              ')});return f.string()}});a.fn.tWindow=function(f){return b.create(this,{name:"tWindow",init:function(g,h){return new b.window(g,h)},success:function(h){var i=h.element,g=a(i);if(g.is(":visible")){b.trigger(i,"open");b.trigger(i,"activated")}},options:f})};a.fn.tWindow.defaults={effects:{list:[{name:"zoom"},{name:"property",properties:["opacity"]}],openDuration:"fast",closeDuration:"fast"},modal:false,resizable:true,draggable:true,minWidth:50,minHeight:50}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/_references.js b/src/Presentation/SmartStore.Web/Scripts/_references.js index 1293a349f1..54be21233f 100644 Binary files a/src/Presentation/SmartStore.Web/Scripts/_references.js and b/src/Presentation/SmartStore.Web/Scripts/_references.js differ diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.af-ZA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.af-ZA.js deleted file mode 100644 index 094a81f4f3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.af-ZA.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture af-ZA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "af-ZA", "default", { - name: "af-ZA", - englishName: "Afrikaans (South Africa)", - nativeName: "Afrikaans (Suid Afrika)", - language: "af", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Sondag","Maandag","Dinsdag","Woensdag","Donderdag","Vrydag","Saterdag"], - namesAbbr: ["Son","Maan","Dins","Woen","Dond","Vry","Sat"], - namesShort: ["So","Ma","Di","Wo","Do","Vr","Sa"] - }, - months: { - names: ["Januarie","Februarie","Maart","April","Mei","Junie","Julie","Augustus","September","Oktober","November","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.af.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.af.js deleted file mode 100644 index 9ac0407974..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.af.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture af - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "af", "default", { - name: "af", - englishName: "Afrikaans", - nativeName: "Afrikaans", - language: "af", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Sondag","Maandag","Dinsdag","Woensdag","Donderdag","Vrydag","Saterdag"], - namesAbbr: ["Son","Maan","Dins","Woen","Dond","Vry","Sat"], - namesShort: ["So","Ma","Di","Wo","Do","Vr","Sa"] - }, - months: { - names: ["Januarie","Februarie","Maart","April","Mei","Junie","Julie","Augustus","September","Oktober","November","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.am-ET.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.am-ET.js deleted file mode 100644 index 742c209012..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.am-ET.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture am-ET - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "am-ET", "default", { - name: "am-ET", - englishName: "Amharic (Ethiopia)", - nativeName: "አማርኛ (ኢትዮጵያ)", - language: "am", - numberFormat: { - decimals: 1, - groupSizes: [3,0], - "NaN": "NAN", - percent: { - pattern: ["-n%","n%"], - decimals: 1, - groupSizes: [3,0] - }, - currency: { - pattern: ["-$n","$n"], - groupSizes: [3,0], - symbol: "ETB" - } - }, - calendars: { - standard: { - days: { - names: ["እሑድ","ሰኞ","ማክሰኞ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesAbbr: ["እሑድ","ሰኞ","ማክሰ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesShort: ["እ","ሰ","ማ","ረ","ሐ","ዓ","ቅ"] - }, - months: { - names: ["ጃንዩወሪ","ፌብሩወሪ","ማርች","ኤፕረል","ሜይ","ጁን","ጁላይ","ኦገስት","ሴፕቴምበር","ኦክተውበር","ኖቬምበር","ዲሴምበር",""], - namesAbbr: ["ጃንዩ","ፌብሩ","ማርች","ኤፕረ","ሜይ","ጁን","ጁላይ","ኦገስ","ሴፕቴ","ኦክተ","ኖቬም","ዲሴም",""] - }, - AM: ["ጡዋት","ጡዋት","ጡዋት"], - PM: ["ከሰዓት","ከሰዓት","ከሰዓት"], - eras: [{"name":"ዓመተ ምሕረት","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "dddd '፣' MMMM d 'ቀን' yyyy", - f: "dddd '፣' MMMM d 'ቀን' yyyy h:mm tt", - F: "dddd '፣' MMMM d 'ቀን' yyyy h:mm:ss tt", - M: "MMMM d ቀን", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.am.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.am.js deleted file mode 100644 index ad6f9d4f24..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.am.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture am - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "am", "default", { - name: "am", - englishName: "Amharic", - nativeName: "አማርኛ", - language: "am", - numberFormat: { - decimals: 1, - groupSizes: [3,0], - "NaN": "NAN", - percent: { - pattern: ["-n%","n%"], - decimals: 1, - groupSizes: [3,0] - }, - currency: { - pattern: ["-$n","$n"], - groupSizes: [3,0], - symbol: "ETB" - } - }, - calendars: { - standard: { - days: { - names: ["እሑድ","ሰኞ","ማክሰኞ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesAbbr: ["እሑድ","ሰኞ","ማክሰ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesShort: ["እ","ሰ","ማ","ረ","ሐ","ዓ","ቅ"] - }, - months: { - names: ["ጃንዩወሪ","ፌብሩወሪ","ማርች","ኤፕረል","ሜይ","ጁን","ጁላይ","ኦገስት","ሴፕቴምበር","ኦክተውበር","ኖቬምበር","ዲሴምበር",""], - namesAbbr: ["ጃንዩ","ፌብሩ","ማርች","ኤፕረ","ሜይ","ጁን","ጁላይ","ኦገስ","ሴፕቴ","ኦክተ","ኖቬም","ዲሴም",""] - }, - AM: ["ጡዋት","ጡዋት","ጡዋት"], - PM: ["ከሰዓት","ከሰዓት","ከሰዓት"], - eras: [{"name":"ዓመተ ምሕረት","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "dddd '፣' MMMM d 'ቀን' yyyy", - f: "dddd '፣' MMMM d 'ቀን' yyyy h:mm tt", - F: "dddd '፣' MMMM d 'ቀን' yyyy h:mm:ss tt", - M: "MMMM d ቀን", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-OM.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-OM.js deleted file mode 100644 index 6b184a1e78..0000000000 Binary files a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-OM.js and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-QA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-QA.js deleted file mode 100644 index dfa405e1bd..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-QA.js +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Globalize Culture ar-QA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ar-QA", "default", { - name: "ar-QA", - englishName: "Arabic (Qatar)", - nativeName: "العربية (قطر)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ر.ق.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-SA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-SA.js deleted file mode 100644 index cba34f69b6..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-SA.js +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Globalize Culture ar-SA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ar-SA", "default", { - name: "ar-SA", - englishName: "Arabic (Saudi Arabia)", - nativeName: "العربية (المملكة العربية السعودية)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ر.س.\u200f" - } - }, - calendars: { - standard: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-SY.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-SY.js deleted file mode 100644 index d75faa6946..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-SY.js +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Globalize Culture ar-SY - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ar-SY", "default", { - name: "ar-SY", - englishName: "Arabic (Syria)", - nativeName: "العربية (سوريا)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ل.س.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-TN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-TN.js deleted file mode 100644 index d7614ada2c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-TN.js +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Globalize Culture ar-TN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ar-TN", "default", { - name: "ar-TN", - englishName: "Arabic (Tunisia)", - nativeName: "العربية (تونس)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - decimals: 3, - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - percent: { - decimals: 3 - }, - currency: { - pattern: ["$n-","$ n"], - decimals: 3, - symbol: "د.ت.\u200f" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MM/yyyy H:mm", - F: "dd/MM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MMMM/yyyy H:mm", - F: "dd/MMMM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-YE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar-YE.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ar.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.arn-CL.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.arn-CL.js deleted file mode 100644 index b898ab344a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.arn-CL.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture arn-CL - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "arn-CL", "default", { - name: "arn-CL", - englishName: "Mapudungun (Chile)", - nativeName: "Mapudungun (Chile)", - language: "arn", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.arn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.arn.js deleted file mode 100644 index b27f5d554e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.arn.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture arn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "arn", "default", { - name: "arn", - englishName: "Mapudungun", - nativeName: "Mapudungun", - language: "arn", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.as-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.as-IN.js deleted file mode 100644 index fe97442858..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.as-IN.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture as-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "as-IN", "default", { - name: "as-IN", - englishName: "Assamese (India)", - nativeName: "অসমীয়া (ভাৰত)", - language: "as", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","n$"], - groupSizes: [3,2], - symbol: "ট" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["সোমবাৰ","মঙ্গলবাৰ","বুধবাৰ","বৃহস্পতিবাৰ","শুক্রবাৰ","শনিবাৰ","ৰবিবাৰ"], - namesAbbr: ["সোম.","মঙ্গল.","বুধ.","বৃহ.","শুক্র.","শনি.","ৰবি."], - namesShort: ["সো","ম","বু","বৃ","শু","শ","র"] - }, - months: { - names: ["জানুৱাৰী","ফেব্রুৱাৰী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টেম্বর","অক্টোবর","নবেম্বর","ডিচেম্বর",""], - namesAbbr: ["জানু","ফেব্রু","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টে","অক্টো","নবে","ডিচে",""] - }, - AM: ["ৰাতিপু","ৰাতিপু","ৰাতিপু"], - PM: ["আবেলি","আবেলি","আবেলি"], - eras: [{"name":"খ্রীষ্টাব্দ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "yyyy,MMMM dd, dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy,MMMM dd, dddd tt h:mm", - F: "yyyy,MMMM dd, dddd tt h:mm:ss", - M: "dd MMMM", - Y: "MMMM,yy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.as.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.as.js deleted file mode 100644 index 5577f8ba67..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.as.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture as - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "as", "default", { - name: "as", - englishName: "Assamese", - nativeName: "অসমীয়া", - language: "as", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","n$"], - groupSizes: [3,2], - symbol: "ট" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["সোমবাৰ","মঙ্গলবাৰ","বুধবাৰ","বৃহস্পতিবাৰ","শুক্রবাৰ","শনিবাৰ","ৰবিবাৰ"], - namesAbbr: ["সোম.","মঙ্গল.","বুধ.","বৃহ.","শুক্র.","শনি.","ৰবি."], - namesShort: ["সো","ম","বু","বৃ","শু","শ","র"] - }, - months: { - names: ["জানুৱাৰী","ফেব্রুৱাৰী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টেম্বর","অক্টোবর","নবেম্বর","ডিচেম্বর",""], - namesAbbr: ["জানু","ফেব্রু","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টে","অক্টো","নবে","ডিচে",""] - }, - AM: ["ৰাতিপু","ৰাতিপু","ৰাতিপু"], - PM: ["আবেলি","আবেলি","আবেলি"], - eras: [{"name":"খ্রীষ্টাব্দ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "yyyy,MMMM dd, dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy,MMMM dd, dddd tt h:mm", - F: "yyyy,MMMM dd, dddd tt h:mm:ss", - M: "dd MMMM", - Y: "MMMM,yy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Cyrl-AZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Cyrl-AZ.js deleted file mode 100644 index 71164b4ddf..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Cyrl-AZ.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture az-Cyrl-AZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "az-Cyrl-AZ", "default", { - name: "az-Cyrl-AZ", - englishName: "Azeri (Cyrillic, Azerbaijan)", - nativeName: "Азәрбајҹан (Азәрбајҹан)", - language: "az-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "ман." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Базар","Базар ертәси","Чәршәнбә ахшамы","Чәршәнбә","Ҹүмә ахшамы","Ҹүмә","Шәнбә"], - namesAbbr: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"], - namesShort: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"] - }, - months: { - names: ["Јанвар","Феврал","Март","Апрел","Мај","Ијун","Ијул","Август","Сентјабр","Октјабр","Нојабр","Декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","Мај","Ијун","Ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["јанвар","феврал","март","апрел","мај","ијун","ијул","август","сентјабр","октјабр","нојабр","декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","мая","ијун","ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Cyrl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Cyrl.js deleted file mode 100644 index 592835629d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Cyrl.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture az-Cyrl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "az-Cyrl", "default", { - name: "az-Cyrl", - englishName: "Azeri (Cyrillic)", - nativeName: "Азәрбајҹан дили", - language: "az-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "ман." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Базар","Базар ертәси","Чәршәнбә ахшамы","Чәршәнбә","Ҹүмә ахшамы","Ҹүмә","Шәнбә"], - namesAbbr: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"], - namesShort: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"] - }, - months: { - names: ["Јанвар","Феврал","Март","Апрел","Мај","Ијун","Ијул","Август","Сентјабр","Октјабр","Нојабр","Декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","Мај","Ијун","Ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["јанвар","феврал","март","апрел","мај","ијун","ијул","август","сентјабр","октјабр","нојабр","декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","мая","ијун","ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Latn-AZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Latn-AZ.js deleted file mode 100644 index 200848e474..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Latn-AZ.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture az-Latn-AZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "az-Latn-AZ", "default", { - name: "az-Latn-AZ", - englishName: "Azeri (Latin, Azerbaijan)", - nativeName: "Azərbaycan\xadılı (Azərbaycan)", - language: "az-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "man." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"], - namesAbbr: ["B","Be","Ça","Ç","Ca","C","Ş"], - namesShort: ["B","Be","Ça","Ç","Ca","C","Ş"] - }, - months: { - names: ["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avgust","Sentyabr","Oktyabr","Noyabr","Dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - monthsGenitive: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Latn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Latn.js deleted file mode 100644 index c4e80c72a3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az-Latn.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture az-Latn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "az-Latn", "default", { - name: "az-Latn", - englishName: "Azeri (Latin)", - nativeName: "Azərbaycan\xadılı", - language: "az-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "man." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"], - namesAbbr: ["B","Be","Ça","Ç","Ca","C","Ş"], - namesShort: ["B","Be","Ça","Ç","Ca","C","Ş"] - }, - months: { - names: ["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avgust","Sentyabr","Oktyabr","Noyabr","Dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - monthsGenitive: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az.js deleted file mode 100644 index 7a5e5ec3b3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.az.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture az - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "az", "default", { - name: "az", - englishName: "Azeri", - nativeName: "Azərbaycan\xadılı", - language: "az", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "man." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"], - namesAbbr: ["B","Be","Ça","Ç","Ca","C","Ş"], - namesShort: ["B","Be","Ça","Ç","Ca","C","Ş"] - }, - months: { - names: ["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avgust","Sentyabr","Oktyabr","Noyabr","Dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - monthsGenitive: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ba-RU.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ba-RU.js deleted file mode 100644 index 4b81713aa9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ba-RU.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture ba-RU - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ba-RU", "default", { - name: "ba-RU", - englishName: "Bashkir (Russia)", - nativeName: "Башҡорт (Россия)", - language: "ba", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ",", - symbol: "һ." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Йәкшәмбе","Дүшәмбе","Шишәмбе","Шаршамбы","Кесаҙна","Йома","Шәмбе"], - namesAbbr: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"], - namesShort: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"] - }, - months: { - names: ["ғинуар","февраль","март","апрель","май","июнь","июль","август","сентябрь","октябрь","ноябрь","декабрь",""], - namesAbbr: ["ғин","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy 'й'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'й' H:mm", - F: "d MMMM yyyy 'й' H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ba.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ba.js deleted file mode 100644 index a665f66c8b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ba.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture ba - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ba", "default", { - name: "ba", - englishName: "Bashkir", - nativeName: "Башҡорт", - language: "ba", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ",", - symbol: "һ." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Йәкшәмбе","Дүшәмбе","Шишәмбе","Шаршамбы","Кесаҙна","Йома","Шәмбе"], - namesAbbr: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"], - namesShort: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"] - }, - months: { - names: ["ғинуар","февраль","март","апрель","май","июнь","июль","август","сентябрь","октябрь","ноябрь","декабрь",""], - namesAbbr: ["ғин","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy 'й'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'й' H:mm", - F: "d MMMM yyyy 'й' H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.be-BY.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.be-BY.js deleted file mode 100644 index 855695aa1e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.be-BY.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture be-BY - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "be-BY", "default", { - name: "be-BY", - englishName: "Belarusian (Belarus)", - nativeName: "Беларускі (Беларусь)", - language: "be", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["нядзеля","панядзелак","аўторак","серада","чацвер","пятніца","субота"], - namesAbbr: ["нд","пн","аў","ср","чц","пт","сб"], - namesShort: ["нд","пн","аў","ср","чц","пт","сб"] - }, - months: { - names: ["Студзень","Люты","Сакавік","Красавік","Май","Чэрвень","Ліпень","Жнівень","Верасень","Кастрычнік","Лістапад","Снежань",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - monthsGenitive: { - names: ["студзеня","лютага","сакавіка","красавіка","мая","чэрвеня","ліпеня","жніўня","верасня","кастрычніка","лістапада","снежня",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.be.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.be.js deleted file mode 100644 index 3db61d9fbb..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.be.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture be - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "be", "default", { - name: "be", - englishName: "Belarusian", - nativeName: "Беларускі", - language: "be", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["нядзеля","панядзелак","аўторак","серада","чацвер","пятніца","субота"], - namesAbbr: ["нд","пн","аў","ср","чц","пт","сб"], - namesShort: ["нд","пн","аў","ср","чц","пт","сб"] - }, - months: { - names: ["Студзень","Люты","Сакавік","Красавік","Май","Чэрвень","Ліпень","Жнівень","Верасень","Кастрычнік","Лістапад","Снежань",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - monthsGenitive: { - names: ["студзеня","лютага","сакавіка","красавіка","мая","чэрвеня","ліпеня","жніўня","верасня","кастрычніка","лістапада","снежня",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bg-BG.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bg-BG.js deleted file mode 100644 index 0de7452f6e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bg-BG.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture bg-BG - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bg-BG", "default", { - name: "bg-BG", - englishName: "Bulgarian (Bulgaria)", - nativeName: "български (България)", - language: "bg", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "- безкрайност", - positiveInfinity: "+ безкрайност", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "лв." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["неделя","понеделник","вторник","сряда","четвъртък","петък","събота"], - namesAbbr: ["нед","пон","вт","ср","четв","пет","съб"], - namesShort: ["н","п","в","с","ч","п","с"] - }, - months: { - names: ["януари","февруари","март","април","май","юни","юли","август","септември","октомври","ноември","декември",""], - namesAbbr: ["ян","февр","март","апр","май","юни","юли","авг","септ","окт","ноември","дек",""] - }, - AM: null, - PM: null, - eras: [{"name":"след новата ера","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy 'г.'", - D: "dd MMMM yyyy 'г.'", - t: "HH:mm 'ч.'", - T: "HH:mm:ss 'ч.'", - f: "dd MMMM yyyy 'г.' HH:mm 'ч.'", - F: "dd MMMM yyyy 'г.' HH:mm:ss 'ч.'", - M: "dd MMMM", - Y: "MMMM yyyy 'г.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bg.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bg.js deleted file mode 100644 index b87a9e5806..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bg.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture bg - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bg", "default", { - name: "bg", - englishName: "Bulgarian", - nativeName: "български", - language: "bg", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "- безкрайност", - positiveInfinity: "+ безкрайност", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "лв." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["неделя","понеделник","вторник","сряда","четвъртък","петък","събота"], - namesAbbr: ["нед","пон","вт","ср","четв","пет","съб"], - namesShort: ["н","п","в","с","ч","п","с"] - }, - months: { - names: ["януари","февруари","март","април","май","юни","юли","август","септември","октомври","ноември","декември",""], - namesAbbr: ["ян","февр","март","апр","май","юни","юли","авг","септ","окт","ноември","дек",""] - }, - AM: null, - PM: null, - eras: [{"name":"след новата ера","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy 'г.'", - D: "dd MMMM yyyy 'г.'", - t: "HH:mm 'ч.'", - T: "HH:mm:ss 'ч.'", - f: "dd MMMM yyyy 'г.' HH:mm 'ч.'", - F: "dd MMMM yyyy 'г.' HH:mm:ss 'ч.'", - M: "dd MMMM", - Y: "MMMM yyyy 'г.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn-BD.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn-BD.js deleted file mode 100644 index cc627097f6..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn-BD.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture bn-BD - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bn-BD", "default", { - name: "bn-BD", - englishName: "Bengali (Bangladesh)", - nativeName: "বাংলা (বাংলাদেশ)", - language: "bn", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "৳" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], - namesAbbr: ["রবি.","সোম.","মঙ্গল.","বুধ.","বৃহস্পতি.","শুক্র.","শনি."], - namesShort: ["র","স","ম","ব","ব","শ","শ"] - }, - months: { - names: ["জানুয়ারী","ফেব্রুয়ারী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর",""], - namesAbbr: ["জানু.","ফেব্রু.","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগ.","সেপ্টে.","অক্টো.","নভে.","ডিসে.",""] - }, - AM: ["পুর্বাহ্ন","পুর্বাহ্ন","পুর্বাহ্ন"], - PM: ["অপরাহ্ন","অপরাহ্ন","অপরাহ্ন"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn-IN.js deleted file mode 100644 index 260129162a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn-IN.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture bn-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bn-IN", "default", { - name: "bn-IN", - englishName: "Bengali (India)", - nativeName: "বাংলা (ভারত)", - language: "bn", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "টা" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], - namesAbbr: ["রবি.","সোম.","মঙ্গল.","বুধ.","বৃহস্পতি.","শুক্র.","শনি."], - namesShort: ["র","স","ম","ব","ব","শ","শ"] - }, - months: { - names: ["জানুয়ারী","ফেব্রুয়ারী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর",""], - namesAbbr: ["জানু.","ফেব্রু.","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগ.","সেপ্টে.","অক্টো.","নভে.","ডিসে.",""] - }, - AM: ["পুর্বাহ্ন","পুর্বাহ্ন","পুর্বাহ্ন"], - PM: ["অপরাহ্ন","অপরাহ্ন","অপরাহ্ন"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn.js deleted file mode 100644 index 82ce2703a3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bn.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture bn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bn", "default", { - name: "bn", - englishName: "Bengali", - nativeName: "বাংলা", - language: "bn", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "টা" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], - namesAbbr: ["রবি.","সোম.","মঙ্গল.","বুধ.","বৃহস্পতি.","শুক্র.","শনি."], - namesShort: ["র","স","ম","ব","ব","শ","শ"] - }, - months: { - names: ["জানুয়ারী","ফেব্রুয়ারী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর",""], - namesAbbr: ["জানু.","ফেব্রু.","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগ.","সেপ্টে.","অক্টো.","নভে.","ডিসে.",""] - }, - AM: ["পুর্বাহ্ন","পুর্বাহ্ন","পুর্বাহ্ন"], - PM: ["অপরাহ্ন","অপরাহ্ন","অপরাহ্ন"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bo-CN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bo-CN.js deleted file mode 100644 index b173a24931..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bo-CN.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture bo-CN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bo-CN", "default", { - name: "bo-CN", - englishName: "Tibetan (PRC)", - nativeName: "བོད་ཡིག (ཀྲུང་ཧྭ་མི་དམངས་སྤྱི་མཐུན་རྒྱལ་ཁབ།)", - language: "bo", - numberFormat: { - groupSizes: [3,0], - "NaN": "ཨང་ཀི་མིན་པ།", - negativeInfinity: "མོ་གྲངས་ཚད་མེད་ཆུང་བ།", - positiveInfinity: "ཕོ་གྲངས་ཚད་མེད་ཆེ་བ།", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["གཟའ་ཉི་མ།","གཟའ་ཟླ་བ།","གཟའ་མིག་དམར།","གཟའ་ལྷག་པ།","གཟའ་ཕུར་བུ།","གཟའ་པ་སངས།","གཟའ་སྤེན་པ།"], - namesAbbr: ["ཉི་མ།","ཟླ་བ།","མིག་དམར།","ལྷག་པ།","ཕུར་བུ།","པ་སངས།","སྤེན་པ།"], - namesShort: ["༧","༡","༢","༣","༤","༥","༦"] - }, - months: { - names: ["སྤྱི་ཟླ་དང་པོ།","སྤྱི་ཟླ་གཉིས་པ།","སྤྱི་ཟླ་གསུམ་པ།","སྤྱི་ཟླ་བཞི་པ།","སྤྱི་ཟླ་ལྔ་པ།","སྤྱི་ཟླ་དྲུག་པ།","སྤྱི་ཟླ་བདུན་པ།","སྤྱི་ཟླ་བརྒྱད་པ།","སྤྱི་ཟླ་དགུ་པ།","སྤྱི་ཟླ་བཅུ་པོ།","སྤྱི་ཟླ་བཅུ་གཅིག་པ།","སྤྱི་ཟླ་བཅུ་གཉིས་པ།",""], - namesAbbr: ["ཟླ་ ༡","ཟླ་ ༢","ཟླ་ ༣","ཟླ་ ༤","ཟླ་ ༥","ཟླ་ ༦","ཟླ་ ༧","ཟླ་ ༨","ཟླ་ ༩","ཟླ་ ༡༠","ཟླ་ ༡༡","ཟླ་ ༡༢",""] - }, - AM: ["སྔ་དྲོ","སྔ་དྲོ","སྔ་དྲོ"], - PM: ["ཕྱི་དྲོ","ཕྱི་དྲོ","ཕྱི་དྲོ"], - eras: [{"name":"སྤྱི་ལོ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ལོའི་ཟླ' M'ཚེས' d", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm", - F: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm:ss", - M: "'ཟླ་' M'ཚེས'd", - Y: "yyyy.M" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bo.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bo.js deleted file mode 100644 index 96f0caabfe..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bo.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture bo - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bo", "default", { - name: "bo", - englishName: "Tibetan", - nativeName: "བོད་ཡིག", - language: "bo", - numberFormat: { - groupSizes: [3,0], - "NaN": "ཨང་ཀི་མིན་པ།", - negativeInfinity: "མོ་གྲངས་ཚད་མེད་ཆུང་བ།", - positiveInfinity: "ཕོ་གྲངས་ཚད་མེད་ཆེ་བ།", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["གཟའ་ཉི་མ།","གཟའ་ཟླ་བ།","གཟའ་མིག་དམར།","གཟའ་ལྷག་པ།","གཟའ་ཕུར་བུ།","གཟའ་པ་སངས།","གཟའ་སྤེན་པ།"], - namesAbbr: ["ཉི་མ།","ཟླ་བ།","མིག་དམར།","ལྷག་པ།","ཕུར་བུ།","པ་སངས།","སྤེན་པ།"], - namesShort: ["༧","༡","༢","༣","༤","༥","༦"] - }, - months: { - names: ["སྤྱི་ཟླ་དང་པོ།","སྤྱི་ཟླ་གཉིས་པ།","སྤྱི་ཟླ་གསུམ་པ།","སྤྱི་ཟླ་བཞི་པ།","སྤྱི་ཟླ་ལྔ་པ།","སྤྱི་ཟླ་དྲུག་པ།","སྤྱི་ཟླ་བདུན་པ།","སྤྱི་ཟླ་བརྒྱད་པ།","སྤྱི་ཟླ་དགུ་པ།","སྤྱི་ཟླ་བཅུ་པོ།","སྤྱི་ཟླ་བཅུ་གཅིག་པ།","སྤྱི་ཟླ་བཅུ་གཉིས་པ།",""], - namesAbbr: ["ཟླ་ ༡","ཟླ་ ༢","ཟླ་ ༣","ཟླ་ ༤","ཟླ་ ༥","ཟླ་ ༦","ཟླ་ ༧","ཟླ་ ༨","ཟླ་ ༩","ཟླ་ ༡༠","ཟླ་ ༡༡","ཟླ་ ༡༢",""] - }, - AM: ["སྔ་དྲོ","སྔ་དྲོ","སྔ་དྲོ"], - PM: ["ཕྱི་དྲོ","ཕྱི་དྲོ","ཕྱི་དྲོ"], - eras: [{"name":"སྤྱི་ལོ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ལོའི་ཟླ' M'ཚེས' d", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm", - F: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm:ss", - M: "'ཟླ་' M'ཚེས'd", - Y: "yyyy.M" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.br-FR.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.br-FR.js deleted file mode 100644 index 37bf5056bb..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.br-FR.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture br-FR - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "br-FR", "default", { - name: "br-FR", - englishName: "Breton (France)", - nativeName: "brezhoneg (Frañs)", - language: "br", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NkN", - negativeInfinity: "-Anfin", - positiveInfinity: "+Anfin", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sul","Lun","Meurzh","Merc'her","Yaou","Gwener","Sadorn"], - namesAbbr: ["Sul","Lun","Meu.","Mer.","Yaou","Gwe.","Sad."], - namesShort: ["Su","Lu","Mz","Mc","Ya","Gw","Sa"] - }, - months: { - names: ["Genver","C'hwevrer","Meurzh","Ebrel","Mae","Mezheven","Gouere","Eost","Gwengolo","Here","Du","Kerzu",""], - namesAbbr: ["Gen.","C'hwe.","Meur.","Ebr.","Mae","Mezh.","Goue.","Eost","Gwen.","Here","Du","Kzu",""] - }, - AM: null, - PM: null, - eras: [{"name":"g. J.-K.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.br.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.br.js deleted file mode 100644 index 29dd176829..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.br.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture br - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "br", "default", { - name: "br", - englishName: "Breton", - nativeName: "brezhoneg", - language: "br", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NkN", - negativeInfinity: "-Anfin", - positiveInfinity: "+Anfin", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sul","Lun","Meurzh","Merc'her","Yaou","Gwener","Sadorn"], - namesAbbr: ["Sul","Lun","Meu.","Mer.","Yaou","Gwe.","Sad."], - namesShort: ["Su","Lu","Mz","Mc","Ya","Gw","Sa"] - }, - months: { - names: ["Genver","C'hwevrer","Meurzh","Ebrel","Mae","Mezheven","Gouere","Eost","Gwengolo","Here","Du","Kerzu",""], - namesAbbr: ["Gen.","C'hwe.","Meur.","Ebr.","Mae","Mezh.","Goue.","Eost","Gwen.","Here","Du","Kzu",""] - }, - AM: null, - PM: null, - eras: [{"name":"g. J.-K.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Cyrl-BA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Cyrl-BA.js deleted file mode 100644 index e525510898..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Cyrl-BA.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture bs-Cyrl-BA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bs-Cyrl-BA", "default", { - name: "bs-Cyrl-BA", - englishName: "Bosnian (Cyrillic, Bosnia and Herzegovina)", - nativeName: "босански (Босна и Херцеговина)", - language: "bs-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "КМ" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недјеља","понедјељак","уторак","сриједа","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["н","п","у","с","ч","п","с"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Cyrl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Cyrl.js deleted file mode 100644 index 8920d40087..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Cyrl.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture bs-Cyrl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bs-Cyrl", "default", { - name: "bs-Cyrl", - englishName: "Bosnian (Cyrillic)", - nativeName: "босански", - language: "bs-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "КМ" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недјеља","понедјељак","уторак","сриједа","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["н","п","у","с","ч","п","с"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Latn-BA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Latn-BA.js deleted file mode 100644 index e02bb96257..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Latn-BA.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture bs-Latn-BA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bs-Latn-BA", "default", { - name: "bs-Latn-BA", - englishName: "Bosnian (Latin, Bosnia and Herzegovina)", - nativeName: "bosanski (Bosna i Hercegovina)", - language: "bs-Latn", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","juni","juli","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Latn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Latn.js deleted file mode 100644 index 3692487f95..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs-Latn.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture bs-Latn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bs-Latn", "default", { - name: "bs-Latn", - englishName: "Bosnian (Latin)", - nativeName: "bosanski", - language: "bs-Latn", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","juni","juli","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs.js deleted file mode 100644 index 0deadc93c9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.bs.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture bs - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "bs", "default", { - name: "bs", - englishName: "Bosnian", - nativeName: "bosanski", - language: "bs", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","juni","juli","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.co-FR.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.co-FR.js deleted file mode 100644 index 7d6ef38158..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.co-FR.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture co-FR - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "co-FR", "default", { - name: "co-FR", - englishName: "Corsican (France)", - nativeName: "Corsu (France)", - language: "co", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Mica numericu", - negativeInfinity: "-Infinitu", - positiveInfinity: "+Infinitu", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumenica","luni","marti","mercuri","ghjovi","venderi","sabbatu"], - namesAbbr: ["dum.","lun.","mar.","mer.","ghj.","ven.","sab."], - namesShort: ["du","lu","ma","me","gh","ve","sa"] - }, - months: { - names: ["ghjennaghju","ferraghju","marzu","aprile","maghju","ghjunghju","lugliu","aostu","settembre","ottobre","nuvembre","dicembre",""], - namesAbbr: ["ghje","ferr","marz","apri","magh","ghju","lugl","aost","sett","otto","nuve","dice",""] - }, - AM: null, - PM: null, - eras: [{"name":"dopu J-C","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.co.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.co.js deleted file mode 100644 index a4535aad8c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.co.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture co - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "co", "default", { - name: "co", - englishName: "Corsican", - nativeName: "Corsu", - language: "co", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Mica numericu", - negativeInfinity: "-Infinitu", - positiveInfinity: "+Infinitu", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumenica","luni","marti","mercuri","ghjovi","venderi","sabbatu"], - namesAbbr: ["dum.","lun.","mar.","mer.","ghj.","ven.","sab."], - namesShort: ["du","lu","ma","me","gh","ve","sa"] - }, - months: { - names: ["ghjennaghju","ferraghju","marzu","aprile","maghju","ghjunghju","lugliu","aostu","settembre","ottobre","nuvembre","dicembre",""], - namesAbbr: ["ghje","ferr","marz","apri","magh","ghju","lugl","aost","sett","otto","nuve","dice",""] - }, - AM: null, - PM: null, - eras: [{"name":"dopu J-C","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.cy-GB.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.cy-GB.js deleted file mode 100644 index 0b07a621f1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.cy-GB.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Globalize Culture cy-GB - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "cy-GB", "default", { - name: "cy-GB", - englishName: "Welsh (United Kingdom)", - nativeName: "Cymraeg (y Deyrnas Unedig)", - language: "cy", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dydd Sul","Dydd Llun","Dydd Mawrth","Dydd Mercher","Dydd Iau","Dydd Gwener","Dydd Sadwrn"], - namesAbbr: ["Sul","Llun","Maw","Mer","Iau","Gwe","Sad"], - namesShort: ["Su","Ll","Ma","Me","Ia","Gw","Sa"] - }, - months: { - names: ["Ionawr","Chwefror","Mawrth","Ebrill","Mai","Mehefin","Gorffennaf","Awst","Medi","Hydref","Tachwedd","Rhagfyr",""], - namesAbbr: ["Ion","Chwe","Maw","Ebr","Mai","Meh","Gor","Aws","Med","Hyd","Tach","Rhag",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.cy.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.cy.js deleted file mode 100644 index 20b93b2739..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.cy.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Globalize Culture cy - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "cy", "default", { - name: "cy", - englishName: "Welsh", - nativeName: "Cymraeg", - language: "cy", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dydd Sul","Dydd Llun","Dydd Mawrth","Dydd Mercher","Dydd Iau","Dydd Gwener","Dydd Sadwrn"], - namesAbbr: ["Sul","Llun","Maw","Mer","Iau","Gwe","Sad"], - namesShort: ["Su","Ll","Ma","Me","Ia","Gw","Sa"] - }, - months: { - names: ["Ionawr","Chwefror","Mawrth","Ebrill","Mai","Mehefin","Gorffennaf","Awst","Medi","Hydref","Tachwedd","Rhagfyr",""], - namesAbbr: ["Ion","Chwe","Maw","Ebr","Mai","Meh","Gor","Aws","Med","Hyd","Tach","Rhag",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.da.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.da.js deleted file mode 100644 index 8186cd5df4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.da.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture da - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "da", "default", { - name: "da", - englishName: "Danish", - nativeName: "dansk", - language: "da", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","marts","april","maj","juni","juli","august","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.de.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.de.js deleted file mode 100644 index d0c718d7a3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.de.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture de - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "de", "default", { - name: "de", - englishName: "German", - nativeName: "Deutsch", - language: "de", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "n. def.", - negativeInfinity: "-unendlich", - positiveInfinity: "+unendlich", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], - namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], - namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d. MMMM yyyy HH:mm", - F: "dddd, d. MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dsb-DE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dsb-DE.js deleted file mode 100644 index 27a633ea8e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dsb-DE.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture dsb-DE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "dsb-DE", "default", { - name: "dsb-DE", - englishName: "Lower Sorbian (Germany)", - nativeName: "dolnoserbšćina (Nimska)", - language: "dsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekońcne", - positiveInfinity: "+njekońcne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njeźela","ponjeźele","wałtora","srjoda","stwortk","pětk","sobota"], - namesAbbr: ["nje","pon","wał","srj","stw","pět","sob"], - namesShort: ["n","p","w","s","s","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","maj","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","maja","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'goź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'goź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dsb.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dsb.js deleted file mode 100644 index 3098b071d8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dsb.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture dsb - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "dsb", "default", { - name: "dsb", - englishName: "Lower Sorbian", - nativeName: "dolnoserbšćina", - language: "dsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekońcne", - positiveInfinity: "+njekońcne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njeźela","ponjeźele","wałtora","srjoda","stwortk","pětk","sobota"], - namesAbbr: ["nje","pon","wał","srj","stw","pět","sob"], - namesShort: ["n","p","w","s","s","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","maj","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","maja","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'goź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'goź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dv-MV.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dv-MV.js deleted file mode 100644 index 26048c20f6..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dv-MV.js +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Globalize Culture dv-MV - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "dv-MV", "default", { - name: "dv-MV", - englishName: "Divehi (Maldives)", - nativeName: "ދިވެހިބަސް (ދިވެހި ރާއްޖެ)", - language: "dv", - isRTL: true, - numberFormat: { - currency: { - pattern: ["n $-","n $"], - symbol: "ރ." - } - }, - calendars: { - standard: { - name: "Hijri", - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""], - namesAbbr: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"ހިޖްރީ","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd/MM/yyyy HH:mm", - F: "dd/MM/yyyy HH:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""], - namesAbbr: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"މީލާދީ","start":null,"offset":0}], - patterns: { - d: "dd/MM/yy", - D: "ddd, yyyy MMMM dd", - t: "HH:mm", - T: "HH:mm:ss", - f: "ddd, yyyy MMMM dd HH:mm", - F: "ddd, yyyy MMMM dd HH:mm:ss", - Y: "yyyy, MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dv.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dv.js deleted file mode 100644 index 9a95e0da65..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.dv.js +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Globalize Culture dv - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "dv", "default", { - name: "dv", - englishName: "Divehi", - nativeName: "ދިވެހިބަސް", - language: "dv", - isRTL: true, - numberFormat: { - currency: { - pattern: ["n $-","n $"], - symbol: "ރ." - } - }, - calendars: { - standard: { - name: "Hijri", - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""], - namesAbbr: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd/MM/yyyy HH:mm", - F: "dd/MM/yyyy HH:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""], - namesAbbr: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"މީލާދީ","start":null,"offset":0}], - patterns: { - d: "dd/MM/yy", - D: "ddd, yyyy MMMM dd", - t: "HH:mm", - T: "HH:mm:ss", - f: "ddd, yyyy MMMM dd HH:mm", - F: "ddd, yyyy MMMM dd HH:mm:ss", - Y: "yyyy, MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.el.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.el.js deleted file mode 100644 index 87ba4b51e9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.el.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Globalize Culture el - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "el", "default", { - name: "el", - englishName: "Greek", - nativeName: "Ελληνικά", - language: "el", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "μη αριθμός", - negativeInfinity: "-Άπειρο", - positiveInfinity: "Άπειρο", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Κυριακή","Δευτέρα","Τρίτη","Τετάρτη","Πέμπτη","Παρασκευή","Σάββατο"], - namesAbbr: ["Κυρ","Δευ","Τρι","Τετ","Πεμ","Παρ","Σαβ"], - namesShort: ["Κυ","Δε","Τρ","Τε","Πε","Πα","Σά"] - }, - months: { - names: ["Ιανουάριος","Φεβρουάριος","Μάρτιος","Απρίλιος","Μάιος","Ιούνιος","Ιούλιος","Αύγουστος","Σεπτέμβριος","Οκτώβριος","Νοέμβριος","Δεκέμβριος",""], - namesAbbr: ["Ιαν","Φεβ","Μαρ","Απρ","Μαϊ","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ",""] - }, - monthsGenitive: { - names: ["Ιανουαρίου","Φεβρουαρίου","Μαρτίου","Απριλίου","Μαΐου","Ιουνίου","Ιουλίου","Αυγούστου","Σεπτεμβρίου","Οκτωβρίου","Νοεμβρίου","Δεκεμβρίου",""], - namesAbbr: ["Ιαν","Φεβ","Μαρ","Απρ","Μαϊ","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ",""] - }, - AM: ["πμ","πμ","ΠΜ"], - PM: ["μμ","μμ","ΜΜ"], - eras: [{"name":"μ.Χ.","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "dddd, d MMMM yyyy", - f: "dddd, d MMMM yyyy h:mm tt", - F: "dddd, d MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-029.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-029.js deleted file mode 100644 index 0e55864463..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-029.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Globalize Culture en-029 - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-029", "default", { - name: "en-029", - englishName: "English (Caribbean)", - nativeName: "English (Caribbean)", - numberFormat: { - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - patterns: { - d: "MM/dd/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-BZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-BZ.js deleted file mode 100644 index 4a0692d2f3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-BZ.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Globalize Culture en-BZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-BZ", "default", { - name: "en-BZ", - englishName: "English (Belize)", - nativeName: "English (Belize)", - numberFormat: { - currency: { - groupSizes: [3,0], - symbol: "BZ$" - } - }, - calendars: { - standard: { - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd MMMM yyyy hh:mm tt", - F: "dddd, dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-IE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-IE.js deleted file mode 100644 index 8475128b90..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-IE.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Globalize Culture en-IE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-IE", "default", { - name: "en-IE", - englishName: "English (Ireland)", - nativeName: "English (Ireland)", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-IN.js deleted file mode 100644 index a98dc7e4cf..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-IN.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture en-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-IN", "default", { - name: "en-IN", - englishName: "English (India)", - nativeName: "English (India)", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "Rs." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-JM.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-JM.js deleted file mode 100644 index 2110f010d3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-JM.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Globalize Culture en-JM - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-JM", "default", { - name: "en-JM", - englishName: "English (Jamaica)", - nativeName: "English (Jamaica)", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "J$" - } - }, - calendars: { - standard: { - patterns: { - d: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-MY.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-MY.js deleted file mode 100644 index 909804d361..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-MY.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Globalize Culture en-MY - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-MY", "default", { - name: "en-MY", - englishName: "English (Malaysia)", - nativeName: "English (Malaysia)", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - }, - currency: { - symbol: "RM" - } - }, - calendars: { - standard: { - days: { - namesShort: ["S","M","T","W","T","F","S"] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd, d MMMM, yyyy", - f: "dddd, d MMMM, yyyy h:mm tt", - F: "dddd, d MMMM, yyyy h:mm:ss tt", - M: "d MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-PH.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-PH.js deleted file mode 100644 index 4d06ea2e7d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-PH.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Globalize Culture en-PH - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-PH", "default", { - name: "en-PH", - englishName: "English (Republic of the Philippines)", - nativeName: "English (Philippines)", - numberFormat: { - currency: { - symbol: "Php" - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-SG.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-SG.js deleted file mode 100644 index 34e0d3bef5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-SG.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Globalize Culture en-SG - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-SG", "default", { - name: "en-SG", - englishName: "English (Singapore)", - nativeName: "English (Singapore)", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - } - }, - calendars: { - standard: { - days: { - namesShort: ["S","M","T","W","T","F","S"] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd, d MMMM, yyyy", - f: "dddd, d MMMM, yyyy h:mm tt", - F: "dddd, d MMMM, yyyy h:mm:ss tt", - M: "d MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-TT.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-TT.js deleted file mode 100644 index 4cc01482b5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-TT.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Globalize Culture en-TT - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-TT", "default", { - name: "en-TT", - englishName: "English (Trinidad and Tobago)", - nativeName: "English (Trinidad y Tobago)", - numberFormat: { - currency: { - groupSizes: [3,0], - symbol: "TT$" - } - }, - calendars: { - standard: { - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd MMMM yyyy hh:mm tt", - F: "dddd, dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-ZA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-ZA.js deleted file mode 100644 index 22dbfd3a19..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-ZA.js +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Globalize Culture en-ZA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-ZA", "default", { - name: "en-ZA", - englishName: "English (South Africa)", - nativeName: "English (South Africa)", - numberFormat: { - ",": " ", - percent: { - pattern: ["-n%","n%"], - ",": " " - }, - currency: { - pattern: ["$-n","$ n"], - ",": " ", - ".": ",", - symbol: "R" - } - }, - calendars: { - standard: { - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-ZW.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-ZW.js deleted file mode 100644 index e4f9beb7cc..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.en-ZW.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Globalize Culture en-ZW - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "en-ZW", "default", { - name: "en-ZW", - englishName: "English (Zimbabwe)", - nativeName: "English (Zimbabwe)", - numberFormat: { - currency: { - symbol: "Z$" - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.es.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.es.js deleted file mode 100644 index 658054d983..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.es.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture es - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "es", "default", { - name: "es", - englishName: "Spanish", - nativeName: "español", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.et-EE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.et-EE.js deleted file mode 100644 index 5759bea40e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.et-EE.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture et-EE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "et-EE", "default", { - name: "et-EE", - englishName: "Estonian (Estonia)", - nativeName: "eesti (Eesti)", - language: "et", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "avaldamatu", - negativeInfinity: "miinuslõpmatus", - positiveInfinity: "plusslõpmatus", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pühapäev","esmaspäev","teisipäev","kolmapäev","neljapäev","reede","laupäev"], - namesAbbr: ["P","E","T","K","N","R","L"], - namesShort: ["P","E","T","K","N","R","L"] - }, - months: { - names: ["jaanuar","veebruar","märts","aprill","mai","juuni","juuli","august","september","oktoober","november","detsember",""], - namesAbbr: ["jaan","veebr","märts","apr","mai","juuni","juuli","aug","sept","okt","nov","dets",""] - }, - AM: ["EL","el","EL"], - PM: ["PL","pl","PL"], - patterns: { - d: "d.MM.yyyy", - D: "d. MMMM yyyy'. a.'", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy'. a.' H:mm", - F: "d. MMMM yyyy'. a.' H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy'. a.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.et.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.et.js deleted file mode 100644 index 386c6a436a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.et.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture et - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "et", "default", { - name: "et", - englishName: "Estonian", - nativeName: "eesti", - language: "et", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "avaldamatu", - negativeInfinity: "miinuslõpmatus", - positiveInfinity: "plusslõpmatus", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pühapäev","esmaspäev","teisipäev","kolmapäev","neljapäev","reede","laupäev"], - namesAbbr: ["P","E","T","K","N","R","L"], - namesShort: ["P","E","T","K","N","R","L"] - }, - months: { - names: ["jaanuar","veebruar","märts","aprill","mai","juuni","juuli","august","september","oktoober","november","detsember",""], - namesAbbr: ["jaan","veebr","märts","apr","mai","juuni","juuli","aug","sept","okt","nov","dets",""] - }, - AM: ["EL","el","EL"], - PM: ["PL","pl","PL"], - patterns: { - d: "d.MM.yyyy", - D: "d. MMMM yyyy'. a.'", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy'. a.' H:mm", - F: "d. MMMM yyyy'. a.' H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy'. a.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.eu-ES.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.eu-ES.js deleted file mode 100644 index 18044b4a94..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.eu-ES.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture eu-ES - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "eu-ES", "default", { - name: "eu-ES", - englishName: "Basque (Basque)", - nativeName: "euskara (euskara)", - language: "eu", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "EdZ", - negativeInfinity: "-Infinitu", - positiveInfinity: "Infinitu", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["igandea","astelehena","asteartea","asteazkena","osteguna","ostirala","larunbata"], - namesAbbr: ["ig.","al.","as.","az.","og.","or.","lr."], - namesShort: ["ig","al","as","az","og","or","lr"] - }, - months: { - names: ["urtarrila","otsaila","martxoa","apirila","maiatza","ekaina","uztaila","abuztua","iraila","urria","azaroa","abendua",""], - namesAbbr: ["urt.","ots.","mar.","api.","mai.","eka.","uzt.","abu.","ira.","urr.","aza.","abe.",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "yyyy/MM/dd", - D: "dddd, yyyy.'eko' MMMM'k 'd", - t: "HH:mm", - T: "H:mm:ss", - f: "dddd, yyyy.'eko' MMMM'k 'd HH:mm", - F: "dddd, yyyy.'eko' MMMM'k 'd H:mm:ss", - Y: "yyyy.'eko' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.eu.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.eu.js deleted file mode 100644 index 4a05b26b9a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.eu.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture eu - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "eu", "default", { - name: "eu", - englishName: "Basque", - nativeName: "euskara", - language: "eu", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "EdZ", - negativeInfinity: "-Infinitu", - positiveInfinity: "Infinitu", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["igandea","astelehena","asteartea","asteazkena","osteguna","ostirala","larunbata"], - namesAbbr: ["ig.","al.","as.","az.","og.","or.","lr."], - namesShort: ["ig","al","as","az","og","or","lr"] - }, - months: { - names: ["urtarrila","otsaila","martxoa","apirila","maiatza","ekaina","uztaila","abuztua","iraila","urria","azaroa","abendua",""], - namesAbbr: ["urt.","ots.","mar.","api.","mai.","eka.","uzt.","abu.","ira.","urr.","aza.","abe.",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "yyyy/MM/dd", - D: "dddd, yyyy.'eko' MMMM'k 'd", - t: "HH:mm", - T: "H:mm:ss", - f: "dddd, yyyy.'eko' MMMM'k 'd HH:mm", - F: "dddd, yyyy.'eko' MMMM'k 'd H:mm:ss", - Y: "yyyy.'eko' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fa-IR.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fa-IR.js deleted file mode 100644 index 551586cadf..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fa-IR.js +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Globalize Culture fa-IR - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fa-IR", "default", { - name: "fa-IR", - englishName: "Persian", - nativeName: "فارسى (ایران)", - language: "fa", - isRTL: true, - numberFormat: { - pattern: ["n-"], - currency: { - pattern: ["$n-","$ n"], - ".": "/", - symbol: "ريال" - } - }, - calendars: { - standard: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""], - namesAbbr: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - patterns: { - d: "yyyy/MM/dd", - D: "yyyy/MM/dd", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "yyyy/MM/dd hh:mm tt", - F: "yyyy/MM/dd hh:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fa.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fa.js deleted file mode 100644 index 2d5d036ae1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fa.js +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Globalize Culture fa - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fa", "default", { - name: "fa", - englishName: "Persian", - nativeName: "فارسى", - language: "fa", - isRTL: true, - numberFormat: { - pattern: ["n-"], - currency: { - pattern: ["$n-","$ n"], - ".": "/", - symbol: "ريال" - } - }, - calendars: { - standard: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""], - namesAbbr: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - patterns: { - d: "yyyy/MM/dd", - D: "yyyy/MM/dd", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "yyyy/MM/dd hh:mm tt", - F: "yyyy/MM/dd hh:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fi.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fi.js deleted file mode 100644 index 33c23056e5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fi.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture fi - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fi", "default", { - name: "fi", - englishName: "Finnish", - nativeName: "suomi", - language: "fi", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sunnuntai","maanantai","tiistai","keskiviikko","torstai","perjantai","lauantai"], - namesAbbr: ["su","ma","ti","ke","to","pe","la"], - namesShort: ["su","ma","ti","ke","to","pe","la"] - }, - months: { - names: ["tammikuu","helmikuu","maaliskuu","huhtikuu","toukokuu","kesäkuu","heinäkuu","elokuu","syyskuu","lokakuu","marraskuu","joulukuu",""], - namesAbbr: ["tammi","helmi","maalis","huhti","touko","kesä","heinä","elo","syys","loka","marras","joulu",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM'ta 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM'ta 'yyyy H:mm", - F: "d. MMMM'ta 'yyyy H:mm:ss", - M: "d. MMMM'ta'", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fil-PH.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fil-PH.js deleted file mode 100644 index 78ac3d46e1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fil-PH.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Globalize Culture fil-PH - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fil-PH", "default", { - name: "fil-PH", - englishName: "Filipino (Philippines)", - nativeName: "Filipino (Pilipinas)", - language: "fil", - numberFormat: { - currency: { - symbol: "PhP" - } - }, - calendars: { - standard: { - days: { - names: ["Linggo","Lunes","Martes","Mierkoles","Huebes","Biernes","Sabado"], - namesAbbr: ["Lin","Lun","Mar","Mier","Hueb","Bier","Saba"], - namesShort: ["L","L","M","M","H","B","S"] - }, - months: { - names: ["Enero","Pebrero","Marso","Abril","Mayo","Hunyo","Hulyo","Agosto","Septyembre","Oktubre","Nobyembre","Disyembre",""], - namesAbbr: ["En","Peb","Mar","Abr","Mayo","Hun","Hul","Agos","Sept","Okt","Nob","Dis",""] - }, - eras: [{"name":"Anno Domini","start":null,"offset":0}] - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fil.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fil.js deleted file mode 100644 index 273c516460..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fil.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Globalize Culture fil - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fil", "default", { - name: "fil", - englishName: "Filipino", - nativeName: "Filipino", - language: "fil", - numberFormat: { - currency: { - symbol: "PhP" - } - }, - calendars: { - standard: { - days: { - names: ["Linggo","Lunes","Martes","Mierkoles","Huebes","Biernes","Sabado"], - namesAbbr: ["Lin","Lun","Mar","Mier","Hueb","Bier","Saba"], - namesShort: ["L","L","M","M","H","B","S"] - }, - months: { - names: ["Enero","Pebrero","Marso","Abril","Mayo","Hunyo","Hulyo","Agosto","Septyembre","Oktubre","Nobyembre","Disyembre",""], - namesAbbr: ["En","Peb","Mar","Abr","Mayo","Hun","Hul","Agos","Sept","Okt","Nob","Dis",""] - }, - eras: [{"name":"Anno Domini","start":null,"offset":0}] - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fo-FO.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fo-FO.js deleted file mode 100644 index 8e11f81a58..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fo-FO.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture fo-FO - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fo-FO", "default", { - name: "fo-FO", - englishName: "Faroese (Faroe Islands)", - nativeName: "føroyskt (Føroyar)", - language: "fo", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sunnudagur","mánadagur","týsdagur","mikudagur","hósdagur","fríggjadagur","leygardagur"], - namesAbbr: ["sun","mán","týs","mik","hós","frí","leyg"], - namesShort: ["su","má","tý","mi","hó","fr","ley"] - }, - months: { - names: ["januar","februar","mars","apríl","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fo.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fo.js deleted file mode 100644 index ca45b44a00..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fo.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture fo - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fo", "default", { - name: "fo", - englishName: "Faroese", - nativeName: "føroyskt", - language: "fo", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sunnudagur","mánadagur","týsdagur","mikudagur","hósdagur","fríggjadagur","leygardagur"], - namesAbbr: ["sun","mán","týs","mik","hós","frí","leyg"], - namesShort: ["su","má","tý","mi","hó","fr","ley"] - }, - months: { - names: ["januar","februar","mars","apríl","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fr-BE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fr-BE.js deleted file mode 100644 index 8f37feb65f..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fr-BE.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture fr-BE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fr-BE", "default", { - name: "fr-BE", - englishName: "French (Belgium)", - nativeName: "français (Belgique)", - language: "fr", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "d/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fr.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fr.js deleted file mode 100644 index e8c7b53a67..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fr.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture fr - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fr", "default", { - name: "fr", - englishName: "French", - nativeName: "français", - language: "fr", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fy-NL.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fy-NL.js deleted file mode 100644 index 549504c231..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fy-NL.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture fy-NL - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fy-NL", "default", { - name: "fy-NL", - englishName: "Frisian (Netherlands)", - nativeName: "Frysk (Nederlân)", - language: "fy", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["Snein","Moandei","Tiisdei","Woansdei","Tongersdei","Freed","Sneon"], - namesAbbr: ["Sn","Mo","Ti","Wo","To","Fr","Sn"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["jannewaris","febrewaris","maart","april","maaie","juny","july","augustus","septimber","oktober","novimber","desimber",""], - namesAbbr: ["jann","febr","mrt","apr","maaie","jun","jul","aug","sept","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "d-M-yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fy.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fy.js deleted file mode 100644 index 4dfd473644..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.fy.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture fy - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "fy", "default", { - name: "fy", - englishName: "Frisian", - nativeName: "Frysk", - language: "fy", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["Snein","Moandei","Tiisdei","Woansdei","Tongersdei","Freed","Sneon"], - namesAbbr: ["Sn","Mo","Ti","Wo","To","Fr","Sn"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["jannewaris","febrewaris","maart","april","maaie","juny","july","augustus","septimber","oktober","novimber","desimber",""], - namesAbbr: ["jann","febr","mrt","apr","maaie","jun","jul","aug","sept","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "d-M-yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ga-IE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ga-IE.js deleted file mode 100644 index 46bb1fb364..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ga-IE.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture ga-IE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ga-IE", "default", { - name: "ga-IE", - englishName: "Irish (Ireland)", - nativeName: "Gaeilge (Éire)", - language: "ga", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dé Domhnaigh","Dé Luain","Dé Máirt","Dé Céadaoin","Déardaoin","Dé hAoine","Dé Sathairn"], - namesAbbr: ["Domh","Luan","Máir","Céad","Déar","Aoi","Sath"], - namesShort: ["Do","Lu","Má","Cé","De","Ao","Sa"] - }, - months: { - names: ["Eanáir","Feabhra","Márta","Aibreán","Bealtaine","Meitheamh","Iúil","Lúnasa","Meán Fómhair","Deireadh Fómhair","Samhain","Nollaig",""], - namesAbbr: ["Ean","Feabh","Már","Aib","Bealt","Meith","Iúil","Lún","M.Fómh","D.Fómh","Samh","Noll",""] - }, - AM: ["r.n.","r.n.","R.N."], - PM: ["i.n.","i.n.","I.N."], - patterns: { - d: "dd/MM/yyyy", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ga.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ga.js deleted file mode 100644 index 282e43b469..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ga.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture ga - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ga", "default", { - name: "ga", - englishName: "Irish", - nativeName: "Gaeilge", - language: "ga", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dé Domhnaigh","Dé Luain","Dé Máirt","Dé Céadaoin","Déardaoin","Dé hAoine","Dé Sathairn"], - namesAbbr: ["Domh","Luan","Máir","Céad","Déar","Aoi","Sath"], - namesShort: ["Do","Lu","Má","Cé","De","Ao","Sa"] - }, - months: { - names: ["Eanáir","Feabhra","Márta","Aibreán","Bealtaine","Meitheamh","Iúil","Lúnasa","Meán Fómhair","Deireadh Fómhair","Samhain","Nollaig",""], - namesAbbr: ["Ean","Feabh","Már","Aib","Bealt","Meith","Iúil","Lún","M.Fómh","D.Fómh","Samh","Noll",""] - }, - AM: ["r.n.","r.n.","R.N."], - PM: ["i.n.","i.n.","I.N."], - patterns: { - d: "dd/MM/yyyy", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gd-GB.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gd-GB.js deleted file mode 100644 index 3abe4eddac..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gd-GB.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Globalize Culture gd-GB - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gd-GB", "default", { - name: "gd-GB", - englishName: "Scottish Gaelic (United Kingdom)", - nativeName: "Gàidhlig (An Rìoghachd Aonaichte)", - language: "gd", - numberFormat: { - negativeInfinity: "-Neo-chrìochnachd", - positiveInfinity: "Neo-chrìochnachd", - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"], - namesAbbr: ["Dòm","Lua","Mài","Cia","Ard","Hao","Sat"], - namesShort: ["D","L","M","C","A","H","S"] - }, - months: { - names: ["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd",""], - namesAbbr: ["Fao","Gea","Màr","Gib","Cèi","Ògm","Iuc","Lùn","Sul","Dàm","Sam","Dùb",""] - }, - AM: ["m","m","M"], - PM: ["f","f","F"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gd.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gd.js deleted file mode 100644 index e3f9c8fa7e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gd.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Globalize Culture gd - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gd", "default", { - name: "gd", - englishName: "Scottish Gaelic", - nativeName: "Gàidhlig", - language: "gd", - numberFormat: { - negativeInfinity: "-Neo-chrìochnachd", - positiveInfinity: "Neo-chrìochnachd", - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"], - namesAbbr: ["Dòm","Lua","Mài","Cia","Ard","Hao","Sat"], - namesShort: ["D","L","M","C","A","H","S"] - }, - months: { - names: ["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd",""], - namesAbbr: ["Fao","Gea","Màr","Gib","Cèi","Ògm","Iuc","Lùn","Sul","Dàm","Sam","Dùb",""] - }, - AM: ["m","m","M"], - PM: ["f","f","F"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gl-ES.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gl-ES.js deleted file mode 100644 index c750c0e2df..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gl-ES.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture gl-ES - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gl-ES", "default", { - name: "gl-ES", - englishName: "Galician (Galician)", - nativeName: "galego (galego)", - language: "gl", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","luns","martes","mércores","xoves","venres","sábado"], - namesAbbr: ["dom","luns","mar","mér","xov","ven","sáb"], - namesShort: ["do","lu","ma","mé","xo","ve","sá"] - }, - months: { - names: ["xaneiro","febreiro","marzo","abril","maio","xuño","xullo","agosto","setembro","outubro","novembro","decembro",""], - namesAbbr: ["xan","feb","mar","abr","maio","xuñ","xull","ago","set","out","nov","dec",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gl.js deleted file mode 100644 index 1d4a2b626a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gl.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture gl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gl", "default", { - name: "gl", - englishName: "Galician", - nativeName: "galego", - language: "gl", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","luns","martes","mércores","xoves","venres","sábado"], - namesAbbr: ["dom","luns","mar","mér","xov","ven","sáb"], - namesShort: ["do","lu","ma","mé","xo","ve","sá"] - }, - months: { - names: ["xaneiro","febreiro","marzo","abril","maio","xuño","xullo","agosto","setembro","outubro","novembro","decembro",""], - namesAbbr: ["xan","feb","mar","abr","maio","xuñ","xull","ago","set","out","nov","dec",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gsw-FR.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gsw-FR.js deleted file mode 100644 index 02c8085567..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gsw-FR.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture gsw-FR - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gsw-FR", "default", { - name: "gsw-FR", - englishName: "Alsatian (France)", - nativeName: "Elsässisch (Frànkrisch)", - language: "gsw", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Ohne Nummer", - negativeInfinity: "-Unendlich", - positiveInfinity: "+Unendlich", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sundàà","Mondàà","Dienschdàà","Mittwuch","Dunnerschdàà","Fridàà","Sàmschdàà"], - namesAbbr: ["Su.","Mo.","Di.","Mi.","Du.","Fr.","Sà."], - namesShort: ["Su","Mo","Di","Mi","Du","Fr","Sà"] - }, - months: { - names: ["Jänner","Feverje","März","Àpril","Mai","Jüni","Jüli","Augscht","September","Oktower","Nowember","Dezember",""], - namesAbbr: ["Jän.","Fev.","März","Apr.","Mai","Jüni","Jüli","Aug.","Sept.","Okt.","Now.","Dez.",""] - }, - AM: null, - PM: null, - eras: [{"name":"Vor J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gsw.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gsw.js deleted file mode 100644 index e6c4a32509..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gsw.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture gsw - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gsw", "default", { - name: "gsw", - englishName: "Alsatian", - nativeName: "Elsässisch", - language: "gsw", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Ohne Nummer", - negativeInfinity: "-Unendlich", - positiveInfinity: "+Unendlich", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sundàà","Mondàà","Dienschdàà","Mittwuch","Dunnerschdàà","Fridàà","Sàmschdàà"], - namesAbbr: ["Su.","Mo.","Di.","Mi.","Du.","Fr.","Sà."], - namesShort: ["Su","Mo","Di","Mi","Du","Fr","Sà"] - }, - months: { - names: ["Jänner","Feverje","März","Àpril","Mai","Jüni","Jüli","Augscht","September","Oktower","Nowember","Dezember",""], - namesAbbr: ["Jän.","Fev.","März","Apr.","Mai","Jüni","Jüli","Aug.","Sept.","Okt.","Now.","Dez.",""] - }, - AM: null, - PM: null, - eras: [{"name":"Vor J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gu-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gu-IN.js deleted file mode 100644 index 2b7fa8d899..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gu-IN.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture gu-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gu-IN", "default", { - name: "gu-IN", - englishName: "Gujarati (India)", - nativeName: "ગુજરાતી (ભારત)", - language: "gu", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "રૂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["રવિવાર","સોમવાર","મંગળવાર","બુધવાર","ગુરુવાર","શુક્રવાર","શનિવાર"], - namesAbbr: ["રવિ","સોમ","મંગળ","બુધ","ગુરુ","શુક્ર","શનિ"], - namesShort: ["ર","સ","મ","બ","ગ","શ","શ"] - }, - months: { - names: ["જાન્યુઆરી","ફેબ્રુઆરી","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટેમ્બર","ઑક્ટ્બર","નવેમ્બર","ડિસેમ્બર",""], - namesAbbr: ["જાન્યુ","ફેબ્રુ","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટે","ઑક્ટો","નવે","ડિસે",""] - }, - AM: ["પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન"], - PM: ["ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gu.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gu.js deleted file mode 100644 index 42766c5d96..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.gu.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture gu - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "gu", "default", { - name: "gu", - englishName: "Gujarati", - nativeName: "ગુજરાતી", - language: "gu", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "રૂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["રવિવાર","સોમવાર","મંગળવાર","બુધવાર","ગુરુવાર","શુક્રવાર","શનિવાર"], - namesAbbr: ["રવિ","સોમ","મંગળ","બુધ","ગુરુ","શુક્ર","શનિ"], - namesShort: ["ર","સ","મ","બ","ગ","શ","શ"] - }, - months: { - names: ["જાન્યુઆરી","ફેબ્રુઆરી","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટેમ્બર","ઑક્ટ્બર","નવેમ્બર","ડિસેમ્બર",""], - namesAbbr: ["જાન્યુ","ફેબ્રુ","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટે","ઑક્ટો","નવે","ડિસે",""] - }, - AM: ["પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન"], - PM: ["ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha-Latn-NG.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha-Latn-NG.js deleted file mode 100644 index 63fb776b43..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha-Latn-NG.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture ha-Latn-NG - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ha-Latn-NG", "default", { - name: "ha-Latn-NG", - englishName: "Hausa (Latin, Nigeria)", - nativeName: "Hausa (Nigeria)", - language: "ha-Latn", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Lahadi","Litinin","Talata","Laraba","Alhamis","Juma'a","Asabar"], - namesAbbr: ["Lah","Lit","Tal","Lar","Alh","Jum","Asa"], - namesShort: ["L","L","T","L","A","J","A"] - }, - months: { - names: ["Januwaru","Febreru","Maris","Afrilu","Mayu","Yuni","Yuli","Agusta","Satumba","Oktocba","Nuwamba","Disamba",""], - namesAbbr: ["Jan","Feb","Mar","Afr","May","Yun","Yul","Agu","Sat","Okt","Nuw","Dis",""] - }, - AM: ["Safe","safe","SAFE"], - PM: ["Yamma","yamma","YAMMA"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha-Latn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha-Latn.js deleted file mode 100644 index d770c50bdc..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha-Latn.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture ha-Latn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ha-Latn", "default", { - name: "ha-Latn", - englishName: "Hausa (Latin)", - nativeName: "Hausa", - language: "ha-Latn", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Lahadi","Litinin","Talata","Laraba","Alhamis","Juma'a","Asabar"], - namesAbbr: ["Lah","Lit","Tal","Lar","Alh","Jum","Asa"], - namesShort: ["L","L","T","L","A","J","A"] - }, - months: { - names: ["Januwaru","Febreru","Maris","Afrilu","Mayu","Yuni","Yuli","Agusta","Satumba","Oktocba","Nuwamba","Disamba",""], - namesAbbr: ["Jan","Feb","Mar","Afr","May","Yun","Yul","Agu","Sat","Okt","Nuw","Dis",""] - }, - AM: ["Safe","safe","SAFE"], - PM: ["Yamma","yamma","YAMMA"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha.js deleted file mode 100644 index 96b726fd38..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ha.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture ha - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ha", "default", { - name: "ha", - englishName: "Hausa", - nativeName: "Hausa", - language: "ha", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Lahadi","Litinin","Talata","Laraba","Alhamis","Juma'a","Asabar"], - namesAbbr: ["Lah","Lit","Tal","Lar","Alh","Jum","Asa"], - namesShort: ["L","L","T","L","A","J","A"] - }, - months: { - names: ["Januwaru","Febreru","Maris","Afrilu","Mayu","Yuni","Yuli","Agusta","Satumba","Oktocba","Nuwamba","Disamba",""], - namesAbbr: ["Jan","Feb","Mar","Afr","May","Yun","Yul","Agu","Sat","Okt","Nuw","Dis",""] - }, - AM: ["Safe","safe","SAFE"], - PM: ["Yamma","yamma","YAMMA"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.he.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.he.js deleted file mode 100644 index 03f7ea4b40..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.he.js +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Globalize Culture he - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "he", "default", { - name: "he", - englishName: "Hebrew", - nativeName: "עברית", - language: "he", - isRTL: true, - numberFormat: { - "NaN": "לא מספר", - negativeInfinity: "אינסוף שלילי", - positiveInfinity: "אינסוף חיובי", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "₪" - } - }, - calendars: { - standard: { - days: { - names: ["יום ראשון","יום שני","יום שלישי","יום רביעי","יום חמישי","יום שישי","שבת"], - namesAbbr: ["יום א","יום ב","יום ג","יום ד","יום ה","יום ו","שבת"], - namesShort: ["א","ב","ג","ד","ה","ו","ש"] - }, - months: { - names: ["ינואר","פברואר","מרץ","אפריל","מאי","יוני","יולי","אוגוסט","ספטמבר","אוקטובר","נובמבר","דצמבר",""], - namesAbbr: ["ינו","פבר","מרץ","אפר","מאי","יונ","יול","אוג","ספט","אוק","נוב","דצמ",""] - }, - eras: [{"name":"לספירה","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd dd MMMM yyyy HH:mm", - F: "dddd dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - }, - Hebrew: { - name: "Hebrew", - "/": " ", - days: { - names: ["יום ראשון","יום שני","יום שלישי","יום רביעי","יום חמישי","יום שישי","שבת"], - namesAbbr: ["א","ב","ג","ד","ה","ו","ש"], - namesShort: ["א","ב","ג","ד","ה","ו","ש"] - }, - months: { - names: ["תשרי","חשון","כסלו","טבת","שבט","אדר","אדר ב","ניסן","אייר","סיון","תמוז","אב","אלול"], - namesAbbr: ["תשרי","חשון","כסלו","טבת","שבט","אדר","אדר ב","ניסן","אייר","סיון","תמוז","אב","אלול"] - }, - eras: [{"name":"C.E.","start":null,"offset":0}], - twoDigitYearMax: 5790, - patterns: { - d: "dd MMMM yyyy", - D: "dddd dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd dd MMMM yyyy HH:mm", - F: "dddd dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hi.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hi.js deleted file mode 100644 index 4343d3a631..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hi.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture hi - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "hi", "default", { - name: "hi", - englishName: "Hindi", - nativeName: "हिंदी", - language: "hi", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["रविवार","सोमवार","मंगलवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"], - namesAbbr: ["रवि.","सोम.","मंगल.","बुध.","गुरु.","शुक्र.","शनि."], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""], - namesAbbr: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""] - }, - AM: ["पूर्वाह्न","पूर्वाह्न","पूर्वाह्न"], - PM: ["अपराह्न","अपराह्न","अपराह्न"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hr.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hr.js deleted file mode 100644 index 6c597a8a59..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hr.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture hr - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "hr", "default", { - name: "hr", - englishName: "Croatian", - nativeName: "hrvatski", - language: "hr", - numberFormat: { - pattern: ["- n"], - ",": ".", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kn" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["siječanj","veljača","ožujak","travanj","svibanj","lipanj","srpanj","kolovoz","rujan","listopad","studeni","prosinac",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - monthsGenitive: { - names: ["siječnja","veljače","ožujka","travnja","svibnja","lipnja","srpnja","kolovoza","rujna","listopada","studenog","prosinca",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy.", - D: "d. MMMM yyyy.", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy. H:mm", - F: "d. MMMM yyyy. H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hsb-DE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hsb-DE.js deleted file mode 100644 index e30a4dac4d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hsb-DE.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture hsb-DE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "hsb-DE", "default", { - name: "hsb-DE", - englishName: "Upper Sorbian (Germany)", - nativeName: "hornjoserbšćina (Němska)", - language: "hsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekónčne", - positiveInfinity: "+njekónčne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njedźela","póndźela","wutora","srjeda","štwórtk","pjatk","sobota"], - namesAbbr: ["nje","pón","wut","srj","štw","pja","sob"], - namesShort: ["n","p","w","s","š","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","meja","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","meje","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'hodź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'hodź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hsb.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hsb.js deleted file mode 100644 index 57a6b06126..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hsb.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture hsb - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "hsb", "default", { - name: "hsb", - englishName: "Upper Sorbian", - nativeName: "hornjoserbšćina", - language: "hsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekónčne", - positiveInfinity: "+njekónčne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njedźela","póndźela","wutora","srjeda","štwórtk","pjatk","sobota"], - namesAbbr: ["nje","pón","wut","srj","štw","pja","sob"], - namesShort: ["n","p","w","s","š","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","meja","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","meje","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'hodź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'hodź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hu.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hu.js deleted file mode 100644 index a4ae56f300..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hu.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture hu - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "hu", "default", { - name: "hu", - englishName: "Hungarian", - nativeName: "magyar", - language: "hu", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "nem szám", - negativeInfinity: "negatív végtelen", - positiveInfinity: "végtelen", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Ft" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["vasárnap","hétfő","kedd","szerda","csütörtök","péntek","szombat"], - namesAbbr: ["V","H","K","Sze","Cs","P","Szo"], - namesShort: ["V","H","K","Sze","Cs","P","Szo"] - }, - months: { - names: ["január","február","március","április","május","június","július","augusztus","szeptember","október","november","december",""], - namesAbbr: ["jan.","febr.","márc.","ápr.","máj.","jún.","júl.","aug.","szept.","okt.","nov.","dec.",""] - }, - AM: ["de.","de.","DE."], - PM: ["du.","du.","DU."], - eras: [{"name":"i.sz.","start":null,"offset":0}], - patterns: { - d: "yyyy.MM.dd.", - D: "yyyy. MMMM d.", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy. MMMM d. H:mm", - F: "yyyy. MMMM d. H:mm:ss", - M: "MMMM d.", - Y: "yyyy. MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hy-AM.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hy-AM.js deleted file mode 100644 index 9fa83be9a4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hy-AM.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture hy-AM - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "hy-AM", "default", { - name: "hy-AM", - englishName: "Armenian (Armenia)", - nativeName: "Հայերեն (Հայաստան)", - language: "hy", - numberFormat: { - currency: { - pattern: ["-n $","n $"], - symbol: "դր." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","ՈՒրբաթ","Շաբաթ"], - namesAbbr: ["Կիր","Երկ","Երք","Չրք","Հնգ","ՈՒր","Շբթ"], - namesShort: ["Կ","Ե","Ե","Չ","Հ","Ո","Շ"] - }, - months: { - names: ["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր",""], - namesAbbr: ["ՀՆՎ","ՓՏՎ","ՄՐՏ","ԱՊՐ","ՄՅՍ","ՀՆՍ","ՀԼՍ","ՕԳՍ","ՍԵՊ","ՀՈԿ","ՆՈՅ","ԴԵԿ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM, yyyy H:mm", - F: "d MMMM, yyyy H:mm:ss", - M: "d MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hy.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hy.js deleted file mode 100644 index 3e78786870..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.hy.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture hy - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "hy", "default", { - name: "hy", - englishName: "Armenian", - nativeName: "Հայերեն", - language: "hy", - numberFormat: { - currency: { - pattern: ["-n $","n $"], - symbol: "դր." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","ՈՒրբաթ","Շաբաթ"], - namesAbbr: ["Կիր","Երկ","Երք","Չրք","Հնգ","ՈՒր","Շբթ"], - namesShort: ["Կ","Ե","Ե","Չ","Հ","Ո","Շ"] - }, - months: { - names: ["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր",""], - namesAbbr: ["ՀՆՎ","ՓՏՎ","ՄՐՏ","ԱՊՐ","ՄՅՍ","ՀՆՍ","ՀԼՍ","ՕԳՍ","ՍԵՊ","ՀՈԿ","ՆՈՅ","ԴԵԿ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM, yyyy H:mm", - F: "d MMMM, yyyy H:mm:ss", - M: "d MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.id-ID.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.id-ID.js deleted file mode 100644 index 283badcc23..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.id-ID.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Globalize Culture id-ID - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "id-ID", "default", { - name: "id-ID", - englishName: "Indonesian (Indonesia)", - nativeName: "Bahasa Indonesia (Indonesia)", - language: "id", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - decimals: 0, - ",": ".", - ".": ",", - symbol: "Rp" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"], - namesAbbr: ["Minggu","Sen","Sel","Rabu","Kamis","Jumat","Sabtu"], - namesShort: ["M","S","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","Nopember","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agust","Sep","Okt","Nop","Des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.id.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.id.js deleted file mode 100644 index 9027e383c7..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.id.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Globalize Culture id - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "id", "default", { - name: "id", - englishName: "Indonesian", - nativeName: "Bahasa Indonesia", - language: "id", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - decimals: 0, - ",": ".", - ".": ",", - symbol: "Rp" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"], - namesAbbr: ["Minggu","Sen","Sel","Rabu","Kamis","Jumat","Sabtu"], - namesShort: ["M","S","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","Nopember","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agust","Sep","Okt","Nop","Des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ig-NG.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ig-NG.js deleted file mode 100644 index 04ad7a3c50..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ig-NG.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture ig-NG - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ig-NG", "default", { - name: "ig-NG", - englishName: "Igbo (Nigeria)", - nativeName: "Igbo (Nigeria)", - language: "ig", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Onwa mbu","Onwa ibua","Onwa ato","Onwa ano","Onwa ise","Onwa isi","Onwa asa","Onwa asato","Onwa itolu","Onwa iri","Onwa iri n'ofu","Onwa iri n'ibua",""], - namesAbbr: ["mbu.","ibu.","ato.","ano.","ise","isi","asa","asa.","ito.","iri.","n'of.","n'ib.",""] - }, - AM: ["Ututu","ututu","UTUTU"], - PM: ["Efifie","efifie","EFIFIE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ig.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ig.js deleted file mode 100644 index 96219bae57..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ig.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture ig - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ig", "default", { - name: "ig", - englishName: "Igbo", - nativeName: "Igbo", - language: "ig", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Onwa mbu","Onwa ibua","Onwa ato","Onwa ano","Onwa ise","Onwa isi","Onwa asa","Onwa asato","Onwa itolu","Onwa iri","Onwa iri n'ofu","Onwa iri n'ibua",""], - namesAbbr: ["mbu.","ibu.","ato.","ano.","ise","isi","asa","asa.","ito.","iri.","n'of.","n'ib.",""] - }, - AM: ["Ututu","ututu","UTUTU"], - PM: ["Efifie","efifie","EFIFIE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ii-CN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ii-CN.js deleted file mode 100644 index 14906bfb07..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ii-CN.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture ii-CN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ii-CN", "default", { - name: "ii-CN", - englishName: "Yi (PRC)", - nativeName: "ꆈꌠꁱꂷ (ꍏꉸꏓꂱꇭꉼꇩ)", - language: "ii", - numberFormat: { - groupSizes: [3,0], - "NaN": "ꌗꂷꀋꉬ", - negativeInfinity: "ꀄꊭꌐꀋꉆ", - positiveInfinity: "ꈤꇁꑖꀋꉬ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ꑭꆏꑍ","ꆏꊂ꒔","ꆏꊂꑍ","ꆏꊂꌕ","ꆏꊂꇖ","ꆏꊂꉬ","ꆏꊂꃘ"], - namesAbbr: ["ꑭꆏ","ꆏ꒔","ꆏꑍ","ꆏꌕ","ꆏꇖ","ꆏꉬ","ꆏꃘ"], - namesShort: ["ꆏ","꒔","ꑍ","ꌕ","ꇖ","ꉬ","ꃘ"] - }, - months: { - names: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""], - namesAbbr: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""] - }, - AM: ["ꂵꆪꈌꈐ","ꂵꆪꈌꈐ","ꂵꆪꈌꈐ"], - PM: ["ꂵꆪꈌꉈ","ꂵꆪꈌꉈ","ꂵꆪꈌꉈ"], - eras: [{"name":"ꇬꑼ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ꈎ' M'ꆪ' d'ꑍ'", - t: "tt h:mm", - T: "H:mm:ss", - f: "yyyy'ꈎ' M'ꆪ' d'ꑍ' tt h:mm", - F: "yyyy'ꈎ' M'ꆪ' d'ꑍ' H:mm:ss", - M: "M'ꆪ' d'ꑍ'", - Y: "yyyy'ꈎ' M'ꆪ'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ii.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ii.js deleted file mode 100644 index 53d078ac25..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ii.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture ii - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ii", "default", { - name: "ii", - englishName: "Yi", - nativeName: "ꆈꌠꁱꂷ", - language: "ii", - numberFormat: { - groupSizes: [3,0], - "NaN": "ꌗꂷꀋꉬ", - negativeInfinity: "ꀄꊭꌐꀋꉆ", - positiveInfinity: "ꈤꇁꑖꀋꉬ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ꑭꆏꑍ","ꆏꊂ꒔","ꆏꊂꑍ","ꆏꊂꌕ","ꆏꊂꇖ","ꆏꊂꉬ","ꆏꊂꃘ"], - namesAbbr: ["ꑭꆏ","ꆏ꒔","ꆏꑍ","ꆏꌕ","ꆏꇖ","ꆏꉬ","ꆏꃘ"], - namesShort: ["ꆏ","꒔","ꑍ","ꌕ","ꇖ","ꉬ","ꃘ"] - }, - months: { - names: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""], - namesAbbr: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""] - }, - AM: ["ꂵꆪꈌꈐ","ꂵꆪꈌꈐ","ꂵꆪꈌꈐ"], - PM: ["ꂵꆪꈌꉈ","ꂵꆪꈌꉈ","ꂵꆪꈌꉈ"], - eras: [{"name":"ꇬꑼ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ꈎ' M'ꆪ' d'ꑍ'", - t: "tt h:mm", - T: "H:mm:ss", - f: "yyyy'ꈎ' M'ꆪ' d'ꑍ' tt h:mm", - F: "yyyy'ꈎ' M'ꆪ' d'ꑍ' H:mm:ss", - M: "M'ꆪ' d'ꑍ'", - Y: "yyyy'ꈎ' M'ꆪ'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.is-IS.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.is-IS.js deleted file mode 100644 index 795f0f93de..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.is-IS.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture is-IS - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "is-IS", "default", { - name: "is-IS", - englishName: "Icelandic (Iceland)", - nativeName: "íslenska (Ísland)", - language: "is", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sunnudagur","mánudagur","þriðjudagur","miðvikudagur","fimmtudagur","föstudagur","laugardagur"], - namesAbbr: ["sun.","mán.","þri.","mið.","fim.","fös.","lau."], - namesShort: ["su","má","þr","mi","fi","fö","la"] - }, - months: { - names: ["janúar","febrúar","mars","apríl","maí","júní","júlí","ágúst","september","október","nóvember","desember",""], - namesAbbr: ["jan.","feb.","mar.","apr.","maí","jún.","júl.","ágú.","sep.","okt.","nóv.","des.",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.is.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.is.js deleted file mode 100644 index f2746928c0..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.is.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture is - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "is", "default", { - name: "is", - englishName: "Icelandic", - nativeName: "íslenska", - language: "is", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sunnudagur","mánudagur","þriðjudagur","miðvikudagur","fimmtudagur","föstudagur","laugardagur"], - namesAbbr: ["sun.","mán.","þri.","mið.","fim.","fös.","lau."], - namesShort: ["su","má","þr","mi","fi","fö","la"] - }, - months: { - names: ["janúar","febrúar","mars","apríl","maí","júní","júlí","ágúst","september","október","nóvember","desember",""], - namesAbbr: ["jan.","feb.","mar.","apr.","maí","jún.","júl.","ágú.","sep.","okt.","nóv.","des.",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.it.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.it.js deleted file mode 100644 index de88495de5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.it.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture it - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "it", "default", { - name: "it", - englishName: "Italian", - nativeName: "italiano", - language: "it", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "Non un numero reale", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"], - namesAbbr: ["dom","lun","mar","mer","gio","ven","sab"], - namesShort: ["do","lu","ma","me","gi","ve","sa"] - }, - months: { - names: ["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre",""], - namesAbbr: ["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Cans-CA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Cans-CA.js deleted file mode 100644 index ac00a68993..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Cans-CA.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Globalize Culture iu-Cans-CA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "iu-Cans-CA", "default", { - name: "iu-Cans-CA", - englishName: "Inuktitut (Syllabics, Canada)", - nativeName: "ᐃᓄᒃᑎᑐᑦ (ᑲᓇᑕᒥ)", - language: "iu-Cans", - numberFormat: { - groupSizes: [3,0], - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["ᓈᑦᑏᖑᔭ","ᓇᒡᒐᔾᔭᐅ","ᐊᐃᑉᐱᖅ","ᐱᖓᑦᓯᖅ","ᓯᑕᒻᒥᖅ","ᑕᓪᓕᕐᒥᖅ","ᓯᕙᑖᕐᕕᒃ"], - namesAbbr: ["ᓈᑦᑏ","ᓇᒡᒐ","ᐊᐃᑉᐱ","ᐱᖓᑦᓯ","ᓯᑕ","ᑕᓪᓕ","ᓯᕙᑖᕐᕕᒃ"], - namesShort: ["ᓈ","ᓇ","ᐊ","ᐱ","ᓯ","ᑕ","ᓯ"] - }, - months: { - names: ["ᔮᓐᓄᐊᕆ","ᕖᕝᕗᐊᕆ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌᓯ","ᓯᑎᐱᕆ","ᐅᑐᐱᕆ","ᓄᕕᐱᕆ","ᑎᓯᐱᕆ",""], - namesAbbr: ["ᔮᓐᓄ","ᕖᕝᕗ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌ","ᓯᑎᐱ","ᐅᑐᐱ","ᓄᕕᐱ","ᑎᓯᐱ",""] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd,MMMM dd,yyyy", - f: "dddd,MMMM dd,yyyy h:mm tt", - F: "dddd,MMMM dd,yyyy h:mm:ss tt", - Y: "MMMM,yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Cans.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Cans.js deleted file mode 100644 index e3942c5c18..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Cans.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Globalize Culture iu-Cans - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "iu-Cans", "default", { - name: "iu-Cans", - englishName: "Inuktitut (Syllabics)", - nativeName: "ᐃᓄᒃᑎᑐᑦ", - language: "iu-Cans", - numberFormat: { - groupSizes: [3,0], - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["ᓈᑦᑏᖑᔭ","ᓇᒡᒐᔾᔭᐅ","ᐊᐃᑉᐱᖅ","ᐱᖓᑦᓯᖅ","ᓯᑕᒻᒥᖅ","ᑕᓪᓕᕐᒥᖅ","ᓯᕙᑖᕐᕕᒃ"], - namesAbbr: ["ᓈᑦᑏ","ᓇᒡᒐ","ᐊᐃᑉᐱ","ᐱᖓᑦᓯ","ᓯᑕ","ᑕᓪᓕ","ᓯᕙᑖᕐᕕᒃ"], - namesShort: ["ᓈ","ᓇ","ᐊ","ᐱ","ᓯ","ᑕ","ᓯ"] - }, - months: { - names: ["ᔮᓐᓄᐊᕆ","ᕖᕝᕗᐊᕆ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌᓯ","ᓯᑎᐱᕆ","ᐅᑐᐱᕆ","ᓄᕕᐱᕆ","ᑎᓯᐱᕆ",""], - namesAbbr: ["ᔮᓐᓄ","ᕖᕝᕗ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌ","ᓯᑎᐱ","ᐅᑐᐱ","ᓄᕕᐱ","ᑎᓯᐱ",""] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd,MMMM dd,yyyy", - f: "dddd,MMMM dd,yyyy h:mm tt", - F: "dddd,MMMM dd,yyyy h:mm:ss tt", - Y: "MMMM,yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Latn-CA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Latn-CA.js deleted file mode 100644 index 689ba45ab8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Latn-CA.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture iu-Latn-CA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "iu-Latn-CA", "default", { - name: "iu-Latn-CA", - englishName: "Inuktitut (Latin, Canada)", - nativeName: "Inuktitut (Kanatami)", - language: "iu-Latn", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Naattiinguja","Naggajjau","Aippiq","Pingatsiq","Sitammiq","Tallirmiq","Sivataarvik"], - namesAbbr: ["Nat","Nag","Aip","Pi","Sit","Tal","Siv"], - namesShort: ["N","N","A","P","S","T","S"] - }, - months: { - names: ["Jaannuari","Viivvuari","Maatsi","Iipuri","Mai","Juuni","Julai","Aaggiisi","Sitipiri","Utupiri","Nuvipiri","Tisipiri",""], - namesAbbr: ["Jan","Viv","Mas","Ipu","Mai","Jun","Jul","Agi","Sii","Uut","Nuv","Tis",""] - }, - patterns: { - d: "d/MM/yyyy", - D: "ddd, MMMM dd,yyyy", - f: "ddd, MMMM dd,yyyy h:mm tt", - F: "ddd, MMMM dd,yyyy h:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Latn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Latn.js deleted file mode 100644 index d6776af954..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu-Latn.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture iu-Latn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "iu-Latn", "default", { - name: "iu-Latn", - englishName: "Inuktitut (Latin)", - nativeName: "Inuktitut", - language: "iu-Latn", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Naattiinguja","Naggajjau","Aippiq","Pingatsiq","Sitammiq","Tallirmiq","Sivataarvik"], - namesAbbr: ["Nat","Nag","Aip","Pi","Sit","Tal","Siv"], - namesShort: ["N","N","A","P","S","T","S"] - }, - months: { - names: ["Jaannuari","Viivvuari","Maatsi","Iipuri","Mai","Juuni","Julai","Aaggiisi","Sitipiri","Utupiri","Nuvipiri","Tisipiri",""], - namesAbbr: ["Jan","Viv","Mas","Ipu","Mai","Jun","Jul","Agi","Sii","Uut","Nuv","Tis",""] - }, - patterns: { - d: "d/MM/yyyy", - D: "ddd, MMMM dd,yyyy", - f: "ddd, MMMM dd,yyyy h:mm tt", - F: "ddd, MMMM dd,yyyy h:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu.js deleted file mode 100644 index 9ec58167b2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.iu.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture iu - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "iu", "default", { - name: "iu", - englishName: "Inuktitut", - nativeName: "Inuktitut", - language: "iu", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Naattiinguja","Naggajjau","Aippiq","Pingatsiq","Sitammiq","Tallirmiq","Sivataarvik"], - namesAbbr: ["Nat","Nag","Aip","Pi","Sit","Tal","Siv"], - namesShort: ["N","N","A","P","S","T","S"] - }, - months: { - names: ["Jaannuari","Viivvuari","Maatsi","Iipuri","Mai","Juuni","Julai","Aaggiisi","Sitipiri","Utupiri","Nuvipiri","Tisipiri",""], - namesAbbr: ["Jan","Viv","Mas","Ipu","Mai","Jun","Jul","Agi","Sii","Uut","Nuv","Tis",""] - }, - patterns: { - d: "d/MM/yyyy", - D: "ddd, MMMM dd,yyyy", - f: "ddd, MMMM dd,yyyy h:mm tt", - F: "ddd, MMMM dd,yyyy h:mm:ss tt" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ja.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ja.js deleted file mode 100644 index 14fe8062a1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ja.js +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Globalize Culture ja - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ja", "default", { - name: "ja", - englishName: "Japanese", - nativeName: "日本語", - language: "ja", - numberFormat: { - "NaN": "NaN (非数値)", - negativeInfinity: "-∞", - positiveInfinity: "+∞", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["-$n","$n"], - decimals: 0, - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], - namesAbbr: ["日","月","火","水","木","金","土"], - namesShort: ["日","月","火","水","木","金","土"] - }, - months: { - names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["午前","午前","午前"], - PM: ["午後","午後","午後"], - eras: [{"name":"西暦","start":null,"offset":0}], - patterns: { - d: "yyyy/MM/dd", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - }, - Japanese: { - name: "Japanese", - days: { - names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], - namesAbbr: ["日","月","火","水","木","金","土"], - namesShort: ["日","月","火","水","木","金","土"] - }, - months: { - names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["午前","午前","午前"], - PM: ["午後","午後","午後"], - eras: [{"name":"平成","start":null,"offset":1867},{"name":"昭和","start":-1812153600000,"offset":1911},{"name":"大正","start":-1357603200000,"offset":1925},{"name":"明治","start":60022080000,"offset":1988}], - twoDigitYearMax: 99, - patterns: { - d: "gg y/M/d", - D: "gg y'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "gg y'年'M'月'd'日' H:mm", - F: "gg y'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "gg y'年'M'月'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ka-GE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ka-GE.js deleted file mode 100644 index d46d7772c0..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ka-GE.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture ka-GE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ka-GE", "default", { - name: "ka-GE", - englishName: "Georgian (Georgia)", - nativeName: "ქართული (საქართველო)", - language: "ka", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Lari" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesAbbr: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesShort: ["კ","ო","ს","ო","ხ","პ","შ"] - }, - months: { - names: ["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბერი","ნოემბერი","დეკემბერი",""], - namesAbbr: ["იან","თებ","მარ","აპრ","მაის","ივნ","ივლ","აგვ","სექ","ოქტ","ნოემ","დეკ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'წლის' dd MM, dddd", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'წლის' dd MM, dddd H:mm", - F: "yyyy 'წლის' dd MM, dddd H:mm:ss", - M: "dd MM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ka.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ka.js deleted file mode 100644 index 4fb5a0c611..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ka.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture ka - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ka", "default", { - name: "ka", - englishName: "Georgian", - nativeName: "ქართული", - language: "ka", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Lari" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesAbbr: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesShort: ["კ","ო","ს","ო","ხ","პ","შ"] - }, - months: { - names: ["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბერი","ნოემბერი","დეკემბერი",""], - namesAbbr: ["იან","თებ","მარ","აპრ","მაის","ივნ","ივლ","აგვ","სექ","ოქტ","ნოემ","დეკ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'წლის' dd MM, dddd", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'წლის' dd MM, dddd H:mm", - F: "yyyy 'წლის' dd MM, dddd H:mm:ss", - M: "dd MM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kk-KZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kk-KZ.js deleted file mode 100644 index 98ce0518d1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kk-KZ.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture kk-KZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kk-KZ", "default", { - name: "kk-KZ", - englishName: "Kazakh (Kazakhstan)", - nativeName: "Қазақ (Қазақстан)", - language: "kk", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$n","$n"], - ",": " ", - ".": "-", - symbol: "Т" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жексенбі","Дүйсенбі","Сейсенбі","Сәрсенбі","Бейсенбі","Жұма","Сенбі"], - namesAbbr: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"], - namesShort: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"] - }, - months: { - names: ["қаңтар","ақпан","наурыз","сәуір","мамыр","маусым","шілде","тамыз","қыркүйек","қазан","қараша","желтоқсан",""], - namesAbbr: ["Қаң","Ақп","Нау","Сәу","Мам","Мау","Шіл","Там","Қыр","Қаз","Қар","Жел",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy 'ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'ж.' H:mm", - F: "d MMMM yyyy 'ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kk.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kk.js deleted file mode 100644 index d1d4877145..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kk.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture kk - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kk", "default", { - name: "kk", - englishName: "Kazakh", - nativeName: "Қазақ", - language: "kk", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$n","$n"], - ",": " ", - ".": "-", - symbol: "Т" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жексенбі","Дүйсенбі","Сейсенбі","Сәрсенбі","Бейсенбі","Жұма","Сенбі"], - namesAbbr: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"], - namesShort: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"] - }, - months: { - names: ["қаңтар","ақпан","наурыз","сәуір","мамыр","маусым","шілде","тамыз","қыркүйек","қазан","қараша","желтоқсан",""], - namesAbbr: ["Қаң","Ақп","Нау","Сәу","Мам","Мау","Шіл","Там","Қыр","Қаз","Қар","Жел",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy 'ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'ж.' H:mm", - F: "d MMMM yyyy 'ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kl-GL.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kl-GL.js deleted file mode 100644 index 1ad7b001f7..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kl-GL.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture kl-GL - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kl-GL", "default", { - name: "kl-GL", - englishName: "Greenlandic (Greenland)", - nativeName: "kalaallisut (Kalaallit Nunaat)", - language: "kl", - numberFormat: { - ",": ".", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - groupSizes: [3,0], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,0], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sapaat","ataasinngorneq","marlunngorneq","pingasunngorneq","sisamanngorneq","tallimanngorneq","arfininngorneq"], - namesAbbr: ["sap","ata","mar","ping","sis","tal","arf"], - namesShort: ["sa","at","ma","pi","si","ta","ar"] - }, - months: { - names: ["januari","februari","martsi","apriili","maaji","juni","juli","aggusti","septembari","oktobari","novembari","decembari",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kl.js deleted file mode 100644 index 55d5449736..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kl.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture kl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kl", "default", { - name: "kl", - englishName: "Greenlandic", - nativeName: "kalaallisut", - language: "kl", - numberFormat: { - ",": ".", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - groupSizes: [3,0], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,0], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sapaat","ataasinngorneq","marlunngorneq","pingasunngorneq","sisamanngorneq","tallimanngorneq","arfininngorneq"], - namesAbbr: ["sap","ata","mar","ping","sis","tal","arf"], - namesShort: ["sa","at","ma","pi","si","ta","ar"] - }, - months: { - names: ["januari","februari","martsi","apriili","maaji","juni","juli","aggusti","septembari","oktobari","novembari","decembari",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.km-KH.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.km-KH.js deleted file mode 100644 index 92e7aecf5e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.km-KH.js +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Globalize Culture km-KH - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "km-KH", "default", { - name: "km-KH", - englishName: "Khmer (Cambodia)", - nativeName: "ខ្មែរ (កម្ពុជា)", - language: "km", - numberFormat: { - pattern: ["- n"], - groupSizes: [3,0], - "NaN": "NAN", - negativeInfinity: "-- អនន្ត", - positiveInfinity: "អនន្ត", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["-n$","n$"], - symbol: "៛" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ថ្ងៃអាទិត្យ","ថ្ងៃច័ន្ទ","ថ្ងៃអង្គារ","ថ្ងៃពុធ","ថ្ងៃព្រហស្បតិ៍","ថ្ងៃសុក្រ","ថ្ងៃសៅរ៍"], - namesAbbr: ["អាទិ.","ច.","អ.","ពុ","ព្រហ.","សុ.","ស."], - namesShort: ["អា","ច","អ","ពុ","ព្","សុ","ស"] - }, - months: { - names: ["មករា","កុម្ភៈ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ",""], - namesAbbr: ["១","២","៣","៤","៥","៦","៧","៨","៩","១០","១១","១២",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"មុនគ.ស.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "d MMMM yyyy H:mm tt", - F: "d MMMM yyyy HH:mm:ss", - M: "'ថ្ងៃទី' dd 'ខែ' MM", - Y: "'ខែ' MM 'ឆ្នាំ' yyyy" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm tt", - F: "dddd, MMMM dd, yyyy HH:mm:ss" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.km.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.km.js deleted file mode 100644 index 4463b919f4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.km.js +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Globalize Culture km - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "km", "default", { - name: "km", - englishName: "Khmer", - nativeName: "ខ្មែរ", - language: "km", - numberFormat: { - pattern: ["- n"], - groupSizes: [3,0], - "NaN": "NAN", - negativeInfinity: "-- អនន្ត", - positiveInfinity: "អនន្ត", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["-n$","n$"], - symbol: "៛" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ថ្ងៃអាទិត្យ","ថ្ងៃច័ន្ទ","ថ្ងៃអង្គារ","ថ្ងៃពុធ","ថ្ងៃព្រហស្បតិ៍","ថ្ងៃសុក្រ","ថ្ងៃសៅរ៍"], - namesAbbr: ["អាទិ.","ច.","អ.","ពុ","ព្រហ.","សុ.","ស."], - namesShort: ["អា","ច","អ","ពុ","ព្","សុ","ស"] - }, - months: { - names: ["មករា","កុម្ភៈ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ",""], - namesAbbr: ["១","២","៣","៤","៥","៦","៧","៨","៩","១០","១១","១២",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"មុនគ.ស.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "d MMMM yyyy H:mm tt", - F: "d MMMM yyyy HH:mm:ss", - M: "'ថ្ងៃទី' dd 'ខែ' MM", - Y: "'ខែ' MM 'ឆ្នាំ' yyyy" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm tt", - F: "dddd, MMMM dd, yyyy HH:mm:ss" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kn-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kn-IN.js deleted file mode 100644 index aa6ff62be0..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kn-IN.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture kn-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kn-IN", "default", { - name: "kn-IN", - englishName: "Kannada (India)", - nativeName: "ಕನ್ನಡ (ಭಾರತ)", - language: "kn", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ರೂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ಭಾನುವಾರ","ಸೋಮವಾರ","ಮಂಗಳವಾರ","ಬುಧವಾರ","ಗುರುವಾರ","ಶುಕ್ರವಾರ","ಶನಿವಾರ"], - namesAbbr: ["ಭಾನು.","ಸೋಮ.","ಮಂಗಳ.","ಬುಧ.","ಗುರು.","ಶುಕ್ರ.","ಶನಿ."], - namesShort: ["ರ","ಸ","ಮ","ಬ","ಗ","ಶ","ಶ"] - }, - months: { - names: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""], - namesAbbr: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""] - }, - AM: ["ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ"], - PM: ["ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kn.js deleted file mode 100644 index 65af8db500..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kn.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture kn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kn", "default", { - name: "kn", - englishName: "Kannada", - nativeName: "ಕನ್ನಡ", - language: "kn", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ರೂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ಭಾನುವಾರ","ಸೋಮವಾರ","ಮಂಗಳವಾರ","ಬುಧವಾರ","ಗುರುವಾರ","ಶುಕ್ರವಾರ","ಶನಿವಾರ"], - namesAbbr: ["ಭಾನು.","ಸೋಮ.","ಮಂಗಳ.","ಬುಧ.","ಗುರು.","ಶುಕ್ರ.","ಶನಿ."], - namesShort: ["ರ","ಸ","ಮ","ಬ","ಗ","ಶ","ಶ"] - }, - months: { - names: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""], - namesAbbr: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""] - }, - AM: ["ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ"], - PM: ["ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ko.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ko.js deleted file mode 100644 index 7cd1c93d1c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ko.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Globalize Culture ko - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ko", "default", { - name: "ko", - englishName: "Korean", - nativeName: "한국어", - language: "ko", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - decimals: 0, - symbol: "₩" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["일요일","월요일","화요일","수요일","목요일","금요일","토요일"], - namesAbbr: ["일","월","화","수","목","금","토"], - namesShort: ["일","월","화","수","목","금","토"] - }, - months: { - names: ["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["오전","오전","오전"], - PM: ["오후","오후","오후"], - eras: [{"name":"서기","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy'년' M'월' d'일' dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy'년' M'월' d'일' dddd tt h:mm", - F: "yyyy'년' M'월' d'일' dddd tt h:mm:ss", - M: "M'월' d'일'", - Y: "yyyy'년' M'월'" - } - }, - Korean: { - name: "Korean", - "/": "-", - days: { - names: ["일요일","월요일","화요일","수요일","목요일","금요일","토요일"], - namesAbbr: ["일","월","화","수","목","금","토"], - namesShort: ["일","월","화","수","목","금","토"] - }, - months: { - names: ["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["오전","오전","오전"], - PM: ["오후","오후","오후"], - eras: [{"name":"단기","start":null,"offset":-2333}], - twoDigitYearMax: 4362, - patterns: { - d: "gg yyyy-MM-dd", - D: "gg yyyy'년' M'월' d'일' dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "gg yyyy'년' M'월' d'일' dddd tt h:mm", - F: "gg yyyy'년' M'월' d'일' dddd tt h:mm:ss", - M: "M'월' d'일'", - Y: "gg yyyy'년' M'월'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kok-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kok-IN.js deleted file mode 100644 index 1d9fca166e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kok-IN.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture kok-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kok-IN", "default", { - name: "kok-IN", - englishName: "Konkani (India)", - nativeName: "कोंकणी (भारत)", - language: "kok", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["आयतार","सोमार","मंगळार","बुधवार","बिरेस्तार","सुक्रार","शेनवार"], - namesAbbr: ["आय.","सोम.","मंगळ.","बुध.","बिरे.","सुक्र.","शेन."], - namesShort: ["आ","स","म","ब","ब","स","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""], - namesAbbr: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kok.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kok.js deleted file mode 100644 index f6b3b3ef89..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.kok.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture kok - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "kok", "default", { - name: "kok", - englishName: "Konkani", - nativeName: "कोंकणी", - language: "kok", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["आयतार","सोमार","मंगळार","बुधवार","बिरेस्तार","सुक्रार","शेनवार"], - namesAbbr: ["आय.","सोम.","मंगळ.","बुध.","बिरे.","सुक्र.","शेन."], - namesShort: ["आ","स","म","ब","ब","स","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""], - namesAbbr: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ky-KG.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ky-KG.js deleted file mode 100644 index 1b372f8c82..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ky-KG.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture ky-KG - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ky-KG", "default", { - name: "ky-KG", - englishName: "Kyrgyz (Kyrgyzstan)", - nativeName: "Кыргыз (Кыргызстан)", - language: "ky", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": "-", - symbol: "сом" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жекшемби","Дүйшөмбү","Шейшемби","Шаршемби","Бейшемби","Жума","Ишемби"], - namesAbbr: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"], - namesShort: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"] - }, - months: { - names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d'-'MMMM yyyy'-ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d'-'MMMM yyyy'-ж.' H:mm", - F: "d'-'MMMM yyyy'-ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy'-ж.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ky.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ky.js deleted file mode 100644 index b19156a9dc..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ky.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture ky - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ky", "default", { - name: "ky", - englishName: "Kyrgyz", - nativeName: "Кыргыз", - language: "ky", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": "-", - symbol: "сом" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жекшемби","Дүйшөмбү","Шейшемби","Шаршемби","Бейшемби","Жума","Ишемби"], - namesAbbr: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"], - namesShort: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"] - }, - months: { - names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d'-'MMMM yyyy'-ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d'-'MMMM yyyy'-ж.' H:mm", - F: "d'-'MMMM yyyy'-ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy'-ж.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lb-LU.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lb-LU.js deleted file mode 100644 index 74d0f64f1c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lb-LU.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture lb-LU - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lb-LU", "default", { - name: "lb-LU", - englishName: "Luxembourgish (Luxembourg)", - nativeName: "Lëtzebuergesch (Luxembourg)", - language: "lb", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "n. num.", - negativeInfinity: "-onendlech", - positiveInfinity: "+onendlech", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sonndeg","Méindeg","Dënschdeg","Mëttwoch","Donneschdeg","Freideg","Samschdeg"], - namesAbbr: ["Son","Méi","Dën","Mët","Don","Fre","Sam"], - namesShort: ["So","Mé","Dë","Më","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","Mäerz","Abrëll","Mee","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mäe","Abr","Mee","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lb.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lb.js deleted file mode 100644 index 51c616a57c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lb.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture lb - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lb", "default", { - name: "lb", - englishName: "Luxembourgish", - nativeName: "Lëtzebuergesch", - language: "lb", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "n. num.", - negativeInfinity: "-onendlech", - positiveInfinity: "+onendlech", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sonndeg","Méindeg","Dënschdeg","Mëttwoch","Donneschdeg","Freideg","Samschdeg"], - namesAbbr: ["Son","Méi","Dën","Mët","Don","Fre","Sam"], - namesShort: ["So","Mé","Dë","Më","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","Mäerz","Abrëll","Mee","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mäe","Abr","Mee","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lo-LA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lo-LA.js deleted file mode 100644 index a6f75e9e4b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lo-LA.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture lo-LA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lo-LA", "default", { - name: "lo-LA", - englishName: "Lao (Lao P.D.R.)", - nativeName: "ລາວ (ສ.ປ.ປ. ລາວ)", - language: "lo", - numberFormat: { - pattern: ["(n)"], - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - }, - currency: { - pattern: ["(n$)","n$"], - groupSizes: [3,0], - symbol: "₭" - } - }, - calendars: { - standard: { - days: { - names: ["ວັນອາທິດ","ວັນຈັນ","ວັນອັງຄານ","ວັນພຸດ","ວັນພະຫັດ","ວັນສຸກ","ວັນເສົາ"], - namesAbbr: ["ອາທິດ","ຈັນ","ອັງຄານ","ພຸດ","ພະຫັດ","ສຸກ","ເສົາ"], - namesShort: ["ອ","ຈ","ອ","ພ","ພ","ສ","ເ"] - }, - months: { - names: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""], - namesAbbr: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""] - }, - AM: ["ເຊົ້າ","ເຊົ້າ","ເຊົ້າ"], - PM: ["ແລງ","ແລງ","ແລງ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dd MMMM yyyy H:mm tt", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lo.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lo.js deleted file mode 100644 index 91a0734cf5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lo.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture lo - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lo", "default", { - name: "lo", - englishName: "Lao", - nativeName: "ລາວ", - language: "lo", - numberFormat: { - pattern: ["(n)"], - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - }, - currency: { - pattern: ["(n$)","n$"], - groupSizes: [3,0], - symbol: "₭" - } - }, - calendars: { - standard: { - days: { - names: ["ວັນອາທິດ","ວັນຈັນ","ວັນອັງຄານ","ວັນພຸດ","ວັນພະຫັດ","ວັນສຸກ","ວັນເສົາ"], - namesAbbr: ["ອາທິດ","ຈັນ","ອັງຄານ","ພຸດ","ພະຫັດ","ສຸກ","ເສົາ"], - namesShort: ["ອ","ຈ","ອ","ພ","ພ","ສ","ເ"] - }, - months: { - names: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""], - namesAbbr: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""] - }, - AM: ["ເຊົ້າ","ເຊົ້າ","ເຊົ້າ"], - PM: ["ແລງ","ແລງ","ແລງ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dd MMMM yyyy H:mm tt", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lt-LT.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lt-LT.js deleted file mode 100644 index e61c1c646a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lt-LT.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture lt-LT - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lt-LT", "default", { - name: "lt-LT", - englishName: "Lithuanian (Lithuania)", - nativeName: "lietuvių (Lietuva)", - language: "lt", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-begalybė", - positiveInfinity: "begalybė", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Lt" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sekmadienis","pirmadienis","antradienis","trečiadienis","ketvirtadienis","penktadienis","šeštadienis"], - namesAbbr: ["Sk","Pr","An","Tr","Kt","Pn","Št"], - namesShort: ["S","P","A","T","K","Pn","Š"] - }, - months: { - names: ["sausis","vasaris","kovas","balandis","gegužė","birželis","liepa","rugpjūtis","rugsėjis","spalis","lapkritis","gruodis",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - monthsGenitive: { - names: ["sausio","vasario","kovo","balandžio","gegužės","birželio","liepos","rugpjūčio","rugsėjo","spalio","lapkričio","gruodžio",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd", - D: "yyyy 'm.' MMMM d 'd.'", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'm.' MMMM d 'd.' HH:mm", - F: "yyyy 'm.' MMMM d 'd.' HH:mm:ss", - M: "MMMM d 'd.'", - Y: "yyyy 'm.' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lt.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lt.js deleted file mode 100644 index 56aeb3b34d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lt.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture lt - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lt", "default", { - name: "lt", - englishName: "Lithuanian", - nativeName: "lietuvių", - language: "lt", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-begalybė", - positiveInfinity: "begalybė", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Lt" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sekmadienis","pirmadienis","antradienis","trečiadienis","ketvirtadienis","penktadienis","šeštadienis"], - namesAbbr: ["Sk","Pr","An","Tr","Kt","Pn","Št"], - namesShort: ["S","P","A","T","K","Pn","Š"] - }, - months: { - names: ["sausis","vasaris","kovas","balandis","gegužė","birželis","liepa","rugpjūtis","rugsėjis","spalis","lapkritis","gruodis",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - monthsGenitive: { - names: ["sausio","vasario","kovo","balandžio","gegužės","birželio","liepos","rugpjūčio","rugsėjo","spalio","lapkričio","gruodžio",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd", - D: "yyyy 'm.' MMMM d 'd.'", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'm.' MMMM d 'd.' HH:mm", - F: "yyyy 'm.' MMMM d 'd.' HH:mm:ss", - M: "MMMM d 'd.'", - Y: "yyyy 'm.' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lv-LV.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lv-LV.js deleted file mode 100644 index 60319c4425..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lv-LV.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture lv-LV - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lv-LV", "default", { - name: "lv-LV", - englishName: "Latvian (Latvia)", - nativeName: "latviešu (Latvija)", - language: "lv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-bezgalība", - positiveInfinity: "bezgalība", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": " ", - ".": ",", - symbol: "Ls" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["svētdiena","pirmdiena","otrdiena","trešdiena","ceturtdiena","piektdiena","sestdiena"], - namesAbbr: ["sv","pr","ot","tr","ce","pk","se"], - namesShort: ["sv","pr","ot","tr","ce","pk","se"] - }, - months: { - names: ["janvāris","februāris","marts","aprīlis","maijs","jūnijs","jūlijs","augusts","septembris","oktobris","novembris","decembris",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - monthsGenitive: { - names: ["janvārī","februārī","martā","aprīlī","maijā","jūnijā","jūlijā","augustā","septembrī","oktobrī","novembrī","decembrī",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd.", - D: "dddd, yyyy'. gada 'd. MMMM", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, yyyy'. gada 'd. MMMM H:mm", - F: "dddd, yyyy'. gada 'd. MMMM H:mm:ss", - M: "d. MMMM", - Y: "yyyy. MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lv.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lv.js deleted file mode 100644 index 1324959118..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.lv.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture lv - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "lv", "default", { - name: "lv", - englishName: "Latvian", - nativeName: "latviešu", - language: "lv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-bezgalība", - positiveInfinity: "bezgalība", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": " ", - ".": ",", - symbol: "Ls" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["svētdiena","pirmdiena","otrdiena","trešdiena","ceturtdiena","piektdiena","sestdiena"], - namesAbbr: ["sv","pr","ot","tr","ce","pk","se"], - namesShort: ["sv","pr","ot","tr","ce","pk","se"] - }, - months: { - names: ["janvāris","februāris","marts","aprīlis","maijs","jūnijs","jūlijs","augusts","septembris","oktobris","novembris","decembris",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - monthsGenitive: { - names: ["janvārī","februārī","martā","aprīlī","maijā","jūnijā","jūlijā","augustā","septembrī","oktobrī","novembrī","decembrī",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd.", - D: "dddd, yyyy'. gada 'd. MMMM", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, yyyy'. gada 'd. MMMM H:mm", - F: "dddd, yyyy'. gada 'd. MMMM H:mm:ss", - M: "d. MMMM", - Y: "yyyy. MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mi-NZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mi-NZ.js deleted file mode 100644 index e8498a2c97..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mi-NZ.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture mi-NZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mi-NZ", "default", { - name: "mi-NZ", - englishName: "Maori (New Zealand)", - nativeName: "Reo Māori (Aotearoa)", - language: "mi", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Rātapu","Rāhina","Rātū","Rāapa","Rāpare","Rāmere","Rāhoroi"], - namesAbbr: ["Ta","Hi","Tū","Apa","Pa","Me","Ho"], - namesShort: ["Ta","Hi","Tū","Aa","Pa","Me","Ho"] - }, - months: { - names: ["Kohi-tātea","Hui-tanguru","Poutū-te-rangi","Paenga-whāwhā","Haratua","Pipiri","Hōngongoi","Here-turi-kōkā","Mahuru","Whiringa-ā-nuku","Whiringa-ā-rangi","Hakihea",""], - namesAbbr: ["Kohi","Hui","Pou","Pae","Hara","Pipi","Hōngo","Here","Mahu","Nuku","Rangi","Haki",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM, yyyy", - f: "dddd, dd MMMM, yyyy h:mm tt", - F: "dddd, dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM, yy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mi.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mi.js deleted file mode 100644 index 54e9bbb40a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mi.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture mi - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mi", "default", { - name: "mi", - englishName: "Maori", - nativeName: "Reo Māori", - language: "mi", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Rātapu","Rāhina","Rātū","Rāapa","Rāpare","Rāmere","Rāhoroi"], - namesAbbr: ["Ta","Hi","Tū","Apa","Pa","Me","Ho"], - namesShort: ["Ta","Hi","Tū","Aa","Pa","Me","Ho"] - }, - months: { - names: ["Kohi-tātea","Hui-tanguru","Poutū-te-rangi","Paenga-whāwhā","Haratua","Pipiri","Hōngongoi","Here-turi-kōkā","Mahuru","Whiringa-ā-nuku","Whiringa-ā-rangi","Hakihea",""], - namesAbbr: ["Kohi","Hui","Pou","Pae","Hara","Pipi","Hōngo","Here","Mahu","Nuku","Rangi","Haki",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM, yyyy", - f: "dddd, dd MMMM, yyyy h:mm tt", - F: "dddd, dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM, yy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mk-MK.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mk-MK.js deleted file mode 100644 index d2f9c0471a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mk-MK.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture mk-MK - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mk-MK", "default", { - name: "mk-MK", - englishName: "Macedonian (Former Yugoslav Republic of Macedonia)", - nativeName: "македонски јазик (Македонија)", - language: "mk", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "ден." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недела","понеделник","вторник","среда","четврток","петок","сабота"], - namesAbbr: ["нед","пон","втр","срд","чет","пет","саб"], - namesShort: ["не","по","вт","ср","че","пе","са"] - }, - months: { - names: ["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември",""], - namesAbbr: ["јан","фев","мар","апр","мај","јун","јул","авг","сеп","окт","ное","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "dddd, dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, dd MMMM yyyy HH:mm", - F: "dddd, dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mk.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mk.js deleted file mode 100644 index 0fdc048f00..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mk.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture mk - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mk", "default", { - name: "mk", - englishName: "Macedonian (FYROM)", - nativeName: "македонски јазик", - language: "mk", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "ден." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недела","понеделник","вторник","среда","четврток","петок","сабота"], - namesAbbr: ["нед","пон","втр","срд","чет","пет","саб"], - namesShort: ["не","по","вт","ср","че","пе","са"] - }, - months: { - names: ["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември",""], - namesAbbr: ["јан","фев","мар","апр","мај","јун","јул","авг","сеп","окт","ное","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "dddd, dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, dd MMMM yyyy HH:mm", - F: "dddd, dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ml-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ml-IN.js deleted file mode 100644 index 1c43494a83..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ml-IN.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture ml-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ml-IN", "default", { - name: "ml-IN", - englishName: "Malayalam (India)", - nativeName: "മലയാളം (ഭാരതം)", - language: "ml", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ക" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["ഞായറാഴ്ച","തിങ്കളാഴ്ച","ചൊവ്വാഴ്ച","ബുധനാഴ്ച","വ്യാഴാഴ്ച","വെള്ളിയാഴ്ച","ശനിയാഴ്ച"], - namesAbbr: ["ഞായർ.","തിങ്കൾ.","ചൊവ്വ.","ബുധൻ.","വ്യാഴം.","വെള്ളി.","ശനി."], - namesShort: ["ഞ","ത","ച","ബ","വ","വെ","ശ"] - }, - months: { - names: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""], - namesAbbr: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""] - }, - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ml.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ml.js deleted file mode 100644 index b6b89e8044..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ml.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture ml - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ml", "default", { - name: "ml", - englishName: "Malayalam", - nativeName: "മലയാളം", - language: "ml", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ക" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["ഞായറാഴ്ച","തിങ്കളാഴ്ച","ചൊവ്വാഴ്ച","ബുധനാഴ്ച","വ്യാഴാഴ്ച","വെള്ളിയാഴ്ച","ശനിയാഴ്ച"], - namesAbbr: ["ഞായർ.","തിങ്കൾ.","ചൊവ്വ.","ബുധൻ.","വ്യാഴം.","വെള്ളി.","ശനി."], - namesShort: ["ഞ","ത","ച","ബ","വ","വെ","ശ"] - }, - months: { - names: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""], - namesAbbr: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""] - }, - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Cyrl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Cyrl.js deleted file mode 100644 index dd07a23791..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Cyrl.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture mn-Cyrl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mn-Cyrl", "default", { - name: "mn-Cyrl", - englishName: "Mongolian (Cyrillic)", - nativeName: "Монгол хэл", - language: "mn-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₮" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"], - namesAbbr: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"], - namesShort: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"] - }, - months: { - names: ["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - monthsGenitive: { - names: ["1 дүгээр сарын","2 дугаар сарын","3 дугаар сарын","4 дүгээр сарын","5 дугаар сарын","6 дугаар сарын","7 дугаар сарын","8 дугаар сарын","9 дүгээр сарын","10 дугаар сарын","11 дүгээр сарын","12 дугаар сарын",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - AM: null, - PM: null, - patterns: { - d: "yy.MM.dd", - D: "yyyy 'оны' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'оны' MMMM d H:mm", - F: "yyyy 'оны' MMMM d H:mm:ss", - M: "d MMMM", - Y: "yyyy 'он' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-MN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-MN.js deleted file mode 100644 index 0f0a8a3c50..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-MN.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture mn-MN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mn-MN", "default", { - name: "mn-MN", - englishName: "Mongolian (Cyrillic, Mongolia)", - nativeName: "Монгол хэл (Монгол улс)", - language: "mn-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₮" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"], - namesAbbr: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"], - namesShort: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"] - }, - months: { - names: ["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - monthsGenitive: { - names: ["1 дүгээр сарын","2 дугаар сарын","3 дугаар сарын","4 дүгээр сарын","5 дугаар сарын","6 дугаар сарын","7 дугаар сарын","8 дугаар сарын","9 дүгээр сарын","10 дугаар сарын","11 дүгээр сарын","12 дугаар сарын",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - AM: null, - PM: null, - patterns: { - d: "yy.MM.dd", - D: "yyyy 'оны' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'оны' MMMM d H:mm", - F: "yyyy 'оны' MMMM d H:mm:ss", - M: "d MMMM", - Y: "yyyy 'он' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Mong-CN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Mong-CN.js deleted file mode 100644 index 02f2e0b2a8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Mong-CN.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture mn-Mong-CN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mn-Mong-CN", "default", { - name: "mn-Mong-CN", - englishName: "Mongolian (Traditional Mongolian, PRC)", - nativeName: "ᠮᠤᠨᠭᠭᠤᠯ ᠬᠡᠯᠡ (ᠪᠦᠭᠦᠳᠡ ᠨᠠᠢᠷᠠᠮᠳᠠᠬᠤ ᠳᠤᠮᠳᠠᠳᠤ ᠠᠷᠠᠳ ᠣᠯᠣᠰ)", - language: "mn-Mong", - numberFormat: { - groupSizes: [3,0], - "NaN": "ᠲᠤᠭᠠᠠ ᠪᠤᠰᠤ", - negativeInfinity: "ᠰᠦᠬᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠡᠬᠡ", - positiveInfinity: "ᠡᠶ᠋ᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠠᠬᠡ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesAbbr: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesShort: ["ᠡ\u200d","ᠨᠢ\u200d","ᠬᠣ\u200d","ᠭᠤ\u200d","ᠳᠥ\u200d","ᠲᠠ\u200d","ᠵᠢ\u200d"] - }, - months: { - names: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""], - namesAbbr: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""] - }, - AM: null, - PM: null, - eras: [{"name":"ᠣᠨ ᠲᠣᠭᠠᠯᠠᠯ ᠤᠨ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm", - F: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm:ss", - M: "M'ᠰᠠᠷ᠎ᠠ' d'ᠡᠳᠦᠷ'", - Y: "yyyy'ᠣᠨ' M'ᠰᠠᠷ᠎ᠠ'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Mong.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Mong.js deleted file mode 100644 index 7f21608e25..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn-Mong.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture mn-Mong - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mn-Mong", "default", { - name: "mn-Mong", - englishName: "Mongolian (Traditional Mongolian)", - nativeName: "ᠮᠤᠨᠭᠭᠤᠯ ᠬᠡᠯᠡ", - language: "mn-Mong", - numberFormat: { - groupSizes: [3,0], - "NaN": "ᠲᠤᠭᠠᠠ ᠪᠤᠰᠤ", - negativeInfinity: "ᠰᠦᠬᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠡᠬᠡ", - positiveInfinity: "ᠡᠶ᠋ᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠠᠬᠡ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesAbbr: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesShort: ["ᠡ\u200d","ᠨᠢ\u200d","ᠬᠣ\u200d","ᠭᠤ\u200d","ᠳᠥ\u200d","ᠲᠠ\u200d","ᠵᠢ\u200d"] - }, - months: { - names: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""], - namesAbbr: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""] - }, - AM: null, - PM: null, - eras: [{"name":"ᠣᠨ ᠲᠣᠭᠠᠯᠠᠯ ᠤᠨ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm", - F: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm:ss", - M: "M'ᠰᠠᠷ᠎ᠠ' d'ᠡᠳᠦᠷ'", - Y: "yyyy'ᠣᠨ' M'ᠰᠠᠷ᠎ᠠ'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn.js deleted file mode 100644 index 5d43c23b9e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mn.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture mn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mn", "default", { - name: "mn", - englishName: "Mongolian", - nativeName: "Монгол хэл", - language: "mn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₮" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"], - namesAbbr: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"], - namesShort: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"] - }, - months: { - names: ["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - monthsGenitive: { - names: ["1 дүгээр сарын","2 дугаар сарын","3 дугаар сарын","4 дүгээр сарын","5 дугаар сарын","6 дугаар сарын","7 дугаар сарын","8 дугаар сарын","9 дүгээр сарын","10 дугаар сарын","11 дүгээр сарын","12 дугаар сарын",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - AM: null, - PM: null, - patterns: { - d: "yy.MM.dd", - D: "yyyy 'оны' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'оны' MMMM d H:mm", - F: "yyyy 'оны' MMMM d H:mm:ss", - M: "d MMMM", - Y: "yyyy 'он' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.moh-CA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.moh-CA.js deleted file mode 100644 index 98a5a2e3b2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.moh-CA.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Globalize Culture moh-CA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "moh-CA", "default", { - name: "moh-CA", - englishName: "Mohawk (Mohawk)", - nativeName: "Kanien'kéha", - language: "moh", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Awentatokentì:ke","Awentataón'ke","Ratironhia'kehronòn:ke","Soséhne","Okaristiiáhne","Ronwaia'tanentaktonhne","Entákta"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["Tsothohrkó:Wa","Enniska","Enniskó:Wa","Onerahtókha","Onerahtohkó:Wa","Ohiari:Ha","Ohiarihkó:Wa","Seskéha","Seskehkó:Wa","Kenténha","Kentenhkó:Wa","Tsothóhrha",""] - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.moh.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.moh.js deleted file mode 100644 index 2bd054c439..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.moh.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Globalize Culture moh - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "moh", "default", { - name: "moh", - englishName: "Mohawk", - nativeName: "Kanien'kéha", - language: "moh", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Awentatokentì:ke","Awentataón'ke","Ratironhia'kehronòn:ke","Soséhne","Okaristiiáhne","Ronwaia'tanentaktonhne","Entákta"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["Tsothohrkó:Wa","Enniska","Enniskó:Wa","Onerahtókha","Onerahtohkó:Wa","Ohiari:Ha","Ohiarihkó:Wa","Seskéha","Seskehkó:Wa","Kenténha","Kentenhkó:Wa","Tsothóhrha",""] - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mr-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mr-IN.js deleted file mode 100644 index cc703a2f71..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mr-IN.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture mr-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mr-IN", "default", { - name: "mr-IN", - englishName: "Marathi (India)", - nativeName: "मराठी (भारत)", - language: "mr", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["रविवार","सोमवार","मंगळवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"], - namesAbbr: ["रवि.","सोम.","मंगळ.","बुध.","गुरु.","शुक्र.","शनि."], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोव्हेंबर","डिसेंबर",""], - namesAbbr: ["जाने.","फेब्रु.","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टें.","ऑक्टो.","नोव्हें.","डिसें.",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mr.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mr.js deleted file mode 100644 index 2d275bef4f..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mr.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture mr - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mr", "default", { - name: "mr", - englishName: "Marathi", - nativeName: "मराठी", - language: "mr", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["रविवार","सोमवार","मंगळवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"], - namesAbbr: ["रवि.","सोम.","मंगळ.","बुध.","गुरु.","शुक्र.","शनि."], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोव्हेंबर","डिसेंबर",""], - namesAbbr: ["जाने.","फेब्रु.","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टें.","ऑक्टो.","नोव्हें.","डिसें.",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms-BN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms-BN.js deleted file mode 100644 index f6b62299b8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms-BN.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture ms-BN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ms-BN", "default", { - name: "ms-BN", - englishName: "Malay (Brunei Darussalam)", - nativeName: "Bahasa Melayu (Brunei Darussalam)", - language: "ms", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - decimals: 0, - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"], - namesAbbr: ["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"], - namesShort: ["A","I","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms-MY.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms-MY.js deleted file mode 100644 index 7a55c388f5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms-MY.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture ms-MY - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ms-MY", "default", { - name: "ms-MY", - englishName: "Malay (Malaysia)", - nativeName: "Bahasa Melayu (Malaysia)", - language: "ms", - numberFormat: { - currency: { - decimals: 0, - symbol: "RM" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"], - namesAbbr: ["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"], - namesShort: ["A","I","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms.js deleted file mode 100644 index 9a8ed21f95..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ms.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture ms - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ms", "default", { - name: "ms", - englishName: "Malay", - nativeName: "Bahasa Melayu", - language: "ms", - numberFormat: { - currency: { - decimals: 0, - symbol: "RM" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"], - namesAbbr: ["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"], - namesShort: ["A","I","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mt-MT.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mt-MT.js deleted file mode 100644 index 639c9020ef..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mt-MT.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Globalize Culture mt-MT - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mt-MT", "default", { - name: "mt-MT", - englishName: "Maltese (Malta)", - nativeName: "Malti (Malta)", - language: "mt", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Il-Ħadd","It-Tnejn","It-Tlieta","L-Erbgħa","Il-Ħamis","Il-Ġimgħa","Is-Sibt"], - namesAbbr: ["Ħad","Tne","Tli","Erb","Ħam","Ġim","Sib"], - namesShort: ["I","I","I","L","I","I","I"] - }, - months: { - names: ["Jannar","Frar","Marzu","April","Mejju","Ġunju","Lulju","Awissu","Settembru","Ottubru","Novembru","Diċembru",""], - namesAbbr: ["Jan","Fra","Mar","Apr","Mej","Ġun","Lul","Awi","Set","Ott","Nov","Diċ",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' ta\\' 'MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' ta\\' 'MMMM yyyy HH:mm", - F: "dddd, d' ta\\' 'MMMM yyyy HH:mm:ss", - M: "d' ta\\' 'MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mt.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mt.js deleted file mode 100644 index cde5105408..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.mt.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Globalize Culture mt - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "mt", "default", { - name: "mt", - englishName: "Maltese", - nativeName: "Malti", - language: "mt", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Il-Ħadd","It-Tnejn","It-Tlieta","L-Erbgħa","Il-Ħamis","Il-Ġimgħa","Is-Sibt"], - namesAbbr: ["Ħad","Tne","Tli","Erb","Ħam","Ġim","Sib"], - namesShort: ["I","I","I","L","I","I","I"] - }, - months: { - names: ["Jannar","Frar","Marzu","April","Mejju","Ġunju","Lulju","Awissu","Settembru","Ottubru","Novembru","Diċembru",""], - namesAbbr: ["Jan","Fra","Mar","Apr","Mej","Ġun","Lul","Awi","Set","Ott","Nov","Diċ",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' ta\\' 'MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' ta\\' 'MMMM yyyy HH:mm", - F: "dddd, d' ta\\' 'MMMM yyyy HH:mm:ss", - M: "d' ta\\' 'MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nb.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nb.js deleted file mode 100644 index 8b959ed6bd..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nb.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture nb - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "nb", "default", { - name: "nb", - englishName: "Norwegian (Bokmål)", - nativeName: "norsk (bokmål)", - language: "nb", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ne-NP.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ne-NP.js deleted file mode 100644 index e353fbac60..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ne-NP.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Globalize Culture ne-NP - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ne-NP", "default", { - name: "ne-NP", - englishName: "Nepali (Nepal)", - nativeName: "नेपाली (नेपाल)", - language: "ne", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "रु" - } - }, - calendars: { - standard: { - days: { - names: ["आइतवार","सोमवार","मङ्गलवार","बुधवार","बिहीवार","शुक्रवार","शनिवार"], - namesAbbr: ["आइत","सोम","मङ्गल","बुध","बिही","शुक्र","शनि"], - namesShort: ["आ","सो","म","बु","बि","शु","श"] - }, - months: { - names: ["जनवरी","फेब्रुअरी","मार्च","अप्रिल","मे","जून","जुलाई","अगस्त","सेप्टेम्बर","अक्टोबर","नोभेम्बर","डिसेम्बर",""], - namesAbbr: ["जन","फेब","मार्च","अप्रिल","मे","जून","जुलाई","अग","सेप्ट","अक्ट","नोभ","डिस",""] - }, - AM: ["विहानी","विहानी","विहानी"], - PM: ["बेलुकी","बेलुकी","बेलुकी"], - eras: [{"name":"a.d.","start":null,"offset":0}], - patterns: { - Y: "MMMM,yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ne.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ne.js deleted file mode 100644 index c36a960128..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ne.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Globalize Culture ne - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ne", "default", { - name: "ne", - englishName: "Nepali", - nativeName: "नेपाली", - language: "ne", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "रु" - } - }, - calendars: { - standard: { - days: { - names: ["आइतवार","सोमवार","मङ्गलवार","बुधवार","बिहीवार","शुक्रवार","शनिवार"], - namesAbbr: ["आइत","सोम","मङ्गल","बुध","बिही","शुक्र","शनि"], - namesShort: ["आ","सो","म","बु","बि","शु","श"] - }, - months: { - names: ["जनवरी","फेब्रुअरी","मार्च","अप्रिल","मे","जून","जुलाई","अगस्त","सेप्टेम्बर","अक्टोबर","नोभेम्बर","डिसेम्बर",""], - namesAbbr: ["जन","फेब","मार्च","अप्रिल","मे","जून","जुलाई","अग","सेप्ट","अक्ट","नोभ","डिस",""] - }, - AM: ["विहानी","विहानी","विहानी"], - PM: ["बेलुकी","बेलुकी","बेलुकी"], - eras: [{"name":"a.d.","start":null,"offset":0}], - patterns: { - Y: "MMMM,yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nl.js deleted file mode 100644 index cb58ea8703..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nl.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture nl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "nl", "default", { - name: "nl", - englishName: "Dutch", - nativeName: "Nederlands", - language: "nl", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"], - namesAbbr: ["zo","ma","di","wo","do","vr","za"], - namesShort: ["zo","ma","di","wo","do","vr","za"] - }, - months: { - names: ["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d-M-yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nn-NO.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nn-NO.js deleted file mode 100644 index e50b1e5293..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nn-NO.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture nn-NO - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "nn-NO", "default", { - name: "nn-NO", - englishName: "Norwegian, Nynorsk (Norway)", - nativeName: "norsk, nynorsk (Noreg)", - language: "nn", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","måndag","tysdag","onsdag","torsdag","fredag","laurdag"], - namesAbbr: ["sø","må","ty","on","to","fr","la"], - namesShort: ["sø","må","ty","on","to","fr","la"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nn.js deleted file mode 100644 index 7f5fa46ee6..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nn.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture nn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "nn", "default", { - name: "nn", - englishName: "Norwegian (Nynorsk)", - nativeName: "norsk (nynorsk)", - language: "nn", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","måndag","tysdag","onsdag","torsdag","fredag","laurdag"], - namesAbbr: ["sø","må","ty","on","to","fr","la"], - namesShort: ["sø","må","ty","on","to","fr","la"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.no.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.no.js deleted file mode 100644 index 5f38c7137e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.no.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture no - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "no", "default", { - name: "no", - englishName: "Norwegian", - nativeName: "norsk", - language: "no", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nso-ZA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nso-ZA.js deleted file mode 100644 index d334ee0f93..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nso-ZA.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture nso-ZA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "nso-ZA", "default", { - name: "nso-ZA", - englishName: "Sesotho sa Leboa (South Africa)", - nativeName: "Sesotho sa Leboa (Afrika Borwa)", - language: "nso", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Lamorena","Mošupologo","Labobedi","Laboraro","Labone","Labohlano","Mokibelo"], - namesAbbr: ["Lam","Moš","Lbb","Lbr","Lbn","Lbh","Mok"], - namesShort: ["L","M","L","L","L","L","M"] - }, - months: { - names: ["Pherekgong","Hlakola","Mopitlo","Moranang","Mosegamanye","Ngoatobošego","Phuphu","Phato","Lewedi","Diphalana","Dibatsela","Manthole",""], - namesAbbr: ["Pher","Hlak","Mop","Mor","Mos","Ngwat","Phup","Phat","Lew","Dip","Dib","Man",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nso.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nso.js deleted file mode 100644 index 9933d40504..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.nso.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture nso - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "nso", "default", { - name: "nso", - englishName: "Sesotho sa Leboa", - nativeName: "Sesotho sa Leboa", - language: "nso", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Lamorena","Mošupologo","Labobedi","Laboraro","Labone","Labohlano","Mokibelo"], - namesAbbr: ["Lam","Moš","Lbb","Lbr","Lbn","Lbh","Mok"], - namesShort: ["L","M","L","L","L","L","M"] - }, - months: { - names: ["Pherekgong","Hlakola","Mopitlo","Moranang","Mosegamanye","Ngoatobošego","Phuphu","Phato","Lewedi","Diphalana","Dibatsela","Manthole",""], - namesAbbr: ["Pher","Hlak","Mop","Mor","Mos","Ngwat","Phup","Phat","Lew","Dip","Dib","Man",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.oc-FR.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.oc-FR.js deleted file mode 100644 index c175e7c5a2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.oc-FR.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture oc-FR - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "oc-FR", "default", { - name: "oc-FR", - englishName: "Occitan (France)", - nativeName: "Occitan (França)", - language: "oc", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numeric", - negativeInfinity: "-Infinit", - positiveInfinity: "+Infinit", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimenge","diluns","dimars","dimècres","dijòus","divendres","dissabte"], - namesAbbr: ["dim.","lun.","mar.","mèc.","jòu.","ven.","sab."], - namesShort: ["di","lu","ma","mè","jò","ve","sa"] - }, - months: { - names: ["genier","febrier","març","abril","mai","junh","julh","agost","setembre","octobre","novembre","desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - monthsGenitive: { - names: ["de genier","de febrier","de març","d'abril","de mai","de junh","de julh","d'agost","de setembre","d'octobre","de novembre","de desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - AM: null, - PM: null, - eras: [{"name":"après Jèsus-Crist","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd,' lo 'd MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd,' lo 'd MMMM' de 'yyyy HH:mm", - F: "dddd,' lo 'd MMMM' de 'yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.oc.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.oc.js deleted file mode 100644 index 7547503bf4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.oc.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture oc - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "oc", "default", { - name: "oc", - englishName: "Occitan", - nativeName: "Occitan", - language: "oc", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numeric", - negativeInfinity: "-Infinit", - positiveInfinity: "+Infinit", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimenge","diluns","dimars","dimècres","dijòus","divendres","dissabte"], - namesAbbr: ["dim.","lun.","mar.","mèc.","jòu.","ven.","sab."], - namesShort: ["di","lu","ma","mè","jò","ve","sa"] - }, - months: { - names: ["genier","febrier","març","abril","mai","junh","julh","agost","setembre","octobre","novembre","desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - monthsGenitive: { - names: ["de genier","de febrier","de març","d'abril","de mai","de junh","de julh","d'agost","de setembre","d'octobre","de novembre","de desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - AM: null, - PM: null, - eras: [{"name":"après Jèsus-Crist","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd,' lo 'd MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd,' lo 'd MMMM' de 'yyyy HH:mm", - F: "dddd,' lo 'd MMMM' de 'yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.or-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.or-IN.js deleted file mode 100644 index 2da61a78be..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.or-IN.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Globalize Culture or-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "or-IN", "default", { - name: "or-IN", - englishName: "Oriya (India)", - nativeName: "ଓଡ଼ିଆ (ଭାରତ)", - language: "or", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ଟ" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ରବିବାର","ସୋମବାର","ମଙ୍ଗଳବାର","ବୁଧବାର","ଗୁରୁବାର","ଶୁକ୍ରବାର","ଶନିବାର"], - namesAbbr: ["ରବି.","ସୋମ.","ମଙ୍ଗଳ.","ବୁଧ.","ଗୁରୁ.","ଶୁକ୍ର.","ଶନି."], - namesShort: ["ର","ସୋ","ମ","ବୁ","ଗୁ","ଶୁ","ଶ"] - }, - months: { - names: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""], - namesAbbr: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""] - }, - eras: [{"name":"ଖ୍ରୀଷ୍ଟାବ୍ଦ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.or.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.or.js deleted file mode 100644 index 3ce2909a96..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.or.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Globalize Culture or - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "or", "default", { - name: "or", - englishName: "Oriya", - nativeName: "ଓଡ଼ିଆ", - language: "or", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ଟ" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ରବିବାର","ସୋମବାର","ମଙ୍ଗଳବାର","ବୁଧବାର","ଗୁରୁବାର","ଶୁକ୍ରବାର","ଶନିବାର"], - namesAbbr: ["ରବି.","ସୋମ.","ମଙ୍ଗଳ.","ବୁଧ.","ଗୁରୁ.","ଶୁକ୍ର.","ଶନି."], - namesShort: ["ର","ସୋ","ମ","ବୁ","ଗୁ","ଶୁ","ଶ"] - }, - months: { - names: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""], - namesAbbr: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""] - }, - eras: [{"name":"ଖ୍ରୀଷ୍ଟାବ୍ଦ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pa-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pa-IN.js deleted file mode 100644 index dcaab14f12..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pa-IN.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture pa-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "pa-IN", "default", { - name: "pa-IN", - englishName: "Punjabi (India)", - nativeName: "ਪੰਜਾਬੀ (ਭਾਰਤ)", - language: "pa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ਰੁ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ਐਤਵਾਰ","ਸੋਮਵਾਰ","ਮੰਗਲਵਾਰ","ਬੁੱਧਵਾਰ","ਵੀਰਵਾਰ","ਸ਼ੁੱਕਰਵਾਰ","ਸ਼ਨਿੱਚਰਵਾਰ"], - namesAbbr: ["ਐਤ.","ਸੋਮ.","ਮੰਗਲ.","ਬੁੱਧ.","ਵੀਰ.","ਸ਼ੁਕਰ.","ਸ਼ਨਿੱਚਰ."], - namesShort: ["ਐ","ਸ","ਮ","ਬ","ਵ","ਸ਼","ਸ਼"] - }, - months: { - names: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""], - namesAbbr: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""] - }, - AM: ["ਸਵੇਰ","ਸਵੇਰ","ਸਵੇਰ"], - PM: ["ਸ਼ਾਮ","ਸ਼ਾਮ","ਸ਼ਾਮ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy dddd", - t: "tt hh:mm", - T: "tt hh:mm:ss", - f: "dd MMMM yyyy dddd tt hh:mm", - F: "dd MMMM yyyy dddd tt hh:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pa.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pa.js deleted file mode 100644 index 74cbec2759..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pa.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture pa - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "pa", "default", { - name: "pa", - englishName: "Punjabi", - nativeName: "ਪੰਜਾਬੀ", - language: "pa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ਰੁ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ਐਤਵਾਰ","ਸੋਮਵਾਰ","ਮੰਗਲਵਾਰ","ਬੁੱਧਵਾਰ","ਵੀਰਵਾਰ","ਸ਼ੁੱਕਰਵਾਰ","ਸ਼ਨਿੱਚਰਵਾਰ"], - namesAbbr: ["ਐਤ.","ਸੋਮ.","ਮੰਗਲ.","ਬੁੱਧ.","ਵੀਰ.","ਸ਼ੁਕਰ.","ਸ਼ਨਿੱਚਰ."], - namesShort: ["ਐ","ਸ","ਮ","ਬ","ਵ","ਸ਼","ਸ਼"] - }, - months: { - names: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""], - namesAbbr: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""] - }, - AM: ["ਸਵੇਰ","ਸਵੇਰ","ਸਵੇਰ"], - PM: ["ਸ਼ਾਮ","ਸ਼ਾਮ","ਸ਼ਾਮ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy dddd", - t: "tt hh:mm", - T: "tt hh:mm:ss", - f: "dd MMMM yyyy dddd tt hh:mm", - F: "dd MMMM yyyy dddd tt hh:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pl.js deleted file mode 100644 index 2a1188d201..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pl.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture pl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "pl", "default", { - name: "pl", - englishName: "Polish", - nativeName: "polski", - language: "pl", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "nie jest liczbą", - negativeInfinity: "-nieskończoność", - positiveInfinity: "+nieskończoność", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "zł" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["niedziela","poniedziałek","wtorek","środa","czwartek","piątek","sobota"], - namesAbbr: ["niedz.","pon.","wt.","śr.","czw.","pt.","sob."], - namesShort: ["N","Pn","Wt","Śr","Cz","Pt","So"] - }, - months: { - names: ["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień",""], - namesAbbr: ["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru",""] - }, - monthsGenitive: { - names: ["stycznia","lutego","marca","kwietnia","maja","czerwca","lipca","sierpnia","września","października","listopada","grudnia",""], - namesAbbr: ["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.prs-AF.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.prs-AF.js deleted file mode 100644 index b50d2112b5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.prs-AF.js +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Globalize Culture prs-AF - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "prs-AF", "default", { - name: "prs-AF", - englishName: "Dari (Afghanistan)", - nativeName: "درى (افغانستان)", - language: "prs", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 5, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 5, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.prs.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.prs.js deleted file mode 100644 index aaf297baa8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.prs.js +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Globalize Culture prs - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "prs", "default", { - name: "prs", - englishName: "Dari", - nativeName: "درى", - language: "prs", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 5, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 5, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ps-AF.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ps-AF.js deleted file mode 100644 index bf38c1bcd3..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ps-AF.js +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Globalize Culture ps-AF - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ps-AF", "default", { - name: "ps-AF", - englishName: "Pashto (Afghanistan)", - nativeName: "پښتو (افغانستان)", - language: "ps", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": "،", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": "،", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - ",": "٬", - ".": "٫", - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښزمرى","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښ","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ps.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ps.js deleted file mode 100644 index 9220a759a8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ps.js +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Globalize Culture ps - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ps", "default", { - name: "ps", - englishName: "Pashto", - nativeName: "پښتو", - language: "ps", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": "،", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": "،", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - ",": "٬", - ".": "٫", - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښزمرى","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښ","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pt.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pt.js deleted file mode 100644 index 45cbbff6a5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.pt.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture pt - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "pt", "default", { - name: "pt", - englishName: "Portuguese", - nativeName: "Português", - language: "pt", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NaN (Não é um número)", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": ",", - symbol: "R$" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"], - namesAbbr: ["dom","seg","ter","qua","qui","sex","sáb"], - namesShort: ["D","S","T","Q","Q","S","S"] - }, - months: { - names: ["janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro",""], - namesAbbr: ["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' de 'MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' de 'MMMM' de 'yyyy HH:mm", - F: "dddd, d' de 'MMMM' de 'yyyy HH:mm:ss", - M: "dd' de 'MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.qut-GT.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.qut-GT.js deleted file mode 100644 index 40f86587e1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.qut-GT.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Globalize Culture qut-GT - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "qut-GT", "default", { - name: "qut-GT", - englishName: "K'iche (Guatemala)", - nativeName: "K'iche (Guatemala)", - language: "qut", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - symbol: "Q" - } - }, - calendars: { - standard: { - days: { - names: ["juq'ij","kaq'ij","oxq'ij","kajq'ij","joq'ij","waqq'ij","wuqq'ij"], - namesAbbr: ["juq","kaq","oxq","kajq","joq","waqq","wuqq"], - namesShort: ["ju","ka","ox","ka","jo","wa","wu"] - }, - months: { - names: ["nab'e ik'","ukab' ik'","rox ik'","ukaj ik'","uro' ik'","uwaq ik'","uwuq ik'","uwajxaq ik'","ub'elej ik'","ulaj ik'","ujulaj ik'","ukab'laj ik'",""], - namesAbbr: ["nab'e","ukab","rox","ukaj","uro","uwaq","uwuq","uwajxaq","ub'elej","ulaj","ujulaj","ukab'laj",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.qut.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.qut.js deleted file mode 100644 index 6d6569d13d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.qut.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Globalize Culture qut - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "qut", "default", { - name: "qut", - englishName: "K'iche", - nativeName: "K'iche", - language: "qut", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - symbol: "Q" - } - }, - calendars: { - standard: { - days: { - names: ["juq'ij","kaq'ij","oxq'ij","kajq'ij","joq'ij","waqq'ij","wuqq'ij"], - namesAbbr: ["juq","kaq","oxq","kajq","joq","waqq","wuqq"], - namesShort: ["ju","ka","ox","ka","jo","wa","wu"] - }, - months: { - names: ["nab'e ik'","ukab' ik'","rox ik'","ukaj ik'","uro' ik'","uwaq ik'","uwuq ik'","uwajxaq ik'","ub'elej ik'","ulaj ik'","ujulaj ik'","ukab'laj ik'",""], - namesAbbr: ["nab'e","ukab","rox","ukaj","uro","uwaq","uwuq","uwajxaq","ub'elej","ulaj","ujulaj","ukab'laj",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-BO.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-BO.js deleted file mode 100644 index 72a80e682a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-BO.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture quz-BO - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "quz-BO", "default", { - name: "quz-BO", - englishName: "Quechua (Bolivia)", - nativeName: "runasimi (Qullasuyu)", - language: "quz", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": ",", - symbol: "$b" - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-EC.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-EC.js deleted file mode 100644 index 30c4b2f492..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-EC.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Globalize Culture quz-EC - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "quz-EC", "default", { - name: "quz-EC", - englishName: "Quechua (Ecuador)", - nativeName: "runasimi (Ecuador)", - language: "quz", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-PE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-PE.js deleted file mode 100644 index e98b31002f..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz-PE.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Globalize Culture quz-PE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "quz-PE", "default", { - name: "quz-PE", - englishName: "Quechua (Peru)", - nativeName: "runasimi (Piruw)", - language: "quz", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$ -n","$ n"], - symbol: "S/." - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz.js deleted file mode 100644 index 705134da67..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.quz.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Globalize Culture quz - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "quz", "default", { - name: "quz", - englishName: "Quechua", - nativeName: "runasimi", - language: "quz", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": ",", - symbol: "$b" - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rm-CH.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rm-CH.js deleted file mode 100644 index bac6d143d9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rm-CH.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture rm-CH - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "rm-CH", "default", { - name: "rm-CH", - englishName: "Romansh (Switzerland)", - nativeName: "Rumantsch (Svizra)", - language: "rm", - numberFormat: { - ",": "'", - "NaN": "betg def.", - negativeInfinity: "-infinit", - positiveInfinity: "+infinit", - percent: { - pattern: ["-n%","n%"], - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "fr." - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumengia","glindesdi","mardi","mesemna","gievgia","venderdi","sonda"], - namesAbbr: ["du","gli","ma","me","gie","ve","so"], - namesShort: ["du","gli","ma","me","gie","ve","so"] - }, - months: { - names: ["schaner","favrer","mars","avrigl","matg","zercladur","fanadur","avust","settember","october","november","december",""], - namesAbbr: ["schan","favr","mars","avr","matg","zercl","fan","avust","sett","oct","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"s. Cr.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d MMMM yyyy HH:mm", - F: "dddd, d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rm.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rm.js deleted file mode 100644 index 761118dd86..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rm.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture rm - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "rm", "default", { - name: "rm", - englishName: "Romansh", - nativeName: "Rumantsch", - language: "rm", - numberFormat: { - ",": "'", - "NaN": "betg def.", - negativeInfinity: "-infinit", - positiveInfinity: "+infinit", - percent: { - pattern: ["-n%","n%"], - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "fr." - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumengia","glindesdi","mardi","mesemna","gievgia","venderdi","sonda"], - namesAbbr: ["du","gli","ma","me","gie","ve","so"], - namesShort: ["du","gli","ma","me","gie","ve","so"] - }, - months: { - names: ["schaner","favrer","mars","avrigl","matg","zercladur","fanadur","avust","settember","october","november","december",""], - namesAbbr: ["schan","favr","mars","avr","matg","zercl","fan","avust","sett","oct","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"s. Cr.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d MMMM yyyy HH:mm", - F: "dddd, d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ro.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ro.js deleted file mode 100644 index 3d5ac20b6d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ro.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture ro - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ro", "default", { - name: "ro", - englishName: "Romanian", - nativeName: "română", - language: "ro", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "lei" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["duminică","luni","marţi","miercuri","joi","vineri","sâmbătă"], - namesAbbr: ["D","L","Ma","Mi","J","V","S"], - namesShort: ["D","L","Ma","Mi","J","V","S"] - }, - months: { - names: ["ianuarie","februarie","martie","aprilie","mai","iunie","iulie","august","septembrie","octombrie","noiembrie","decembrie",""], - namesAbbr: ["ian.","feb.","mar.","apr.","mai.","iun.","iul.","aug.","sep.","oct.","nov.","dec.",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ru.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ru.js deleted file mode 100644 index 23d54fa7ac..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ru.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Globalize Culture ru - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ru", "default", { - name: "ru", - englishName: "Russian", - nativeName: "русский", - language: "ru", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["воскресенье","понедельник","вторник","среда","четверг","пятница","суббота"], - namesAbbr: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"], - namesShort: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"] - }, - months: { - names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - monthsGenitive: { - names: ["января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря",""], - namesAbbr: ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy 'г.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'г.' H:mm", - F: "d MMMM yyyy 'г.' H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rw-RW.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rw-RW.js deleted file mode 100644 index 6052f4df0c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rw-RW.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Globalize Culture rw-RW - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "rw-RW", "default", { - name: "rw-RW", - englishName: "Kinyarwanda (Rwanda)", - nativeName: "Kinyarwanda (Rwanda)", - language: "rw", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$-n","$ n"], - ",": " ", - ".": ",", - symbol: "RWF" - } - }, - calendars: { - standard: { - days: { - names: ["Ku wa mbere","Ku wa kabiri","Ku wa gatatu","Ku wa kane","Ku wa gatanu","Ku wa gatandatu","Ku cyumweru"], - namesAbbr: ["mbe.","kab.","gat.","kan.","gat.","gat.","cyu."], - namesShort: ["mb","ka","ga","ka","ga","ga","cy"] - }, - months: { - names: ["Mutarama","Gashyantare","Werurwe","Mata","Gicurasi","Kamena","Nyakanga","Kanama","Nzeli","Ukwakira","Ugushyingo","Ukuboza",""], - namesAbbr: ["Mut","Gas","Wer","Mat","Gic","Kam","Nya","Kan","Nze","Ukwa","Ugu","Uku",""] - }, - AM: ["saa moya z.m.","saa moya z.m.","SAA MOYA Z.M."], - PM: ["saa moya z.n.","saa moya z.n.","SAA MOYA Z.N."], - eras: [{"name":"AD","start":null,"offset":0}] - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rw.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rw.js deleted file mode 100644 index 8d63d977bb..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.rw.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Globalize Culture rw - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "rw", "default", { - name: "rw", - englishName: "Kinyarwanda", - nativeName: "Kinyarwanda", - language: "rw", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$-n","$ n"], - ",": " ", - ".": ",", - symbol: "RWF" - } - }, - calendars: { - standard: { - days: { - names: ["Ku wa mbere","Ku wa kabiri","Ku wa gatatu","Ku wa kane","Ku wa gatanu","Ku wa gatandatu","Ku cyumweru"], - namesAbbr: ["mbe.","kab.","gat.","kan.","gat.","gat.","cyu."], - namesShort: ["mb","ka","ga","ka","ga","ga","cy"] - }, - months: { - names: ["Mutarama","Gashyantare","Werurwe","Mata","Gicurasi","Kamena","Nyakanga","Kanama","Nzeli","Ukwakira","Ugushyingo","Ukuboza",""], - namesAbbr: ["Mut","Gas","Wer","Mat","Gic","Kam","Nya","Kan","Nze","Ukwa","Ugu","Uku",""] - }, - AM: ["saa moya z.m.","saa moya z.m.","SAA MOYA Z.M."], - PM: ["saa moya z.n.","saa moya z.n.","SAA MOYA Z.N."], - eras: [{"name":"AD","start":null,"offset":0}] - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sa-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sa-IN.js deleted file mode 100644 index b94958d16b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sa-IN.js +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Globalize Culture sa-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sa-IN", "default", { - name: "sa-IN", - englishName: "Sanskrit (India)", - nativeName: "संस्कृत (भारतम्)", - language: "sa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesAbbr: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""], - namesAbbr: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""] - }, - AM: ["पूर्वाह्न","पूर्वाह्न","पूर्वाह्न"], - PM: ["अपराह्न","अपराह्न","अपराह्न"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy dddd", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy dddd HH:mm", - F: "dd MMMM yyyy dddd HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sa.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sa.js deleted file mode 100644 index 059f4bf551..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sa.js +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Globalize Culture sa - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sa", "default", { - name: "sa", - englishName: "Sanskrit", - nativeName: "संस्कृत", - language: "sa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesAbbr: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""], - namesAbbr: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""] - }, - AM: ["पूर्वाह्न","पूर्वाह्न","पूर्वाह्न"], - PM: ["अपराह्न","अपराह्न","अपराह्न"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy dddd", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy dddd HH:mm", - F: "dd MMMM yyyy dddd HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sah-RU.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sah-RU.js deleted file mode 100644 index 7d1ae37e28..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sah-RU.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture sah-RU - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sah-RU", "default", { - name: "sah-RU", - englishName: "Yakut (Russia)", - nativeName: "саха (Россия)", - language: "sah", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NAN", - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "с." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["баскыһыанньа","бэнидиэнньик","оптуорунньук","сэрэдэ","чэппиэр","бээтинсэ","субуота"], - namesAbbr: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"], - namesShort: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"] - }, - months: { - names: ["Тохсунньу","Олунньу","Кулун тутар","Муус устар","Ыам ыйа","Бэс ыйа","От ыйа","Атырдьах ыйа","Балаҕан ыйа","Алтынньы","Сэтинньи","Ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - monthsGenitive: { - names: ["тохсунньу","олунньу","кулун тутар","муус устар","ыам ыйын","бэс ыйын","от ыйын","атырдьах ыйын","балаҕан ыйын","алтынньы","сэтинньи","ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - AM: null, - PM: null, - patterns: { - d: "MM.dd.yyyy", - D: "MMMM d yyyy 'с.'", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d yyyy 'с.' H:mm", - F: "MMMM d yyyy 'с.' H:mm:ss", - Y: "MMMM yyyy 'с.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sah.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sah.js deleted file mode 100644 index 4ad841be0b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sah.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture sah - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sah", "default", { - name: "sah", - englishName: "Yakut", - nativeName: "саха", - language: "sah", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NAN", - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "с." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["баскыһыанньа","бэнидиэнньик","оптуорунньук","сэрэдэ","чэппиэр","бээтинсэ","субуота"], - namesAbbr: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"], - namesShort: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"] - }, - months: { - names: ["Тохсунньу","Олунньу","Кулун тутар","Муус устар","Ыам ыйа","Бэс ыйа","От ыйа","Атырдьах ыйа","Балаҕан ыйа","Алтынньы","Сэтинньи","Ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - monthsGenitive: { - names: ["тохсунньу","олунньу","кулун тутар","муус устар","ыам ыйын","бэс ыйын","от ыйын","атырдьах ыйын","балаҕан ыйын","алтынньы","сэтинньи","ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - AM: null, - PM: null, - patterns: { - d: "MM.dd.yyyy", - D: "MMMM d yyyy 'с.'", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d yyyy 'с.' H:mm", - F: "MMMM d yyyy 'с.' H:mm:ss", - Y: "MMMM yyyy 'с.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-FI.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-FI.js deleted file mode 100644 index b270fa5807..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-FI.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture se-FI - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "se-FI", "default", { - name: "se-FI", - englishName: "Sami, Northern (Finland)", - nativeName: "davvisámegiella (Suopma)", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","vuos","maŋ","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. b. 'yyyy H:mm", - F: "MMMM d'. b. 'yyyy H:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-NO.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-NO.js deleted file mode 100644 index 46f387f499..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-NO.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture se-NO - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "se-NO", "default", { - name: "se-NO", - englishName: "Sami, Northern (Norway)", - nativeName: "davvisámegiella (Norga)", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","vuos","maŋ","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-SE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-SE.js deleted file mode 100644 index fd4ec323f1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se-SE.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture se-SE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "se-SE", "default", { - name: "se-SE", - englishName: "Sami, Northern (Sweden)", - nativeName: "davvisámegiella (Ruoŧŧa)", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sotnabeaivi","mánnodat","disdat","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","mán","dis","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se.js deleted file mode 100644 index 9a5dcec64d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.se.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture se - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "se", "default", { - name: "se", - englishName: "Sami (Northern)", - nativeName: "davvisámegiella", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","vuos","maŋ","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.si-LK.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.si-LK.js deleted file mode 100644 index a331625f72..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.si-LK.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture si-LK - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "si-LK", "default", { - name: "si-LK", - englishName: "Sinhala (Sri Lanka)", - nativeName: "සිංහල (ශ්\u200dරී ලංකා)", - language: "si", - numberFormat: { - groupSizes: [3,2], - negativeInfinity: "-අනන්තය", - positiveInfinity: "අනන්තය", - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["($ n)","$ n"], - symbol: "රු." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ඉරිදා","සඳුදා","අඟහරුවාදා","බදාදා","බ්\u200dරහස්පතින්දා","සිකුරාදා","සෙනසුරාදා"], - namesAbbr: ["ඉරිදා","සඳුදා","කුජදා","බුදදා","ගුරුදා","කිවිදා","ශනිදා"], - namesShort: ["ඉ","ස","අ","බ","බ්\u200dර","සි","සෙ"] - }, - months: { - names: ["ජනවාරි","පෙබරවාරි","මාර්තු","අ\u200cප්\u200dරේල්","මැයි","ජූනි","ජූලි","අ\u200cගෝස්තු","සැප්තැම්බර්","ඔක්තෝබර්","නොවැම්බර්","දෙසැම්බර්",""], - namesAbbr: ["ජන.","පෙබ.","මාර්තු.","අප්\u200dරේල්.","මැයි.","ජූනි.","ජූලි.","අගෝ.","සැප්.","ඔක්.","නොවැ.","දෙසැ.",""] - }, - AM: ["පෙ.ව.","පෙ.ව.","පෙ.ව."], - PM: ["ප.ව.","ප.ව.","ප.ව."], - eras: [{"name":"ක්\u200dරි.ව.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy MMMM' මස 'dd' වැනිදා 'dddd", - f: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm tt", - F: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm:ss tt", - Y: "yyyy MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.si.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.si.js deleted file mode 100644 index c9141e2501..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.si.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture si - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "si", "default", { - name: "si", - englishName: "Sinhala", - nativeName: "සිංහල", - language: "si", - numberFormat: { - groupSizes: [3,2], - negativeInfinity: "-අනන්තය", - positiveInfinity: "අනන්තය", - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["($ n)","$ n"], - symbol: "රු." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ඉරිදා","සඳුදා","අඟහරුවාදා","බදාදා","බ්\u200dරහස්පතින්දා","සිකුරාදා","සෙනසුරාදා"], - namesAbbr: ["ඉරිදා","සඳුදා","කුජදා","බුදදා","ගුරුදා","කිවිදා","ශනිදා"], - namesShort: ["ඉ","ස","අ","බ","බ්\u200dර","සි","සෙ"] - }, - months: { - names: ["ජනවාරි","පෙබරවාරි","මාර්තු","අ\u200cප්\u200dරේල්","මැයි","ජූනි","ජූලි","අ\u200cගෝස්තු","සැප්තැම්බර්","ඔක්තෝබර්","නොවැම්බර්","දෙසැම්බර්",""], - namesAbbr: ["ජන.","පෙබ.","මාර්තු.","අප්\u200dරේල්.","මැයි.","ජූනි.","ජූලි.","අගෝ.","සැප්.","ඔක්.","නොවැ.","දෙසැ.",""] - }, - AM: ["පෙ.ව.","පෙ.ව.","පෙ.ව."], - PM: ["ප.ව.","ප.ව.","ප.ව."], - eras: [{"name":"ක්\u200dරි.ව.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy MMMM' මස 'dd' වැනිදා 'dddd", - f: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm tt", - F: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm:ss tt", - Y: "yyyy MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sk.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sk.js deleted file mode 100644 index 3cd66db999..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sk.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Globalize Culture sk - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sk", "default", { - name: "sk", - englishName: "Slovak", - nativeName: "slovenčina", - language: "sk", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Nie je číslo", - negativeInfinity: "-nekonečno", - positiveInfinity: "+nekonečno", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["nedeľa","pondelok","utorok","streda","štvrtok","piatok","sobota"], - namesAbbr: ["ne","po","ut","st","št","pi","so"], - namesShort: ["ne","po","ut","st","št","pi","so"] - }, - months: { - names: ["január","február","marec","apríl","máj","jún","júl","august","september","október","november","december",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - monthsGenitive: { - names: ["januára","februára","marca","apríla","mája","júna","júla","augusta","septembra","októbra","novembra","decembra",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. l.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sl.js deleted file mode 100644 index a75dbdedc0..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sl.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture sl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sl", "default", { - name: "sl", - englishName: "Slovenian", - nativeName: "slovenski", - language: "sl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-neskončnost", - positiveInfinity: "neskončnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljek","torek","sreda","četrtek","petek","sobota"], - namesAbbr: ["ned","pon","tor","sre","čet","pet","sob"], - namesShort: ["ne","po","to","sr","če","pe","so"] - }, - months: { - names: ["januar","februar","marec","april","maj","junij","julij","avgust","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma-NO.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma-NO.js deleted file mode 100644 index 4954494e5c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma-NO.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture sma-NO - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sma-NO", "default", { - name: "sma-NO", - englishName: "Sami, Southern (Norway)", - nativeName: "åarjelsaemiengiele (Nöörje)", - language: "sma", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"], - namesAbbr: ["aej","måa","dæj","gask","duar","bearj","laav"], - namesShort: ["a","m","d","g","d","b","l"] - }, - months: { - names: ["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - monthsGenitive: { - names: ["tsïengelen","goevten","njoktjen","voerhtjen","suehpeden","ruffien","snjaltjen","mïetsken","skïereden","golken","rahkan","goeven",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma-SE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma-SE.js deleted file mode 100644 index d6c02c0282..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma-SE.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture sma-SE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sma-SE", "default", { - name: "sma-SE", - englishName: "Sami, Southern (Sweden)", - nativeName: "åarjelsaemiengiele (Sveerje)", - language: "sma", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"], - namesAbbr: ["aej","måa","dæj","gask","duar","bearj","laav"], - namesShort: ["a","m","d","g","d","b","l"] - }, - months: { - names: ["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - monthsGenitive: { - names: ["tsïengelen","goevten","njoktjen","voerhtjen","suehpeden","ruffien","snjaltjen","mïetsken","skïereden","golken","rahkan","goeven",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma.js deleted file mode 100644 index 5b8935647d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sma.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture sma - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sma", "default", { - name: "sma", - englishName: "Sami (Southern)", - nativeName: "åarjelsaemiengiele", - language: "sma", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"], - namesAbbr: ["aej","måa","dæj","gask","duar","bearj","laav"], - namesShort: ["a","m","d","g","d","b","l"] - }, - months: { - names: ["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - monthsGenitive: { - names: ["tsïengelen","goevten","njoktjen","voerhtjen","suehpeden","ruffien","snjaltjen","mïetsken","skïereden","golken","rahkan","goeven",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj-NO.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj-NO.js deleted file mode 100644 index f6f13823e2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj-NO.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture smj-NO - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "smj-NO", "default", { - name: "smj-NO", - englishName: "Sami, Lule (Norway)", - nativeName: "julevusámegiella (Vuodna)", - language: "smj", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sådnåbiejvve","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"], - namesAbbr: ["såd","mán","dis","gas","duor","bier","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - monthsGenitive: { - names: ["ådåjakmáno","guovvamáno","sjnjuktjamáno","vuoratjismáno","moarmesmáno","biehtsemáno","sjnjilltjamáno","bårggemáno","ragátmáno","gålgådismáno","basádismáno","javllamáno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj-SE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj-SE.js deleted file mode 100644 index b7ee88aff5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj-SE.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture smj-SE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "smj-SE", "default", { - name: "smj-SE", - englishName: "Sami, Lule (Sweden)", - nativeName: "julevusámegiella (Svierik)", - language: "smj", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ájllek","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"], - namesAbbr: ["ájl","mán","dis","gas","duor","bier","láv"], - namesShort: ["á","m","d","g","d","b","l"] - }, - months: { - names: ["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - monthsGenitive: { - names: ["ådåjakmáno","guovvamáno","sjnjuktjamáno","vuoratjismáno","moarmesmáno","biehtsemáno","sjnjilltjamáno","bårggemáno","ragátmáno","gålgådismáno","basádismáno","javllamáno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj.js deleted file mode 100644 index 021f9a3155..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smj.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture smj - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "smj", "default", { - name: "smj", - englishName: "Sami (Lule)", - nativeName: "julevusámegiella", - language: "smj", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ájllek","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"], - namesAbbr: ["ájl","mán","dis","gas","duor","bier","láv"], - namesShort: ["á","m","d","g","d","b","l"] - }, - months: { - names: ["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - monthsGenitive: { - names: ["ådåjakmáno","guovvamáno","sjnjuktjamáno","vuoratjismáno","moarmesmáno","biehtsemáno","sjnjilltjamáno","bårggemáno","ragátmáno","gålgådismáno","basádismáno","javllamáno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smn-FI.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smn-FI.js deleted file mode 100644 index ce73bd3d4d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smn-FI.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture smn-FI - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "smn-FI", "default", { - name: "smn-FI", - englishName: "Sami, Inari (Finland)", - nativeName: "sämikielâ (Suomâ)", - language: "smn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pasepeivi","vuossargâ","majebargâ","koskokko","tuorâstâh","vástuppeivi","lávárdâh"], - namesAbbr: ["pa","vu","ma","ko","tu","vá","lá"], - namesShort: ["p","v","m","k","t","v","l"] - }, - months: { - names: ["uđđâivemáánu","kuovâmáánu","njuhčâmáánu","cuáŋuimáánu","vyesimáánu","kesimáánu","syeinimáánu","porgemáánu","čohčâmáánu","roovvâdmáánu","skammâmáánu","juovlâmáánu",""], - namesAbbr: ["uđiv","kuov","njuh","cuoŋ","vyes","kesi","syei","porg","čoh","roov","ska","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smn.js deleted file mode 100644 index aba89e0e64..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.smn.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Globalize Culture smn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "smn", "default", { - name: "smn", - englishName: "Sami (Inari)", - nativeName: "sämikielâ", - language: "smn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pasepeivi","vuossargâ","majebargâ","koskokko","tuorâstâh","vástuppeivi","lávárdâh"], - namesAbbr: ["pa","vu","ma","ko","tu","vá","lá"], - namesShort: ["p","v","m","k","t","v","l"] - }, - months: { - names: ["uđđâivemáánu","kuovâmáánu","njuhčâmáánu","cuáŋuimáánu","vyesimáánu","kesimáánu","syeinimáánu","porgemáánu","čohčâmáánu","roovvâdmáánu","skammâmáánu","juovlâmáánu",""], - namesAbbr: ["uđiv","kuov","njuh","cuoŋ","vyes","kesi","syei","porg","čoh","roov","ska","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sms-FI.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sms-FI.js deleted file mode 100644 index d5a23e12d6..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sms-FI.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture sms-FI - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sms-FI", "default", { - name: "sms-FI", - englishName: "Sami, Skolt (Finland)", - nativeName: "sääm´ǩiõll (Lää´ddjânnam)", - language: "sms", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pâ´sspei´vv","vuõssargg","mââibargg","seärad","nelljdpei´vv","piâtnâc","sue´vet"], - namesAbbr: ["pâ","vu","mâ","se","ne","pi","su"], - namesShort: ["p","v","m","s","n","p","s"] - }, - months: { - names: ["ođđee´jjmään","tä´lvvmään","pâ´zzlâšttammään","njuhččmään","vue´ssmään","ǩie´ssmään","suei´nnmään","på´rǧǧmään","čõhččmään","kålggmään","skamm´mään","rosttovmään",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - monthsGenitive: { - names: ["ođđee´jjmannu","tä´lvvmannu","pâ´zzlâšttammannu","njuhččmannu","vue´ssmannu","ǩie´ssmannu","suei´nnmannu","på´rǧǧmannu","čõhččmannu","kålggmannu","skamm´mannu","rosttovmannu",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sms.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sms.js deleted file mode 100644 index b5bf2b92a9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sms.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture sms - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sms", "default", { - name: "sms", - englishName: "Sami (Skolt)", - nativeName: "sääm´ǩiõll", - language: "sms", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pâ´sspei´vv","vuõssargg","mââibargg","seärad","nelljdpei´vv","piâtnâc","sue´vet"], - namesAbbr: ["pâ","vu","mâ","se","ne","pi","su"], - namesShort: ["p","v","m","s","n","p","s"] - }, - months: { - names: ["ođđee´jjmään","tä´lvvmään","pâ´zzlâšttammään","njuhččmään","vue´ssmään","ǩie´ssmään","suei´nnmään","på´rǧǧmään","čõhččmään","kålggmään","skamm´mään","rosttovmään",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - monthsGenitive: { - names: ["ođđee´jjmannu","tä´lvvmannu","pâ´zzlâšttammannu","njuhččmannu","vue´ssmannu","ǩie´ssmannu","suei´nnmannu","på´rǧǧmannu","čõhččmannu","kålggmannu","skamm´mannu","rosttovmannu",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sq-AL.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sq-AL.js deleted file mode 100644 index b5c770d6e4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sq-AL.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture sq-AL - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sq-AL", "default", { - name: "sq-AL", - englishName: "Albanian (Albania)", - nativeName: "shqipe (Shqipëria)", - language: "sq", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-infinit", - positiveInfinity: "infinit", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": ".", - ".": ",", - symbol: "Lek" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["e diel","e hënë","e martë","e mërkurë","e enjte","e premte","e shtunë"], - namesAbbr: ["Die","Hën","Mar","Mër","Enj","Pre","Sht"], - namesShort: ["Di","Hë","Ma","Më","En","Pr","Sh"] - }, - months: { - names: ["janar","shkurt","mars","prill","maj","qershor","korrik","gusht","shtator","tetor","nëntor","dhjetor",""], - namesAbbr: ["Jan","Shk","Mar","Pri","Maj","Qer","Kor","Gsh","Sht","Tet","Nën","Dhj",""] - }, - AM: ["PD","pd","PD"], - PM: ["MD","md","MD"], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy-MM-dd", - t: "h:mm.tt", - T: "h:mm:ss.tt", - f: "yyyy-MM-dd h:mm.tt", - F: "yyyy-MM-dd h:mm:ss.tt", - Y: "yyyy-MM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sq.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sq.js deleted file mode 100644 index d6a8f99969..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sq.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture sq - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sq", "default", { - name: "sq", - englishName: "Albanian", - nativeName: "shqipe", - language: "sq", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-infinit", - positiveInfinity: "infinit", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": ".", - ".": ",", - symbol: "Lek" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["e diel","e hënë","e martë","e mërkurë","e enjte","e premte","e shtunë"], - namesAbbr: ["Die","Hën","Mar","Mër","Enj","Pre","Sht"], - namesShort: ["Di","Hë","Ma","Më","En","Pr","Sh"] - }, - months: { - names: ["janar","shkurt","mars","prill","maj","qershor","korrik","gusht","shtator","tetor","nëntor","dhjetor",""], - namesAbbr: ["Jan","Shk","Mar","Pri","Maj","Qer","Kor","Gsh","Sht","Tet","Nën","Dhj",""] - }, - AM: ["PD","pd","PD"], - PM: ["MD","md","MD"], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy-MM-dd", - t: "h:mm.tt", - T: "h:mm:ss.tt", - f: "yyyy-MM-dd h:mm.tt", - F: "yyyy-MM-dd h:mm:ss.tt", - Y: "yyyy-MM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sr.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sr.js deleted file mode 100644 index 2d691fe827..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sr.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Globalize Culture sr - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sr", "default", { - name: "sr", - englishName: "Serbian", - nativeName: "srpski", - language: "sr", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-beskonačnost", - positiveInfinity: "+beskonačnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Din." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sre","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"n.e.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sv.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sv.js deleted file mode 100644 index ed02c2f757..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sv.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture sv - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sv", "default", { - name: "sv", - englishName: "Swedish", - nativeName: "svenska", - language: "sv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"], - namesAbbr: ["sö","må","ti","on","to","fr","lö"], - namesShort: ["sö","må","ti","on","to","fr","lö"] - }, - months: { - names: ["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "'den 'd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "'den 'd MMMM yyyy HH:mm", - F: "'den 'd MMMM yyyy HH:mm:ss", - M: "'den 'd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sw-KE.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sw-KE.js deleted file mode 100644 index 579e4fafc2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sw-KE.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Globalize Culture sw-KE - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sw-KE", "default", { - name: "sw-KE", - englishName: "Kiswahili (Kenya)", - nativeName: "Kiswahili (Kenya)", - language: "sw", - numberFormat: { - currency: { - symbol: "S" - } - }, - calendars: { - standard: { - days: { - names: ["Jumapili","Jumatatu","Jumanne","Jumatano","Alhamisi","Ijumaa","Jumamosi"], - namesAbbr: ["Jumap.","Jumat.","Juman.","Jumat.","Alh.","Iju.","Jumam."], - namesShort: ["P","T","N","T","A","I","M"] - }, - months: { - names: ["Januari","Februari","Machi","Aprili","Mei","Juni","Julai","Agosti","Septemba","Oktoba","Novemba","Decemba",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ago","Sep","Okt","Nov","Dec",""] - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sw.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sw.js deleted file mode 100644 index 14824e9093..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.sw.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Globalize Culture sw - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "sw", "default", { - name: "sw", - englishName: "Kiswahili", - nativeName: "Kiswahili", - language: "sw", - numberFormat: { - currency: { - symbol: "S" - } - }, - calendars: { - standard: { - days: { - names: ["Jumapili","Jumatatu","Jumanne","Jumatano","Alhamisi","Ijumaa","Jumamosi"], - namesAbbr: ["Jumap.","Jumat.","Juman.","Jumat.","Alh.","Iju.","Jumam."], - namesShort: ["P","T","N","T","A","I","M"] - }, - months: { - names: ["Januari","Februari","Machi","Aprili","Mei","Juni","Julai","Agosti","Septemba","Oktoba","Novemba","Decemba",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ago","Sep","Okt","Nov","Dec",""] - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.syr-SY.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.syr-SY.js deleted file mode 100644 index b44cf98702..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.syr-SY.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture syr-SY - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "syr-SY", "default", { - name: "syr-SY", - englishName: "Syriac (Syria)", - nativeName: "ܣܘܪܝܝܐ (سوريا)", - language: "syr", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$ n"], - symbol: "ل.س.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["ܚܕ ܒܫܒܐ","ܬܪܝܢ ܒܫܒܐ","ܬܠܬܐ ܒܫܒܐ","ܐܪܒܥܐ ܒܫܒܐ","ܚܡܫܐ ܒܫܒܐ","ܥܪܘܒܬܐ","ܫܒܬܐ"], - namesAbbr: ["\u070fܐ \u070fܒܫ","\u070fܒ \u070fܒܫ","\u070fܓ \u070fܒܫ","\u070fܕ \u070fܒܫ","\u070fܗ \u070fܒܫ","\u070fܥܪܘܒ","\u070fܫܒ"], - namesShort: ["ܐ","ܒ","ܓ","ܕ","ܗ","ܥ","ܫ"] - }, - months: { - names: ["ܟܢܘܢ ܐܚܪܝ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","ܬܫܪܝ ܩܕܝܡ","ܬܫܪܝ ܐܚܪܝ","ܟܢܘܢ ܩܕܝܡ",""], - namesAbbr: ["\u070fܟܢ \u070fܒ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","\u070fܬܫ \u070fܐ","\u070fܬܫ \u070fܒ","\u070fܟܢ \u070fܐ",""] - }, - AM: ["ܩ.ܛ","ܩ.ܛ","ܩ.ܛ"], - PM: ["ܒ.ܛ","ܒ.ܛ","ܒ.ܛ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.syr.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.syr.js deleted file mode 100644 index 2d9f1d2fed..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.syr.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture syr - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "syr", "default", { - name: "syr", - englishName: "Syriac", - nativeName: "ܣܘܪܝܝܐ", - language: "syr", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$ n"], - symbol: "ل.س.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["ܚܕ ܒܫܒܐ","ܬܪܝܢ ܒܫܒܐ","ܬܠܬܐ ܒܫܒܐ","ܐܪܒܥܐ ܒܫܒܐ","ܚܡܫܐ ܒܫܒܐ","ܥܪܘܒܬܐ","ܫܒܬܐ"], - namesAbbr: ["\u070fܐ \u070fܒܫ","\u070fܒ \u070fܒܫ","\u070fܓ \u070fܒܫ","\u070fܕ \u070fܒܫ","\u070fܗ \u070fܒܫ","\u070fܥܪܘܒ","\u070fܫܒ"], - namesShort: ["ܐ","ܒ","ܓ","ܕ","ܗ","ܥ","ܫ"] - }, - months: { - names: ["ܟܢܘܢ ܐܚܪܝ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","ܬܫܪܝ ܩܕܝܡ","ܬܫܪܝ ܐܚܪܝ","ܟܢܘܢ ܩܕܝܡ",""], - namesAbbr: ["\u070fܟܢ \u070fܒ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","\u070fܬܫ \u070fܐ","\u070fܬܫ \u070fܒ","\u070fܟܢ \u070fܐ",""] - }, - AM: ["ܩ.ܛ","ܩ.ܛ","ܩ.ܛ"], - PM: ["ܒ.ܛ","ܒ.ܛ","ܒ.ܛ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ta-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ta-IN.js deleted file mode 100644 index b9d550acb8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ta-IN.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Globalize Culture ta-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ta-IN", "default", { - name: "ta-IN", - englishName: "Tamil (India)", - nativeName: "தமிழ் (இந்தியா)", - language: "ta", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ரூ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ஞாயிற்றுக்கிழமை","திங்கள்கிழமை","செவ்வாய்கிழமை","புதன்கிழமை","வியாழக்கிழமை","வெள்ளிக்கிழமை","சனிக்கிழமை"], - namesAbbr: ["ஞாயிறு","திங்கள்","செவ்வாய்","புதன்","வியாழன்","வெள்ளி","சனி"], - namesShort: ["ஞா","தி","செ","பு","வி","வெ","ச"] - }, - months: { - names: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""], - namesAbbr: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""] - }, - AM: ["காலை","காலை","காலை"], - PM: ["மாலை","மாலை","மாலை"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ta.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ta.js deleted file mode 100644 index 3d15ce1670..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ta.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Globalize Culture ta - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ta", "default", { - name: "ta", - englishName: "Tamil", - nativeName: "தமிழ்", - language: "ta", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ரூ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ஞாயிற்றுக்கிழமை","திங்கள்கிழமை","செவ்வாய்கிழமை","புதன்கிழமை","வியாழக்கிழமை","வெள்ளிக்கிழமை","சனிக்கிழமை"], - namesAbbr: ["ஞாயிறு","திங்கள்","செவ்வாய்","புதன்","வியாழன்","வெள்ளி","சனி"], - namesShort: ["ஞா","தி","செ","பு","வி","வெ","ச"] - }, - months: { - names: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""], - namesAbbr: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""] - }, - AM: ["காலை","காலை","காலை"], - PM: ["மாலை","மாலை","மாலை"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.te-IN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.te-IN.js deleted file mode 100644 index b9f8b8484e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.te-IN.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture te-IN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "te-IN", "default", { - name: "te-IN", - englishName: "Telugu (India)", - nativeName: "తెలుగు (భారత దేశం)", - language: "te", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "రూ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ఆదివారం","సోమవారం","మంగళవారం","బుధవారం","గురువారం","శుక్రవారం","శనివారం"], - namesAbbr: ["ఆది.","సోమ.","మంగళ.","బుధ.","గురు.","శుక్ర.","శని."], - namesShort: ["ఆ","సో","మం","బు","గు","శు","శ"] - }, - months: { - names: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""], - namesAbbr: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""] - }, - AM: ["పూర్వాహ్న","పూర్వాహ్న","పూర్వాహ్న"], - PM: ["అపరాహ్న","అపరాహ్న","అపరాహ్న"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.te.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.te.js deleted file mode 100644 index 4ef21e08e5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.te.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Globalize Culture te - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "te", "default", { - name: "te", - englishName: "Telugu", - nativeName: "తెలుగు", - language: "te", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "రూ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ఆదివారం","సోమవారం","మంగళవారం","బుధవారం","గురువారం","శుక్రవారం","శనివారం"], - namesAbbr: ["ఆది.","సోమ.","మంగళ.","బుధ.","గురు.","శుక్ర.","శని."], - namesShort: ["ఆ","సో","మం","బు","గు","శు","శ"] - }, - months: { - names: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""], - namesAbbr: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""] - }, - AM: ["పూర్వాహ్న","పూర్వాహ్న","పూర్వాహ్న"], - PM: ["అపరాహ్న","అపరాహ్న","అపరాహ్న"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg-Cyrl-TJ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg-Cyrl-TJ.js deleted file mode 100644 index 3fe4d1b279..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg-Cyrl-TJ.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture tg-Cyrl-TJ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tg-Cyrl-TJ", "default", { - name: "tg-Cyrl-TJ", - englishName: "Tajik (Cyrillic, Tajikistan)", - nativeName: "Тоҷикӣ (Тоҷикистон)", - language: "tg-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ";", - symbol: "т.р." - } - }, - calendars: { - standard: { - "/": ".", - days: { - names: ["Яш","Душанбе","Сешанбе","Чоршанбе","Панҷшанбе","Ҷумъа","Шанбе"], - namesAbbr: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"], - namesShort: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январи","феврали","марти","апрели","маи","июни","июли","августи","сентябри","октябри","ноябри","декабри",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg-Cyrl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg-Cyrl.js deleted file mode 100644 index 5825abdb58..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg-Cyrl.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture tg-Cyrl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tg-Cyrl", "default", { - name: "tg-Cyrl", - englishName: "Tajik (Cyrillic)", - nativeName: "Тоҷикӣ", - language: "tg-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ";", - symbol: "т.р." - } - }, - calendars: { - standard: { - "/": ".", - days: { - names: ["Яш","Душанбе","Сешанбе","Чоршанбе","Панҷшанбе","Ҷумъа","Шанбе"], - namesAbbr: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"], - namesShort: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январи","феврали","марти","апрели","маи","июни","июли","августи","сентябри","октябри","ноябри","декабри",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg.js deleted file mode 100644 index 5c3494f8db..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tg.js +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Globalize Culture tg - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tg", "default", { - name: "tg", - englishName: "Tajik", - nativeName: "Тоҷикӣ", - language: "tg", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ";", - symbol: "т.р." - } - }, - calendars: { - standard: { - "/": ".", - days: { - names: ["Яш","Душанбе","Сешанбе","Чоршанбе","Панҷшанбе","Ҷумъа","Шанбе"], - namesAbbr: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"], - namesShort: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январи","феврали","марти","апрели","маи","июни","июли","августи","сентябри","октябри","ноябри","декабри",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.th.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.th.js deleted file mode 100644 index 5490f588d0..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.th.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Globalize Culture th - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "th", "default", { - name: "th", - englishName: "Thai", - nativeName: "ไทย", - language: "th", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "฿" - } - }, - calendars: { - standard: { - name: "ThaiBuddhist", - firstDay: 1, - days: { - names: ["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"], - namesAbbr: ["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."], - namesShort: ["อ","จ","อ","พ","พ","ศ","ส"] - }, - months: { - names: ["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม",""], - namesAbbr: ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค.",""] - }, - eras: [{"name":"พ.ศ.","start":null,"offset":-543}], - twoDigitYearMax: 2572, - patterns: { - d: "d/M/yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - }, - Gregorian_Localized: { - firstDay: 1, - days: { - names: ["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"], - namesAbbr: ["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."], - namesShort: ["อ","จ","อ","พ","พ","ศ","ส"] - }, - months: { - names: ["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม",""], - namesAbbr: ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค.",""] - }, - patterns: { - d: "d/M/yyyy", - D: "'วัน'dddd'ที่' d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "'วัน'dddd'ที่' d MMMM yyyy H:mm", - F: "'วัน'dddd'ที่' d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tk-TM.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tk-TM.js deleted file mode 100644 index 7f2e2a3245..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tk-TM.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture tk-TM - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tk-TM", "default", { - name: "tk-TM", - englishName: "Turkmen (Turkmenistan)", - nativeName: "türkmençe (Türkmenistan)", - language: "tk", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-üznüksizlik", - positiveInfinity: "üznüksizlik", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "m." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Duşenbe","Sişenbe","Çarşenbe","Penşenbe","Anna","Şenbe","Ýekşenbe"], - namesAbbr: ["Db","Sb","Çb","Pb","An","Şb","Ýb"], - namesShort: ["D","S","Ç","P","A","Ş","Ý"] - }, - months: { - names: ["Ýanwar","Fewral","Mart","Aprel","Maý","lýun","lýul","Awgust","Sentýabr","Oktýabr","Noýabr","Dekabr",""], - namesAbbr: ["Ýan","Few","Mart","Apr","Maý","lýun","lýul","Awg","Sen","Okt","Not","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "yyyy 'ý.' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'ý.' MMMM d H:mm", - F: "yyyy 'ý.' MMMM d H:mm:ss", - Y: "yyyy 'ý.' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tk.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tk.js deleted file mode 100644 index 151c2ee6d1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tk.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Globalize Culture tk - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tk", "default", { - name: "tk", - englishName: "Turkmen", - nativeName: "türkmençe", - language: "tk", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-üznüksizlik", - positiveInfinity: "üznüksizlik", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "m." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Duşenbe","Sişenbe","Çarşenbe","Penşenbe","Anna","Şenbe","Ýekşenbe"], - namesAbbr: ["Db","Sb","Çb","Pb","An","Şb","Ýb"], - namesShort: ["D","S","Ç","P","A","Ş","Ý"] - }, - months: { - names: ["Ýanwar","Fewral","Mart","Aprel","Maý","lýun","lýul","Awgust","Sentýabr","Oktýabr","Noýabr","Dekabr",""], - namesAbbr: ["Ýan","Few","Mart","Apr","Maý","lýun","lýul","Awg","Sen","Okt","Not","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "yyyy 'ý.' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'ý.' MMMM d H:mm", - F: "yyyy 'ý.' MMMM d H:mm:ss", - Y: "yyyy 'ý.' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tn-ZA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tn-ZA.js deleted file mode 100644 index e08cc810d1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tn-ZA.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture tn-ZA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tn-ZA", "default", { - name: "tn-ZA", - englishName: "Setswana (South Africa)", - nativeName: "Setswana (Aforika Borwa)", - language: "tn", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Latshipi","Mosupologo","Labobedi","Laboraro","Labone","Labotlhano","Lamatlhatso"], - namesAbbr: ["Ltp.","Mos.","Lbd.","Lbr.","Lbn.","Lbt.","Lmt."], - namesShort: ["Lp","Ms","Lb","Lr","Ln","Lt","Lm"] - }, - months: { - names: ["Ferikgong","Tlhakole","Mopitloe","Moranang","Motsheganong","Seetebosigo","Phukwi","Phatwe","Lwetse","Diphalane","Ngwanatsele","Sedimothole",""], - namesAbbr: ["Fer.","Tlhak.","Mop.","Mor.","Motsh.","Seet.","Phukw.","Phatw.","Lwets.","Diph.","Ngwan.","Sed.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tn.js deleted file mode 100644 index 54b9745d73..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tn.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Globalize Culture tn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tn", "default", { - name: "tn", - englishName: "Setswana", - nativeName: "Setswana", - language: "tn", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Latshipi","Mosupologo","Labobedi","Laboraro","Labone","Labotlhano","Lamatlhatso"], - namesAbbr: ["Ltp.","Mos.","Lbd.","Lbr.","Lbn.","Lbt.","Lmt."], - namesShort: ["Lp","Ms","Lb","Lr","Ln","Lt","Lm"] - }, - months: { - names: ["Ferikgong","Tlhakole","Mopitloe","Moranang","Motsheganong","Seetebosigo","Phukwi","Phatwe","Lwetse","Diphalane","Ngwanatsele","Sedimothole",""], - namesAbbr: ["Fer.","Tlhak.","Mop.","Mor.","Motsh.","Seet.","Phukw.","Phatw.","Lwets.","Diph.","Ngwan.","Sed.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tr.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tr.js deleted file mode 100644 index 47a18ccf74..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tr.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture tr - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tr", "default", { - name: "tr", - englishName: "Turkish", - nativeName: "Türkçe", - language: "tr", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "TL" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"], - namesAbbr: ["Paz","Pzt","Sal","Çar","Per","Cum","Cmt"], - namesShort: ["Pz","Pt","Sa","Ça","Pe","Cu","Ct"] - }, - months: { - names: ["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık",""], - namesAbbr: ["Oca","Şub","Mar","Nis","May","Haz","Tem","Ağu","Eyl","Eki","Kas","Ara",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "dd MMMM yyyy dddd", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy dddd HH:mm", - F: "dd MMMM yyyy dddd HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tt-RU.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tt-RU.js deleted file mode 100644 index 163d7555ac..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tt-RU.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture tt-RU - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tt-RU", "default", { - name: "tt-RU", - englishName: "Tatar (Russia)", - nativeName: "Татар (Россия)", - language: "tt", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Якшәмбе","Дүшәмбе","Сишәмбе","Чәршәмбе","Пәнҗешәмбе","Җомга","Шимбә"], - namesAbbr: ["Якш","Дүш","Сиш","Чәрш","Пәнҗ","Җом","Шим"], - namesShort: ["Я","Д","С","Ч","П","Җ","Ш"] - }, - months: { - names: ["Гыйнвар","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Гыйн.","Фев.","Мар.","Апр.","Май","Июнь","Июль","Авг.","Сен.","Окт.","Нояб.","Дек.",""] - }, - monthsGenitive: { - names: ["Гыйнварның","Февральнең","Мартның","Апрельнең","Майның","Июньнең","Июльнең","Августның","Сентябрьның","Октябрьның","Ноябрьның","Декабрьның",""], - namesAbbr: ["Гыйн.-ның","Фев.-нең","Мар.-ның","Апр.-нең","Майның","Июньнең","Июльнең","Авг.-ның","Сен.-ның","Окт.-ның","Нояб.-ның","Дек.-ның",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tt.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tt.js deleted file mode 100644 index 0d810ad8a9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tt.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture tt - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tt", "default", { - name: "tt", - englishName: "Tatar", - nativeName: "Татар", - language: "tt", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Якшәмбе","Дүшәмбе","Сишәмбе","Чәршәмбе","Пәнҗешәмбе","Җомга","Шимбә"], - namesAbbr: ["Якш","Дүш","Сиш","Чәрш","Пәнҗ","Җом","Шим"], - namesShort: ["Я","Д","С","Ч","П","Җ","Ш"] - }, - months: { - names: ["Гыйнвар","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Гыйн.","Фев.","Мар.","Апр.","Май","Июнь","Июль","Авг.","Сен.","Окт.","Нояб.","Дек.",""] - }, - monthsGenitive: { - names: ["Гыйнварның","Февральнең","Мартның","Апрельнең","Майның","Июньнең","Июльнең","Августның","Сентябрьның","Октябрьның","Ноябрьның","Декабрьның",""], - namesAbbr: ["Гыйн.-ның","Фев.-нең","Мар.-ның","Апр.-нең","Майның","Июньнең","Июльнең","Авг.-ның","Сен.-ның","Окт.-ның","Нояб.-ның","Дек.-ның",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm-Latn-DZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm-Latn-DZ.js deleted file mode 100644 index 68504af320..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm-Latn-DZ.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture tzm-Latn-DZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tzm-Latn-DZ", "default", { - name: "tzm-Latn-DZ", - englishName: "Tamazight (Latin, Algeria)", - nativeName: "Tamazight (Djazaïr)", - language: "tzm-Latn", - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - symbol: "DZD" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 6, - days: { - names: ["Acer","Arime","Aram","Ahad","Amhadh","Sem","Sedh"], - namesAbbr: ["Ace","Ari","Ara","Aha","Amh","Sem","Sed"], - namesShort: ["Ac","Ar","Ar","Ah","Am","Se","Se"] - }, - months: { - names: ["Yenayer","Furar","Maghres","Yebrir","Mayu","Yunyu","Yulyu","Ghuct","Cutenber","Ktuber","Wambir","Dujanbir",""], - namesAbbr: ["Yen","Fur","Mag","Yeb","May","Yun","Yul","Ghu","Cut","Ktu","Wam","Duj",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm-Latn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm-Latn.js deleted file mode 100644 index 0391387843..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm-Latn.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture tzm-Latn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tzm-Latn", "default", { - name: "tzm-Latn", - englishName: "Tamazight (Latin)", - nativeName: "Tamazight", - language: "tzm-Latn", - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - symbol: "DZD" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 6, - days: { - names: ["Acer","Arime","Aram","Ahad","Amhadh","Sem","Sedh"], - namesAbbr: ["Ace","Ari","Ara","Aha","Amh","Sem","Sed"], - namesShort: ["Ac","Ar","Ar","Ah","Am","Se","Se"] - }, - months: { - names: ["Yenayer","Furar","Maghres","Yebrir","Mayu","Yunyu","Yulyu","Ghuct","Cutenber","Ktuber","Wambir","Dujanbir",""], - namesAbbr: ["Yen","Fur","Mag","Yeb","May","Yun","Yul","Ghu","Cut","Ktu","Wam","Duj",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm.js deleted file mode 100644 index 92b44c6e0a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.tzm.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture tzm - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "tzm", "default", { - name: "tzm", - englishName: "Tamazight", - nativeName: "Tamazight", - language: "tzm", - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - symbol: "DZD" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 6, - days: { - names: ["Acer","Arime","Aram","Ahad","Amhadh","Sem","Sedh"], - namesAbbr: ["Ace","Ari","Ara","Aha","Amh","Sem","Sed"], - namesShort: ["Ac","Ar","Ar","Ah","Am","Se","Se"] - }, - months: { - names: ["Yenayer","Furar","Maghres","Yebrir","Mayu","Yunyu","Yulyu","Ghuct","Cutenber","Ktuber","Wambir","Dujanbir",""], - namesAbbr: ["Yen","Fur","Mag","Yeb","May","Yun","Yul","Ghu","Cut","Ktu","Wam","Duj",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ug-CN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ug-CN.js deleted file mode 100644 index 02a3d50126..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ug-CN.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Globalize Culture ug-CN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ug-CN", "default", { - name: "ug-CN", - englishName: "Uyghur (PRC)", - nativeName: "ئۇيغۇرچە (جۇڭخۇا خەلق جۇمھۇرىيىتى)", - language: "ug", - isRTL: true, - numberFormat: { - "NaN": "سان ئەمەس", - negativeInfinity: "مەنپىي چەكسىزلىك", - positiveInfinity: "مۇسبەت چەكسىزلىك", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["يەكشەنبە","دۈشەنبە","سەيشەنبە","چارشەنبە","پەيشەنبە","جۈمە","شەنبە"], - namesAbbr: ["يە","دۈ","سە","چا","پە","جۈ","شە"], - namesShort: ["ي","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""], - namesAbbr: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""] - }, - AM: ["چۈشتىن بۇرۇن","چۈشتىن بۇرۇن","چۈشتىن بۇرۇن"], - PM: ["چۈشتىن كېيىن","چۈشتىن كېيىن","چۈشتىن كېيىن"], - eras: [{"name":"مىلادى","start":null,"offset":0}], - patterns: { - d: "yyyy-M-d", - D: "yyyy-'يىلى' MMMM d-'كۈنى،'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm", - F: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm:ss", - M: "MMMM d'-كۈنى'", - Y: "yyyy-'يىلى' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ug.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ug.js deleted file mode 100644 index d8dd8a4ea9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ug.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Globalize Culture ug - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ug", "default", { - name: "ug", - englishName: "Uyghur", - nativeName: "ئۇيغۇرچە", - language: "ug", - isRTL: true, - numberFormat: { - "NaN": "سان ئەمەس", - negativeInfinity: "مەنپىي چەكسىزلىك", - positiveInfinity: "مۇسبەت چەكسىزلىك", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["يەكشەنبە","دۈشەنبە","سەيشەنبە","چارشەنبە","پەيشەنبە","جۈمە","شەنبە"], - namesAbbr: ["يە","دۈ","سە","چا","پە","جۈ","شە"], - namesShort: ["ي","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""], - namesAbbr: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""] - }, - AM: ["چۈشتىن بۇرۇن","چۈشتىن بۇرۇن","چۈشتىن بۇرۇن"], - PM: ["چۈشتىن كېيىن","چۈشتىن كېيىن","چۈشتىن كېيىن"], - eras: [{"name":"مىلادى","start":null,"offset":0}], - patterns: { - d: "yyyy-M-d", - D: "yyyy-'يىلى' MMMM d-'كۈنى،'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm", - F: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm:ss", - M: "MMMM d'-كۈنى'", - Y: "yyyy-'يىلى' MMMM" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uk.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uk.js deleted file mode 100644 index 18e0a89273..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uk.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Globalize Culture uk - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "uk", "default", { - name: "uk", - englishName: "Ukrainian", - nativeName: "українська", - language: "uk", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-безмежність", - positiveInfinity: "безмежність", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₴" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["неділя","понеділок","вівторок","середа","четвер","п'ятниця","субота"], - namesAbbr: ["Нд","Пн","Вт","Ср","Чт","Пт","Сб"], - namesShort: ["Нд","Пн","Вт","Ср","Чт","Пт","Сб"] - }, - months: { - names: ["Січень","Лютий","Березень","Квітень","Травень","Червень","Липень","Серпень","Вересень","Жовтень","Листопад","Грудень",""], - namesAbbr: ["Січ","Лют","Бер","Кві","Тра","Чер","Лип","Сер","Вер","Жов","Лис","Гру",""] - }, - monthsGenitive: { - names: ["січня","лютого","березня","квітня","травня","червня","липня","серпня","вересня","жовтня","листопада","грудня",""], - namesAbbr: ["січ","лют","бер","кві","тра","чер","лип","сер","вер","жов","лис","гру",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy' р.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy' р.' H:mm", - F: "d MMMM yyyy' р.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy' р.'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ur-PK.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ur-PK.js deleted file mode 100644 index c92e6e30be..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ur-PK.js +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Globalize Culture ur-PK - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ur-PK", "default", { - name: "ur-PK", - englishName: "Urdu (Islamic Republic of Pakistan)", - nativeName: "اُردو (پاکستان)", - language: "ur", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$n"], - symbol: "Rs" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesAbbr: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesShort: ["ا","پ","م","ب","ج","ج","ه"] - }, - months: { - names: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""], - namesAbbr: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - f: "dd MMMM, yyyy h:mm tt", - F: "dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ur.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ur.js deleted file mode 100644 index 3b6709db8a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.ur.js +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Globalize Culture ur - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ur", "default", { - name: "ur", - englishName: "Urdu", - nativeName: "اُردو", - language: "ur", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$n"], - symbol: "Rs" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesAbbr: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesShort: ["ا","پ","م","ب","ج","ج","ه"] - }, - months: { - names: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""], - namesAbbr: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - f: "dd MMMM, yyyy h:mm tt", - F: "dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Cyrl-UZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Cyrl-UZ.js deleted file mode 100644 index f034500b00..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Cyrl-UZ.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture uz-Cyrl-UZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "uz-Cyrl-UZ", "default", { - name: "uz-Cyrl-UZ", - englishName: "Uzbek (Cyrillic, Uzbekistan)", - nativeName: "Ўзбек (Ўзбекистон)", - language: "uz-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "сўм" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["якшанба","душанба","сешанба","чоршанба","пайшанба","жума","шанба"], - namesAbbr: ["якш","дш","сш","чш","пш","ж","ш"], - namesShort: ["я","д","с","ч","п","ж","ш"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январ","феврал","март","апрел","май","июн","июл","август","сентябр","октябр","ноябр","декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","мая","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'йил' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'йил' d-MMMM HH:mm", - F: "yyyy 'йил' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Cyrl.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Cyrl.js deleted file mode 100644 index 8dbb77ca54..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Cyrl.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Globalize Culture uz-Cyrl - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "uz-Cyrl", "default", { - name: "uz-Cyrl", - englishName: "Uzbek (Cyrillic)", - nativeName: "Ўзбек", - language: "uz-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "сўм" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["якшанба","душанба","сешанба","чоршанба","пайшанба","жума","шанба"], - namesAbbr: ["якш","дш","сш","чш","пш","ж","ш"], - namesShort: ["я","д","с","ч","п","ж","ш"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январ","феврал","март","апрел","май","июн","июл","август","сентябр","октябр","ноябр","декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","мая","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'йил' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'йил' d-MMMM HH:mm", - F: "yyyy 'йил' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Latn-UZ.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Latn-UZ.js deleted file mode 100644 index 7f22ce802f..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Latn-UZ.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture uz-Latn-UZ - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "uz-Latn-UZ", "default", { - name: "uz-Latn-UZ", - englishName: "Uzbek (Latin, Uzbekistan)", - nativeName: "U'zbek (U'zbekiston Respublikasi)", - language: "uz-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": " ", - ".": ",", - symbol: "so'm" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["yakshanba","dushanba","seshanba","chorshanba","payshanba","juma","shanba"], - namesAbbr: ["yak.","dsh.","sesh.","chr.","psh.","jm.","sh."], - namesShort: ["ya","d","s","ch","p","j","sh"] - }, - months: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM yyyy", - D: "yyyy 'yil' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'yil' d-MMMM HH:mm", - F: "yyyy 'yil' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Latn.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Latn.js deleted file mode 100644 index 33d160bb7d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz-Latn.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture uz-Latn - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "uz-Latn", "default", { - name: "uz-Latn", - englishName: "Uzbek (Latin)", - nativeName: "U'zbek", - language: "uz-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": " ", - ".": ",", - symbol: "so'm" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["yakshanba","dushanba","seshanba","chorshanba","payshanba","juma","shanba"], - namesAbbr: ["yak.","dsh.","sesh.","chr.","psh.","jm.","sh."], - namesShort: ["ya","d","s","ch","p","j","sh"] - }, - months: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM yyyy", - D: "yyyy 'yil' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'yil' d-MMMM HH:mm", - F: "yyyy 'yil' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz.js deleted file mode 100644 index 63eac49c0c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.uz.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Globalize Culture uz - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "uz", "default", { - name: "uz", - englishName: "Uzbek", - nativeName: "U'zbek", - language: "uz", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": " ", - ".": ",", - symbol: "so'm" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["yakshanba","dushanba","seshanba","chorshanba","payshanba","juma","shanba"], - namesAbbr: ["yak.","dsh.","sesh.","chr.","psh.","jm.","sh."], - namesShort: ["ya","d","s","ch","p","j","sh"] - }, - months: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM yyyy", - D: "yyyy 'yil' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'yil' d-MMMM HH:mm", - F: "yyyy 'yil' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.vi.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.vi.js deleted file mode 100644 index d7191bfc0c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.vi.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Globalize Culture vi - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "vi", "default", { - name: "vi", - englishName: "Vietnamese", - nativeName: "Tiếng Việt", - language: "vi", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "₫" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Chủ Nhật","Thứ Hai","Thứ Ba","Thứ Tư","Thứ Năm","Thứ Sáu","Thứ Bảy"], - namesAbbr: ["CN","Hai","Ba","Tư","Năm","Sáu","Bảy"], - namesShort: ["C","H","B","T","N","S","B"] - }, - months: { - names: ["Tháng Giêng","Tháng Hai","Tháng Ba","Tháng Tư","Tháng Năm","Tháng Sáu","Tháng Bảy","Tháng Tám","Tháng Chín","Tháng Mười","Tháng Mười Một","Tháng Mười Hai",""], - namesAbbr: ["Thg1","Thg2","Thg3","Thg4","Thg5","Thg6","Thg7","Thg8","Thg9","Thg10","Thg11","Thg12",""] - }, - AM: ["SA","sa","SA"], - PM: ["CH","ch","CH"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - f: "dd MMMM yyyy h:mm tt", - F: "dd MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.wo-SN.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.wo-SN.js deleted file mode 100644 index 245f6ec6ce..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.wo-SN.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture wo-SN - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "wo-SN", "default", { - name: "wo-SN", - englishName: "Wolof (Senegal)", - nativeName: "Wolof (Sénégal)", - language: "wo", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "XOF" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.wo.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.wo.js deleted file mode 100644 index da949053e0..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.wo.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Globalize Culture wo - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "wo", "default", { - name: "wo", - englishName: "Wolof", - nativeName: "Wolof", - language: "wo", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "XOF" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.xh-ZA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.xh-ZA.js deleted file mode 100644 index 10f34c3733..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.xh-ZA.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Globalize Culture xh-ZA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "xh-ZA", "default", { - name: "xh-ZA", - englishName: "isiXhosa (South Africa)", - nativeName: "isiXhosa (uMzantsi Afrika)", - language: "xh", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iCawa","uMvulo","uLwesibini","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesShort: ["Ca","Mv","Lb","Lt","Ln","Lh","Mg"] - }, - months: { - names: ["Mqungu","Mdumba","Kwindla","Tshazimpuzi","Canzibe","Silimela","Khala","Thupha","Msintsi","Dwarha","Nkanga","Mnga",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.xh.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.xh.js deleted file mode 100644 index d15a3b85c8..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.xh.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Globalize Culture xh - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "xh", "default", { - name: "xh", - englishName: "isiXhosa", - nativeName: "isiXhosa", - language: "xh", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iCawa","uMvulo","uLwesibini","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesShort: ["Ca","Mv","Lb","Lt","Ln","Lh","Mg"] - }, - months: { - names: ["Mqungu","Mdumba","Kwindla","Tshazimpuzi","Canzibe","Silimela","Khala","Thupha","Msintsi","Dwarha","Nkanga","Mnga",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.yo-NG.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.yo-NG.js deleted file mode 100644 index c968ad328c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.yo-NG.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture yo-NG - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "yo-NG", "default", { - name: "yo-NG", - englishName: "Yoruba (Nigeria)", - nativeName: "Yoruba (Nigeria)", - language: "yo", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Osu kinni","Osu keji","Osu keta","Osu kerin","Osu karun","Osu kefa","Osu keje","Osu kejo","Osu kesan","Osu kewa","Osu kokanla","Osu keresi",""], - namesAbbr: ["kin.","kej.","ket.","ker.","kar.","kef.","kej.","kej.","kes.","kew.","kok.","ker.",""] - }, - AM: ["Owuro","owuro","OWURO"], - PM: ["Ale","ale","ALE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.yo.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.yo.js deleted file mode 100644 index 15b5c8c0e1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.yo.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Globalize Culture yo - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "yo", "default", { - name: "yo", - englishName: "Yoruba", - nativeName: "Yoruba", - language: "yo", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Osu kinni","Osu keji","Osu keta","Osu kerin","Osu karun","Osu kefa","Osu keje","Osu kejo","Osu kesan","Osu kewa","Osu kokanla","Osu keresi",""], - namesAbbr: ["kin.","kej.","ket.","ker.","kar.","kef.","kej.","kej.","kes.","kew.","kok.","ker.",""] - }, - AM: ["Owuro","owuro","OWURO"], - PM: ["Ale","ale","ALE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zh.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zh.js deleted file mode 100644 index b828385ff2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zh.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Globalize Culture zh - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "zh", "default", { - name: "zh", - englishName: "Chinese", - nativeName: "中文", - language: "zh", - numberFormat: { - "NaN": "非数字", - negativeInfinity: "负无穷大", - positiveInfinity: "正无穷大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["周日","周一","周二","周三","周四","周五","周六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zu-ZA.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zu-ZA.js deleted file mode 100644 index ffc89474c9..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zu-ZA.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Globalize Culture zu-ZA - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "zu-ZA", "default", { - name: "zu-ZA", - englishName: "isiZulu (South Africa)", - nativeName: "isiZulu (iNingizimu Afrika)", - language: "zu", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iSonto","uMsombuluko","uLwesibili","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesAbbr: ["Son.","Mso.","Bi.","Tha.","Ne.","Hla.","Mgq."] - }, - months: { - names: ["uMasingana","uNhlolanja","uNdasa","uMbaso","uNhlaba","uNhlangulana","uNtulikazi","uNcwaba","uMandulo","uMfumfu","uLwezi","uZibandlela",""], - namesAbbr: ["Mas.","Nhlo.","Nda.","Mba.","Nhla.","Nhlang.","Ntu.","Ncwa.","Man.","Mfu.","Lwe.","Zib.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zu.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zu.js deleted file mode 100644 index d1fbcc1acc..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.culture.zu.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Globalize Culture zu - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "zu", "default", { - name: "zu", - englishName: "isiZulu", - nativeName: "isiZulu", - language: "zu", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iSonto","uMsombuluko","uLwesibili","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesAbbr: ["Son.","Mso.","Bi.","Tha.","Ne.","Hla.","Mgq."] - }, - months: { - names: ["uMasingana","uNhlolanja","uNdasa","uMbaso","uNhlaba","uNhlangulana","uNtulikazi","uNcwaba","uMandulo","uMfumfu","uLwezi","uZibandlela",""], - namesAbbr: ["Mas.","Nhlo.","Nda.","Mba.","Nhla.","Nhlang.","Ntu.","Ncwa.","Man.","Mfu.","Lwe.","Zib.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.cultures.js b/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.cultures.js deleted file mode 100644 index 8b16cfce55..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/globalize/cultures/globalize.cultures.js +++ /dev/null @@ -1,24063 +0,0 @@ -/* - * Globalize Cultures - * - * http://github.com/jquery/globalize - * - * Copyright Software Freedom Conservancy, Inc. - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * This file was generated by the Globalize Culture Generator - * Translation: bugs found in this file need to be fixed in the generator - */ - -(function( window, undefined ) { - -var Globalize; - -if ( typeof require !== "undefined" && - typeof exports !== "undefined" && - typeof module !== "undefined" ) { - // Assume CommonJS - Globalize = require( "globalize" ); -} else { - // Global variable - Globalize = window.Globalize; -} - -Globalize.addCultureInfo( "ar", "default", { - name: "ar", - englishName: "Arabic", - nativeName: "العربية", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ر.س.\u200f" - } - }, - calendars: { - standard: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "bg", "default", { - name: "bg", - englishName: "Bulgarian", - nativeName: "български", - language: "bg", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "- безкрайност", - positiveInfinity: "+ безкрайност", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "лв." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["неделя","понеделник","вторник","сряда","четвъртък","петък","събота"], - namesAbbr: ["нед","пон","вт","ср","четв","пет","съб"], - namesShort: ["н","п","в","с","ч","п","с"] - }, - months: { - names: ["януари","февруари","март","април","май","юни","юли","август","септември","октомври","ноември","декември",""], - namesAbbr: ["ян","февр","март","апр","май","юни","юли","авг","септ","окт","ноември","дек",""] - }, - AM: null, - PM: null, - eras: [{"name":"след новата ера","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy 'г.'", - D: "dd MMMM yyyy 'г.'", - t: "HH:mm 'ч.'", - T: "HH:mm:ss 'ч.'", - f: "dd MMMM yyyy 'г.' HH:mm 'ч.'", - F: "dd MMMM yyyy 'г.' HH:mm:ss 'ч.'", - M: "dd MMMM", - Y: "MMMM yyyy 'г.'" - } - } - } -}); - -Globalize.addCultureInfo( "ca", "default", { - name: "ca", - englishName: "Catalan", - nativeName: "català", - language: "ca", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinit", - positiveInfinity: "Infinit", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["diumenge","dilluns","dimarts","dimecres","dijous","divendres","dissabte"], - namesAbbr: ["dg.","dl.","dt.","dc.","dj.","dv.","ds."], - namesShort: ["dg","dl","dt","dc","dj","dv","ds"] - }, - months: { - names: ["gener","febrer","març","abril","maig","juny","juliol","agost","setembre","octubre","novembre","desembre",""], - namesAbbr: ["gen","feb","març","abr","maig","juny","jul","ag","set","oct","nov","des",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' / 'MMMM' / 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' / 'MMMM' / 'yyyy HH:mm", - F: "dddd, d' / 'MMMM' / 'yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM' / 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "zh-Hans", "default", { - name: "zh-Hans", - englishName: "Chinese (Simplified)", - nativeName: "中文(简体)", - language: "zh-Hans", - numberFormat: { - "NaN": "非数字", - negativeInfinity: "负无穷大", - positiveInfinity: "正无穷大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["周日","周一","周二","周三","周四","周五","周六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "cs", "default", { - name: "cs", - englishName: "Czech", - nativeName: "čeština", - language: "cs", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Není číslo", - negativeInfinity: "-nekonečno", - positiveInfinity: "+nekonečno", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Kč" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["neděle","pondělí","úterý","středa","čtvrtek","pátek","sobota"], - namesAbbr: ["ne","po","út","st","čt","pá","so"], - namesShort: ["ne","po","út","st","čt","pá","so"] - }, - months: { - names: ["leden","únor","březen","duben","květen","červen","červenec","srpen","září","říjen","listopad","prosinec",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - monthsGenitive: { - names: ["ledna","února","března","dubna","května","června","července","srpna","září","října","listopadu","prosince",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["dop.","dop.","DOP."], - PM: ["odp.","odp.","ODP."], - eras: [{"name":"n. l.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "da", "default", { - name: "da", - englishName: "Danish", - nativeName: "dansk", - language: "da", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","marts","april","maj","juni","juli","august","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "de", "default", { - name: "de", - englishName: "German", - nativeName: "Deutsch", - language: "de", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "n. def.", - negativeInfinity: "-unendlich", - positiveInfinity: "+unendlich", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], - namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], - namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d. MMMM yyyy HH:mm", - F: "dddd, d. MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "el", "default", { - name: "el", - englishName: "Greek", - nativeName: "Ελληνικά", - language: "el", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "μη αριθμός", - negativeInfinity: "-Άπειρο", - positiveInfinity: "Άπειρο", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Κυριακή","Δευτέρα","Τρίτη","Τετάρτη","Πέμπτη","Παρασκευή","Σάββατο"], - namesAbbr: ["Κυρ","Δευ","Τρι","Τετ","Πεμ","Παρ","Σαβ"], - namesShort: ["Κυ","Δε","Τρ","Τε","Πε","Πα","Σά"] - }, - months: { - names: ["Ιανουάριος","Φεβρουάριος","Μάρτιος","Απρίλιος","Μάιος","Ιούνιος","Ιούλιος","Αύγουστος","Σεπτέμβριος","Οκτώβριος","Νοέμβριος","Δεκέμβριος",""], - namesAbbr: ["Ιαν","Φεβ","Μαρ","Απρ","Μαϊ","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ",""] - }, - monthsGenitive: { - names: ["Ιανουαρίου","Φεβρουαρίου","Μαρτίου","Απριλίου","Μαΐου","Ιουνίου","Ιουλίου","Αυγούστου","Σεπτεμβρίου","Οκτωβρίου","Νοεμβρίου","Δεκεμβρίου",""], - namesAbbr: ["Ιαν","Φεβ","Μαρ","Απρ","Μαϊ","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ",""] - }, - AM: ["πμ","πμ","ΠΜ"], - PM: ["μμ","μμ","ΜΜ"], - eras: [{"name":"μ.Χ.","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "dddd, d MMMM yyyy", - f: "dddd, d MMMM yyyy h:mm tt", - F: "dddd, d MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es", "default", { - name: "es", - englishName: "Spanish", - nativeName: "español", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fi", "default", { - name: "fi", - englishName: "Finnish", - nativeName: "suomi", - language: "fi", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sunnuntai","maanantai","tiistai","keskiviikko","torstai","perjantai","lauantai"], - namesAbbr: ["su","ma","ti","ke","to","pe","la"], - namesShort: ["su","ma","ti","ke","to","pe","la"] - }, - months: { - names: ["tammikuu","helmikuu","maaliskuu","huhtikuu","toukokuu","kesäkuu","heinäkuu","elokuu","syyskuu","lokakuu","marraskuu","joulukuu",""], - namesAbbr: ["tammi","helmi","maalis","huhti","touko","kesä","heinä","elo","syys","loka","marras","joulu",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM'ta 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM'ta 'yyyy H:mm", - F: "d. MMMM'ta 'yyyy H:mm:ss", - M: "d. MMMM'ta'", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fr", "default", { - name: "fr", - englishName: "French", - nativeName: "français", - language: "fr", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "he", "default", { - name: "he", - englishName: "Hebrew", - nativeName: "עברית", - language: "he", - isRTL: true, - numberFormat: { - "NaN": "לא מספר", - negativeInfinity: "אינסוף שלילי", - positiveInfinity: "אינסוף חיובי", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "₪" - } - }, - calendars: { - standard: { - days: { - names: ["יום ראשון","יום שני","יום שלישי","יום רביעי","יום חמישי","יום שישי","שבת"], - namesAbbr: ["יום א","יום ב","יום ג","יום ד","יום ה","יום ו","שבת"], - namesShort: ["א","ב","ג","ד","ה","ו","ש"] - }, - months: { - names: ["ינואר","פברואר","מרץ","אפריל","מאי","יוני","יולי","אוגוסט","ספטמבר","אוקטובר","נובמבר","דצמבר",""], - namesAbbr: ["ינו","פבר","מרץ","אפר","מאי","יונ","יול","אוג","ספט","אוק","נוב","דצמ",""] - }, - eras: [{"name":"לספירה","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd dd MMMM yyyy HH:mm", - F: "dddd dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - }, - Hebrew: { - name: "Hebrew", - "/": " ", - days: { - names: ["יום ראשון","יום שני","יום שלישי","יום רביעי","יום חמישי","יום שישי","שבת"], - namesAbbr: ["א","ב","ג","ד","ה","ו","ש"], - namesShort: ["א","ב","ג","ד","ה","ו","ש"] - }, - months: { - names: ["תשרי","חשון","כסלו","טבת","שבט","אדר","אדר ב","ניסן","אייר","סיון","תמוז","אב","אלול"], - namesAbbr: ["תשרי","חשון","כסלו","טבת","שבט","אדר","אדר ב","ניסן","אייר","סיון","תמוז","אב","אלול"] - }, - eras: [{"name":"C.E.","start":null,"offset":0}], - twoDigitYearMax: 5790, - patterns: { - d: "dd MMMM yyyy", - D: "dddd dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd dd MMMM yyyy HH:mm", - F: "dddd dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hu", "default", { - name: "hu", - englishName: "Hungarian", - nativeName: "magyar", - language: "hu", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "nem szám", - negativeInfinity: "negatív végtelen", - positiveInfinity: "végtelen", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Ft" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["vasárnap","hétfő","kedd","szerda","csütörtök","péntek","szombat"], - namesAbbr: ["V","H","K","Sze","Cs","P","Szo"], - namesShort: ["V","H","K","Sze","Cs","P","Szo"] - }, - months: { - names: ["január","február","március","április","május","június","július","augusztus","szeptember","október","november","december",""], - namesAbbr: ["jan.","febr.","márc.","ápr.","máj.","jún.","júl.","aug.","szept.","okt.","nov.","dec.",""] - }, - AM: ["de.","de.","DE."], - PM: ["du.","du.","DU."], - eras: [{"name":"i.sz.","start":null,"offset":0}], - patterns: { - d: "yyyy.MM.dd.", - D: "yyyy. MMMM d.", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy. MMMM d. H:mm", - F: "yyyy. MMMM d. H:mm:ss", - M: "MMMM d.", - Y: "yyyy. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "is", "default", { - name: "is", - englishName: "Icelandic", - nativeName: "íslenska", - language: "is", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sunnudagur","mánudagur","þriðjudagur","miðvikudagur","fimmtudagur","föstudagur","laugardagur"], - namesAbbr: ["sun.","mán.","þri.","mið.","fim.","fös.","lau."], - namesShort: ["su","má","þr","mi","fi","fö","la"] - }, - months: { - names: ["janúar","febrúar","mars","apríl","maí","júní","júlí","ágúst","september","október","nóvember","desember",""], - namesAbbr: ["jan.","feb.","mar.","apr.","maí","jún.","júl.","ágú.","sep.","okt.","nóv.","des.",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "it", "default", { - name: "it", - englishName: "Italian", - nativeName: "italiano", - language: "it", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "Non un numero reale", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"], - namesAbbr: ["dom","lun","mar","mer","gio","ven","sab"], - namesShort: ["do","lu","ma","me","gi","ve","sa"] - }, - months: { - names: ["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre",""], - namesAbbr: ["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ja", "default", { - name: "ja", - englishName: "Japanese", - nativeName: "日本語", - language: "ja", - numberFormat: { - "NaN": "NaN (非数値)", - negativeInfinity: "-∞", - positiveInfinity: "+∞", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["-$n","$n"], - decimals: 0, - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], - namesAbbr: ["日","月","火","水","木","金","土"], - namesShort: ["日","月","火","水","木","金","土"] - }, - months: { - names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["午前","午前","午前"], - PM: ["午後","午後","午後"], - eras: [{"name":"西暦","start":null,"offset":0}], - patterns: { - d: "yyyy/MM/dd", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - }, - Japanese: { - name: "Japanese", - days: { - names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], - namesAbbr: ["日","月","火","水","木","金","土"], - namesShort: ["日","月","火","水","木","金","土"] - }, - months: { - names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["午前","午前","午前"], - PM: ["午後","午後","午後"], - eras: [{"name":"平成","start":null,"offset":1867},{"name":"昭和","start":-1812153600000,"offset":1911},{"name":"大正","start":-1357603200000,"offset":1925},{"name":"明治","start":60022080000,"offset":1988}], - twoDigitYearMax: 99, - patterns: { - d: "gg y/M/d", - D: "gg y'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "gg y'年'M'月'd'日' H:mm", - F: "gg y'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "gg y'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "ko", "default", { - name: "ko", - englishName: "Korean", - nativeName: "한국어", - language: "ko", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - decimals: 0, - symbol: "₩" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["일요일","월요일","화요일","수요일","목요일","금요일","토요일"], - namesAbbr: ["일","월","화","수","목","금","토"], - namesShort: ["일","월","화","수","목","금","토"] - }, - months: { - names: ["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["오전","오전","오전"], - PM: ["오후","오후","오후"], - eras: [{"name":"서기","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy'년' M'월' d'일' dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy'년' M'월' d'일' dddd tt h:mm", - F: "yyyy'년' M'월' d'일' dddd tt h:mm:ss", - M: "M'월' d'일'", - Y: "yyyy'년' M'월'" - } - }, - Korean: { - name: "Korean", - "/": "-", - days: { - names: ["일요일","월요일","화요일","수요일","목요일","금요일","토요일"], - namesAbbr: ["일","월","화","수","목","금","토"], - namesShort: ["일","월","화","수","목","금","토"] - }, - months: { - names: ["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["오전","오전","오전"], - PM: ["오후","오후","오후"], - eras: [{"name":"단기","start":null,"offset":-2333}], - twoDigitYearMax: 4362, - patterns: { - d: "gg yyyy-MM-dd", - D: "gg yyyy'년' M'월' d'일' dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "gg yyyy'년' M'월' d'일' dddd tt h:mm", - F: "gg yyyy'년' M'월' d'일' dddd tt h:mm:ss", - M: "M'월' d'일'", - Y: "gg yyyy'년' M'월'" - } - } - } -}); - -Globalize.addCultureInfo( "nl", "default", { - name: "nl", - englishName: "Dutch", - nativeName: "Nederlands", - language: "nl", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"], - namesAbbr: ["zo","ma","di","wo","do","vr","za"], - namesShort: ["zo","ma","di","wo","do","vr","za"] - }, - months: { - names: ["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d-M-yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "no", "default", { - name: "no", - englishName: "Norwegian", - nativeName: "norsk", - language: "no", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "pl", "default", { - name: "pl", - englishName: "Polish", - nativeName: "polski", - language: "pl", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "nie jest liczbą", - negativeInfinity: "-nieskończoność", - positiveInfinity: "+nieskończoność", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "zł" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["niedziela","poniedziałek","wtorek","środa","czwartek","piątek","sobota"], - namesAbbr: ["N","Pn","Wt","Śr","Cz","Pt","So"], - namesShort: ["N","Pn","Wt","Śr","Cz","Pt","So"] - }, - months: { - names: ["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień",""], - namesAbbr: ["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru",""] - }, - monthsGenitive: { - names: ["stycznia","lutego","marca","kwietnia","maja","czerwca","lipca","sierpnia","września","października","listopada","grudnia",""], - namesAbbr: ["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "pt", "default", { - name: "pt", - englishName: "Portuguese", - nativeName: "Português", - language: "pt", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NaN (Não é um número)", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": ",", - symbol: "R$" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"], - namesAbbr: ["dom","seg","ter","qua","qui","sex","sáb"], - namesShort: ["D","S","T","Q","Q","S","S"] - }, - months: { - names: ["janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro",""], - namesAbbr: ["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' de 'MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' de 'MMMM' de 'yyyy HH:mm", - F: "dddd, d' de 'MMMM' de 'yyyy HH:mm:ss", - M: "dd' de 'MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "rm", "default", { - name: "rm", - englishName: "Romansh", - nativeName: "Rumantsch", - language: "rm", - numberFormat: { - ",": "'", - "NaN": "betg def.", - negativeInfinity: "-infinit", - positiveInfinity: "+infinit", - percent: { - pattern: ["-n%","n%"], - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "fr." - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumengia","glindesdi","mardi","mesemna","gievgia","venderdi","sonda"], - namesAbbr: ["du","gli","ma","me","gie","ve","so"], - namesShort: ["du","gli","ma","me","gie","ve","so"] - }, - months: { - names: ["schaner","favrer","mars","avrigl","matg","zercladur","fanadur","avust","settember","october","november","december",""], - namesAbbr: ["schan","favr","mars","avr","matg","zercl","fan","avust","sett","oct","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"s. Cr.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d MMMM yyyy HH:mm", - F: "dddd, d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ro", "default", { - name: "ro", - englishName: "Romanian", - nativeName: "română", - language: "ro", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "lei" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["duminică","luni","marţi","miercuri","joi","vineri","sâmbătă"], - namesAbbr: ["D","L","Ma","Mi","J","V","S"], - namesShort: ["D","L","Ma","Mi","J","V","S"] - }, - months: { - names: ["ianuarie","februarie","martie","aprilie","mai","iunie","iulie","august","septembrie","octombrie","noiembrie","decembrie",""], - namesAbbr: ["ian.","feb.","mar.","apr.","mai.","iun.","iul.","aug.","sep.","oct.","nov.","dec.",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ru", "default", { - name: "ru", - englishName: "Russian", - nativeName: "русский", - language: "ru", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["воскресенье","понедельник","вторник","среда","четверг","пятница","суббота"], - namesAbbr: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"], - namesShort: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"] - }, - months: { - names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - monthsGenitive: { - names: ["января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря",""], - namesAbbr: ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy 'г.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'г.' H:mm", - F: "d MMMM yyyy 'г.' H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hr", "default", { - name: "hr", - englishName: "Croatian", - nativeName: "hrvatski", - language: "hr", - numberFormat: { - pattern: ["- n"], - ",": ".", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kn" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["siječanj","veljača","ožujak","travanj","svibanj","lipanj","srpanj","kolovoz","rujan","listopad","studeni","prosinac",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - monthsGenitive: { - names: ["siječnja","veljače","ožujka","travnja","svibnja","lipnja","srpnja","kolovoza","rujna","listopada","studenog","prosinca",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy.", - D: "d. MMMM yyyy.", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy. H:mm", - F: "d. MMMM yyyy. H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "sk", "default", { - name: "sk", - englishName: "Slovak", - nativeName: "slovenčina", - language: "sk", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Nie je číslo", - negativeInfinity: "-nekonečno", - positiveInfinity: "+nekonečno", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["nedeľa","pondelok","utorok","streda","štvrtok","piatok","sobota"], - namesAbbr: ["ne","po","ut","st","št","pi","so"], - namesShort: ["ne","po","ut","st","št","pi","so"] - }, - months: { - names: ["január","február","marec","apríl","máj","jún","júl","august","september","október","november","december",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - monthsGenitive: { - names: ["januára","februára","marca","apríla","mája","júna","júla","augusta","septembra","októbra","novembra","decembra",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. l.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sq", "default", { - name: "sq", - englishName: "Albanian", - nativeName: "shqipe", - language: "sq", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-infinit", - positiveInfinity: "infinit", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": ".", - ".": ",", - symbol: "Lek" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["e diel","e hënë","e martë","e mërkurë","e enjte","e premte","e shtunë"], - namesAbbr: ["Die","Hën","Mar","Mër","Enj","Pre","Sht"], - namesShort: ["Di","Hë","Ma","Më","En","Pr","Sh"] - }, - months: { - names: ["janar","shkurt","mars","prill","maj","qershor","korrik","gusht","shtator","tetor","nëntor","dhjetor",""], - namesAbbr: ["Jan","Shk","Mar","Pri","Maj","Qer","Kor","Gsh","Sht","Tet","Nën","Dhj",""] - }, - AM: ["PD","pd","PD"], - PM: ["MD","md","MD"], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy-MM-dd", - t: "h:mm.tt", - T: "h:mm:ss.tt", - f: "yyyy-MM-dd h:mm.tt", - F: "yyyy-MM-dd h:mm:ss.tt", - Y: "yyyy-MM" - } - } - } -}); - -Globalize.addCultureInfo( "sv", "default", { - name: "sv", - englishName: "Swedish", - nativeName: "svenska", - language: "sv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"], - namesAbbr: ["sö","må","ti","on","to","fr","lö"], - namesShort: ["sö","må","ti","on","to","fr","lö"] - }, - months: { - names: ["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "'den 'd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "'den 'd MMMM yyyy HH:mm", - F: "'den 'd MMMM yyyy HH:mm:ss", - M: "'den 'd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "th", "default", { - name: "th", - englishName: "Thai", - nativeName: "ไทย", - language: "th", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "฿" - } - }, - calendars: { - standard: { - name: "ThaiBuddhist", - firstDay: 1, - days: { - names: ["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"], - namesAbbr: ["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."], - namesShort: ["อ","จ","อ","พ","พ","ศ","ส"] - }, - months: { - names: ["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม",""], - namesAbbr: ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค.",""] - }, - eras: [{"name":"พ.ศ.","start":null,"offset":-543}], - twoDigitYearMax: 2572, - patterns: { - d: "d/M/yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - }, - Gregorian_Localized: { - firstDay: 1, - days: { - names: ["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"], - namesAbbr: ["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."], - namesShort: ["อ","จ","อ","พ","พ","ศ","ส"] - }, - months: { - names: ["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม",""], - namesAbbr: ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค.",""] - }, - patterns: { - d: "d/M/yyyy", - D: "'วัน'dddd'ที่' d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "'วัน'dddd'ที่' d MMMM yyyy H:mm", - F: "'วัน'dddd'ที่' d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tr", "default", { - name: "tr", - englishName: "Turkish", - nativeName: "Türkçe", - language: "tr", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "TL" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"], - namesAbbr: ["Paz","Pzt","Sal","Çar","Per","Cum","Cmt"], - namesShort: ["Pz","Pt","Sa","Ça","Pe","Cu","Ct"] - }, - months: { - names: ["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık",""], - namesAbbr: ["Oca","Şub","Mar","Nis","May","Haz","Tem","Ağu","Eyl","Eki","Kas","Ara",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "dd MMMM yyyy dddd", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy dddd HH:mm", - F: "dd MMMM yyyy dddd HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ur", "default", { - name: "ur", - englishName: "Urdu", - nativeName: "اُردو", - language: "ur", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$n"], - symbol: "Rs" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesAbbr: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesShort: ["ا","پ","م","ب","ج","ج","ه"] - }, - months: { - names: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""], - namesAbbr: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - f: "dd MMMM, yyyy h:mm tt", - F: "dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - } - } -}); - -Globalize.addCultureInfo( "id", "default", { - name: "id", - englishName: "Indonesian", - nativeName: "Bahasa Indonesia", - language: "id", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - decimals: 0, - ",": ".", - ".": ",", - symbol: "Rp" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"], - namesAbbr: ["Minggu","Sen","Sel","Rabu","Kamis","Jumat","Sabtu"], - namesShort: ["M","S","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","Nopember","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agust","Sep","Okt","Nop","Des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "uk", "default", { - name: "uk", - englishName: "Ukrainian", - nativeName: "українська", - language: "uk", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-безмежність", - positiveInfinity: "безмежність", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₴" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["неділя","понеділок","вівторок","середа","четвер","п'ятниця","субота"], - namesAbbr: ["Нд","Пн","Вт","Ср","Чт","Пт","Сб"], - namesShort: ["Нд","Пн","Вт","Ср","Чт","Пт","Сб"] - }, - months: { - names: ["Січень","Лютий","Березень","Квітень","Травень","Червень","Липень","Серпень","Вересень","Жовтень","Листопад","Грудень",""], - namesAbbr: ["Січ","Лют","Бер","Кві","Тра","Чер","Лип","Сер","Вер","Жов","Лис","Гру",""] - }, - monthsGenitive: { - names: ["січня","лютого","березня","квітня","травня","червня","липня","серпня","вересня","жовтня","листопада","грудня",""], - namesAbbr: ["січ","лют","бер","кві","тра","чер","лип","сер","вер","жов","лис","гру",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy' р.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy' р.' H:mm", - F: "d MMMM yyyy' р.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy' р.'" - } - } - } -}); - -Globalize.addCultureInfo( "be", "default", { - name: "be", - englishName: "Belarusian", - nativeName: "Беларускі", - language: "be", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["нядзеля","панядзелак","аўторак","серада","чацвер","пятніца","субота"], - namesAbbr: ["нд","пн","аў","ср","чц","пт","сб"], - namesShort: ["нд","пн","аў","ср","чц","пт","сб"] - }, - months: { - names: ["Студзень","Люты","Сакавік","Красавік","Май","Чэрвень","Ліпень","Жнівень","Верасень","Кастрычнік","Лістапад","Снежань",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - monthsGenitive: { - names: ["студзеня","лютага","сакавіка","красавіка","мая","чэрвеня","ліпеня","жніўня","верасня","кастрычніка","лістапада","снежня",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sl", "default", { - name: "sl", - englishName: "Slovenian", - nativeName: "slovenski", - language: "sl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-neskončnost", - positiveInfinity: "neskončnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljek","torek","sreda","četrtek","petek","sobota"], - namesAbbr: ["ned","pon","tor","sre","čet","pet","sob"], - namesShort: ["ne","po","to","sr","če","pe","so"] - }, - months: { - names: ["januar","februar","marec","april","maj","junij","julij","avgust","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "et", "default", { - name: "et", - englishName: "Estonian", - nativeName: "eesti", - language: "et", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "avaldamatu", - negativeInfinity: "miinuslõpmatus", - positiveInfinity: "plusslõpmatus", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pühapäev","esmaspäev","teisipäev","kolmapäev","neljapäev","reede","laupäev"], - namesAbbr: ["P","E","T","K","N","R","L"], - namesShort: ["P","E","T","K","N","R","L"] - }, - months: { - names: ["jaanuar","veebruar","märts","aprill","mai","juuni","juuli","august","september","oktoober","november","detsember",""], - namesAbbr: ["jaan","veebr","märts","apr","mai","juuni","juuli","aug","sept","okt","nov","dets",""] - }, - AM: ["EL","el","EL"], - PM: ["PL","pl","PL"], - patterns: { - d: "d.MM.yyyy", - D: "d. MMMM yyyy'. a.'", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy'. a.' H:mm", - F: "d. MMMM yyyy'. a.' H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy'. a.'" - } - } - } -}); - -Globalize.addCultureInfo( "lv", "default", { - name: "lv", - englishName: "Latvian", - nativeName: "latviešu", - language: "lv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-bezgalība", - positiveInfinity: "bezgalība", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": " ", - ".": ",", - symbol: "Ls" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["svētdiena","pirmdiena","otrdiena","trešdiena","ceturtdiena","piektdiena","sestdiena"], - namesAbbr: ["sv","pr","ot","tr","ce","pk","se"], - namesShort: ["sv","pr","ot","tr","ce","pk","se"] - }, - months: { - names: ["janvāris","februāris","marts","aprīlis","maijs","jūnijs","jūlijs","augusts","septembris","oktobris","novembris","decembris",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - monthsGenitive: { - names: ["janvārī","februārī","martā","aprīlī","maijā","jūnijā","jūlijā","augustā","septembrī","oktobrī","novembrī","decembrī",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd.", - D: "dddd, yyyy'. gada 'd. MMMM", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, yyyy'. gada 'd. MMMM H:mm", - F: "dddd, yyyy'. gada 'd. MMMM H:mm:ss", - M: "d. MMMM", - Y: "yyyy. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "lt", "default", { - name: "lt", - englishName: "Lithuanian", - nativeName: "lietuvių", - language: "lt", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-begalybė", - positiveInfinity: "begalybė", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Lt" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sekmadienis","pirmadienis","antradienis","trečiadienis","ketvirtadienis","penktadienis","šeštadienis"], - namesAbbr: ["Sk","Pr","An","Tr","Kt","Pn","Št"], - namesShort: ["S","P","A","T","K","Pn","Š"] - }, - months: { - names: ["sausis","vasaris","kovas","balandis","gegužė","birželis","liepa","rugpjūtis","rugsėjis","spalis","lapkritis","gruodis",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - monthsGenitive: { - names: ["sausio","vasario","kovo","balandžio","gegužės","birželio","liepos","rugpjūčio","rugsėjo","spalio","lapkričio","gruodžio",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd", - D: "yyyy 'm.' MMMM d 'd.'", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'm.' MMMM d 'd.' HH:mm", - F: "yyyy 'm.' MMMM d 'd.' HH:mm:ss", - M: "MMMM d 'd.'", - Y: "yyyy 'm.' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "tg", "default", { - name: "tg", - englishName: "Tajik", - nativeName: "Тоҷикӣ", - language: "tg", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ";", - symbol: "т.р." - } - }, - calendars: { - standard: { - "/": ".", - days: { - names: ["Яш","Душанбе","Сешанбе","Чоршанбе","Панҷшанбе","Ҷумъа","Шанбе"], - namesAbbr: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"], - namesShort: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январи","феврали","марти","апрели","маи","июни","июли","августи","сентябри","октябри","ноябри","декабри",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fa", "default", { - name: "fa", - englishName: "Persian", - nativeName: "فارسى", - language: "fa", - isRTL: true, - numberFormat: { - pattern: ["n-"], - currency: { - pattern: ["$n-","$ n"], - ".": "/", - symbol: "ريال" - } - }, - calendars: { - standard: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""], - namesAbbr: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - patterns: { - d: "yyyy/MM/dd", - D: "yyyy/MM/dd", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "yyyy/MM/dd hh:mm tt", - F: "yyyy/MM/dd hh:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "vi", "default", { - name: "vi", - englishName: "Vietnamese", - nativeName: "Tiếng Việt", - language: "vi", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "₫" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Chủ Nhật","Thứ Hai","Thứ Ba","Thứ Tư","Thứ Năm","Thứ Sáu","Thứ Bảy"], - namesAbbr: ["CN","Hai","Ba","Tư","Năm","Sáu","Bảy"], - namesShort: ["C","H","B","T","N","S","B"] - }, - months: { - names: ["Tháng Giêng","Tháng Hai","Tháng Ba","Tháng Tư","Tháng Năm","Tháng Sáu","Tháng Bảy","Tháng Tám","Tháng Chín","Tháng Mười","Tháng Mười Một","Tháng Mười Hai",""], - namesAbbr: ["Thg1","Thg2","Thg3","Thg4","Thg5","Thg6","Thg7","Thg8","Thg9","Thg10","Thg11","Thg12",""] - }, - AM: ["SA","sa","SA"], - PM: ["CH","ch","CH"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - f: "dd MMMM yyyy h:mm tt", - F: "dd MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hy", "default", { - name: "hy", - englishName: "Armenian", - nativeName: "Հայերեն", - language: "hy", - numberFormat: { - currency: { - pattern: ["-n $","n $"], - symbol: "դր." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","ՈՒրբաթ","Շաբաթ"], - namesAbbr: ["Կիր","Երկ","Երք","Չրք","Հնգ","ՈՒր","Շբթ"], - namesShort: ["Կ","Ե","Ե","Չ","Հ","Ո","Շ"] - }, - months: { - names: ["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր",""], - namesAbbr: ["ՀՆՎ","ՓՏՎ","ՄՐՏ","ԱՊՐ","ՄՅՍ","ՀՆՍ","ՀԼՍ","ՕԳՍ","ՍԵՊ","ՀՈԿ","ՆՈՅ","ԴԵԿ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM, yyyy H:mm", - F: "d MMMM, yyyy H:mm:ss", - M: "d MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "az", "default", { - name: "az", - englishName: "Azeri", - nativeName: "Azərbaycan\xadılı", - language: "az", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "man." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"], - namesAbbr: ["B","Be","Ça","Ç","Ca","C","Ş"], - namesShort: ["B","Be","Ça","Ç","Ca","C","Ş"] - }, - months: { - names: ["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avgust","Sentyabr","Oktyabr","Noyabr","Dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - monthsGenitive: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "eu", "default", { - name: "eu", - englishName: "Basque", - nativeName: "euskara", - language: "eu", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "EdZ", - negativeInfinity: "-Infinitu", - positiveInfinity: "Infinitu", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["igandea","astelehena","asteartea","asteazkena","osteguna","ostirala","larunbata"], - namesAbbr: ["ig.","al.","as.","az.","og.","or.","lr."], - namesShort: ["ig","al","as","az","og","or","lr"] - }, - months: { - names: ["urtarrila","otsaila","martxoa","apirila","maiatza","ekaina","uztaila","abuztua","iraila","urria","azaroa","abendua",""], - namesAbbr: ["urt.","ots.","mar.","api.","mai.","eka.","uzt.","abu.","ira.","urr.","aza.","abe.",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "yyyy/MM/dd", - D: "dddd, yyyy.'eko' MMMM'k 'd", - t: "HH:mm", - T: "H:mm:ss", - f: "dddd, yyyy.'eko' MMMM'k 'd HH:mm", - F: "dddd, yyyy.'eko' MMMM'k 'd H:mm:ss", - Y: "yyyy.'eko' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "hsb", "default", { - name: "hsb", - englishName: "Upper Sorbian", - nativeName: "hornjoserbšćina", - language: "hsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekónčne", - positiveInfinity: "+njekónčne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njedźela","póndźela","wutora","srjeda","štwórtk","pjatk","sobota"], - namesAbbr: ["nje","pón","wut","srj","štw","pja","sob"], - namesShort: ["n","p","w","s","š","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","meja","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","meje","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'hodź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'hodź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "mk", "default", { - name: "mk", - englishName: "Macedonian (FYROM)", - nativeName: "македонски јазик", - language: "mk", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "ден." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недела","понеделник","вторник","среда","четврток","петок","сабота"], - namesAbbr: ["нед","пон","втр","срд","чет","пет","саб"], - namesShort: ["не","по","вт","ср","че","пе","са"] - }, - months: { - names: ["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември",""], - namesAbbr: ["јан","фев","мар","апр","мај","јун","јул","авг","сеп","окт","ное","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "dddd, dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, dd MMMM yyyy HH:mm", - F: "dddd, dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tn", "default", { - name: "tn", - englishName: "Setswana", - nativeName: "Setswana", - language: "tn", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Latshipi","Mosupologo","Labobedi","Laboraro","Labone","Labotlhano","Lamatlhatso"], - namesAbbr: ["Ltp.","Mos.","Lbd.","Lbr.","Lbn.","Lbt.","Lmt."], - namesShort: ["Lp","Ms","Lb","Lr","Ln","Lt","Lm"] - }, - months: { - names: ["Ferikgong","Tlhakole","Mopitloe","Moranang","Motsheganong","Seetebosigo","Phukwi","Phatwe","Lwetse","Diphalane","Ngwanatsele","Sedimothole",""], - namesAbbr: ["Fer.","Tlhak.","Mop.","Mor.","Motsh.","Seet.","Phukw.","Phatw.","Lwets.","Diph.","Ngwan.","Sed.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "xh", "default", { - name: "xh", - englishName: "isiXhosa", - nativeName: "isiXhosa", - language: "xh", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iCawa","uMvulo","uLwesibini","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesShort: ["Ca","Mv","Lb","Lt","Ln","Lh","Mg"] - }, - months: { - names: ["Mqungu","Mdumba","Kwindla","Tshazimpuzi","Canzibe","Silimela","Khala","Thupha","Msintsi","Dwarha","Nkanga","Mnga",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "zu", "default", { - name: "zu", - englishName: "isiZulu", - nativeName: "isiZulu", - language: "zu", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iSonto","uMsombuluko","uLwesibili","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesAbbr: ["Son.","Mso.","Bi.","Tha.","Ne.","Hla.","Mgq."] - }, - months: { - names: ["uMasingana","uNhlolanja","uNdasa","uMbaso","uNhlaba","uNhlangulana","uNtulikazi","uNcwaba","uMandulo","uMfumfu","uLwezi","uZibandlela",""], - namesAbbr: ["Mas.","Nhlo.","Nda.","Mba.","Nhla.","Nhlang.","Ntu.","Ncwa.","Man.","Mfu.","Lwe.","Zib.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "af", "default", { - name: "af", - englishName: "Afrikaans", - nativeName: "Afrikaans", - language: "af", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Sondag","Maandag","Dinsdag","Woensdag","Donderdag","Vrydag","Saterdag"], - namesAbbr: ["Son","Maan","Dins","Woen","Dond","Vry","Sat"], - namesShort: ["So","Ma","Di","Wo","Do","Vr","Sa"] - }, - months: { - names: ["Januarie","Februarie","Maart","April","Mei","Junie","Julie","Augustus","September","Oktober","November","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ka", "default", { - name: "ka", - englishName: "Georgian", - nativeName: "ქართული", - language: "ka", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Lari" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesAbbr: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesShort: ["კ","ო","ს","ო","ხ","პ","შ"] - }, - months: { - names: ["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბერი","ნოემბერი","დეკემბერი",""], - namesAbbr: ["იან","თებ","მარ","აპრ","მაის","ივნ","ივლ","აგვ","სექ","ოქტ","ნოემ","დეკ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'წლის' dd MM, dddd", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'წლის' dd MM, dddd H:mm", - F: "yyyy 'წლის' dd MM, dddd H:mm:ss", - M: "dd MM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fo", "default", { - name: "fo", - englishName: "Faroese", - nativeName: "føroyskt", - language: "fo", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sunnudagur","mánadagur","týsdagur","mikudagur","hósdagur","fríggjadagur","leygardagur"], - namesAbbr: ["sun","mán","týs","mik","hós","frí","leyg"], - namesShort: ["su","má","tý","mi","hó","fr","ley"] - }, - months: { - names: ["januar","februar","mars","apríl","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hi", "default", { - name: "hi", - englishName: "Hindi", - nativeName: "हिंदी", - language: "hi", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["रविवार","सोमवार","मंगलवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"], - namesAbbr: ["रवि.","सोम.","मंगल.","बुध.","गुरु.","शुक्र.","शनि."], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""], - namesAbbr: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""] - }, - AM: ["पूर्वाह्न","पूर्वाह्न","पूर्वाह्न"], - PM: ["अपराह्न","अपराह्न","अपराह्न"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "mt", "default", { - name: "mt", - englishName: "Maltese", - nativeName: "Malti", - language: "mt", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Il-Ħadd","It-Tnejn","It-Tlieta","L-Erbgħa","Il-Ħamis","Il-Ġimgħa","Is-Sibt"], - namesAbbr: ["Ħad","Tne","Tli","Erb","Ħam","Ġim","Sib"], - namesShort: ["I","I","I","L","I","I","I"] - }, - months: { - names: ["Jannar","Frar","Marzu","April","Mejju","Ġunju","Lulju","Awissu","Settembru","Ottubru","Novembru","Diċembru",""], - namesAbbr: ["Jan","Fra","Mar","Apr","Mej","Ġun","Lul","Awi","Set","Ott","Nov","Diċ",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' ta\\' 'MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' ta\\' 'MMMM yyyy HH:mm", - F: "dddd, d' ta\\' 'MMMM yyyy HH:mm:ss", - M: "d' ta\\' 'MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "se", "default", { - name: "se", - englishName: "Sami (Northern)", - nativeName: "davvisámegiella", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","vuos","maŋ","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ga", "default", { - name: "ga", - englishName: "Irish", - nativeName: "Gaeilge", - language: "ga", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dé Domhnaigh","Dé Luain","Dé Máirt","Dé Céadaoin","Déardaoin","Dé hAoine","Dé Sathairn"], - namesAbbr: ["Domh","Luan","Máir","Céad","Déar","Aoi","Sath"], - namesShort: ["Do","Lu","Má","Cé","De","Ao","Sa"] - }, - months: { - names: ["Eanáir","Feabhra","Márta","Aibreán","Bealtaine","Meitheamh","Iúil","Lúnasa","Meán Fómhair","Deireadh Fómhair","Samhain","Nollaig",""], - namesAbbr: ["Ean","Feabh","Már","Aib","Bealt","Meith","Iúil","Lún","M.Fómh","D.Fómh","Samh","Noll",""] - }, - AM: ["r.n.","r.n.","R.N."], - PM: ["i.n.","i.n.","I.N."], - patterns: { - d: "dd/MM/yyyy", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ms", "default", { - name: "ms", - englishName: "Malay", - nativeName: "Bahasa Melayu", - language: "ms", - numberFormat: { - currency: { - decimals: 0, - symbol: "RM" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"], - namesAbbr: ["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"], - namesShort: ["A","I","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "kk", "default", { - name: "kk", - englishName: "Kazakh", - nativeName: "Қазақ", - language: "kk", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$n","$n"], - ",": " ", - ".": "-", - symbol: "Т" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жексенбі","Дүйсенбі","Сейсенбі","Сәрсенбі","Бейсенбі","Жұма","Сенбі"], - namesAbbr: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"], - namesShort: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"] - }, - months: { - names: ["қаңтар","ақпан","наурыз","сәуір","мамыр","маусым","шілде","тамыз","қыркүйек","қазан","қараша","желтоқсан",""], - namesAbbr: ["Қаң","Ақп","Нау","Сәу","Мам","Мау","Шіл","Там","Қыр","Қаз","Қар","Жел",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy 'ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'ж.' H:mm", - F: "d MMMM yyyy 'ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ky", "default", { - name: "ky", - englishName: "Kyrgyz", - nativeName: "Кыргыз", - language: "ky", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": "-", - symbol: "сом" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жекшемби","Дүйшөмбү","Шейшемби","Шаршемби","Бейшемби","Жума","Ишемби"], - namesAbbr: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"], - namesShort: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"] - }, - months: { - names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d'-'MMMM yyyy'-ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d'-'MMMM yyyy'-ж.' H:mm", - F: "d'-'MMMM yyyy'-ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy'-ж.'" - } - } - } -}); - -Globalize.addCultureInfo( "sw", "default", { - name: "sw", - englishName: "Kiswahili", - nativeName: "Kiswahili", - language: "sw", - numberFormat: { - currency: { - symbol: "S" - } - }, - calendars: { - standard: { - days: { - names: ["Jumapili","Jumatatu","Jumanne","Jumatano","Alhamisi","Ijumaa","Jumamosi"], - namesAbbr: ["Jumap.","Jumat.","Juman.","Jumat.","Alh.","Iju.","Jumam."], - namesShort: ["P","T","N","T","A","I","M"] - }, - months: { - names: ["Januari","Februari","Machi","Aprili","Mei","Juni","Julai","Agosti","Septemba","Oktoba","Novemba","Decemba",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ago","Sep","Okt","Nov","Dec",""] - } - } - } -}); - -Globalize.addCultureInfo( "tk", "default", { - name: "tk", - englishName: "Turkmen", - nativeName: "türkmençe", - language: "tk", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-üznüksizlik", - positiveInfinity: "üznüksizlik", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "m." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Duşenbe","Sişenbe","Çarşenbe","Penşenbe","Anna","Şenbe","Ýekşenbe"], - namesAbbr: ["Db","Sb","Çb","Pb","An","Şb","Ýb"], - namesShort: ["D","S","Ç","P","A","Ş","Ý"] - }, - months: { - names: ["Ýanwar","Fewral","Mart","Aprel","Maý","lýun","lýul","Awgust","Sentýabr","Oktýabr","Noýabr","Dekabr",""], - namesAbbr: ["Ýan","Few","Mart","Apr","Maý","lýun","lýul","Awg","Sen","Okt","Not","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "yyyy 'ý.' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'ý.' MMMM d H:mm", - F: "yyyy 'ý.' MMMM d H:mm:ss", - Y: "yyyy 'ý.' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "uz", "default", { - name: "uz", - englishName: "Uzbek", - nativeName: "U'zbek", - language: "uz", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": " ", - ".": ",", - symbol: "so'm" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["yakshanba","dushanba","seshanba","chorshanba","payshanba","juma","shanba"], - namesAbbr: ["yak.","dsh.","sesh.","chr.","psh.","jm.","sh."], - namesShort: ["ya","d","s","ch","p","j","sh"] - }, - months: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM yyyy", - D: "yyyy 'yil' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'yil' d-MMMM HH:mm", - F: "yyyy 'yil' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tt", "default", { - name: "tt", - englishName: "Tatar", - nativeName: "Татар", - language: "tt", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Якшәмбе","Дүшәмбе","Сишәмбе","Чәршәмбе","Пәнҗешәмбе","Җомга","Шимбә"], - namesAbbr: ["Якш","Дүш","Сиш","Чәрш","Пәнҗ","Җом","Шим"], - namesShort: ["Я","Д","С","Ч","П","Җ","Ш"] - }, - months: { - names: ["Гыйнвар","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Гыйн.","Фев.","Мар.","Апр.","Май","Июнь","Июль","Авг.","Сен.","Окт.","Нояб.","Дек.",""] - }, - monthsGenitive: { - names: ["Гыйнварның","Февральнең","Мартның","Апрельнең","Майның","Июньнең","Июльнең","Августның","Сентябрьның","Октябрьның","Ноябрьның","Декабрьның",""], - namesAbbr: ["Гыйн.-ның","Фев.-нең","Мар.-ның","Апр.-нең","Майның","Июньнең","Июльнең","Авг.-ның","Сен.-ның","Окт.-ның","Нояб.-ның","Дек.-ның",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "bn", "default", { - name: "bn", - englishName: "Bengali", - nativeName: "বাংলা", - language: "bn", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "টা" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], - namesAbbr: ["রবি.","সোম.","মঙ্গল.","বুধ.","বৃহস্পতি.","শুক্র.","শনি."], - namesShort: ["র","স","ম","ব","ব","শ","শ"] - }, - months: { - names: ["জানুয়ারী","ফেব্রুয়ারী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর",""], - namesAbbr: ["জানু.","ফেব্রু.","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগ.","সেপ্টে.","অক্টো.","নভে.","ডিসে.",""] - }, - AM: ["পুর্বাহ্ন","পুর্বাহ্ন","পুর্বাহ্ন"], - PM: ["অপরাহ্ন","অপরাহ্ন","অপরাহ্ন"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "pa", "default", { - name: "pa", - englishName: "Punjabi", - nativeName: "ਪੰਜਾਬੀ", - language: "pa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ਰੁ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ਐਤਵਾਰ","ਸੋਮਵਾਰ","ਮੰਗਲਵਾਰ","ਬੁੱਧਵਾਰ","ਵੀਰਵਾਰ","ਸ਼ੁੱਕਰਵਾਰ","ਸ਼ਨਿੱਚਰਵਾਰ"], - namesAbbr: ["ਐਤ.","ਸੋਮ.","ਮੰਗਲ.","ਬੁੱਧ.","ਵੀਰ.","ਸ਼ੁਕਰ.","ਸ਼ਨਿੱਚਰ."], - namesShort: ["ਐ","ਸ","ਮ","ਬ","ਵ","ਸ਼","ਸ਼"] - }, - months: { - names: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""], - namesAbbr: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""] - }, - AM: ["ਸਵੇਰ","ਸਵੇਰ","ਸਵੇਰ"], - PM: ["ਸ਼ਾਮ","ਸ਼ਾਮ","ਸ਼ਾਮ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy dddd", - t: "tt hh:mm", - T: "tt hh:mm:ss", - f: "dd MMMM yyyy dddd tt hh:mm", - F: "dd MMMM yyyy dddd tt hh:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "gu", "default", { - name: "gu", - englishName: "Gujarati", - nativeName: "ગુજરાતી", - language: "gu", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "રૂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["રવિવાર","સોમવાર","મંગળવાર","બુધવાર","ગુરુવાર","શુક્રવાર","શનિવાર"], - namesAbbr: ["રવિ","સોમ","મંગળ","બુધ","ગુરુ","શુક્ર","શનિ"], - namesShort: ["ર","સ","મ","બ","ગ","શ","શ"] - }, - months: { - names: ["જાન્યુઆરી","ફેબ્રુઆરી","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટેમ્બર","ઑક્ટ્બર","નવેમ્બર","ડિસેમ્બર",""], - namesAbbr: ["જાન્યુ","ફેબ્રુ","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટે","ઑક્ટો","નવે","ડિસે",""] - }, - AM: ["પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન"], - PM: ["ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "or", "default", { - name: "or", - englishName: "Oriya", - nativeName: "ଓଡ଼ିଆ", - language: "or", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ଟ" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ରବିବାର","ସୋମବାର","ମଙ୍ଗଳବାର","ବୁଧବାର","ଗୁରୁବାର","ଶୁକ୍ରବାର","ଶନିବାର"], - namesAbbr: ["ରବି.","ସୋମ.","ମଙ୍ଗଳ.","ବୁଧ.","ଗୁରୁ.","ଶୁକ୍ର.","ଶନି."], - namesShort: ["ର","ସୋ","ମ","ବୁ","ଗୁ","ଶୁ","ଶ"] - }, - months: { - names: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""], - namesAbbr: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""] - }, - eras: [{"name":"ଖ୍ରୀଷ୍ଟାବ୍ଦ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ta", "default", { - name: "ta", - englishName: "Tamil", - nativeName: "தமிழ்", - language: "ta", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ரூ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ஞாயிற்றுக்கிழமை","திங்கள்கிழமை","செவ்வாய்கிழமை","புதன்கிழமை","வியாழக்கிழமை","வெள்ளிக்கிழமை","சனிக்கிழமை"], - namesAbbr: ["ஞாயிறு","திங்கள்","செவ்வாய்","புதன்","வியாழன்","வெள்ளி","சனி"], - namesShort: ["ஞா","தி","செ","பு","வி","வெ","ச"] - }, - months: { - names: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""], - namesAbbr: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""] - }, - AM: ["காலை","காலை","காலை"], - PM: ["மாலை","மாலை","மாலை"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "te", "default", { - name: "te", - englishName: "Telugu", - nativeName: "తెలుగు", - language: "te", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "రూ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ఆదివారం","సోమవారం","మంగళవారం","బుధవారం","గురువారం","శుక్రవారం","శనివారం"], - namesAbbr: ["ఆది.","సోమ.","మంగళ.","బుధ.","గురు.","శుక్ర.","శని."], - namesShort: ["ఆ","సో","మం","బు","గు","శు","శ"] - }, - months: { - names: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""], - namesAbbr: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""] - }, - AM: ["పూర్వాహ్న","పూర్వాహ్న","పూర్వాహ్న"], - PM: ["అపరాహ్న","అపరాహ్న","అపరాహ్న"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "kn", "default", { - name: "kn", - englishName: "Kannada", - nativeName: "ಕನ್ನಡ", - language: "kn", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ರೂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ಭಾನುವಾರ","ಸೋಮವಾರ","ಮಂಗಳವಾರ","ಬುಧವಾರ","ಗುರುವಾರ","ಶುಕ್ರವಾರ","ಶನಿವಾರ"], - namesAbbr: ["ಭಾನು.","ಸೋಮ.","ಮಂಗಳ.","ಬುಧ.","ಗುರು.","ಶುಕ್ರ.","ಶನಿ."], - namesShort: ["ರ","ಸ","ಮ","ಬ","ಗ","ಶ","ಶ"] - }, - months: { - names: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""], - namesAbbr: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""] - }, - AM: ["ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ"], - PM: ["ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ml", "default", { - name: "ml", - englishName: "Malayalam", - nativeName: "മലയാളം", - language: "ml", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ക" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["ഞായറാഴ്ച","തിങ്കളാഴ്ച","ചൊവ്വാഴ്ച","ബുധനാഴ്ച","വ്യാഴാഴ്ച","വെള്ളിയാഴ്ച","ശനിയാഴ്ച"], - namesAbbr: ["ഞായർ.","തിങ്കൾ.","ചൊവ്വ.","ബുധൻ.","വ്യാഴം.","വെള്ളി.","ശനി."], - namesShort: ["ഞ","ത","ച","ബ","വ","വെ","ശ"] - }, - months: { - names: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""], - namesAbbr: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""] - }, - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "as", "default", { - name: "as", - englishName: "Assamese", - nativeName: "অসমীয়া", - language: "as", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","n$"], - groupSizes: [3,2], - symbol: "ট" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["সোমবাৰ","মঙ্গলবাৰ","বুধবাৰ","বৃহস্পতিবাৰ","শুক্রবাৰ","শনিবাৰ","ৰবিবাৰ"], - namesAbbr: ["সোম.","মঙ্গল.","বুধ.","বৃহ.","শুক্র.","শনি.","ৰবি."], - namesShort: ["সো","ম","বু","বৃ","শু","শ","র"] - }, - months: { - names: ["জানুৱাৰী","ফেব্রুৱাৰী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টেম্বর","অক্টোবর","নবেম্বর","ডিচেম্বর",""], - namesAbbr: ["জানু","ফেব্রু","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টে","অক্টো","নবে","ডিচে",""] - }, - AM: ["ৰাতিপু","ৰাতিপু","ৰাতিপু"], - PM: ["আবেলি","আবেলি","আবেলি"], - eras: [{"name":"খ্রীষ্টাব্দ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "yyyy,MMMM dd, dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy,MMMM dd, dddd tt h:mm", - F: "yyyy,MMMM dd, dddd tt h:mm:ss", - M: "dd MMMM", - Y: "MMMM,yy" - } - } - } -}); - -Globalize.addCultureInfo( "mr", "default", { - name: "mr", - englishName: "Marathi", - nativeName: "मराठी", - language: "mr", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["रविवार","सोमवार","मंगळवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"], - namesAbbr: ["रवि.","सोम.","मंगळ.","बुध.","गुरु.","शुक्र.","शनि."], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोव्हेंबर","डिसेंबर",""], - namesAbbr: ["जाने.","फेब्रु.","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टें.","ऑक्टो.","नोव्हें.","डिसें.",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "sa", "default", { - name: "sa", - englishName: "Sanskrit", - nativeName: "संस्कृत", - language: "sa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesAbbr: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""], - namesAbbr: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""] - }, - AM: ["पूर्वाह्न","पूर्वाह्न","पूर्वाह्न"], - PM: ["अपराह्न","अपराह्न","अपराह्न"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy dddd", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy dddd HH:mm", - F: "dd MMMM yyyy dddd HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "mn", "default", { - name: "mn", - englishName: "Mongolian", - nativeName: "Монгол хэл", - language: "mn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₮" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"], - namesAbbr: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"], - namesShort: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"] - }, - months: { - names: ["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - monthsGenitive: { - names: ["1 дүгээр сарын","2 дугаар сарын","3 дугаар сарын","4 дүгээр сарын","5 дугаар сарын","6 дугаар сарын","7 дугаар сарын","8 дугаар сарын","9 дүгээр сарын","10 дугаар сарын","11 дүгээр сарын","12 дугаар сарын",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - AM: null, - PM: null, - patterns: { - d: "yy.MM.dd", - D: "yyyy 'оны' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'оны' MMMM d H:mm", - F: "yyyy 'оны' MMMM d H:mm:ss", - M: "d MMMM", - Y: "yyyy 'он' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "bo", "default", { - name: "bo", - englishName: "Tibetan", - nativeName: "བོད་ཡིག", - language: "bo", - numberFormat: { - groupSizes: [3,0], - "NaN": "ཨང་ཀི་མིན་པ།", - negativeInfinity: "མོ་གྲངས་ཚད་མེད་ཆུང་བ།", - positiveInfinity: "ཕོ་གྲངས་ཚད་མེད་ཆེ་བ།", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["གཟའ་ཉི་མ།","གཟའ་ཟླ་བ།","གཟའ་མིག་དམར།","གཟའ་ལྷག་པ།","གཟའ་ཕུར་བུ།","གཟའ་པ་སངས།","གཟའ་སྤེན་པ།"], - namesAbbr: ["ཉི་མ།","ཟླ་བ།","མིག་དམར།","ལྷག་པ།","ཕུར་བུ།","པ་སངས།","སྤེན་པ།"], - namesShort: ["༧","༡","༢","༣","༤","༥","༦"] - }, - months: { - names: ["སྤྱི་ཟླ་དང་པོ།","སྤྱི་ཟླ་གཉིས་པ།","སྤྱི་ཟླ་གསུམ་པ།","སྤྱི་ཟླ་བཞི་པ།","སྤྱི་ཟླ་ལྔ་པ།","སྤྱི་ཟླ་དྲུག་པ།","སྤྱི་ཟླ་བདུན་པ།","སྤྱི་ཟླ་བརྒྱད་པ།","སྤྱི་ཟླ་དགུ་པ།","སྤྱི་ཟླ་བཅུ་པོ།","སྤྱི་ཟླ་བཅུ་གཅིག་པ།","སྤྱི་ཟླ་བཅུ་གཉིས་པ།",""], - namesAbbr: ["ཟླ་ ༡","ཟླ་ ༢","ཟླ་ ༣","ཟླ་ ༤","ཟླ་ ༥","ཟླ་ ༦","ཟླ་ ༧","ཟླ་ ༨","ཟླ་ ༩","ཟླ་ ༡༠","ཟླ་ ༡༡","ཟླ་ ༡༢",""] - }, - AM: ["སྔ་དྲོ","སྔ་དྲོ","སྔ་དྲོ"], - PM: ["ཕྱི་དྲོ","ཕྱི་དྲོ","ཕྱི་དྲོ"], - eras: [{"name":"སྤྱི་ལོ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ལོའི་ཟླ' M'ཚེས' d", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm", - F: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm:ss", - M: "'ཟླ་' M'ཚེས'd", - Y: "yyyy.M" - } - } - } -}); - -Globalize.addCultureInfo( "cy", "default", { - name: "cy", - englishName: "Welsh", - nativeName: "Cymraeg", - language: "cy", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dydd Sul","Dydd Llun","Dydd Mawrth","Dydd Mercher","Dydd Iau","Dydd Gwener","Dydd Sadwrn"], - namesAbbr: ["Sul","Llun","Maw","Mer","Iau","Gwe","Sad"], - namesShort: ["Su","Ll","Ma","Me","Ia","Gw","Sa"] - }, - months: { - names: ["Ionawr","Chwefror","Mawrth","Ebrill","Mai","Mehefin","Gorffennaf","Awst","Medi","Hydref","Tachwedd","Rhagfyr",""], - namesAbbr: ["Ion","Chwe","Maw","Ebr","Mai","Meh","Gor","Aws","Med","Hyd","Tach","Rhag",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "km", "default", { - name: "km", - englishName: "Khmer", - nativeName: "ខ្មែរ", - language: "km", - numberFormat: { - pattern: ["- n"], - groupSizes: [3,0], - "NaN": "NAN", - negativeInfinity: "-- អនន្ត", - positiveInfinity: "អនន្ត", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["-n$","n$"], - symbol: "៛" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ថ្ងៃអាទិត្យ","ថ្ងៃច័ន្ទ","ថ្ងៃអង្គារ","ថ្ងៃពុធ","ថ្ងៃព្រហស្បតិ៍","ថ្ងៃសុក្រ","ថ្ងៃសៅរ៍"], - namesAbbr: ["អាទិ.","ច.","អ.","ពុ","ព្រហ.","សុ.","ស."], - namesShort: ["អា","ច","អ","ពុ","ព្","សុ","ស"] - }, - months: { - names: ["មករា","កុម្ភៈ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ",""], - namesAbbr: ["១","២","៣","៤","៥","៦","៧","៨","៩","១០","១១","១២",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"មុនគ.ស.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "d MMMM yyyy H:mm tt", - F: "d MMMM yyyy HH:mm:ss", - M: "'ថ្ងៃទី' dd 'ខែ' MM", - Y: "'ខែ' MM 'ឆ្នាំ' yyyy" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm tt", - F: "dddd, MMMM dd, yyyy HH:mm:ss" - } - } - } -}); - -Globalize.addCultureInfo( "lo", "default", { - name: "lo", - englishName: "Lao", - nativeName: "ລາວ", - language: "lo", - numberFormat: { - pattern: ["(n)"], - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - }, - currency: { - pattern: ["(n$)","n$"], - groupSizes: [3,0], - symbol: "₭" - } - }, - calendars: { - standard: { - days: { - names: ["ວັນອາທິດ","ວັນຈັນ","ວັນອັງຄານ","ວັນພຸດ","ວັນພະຫັດ","ວັນສຸກ","ວັນເສົາ"], - namesAbbr: ["ອາທິດ","ຈັນ","ອັງຄານ","ພຸດ","ພະຫັດ","ສຸກ","ເສົາ"], - namesShort: ["ອ","ຈ","ອ","ພ","ພ","ສ","ເ"] - }, - months: { - names: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""], - namesAbbr: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""] - }, - AM: ["ເຊົ້າ","ເຊົ້າ","ເຊົ້າ"], - PM: ["ແລງ","ແລງ","ແລງ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dd MMMM yyyy H:mm tt", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "gl", "default", { - name: "gl", - englishName: "Galician", - nativeName: "galego", - language: "gl", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","luns","martes","mércores","xoves","venres","sábado"], - namesAbbr: ["dom","luns","mar","mér","xov","ven","sáb"], - namesShort: ["do","lu","ma","mé","xo","ve","sá"] - }, - months: { - names: ["xaneiro","febreiro","marzo","abril","maio","xuño","xullo","agosto","setembro","outubro","novembro","decembro",""], - namesAbbr: ["xan","feb","mar","abr","maio","xuñ","xull","ago","set","out","nov","dec",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "kok", "default", { - name: "kok", - englishName: "Konkani", - nativeName: "कोंकणी", - language: "kok", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["आयतार","सोमार","मंगळार","बुधवार","बिरेस्तार","सुक्रार","शेनवार"], - namesAbbr: ["आय.","सोम.","मंगळ.","बुध.","बिरे.","सुक्र.","शेन."], - namesShort: ["आ","स","म","ब","ब","स","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""], - namesAbbr: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "syr", "default", { - name: "syr", - englishName: "Syriac", - nativeName: "ܣܘܪܝܝܐ", - language: "syr", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$ n"], - symbol: "ل.س.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["ܚܕ ܒܫܒܐ","ܬܪܝܢ ܒܫܒܐ","ܬܠܬܐ ܒܫܒܐ","ܐܪܒܥܐ ܒܫܒܐ","ܚܡܫܐ ܒܫܒܐ","ܥܪܘܒܬܐ","ܫܒܬܐ"], - namesAbbr: ["\u070fܐ \u070fܒܫ","\u070fܒ \u070fܒܫ","\u070fܓ \u070fܒܫ","\u070fܕ \u070fܒܫ","\u070fܗ \u070fܒܫ","\u070fܥܪܘܒ","\u070fܫܒ"], - namesShort: ["ܐ","ܒ","ܓ","ܕ","ܗ","ܥ","ܫ"] - }, - months: { - names: ["ܟܢܘܢ ܐܚܪܝ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","ܬܫܪܝ ܩܕܝܡ","ܬܫܪܝ ܐܚܪܝ","ܟܢܘܢ ܩܕܝܡ",""], - namesAbbr: ["\u070fܟܢ \u070fܒ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","\u070fܬܫ \u070fܐ","\u070fܬܫ \u070fܒ","\u070fܟܢ \u070fܐ",""] - }, - AM: ["ܩ.ܛ","ܩ.ܛ","ܩ.ܛ"], - PM: ["ܒ.ܛ","ܒ.ܛ","ܒ.ܛ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "si", "default", { - name: "si", - englishName: "Sinhala", - nativeName: "සිංහල", - language: "si", - numberFormat: { - groupSizes: [3,2], - negativeInfinity: "-අනන්තය", - positiveInfinity: "අනන්තය", - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["($ n)","$ n"], - symbol: "රු." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ඉරිදා","සඳුදා","අඟහරුවාදා","බදාදා","බ්\u200dරහස්පතින්දා","සිකුරාදා","සෙනසුරාදා"], - namesAbbr: ["ඉරිදා","සඳුදා","කුජදා","බුදදා","ගුරුදා","කිවිදා","ශනිදා"], - namesShort: ["ඉ","ස","අ","බ","බ්\u200dර","සි","සෙ"] - }, - months: { - names: ["ජනවාරි","පෙබරවාරි","මාර්තු","අ\u200cප්\u200dරේල්","මැයි","ජූනි","ජූලි","අ\u200cගෝස්තු","සැප්තැම්බර්","ඔක්තෝබර්","නොවැම්බර්","දෙසැම්බර්",""], - namesAbbr: ["ජන.","පෙබ.","මාර්තු.","අප්\u200dරේල්.","මැයි.","ජූනි.","ජූලි.","අගෝ.","සැප්.","ඔක්.","නොවැ.","දෙසැ.",""] - }, - AM: ["පෙ.ව.","පෙ.ව.","පෙ.ව."], - PM: ["ප.ව.","ප.ව.","ප.ව."], - eras: [{"name":"ක්\u200dරි.ව.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy MMMM' මස 'dd' වැනිදා 'dddd", - f: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm tt", - F: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm:ss tt", - Y: "yyyy MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "iu", "default", { - name: "iu", - englishName: "Inuktitut", - nativeName: "Inuktitut", - language: "iu", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Naattiinguja","Naggajjau","Aippiq","Pingatsiq","Sitammiq","Tallirmiq","Sivataarvik"], - namesAbbr: ["Nat","Nag","Aip","Pi","Sit","Tal","Siv"], - namesShort: ["N","N","A","P","S","T","S"] - }, - months: { - names: ["Jaannuari","Viivvuari","Maatsi","Iipuri","Mai","Juuni","Julai","Aaggiisi","Sitipiri","Utupiri","Nuvipiri","Tisipiri",""], - namesAbbr: ["Jan","Viv","Mas","Ipu","Mai","Jun","Jul","Agi","Sii","Uut","Nuv","Tis",""] - }, - patterns: { - d: "d/MM/yyyy", - D: "ddd, MMMM dd,yyyy", - f: "ddd, MMMM dd,yyyy h:mm tt", - F: "ddd, MMMM dd,yyyy h:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "am", "default", { - name: "am", - englishName: "Amharic", - nativeName: "አማርኛ", - language: "am", - numberFormat: { - decimals: 1, - groupSizes: [3,0], - "NaN": "NAN", - percent: { - pattern: ["-n%","n%"], - decimals: 1, - groupSizes: [3,0] - }, - currency: { - pattern: ["-$n","$n"], - groupSizes: [3,0], - symbol: "ETB" - } - }, - calendars: { - standard: { - days: { - names: ["እሑድ","ሰኞ","ማክሰኞ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesAbbr: ["እሑድ","ሰኞ","ማክሰ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesShort: ["እ","ሰ","ማ","ረ","ሐ","ዓ","ቅ"] - }, - months: { - names: ["ጃንዩወሪ","ፌብሩወሪ","ማርች","ኤፕረል","ሜይ","ጁን","ጁላይ","ኦገስት","ሴፕቴምበር","ኦክተውበር","ኖቬምበር","ዲሴምበር",""], - namesAbbr: ["ጃንዩ","ፌብሩ","ማርች","ኤፕረ","ሜይ","ጁን","ጁላይ","ኦገስ","ሴፕቴ","ኦክተ","ኖቬም","ዲሴም",""] - }, - AM: ["ጡዋት","ጡዋት","ጡዋት"], - PM: ["ከሰዓት","ከሰዓት","ከሰዓት"], - eras: [{"name":"ዓመተ ምሕረት","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "dddd '፣' MMMM d 'ቀን' yyyy", - f: "dddd '፣' MMMM d 'ቀን' yyyy h:mm tt", - F: "dddd '፣' MMMM d 'ቀን' yyyy h:mm:ss tt", - M: "MMMM d ቀን", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tzm", "default", { - name: "tzm", - englishName: "Tamazight", - nativeName: "Tamazight", - language: "tzm", - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - symbol: "DZD" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 6, - days: { - names: ["Acer","Arime","Aram","Ahad","Amhadh","Sem","Sedh"], - namesAbbr: ["Ace","Ari","Ara","Aha","Amh","Sem","Sed"], - namesShort: ["Ac","Ar","Ar","Ah","Am","Se","Se"] - }, - months: { - names: ["Yenayer","Furar","Maghres","Yebrir","Mayu","Yunyu","Yulyu","Ghuct","Cutenber","Ktuber","Wambir","Dujanbir",""], - namesAbbr: ["Yen","Fur","Mag","Yeb","May","Yun","Yul","Ghu","Cut","Ktu","Wam","Duj",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ne", "default", { - name: "ne", - englishName: "Nepali", - nativeName: "नेपाली", - language: "ne", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "रु" - } - }, - calendars: { - standard: { - days: { - names: ["आइतवार","सोमवार","मङ्गलवार","बुधवार","बिहीवार","शुक्रवार","शनिवार"], - namesAbbr: ["आइत","सोम","मङ्गल","बुध","बिही","शुक्र","शनि"], - namesShort: ["आ","सो","म","बु","बि","शु","श"] - }, - months: { - names: ["जनवरी","फेब्रुअरी","मार्च","अप्रिल","मे","जून","जुलाई","अगस्त","सेप्टेम्बर","अक्टोबर","नोभेम्बर","डिसेम्बर",""], - namesAbbr: ["जन","फेब","मार्च","अप्रिल","मे","जून","जुलाई","अग","सेप्ट","अक्ट","नोभ","डिस",""] - }, - AM: ["विहानी","विहानी","विहानी"], - PM: ["बेलुकी","बेलुकी","बेलुकी"], - eras: [{"name":"a.d.","start":null,"offset":0}], - patterns: { - Y: "MMMM,yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fy", "default", { - name: "fy", - englishName: "Frisian", - nativeName: "Frysk", - language: "fy", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["Snein","Moandei","Tiisdei","Woansdei","Tongersdei","Freed","Sneon"], - namesAbbr: ["Sn","Mo","Ti","Wo","To","Fr","Sn"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["jannewaris","febrewaris","maart","april","maaie","juny","july","augustus","septimber","oktober","novimber","desimber",""], - namesAbbr: ["jann","febr","mrt","apr","maaie","jun","jul","aug","sept","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "d-M-yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ps", "default", { - name: "ps", - englishName: "Pashto", - nativeName: "پښتو", - language: "ps", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": "،", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": "،", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - ",": "٬", - ".": "٫", - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښزمرى","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښ","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fil", "default", { - name: "fil", - englishName: "Filipino", - nativeName: "Filipino", - language: "fil", - numberFormat: { - currency: { - symbol: "PhP" - } - }, - calendars: { - standard: { - days: { - names: ["Linggo","Lunes","Martes","Mierkoles","Huebes","Biernes","Sabado"], - namesAbbr: ["Lin","Lun","Mar","Mier","Hueb","Bier","Saba"], - namesShort: ["L","L","M","M","H","B","S"] - }, - months: { - names: ["Enero","Pebrero","Marso","Abril","Mayo","Hunyo","Hulyo","Agosto","Septyembre","Oktubre","Nobyembre","Disyembre",""], - namesAbbr: ["En","Peb","Mar","Abr","Mayo","Hun","Hul","Agos","Sept","Okt","Nob","Dis",""] - }, - eras: [{"name":"Anno Domini","start":null,"offset":0}] - } - } -}); - -Globalize.addCultureInfo( "dv", "default", { - name: "dv", - englishName: "Divehi", - nativeName: "ދިވެހިބަސް", - language: "dv", - isRTL: true, - numberFormat: { - currency: { - pattern: ["n $-","n $"], - symbol: "ރ." - } - }, - calendars: { - standard: { - name: "Hijri", - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""], - namesAbbr: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd/MM/yyyy HH:mm", - F: "dd/MM/yyyy HH:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""], - namesAbbr: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"މީލާދީ","start":null,"offset":0}], - patterns: { - d: "dd/MM/yy", - D: "ddd, yyyy MMMM dd", - t: "HH:mm", - T: "HH:mm:ss", - f: "ddd, yyyy MMMM dd HH:mm", - F: "ddd, yyyy MMMM dd HH:mm:ss", - Y: "yyyy, MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ha", "default", { - name: "ha", - englishName: "Hausa", - nativeName: "Hausa", - language: "ha", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Lahadi","Litinin","Talata","Laraba","Alhamis","Juma'a","Asabar"], - namesAbbr: ["Lah","Lit","Tal","Lar","Alh","Jum","Asa"], - namesShort: ["L","L","T","L","A","J","A"] - }, - months: { - names: ["Januwaru","Febreru","Maris","Afrilu","Mayu","Yuni","Yuli","Agusta","Satumba","Oktocba","Nuwamba","Disamba",""], - namesAbbr: ["Jan","Feb","Mar","Afr","May","Yun","Yul","Agu","Sat","Okt","Nuw","Dis",""] - }, - AM: ["Safe","safe","SAFE"], - PM: ["Yamma","yamma","YAMMA"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "yo", "default", { - name: "yo", - englishName: "Yoruba", - nativeName: "Yoruba", - language: "yo", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Osu kinni","Osu keji","Osu keta","Osu kerin","Osu karun","Osu kefa","Osu keje","Osu kejo","Osu kesan","Osu kewa","Osu kokanla","Osu keresi",""], - namesAbbr: ["kin.","kej.","ket.","ker.","kar.","kef.","kej.","kej.","kes.","kew.","kok.","ker.",""] - }, - AM: ["Owuro","owuro","OWURO"], - PM: ["Ale","ale","ALE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "quz", "default", { - name: "quz", - englishName: "Quechua", - nativeName: "runasimi", - language: "quz", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": ",", - symbol: "$b" - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "nso", "default", { - name: "nso", - englishName: "Sesotho sa Leboa", - nativeName: "Sesotho sa Leboa", - language: "nso", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Lamorena","Mošupologo","Labobedi","Laboraro","Labone","Labohlano","Mokibelo"], - namesAbbr: ["Lam","Moš","Lbb","Lbr","Lbn","Lbh","Mok"], - namesShort: ["L","M","L","L","L","L","M"] - }, - months: { - names: ["Pherekgong","Hlakola","Mopitlo","Moranang","Mosegamanye","Ngoatobošego","Phuphu","Phato","Lewedi","Diphalana","Dibatsela","Manthole",""], - namesAbbr: ["Pher","Hlak","Mop","Mor","Mos","Ngwat","Phup","Phat","Lew","Dip","Dib","Man",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ba", "default", { - name: "ba", - englishName: "Bashkir", - nativeName: "Башҡорт", - language: "ba", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ",", - symbol: "һ." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Йәкшәмбе","Дүшәмбе","Шишәмбе","Шаршамбы","Кесаҙна","Йома","Шәмбе"], - namesAbbr: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"], - namesShort: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"] - }, - months: { - names: ["ғинуар","февраль","март","апрель","май","июнь","июль","август","сентябрь","октябрь","ноябрь","декабрь",""], - namesAbbr: ["ғин","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy 'й'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'й' H:mm", - F: "d MMMM yyyy 'й' H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "lb", "default", { - name: "lb", - englishName: "Luxembourgish", - nativeName: "Lëtzebuergesch", - language: "lb", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "n. num.", - negativeInfinity: "-onendlech", - positiveInfinity: "+onendlech", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sonndeg","Méindeg","Dënschdeg","Mëttwoch","Donneschdeg","Freideg","Samschdeg"], - namesAbbr: ["Son","Méi","Dën","Mët","Don","Fre","Sam"], - namesShort: ["So","Mé","Dë","Më","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","Mäerz","Abrëll","Mee","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mäe","Abr","Mee","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "kl", "default", { - name: "kl", - englishName: "Greenlandic", - nativeName: "kalaallisut", - language: "kl", - numberFormat: { - ",": ".", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - groupSizes: [3,0], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,0], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sapaat","ataasinngorneq","marlunngorneq","pingasunngorneq","sisamanngorneq","tallimanngorneq","arfininngorneq"], - namesAbbr: ["sap","ata","mar","ping","sis","tal","arf"], - namesShort: ["sa","at","ma","pi","si","ta","ar"] - }, - months: { - names: ["januari","februari","martsi","apriili","maaji","juni","juli","aggusti","septembari","oktobari","novembari","decembari",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ig", "default", { - name: "ig", - englishName: "Igbo", - nativeName: "Igbo", - language: "ig", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Onwa mbu","Onwa ibua","Onwa ato","Onwa ano","Onwa ise","Onwa isi","Onwa asa","Onwa asato","Onwa itolu","Onwa iri","Onwa iri n'ofu","Onwa iri n'ibua",""], - namesAbbr: ["mbu.","ibu.","ato.","ano.","ise","isi","asa","asa.","ito.","iri.","n'of.","n'ib.",""] - }, - AM: ["Ututu","ututu","UTUTU"], - PM: ["Efifie","efifie","EFIFIE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ii", "default", { - name: "ii", - englishName: "Yi", - nativeName: "ꆈꌠꁱꂷ", - language: "ii", - numberFormat: { - groupSizes: [3,0], - "NaN": "ꌗꂷꀋꉬ", - negativeInfinity: "ꀄꊭꌐꀋꉆ", - positiveInfinity: "ꈤꇁꑖꀋꉬ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ꑭꆏꑍ","ꆏꊂ꒔","ꆏꊂꑍ","ꆏꊂꌕ","ꆏꊂꇖ","ꆏꊂꉬ","ꆏꊂꃘ"], - namesAbbr: ["ꑭꆏ","ꆏ꒔","ꆏꑍ","ꆏꌕ","ꆏꇖ","ꆏꉬ","ꆏꃘ"], - namesShort: ["ꆏ","꒔","ꑍ","ꌕ","ꇖ","ꉬ","ꃘ"] - }, - months: { - names: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""], - namesAbbr: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""] - }, - AM: ["ꂵꆪꈌꈐ","ꂵꆪꈌꈐ","ꂵꆪꈌꈐ"], - PM: ["ꂵꆪꈌꉈ","ꂵꆪꈌꉈ","ꂵꆪꈌꉈ"], - eras: [{"name":"ꇬꑼ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ꈎ' M'ꆪ' d'ꑍ'", - t: "tt h:mm", - T: "H:mm:ss", - f: "yyyy'ꈎ' M'ꆪ' d'ꑍ' tt h:mm", - F: "yyyy'ꈎ' M'ꆪ' d'ꑍ' H:mm:ss", - M: "M'ꆪ' d'ꑍ'", - Y: "yyyy'ꈎ' M'ꆪ'" - } - } - } -}); - -Globalize.addCultureInfo( "arn", "default", { - name: "arn", - englishName: "Mapudungun", - nativeName: "Mapudungun", - language: "arn", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "moh", "default", { - name: "moh", - englishName: "Mohawk", - nativeName: "Kanien'kéha", - language: "moh", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Awentatokentì:ke","Awentataón'ke","Ratironhia'kehronòn:ke","Soséhne","Okaristiiáhne","Ronwaia'tanentaktonhne","Entákta"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["Tsothohrkó:Wa","Enniska","Enniskó:Wa","Onerahtókha","Onerahtohkó:Wa","Ohiari:Ha","Ohiarihkó:Wa","Seskéha","Seskehkó:Wa","Kenténha","Kentenhkó:Wa","Tsothóhrha",""] - } - } - } -}); - -Globalize.addCultureInfo( "br", "default", { - name: "br", - englishName: "Breton", - nativeName: "brezhoneg", - language: "br", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NkN", - negativeInfinity: "-Anfin", - positiveInfinity: "+Anfin", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sul","Lun","Meurzh","Merc'her","Yaou","Gwener","Sadorn"], - namesAbbr: ["Sul","Lun","Meu.","Mer.","Yaou","Gwe.","Sad."], - namesShort: ["Su","Lu","Mz","Mc","Ya","Gw","Sa"] - }, - months: { - names: ["Genver","C'hwevrer","Meurzh","Ebrel","Mae","Mezheven","Gouere","Eost","Gwengolo","Here","Du","Kerzu",""], - namesAbbr: ["Gen.","C'hwe.","Meur.","Ebr.","Mae","Mezh.","Goue.","Eost","Gwen.","Here","Du","Kzu",""] - }, - AM: null, - PM: null, - eras: [{"name":"g. J.-K.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ug", "default", { - name: "ug", - englishName: "Uyghur", - nativeName: "ئۇيغۇرچە", - language: "ug", - isRTL: true, - numberFormat: { - "NaN": "سان ئەمەس", - negativeInfinity: "مەنپىي چەكسىزلىك", - positiveInfinity: "مۇسبەت چەكسىزلىك", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["يەكشەنبە","دۈشەنبە","سەيشەنبە","چارشەنبە","پەيشەنبە","جۈمە","شەنبە"], - namesAbbr: ["يە","دۈ","سە","چا","پە","جۈ","شە"], - namesShort: ["ي","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""], - namesAbbr: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""] - }, - AM: ["چۈشتىن بۇرۇن","چۈشتىن بۇرۇن","چۈشتىن بۇرۇن"], - PM: ["چۈشتىن كېيىن","چۈشتىن كېيىن","چۈشتىن كېيىن"], - eras: [{"name":"مىلادى","start":null,"offset":0}], - patterns: { - d: "yyyy-M-d", - D: "yyyy-'يىلى' MMMM d-'كۈنى،'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm", - F: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm:ss", - M: "MMMM d'-كۈنى'", - Y: "yyyy-'يىلى' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "mi", "default", { - name: "mi", - englishName: "Maori", - nativeName: "Reo Māori", - language: "mi", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Rātapu","Rāhina","Rātū","Rāapa","Rāpare","Rāmere","Rāhoroi"], - namesAbbr: ["Ta","Hi","Tū","Apa","Pa","Me","Ho"], - namesShort: ["Ta","Hi","Tū","Aa","Pa","Me","Ho"] - }, - months: { - names: ["Kohi-tātea","Hui-tanguru","Poutū-te-rangi","Paenga-whāwhā","Haratua","Pipiri","Hōngongoi","Here-turi-kōkā","Mahuru","Whiringa-ā-nuku","Whiringa-ā-rangi","Hakihea",""], - namesAbbr: ["Kohi","Hui","Pou","Pae","Hara","Pipi","Hōngo","Here","Mahu","Nuku","Rangi","Haki",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM, yyyy", - f: "dddd, dd MMMM, yyyy h:mm tt", - F: "dddd, dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM, yy" - } - } - } -}); - -Globalize.addCultureInfo( "oc", "default", { - name: "oc", - englishName: "Occitan", - nativeName: "Occitan", - language: "oc", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numeric", - negativeInfinity: "-Infinit", - positiveInfinity: "+Infinit", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimenge","diluns","dimars","dimècres","dijòus","divendres","dissabte"], - namesAbbr: ["dim.","lun.","mar.","mèc.","jòu.","ven.","sab."], - namesShort: ["di","lu","ma","mè","jò","ve","sa"] - }, - months: { - names: ["genier","febrier","març","abril","mai","junh","julh","agost","setembre","octobre","novembre","desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - monthsGenitive: { - names: ["de genier","de febrier","de març","d'abril","de mai","de junh","de julh","d'agost","de setembre","d'octobre","de novembre","de desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - AM: null, - PM: null, - eras: [{"name":"après Jèsus-Crist","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd,' lo 'd MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd,' lo 'd MMMM' de 'yyyy HH:mm", - F: "dddd,' lo 'd MMMM' de 'yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "co", "default", { - name: "co", - englishName: "Corsican", - nativeName: "Corsu", - language: "co", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Mica numericu", - negativeInfinity: "-Infinitu", - positiveInfinity: "+Infinitu", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumenica","luni","marti","mercuri","ghjovi","venderi","sabbatu"], - namesAbbr: ["dum.","lun.","mar.","mer.","ghj.","ven.","sab."], - namesShort: ["du","lu","ma","me","gh","ve","sa"] - }, - months: { - names: ["ghjennaghju","ferraghju","marzu","aprile","maghju","ghjunghju","lugliu","aostu","settembre","ottobre","nuvembre","dicembre",""], - namesAbbr: ["ghje","ferr","marz","apri","magh","ghju","lugl","aost","sett","otto","nuve","dice",""] - }, - AM: null, - PM: null, - eras: [{"name":"dopu J-C","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "gsw", "default", { - name: "gsw", - englishName: "Alsatian", - nativeName: "Elsässisch", - language: "gsw", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Ohne Nummer", - negativeInfinity: "-Unendlich", - positiveInfinity: "+Unendlich", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sundàà","Mondàà","Dienschdàà","Mittwuch","Dunnerschdàà","Fridàà","Sàmschdàà"], - namesAbbr: ["Su.","Mo.","Di.","Mi.","Du.","Fr.","Sà."], - namesShort: ["Su","Mo","Di","Mi","Du","Fr","Sà"] - }, - months: { - names: ["Jänner","Feverje","März","Àpril","Mai","Jüni","Jüli","Augscht","September","Oktower","Nowember","Dezember",""], - namesAbbr: ["Jän.","Fev.","März","Apr.","Mai","Jüni","Jüli","Aug.","Sept.","Okt.","Now.","Dez.",""] - }, - AM: null, - PM: null, - eras: [{"name":"Vor J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sah", "default", { - name: "sah", - englishName: "Yakut", - nativeName: "саха", - language: "sah", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NAN", - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "с." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["баскыһыанньа","бэнидиэнньик","оптуорунньук","сэрэдэ","чэппиэр","бээтинсэ","субуота"], - namesAbbr: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"], - namesShort: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"] - }, - months: { - names: ["Тохсунньу","Олунньу","Кулун тутар","Муус устар","Ыам ыйа","Бэс ыйа","От ыйа","Атырдьах ыйа","Балаҕан ыйа","Алтынньы","Сэтинньи","Ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - monthsGenitive: { - names: ["тохсунньу","олунньу","кулун тутар","муус устар","ыам ыйын","бэс ыйын","от ыйын","атырдьах ыйын","балаҕан ыйын","алтынньы","сэтинньи","ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - AM: null, - PM: null, - patterns: { - d: "MM.dd.yyyy", - D: "MMMM d yyyy 'с.'", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d yyyy 'с.' H:mm", - F: "MMMM d yyyy 'с.' H:mm:ss", - Y: "MMMM yyyy 'с.'" - } - } - } -}); - -Globalize.addCultureInfo( "qut", "default", { - name: "qut", - englishName: "K'iche", - nativeName: "K'iche", - language: "qut", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - symbol: "Q" - } - }, - calendars: { - standard: { - days: { - names: ["juq'ij","kaq'ij","oxq'ij","kajq'ij","joq'ij","waqq'ij","wuqq'ij"], - namesAbbr: ["juq","kaq","oxq","kajq","joq","waqq","wuqq"], - namesShort: ["ju","ka","ox","ka","jo","wa","wu"] - }, - months: { - names: ["nab'e ik'","ukab' ik'","rox ik'","ukaj ik'","uro' ik'","uwaq ik'","uwuq ik'","uwajxaq ik'","ub'elej ik'","ulaj ik'","ujulaj ik'","ukab'laj ik'",""], - namesAbbr: ["nab'e","ukab","rox","ukaj","uro","uwaq","uwuq","uwajxaq","ub'elej","ulaj","ujulaj","ukab'laj",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "rw", "default", { - name: "rw", - englishName: "Kinyarwanda", - nativeName: "Kinyarwanda", - language: "rw", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$-n","$ n"], - ",": " ", - ".": ",", - symbol: "RWF" - } - }, - calendars: { - standard: { - days: { - names: ["Ku wa mbere","Ku wa kabiri","Ku wa gatatu","Ku wa kane","Ku wa gatanu","Ku wa gatandatu","Ku cyumweru"], - namesAbbr: ["mbe.","kab.","gat.","kan.","gat.","gat.","cyu."], - namesShort: ["mb","ka","ga","ka","ga","ga","cy"] - }, - months: { - names: ["Mutarama","Gashyantare","Werurwe","Mata","Gicurasi","Kamena","Nyakanga","Kanama","Nzeli","Ukwakira","Ugushyingo","Ukuboza",""], - namesAbbr: ["Mut","Gas","Wer","Mat","Gic","Kam","Nya","Kan","Nze","Ukwa","Ugu","Uku",""] - }, - AM: ["saa moya z.m.","saa moya z.m.","SAA MOYA Z.M."], - PM: ["saa moya z.n.","saa moya z.n.","SAA MOYA Z.N."], - eras: [{"name":"AD","start":null,"offset":0}] - } - } -}); - -Globalize.addCultureInfo( "wo", "default", { - name: "wo", - englishName: "Wolof", - nativeName: "Wolof", - language: "wo", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "XOF" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "prs", "default", { - name: "prs", - englishName: "Dari", - nativeName: "درى", - language: "prs", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 5, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 5, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "gd", "default", { - name: "gd", - englishName: "Scottish Gaelic", - nativeName: "Gàidhlig", - language: "gd", - numberFormat: { - negativeInfinity: "-Neo-chrìochnachd", - positiveInfinity: "Neo-chrìochnachd", - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"], - namesAbbr: ["Dòm","Lua","Mài","Cia","Ard","Hao","Sat"], - namesShort: ["D","L","M","C","A","H","S"] - }, - months: { - names: ["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd",""], - namesAbbr: ["Fao","Gea","Màr","Gib","Cèi","Ògm","Iuc","Lùn","Sul","Dàm","Sam","Dùb",""] - }, - AM: ["m","m","M"], - PM: ["f","f","F"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-SA", "default", { - name: "ar-SA", - englishName: "Arabic (Saudi Arabia)", - nativeName: "العربية (المملكة العربية السعودية)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ر.س.\u200f" - } - }, - calendars: { - standard: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "bg-BG", "default", { - name: "bg-BG", - englishName: "Bulgarian (Bulgaria)", - nativeName: "български (България)", - language: "bg", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "- безкрайност", - positiveInfinity: "+ безкрайност", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "лв." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["неделя","понеделник","вторник","сряда","четвъртък","петък","събота"], - namesAbbr: ["нед","пон","вт","ср","четв","пет","съб"], - namesShort: ["н","п","в","с","ч","п","с"] - }, - months: { - names: ["януари","февруари","март","април","май","юни","юли","август","септември","октомври","ноември","декември",""], - namesAbbr: ["ян","февр","март","апр","май","юни","юли","авг","септ","окт","ноември","дек",""] - }, - AM: null, - PM: null, - eras: [{"name":"след новата ера","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy 'г.'", - D: "dd MMMM yyyy 'г.'", - t: "HH:mm 'ч.'", - T: "HH:mm:ss 'ч.'", - f: "dd MMMM yyyy 'г.' HH:mm 'ч.'", - F: "dd MMMM yyyy 'г.' HH:mm:ss 'ч.'", - M: "dd MMMM", - Y: "MMMM yyyy 'г.'" - } - } - } -}); - -Globalize.addCultureInfo( "ca-ES", "default", { - name: "ca-ES", - englishName: "Catalan (Catalan)", - nativeName: "català (català)", - language: "ca", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinit", - positiveInfinity: "Infinit", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["diumenge","dilluns","dimarts","dimecres","dijous","divendres","dissabte"], - namesAbbr: ["dg.","dl.","dt.","dc.","dj.","dv.","ds."], - namesShort: ["dg","dl","dt","dc","dj","dv","ds"] - }, - months: { - names: ["gener","febrer","març","abril","maig","juny","juliol","agost","setembre","octubre","novembre","desembre",""], - namesAbbr: ["gen","feb","març","abr","maig","juny","jul","ag","set","oct","nov","des",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' / 'MMMM' / 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' / 'MMMM' / 'yyyy HH:mm", - F: "dddd, d' / 'MMMM' / 'yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM' / 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "zh-TW", "default", { - name: "zh-TW", - englishName: "Chinese (Traditional, Taiwan)", - nativeName: "中文(台灣)", - language: "zh-CHT", - numberFormat: { - "NaN": "不是一個數字", - negativeInfinity: "負無窮大", - positiveInfinity: "正無窮大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "NT$" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["週日","週一","週二","週三","週四","週五","週六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"西元","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'年'M'月'd'日'", - t: "tt hh:mm", - T: "tt hh:mm:ss", - f: "yyyy'年'M'月'd'日' tt hh:mm", - F: "yyyy'年'M'月'd'日' tt hh:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - }, - Taiwan: { - name: "Taiwan", - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["週日","週一","週二","週三","週四","週五","週六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"","start":null,"offset":1911}], - twoDigitYearMax: 99, - patterns: { - d: "yyyy/M/d", - D: "yyyy'年'M'月'd'日'", - t: "tt hh:mm", - T: "tt hh:mm:ss", - f: "yyyy'年'M'月'd'日' tt hh:mm", - F: "yyyy'年'M'月'd'日' tt hh:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "cs-CZ", "default", { - name: "cs-CZ", - englishName: "Czech (Czech Republic)", - nativeName: "čeština (Česká republika)", - language: "cs", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Není číslo", - negativeInfinity: "-nekonečno", - positiveInfinity: "+nekonečno", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Kč" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["neděle","pondělí","úterý","středa","čtvrtek","pátek","sobota"], - namesAbbr: ["ne","po","út","st","čt","pá","so"], - namesShort: ["ne","po","út","st","čt","pá","so"] - }, - months: { - names: ["leden","únor","březen","duben","květen","červen","červenec","srpen","září","říjen","listopad","prosinec",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - monthsGenitive: { - names: ["ledna","února","března","dubna","května","června","července","srpna","září","října","listopadu","prosince",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["dop.","dop.","DOP."], - PM: ["odp.","odp.","ODP."], - eras: [{"name":"n. l.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "da-DK", "default", { - name: "da-DK", - englishName: "Danish (Denmark)", - nativeName: "dansk (Danmark)", - language: "da", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","marts","april","maj","juni","juli","august","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "de-DE", "default", { - name: "de-DE", - englishName: "German (Germany)", - nativeName: "Deutsch (Deutschland)", - language: "de", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "n. def.", - negativeInfinity: "-unendlich", - positiveInfinity: "+unendlich", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], - namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], - namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d. MMMM yyyy HH:mm", - F: "dddd, d. MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "el-GR", "default", { - name: "el-GR", - englishName: "Greek (Greece)", - nativeName: "Ελληνικά (Ελλάδα)", - language: "el", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "μη αριθμός", - negativeInfinity: "-Άπειρο", - positiveInfinity: "Άπειρο", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Κυριακή","Δευτέρα","Τρίτη","Τετάρτη","Πέμπτη","Παρασκευή","Σάββατο"], - namesAbbr: ["Κυρ","Δευ","Τρι","Τετ","Πεμ","Παρ","Σαβ"], - namesShort: ["Κυ","Δε","Τρ","Τε","Πε","Πα","Σά"] - }, - months: { - names: ["Ιανουάριος","Φεβρουάριος","Μάρτιος","Απρίλιος","Μάιος","Ιούνιος","Ιούλιος","Αύγουστος","Σεπτέμβριος","Οκτώβριος","Νοέμβριος","Δεκέμβριος",""], - namesAbbr: ["Ιαν","Φεβ","Μαρ","Απρ","Μαϊ","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ",""] - }, - monthsGenitive: { - names: ["Ιανουαρίου","Φεβρουαρίου","Μαρτίου","Απριλίου","Μαΐου","Ιουνίου","Ιουλίου","Αυγούστου","Σεπτεμβρίου","Οκτωβρίου","Νοεμβρίου","Δεκεμβρίου",""], - namesAbbr: ["Ιαν","Φεβ","Μαρ","Απρ","Μαϊ","Ιουν","Ιουλ","Αυγ","Σεπ","Οκτ","Νοε","Δεκ",""] - }, - AM: ["πμ","πμ","ΠΜ"], - PM: ["μμ","μμ","ΜΜ"], - eras: [{"name":"μ.Χ.","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "dddd, d MMMM yyyy", - f: "dddd, d MMMM yyyy h:mm tt", - F: "dddd, d MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "en-US", "default", { - name: "en-US", - englishName: "English (United States)" -}); - -Globalize.addCultureInfo( "fi-FI", "default", { - name: "fi-FI", - englishName: "Finnish (Finland)", - nativeName: "suomi (Suomi)", - language: "fi", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sunnuntai","maanantai","tiistai","keskiviikko","torstai","perjantai","lauantai"], - namesAbbr: ["su","ma","ti","ke","to","pe","la"], - namesShort: ["su","ma","ti","ke","to","pe","la"] - }, - months: { - names: ["tammikuu","helmikuu","maaliskuu","huhtikuu","toukokuu","kesäkuu","heinäkuu","elokuu","syyskuu","lokakuu","marraskuu","joulukuu",""], - namesAbbr: ["tammi","helmi","maalis","huhti","touko","kesä","heinä","elo","syys","loka","marras","joulu",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM'ta 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM'ta 'yyyy H:mm", - F: "d. MMMM'ta 'yyyy H:mm:ss", - M: "d. MMMM'ta'", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fr-FR", "default", { - name: "fr-FR", - englishName: "French (France)", - nativeName: "français (France)", - language: "fr", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "he-IL", "default", { - name: "he-IL", - englishName: "Hebrew (Israel)", - nativeName: "עברית (ישראל)", - language: "he", - isRTL: true, - numberFormat: { - "NaN": "לא מספר", - negativeInfinity: "אינסוף שלילי", - positiveInfinity: "אינסוף חיובי", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "₪" - } - }, - calendars: { - standard: { - days: { - names: ["יום ראשון","יום שני","יום שלישי","יום רביעי","יום חמישי","יום שישי","שבת"], - namesAbbr: ["יום א","יום ב","יום ג","יום ד","יום ה","יום ו","שבת"], - namesShort: ["א","ב","ג","ד","ה","ו","ש"] - }, - months: { - names: ["ינואר","פברואר","מרץ","אפריל","מאי","יוני","יולי","אוגוסט","ספטמבר","אוקטובר","נובמבר","דצמבר",""], - namesAbbr: ["ינו","פבר","מרץ","אפר","מאי","יונ","יול","אוג","ספט","אוק","נוב","דצמ",""] - }, - eras: [{"name":"לספירה","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd dd MMMM yyyy HH:mm", - F: "dddd dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - }, - Hebrew: { - name: "Hebrew", - "/": " ", - days: { - names: ["יום ראשון","יום שני","יום שלישי","יום רביעי","יום חמישי","יום שישי","שבת"], - namesAbbr: ["א","ב","ג","ד","ה","ו","ש"], - namesShort: ["א","ב","ג","ד","ה","ו","ש"] - }, - months: { - names: ["תשרי","חשון","כסלו","טבת","שבט","אדר","אדר ב","ניסן","אייר","סיון","תמוז","אב","אלול"], - namesAbbr: ["תשרי","חשון","כסלו","טבת","שבט","אדר","אדר ב","ניסן","אייר","סיון","תמוז","אב","אלול"] - }, - eras: [{"name":"C.E.","start":null,"offset":0}], - twoDigitYearMax: 5790, - patterns: { - d: "dd MMMM yyyy", - D: "dddd dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd dd MMMM yyyy HH:mm", - F: "dddd dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hu-HU", "default", { - name: "hu-HU", - englishName: "Hungarian (Hungary)", - nativeName: "magyar (Magyarország)", - language: "hu", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "nem szám", - negativeInfinity: "negatív végtelen", - positiveInfinity: "végtelen", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Ft" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["vasárnap","hétfő","kedd","szerda","csütörtök","péntek","szombat"], - namesAbbr: ["V","H","K","Sze","Cs","P","Szo"], - namesShort: ["V","H","K","Sze","Cs","P","Szo"] - }, - months: { - names: ["január","február","március","április","május","június","július","augusztus","szeptember","október","november","december",""], - namesAbbr: ["jan.","febr.","márc.","ápr.","máj.","jún.","júl.","aug.","szept.","okt.","nov.","dec.",""] - }, - AM: ["de.","de.","DE."], - PM: ["du.","du.","DU."], - eras: [{"name":"i.sz.","start":null,"offset":0}], - patterns: { - d: "yyyy.MM.dd.", - D: "yyyy. MMMM d.", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy. MMMM d. H:mm", - F: "yyyy. MMMM d. H:mm:ss", - M: "MMMM d.", - Y: "yyyy. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "is-IS", "default", { - name: "is-IS", - englishName: "Icelandic (Iceland)", - nativeName: "íslenska (Ísland)", - language: "is", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sunnudagur","mánudagur","þriðjudagur","miðvikudagur","fimmtudagur","föstudagur","laugardagur"], - namesAbbr: ["sun.","mán.","þri.","mið.","fim.","fös.","lau."], - namesShort: ["su","má","þr","mi","fi","fö","la"] - }, - months: { - names: ["janúar","febrúar","mars","apríl","maí","júní","júlí","ágúst","september","október","nóvember","desember",""], - namesAbbr: ["jan.","feb.","mar.","apr.","maí","jún.","júl.","ágú.","sep.","okt.","nóv.","des.",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "it-IT", "default", { - name: "it-IT", - englishName: "Italian (Italy)", - nativeName: "italiano (Italia)", - language: "it", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "Non un numero reale", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"], - namesAbbr: ["dom","lun","mar","mer","gio","ven","sab"], - namesShort: ["do","lu","ma","me","gi","ve","sa"] - }, - months: { - names: ["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre",""], - namesAbbr: ["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ja-JP", "default", { - name: "ja-JP", - englishName: "Japanese (Japan)", - nativeName: "日本語 (日本)", - language: "ja", - numberFormat: { - "NaN": "NaN (非数値)", - negativeInfinity: "-∞", - positiveInfinity: "+∞", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["-$n","$n"], - decimals: 0, - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], - namesAbbr: ["日","月","火","水","木","金","土"], - namesShort: ["日","月","火","水","木","金","土"] - }, - months: { - names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["午前","午前","午前"], - PM: ["午後","午後","午後"], - eras: [{"name":"西暦","start":null,"offset":0}], - patterns: { - d: "yyyy/MM/dd", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - }, - Japanese: { - name: "Japanese", - days: { - names: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], - namesAbbr: ["日","月","火","水","木","金","土"], - namesShort: ["日","月","火","水","木","金","土"] - }, - months: { - names: ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["午前","午前","午前"], - PM: ["午後","午後","午後"], - eras: [{"name":"平成","start":null,"offset":1867},{"name":"昭和","start":-1812153600000,"offset":1911},{"name":"大正","start":-1357603200000,"offset":1925},{"name":"明治","start":60022080000,"offset":1988}], - twoDigitYearMax: 99, - patterns: { - d: "gg y/M/d", - D: "gg y'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "gg y'年'M'月'd'日' H:mm", - F: "gg y'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "gg y'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "ko-KR", "default", { - name: "ko-KR", - englishName: "Korean (Korea)", - nativeName: "한국어 (대한민국)", - language: "ko", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - decimals: 0, - symbol: "₩" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["일요일","월요일","화요일","수요일","목요일","금요일","토요일"], - namesAbbr: ["일","월","화","수","목","금","토"], - namesShort: ["일","월","화","수","목","금","토"] - }, - months: { - names: ["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["오전","오전","오전"], - PM: ["오후","오후","오후"], - eras: [{"name":"서기","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy'년' M'월' d'일' dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy'년' M'월' d'일' dddd tt h:mm", - F: "yyyy'년' M'월' d'일' dddd tt h:mm:ss", - M: "M'월' d'일'", - Y: "yyyy'년' M'월'" - } - }, - Korean: { - name: "Korean", - "/": "-", - days: { - names: ["일요일","월요일","화요일","수요일","목요일","금요일","토요일"], - namesAbbr: ["일","월","화","수","목","금","토"], - namesShort: ["일","월","화","수","목","금","토"] - }, - months: { - names: ["1월","2월","3월","4월","5월","6월","7월","8월","9월","10월","11월","12월",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: ["오전","오전","오전"], - PM: ["오후","오후","오후"], - eras: [{"name":"단기","start":null,"offset":-2333}], - twoDigitYearMax: 4362, - patterns: { - d: "gg yyyy-MM-dd", - D: "gg yyyy'년' M'월' d'일' dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "gg yyyy'년' M'월' d'일' dddd tt h:mm", - F: "gg yyyy'년' M'월' d'일' dddd tt h:mm:ss", - M: "M'월' d'일'", - Y: "gg yyyy'년' M'월'" - } - } - } -}); - -Globalize.addCultureInfo( "nl-NL", "default", { - name: "nl-NL", - englishName: "Dutch (Netherlands)", - nativeName: "Nederlands (Nederland)", - language: "nl", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"], - namesAbbr: ["zo","ma","di","wo","do","vr","za"], - namesShort: ["zo","ma","di","wo","do","vr","za"] - }, - months: { - names: ["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d-M-yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "nb-NO", "default", { - name: "nb-NO", - englishName: "Norwegian, Bokmål (Norway)", - nativeName: "norsk, bokmål (Norge)", - language: "nb", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "pl-PL", "default", { - name: "pl-PL", - englishName: "Polish (Poland)", - nativeName: "polski (Polska)", - language: "pl", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "nie jest liczbą", - negativeInfinity: "-nieskończoność", - positiveInfinity: "+nieskończoność", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "zł" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["niedziela","poniedziałek","wtorek","środa","czwartek","piątek","sobota"], - namesAbbr: ["N","Pn","Wt","Śr","Cz","Pt","So"], - namesShort: ["N","Pn","Wt","Śr","Cz","Pt","So"] - }, - months: { - names: ["styczeń","luty","marzec","kwiecień","maj","czerwiec","lipiec","sierpień","wrzesień","październik","listopad","grudzień",""], - namesAbbr: ["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru",""] - }, - monthsGenitive: { - names: ["stycznia","lutego","marca","kwietnia","maja","czerwca","lipca","sierpnia","września","października","listopada","grudnia",""], - namesAbbr: ["sty","lut","mar","kwi","maj","cze","lip","sie","wrz","paź","lis","gru",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "pt-BR", "default", { - name: "pt-BR", - englishName: "Portuguese (Brazil)", - nativeName: "Português (Brasil)", - language: "pt", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NaN (Não é um número)", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": ",", - symbol: "R$" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"], - namesAbbr: ["dom","seg","ter","qua","qui","sex","sáb"], - namesShort: ["D","S","T","Q","Q","S","S"] - }, - months: { - names: ["janeiro","fevereiro","março","abril","maio","junho","julho","agosto","setembro","outubro","novembro","dezembro",""], - namesAbbr: ["jan","fev","mar","abr","mai","jun","jul","ago","set","out","nov","dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' de 'MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' de 'MMMM' de 'yyyy HH:mm", - F: "dddd, d' de 'MMMM' de 'yyyy HH:mm:ss", - M: "dd' de 'MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "rm-CH", "default", { - name: "rm-CH", - englishName: "Romansh (Switzerland)", - nativeName: "Rumantsch (Svizra)", - language: "rm", - numberFormat: { - ",": "'", - "NaN": "betg def.", - negativeInfinity: "-infinit", - positiveInfinity: "+infinit", - percent: { - pattern: ["-n%","n%"], - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "fr." - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumengia","glindesdi","mardi","mesemna","gievgia","venderdi","sonda"], - namesAbbr: ["du","gli","ma","me","gie","ve","so"], - namesShort: ["du","gli","ma","me","gie","ve","so"] - }, - months: { - names: ["schaner","favrer","mars","avrigl","matg","zercladur","fanadur","avust","settember","october","november","december",""], - namesAbbr: ["schan","favr","mars","avr","matg","zercl","fan","avust","sett","oct","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"s. Cr.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d MMMM yyyy HH:mm", - F: "dddd, d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ro-RO", "default", { - name: "ro-RO", - englishName: "Romanian (Romania)", - nativeName: "română (România)", - language: "ro", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "lei" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["duminică","luni","marţi","miercuri","joi","vineri","sâmbătă"], - namesAbbr: ["D","L","Ma","Mi","J","V","S"], - namesShort: ["D","L","Ma","Mi","J","V","S"] - }, - months: { - names: ["ianuarie","februarie","martie","aprilie","mai","iunie","iulie","august","septembrie","octombrie","noiembrie","decembrie",""], - namesAbbr: ["ian.","feb.","mar.","apr.","mai.","iun.","iul.","aug.","sep.","oct.","nov.","dec.",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ru-RU", "default", { - name: "ru-RU", - englishName: "Russian (Russia)", - nativeName: "русский (Россия)", - language: "ru", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["воскресенье","понедельник","вторник","среда","четверг","пятница","суббота"], - namesAbbr: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"], - namesShort: ["Вс","Пн","Вт","Ср","Чт","Пт","Сб"] - }, - months: { - names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - monthsGenitive: { - names: ["января","февраля","марта","апреля","мая","июня","июля","августа","сентября","октября","ноября","декабря",""], - namesAbbr: ["янв","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy 'г.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'г.' H:mm", - F: "d MMMM yyyy 'г.' H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hr-HR", "default", { - name: "hr-HR", - englishName: "Croatian (Croatia)", - nativeName: "hrvatski (Hrvatska)", - language: "hr", - numberFormat: { - pattern: ["- n"], - ",": ".", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kn" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["siječanj","veljača","ožujak","travanj","svibanj","lipanj","srpanj","kolovoz","rujan","listopad","studeni","prosinac",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - monthsGenitive: { - names: ["siječnja","veljače","ožujka","travnja","svibnja","lipnja","srpnja","kolovoza","rujna","listopada","studenog","prosinca",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy.", - D: "d. MMMM yyyy.", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy. H:mm", - F: "d. MMMM yyyy. H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "sk-SK", "default", { - name: "sk-SK", - englishName: "Slovak (Slovakia)", - nativeName: "slovenčina (Slovenská republika)", - language: "sk", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Nie je číslo", - negativeInfinity: "-nekonečno", - positiveInfinity: "+nekonečno", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["nedeľa","pondelok","utorok","streda","štvrtok","piatok","sobota"], - namesAbbr: ["ne","po","ut","st","št","pi","so"], - namesShort: ["ne","po","ut","st","št","pi","so"] - }, - months: { - names: ["január","február","marec","apríl","máj","jún","júl","august","september","október","november","december",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - monthsGenitive: { - names: ["januára","februára","marca","apríla","mája","júna","júla","augusta","septembra","októbra","novembra","decembra",""], - namesAbbr: ["1","2","3","4","5","6","7","8","9","10","11","12",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. l.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sq-AL", "default", { - name: "sq-AL", - englishName: "Albanian (Albania)", - nativeName: "shqipe (Shqipëria)", - language: "sq", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-infinit", - positiveInfinity: "infinit", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": ".", - ".": ",", - symbol: "Lek" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["e diel","e hënë","e martë","e mërkurë","e enjte","e premte","e shtunë"], - namesAbbr: ["Die","Hën","Mar","Mër","Enj","Pre","Sht"], - namesShort: ["Di","Hë","Ma","Më","En","Pr","Sh"] - }, - months: { - names: ["janar","shkurt","mars","prill","maj","qershor","korrik","gusht","shtator","tetor","nëntor","dhjetor",""], - namesAbbr: ["Jan","Shk","Mar","Pri","Maj","Qer","Kor","Gsh","Sht","Tet","Nën","Dhj",""] - }, - AM: ["PD","pd","PD"], - PM: ["MD","md","MD"], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy-MM-dd", - t: "h:mm.tt", - T: "h:mm:ss.tt", - f: "yyyy-MM-dd h:mm.tt", - F: "yyyy-MM-dd h:mm:ss.tt", - Y: "yyyy-MM" - } - } - } -}); - -Globalize.addCultureInfo( "sv-SE", "default", { - name: "sv-SE", - englishName: "Swedish (Sweden)", - nativeName: "svenska (Sverige)", - language: "sv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"], - namesAbbr: ["sö","må","ti","on","to","fr","lö"], - namesShort: ["sö","må","ti","on","to","fr","lö"] - }, - months: { - names: ["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "'den 'd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "'den 'd MMMM yyyy HH:mm", - F: "'den 'd MMMM yyyy HH:mm:ss", - M: "'den 'd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "th-TH", "default", { - name: "th-TH", - englishName: "Thai (Thailand)", - nativeName: "ไทย (ไทย)", - language: "th", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "฿" - } - }, - calendars: { - standard: { - name: "ThaiBuddhist", - firstDay: 1, - days: { - names: ["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"], - namesAbbr: ["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."], - namesShort: ["อ","จ","อ","พ","พ","ศ","ส"] - }, - months: { - names: ["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม",""], - namesAbbr: ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค.",""] - }, - eras: [{"name":"พ.ศ.","start":null,"offset":-543}], - twoDigitYearMax: 2572, - patterns: { - d: "d/M/yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - }, - Gregorian_Localized: { - firstDay: 1, - days: { - names: ["อาทิตย์","จันทร์","อังคาร","พุธ","พฤหัสบดี","ศุกร์","เสาร์"], - namesAbbr: ["อา.","จ.","อ.","พ.","พฤ.","ศ.","ส."], - namesShort: ["อ","จ","อ","พ","พ","ศ","ส"] - }, - months: { - names: ["มกราคม","กุมภาพันธ์","มีนาคม","เมษายน","พฤษภาคม","มิถุนายน","กรกฎาคม","สิงหาคม","กันยายน","ตุลาคม","พฤศจิกายน","ธันวาคม",""], - namesAbbr: ["ม.ค.","ก.พ.","มี.ค.","เม.ย.","พ.ค.","มิ.ย.","ก.ค.","ส.ค.","ก.ย.","ต.ค.","พ.ย.","ธ.ค.",""] - }, - patterns: { - d: "d/M/yyyy", - D: "'วัน'dddd'ที่' d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "'วัน'dddd'ที่' d MMMM yyyy H:mm", - F: "'วัน'dddd'ที่' d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tr-TR", "default", { - name: "tr-TR", - englishName: "Turkish (Turkey)", - nativeName: "Türkçe (Türkiye)", - language: "tr", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "TL" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"], - namesAbbr: ["Paz","Pzt","Sal","Çar","Per","Cum","Cmt"], - namesShort: ["Pz","Pt","Sa","Ça","Pe","Cu","Ct"] - }, - months: { - names: ["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık",""], - namesAbbr: ["Oca","Şub","Mar","Nis","May","Haz","Tem","Ağu","Eyl","Eki","Kas","Ara",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "dd MMMM yyyy dddd", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy dddd HH:mm", - F: "dd MMMM yyyy dddd HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ur-PK", "default", { - name: "ur-PK", - englishName: "Urdu (Islamic Republic of Pakistan)", - nativeName: "اُردو (پاکستان)", - language: "ur", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$n"], - symbol: "Rs" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesAbbr: ["اتوار","پير","منگل","بدھ","جمعرات","جمعه","هفته"], - namesShort: ["ا","پ","م","ب","ج","ج","ه"] - }, - months: { - names: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""], - namesAbbr: ["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - f: "dd MMMM, yyyy h:mm tt", - F: "dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - } - } -}); - -Globalize.addCultureInfo( "id-ID", "default", { - name: "id-ID", - englishName: "Indonesian (Indonesia)", - nativeName: "Bahasa Indonesia (Indonesia)", - language: "id", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - decimals: 0, - ",": ".", - ".": ",", - symbol: "Rp" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Minggu","Senin","Selasa","Rabu","Kamis","Jumat","Sabtu"], - namesAbbr: ["Minggu","Sen","Sel","Rabu","Kamis","Jumat","Sabtu"], - namesShort: ["M","S","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","Nopember","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agust","Sep","Okt","Nop","Des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "uk-UA", "default", { - name: "uk-UA", - englishName: "Ukrainian (Ukraine)", - nativeName: "українська (Україна)", - language: "uk", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-безмежність", - positiveInfinity: "безмежність", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₴" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["неділя","понеділок","вівторок","середа","четвер","п'ятниця","субота"], - namesAbbr: ["Нд","Пн","Вт","Ср","Чт","Пт","Сб"], - namesShort: ["Нд","Пн","Вт","Ср","Чт","Пт","Сб"] - }, - months: { - names: ["Січень","Лютий","Березень","Квітень","Травень","Червень","Липень","Серпень","Вересень","Жовтень","Листопад","Грудень",""], - namesAbbr: ["Січ","Лют","Бер","Кві","Тра","Чер","Лип","Сер","Вер","Жов","Лис","Гру",""] - }, - monthsGenitive: { - names: ["січня","лютого","березня","квітня","травня","червня","липня","серпня","вересня","жовтня","листопада","грудня",""], - namesAbbr: ["січ","лют","бер","кві","тра","чер","лип","сер","вер","жов","лис","гру",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy' р.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy' р.' H:mm", - F: "d MMMM yyyy' р.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy' р.'" - } - } - } -}); - -Globalize.addCultureInfo( "be-BY", "default", { - name: "be-BY", - englishName: "Belarusian (Belarus)", - nativeName: "Беларускі (Беларусь)", - language: "be", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["нядзеля","панядзелак","аўторак","серада","чацвер","пятніца","субота"], - namesAbbr: ["нд","пн","аў","ср","чц","пт","сб"], - namesShort: ["нд","пн","аў","ср","чц","пт","сб"] - }, - months: { - names: ["Студзень","Люты","Сакавік","Красавік","Май","Чэрвень","Ліпень","Жнівень","Верасень","Кастрычнік","Лістапад","Снежань",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - monthsGenitive: { - names: ["студзеня","лютага","сакавіка","красавіка","мая","чэрвеня","ліпеня","жніўня","верасня","кастрычніка","лістапада","снежня",""], - namesAbbr: ["Сту","Лют","Сак","Кра","Май","Чэр","Ліп","Жні","Вер","Кас","Ліс","Сне",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sl-SI", "default", { - name: "sl-SI", - englishName: "Slovenian (Slovenia)", - nativeName: "slovenski (Slovenija)", - language: "sl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-neskončnost", - positiveInfinity: "neskončnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljek","torek","sreda","četrtek","petek","sobota"], - namesAbbr: ["ned","pon","tor","sre","čet","pet","sob"], - namesShort: ["ne","po","to","sr","če","pe","so"] - }, - months: { - names: ["januar","februar","marec","april","maj","junij","julij","avgust","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "et-EE", "default", { - name: "et-EE", - englishName: "Estonian (Estonia)", - nativeName: "eesti (Eesti)", - language: "et", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "avaldamatu", - negativeInfinity: "miinuslõpmatus", - positiveInfinity: "plusslõpmatus", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pühapäev","esmaspäev","teisipäev","kolmapäev","neljapäev","reede","laupäev"], - namesAbbr: ["P","E","T","K","N","R","L"], - namesShort: ["P","E","T","K","N","R","L"] - }, - months: { - names: ["jaanuar","veebruar","märts","aprill","mai","juuni","juuli","august","september","oktoober","november","detsember",""], - namesAbbr: ["jaan","veebr","märts","apr","mai","juuni","juuli","aug","sept","okt","nov","dets",""] - }, - AM: ["EL","el","EL"], - PM: ["PL","pl","PL"], - patterns: { - d: "d.MM.yyyy", - D: "d. MMMM yyyy'. a.'", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy'. a.' H:mm", - F: "d. MMMM yyyy'. a.' H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy'. a.'" - } - } - } -}); - -Globalize.addCultureInfo( "lv-LV", "default", { - name: "lv-LV", - englishName: "Latvian (Latvia)", - nativeName: "latviešu (Latvija)", - language: "lv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-bezgalība", - positiveInfinity: "bezgalība", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": " ", - ".": ",", - symbol: "Ls" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["svētdiena","pirmdiena","otrdiena","trešdiena","ceturtdiena","piektdiena","sestdiena"], - namesAbbr: ["sv","pr","ot","tr","ce","pk","se"], - namesShort: ["sv","pr","ot","tr","ce","pk","se"] - }, - months: { - names: ["janvāris","februāris","marts","aprīlis","maijs","jūnijs","jūlijs","augusts","septembris","oktobris","novembris","decembris",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - monthsGenitive: { - names: ["janvārī","februārī","martā","aprīlī","maijā","jūnijā","jūlijā","augustā","septembrī","oktobrī","novembrī","decembrī",""], - namesAbbr: ["jan","feb","mar","apr","mai","jūn","jūl","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd.", - D: "dddd, yyyy'. gada 'd. MMMM", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, yyyy'. gada 'd. MMMM H:mm", - F: "dddd, yyyy'. gada 'd. MMMM H:mm:ss", - M: "d. MMMM", - Y: "yyyy. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "lt-LT", "default", { - name: "lt-LT", - englishName: "Lithuanian (Lithuania)", - nativeName: "lietuvių (Lietuva)", - language: "lt", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-begalybė", - positiveInfinity: "begalybė", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Lt" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sekmadienis","pirmadienis","antradienis","trečiadienis","ketvirtadienis","penktadienis","šeštadienis"], - namesAbbr: ["Sk","Pr","An","Tr","Kt","Pn","Št"], - namesShort: ["S","P","A","T","K","Pn","Š"] - }, - months: { - names: ["sausis","vasaris","kovas","balandis","gegužė","birželis","liepa","rugpjūtis","rugsėjis","spalis","lapkritis","gruodis",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - monthsGenitive: { - names: ["sausio","vasario","kovo","balandžio","gegužės","birželio","liepos","rugpjūčio","rugsėjo","spalio","lapkričio","gruodžio",""], - namesAbbr: ["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rgp","Rgs","Spl","Lap","Grd",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy.MM.dd", - D: "yyyy 'm.' MMMM d 'd.'", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'm.' MMMM d 'd.' HH:mm", - F: "yyyy 'm.' MMMM d 'd.' HH:mm:ss", - M: "MMMM d 'd.'", - Y: "yyyy 'm.' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "tg-Cyrl-TJ", "default", { - name: "tg-Cyrl-TJ", - englishName: "Tajik (Cyrillic, Tajikistan)", - nativeName: "Тоҷикӣ (Тоҷикистон)", - language: "tg-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ";", - symbol: "т.р." - } - }, - calendars: { - standard: { - "/": ".", - days: { - names: ["Яш","Душанбе","Сешанбе","Чоршанбе","Панҷшанбе","Ҷумъа","Шанбе"], - namesAbbr: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"], - namesShort: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январи","феврали","марти","апрели","маи","июни","июли","августи","сентябри","октябри","ноябри","декабри",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fa-IR", "default", { - name: "fa-IR", - englishName: "Persian", - nativeName: "فارسى (ایران)", - language: "fa", - isRTL: true, - numberFormat: { - pattern: ["n-"], - currency: { - pattern: ["$n-","$ n"], - ".": "/", - symbol: "ريال" - } - }, - calendars: { - standard: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["يكشنبه","دوشنبه","سه شنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""], - namesAbbr: ["ژانويه","فوريه","مارس","آوريل","مى","ژوئن","ژوئيه","اوت","سپتامبر","اُكتبر","نوامبر","دسامبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - patterns: { - d: "yyyy/MM/dd", - D: "yyyy/MM/dd", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "yyyy/MM/dd hh:mm tt", - F: "yyyy/MM/dd hh:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ق.ظ","ق.ظ","ق.ظ"], - PM: ["ب.ظ","ب.ظ","ب.ظ"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "vi-VN", "default", { - name: "vi-VN", - englishName: "Vietnamese (Vietnam)", - nativeName: "Tiếng Việt (Việt Nam)", - language: "vi", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "₫" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Chủ Nhật","Thứ Hai","Thứ Ba","Thứ Tư","Thứ Năm","Thứ Sáu","Thứ Bảy"], - namesAbbr: ["CN","Hai","Ba","Tư","Năm","Sáu","Bảy"], - namesShort: ["C","H","B","T","N","S","B"] - }, - months: { - names: ["Tháng Giêng","Tháng Hai","Tháng Ba","Tháng Tư","Tháng Năm","Tháng Sáu","Tháng Bảy","Tháng Tám","Tháng Chín","Tháng Mười","Tháng Mười Một","Tháng Mười Hai",""], - namesAbbr: ["Thg1","Thg2","Thg3","Thg4","Thg5","Thg6","Thg7","Thg8","Thg9","Thg10","Thg11","Thg12",""] - }, - AM: ["SA","sa","SA"], - PM: ["CH","ch","CH"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - f: "dd MMMM yyyy h:mm tt", - F: "dd MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hy-AM", "default", { - name: "hy-AM", - englishName: "Armenian (Armenia)", - nativeName: "Հայերեն (Հայաստան)", - language: "hy", - numberFormat: { - currency: { - pattern: ["-n $","n $"], - symbol: "դր." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Կիրակի","Երկուշաբթի","Երեքշաբթի","Չորեքշաբթի","Հինգշաբթի","ՈՒրբաթ","Շաբաթ"], - namesAbbr: ["Կիր","Երկ","Երք","Չրք","Հնգ","ՈՒր","Շբթ"], - namesShort: ["Կ","Ե","Ե","Չ","Հ","Ո","Շ"] - }, - months: { - names: ["Հունվար","Փետրվար","Մարտ","Ապրիլ","Մայիս","Հունիս","Հուլիս","Օգոստոս","Սեպտեմբեր","Հոկտեմբեր","Նոյեմբեր","Դեկտեմբեր",""], - namesAbbr: ["ՀՆՎ","ՓՏՎ","ՄՐՏ","ԱՊՐ","ՄՅՍ","ՀՆՍ","ՀԼՍ","ՕԳՍ","ՍԵՊ","ՀՈԿ","ՆՈՅ","ԴԵԿ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM, yyyy H:mm", - F: "d MMMM, yyyy H:mm:ss", - M: "d MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "az-Latn-AZ", "default", { - name: "az-Latn-AZ", - englishName: "Azeri (Latin, Azerbaijan)", - nativeName: "Azərbaycan\xadılı (Azərbaycan)", - language: "az-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "man." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"], - namesAbbr: ["B","Be","Ça","Ç","Ca","C","Ş"], - namesShort: ["B","Be","Ça","Ç","Ca","C","Ş"] - }, - months: { - names: ["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avgust","Sentyabr","Oktyabr","Noyabr","Dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - monthsGenitive: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "eu-ES", "default", { - name: "eu-ES", - englishName: "Basque (Basque)", - nativeName: "euskara (euskara)", - language: "eu", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "EdZ", - negativeInfinity: "-Infinitu", - positiveInfinity: "Infinitu", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["igandea","astelehena","asteartea","asteazkena","osteguna","ostirala","larunbata"], - namesAbbr: ["ig.","al.","as.","az.","og.","or.","lr."], - namesShort: ["ig","al","as","az","og","or","lr"] - }, - months: { - names: ["urtarrila","otsaila","martxoa","apirila","maiatza","ekaina","uztaila","abuztua","iraila","urria","azaroa","abendua",""], - namesAbbr: ["urt.","ots.","mar.","api.","mai.","eka.","uzt.","abu.","ira.","urr.","aza.","abe.",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "yyyy/MM/dd", - D: "dddd, yyyy.'eko' MMMM'k 'd", - t: "HH:mm", - T: "H:mm:ss", - f: "dddd, yyyy.'eko' MMMM'k 'd HH:mm", - F: "dddd, yyyy.'eko' MMMM'k 'd H:mm:ss", - Y: "yyyy.'eko' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "hsb-DE", "default", { - name: "hsb-DE", - englishName: "Upper Sorbian (Germany)", - nativeName: "hornjoserbšćina (Němska)", - language: "hsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekónčne", - positiveInfinity: "+njekónčne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njedźela","póndźela","wutora","srjeda","štwórtk","pjatk","sobota"], - namesAbbr: ["nje","pón","wut","srj","štw","pja","sob"], - namesShort: ["n","p","w","s","š","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","meja","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","meje","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","mej","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'hodź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'hodź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "mk-MK", "default", { - name: "mk-MK", - englishName: "Macedonian (Former Yugoslav Republic of Macedonia)", - nativeName: "македонски јазик (Македонија)", - language: "mk", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "ден." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недела","понеделник","вторник","среда","четврток","петок","сабота"], - namesAbbr: ["нед","пон","втр","срд","чет","пет","саб"], - namesShort: ["не","по","вт","ср","че","пе","са"] - }, - months: { - names: ["јануари","февруари","март","април","мај","јуни","јули","август","септември","октомври","ноември","декември",""], - namesAbbr: ["јан","фев","мар","апр","мај","јун","јул","авг","сеп","окт","ное","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "dddd, dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, dd MMMM yyyy HH:mm", - F: "dddd, dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tn-ZA", "default", { - name: "tn-ZA", - englishName: "Setswana (South Africa)", - nativeName: "Setswana (Aforika Borwa)", - language: "tn", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Latshipi","Mosupologo","Labobedi","Laboraro","Labone","Labotlhano","Lamatlhatso"], - namesAbbr: ["Ltp.","Mos.","Lbd.","Lbr.","Lbn.","Lbt.","Lmt."], - namesShort: ["Lp","Ms","Lb","Lr","Ln","Lt","Lm"] - }, - months: { - names: ["Ferikgong","Tlhakole","Mopitloe","Moranang","Motsheganong","Seetebosigo","Phukwi","Phatwe","Lwetse","Diphalane","Ngwanatsele","Sedimothole",""], - namesAbbr: ["Fer.","Tlhak.","Mop.","Mor.","Motsh.","Seet.","Phukw.","Phatw.","Lwets.","Diph.","Ngwan.","Sed.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "xh-ZA", "default", { - name: "xh-ZA", - englishName: "isiXhosa (South Africa)", - nativeName: "isiXhosa (uMzantsi Afrika)", - language: "xh", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iCawa","uMvulo","uLwesibini","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesShort: ["Ca","Mv","Lb","Lt","Ln","Lh","Mg"] - }, - months: { - names: ["Mqungu","Mdumba","Kwindla","Tshazimpuzi","Canzibe","Silimela","Khala","Thupha","Msintsi","Dwarha","Nkanga","Mnga",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "zu-ZA", "default", { - name: "zu-ZA", - englishName: "isiZulu (South Africa)", - nativeName: "isiZulu (iNingizimu Afrika)", - language: "zu", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["iSonto","uMsombuluko","uLwesibili","uLwesithathu","uLwesine","uLwesihlanu","uMgqibelo"], - namesAbbr: ["Son.","Mso.","Bi.","Tha.","Ne.","Hla.","Mgq."] - }, - months: { - names: ["uMasingana","uNhlolanja","uNdasa","uMbaso","uNhlaba","uNhlangulana","uNtulikazi","uNcwaba","uMandulo","uMfumfu","uLwezi","uZibandlela",""], - namesAbbr: ["Mas.","Nhlo.","Nda.","Mba.","Nhla.","Nhlang.","Ntu.","Ncwa.","Man.","Mfu.","Lwe.","Zib.",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "af-ZA", "default", { - name: "af-ZA", - englishName: "Afrikaans (South Africa)", - nativeName: "Afrikaans (Suid Afrika)", - language: "af", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Sondag","Maandag","Dinsdag","Woensdag","Donderdag","Vrydag","Saterdag"], - namesAbbr: ["Son","Maan","Dins","Woen","Dond","Vry","Sat"], - namesShort: ["So","Ma","Di","Wo","Do","Vr","Sa"] - }, - months: { - names: ["Januarie","Februarie","Maart","April","Mei","Junie","Julie","Augustus","September","Oktober","November","Desember",""], - namesAbbr: ["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Aug","Sep","Okt","Nov","Des",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ka-GE", "default", { - name: "ka-GE", - englishName: "Georgian (Georgia)", - nativeName: "ქართული (საქართველო)", - language: "ka", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "Lari" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesAbbr: ["კვირა","ორშაბათი","სამშაბათი","ოთხშაბათი","ხუთშაბათი","პარასკევი","შაბათი"], - namesShort: ["კ","ო","ს","ო","ხ","პ","შ"] - }, - months: { - names: ["იანვარი","თებერვალი","მარტი","აპრილი","მაისი","ივნისი","ივლისი","აგვისტო","სექტემბერი","ოქტომბერი","ნოემბერი","დეკემბერი",""], - namesAbbr: ["იან","თებ","მარ","აპრ","მაის","ივნ","ივლ","აგვ","სექ","ოქტ","ნოემ","დეკ",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'წლის' dd MM, dddd", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'წლის' dd MM, dddd H:mm", - F: "yyyy 'წლის' dd MM, dddd H:mm:ss", - M: "dd MM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fo-FO", "default", { - name: "fo-FO", - englishName: "Faroese (Faroe Islands)", - nativeName: "føroyskt (Føroyar)", - language: "fo", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sunnudagur","mánadagur","týsdagur","mikudagur","hósdagur","fríggjadagur","leygardagur"], - namesAbbr: ["sun","mán","týs","mik","hós","frí","leyg"], - namesShort: ["su","má","tý","mi","hó","fr","ley"] - }, - months: { - names: ["januar","februar","mars","apríl","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hi-IN", "default", { - name: "hi-IN", - englishName: "Hindi (India)", - nativeName: "हिंदी (भारत)", - language: "hi", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["रविवार","सोमवार","मंगलवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"], - namesAbbr: ["रवि.","सोम.","मंगल.","बुध.","गुरु.","शुक्र.","शनि."], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""], - namesAbbr: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""] - }, - AM: ["पूर्वाह्न","पूर्वाह्न","पूर्वाह्न"], - PM: ["अपराह्न","अपराह्न","अपराह्न"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "mt-MT", "default", { - name: "mt-MT", - englishName: "Maltese (Malta)", - nativeName: "Malti (Malta)", - language: "mt", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Il-Ħadd","It-Tnejn","It-Tlieta","L-Erbgħa","Il-Ħamis","Il-Ġimgħa","Is-Sibt"], - namesAbbr: ["Ħad","Tne","Tli","Erb","Ħam","Ġim","Sib"], - namesShort: ["I","I","I","L","I","I","I"] - }, - months: { - names: ["Jannar","Frar","Marzu","April","Mejju","Ġunju","Lulju","Awissu","Settembru","Ottubru","Novembru","Diċembru",""], - namesAbbr: ["Jan","Fra","Mar","Apr","Mej","Ġun","Lul","Awi","Set","Ott","Nov","Diċ",""] - }, - patterns: { - d: "dd/MM/yyyy", - D: "dddd, d' ta\\' 'MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' ta\\' 'MMMM yyyy HH:mm", - F: "dddd, d' ta\\' 'MMMM yyyy HH:mm:ss", - M: "d' ta\\' 'MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "se-NO", "default", { - name: "se-NO", - englishName: "Sami, Northern (Norway)", - nativeName: "davvisámegiella (Norga)", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","vuos","maŋ","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ms-MY", "default", { - name: "ms-MY", - englishName: "Malay (Malaysia)", - nativeName: "Bahasa Melayu (Malaysia)", - language: "ms", - numberFormat: { - currency: { - decimals: 0, - symbol: "RM" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"], - namesAbbr: ["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"], - namesShort: ["A","I","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "kk-KZ", "default", { - name: "kk-KZ", - englishName: "Kazakh (Kazakhstan)", - nativeName: "Қазақ (Қазақстан)", - language: "kk", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-$n","$n"], - ",": " ", - ".": "-", - symbol: "Т" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жексенбі","Дүйсенбі","Сейсенбі","Сәрсенбі","Бейсенбі","Жұма","Сенбі"], - namesAbbr: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"], - namesShort: ["Жк","Дс","Сс","Ср","Бс","Жм","Сн"] - }, - months: { - names: ["қаңтар","ақпан","наурыз","сәуір","мамыр","маусым","шілде","тамыз","қыркүйек","қазан","қараша","желтоқсан",""], - namesAbbr: ["Қаң","Ақп","Нау","Сәу","Мам","Мау","Шіл","Там","Қыр","Қаз","Қар","Жел",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy 'ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'ж.' H:mm", - F: "d MMMM yyyy 'ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ky-KG", "default", { - name: "ky-KG", - englishName: "Kyrgyz (Kyrgyzstan)", - nativeName: "Кыргыз (Кыргызстан)", - language: "ky", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": "-", - symbol: "сом" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Жекшемби","Дүйшөмбү","Шейшемби","Шаршемби","Бейшемби","Жума","Ишемби"], - namesAbbr: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"], - namesShort: ["Жш","Дш","Шш","Шр","Бш","Жм","Иш"] - }, - months: { - names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d'-'MMMM yyyy'-ж.'", - t: "H:mm", - T: "H:mm:ss", - f: "d'-'MMMM yyyy'-ж.' H:mm", - F: "d'-'MMMM yyyy'-ж.' H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy'-ж.'" - } - } - } -}); - -Globalize.addCultureInfo( "sw-KE", "default", { - name: "sw-KE", - englishName: "Kiswahili (Kenya)", - nativeName: "Kiswahili (Kenya)", - language: "sw", - numberFormat: { - currency: { - symbol: "S" - } - }, - calendars: { - standard: { - days: { - names: ["Jumapili","Jumatatu","Jumanne","Jumatano","Alhamisi","Ijumaa","Jumamosi"], - namesAbbr: ["Jumap.","Jumat.","Juman.","Jumat.","Alh.","Iju.","Jumam."], - namesShort: ["P","T","N","T","A","I","M"] - }, - months: { - names: ["Januari","Februari","Machi","Aprili","Mei","Juni","Julai","Agosti","Septemba","Oktoba","Novemba","Decemba",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ago","Sep","Okt","Nov","Dec",""] - } - } - } -}); - -Globalize.addCultureInfo( "tk-TM", "default", { - name: "tk-TM", - englishName: "Turkmen (Turkmenistan)", - nativeName: "türkmençe (Türkmenistan)", - language: "tk", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-üznüksizlik", - positiveInfinity: "üznüksizlik", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "m." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Duşenbe","Sişenbe","Çarşenbe","Penşenbe","Anna","Şenbe","Ýekşenbe"], - namesAbbr: ["Db","Sb","Çb","Pb","An","Şb","Ýb"], - namesShort: ["D","S","Ç","P","A","Ş","Ý"] - }, - months: { - names: ["Ýanwar","Fewral","Mart","Aprel","Maý","lýun","lýul","Awgust","Sentýabr","Oktýabr","Noýabr","Dekabr",""], - namesAbbr: ["Ýan","Few","Mart","Apr","Maý","lýun","lýul","Awg","Sen","Okt","Not","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "yyyy 'ý.' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'ý.' MMMM d H:mm", - F: "yyyy 'ý.' MMMM d H:mm:ss", - Y: "yyyy 'ý.' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "uz-Latn-UZ", "default", { - name: "uz-Latn-UZ", - englishName: "Uzbek (Latin, Uzbekistan)", - nativeName: "U'zbek (U'zbekiston Respublikasi)", - language: "uz-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": " ", - ".": ",", - symbol: "so'm" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["yakshanba","dushanba","seshanba","chorshanba","payshanba","juma","shanba"], - namesAbbr: ["yak.","dsh.","sesh.","chr.","psh.","jm.","sh."], - namesShort: ["ya","d","s","ch","p","j","sh"] - }, - months: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM yyyy", - D: "yyyy 'yil' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'yil' d-MMMM HH:mm", - F: "yyyy 'yil' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tt-RU", "default", { - name: "tt-RU", - englishName: "Tatar (Russia)", - nativeName: "Татар (Россия)", - language: "tt", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "р." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Якшәмбе","Дүшәмбе","Сишәмбе","Чәршәмбе","Пәнҗешәмбе","Җомга","Шимбә"], - namesAbbr: ["Якш","Дүш","Сиш","Чәрш","Пәнҗ","Җом","Шим"], - namesShort: ["Я","Д","С","Ч","П","Җ","Ш"] - }, - months: { - names: ["Гыйнвар","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь",""], - namesAbbr: ["Гыйн.","Фев.","Мар.","Апр.","Май","Июнь","Июль","Авг.","Сен.","Окт.","Нояб.","Дек.",""] - }, - monthsGenitive: { - names: ["Гыйнварның","Февральнең","Мартның","Апрельнең","Майның","Июньнең","Июльнең","Августның","Сентябрьның","Октябрьның","Ноябрьның","Декабрьның",""], - namesAbbr: ["Гыйн.-ның","Фев.-нең","Мар.-ның","Апр.-нең","Майның","Июньнең","Июльнең","Авг.-ның","Сен.-ның","Окт.-ның","Нояб.-ның","Дек.-ның",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "bn-IN", "default", { - name: "bn-IN", - englishName: "Bengali (India)", - nativeName: "বাংলা (ভারত)", - language: "bn", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "টা" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], - namesAbbr: ["রবি.","সোম.","মঙ্গল.","বুধ.","বৃহস্পতি.","শুক্র.","শনি."], - namesShort: ["র","স","ম","ব","ব","শ","শ"] - }, - months: { - names: ["জানুয়ারী","ফেব্রুয়ারী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর",""], - namesAbbr: ["জানু.","ফেব্রু.","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগ.","সেপ্টে.","অক্টো.","নভে.","ডিসে.",""] - }, - AM: ["পুর্বাহ্ন","পুর্বাহ্ন","পুর্বাহ্ন"], - PM: ["অপরাহ্ন","অপরাহ্ন","অপরাহ্ন"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "pa-IN", "default", { - name: "pa-IN", - englishName: "Punjabi (India)", - nativeName: "ਪੰਜਾਬੀ (ਭਾਰਤ)", - language: "pa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ਰੁ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ਐਤਵਾਰ","ਸੋਮਵਾਰ","ਮੰਗਲਵਾਰ","ਬੁੱਧਵਾਰ","ਵੀਰਵਾਰ","ਸ਼ੁੱਕਰਵਾਰ","ਸ਼ਨਿੱਚਰਵਾਰ"], - namesAbbr: ["ਐਤ.","ਸੋਮ.","ਮੰਗਲ.","ਬੁੱਧ.","ਵੀਰ.","ਸ਼ੁਕਰ.","ਸ਼ਨਿੱਚਰ."], - namesShort: ["ਐ","ਸ","ਮ","ਬ","ਵ","ਸ਼","ਸ਼"] - }, - months: { - names: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""], - namesAbbr: ["ਜਨਵਰੀ","ਫ਼ਰਵਰੀ","ਮਾਰਚ","ਅਪ੍ਰੈਲ","ਮਈ","ਜੂਨ","ਜੁਲਾਈ","ਅਗਸਤ","ਸਤੰਬਰ","ਅਕਤੂਬਰ","ਨਵੰਬਰ","ਦਸੰਬਰ",""] - }, - AM: ["ਸਵੇਰ","ਸਵੇਰ","ਸਵੇਰ"], - PM: ["ਸ਼ਾਮ","ਸ਼ਾਮ","ਸ਼ਾਮ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy dddd", - t: "tt hh:mm", - T: "tt hh:mm:ss", - f: "dd MMMM yyyy dddd tt hh:mm", - F: "dd MMMM yyyy dddd tt hh:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "gu-IN", "default", { - name: "gu-IN", - englishName: "Gujarati (India)", - nativeName: "ગુજરાતી (ભારત)", - language: "gu", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "રૂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["રવિવાર","સોમવાર","મંગળવાર","બુધવાર","ગુરુવાર","શુક્રવાર","શનિવાર"], - namesAbbr: ["રવિ","સોમ","મંગળ","બુધ","ગુરુ","શુક્ર","શનિ"], - namesShort: ["ર","સ","મ","બ","ગ","શ","શ"] - }, - months: { - names: ["જાન્યુઆરી","ફેબ્રુઆરી","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટેમ્બર","ઑક્ટ્બર","નવેમ્બર","ડિસેમ્બર",""], - namesAbbr: ["જાન્યુ","ફેબ્રુ","માર્ચ","એપ્રિલ","મે","જૂન","જુલાઈ","ઑગસ્ટ","સપ્ટે","ઑક્ટો","નવે","ડિસે",""] - }, - AM: ["પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન","પૂર્વ મધ્યાહ્ન"], - PM: ["ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન","ઉત્તર મધ્યાહ્ન"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "or-IN", "default", { - name: "or-IN", - englishName: "Oriya (India)", - nativeName: "ଓଡ଼ିଆ (ଭାରତ)", - language: "or", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ଟ" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ରବିବାର","ସୋମବାର","ମଙ୍ଗଳବାର","ବୁଧବାର","ଗୁରୁବାର","ଶୁକ୍ରବାର","ଶନିବାର"], - namesAbbr: ["ରବି.","ସୋମ.","ମଙ୍ଗଳ.","ବୁଧ.","ଗୁରୁ.","ଶୁକ୍ର.","ଶନି."], - namesShort: ["ର","ସୋ","ମ","ବୁ","ଗୁ","ଶୁ","ଶ"] - }, - months: { - names: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""], - namesAbbr: ["ଜାନୁୟାରୀ","ଫ୍ରେବୃୟାରୀ","ମାର୍ଚ୍ଚ","ଏପ୍ରିଲ୍\u200c","ମେ","ଜୁନ୍\u200c","ଜୁଲାଇ","ଅଗଷ୍ଟ","ସେପ୍ଟେମ୍ବର","ଅକ୍ଟୋବର","ନଭେମ୍ବର","(ଡିସେମ୍ବର",""] - }, - eras: [{"name":"ଖ୍ରୀଷ୍ଟାବ୍ଦ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ta-IN", "default", { - name: "ta-IN", - englishName: "Tamil (India)", - nativeName: "தமிழ் (இந்தியா)", - language: "ta", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ரூ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ஞாயிற்றுக்கிழமை","திங்கள்கிழமை","செவ்வாய்கிழமை","புதன்கிழமை","வியாழக்கிழமை","வெள்ளிக்கிழமை","சனிக்கிழமை"], - namesAbbr: ["ஞாயிறு","திங்கள்","செவ்வாய்","புதன்","வியாழன்","வெள்ளி","சனி"], - namesShort: ["ஞா","தி","செ","பு","வி","வெ","ச"] - }, - months: { - names: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""], - namesAbbr: ["ஜனவரி","பிப்ரவரி","மார்ச்","ஏப்ரல்","மே","ஜூன்","ஜூலை","ஆகஸ்ட்","செப்டம்பர்","அக்டோபர்","நவம்பர்","டிசம்பர்",""] - }, - AM: ["காலை","காலை","காலை"], - PM: ["மாலை","மாலை","மாலை"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "te-IN", "default", { - name: "te-IN", - englishName: "Telugu (India)", - nativeName: "తెలుగు (భారత దేశం)", - language: "te", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "రూ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ఆదివారం","సోమవారం","మంగళవారం","బుధవారం","గురువారం","శుక్రవారం","శనివారం"], - namesAbbr: ["ఆది.","సోమ.","మంగళ.","బుధ.","గురు.","శుక్ర.","శని."], - namesShort: ["ఆ","సో","మం","బు","గు","శు","శ"] - }, - months: { - names: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""], - namesAbbr: ["జనవరి","ఫిబ్రవరి","మార్చి","ఏప్రిల్","మే","జూన్","జూలై","ఆగస్టు","సెప్టెంబర్","అక్టోబర్","నవంబర్","డిసెంబర్",""] - }, - AM: ["పూర్వాహ్న","పూర్వాహ్న","పూర్వాహ్న"], - PM: ["అపరాహ్న","అపరాహ్న","అపరాహ్న"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "kn-IN", "default", { - name: "kn-IN", - englishName: "Kannada (India)", - nativeName: "ಕನ್ನಡ (ಭಾರತ)", - language: "kn", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ರೂ" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ಭಾನುವಾರ","ಸೋಮವಾರ","ಮಂಗಳವಾರ","ಬುಧವಾರ","ಗುರುವಾರ","ಶುಕ್ರವಾರ","ಶನಿವಾರ"], - namesAbbr: ["ಭಾನು.","ಸೋಮ.","ಮಂಗಳ.","ಬುಧ.","ಗುರು.","ಶುಕ್ರ.","ಶನಿ."], - namesShort: ["ರ","ಸ","ಮ","ಬ","ಗ","ಶ","ಶ"] - }, - months: { - names: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""], - namesAbbr: ["ಜನವರಿ","ಫೆಬ್ರವರಿ","ಮಾರ್ಚ್","ಎಪ್ರಿಲ್","ಮೇ","ಜೂನ್","ಜುಲೈ","ಆಗಸ್ಟ್","ಸೆಪ್ಟಂಬರ್","ಅಕ್ಟೋಬರ್","ನವೆಂಬರ್","ಡಿಸೆಂಬರ್",""] - }, - AM: ["ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ","ಪೂರ್ವಾಹ್ನ"], - PM: ["ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ","ಅಪರಾಹ್ನ"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ml-IN", "default", { - name: "ml-IN", - englishName: "Malayalam (India)", - nativeName: "മലയാളം (ഭാരതം)", - language: "ml", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "ക" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["ഞായറാഴ്ച","തിങ്കളാഴ്ച","ചൊവ്വാഴ്ച","ബുധനാഴ്ച","വ്യാഴാഴ്ച","വെള്ളിയാഴ്ച","ശനിയാഴ്ച"], - namesAbbr: ["ഞായർ.","തിങ്കൾ.","ചൊവ്വ.","ബുധൻ.","വ്യാഴം.","വെള്ളി.","ശനി."], - namesShort: ["ഞ","ത","ച","ബ","വ","വെ","ശ"] - }, - months: { - names: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""], - namesAbbr: ["ജനുവരി","ഫെബ്റുവരി","മാറ്ച്ച്","ഏപ്റില്","മെയ്","ജൂണ്","ജൂലൈ","ഓഗസ്ററ്","സെപ്ററംബറ്","ഒക്ടോബറ്","നവംബറ്","ഡിസംബറ്",""] - }, - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "as-IN", "default", { - name: "as-IN", - englishName: "Assamese (India)", - nativeName: "অসমীয়া (ভাৰত)", - language: "as", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","n$"], - groupSizes: [3,2], - symbol: "ট" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["সোমবাৰ","মঙ্গলবাৰ","বুধবাৰ","বৃহস্পতিবাৰ","শুক্রবাৰ","শনিবাৰ","ৰবিবাৰ"], - namesAbbr: ["সোম.","মঙ্গল.","বুধ.","বৃহ.","শুক্র.","শনি.","ৰবি."], - namesShort: ["সো","ম","বু","বৃ","শু","শ","র"] - }, - months: { - names: ["জানুৱাৰী","ফেব্রুৱাৰী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টেম্বর","অক্টোবর","নবেম্বর","ডিচেম্বর",""], - namesAbbr: ["জানু","ফেব্রু","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগষ্ট","চেপ্টে","অক্টো","নবে","ডিচে",""] - }, - AM: ["ৰাতিপু","ৰাতিপু","ৰাতিপু"], - PM: ["আবেলি","আবেলি","আবেলি"], - eras: [{"name":"খ্রীষ্টাব্দ","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "yyyy,MMMM dd, dddd", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy,MMMM dd, dddd tt h:mm", - F: "yyyy,MMMM dd, dddd tt h:mm:ss", - M: "dd MMMM", - Y: "MMMM,yy" - } - } - } -}); - -Globalize.addCultureInfo( "mr-IN", "default", { - name: "mr-IN", - englishName: "Marathi (India)", - nativeName: "मराठी (भारत)", - language: "mr", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["रविवार","सोमवार","मंगळवार","बुधवार","गुरुवार","शुक्रवार","शनिवार"], - namesAbbr: ["रवि.","सोम.","मंगळ.","बुध.","गुरु.","शुक्र.","शनि."], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोव्हेंबर","डिसेंबर",""], - namesAbbr: ["जाने.","फेब्रु.","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टें.","ऑक्टो.","नोव्हें.","डिसें.",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "sa-IN", "default", { - name: "sa-IN", - englishName: "Sanskrit (India)", - nativeName: "संस्कृत (भारतम्)", - language: "sa", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesAbbr: ["रविवासरः","सोमवासरः","मङ्गलवासरः","बुधवासरः","गुरुवासरः","शुक्रवासरः","शनिवासरः"], - namesShort: ["र","स","म","ब","ग","श","श"] - }, - months: { - names: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""], - namesAbbr: ["जनवरी","फरवरी","मार्च","अप्रैल","मई","जून","जुलाई","अगस्त","सितम्बर","अक्तूबर","नवम्बर","दिसम्बर",""] - }, - AM: ["पूर्वाह्न","पूर्वाह्न","पूर्वाह्न"], - PM: ["अपराह्न","अपराह्न","अपराह्न"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy dddd", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy dddd HH:mm", - F: "dd MMMM yyyy dddd HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "mn-MN", "default", { - name: "mn-MN", - englishName: "Mongolian (Cyrillic, Mongolia)", - nativeName: "Монгол хэл (Монгол улс)", - language: "mn-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₮" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"], - namesAbbr: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"], - namesShort: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"] - }, - months: { - names: ["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - monthsGenitive: { - names: ["1 дүгээр сарын","2 дугаар сарын","3 дугаар сарын","4 дүгээр сарын","5 дугаар сарын","6 дугаар сарын","7 дугаар сарын","8 дугаар сарын","9 дүгээр сарын","10 дугаар сарын","11 дүгээр сарын","12 дугаар сарын",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - AM: null, - PM: null, - patterns: { - d: "yy.MM.dd", - D: "yyyy 'оны' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'оны' MMMM d H:mm", - F: "yyyy 'оны' MMMM d H:mm:ss", - M: "d MMMM", - Y: "yyyy 'он' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "bo-CN", "default", { - name: "bo-CN", - englishName: "Tibetan (PRC)", - nativeName: "བོད་ཡིག (ཀྲུང་ཧྭ་མི་དམངས་སྤྱི་མཐུན་རྒྱལ་ཁབ།)", - language: "bo", - numberFormat: { - groupSizes: [3,0], - "NaN": "ཨང་ཀི་མིན་པ།", - negativeInfinity: "མོ་གྲངས་ཚད་མེད་ཆུང་བ།", - positiveInfinity: "ཕོ་གྲངས་ཚད་མེད་ཆེ་བ།", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["གཟའ་ཉི་མ།","གཟའ་ཟླ་བ།","གཟའ་མིག་དམར།","གཟའ་ལྷག་པ།","གཟའ་ཕུར་བུ།","གཟའ་པ་སངས།","གཟའ་སྤེན་པ།"], - namesAbbr: ["ཉི་མ།","ཟླ་བ།","མིག་དམར།","ལྷག་པ།","ཕུར་བུ།","པ་སངས།","སྤེན་པ།"], - namesShort: ["༧","༡","༢","༣","༤","༥","༦"] - }, - months: { - names: ["སྤྱི་ཟླ་དང་པོ།","སྤྱི་ཟླ་གཉིས་པ།","སྤྱི་ཟླ་གསུམ་པ།","སྤྱི་ཟླ་བཞི་པ།","སྤྱི་ཟླ་ལྔ་པ།","སྤྱི་ཟླ་དྲུག་པ།","སྤྱི་ཟླ་བདུན་པ།","སྤྱི་ཟླ་བརྒྱད་པ།","སྤྱི་ཟླ་དགུ་པ།","སྤྱི་ཟླ་བཅུ་པོ།","སྤྱི་ཟླ་བཅུ་གཅིག་པ།","སྤྱི་ཟླ་བཅུ་གཉིས་པ།",""], - namesAbbr: ["ཟླ་ ༡","ཟླ་ ༢","ཟླ་ ༣","ཟླ་ ༤","ཟླ་ ༥","ཟླ་ ༦","ཟླ་ ༧","ཟླ་ ༨","ཟླ་ ༩","ཟླ་ ༡༠","ཟླ་ ༡༡","ཟླ་ ༡༢",""] - }, - AM: ["སྔ་དྲོ","སྔ་དྲོ","སྔ་དྲོ"], - PM: ["ཕྱི་དྲོ","ཕྱི་དྲོ","ཕྱི་དྲོ"], - eras: [{"name":"སྤྱི་ལོ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ལོའི་ཟླ' M'ཚེས' d", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm", - F: "yyyy'ལོའི་ཟླ' M'ཚེས' d HH:mm:ss", - M: "'ཟླ་' M'ཚེས'd", - Y: "yyyy.M" - } - } - } -}); - -Globalize.addCultureInfo( "cy-GB", "default", { - name: "cy-GB", - englishName: "Welsh (United Kingdom)", - nativeName: "Cymraeg (y Deyrnas Unedig)", - language: "cy", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dydd Sul","Dydd Llun","Dydd Mawrth","Dydd Mercher","Dydd Iau","Dydd Gwener","Dydd Sadwrn"], - namesAbbr: ["Sul","Llun","Maw","Mer","Iau","Gwe","Sad"], - namesShort: ["Su","Ll","Ma","Me","Ia","Gw","Sa"] - }, - months: { - names: ["Ionawr","Chwefror","Mawrth","Ebrill","Mai","Mehefin","Gorffennaf","Awst","Medi","Hydref","Tachwedd","Rhagfyr",""], - namesAbbr: ["Ion","Chwe","Maw","Ebr","Mai","Meh","Gor","Aws","Med","Hyd","Tach","Rhag",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "km-KH", "default", { - name: "km-KH", - englishName: "Khmer (Cambodia)", - nativeName: "ខ្មែរ (កម្ពុជា)", - language: "km", - numberFormat: { - pattern: ["- n"], - groupSizes: [3,0], - "NaN": "NAN", - negativeInfinity: "-- អនន្ត", - positiveInfinity: "អនន្ត", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["-n$","n$"], - symbol: "៛" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["ថ្ងៃអាទិត្យ","ថ្ងៃច័ន្ទ","ថ្ងៃអង្គារ","ថ្ងៃពុធ","ថ្ងៃព្រហស្បតិ៍","ថ្ងៃសុក្រ","ថ្ងៃសៅរ៍"], - namesAbbr: ["អាទិ.","ច.","អ.","ពុ","ព្រហ.","សុ.","ស."], - namesShort: ["អា","ច","អ","ពុ","ព្","សុ","ស"] - }, - months: { - names: ["មករា","កុម្ភៈ","មិនា","មេសា","ឧសភា","មិថុនា","កក្កដា","សីហា","កញ្ញា","តុលា","វិច្ឆិកា","ធ្នូ",""], - namesAbbr: ["១","២","៣","៤","៥","៦","៧","៨","៩","១០","១១","១២",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"មុនគ.ស.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "d MMMM yyyy H:mm tt", - F: "d MMMM yyyy HH:mm:ss", - M: "'ថ្ងៃទី' dd 'ខែ' MM", - Y: "'ខែ' MM 'ឆ្នាំ' yyyy" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ព្រឹក","ព្រឹក","ព្រឹក"], - PM: ["ល្ងាច","ល្ងាច","ល្ងាច"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm tt", - F: "dddd, MMMM dd, yyyy HH:mm:ss" - } - } - } -}); - -Globalize.addCultureInfo( "lo-LA", "default", { - name: "lo-LA", - englishName: "Lao (Lao P.D.R.)", - nativeName: "ລາວ (ສ.ປ.ປ. ລາວ)", - language: "lo", - numberFormat: { - pattern: ["(n)"], - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - }, - currency: { - pattern: ["(n$)","n$"], - groupSizes: [3,0], - symbol: "₭" - } - }, - calendars: { - standard: { - days: { - names: ["ວັນອາທິດ","ວັນຈັນ","ວັນອັງຄານ","ວັນພຸດ","ວັນພະຫັດ","ວັນສຸກ","ວັນເສົາ"], - namesAbbr: ["ອາທິດ","ຈັນ","ອັງຄານ","ພຸດ","ພະຫັດ","ສຸກ","ເສົາ"], - namesShort: ["ອ","ຈ","ອ","ພ","ພ","ສ","ເ"] - }, - months: { - names: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""], - namesAbbr: ["ມັງກອນ","ກຸມພາ","ມີນາ","ເມສາ","ພຶດສະພາ","ມິຖຸນາ","ກໍລະກົດ","ສິງຫາ","ກັນຍາ","ຕຸລາ","ພະຈິກ","ທັນວາ",""] - }, - AM: ["ເຊົ້າ","ເຊົ້າ","ເຊົ້າ"], - PM: ["ແລງ","ແລງ","ແລງ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm tt", - T: "HH:mm:ss", - f: "dd MMMM yyyy H:mm tt", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "gl-ES", "default", { - name: "gl-ES", - englishName: "Galician (Galician)", - nativeName: "galego (galego)", - language: "gl", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","luns","martes","mércores","xoves","venres","sábado"], - namesAbbr: ["dom","luns","mar","mér","xov","ven","sáb"], - namesShort: ["do","lu","ma","mé","xo","ve","sá"] - }, - months: { - names: ["xaneiro","febreiro","marzo","abril","maio","xuño","xullo","agosto","setembro","outubro","novembro","decembro",""], - namesAbbr: ["xan","feb","mar","abr","maio","xuñ","xull","ago","set","out","nov","dec",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "kok-IN", "default", { - name: "kok-IN", - englishName: "Konkani (India)", - nativeName: "कोंकणी (भारत)", - language: "kok", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "रु" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["आयतार","सोमार","मंगळार","बुधवार","बिरेस्तार","सुक्रार","शेनवार"], - namesAbbr: ["आय.","सोम.","मंगळ.","बुध.","बिरे.","सुक्र.","शेन."], - namesShort: ["आ","स","म","ब","ब","स","श"] - }, - months: { - names: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""], - namesAbbr: ["जानेवारी","फेब्रुवारी","मार्च","एप्रिल","मे","जून","जुलै","ऑगस्ट","सप्टेंबर","ऑक्टोबर","नोवेम्बर","डिसेंबर",""] - }, - AM: ["म.पू.","म.पू.","म.पू."], - PM: ["म.नं.","म.नं.","म.नं."], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "syr-SY", "default", { - name: "syr-SY", - englishName: "Syriac (Syria)", - nativeName: "ܣܘܪܝܝܐ (سوريا)", - language: "syr", - isRTL: true, - numberFormat: { - currency: { - pattern: ["$n-","$ n"], - symbol: "ل.س.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["ܚܕ ܒܫܒܐ","ܬܪܝܢ ܒܫܒܐ","ܬܠܬܐ ܒܫܒܐ","ܐܪܒܥܐ ܒܫܒܐ","ܚܡܫܐ ܒܫܒܐ","ܥܪܘܒܬܐ","ܫܒܬܐ"], - namesAbbr: ["\u070fܐ \u070fܒܫ","\u070fܒ \u070fܒܫ","\u070fܓ \u070fܒܫ","\u070fܕ \u070fܒܫ","\u070fܗ \u070fܒܫ","\u070fܥܪܘܒ","\u070fܫܒ"], - namesShort: ["ܐ","ܒ","ܓ","ܕ","ܗ","ܥ","ܫ"] - }, - months: { - names: ["ܟܢܘܢ ܐܚܪܝ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","ܬܫܪܝ ܩܕܝܡ","ܬܫܪܝ ܐܚܪܝ","ܟܢܘܢ ܩܕܝܡ",""], - namesAbbr: ["\u070fܟܢ \u070fܒ","ܫܒܛ","ܐܕܪ","ܢܝܣܢ","ܐܝܪ","ܚܙܝܪܢ","ܬܡܘܙ","ܐܒ","ܐܝܠܘܠ","\u070fܬܫ \u070fܐ","\u070fܬܫ \u070fܒ","\u070fܟܢ \u070fܐ",""] - }, - AM: ["ܩ.ܛ","ܩ.ܛ","ܩ.ܛ"], - PM: ["ܒ.ܛ","ܒ.ܛ","ܒ.ܛ"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "si-LK", "default", { - name: "si-LK", - englishName: "Sinhala (Sri Lanka)", - nativeName: "සිංහල (ශ්\u200dරී ලංකා)", - language: "si", - numberFormat: { - groupSizes: [3,2], - negativeInfinity: "-අනන්තය", - positiveInfinity: "අනන්තය", - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["($ n)","$ n"], - symbol: "රු." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ඉරිදා","සඳුදා","අඟහරුවාදා","බදාදා","බ්\u200dරහස්පතින්දා","සිකුරාදා","සෙනසුරාදා"], - namesAbbr: ["ඉරිදා","සඳුදා","කුජදා","බුදදා","ගුරුදා","කිවිදා","ශනිදා"], - namesShort: ["ඉ","ස","අ","බ","බ්\u200dර","සි","සෙ"] - }, - months: { - names: ["ජනවාරි","පෙබරවාරි","මාර්තු","අ\u200cප්\u200dරේල්","මැයි","ජූනි","ජූලි","අ\u200cගෝස්තු","සැප්තැම්බර්","ඔක්තෝබර්","නොවැම්බර්","දෙසැම්බර්",""], - namesAbbr: ["ජන.","පෙබ.","මාර්තු.","අප්\u200dරේල්.","මැයි.","ජූනි.","ජූලි.","අගෝ.","සැප්.","ඔක්.","නොවැ.","දෙසැ.",""] - }, - AM: ["පෙ.ව.","පෙ.ව.","පෙ.ව."], - PM: ["ප.ව.","ප.ව.","ප.ව."], - eras: [{"name":"ක්\u200dරි.ව.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "yyyy MMMM' මස 'dd' වැනිදා 'dddd", - f: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm tt", - F: "yyyy MMMM' මස 'dd' වැනිදා 'dddd h:mm:ss tt", - Y: "yyyy MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "iu-Cans-CA", "default", { - name: "iu-Cans-CA", - englishName: "Inuktitut (Syllabics, Canada)", - nativeName: "ᐃᓄᒃᑎᑐᑦ (ᑲᓇᑕᒥ)", - language: "iu-Cans", - numberFormat: { - groupSizes: [3,0], - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["ᓈᑦᑏᖑᔭ","ᓇᒡᒐᔾᔭᐅ","ᐊᐃᑉᐱᖅ","ᐱᖓᑦᓯᖅ","ᓯᑕᒻᒥᖅ","ᑕᓪᓕᕐᒥᖅ","ᓯᕙᑖᕐᕕᒃ"], - namesAbbr: ["ᓈᑦᑏ","ᓇᒡᒐ","ᐊᐃᑉᐱ","ᐱᖓᑦᓯ","ᓯᑕ","ᑕᓪᓕ","ᓯᕙᑖᕐᕕᒃ"], - namesShort: ["ᓈ","ᓇ","ᐊ","ᐱ","ᓯ","ᑕ","ᓯ"] - }, - months: { - names: ["ᔮᓐᓄᐊᕆ","ᕖᕝᕗᐊᕆ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌᓯ","ᓯᑎᐱᕆ","ᐅᑐᐱᕆ","ᓄᕕᐱᕆ","ᑎᓯᐱᕆ",""], - namesAbbr: ["ᔮᓐᓄ","ᕖᕝᕗ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌ","ᓯᑎᐱ","ᐅᑐᐱ","ᓄᕕᐱ","ᑎᓯᐱ",""] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd,MMMM dd,yyyy", - f: "dddd,MMMM dd,yyyy h:mm tt", - F: "dddd,MMMM dd,yyyy h:mm:ss tt", - Y: "MMMM,yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "am-ET", "default", { - name: "am-ET", - englishName: "Amharic (Ethiopia)", - nativeName: "አማርኛ (ኢትዮጵያ)", - language: "am", - numberFormat: { - decimals: 1, - groupSizes: [3,0], - "NaN": "NAN", - percent: { - pattern: ["-n%","n%"], - decimals: 1, - groupSizes: [3,0] - }, - currency: { - pattern: ["-$n","$n"], - groupSizes: [3,0], - symbol: "ETB" - } - }, - calendars: { - standard: { - days: { - names: ["እሑድ","ሰኞ","ማክሰኞ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesAbbr: ["እሑድ","ሰኞ","ማክሰ","ረቡዕ","ሐሙስ","ዓርብ","ቅዳሜ"], - namesShort: ["እ","ሰ","ማ","ረ","ሐ","ዓ","ቅ"] - }, - months: { - names: ["ጃንዩወሪ","ፌብሩወሪ","ማርች","ኤፕረል","ሜይ","ጁን","ጁላይ","ኦገስት","ሴፕቴምበር","ኦክተውበር","ኖቬምበር","ዲሴምበር",""], - namesAbbr: ["ጃንዩ","ፌብሩ","ማርች","ኤፕረ","ሜይ","ጁን","ጁላይ","ኦገስ","ሴፕቴ","ኦክተ","ኖቬም","ዲሴም",""] - }, - AM: ["ጡዋት","ጡዋት","ጡዋት"], - PM: ["ከሰዓት","ከሰዓት","ከሰዓት"], - eras: [{"name":"ዓመተ ምሕረት","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "dddd '፣' MMMM d 'ቀን' yyyy", - f: "dddd '፣' MMMM d 'ቀን' yyyy h:mm tt", - F: "dddd '፣' MMMM d 'ቀን' yyyy h:mm:ss tt", - M: "MMMM d ቀን", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ne-NP", "default", { - name: "ne-NP", - englishName: "Nepali (Nepal)", - nativeName: "नेपाली (नेपाल)", - language: "ne", - numberFormat: { - groupSizes: [3,2], - "NaN": "nan", - negativeInfinity: "-infinity", - positiveInfinity: "infinity", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,2] - }, - currency: { - pattern: ["-$n","$n"], - symbol: "रु" - } - }, - calendars: { - standard: { - days: { - names: ["आइतवार","सोमवार","मङ्गलवार","बुधवार","बिहीवार","शुक्रवार","शनिवार"], - namesAbbr: ["आइत","सोम","मङ्गल","बुध","बिही","शुक्र","शनि"], - namesShort: ["आ","सो","म","बु","बि","शु","श"] - }, - months: { - names: ["जनवरी","फेब्रुअरी","मार्च","अप्रिल","मे","जून","जुलाई","अगस्त","सेप्टेम्बर","अक्टोबर","नोभेम्बर","डिसेम्बर",""], - namesAbbr: ["जन","फेब","मार्च","अप्रिल","मे","जून","जुलाई","अग","सेप्ट","अक्ट","नोभ","डिस",""] - }, - AM: ["विहानी","विहानी","विहानी"], - PM: ["बेलुकी","बेलुकी","बेलुकी"], - eras: [{"name":"a.d.","start":null,"offset":0}], - patterns: { - Y: "MMMM,yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fy-NL", "default", { - name: "fy-NL", - englishName: "Frisian (Netherlands)", - nativeName: "Frysk (Nederlân)", - language: "fy", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["Snein","Moandei","Tiisdei","Woansdei","Tongersdei","Freed","Sneon"], - namesAbbr: ["Sn","Mo","Ti","Wo","To","Fr","Sn"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["jannewaris","febrewaris","maart","april","maaie","juny","july","augustus","septimber","oktober","novimber","desimber",""], - namesAbbr: ["jann","febr","mrt","apr","maaie","jun","jul","aug","sept","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "d-M-yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ps-AF", "default", { - name: "ps-AF", - englishName: "Pashto (Afghanistan)", - nativeName: "پښتو (افغانستان)", - language: "ps", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": "،", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": "،", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - ",": "٬", - ".": "٫", - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 6, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښزمرى","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګا ښ","زمرى","وږى","تله","لړم","لنڈ ۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fil-PH", "default", { - name: "fil-PH", - englishName: "Filipino (Philippines)", - nativeName: "Filipino (Pilipinas)", - language: "fil", - numberFormat: { - currency: { - symbol: "PhP" - } - }, - calendars: { - standard: { - days: { - names: ["Linggo","Lunes","Martes","Mierkoles","Huebes","Biernes","Sabado"], - namesAbbr: ["Lin","Lun","Mar","Mier","Hueb","Bier","Saba"], - namesShort: ["L","L","M","M","H","B","S"] - }, - months: { - names: ["Enero","Pebrero","Marso","Abril","Mayo","Hunyo","Hulyo","Agosto","Septyembre","Oktubre","Nobyembre","Disyembre",""], - namesAbbr: ["En","Peb","Mar","Abr","Mayo","Hun","Hul","Agos","Sept","Okt","Nob","Dis",""] - }, - eras: [{"name":"Anno Domini","start":null,"offset":0}] - } - } -}); - -Globalize.addCultureInfo( "dv-MV", "default", { - name: "dv-MV", - englishName: "Divehi (Maldives)", - nativeName: "ދިވެހިބަސް (ދިވެހި ރާއްޖެ)", - language: "dv", - isRTL: true, - numberFormat: { - currency: { - pattern: ["n $-","n $"], - symbol: "ރ." - } - }, - calendars: { - standard: { - name: "Hijri", - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""], - namesAbbr: ["މުޙައްރަމް","ޞަފަރު","ރަބީޢުލްއައްވަލް","ރަބީޢުލްއާޚިރު","ޖުމާދަލްއޫލާ","ޖުމާދަލްއާޚިރާ","ރަޖަބް","ޝަޢްބާން","ރަމަޟާން","ޝައްވާލް","ޛުލްޤަޢިދާ","ޛުލްޙިއްޖާ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"ހިޖްރީ","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd/MM/yyyy HH:mm", - F: "dd/MM/yyyy HH:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - days: { - names: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesAbbr: ["އާދީއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"], - namesShort: ["އާ","ހޯ","އަ","ބު","ބު","ހު","ހޮ"] - }, - months: { - names: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""], - namesAbbr: ["ޖަނަވަރީ","ފެބްރުއަރީ","މާޗް","އޭޕްރިލް","މެއި","ޖޫން","ޖުލައި","އޯގަސްޓް","ސެޕްޓެމްބަރ","އޮކްޓޯބަރ","ނޮވެމްބަރ","ޑިސެމްބަރ",""] - }, - AM: ["މކ","މކ","މކ"], - PM: ["މފ","މފ","މފ"], - eras: [{"name":"މީލާދީ","start":null,"offset":0}], - patterns: { - d: "dd/MM/yy", - D: "ddd, yyyy MMMM dd", - t: "HH:mm", - T: "HH:mm:ss", - f: "ddd, yyyy MMMM dd HH:mm", - F: "ddd, yyyy MMMM dd HH:mm:ss", - Y: "yyyy, MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ha-Latn-NG", "default", { - name: "ha-Latn-NG", - englishName: "Hausa (Latin, Nigeria)", - nativeName: "Hausa (Nigeria)", - language: "ha-Latn", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Lahadi","Litinin","Talata","Laraba","Alhamis","Juma'a","Asabar"], - namesAbbr: ["Lah","Lit","Tal","Lar","Alh","Jum","Asa"], - namesShort: ["L","L","T","L","A","J","A"] - }, - months: { - names: ["Januwaru","Febreru","Maris","Afrilu","Mayu","Yuni","Yuli","Agusta","Satumba","Oktocba","Nuwamba","Disamba",""], - namesAbbr: ["Jan","Feb","Mar","Afr","May","Yun","Yul","Agu","Sat","Okt","Nuw","Dis",""] - }, - AM: ["Safe","safe","SAFE"], - PM: ["Yamma","yamma","YAMMA"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "yo-NG", "default", { - name: "yo-NG", - englishName: "Yoruba (Nigeria)", - nativeName: "Yoruba (Nigeria)", - language: "yo", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Osu kinni","Osu keji","Osu keta","Osu kerin","Osu karun","Osu kefa","Osu keje","Osu kejo","Osu kesan","Osu kewa","Osu kokanla","Osu keresi",""], - namesAbbr: ["kin.","kej.","ket.","ker.","kar.","kef.","kej.","kej.","kes.","kew.","kok.","ker.",""] - }, - AM: ["Owuro","owuro","OWURO"], - PM: ["Ale","ale","ALE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "quz-BO", "default", { - name: "quz-BO", - englishName: "Quechua (Bolivia)", - nativeName: "runasimi (Qullasuyu)", - language: "quz", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": ",", - symbol: "$b" - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "nso-ZA", "default", { - name: "nso-ZA", - englishName: "Sesotho sa Leboa (South Africa)", - nativeName: "Sesotho sa Leboa (Afrika Borwa)", - language: "nso", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$-n","$ n"], - symbol: "R" - } - }, - calendars: { - standard: { - days: { - names: ["Lamorena","Mošupologo","Labobedi","Laboraro","Labone","Labohlano","Mokibelo"], - namesAbbr: ["Lam","Moš","Lbb","Lbr","Lbn","Lbh","Mok"], - namesShort: ["L","M","L","L","L","L","M"] - }, - months: { - names: ["Pherekgong","Hlakola","Mopitlo","Moranang","Mosegamanye","Ngoatobošego","Phuphu","Phato","Lewedi","Diphalana","Dibatsela","Manthole",""], - namesAbbr: ["Pher","Hlak","Mop","Mor","Mos","Ngwat","Phup","Phat","Lew","Dip","Dib","Man",""] - }, - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ba-RU", "default", { - name: "ba-RU", - englishName: "Bashkir (Russia)", - nativeName: "Башҡорт (Россия)", - language: "ba", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ",", - symbol: "һ." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Йәкшәмбе","Дүшәмбе","Шишәмбе","Шаршамбы","Кесаҙна","Йома","Шәмбе"], - namesAbbr: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"], - namesShort: ["Йш","Дш","Шш","Шр","Кс","Йм","Шб"] - }, - months: { - names: ["ғинуар","февраль","март","апрель","май","июнь","июль","август","сентябрь","октябрь","ноябрь","декабрь",""], - namesAbbr: ["ғин","фев","мар","апр","май","июн","июл","авг","сен","окт","ноя","дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy 'й'", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy 'й' H:mm", - F: "d MMMM yyyy 'й' H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "lb-LU", "default", { - name: "lb-LU", - englishName: "Luxembourgish (Luxembourg)", - nativeName: "Lëtzebuergesch (Luxembourg)", - language: "lb", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "n. num.", - negativeInfinity: "-onendlech", - positiveInfinity: "+onendlech", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sonndeg","Méindeg","Dënschdeg","Mëttwoch","Donneschdeg","Freideg","Samschdeg"], - namesAbbr: ["Son","Méi","Dën","Mët","Don","Fre","Sam"], - namesShort: ["So","Mé","Dë","Më","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","Mäerz","Abrëll","Mee","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mäe","Abr","Mee","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "kl-GL", "default", { - name: "kl-GL", - englishName: "Greenlandic (Greenland)", - nativeName: "kalaallisut (Kalaallit Nunaat)", - language: "kl", - numberFormat: { - ",": ".", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - groupSizes: [3,0], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,0], - ",": ".", - ".": ",", - symbol: "kr." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sapaat","ataasinngorneq","marlunngorneq","pingasunngorneq","sisamanngorneq","tallimanngorneq","arfininngorneq"], - namesAbbr: ["sap","ata","mar","ping","sis","tal","arf"], - namesShort: ["sa","at","ma","pi","si","ta","ar"] - }, - months: { - names: ["januari","februari","martsi","apriili","maaji","juni","juli","aggusti","septembari","oktobari","novembari","decembari",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ig-NG", "default", { - name: "ig-NG", - englishName: "Igbo (Nigeria)", - nativeName: "Igbo (Nigeria)", - language: "ig", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Aiku","Aje","Isegun","Ojo'ru","Ojo'bo","Eti","Abameta"], - namesAbbr: ["Aik","Aje","Ise","Ojo","Ojo","Eti","Aba"], - namesShort: ["A","A","I","O","O","E","A"] - }, - months: { - names: ["Onwa mbu","Onwa ibua","Onwa ato","Onwa ano","Onwa ise","Onwa isi","Onwa asa","Onwa asato","Onwa itolu","Onwa iri","Onwa iri n'ofu","Onwa iri n'ibua",""], - namesAbbr: ["mbu.","ibu.","ato.","ano.","ise","isi","asa","asa.","ito.","iri.","n'of.","n'ib.",""] - }, - AM: ["Ututu","ututu","UTUTU"], - PM: ["Efifie","efifie","EFIFIE"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ii-CN", "default", { - name: "ii-CN", - englishName: "Yi (PRC)", - nativeName: "ꆈꌠꁱꂷ (ꍏꉸꏓꂱꇭꉼꇩ)", - language: "ii", - numberFormat: { - groupSizes: [3,0], - "NaN": "ꌗꂷꀋꉬ", - negativeInfinity: "ꀄꊭꌐꀋꉆ", - positiveInfinity: "ꈤꇁꑖꀋꉬ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ꑭꆏꑍ","ꆏꊂ꒔","ꆏꊂꑍ","ꆏꊂꌕ","ꆏꊂꇖ","ꆏꊂꉬ","ꆏꊂꃘ"], - namesAbbr: ["ꑭꆏ","ꆏ꒔","ꆏꑍ","ꆏꌕ","ꆏꇖ","ꆏꉬ","ꆏꃘ"], - namesShort: ["ꆏ","꒔","ꑍ","ꌕ","ꇖ","ꉬ","ꃘ"] - }, - months: { - names: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""], - namesAbbr: ["ꋍꆪ","ꑍꆪ","ꌕꆪ","ꇖꆪ","ꉬꆪ","ꃘꆪ","ꏃꆪ","ꉆꆪ","ꈬꆪ","ꊰꆪ","ꊯꊪꆪ","ꊰꑋꆪ",""] - }, - AM: ["ꂵꆪꈌꈐ","ꂵꆪꈌꈐ","ꂵꆪꈌꈐ"], - PM: ["ꂵꆪꈌꉈ","ꂵꆪꈌꉈ","ꂵꆪꈌꉈ"], - eras: [{"name":"ꇬꑼ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ꈎ' M'ꆪ' d'ꑍ'", - t: "tt h:mm", - T: "H:mm:ss", - f: "yyyy'ꈎ' M'ꆪ' d'ꑍ' tt h:mm", - F: "yyyy'ꈎ' M'ꆪ' d'ꑍ' H:mm:ss", - M: "M'ꆪ' d'ꑍ'", - Y: "yyyy'ꈎ' M'ꆪ'" - } - } - } -}); - -Globalize.addCultureInfo( "arn-CL", "default", { - name: "arn-CL", - englishName: "Mapudungun (Chile)", - nativeName: "Mapudungun (Chile)", - language: "arn", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "moh-CA", "default", { - name: "moh-CA", - englishName: "Mohawk (Mohawk)", - nativeName: "Kanien'kéha", - language: "moh", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Awentatokentì:ke","Awentataón'ke","Ratironhia'kehronòn:ke","Soséhne","Okaristiiáhne","Ronwaia'tanentaktonhne","Entákta"], - namesShort: ["S","M","T","W","T","F","S"] - }, - months: { - names: ["Tsothohrkó:Wa","Enniska","Enniskó:Wa","Onerahtókha","Onerahtohkó:Wa","Ohiari:Ha","Ohiarihkó:Wa","Seskéha","Seskehkó:Wa","Kenténha","Kentenhkó:Wa","Tsothóhrha",""] - } - } - } -}); - -Globalize.addCultureInfo( "br-FR", "default", { - name: "br-FR", - englishName: "Breton (France)", - nativeName: "brezhoneg (Frañs)", - language: "br", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NkN", - negativeInfinity: "-Anfin", - positiveInfinity: "+Anfin", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sul","Lun","Meurzh","Merc'her","Yaou","Gwener","Sadorn"], - namesAbbr: ["Sul","Lun","Meu.","Mer.","Yaou","Gwe.","Sad."], - namesShort: ["Su","Lu","Mz","Mc","Ya","Gw","Sa"] - }, - months: { - names: ["Genver","C'hwevrer","Meurzh","Ebrel","Mae","Mezheven","Gouere","Eost","Gwengolo","Here","Du","Kerzu",""], - namesAbbr: ["Gen.","C'hwe.","Meur.","Ebr.","Mae","Mezh.","Goue.","Eost","Gwen.","Here","Du","Kzu",""] - }, - AM: null, - PM: null, - eras: [{"name":"g. J.-K.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ug-CN", "default", { - name: "ug-CN", - englishName: "Uyghur (PRC)", - nativeName: "ئۇيغۇرچە (جۇڭخۇا خەلق جۇمھۇرىيىتى)", - language: "ug", - isRTL: true, - numberFormat: { - "NaN": "سان ئەمەس", - negativeInfinity: "مەنپىي چەكسىزلىك", - positiveInfinity: "مۇسبەت چەكسىزلىك", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["يەكشەنبە","دۈشەنبە","سەيشەنبە","چارشەنبە","پەيشەنبە","جۈمە","شەنبە"], - namesAbbr: ["يە","دۈ","سە","چا","پە","جۈ","شە"], - namesShort: ["ي","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""], - namesAbbr: ["1-ئاي","2-ئاي","3-ئاي","4-ئاي","5-ئاي","6-ئاي","7-ئاي","8-ئاي","9-ئاي","10-ئاي","11-ئاي","12-ئاي",""] - }, - AM: ["چۈشتىن بۇرۇن","چۈشتىن بۇرۇن","چۈشتىن بۇرۇن"], - PM: ["چۈشتىن كېيىن","چۈشتىن كېيىن","چۈشتىن كېيىن"], - eras: [{"name":"مىلادى","start":null,"offset":0}], - patterns: { - d: "yyyy-M-d", - D: "yyyy-'يىلى' MMMM d-'كۈنى،'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm", - F: "yyyy-'يىلى' MMMM d-'كۈنى،' H:mm:ss", - M: "MMMM d'-كۈنى'", - Y: "yyyy-'يىلى' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "mi-NZ", "default", { - name: "mi-NZ", - englishName: "Maori (New Zealand)", - nativeName: "Reo Māori (Aotearoa)", - language: "mi", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Rātapu","Rāhina","Rātū","Rāapa","Rāpare","Rāmere","Rāhoroi"], - namesAbbr: ["Ta","Hi","Tū","Apa","Pa","Me","Ho"], - namesShort: ["Ta","Hi","Tū","Aa","Pa","Me","Ho"] - }, - months: { - names: ["Kohi-tātea","Hui-tanguru","Poutū-te-rangi","Paenga-whāwhā","Haratua","Pipiri","Hōngongoi","Here-turi-kōkā","Mahuru","Whiringa-ā-nuku","Whiringa-ā-rangi","Hakihea",""], - namesAbbr: ["Kohi","Hui","Pou","Pae","Hara","Pipi","Hōngo","Here","Mahu","Nuku","Rangi","Haki",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM, yyyy", - f: "dddd, dd MMMM, yyyy h:mm tt", - F: "dddd, dd MMMM, yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM, yy" - } - } - } -}); - -Globalize.addCultureInfo( "oc-FR", "default", { - name: "oc-FR", - englishName: "Occitan (France)", - nativeName: "Occitan (França)", - language: "oc", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numeric", - negativeInfinity: "-Infinit", - positiveInfinity: "+Infinit", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimenge","diluns","dimars","dimècres","dijòus","divendres","dissabte"], - namesAbbr: ["dim.","lun.","mar.","mèc.","jòu.","ven.","sab."], - namesShort: ["di","lu","ma","mè","jò","ve","sa"] - }, - months: { - names: ["genier","febrier","març","abril","mai","junh","julh","agost","setembre","octobre","novembre","desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - monthsGenitive: { - names: ["de genier","de febrier","de març","d'abril","de mai","de junh","de julh","d'agost","de setembre","d'octobre","de novembre","de desembre",""], - namesAbbr: ["gen.","feb.","mar.","abr.","mai.","jun.","jul.","ag.","set.","oct.","nov.","des.",""] - }, - AM: null, - PM: null, - eras: [{"name":"après Jèsus-Crist","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd,' lo 'd MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd,' lo 'd MMMM' de 'yyyy HH:mm", - F: "dddd,' lo 'd MMMM' de 'yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "co-FR", "default", { - name: "co-FR", - englishName: "Corsican (France)", - nativeName: "Corsu (France)", - language: "co", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Mica numericu", - negativeInfinity: "-Infinitu", - positiveInfinity: "+Infinitu", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dumenica","luni","marti","mercuri","ghjovi","venderi","sabbatu"], - namesAbbr: ["dum.","lun.","mar.","mer.","ghj.","ven.","sab."], - namesShort: ["du","lu","ma","me","gh","ve","sa"] - }, - months: { - names: ["ghjennaghju","ferraghju","marzu","aprile","maghju","ghjunghju","lugliu","aostu","settembre","ottobre","nuvembre","dicembre",""], - namesAbbr: ["ghje","ferr","marz","apri","magh","ghju","lugl","aost","sett","otto","nuve","dice",""] - }, - AM: null, - PM: null, - eras: [{"name":"dopu J-C","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "gsw-FR", "default", { - name: "gsw-FR", - englishName: "Alsatian (France)", - nativeName: "Elsässisch (Frànkrisch)", - language: "gsw", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Ohne Nummer", - negativeInfinity: "-Unendlich", - positiveInfinity: "+Unendlich", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Sundàà","Mondàà","Dienschdàà","Mittwuch","Dunnerschdàà","Fridàà","Sàmschdàà"], - namesAbbr: ["Su.","Mo.","Di.","Mi.","Du.","Fr.","Sà."], - namesShort: ["Su","Mo","Di","Mi","Du","Fr","Sà"] - }, - months: { - names: ["Jänner","Feverje","März","Àpril","Mai","Jüni","Jüli","Augscht","September","Oktower","Nowember","Dezember",""], - namesAbbr: ["Jän.","Fev.","März","Apr.","Mai","Jüni","Jüli","Aug.","Sept.","Okt.","Now.","Dez.",""] - }, - AM: null, - PM: null, - eras: [{"name":"Vor J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sah-RU", "default", { - name: "sah-RU", - englishName: "Yakut (Russia)", - nativeName: "саха (Россия)", - language: "sah", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "NAN", - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "с." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["баскыһыанньа","бэнидиэнньик","оптуорунньук","сэрэдэ","чэппиэр","бээтинсэ","субуота"], - namesAbbr: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"], - namesShort: ["Бс","Бн","Оп","Ср","Чп","Бт","Сб"] - }, - months: { - names: ["Тохсунньу","Олунньу","Кулун тутар","Муус устар","Ыам ыйа","Бэс ыйа","От ыйа","Атырдьах ыйа","Балаҕан ыйа","Алтынньы","Сэтинньи","Ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - monthsGenitive: { - names: ["тохсунньу","олунньу","кулун тутар","муус устар","ыам ыйын","бэс ыйын","от ыйын","атырдьах ыйын","балаҕан ыйын","алтынньы","сэтинньи","ахсынньы",""], - namesAbbr: ["тхс","олн","кул","мст","ыам","бэс","отй","атр","блҕ","алт","стн","ахс",""] - }, - AM: null, - PM: null, - patterns: { - d: "MM.dd.yyyy", - D: "MMMM d yyyy 'с.'", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d yyyy 'с.' H:mm", - F: "MMMM d yyyy 'с.' H:mm:ss", - Y: "MMMM yyyy 'с.'" - } - } - } -}); - -Globalize.addCultureInfo( "qut-GT", "default", { - name: "qut-GT", - englishName: "K'iche (Guatemala)", - nativeName: "K'iche (Guatemala)", - language: "qut", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - symbol: "Q" - } - }, - calendars: { - standard: { - days: { - names: ["juq'ij","kaq'ij","oxq'ij","kajq'ij","joq'ij","waqq'ij","wuqq'ij"], - namesAbbr: ["juq","kaq","oxq","kajq","joq","waqq","wuqq"], - namesShort: ["ju","ka","ox","ka","jo","wa","wu"] - }, - months: { - names: ["nab'e ik'","ukab' ik'","rox ik'","ukaj ik'","uro' ik'","uwaq ik'","uwuq ik'","uwajxaq ik'","ub'elej ik'","ulaj ik'","ujulaj ik'","ukab'laj ik'",""], - namesAbbr: ["nab'e","ukab","rox","ukaj","uro","uwaq","uwuq","uwajxaq","ub'elej","ulaj","ujulaj","ukab'laj",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "rw-RW", "default", { - name: "rw-RW", - englishName: "Kinyarwanda (Rwanda)", - nativeName: "Kinyarwanda (Rwanda)", - language: "rw", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$-n","$ n"], - ",": " ", - ".": ",", - symbol: "RWF" - } - }, - calendars: { - standard: { - days: { - names: ["Ku wa mbere","Ku wa kabiri","Ku wa gatatu","Ku wa kane","Ku wa gatanu","Ku wa gatandatu","Ku cyumweru"], - namesAbbr: ["mbe.","kab.","gat.","kan.","gat.","gat.","cyu."], - namesShort: ["mb","ka","ga","ka","ga","ga","cy"] - }, - months: { - names: ["Mutarama","Gashyantare","Werurwe","Mata","Gicurasi","Kamena","Nyakanga","Kanama","Nzeli","Ukwakira","Ugushyingo","Ukuboza",""], - namesAbbr: ["Mut","Gas","Wer","Mat","Gic","Kam","Nya","Kan","Nze","Ukwa","Ugu","Uku",""] - }, - AM: ["saa moya z.m.","saa moya z.m.","SAA MOYA Z.M."], - PM: ["saa moya z.n.","saa moya z.n.","SAA MOYA Z.N."], - eras: [{"name":"AD","start":null,"offset":0}] - } - } -}); - -Globalize.addCultureInfo( "wo-SN", "default", { - name: "wo-SN", - englishName: "Wolof (Senegal)", - nativeName: "Wolof (Sénégal)", - language: "wo", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "XOF" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "prs-AF", "default", { - name: "prs-AF", - englishName: "Dari (Afghanistan)", - nativeName: "درى (افغانستان)", - language: "prs", - isRTL: true, - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "غ ع", - negativeInfinity: "-∞", - positiveInfinity: "∞", - percent: { - pattern: ["%n-","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$n-","$n"], - symbol: "؋" - } - }, - calendars: { - standard: { - name: "Hijri", - firstDay: 5, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - f: "dd/MM/yyyy h:mm tt", - F: "dd/MM/yyyy h:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_Localized: { - firstDay: 5, - days: { - names: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesAbbr: ["یکشنبه","دوشنبه","سه\u200cشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"], - namesShort: ["ی","د","س","چ","پ","ج","ش"] - }, - months: { - names: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""], - namesAbbr: ["سلواغه","كب","ورى","غويى","غبرګولى","چنګاښ","زمرى","وږى","تله","لړم","ليندۍ","مرغومى",""] - }, - AM: ["غ.م","غ.م","غ.م"], - PM: ["غ.و","غ.و","غ.و"], - eras: [{"name":"ل.ه","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy, dd, MMMM, dddd", - f: "yyyy, dd, MMMM, dddd h:mm tt", - F: "yyyy, dd, MMMM, dddd h:mm:ss tt", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "gd-GB", "default", { - name: "gd-GB", - englishName: "Scottish Gaelic (United Kingdom)", - nativeName: "Gàidhlig (An Rìoghachd Aonaichte)", - language: "gd", - numberFormat: { - negativeInfinity: "-Neo-chrìochnachd", - positiveInfinity: "Neo-chrìochnachd", - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"], - namesAbbr: ["Dòm","Lua","Mài","Cia","Ard","Hao","Sat"], - namesShort: ["D","L","M","C","A","H","S"] - }, - months: { - names: ["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd",""], - namesAbbr: ["Fao","Gea","Màr","Gib","Cèi","Ògm","Iuc","Lùn","Sul","Dàm","Sam","Dùb",""] - }, - AM: ["m","m","M"], - PM: ["f","f","F"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-IQ", "default", { - name: "ar-IQ", - englishName: "Arabic (Iraq)", - nativeName: "العربية (العراق)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "د.ع.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "zh-CN", "default", { - name: "zh-CN", - englishName: "Chinese (Simplified, PRC)", - nativeName: "中文(中华人民共和国)", - language: "zh-CHS", - numberFormat: { - "NaN": "非数字", - negativeInfinity: "负无穷大", - positiveInfinity: "正无穷大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["周日","周一","周二","周三","周四","周五","周六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "de-CH", "default", { - name: "de-CH", - englishName: "German (Switzerland)", - nativeName: "Deutsch (Schweiz)", - language: "de", - numberFormat: { - ",": "'", - "NaN": "n. def.", - negativeInfinity: "-unendlich", - positiveInfinity: "+unendlich", - percent: { - pattern: ["-n%","n%"], - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "Fr." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], - namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], - namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d. MMMM yyyy HH:mm", - F: "dddd, d. MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "en-GB", "default", { - name: "en-GB", - englishName: "English (United Kingdom)", - nativeName: "English (United Kingdom)", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "£" - } - }, - calendars: { - standard: { - firstDay: 1, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-MX", "default", { - name: "es-MX", - englishName: "Spanish (Mexico)", - nativeName: "Español (México)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fr-BE", "default", { - name: "fr-BE", - englishName: "French (Belgium)", - nativeName: "français (Belgique)", - language: "fr", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "d/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "it-CH", "default", { - name: "it-CH", - englishName: "Italian (Switzerland)", - nativeName: "italiano (Svizzera)", - language: "it", - numberFormat: { - ",": "'", - "NaN": "Non un numero reale", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "fr." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["domenica","lunedì","martedì","mercoledì","giovedì","venerdì","sabato"], - namesAbbr: ["dom","lun","mar","mer","gio","ven","sab"], - namesShort: ["do","lu","ma","me","gi","ve","sa"] - }, - months: { - names: ["gennaio","febbraio","marzo","aprile","maggio","giugno","luglio","agosto","settembre","ottobre","novembre","dicembre",""], - namesAbbr: ["gen","feb","mar","apr","mag","giu","lug","ago","set","ott","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d. MMMM yyyy HH:mm", - F: "dddd, d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "nl-BE", "default", { - name: "nl-BE", - englishName: "Dutch (Belgium)", - nativeName: "Nederlands (België)", - language: "nl", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NaN (Niet-een-getal)", - negativeInfinity: "-oneindig", - positiveInfinity: "oneindig", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"], - namesAbbr: ["zo","ma","di","wo","do","vr","za"], - namesShort: ["zo","ma","di","wo","do","vr","za"] - }, - months: { - names: ["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd d MMMM yyyy H:mm", - F: "dddd d MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "nn-NO", "default", { - name: "nn-NO", - englishName: "Norwegian, Nynorsk (Norway)", - nativeName: "norsk, nynorsk (Noreg)", - language: "nn", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","måndag","tysdag","onsdag","torsdag","fredag","laurdag"], - namesAbbr: ["sø","må","ty","on","to","fr","la"], - namesShort: ["sø","må","ty","on","to","fr","la"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "pt-PT", "default", { - name: "pt-PT", - englishName: "Portuguese (Portugal)", - nativeName: "português (Portugal)", - language: "pt", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NaN (Não é um número)", - negativeInfinity: "-Infinito", - positiveInfinity: "+Infinito", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["domingo","segunda-feira","terça-feira","quarta-feira","quinta-feira","sexta-feira","sábado"], - namesAbbr: ["dom","seg","ter","qua","qui","sex","sáb"], - namesShort: ["D","S","T","Q","Q","S","S"] - }, - months: { - names: ["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro",""], - namesAbbr: ["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "dddd, d' de 'MMMM' de 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d' de 'MMMM' de 'yyyy HH:mm", - F: "dddd, d' de 'MMMM' de 'yyyy HH:mm:ss", - M: "d/M", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Latn-CS", "default", { - name: "sr-Latn-CS", - englishName: "Serbian (Latin, Serbia and Montenegro (Former))", - nativeName: "srpski (Srbija i Crna Gora (Prethodno))", - language: "sr-Latn", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-beskonačnost", - positiveInfinity: "+beskonačnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Din." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sre","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"n.e.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sv-FI", "default", { - name: "sv-FI", - englishName: "Swedish (Finland)", - nativeName: "svenska (Finland)", - language: "sv", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["söndag","måndag","tisdag","onsdag","torsdag","fredag","lördag"], - namesAbbr: ["sö","må","ti","on","to","fr","lö"], - namesShort: ["sö","må","ti","on","to","fr","lö"] - }, - months: { - names: ["januari","februari","mars","april","maj","juni","juli","augusti","september","oktober","november","december",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","aug","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "'den 'd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "'den 'd MMMM yyyy HH:mm", - F: "'den 'd MMMM yyyy HH:mm:ss", - M: "'den 'd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "az-Cyrl-AZ", "default", { - name: "az-Cyrl-AZ", - englishName: "Azeri (Cyrillic, Azerbaijan)", - nativeName: "Азәрбајҹан (Азәрбајҹан)", - language: "az-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "ман." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Базар","Базар ертәси","Чәршәнбә ахшамы","Чәршәнбә","Ҹүмә ахшамы","Ҹүмә","Шәнбә"], - namesAbbr: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"], - namesShort: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"] - }, - months: { - names: ["Јанвар","Феврал","Март","Апрел","Мај","Ијун","Ијул","Август","Сентјабр","Октјабр","Нојабр","Декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","Мај","Ијун","Ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["јанвар","феврал","март","апрел","мај","ијун","ијул","август","сентјабр","октјабр","нојабр","декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","мая","ијун","ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "dsb-DE", "default", { - name: "dsb-DE", - englishName: "Lower Sorbian (Germany)", - nativeName: "dolnoserbšćina (Nimska)", - language: "dsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekońcne", - positiveInfinity: "+njekońcne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njeźela","ponjeźele","wałtora","srjoda","stwortk","pětk","sobota"], - namesAbbr: ["nje","pon","wał","srj","stw","pět","sob"], - namesShort: ["n","p","w","s","s","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","maj","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","maja","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'goź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'goź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "se-SE", "default", { - name: "se-SE", - englishName: "Sami, Northern (Sweden)", - nativeName: "davvisámegiella (Ruoŧŧa)", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["sotnabeaivi","mánnodat","disdat","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","mán","dis","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ga-IE", "default", { - name: "ga-IE", - englishName: "Irish (Ireland)", - nativeName: "Gaeilge (Éire)", - language: "ga", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Dé Domhnaigh","Dé Luain","Dé Máirt","Dé Céadaoin","Déardaoin","Dé hAoine","Dé Sathairn"], - namesAbbr: ["Domh","Luan","Máir","Céad","Déar","Aoi","Sath"], - namesShort: ["Do","Lu","Má","Cé","De","Ao","Sa"] - }, - months: { - names: ["Eanáir","Feabhra","Márta","Aibreán","Bealtaine","Meitheamh","Iúil","Lúnasa","Meán Fómhair","Deireadh Fómhair","Samhain","Nollaig",""], - namesAbbr: ["Ean","Feabh","Már","Aib","Bealt","Meith","Iúil","Lún","M.Fómh","D.Fómh","Samh","Noll",""] - }, - AM: ["r.n.","r.n.","R.N."], - PM: ["i.n.","i.n.","I.N."], - patterns: { - d: "dd/MM/yyyy", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ms-BN", "default", { - name: "ms-BN", - englishName: "Malay (Brunei Darussalam)", - nativeName: "Bahasa Melayu (Brunei Darussalam)", - language: "ms", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - decimals: 0, - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["Ahad","Isnin","Selasa","Rabu","Khamis","Jumaat","Sabtu"], - namesAbbr: ["Ahad","Isnin","Sel","Rabu","Khamis","Jumaat","Sabtu"], - namesShort: ["A","I","S","R","K","J","S"] - }, - months: { - names: ["Januari","Februari","Mac","April","Mei","Jun","Julai","Ogos","September","Oktober","November","Disember",""], - namesAbbr: ["Jan","Feb","Mac","Apr","Mei","Jun","Jul","Ogos","Sept","Okt","Nov","Dis",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM yyyy H:mm", - F: "dd MMMM yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "uz-Cyrl-UZ", "default", { - name: "uz-Cyrl-UZ", - englishName: "Uzbek (Cyrillic, Uzbekistan)", - nativeName: "Ўзбек (Ўзбекистон)", - language: "uz-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "сўм" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["якшанба","душанба","сешанба","чоршанба","пайшанба","жума","шанба"], - namesAbbr: ["якш","дш","сш","чш","пш","ж","ш"], - namesShort: ["я","д","с","ч","п","ж","ш"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январ","феврал","март","апрел","май","июн","июл","август","сентябр","октябр","ноябр","декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","мая","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'йил' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'йил' d-MMMM HH:mm", - F: "yyyy 'йил' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "bn-BD", "default", { - name: "bn-BD", - englishName: "Bengali (Bangladesh)", - nativeName: "বাংলা (বাংলাদেশ)", - language: "bn", - numberFormat: { - groupSizes: [3,2], - percent: { - pattern: ["-%n","%n"], - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "৳" - } - }, - calendars: { - standard: { - "/": "-", - ":": ".", - firstDay: 1, - days: { - names: ["রবিবার","সোমবার","মঙ্গলবার","বুধবার","বৃহস্পতিবার","শুক্রবার","শনিবার"], - namesAbbr: ["রবি.","সোম.","মঙ্গল.","বুধ.","বৃহস্পতি.","শুক্র.","শনি."], - namesShort: ["র","স","ম","ব","ব","শ","শ"] - }, - months: { - names: ["জানুয়ারী","ফেব্রুয়ারী","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগস্ট","সেপ্টেম্বর","অক্টোবর","নভেম্বর","ডিসেম্বর",""], - namesAbbr: ["জানু.","ফেব্রু.","মার্চ","এপ্রিল","মে","জুন","জুলাই","আগ.","সেপ্টে.","অক্টো.","নভে.","ডিসে.",""] - }, - AM: ["পুর্বাহ্ন","পুর্বাহ্ন","পুর্বাহ্ন"], - PM: ["অপরাহ্ন","অপরাহ্ন","অপরাহ্ন"], - patterns: { - d: "dd-MM-yy", - D: "dd MMMM yyyy", - t: "HH.mm", - T: "HH.mm.ss", - f: "dd MMMM yyyy HH.mm", - F: "dd MMMM yyyy HH.mm.ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "mn-Mong-CN", "default", { - name: "mn-Mong-CN", - englishName: "Mongolian (Traditional Mongolian, PRC)", - nativeName: "ᠮᠤᠨᠭᠭᠤᠯ ᠬᠡᠯᠡ (ᠪᠦᠭᠦᠳᠡ ᠨᠠᠢᠷᠠᠮᠳᠠᠬᠤ ᠳᠤᠮᠳᠠᠳᠤ ᠠᠷᠠᠳ ᠣᠯᠣᠰ)", - language: "mn-Mong", - numberFormat: { - groupSizes: [3,0], - "NaN": "ᠲᠤᠭᠠᠠ ᠪᠤᠰᠤ", - negativeInfinity: "ᠰᠦᠬᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠡᠬᠡ", - positiveInfinity: "ᠡᠶ᠋ᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠠᠬᠡ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesAbbr: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesShort: ["ᠡ\u200d","ᠨᠢ\u200d","ᠬᠣ\u200d","ᠭᠤ\u200d","ᠳᠥ\u200d","ᠲᠠ\u200d","ᠵᠢ\u200d"] - }, - months: { - names: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""], - namesAbbr: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""] - }, - AM: null, - PM: null, - eras: [{"name":"ᠣᠨ ᠲᠣᠭᠠᠯᠠᠯ ᠤᠨ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm", - F: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm:ss", - M: "M'ᠰᠠᠷ᠎ᠠ' d'ᠡᠳᠦᠷ'", - Y: "yyyy'ᠣᠨ' M'ᠰᠠᠷ᠎ᠠ'" - } - } - } -}); - -Globalize.addCultureInfo( "iu-Latn-CA", "default", { - name: "iu-Latn-CA", - englishName: "Inuktitut (Latin, Canada)", - nativeName: "Inuktitut (Kanatami)", - language: "iu-Latn", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Naattiinguja","Naggajjau","Aippiq","Pingatsiq","Sitammiq","Tallirmiq","Sivataarvik"], - namesAbbr: ["Nat","Nag","Aip","Pi","Sit","Tal","Siv"], - namesShort: ["N","N","A","P","S","T","S"] - }, - months: { - names: ["Jaannuari","Viivvuari","Maatsi","Iipuri","Mai","Juuni","Julai","Aaggiisi","Sitipiri","Utupiri","Nuvipiri","Tisipiri",""], - namesAbbr: ["Jan","Viv","Mas","Ipu","Mai","Jun","Jul","Agi","Sii","Uut","Nuv","Tis",""] - }, - patterns: { - d: "d/MM/yyyy", - D: "ddd, MMMM dd,yyyy", - f: "ddd, MMMM dd,yyyy h:mm tt", - F: "ddd, MMMM dd,yyyy h:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "tzm-Latn-DZ", "default", { - name: "tzm-Latn-DZ", - englishName: "Tamazight (Latin, Algeria)", - nativeName: "Tamazight (Djazaïr)", - language: "tzm-Latn", - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - symbol: "DZD" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 6, - days: { - names: ["Acer","Arime","Aram","Ahad","Amhadh","Sem","Sedh"], - namesAbbr: ["Ace","Ari","Ara","Aha","Amh","Sem","Sed"], - namesShort: ["Ac","Ar","Ar","Ah","Am","Se","Se"] - }, - months: { - names: ["Yenayer","Furar","Maghres","Yebrir","Mayu","Yunyu","Yulyu","Ghuct","Cutenber","Ktuber","Wambir","Dujanbir",""], - namesAbbr: ["Yen","Fur","Mag","Yeb","May","Yun","Yul","Ghu","Cut","Ktu","Wam","Duj",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "quz-EC", "default", { - name: "quz-EC", - englishName: "Quechua (Ecuador)", - nativeName: "runasimi (Ecuador)", - language: "quz", - numberFormat: { - ",": ".", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-EG", "default", { - name: "ar-EG", - englishName: "Arabic (Egypt)", - nativeName: "العربية (مصر)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - decimals: 3, - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - percent: { - decimals: 3 - }, - currency: { - pattern: ["$n-","$ n"], - symbol: "ج.م.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "zh-HK", "default", { - name: "zh-HK", - englishName: "Chinese (Traditional, Hong Kong S.A.R.)", - nativeName: "中文(香港特別行政區)", - language: "zh-CHT", - numberFormat: { - "NaN": "非數字", - negativeInfinity: "負無窮大", - positiveInfinity: "正無窮大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - symbol: "HK$" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["週日","週一","週二","週三","週四","週五","週六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "de-AT", "default", { - name: "de-AT", - englishName: "German (Austria)", - nativeName: "Deutsch (Österreich)", - language: "de", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "n. def.", - negativeInfinity: "-unendlich", - positiveInfinity: "+unendlich", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], - namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], - namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] - }, - months: { - names: ["Jänner","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jän","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, dd. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, dd. MMMM yyyy HH:mm", - F: "dddd, dd. MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "en-AU", "default", { - name: "en-AU", - englishName: "English (Australia)", - nativeName: "English (Australia)", - numberFormat: { - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - patterns: { - d: "d/MM/yyyy", - D: "dddd, d MMMM yyyy", - f: "dddd, d MMMM yyyy h:mm tt", - F: "dddd, d MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-ES", "default", { - name: "es-ES", - englishName: "Spanish (Spain, International Sort)", - nativeName: "Español (España, alfabetización internacional)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fr-CA", "default", { - name: "fr-CA", - englishName: "French (Canada)", - nativeName: "français (Canada)", - language: "fr", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["(n $)","n $"], - ",": " ", - ".": "," - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "yyyy-MM-dd", - D: "d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d MMMM yyyy HH:mm", - F: "d MMMM yyyy HH:mm:ss", - M: "d MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Cyrl-CS", "default", { - name: "sr-Cyrl-CS", - englishName: "Serbian (Cyrillic, Serbia and Montenegro (Former))", - nativeName: "српски (Србија и Црна Гора (Претходно))", - language: "sr-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Дин." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недеља","понедељак","уторак","среда","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["не","по","ут","ср","че","пе","су"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "se-FI", "default", { - name: "se-FI", - englishName: "Sami, Northern (Finland)", - nativeName: "davvisámegiella (Suopma)", - language: "se", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sotnabeaivi","vuossárga","maŋŋebárga","gaskavahkku","duorastat","bearjadat","lávvardat"], - namesAbbr: ["sotn","vuos","maŋ","gask","duor","bear","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ođđajagemánnu","guovvamánnu","njukčamánnu","cuoŋománnu","miessemánnu","geassemánnu","suoidnemánnu","borgemánnu","čakčamánnu","golggotmánnu","skábmamánnu","juovlamánnu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - monthsGenitive: { - names: ["ođđajagimánu","guovvamánu","njukčamánu","cuoŋománu","miessemánu","geassemánu","suoidnemánu","borgemánu","čakčamánu","golggotmánu","skábmamánu","juovlamánu",""], - namesAbbr: ["ođđj","guov","njuk","cuo","mies","geas","suoi","borg","čakč","golg","skáb","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. b. 'yyyy H:mm", - F: "MMMM d'. b. 'yyyy H:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "quz-PE", "default", { - name: "quz-PE", - englishName: "Quechua (Peru)", - nativeName: "runasimi (Piruw)", - language: "quz", - numberFormat: { - percent: { - pattern: ["-%n","%n"] - }, - currency: { - pattern: ["$ -n","$ n"], - symbol: "S/." - } - }, - calendars: { - standard: { - days: { - names: ["intichaw","killachaw","atipachaw","quyllurchaw","Ch' askachaw","Illapachaw","k'uychichaw"], - namesAbbr: ["int","kil","ati","quy","Ch'","Ill","k'u"], - namesShort: ["d","k","a","m","h","b","k"] - }, - months: { - names: ["Qulla puquy","Hatun puquy","Pauqar waray","ayriwa","Aymuray","Inti raymi","Anta Sitwa","Qhapaq Sitwa","Uma raymi","Kantaray","Ayamarq'a","Kapaq Raymi",""], - namesAbbr: ["Qul","Hat","Pau","ayr","Aym","Int","Ant","Qha","Uma","Kan","Aya","Kap",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-LY", "default", { - name: "ar-LY", - englishName: "Arabic (Libya)", - nativeName: "العربية (ليبيا)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - decimals: 3, - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - percent: { - decimals: 3 - }, - currency: { - pattern: ["$n-","$n"], - decimals: 3, - symbol: "د.ل.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "zh-SG", "default", { - name: "zh-SG", - englishName: "Chinese (Simplified, Singapore)", - nativeName: "中文(新加坡)", - language: "zh-CHS", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["周日","周一","周二","周三","周四","周五","周六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - patterns: { - d: "d/M/yyyy", - D: "yyyy'年'M'月'd'日'", - t: "tt h:mm", - T: "tt h:mm:ss", - f: "yyyy'年'M'月'd'日' tt h:mm", - F: "yyyy'年'M'月'd'日' tt h:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "de-LU", "default", { - name: "de-LU", - englishName: "German (Luxembourg)", - nativeName: "Deutsch (Luxemburg)", - language: "de", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "n. def.", - negativeInfinity: "-unendlich", - positiveInfinity: "+unendlich", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], - namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], - namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d. MMMM yyyy HH:mm", - F: "dddd, d. MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "en-CA", "default", { - name: "en-CA", - englishName: "English (Canada)", - nativeName: "English (Canada)", - numberFormat: { - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - patterns: { - d: "dd/MM/yyyy", - D: "MMMM-dd-yy", - f: "MMMM-dd-yy h:mm tt", - F: "MMMM-dd-yy h:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "es-GT", "default", { - name: "es-GT", - englishName: "Spanish (Guatemala)", - nativeName: "Español (Guatemala)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - symbol: "Q" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fr-CH", "default", { - name: "fr-CH", - englishName: "French (Switzerland)", - nativeName: "français (Suisse)", - language: "fr", - numberFormat: { - ",": "'", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "fr." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "hr-BA", "default", { - name: "hr-BA", - englishName: "Croatian (Latin, Bosnia and Herzegovina)", - nativeName: "hrvatski (Bosna i Hercegovina)", - language: "hr", - numberFormat: { - pattern: ["- n"], - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["siječanj","veljača","ožujak","travanj","svibanj","lipanj","srpanj","kolovoz","rujan","listopad","studeni","prosinac",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - monthsGenitive: { - names: ["siječnja","veljače","ožujka","travnja","svibnja","lipnja","srpnja","kolovoza","rujna","listopada","studenog","prosinca",""], - namesAbbr: ["sij","vlj","ožu","tra","svi","lip","srp","kol","ruj","lis","stu","pro",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy.", - D: "d. MMMM yyyy.", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy. H:mm", - F: "d. MMMM yyyy. H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "smj-NO", "default", { - name: "smj-NO", - englishName: "Sami, Lule (Norway)", - nativeName: "julevusámegiella (Vuodna)", - language: "smj", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["sådnåbiejvve","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"], - namesAbbr: ["såd","mán","dis","gas","duor","bier","láv"], - namesShort: ["s","m","d","g","d","b","l"] - }, - months: { - names: ["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - monthsGenitive: { - names: ["ådåjakmáno","guovvamáno","sjnjuktjamáno","vuoratjismáno","moarmesmáno","biehtsemáno","sjnjilltjamáno","bårggemáno","ragátmáno","gålgådismáno","basádismáno","javllamáno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-DZ", "default", { - name: "ar-DZ", - englishName: "Arabic (Algeria)", - nativeName: "العربية (الجزائر)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "د.ج.\u200f" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MM/yyyy H:mm", - F: "dd/MM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MMMM/yyyy H:mm", - F: "dd/MMMM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - } - } -}); - -Globalize.addCultureInfo( "zh-MO", "default", { - name: "zh-MO", - englishName: "Chinese (Traditional, Macao S.A.R.)", - nativeName: "中文(澳門特別行政區)", - language: "zh-CHT", - numberFormat: { - "NaN": "非數字", - negativeInfinity: "負無窮大", - positiveInfinity: "正無窮大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - symbol: "MOP" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["週日","週一","週二","週三","週四","週五","週六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "de-LI", "default", { - name: "de-LI", - englishName: "German (Liechtenstein)", - nativeName: "Deutsch (Liechtenstein)", - language: "de", - numberFormat: { - ",": "'", - "NaN": "n. def.", - negativeInfinity: "-unendlich", - positiveInfinity: "+unendlich", - percent: { - pattern: ["-n%","n%"], - ",": "'" - }, - currency: { - pattern: ["$-n","$ n"], - ",": "'", - symbol: "CHF" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"], - namesAbbr: ["So","Mo","Di","Mi","Do","Fr","Sa"], - namesShort: ["So","Mo","Di","Mi","Do","Fr","Sa"] - }, - months: { - names: ["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember",""], - namesAbbr: ["Jan","Feb","Mrz","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez",""] - }, - AM: null, - PM: null, - eras: [{"name":"n. Chr.","start":null,"offset":0}], - patterns: { - d: "dd.MM.yyyy", - D: "dddd, d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd, d. MMMM yyyy HH:mm", - F: "dddd, d. MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "en-NZ", "default", { - name: "en-NZ", - englishName: "English (New Zealand)", - nativeName: "English (New Zealand)", - numberFormat: { - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - patterns: { - d: "d/MM/yyyy", - D: "dddd, d MMMM yyyy", - f: "dddd, d MMMM yyyy h:mm tt", - F: "dddd, d MMMM yyyy h:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-CR", "default", { - name: "es-CR", - englishName: "Spanish (Costa Rica)", - nativeName: "Español (Costa Rica)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - ",": ".", - ".": ",", - symbol: "₡" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fr-LU", "default", { - name: "fr-LU", - englishName: "French (Luxembourg)", - nativeName: "français (Luxembourg)", - language: "fr", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "bs-Latn-BA", "default", { - name: "bs-Latn-BA", - englishName: "Bosnian (Latin, Bosnia and Herzegovina)", - nativeName: "bosanski (Bosna i Hercegovina)", - language: "bs-Latn", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","juni","juli","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "smj-SE", "default", { - name: "smj-SE", - englishName: "Sami, Lule (Sweden)", - nativeName: "julevusámegiella (Svierik)", - language: "smj", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ájllek","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"], - namesAbbr: ["ájl","mán","dis","gas","duor","bier","láv"], - namesShort: ["á","m","d","g","d","b","l"] - }, - months: { - names: ["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - monthsGenitive: { - names: ["ådåjakmáno","guovvamáno","sjnjuktjamáno","vuoratjismáno","moarmesmáno","biehtsemáno","sjnjilltjamáno","bårggemáno","ragátmáno","gålgådismáno","basádismáno","javllamáno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-MA", "default", { - name: "ar-MA", - englishName: "Arabic (Morocco)", - nativeName: "العربية (المملكة المغربية)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "د.م.\u200f" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","ماي","يونيو","يوليوز","غشت","شتنبر","أكتوبر","نونبر","دجنبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","ماي","يونيو","يوليوز","غشت","شتنبر","أكتوبر","نونبر","دجنبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MM/yyyy H:mm", - F: "dd/MM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MMMM/yyyy H:mm", - F: "dd/MMMM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - } - } -}); - -Globalize.addCultureInfo( "en-IE", "default", { - name: "en-IE", - englishName: "English (Ireland)", - nativeName: "English (Ireland)", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - AM: null, - PM: null, - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-PA", "default", { - name: "es-PA", - englishName: "Spanish (Panama)", - nativeName: "Español (Panamá)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - pattern: ["($ n)","$ n"], - symbol: "B/." - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "fr-MC", "default", { - name: "fr-MC", - englishName: "French (Monaco)", - nativeName: "français (Principauté de Monaco)", - language: "fr", - numberFormat: { - ",": " ", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: null, - PM: null, - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd d MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dddd d MMMM yyyy HH:mm", - F: "dddd d MMMM yyyy HH:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Latn-BA", "default", { - name: "sr-Latn-BA", - englishName: "Serbian (Latin, Bosnia and Herzegovina)", - nativeName: "srpski (Bosna i Hercegovina)", - language: "sr-Latn", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-beskonačnost", - positiveInfinity: "+beskonačnost", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sre","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"n.e.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sma-NO", "default", { - name: "sma-NO", - englishName: "Sami, Southern (Norway)", - nativeName: "åarjelsaemiengiele (Nöörje)", - language: "sma", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-%n","%n"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"], - namesAbbr: ["aej","måa","dæj","gask","duar","bearj","laav"], - namesShort: ["a","m","d","g","d","b","l"] - }, - months: { - names: ["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - monthsGenitive: { - names: ["tsïengelen","goevten","njoktjen","voerhtjen","suehpeden","ruffien","snjaltjen","mïetsken","skïereden","golken","rahkan","goeven",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-TN", "default", { - name: "ar-TN", - englishName: "Arabic (Tunisia)", - nativeName: "العربية (تونس)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - decimals: 3, - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - percent: { - decimals: 3 - }, - currency: { - pattern: ["$n-","$ n"], - decimals: 3, - symbol: "د.ت.\u200f" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MM/yyyy H:mm", - F: "dd/MM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd/MMMM/yyyy H:mm", - F: "dd/MMMM/yyyy H:mm:ss", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, MMMM dd, yyyy H:mm", - F: "dddd, MMMM dd, yyyy H:mm:ss" - } - } - } -}); - -Globalize.addCultureInfo( "en-ZA", "default", { - name: "en-ZA", - englishName: "English (South Africa)", - nativeName: "English (South Africa)", - numberFormat: { - ",": " ", - percent: { - pattern: ["-n%","n%"], - ",": " " - }, - currency: { - pattern: ["$-n","$ n"], - ",": " ", - ".": ",", - symbol: "R" - } - }, - calendars: { - standard: { - patterns: { - d: "yyyy/MM/dd", - D: "dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM yyyy hh:mm tt", - F: "dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-DO", "default", { - name: "es-DO", - englishName: "Spanish (Dominican Republic)", - nativeName: "Español (República Dominicana)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - symbol: "RD$" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Cyrl-BA", "default", { - name: "sr-Cyrl-BA", - englishName: "Serbian (Cyrillic, Bosnia and Herzegovina)", - nativeName: "српски (Босна и Херцеговина)", - language: "sr-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "КМ" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недеља","понедељак","уторак","среда","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["н","п","у","с","ч","п","с"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "sma-SE", "default", { - name: "sma-SE", - englishName: "Sami, Southern (Sweden)", - nativeName: "åarjelsaemiengiele (Sveerje)", - language: "sma", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"], - namesAbbr: ["aej","måa","dæj","gask","duar","bearj","laav"], - namesShort: ["a","m","d","g","d","b","l"] - }, - months: { - names: ["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - monthsGenitive: { - names: ["tsïengelen","goevten","njoktjen","voerhtjen","suehpeden","ruffien","snjaltjen","mïetsken","skïereden","golken","rahkan","goeven",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-OM", "default", { - name: "ar-OM", - englishName: "Arabic (Oman)", - nativeName: "العربية (عمان)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - decimals: 3, - symbol: "ر.ع.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "en-JM", "default", { - name: "en-JM", - englishName: "English (Jamaica)", - nativeName: "English (Jamaica)", - numberFormat: { - currency: { - pattern: ["-$n","$n"], - symbol: "J$" - } - }, - calendars: { - standard: { - patterns: { - d: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "es-VE", "default", { - name: "es-VE", - englishName: "Spanish (Bolivarian Republic of Venezuela)", - nativeName: "Español (Republica Bolivariana de Venezuela)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": ".", - ".": ",", - symbol: "Bs. F." - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "bs-Cyrl-BA", "default", { - name: "bs-Cyrl-BA", - englishName: "Bosnian (Cyrillic, Bosnia and Herzegovina)", - nativeName: "босански (Босна и Херцеговина)", - language: "bs-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "КМ" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недјеља","понедјељак","уторак","сриједа","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["н","п","у","с","ч","п","с"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "sms-FI", "default", { - name: "sms-FI", - englishName: "Sami, Skolt (Finland)", - nativeName: "sääm´ǩiõll (Lää´ddjânnam)", - language: "sms", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pâ´sspei´vv","vuõssargg","mââibargg","seärad","nelljdpei´vv","piâtnâc","sue´vet"], - namesAbbr: ["pâ","vu","mâ","se","ne","pi","su"], - namesShort: ["p","v","m","s","n","p","s"] - }, - months: { - names: ["ođđee´jjmään","tä´lvvmään","pâ´zzlâšttammään","njuhččmään","vue´ssmään","ǩie´ssmään","suei´nnmään","på´rǧǧmään","čõhččmään","kålggmään","skamm´mään","rosttovmään",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - monthsGenitive: { - names: ["ođđee´jjmannu","tä´lvvmannu","pâ´zzlâšttammannu","njuhččmannu","vue´ssmannu","ǩie´ssmannu","suei´nnmannu","på´rǧǧmannu","čõhččmannu","kålggmannu","skamm´mannu","rosttovmannu",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-YE", "default", { - name: "ar-YE", - englishName: "Arabic (Yemen)", - nativeName: "العربية (اليمن)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ر.ي.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "en-029", "default", { - name: "en-029", - englishName: "English (Caribbean)", - nativeName: "English (Caribbean)", - numberFormat: { - currency: { - pattern: ["-$n","$n"] - } - }, - calendars: { - standard: { - firstDay: 1, - patterns: { - d: "MM/dd/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-CO", "default", { - name: "es-CO", - englishName: "Spanish (Colombia)", - nativeName: "Español (Colombia)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Latn-RS", "default", { - name: "sr-Latn-RS", - englishName: "Serbian (Latin, Serbia)", - nativeName: "srpski (Srbija)", - language: "sr-Latn", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-beskonačnost", - positiveInfinity: "+beskonačnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Din." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sre","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"n.e.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "smn-FI", "default", { - name: "smn-FI", - englishName: "Sami, Inari (Finland)", - nativeName: "sämikielâ (Suomâ)", - language: "smn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pasepeivi","vuossargâ","majebargâ","koskokko","tuorâstâh","vástuppeivi","lávárdâh"], - namesAbbr: ["pa","vu","ma","ko","tu","vá","lá"], - namesShort: ["p","v","m","k","t","v","l"] - }, - months: { - names: ["uđđâivemáánu","kuovâmáánu","njuhčâmáánu","cuáŋuimáánu","vyesimáánu","kesimáánu","syeinimáánu","porgemáánu","čohčâmáánu","roovvâdmáánu","skammâmáánu","juovlâmáánu",""], - namesAbbr: ["uđiv","kuov","njuh","cuoŋ","vyes","kesi","syei","porg","čoh","roov","ska","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-SY", "default", { - name: "ar-SY", - englishName: "Arabic (Syria)", - nativeName: "العربية (سوريا)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ل.س.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "en-BZ", "default", { - name: "en-BZ", - englishName: "English (Belize)", - nativeName: "English (Belize)", - numberFormat: { - currency: { - groupSizes: [3,0], - symbol: "BZ$" - } - }, - calendars: { - standard: { - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd MMMM yyyy hh:mm tt", - F: "dddd, dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-PE", "default", { - name: "es-PE", - englishName: "Spanish (Peru)", - nativeName: "Español (Perú)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - pattern: ["$ -n","$ n"], - symbol: "S/." - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Cyrl-RS", "default", { - name: "sr-Cyrl-RS", - englishName: "Serbian (Cyrillic, Serbia)", - nativeName: "српски (Србија)", - language: "sr-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Дин." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недеља","понедељак","уторак","среда","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["не","по","ут","ср","че","пе","су"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-JO", "default", { - name: "ar-JO", - englishName: "Arabic (Jordan)", - nativeName: "العربية (الأردن)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - decimals: 3, - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - percent: { - decimals: 3 - }, - currency: { - pattern: ["$n-","$ n"], - decimals: 3, - symbol: "د.ا.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "en-TT", "default", { - name: "en-TT", - englishName: "English (Trinidad and Tobago)", - nativeName: "English (Trinidad y Tobago)", - numberFormat: { - currency: { - groupSizes: [3,0], - symbol: "TT$" - } - }, - calendars: { - standard: { - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd MMMM yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd MMMM yyyy hh:mm tt", - F: "dddd, dd MMMM yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-AR", "default", { - name: "es-AR", - englishName: "Spanish (Argentina)", - nativeName: "Español (Argentina)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["$-n","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Latn-ME", "default", { - name: "sr-Latn-ME", - englishName: "Serbian (Latin, Montenegro)", - nativeName: "srpski (Crna Gora)", - language: "sr-Latn", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-beskonačnost", - positiveInfinity: "+beskonačnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sre","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"n.e.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-LB", "default", { - name: "ar-LB", - englishName: "Arabic (Lebanon)", - nativeName: "العربية (لبنان)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ل.ل.\u200f" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 1, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_TransliteratedEnglish: { - name: "Gregorian_TransliteratedEnglish", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["أ","ا","ث","أ","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 1, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "en-ZW", "default", { - name: "en-ZW", - englishName: "English (Zimbabwe)", - nativeName: "English (Zimbabwe)", - numberFormat: { - currency: { - symbol: "Z$" - } - } -}); - -Globalize.addCultureInfo( "es-EC", "default", { - name: "es-EC", - englishName: "Spanish (Ecuador)", - nativeName: "Español (Ecuador)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Cyrl-ME", "default", { - name: "sr-Cyrl-ME", - englishName: "Serbian (Cyrillic, Montenegro)", - nativeName: "српски (Црна Гора)", - language: "sr-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недеља","понедељак","уторак","среда","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["не","по","ут","ср","че","пе","су"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-KW", "default", { - name: "ar-KW", - englishName: "Arabic (Kuwait)", - nativeName: "العربية (الكويت)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - decimals: 3, - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - percent: { - decimals: 3 - }, - currency: { - pattern: ["$n-","$ n"], - decimals: 3, - symbol: "د.ك.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "en-PH", "default", { - name: "en-PH", - englishName: "English (Republic of the Philippines)", - nativeName: "English (Philippines)", - numberFormat: { - currency: { - symbol: "Php" - } - } -}); - -Globalize.addCultureInfo( "es-CL", "default", { - name: "es-CL", - englishName: "Spanish (Chile)", - nativeName: "Español (Chile)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-$ n","$ n"], - ",": ".", - ".": "," - } - }, - calendars: { - standard: { - "/": "-", - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: null, - PM: null, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd-MM-yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dddd, dd' de 'MMMM' de 'yyyy H:mm", - F: "dddd, dd' de 'MMMM' de 'yyyy H:mm:ss", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-AE", "default", { - name: "ar-AE", - englishName: "Arabic (U.A.E.)", - nativeName: "العربية (الإمارات العربية المتحدة)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "د.إ.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "es-UY", "default", { - name: "es-UY", - englishName: "Spanish (Uruguay)", - nativeName: "Español (Uruguay)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": ",", - symbol: "$U" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-BH", "default", { - name: "ar-BH", - englishName: "Arabic (Bahrain)", - nativeName: "العربية (البحرين)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - decimals: 3, - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - percent: { - decimals: 3 - }, - currency: { - pattern: ["$n-","$ n"], - decimals: 3, - symbol: "د.ب.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","ابريل","مايو","يونيو","يوليو","اغسطس","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "es-PY", "default", { - name: "es-PY", - englishName: "Spanish (Paraguay)", - nativeName: "Español (Paraguay)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": ",", - symbol: "Gs" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "ar-QA", "default", { - name: "ar-QA", - englishName: "Arabic (Qatar)", - nativeName: "العربية (قطر)", - language: "ar", - isRTL: true, - numberFormat: { - pattern: ["n-"], - "NaN": "ليس برقم", - negativeInfinity: "-لا نهاية", - positiveInfinity: "+لا نهاية", - currency: { - pattern: ["$n-","$ n"], - symbol: "ر.ق.\u200f" - } - }, - calendars: { - standard: { - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - patterns: { - d: "dd/MM/yyyy", - D: "dd MMMM, yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd MMMM, yyyy hh:mm tt", - F: "dd MMMM, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - UmAlQura: { - name: "UmAlQura", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MMMM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MMMM/yyyy hh:mm tt", - F: "dd/MMMM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - _yearInfo: [ - // MonthLengthFlags, Gregorian Date - [746, -2198707200000], - [1769, -2168121600000], - [3794, -2137449600000], - [3748, -2106777600000], - [3402, -2076192000000], - [2710, -2045606400000], - [1334, -2015020800000], - [2741, -1984435200000], - [3498, -1953763200000], - [2980, -1923091200000], - [2889, -1892505600000], - [2707, -1861920000000], - [1323, -1831334400000], - [2647, -1800748800000], - [1206, -1770076800000], - [2741, -1739491200000], - [1450, -1708819200000], - [3413, -1678233600000], - [3370, -1647561600000], - [2646, -1616976000000], - [1198, -1586390400000], - [2397, -1555804800000], - [748, -1525132800000], - [1749, -1494547200000], - [1706, -1463875200000], - [1365, -1433289600000], - [1195, -1402704000000], - [2395, -1372118400000], - [698, -1341446400000], - [1397, -1310860800000], - [2994, -1280188800000], - [1892, -1249516800000], - [1865, -1218931200000], - [1621, -1188345600000], - [683, -1157760000000], - [1371, -1127174400000], - [2778, -1096502400000], - [1748, -1065830400000], - [3785, -1035244800000], - [3474, -1004572800000], - [3365, -973987200000], - [2637, -943401600000], - [685, -912816000000], - [1389, -882230400000], - [2922, -851558400000], - [2898, -820886400000], - [2725, -790300800000], - [2635, -759715200000], - [1175, -729129600000], - [2359, -698544000000], - [694, -667872000000], - [1397, -637286400000], - [3434, -606614400000], - [3410, -575942400000], - [2710, -545356800000], - [2349, -514771200000], - [605, -484185600000], - [1245, -453600000000], - [2778, -422928000000], - [1492, -392256000000], - [3497, -361670400000], - [3410, -330998400000], - [2730, -300412800000], - [1238, -269827200000], - [2486, -239241600000], - [884, -208569600000], - [1897, -177984000000], - [1874, -147312000000], - [1701, -116726400000], - [1355, -86140800000], - [2731, -55555200000], - [1370, -24883200000], - [2773, 5702400000], - [3538, 36374400000], - [3492, 67046400000], - [3401, 97632000000], - [2709, 128217600000], - [1325, 158803200000], - [2653, 189388800000], - [1370, 220060800000], - [2773, 250646400000], - [1706, 281318400000], - [1685, 311904000000], - [1323, 342489600000], - [2647, 373075200000], - [1198, 403747200000], - [2422, 434332800000], - [1388, 465004800000], - [2901, 495590400000], - [2730, 526262400000], - [2645, 556848000000], - [1197, 587433600000], - [2397, 618019200000], - [730, 648691200000], - [1497, 679276800000], - [3506, 709948800000], - [2980, 740620800000], - [2890, 771206400000], - [2645, 801792000000], - [693, 832377600000], - [1397, 862963200000], - [2922, 893635200000], - [3026, 924307200000], - [3012, 954979200000], - [2953, 985564800000], - [2709, 1016150400000], - [1325, 1046736000000], - [1453, 1077321600000], - [2922, 1107993600000], - [1748, 1138665600000], - [3529, 1169251200000], - [3474, 1199923200000], - [2726, 1230508800000], - [2390, 1261094400000], - [686, 1291680000000], - [1389, 1322265600000], - [874, 1352937600000], - [2901, 1383523200000], - [2730, 1414195200000], - [2381, 1444780800000], - [1181, 1475366400000], - [2397, 1505952000000], - [698, 1536624000000], - [1461, 1567209600000], - [1450, 1597881600000], - [3413, 1628467200000], - [2714, 1659139200000], - [2350, 1689724800000], - [622, 1720310400000], - [1373, 1750896000000], - [2778, 1781568000000], - [1748, 1812240000000], - [1701, 1842825600000], - [0, 1873411200000] - ], - minDate: -2198707200000, - maxDate: 1873411199999, - toGregorian: function(hyear, hmonth, hday) { - var days = hday - 1, - gyear = hyear - 1318; - if (gyear < 0 || gyear >= this._yearInfo.length) return null; - var info = this._yearInfo[gyear], - gdate = new Date(info[1]), - monthLength = info[0]; - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the gregorian date in the same timezone, - // not what the gregorian date was at GMT time, so we adjust for the offset. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - for (var i = 0; i < hmonth; i++) { - days += 29 + (monthLength & 1); - monthLength = monthLength >> 1; - } - gdate.setDate(gdate.getDate() + days); - return gdate; - }, - fromGregorian: function(gdate) { - // Date's ticks in javascript are always from the GMT time, - // but we are interested in the hijri date in the same timezone, - // not what the hijri date was at GMT time, so we adjust for the offset. - var ticks = gdate - gdate.getTimezoneOffset() * 60000; - if (ticks < this.minDate || ticks > this.maxDate) return null; - var hyear = 0, - hmonth = 1; - // find the earliest gregorian date in the array that is greater than or equal to the given date - while (ticks > this._yearInfo[++hyear][1]) { } - if (ticks !== this._yearInfo[hyear][1]) { - hyear--; - } - var info = this._yearInfo[hyear], - // how many days has it been since the date we found in the array? - // 86400000 = ticks per day - days = Math.floor((ticks - info[1]) / 86400000), - monthLength = info[0]; - hyear += 1318; // the Nth array entry corresponds to hijri year 1318+N - // now increment day/month based on the total days, considering - // how many days are in each month. We cannot run past the year - // mark since we would have found a different array entry in that case. - var daysInMonth = 29 + (monthLength & 1); - while (days >= daysInMonth) { - days -= daysInMonth; - monthLength = monthLength >> 1; - daysInMonth = 29 + (monthLength & 1); - hmonth++; - } - // remaining days is less than is in one month, thus is the day of the month we landed on - // hmonth-1 because in javascript months are zero based, stay consistent with that. - return [hyear, hmonth - 1, days + 1]; - } - } - }, - Hijri: { - name: "Hijri", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""], - namesAbbr: ["محرم","صفر","ربيع الأول","ربيع الثاني","جمادى الأولى","جمادى الثانية","رجب","شعبان","رمضان","شوال","ذو القعدة","ذو الحجة",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"بعد الهجرة","start":null,"offset":0}], - twoDigitYearMax: 1451, - patterns: { - d: "dd/MM/yy", - D: "dd/MM/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dd/MM/yyyy hh:mm tt", - F: "dd/MM/yyyy hh:mm:ss tt", - M: "dd MMMM" - }, - convert: { - // Adapted to Script from System.Globalization.HijriCalendar - ticks1970: 62135596800000, - // number of days leading up to each month - monthDays: [0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355], - minDate: -42521673600000, - maxDate: 253402300799999, - // The number of days to add or subtract from the calendar to accommodate the variances - // in the start and the end of Ramadan and to accommodate the date difference between - // countries/regions. May be dynamically adjusted based on user preference, but should - // remain in the range of -2 to 2, inclusive. - hijriAdjustment: 0, - toGregorian: function(hyear, hmonth, hday) { - var daysSinceJan0101 = this.daysToYear(hyear) + this.monthDays[hmonth] + hday - 1 - this.hijriAdjustment; - // 86400000 = ticks per day - var gdate = new Date(daysSinceJan0101 * 86400000 - this.ticks1970); - // adjust for timezone, because we are interested in the gregorian date for the same timezone - // but ticks in javascript is always from GMT, unlike the server were ticks counts from the base - // date in the current timezone. - gdate.setMinutes(gdate.getMinutes() + gdate.getTimezoneOffset()); - return gdate; - }, - fromGregorian: function(gdate) { - if ((gdate < this.minDate) || (gdate > this.maxDate)) return null; - var ticks = this.ticks1970 + (gdate-0) - gdate.getTimezoneOffset() * 60000, - daysSinceJan0101 = Math.floor(ticks / 86400000) + 1 + this.hijriAdjustment; - // very particular formula determined by someone smart, adapted from the server-side implementation. - // it approximates the hijri year. - var hday, hmonth, hyear = Math.floor(((daysSinceJan0101 - 227013) * 30) / 10631) + 1, - absDays = this.daysToYear(hyear), - daysInYear = this.isLeapYear(hyear) ? 355 : 354; - // hyear is just approximate, it may need adjustment up or down by 1. - if (daysSinceJan0101 < absDays) { - hyear--; - absDays -= daysInYear; - } - else if (daysSinceJan0101 === absDays) { - hyear--; - absDays = this.daysToYear(hyear); - } - else { - if (daysSinceJan0101 > (absDays + daysInYear)) { - absDays += daysInYear; - hyear++; - } - } - // determine month by looking at how many days into the hyear we are - // monthDays contains the number of days up to each month. - hmonth = 0; - var daysIntoYear = daysSinceJan0101 - absDays; - while (hmonth <= 11 && daysIntoYear > this.monthDays[hmonth]) { - hmonth++; - } - hmonth--; - hday = daysIntoYear - this.monthDays[hmonth]; - return [hyear, hmonth, hday]; - }, - daysToYear: function(year) { - // calculates how many days since Jan 1, 0001 - var yearsToYear30 = Math.floor((year - 1) / 30) * 30, - yearsInto30 = year - yearsToYear30 - 1, - days = Math.floor((yearsToYear30 * 10631) / 30) + 227013; - while (yearsInto30 > 0) { - days += (this.isLeapYear(yearsInto30) ? 355 : 354); - yearsInto30--; - } - return days; - }, - isLeapYear: function(year) { - return ((((year * 11) + 14) % 30) < 11); - } - } - }, - Gregorian_MiddleEastFrench: { - name: "Gregorian_MiddleEastFrench", - firstDay: 6, - days: { - names: ["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"], - namesAbbr: ["dim.","lun.","mar.","mer.","jeu.","ven.","sam."], - namesShort: ["di","lu","ma","me","je","ve","sa"] - }, - months: { - names: ["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre",""], - namesAbbr: ["janv.","févr.","mars","avr.","mai","juin","juil.","août","sept.","oct.","nov.","déc.",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"ap. J.-C.","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt", - M: "dd MMMM" - } - }, - Gregorian_Arabic: { - name: "Gregorian_Arabic", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""], - namesAbbr: ["كانون الثاني","شباط","آذار","نيسان","أيار","حزيران","تموز","آب","أيلول","تشرين الأول","تشرين الثاني","كانون الأول",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - }, - Gregorian_TransliteratedFrench: { - name: "Gregorian_TransliteratedFrench", - firstDay: 6, - days: { - names: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesAbbr: ["الأحد","الإثنين","الثلاثاء","الأربعاء","الخميس","الجمعة","السبت"], - namesShort: ["ح","ن","ث","ر","خ","ج","س"] - }, - months: { - names: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""], - namesAbbr: ["جانفييه","فيفرييه","مارس","أفريل","مي","جوان","جوييه","أوت","سبتمبر","اكتوبر","نوفمبر","ديسمبر",""] - }, - AM: ["ص","ص","ص"], - PM: ["م","م","م"], - eras: [{"name":"م","start":null,"offset":0}], - patterns: { - d: "MM/dd/yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, MMMM dd, yyyy hh:mm tt", - F: "dddd, MMMM dd, yyyy hh:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "en-IN", "default", { - name: "en-IN", - englishName: "English (India)", - nativeName: "English (India)", - numberFormat: { - groupSizes: [3,2], - percent: { - groupSizes: [3,2] - }, - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,2], - symbol: "Rs." - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "dd MMMM yyyy HH:mm", - F: "dd MMMM yyyy HH:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "es-BO", "default", { - name: "es-BO", - englishName: "Spanish (Bolivia)", - nativeName: "Español (Bolivia)", - language: "es", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["($ n)","$ n"], - ",": ".", - ".": ",", - symbol: "$b" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "en-MY", "default", { - name: "en-MY", - englishName: "English (Malaysia)", - nativeName: "English (Malaysia)", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - }, - currency: { - symbol: "RM" - } - }, - calendars: { - standard: { - days: { - namesShort: ["S","M","T","W","T","F","S"] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd, d MMMM, yyyy", - f: "dddd, d MMMM, yyyy h:mm tt", - F: "dddd, d MMMM, yyyy h:mm:ss tt", - M: "d MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "es-SV", "default", { - name: "es-SV", - englishName: "Spanish (El Salvador)", - nativeName: "Español (El Salvador)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "en-SG", "default", { - name: "en-SG", - englishName: "English (Singapore)", - nativeName: "English (Singapore)", - numberFormat: { - percent: { - pattern: ["-n%","n%"] - } - }, - calendars: { - standard: { - days: { - namesShort: ["S","M","T","W","T","F","S"] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd, d MMMM, yyyy", - f: "dddd, d MMMM, yyyy h:mm tt", - F: "dddd, d MMMM, yyyy h:mm:ss tt", - M: "d MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "es-HN", "default", { - name: "es-HN", - englishName: "Spanish (Honduras)", - nativeName: "Español (Honduras)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - pattern: ["$ -n","$ n"], - groupSizes: [3,0], - symbol: "L." - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-NI", "default", { - name: "es-NI", - englishName: "Spanish (Nicaragua)", - nativeName: "Español (Nicaragua)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - pattern: ["($ n)","$ n"], - groupSizes: [3,0], - symbol: "C$" - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-PR", "default", { - name: "es-PR", - englishName: "Spanish (Puerto Rico)", - nativeName: "Español (Puerto Rico)", - language: "es", - numberFormat: { - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - currency: { - pattern: ["($ n)","$ n"], - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sá"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - AM: ["a.m.","a.m.","A.M."], - PM: ["p.m.","p.m.","P.M."], - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - d: "dd/MM/yyyy", - D: "dddd, dd' de 'MMMM' de 'yyyy", - t: "hh:mm tt", - T: "hh:mm:ss tt", - f: "dddd, dd' de 'MMMM' de 'yyyy hh:mm tt", - F: "dddd, dd' de 'MMMM' de 'yyyy hh:mm:ss tt", - M: "dd MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "es-US", "default", { - name: "es-US", - englishName: "Spanish (United States)", - nativeName: "Español (Estados Unidos)", - language: "es", - numberFormat: { - groupSizes: [3,0], - "NaN": "NeuN", - negativeInfinity: "-Infinito", - positiveInfinity: "Infinito", - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["domingo","lunes","martes","miércoles","jueves","viernes","sábado"], - namesAbbr: ["dom","lun","mar","mié","jue","vie","sáb"], - namesShort: ["do","lu","ma","mi","ju","vi","sa"] - }, - months: { - names: ["enero","febrero","marzo","abril","mayo","junio","julio","agosto","septiembre","octubre","noviembre","diciembre",""], - namesAbbr: ["ene","feb","mar","abr","may","jun","jul","ago","sep","oct","nov","dic",""] - }, - eras: [{"name":"d.C.","start":null,"offset":0}], - patterns: { - M: "dd' de 'MMMM", - Y: "MMMM' de 'yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "bs-Cyrl", "default", { - name: "bs-Cyrl", - englishName: "Bosnian (Cyrillic)", - nativeName: "босански", - language: "bs-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "КМ" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недјеља","понедјељак","уторак","сриједа","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["н","п","у","с","ч","п","с"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "bs-Latn", "default", { - name: "bs-Latn", - englishName: "Bosnian (Latin)", - nativeName: "bosanski", - language: "bs-Latn", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","juni","juli","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Cyrl", "default", { - name: "sr-Cyrl", - englishName: "Serbian (Cyrillic)", - nativeName: "српски", - language: "sr-Cyrl", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-бесконачност", - positiveInfinity: "+бесконачност", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Дин." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["недеља","понедељак","уторак","среда","четвртак","петак","субота"], - namesAbbr: ["нед","пон","уто","сре","чет","пет","суб"], - namesShort: ["не","по","ут","ср","че","пе","су"] - }, - months: { - names: ["јануар","фебруар","март","април","мај","јун","јул","август","септембар","октобар","новембар","децембар",""], - namesAbbr: ["јан","феб","мар","апр","мај","јун","јул","авг","сеп","окт","нов","дец",""] - }, - AM: null, - PM: null, - eras: [{"name":"н.е.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr-Latn", "default", { - name: "sr-Latn", - englishName: "Serbian (Latin)", - nativeName: "srpski", - language: "sr-Latn", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-beskonačnost", - positiveInfinity: "+beskonačnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Din." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sre","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"n.e.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "smn", "default", { - name: "smn", - englishName: "Sami (Inari)", - nativeName: "sämikielâ", - language: "smn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pasepeivi","vuossargâ","majebargâ","koskokko","tuorâstâh","vástuppeivi","lávárdâh"], - namesAbbr: ["pa","vu","ma","ko","tu","vá","lá"], - namesShort: ["p","v","m","k","t","v","l"] - }, - months: { - names: ["uđđâivemáánu","kuovâmáánu","njuhčâmáánu","cuáŋuimáánu","vyesimáánu","kesimáánu","syeinimáánu","porgemáánu","čohčâmáánu","roovvâdmáánu","skammâmáánu","juovlâmáánu",""], - namesAbbr: ["uđiv","kuov","njuh","cuoŋ","vyes","kesi","syei","porg","čoh","roov","ska","juov",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "az-Cyrl", "default", { - name: "az-Cyrl", - englishName: "Azeri (Cyrillic)", - nativeName: "Азәрбајҹан дили", - language: "az-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "ман." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Базар","Базар ертәси","Чәршәнбә ахшамы","Чәршәнбә","Ҹүмә ахшамы","Ҹүмә","Шәнбә"], - namesAbbr: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"], - namesShort: ["Б","Бе","Ча","Ч","Ҹа","Ҹ","Ш"] - }, - months: { - names: ["Јанвар","Феврал","Март","Апрел","Мај","Ијун","Ијул","Август","Сентјабр","Октјабр","Нојабр","Декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","Мај","Ијун","Ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["јанвар","феврал","март","апрел","мај","ијун","ијул","август","сентјабр","октјабр","нојабр","декабр",""], - namesAbbr: ["Јан","Фев","Мар","Апр","мая","ијун","ијул","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sms", "default", { - name: "sms", - englishName: "Sami (Skolt)", - nativeName: "sääm´ǩiõll", - language: "sms", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["pâ´sspei´vv","vuõssargg","mââibargg","seärad","nelljdpei´vv","piâtnâc","sue´vet"], - namesAbbr: ["pâ","vu","mâ","se","ne","pi","su"], - namesShort: ["p","v","m","s","n","p","s"] - }, - months: { - names: ["ođđee´jjmään","tä´lvvmään","pâ´zzlâšttammään","njuhččmään","vue´ssmään","ǩie´ssmään","suei´nnmään","på´rǧǧmään","čõhččmään","kålggmään","skamm´mään","rosttovmään",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - monthsGenitive: { - names: ["ođđee´jjmannu","tä´lvvmannu","pâ´zzlâšttammannu","njuhččmannu","vue´ssmannu","ǩie´ssmannu","suei´nnmannu","på´rǧǧmannu","čõhččmannu","kålggmannu","skamm´mannu","rosttovmannu",""], - namesAbbr: ["ođjm","tä´lvv","pâzl","njuh","vue","ǩie","suei","på´r","čõh","kålg","ska","rost",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "MMMM d'. p. 'yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "MMMM d'. p. 'yyyy H:mm", - F: "MMMM d'. p. 'yyyy H:mm:ss", - M: "MMMM d'. p. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "zh", "default", { - name: "zh", - englishName: "Chinese", - nativeName: "中文", - language: "zh", - numberFormat: { - "NaN": "非数字", - negativeInfinity: "负无穷大", - positiveInfinity: "正无穷大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["周日","周一","周二","周三","周四","周五","周六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "nn", "default", { - name: "nn", - englishName: "Norwegian (Nynorsk)", - nativeName: "norsk (nynorsk)", - language: "nn", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","måndag","tysdag","onsdag","torsdag","fredag","laurdag"], - namesAbbr: ["sø","må","ty","on","to","fr","la"], - namesShort: ["sø","må","ty","on","to","fr","la"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "bs", "default", { - name: "bs", - englishName: "Bosnian", - nativeName: "bosanski", - language: "bs", - numberFormat: { - ",": ".", - ".": ",", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "KM" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedjelja","ponedjeljak","utorak","srijeda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sri","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","juni","juli","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "az-Latn", "default", { - name: "az-Latn", - englishName: "Azeri (Latin)", - nativeName: "Azərbaycan\xadılı", - language: "az-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "man." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Bazar","Bazar ertəsi","Çərşənbə axşamı","Çərşənbə","Cümə axşamı","Cümə","Şənbə"], - namesAbbr: ["B","Be","Ça","Ç","Ca","C","Ş"], - namesShort: ["B","Be","Ça","Ç","Ca","C","Ş"] - }, - months: { - names: ["Yanvar","Fevral","Mart","Aprel","May","İyun","İyul","Avgust","Sentyabr","Oktyabr","Noyabr","Dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - monthsGenitive: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["Yan","Fev","Mar","Apr","May","İyun","İyul","Avg","Sen","Okt","Noy","Dek",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - M: "d MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sma", "default", { - name: "sma", - englishName: "Sami (Southern)", - nativeName: "åarjelsaemiengiele", - language: "sma", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["aejlege","måanta","dæjsta","gaskevåhkoe","duarsta","bearjadahke","laavvardahke"], - namesAbbr: ["aej","måa","dæj","gask","duar","bearj","laav"], - namesShort: ["a","m","d","g","d","b","l"] - }, - months: { - names: ["tsïengele","goevte","njoktje","voerhtje","suehpede","ruffie","snjaltje","mïetske","skïerede","golke","rahka","goeve",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - monthsGenitive: { - names: ["tsïengelen","goevten","njoktjen","voerhtjen","suehpeden","ruffien","snjaltjen","mïetsken","skïereden","golken","rahkan","goeven",""], - namesAbbr: ["tsïen","goevt","njok","voer","sueh","ruff","snja","mïet","skïer","golk","rahk","goev",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "uz-Cyrl", "default", { - name: "uz-Cyrl", - englishName: "Uzbek (Cyrillic)", - nativeName: "Ўзбек", - language: "uz-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": " ", - ".": ",", - symbol: "сўм" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["якшанба","душанба","сешанба","чоршанба","пайшанба","жума","шанба"], - namesAbbr: ["якш","дш","сш","чш","пш","ж","ш"], - namesShort: ["я","д","с","ч","п","ж","ш"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январ","феврал","март","апрел","май","июн","июл","август","сентябр","октябр","ноябр","декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","мая","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "yyyy 'йил' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'йил' d-MMMM HH:mm", - F: "yyyy 'йил' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "mn-Cyrl", "default", { - name: "mn-Cyrl", - englishName: "Mongolian (Cyrillic)", - nativeName: "Монгол хэл", - language: "mn-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n$","n$"], - ",": " ", - ".": ",", - symbol: "₮" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["Ням","Даваа","Мягмар","Лхагва","Пүрэв","Баасан","Бямба"], - namesAbbr: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"], - namesShort: ["Ня","Да","Мя","Лх","Пү","Ба","Бя"] - }, - months: { - names: ["1 дүгээр сар","2 дугаар сар","3 дугаар сар","4 дүгээр сар","5 дугаар сар","6 дугаар сар","7 дугаар сар","8 дугаар сар","9 дүгээр сар","10 дугаар сар","11 дүгээр сар","12 дугаар сар",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - monthsGenitive: { - names: ["1 дүгээр сарын","2 дугаар сарын","3 дугаар сарын","4 дүгээр сарын","5 дугаар сарын","6 дугаар сарын","7 дугаар сарын","8 дугаар сарын","9 дүгээр сарын","10 дугаар сарын","11 дүгээр сарын","12 дугаар сарын",""], - namesAbbr: ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI","XII",""] - }, - AM: null, - PM: null, - patterns: { - d: "yy.MM.dd", - D: "yyyy 'оны' MMMM d", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy 'оны' MMMM d H:mm", - F: "yyyy 'оны' MMMM d H:mm:ss", - M: "d MMMM", - Y: "yyyy 'он' MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "iu-Cans", "default", { - name: "iu-Cans", - englishName: "Inuktitut (Syllabics)", - nativeName: "ᐃᓄᒃᑎᑐᑦ", - language: "iu-Cans", - numberFormat: { - groupSizes: [3,0], - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["ᓈᑦᑏᖑᔭ","ᓇᒡᒐᔾᔭᐅ","ᐊᐃᑉᐱᖅ","ᐱᖓᑦᓯᖅ","ᓯᑕᒻᒥᖅ","ᑕᓪᓕᕐᒥᖅ","ᓯᕙᑖᕐᕕᒃ"], - namesAbbr: ["ᓈᑦᑏ","ᓇᒡᒐ","ᐊᐃᑉᐱ","ᐱᖓᑦᓯ","ᓯᑕ","ᑕᓪᓕ","ᓯᕙᑖᕐᕕᒃ"], - namesShort: ["ᓈ","ᓇ","ᐊ","ᐱ","ᓯ","ᑕ","ᓯ"] - }, - months: { - names: ["ᔮᓐᓄᐊᕆ","ᕖᕝᕗᐊᕆ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌᓯ","ᓯᑎᐱᕆ","ᐅᑐᐱᕆ","ᓄᕕᐱᕆ","ᑎᓯᐱᕆ",""], - namesAbbr: ["ᔮᓐᓄ","ᕖᕝᕗ","ᒫᑦᓯ","ᐄᐳᕆ","ᒪᐃ","ᔫᓂ","ᔪᓚᐃ","ᐋᒡᒌ","ᓯᑎᐱ","ᐅᑐᐱ","ᓄᕕᐱ","ᑎᓯᐱ",""] - }, - patterns: { - d: "d/M/yyyy", - D: "dddd,MMMM dd,yyyy", - f: "dddd,MMMM dd,yyyy h:mm tt", - F: "dddd,MMMM dd,yyyy h:mm:ss tt", - Y: "MMMM,yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "zh-Hant", "default", { - name: "zh-Hant", - englishName: "Chinese (Traditional)", - nativeName: "中文(繁體)", - language: "zh-Hant", - numberFormat: { - "NaN": "非數字", - negativeInfinity: "負無窮大", - positiveInfinity: "正無窮大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - symbol: "HK$" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["週日","週一","週二","週三","週四","週五","週六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "nb", "default", { - name: "nb", - englishName: "Norwegian (Bokmål)", - nativeName: "norsk (bokmål)", - language: "nb", - numberFormat: { - ",": " ", - ".": ",", - negativeInfinity: "-INF", - positiveInfinity: "INF", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["$ -n","$ n"], - ",": " ", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"], - namesAbbr: ["sø","ma","ti","on","to","fr","lø"], - namesShort: ["sø","ma","ti","on","to","fr","lø"] - }, - months: { - names: ["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember",""], - namesAbbr: ["jan","feb","mar","apr","mai","jun","jul","aug","sep","okt","nov","des",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yyyy", - D: "d. MMMM yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "d. MMMM yyyy HH:mm", - F: "d. MMMM yyyy HH:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "sr", "default", { - name: "sr", - englishName: "Serbian", - nativeName: "srpski", - language: "sr", - numberFormat: { - ",": ".", - ".": ",", - negativeInfinity: "-beskonačnost", - positiveInfinity: "+beskonačnost", - percent: { - pattern: ["-n%","n%"], - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "Din." - } - }, - calendars: { - standard: { - "/": ".", - firstDay: 1, - days: { - names: ["nedelja","ponedeljak","utorak","sreda","četvrtak","petak","subota"], - namesAbbr: ["ned","pon","uto","sre","čet","pet","sub"], - namesShort: ["ne","po","ut","sr","če","pe","su"] - }, - months: { - names: ["januar","februar","mart","april","maj","jun","jul","avgust","septembar","oktobar","novembar","decembar",""], - namesAbbr: ["jan","feb","mar","apr","maj","jun","jul","avg","sep","okt","nov","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"n.e.","start":null,"offset":0}], - patterns: { - d: "d.M.yyyy", - D: "d. MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d. MMMM yyyy H:mm", - F: "d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "tg-Cyrl", "default", { - name: "tg-Cyrl", - englishName: "Tajik (Cyrillic)", - nativeName: "Тоҷикӣ", - language: "tg-Cyrl", - numberFormat: { - ",": " ", - ".": ",", - groupSizes: [3,0], - negativeInfinity: "-бесконечность", - positiveInfinity: "бесконечность", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - groupSizes: [3,0], - ",": " ", - ".": ";", - symbol: "т.р." - } - }, - calendars: { - standard: { - "/": ".", - days: { - names: ["Яш","Душанбе","Сешанбе","Чоршанбе","Панҷшанбе","Ҷумъа","Шанбе"], - namesAbbr: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"], - namesShort: ["Яш","Дш","Сш","Чш","Пш","Ҷм","Шн"] - }, - months: { - names: ["Январ","Феврал","Март","Апрел","Май","Июн","Июл","Август","Сентябр","Октябр","Ноябр","Декабр",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - monthsGenitive: { - names: ["январи","феврали","марти","апрели","маи","июни","июли","августи","сентябри","октябри","ноябри","декабри",""], - namesAbbr: ["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd.MM.yy", - D: "d MMMM yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "d MMMM yyyy H:mm", - F: "d MMMM yyyy H:mm:ss", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "dsb", "default", { - name: "dsb", - englishName: "Lower Sorbian", - nativeName: "dolnoserbšćina", - language: "dsb", - numberFormat: { - ",": ".", - ".": ",", - "NaN": "njedefinowane", - negativeInfinity: "-njekońcne", - positiveInfinity: "+njekońcne", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "€" - } - }, - calendars: { - standard: { - "/": ". ", - firstDay: 1, - days: { - names: ["njeźela","ponjeźele","wałtora","srjoda","stwortk","pětk","sobota"], - namesAbbr: ["nje","pon","wał","srj","stw","pět","sob"], - namesShort: ["n","p","w","s","s","p","s"] - }, - months: { - names: ["januar","februar","měrc","apryl","maj","junij","julij","awgust","september","oktober","nowember","december",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - monthsGenitive: { - names: ["januara","februara","měrca","apryla","maja","junija","julija","awgusta","septembra","oktobra","nowembra","decembra",""], - namesAbbr: ["jan","feb","měr","apr","maj","jun","jul","awg","sep","okt","now","dec",""] - }, - AM: null, - PM: null, - eras: [{"name":"po Chr.","start":null,"offset":0}], - patterns: { - d: "d. M. yyyy", - D: "dddd, 'dnja' d. MMMM yyyy", - t: "H.mm 'goź.'", - T: "H:mm:ss", - f: "dddd, 'dnja' d. MMMM yyyy H.mm 'goź.'", - F: "dddd, 'dnja' d. MMMM yyyy H:mm:ss", - M: "d. MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "smj", "default", { - name: "smj", - englishName: "Sami (Lule)", - nativeName: "julevusámegiella", - language: "smj", - numberFormat: { - ",": " ", - ".": ",", - percent: { - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - ",": ".", - ".": ",", - symbol: "kr" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 1, - days: { - names: ["ájllek","mánnodahka","dijstahka","gasskavahkko","duorastahka","bierjjedahka","lávvodahka"], - namesAbbr: ["ájl","mán","dis","gas","duor","bier","láv"], - namesShort: ["á","m","d","g","d","b","l"] - }, - months: { - names: ["ådåjakmánno","guovvamánno","sjnjuktjamánno","vuoratjismánno","moarmesmánno","biehtsemánno","sjnjilltjamánno","bårggemánno","ragátmánno","gålgådismánno","basádismánno","javllamánno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - monthsGenitive: { - names: ["ådåjakmáno","guovvamáno","sjnjuktjamáno","vuoratjismáno","moarmesmáno","biehtsemáno","sjnjilltjamáno","bårggemáno","ragátmáno","gålgådismáno","basádismáno","javllamáno",""], - namesAbbr: ["ådåj","guov","snju","vuor","moar","bieh","snji","bårg","ragá","gålg","basá","javl",""] - }, - AM: null, - PM: null, - patterns: { - d: "yyyy-MM-dd", - D: "MMMM d'. b. 'yyyy", - t: "HH:mm", - T: "HH:mm:ss", - f: "MMMM d'. b. 'yyyy HH:mm", - F: "MMMM d'. b. 'yyyy HH:mm:ss", - M: "MMMM d'. b. '", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "uz-Latn", "default", { - name: "uz-Latn", - englishName: "Uzbek (Latin)", - nativeName: "U'zbek", - language: "uz-Latn", - numberFormat: { - ",": " ", - ".": ",", - percent: { - pattern: ["-n%","n%"], - ",": " ", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - decimals: 0, - ",": " ", - ".": ",", - symbol: "so'm" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["yakshanba","dushanba","seshanba","chorshanba","payshanba","juma","shanba"], - namesAbbr: ["yak.","dsh.","sesh.","chr.","psh.","jm.","sh."], - namesShort: ["ya","d","s","ch","p","j","sh"] - }, - months: { - names: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""], - namesAbbr: ["yanvar","fevral","mart","aprel","may","iyun","iyul","avgust","sentyabr","oktyabr","noyabr","dekabr",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd/MM yyyy", - D: "yyyy 'yil' d-MMMM", - t: "HH:mm", - T: "HH:mm:ss", - f: "yyyy 'yil' d-MMMM HH:mm", - F: "yyyy 'yil' d-MMMM HH:mm:ss", - M: "d-MMMM", - Y: "MMMM yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "mn-Mong", "default", { - name: "mn-Mong", - englishName: "Mongolian (Traditional Mongolian)", - nativeName: "ᠮᠤᠨᠭᠭᠤᠯ ᠬᠡᠯᠡ", - language: "mn-Mong", - numberFormat: { - groupSizes: [3,0], - "NaN": "ᠲᠤᠭᠠᠠ ᠪᠤᠰᠤ", - negativeInfinity: "ᠰᠦᠬᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠡᠬᠡ", - positiveInfinity: "ᠡᠶ᠋ᠡᠷᠬᠦ ᠬᠢᠵᠠᠭᠠᠷᠭᠦᠢ ᠶᠠᠬᠡ", - percent: { - pattern: ["-n%","n%"], - groupSizes: [3,0] - }, - currency: { - pattern: ["$-n","$n"], - groupSizes: [3,0], - symbol: "¥" - } - }, - calendars: { - standard: { - firstDay: 1, - days: { - names: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesAbbr: ["ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠡᠳᠦᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠨᠢᠭᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠬᠣᠶᠠᠷ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠭᠤᠷᠪᠠᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠳᠥᠷᠪᠡᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠲᠠᠪᠤᠨ","ᠭᠠᠷᠠᠭ\u202fᠤᠨ ᠵᠢᠷᠭᠤᠭᠠᠨ"], - namesShort: ["ᠡ\u200d","ᠨᠢ\u200d","ᠬᠣ\u200d","ᠭᠤ\u200d","ᠳᠥ\u200d","ᠲᠠ\u200d","ᠵᠢ\u200d"] - }, - months: { - names: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""], - namesAbbr: ["ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠭᠤᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠦᠷᠪᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠠᠪᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠵᠢᠷᠭᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠲᠤᠯᠤᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠨᠠᠢᠮᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠶᠢᠰᠦᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠨᠢᠭᠡᠳᠦᠭᠡᠷ ᠰᠠᠷ᠎ᠠ","ᠠᠷᠪᠠᠨ ᠬᠤᠶ᠋ᠠᠳᠤᠭᠠᠷ ᠰᠠᠷ᠎ᠠ",""] - }, - AM: null, - PM: null, - eras: [{"name":"ᠣᠨ ᠲᠣᠭᠠᠯᠠᠯ ᠤᠨ","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm", - F: "yyyy'ᠣᠨ ᠤ᠋' M'ᠰᠠᠷ᠎ᠠ \u202fᠢᠢᠨ 'd' ᠤ᠋ ᠡᠳᠦᠷ' H:mm:ss", - M: "M'ᠰᠠᠷ᠎ᠠ' d'ᠡᠳᠦᠷ'", - Y: "yyyy'ᠣᠨ' M'ᠰᠠᠷ᠎ᠠ'" - } - } - } -}); - -Globalize.addCultureInfo( "iu-Latn", "default", { - name: "iu-Latn", - englishName: "Inuktitut (Latin)", - nativeName: "Inuktitut", - language: "iu-Latn", - numberFormat: { - groupSizes: [3,0], - percent: { - groupSizes: [3,0] - } - }, - calendars: { - standard: { - days: { - names: ["Naattiinguja","Naggajjau","Aippiq","Pingatsiq","Sitammiq","Tallirmiq","Sivataarvik"], - namesAbbr: ["Nat","Nag","Aip","Pi","Sit","Tal","Siv"], - namesShort: ["N","N","A","P","S","T","S"] - }, - months: { - names: ["Jaannuari","Viivvuari","Maatsi","Iipuri","Mai","Juuni","Julai","Aaggiisi","Sitipiri","Utupiri","Nuvipiri","Tisipiri",""], - namesAbbr: ["Jan","Viv","Mas","Ipu","Mai","Jun","Jul","Agi","Sii","Uut","Nuv","Tis",""] - }, - patterns: { - d: "d/MM/yyyy", - D: "ddd, MMMM dd,yyyy", - f: "ddd, MMMM dd,yyyy h:mm tt", - F: "ddd, MMMM dd,yyyy h:mm:ss tt" - } - } - } -}); - -Globalize.addCultureInfo( "tzm-Latn", "default", { - name: "tzm-Latn", - englishName: "Tamazight (Latin)", - nativeName: "Tamazight", - language: "tzm-Latn", - numberFormat: { - pattern: ["n-"], - ",": ".", - ".": ",", - "NaN": "Non Numérique", - negativeInfinity: "-Infini", - positiveInfinity: "+Infini", - percent: { - ",": ".", - ".": "," - }, - currency: { - pattern: ["-n $","n $"], - symbol: "DZD" - } - }, - calendars: { - standard: { - "/": "-", - firstDay: 6, - days: { - names: ["Acer","Arime","Aram","Ahad","Amhadh","Sem","Sedh"], - namesAbbr: ["Ace","Ari","Ara","Aha","Amh","Sem","Sed"], - namesShort: ["Ac","Ar","Ar","Ah","Am","Se","Se"] - }, - months: { - names: ["Yenayer","Furar","Maghres","Yebrir","Mayu","Yunyu","Yulyu","Ghuct","Cutenber","Ktuber","Wambir","Dujanbir",""], - namesAbbr: ["Yen","Fur","Mag","Yeb","May","Yun","Yul","Ghu","Cut","Ktu","Wam","Duj",""] - }, - AM: null, - PM: null, - patterns: { - d: "dd-MM-yyyy", - D: "dd MMMM, yyyy", - t: "H:mm", - T: "H:mm:ss", - f: "dd MMMM, yyyy H:mm", - F: "dd MMMM, yyyy H:mm:ss", - M: "dd MMMM" - } - } - } -}); - -Globalize.addCultureInfo( "ha-Latn", "default", { - name: "ha-Latn", - englishName: "Hausa (Latin)", - nativeName: "Hausa", - language: "ha-Latn", - numberFormat: { - currency: { - pattern: ["$-n","$ n"], - symbol: "N" - } - }, - calendars: { - standard: { - days: { - names: ["Lahadi","Litinin","Talata","Laraba","Alhamis","Juma'a","Asabar"], - namesAbbr: ["Lah","Lit","Tal","Lar","Alh","Jum","Asa"], - namesShort: ["L","L","T","L","A","J","A"] - }, - months: { - names: ["Januwaru","Febreru","Maris","Afrilu","Mayu","Yuni","Yuli","Agusta","Satumba","Oktocba","Nuwamba","Disamba",""], - namesAbbr: ["Jan","Feb","Mar","Afr","May","Yun","Yul","Agu","Sat","Okt","Nuw","Dis",""] - }, - AM: ["Safe","safe","SAFE"], - PM: ["Yamma","yamma","YAMMA"], - eras: [{"name":"AD","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy" - } - } - } -}); - -Globalize.addCultureInfo( "zh-CHS", "default", { - name: "zh-CHS", - englishName: "Chinese (Simplified) Legacy", - nativeName: "中文(简体) 旧版", - language: "zh-CHS", - numberFormat: { - "NaN": "非数字", - negativeInfinity: "负无穷大", - positiveInfinity: "正无穷大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - pattern: ["$-n","$n"], - symbol: "¥" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["周日","周一","周二","周三","周四","周五","周六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "yyyy/M/d", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -Globalize.addCultureInfo( "zh-CHT", "default", { - name: "zh-CHT", - englishName: "Chinese (Traditional) Legacy", - nativeName: "中文(繁體) 舊版", - language: "zh-CHT", - numberFormat: { - "NaN": "非數字", - negativeInfinity: "負無窮大", - positiveInfinity: "正無窮大", - percent: { - pattern: ["-n%","n%"] - }, - currency: { - symbol: "HK$" - } - }, - calendars: { - standard: { - days: { - names: ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"], - namesAbbr: ["週日","週一","週二","週三","週四","週五","週六"], - namesShort: ["日","一","二","三","四","五","六"] - }, - months: { - names: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""], - namesAbbr: ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月",""] - }, - AM: ["上午","上午","上午"], - PM: ["下午","下午","下午"], - eras: [{"name":"公元","start":null,"offset":0}], - patterns: { - d: "d/M/yyyy", - D: "yyyy'年'M'月'd'日'", - t: "H:mm", - T: "H:mm:ss", - f: "yyyy'年'M'月'd'日' H:mm", - F: "yyyy'年'M'月'd'日' H:mm:ss", - M: "M'月'd'日'", - Y: "yyyy'年'M'月'" - } - } - } -}); - -}( this )); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-2.1.1.intellisense.js b/src/Presentation/SmartStore.Web/Scripts/jquery-2.1.1.intellisense.js new file mode 100644 index 0000000000..a88b6c6e3f --- /dev/null +++ b/src/Presentation/SmartStore.Web/Scripts/jquery-2.1.1.intellisense.js @@ -0,0 +1,2670 @@ +intellisense.annotate(jQuery, { + 'ajax': function() { + /// + /// Perform an asynchronous HTTP (Ajax) request. + /// A string containing the URL to which the request is sent. + /// A set of key/value pairs that configure the Ajax request. All settings are optional. A default can be set for any option with $.ajaxSetup(). See jQuery.ajax( settings ) below for a complete list of all settings. + /// + /// + /// + /// Perform an asynchronous HTTP (Ajax) request. + /// A set of key/value pairs that configure the Ajax request. All settings are optional. A default can be set for any option with $.ajaxSetup(). + /// + /// + }, + 'ajaxPrefilter': function() { + /// + /// Handle custom Ajax options or modify existing options before each request is sent and before they are processed by $.ajax(). + /// An optional string containing one or more space-separated dataTypes + /// A handler to set default values for future Ajax requests. + /// + }, + 'ajaxSetup': function() { + /// + /// Set default values for future Ajax requests. Its use is not recommended. + /// A set of key/value pairs that configure the default Ajax request. All options are optional. + /// + }, + 'ajaxTransport': function() { + /// + /// Creates an object that handles the actual transmission of Ajax data. + /// A string identifying the data type to use + /// A handler to return the new transport object to use with the data type provided in the first argument. + /// + }, + 'boxModel': function() { + /// Deprecated in jQuery 1.3 (see jQuery.support). States if the current page, in the user's browser, is being rendered using the W3C CSS Box Model. + /// + }, + 'browser': function() { + /// Contains flags for the useragent, read from navigator.userAgent. This property was removed in jQuery 1.9 and is available only through the jQuery.migrate plugin. Please try to use feature detection instead. + /// + }, + 'browser.version': function() { + /// The version number of the rendering engine for the user's browser. This property was removed in jQuery 1.9 and is available only through the jQuery.migrate plugin. + /// + }, + 'Callbacks': function() { + /// + /// A multi-purpose callbacks list object that provides a powerful way to manage callback lists. + /// An optional list of space-separated flags that change how the callback list behaves. + /// + /// + }, + 'contains': function() { + /// + /// Check to see if a DOM element is a descendant of another DOM element. + /// The DOM element that may contain the other element. + /// The DOM element that may be contained by (a descendant of) the other element. + /// + /// + }, + 'cssHooks': function() { + /// Hook directly into jQuery to override how particular CSS properties are retrieved or set, normalize CSS property naming, or create custom properties. + /// + }, + 'data': function() { + /// + /// Returns value at named data store for the element, as set by jQuery.data(element, name, value), or the full data store for the element. + /// The DOM element to query for the data. + /// Name of the data stored. + /// + /// + /// + /// Returns value at named data store for the element, as set by jQuery.data(element, name, value), or the full data store for the element. + /// The DOM element to query for the data. + /// + /// + }, + 'Deferred': function() { + /// + /// A constructor function that returns a chainable utility object with methods to register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function. + /// A function that is called just before the constructor returns. + /// + /// + }, + 'dequeue': function() { + /// + /// Execute the next function on the queue for the matched element. + /// A DOM element from which to remove and execute a queued function. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// + }, + 'each': function() { + /// + /// A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1. Other objects are iterated via their named properties. + /// The object or array to iterate over. + /// The function that will be executed on every object. + /// + /// + }, + 'error': function() { + /// + /// Takes a string and throws an exception containing it. + /// The message to send out. + /// + }, + 'extend': function() { + /// + /// Merge the contents of two or more objects together into the first object. + /// An object that will receive the new properties if additional objects are passed in or that will extend the jQuery namespace if it is the sole argument. + /// An object containing additional properties to merge in. + /// Additional objects containing properties to merge in. + /// + /// + /// + /// Merge the contents of two or more objects together into the first object. + /// If true, the merge becomes recursive (aka. deep copy). + /// The object to extend. It will receive the new properties. + /// An object containing additional properties to merge in. + /// Additional objects containing properties to merge in. + /// + /// + }, + 'fn.extend': function() { + /// + /// Merge the contents of an object onto the jQuery prototype to provide new jQuery instance methods. + /// An object to merge onto the jQuery prototype. + /// + /// + }, + 'get': function() { + /// + /// Load data from the server using a HTTP GET request. + /// A string containing the URL to which the request is sent. + /// A plain object or string that is sent to the server with the request. + /// A callback function that is executed if the request succeeds. + /// The type of data expected from the server. Default: Intelligent Guess (xml, json, script, or html). + /// + /// + }, + 'getJSON': function() { + /// + /// Load JSON-encoded data from the server using a GET HTTP request. + /// A string containing the URL to which the request is sent. + /// A plain object or string that is sent to the server with the request. + /// A callback function that is executed if the request succeeds. + /// + /// + }, + 'getScript': function() { + /// + /// Load a JavaScript file from the server using a GET HTTP request, then execute it. + /// A string containing the URL to which the request is sent. + /// A callback function that is executed if the request succeeds. + /// + /// + }, + 'globalEval': function() { + /// + /// Execute some JavaScript code globally. + /// The JavaScript code to execute. + /// + }, + 'grep': function() { + /// + /// Finds the elements of an array which satisfy a filter function. The original array is not affected. + /// The array to search through. + /// The function to process each item against. The first argument to the function is the item, and the second argument is the index. The function should return a Boolean value. this will be the global window object. + /// If "invert" is false, or not provided, then the function returns an array consisting of all elements for which "callback" returns true. If "invert" is true, then the function returns an array consisting of all elements for which "callback" returns false. + /// + /// + }, + 'hasData': function() { + /// + /// Determine whether an element has any jQuery data associated with it. + /// A DOM element to be checked for data. + /// + /// + }, + 'holdReady': function() { + /// + /// Holds or releases the execution of jQuery's ready event. + /// Indicates whether the ready hold is being requested or released + /// + }, + 'inArray': function() { + /// + /// Search for a specified value within an array and return its index (or -1 if not found). + /// The value to search for. + /// An array through which to search. + /// The index of the array at which to begin the search. The default is 0, which will search the whole array. + /// + /// + }, + 'isArray': function() { + /// + /// Determine whether the argument is an array. + /// Object to test whether or not it is an array. + /// + /// + }, + 'isEmptyObject': function() { + /// + /// Check to see if an object is empty (contains no enumerable properties). + /// The object that will be checked to see if it's empty. + /// + /// + }, + 'isFunction': function() { + /// + /// Determine if the argument passed is a Javascript function object. + /// Object to test whether or not it is a function. + /// + /// + }, + 'isNumeric': function() { + /// + /// Determines whether its argument is a number. + /// The value to be tested. + /// + /// + }, + 'isPlainObject': function() { + /// + /// Check to see if an object is a plain object (created using "{}" or "new Object"). + /// The object that will be checked to see if it's a plain object. + /// + /// + }, + 'isWindow': function() { + /// + /// Determine whether the argument is a window. + /// Object to test whether or not it is a window. + /// + /// + }, + 'isXMLDoc': function() { + /// + /// Check to see if a DOM node is within an XML document (or is an XML document). + /// The DOM node that will be checked to see if it's in an XML document. + /// + /// + }, + 'makeArray': function() { + /// + /// Convert an array-like object into a true JavaScript array. + /// Any object to turn into a native Array. + /// + /// + }, + 'map': function() { + /// + /// Translate all items in an array or object to new array of items. + /// The Array to translate. + /// The function to process each item against. The first argument to the function is the array item, the second argument is the index in array The function can return any value. Within the function, this refers to the global (window) object. + /// + /// + /// + /// Translate all items in an array or object to new array of items. + /// The Array or Object to translate. + /// The function to process each item against. The first argument to the function is the value; the second argument is the index or key of the array or object property. The function can return any value to add to the array. A returned array will be flattened into the resulting array. Within the function, this refers to the global (window) object. + /// + /// + }, + 'merge': function() { + /// + /// Merge the contents of two arrays together into the first array. + /// The first array to merge, the elements of second added. + /// The second array to merge into the first, unaltered. + /// + /// + }, + 'noConflict': function() { + /// + /// Relinquish jQuery's control of the $ variable. + /// A Boolean indicating whether to remove all jQuery variables from the global scope (including jQuery itself). + /// + /// + }, + 'noop': function() { + /// An empty function. + }, + 'now': function() { + /// Return a number representing the current time. + /// + }, + 'param': function() { + /// + /// Create a serialized representation of an array or object, suitable for use in a URL query string or Ajax request. + /// An array or object to serialize. + /// + /// + /// + /// Create a serialized representation of an array or object, suitable for use in a URL query string or Ajax request. + /// An array or object to serialize. + /// A Boolean indicating whether to perform a traditional "shallow" serialization. + /// + /// + }, + 'parseHTML': function() { + /// + /// Parses a string into an array of DOM nodes. + /// HTML string to be parsed + /// Document element to serve as the context in which the HTML fragment will be created + /// A Boolean indicating whether to include scripts passed in the HTML string + /// + /// + }, + 'parseJSON': function() { + /// + /// Takes a well-formed JSON string and returns the resulting JavaScript object. + /// The JSON string to parse. + /// + /// + }, + 'parseXML': function() { + /// + /// Parses a string into an XML document. + /// a well-formed XML string to be parsed + /// + /// + }, + 'post': function() { + /// + /// Load data from the server using a HTTP POST request. + /// A string containing the URL to which the request is sent. + /// A plain object or string that is sent to the server with the request. + /// A callback function that is executed if the request succeeds. Required if dataType is provided, but can be null in that case. + /// The type of data expected from the server. Default: Intelligent Guess (xml, json, script, text, html). + /// + /// + }, + 'proxy': function() { + /// + /// Takes a function and returns a new one that will always have a particular context. + /// The function whose context will be changed. + /// The object to which the context (this) of the function should be set. + /// + /// + /// + /// Takes a function and returns a new one that will always have a particular context. + /// The object to which the context of the function should be set. + /// The name of the function whose context will be changed (should be a property of the context object). + /// + /// + /// + /// Takes a function and returns a new one that will always have a particular context. + /// The function whose context will be changed. + /// The object to which the context (this) of the function should be set. + /// Any number of arguments to be passed to the function referenced in the function argument. + /// + /// + /// + /// Takes a function and returns a new one that will always have a particular context. + /// The object to which the context of the function should be set. + /// The name of the function whose context will be changed (should be a property of the context object). + /// Any number of arguments to be passed to the function named in the name argument. + /// + /// + }, + 'queue': function() { + /// + /// Manipulate the queue of functions to be executed on the matched element. + /// A DOM element where the array of queued functions is attached. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// An array of functions to replace the current queue contents. + /// + /// + /// + /// Manipulate the queue of functions to be executed on the matched element. + /// A DOM element on which to add a queued function. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// The new function to add to the queue. + /// + /// + }, + 'removeData': function() { + /// + /// Remove a previously-stored piece of data. + /// A DOM element from which to remove data. + /// A string naming the piece of data to remove. + /// + /// + }, + 'sub': function() { + /// Creates a new copy of jQuery whose properties and methods can be modified without affecting the original jQuery object. + /// + }, + 'support': function() { + /// A collection of properties that represent the presence of different browser features or bugs. Primarily intended for jQuery's internal use; specific properties may be removed when they are no longer needed internally to improve page startup performance. + /// + }, + 'trim': function() { + /// + /// Remove the whitespace from the beginning and end of a string. + /// The string to trim. + /// + /// + }, + 'type': function() { + /// + /// Determine the internal JavaScript [[Class]] of an object. + /// Object to get the internal JavaScript [[Class]] of. + /// + /// + }, + 'unique': function() { + /// + /// Sorts an array of DOM elements, in place, with the duplicates removed. Note that this only works on arrays of DOM elements, not strings or numbers. + /// The Array of DOM elements. + /// + /// + }, + 'when': function() { + /// + /// Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events. + /// One or more Deferred objects, or plain JavaScript objects. + /// + /// + }, +}); + +var _1228819969 = jQuery.Callbacks; +jQuery.Callbacks = function(flags) { +var _object = _1228819969(flags); +intellisense.annotate(_object, { + 'add': function() { + /// + /// Add a callback or a collection of callbacks to a callback list. + /// A function, or array of functions, that are to be added to the callback list. + /// + /// + }, + 'disable': function() { + /// Disable a callback list from doing anything more. + /// + }, + 'disabled': function() { + /// Determine if the callbacks list has been disabled. + /// + }, + 'empty': function() { + /// Remove all of the callbacks from a list. + /// + }, + 'fire': function() { + /// + /// Call all of the callbacks with the given arguments + /// The argument or list of arguments to pass back to the callback list. + /// + /// + }, + 'fired': function() { + /// Determine if the callbacks have already been called at least once. + /// + }, + 'fireWith': function() { + /// + /// Call all callbacks in a list with the given context and arguments. + /// A reference to the context in which the callbacks in the list should be fired. + /// An argument, or array of arguments, to pass to the callbacks in the list. + /// + /// + }, + 'has': function() { + /// + /// Determine whether a supplied callback is in a list + /// The callback to search for. + /// + /// + }, + 'lock': function() { + /// Lock a callback list in its current state. + /// + }, + 'locked': function() { + /// Determine if the callbacks list has been locked. + /// + }, + 'remove': function() { + /// + /// Remove a callback or a collection of callbacks from a callback list. + /// A function, or array of functions, that are to be removed from the callback list. + /// + /// + }, +}); + +return _object; +}; +intellisense.redirectDefinition(jQuery.Callbacks, _1228819969); + +var _731531622 = jQuery.Deferred; +jQuery.Deferred = function(func) { +var _object = _731531622(func); +intellisense.annotate(_object, { + 'always': function() { + /// + /// Add handlers to be called when the Deferred object is either resolved or rejected. + /// A function, or array of functions, that is called when the Deferred is resolved or rejected. + /// Optional additional functions, or arrays of functions, that are called when the Deferred is resolved or rejected. + /// + /// + }, + 'done': function() { + /// + /// Add handlers to be called when the Deferred object is resolved. + /// A function, or array of functions, that are called when the Deferred is resolved. + /// Optional additional functions, or arrays of functions, that are called when the Deferred is resolved. + /// + /// + }, + 'fail': function() { + /// + /// Add handlers to be called when the Deferred object is rejected. + /// A function, or array of functions, that are called when the Deferred is rejected. + /// Optional additional functions, or arrays of functions, that are called when the Deferred is rejected. + /// + /// + }, + 'isRejected': function() { + /// Determine whether a Deferred object has been rejected. + /// + }, + 'isResolved': function() { + /// Determine whether a Deferred object has been resolved. + /// + }, + 'notify': function() { + /// + /// Call the progressCallbacks on a Deferred object with the given args. + /// Optional arguments that are passed to the progressCallbacks. + /// + /// + }, + 'notifyWith': function() { + /// + /// Call the progressCallbacks on a Deferred object with the given context and args. + /// Context passed to the progressCallbacks as the this object. + /// Optional arguments that are passed to the progressCallbacks. + /// + /// + }, + 'pipe': function() { + /// + /// Utility method to filter and/or chain Deferreds. + /// An optional function that is called when the Deferred is resolved. + /// An optional function that is called when the Deferred is rejected. + /// + /// + /// + /// Utility method to filter and/or chain Deferreds. + /// An optional function that is called when the Deferred is resolved. + /// An optional function that is called when the Deferred is rejected. + /// An optional function that is called when progress notifications are sent to the Deferred. + /// + /// + }, + 'progress': function() { + /// + /// Add handlers to be called when the Deferred object generates progress notifications. + /// A function, or array of functions, to be called when the Deferred generates progress notifications. + /// + /// + }, + 'promise': function() { + /// + /// Return a Deferred's Promise object. + /// Object onto which the promise methods have to be attached + /// + /// + }, + 'reject': function() { + /// + /// Reject a Deferred object and call any failCallbacks with the given args. + /// Optional arguments that are passed to the failCallbacks. + /// + /// + }, + 'rejectWith': function() { + /// + /// Reject a Deferred object and call any failCallbacks with the given context and args. + /// Context passed to the failCallbacks as the this object. + /// An optional array of arguments that are passed to the failCallbacks. + /// + /// + }, + 'resolve': function() { + /// + /// Resolve a Deferred object and call any doneCallbacks with the given args. + /// Optional arguments that are passed to the doneCallbacks. + /// + /// + }, + 'resolveWith': function() { + /// + /// Resolve a Deferred object and call any doneCallbacks with the given context and args. + /// Context passed to the doneCallbacks as the this object. + /// An optional array of arguments that are passed to the doneCallbacks. + /// + /// + }, + 'state': function() { + /// Determine the current state of a Deferred object. + /// + }, + 'then': function() { + /// + /// Add handlers to be called when the Deferred object is resolved, rejected, or still in progress. + /// A function that is called when the Deferred is resolved. + /// An optional function that is called when the Deferred is rejected. + /// An optional function that is called when progress notifications are sent to the Deferred. + /// + /// + /// + /// Add handlers to be called when the Deferred object is resolved, rejected, or still in progress. + /// A function, or array of functions, called when the Deferred is resolved. + /// A function, or array of functions, called when the Deferred is rejected. + /// + /// + /// + /// Add handlers to be called when the Deferred object is resolved, rejected, or still in progress. + /// A function, or array of functions, called when the Deferred is resolved. + /// A function, or array of functions, called when the Deferred is rejected. + /// A function, or array of functions, called when the Deferred notifies progress. + /// + /// + }, +}); + +return _object; +}; +intellisense.redirectDefinition(jQuery.Callbacks, _731531622); + +intellisense.annotate(jQuery.Event.prototype, { + 'currentTarget': function() { + /// The current DOM element within the event bubbling phase. + /// + }, + 'data': function() { + /// An optional object of data passed to an event method when the current executing handler is bound. + /// + }, + 'delegateTarget': function() { + /// The element where the currently-called jQuery event handler was attached. + /// + }, + 'isDefaultPrevented': function() { + /// Returns whether event.preventDefault() was ever called on this event object. + /// + }, + 'isImmediatePropagationStopped': function() { + /// Returns whether event.stopImmediatePropagation() was ever called on this event object. + /// + }, + 'isPropagationStopped': function() { + /// Returns whether event.stopPropagation() was ever called on this event object. + /// + }, + 'metaKey': function() { + /// Indicates whether the META key was pressed when the event fired. + /// + }, + 'namespace': function() { + /// The namespace specified when the event was triggered. + /// + }, + 'pageX': function() { + /// The mouse position relative to the left edge of the document. + /// + }, + 'pageY': function() { + /// The mouse position relative to the top edge of the document. + /// + }, + 'preventDefault': function() { + /// If this method is called, the default action of the event will not be triggered. + }, + 'relatedTarget': function() { + /// The other DOM element involved in the event, if any. + /// + }, + 'result': function() { + /// The last value returned by an event handler that was triggered by this event, unless the value was undefined. + /// + }, + 'stopImmediatePropagation': function() { + /// Keeps the rest of the handlers from being executed and prevents the event from bubbling up the DOM tree. + }, + 'stopPropagation': function() { + /// Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event. + }, + 'target': function() { + /// The DOM element that initiated the event. + /// + }, + 'timeStamp': function() { + /// The difference in milliseconds between the time the browser created the event and January 1, 1970. + /// + }, + 'type': function() { + /// Describes the nature of the event. + /// + }, + 'which': function() { + /// For key or mouse events, this property indicates the specific key or button that was pressed. + /// + }, +}); + +intellisense.annotate(jQuery.fn, { + 'add': function() { + /// + /// Add elements to the set of matched elements. + /// A string representing a selector expression to find additional elements to add to the set of matched elements. + /// + /// + /// + /// Add elements to the set of matched elements. + /// One or more elements to add to the set of matched elements. + /// + /// + /// + /// Add elements to the set of matched elements. + /// An HTML fragment to add to the set of matched elements. + /// + /// + /// + /// Add elements to the set of matched elements. + /// An existing jQuery object to add to the set of matched elements. + /// + /// + /// + /// Add elements to the set of matched elements. + /// A string representing a selector expression to find additional elements to add to the set of matched elements. + /// The point in the document at which the selector should begin matching; similar to the context argument of the $(selector, context) method. + /// + /// + }, + 'addBack': function() { + /// + /// Add the previous set of elements on the stack to the current set, optionally filtered by a selector. + /// A string containing a selector expression to match the current set of elements against. + /// + /// + }, + 'addClass': function() { + /// + /// Adds the specified class(es) to each of the set of matched elements. + /// One or more space-separated classes to be added to the class attribute of each matched element. + /// + /// + /// + /// Adds the specified class(es) to each of the set of matched elements. + /// A function returning one or more space-separated class names to be added to the existing class name(s). Receives the index position of the element in the set and the existing class name(s) as arguments. Within the function, this refers to the current element in the set. + /// + /// + }, + 'after': function() { + /// + /// Insert content, specified by the parameter, after each element in the set of matched elements. + /// HTML string, DOM element, or jQuery object to insert after each element in the set of matched elements. + /// One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert after each element in the set of matched elements. + /// + /// + /// + /// Insert content, specified by the parameter, after each element in the set of matched elements. + /// A function that returns an HTML string, DOM element(s), or jQuery object to insert after each element in the set of matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + /// + /// + }, + 'ajaxComplete': function() { + /// + /// Register a handler to be called when Ajax requests complete. This is an AjaxEvent. + /// The function to be invoked. + /// + /// + }, + 'ajaxError': function() { + /// + /// Register a handler to be called when Ajax requests complete with an error. This is an Ajax Event. + /// The function to be invoked. + /// + /// + }, + 'ajaxSend': function() { + /// + /// Attach a function to be executed before an Ajax request is sent. This is an Ajax Event. + /// The function to be invoked. + /// + /// + }, + 'ajaxStart': function() { + /// + /// Register a handler to be called when the first Ajax request begins. This is an Ajax Event. + /// The function to be invoked. + /// + /// + }, + 'ajaxStop': function() { + /// + /// Register a handler to be called when all Ajax requests have completed. This is an Ajax Event. + /// The function to be invoked. + /// + /// + }, + 'ajaxSuccess': function() { + /// + /// Attach a function to be executed whenever an Ajax request completes successfully. This is an Ajax Event. + /// The function to be invoked. + /// + /// + }, + 'all': function() { + /// Selects all elements. + }, + 'andSelf': function() { + /// Add the previous set of elements on the stack to the current set. + /// + }, + 'animate': function() { + /// + /// Perform a custom animation of a set of CSS properties. + /// An object of CSS properties and values that the animation will move toward. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + /// + /// Perform a custom animation of a set of CSS properties. + /// An object of CSS properties and values that the animation will move toward. + /// A map of additional options to pass to the method. + /// + /// + }, + 'animated': function() { + /// Select all elements that are in the progress of an animation at the time the selector is run. + }, + 'append': function() { + /// + /// Insert content, specified by the parameter, to the end of each element in the set of matched elements. + /// DOM element, HTML string, or jQuery object to insert at the end of each element in the set of matched elements. + /// One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert at the end of each element in the set of matched elements. + /// + /// + /// + /// Insert content, specified by the parameter, to the end of each element in the set of matched elements. + /// A function that returns an HTML string, DOM element(s), or jQuery object to insert at the end of each element in the set of matched elements. Receives the index position of the element in the set and the old HTML value of the element as arguments. Within the function, this refers to the current element in the set. + /// + /// + }, + 'appendTo': function() { + /// + /// Insert every element in the set of matched elements to the end of the target. + /// A selector, element, HTML string, or jQuery object; the matched set of elements will be inserted at the end of the element(s) specified by this parameter. + /// + /// + }, + 'attr': function() { + /// + /// Set one or more attributes for the set of matched elements. + /// The name of the attribute to set. + /// A value to set for the attribute. + /// + /// + /// + /// Set one or more attributes for the set of matched elements. + /// An object of attribute-value pairs to set. + /// + /// + /// + /// Set one or more attributes for the set of matched elements. + /// The name of the attribute to set. + /// A function returning the value to set. this is the current element. Receives the index position of the element in the set and the old attribute value as arguments. + /// + /// + }, + 'attributeContains': function() { + /// + /// Selects elements that have the specified attribute with a value containing the a given substring. + /// An attribute name. + /// An attribute value. Can be either an unquoted single word or a quoted string. + /// + }, + 'attributeContainsPrefix': function() { + /// + /// Selects elements that have the specified attribute with a value either equal to a given string or starting with that string followed by a hyphen (-). + /// An attribute name. + /// An attribute value. Can be either an unquoted single word or a quoted string. + /// + }, + 'attributeContainsWord': function() { + /// + /// Selects elements that have the specified attribute with a value containing a given word, delimited by spaces. + /// An attribute name. + /// An attribute value. Can be either an unquoted single word or a quoted string. + /// + }, + 'attributeEndsWith': function() { + /// + /// Selects elements that have the specified attribute with a value ending exactly with a given string. The comparison is case sensitive. + /// An attribute name. + /// An attribute value. Can be either an unquoted single word or a quoted string. + /// + }, + 'attributeEquals': function() { + /// + /// Selects elements that have the specified attribute with a value exactly equal to a certain value. + /// An attribute name. + /// An attribute value. Can be either an unquoted single word or a quoted string. + /// + }, + 'attributeHas': function() { + /// + /// Selects elements that have the specified attribute, with any value. + /// An attribute name. + /// + }, + 'attributeMultiple': function() { + /// + /// Matches elements that match all of the specified attribute filters. + /// An attribute filter. + /// Another attribute filter, reducing the selection even more + /// As many more attribute filters as necessary + /// + }, + 'attributeNotEqual': function() { + /// + /// Select elements that either don't have the specified attribute, or do have the specified attribute but not with a certain value. + /// An attribute name. + /// An attribute value. Can be either an unquoted single word or a quoted string. + /// + }, + 'attributeStartsWith': function() { + /// + /// Selects elements that have the specified attribute with a value beginning exactly with a given string. + /// An attribute name. + /// An attribute value. Can be either an unquoted single word or a quoted string. + /// + }, + 'before': function() { + /// + /// Insert content, specified by the parameter, before each element in the set of matched elements. + /// HTML string, DOM element, or jQuery object to insert before each element in the set of matched elements. + /// One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert before each element in the set of matched elements. + /// + /// + /// + /// Insert content, specified by the parameter, before each element in the set of matched elements. + /// A function that returns an HTML string, DOM element(s), or jQuery object to insert before each element in the set of matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + /// + /// + }, + 'bind': function() { + /// + /// Attach a handler to an event for the elements. + /// A string containing one or more DOM event types, such as "click" or "submit," or custom event names. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Attach a handler to an event for the elements. + /// A string containing one or more DOM event types, such as "click" or "submit," or custom event names. + /// An object containing data that will be passed to the event handler. + /// Setting the third argument to false will attach a function that prevents the default action from occurring and stops the event from bubbling. The default is true. + /// + /// + /// + /// Attach a handler to an event for the elements. + /// An object containing one or more DOM event types and functions to execute for them. + /// + /// + }, + 'blur': function() { + /// + /// Bind an event handler to the "blur" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "blur" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'button': function() { + /// Selects all button elements and elements of type button. + }, + 'change': function() { + /// + /// Bind an event handler to the "change" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "change" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'checkbox': function() { + /// Selects all elements of type checkbox. + }, + 'checked': function() { + /// Matches all elements that are checked or selected. + }, + 'child': function() { + /// + /// Selects all direct child elements specified by "child" of elements specified by "parent". + /// Any valid selector. + /// A selector to filter the child elements. + /// + }, + 'children': function() { + /// + /// Get the children of each element in the set of matched elements, optionally filtered by a selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'class': function() { + /// + /// Selects all elements with the given class. + /// A class to search for. An element can have multiple classes; only one of them must match. + /// + }, + 'clearQueue': function() { + /// + /// Remove from the queue all items that have not yet been run. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// + /// + }, + 'click': function() { + /// + /// Bind an event handler to the "click" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "click" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'clone': function() { + /// + /// Create a deep copy of the set of matched elements. + /// A Boolean indicating whether event handlers should be copied along with the elements. As of jQuery 1.4, element data will be copied as well. + /// + /// + /// + /// Create a deep copy of the set of matched elements. + /// A Boolean indicating whether event handlers and data should be copied along with the elements. The default value is false. *In jQuery 1.5.0 the default value was incorrectly true; it was changed back to false in 1.5.1 and up. + /// A Boolean indicating whether event handlers and data for all children of the cloned element should be copied. By default its value matches the first argument's value (which defaults to false). + /// + /// + }, + 'closest': function() { + /// + /// For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + /// A string containing a selector expression to match elements against. + /// A DOM element within which a matching element may be found. If no context is passed in then the context of the jQuery set will be used instead. + /// + /// + /// + /// For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + /// A jQuery object to match elements against. + /// + /// + /// + /// For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. + /// An element to match elements against. + /// + /// + }, + 'contains': function() { + /// + /// Select all elements that contain the specified text. + /// A string of text to look for. It's case sensitive. + /// + }, + 'contents': function() { + /// Get the children of each element in the set of matched elements, including text and comment nodes. + /// + }, + 'context': function() { + /// The DOM node context originally passed to jQuery(); if none was passed then context will likely be the document. + /// + }, + 'css': function() { + /// + /// Set one or more CSS properties for the set of matched elements. + /// A CSS property name. + /// A value to set for the property. + /// + /// + /// + /// Set one or more CSS properties for the set of matched elements. + /// A CSS property name. + /// A function returning the value to set. this is the current element. Receives the index position of the element in the set and the old value as arguments. + /// + /// + /// + /// Set one or more CSS properties for the set of matched elements. + /// An object of property-value pairs to set. + /// + /// + }, + 'data': function() { + /// + /// Store arbitrary data associated with the matched elements. + /// A string naming the piece of data to set. + /// The new data value; it can be any Javascript type including Array or Object. + /// + /// + /// + /// Store arbitrary data associated with the matched elements. + /// An object of key-value pairs of data to update. + /// + /// + }, + 'dblclick': function() { + /// + /// Bind an event handler to the "dblclick" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "dblclick" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'delay': function() { + /// + /// Set a timer to delay execution of subsequent items in the queue. + /// An integer indicating the number of milliseconds to delay execution of the next item in the queue. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// + /// + }, + 'delegate': function() { + /// + /// Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements. + /// A selector to filter the elements that trigger the event. + /// A string containing one or more space-separated JavaScript event types, such as "click" or "keydown," or custom event names. + /// A function to execute at the time the event is triggered. + /// + /// + /// + /// Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements. + /// A selector to filter the elements that trigger the event. + /// A string containing one or more space-separated JavaScript event types, such as "click" or "keydown," or custom event names. + /// An object containing data that will be passed to the event handler. + /// A function to execute at the time the event is triggered. + /// + /// + /// + /// Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements. + /// A selector to filter the elements that trigger the event. + /// A plain object of one or more event types and functions to execute for them. + /// + /// + }, + 'dequeue': function() { + /// + /// Execute the next function on the queue for the matched elements. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// + /// + }, + 'descendant': function() { + /// + /// Selects all elements that are descendants of a given ancestor. + /// Any valid selector. + /// A selector to filter the descendant elements. + /// + }, + 'detach': function() { + /// + /// Remove the set of matched elements from the DOM. + /// A selector expression that filters the set of matched elements to be removed. + /// + /// + }, + 'die': function() { + /// + /// Remove event handlers previously attached using .live() from the elements. + /// A string containing a JavaScript event type, such as click or keydown. + /// The function that is no longer to be executed. + /// + /// + /// + /// Remove event handlers previously attached using .live() from the elements. + /// A plain object of one or more event types, such as click or keydown and their corresponding functions that are no longer to be executed. + /// + /// + }, + 'disabled': function() { + /// Selects all elements that are disabled. + }, + 'each': function() { + /// + /// Iterate over a jQuery object, executing a function for each matched element. + /// A function to execute for each matched element. + /// + /// + }, + 'element': function() { + /// + /// Selects all elements with the given tag name. + /// An element to search for. Refers to the tagName of DOM nodes. + /// + }, + 'empty': function() { + /// Select all elements that have no children (including text nodes). + }, + 'enabled': function() { + /// Selects all elements that are enabled. + }, + 'end': function() { + /// End the most recent filtering operation in the current chain and return the set of matched elements to its previous state. + /// + }, + 'eq': function() { + /// + /// Select the element at index n within the matched set. + /// Zero-based index of the element to match. + /// + /// + /// Select the element at index n within the matched set. + /// Zero-based index of the element to match, counting backwards from the last element. + /// + }, + 'error': function() { + /// + /// Bind an event handler to the "error" JavaScript event. + /// A function to execute when the event is triggered. + /// + /// + /// + /// Bind an event handler to the "error" JavaScript event. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'even': function() { + /// Selects even elements, zero-indexed. See also odd. + }, + 'fadeIn': function() { + /// + /// Display the matched elements by fading them to opaque. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Display the matched elements by fading them to opaque. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Display the matched elements by fading them to opaque. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'fadeOut': function() { + /// + /// Hide the matched elements by fading them to transparent. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Hide the matched elements by fading them to transparent. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Hide the matched elements by fading them to transparent. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'fadeTo': function() { + /// + /// Adjust the opacity of the matched elements. + /// A string or number determining how long the animation will run. + /// A number between 0 and 1 denoting the target opacity. + /// A function to call once the animation is complete. + /// + /// + /// + /// Adjust the opacity of the matched elements. + /// A string or number determining how long the animation will run. + /// A number between 0 and 1 denoting the target opacity. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'fadeToggle': function() { + /// + /// Display or hide the matched elements by animating their opacity. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + /// + /// Display or hide the matched elements by animating their opacity. + /// A map of additional options to pass to the method. + /// + /// + }, + 'file': function() { + /// Selects all elements of type file. + }, + 'filter': function() { + /// + /// Reduce the set of matched elements to those that match the selector or pass the function's test. + /// A string containing a selector expression to match the current set of elements against. + /// + /// + /// + /// Reduce the set of matched elements to those that match the selector or pass the function's test. + /// A function used as a test for each element in the set. this is the current DOM element. + /// + /// + /// + /// Reduce the set of matched elements to those that match the selector or pass the function's test. + /// An element to match the current set of elements against. + /// + /// + /// + /// Reduce the set of matched elements to those that match the selector or pass the function's test. + /// An existing jQuery object to match the current set of elements against. + /// + /// + }, + 'find': function() { + /// + /// Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element. + /// A jQuery object to match elements against. + /// + /// + /// + /// Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element. + /// An element to match elements against. + /// + /// + }, + 'finish': function() { + /// + /// Stop the currently-running animation, remove all queued animations, and complete all animations for the matched elements. + /// The name of the queue in which to stop animations. + /// + /// + }, + 'first': function() { + /// Selects the first matched element. + }, + 'first-child': function() { + /// Selects all elements that are the first child of their parent. + }, + 'first-of-type': function() { + /// Selects all elements that are the first among siblings of the same element name. + }, + 'focus': function() { + /// + /// Bind an event handler to the "focus" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "focus" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'focusin': function() { + /// + /// Bind an event handler to the "focusin" event. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "focusin" event. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'focusout': function() { + /// + /// Bind an event handler to the "focusout" JavaScript event. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "focusout" JavaScript event. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'get': function() { + /// + /// Retrieve one of the DOM elements matched by the jQuery object. + /// A zero-based integer indicating which element to retrieve. + /// + /// + }, + 'gt': function() { + /// + /// Select all elements at an index greater than index within the matched set. + /// Zero-based index. + /// + /// + /// Select all elements at an index greater than index within the matched set. + /// Zero-based index, counting backwards from the last element. + /// + }, + 'has': function() { + /// + /// Reduce the set of matched elements to those that have a descendant that matches the selector or DOM element. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// Reduce the set of matched elements to those that have a descendant that matches the selector or DOM element. + /// A DOM element to match elements against. + /// + /// + }, + 'hasClass': function() { + /// + /// Determine whether any of the matched elements are assigned the given class. + /// The class name to search for. + /// + /// + }, + 'header': function() { + /// Selects all elements that are headers, like h1, h2, h3 and so on. + }, + 'height': function() { + /// + /// Set the CSS height of every matched element. + /// An integer representing the number of pixels, or an integer with an optional unit of measure appended (as a string). + /// + /// + /// + /// Set the CSS height of every matched element. + /// A function returning the height to set. Receives the index position of the element in the set and the old height as arguments. Within the function, this refers to the current element in the set. + /// + /// + }, + 'hidden': function() { + /// Selects all elements that are hidden. + }, + 'hide': function() { + /// + /// Hide the matched elements. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Hide the matched elements. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Hide the matched elements. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'hover': function() { + /// + /// Bind two handlers to the matched elements, to be executed when the mouse pointer enters and leaves the elements. + /// A function to execute when the mouse pointer enters the element. + /// A function to execute when the mouse pointer leaves the element. + /// + /// + }, + 'html': function() { + /// + /// Set the HTML contents of each element in the set of matched elements. + /// A string of HTML to set as the content of each matched element. + /// + /// + /// + /// Set the HTML contents of each element in the set of matched elements. + /// A function returning the HTML content to set. Receives the index position of the element in the set and the old HTML value as arguments. jQuery empties the element before calling the function; use the oldhtml argument to reference the previous content. Within the function, this refers to the current element in the set. + /// + /// + }, + 'id': function() { + /// + /// Selects a single element with the given id attribute. + /// An ID to search for, specified via the id attribute of an element. + /// + }, + 'image': function() { + /// Selects all elements of type image. + }, + 'index': function() { + /// + /// Search for a given element from among the matched elements. + /// A selector representing a jQuery collection in which to look for an element. + /// + /// + /// + /// Search for a given element from among the matched elements. + /// The DOM element or first element within the jQuery object to look for. + /// + /// + }, + 'init': function() { + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// A string containing a selector expression + /// A DOM Element, Document, or jQuery to use as context + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// A DOM element to wrap in a jQuery object. + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// An array containing a set of DOM elements to wrap in a jQuery object. + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// A plain object to wrap in a jQuery object. + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// An existing jQuery object to clone. + /// + /// + }, + 'innerHeight': function() { + /// Get the current computed height for the first element in the set of matched elements, including padding but not border. + /// + }, + 'innerWidth': function() { + /// Get the current computed width for the first element in the set of matched elements, including padding but not border. + /// + }, + 'input': function() { + /// Selects all input, textarea, select and button elements. + }, + 'insertAfter': function() { + /// + /// Insert every element in the set of matched elements after the target. + /// A selector, element, HTML string, or jQuery object; the matched set of elements will be inserted after the element(s) specified by this parameter. + /// + /// + }, + 'insertBefore': function() { + /// + /// Insert every element in the set of matched elements before the target. + /// A selector, element, HTML string, or jQuery object; the matched set of elements will be inserted before the element(s) specified by this parameter. + /// + /// + }, + 'is': function() { + /// + /// Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + /// A function used as a test for the set of elements. It accepts one argument, index, which is the element's index in the jQuery collection.Within the function, this refers to the current DOM element. + /// + /// + /// + /// Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + /// An existing jQuery object to match the current set of elements against. + /// + /// + /// + /// Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. + /// An element to match the current set of elements against. + /// + /// + }, + 'jquery': function() { + /// A string containing the jQuery version number. + /// + }, + 'keydown': function() { + /// + /// Bind an event handler to the "keydown" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "keydown" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'keypress': function() { + /// + /// Bind an event handler to the "keypress" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "keypress" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'keyup': function() { + /// + /// Bind an event handler to the "keyup" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "keyup" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'lang': function() { + /// + /// Selects all elements of the specified language. + /// A language code. + /// + }, + 'last': function() { + /// Selects the last matched element. + }, + 'last-child': function() { + /// Selects all elements that are the last child of their parent. + }, + 'last-of-type': function() { + /// Selects all elements that are the last among siblings of the same element name. + }, + 'length': function() { + /// The number of elements in the jQuery object. + /// + }, + 'live': function() { + /// + /// Attach an event handler for all elements which match the current selector, now and in the future. + /// A string containing a JavaScript event type, such as "click" or "keydown." As of jQuery 1.4 the string can contain multiple, space-separated event types or custom event names. + /// A function to execute at the time the event is triggered. + /// + /// + /// + /// Attach an event handler for all elements which match the current selector, now and in the future. + /// A string containing a JavaScript event type, such as "click" or "keydown." As of jQuery 1.4 the string can contain multiple, space-separated event types or custom event names. + /// An object containing data that will be passed to the event handler. + /// A function to execute at the time the event is triggered. + /// + /// + /// + /// Attach an event handler for all elements which match the current selector, now and in the future. + /// A plain object of one or more JavaScript event types and functions to execute for them. + /// + /// + }, + 'load': function() { + /// + /// Bind an event handler to the "load" JavaScript event. + /// A function to execute when the event is triggered. + /// + /// + /// + /// Bind an event handler to the "load" JavaScript event. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'lt': function() { + /// + /// Select all elements at an index less than index within the matched set. + /// Zero-based index. + /// + /// + /// Select all elements at an index less than index within the matched set. + /// Zero-based index, counting backwards from the last element. + /// + }, + 'map': function() { + /// + /// Pass each element in the current matched set through a function, producing a new jQuery object containing the return values. + /// A function object that will be invoked for each element in the current set. + /// + /// + }, + 'mousedown': function() { + /// + /// Bind an event handler to the "mousedown" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "mousedown" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'mouseenter': function() { + /// + /// Bind an event handler to be fired when the mouse enters an element, or trigger that handler on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to be fired when the mouse enters an element, or trigger that handler on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'mouseleave': function() { + /// + /// Bind an event handler to be fired when the mouse leaves an element, or trigger that handler on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to be fired when the mouse leaves an element, or trigger that handler on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'mousemove': function() { + /// + /// Bind an event handler to the "mousemove" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "mousemove" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'mouseout': function() { + /// + /// Bind an event handler to the "mouseout" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "mouseout" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'mouseover': function() { + /// + /// Bind an event handler to the "mouseover" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "mouseover" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'mouseup': function() { + /// + /// Bind an event handler to the "mouseup" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "mouseup" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'multiple': function() { + /// + /// Selects the combined results of all the specified selectors. + /// Any valid selector. + /// Another valid selector. + /// As many more valid selectors as you like. + /// + }, + 'next': function() { + /// + /// Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'next adjacent': function() { + /// + /// Selects all next elements matching "next" that are immediately preceded by a sibling "prev". + /// Any valid selector. + /// A selector to match the element that is next to the first selector. + /// + }, + 'next siblings': function() { + /// + /// Selects all sibling elements that follow after the "prev" element, have the same parent, and match the filtering "siblings" selector. + /// Any valid selector. + /// A selector to filter elements that are the following siblings of the first selector. + /// + }, + 'nextAll': function() { + /// + /// Get all following siblings of each element in the set of matched elements, optionally filtered by a selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'nextUntil': function() { + /// + /// Get all following siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object passed. + /// A string containing a selector expression to indicate where to stop matching following sibling elements. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// Get all following siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object passed. + /// A DOM node or jQuery object indicating where to stop matching following sibling elements. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'not': function() { + /// + /// Remove elements from the set of matched elements. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// Remove elements from the set of matched elements. + /// One or more DOM elements to remove from the matched set. + /// + /// + /// + /// Remove elements from the set of matched elements. + /// A function used as a test for each element in the set. this is the current DOM element. + /// + /// + /// + /// Remove elements from the set of matched elements. + /// An existing jQuery object to match the current set of elements against. + /// + /// + }, + 'nth-child': function() { + /// + /// Selects all elements that are the nth-child of their parent. + /// The index of each child to match, starting with 1, the string even or odd, or an equation ( eg. :nth-child(even), :nth-child(4n) ) + /// + }, + 'nth-last-child': function() { + /// + /// Selects all elements that are the nth-child of their parent, counting from the last element to the first. + /// The index of each child to match, starting with the last one (1), the string even or odd, or an equation ( eg. :nth-last-child(even), :nth-last-child(4n) ) + /// + }, + 'nth-last-of-type': function() { + /// + /// Selects all elements that are the nth-child of their parent, counting from the last element to the first. + /// The index of each child to match, starting with the last one (1), the string even or odd, or an equation ( eg. :nth-last-of-type(even), :nth-last-of-type(4n) ) + /// + }, + 'nth-of-type': function() { + /// + /// Selects all elements that are the nth child of their parent in relation to siblings with the same element name. + /// The index of each child to match, starting with 1, the string even or odd, or an equation ( eg. :nth-of-type(even), :nth-of-type(4n) ) + /// + }, + 'odd': function() { + /// Selects odd elements, zero-indexed. See also even. + }, + 'off': function() { + /// + /// Remove an event handler. + /// One or more space-separated event types and optional namespaces, or just namespaces, such as "click", "keydown.myPlugin", or ".myPlugin". + /// A selector which should match the one originally passed to .on() when attaching event handlers. + /// A handler function previously attached for the event(s), or the special value false. + /// + /// + /// + /// Remove an event handler. + /// An object where the string keys represent one or more space-separated event types and optional namespaces, and the values represent handler functions previously attached for the event(s). + /// A selector which should match the one originally passed to .on() when attaching event handlers. + /// + /// + }, + 'offset': function() { + /// + /// Set the current coordinates of every element in the set of matched elements, relative to the document. + /// An object containing the properties top and left, which are integers indicating the new top and left coordinates for the elements. + /// + /// + /// + /// Set the current coordinates of every element in the set of matched elements, relative to the document. + /// A function to return the coordinates to set. Receives the index of the element in the collection as the first argument and the current coordinates as the second argument. The function should return an object with the new top and left properties. + /// + /// + }, + 'offsetParent': function() { + /// Get the closest ancestor element that is positioned. + /// + }, + 'on': function() { + /// + /// Attach an event handler function for one or more events to the selected elements. + /// One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + /// A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element. + /// Data to be passed to the handler in event.data when an event is triggered. + /// A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. + /// + /// + /// + /// Attach an event handler function for one or more events to the selected elements. + /// An object in which the string keys represent one or more space-separated event types and optional namespaces, and the values represent a handler function to be called for the event(s). + /// A selector string to filter the descendants of the selected elements that will call the handler. If the selector is null or omitted, the handler is always called when it reaches the selected element. + /// Data to be passed to the handler in event.data when an event occurs. + /// + /// + }, + 'one': function() { + /// + /// Attach a handler to an event for the elements. The handler is executed at most once per element. + /// A string containing one or more JavaScript event types, such as "click" or "submit," or custom event names. + /// An object containing data that will be passed to the event handler. + /// A function to execute at the time the event is triggered. + /// + /// + /// + /// Attach a handler to an event for the elements. The handler is executed at most once per element. + /// One or more space-separated event types and optional namespaces, such as "click" or "keydown.myPlugin". + /// A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element. + /// Data to be passed to the handler in event.data when an event is triggered. + /// A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false. + /// + /// + /// + /// Attach a handler to an event for the elements. The handler is executed at most once per element. + /// An object in which the string keys represent one or more space-separated event types and optional namespaces, and the values represent a handler function to be called for the event(s). + /// A selector string to filter the descendants of the selected elements that will call the handler. If the selector is null or omitted, the handler is always called when it reaches the selected element. + /// Data to be passed to the handler in event.data when an event occurs. + /// + /// + }, + 'only-child': function() { + /// Selects all elements that are the only child of their parent. + }, + 'only-of-type': function() { + /// Selects all elements that have no siblings with the same element name. + }, + 'outerHeight': function() { + /// + /// Get the current computed height for the first element in the set of matched elements, including padding, border, and optionally margin. Returns an integer (without "px") representation of the value or null if called on an empty set of elements. + /// A Boolean indicating whether to include the element's margin in the calculation. + /// + /// + }, + 'outerWidth': function() { + /// + /// Get the current computed width for the first element in the set of matched elements, including padding and border. + /// A Boolean indicating whether to include the element's margin in the calculation. + /// + /// + }, + 'parent': function() { + /// + /// Get the parent of each element in the current set of matched elements, optionally filtered by a selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'parents': function() { + /// + /// Get the ancestors of each element in the current set of matched elements, optionally filtered by a selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'parentsUntil': function() { + /// + /// Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object. + /// A string containing a selector expression to indicate where to stop matching ancestor elements. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// Get the ancestors of each element in the current set of matched elements, up to but not including the element matched by the selector, DOM node, or jQuery object. + /// A DOM node or jQuery object indicating where to stop matching ancestor elements. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'password': function() { + /// Selects all elements of type password. + }, + 'position': function() { + /// Get the current coordinates of the first element in the set of matched elements, relative to the offset parent. + /// + }, + 'prepend': function() { + /// + /// Insert content, specified by the parameter, to the beginning of each element in the set of matched elements. + /// DOM element, array of elements, HTML string, or jQuery object to insert at the beginning of each element in the set of matched elements. + /// One or more additional DOM elements, arrays of elements, HTML strings, or jQuery objects to insert at the beginning of each element in the set of matched elements. + /// + /// + /// + /// Insert content, specified by the parameter, to the beginning of each element in the set of matched elements. + /// A function that returns an HTML string, DOM element(s), or jQuery object to insert at the beginning of each element in the set of matched elements. Receives the index position of the element in the set and the old HTML value of the element as arguments. Within the function, this refers to the current element in the set. + /// + /// + }, + 'prependTo': function() { + /// + /// Insert every element in the set of matched elements to the beginning of the target. + /// A selector, element, HTML string, or jQuery object; the matched set of elements will be inserted at the beginning of the element(s) specified by this parameter. + /// + /// + }, + 'prev': function() { + /// + /// Get the immediately preceding sibling of each element in the set of matched elements, optionally filtered by a selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'prevAll': function() { + /// + /// Get all preceding siblings of each element in the set of matched elements, optionally filtered by a selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'prevUntil': function() { + /// + /// Get all preceding siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object. + /// A string containing a selector expression to indicate where to stop matching preceding sibling elements. + /// A string containing a selector expression to match elements against. + /// + /// + /// + /// Get all preceding siblings of each element up to but not including the element matched by the selector, DOM node, or jQuery object. + /// A DOM node or jQuery object indicating where to stop matching preceding sibling elements. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'promise': function() { + /// + /// Return a Promise object to observe when all actions of a certain type bound to the collection, queued or not, have finished. + /// The type of queue that needs to be observed. + /// Object onto which the promise methods have to be attached + /// + /// + }, + 'prop': function() { + /// + /// Set one or more properties for the set of matched elements. + /// The name of the property to set. + /// A value to set for the property. + /// + /// + /// + /// Set one or more properties for the set of matched elements. + /// An object of property-value pairs to set. + /// + /// + /// + /// Set one or more properties for the set of matched elements. + /// The name of the property to set. + /// A function returning the value to set. Receives the index position of the element in the set and the old property value as arguments. Within the function, the keyword this refers to the current element. + /// + /// + }, + 'pushStack': function() { + /// + /// Add a collection of DOM elements onto the jQuery stack. + /// An array of elements to push onto the stack and make into a new jQuery object. + /// + /// + /// + /// Add a collection of DOM elements onto the jQuery stack. + /// An array of elements to push onto the stack and make into a new jQuery object. + /// The name of a jQuery method that generated the array of elements. + /// The arguments that were passed in to the jQuery method (for serialization). + /// + /// + }, + 'queue': function() { + /// + /// Manipulate the queue of functions to be executed, once for each matched element. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// An array of functions to replace the current queue contents. + /// + /// + /// + /// Manipulate the queue of functions to be executed, once for each matched element. + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// The new function to add to the queue, with a function to call that will dequeue the next item. + /// + /// + }, + 'radio': function() { + /// Selects all elements of type radio. + }, + 'ready': function() { + /// + /// Specify a function to execute when the DOM is fully loaded. + /// A function to execute after the DOM is ready. + /// + /// + }, + 'remove': function() { + /// + /// Remove the set of matched elements from the DOM. + /// A selector expression that filters the set of matched elements to be removed. + /// + /// + }, + 'removeAttr': function() { + /// + /// Remove an attribute from each element in the set of matched elements. + /// An attribute to remove; as of version 1.7, it can be a space-separated list of attributes. + /// + /// + }, + 'removeClass': function() { + /// + /// Remove a single class, multiple classes, or all classes from each element in the set of matched elements. + /// One or more space-separated classes to be removed from the class attribute of each matched element. + /// + /// + /// + /// Remove a single class, multiple classes, or all classes from each element in the set of matched elements. + /// A function returning one or more space-separated class names to be removed. Receives the index position of the element in the set and the old class value as arguments. + /// + /// + }, + 'removeData': function() { + /// + /// Remove a previously-stored piece of data. + /// A string naming the piece of data to delete. + /// + /// + /// + /// Remove a previously-stored piece of data. + /// An array or space-separated string naming the pieces of data to delete. + /// + /// + }, + 'removeProp': function() { + /// + /// Remove a property for the set of matched elements. + /// The name of the property to remove. + /// + /// + }, + 'replaceAll': function() { + /// + /// Replace each target element with the set of matched elements. + /// A selector string, jQuery object, or DOM element reference indicating which element(s) to replace. + /// + /// + }, + 'replaceWith': function() { + /// + /// Replace each element in the set of matched elements with the provided new content and return the set of elements that was removed. + /// The content to insert. May be an HTML string, DOM element, or jQuery object. + /// + /// + /// + /// Replace each element in the set of matched elements with the provided new content and return the set of elements that was removed. + /// A function that returns content with which to replace the set of matched elements. + /// + /// + }, + 'reset': function() { + /// Selects all elements of type reset. + }, + 'resize': function() { + /// + /// Bind an event handler to the "resize" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "resize" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'root': function() { + /// Selects the element that is the root of the document. + }, + 'scroll': function() { + /// + /// Bind an event handler to the "scroll" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "scroll" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'scrollLeft': function() { + /// + /// Set the current horizontal position of the scroll bar for each of the set of matched elements. + /// An integer indicating the new position to set the scroll bar to. + /// + /// + }, + 'scrollTop': function() { + /// + /// Set the current vertical position of the scroll bar for each of the set of matched elements. + /// An integer indicating the new position to set the scroll bar to. + /// + /// + }, + 'select': function() { + /// + /// Bind an event handler to the "select" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "select" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'selected': function() { + /// Selects all elements that are selected. + }, + 'selector': function() { + /// A selector representing selector passed to jQuery(), if any, when creating the original set. + /// + }, + 'serialize': function() { + /// Encode a set of form elements as a string for submission. + /// + }, + 'serializeArray': function() { + /// Encode a set of form elements as an array of names and values. + /// + }, + 'show': function() { + /// + /// Display the matched elements. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Display the matched elements. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Display the matched elements. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'siblings': function() { + /// + /// Get the siblings of each element in the set of matched elements, optionally filtered by a selector. + /// A string containing a selector expression to match elements against. + /// + /// + }, + 'size': function() { + /// Return the number of elements in the jQuery object. + /// + }, + 'slice': function() { + /// + /// Reduce the set of matched elements to a subset specified by a range of indices. + /// An integer indicating the 0-based position at which the elements begin to be selected. If negative, it indicates an offset from the end of the set. + /// An integer indicating the 0-based position at which the elements stop being selected. If negative, it indicates an offset from the end of the set. If omitted, the range continues until the end of the set. + /// + /// + }, + 'slideDown': function() { + /// + /// Display the matched elements with a sliding motion. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Display the matched elements with a sliding motion. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Display the matched elements with a sliding motion. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'slideToggle': function() { + /// + /// Display or hide the matched elements with a sliding motion. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Display or hide the matched elements with a sliding motion. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Display or hide the matched elements with a sliding motion. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'slideUp': function() { + /// + /// Hide the matched elements with a sliding motion. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Hide the matched elements with a sliding motion. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Hide the matched elements with a sliding motion. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + }, + 'stop': function() { + /// + /// Stop the currently-running animation on the matched elements. + /// A Boolean indicating whether to remove queued animation as well. Defaults to false. + /// A Boolean indicating whether to complete the current animation immediately. Defaults to false. + /// + /// + /// + /// Stop the currently-running animation on the matched elements. + /// The name of the queue in which to stop animations. + /// A Boolean indicating whether to remove queued animation as well. Defaults to false. + /// A Boolean indicating whether to complete the current animation immediately. Defaults to false. + /// + /// + }, + 'submit': function() { + /// + /// Bind an event handler to the "submit" JavaScript event, or trigger that event on an element. + /// A function to execute each time the event is triggered. + /// + /// + /// + /// Bind an event handler to the "submit" JavaScript event, or trigger that event on an element. + /// An object containing data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'target': function() { + /// Selects the target element indicated by the fragment identifier of the document's URI. + }, + 'text': function() { + /// + /// Set the content of each element in the set of matched elements to the specified text. + /// A string of text to set as the content of each matched element. + /// + /// + /// + /// Set the content of each element in the set of matched elements to the specified text. + /// A function returning the text content to set. Receives the index position of the element in the set and the old text value as arguments. + /// + /// + }, + 'toArray': function() { + /// Retrieve all the DOM elements contained in the jQuery set, as an array. + /// + }, + 'toggle': function() { + /// + /// Display or hide the matched elements. + /// A string or number determining how long the animation will run. + /// A function to call once the animation is complete. + /// + /// + /// + /// Display or hide the matched elements. + /// A map of additional options to pass to the method. + /// + /// + /// + /// Display or hide the matched elements. + /// A string or number determining how long the animation will run. + /// A string indicating which easing function to use for the transition. + /// A function to call once the animation is complete. + /// + /// + /// + /// Display or hide the matched elements. + /// A Boolean indicating whether to show or hide the elements. + /// + /// + }, + 'toggleClass': function() { + /// + /// Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument. + /// One or more class names (separated by spaces) to be toggled for each element in the matched set. + /// + /// + /// + /// Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument. + /// One or more class names (separated by spaces) to be toggled for each element in the matched set. + /// A Boolean (not just truthy/falsy) value to determine whether the class should be added or removed. + /// + /// + /// + /// Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument. + /// A boolean value to determine whether the class should be added or removed. + /// + /// + /// + /// Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument. + /// A function that returns class names to be toggled in the class attribute of each element in the matched set. Receives the index position of the element in the set, the old class value, and the switch as arguments. + /// A boolean value to determine whether the class should be added or removed. + /// + /// + }, + 'trigger': function() { + /// + /// Execute all handlers and behaviors attached to the matched elements for the given event type. + /// A string containing a JavaScript event type, such as click or submit. + /// Additional parameters to pass along to the event handler. + /// + /// + /// + /// Execute all handlers and behaviors attached to the matched elements for the given event type. + /// A jQuery.Event object. + /// Additional parameters to pass along to the event handler. + /// + /// + }, + 'triggerHandler': function() { + /// + /// Execute all handlers attached to an element for an event. + /// A string containing a JavaScript event type, such as click or submit. + /// An array of additional parameters to pass along to the event handler. + /// + /// + }, + 'unbind': function() { + /// + /// Remove a previously-attached event handler from the elements. + /// A string containing a JavaScript event type, such as click or submit. + /// The function that is to be no longer executed. + /// + /// + /// + /// Remove a previously-attached event handler from the elements. + /// A string containing a JavaScript event type, such as click or submit. + /// Unbinds the corresponding 'return false' function that was bound using .bind( eventType, false ). + /// + /// + /// + /// Remove a previously-attached event handler from the elements. + /// A JavaScript event object as passed to an event handler. + /// + /// + }, + 'undelegate': function() { + /// + /// Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + /// A selector which will be used to filter the event results. + /// A string containing a JavaScript event type, such as "click" or "keydown" + /// + /// + /// + /// Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + /// A selector which will be used to filter the event results. + /// A string containing a JavaScript event type, such as "click" or "keydown" + /// A function to execute at the time the event is triggered. + /// + /// + /// + /// Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + /// A selector which will be used to filter the event results. + /// An object of one or more event types and previously bound functions to unbind from them. + /// + /// + /// + /// Remove a handler from the event for all elements which match the current selector, based upon a specific set of root elements. + /// A string containing a namespace to unbind all events from. + /// + /// + }, + 'unload': function() { + /// + /// Bind an event handler to the "unload" JavaScript event. + /// A function to execute when the event is triggered. + /// + /// + /// + /// Bind an event handler to the "unload" JavaScript event. + /// A plain object of data that will be passed to the event handler. + /// A function to execute each time the event is triggered. + /// + /// + }, + 'unwrap': function() { + /// Remove the parents of the set of matched elements from the DOM, leaving the matched elements in their place. + /// + }, + 'val': function() { + /// + /// Set the value of each element in the set of matched elements. + /// A string of text or an array of strings corresponding to the value of each matched element to set as selected/checked. + /// + /// + /// + /// Set the value of each element in the set of matched elements. + /// A function returning the value to set. this is the current element. Receives the index position of the element in the set and the old value as arguments. + /// + /// + }, + 'visible': function() { + /// Selects all elements that are visible. + }, + 'width': function() { + /// + /// Set the CSS width of each element in the set of matched elements. + /// An integer representing the number of pixels, or an integer along with an optional unit of measure appended (as a string). + /// + /// + /// + /// Set the CSS width of each element in the set of matched elements. + /// A function returning the width to set. Receives the index position of the element in the set and the old width as arguments. Within the function, this refers to the current element in the set. + /// + /// + }, + 'wrap': function() { + /// + /// Wrap an HTML structure around each element in the set of matched elements. + /// A selector, element, HTML string, or jQuery object specifying the structure to wrap around the matched elements. + /// + /// + /// + /// Wrap an HTML structure around each element in the set of matched elements. + /// A callback function returning the HTML content or jQuery object to wrap around the matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + /// + /// + }, + 'wrapAll': function() { + /// + /// Wrap an HTML structure around all elements in the set of matched elements. + /// A selector, element, HTML string, or jQuery object specifying the structure to wrap around the matched elements. + /// + /// + }, + 'wrapInner': function() { + /// + /// Wrap an HTML structure around the content of each element in the set of matched elements. + /// An HTML snippet, selector expression, jQuery object, or DOM element specifying the structure to wrap around the content of the matched elements. + /// + /// + /// + /// Wrap an HTML structure around the content of each element in the set of matched elements. + /// A callback function which generates a structure to wrap around the content of the matched elements. Receives the index position of the element in the set as an argument. Within the function, this refers to the current element in the set. + /// + /// + }, +}); + +intellisense.annotate(window, { + '$': function() { + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// A string containing a selector expression + /// A DOM Element, Document, or jQuery to use as context + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// A DOM element to wrap in a jQuery object. + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// An array containing a set of DOM elements to wrap in a jQuery object. + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// A plain object to wrap in a jQuery object. + /// + /// + /// + /// Accepts a string containing a CSS selector which is then used to match a set of elements. + /// An existing jQuery object to clone. + /// + /// + }, +}); + diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-2.1.1.js b/src/Presentation/SmartStore.Web/Scripts/jquery-2.1.1.js new file mode 100644 index 0000000000..9f7b3d3895 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Scripts/jquery-2.1.1.js @@ -0,0 +1,9190 @@ +/*! + * jQuery JavaScript Library v2.1.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-05-01T17:11Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper window is present, + // execute the factory and get jQuery + // For environments that do not inherently posses a window with a document + // (such as Node.js), expose a jQuery-making factory as module.exports + // This accentuates the need for the creation of a real window + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +// + +var arr = []; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + version = "2.1.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android<4.1 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; + }, + + isPlainObject: function( obj ) { + // Not plain objects: + // - Any object or value whose internal [[Class]] property is not "[object Object]" + // - DOM nodes + // - window + if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.constructor && + !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { + return false; + } + + // If the function hasn't returned already, we're confident that + // |obj| is a plain object, created by {} or constructed with new Object + return true; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + // Support: Android < 4.0, iOS < 6 (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call(obj) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + var script, + indirect = eval; + + code = jQuery.trim( code ); + + if ( code ) { + // If the code includes a valid, prologue position + // strict mode pragma, execute code by injecting a + // script tag into the document. + if ( code.indexOf("use strict") === 1 ) { + script = document.createElement("script"); + script.text = code; + document.head.appendChild( script ).parentNode.removeChild( script ); + } else { + // Otherwise, avoid the DOM node creation, insertion + // and removal by using an indirect global eval + indirect( code ); + } + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Support: Android<4.1 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v1.10.19 + * http://sizzlejs.com/ + * + * Copyright 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-04-18 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + characterEncoding + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( documentIsHTML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document (jQuery #6963) + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== strundefined && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, + doc = node ? node.ownerDocument || node : preferredDoc, + parent = doc.defaultView; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsHTML = !isXML( doc ); + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent !== parent.top ) { + // IE11 does not have attachEvent, so all must suffer + if ( parent.addEventListener ) { + parent.addEventListener( "unload", function() { + setDocument(); + }, false ); + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", function() { + setDocument(); + }); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if getElementsByClassName can be trusted + support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { + div.innerHTML = "
              "; + + // Support: Safari<4 + // Catch class over-caching + div.firstChild.className = "i"; + // Support: Opera<10 + // Catch gEBCN failure to find non-leading classes + return div.getElementsByClassName("i").length === 2; + }); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowclip^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (oldCache = outerCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + outerCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context !== document && context; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is no seed and only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome<14 +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) >= 0 ) !== not; + }); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + len = this.length, + ret = [], + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +}); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof rootjQuery.ready !== "undefined" ? + rootjQuery.ready( selector ) : + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.extend({ + dir: function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; + }, + + sibling: function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; + } +}); + +jQuery.fn.extend({ + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter(function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.unique( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return elem.contentDocument || jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.unique( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +}); +var rnotwhite = (/\S+/g); + + + +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend({ + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +}); + +/** + * The ready event handler and self cleanup method + */ +function completed() { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + jQuery.ready(); +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + } else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + } + } + return readyList.promise( obj ); +}; + +// Kick off the DOM ready check even if the user does not +jQuery.ready.promise(); + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + len ? fn( elems[0], key ) : emptyGet; +}; + + +/** + * Determines whether an object can have data + */ +jQuery.acceptData = function( owner ) { + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + /* jshint -W018 */ + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + +function Data() { + // Support: Android < 4, + // Old WebKit does not have Object.preventExtensions/freeze method, + // return new empty object instead with no [[set]] accessor + Object.defineProperty( this.cache = {}, 0, { + get: function() { + return {}; + } + }); + + this.expando = jQuery.expando + Math.random(); +} + +Data.uid = 1; +Data.accepts = jQuery.acceptData; + +Data.prototype = { + key: function( owner ) { + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return the key for a frozen object. + if ( !Data.accepts( owner ) ) { + return 0; + } + + var descriptor = {}, + // Check if the owner object already has a cache key + unlock = owner[ this.expando ]; + + // If not, create one + if ( !unlock ) { + unlock = Data.uid++; + + // Secure it in a non-enumerable, non-writable property + try { + descriptor[ this.expando ] = { value: unlock }; + Object.defineProperties( owner, descriptor ); + + // Support: Android < 4 + // Fallback to a less secure definition + } catch ( e ) { + descriptor[ this.expando ] = unlock; + jQuery.extend( owner, descriptor ); + } + } + + // Ensure the cache object + if ( !this.cache[ unlock ] ) { + this.cache[ unlock ] = {}; + } + + return unlock; + }, + set: function( owner, data, value ) { + var prop, + // There may be an unlock assigned to this node, + // if there is no entry for this "owner", create one inline + // and set the unlock as though an owner entry had always existed + unlock = this.key( owner ), + cache = this.cache[ unlock ]; + + // Handle: [ owner, key, value ] args + if ( typeof data === "string" ) { + cache[ data ] = value; + + // Handle: [ owner, { properties } ] args + } else { + // Fresh assignments by object are shallow copied + if ( jQuery.isEmptyObject( cache ) ) { + jQuery.extend( this.cache[ unlock ], data ); + // Otherwise, copy the properties one-by-one to the cache object + } else { + for ( prop in data ) { + cache[ prop ] = data[ prop ]; + } + } + } + return cache; + }, + get: function( owner, key ) { + // Either a valid cache is found, or will be created. + // New caches will be created and the unlock returned, + // allowing direct access to the newly created + // empty data object. A valid owner object must be provided. + var cache = this.cache[ this.key( owner ) ]; + + return key === undefined ? + cache : cache[ key ]; + }, + access: function( owner, key, value ) { + var stored; + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ((key && typeof key === "string") && value === undefined) ) { + + stored = this.get( owner, key ); + + return stored !== undefined ? + stored : this.get( owner, jQuery.camelCase(key) ); + } + + // [*]When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, name, camel, + unlock = this.key( owner ), + cache = this.cache[ unlock ]; + + if ( key === undefined ) { + this.cache[ unlock ] = {}; + + } else { + // Support array or space separated string of keys + if ( jQuery.isArray( key ) ) { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = key.concat( key.map( jQuery.camelCase ) ); + } else { + camel = jQuery.camelCase( key ); + // Try the string as a key before any manipulation + if ( key in cache ) { + name = [ key, camel ]; + } else { + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + name = camel; + name = name in cache ? + [ name ] : ( name.match( rnotwhite ) || [] ); + } + } + + i = name.length; + while ( i-- ) { + delete cache[ name[ i ] ]; + } + } + }, + hasData: function( owner ) { + return !jQuery.isEmptyObject( + this.cache[ owner[ this.expando ] ] || {} + ); + }, + discard: function( owner ) { + if ( owner[ this.expando ] ) { + delete this.cache[ owner[ this.expando ] ]; + } + } +}; +var data_priv = new Data(); + +var data_user = new Data(); + + + +/* + Implementation Summary + + 1. Enforce API surface and semantic compatibility with 1.9.x branch + 2. Improve the module's maintainability by reducing the storage + paths to a single mechanism. + 3. Use the same single mechanism to support "private" and "user" data. + 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) + 5. Avoid exposing implementation details on user objects (eg. expando properties) + 6. Provide a clear path for implementation upgrade to WeakMap in 2014 +*/ +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + data_user.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend({ + hasData: function( elem ) { + return data_user.hasData( elem ) || data_priv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return data_user.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + data_user.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to data_priv methods, these can be deprecated. + _data: function( elem, name, data ) { + return data_priv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + data_priv.remove( elem, name ); + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = data_user.get( elem ); + + if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + data_priv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + data_user.set( this, key ); + }); + } + + return access( this, function( value ) { + var data, + camelKey = jQuery.camelCase( key ); + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + // Attempt to get data from the cache + // with the key as-is + data = data_user.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to get data from the cache + // with the key camelized + data = data_user.get( elem, camelKey ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, camelKey, undefined ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each(function() { + // First, attempt to store a copy or reference of any + // data that might've been store with a camelCased key. + var data = data_user.get( this, camelKey ); + + // For HTML5 data-* attribute interop, we have to + // store property names with dashes in a camelCase form. + // This might not apply to all properties...* + data_user.set( this, camelKey, value ); + + // *... In the case of properties that might _actually_ + // have dashes, we need to also store a copy of that + // unchanged property. + if ( key.indexOf("-") !== -1 && data !== undefined ) { + data_user.set( this, key, value ); + } + }); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each(function() { + data_user.remove( this, key ); + }); + } +}); + + +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = data_priv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray( data ) ) { + queue = data_priv.access( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return data_priv.get( elem, key ) || data_priv.access( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + data_priv.remove( elem, [ type + "queue", key ] ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = data_priv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); + }; + +var rcheckableType = (/^(?:checkbox|radio)$/i); + + + +(function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // #11217 - WebKit loses check when the name is after the checked attribute + // Support: Windows Web Apps (WWA) + // `name` and `type` need .setAttribute for WWA + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE9-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +})(); +var strundefined = typeof undefined; + + + +support.focusinBubbles = "onfocusin" in window; + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = data_priv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = data_priv.hasData( elem ) && data_priv.get( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + data_priv.remove( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && jQuery.acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, j, ret, matched, handleObj, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.disabled !== true || event.type !== "click" ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: Cordova 2.5 (WebKit) (#13255) + // All events should have a target; Cordova deviceready doesn't + if ( !event.target ) { + event.target = document; + } + + // Support: Safari 6.0+, Chrome < 28 + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } +}; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + // Support: Android < 4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && e.preventDefault ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && e.stopPropagation ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +// Support: Chrome 15+ +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// Create "bubbling" focus and blur events +// Support: Firefox, Chrome, Safari +if ( !support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = data_priv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + data_priv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = data_priv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + data_priv.remove( doc, fix ); + + } else { + data_priv.access( doc, fix, attaches ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); + + +var + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rhtml = /<|&#?\w+;/, + rnoInnerhtml = /<(?:script|style|link)/i, + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /^$|\/(?:java|ecma)script/i, + rscriptTypeMasked = /^true\/(.*)/, + rcleanScript = /^\s*\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + + // Support: IE 9 + option: [ 1, "" ], + + thead: [ 1, "", "
              " ], + col: [ 2, "", "
              " ], + tr: [ 2, "", "
              " ], + td: [ 3, "", "
              " ], + + _default: [ 0, "", "" ] + }; + +// Support: IE 9 +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: 1.x compatibility +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute("type"); + } + + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + data_priv.set( + elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" ) + ); + } +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( data_priv.hasData( src ) ) { + pdataOld = data_priv.access( src ); + pdataCur = data_priv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( data_user.hasData( src ) ) { + udataOld = data_user.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + data_user.set( dest, udataCur ); + } +} + +function getAll( context, tag ) { + var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) : + context.querySelectorAll ? context.querySelectorAll( tag || "*" ) : + []; + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], ret ) : + ret; +} + +// Support: IE >= 9 +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Support: IE >= 9 + // Fix Cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + // Support: QtWebKit + // jQuery.merge because push.apply(_, arraylike) throws + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: QtWebKit + // jQuery.merge because push.apply(_, arraylike) throws + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Fixes #12346 + // Support: Webkit, IE + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; + }, + + cleanData: function( elems ) { + var data, elem, type, key, + special = jQuery.event.special, + i = 0; + + for ( ; (elem = elems[ i ]) !== undefined; i++ ) { + if ( jQuery.acceptData( elem ) ) { + key = elem[ data_priv.expando ]; + + if ( key && (data = data_priv.cache[ key ]) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + if ( data_priv.cache[ key ] ) { + // Discard any remaining `private` data + delete data_priv.cache[ key ]; + } + } + } + // Discard any remaining `user` data + delete data_user.cache[ elem[ data_user.expando ] ]; + } + } +}); + +jQuery.fn.extend({ + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each(function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + }); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + remove: function( selector, keepData /* Internal Use Only */ ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map(function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var arg = arguments[ 0 ]; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + arg = this.parentNode; + + jQuery.cleanData( getAll( this ) ); + + if ( arg ) { + arg.replaceChild( elem, this ); + } + }); + + // Force removal if there was no new content (e.g., from empty arguments) + return arg && (arg.length || arg.nodeType) ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + self.domManip( args, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + // Support: QtWebKit + // jQuery.merge because push.apply(_, arraylike) throws + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); + } + } + } + } + } + } + + return this; + } +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: QtWebKit + // .get() because push.apply(_, arraylike) throws + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + + +var iframe, + elemdisplay = {}; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var style, + elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + // getDefaultComputedStyle might be reliably used only on attached element + display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? + + // Use of this method is a temporary fix (more like optmization) until something better comes along, + // since it was removed from specification and supported only in FF + style.display : jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = (iframe || jQuery( "' : ''); - inst._keyEvent = false; - return html; - }, - - /* Generate the month and year header. */ - _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, - secondary, monthNames, monthNamesShort) { - var changeMonth = this._get(inst, 'changeMonth'); - var changeYear = this._get(inst, 'changeYear'); - var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); - var html = '
              '; - var monthHtml = ''; - // month selection - if (secondary || !changeMonth) - monthHtml += '' + monthNames[drawMonth] + ''; - else { - var inMinYear = (minDate && minDate.getFullYear() == drawYear); - var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); - monthHtml += ''; - } - if (!showMonthAfterYear) - html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); - // year selection - if ( !inst.yearshtml ) { - inst.yearshtml = ''; - if (secondary || !changeYear) - html += '' + drawYear + ''; - else { - // determine range of years to display - var years = this._get(inst, 'yearRange').split(':'); - var thisYear = new Date().getFullYear(); - var determineYear = function(value) { - var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : - parseInt(value, 10))); - return (isNaN(year) ? thisYear : year); - }; - var year = determineYear(years[0]); - var endYear = Math.max(year, determineYear(years[1] || '')); - year = (minDate ? Math.max(year, minDate.getFullYear()) : year); - endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); - inst.yearshtml += ''; - - html += inst.yearshtml; - inst.yearshtml = null; - } - } - html += this._get(inst, 'yearSuffix'); - if (showMonthAfterYear) - html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; - html += '
              '; // Close datepicker_header - return html; - }, - - /* Adjust one of the date sub-fields. */ - _adjustInstDate: function(inst, offset, period) { - var year = inst.drawYear + (period == 'Y' ? offset : 0); - var month = inst.drawMonth + (period == 'M' ? offset : 0); - var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + - (period == 'D' ? offset : 0); - var date = this._restrictMinMax(inst, - this._daylightSavingAdjust(new Date(year, month, day))); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - if (period == 'M' || period == 'Y') - this._notifyChange(inst); - }, - - /* Ensure a date is within any min/max bounds. */ - _restrictMinMax: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var newDate = (minDate && date < minDate ? minDate : date); - newDate = (maxDate && newDate > maxDate ? maxDate : newDate); - return newDate; - }, - - /* Notify change of month/year. */ - _notifyChange: function(inst) { - var onChange = this._get(inst, 'onChangeMonthYear'); - if (onChange) - onChange.apply((inst.input ? inst.input[0] : null), - [inst.selectedYear, inst.selectedMonth + 1, inst]); - }, - - /* Determine the number of months to show. */ - _getNumberOfMonths: function(inst) { - var numMonths = this._get(inst, 'numberOfMonths'); - return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); - }, - - /* Determine the current maximum date - ensure no time components are set. */ - _getMinMaxDate: function(inst, minMax) { - return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); - }, - - /* Find the number of days in a given month. */ - _getDaysInMonth: function(year, month) { - return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); - }, - - /* Find the day of the week of the first of a month. */ - _getFirstDayOfMonth: function(year, month) { - return new Date(year, month, 1).getDay(); - }, - - /* Determines if we should allow a "next/prev" month display change. */ - _canAdjustMonth: function(inst, offset, curYear, curMonth) { - var numMonths = this._getNumberOfMonths(inst); - var date = this._daylightSavingAdjust(new Date(curYear, - curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); - if (offset < 0) - date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); - return this._isInRange(inst, date); - }, - - /* Is the given date in the accepted range? */ - _isInRange: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - return ((!minDate || date.getTime() >= minDate.getTime()) && - (!maxDate || date.getTime() <= maxDate.getTime())); - }, - - /* Provide the configuration settings for formatting/parsing. */ - _getFormatConfig: function(inst) { - var shortYearCutoff = this._get(inst, 'shortYearCutoff'); - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - return {shortYearCutoff: shortYearCutoff, - dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), - monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; - }, - - /* Format the given date for display. */ - _formatDate: function(inst, day, month, year) { - if (!day) { - inst.currentDay = inst.selectedDay; - inst.currentMonth = inst.selectedMonth; - inst.currentYear = inst.selectedYear; - } - var date = (day ? (typeof day == 'object' ? day : - this._daylightSavingAdjust(new Date(year, month, day))) : - this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); - } -}); - -/* - * Bind hover events for datepicker elements. - * Done via delegate so the binding only occurs once in the lifetime of the parent div. - * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. - */ -function bindHover(dpDiv) { - var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; - return dpDiv.bind('mouseout', function(event) { - var elem = $( event.target ).closest( selector ); - if ( !elem.length ) { - return; - } - elem.removeClass( "ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover" ); - }) - .bind('mouseover', function(event) { - var elem = $( event.target ).closest( selector ); - if ($.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0]) || - !elem.length ) { - return; - } - elem.parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); - elem.addClass('ui-state-hover'); - if (elem.hasClass('ui-datepicker-prev')) elem.addClass('ui-datepicker-prev-hover'); - if (elem.hasClass('ui-datepicker-next')) elem.addClass('ui-datepicker-next-hover'); - }); -} - -/* jQuery extend now ignores nulls! */ -function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) - if (props[name] == null || props[name] == undefined) - target[name] = props[name]; - return target; -}; - -/* Determine whether an object is an array. */ -function isArray(a) { - return (a && (($.browser.safari && typeof a == 'object' && a.length) || - (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); -}; - -/* Invoke the datepicker functionality. - @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality - @return jQuery object */ -$.fn.datepicker = function(options){ - - /* Verify an empty collection wasn't passed - Fixes #6976 */ - if ( !this.length ) { - return this; - } - - /* Initialise the date picker. */ - if (!$.datepicker.initialized) { - $(document).mousedown($.datepicker._checkExternalClick). - find('body').append($.datepicker.dpDiv); - $.datepicker.initialized = true; - } - - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - return this.each(function() { - typeof options == 'string' ? - $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this].concat(otherArgs)) : - $.datepicker._attachDatepicker(this, options); - }); -}; - -$.datepicker = new Datepicker(); // singleton instance -$.datepicker.initialized = false; -$.datepicker.uuid = new Date().getTime(); -$.datepicker.version = "1.8.24"; - -// Workaround for #4055 -// Add another global to avoid noConflict issues with inline event handlers -window['DP_jQuery_' + dpuuid] = $; - -})(jQuery); - -(function( $, undefined ) { - -var uiDialogClasses = - 'ui-dialog ' + - 'ui-widget ' + - 'ui-widget-content ' + - 'ui-corner-all ', - sizeRelatedOptions = { - buttons: true, - height: true, - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true, - width: true - }, - resizableRelatedOptions = { - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true - }; - -$.widget("ui.dialog", { - options: { - autoOpen: true, - buttons: {}, - closeOnEscape: true, - closeText: 'close', - dialogClass: '', - draggable: true, - hide: null, - height: 'auto', - maxHeight: false, - maxWidth: false, - minHeight: 150, - minWidth: 150, - modal: false, - position: { - my: 'center', - at: 'center', - collision: 'fit', - // ensure that the titlebar is never outside the document - using: function(pos) { - var topOffset = $(this).css(pos).offset().top; - if (topOffset < 0) { - $(this).css('top', pos.top - topOffset); - } - } - }, - resizable: true, - show: null, - stack: true, - title: '', - width: 300, - zIndex: 1000 - }, - - _create: function() { - this.originalTitle = this.element.attr('title'); - // #5742 - .attr() might return a DOMElement - if ( typeof this.originalTitle !== "string" ) { - this.originalTitle = ""; - } - - this.options.title = this.options.title || this.originalTitle; - var self = this, - options = self.options, - - title = options.title || ' ', - titleId = $.ui.dialog.getTitleId(self.element), - - uiDialog = (self.uiDialog = $('
              ')) - .appendTo(document.body) - .hide() - .addClass(uiDialogClasses + options.dialogClass) - .css({ - zIndex: options.zIndex - }) - // setting tabIndex makes the div focusable - // setting outline to 0 prevents a border on focus in Mozilla - .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { - if (options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - self.close(event); - event.preventDefault(); - } - }) - .attr({ - role: 'dialog', - 'aria-labelledby': titleId - }) - .mousedown(function(event) { - self.moveToTop(false, event); - }), - - uiDialogContent = self.element - .show() - .removeAttr('title') - .addClass( - 'ui-dialog-content ' + - 'ui-widget-content') - .appendTo(uiDialog), - - uiDialogTitlebar = (self.uiDialogTitlebar = $('
              ')) - .addClass( - 'ui-dialog-titlebar ' + - 'ui-widget-header ' + - 'ui-corner-all ' + - 'ui-helper-clearfix' - ) - .prependTo(uiDialog), - - uiDialogTitlebarClose = $('') - .addClass( - 'ui-dialog-titlebar-close ' + - 'ui-corner-all' - ) - .attr('role', 'button') - .hover( - function() { - uiDialogTitlebarClose.addClass('ui-state-hover'); - }, - function() { - uiDialogTitlebarClose.removeClass('ui-state-hover'); - } - ) - .focus(function() { - uiDialogTitlebarClose.addClass('ui-state-focus'); - }) - .blur(function() { - uiDialogTitlebarClose.removeClass('ui-state-focus'); - }) - .click(function(event) { - self.close(event); - return false; - }) - .appendTo(uiDialogTitlebar), - - uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('')) - .addClass( - 'ui-icon ' + - 'ui-icon-closethick' - ) - .text(options.closeText) - .appendTo(uiDialogTitlebarClose), - - uiDialogTitle = $('') - .addClass('ui-dialog-title') - .attr('id', titleId) - .html(title) - .prependTo(uiDialogTitlebar); - - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) { - options.beforeClose = options.beforeclose; - } - - uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); - - if (options.draggable && $.fn.draggable) { - self._makeDraggable(); - } - if (options.resizable && $.fn.resizable) { - self._makeResizable(); - } - - self._createButtons(options.buttons); - self._isOpen = false; - - if ($.fn.bgiframe) { - uiDialog.bgiframe(); - } - }, - - _init: function() { - if ( this.options.autoOpen ) { - this.open(); - } - }, - - destroy: function() { - var self = this; - - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.hide(); - self.element - .unbind('.dialog') - .removeData('dialog') - .removeClass('ui-dialog-content ui-widget-content') - .hide().appendTo('body'); - self.uiDialog.remove(); - - if (self.originalTitle) { - self.element.attr('title', self.originalTitle); - } - - return self; - }, - - widget: function() { - return this.uiDialog; - }, - - close: function(event) { - var self = this, - maxZ, thisZ; - - if (false === self._trigger('beforeClose', event)) { - return; - } - - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.unbind('keypress.ui-dialog'); - - self._isOpen = false; - - if (self.options.hide) { - self.uiDialog.hide(self.options.hide, function() { - self._trigger('close', event); - }); - } else { - self.uiDialog.hide(); - self._trigger('close', event); - } - - $.ui.dialog.overlay.resize(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - if (self.options.modal) { - maxZ = 0; - $('.ui-dialog').each(function() { - if (this !== self.uiDialog[0]) { - thisZ = $(this).css('z-index'); - if(!isNaN(thisZ)) { - maxZ = Math.max(maxZ, thisZ); - } - } - }); - $.ui.dialog.maxZ = maxZ; - } - - return self; - }, - - isOpen: function() { - return this._isOpen; - }, - - // the force parameter allows us to move modal dialogs to their correct - // position on open - moveToTop: function(force, event) { - var self = this, - options = self.options, - saveScroll; - - if ((options.modal && !force) || - (!options.stack && !options.modal)) { - return self._trigger('focus', event); - } - - if (options.zIndex > $.ui.dialog.maxZ) { - $.ui.dialog.maxZ = options.zIndex; - } - if (self.overlay) { - $.ui.dialog.maxZ += 1; - self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ); - } - - //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. - // http://ui.jquery.com/bugs/ticket/3193 - saveScroll = { scrollTop: self.element.scrollTop(), scrollLeft: self.element.scrollLeft() }; - $.ui.dialog.maxZ += 1; - self.uiDialog.css('z-index', $.ui.dialog.maxZ); - self.element.attr(saveScroll); - self._trigger('focus', event); - - return self; - }, - - open: function() { - if (this._isOpen) { return; } - - var self = this, - options = self.options, - uiDialog = self.uiDialog; - - self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null; - self._size(); - self._position(options.position); - uiDialog.show(options.show); - self.moveToTop(true); - - // prevent tabbing out of modal dialogs - if ( options.modal ) { - uiDialog.bind( "keydown.ui-dialog", function( event ) { - if ( event.keyCode !== $.ui.keyCode.TAB ) { - return; - } - - var tabbables = $(':tabbable', this), - first = tabbables.filter(':first'), - last = tabbables.filter(':last'); - - if (event.target === last[0] && !event.shiftKey) { - first.focus(1); - return false; - } else if (event.target === first[0] && event.shiftKey) { - last.focus(1); - return false; - } - }); - } - - // set focus to the first tabbable element in the content area or the first button - // if there are no tabbable elements, set focus on the dialog itself - $(self.element.find(':tabbable').get().concat( - uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat( - uiDialog.get()))).eq(0).focus(); - - self._isOpen = true; - self._trigger('open'); - - return self; - }, - - _createButtons: function(buttons) { - var self = this, - hasButtons = false, - uiDialogButtonPane = $('
              ') - .addClass( - 'ui-dialog-buttonpane ' + - 'ui-widget-content ' + - 'ui-helper-clearfix' - ), - uiButtonSet = $( "
              " ) - .addClass( "ui-dialog-buttonset" ) - .appendTo( uiDialogButtonPane ); - - // if we already have a button pane, remove it - self.uiDialog.find('.ui-dialog-buttonpane').remove(); - - if (typeof buttons === 'object' && buttons !== null) { - $.each(buttons, function() { - return !(hasButtons = true); - }); - } - if (hasButtons) { - $.each(buttons, function(name, props) { - props = $.isFunction( props ) ? - { click: props, text: name } : - props; - var button = $('') - .click(function() { - props.click.apply(self.element[0], arguments); - }) - .appendTo(uiButtonSet); - // can't use .attr( props, true ) with jQuery 1.3.2. - $.each( props, function( key, value ) { - if ( key === "click" ) { - return; - } - if ( key in button ) { - button[ key ]( value ); - } else { - button.attr( key, value ); - } - }); - if ($.fn.button) { - button.button(); - } - }); - uiDialogButtonPane.appendTo(self.uiDialog); - } - }, - - _makeDraggable: function() { - var self = this, - options = self.options, - doc = $(document), - heightBeforeDrag; - - function filteredUi(ui) { - return { - position: ui.position, - offset: ui.offset - }; - } - - self.uiDialog.draggable({ - cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', - handle: '.ui-dialog-titlebar', - containment: 'document', - start: function(event, ui) { - heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height(); - $(this).height($(this).height()).addClass("ui-dialog-dragging"); - self._trigger('dragStart', event, filteredUi(ui)); - }, - drag: function(event, ui) { - self._trigger('drag', event, filteredUi(ui)); - }, - stop: function(event, ui) { - options.position = [ui.position.left - doc.scrollLeft(), - ui.position.top - doc.scrollTop()]; - $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); - self._trigger('dragStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }); - }, - - _makeResizable: function(handles) { - handles = (handles === undefined ? this.options.resizable : handles); - var self = this, - options = self.options, - // .ui-resizable has position: relative defined in the stylesheet - // but dialogs have to use absolute or fixed positioning - position = self.uiDialog.css('position'), - resizeHandles = (typeof handles === 'string' ? - handles : - 'n,e,s,w,se,sw,ne,nw' - ); - - function filteredUi(ui) { - return { - originalPosition: ui.originalPosition, - originalSize: ui.originalSize, - position: ui.position, - size: ui.size - }; - } - - self.uiDialog.resizable({ - cancel: '.ui-dialog-content', - containment: 'document', - alsoResize: self.element, - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - minWidth: options.minWidth, - minHeight: self._minHeight(), - handles: resizeHandles, - start: function(event, ui) { - $(this).addClass("ui-dialog-resizing"); - self._trigger('resizeStart', event, filteredUi(ui)); - }, - resize: function(event, ui) { - self._trigger('resize', event, filteredUi(ui)); - }, - stop: function(event, ui) { - $(this).removeClass("ui-dialog-resizing"); - options.height = $(this).height(); - options.width = $(this).width(); - self._trigger('resizeStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }) - .css('position', position) - .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); - }, - - _minHeight: function() { - var options = this.options; - - if (options.height === 'auto') { - return options.minHeight; - } else { - return Math.min(options.minHeight, options.height); - } - }, - - _position: function(position) { - var myAt = [], - offset = [0, 0], - isVisible; - - if (position) { - // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( - // if (typeof position == 'string' || $.isArray(position)) { - // myAt = $.isArray(position) ? position : position.split(' '); - - if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) { - myAt = position.split ? position.split(' ') : [position[0], position[1]]; - if (myAt.length === 1) { - myAt[1] = myAt[0]; - } - - $.each(['left', 'top'], function(i, offsetPosition) { - if (+myAt[i] === myAt[i]) { - offset[i] = myAt[i]; - myAt[i] = offsetPosition; - } - }); - - position = { - my: myAt.join(" "), - at: myAt.join(" "), - offset: offset.join(" ") - }; - } - - position = $.extend({}, $.ui.dialog.prototype.options.position, position); - } else { - position = $.ui.dialog.prototype.options.position; - } - - // need to show the dialog to get the actual offset in the position plugin - isVisible = this.uiDialog.is(':visible'); - if (!isVisible) { - this.uiDialog.show(); - } - this.uiDialog - // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 - .css({ top: 0, left: 0 }) - .position($.extend({ of: window }, position)); - if (!isVisible) { - this.uiDialog.hide(); - } - }, - - _setOptions: function( options ) { - var self = this, - resizableOptions = {}, - resize = false; - - $.each( options, function( key, value ) { - self._setOption( key, value ); - - if ( key in sizeRelatedOptions ) { - resize = true; - } - if ( key in resizableRelatedOptions ) { - resizableOptions[ key ] = value; - } - }); - - if ( resize ) { - this._size(); - } - if ( this.uiDialog.is( ":data(resizable)" ) ) { - this.uiDialog.resizable( "option", resizableOptions ); - } - }, - - _setOption: function(key, value){ - var self = this, - uiDialog = self.uiDialog; - - switch (key) { - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - case "beforeclose": - key = "beforeClose"; - break; - case "buttons": - self._createButtons(value); - break; - case "closeText": - // ensure that we always pass a string - self.uiDialogTitlebarCloseText.text("" + value); - break; - case "dialogClass": - uiDialog - .removeClass(self.options.dialogClass) - .addClass(uiDialogClasses + value); - break; - case "disabled": - if (value) { - uiDialog.addClass('ui-dialog-disabled'); - } else { - uiDialog.removeClass('ui-dialog-disabled'); - } - break; - case "draggable": - var isDraggable = uiDialog.is( ":data(draggable)" ); - if ( isDraggable && !value ) { - uiDialog.draggable( "destroy" ); - } - - if ( !isDraggable && value ) { - self._makeDraggable(); - } - break; - case "position": - self._position(value); - break; - case "resizable": - // currently resizable, becoming non-resizable - var isResizable = uiDialog.is( ":data(resizable)" ); - if (isResizable && !value) { - uiDialog.resizable('destroy'); - } - - // currently resizable, changing handles - if (isResizable && typeof value === 'string') { - uiDialog.resizable('option', 'handles', value); - } - - // currently non-resizable, becoming resizable - if (!isResizable && value !== false) { - self._makeResizable(value); - } - break; - case "title": - // convert whatever was passed in o a string, for html() to not throw up - $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' ')); - break; - } - - $.Widget.prototype._setOption.apply(self, arguments); - }, - - _size: function() { - /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - * divs will both have width and height set, so we need to reset them - */ - var options = this.options, - nonContentHeight, - minContentHeight, - isVisible = this.uiDialog.is( ":visible" ); - - // reset content sizing - this.element.show().css({ - width: 'auto', - minHeight: 0, - height: 0 - }); - - if (options.minWidth > options.width) { - options.width = options.minWidth; - } - - // reset wrapper sizing - // determine the height of all the non-content elements - nonContentHeight = this.uiDialog.css({ - height: 'auto', - width: options.width - }) - .height(); - minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); - - if ( options.height === "auto" ) { - // only needed for IE6 support - if ( $.support.minHeight ) { - this.element.css({ - minHeight: minContentHeight, - height: "auto" - }); - } else { - this.uiDialog.show(); - var autoHeight = this.element.css( "height", "auto" ).height(); - if ( !isVisible ) { - this.uiDialog.hide(); - } - this.element.height( Math.max( autoHeight, minContentHeight ) ); - } - } else { - this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); - } - - if (this.uiDialog.is(':data(resizable)')) { - this.uiDialog.resizable('option', 'minHeight', this._minHeight()); - } - } -}); - -$.extend($.ui.dialog, { - version: "1.8.24", - - uuid: 0, - maxZ: 0, - - getTitleId: function($el) { - var id = $el.attr('id'); - if (!id) { - this.uuid += 1; - id = this.uuid; - } - return 'ui-dialog-title-' + id; - }, - - overlay: function(dialog) { - this.$el = $.ui.dialog.overlay.create(dialog); - } -}); - -$.extend($.ui.dialog.overlay, { - instances: [], - // reuse old instances due to IE memory leak with alpha transparency (see #5185) - oldInstances: [], - maxZ: 0, - events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), - function(event) { return event + '.dialog-overlay'; }).join(' '), - create: function(dialog) { - if (this.instances.length === 0) { - // prevent use of anchors and inputs - // we use a setTimeout in case the overlay is created from an - // event that we're going to be cancelling (see #2804) - setTimeout(function() { - // handle $(el).dialog().dialog('close') (see #4065) - if ($.ui.dialog.overlay.instances.length) { - $(document).bind($.ui.dialog.overlay.events, function(event) { - // stop events if the z-index of the target is < the z-index of the overlay - // we cannot return true when we don't want to cancel the event (#3523) - if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) { - return false; - } - }); - } - }, 1); - - // allow closing by pressing the escape key - $(document).bind('keydown.dialog-overlay', function(event) { - if (dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - dialog.close(event); - event.preventDefault(); - } - }); - - // handle window resize - $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); - } - - var $el = (this.oldInstances.pop() || $('
              ').addClass('ui-widget-overlay')) - .appendTo(document.body) - .css({ - width: this.width(), - height: this.height() - }); - - if ($.fn.bgiframe) { - $el.bgiframe(); - } - - this.instances.push($el); - return $el; - }, - - destroy: function($el) { - var indexOf = $.inArray($el, this.instances); - if (indexOf != -1){ - this.oldInstances.push(this.instances.splice(indexOf, 1)[0]); - } - - if (this.instances.length === 0) { - $([document, window]).unbind('.dialog-overlay'); - } - - $el.remove(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - var maxZ = 0; - $.each(this.instances, function() { - maxZ = Math.max(maxZ, this.css('z-index')); - }); - this.maxZ = maxZ; - }, - - height: function() { - var scrollHeight, - offsetHeight; - // handle IE 6 - if ($.browser.msie && $.browser.version < 7) { - scrollHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight - ); - offsetHeight = Math.max( - document.documentElement.offsetHeight, - document.body.offsetHeight - ); - - if (scrollHeight < offsetHeight) { - return $(window).height() + 'px'; - } else { - return scrollHeight + 'px'; - } - // handle "good" browsers - } else { - return $(document).height() + 'px'; - } - }, - - width: function() { - var scrollWidth, - offsetWidth; - // handle IE - if ( $.browser.msie ) { - scrollWidth = Math.max( - document.documentElement.scrollWidth, - document.body.scrollWidth - ); - offsetWidth = Math.max( - document.documentElement.offsetWidth, - document.body.offsetWidth - ); - - if (scrollWidth < offsetWidth) { - return $(window).width() + 'px'; - } else { - return scrollWidth + 'px'; - } - // handle "good" browsers - } else { - return $(document).width() + 'px'; - } - }, - - resize: function() { - /* If the dialog is draggable and the user drags it past the - * right edge of the window, the document becomes wider so we - * need to stretch the overlay. If the user then drags the - * dialog back to the left, the document will become narrower, - * so we need to shrink the overlay to the appropriate size. - * This is handled by shrinking the overlay before setting it - * to the full document size. - */ - var $overlays = $([]); - $.each($.ui.dialog.overlay.instances, function() { - $overlays = $overlays.add(this); - }); - - $overlays.css({ - width: 0, - height: 0 - }).css({ - width: $.ui.dialog.overlay.width(), - height: $.ui.dialog.overlay.height() - }); - } -}); - -$.extend($.ui.dialog.overlay.prototype, { - destroy: function() { - $.ui.dialog.overlay.destroy(this.$el); - } -}); - -}(jQuery)); - -(function( $, undefined ) { - -$.ui = $.ui || {}; - -var horizontalPositions = /left|center|right/, - verticalPositions = /top|center|bottom/, - center = "center", - support = {}, - _position = $.fn.position, - _offset = $.fn.offset; - -$.fn.position = function( options ) { - if ( !options || !options.of ) { - return _position.apply( this, arguments ); - } - - // make a copy, we don't want to modify arguments - options = $.extend( {}, options ); - - var target = $( options.of ), - targetElem = target[0], - collision = ( options.collision || "flip" ).split( " " ), - offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], - targetWidth, - targetHeight, - basePosition; - - if ( targetElem.nodeType === 9 ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: 0, left: 0 }; - // TODO: use $.isWindow() in 1.9 - } else if ( targetElem.setTimeout ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; - } else if ( targetElem.preventDefault ) { - // force left top to allow flipping - options.at = "left top"; - targetWidth = targetHeight = 0; - basePosition = { top: options.of.pageY, left: options.of.pageX }; - } else { - targetWidth = target.outerWidth(); - targetHeight = target.outerHeight(); - basePosition = target.offset(); - } - - // force my and at to have valid horizontal and veritcal positions - // if a value is missing or invalid, it will be converted to center - $.each( [ "my", "at" ], function() { - var pos = ( options[this] || "" ).split( " " ); - if ( pos.length === 1) { - pos = horizontalPositions.test( pos[0] ) ? - pos.concat( [center] ) : - verticalPositions.test( pos[0] ) ? - [ center ].concat( pos ) : - [ center, center ]; - } - pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center; - pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center; - options[ this ] = pos; - }); - - // normalize collision option - if ( collision.length === 1 ) { - collision[ 1 ] = collision[ 0 ]; - } - - // normalize offset option - offset[ 0 ] = parseInt( offset[0], 10 ) || 0; - if ( offset.length === 1 ) { - offset[ 1 ] = offset[ 0 ]; - } - offset[ 1 ] = parseInt( offset[1], 10 ) || 0; - - if ( options.at[0] === "right" ) { - basePosition.left += targetWidth; - } else if ( options.at[0] === center ) { - basePosition.left += targetWidth / 2; - } - - if ( options.at[1] === "bottom" ) { - basePosition.top += targetHeight; - } else if ( options.at[1] === center ) { - basePosition.top += targetHeight / 2; - } - - basePosition.left += offset[ 0 ]; - basePosition.top += offset[ 1 ]; - - return this.each(function() { - var elem = $( this ), - elemWidth = elem.outerWidth(), - elemHeight = elem.outerHeight(), - marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0, - marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0, - collisionWidth = elemWidth + marginLeft + - ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ), - collisionHeight = elemHeight + marginTop + - ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ), - position = $.extend( {}, basePosition ), - collisionPosition; - - if ( options.my[0] === "right" ) { - position.left -= elemWidth; - } else if ( options.my[0] === center ) { - position.left -= elemWidth / 2; - } - - if ( options.my[1] === "bottom" ) { - position.top -= elemHeight; - } else if ( options.my[1] === center ) { - position.top -= elemHeight / 2; - } - - // prevent fractions if jQuery version doesn't support them (see #5280) - if ( !support.fractions ) { - position.left = Math.round( position.left ); - position.top = Math.round( position.top ); - } - - collisionPosition = { - left: position.left - marginLeft, - top: position.top - marginTop - }; - - $.each( [ "left", "top" ], function( i, dir ) { - if ( $.ui.position[ collision[i] ] ) { - $.ui.position[ collision[i] ][ dir ]( position, { - targetWidth: targetWidth, - targetHeight: targetHeight, - elemWidth: elemWidth, - elemHeight: elemHeight, - collisionPosition: collisionPosition, - collisionWidth: collisionWidth, - collisionHeight: collisionHeight, - offset: offset, - my: options.my, - at: options.at - }); - } - }); - - if ( $.fn.bgiframe ) { - elem.bgiframe(); - } - elem.offset( $.extend( position, { using: options.using } ) ); - }); -}; - -$.ui.position = { - fit: { - left: function( position, data ) { - var win = $( window ), - over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(); - position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left ); - }, - top: function( position, data ) { - var win = $( window ), - over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(); - position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top ); - } - }, - - flip: { - left: function( position, data ) { - if ( data.at[0] === center ) { - return; - } - var win = $( window ), - over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), - myOffset = data.my[ 0 ] === "left" ? - -data.elemWidth : - data.my[ 0 ] === "right" ? - data.elemWidth : - 0, - atOffset = data.at[ 0 ] === "left" ? - data.targetWidth : - -data.targetWidth, - offset = -2 * data.offset[ 0 ]; - position.left += data.collisionPosition.left < 0 ? - myOffset + atOffset + offset : - over > 0 ? - myOffset + atOffset + offset : - 0; - }, - top: function( position, data ) { - if ( data.at[1] === center ) { - return; - } - var win = $( window ), - over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), - myOffset = data.my[ 1 ] === "top" ? - -data.elemHeight : - data.my[ 1 ] === "bottom" ? - data.elemHeight : - 0, - atOffset = data.at[ 1 ] === "top" ? - data.targetHeight : - -data.targetHeight, - offset = -2 * data.offset[ 1 ]; - position.top += data.collisionPosition.top < 0 ? - myOffset + atOffset + offset : - over > 0 ? - myOffset + atOffset + offset : - 0; - } - } -}; - -// offset setter from jQuery 1.4 -if ( !$.offset.setOffset ) { - $.offset.setOffset = function( elem, options ) { - // set position first, in-case top/left are set even on static elem - if ( /static/.test( $.curCSS( elem, "position" ) ) ) { - elem.style.position = "relative"; - } - var curElem = $( elem ), - curOffset = curElem.offset(), - curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0, - curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0, - props = { - top: (options.top - curOffset.top) + curTop, - left: (options.left - curOffset.left) + curLeft - }; - - if ( 'using' in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - }; - - $.fn.offset = function( options ) { - var elem = this[ 0 ]; - if ( !elem || !elem.ownerDocument ) { return null; } - if ( options ) { - if ( $.isFunction( options ) ) { - return this.each(function( i ) { - $( this ).offset( options.call( this, i, $( this ).offset() ) ); - }); - } - return this.each(function() { - $.offset.setOffset( this, options ); - }); - } - return _offset.call( this ); - }; -} - -// jQuery <1.4.3 uses curCSS, in 1.4.3 - 1.7.2 curCSS = css, 1.8+ only has css -if ( !$.curCSS ) { - $.curCSS = $.css; -} - -// fraction support test (older versions of jQuery don't support fractions) -(function () { - var body = document.getElementsByTagName( "body" )[ 0 ], - div = document.createElement( "div" ), - testElement, testElementParent, testElementStyle, offset, offsetTotal; - - //Create a "fake body" for testing based on method used in jQuery.support - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - $.extend( testElementStyle, { - position: "absolute", - left: "-1000px", - top: "-1000px" - }); - } - for ( var i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || document.documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - div.style.cssText = "position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;"; - - offset = $( div ).offset( function( _, offset ) { - return offset; - }).offset(); - - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); - - offsetTotal = offset.top + offset.left + ( body ? 2000 : 0 ); - support.fractions = offsetTotal > 21 && offsetTotal < 22; -})(); - -}( jQuery )); - -(function( $, undefined ) { - -$.widget( "ui.progressbar", { - options: { - value: 0, - max: 100 - }, - - min: 0, - - _create: function() { - this.element - .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .attr({ - role: "progressbar", - "aria-valuemin": this.min, - "aria-valuemax": this.options.max, - "aria-valuenow": this._value() - }); - - this.valueDiv = $( "
              " ) - .appendTo( this.element ); - - this.oldValue = this._value(); - this._refreshValue(); - }, - - destroy: function() { - this.element - .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - - this.valueDiv.remove(); - - $.Widget.prototype.destroy.apply( this, arguments ); - }, - - value: function( newValue ) { - if ( newValue === undefined ) { - return this._value(); - } - - this._setOption( "value", newValue ); - return this; - }, - - _setOption: function( key, value ) { - if ( key === "value" ) { - this.options.value = value; - this._refreshValue(); - if ( this._value() === this.options.max ) { - this._trigger( "complete" ); - } - } - - $.Widget.prototype._setOption.apply( this, arguments ); - }, - - _value: function() { - var val = this.options.value; - // normalize invalid value - if ( typeof val !== "number" ) { - val = 0; - } - return Math.min( this.options.max, Math.max( this.min, val ) ); - }, - - _percentage: function() { - return 100 * this._value() / this.options.max; - }, - - _refreshValue: function() { - var value = this.value(); - var percentage = this._percentage(); - - if ( this.oldValue !== value ) { - this.oldValue = value; - this._trigger( "change" ); - } - - this.valueDiv - .toggle( value > this.min ) - .toggleClass( "ui-corner-right", value === this.options.max ) - .width( percentage.toFixed(0) + "%" ); - this.element.attr( "aria-valuenow", value ); - } -}); - -$.extend( $.ui.progressbar, { - version: "1.8.24" -}); - -})( jQuery ); - -(function( $, undefined ) { - -// number of pages in a slider -// (how many times can you page up/down to go through the whole range) -var numPages = 5; - -$.widget( "ui.slider", $.ui.mouse, { - - widgetEventPrefix: "slide", - - options: { - animate: false, - distance: 0, - max: 100, - min: 0, - orientation: "horizontal", - range: false, - step: 1, - value: 0, - values: null - }, - - _create: function() { - var self = this, - o = this.options, - existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), - handle = "", - handleCount = ( o.values && o.values.length ) || 1, - handles = []; - - this._keySliding = false; - this._mouseSliding = false; - this._animateOff = true; - this._handleIndex = null; - this._detectOrientation(); - this._mouseInit(); - - this.element - .addClass( "ui-slider" + - " ui-slider-" + this.orientation + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" + - ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) ); - - this.range = $([]); - - if ( o.range ) { - if ( o.range === true ) { - if ( !o.values ) { - o.values = [ this._valueMin(), this._valueMin() ]; - } - if ( o.values.length && o.values.length !== 2 ) { - o.values = [ o.values[0], o.values[0] ]; - } - } - - this.range = $( "
              " ) - .appendTo( this.element ) - .addClass( "ui-slider-range" + - // note: this isn't the most fittingly semantic framework class for this element, - // but worked best visually with a variety of themes - " ui-widget-header" + - ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); - } - - for ( var i = existingHandles.length; i < handleCount; i += 1 ) { - handles.push( handle ); - } - - this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( self.element ) ); - - this.handle = this.handles.eq( 0 ); - - this.handles.add( this.range ).filter( "a" ) - .click(function( event ) { - event.preventDefault(); - }) - .hover(function() { - if ( !o.disabled ) { - $( this ).addClass( "ui-state-hover" ); - } - }, function() { - $( this ).removeClass( "ui-state-hover" ); - }) - .focus(function() { - if ( !o.disabled ) { - $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); - $( this ).addClass( "ui-state-focus" ); - } else { - $( this ).blur(); - } - }) - .blur(function() { - $( this ).removeClass( "ui-state-focus" ); - }); - - this.handles.each(function( i ) { - $( this ).data( "index.ui-slider-handle", i ); - }); - - this.handles - .keydown(function( event ) { - var index = $( this ).data( "index.ui-slider-handle" ), - allowed, - curVal, - newVal, - step; - - if ( self.options.disabled ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.PAGE_UP: - case $.ui.keyCode.PAGE_DOWN: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - event.preventDefault(); - if ( !self._keySliding ) { - self._keySliding = true; - $( this ).addClass( "ui-state-active" ); - allowed = self._start( event, index ); - if ( allowed === false ) { - return; - } - } - break; - } - - step = self.options.step; - if ( self.options.values && self.options.values.length ) { - curVal = newVal = self.values( index ); - } else { - curVal = newVal = self.value(); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - newVal = self._valueMin(); - break; - case $.ui.keyCode.END: - newVal = self._valueMax(); - break; - case $.ui.keyCode.PAGE_UP: - newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.PAGE_DOWN: - newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - if ( curVal === self._valueMax() ) { - return; - } - newVal = self._trimAlignValue( curVal + step ); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if ( curVal === self._valueMin() ) { - return; - } - newVal = self._trimAlignValue( curVal - step ); - break; - } - - self._slide( event, index, newVal ); - }) - .keyup(function( event ) { - var index = $( this ).data( "index.ui-slider-handle" ); - - if ( self._keySliding ) { - self._keySliding = false; - self._stop( event, index ); - self._change( event, index ); - $( this ).removeClass( "ui-state-active" ); - } - - }); - - this._refreshValue(); - - this._animateOff = false; - }, - - destroy: function() { - this.handles.remove(); - this.range.remove(); - - this.element - .removeClass( "ui-slider" + - " ui-slider-horizontal" + - " ui-slider-vertical" + - " ui-slider-disabled" + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" ) - .removeData( "slider" ) - .unbind( ".slider" ); - - this._mouseDestroy(); - - return this; - }, - - _mouseCapture: function( event ) { - var o = this.options, - position, - normValue, - distance, - closestHandle, - self, - index, - allowed, - offset, - mouseOverHandle; - - if ( o.disabled ) { - return false; - } - - this.elementSize = { - width: this.element.outerWidth(), - height: this.element.outerHeight() - }; - this.elementOffset = this.element.offset(); - - position = { x: event.pageX, y: event.pageY }; - normValue = this._normValueFromMouse( position ); - distance = this._valueMax() - this._valueMin() + 1; - self = this; - this.handles.each(function( i ) { - var thisDistance = Math.abs( normValue - self.values(i) ); - if ( distance > thisDistance ) { - distance = thisDistance; - closestHandle = $( this ); - index = i; - } - }); - - // workaround for bug #3736 (if both handles of a range are at 0, - // the first is always used as the one with least distance, - // and moving it is obviously prevented by preventing negative ranges) - if( o.range === true && this.values(1) === o.min ) { - index += 1; - closestHandle = $( this.handles[index] ); - } - - allowed = this._start( event, index ); - if ( allowed === false ) { - return false; - } - this._mouseSliding = true; - - self._handleIndex = index; - - closestHandle - .addClass( "ui-state-active" ) - .focus(); - - offset = closestHandle.offset(); - mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); - this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { - left: event.pageX - offset.left - ( closestHandle.width() / 2 ), - top: event.pageY - offset.top - - ( closestHandle.height() / 2 ) - - ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - - ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + - ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) - }; - - if ( !this.handles.hasClass( "ui-state-hover" ) ) { - this._slide( event, index, normValue ); - } - this._animateOff = true; - return true; - }, - - _mouseStart: function( event ) { - return true; - }, - - _mouseDrag: function( event ) { - var position = { x: event.pageX, y: event.pageY }, - normValue = this._normValueFromMouse( position ); - - this._slide( event, this._handleIndex, normValue ); - - return false; - }, - - _mouseStop: function( event ) { - this.handles.removeClass( "ui-state-active" ); - this._mouseSliding = false; - - this._stop( event, this._handleIndex ); - this._change( event, this._handleIndex ); - - this._handleIndex = null; - this._clickOffset = null; - this._animateOff = false; - - return false; - }, - - _detectOrientation: function() { - this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; - }, - - _normValueFromMouse: function( position ) { - var pixelTotal, - pixelMouse, - percentMouse, - valueTotal, - valueMouse; - - if ( this.orientation === "horizontal" ) { - pixelTotal = this.elementSize.width; - pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); - } else { - pixelTotal = this.elementSize.height; - pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); - } - - percentMouse = ( pixelMouse / pixelTotal ); - if ( percentMouse > 1 ) { - percentMouse = 1; - } - if ( percentMouse < 0 ) { - percentMouse = 0; - } - if ( this.orientation === "vertical" ) { - percentMouse = 1 - percentMouse; - } - - valueTotal = this._valueMax() - this._valueMin(); - valueMouse = this._valueMin() + percentMouse * valueTotal; - - return this._trimAlignValue( valueMouse ); - }, - - _start: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - return this._trigger( "start", event, uiHash ); - }, - - _slide: function( event, index, newVal ) { - var otherVal, - newValues, - allowed; - - if ( this.options.values && this.options.values.length ) { - otherVal = this.values( index ? 0 : 1 ); - - if ( ( this.options.values.length === 2 && this.options.range === true ) && - ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) - ) { - newVal = otherVal; - } - - if ( newVal !== this.values( index ) ) { - newValues = this.values(); - newValues[ index ] = newVal; - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal, - values: newValues - } ); - otherVal = this.values( index ? 0 : 1 ); - if ( allowed !== false ) { - this.values( index, newVal, true ); - } - } - } else { - if ( newVal !== this.value() ) { - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal - } ); - if ( allowed !== false ) { - this.value( newVal ); - } - } - } - }, - - _stop: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "stop", event, uiHash ); - }, - - _change: function( event, index ) { - if ( !this._keySliding && !this._mouseSliding ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "change", event, uiHash ); - } - }, - - value: function( newValue ) { - if ( arguments.length ) { - this.options.value = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, 0 ); - return; - } - - return this._value(); - }, - - values: function( index, newValue ) { - var vals, - newValues, - i; - - if ( arguments.length > 1 ) { - this.options.values[ index ] = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, index ); - return; - } - - if ( arguments.length ) { - if ( $.isArray( arguments[ 0 ] ) ) { - vals = this.options.values; - newValues = arguments[ 0 ]; - for ( i = 0; i < vals.length; i += 1 ) { - vals[ i ] = this._trimAlignValue( newValues[ i ] ); - this._change( null, i ); - } - this._refreshValue(); - } else { - if ( this.options.values && this.options.values.length ) { - return this._values( index ); - } else { - return this.value(); - } - } - } else { - return this._values(); - } - }, - - _setOption: function( key, value ) { - var i, - valsLength = 0; - - if ( $.isArray( this.options.values ) ) { - valsLength = this.options.values.length; - } - - $.Widget.prototype._setOption.apply( this, arguments ); - - switch ( key ) { - case "disabled": - if ( value ) { - this.handles.filter( ".ui-state-focus" ).blur(); - this.handles.removeClass( "ui-state-hover" ); - this.handles.propAttr( "disabled", true ); - this.element.addClass( "ui-disabled" ); - } else { - this.handles.propAttr( "disabled", false ); - this.element.removeClass( "ui-disabled" ); - } - break; - case "orientation": - this._detectOrientation(); - this.element - .removeClass( "ui-slider-horizontal ui-slider-vertical" ) - .addClass( "ui-slider-" + this.orientation ); - this._refreshValue(); - break; - case "value": - this._animateOff = true; - this._refreshValue(); - this._change( null, 0 ); - this._animateOff = false; - break; - case "values": - this._animateOff = true; - this._refreshValue(); - for ( i = 0; i < valsLength; i += 1 ) { - this._change( null, i ); - } - this._animateOff = false; - break; - } - }, - - //internal value getter - // _value() returns value trimmed by min and max, aligned by step - _value: function() { - var val = this.options.value; - val = this._trimAlignValue( val ); - - return val; - }, - - //internal values getter - // _values() returns array of values trimmed by min and max, aligned by step - // _values( index ) returns single value trimmed by min and max, aligned by step - _values: function( index ) { - var val, - vals, - i; - - if ( arguments.length ) { - val = this.options.values[ index ]; - val = this._trimAlignValue( val ); - - return val; - } else { - // .slice() creates a copy of the array - // this copy gets trimmed by min and max and then returned - vals = this.options.values.slice(); - for ( i = 0; i < vals.length; i+= 1) { - vals[ i ] = this._trimAlignValue( vals[ i ] ); - } - - return vals; - } - }, - - // returns the step-aligned value that val is closest to, between (inclusive) min and max - _trimAlignValue: function( val ) { - if ( val <= this._valueMin() ) { - return this._valueMin(); - } - if ( val >= this._valueMax() ) { - return this._valueMax(); - } - var step = ( this.options.step > 0 ) ? this.options.step : 1, - valModStep = (val - this._valueMin()) % step, - alignValue = val - valModStep; - - if ( Math.abs(valModStep) * 2 >= step ) { - alignValue += ( valModStep > 0 ) ? step : ( -step ); - } - - // Since JavaScript has problems with large floats, round - // the final value to 5 digits after the decimal point (see #4124) - return parseFloat( alignValue.toFixed(5) ); - }, - - _valueMin: function() { - return this.options.min; - }, - - _valueMax: function() { - return this.options.max; - }, - - _refreshValue: function() { - var oRange = this.options.range, - o = this.options, - self = this, - animate = ( !this._animateOff ) ? o.animate : false, - valPercent, - _set = {}, - lastValPercent, - value, - valueMin, - valueMax; - - if ( this.options.values && this.options.values.length ) { - this.handles.each(function( i, j ) { - valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - if ( self.options.range === true ) { - if ( self.orientation === "horizontal" ) { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } else { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - lastValPercent = valPercent; - }); - } else { - value = this.value(); - valueMin = this._valueMin(); - valueMax = this._valueMax(); - valPercent = ( valueMax !== valueMin ) ? - ( value - valueMin ) / ( valueMax - valueMin ) * 100 : - 0; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - - if ( oRange === "min" && this.orientation === "horizontal" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "horizontal" ) { - this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - if ( oRange === "min" && this.orientation === "vertical" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "vertical" ) { - this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - -}); - -$.extend( $.ui.slider, { - version: "1.8.24" -}); - -}(jQuery)); - -(function( $, undefined ) { - -var tabId = 0, - listId = 0; - -function getNextTabId() { - return ++tabId; -} - -function getNextListId() { - return ++listId; -} - -$.widget( "ui.tabs", { - options: { - add: null, - ajaxOptions: null, - cache: false, - cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } - collapsible: false, - disable: null, - disabled: [], - enable: null, - event: "click", - fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } - idPrefix: "ui-tabs-", - load: null, - panelTemplate: "
              ", - remove: null, - select: null, - show: null, - spinner: "Loading…", - tabTemplate: "
            • #{label}
            • " - }, - - _create: function() { - this._tabify( true ); - }, - - _setOption: function( key, value ) { - if ( key == "selected" ) { - if (this.options.collapsible && value == this.options.selected ) { - return; - } - this.select( value ); - } else { - this.options[ key ] = value; - this._tabify(); - } - }, - - _tabId: function( a ) { - return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || - this.options.idPrefix + getNextTabId(); - }, - - _sanitizeSelector: function( hash ) { - // we need this because an id may contain a ":" - return hash.replace( /:/g, "\\:" ); - }, - - _cookie: function() { - var cookie = this.cookie || - ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); - return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); - }, - - _ui: function( tab, panel ) { - return { - tab: tab, - panel: panel, - index: this.anchors.index( tab ) - }; - }, - - _cleanup: function() { - // restore all former loading tabs labels - this.lis.filter( ".ui-state-processing" ) - .removeClass( "ui-state-processing" ) - .find( "span:data(label.tabs)" ) - .each(function() { - var el = $( this ); - el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" ); - }); - }, - - _tabify: function( init ) { - var self = this, - o = this.options, - fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash - - this.list = this.element.find( "ol,ul" ).eq( 0 ); - this.lis = $( " > li:has(a[href])", this.list ); - this.anchors = this.lis.map(function() { - return $( "a", this )[ 0 ]; - }); - this.panels = $( [] ); - - this.anchors.each(function( i, a ) { - var href = $( a ).attr( "href" ); - // For dynamically created HTML that contains a hash as href IE < 8 expands - // such href to the full page url with hash and then misinterprets tab as ajax. - // Same consideration applies for an added tab with a fragment identifier - // since a[href=#fragment-identifier] does unexpectedly not match. - // Thus normalize href attribute... - var hrefBase = href.split( "#" )[ 0 ], - baseEl; - if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] || - ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) { - href = a.hash; - a.href = href; - } - - // inline tab - if ( fragmentId.test( href ) ) { - self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) ); - // remote tab - // prevent loading the page itself if href is just "#" - } else if ( href && href !== "#" ) { - // required for restore on destroy - $.data( a, "href.tabs", href ); - - // TODO until #3808 is fixed strip fragment identifier from url - // (IE fails to load from such url) - $.data( a, "load.tabs", href.replace( /#.*$/, "" ) ); - - var id = self._tabId( a ); - a.href = "#" + id; - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .insertAfter( self.panels[ i - 1 ] || self.list ); - $panel.data( "destroy.tabs", true ); - } - self.panels = self.panels.add( $panel ); - // invalid tab href - } else { - o.disabled.push( i ); - } - }); - - // initialization from scratch - if ( init ) { - // attach necessary classes for styling - this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); - this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); - this.lis.addClass( "ui-state-default ui-corner-top" ); - this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); - - // Selected tab - // use "selected" option or try to retrieve: - // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
            • - if ( o.selected === undefined ) { - if ( location.hash ) { - this.anchors.each(function( i, a ) { - if ( a.hash == location.hash ) { - o.selected = i; - return false; - } - }); - } - if ( typeof o.selected !== "number" && o.cookie ) { - o.selected = parseInt( self._cookie(), 10 ); - } - if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); - } - o.selected = o.selected || ( this.lis.length ? 0 : -1 ); - } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release - o.selected = -1; - } - - // sanity check - default to first tab... - o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) - ? o.selected - : 0; - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - // A selected tab cannot become disabled. - o.disabled = $.unique( o.disabled.concat( - $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { - return self.lis.index( n ); - }) - ) ).sort(); - - if ( $.inArray( o.selected, o.disabled ) != -1 ) { - o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 ); - } - - // highlight selected tab - this.panels.addClass( "ui-tabs-hide" ); - this.lis.removeClass( "ui-tabs-selected ui-state-active" ); - // check for length avoids error when initializing empty list - if ( o.selected >= 0 && this.anchors.length ) { - self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" ); - this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); - - // seems to be expected behavior that the show callback is fired - self.element.queue( "tabs", function() { - self._trigger( "show", null, - self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); - }); - - this.load( o.selected ); - } - - // clean up to avoid memory leaks in certain versions of IE 6 - // TODO: namespace this event - $( window ).bind( "unload", function() { - self.lis.add( self.anchors ).unbind( ".tabs" ); - self.lis = self.anchors = self.panels = null; - }); - // update selected after add/remove - } else { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); - } - - // update collapsible - // TODO: use .toggleClass() - this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" ); - - // set or update cookie after init and add/remove respectively - if ( o.cookie ) { - this._cookie( o.selected, o.cookie ); - } - - // disable tabs - for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { - $( li )[ $.inArray( i, o.disabled ) != -1 && - // TODO: use .toggleClass() - !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" ); - } - - // reset cache if switching from cached to not cached - if ( o.cache === false ) { - this.anchors.removeData( "cache.tabs" ); - } - - // remove all handlers before, tabify may run on existing tabs after add or option change - this.lis.add( this.anchors ).unbind( ".tabs" ); - - if ( o.event !== "mouseover" ) { - var addState = function( state, el ) { - if ( el.is( ":not(.ui-state-disabled)" ) ) { - el.addClass( "ui-state-" + state ); - } - }; - var removeState = function( state, el ) { - el.removeClass( "ui-state-" + state ); - }; - this.lis.bind( "mouseover.tabs" , function() { - addState( "hover", $( this ) ); - }); - this.lis.bind( "mouseout.tabs", function() { - removeState( "hover", $( this ) ); - }); - this.anchors.bind( "focus.tabs", function() { - addState( "focus", $( this ).closest( "li" ) ); - }); - this.anchors.bind( "blur.tabs", function() { - removeState( "focus", $( this ).closest( "li" ) ); - }); - } - - // set up animations - var hideFx, showFx; - if ( o.fx ) { - if ( $.isArray( o.fx ) ) { - hideFx = o.fx[ 0 ]; - showFx = o.fx[ 1 ]; - } else { - hideFx = showFx = o.fx; - } - } - - // Reset certain styles left over from animation - // and prevent IE's ClearType bug... - function resetStyle( $el, fx ) { - $el.css( "display", "" ); - if ( !$.support.opacity && fx.opacity ) { - $el[ 0 ].style.removeAttribute( "filter" ); - } - } - - // Show a tab... - var showTab = showFx - ? function( clicked, $show ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way - .animate( showFx, showFx.duration || "normal", function() { - resetStyle( $show, showFx ); - self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); - }); - } - : function( clicked, $show ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.removeClass( "ui-tabs-hide" ); - self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); - }; - - // Hide a tab, $show is optional... - var hideTab = hideFx - ? function( clicked, $hide ) { - $hide.animate( hideFx, hideFx.duration || "normal", function() { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); - resetStyle( $hide, hideFx ); - self.element.dequeue( "tabs" ); - }); - } - : function( clicked, $hide, $show ) { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); - self.element.dequeue( "tabs" ); - }; - - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.anchors.bind( o.event + ".tabs", function() { - var el = this, - $li = $(el).closest( "li" ), - $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), - $show = self.element.find( self._sanitizeSelector( el.hash ) ); - - // If tab is already selected and not collapsible or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || - $li.hasClass( "ui-state-disabled" ) || - $li.hasClass( "ui-state-processing" ) || - self.panels.filter( ":animated" ).length || - self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) { - this.blur(); - return false; - } - - o.selected = self.anchors.index( this ); - - self.abort(); - - // if tab may be closed - if ( o.collapsible ) { - if ( $li.hasClass( "ui-tabs-selected" ) ) { - o.selected = -1; - - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } - - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }).dequeue( "tabs" ); - - this.blur(); - return false; - } else if ( !$hide.length ) { - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } - - self.element.queue( "tabs", function() { - showTab( el, $show ); - }); - - // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 - self.load( self.anchors.index( this ) ); - - this.blur(); - return false; - } - } - - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } - - // show new tab - if ( $show.length ) { - if ( $hide.length ) { - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }); - } - self.element.queue( "tabs", function() { - showTab( el, $show ); - }); - - self.load( self.anchors.index( this ) ); - } else { - throw "jQuery UI Tabs: Mismatching fragment identifier."; - } - - // Prevent IE from keeping other link focussed when using the back button - // and remove dotted border from clicked link. This is controlled via CSS - // in modern browsers; blur() removes focus from address bar in Firefox - // which can become a usability and annoying problem with tabs('rotate'). - if ( $.browser.msie ) { - this.blur(); - } - }); - - // disable click in any case - this.anchors.bind( "click.tabs", function(){ - return false; - }); - }, - - _getIndex: function( index ) { - // meta-function to give users option to provide a href string instead of a numerical index. - // also sanitizes numerical indexes to valid values. - if ( typeof index == "string" ) { - index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); - } - - return index; - }, - - destroy: function() { - var o = this.options; - - this.abort(); - - this.element - .unbind( ".tabs" ) - .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ) - .removeData( "tabs" ); - - this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); - - this.anchors.each(function() { - var href = $.data( this, "href.tabs" ); - if ( href ) { - this.href = href; - } - var $this = $( this ).unbind( ".tabs" ); - $.each( [ "href", "load", "cache" ], function( i, prefix ) { - $this.removeData( prefix + ".tabs" ); - }); - }); - - this.lis.unbind( ".tabs" ).add( this.panels ).each(function() { - if ( $.data( this, "destroy.tabs" ) ) { - $( this ).remove(); - } else { - $( this ).removeClass([ - "ui-state-default", - "ui-corner-top", - "ui-tabs-selected", - "ui-state-active", - "ui-state-hover", - "ui-state-focus", - "ui-state-disabled", - "ui-tabs-panel", - "ui-widget-content", - "ui-corner-bottom", - "ui-tabs-hide" - ].join( " " ) ); - } - }); - - if ( o.cookie ) { - this._cookie( null, o.cookie ); - } - - return this; - }, - - add: function( url, label, index ) { - if ( index === undefined ) { - index = this.anchors.length; - } - - var self = this, - o = this.options, - $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), - id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); - - $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); - - // try to find an existing element before creating a new one - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .data( "destroy.tabs", true ); - } - $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); - - if ( index >= this.lis.length ) { - $li.appendTo( this.list ); - $panel.appendTo( this.list[ 0 ].parentNode ); - } else { - $li.insertBefore( this.lis[ index ] ); - $panel.insertBefore( this.panels[ index ] ); - } - - o.disabled = $.map( o.disabled, function( n, i ) { - return n >= index ? ++n : n; - }); - - this._tabify(); - - if ( this.anchors.length == 1 ) { - o.selected = 0; - $li.addClass( "ui-tabs-selected ui-state-active" ); - $panel.removeClass( "ui-tabs-hide" ); - this.element.queue( "tabs", function() { - self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); - }); - - this.load( 0 ); - } - - this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; - }, - - remove: function( index ) { - index = this._getIndex( index ); - var o = this.options, - $li = this.lis.eq( index ).remove(), - $panel = this.panels.eq( index ).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { - this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); - } - - o.disabled = $.map( - $.grep( o.disabled, function(n, i) { - return n != index; - }), - function( n, i ) { - return n >= index ? --n : n; - }); - - this._tabify(); - - this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); - return this; - }, - - enable: function( index ) { - index = this._getIndex( index ); - var o = this.options; - if ( $.inArray( index, o.disabled ) == -1 ) { - return; - } - - this.lis.eq( index ).removeClass( "ui-state-disabled" ); - o.disabled = $.grep( o.disabled, function( n, i ) { - return n != index; - }); - - this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; - }, - - disable: function( index ) { - index = this._getIndex( index ); - var self = this, o = this.options; - // cannot disable already selected tab - if ( index != o.selected ) { - this.lis.eq( index ).addClass( "ui-state-disabled" ); - - o.disabled.push( index ); - o.disabled.sort(); - - this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - } - - return this; - }, - - select: function( index ) { - index = this._getIndex( index ); - if ( index == -1 ) { - if ( this.options.collapsible && this.options.selected != -1 ) { - index = this.options.selected; - } else { - return this; - } - } - this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); - return this; - }, - - load: function( index ) { - index = this._getIndex( index ); - var self = this, - o = this.options, - a = this.anchors.eq( index )[ 0 ], - url = $.data( a, "load.tabs" ); - - this.abort(); - - // not remote or from cache - if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) { - this.element.dequeue( "tabs" ); - return; - } - - // load remote from here on - this.lis.eq( index ).addClass( "ui-state-processing" ); - - if ( o.spinner ) { - var span = $( "span", a ); - span.data( "label.tabs", span.html() ).html( o.spinner ); - } - - this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, { - url: url, - success: function( r, s ) { - self.element.find( self._sanitizeSelector( a.hash ) ).html( r ); - - // take care of tab labels - self._cleanup(); - - if ( o.cache ) { - $.data( a, "cache.tabs", true ); - } - - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - o.ajaxOptions.success( r, s ); - } - catch ( e ) {} - }, - error: function( xhr, s, e ) { - // take care of tab labels - self._cleanup(); - - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - o.ajaxOptions.error( xhr, s, index, a ); - } - catch ( e ) {} - } - } ) ); - - // last, so that load event is fired before show... - self.element.dequeue( "tabs" ); - - return this; - }, - - abort: function() { - // stop possibly running animations - this.element.queue( [] ); - this.panels.stop( false, true ); - - // "tabs" queue must not contain more than two elements, - // which are the callbacks for the latest clicked tab... - this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) ); - - // terminate pending requests from other tabs - if ( this.xhr ) { - this.xhr.abort(); - delete this.xhr; - } - - // take care of tab labels - this._cleanup(); - return this; - }, - - url: function( index, url ) { - this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url ); - return this; - }, - - length: function() { - return this.anchors.length; - } -}); - -$.extend( $.ui.tabs, { - version: "1.8.24" -}); - -/* - * Tabs Extensions - */ - -/* - * Rotate - */ -$.extend( $.ui.tabs.prototype, { - rotation: null, - rotate: function( ms, continuing ) { - var self = this, - o = this.options; - - var rotate = self._rotate || ( self._rotate = function( e ) { - clearTimeout( self.rotation ); - self.rotation = setTimeout(function() { - var t = o.selected; - self.select( ++t < self.anchors.length ? t : 0 ); - }, ms ); - - if ( e ) { - e.stopPropagation(); - } - }); - - var stop = self._unrotate || ( self._unrotate = !continuing - ? function(e) { - if (e.clientX) { // in case of a true click - self.rotate(null); - } - } - : function( e ) { - rotate(); - }); - - // start rotation - if ( ms ) { - this.element.bind( "tabsshow", rotate ); - this.anchors.bind( o.event + ".tabs", stop ); - rotate(); - // stop rotation - } else { - clearTimeout( self.rotation ); - this.element.unbind( "tabsshow", rotate ); - this.anchors.unbind( o.event + ".tabs", stop ); - delete this._rotate; - delete this._unrotate; - } - - return this; - } -}); - -})( jQuery ); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery-ui.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery-ui.min.js deleted file mode 100644 index 48b6629df7..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery-ui.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.effects.core.js, jquery.effects.blind.js, jquery.effects.bounce.js, jquery.effects.clip.js, jquery.effects.drop.js, jquery.effects.explode.js, jquery.effects.fade.js, jquery.effects.fold.js, jquery.effects.highlight.js, jquery.effects.pulsate.js, jquery.effects.scale.js, jquery.effects.shake.js, jquery.effects.slide.js, jquery.effects.transfer.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.tabs.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.24",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})}(jQuery),function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('
              ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.lefth[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.toph[3]?j-this.offset.click.toph[2]?k-this.offset.click.left=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f=k&&g<=l||h>=k&&h<=l||gl)&&(e>=i&&e<=j||f>=i&&f<=j||ej);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h
            • ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e
              ');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),ea.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d
              ');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.24"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}}(jQuery),function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("
              ")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.righth||i.bottome&&i.rightf&&i.bottom *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(f.instance!==this.currentContainer)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+jf&&b+ka[this.floating?"width":"height"]?l:f0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.leftthis.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.topthis.containment[3]?h-this.offset.click.topthis.containment[2]?i-this.offset.click.left=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f
              ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}});var m={};a.each(["Quad","Cubic","Quart","Quint","Expo"],function(a,b){m[b]=function(b){return Math.pow(b,a+2)}}),a.extend(m,{Sine:function(a){return 1-Math.cos(a*Math.PI/2)},Circ:function(a){return 1-Math.sqrt(1-a*a)},Elastic:function(a){return a===0||a===1?a:-Math.pow(2,8*(a-1))*Math.sin(((a-1)*80-7.5)*Math.PI/15)},Back:function(a){return a*a*(3*a-2)},Bounce:function(a){var b,c=4;while(a<((b=Math.pow(2,--c))-1)/11);return 1/Math.pow(4,3-c)-7.5625*Math.pow((b*3-2)/22-a,2)}}),a.each(m,function(b,c){a.easing["easeIn"+b]=c,a.easing["easeOut"+b]=function(a){return 1-c(1-a)},a.easing["easeInOut"+b]=function(a){return a<.5?c(a*2)/2:c(a*-2+2)/-2+1}})}(jQuery),function(a,b){a.effects.blind=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"vertical";a.effects.save(c,d),c.show();var g=a.effects.createWrapper(c).css({overflow:"hidden"}),h=f=="vertical"?"height":"width",i=f=="vertical"?g.height():g.width();e=="show"&&g.css(h,0);var j={};j[h]=e=="show"?i:0,g.animate(j,b.duration,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}}(jQuery),function(a,b){a.effects.bounce=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"effect"),f=b.options.direction||"up",g=b.options.distance||20,h=b.options.times||5,i=b.duration||250;/show|hide/.test(e)&&d.push("opacity"),a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var j=f=="up"||f=="down"?"top":"left",k=f=="up"||f=="left"?"pos":"neg",g=b.options.distance||(j=="top"?c.outerHeight(!0)/3:c.outerWidth(!0)/3);e=="show"&&c.css("opacity",0).css(j,k=="pos"?-g:g),e=="hide"&&(g=g/(h*2)),e!="hide"&&h--;if(e=="show"){var l={opacity:1};l[j]=(k=="pos"?"+=":"-=")+g,c.animate(l,i/2,b.options.easing),g=g/2,h--}for(var m=0;m
              ").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}}(jQuery),function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}}(jQuery),function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}}(jQuery),function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i
              ').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}}(jQuery),function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}return f?(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),!1):!0},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];return this._clickHandler({target:b},b),this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(d.disabled)return;if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!g)return;return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(this.running)return;this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data)}}),a.extend(a.ui.accordion,{version:"1.8.24",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size()){b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);return}if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})}(jQuery),function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.isMultiLine=this.element.is("textarea"),this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(b.options.disabled||b.element.propAttr("readOnly"))return;d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._keyEvent("previous",c);break;case e.DOWN:b._keyEvent("next",c);break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){if(b.options.disabled)return;b.selectedItem=null,b.previous=b.element.val()}).bind("blur.autocomplete",function(a){if(b.options.disabled)return;clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150)}),this._initSource(),this.menu=a("
                ").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,c,d;a.isArray(this.options.source)?(c=this.options.source,this.source=function(b,d){d(a.ui.autocomplete.filter(c,b.term))}):typeof this.options.source=="string"?(d=this.options.source,this.source=function(c,e){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:d,data:c,dataType:"json",success:function(a,b){e(a)},error:function(){e([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length").data("item.autocomplete",c).append(a("
                ").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)},widget:function(){return this.menu.element},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})}(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(!a(c.target).closest(".ui-menu-item a").length)return;c.preventDefault(),b.select(c)}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){if(!this.active)return;this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active){this.activate(c,this.element.children(b));return}var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:first")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend(""),d.secondary&&b.append(""),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})}(jQuery),function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('
                '))}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);if(!c.length)return;c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);if($.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])||!d.length)return;d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover")})}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}$.extend($.ui,{datepicker:{version:"1.8.24"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){return extendRemove(this._defaults,a||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('
                ')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);if(c.hasClass(this.markerClassName))return;this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a)},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$(''+c+""),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('').addClass(this._triggerClass).html(g==""?f:$("").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]),!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;db&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);if(c.hasClass(this.markerClassName))return;c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block")},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$(''),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f),this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(d){$.datepicker.log(d)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if($.datepicker._isDisabledDatepicker(a)||$.datepicker._lastInput==a)return;var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){return e|=$(this).css("position")=="fixed",!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a)),this._attachHandlers(a);var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+(c?0:$(document).scrollLeft()),i=document.documentElement.clientHeight+(c?0:$(document).scrollTop());return b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0),b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!b||a&&b!=$.data(a,PROP_NAME))return;if(this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=function(){$.datepicker._tidyDialog(b)};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,e):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,e),c||e(),this._datepickerShowing=!1;var f=this._get(b,"onClose");f&&f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!$.datepicker._curInst)return;var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);if(this._isDisabledDatepicker(d[0]))return;this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e)},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if($(d).hasClass(this._unselectableClass)||this._isDisabledDatepicker(e[0]))return;var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1-1){j=1,k=l;do{var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}while(!0)}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+112?a.getHours()+2:0),a):null},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_attachHandlers:function(a){var b=this._get(a,"stepMonths"),c="#"+a.id.replace(/\\\\/g,"\\");a.dpDiv.find("[data-handler]").map(function(){var a={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,-b,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,+b,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(c)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(c,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),a[this.getAttribute("data-handler")])})},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&pp)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?''+q+"":e?"":''+q+"",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?''+s+"":e?"":''+s+"",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'",x=d?'
                '+(c?w:"")+(this._isInRange(a,v)?'":"")+(c?"":w)+"
                ":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='
                '+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'
                '+"";var R=z?'":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="=5?' class="ui-datepicker-week-end"':"")+">"+''+C[T]+""}Q+=R+"";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z";var _=z?'":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Ym;_+='",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+""}n++,n>11&&(n=0,o++),Q+="
                '+this._get(a,"weekHeader")+"
                '+this._get(a,"calculateWeek")(Y)+""+(bb&&!G?" ":bc?''+Y.getDate()+"":''+Y.getDate()+"")+"
                "+(j?"
                "+(g[0]>0&&N==g[1]-1?'
                ':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='
                ',m="";if(f||!i)m+=''+g[b]+"";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+=''+c+"";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="
                ",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&bd?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.24",window["DP_jQuery_"+dpuuid]=$}(jQuery),function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("
                ")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("
                ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("
                ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),f=a("
                ").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(f);a.each(d,function(a,b){if(a==="click")return;a in e?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||" "))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.24",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()}(jQuery),function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("
                ").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.24"})}(jQuery),function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("
                ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;ic&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.24"})}(jQuery),function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
                ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
              • #{label}
              • "},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.24"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a') - .addClass('ui-effects-wrapper') - .css({ - fontSize: '100%', - background: 'transparent', - border: 'none', - margin: 0, - padding: 0 - }), - active = document.activeElement; - - // support: Firefox - // Firefox incorrectly exposes anonymous content - // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 - try { - active.id; - } catch( e ) { - active = document.body; - } - - element.wrap( wrapper ); - - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - - wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element - - // transfer positioning properties to the wrapper - if (element.css('position') == 'static') { - wrapper.css({ position: 'relative' }); - element.css({ position: 'relative' }); - } else { - $.extend(props, { - position: element.css('position'), - zIndex: element.css('z-index') - }); - $.each(['top', 'left', 'bottom', 'right'], function(i, pos) { - props[pos] = element.css(pos); - if (isNaN(parseInt(props[pos], 10))) { - props[pos] = 'auto'; - } - }); - element.css({position: 'relative', top: 0, left: 0, right: 'auto', bottom: 'auto' }); - } - - return wrapper.css(props).show(); - }, - - removeWrapper: function(element) { - var parent, - active = document.activeElement; - - if (element.parent().is('.ui-effects-wrapper')) { - parent = element.parent().replaceWith(element); - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - return parent; - } - - return element; - }, - - setTransition: function(element, list, factor, value) { - value = value || {}; - $.each(list, function(i, x){ - var unit = element.cssUnit(x); - if (unit[0] > 0) value[x] = unit[0] * factor + unit[1]; - }); - return value; - } -}); - - -function _normalizeArguments(effect, options, speed, callback) { - // shift params for method overloading - if (typeof effect == 'object') { - callback = options; - speed = null; - options = effect; - effect = options.effect; - } - if ($.isFunction(options)) { - callback = options; - speed = null; - options = {}; - } - if (typeof options == 'number' || $.fx.speeds[options]) { - callback = speed; - speed = options; - options = {}; - } - if ($.isFunction(speed)) { - callback = speed; - speed = null; - } - - options = options || {}; - - speed = speed || options.duration; - speed = $.fx.off ? 0 : typeof speed == 'number' - ? speed : speed in $.fx.speeds ? $.fx.speeds[speed] : $.fx.speeds._default; - - callback = callback || options.complete; - - return [effect, options, speed, callback]; -} - -function standardSpeed( speed ) { - // valid standard speeds - if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) { - return true; - } - - // invalid strings - treat as "normal" speed - if ( typeof speed === "string" && !$.effects[ speed ] ) { - return true; - } - - return false; -} - -$.fn.extend({ - effect: function(effect, options, speed, callback) { - var args = _normalizeArguments.apply(this, arguments), - // TODO: make effects take actual parameters instead of a hash - args2 = { - options: args[1], - duration: args[2], - callback: args[3] - }, - mode = args2.options.mode, - effectMethod = $.effects[effect]; - - if ( $.fx.off || !effectMethod ) { - // delegate to the original method (e.g., .show()) if possible - if ( mode ) { - return this[ mode ]( args2.duration, args2.callback ); - } else { - return this.each(function() { - if ( args2.callback ) { - args2.callback.call( this ); - } - }); - } - } - - return effectMethod.call(this, args2); - }, - - _show: $.fn.show, - show: function(speed) { - if ( standardSpeed( speed ) ) { - return this._show.apply(this, arguments); - } else { - var args = _normalizeArguments.apply(this, arguments); - args[1].mode = 'show'; - return this.effect.apply(this, args); - } - }, - - _hide: $.fn.hide, - hide: function(speed) { - if ( standardSpeed( speed ) ) { - return this._hide.apply(this, arguments); - } else { - var args = _normalizeArguments.apply(this, arguments); - args[1].mode = 'hide'; - return this.effect.apply(this, args); - } - }, - - // jQuery core overloads toggle and creates _toggle - __toggle: $.fn.toggle, - toggle: function(speed) { - if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) { - return this.__toggle.apply(this, arguments); - } else { - var args = _normalizeArguments.apply(this, arguments); - args[1].mode = 'toggle'; - return this.effect.apply(this, args); - } - }, - - // helper functions - cssUnit: function(key) { - var style = this.css(key), val = []; - $.each( ['em','px','%','pt'], function(i, unit){ - if(style.indexOf(unit) > 0) - val = [parseFloat(style), unit]; - }); - return val; - } -}); - - - -/******************************************************************************/ -/*********************************** EASING ***********************************/ -/******************************************************************************/ - -// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) - -var baseEasings = {}; - -$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { - baseEasings[ name ] = function( p ) { - return Math.pow( p, i + 2 ); - }; -}); - -$.extend( baseEasings, { - Sine: function ( p ) { - return 1 - Math.cos( p * Math.PI / 2 ); - }, - Circ: function ( p ) { - return 1 - Math.sqrt( 1 - p * p ); - }, - Elastic: function( p ) { - return p === 0 || p === 1 ? p : - -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); - }, - Back: function( p ) { - return p * p * ( 3 * p - 2 ); - }, - Bounce: function ( p ) { - var pow2, - bounce = 4; - - while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} - return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); - } -}); - -$.each( baseEasings, function( name, easeIn ) { - $.easing[ "easeIn" + name ] = easeIn; - $.easing[ "easeOut" + name ] = function( p ) { - return 1 - easeIn( 1 - p ); - }; - $.easing[ "easeInOut" + name ] = function( p ) { - return p < .5 ? - easeIn( p * 2 ) / 2 : - easeIn( p * -2 + 2 ) / -2 + 1; - }; -}); - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.core.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.core.min.js deleted file mode 100644 index 1c1161082a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.core.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.core.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -jQuery.effects||function(a,b){function c(b){var c;return b&&b.constructor==Array&&b.length==3?b:(c=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(b))?[parseInt(c[1],10),parseInt(c[2],10),parseInt(c[3],10)]:(c=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(b))?[parseFloat(c[1])*2.55,parseFloat(c[2])*2.55,parseFloat(c[3])*2.55]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(b))?[parseInt(c[1],16),parseInt(c[2],16),parseInt(c[3],16)]:(c=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(b))?[parseInt(c[1]+c[1],16),parseInt(c[2]+c[2],16),parseInt(c[3]+c[3],16)]:(c=/rgba\(0, 0, 0, 0\)/.exec(b))?e.transparent:e[a.trim(b).toLowerCase()]}function d(b,d){var e;do{e=(a.curCSS||a.css)(b,d);if(e!=""&&e!="transparent"||a.nodeName(b,"body"))break;d="backgroundColor"}while(b=b.parentNode);return c(e)}function h(){var a=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,b={},c,d;if(a&&a.length&&a[0]&&a[a[0]]){var e=a.length;while(e--)c=a[e],typeof a[c]=="string"&&(d=c.replace(/\-(\w)/g,function(a,b){return b.toUpperCase()}),b[d]=a[c])}else for(c in a)typeof a[c]=="string"&&(b[c]=a[c]);return b}function i(b){var c,d;for(c in b)d=b[c],(d==null||a.isFunction(d)||c in g||/scrollbar/.test(c)||!/color/i.test(c)&&isNaN(parseFloat(d)))&&delete b[c];return b}function j(a,b){var c={_:0},d;for(d in b)a[d]!=b[d]&&(c[d]=b[d]);return c}function k(b,c,d,e){typeof b=="object"&&(e=c,d=null,c=b,b=c.effect),a.isFunction(c)&&(e=c,d=null,c={});if(typeof c=="number"||a.fx.speeds[c])e=d,d=c,c={};return a.isFunction(d)&&(e=d,d=null),c=c||{},d=d||c.duration,d=a.fx.off?0:typeof d=="number"?d:d in a.fx.speeds?a.fx.speeds[d]:a.fx.speeds._default,e=e||c.complete,[b,c,d,e]}function l(b){return!b||typeof b=="number"||a.fx.speeds[b]?!0:typeof b=="string"&&!a.effects[b]?!0:!1}a.effects={},a.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","borderColor","color","outlineColor"],function(b,e){a.fx.step[e]=function(a){a.colorInit||(a.start=d(a.elem,e),a.end=c(a.end),a.colorInit=!0),a.elem.style[e]="rgb("+Math.max(Math.min(parseInt(a.pos*(a.end[0]-a.start[0])+a.start[0],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[1]-a.start[1])+a.start[1],10),255),0)+","+Math.max(Math.min(parseInt(a.pos*(a.end[2]-a.start[2])+a.start[2],10),255),0)+")"}});var e={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},f=["add","remove","toggle"],g={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};a.effects.animateClass=function(b,c,d,e){return a.isFunction(d)&&(e=d,d=null),this.queue(function(){var g=a(this),k=g.attr("style")||" ",l=i(h.call(this)),m,n=g.attr("class")||"";a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),m=i(h.call(this)),g.attr("class",n),g.animate(j(l,m),{queue:!1,duration:c,easing:d,complete:function(){a.each(f,function(a,c){b[c]&&g[c+"Class"](b[c])}),typeof g.attr("style")=="object"?(g.attr("style").cssText="",g.attr("style").cssText=k):g.attr("style",k),e&&e.apply(this,arguments),a.dequeue(this)}})})},a.fn.extend({_addClass:a.fn.addClass,addClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{add:b},c,d,e]):this._addClass(b)},_removeClass:a.fn.removeClass,removeClass:function(b,c,d,e){return c?a.effects.animateClass.apply(this,[{remove:b},c,d,e]):this._removeClass(b)},_toggleClass:a.fn.toggleClass,toggleClass:function(c,d,e,f,g){return typeof d=="boolean"||d===b?e?a.effects.animateClass.apply(this,[d?{add:c}:{remove:c},e,f,g]):this._toggleClass(c,d):a.effects.animateClass.apply(this,[{toggle:c},d,e,f])},switchClass:function(b,c,d,e,f){return a.effects.animateClass.apply(this,[{add:c,remove:b},d,e,f])}}),a.extend(a.effects,{version:"1.8.24",save:function(a,b){for(var c=0;c").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e=document.activeElement;try{e.id}catch(f){e=document.body}return b.wrap(d),(b[0]===e||a.contains(b[0],e))&&a(e).focus(),d=b.parent(),b.css("position")=="static"?(d.css({position:"relative"}),b.css({position:"relative"})):(a.extend(c,{position:b.css("position"),zIndex:b.css("z-index")}),a.each(["top","left","bottom","right"],function(a,d){c[d]=b.css(d),isNaN(parseInt(c[d],10))&&(c[d]="auto")}),b.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),d.css(c).show()},removeWrapper:function(b){var c,d=document.activeElement;return b.parent().is(".ui-effects-wrapper")?(c=b.parent().replaceWith(b),(b[0]===d||a.contains(b[0],d))&&a(d).focus(),c):b},setTransition:function(b,c,d,e){return e=e||{},a.each(c,function(a,c){var f=b.cssUnit(c);f[0]>0&&(e[c]=f[0]*d+f[1])}),e}}),a.fn.extend({effect:function(b,c,d,e){var f=k.apply(this,arguments),g={options:f[1],duration:f[2],callback:f[3]},h=g.options.mode,i=a.effects[b];return a.fx.off||!i?h?this[h](g.duration,g.callback):this.each(function(){g.callback&&g.callback.call(this)}):i.call(this,g)},_show:a.fn.show,show:function(a){if(l(a))return this._show.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="show",this.effect.apply(this,b)},_hide:a.fn.hide,hide:function(a){if(l(a))return this._hide.apply(this,arguments);var b=k.apply(this,arguments);return b[1].mode="hide",this.effect.apply(this,b)},__toggle:a.fn.toggle,toggle:function(b){if(l(b)||typeof b=="boolean"||a.isFunction(b))return this.__toggle.apply(this,arguments);var c=k.apply(this,arguments);return c[1].mode="toggle",this.effect.apply(this,c)},cssUnit:function(b){var c=this.css(b),d=[];return a.each(["em","px","%","pt"],function(a,b){c.indexOf(b)>0&&(d=[parseFloat(c),b])}),d}});var m={};a.each(["Quad","Cubic","Quart","Quint","Expo"],function(a,b){m[b]=function(b){return Math.pow(b,a+2)}}),a.extend(m,{Sine:function(a){return 1-Math.cos(a*Math.PI/2)},Circ:function(a){return 1-Math.sqrt(1-a*a)},Elastic:function(a){return a===0||a===1?a:-Math.pow(2,8*(a-1))*Math.sin(((a-1)*80-7.5)*Math.PI/15)},Back:function(a){return a*a*(3*a-2)},Bounce:function(a){var b,c=4;while(a<((b=Math.pow(2,--c))-1)/11);return 1/Math.pow(4,3-c)-7.5625*Math.pow((b*3-2)/22-a,2)}}),a.each(m,function(b,c){a.easing["easeIn"+b]=c,a.easing["easeOut"+b]=function(a){return 1-c(1-a)},a.easing["easeInOut"+b]=function(a){return a<.5?c(a*2)/2:c(a*-2+2)/-2+1}})}(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.drop.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.drop.js deleted file mode 100644 index 97e5abd43a..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.drop.js +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * jQuery UI Effects Drop 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Drop - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { - -$.effects.drop = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['position','top','bottom','left','right','opacity']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode - var direction = o.options.direction || 'left'; // Default Direction - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - $.effects.createWrapper(el); // Create Wrapper - var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; - var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; - var distance = o.options.distance || (ref == 'top' ? el.outerHeight( true ) / 2 : el.outerWidth( true ) / 2); - if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift - - // Animation - var animation = {opacity: mode == 'show' ? 1 : 0}; - animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; - - // Animate - el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(this, arguments); // Callback - el.dequeue(); - }}); - - }); - -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.drop.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.drop.min.js deleted file mode 100644 index 79713402fe..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.drop.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.drop.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.drop=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right","opacity"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.direction||"left";a.effects.save(c,d),c.show(),a.effects.createWrapper(c);var g=f=="up"||f=="down"?"top":"left",h=f=="up"||f=="left"?"pos":"neg",i=b.options.distance||(g=="top"?c.outerHeight(!0)/2:c.outerWidth(!0)/2);e=="show"&&c.css("opacity",0).css(g,h=="pos"?-i:i);var j={opacity:e=="show"?1:0};j[g]=(e=="show"?h=="pos"?"+=":"-=":h=="pos"?"-=":"+=")+i,c.animate(j,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.explode.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.explode.js deleted file mode 100644 index f63e47a225..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.explode.js +++ /dev/null @@ -1,79 +0,0 @@ -/*! - * jQuery UI Effects Explode 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Explode - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { - -$.effects.explode = function(o) { - - return this.queue(function() { - - var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; - var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3; - - o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode; - var el = $(this).show().css('visibility', 'hidden'); - var offset = el.offset(); - - //Substract the margins - not fixing the problem yet. - offset.top -= parseInt(el.css("marginTop"),10) || 0; - offset.left -= parseInt(el.css("marginLeft"),10) || 0; - - var width = el.outerWidth(true); - var height = el.outerHeight(true); - - for(var i=0;i') - .css({ - position: 'absolute', - visibility: 'visible', - left: -j*(width/cells), - top: -i*(height/rows) - }) - .parent() - .addClass('ui-effects-explode') - .css({ - position: 'absolute', - overflow: 'hidden', - width: width/cells, - height: height/rows, - left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0), - top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0), - opacity: o.options.mode == 'show' ? 0 : 1 - }).animate({ - left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)), - top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)), - opacity: o.options.mode == 'show' ? 1 : 0 - }, o.duration || 500); - } - } - - // Set a timeout, to call the callback approx. when the other animations have finished - setTimeout(function() { - - o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide(); - if(o.callback) o.callback.apply(el[0]); // Callback - el.dequeue(); - - $('div.ui-effects-explode').remove(); - - }, o.duration || 500); - - - }); - -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.explode.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.explode.min.js deleted file mode 100644 index 723795cc1b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.explode.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.explode.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.explode=function(b){return this.queue(function(){var c=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3,d=b.options.pieces?Math.round(Math.sqrt(b.options.pieces)):3;b.options.mode=b.options.mode=="toggle"?a(this).is(":visible")?"hide":"show":b.options.mode;var e=a(this).show().css("visibility","hidden"),f=e.offset();f.top-=parseInt(e.css("marginTop"),10)||0,f.left-=parseInt(e.css("marginLeft"),10)||0;var g=e.outerWidth(!0),h=e.outerHeight(!0);for(var i=0;i").css({position:"absolute",visibility:"visible",left:-j*(g/d),top:-i*(h/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/d,height:h/c,left:f.left+j*(g/d)+(b.options.mode=="show"?(j-Math.floor(d/2))*(g/d):0),top:f.top+i*(h/c)+(b.options.mode=="show"?(i-Math.floor(c/2))*(h/c):0),opacity:b.options.mode=="show"?0:1}).animate({left:f.left+j*(g/d)+(b.options.mode=="show"?0:(j-Math.floor(d/2))*(g/d)),top:f.top+i*(h/c)+(b.options.mode=="show"?0:(i-Math.floor(c/2))*(h/c)),opacity:b.options.mode=="show"?1:0},b.duration||500);setTimeout(function(){b.options.mode=="show"?e.css({visibility:"visible"}):e.css({visibility:"visible"}).hide(),b.callback&&b.callback.apply(e[0]),e.dequeue(),a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fade.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fade.js deleted file mode 100644 index 7aa37b1aa7..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fade.js +++ /dev/null @@ -1,32 +0,0 @@ -/*! - * jQuery UI Effects Fade 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { - -$.effects.fade = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'hide'); - - elem.animate({ opacity: mode }, { - queue: false, - duration: o.duration, - easing: o.options.easing, - complete: function() { - (o.callback && o.callback.apply(this, arguments)); - elem.dequeue(); - } - }); - }); -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fade.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fade.min.js deleted file mode 100644 index 97a4b6d76b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fade.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.fade.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.fade=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"hide");c.animate({opacity:d},{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fold.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fold.js deleted file mode 100644 index 06cc553382..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fold.js +++ /dev/null @@ -1,56 +0,0 @@ -/*! - * jQuery UI Effects Fold 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { - -$.effects.fold = function(o) { - - return this.queue(function() { - - // Create element - var el = $(this), props = ['position','top','bottom','left','right']; - - // Set options - var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode - var size = o.options.size || 15; // Default fold size - var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value - var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; - - // Adjust - $.effects.save(el, props); el.show(); // Save & Show - var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper - var widthFirst = ((mode == 'show') != horizFirst); - var ref = widthFirst ? ['width', 'height'] : ['height', 'width']; - var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()]; - var percent = /([0-9]+)%/.exec(size); - if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1]; - if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift - - // Animation - var animation1 = {}, animation2 = {}; - animation1[ref[0]] = mode == 'show' ? distance[0] : size; - animation2[ref[1]] = mode == 'show' ? distance[1] : 0; - - // Animate - wrapper.animate(animation1, duration, o.options.easing) - .animate(animation2, duration, o.options.easing, function() { - if(mode == 'hide') el.hide(); // Hide - $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore - if(o.callback) o.callback.apply(el[0], arguments); // Callback - el.dequeue(); - }); - - }); - -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fold.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fold.min.js deleted file mode 100644 index 8a2361b5cd..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.fold.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.fold.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.fold=function(b){return this.queue(function(){var c=a(this),d=["position","top","bottom","left","right"],e=a.effects.setMode(c,b.options.mode||"hide"),f=b.options.size||15,g=!!b.options.horizFirst,h=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(c,d),c.show();var i=a.effects.createWrapper(c).css({overflow:"hidden"}),j=e=="show"!=g,k=j?["width","height"]:["height","width"],l=j?[i.width(),i.height()]:[i.height(),i.width()],m=/([0-9]+)%/.exec(f);m&&(f=parseInt(m[1],10)/100*l[e=="hide"?0:1]),e=="show"&&i.css(g?{height:0,width:f}:{height:f,width:0});var n={},p={};n[k[0]]=e=="show"?l[0]:f,p[k[1]]=e=="show"?l[1]:0,i.animate(n,h,b.options.easing).animate(p,h,b.options.easing,function(){e=="hide"&&c.hide(),a.effects.restore(c,d),a.effects.removeWrapper(c),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.highlight.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.highlight.js deleted file mode 100644 index ad9e7bd4d4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.highlight.js +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * jQuery UI Effects Highlight 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { - -$.effects.highlight = function(o) { - return this.queue(function() { - var elem = $(this), - props = ['backgroundImage', 'backgroundColor', 'opacity'], - mode = $.effects.setMode(elem, o.options.mode || 'show'), - animation = { - backgroundColor: elem.css('backgroundColor') - }; - - if (mode == 'hide') { - animation.opacity = 0; - } - - $.effects.save(elem, props); - elem - .show() - .css({ - backgroundImage: 'none', - backgroundColor: o.options.color || '#ffff99' - }) - .animate(animation, { - queue: false, - duration: o.duration, - easing: o.options.easing, - complete: function() { - (mode == 'hide' && elem.hide()); - $.effects.restore(elem, props); - (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter')); - (o.callback && o.callback.apply(this, arguments)); - elem.dequeue(); - } - }); - }); -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.highlight.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.highlight.min.js deleted file mode 100644 index 6a1755e8c2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.highlight.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.highlight.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.highlight=function(b){return this.queue(function(){var c=a(this),d=["backgroundImage","backgroundColor","opacity"],e=a.effects.setMode(c,b.options.mode||"show"),f={backgroundColor:c.css("backgroundColor")};e=="hide"&&(f.opacity=0),a.effects.save(c,d),c.show().css({backgroundImage:"none",backgroundColor:b.options.color||"#ffff99"}).animate(f,{queue:!1,duration:b.duration,easing:b.options.easing,complete:function(){e=="hide"&&c.hide(),a.effects.restore(c,d),e=="show"&&!a.support.opacity&&this.style.removeAttribute("filter"),b.callback&&b.callback.apply(this,arguments),c.dequeue()}})})}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.pulsate.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.pulsate.js deleted file mode 100644 index d730beedf5..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.pulsate.js +++ /dev/null @@ -1,51 +0,0 @@ -/*! - * jQuery UI Effects Pulsate 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function( $, undefined ) { - -$.effects.pulsate = function(o) { - return this.queue(function() { - var elem = $(this), - mode = $.effects.setMode(elem, o.options.mode || 'show'), - times = ((o.options.times || 5) * 2) - 1, - duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2, - isVisible = elem.is(':visible'), - animateTo = 0; - - if (!isVisible) { - elem.css('opacity', 0).show(); - animateTo = 1; - } - - if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) { - times--; - } - - for (var i = 0; i < times; i++) { - elem.animate({ opacity: animateTo }, duration, o.options.easing); - animateTo = (animateTo + 1) % 2; - } - - elem.animate({ opacity: animateTo }, duration, o.options.easing, function() { - if (animateTo == 0) { - elem.hide(); - } - (o.callback && o.callback.apply(this, arguments)); - }); - - elem - .queue('fx', function() { elem.dequeue(); }) - .dequeue(); - }); -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.pulsate.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.pulsate.min.js deleted file mode 100644 index 3b7ace2c1c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.pulsate.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.pulsate.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.pulsate=function(b){return this.queue(function(){var c=a(this),d=a.effects.setMode(c,b.options.mode||"show"),e=(b.options.times||5)*2-1,f=b.duration?b.duration/2:a.fx.speeds._default/2,g=c.is(":visible"),h=0;g||(c.css("opacity",0).show(),h=1),(d=="hide"&&g||d=="show"&&!g)&&e--;for(var i=0;i') - .appendTo(document.body) - .addClass(o.options.className) - .css({ - top: startPosition.top, - left: startPosition.left, - height: elem.innerHeight(), - width: elem.innerWidth(), - position: 'absolute' - }) - .animate(animation, o.duration, o.options.easing, function() { - transfer.remove(); - (o.callback && o.callback.apply(elem[0], arguments)); - elem.dequeue(); - }); - }); -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.transfer.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.transfer.min.js deleted file mode 100644 index cea4241ccf..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.effects.transfer.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.effects.transfer.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.effects.transfer=function(b){return this.queue(function(){var c=a(this),d=a(b.options.to),e=d.offset(),f={top:e.top,left:e.left,height:d.innerHeight(),width:d.innerWidth()},g=c.offset(),h=a('
                ').appendTo(document.body).addClass(b.options.className).css({top:g.top,left:g.left,height:c.innerHeight(),width:c.innerWidth(),position:"absolute"}).animate(f,b.duration,b.options.easing,function(){h.remove(),b.callback&&b.callback.apply(c[0],arguments),c.dequeue()})})}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.accordion.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.accordion.js deleted file mode 100644 index dc1ba60aa4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.accordion.js +++ /dev/null @@ -1,611 +0,0 @@ -/*! - * jQuery UI Accordion 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget( "ui.accordion", { - options: { - active: 0, - animated: "slide", - autoHeight: true, - clearStyle: false, - collapsible: false, - event: "click", - fillSpace: false, - header: "> li > :first-child,> :not(li):even", - icons: { - header: "ui-icon-triangle-1-e", - headerSelected: "ui-icon-triangle-1-s" - }, - navigation: false, - navigationFilter: function() { - return this.href.toLowerCase() === location.href.toLowerCase(); - } - }, - - _create: function() { - var self = this, - options = self.options; - - self.running = 0; - - self.element - .addClass( "ui-accordion ui-widget ui-helper-reset" ) - // in lack of child-selectors in CSS - // we need to mark top-LIs in a UL-accordion for some IE-fix - .children( "li" ) - .addClass( "ui-accordion-li-fix" ); - - self.headers = self.element.find( options.header ) - .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ) - .bind( "mouseenter.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).addClass( "ui-state-hover" ); - }) - .bind( "mouseleave.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).removeClass( "ui-state-hover" ); - }) - .bind( "focus.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).addClass( "ui-state-focus" ); - }) - .bind( "blur.accordion", function() { - if ( options.disabled ) { - return; - } - $( this ).removeClass( "ui-state-focus" ); - }); - - self.headers.next() - .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ); - - if ( options.navigation ) { - var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 ); - if ( current.length ) { - var header = current.closest( ".ui-accordion-header" ); - if ( header.length ) { - // anchor within header - self.active = header; - } else { - // anchor within content - self.active = current.closest( ".ui-accordion-content" ).prev(); - } - } - } - - self.active = self._findActive( self.active || options.active ) - .addClass( "ui-state-default ui-state-active" ) - .toggleClass( "ui-corner-all" ) - .toggleClass( "ui-corner-top" ); - self.active.next().addClass( "ui-accordion-content-active" ); - - self._createIcons(); - self.resize(); - - // ARIA - self.element.attr( "role", "tablist" ); - - self.headers - .attr( "role", "tab" ) - .bind( "keydown.accordion", function( event ) { - return self._keydown( event ); - }) - .next() - .attr( "role", "tabpanel" ); - - self.headers - .not( self.active || "" ) - .attr({ - "aria-expanded": "false", - "aria-selected": "false", - tabIndex: -1 - }) - .next() - .hide(); - - // make sure at least one header is in the tab order - if ( !self.active.length ) { - self.headers.eq( 0 ).attr( "tabIndex", 0 ); - } else { - self.active - .attr({ - "aria-expanded": "true", - "aria-selected": "true", - tabIndex: 0 - }); - } - - // only need links in tab order for Safari - if ( !$.browser.safari ) { - self.headers.find( "a" ).attr( "tabIndex", -1 ); - } - - if ( options.event ) { - self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) { - self._clickHandler.call( self, event, this ); - event.preventDefault(); - }); - } - }, - - _createIcons: function() { - var options = this.options; - if ( options.icons ) { - $( "" ) - .addClass( "ui-icon " + options.icons.header ) - .prependTo( this.headers ); - this.active.children( ".ui-icon" ) - .toggleClass(options.icons.header) - .toggleClass(options.icons.headerSelected); - this.element.addClass( "ui-accordion-icons" ); - } - }, - - _destroyIcons: function() { - this.headers.children( ".ui-icon" ).remove(); - this.element.removeClass( "ui-accordion-icons" ); - }, - - destroy: function() { - var options = this.options; - - this.element - .removeClass( "ui-accordion ui-widget ui-helper-reset" ) - .removeAttr( "role" ); - - this.headers - .unbind( ".accordion" ) - .removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) - .removeAttr( "role" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-selected" ) - .removeAttr( "tabIndex" ); - - this.headers.find( "a" ).removeAttr( "tabIndex" ); - this._destroyIcons(); - var contents = this.headers.next() - .css( "display", "" ) - .removeAttr( "role" ) - .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" ); - if ( options.autoHeight || options.fillHeight ) { - contents.css( "height", "" ); - } - - return $.Widget.prototype.destroy.call( this ); - }, - - _setOption: function( key, value ) { - $.Widget.prototype._setOption.apply( this, arguments ); - - if ( key == "active" ) { - this.activate( value ); - } - if ( key == "icons" ) { - this._destroyIcons(); - if ( value ) { - this._createIcons(); - } - } - // #5332 - opacity doesn't cascade to positioned elements in IE - // so we need to add the disabled class to the headers and panels - if ( key == "disabled" ) { - this.headers.add(this.headers.next()) - [ value ? "addClass" : "removeClass" ]( - "ui-accordion-disabled ui-state-disabled" ); - } - }, - - _keydown: function( event ) { - if ( this.options.disabled || event.altKey || event.ctrlKey ) { - return; - } - - var keyCode = $.ui.keyCode, - length = this.headers.length, - currentIndex = this.headers.index( event.target ), - toFocus = false; - - switch ( event.keyCode ) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.headers[ ( currentIndex + 1 ) % length ]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - this._clickHandler( { target: event.target }, event.target ); - event.preventDefault(); - } - - if ( toFocus ) { - $( event.target ).attr( "tabIndex", -1 ); - $( toFocus ).attr( "tabIndex", 0 ); - toFocus.focus(); - return false; - } - - return true; - }, - - resize: function() { - var options = this.options, - maxHeight; - - if ( options.fillSpace ) { - if ( $.browser.msie ) { - var defOverflow = this.element.parent().css( "overflow" ); - this.element.parent().css( "overflow", "hidden"); - } - maxHeight = this.element.parent().height(); - if ($.browser.msie) { - this.element.parent().css( "overflow", defOverflow ); - } - - this.headers.each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.headers.next() - .each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( options.autoHeight ) { - maxHeight = 0; - this.headers.next() - .each(function() { - maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); - }) - .height( maxHeight ); - } - - return this; - }, - - activate: function( index ) { - // TODO this gets called on init, changing the option without an explicit call for that - this.options.active = index; - // call clickHandler with custom event - var active = this._findActive( index )[ 0 ]; - this._clickHandler( { target: active }, active ); - - return this; - }, - - _findActive: function( selector ) { - return selector - ? typeof selector === "number" - ? this.headers.filter( ":eq(" + selector + ")" ) - : this.headers.not( this.headers.not( selector ) ) - : selector === false - ? $( [] ) - : this.headers.filter( ":eq(0)" ); - }, - - // TODO isn't event.target enough? why the separate target argument? - _clickHandler: function( event, target ) { - var options = this.options; - if ( options.disabled ) { - return; - } - - // called only when using activate(false) to close all parts programmatically - if ( !event.target ) { - if ( !options.collapsible ) { - return; - } - this.active - .removeClass( "ui-state-active ui-corner-top" ) - .addClass( "ui-state-default ui-corner-all" ) - .children( ".ui-icon" ) - .removeClass( options.icons.headerSelected ) - .addClass( options.icons.header ); - this.active.next().addClass( "ui-accordion-content-active" ); - var toHide = this.active.next(), - data = { - options: options, - newHeader: $( [] ), - oldHeader: options.active, - newContent: $( [] ), - oldContent: toHide - }, - toShow = ( this.active = $( [] ) ); - this._toggle( toShow, toHide, data ); - return; - } - - // get the click target - var clicked = $( event.currentTarget || target ), - clickedIsActive = clicked[0] === this.active[0]; - - // TODO the option is changed, is that correct? - // TODO if it is correct, shouldn't that happen after determining that the click is valid? - options.active = options.collapsible && clickedIsActive ? - false : - this.headers.index( clicked ); - - // if animations are still active, or the active header is the target, ignore click - if ( this.running || ( !options.collapsible && clickedIsActive ) ) { - return; - } - - // find elements to show and hide - var active = this.active, - toShow = clicked.next(), - toHide = this.active.next(), - data = { - options: options, - newHeader: clickedIsActive && options.collapsible ? $([]) : clicked, - oldHeader: this.active, - newContent: clickedIsActive && options.collapsible ? $([]) : toShow, - oldContent: toHide - }, - down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] ); - - // when the call to ._toggle() comes after the class changes - // it causes a very odd bug in IE 8 (see #6720) - this.active = clickedIsActive ? $([]) : clicked; - this._toggle( toShow, toHide, data, clickedIsActive, down ); - - // switch classes - active - .removeClass( "ui-state-active ui-corner-top" ) - .addClass( "ui-state-default ui-corner-all" ) - .children( ".ui-icon" ) - .removeClass( options.icons.headerSelected ) - .addClass( options.icons.header ); - if ( !clickedIsActive ) { - clicked - .removeClass( "ui-state-default ui-corner-all" ) - .addClass( "ui-state-active ui-corner-top" ) - .children( ".ui-icon" ) - .removeClass( options.icons.header ) - .addClass( options.icons.headerSelected ); - clicked - .next() - .addClass( "ui-accordion-content-active" ); - } - - return; - }, - - _toggle: function( toShow, toHide, data, clickedIsActive, down ) { - var self = this, - options = self.options; - - self.toShow = toShow; - self.toHide = toHide; - self.data = data; - - var complete = function() { - if ( !self ) { - return; - } - return self._completed.apply( self, arguments ); - }; - - // trigger changestart event - self._trigger( "changestart", null, self.data ); - - // count elements to animate - self.running = toHide.size() === 0 ? toShow.size() : toHide.size(); - - if ( options.animated ) { - var animOptions = {}; - - if ( options.collapsible && clickedIsActive ) { - animOptions = { - toShow: $( [] ), - toHide: toHide, - complete: complete, - down: down, - autoHeight: options.autoHeight || options.fillSpace - }; - } else { - animOptions = { - toShow: toShow, - toHide: toHide, - complete: complete, - down: down, - autoHeight: options.autoHeight || options.fillSpace - }; - } - - if ( !options.proxied ) { - options.proxied = options.animated; - } - - if ( !options.proxiedDuration ) { - options.proxiedDuration = options.duration; - } - - options.animated = $.isFunction( options.proxied ) ? - options.proxied( animOptions ) : - options.proxied; - - options.duration = $.isFunction( options.proxiedDuration ) ? - options.proxiedDuration( animOptions ) : - options.proxiedDuration; - - var animations = $.ui.accordion.animations, - duration = options.duration, - easing = options.animated; - - if ( easing && !animations[ easing ] && !$.easing[ easing ] ) { - easing = "slide"; - } - if ( !animations[ easing ] ) { - animations[ easing ] = function( options ) { - this.slide( options, { - easing: easing, - duration: duration || 700 - }); - }; - } - - animations[ easing ]( animOptions ); - } else { - if ( options.collapsible && clickedIsActive ) { - toShow.toggle(); - } else { - toHide.hide(); - toShow.show(); - } - - complete( true ); - } - - // TODO assert that the blur and focus triggers are really necessary, remove otherwise - toHide.prev() - .attr({ - "aria-expanded": "false", - "aria-selected": "false", - tabIndex: -1 - }) - .blur(); - toShow.prev() - .attr({ - "aria-expanded": "true", - "aria-selected": "true", - tabIndex: 0 - }) - .focus(); - }, - - _completed: function( cancel ) { - this.running = cancel ? 0 : --this.running; - if ( this.running ) { - return; - } - - if ( this.options.clearStyle ) { - this.toShow.add( this.toHide ).css({ - height: "", - overflow: "" - }); - } - - // other classes are removed before the animation; this one needs to stay until completed - this.toHide.removeClass( "ui-accordion-content-active" ); - // Work around for rendering bug in IE (#5421) - if ( this.toHide.length ) { - this.toHide.parent()[0].className = this.toHide.parent()[0].className; - } - - this._trigger( "change", null, this.data ); - } -}); - -$.extend( $.ui.accordion, { - version: "1.8.24", - animations: { - slide: function( options, additions ) { - options = $.extend({ - easing: "swing", - duration: 300 - }, options, additions ); - if ( !options.toHide.size() ) { - options.toShow.animate({ - height: "show", - paddingTop: "show", - paddingBottom: "show" - }, options ); - return; - } - if ( !options.toShow.size() ) { - options.toHide.animate({ - height: "hide", - paddingTop: "hide", - paddingBottom: "hide" - }, options ); - return; - } - var overflow = options.toShow.css( "overflow" ), - percentDone = 0, - showProps = {}, - hideProps = {}, - fxAttrs = [ "height", "paddingTop", "paddingBottom" ], - originalWidth; - // fix width before calculating height of hidden element - var s = options.toShow; - originalWidth = s[0].style.width; - s.width( s.parent().width() - - parseFloat( s.css( "paddingLeft" ) ) - - parseFloat( s.css( "paddingRight" ) ) - - ( parseFloat( s.css( "borderLeftWidth" ) ) || 0 ) - - ( parseFloat( s.css( "borderRightWidth" ) ) || 0 ) ); - - $.each( fxAttrs, function( i, prop ) { - hideProps[ prop ] = "hide"; - - var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ ); - showProps[ prop ] = { - value: parts[ 1 ], - unit: parts[ 2 ] || "px" - }; - }); - options.toShow.css({ height: 0, overflow: "hidden" }).show(); - options.toHide - .filter( ":hidden" ) - .each( options.complete ) - .end() - .filter( ":visible" ) - .animate( hideProps, { - step: function( now, settings ) { - // only calculate the percent when animating height - // IE gets very inconsistent results when animating elements - // with small values, which is common for padding - if ( settings.prop == "height" ) { - percentDone = ( settings.end - settings.start === 0 ) ? 0 : - ( settings.now - settings.start ) / ( settings.end - settings.start ); - } - - options.toShow[ 0 ].style[ settings.prop ] = - ( percentDone * showProps[ settings.prop ].value ) - + showProps[ settings.prop ].unit; - }, - duration: options.duration, - easing: options.easing, - complete: function() { - if ( !options.autoHeight ) { - options.toShow.css( "height", "" ); - } - options.toShow.css({ - width: originalWidth, - overflow: overflow - }); - options.complete(); - } - }); - }, - bounceslide: function( options ) { - this.slide( options, { - easing: options.down ? "easeOutBounce" : "swing", - duration: options.down ? 1000 : 200 - }); - } - } -}); - -})( jQuery ); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.accordion.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.accordion.min.js deleted file mode 100644 index 40a763057b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.accordion.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.accordion.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:!0,clearStyle:!1,collapsible:!1,event:"click",fillSpace:!1,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:!1,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var b=this,c=b.options;b.running=0,b.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix"),b.headers=b.element.find(c.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){if(c.disabled)return;a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){if(c.disabled)return;a(this).removeClass("ui-state-focus")}),b.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");if(c.navigation){var d=b.element.find("a").filter(c.navigationFilter).eq(0);if(d.length){var e=d.closest(".ui-accordion-header");e.length?b.active=e:b.active=d.closest(".ui-accordion-content").prev()}}b.active=b._findActive(b.active||c.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top"),b.active.next().addClass("ui-accordion-content-active"),b._createIcons(),b.resize(),b.element.attr("role","tablist"),b.headers.attr("role","tab").bind("keydown.accordion",function(a){return b._keydown(a)}).next().attr("role","tabpanel"),b.headers.not(b.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide(),b.active.length?b.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):b.headers.eq(0).attr("tabIndex",0),a.browser.safari||b.headers.find("a").attr("tabIndex",-1),c.event&&b.headers.bind(c.event.split(" ").join(".accordion ")+".accordion",function(a){b._clickHandler.call(b,a,this),a.preventDefault()})},_createIcons:function(){var b=this.options;b.icons&&(a("").addClass("ui-icon "+b.icons.header).prependTo(this.headers),this.active.children(".ui-icon").toggleClass(b.icons.header).toggleClass(b.icons.headerSelected),this.element.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.children(".ui-icon").remove(),this.element.removeClass("ui-accordion-icons")},destroy:function(){var b=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex"),this.headers.find("a").removeAttr("tabIndex"),this._destroyIcons();var c=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");return(b.autoHeight||b.fillHeight)&&c.css("height",""),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b=="active"&&this.activate(c),b=="icons"&&(this._destroyIcons(),c&&this._createIcons()),b=="disabled"&&this.headers.add(this.headers.next())[c?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(b){if(this.options.disabled||b.altKey||b.ctrlKey)return;var c=a.ui.keyCode,d=this.headers.length,e=this.headers.index(b.target),f=!1;switch(b.keyCode){case c.RIGHT:case c.DOWN:f=this.headers[(e+1)%d];break;case c.LEFT:case c.UP:f=this.headers[(e-1+d)%d];break;case c.SPACE:case c.ENTER:this._clickHandler({target:b.target},b.target),b.preventDefault()}return f?(a(b.target).attr("tabIndex",-1),a(f).attr("tabIndex",0),f.focus(),!1):!0},resize:function(){var b=this.options,c;if(b.fillSpace){if(a.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}c=this.element.parent().height(),a.browser.msie&&this.element.parent().css("overflow",d),this.headers.each(function(){c-=a(this).outerHeight(!0)}),this.headers.next().each(function(){a(this).height(Math.max(0,c-a(this).innerHeight()+a(this).height()))}).css("overflow","auto")}else b.autoHeight&&(c=0,this.headers.next().each(function(){c=Math.max(c,a(this).height("").height())}).height(c));return this},activate:function(a){this.options.active=a;var b=this._findActive(a)[0];return this._clickHandler({target:b},b),this},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===!1?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,c){var d=this.options;if(d.disabled)return;if(!b.target){if(!d.collapsible)return;this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),this.active.next().addClass("ui-accordion-content-active");var e=this.active.next(),f={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:e},g=this.active=a([]);this._toggle(g,e,f);return}var h=a(b.currentTarget||c),i=h[0]===this.active[0];d.active=d.collapsible&&i?!1:this.headers.index(h);if(this.running||!d.collapsible&&i)return;var j=this.active,g=h.next(),e=this.active.next(),f={options:d,newHeader:i&&d.collapsible?a([]):h,oldHeader:this.active,newContent:i&&d.collapsible?a([]):g,oldContent:e},k=this.headers.index(this.active[0])>this.headers.index(h[0]);this.active=i?a([]):h,this._toggle(g,e,f,i,k),j.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header),i||(h.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected),h.next().addClass("ui-accordion-content-active"));return},_toggle:function(b,c,d,e,f){var g=this,h=g.options;g.toShow=b,g.toHide=c,g.data=d;var i=function(){if(!g)return;return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data),g.running=c.size()===0?b.size():c.size();if(h.animated){var j={};h.collapsible&&e?j={toShow:a([]),toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace}:j={toShow:b,toHide:c,complete:i,down:f,autoHeight:h.autoHeight||h.fillSpace},h.proxied||(h.proxied=h.animated),h.proxiedDuration||(h.proxiedDuration=h.duration),h.animated=a.isFunction(h.proxied)?h.proxied(j):h.proxied,h.duration=a.isFunction(h.proxiedDuration)?h.proxiedDuration(j):h.proxiedDuration;var k=a.ui.accordion.animations,l=h.duration,m=h.animated;m&&!k[m]&&!a.easing[m]&&(m="slide"),k[m]||(k[m]=function(a){this.slide(a,{easing:m,duration:l||700})}),k[m](j)}else h.collapsible&&e?b.toggle():(c.hide(),b.show()),i(!0);c.prev().attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).blur(),b.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(this.running)return;this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""}),this.toHide.removeClass("ui-accordion-content-active"),this.toHide.length&&(this.toHide.parent()[0].className=this.toHide.parent()[0].className),this._trigger("change",null,this.data)}}),a.extend(a.ui.accordion,{version:"1.8.24",animations:{slide:function(b,c){b=a.extend({easing:"swing",duration:300},b,c);if(!b.toHide.size()){b.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},b);return}if(!b.toShow.size()){b.toHide.animate({height:"hide",paddingTop:"hide",paddingBottom:"hide"},b);return}var d=b.toShow.css("overflow"),e=0,f={},g={},h=["height","paddingTop","paddingBottom"],i,j=b.toShow;i=j[0].style.width,j.width(j.parent().width()-parseFloat(j.css("paddingLeft"))-parseFloat(j.css("paddingRight"))-(parseFloat(j.css("borderLeftWidth"))||0)-(parseFloat(j.css("borderRightWidth"))||0)),a.each(h,function(c,d){g[d]="hide";var e=(""+a.css(b.toShow[0],d)).match(/^([\d+-.]+)(.*)$/);f[d]={value:e[1],unit:e[2]||"px"}}),b.toShow.css({height:0,overflow:"hidden"}).show(),b.toHide.filter(":hidden").each(b.complete).end().filter(":visible").animate(g,{step:function(a,c){c.prop=="height"&&(e=c.end-c.start===0?0:(c.now-c.start)/(c.end-c.start)),b.toShow[0].style[c.prop]=e*f[c.prop].value+f[c.prop].unit},duration:b.duration,easing:b.easing,complete:function(){b.autoHeight||b.toShow.css("height",""),b.toShow.css({width:i,overflow:d}),b.complete()}})},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1e3:200})}}})})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.autocomplete.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.autocomplete.js deleted file mode 100644 index 8d69be2877..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.autocomplete.js +++ /dev/null @@ -1,631 +0,0 @@ -/*! - * jQuery UI Autocomplete 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.position.js - */ -(function( $, undefined ) { - -// used to prevent race conditions with remote data sources -var requestIndex = 0; - -$.widget( "ui.autocomplete", { - options: { - appendTo: "body", - autoFocus: false, - delay: 300, - minLength: 1, - position: { - my: "left top", - at: "left bottom", - collision: "none" - }, - source: null - }, - - pending: 0, - - _create: function() { - var self = this, - doc = this.element[ 0 ].ownerDocument, - suppressKeyPress; - this.isMultiLine = this.element.is( "textarea" ); - - this.element - .addClass( "ui-autocomplete-input" ) - .attr( "autocomplete", "off" ) - // TODO verify these actually work as intended - .attr({ - role: "textbox", - "aria-autocomplete": "list", - "aria-haspopup": "true" - }) - .bind( "keydown.autocomplete", function( event ) { - if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) { - return; - } - - suppressKeyPress = false; - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - self._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - self._move( "nextPage", event ); - break; - case keyCode.UP: - self._keyEvent( "previous", event ); - break; - case keyCode.DOWN: - self._keyEvent( "next", event ); - break; - case keyCode.ENTER: - case keyCode.NUMPAD_ENTER: - // when menu is open and has focus - if ( self.menu.active ) { - // #6055 - Opera still allows the keypress to occur - // which causes forms to submit - suppressKeyPress = true; - event.preventDefault(); - } - //passthrough - ENTER and TAB both select the current element - case keyCode.TAB: - if ( !self.menu.active ) { - return; - } - self.menu.select( event ); - break; - case keyCode.ESCAPE: - self.element.val( self.term ); - self.close( event ); - break; - default: - // keypress is triggered before the input value is changed - clearTimeout( self.searching ); - self.searching = setTimeout(function() { - // only search if the value has changed - if ( self.term != self.element.val() ) { - self.selectedItem = null; - self.search( null, event ); - } - }, self.options.delay ); - break; - } - }) - .bind( "keypress.autocomplete", function( event ) { - if ( suppressKeyPress ) { - suppressKeyPress = false; - event.preventDefault(); - } - }) - .bind( "focus.autocomplete", function() { - if ( self.options.disabled ) { - return; - } - - self.selectedItem = null; - self.previous = self.element.val(); - }) - .bind( "blur.autocomplete", function( event ) { - if ( self.options.disabled ) { - return; - } - - clearTimeout( self.searching ); - // clicks on the menu (or a button to trigger a search) will cause a blur event - self.closing = setTimeout(function() { - self.close( event ); - self._change( event ); - }, 150 ); - }); - this._initSource(); - this.menu = $( "
                  " ) - .addClass( "ui-autocomplete" ) - .appendTo( $( this.options.appendTo || "body", doc )[0] ) - // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown) - .mousedown(function( event ) { - // clicking on the scrollbar causes focus to shift to the body - // but we can't detect a mouseup or a click immediately afterward - // so we have to track the next mousedown and close the menu if - // the user clicks somewhere outside of the autocomplete - var menuElement = self.menu.element[ 0 ]; - if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { - setTimeout(function() { - $( document ).one( 'mousedown', function( event ) { - if ( event.target !== self.element[ 0 ] && - event.target !== menuElement && - !$.ui.contains( menuElement, event.target ) ) { - self.close(); - } - }); - }, 1 ); - } - - // use another timeout to make sure the blur-event-handler on the input was already triggered - setTimeout(function() { - clearTimeout( self.closing ); - }, 13); - }) - .menu({ - focus: function( event, ui ) { - var item = ui.item.data( "item.autocomplete" ); - if ( false !== self._trigger( "focus", event, { item: item } ) ) { - // use value to match what will end up in the input, if it was a key event - if ( /^key/.test(event.originalEvent.type) ) { - self.element.val( item.value ); - } - } - }, - selected: function( event, ui ) { - var item = ui.item.data( "item.autocomplete" ), - previous = self.previous; - - // only trigger when focus was lost (click on menu) - if ( self.element[0] !== doc.activeElement ) { - self.element.focus(); - self.previous = previous; - // #6109 - IE triggers two focus events and the second - // is asynchronous, so we need to reset the previous - // term synchronously and asynchronously :-( - setTimeout(function() { - self.previous = previous; - self.selectedItem = item; - }, 1); - } - - if ( false !== self._trigger( "select", event, { item: item } ) ) { - self.element.val( item.value ); - } - // reset the term after the select event - // this allows custom select handling to work properly - self.term = self.element.val(); - - self.close( event ); - self.selectedItem = item; - }, - blur: function( event, ui ) { - // don't set the value of the text field if it's already correct - // this prevents moving the cursor unnecessarily - if ( self.menu.element.is(":visible") && - ( self.element.val() !== self.term ) ) { - self.element.val( self.term ); - } - } - }) - .zIndex( this.element.zIndex() + 1 ) - // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 - .css({ top: 0, left: 0 }) - .hide() - .data( "menu" ); - if ( $.fn.bgiframe ) { - this.menu.element.bgiframe(); - } - // turning off autocomplete prevents the browser from remembering the - // value when navigating through history, so we re-enable autocomplete - // if the page is unloaded before the widget is destroyed. #7790 - self.beforeunloadHandler = function() { - self.element.removeAttr( "autocomplete" ); - }; - $( window ).bind( "beforeunload", self.beforeunloadHandler ); - }, - - destroy: function() { - this.element - .removeClass( "ui-autocomplete-input" ) - .removeAttr( "autocomplete" ) - .removeAttr( "role" ) - .removeAttr( "aria-autocomplete" ) - .removeAttr( "aria-haspopup" ); - this.menu.element.remove(); - $( window ).unbind( "beforeunload", this.beforeunloadHandler ); - $.Widget.prototype.destroy.call( this ); - }, - - _setOption: function( key, value ) { - $.Widget.prototype._setOption.apply( this, arguments ); - if ( key === "source" ) { - this._initSource(); - } - if ( key === "appendTo" ) { - this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] ) - } - if ( key === "disabled" && value && this.xhr ) { - this.xhr.abort(); - } - }, - - _initSource: function() { - var self = this, - array, - url; - if ( $.isArray(this.options.source) ) { - array = this.options.source; - this.source = function( request, response ) { - response( $.ui.autocomplete.filter(array, request.term) ); - }; - } else if ( typeof this.options.source === "string" ) { - url = this.options.source; - this.source = function( request, response ) { - if ( self.xhr ) { - self.xhr.abort(); - } - self.xhr = $.ajax({ - url: url, - data: request, - dataType: "json", - success: function( data, status ) { - response( data ); - }, - error: function() { - response( [] ); - } - }); - }; - } else { - this.source = this.options.source; - } - }, - - search: function( value, event ) { - value = value != null ? value : this.element.val(); - - // always save the actual value, not the one passed as an argument - this.term = this.element.val(); - - if ( value.length < this.options.minLength ) { - return this.close( event ); - } - - clearTimeout( this.closing ); - if ( this._trigger( "search", event ) === false ) { - return; - } - - return this._search( value ); - }, - - _search: function( value ) { - this.pending++; - this.element.addClass( "ui-autocomplete-loading" ); - - this.source( { term: value }, this._response() ); - }, - - _response: function() { - var that = this, - index = ++requestIndex; - - return function( content ) { - if ( index === requestIndex ) { - that.__response( content ); - } - - that.pending--; - if ( !that.pending ) { - that.element.removeClass( "ui-autocomplete-loading" ); - } - }; - }, - - __response: function( content ) { - if ( !this.options.disabled && content && content.length ) { - content = this._normalize( content ); - this._suggest( content ); - this._trigger( "open" ); - } else { - this.close(); - } - }, - - close: function( event ) { - clearTimeout( this.closing ); - if ( this.menu.element.is(":visible") ) { - this.menu.element.hide(); - this.menu.deactivate(); - this._trigger( "close", event ); - } - }, - - _change: function( event ) { - if ( this.previous !== this.element.val() ) { - this._trigger( "change", event, { item: this.selectedItem } ); - } - }, - - _normalize: function( items ) { - // assume all items have the right format when the first item is complete - if ( items.length && items[0].label && items[0].value ) { - return items; - } - return $.map( items, function(item) { - if ( typeof item === "string" ) { - return { - label: item, - value: item - }; - } - return $.extend({ - label: item.label || item.value, - value: item.value || item.label - }, item ); - }); - }, - - _suggest: function( items ) { - var ul = this.menu.element - .empty() - .zIndex( this.element.zIndex() + 1 ); - this._renderMenu( ul, items ); - // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate - this.menu.deactivate(); - this.menu.refresh(); - - // size and position menu - ul.show(); - this._resizeMenu(); - ul.position( $.extend({ - of: this.element - }, this.options.position )); - - if ( this.options.autoFocus ) { - this.menu.next( new $.Event("mouseover") ); - } - }, - - _resizeMenu: function() { - var ul = this.menu.element; - ul.outerWidth( Math.max( - // Firefox wraps long text (possibly a rounding bug) - // so we add 1px to avoid the wrapping (#7513) - ul.width( "" ).outerWidth() + 1, - this.element.outerWidth() - ) ); - }, - - _renderMenu: function( ul, items ) { - var self = this; - $.each( items, function( index, item ) { - self._renderItem( ul, item ); - }); - }, - - _renderItem: function( ul, item) { - return $( "
                • " ) - .data( "item.autocomplete", item ) - .append( $( "" ).text( item.label ) ) - .appendTo( ul ); - }, - - _move: function( direction, event ) { - if ( !this.menu.element.is(":visible") ) { - this.search( null, event ); - return; - } - if ( this.menu.first() && /^previous/.test(direction) || - this.menu.last() && /^next/.test(direction) ) { - this.element.val( this.term ); - this.menu.deactivate(); - return; - } - this.menu[ direction ]( event ); - }, - - widget: function() { - return this.menu.element; - }, - _keyEvent: function( keyEvent, event ) { - if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { - this._move( keyEvent, event ); - - // prevents moving cursor to beginning/end of the text field in some browsers - event.preventDefault(); - } - } -}); - -$.extend( $.ui.autocomplete, { - escapeRegex: function( value ) { - return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); - }, - filter: function(array, term) { - var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); - return $.grep( array, function(value) { - return matcher.test( value.label || value.value || value ); - }); - } -}); - -}( jQuery )); - -/* - * jQuery UI Menu (not officially released) - * - * This widget isn't yet finished and the API is subject to change. We plan to finish - * it for the next release. You're welcome to give it a try anyway and give us feedback, - * as long as you're okay with migrating your code later on. We can help with that, too. - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.menu", { - _create: function() { - var self = this; - this.element - .addClass("ui-menu ui-widget ui-widget-content ui-corner-all") - .attr({ - role: "listbox", - "aria-activedescendant": "ui-active-menuitem" - }) - .click(function( event ) { - if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { - return; - } - // temporary - event.preventDefault(); - self.select( event ); - }); - this.refresh(); - }, - - refresh: function() { - var self = this; - - // don't refresh list items that are already adapted - var items = this.element.children("li:not(.ui-menu-item):has(a)") - .addClass("ui-menu-item") - .attr("role", "menuitem"); - - items.children("a") - .addClass("ui-corner-all") - .attr("tabindex", -1) - // mouseenter doesn't work with event delegation - .mouseenter(function( event ) { - self.activate( event, $(this).parent() ); - }) - .mouseleave(function() { - self.deactivate(); - }); - }, - - activate: function( event, item ) { - this.deactivate(); - if (this.hasScroll()) { - var offset = item.offset().top - this.element.offset().top, - scroll = this.element.scrollTop(), - elementHeight = this.element.height(); - if (offset < 0) { - this.element.scrollTop( scroll + offset); - } else if (offset >= elementHeight) { - this.element.scrollTop( scroll + offset - elementHeight + item.height()); - } - } - this.active = item.eq(0) - .children("a") - .addClass("ui-state-hover") - .attr("id", "ui-active-menuitem") - .end(); - this._trigger("focus", event, { item: item }); - }, - - deactivate: function() { - if (!this.active) { return; } - - this.active.children("a") - .removeClass("ui-state-hover") - .removeAttr("id"); - this._trigger("blur"); - this.active = null; - }, - - next: function(event) { - this.move("next", ".ui-menu-item:first", event); - }, - - previous: function(event) { - this.move("prev", ".ui-menu-item:last", event); - }, - - first: function() { - return this.active && !this.active.prevAll(".ui-menu-item").length; - }, - - last: function() { - return this.active && !this.active.nextAll(".ui-menu-item").length; - }, - - move: function(direction, edge, event) { - if (!this.active) { - this.activate(event, this.element.children(edge)); - return; - } - var next = this.active[direction + "All"](".ui-menu-item").eq(0); - if (next.length) { - this.activate(event, next); - } else { - this.activate(event, this.element.children(edge)); - } - }, - - // TODO merge with previousPage - nextPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.last()) { - this.activate(event, this.element.children(".ui-menu-item:first")); - return; - } - var base = this.active.offset().top, - height = this.element.height(), - result = this.element.children(".ui-menu-item").filter(function() { - var close = $(this).offset().top - base - height + $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); - - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(".ui-menu-item:last"); - } - this.activate(event, result); - } else { - this.activate(event, this.element.children(".ui-menu-item") - .filter(!this.active || this.last() ? ":first" : ":last")); - } - }, - - // TODO merge with nextPage - previousPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.first()) { - this.activate(event, this.element.children(".ui-menu-item:last")); - return; - } - - var base = this.active.offset().top, - height = this.element.height(), - result = this.element.children(".ui-menu-item").filter(function() { - var close = $(this).offset().top - base + height - $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); - - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(".ui-menu-item:first"); - } - this.activate(event, result); - } else { - this.activate(event, this.element.children(".ui-menu-item") - .filter(!this.active || this.first() ? ":last" : ":first")); - } - }, - - hasScroll: function() { - return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight"); - }, - - select: function( event ) { - this._trigger("selected", event, { item: this.active }); - } -}); - -}(jQuery)); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.autocomplete.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.autocomplete.min.js deleted file mode 100644 index 205e24b697..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.autocomplete.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.autocomplete.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c=0;a.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var b=this,c=this.element[0].ownerDocument,d;this.isMultiLine=this.element.is("textarea"),this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(b.options.disabled||b.element.propAttr("readOnly"))return;d=!1;var e=a.ui.keyCode;switch(c.keyCode){case e.PAGE_UP:b._move("previousPage",c);break;case e.PAGE_DOWN:b._move("nextPage",c);break;case e.UP:b._keyEvent("previous",c);break;case e.DOWN:b._keyEvent("next",c);break;case e.ENTER:case e.NUMPAD_ENTER:b.menu.active&&(d=!0,c.preventDefault());case e.TAB:if(!b.menu.active)return;b.menu.select(c);break;case e.ESCAPE:b.element.val(b.term),b.close(c);break;default:clearTimeout(b.searching),b.searching=setTimeout(function(){b.term!=b.element.val()&&(b.selectedItem=null,b.search(null,c))},b.options.delay)}}).bind("keypress.autocomplete",function(a){d&&(d=!1,a.preventDefault())}).bind("focus.autocomplete",function(){if(b.options.disabled)return;b.selectedItem=null,b.previous=b.element.val()}).bind("blur.autocomplete",function(a){if(b.options.disabled)return;clearTimeout(b.searching),b.closing=setTimeout(function(){b.close(a),b._change(a)},150)}),this._initSource(),this.menu=a("
                    ").addClass("ui-autocomplete").appendTo(a(this.options.appendTo||"body",c)[0]).mousedown(function(c){var d=b.menu.element[0];a(c.target).closest(".ui-menu-item").length||setTimeout(function(){a(document).one("mousedown",function(c){c.target!==b.element[0]&&c.target!==d&&!a.ui.contains(d,c.target)&&b.close()})},1),setTimeout(function(){clearTimeout(b.closing)},13)}).menu({focus:function(a,c){var d=c.item.data("item.autocomplete");!1!==b._trigger("focus",a,{item:d})&&/^key/.test(a.originalEvent.type)&&b.element.val(d.value)},selected:function(a,d){var e=d.item.data("item.autocomplete"),f=b.previous;b.element[0]!==c.activeElement&&(b.element.focus(),b.previous=f,setTimeout(function(){b.previous=f,b.selectedItem=e},1)),!1!==b._trigger("select",a,{item:e})&&b.element.val(e.value),b.term=b.element.val(),b.close(a),b.selectedItem=e},blur:function(a,c){b.menu.element.is(":visible")&&b.element.val()!==b.term&&b.element.val(b.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"),a.fn.bgiframe&&this.menu.element.bgiframe(),b.beforeunloadHandler=function(){b.element.removeAttr("autocomplete")},a(window).bind("beforeunload",b.beforeunloadHandler)},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup"),this.menu.element.remove(),a(window).unbind("beforeunload",this.beforeunloadHandler),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments),b==="source"&&this._initSource(),b==="appendTo"&&this.menu.element.appendTo(a(c||"body",this.element[0].ownerDocument)[0]),b==="disabled"&&c&&this.xhr&&this.xhr.abort()},_initSource:function(){var b=this,c,d;a.isArray(this.options.source)?(c=this.options.source,this.source=function(b,d){d(a.ui.autocomplete.filter(c,b.term))}):typeof this.options.source=="string"?(d=this.options.source,this.source=function(c,e){b.xhr&&b.xhr.abort(),b.xhr=a.ajax({url:d,data:c,dataType:"json",success:function(a,b){e(a)},error:function(){e([])}})}):this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val(),this.term=this.element.val();if(a.length").data("item.autocomplete",c).append(a("").text(c.label)).appendTo(b)},_move:function(a,b){if(!this.menu.element.is(":visible")){this.search(null,b);return}if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term),this.menu.deactivate();return}this.menu[a](b)},widget:function(){return this.menu.element},_keyEvent:function(a,b){if(!this.isMultiLine||this.menu.element.is(":visible"))this._move(a,b),b.preventDefault()}}),a.extend(a.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(b,c){var d=new RegExp(a.ui.autocomplete.escapeRegex(c),"i");return a.grep(b,function(a){return d.test(a.label||a.value||a)})}})})(jQuery),function(a){a.widget("ui.menu",{_create:function(){var b=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(c){if(!a(c.target).closest(".ui-menu-item a").length)return;c.preventDefault(),b.select(c)}),this.refresh()},refresh:function(){var b=this,c=this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem");c.children("a").addClass("ui-corner-all").attr("tabindex",-1).mouseenter(function(c){b.activate(c,a(this).parent())}).mouseleave(function(){b.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var c=b.offset().top-this.element.offset().top,d=this.element.scrollTop(),e=this.element.height();c<0?this.element.scrollTop(d+c):c>=e&&this.element.scrollTop(d+c-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end(),this._trigger("focus",a,{item:b})},deactivate:function(){if(!this.active)return;this.active.children("a").removeClass("ui-state-hover").removeAttr("id"),this._trigger("blur"),this.active=null},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,c){if(!this.active){this.activate(c,this.element.children(b));return}var d=this.active[a+"All"](".ui-menu-item").eq(0);d.length?this.activate(c,d):this.activate(c,this.element.children(b))},nextPage:function(b){if(this.hasScroll()){if(!this.active||this.last()){this.activate(b,this.element.children(".ui-menu-item:first"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c-d+a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:last")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(b){if(this.hasScroll()){if(!this.active||this.first()){this.activate(b,this.element.children(".ui-menu-item:last"));return}var c=this.active.offset().top,d=this.element.height(),e=this.element.children(".ui-menu-item").filter(function(){var b=a(this).offset().top-c+d-a(this).height();return b<10&&b>-10});e.length||(e=this.element.children(".ui-menu-item:first")),this.activate(b,e)}else this.activate(b,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()", this.element[0].ownerDocument ) - .addClass( "ui-button-text" ) - .html( this.options.label ) - .appendTo( buttonElement.empty() ) - .text(), - icons = this.options.icons, - multipleIcons = icons.primary && icons.secondary, - buttonClasses = []; - - if ( icons.primary || icons.secondary ) { - if ( this.options.text ) { - buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); - } - - if ( icons.primary ) { - buttonElement.prepend( "" ); - } - - if ( icons.secondary ) { - buttonElement.append( "" ); - } - - if ( !this.options.text ) { - buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); - - if ( !this.hasTitle ) { - buttonElement.attr( "title", buttonText ); - } - } - } else { - buttonClasses.push( "ui-button-text-only" ); - } - buttonElement.addClass( buttonClasses.join( " " ) ); - } -}); - -$.widget( "ui.buttonset", { - options: { - items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)" - }, - - _create: function() { - this.element.addClass( "ui-buttonset" ); - }, - - _init: function() { - this.refresh(); - }, - - _setOption: function( key, value ) { - if ( key === "disabled" ) { - this.buttons.button( "option", key, value ); - } - - $.Widget.prototype._setOption.apply( this, arguments ); - }, - - refresh: function() { - var rtl = this.element.css( "direction" ) === "rtl"; - - this.buttons = this.element.find( this.options.items ) - .filter( ":ui-button" ) - .button( "refresh" ) - .end() - .not( ":ui-button" ) - .button() - .end() - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) - .filter( ":first" ) - .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) - .end() - .filter( ":last" ) - .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) - .end() - .end(); - }, - - destroy: function() { - this.element.removeClass( "ui-buttonset" ); - this.buttons - .map(function() { - return $( this ).button( "widget" )[ 0 ]; - }) - .removeClass( "ui-corner-left ui-corner-right" ) - .end() - .button( "destroy" ); - - $.Widget.prototype.destroy.call( this ); - } -}); - -}( jQuery ) ); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.button.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.button.min.js deleted file mode 100644 index 6b4045a610..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.button.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.button.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c,d,e,f,g="ui-button ui-widget ui-state-default ui-corner-all",h="ui-state-hover ui-state-active ",i="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",j=function(){var b=a(this).find(":ui-button");setTimeout(function(){b.button("refresh")},1)},k=function(b){var c=b.name,d=b.form,e=a([]);return c&&(d?e=a(d).find("[name='"+c+"']"):e=a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form})),e};a.widget("ui.button",{options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",j),typeof this.options.disabled!="boolean"?this.options.disabled=!!this.element.propAttr("disabled"):this.element.propAttr("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var b=this,h=this.options,i=this.type==="checkbox"||this.type==="radio",l="ui-state-hover"+(i?"":" ui-state-active"),m="ui-state-focus";h.label===null&&(h.label=this.buttonElement.html()),this.buttonElement.addClass(g).attr("role","button").bind("mouseenter.button",function(){if(h.disabled)return;a(this).addClass("ui-state-hover"),this===c&&a(this).addClass("ui-state-active")}).bind("mouseleave.button",function(){if(h.disabled)return;a(this).removeClass(l)}).bind("click.button",function(a){h.disabled&&(a.preventDefault(),a.stopImmediatePropagation())}),this.element.bind("focus.button",function(){b.buttonElement.addClass(m)}).bind("blur.button",function(){b.buttonElement.removeClass(m)}),i&&(this.element.bind("change.button",function(){if(f)return;b.refresh()}),this.buttonElement.bind("mousedown.button",function(a){if(h.disabled)return;f=!1,d=a.pageX,e=a.pageY}).bind("mouseup.button",function(a){if(h.disabled)return;if(d!==a.pageX||e!==a.pageY)f=!0})),this.type==="checkbox"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).toggleClass("ui-state-active"),b.buttonElement.attr("aria-pressed",b.element[0].checked)}):this.type==="radio"?this.buttonElement.bind("click.button",function(){if(h.disabled||f)return!1;a(this).addClass("ui-state-active"),b.buttonElement.attr("aria-pressed","true");var c=b.element[0];k(c).not(c).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown.button",function(){if(h.disabled)return!1;a(this).addClass("ui-state-active"),c=this,a(document).one("mouseup",function(){c=null})}).bind("mouseup.button",function(){if(h.disabled)return!1;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(b){if(h.disabled)return!1;(b.keyCode==a.ui.keyCode.SPACE||b.keyCode==a.ui.keyCode.ENTER)&&a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(b){b.keyCode===a.ui.keyCode.SPACE&&a(this).click()})),this._setOption("disabled",h.disabled),this._resetButton()},_determineButtonType:function(){this.element.is(":checkbox")?this.type="checkbox":this.element.is(":radio")?this.type="radio":this.element.is("input")?this.type="input":this.type="button";if(this.type==="checkbox"||this.type==="radio"){var a=this.element.parents().filter(":last"),b="label[for='"+this.element.attr("id")+"']";this.buttonElement=a.find(b),this.buttonElement.length||(a=a.length?a.siblings():this.element.siblings(),this.buttonElement=a.filter(b),this.buttonElement.length||(this.buttonElement=a.find(b))),this.element.addClass("ui-helper-hidden-accessible");var c=this.element.is(":checked");c&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.attr("aria-pressed",c)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(g+" "+h+" "+i).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title"),a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled"){c?this.element.propAttr("disabled",!0):this.element.propAttr("disabled",!1);return}this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b),this.type==="radio"?k(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):this.type==="checkbox"&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if(this.type==="input"){this.options.label&&this.element.val(this.options.label);return}var b=this.buttonElement.removeClass(i),c=a("",this.element[0].ownerDocument).addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary,f=[];d.primary||d.secondary?(this.options.text&&f.push("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary")),d.primary&&b.prepend(""),d.secondary&&b.append(""),this.options.text||(f.push(e?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||b.attr("title",c))):f.push("ui-button-text-only"),b.addClass(f.join(" "))}}),a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c),a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var b=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(b?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(b?"ui-corner-left":"ui-corner-right").end().end()},destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"),a.Widget.prototype.destroy.call(this)}})})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.core.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.core.js deleted file mode 100644 index b36c1ac4bf..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.core.js +++ /dev/null @@ -1,334 +0,0 @@ -/*! - * jQuery UI 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI - */ -(function( $, undefined ) { - -// prevent duplicate loading -// this is only a problem because we proxy existing functions -// and we don't want to double proxy them -$.ui = $.ui || {}; -if ( $.ui.version ) { - return; -} - -$.extend( $.ui, { - version: "1.8.24", - - keyCode: { - ALT: 18, - BACKSPACE: 8, - CAPS_LOCK: 20, - COMMA: 188, - COMMAND: 91, - COMMAND_LEFT: 91, // COMMAND - COMMAND_RIGHT: 93, - CONTROL: 17, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - INSERT: 45, - LEFT: 37, - MENU: 93, // COMMAND_RIGHT - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SHIFT: 16, - SPACE: 32, - TAB: 9, - UP: 38, - WINDOWS: 91 // COMMAND - } -}); - -// plugins -$.fn.extend({ - propAttr: $.fn.prop || $.fn.attr, - - _focus: $.fn.focus, - focus: function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - this._focus.apply( this, arguments ); - }, - - scrollParent: function() { - var scrollParent; - if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1)); - }).eq(0); - } - - return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
                    - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0; - if ( border ) { - size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - var map = element.parentNode, - mapName = map.name, - img; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) - ? !element.disabled - : "a" == nodeName - ? element.href || isTabIndexNotNaN - : isTabIndexNotNaN) - // the element and all of its ancestors must be visible - && visible( element ); -} - -function visible( element ) { - return !$( element ).parents().andSelf().filter(function() { - return $.curCSS( this, "visibility" ) === "hidden" || - $.expr.filters.hidden( this ); - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support -$(function() { - var body = document.body, - div = body.appendChild( div = document.createElement( "div" ) ); - - // access offsetHeight before setting the style to prevent a layout bug - // in IE 9 which causes the elemnt to continue to take up space even - // after it is removed from the DOM (#8026) - div.offsetHeight; - - $.extend( div.style, { - minHeight: "100px", - height: "auto", - padding: 0, - borderWidth: 0 - }); - - $.support.minHeight = div.offsetHeight === 100; - $.support.selectstart = "onselectstart" in div; - - // set display to none to avoid a layout bug in IE - // http://dev.jquery.com/ticket/4014 - body.removeChild( div ).style.display = "none"; -}); - -// jQuery <1.4.3 uses curCSS, in 1.4.3 - 1.7.2 curCSS = css, 1.8+ only has css -if ( !$.curCSS ) { - $.curCSS = $.css; -} - - - - - -// deprecated -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use the proxy pattern instead. - plugin: { - add: function( module, option, set ) { - var proto = $.ui[ module ].prototype; - for ( var i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode ) { - return; - } - - for ( var i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // will be deprecated when we switch to jQuery 1.4 - use jQuery.contains() - contains: function( a, b ) { - return document.compareDocumentPosition ? - a.compareDocumentPosition( b ) & 16 : - a !== b && a.contains( b ); - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - }, - - // these are odd functions, fix the API or move into individual plugins - isOverAxis: function( x, reference, size ) { - //Determines when x coordinate is over "b" element axis - return ( x > reference ) && ( x < ( reference + size ) ); - }, - isOver: function( y, x, top, left, height, width ) { - //Determines when x, y coordinates is over "b" element - return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width ); - } -}); - -})( jQuery ); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.core.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.core.min.js deleted file mode 100644 index 9724c2a4d2..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.core.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.core.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.24",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a this are in the previous century, - // string value starting with '+' for current year + value - minDate: null, // The earliest selectable date, or null for no limit - maxDate: null, // The latest selectable date, or null for no limit - duration: 'fast', // Duration of display/closure - beforeShowDay: null, // Function that takes a date and returns an array with - // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', - // [2] = cell title (optional), e.g. $.datepicker.noWeekends - beforeShow: null, // Function that takes an input field and - // returns a set of custom settings for the date picker - onSelect: null, // Define a callback function when a date is selected - onChangeMonthYear: null, // Define a callback function when the month or year is changed - onClose: null, // Define a callback function when the datepicker is closed - numberOfMonths: 1, // Number of months to show at a time - showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) - stepMonths: 1, // Number of months to step back/forward - stepBigMonths: 12, // Number of months to step back/forward for the big links - altField: '', // Selector for an alternate field to store selected dates into - altFormat: '', // The date format to use for the alternate field - constrainInput: true, // The input is constrained by the current date format - showButtonPanel: false, // True to show button panel, false to not show it - autoSize: false, // True to size the input for the date format, false to leave as is - disabled: false // The initial disabled state - }; - $.extend(this._defaults, this.regional['']); - this.dpDiv = bindHover($('
                    ')); -} - -$.extend(Datepicker.prototype, { - /* Class name added to elements to indicate already configured with a date picker. */ - markerClassName: 'hasDatepicker', - - //Keep track of the maximum number of rows displayed (see #7043) - maxRows: 4, - - /* Debug logging (if enabled). */ - log: function () { - if (this.debug) - console.log.apply('', arguments); - }, - - // TODO rename to "widget" when switching to widget factory - _widgetDatepicker: function() { - return this.dpDiv; - }, - - /* Override the default settings for all instances of the date picker. - @param settings object - the new settings to use as defaults (anonymous object) - @return the manager object */ - setDefaults: function(settings) { - extendRemove(this._defaults, settings || {}); - return this; - }, - - /* Attach the date picker to a jQuery selection. - @param target element - the target input field or division or span - @param settings object - the new settings to use for this date picker instance (anonymous) */ - _attachDatepicker: function(target, settings) { - // check for settings on the control itself - in namespace 'date:' - var inlineSettings = null; - for (var attrName in this._defaults) { - var attrValue = target.getAttribute('date:' + attrName); - if (attrValue) { - inlineSettings = inlineSettings || {}; - try { - inlineSettings[attrName] = eval(attrValue); - } catch (err) { - inlineSettings[attrName] = attrValue; - } - } - } - var nodeName = target.nodeName.toLowerCase(); - var inline = (nodeName == 'div' || nodeName == 'span'); - if (!target.id) { - this.uuid += 1; - target.id = 'dp' + this.uuid; - } - var inst = this._newInst($(target), inline); - inst.settings = $.extend({}, settings || {}, inlineSettings || {}); - if (nodeName == 'input') { - this._connectDatepicker(target, inst); - } else if (inline) { - this._inlineDatepicker(target, inst); - } - }, - - /* Create a new instance object. */ - _newInst: function(target, inline) { - var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars - return {id: id, input: target, // associated target - selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection - drawMonth: 0, drawYear: 0, // month being drawn - inline: inline, // is datepicker inline or not - dpDiv: (!inline ? this.dpDiv : // presentation div - bindHover($('
                    ')))}; - }, - - /* Attach the date picker to an input field. */ - _connectDatepicker: function(target, inst) { - var input = $(target); - inst.append = $([]); - inst.trigger = $([]); - if (input.hasClass(this.markerClassName)) - return; - this._attachments(input, inst); - input.addClass(this.markerClassName).keydown(this._doKeyDown). - keypress(this._doKeyPress).keyup(this._doKeyUp). - bind("setData.datepicker", function(event, key, value) { - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key) { - return this._get(inst, key); - }); - this._autoSize(inst); - $.data(target, PROP_NAME, inst); - //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) - if( inst.settings.disabled ) { - this._disableDatepicker( target ); - } - }, - - /* Make attachments based on settings. */ - _attachments: function(input, inst) { - var appendText = this._get(inst, 'appendText'); - var isRTL = this._get(inst, 'isRTL'); - if (inst.append) - inst.append.remove(); - if (appendText) { - inst.append = $('' + appendText + ''); - input[isRTL ? 'before' : 'after'](inst.append); - } - input.unbind('focus', this._showDatepicker); - if (inst.trigger) - inst.trigger.remove(); - var showOn = this._get(inst, 'showOn'); - if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field - input.focus(this._showDatepicker); - if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked - var buttonText = this._get(inst, 'buttonText'); - var buttonImage = this._get(inst, 'buttonImage'); - inst.trigger = $(this._get(inst, 'buttonImageOnly') ? - $('').addClass(this._triggerClass). - attr({ src: buttonImage, alt: buttonText, title: buttonText }) : - $('').addClass(this._triggerClass). - html(buttonImage == '' ? buttonText : $('').attr( - { src:buttonImage, alt:buttonText, title:buttonText }))); - input[isRTL ? 'before' : 'after'](inst.trigger); - inst.trigger.click(function() { - if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0]) - $.datepicker._hideDatepicker(); - else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) { - $.datepicker._hideDatepicker(); - $.datepicker._showDatepicker(input[0]); - } else - $.datepicker._showDatepicker(input[0]); - return false; - }); - } - }, - - /* Apply the maximum length for the date format. */ - _autoSize: function(inst) { - if (this._get(inst, 'autoSize') && !inst.inline) { - var date = new Date(2009, 12 - 1, 20); // Ensure double digits - var dateFormat = this._get(inst, 'dateFormat'); - if (dateFormat.match(/[DM]/)) { - var findMax = function(names) { - var max = 0; - var maxI = 0; - for (var i = 0; i < names.length; i++) { - if (names[i].length > max) { - max = names[i].length; - maxI = i; - } - } - return maxI; - }; - date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? - 'monthNames' : 'monthNamesShort')))); - date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? - 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay()); - } - inst.input.attr('size', this._formatDate(inst, date).length); - } - }, - - /* Attach an inline date picker to a div. */ - _inlineDatepicker: function(target, inst) { - var divSpan = $(target); - if (divSpan.hasClass(this.markerClassName)) - return; - divSpan.addClass(this.markerClassName).append(inst.dpDiv). - bind("setData.datepicker", function(event, key, value){ - inst.settings[key] = value; - }).bind("getData.datepicker", function(event, key){ - return this._get(inst, key); - }); - $.data(target, PROP_NAME, inst); - this._setDate(inst, this._getDefaultDate(inst), true); - this._updateDatepicker(inst); - this._updateAlternate(inst); - //If disabled option is true, disable the datepicker before showing it (see ticket #5665) - if( inst.settings.disabled ) { - this._disableDatepicker( target ); - } - // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements - // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height - inst.dpDiv.css( "display", "block" ); - }, - - /* Pop-up the date picker in a "dialog" box. - @param input element - ignored - @param date string or Date - the initial date to display - @param onSelect function - the function to call when a date is selected - @param settings object - update the dialog date picker instance's settings (anonymous object) - @param pos int[2] - coordinates for the dialog's position within the screen or - event - with x/y coordinates or - leave empty for default (screen centre) - @return the manager object */ - _dialogDatepicker: function(input, date, onSelect, settings, pos) { - var inst = this._dialogInst; // internal instance - if (!inst) { - this.uuid += 1; - var id = 'dp' + this.uuid; - this._dialogInput = $(''); - this._dialogInput.keydown(this._doKeyDown); - $('body').append(this._dialogInput); - inst = this._dialogInst = this._newInst(this._dialogInput, false); - inst.settings = {}; - $.data(this._dialogInput[0], PROP_NAME, inst); - } - extendRemove(inst.settings, settings || {}); - date = (date && date.constructor == Date ? this._formatDate(inst, date) : date); - this._dialogInput.val(date); - - this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); - if (!this._pos) { - var browserWidth = document.documentElement.clientWidth; - var browserHeight = document.documentElement.clientHeight; - var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; - var scrollY = document.documentElement.scrollTop || document.body.scrollTop; - this._pos = // should use actual width/height below - [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; - } - - // move input on screen for focus, but hidden behind dialog - this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px'); - inst.settings.onSelect = onSelect; - this._inDialog = true; - this.dpDiv.addClass(this._dialogClass); - this._showDatepicker(this._dialogInput[0]); - if ($.blockUI) - $.blockUI(this.dpDiv); - $.data(this._dialogInput[0], PROP_NAME, inst); - return this; - }, - - /* Detach a datepicker from its control. - @param target element - the target input field or division or span */ - _destroyDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - $.removeData(target, PROP_NAME); - if (nodeName == 'input') { - inst.append.remove(); - inst.trigger.remove(); - $target.removeClass(this.markerClassName). - unbind('focus', this._showDatepicker). - unbind('keydown', this._doKeyDown). - unbind('keypress', this._doKeyPress). - unbind('keyup', this._doKeyUp); - } else if (nodeName == 'div' || nodeName == 'span') - $target.removeClass(this.markerClassName).empty(); - }, - - /* Enable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _enableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = false; - inst.trigger.filter('button'). - each(function() { this.disabled = false; }).end(). - filter('img').css({opacity: '1.0', cursor: ''}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().removeClass('ui-state-disabled'); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - removeAttr("disabled"); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - }, - - /* Disable the date picker to a jQuery selection. - @param target element - the target input field or division or span */ - _disableDatepicker: function(target) { - var $target = $(target); - var inst = $.data(target, PROP_NAME); - if (!$target.hasClass(this.markerClassName)) { - return; - } - var nodeName = target.nodeName.toLowerCase(); - if (nodeName == 'input') { - target.disabled = true; - inst.trigger.filter('button'). - each(function() { this.disabled = true; }).end(). - filter('img').css({opacity: '0.5', cursor: 'default'}); - } - else if (nodeName == 'div' || nodeName == 'span') { - var inline = $target.children('.' + this._inlineClass); - inline.children().addClass('ui-state-disabled'); - inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). - attr("disabled", "disabled"); - } - this._disabledInputs = $.map(this._disabledInputs, - function(value) { return (value == target ? null : value); }); // delete entry - this._disabledInputs[this._disabledInputs.length] = target; - }, - - /* Is the first field in a jQuery collection disabled as a datepicker? - @param target element - the target input field or division or span - @return boolean - true if disabled, false if enabled */ - _isDisabledDatepicker: function(target) { - if (!target) { - return false; - } - for (var i = 0; i < this._disabledInputs.length; i++) { - if (this._disabledInputs[i] == target) - return true; - } - return false; - }, - - /* Retrieve the instance data for the target control. - @param target element - the target input field or division or span - @return object - the associated instance data - @throws error if a jQuery problem getting data */ - _getInst: function(target) { - try { - return $.data(target, PROP_NAME); - } - catch (err) { - throw 'Missing instance data for this datepicker'; - } - }, - - /* Update or retrieve the settings for a date picker attached to an input field or division. - @param target element - the target input field or division or span - @param name object - the new settings to update or - string - the name of the setting to change or retrieve, - when retrieving also 'all' for all instance settings or - 'defaults' for all global defaults - @param value any - the new value for the setting - (omit if above is an object or to retrieve a value) */ - _optionDatepicker: function(target, name, value) { - var inst = this._getInst(target); - if (arguments.length == 2 && typeof name == 'string') { - return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) : - (inst ? (name == 'all' ? $.extend({}, inst.settings) : - this._get(inst, name)) : null)); - } - var settings = name || {}; - if (typeof name == 'string') { - settings = {}; - settings[name] = value; - } - if (inst) { - if (this._curInst == inst) { - this._hideDatepicker(); - } - var date = this._getDateDatepicker(target, true); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - extendRemove(inst.settings, settings); - // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided - if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined) - inst.settings.minDate = this._formatDate(inst, minDate); - if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined) - inst.settings.maxDate = this._formatDate(inst, maxDate); - this._attachments($(target), inst); - this._autoSize(inst); - this._setDate(inst, date); - this._updateAlternate(inst); - this._updateDatepicker(inst); - } - }, - - // change method deprecated - _changeDatepicker: function(target, name, value) { - this._optionDatepicker(target, name, value); - }, - - /* Redraw the date picker attached to an input field or division. - @param target element - the target input field or division or span */ - _refreshDatepicker: function(target) { - var inst = this._getInst(target); - if (inst) { - this._updateDatepicker(inst); - } - }, - - /* Set the dates for a jQuery selection. - @param target element - the target input field or division or span - @param date Date - the new date */ - _setDateDatepicker: function(target, date) { - var inst = this._getInst(target); - if (inst) { - this._setDate(inst, date); - this._updateDatepicker(inst); - this._updateAlternate(inst); - } - }, - - /* Get the date(s) for the first entry in a jQuery selection. - @param target element - the target input field or division or span - @param noDefault boolean - true if no default date is to be used - @return Date - the current date */ - _getDateDatepicker: function(target, noDefault) { - var inst = this._getInst(target); - if (inst && !inst.inline) - this._setDateFromField(inst, noDefault); - return (inst ? this._getDate(inst) : null); - }, - - /* Handle keystrokes. */ - _doKeyDown: function(event) { - var inst = $.datepicker._getInst(event.target); - var handled = true; - var isRTL = inst.dpDiv.is('.ui-datepicker-rtl'); - inst._keyEvent = true; - if ($.datepicker._datepickerShowing) - switch (event.keyCode) { - case 9: $.datepicker._hideDatepicker(); - handled = false; - break; // hide on tab out - case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' + - $.datepicker._currentClass + ')', inst.dpDiv); - if (sel[0]) - $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); - var onSelect = $.datepicker._get(inst, 'onSelect'); - if (onSelect) { - var dateStr = $.datepicker._formatDate(inst); - - // trigger custom callback - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); - } - else - $.datepicker._hideDatepicker(); - return false; // don't submit the form - break; // select the value on enter - case 27: $.datepicker._hideDatepicker(); - break; // hide on escape - case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // previous month/year on page up/+ ctrl - case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - break; // next month/year on page down/+ ctrl - case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target); - handled = event.ctrlKey || event.metaKey; - break; // clear on ctrl or command +end - case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target); - handled = event.ctrlKey || event.metaKey; - break; // current on ctrl or command +home - case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D'); - handled = event.ctrlKey || event.metaKey; - // -1 day on ctrl or command +left - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - -$.datepicker._get(inst, 'stepBigMonths') : - -$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +left on Mac - break; - case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // -1 week on ctrl or command +up - case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D'); - handled = event.ctrlKey || event.metaKey; - // +1 day on ctrl or command +right - if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ? - +$.datepicker._get(inst, 'stepBigMonths') : - +$.datepicker._get(inst, 'stepMonths')), 'M'); - // next month/year on alt +right - break; - case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D'); - handled = event.ctrlKey || event.metaKey; - break; // +1 week on ctrl or command +down - default: handled = false; - } - else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home - $.datepicker._showDatepicker(this); - else { - handled = false; - } - if (handled) { - event.preventDefault(); - event.stopPropagation(); - } - }, - - /* Filter entered characters - based on date format. */ - _doKeyPress: function(event) { - var inst = $.datepicker._getInst(event.target); - if ($.datepicker._get(inst, 'constrainInput')) { - var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')); - var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode); - return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1); - } - }, - - /* Synchronise manual entry and field/alternate field. */ - _doKeyUp: function(event) { - var inst = $.datepicker._getInst(event.target); - if (inst.input.val() != inst.lastVal) { - try { - var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - (inst.input ? inst.input.val() : null), - $.datepicker._getFormatConfig(inst)); - if (date) { // only if valid - $.datepicker._setDateFromField(inst); - $.datepicker._updateAlternate(inst); - $.datepicker._updateDatepicker(inst); - } - } - catch (err) { - $.datepicker.log(err); - } - } - return true; - }, - - /* Pop-up the date picker for a given input field. - If false returned from beforeShow event handler do not show. - @param input element - the input field attached to the date picker or - event - if triggered by focus */ - _showDatepicker: function(input) { - input = input.target || input; - if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger - input = $('input', input.parentNode)[0]; - if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here - return; - var inst = $.datepicker._getInst(input); - if ($.datepicker._curInst && $.datepicker._curInst != inst) { - $.datepicker._curInst.dpDiv.stop(true, true); - if ( inst && $.datepicker._datepickerShowing ) { - $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); - } - } - var beforeShow = $.datepicker._get(inst, 'beforeShow'); - var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; - if(beforeShowSettings === false){ - //false - return; - } - extendRemove(inst.settings, beforeShowSettings); - inst.lastVal = null; - $.datepicker._lastInput = input; - $.datepicker._setDateFromField(inst); - if ($.datepicker._inDialog) // hide cursor - input.value = ''; - if (!$.datepicker._pos) { // position below input - $.datepicker._pos = $.datepicker._findPos(input); - $.datepicker._pos[1] += input.offsetHeight; // add the height - } - var isFixed = false; - $(input).parents().each(function() { - isFixed |= $(this).css('position') == 'fixed'; - return !isFixed; - }); - if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled - $.datepicker._pos[0] -= document.documentElement.scrollLeft; - $.datepicker._pos[1] -= document.documentElement.scrollTop; - } - var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; - $.datepicker._pos = null; - //to avoid flashes on Firefox - inst.dpDiv.empty(); - // determine sizing offscreen - inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'}); - $.datepicker._updateDatepicker(inst); - // fix width for dynamic number of date pickers - // and adjust position before showing - offset = $.datepicker._checkOffset(inst, offset, isFixed); - inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? - 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none', - left: offset.left + 'px', top: offset.top + 'px'}); - if (!inst.inline) { - var showAnim = $.datepicker._get(inst, 'showAnim'); - var duration = $.datepicker._get(inst, 'duration'); - var postProcess = function() { - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !! cover.length ){ - var borders = $.datepicker._getBorders(inst.dpDiv); - cover.css({left: -borders[0], top: -borders[1], - width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}); - } - }; - inst.dpDiv.zIndex($(input).zIndex()+1); - $.datepicker._datepickerShowing = true; - if ($.effects && $.effects[showAnim]) - inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess); - if (!showAnim || !duration) - postProcess(); - if (inst.input.is(':visible') && !inst.input.is(':disabled')) - inst.input.focus(); - $.datepicker._curInst = inst; - } - }, - - /* Generate the date picker content. */ - _updateDatepicker: function(inst) { - var self = this; - self.maxRows = 4; //Reset the max number of rows being displayed (see #7043) - var borders = $.datepicker._getBorders(inst.dpDiv); - instActive = inst; // for delegate hover events - inst.dpDiv.empty().append(this._generateHTML(inst)); - this._attachHandlers(inst); - var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only - if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6 - cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()}) - } - inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover(); - var numMonths = this._getNumberOfMonths(inst); - var cols = numMonths[1]; - var width = 17; - inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width(''); - if (cols > 1) - inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em'); - inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') + - 'Class']('ui-datepicker-multi'); - inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') + - 'Class']('ui-datepicker-rtl'); - if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input && - // #6694 - don't focus the input if it's already focused - // this breaks the change event in IE - inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement) - inst.input.focus(); - // deffered render of the years select (to avoid flashes on Firefox) - if( inst.yearshtml ){ - var origyearshtml = inst.yearshtml; - setTimeout(function(){ - //assure that inst.yearshtml didn't change. - if( origyearshtml === inst.yearshtml && inst.yearshtml ){ - inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml); - } - origyearshtml = inst.yearshtml = null; - }, 0); - } - }, - - /* Retrieve the size of left and top borders for an element. - @param elem (jQuery object) the element of interest - @return (number[2]) the left and top borders */ - _getBorders: function(elem) { - var convert = function(value) { - return {thin: 1, medium: 2, thick: 3}[value] || value; - }; - return [parseFloat(convert(elem.css('border-left-width'))), - parseFloat(convert(elem.css('border-top-width')))]; - }, - - /* Check positioning to remain on screen. */ - _checkOffset: function(inst, offset, isFixed) { - var dpWidth = inst.dpDiv.outerWidth(); - var dpHeight = inst.dpDiv.outerHeight(); - var inputWidth = inst.input ? inst.input.outerWidth() : 0; - var inputHeight = inst.input ? inst.input.outerHeight() : 0; - var viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()); - var viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); - - offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0); - offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0; - offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; - - // now check if datepicker is showing outside window viewport - move to a better place if so. - offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? - Math.abs(offset.left + dpWidth - viewWidth) : 0); - offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? - Math.abs(dpHeight + inputHeight) : 0); - - return offset; - }, - - /* Find an object's position on the screen. */ - _findPos: function(obj) { - var inst = this._getInst(obj); - var isRTL = this._get(inst, 'isRTL'); - while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) { - obj = obj[isRTL ? 'previousSibling' : 'nextSibling']; - } - var position = $(obj).offset(); - return [position.left, position.top]; - }, - - /* Hide the date picker from view. - @param input element - the input field attached to the date picker */ - _hideDatepicker: function(input) { - var inst = this._curInst; - if (!inst || (input && inst != $.data(input, PROP_NAME))) - return; - if (this._datepickerShowing) { - var showAnim = this._get(inst, 'showAnim'); - var duration = this._get(inst, 'duration'); - var postProcess = function() { - $.datepicker._tidyDialog(inst); - }; - if ($.effects && $.effects[showAnim]) - inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess); - else - inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' : - (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess); - if (!showAnim) - postProcess(); - this._datepickerShowing = false; - var onClose = this._get(inst, 'onClose'); - if (onClose) - onClose.apply((inst.input ? inst.input[0] : null), - [(inst.input ? inst.input.val() : ''), inst]); - this._lastInput = null; - if (this._inDialog) { - this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' }); - if ($.blockUI) { - $.unblockUI(); - $('body').append(this.dpDiv); - } - } - this._inDialog = false; - } - }, - - /* Tidy up after a dialog display. */ - _tidyDialog: function(inst) { - inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar'); - }, - - /* Close date picker if clicked elsewhere. */ - _checkExternalClick: function(event) { - if (!$.datepicker._curInst) - return; - - var $target = $(event.target), - inst = $.datepicker._getInst($target[0]); - - if ( ( ( $target[0].id != $.datepicker._mainDivId && - $target.parents('#' + $.datepicker._mainDivId).length == 0 && - !$target.hasClass($.datepicker.markerClassName) && - !$target.closest("." + $.datepicker._triggerClass).length && - $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || - ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) ) - $.datepicker._hideDatepicker(); - }, - - /* Adjust one of the date sub-fields. */ - _adjustDate: function(id, offset, period) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._isDisabledDatepicker(target[0])) { - return; - } - this._adjustInstDate(inst, offset + - (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning - period); - this._updateDatepicker(inst); - }, - - /* Action for current link. */ - _gotoToday: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - if (this._get(inst, 'gotoCurrent') && inst.currentDay) { - inst.selectedDay = inst.currentDay; - inst.drawMonth = inst.selectedMonth = inst.currentMonth; - inst.drawYear = inst.selectedYear = inst.currentYear; - } - else { - var date = new Date(); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - } - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Action for selecting a new month/year. */ - _selectMonthYear: function(id, select, period) { - var target = $(id); - var inst = this._getInst(target[0]); - inst['selected' + (period == 'M' ? 'Month' : 'Year')] = - inst['draw' + (period == 'M' ? 'Month' : 'Year')] = - parseInt(select.options[select.selectedIndex].value,10); - this._notifyChange(inst); - this._adjustDate(target); - }, - - /* Action for selecting a day. */ - _selectDay: function(id, month, year, td) { - var target = $(id); - if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { - return; - } - var inst = this._getInst(target[0]); - inst.selectedDay = inst.currentDay = $('a', td).html(); - inst.selectedMonth = inst.currentMonth = month; - inst.selectedYear = inst.currentYear = year; - this._selectDate(id, this._formatDate(inst, - inst.currentDay, inst.currentMonth, inst.currentYear)); - }, - - /* Erase the input field and hide the date picker. */ - _clearDate: function(id) { - var target = $(id); - var inst = this._getInst(target[0]); - this._selectDate(target, ''); - }, - - /* Update the input field with the selected date. */ - _selectDate: function(id, dateStr) { - var target = $(id); - var inst = this._getInst(target[0]); - dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); - if (inst.input) - inst.input.val(dateStr); - this._updateAlternate(inst); - var onSelect = this._get(inst, 'onSelect'); - if (onSelect) - onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback - else if (inst.input) - inst.input.trigger('change'); // fire the change event - if (inst.inline) - this._updateDatepicker(inst); - else { - this._hideDatepicker(); - this._lastInput = inst.input[0]; - if (typeof(inst.input[0]) != 'object') - inst.input.focus(); // restore focus - this._lastInput = null; - } - }, - - /* Update any alternate field to synchronise with the main field. */ - _updateAlternate: function(inst) { - var altField = this._get(inst, 'altField'); - if (altField) { // update alternate field too - var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat'); - var date = this._getDate(inst); - var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); - $(altField).each(function() { $(this).val(dateStr); }); - } - }, - - /* Set as beforeShowDay function to prevent selection of weekends. - @param date Date - the date to customise - @return [boolean, string] - is this date selectable?, what is its CSS class? */ - noWeekends: function(date) { - var day = date.getDay(); - return [(day > 0 && day < 6), '']; - }, - - /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - @param date Date - the date to get the week for - @return number - the number of the week within the year that contains this date */ - iso8601Week: function(date) { - var checkDate = new Date(date.getTime()); - // Find Thursday of this week starting on Monday - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - var time = checkDate.getTime(); - checkDate.setMonth(0); // Compare with Jan 1 - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; - }, - - /* Parse a string value into a date object. - See formatDate below for the possible formats. - - @param format string - the expected format of the date - @param value string - the date in the above format - @param settings Object - attributes include: - shortYearCutoff number - the cutoff year for determining the century (optional) - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return Date - the extracted date value or null if value is blank */ - parseDate: function (format, value, settings) { - if (format == null || value == null) - throw 'Invalid arguments'; - value = (typeof value == 'object' ? value.toString() : value + ''); - if (value == '') - return null; - var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff; - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - var year = -1; - var month = -1; - var day = -1; - var doy = -1; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Extract a number from the string value - var getNumber = function(match) { - var isDoubled = lookAhead(match); - var size = (match == '@' ? 14 : (match == '!' ? 20 : - (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2)))); - var digits = new RegExp('^\\d{1,' + size + '}'); - var num = value.substring(iValue).match(digits); - if (!num) - throw 'Missing number at position ' + iValue; - iValue += num[0].length; - return parseInt(num[0], 10); - }; - // Extract a name from the string value and convert to an index - var getName = function(match, shortNames, longNames) { - var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { - return [ [k, v] ]; - }).sort(function (a, b) { - return -(a[1].length - b[1].length); - }); - var index = -1; - $.each(names, function (i, pair) { - var name = pair[1]; - if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) { - index = pair[0]; - iValue += name.length; - return false; - } - }); - if (index != -1) - return index + 1; - else - throw 'Unknown name at position ' + iValue; - }; - // Confirm that a literal character matches the string value - var checkLiteral = function() { - if (value.charAt(iValue) != format.charAt(iFormat)) - throw 'Unexpected literal at position ' + iValue; - iValue++; - }; - var iValue = 0; - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - checkLiteral(); - else - switch (format.charAt(iFormat)) { - case 'd': - day = getNumber('d'); - break; - case 'D': - getName('D', dayNamesShort, dayNames); - break; - case 'o': - doy = getNumber('o'); - break; - case 'm': - month = getNumber('m'); - break; - case 'M': - month = getName('M', monthNamesShort, monthNames); - break; - case 'y': - year = getNumber('y'); - break; - case '@': - var date = new Date(getNumber('@')); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case '!': - var date = new Date((getNumber('!') - this._ticksTo1970) / 10000); - year = date.getFullYear(); - month = date.getMonth() + 1; - day = date.getDate(); - break; - case "'": - if (lookAhead("'")) - checkLiteral(); - else - literal = true; - break; - default: - checkLiteral(); - } - } - if (iValue < value.length){ - throw "Extra/unparsed characters found in date: " + value.substring(iValue); - } - if (year == -1) - year = new Date().getFullYear(); - else if (year < 100) - year += new Date().getFullYear() - new Date().getFullYear() % 100 + - (year <= shortYearCutoff ? 0 : -100); - if (doy > -1) { - month = 1; - day = doy; - do { - var dim = this._getDaysInMonth(year, month - 1); - if (day <= dim) - break; - month++; - day -= dim; - } while (true); - } - var date = this._daylightSavingAdjust(new Date(year, month - 1, day)); - if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day) - throw 'Invalid date'; // E.g. 31/02/00 - return date; - }, - - /* Standard date formats. */ - ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601) - COOKIE: 'D, dd M yy', - ISO_8601: 'yy-mm-dd', - RFC_822: 'D, d M y', - RFC_850: 'DD, dd-M-y', - RFC_1036: 'D, d M y', - RFC_1123: 'D, d M yy', - RFC_2822: 'D, d M yy', - RSS: 'D, d M y', // RFC 822 - TICKS: '!', - TIMESTAMP: '@', - W3C: 'yy-mm-dd', // ISO 8601 - - _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + - Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), - - /* Format a date object into a string value. - The format can be combinations of the following: - d - day of month (no leading zero) - dd - day of month (two digit) - o - day of year (no leading zeros) - oo - day of year (three digit) - D - day name short - DD - day name long - m - month of year (no leading zero) - mm - month of year (two digit) - M - month name short - MM - month name long - y - year (two digit) - yy - year (four digit) - @ - Unix timestamp (ms since 01/01/1970) - ! - Windows ticks (100ns since 01/01/0001) - '...' - literal text - '' - single quote - - @param format string - the desired format of the date - @param date Date - the date value to format - @param settings Object - attributes include: - dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) - dayNames string[7] - names of the days from Sunday (optional) - monthNamesShort string[12] - abbreviated names of the months (optional) - monthNames string[12] - names of the months (optional) - @return string - the date in the above format */ - formatDate: function (format, date, settings) { - if (!date) - return ''; - var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort; - var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames; - var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort; - var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - // Format a number, with leading zero if necessary - var formatNumber = function(match, value, len) { - var num = '' + value; - if (lookAhead(match)) - while (num.length < len) - num = '0' + num; - return num; - }; - // Format a name, short or long as requested - var formatName = function(match, value, shortNames, longNames) { - return (lookAhead(match) ? longNames[value] : shortNames[value]); - }; - var output = ''; - var literal = false; - if (date) - for (var iFormat = 0; iFormat < format.length; iFormat++) { - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - output += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': - output += formatNumber('d', date.getDate(), 2); - break; - case 'D': - output += formatName('D', date.getDay(), dayNamesShort, dayNames); - break; - case 'o': - output += formatNumber('o', - Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); - break; - case 'm': - output += formatNumber('m', date.getMonth() + 1, 2); - break; - case 'M': - output += formatName('M', date.getMonth(), monthNamesShort, monthNames); - break; - case 'y': - output += (lookAhead('y') ? date.getFullYear() : - (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100); - break; - case '@': - output += date.getTime(); - break; - case '!': - output += date.getTime() * 10000 + this._ticksTo1970; - break; - case "'": - if (lookAhead("'")) - output += "'"; - else - literal = true; - break; - default: - output += format.charAt(iFormat); - } - } - return output; - }, - - /* Extract all possible characters from the date format. */ - _possibleChars: function (format) { - var chars = ''; - var literal = false; - // Check whether a format character is doubled - var lookAhead = function(match) { - var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match); - if (matches) - iFormat++; - return matches; - }; - for (var iFormat = 0; iFormat < format.length; iFormat++) - if (literal) - if (format.charAt(iFormat) == "'" && !lookAhead("'")) - literal = false; - else - chars += format.charAt(iFormat); - else - switch (format.charAt(iFormat)) { - case 'd': case 'm': case 'y': case '@': - chars += '0123456789'; - break; - case 'D': case 'M': - return null; // Accept anything - case "'": - if (lookAhead("'")) - chars += "'"; - else - literal = true; - break; - default: - chars += format.charAt(iFormat); - } - return chars; - }, - - /* Get a setting value, defaulting if necessary. */ - _get: function(inst, name) { - return inst.settings[name] !== undefined ? - inst.settings[name] : this._defaults[name]; - }, - - /* Parse existing date and initialise date picker. */ - _setDateFromField: function(inst, noDefault) { - if (inst.input.val() == inst.lastVal) { - return; - } - var dateFormat = this._get(inst, 'dateFormat'); - var dates = inst.lastVal = inst.input ? inst.input.val() : null; - var date, defaultDate; - date = defaultDate = this._getDefaultDate(inst); - var settings = this._getFormatConfig(inst); - try { - date = this.parseDate(dateFormat, dates, settings) || defaultDate; - } catch (event) { - this.log(event); - dates = (noDefault ? '' : dates); - } - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - inst.currentDay = (dates ? date.getDate() : 0); - inst.currentMonth = (dates ? date.getMonth() : 0); - inst.currentYear = (dates ? date.getFullYear() : 0); - this._adjustInstDate(inst); - }, - - /* Retrieve the default date shown on opening. */ - _getDefaultDate: function(inst) { - return this._restrictMinMax(inst, - this._determineDate(inst, this._get(inst, 'defaultDate'), new Date())); - }, - - /* A date may be specified as an exact value or a relative one. */ - _determineDate: function(inst, date, defaultDate) { - var offsetNumeric = function(offset) { - var date = new Date(); - date.setDate(date.getDate() + offset); - return date; - }; - var offsetString = function(offset) { - try { - return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'), - offset, $.datepicker._getFormatConfig(inst)); - } - catch (e) { - // Ignore - } - var date = (offset.toLowerCase().match(/^c/) ? - $.datepicker._getDate(inst) : null) || new Date(); - var year = date.getFullYear(); - var month = date.getMonth(); - var day = date.getDate(); - var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g; - var matches = pattern.exec(offset); - while (matches) { - switch (matches[2] || 'd') { - case 'd' : case 'D' : - day += parseInt(matches[1],10); break; - case 'w' : case 'W' : - day += parseInt(matches[1],10) * 7; break; - case 'm' : case 'M' : - month += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - case 'y': case 'Y' : - year += parseInt(matches[1],10); - day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); - break; - } - matches = pattern.exec(offset); - } - return new Date(year, month, day); - }; - var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) : - (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); - newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate); - if (newDate) { - newDate.setHours(0); - newDate.setMinutes(0); - newDate.setSeconds(0); - newDate.setMilliseconds(0); - } - return this._daylightSavingAdjust(newDate); - }, - - /* Handle switch to/from daylight saving. - Hours may be non-zero on daylight saving cut-over: - > 12 when midnight changeover, but then cannot generate - midnight datetime, so jump to 1AM, otherwise reset. - @param date (Date) the date to check - @return (Date) the corrected date */ - _daylightSavingAdjust: function(date) { - if (!date) return null; - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; - }, - - /* Set the date(s) directly. */ - _setDate: function(inst, date, noChange) { - var clear = !date; - var origMonth = inst.selectedMonth; - var origYear = inst.selectedYear; - var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); - inst.selectedDay = inst.currentDay = newDate.getDate(); - inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); - inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); - if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange) - this._notifyChange(inst); - this._adjustInstDate(inst); - if (inst.input) { - inst.input.val(clear ? '' : this._formatDate(inst)); - } - }, - - /* Retrieve the date(s) directly. */ - _getDate: function(inst) { - var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null : - this._daylightSavingAdjust(new Date( - inst.currentYear, inst.currentMonth, inst.currentDay))); - return startDate; - }, - - /* Attach the onxxx handlers. These are declared statically so - * they work with static code transformers like Caja. - */ - _attachHandlers: function(inst) { - var stepMonths = this._get(inst, 'stepMonths'); - var id = '#' + inst.id.replace( /\\\\/g, "\\" ); - inst.dpDiv.find('[data-handler]').map(function () { - var handler = { - prev: function () { - window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, -stepMonths, 'M'); - }, - next: function () { - window['DP_jQuery_' + dpuuid].datepicker._adjustDate(id, +stepMonths, 'M'); - }, - hide: function () { - window['DP_jQuery_' + dpuuid].datepicker._hideDatepicker(); - }, - today: function () { - window['DP_jQuery_' + dpuuid].datepicker._gotoToday(id); - }, - selectDay: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectDay(id, +this.getAttribute('data-month'), +this.getAttribute('data-year'), this); - return false; - }, - selectMonth: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'M'); - return false; - }, - selectYear: function () { - window['DP_jQuery_' + dpuuid].datepicker._selectMonthYear(id, this, 'Y'); - return false; - } - }; - $(this).bind(this.getAttribute('data-event'), handler[this.getAttribute('data-handler')]); - }); - }, - - /* Generate the HTML for the current state of the date picker. */ - _generateHTML: function(inst) { - var today = new Date(); - today = this._daylightSavingAdjust( - new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time - var isRTL = this._get(inst, 'isRTL'); - var showButtonPanel = this._get(inst, 'showButtonPanel'); - var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext'); - var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat'); - var numMonths = this._getNumberOfMonths(inst); - var showCurrentAtPos = this._get(inst, 'showCurrentAtPos'); - var stepMonths = this._get(inst, 'stepMonths'); - var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1); - var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : - new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var drawMonth = inst.drawMonth - showCurrentAtPos; - var drawYear = inst.drawYear; - if (drawMonth < 0) { - drawMonth += 12; - drawYear--; - } - if (maxDate) { - var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), - maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); - maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); - while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { - drawMonth--; - if (drawMonth < 0) { - drawMonth = 11; - drawYear--; - } - } - } - inst.drawMonth = drawMonth; - inst.drawYear = drawYear; - var prevText = this._get(inst, 'prevText'); - prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), - this._getFormatConfig(inst))); - var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? - '
                    ' + prevText + '' : - (hideIfNoPrevNext ? '' : '' + prevText + '')); - var nextText = this._get(inst, 'nextText'); - nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, - this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), - this._getFormatConfig(inst))); - var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? - '' + nextText + '' : - (hideIfNoPrevNext ? '' : '' + nextText + '')); - var currentText = this._get(inst, 'currentText'); - var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); - currentText = (!navigationAsDateFormat ? currentText : - this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); - var controls = (!inst.inline ? '' : ''); - var buttonPanel = (showButtonPanel) ? '
                    ' + (isRTL ? controls : '') + - (this._isInRange(inst, gotoDate) ? '' : '') + (isRTL ? '' : controls) + '
                    ' : ''; - var firstDay = parseInt(this._get(inst, 'firstDay'),10); - firstDay = (isNaN(firstDay) ? 0 : firstDay); - var showWeek = this._get(inst, 'showWeek'); - var dayNames = this._get(inst, 'dayNames'); - var dayNamesShort = this._get(inst, 'dayNamesShort'); - var dayNamesMin = this._get(inst, 'dayNamesMin'); - var monthNames = this._get(inst, 'monthNames'); - var monthNamesShort = this._get(inst, 'monthNamesShort'); - var beforeShowDay = this._get(inst, 'beforeShowDay'); - var showOtherMonths = this._get(inst, 'showOtherMonths'); - var selectOtherMonths = this._get(inst, 'selectOtherMonths'); - var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week; - var defaultDate = this._getDefaultDate(inst); - var html = ''; - for (var row = 0; row < numMonths[0]; row++) { - var group = ''; - this.maxRows = 4; - for (var col = 0; col < numMonths[1]; col++) { - var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); - var cornerClass = ' ui-corner-all'; - var calender = ''; - if (isMultiMonth) { - calender += '
                    '; - } - calender += '
                    ' + - (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') + - (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') + - this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, - row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers - '
                    ' + - ''; - var thead = (showWeek ? '' : ''); - for (var dow = 0; dow < 7; dow++) { // days of the week - var day = (dow + firstDay) % 7; - thead += '= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' + - '' + dayNamesMin[day] + ''; - } - calender += thead + ''; - var daysInMonth = this._getDaysInMonth(drawYear, drawMonth); - if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth) - inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); - var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; - var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate - var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) - this.maxRows = numRows; - var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); - for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows - calender += ''; - var tbody = (!showWeek ? '' : ''); - for (var dow = 0; dow < 7; dow++) { // create date picker days - var daySettings = (beforeShowDay ? - beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']); - var otherMonth = (printDate.getMonth() != drawMonth); - var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || - (minDate && printDate < minDate) || (maxDate && printDate > maxDate); - tbody += ''; // display selectable date - printDate.setDate(printDate.getDate() + 1); - printDate = this._daylightSavingAdjust(printDate); - } - calender += tbody + ''; - } - drawMonth++; - if (drawMonth > 11) { - drawMonth = 0; - drawYear++; - } - calender += '
                    ' + this._get(inst, 'weekHeader') + '
                    ' + - this._get(inst, 'calculateWeek')(printDate) + '' + // actions - (otherMonth && !showOtherMonths ? ' ' : // display for other months - (unselectable ? '' + printDate.getDate() + '' : '' + printDate.getDate() + '')) + '
                    ' + (isMultiMonth ? '
                    ' + - ((numMonths[0] > 0 && col == numMonths[1]-1) ? '
                    ' : '') : ''); - group += calender; - } - html += group; - } - html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ? - '' : ''); - inst._keyEvent = false; - return html; - }, - - /* Generate the month and year header. */ - _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, - secondary, monthNames, monthNamesShort) { - var changeMonth = this._get(inst, 'changeMonth'); - var changeYear = this._get(inst, 'changeYear'); - var showMonthAfterYear = this._get(inst, 'showMonthAfterYear'); - var html = '
                    '; - var monthHtml = ''; - // month selection - if (secondary || !changeMonth) - monthHtml += '' + monthNames[drawMonth] + ''; - else { - var inMinYear = (minDate && minDate.getFullYear() == drawYear); - var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear); - monthHtml += ''; - } - if (!showMonthAfterYear) - html += monthHtml + (secondary || !(changeMonth && changeYear) ? ' ' : ''); - // year selection - if ( !inst.yearshtml ) { - inst.yearshtml = ''; - if (secondary || !changeYear) - html += '' + drawYear + ''; - else { - // determine range of years to display - var years = this._get(inst, 'yearRange').split(':'); - var thisYear = new Date().getFullYear(); - var determineYear = function(value) { - var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) : - (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) : - parseInt(value, 10))); - return (isNaN(year) ? thisYear : year); - }; - var year = determineYear(years[0]); - var endYear = Math.max(year, determineYear(years[1] || '')); - year = (minDate ? Math.max(year, minDate.getFullYear()) : year); - endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); - inst.yearshtml += ''; - - html += inst.yearshtml; - inst.yearshtml = null; - } - } - html += this._get(inst, 'yearSuffix'); - if (showMonthAfterYear) - html += (secondary || !(changeMonth && changeYear) ? ' ' : '') + monthHtml; - html += '
                    '; // Close datepicker_header - return html; - }, - - /* Adjust one of the date sub-fields. */ - _adjustInstDate: function(inst, offset, period) { - var year = inst.drawYear + (period == 'Y' ? offset : 0); - var month = inst.drawMonth + (period == 'M' ? offset : 0); - var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + - (period == 'D' ? offset : 0); - var date = this._restrictMinMax(inst, - this._daylightSavingAdjust(new Date(year, month, day))); - inst.selectedDay = date.getDate(); - inst.drawMonth = inst.selectedMonth = date.getMonth(); - inst.drawYear = inst.selectedYear = date.getFullYear(); - if (period == 'M' || period == 'Y') - this._notifyChange(inst); - }, - - /* Ensure a date is within any min/max bounds. */ - _restrictMinMax: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - var newDate = (minDate && date < minDate ? minDate : date); - newDate = (maxDate && newDate > maxDate ? maxDate : newDate); - return newDate; - }, - - /* Notify change of month/year. */ - _notifyChange: function(inst) { - var onChange = this._get(inst, 'onChangeMonthYear'); - if (onChange) - onChange.apply((inst.input ? inst.input[0] : null), - [inst.selectedYear, inst.selectedMonth + 1, inst]); - }, - - /* Determine the number of months to show. */ - _getNumberOfMonths: function(inst) { - var numMonths = this._get(inst, 'numberOfMonths'); - return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths)); - }, - - /* Determine the current maximum date - ensure no time components are set. */ - _getMinMaxDate: function(inst, minMax) { - return this._determineDate(inst, this._get(inst, minMax + 'Date'), null); - }, - - /* Find the number of days in a given month. */ - _getDaysInMonth: function(year, month) { - return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); - }, - - /* Find the day of the week of the first of a month. */ - _getFirstDayOfMonth: function(year, month) { - return new Date(year, month, 1).getDay(); - }, - - /* Determines if we should allow a "next/prev" month display change. */ - _canAdjustMonth: function(inst, offset, curYear, curMonth) { - var numMonths = this._getNumberOfMonths(inst); - var date = this._daylightSavingAdjust(new Date(curYear, - curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); - if (offset < 0) - date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); - return this._isInRange(inst, date); - }, - - /* Is the given date in the accepted range? */ - _isInRange: function(inst, date) { - var minDate = this._getMinMaxDate(inst, 'min'); - var maxDate = this._getMinMaxDate(inst, 'max'); - return ((!minDate || date.getTime() >= minDate.getTime()) && - (!maxDate || date.getTime() <= maxDate.getTime())); - }, - - /* Provide the configuration settings for formatting/parsing. */ - _getFormatConfig: function(inst) { - var shortYearCutoff = this._get(inst, 'shortYearCutoff'); - shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff : - new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); - return {shortYearCutoff: shortYearCutoff, - dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'), - monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')}; - }, - - /* Format the given date for display. */ - _formatDate: function(inst, day, month, year) { - if (!day) { - inst.currentDay = inst.selectedDay; - inst.currentMonth = inst.selectedMonth; - inst.currentYear = inst.selectedYear; - } - var date = (day ? (typeof day == 'object' ? day : - this._daylightSavingAdjust(new Date(year, month, day))) : - this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); - return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst)); - } -}); - -/* - * Bind hover events for datepicker elements. - * Done via delegate so the binding only occurs once in the lifetime of the parent div. - * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. - */ -function bindHover(dpDiv) { - var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a'; - return dpDiv.bind('mouseout', function(event) { - var elem = $( event.target ).closest( selector ); - if ( !elem.length ) { - return; - } - elem.removeClass( "ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover" ); - }) - .bind('mouseover', function(event) { - var elem = $( event.target ).closest( selector ); - if ($.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0]) || - !elem.length ) { - return; - } - elem.parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover'); - elem.addClass('ui-state-hover'); - if (elem.hasClass('ui-datepicker-prev')) elem.addClass('ui-datepicker-prev-hover'); - if (elem.hasClass('ui-datepicker-next')) elem.addClass('ui-datepicker-next-hover'); - }); -} - -/* jQuery extend now ignores nulls! */ -function extendRemove(target, props) { - $.extend(target, props); - for (var name in props) - if (props[name] == null || props[name] == undefined) - target[name] = props[name]; - return target; -}; - -/* Determine whether an object is an array. */ -function isArray(a) { - return (a && (($.browser.safari && typeof a == 'object' && a.length) || - (a.constructor && a.constructor.toString().match(/\Array\(\)/)))); -}; - -/* Invoke the datepicker functionality. - @param options string - a command, optionally followed by additional parameters or - Object - settings for attaching new datepicker functionality - @return jQuery object */ -$.fn.datepicker = function(options){ - - /* Verify an empty collection wasn't passed - Fixes #6976 */ - if ( !this.length ) { - return this; - } - - /* Initialise the date picker. */ - if (!$.datepicker.initialized) { - $(document).mousedown($.datepicker._checkExternalClick). - find('body').append($.datepicker.dpDiv); - $.datepicker.initialized = true; - } - - var otherArgs = Array.prototype.slice.call(arguments, 1); - if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget')) - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string') - return $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this[0]].concat(otherArgs)); - return this.each(function() { - typeof options == 'string' ? - $.datepicker['_' + options + 'Datepicker']. - apply($.datepicker, [this].concat(otherArgs)) : - $.datepicker._attachDatepicker(this, options); - }); -}; - -$.datepicker = new Datepicker(); // singleton instance -$.datepicker.initialized = false; -$.datepicker.uuid = new Date().getTime(); -$.datepicker.version = "1.8.24"; - -// Workaround for #4055 -// Add another global to avoid noConflict issues with inline event handlers -window['DP_jQuery_' + dpuuid] = $; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.datepicker.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.datepicker.min.js deleted file mode 100644 index ed5dd59246..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.datepicker.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.datepicker.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function($,undefined){function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('
                    '))}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);if(!c.length)return;c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);if($.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])||!d.length)return;d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover")})}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}$.extend($.ui,{datepicker:{version:"1.8.24"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){return extendRemove(this._defaults,a||{}),this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('
                    ')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);if(c.hasClass(this.markerClassName))return;this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a)},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$(''+c+""),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('').addClass(this._triggerClass).html(g==""?f:$("").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){return $.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]),!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;db&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);if(c.hasClass(this.markerClassName))return;c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block")},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$(''),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}return this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f),this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!b.hasClass(this.markerClassName))return;var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(d){$.datepicker.log(d)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if($.datepicker._isDisabledDatepicker(a)||$.datepicker._lastInput==a)return;var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){return e|=$(this).css("position")=="fixed",!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a)),this._attachHandlers(a);var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+(c?0:$(document).scrollLeft()),i=document.documentElement.clientHeight+(c?0:$(document).scrollTop());return b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0),b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!b||a&&b!=$.data(a,PROP_NAME))return;if(this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=function(){$.datepicker._tidyDialog(b)};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,e):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,e),c||e(),this._datepickerShowing=!1;var f=this._get(b,"onClose");f&&f.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!$.datepicker._curInst)return;var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);if(this._isDisabledDatepicker(d[0]))return;this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e)},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if($(d).hasClass(this._unselectableClass)||this._isDisabledDatepicker(e[0]))return;var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();return b.setMonth(0),b.setDate(1),Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1-1){j=1,k=l;do{var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}while(!0)}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+112?a.getHours()+2:0),a):null},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_attachHandlers:function(a){var b=this._get(a,"stepMonths"),c="#"+a.id.replace(/\\\\/g,"\\");a.dpDiv.find("[data-handler]").map(function(){var a={prev:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,-b,"M")},next:function(){window["DP_jQuery_"+dpuuid].datepicker._adjustDate(c,+b,"M")},hide:function(){window["DP_jQuery_"+dpuuid].datepicker._hideDatepicker()},today:function(){window["DP_jQuery_"+dpuuid].datepicker._gotoToday(c)},selectDay:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectDay(c,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"M"),!1},selectYear:function(){return window["DP_jQuery_"+dpuuid].datepicker._selectMonthYear(c,this,"Y"),!1}};$(this).bind(this.getAttribute("data-event"),a[this.getAttribute("data-handler")])})},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&pp)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?''+q+"":e?"":''+q+"",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?''+s+"":e?"":''+s+"",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'",x=d?'
                    '+(c?w:"")+(this._isInRange(a,v)?'":"")+(c?"":w)+"
                    ":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='
                    '+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'
                    '+"";var R=z?'":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="=5?' class="ui-datepicker-week-end"':"")+">"+''+C[T]+""}Q+=R+"";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z";var _=z?'":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Ym;_+='",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+""}n++,n>11&&(n=0,o++),Q+="
                    '+this._get(a,"weekHeader")+"
                    '+this._get(a,"calculateWeek")(Y)+""+(bb&&!G?" ":bc?''+Y.getDate()+"":''+Y.getDate()+"")+"
                    "+(j?""+(g[0]>0&&N==g[1]-1?'
                    ':""):""),M+=Q}K+=M}return K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='
                    ',m="";if(f||!i)m+=''+g[b]+"";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+=''+c+"";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="
                    ",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&bd?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.24",window["DP_jQuery_"+dpuuid]=$})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.dialog.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.dialog.js deleted file mode 100644 index 06b85f23a1..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.dialog.js +++ /dev/null @@ -1,866 +0,0 @@ -/*! - * jQuery UI Dialog 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function( $, undefined ) { - -var uiDialogClasses = - 'ui-dialog ' + - 'ui-widget ' + - 'ui-widget-content ' + - 'ui-corner-all ', - sizeRelatedOptions = { - buttons: true, - height: true, - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true, - width: true - }, - resizableRelatedOptions = { - maxHeight: true, - maxWidth: true, - minHeight: true, - minWidth: true - }; - -$.widget("ui.dialog", { - options: { - autoOpen: true, - buttons: {}, - closeOnEscape: true, - closeText: 'close', - dialogClass: '', - draggable: true, - hide: null, - height: 'auto', - maxHeight: false, - maxWidth: false, - minHeight: 150, - minWidth: 150, - modal: false, - position: { - my: 'center', - at: 'center', - collision: 'fit', - // ensure that the titlebar is never outside the document - using: function(pos) { - var topOffset = $(this).css(pos).offset().top; - if (topOffset < 0) { - $(this).css('top', pos.top - topOffset); - } - } - }, - resizable: true, - show: null, - stack: true, - title: '', - width: 300, - zIndex: 1000 - }, - - _create: function() { - this.originalTitle = this.element.attr('title'); - // #5742 - .attr() might return a DOMElement - if ( typeof this.originalTitle !== "string" ) { - this.originalTitle = ""; - } - - this.options.title = this.options.title || this.originalTitle; - var self = this, - options = self.options, - - title = options.title || ' ', - titleId = $.ui.dialog.getTitleId(self.element), - - uiDialog = (self.uiDialog = $('
                    ')) - .appendTo(document.body) - .hide() - .addClass(uiDialogClasses + options.dialogClass) - .css({ - zIndex: options.zIndex - }) - // setting tabIndex makes the div focusable - // setting outline to 0 prevents a border on focus in Mozilla - .attr('tabIndex', -1).css('outline', 0).keydown(function(event) { - if (options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - self.close(event); - event.preventDefault(); - } - }) - .attr({ - role: 'dialog', - 'aria-labelledby': titleId - }) - .mousedown(function(event) { - self.moveToTop(false, event); - }), - - uiDialogContent = self.element - .show() - .removeAttr('title') - .addClass( - 'ui-dialog-content ' + - 'ui-widget-content') - .appendTo(uiDialog), - - uiDialogTitlebar = (self.uiDialogTitlebar = $('
                    ')) - .addClass( - 'ui-dialog-titlebar ' + - 'ui-widget-header ' + - 'ui-corner-all ' + - 'ui-helper-clearfix' - ) - .prependTo(uiDialog), - - uiDialogTitlebarClose = $('') - .addClass( - 'ui-dialog-titlebar-close ' + - 'ui-corner-all' - ) - .attr('role', 'button') - .hover( - function() { - uiDialogTitlebarClose.addClass('ui-state-hover'); - }, - function() { - uiDialogTitlebarClose.removeClass('ui-state-hover'); - } - ) - .focus(function() { - uiDialogTitlebarClose.addClass('ui-state-focus'); - }) - .blur(function() { - uiDialogTitlebarClose.removeClass('ui-state-focus'); - }) - .click(function(event) { - self.close(event); - return false; - }) - .appendTo(uiDialogTitlebar), - - uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('')) - .addClass( - 'ui-icon ' + - 'ui-icon-closethick' - ) - .text(options.closeText) - .appendTo(uiDialogTitlebarClose), - - uiDialogTitle = $('') - .addClass('ui-dialog-title') - .attr('id', titleId) - .html(title) - .prependTo(uiDialogTitlebar); - - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) { - options.beforeClose = options.beforeclose; - } - - uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection(); - - if (options.draggable && $.fn.draggable) { - self._makeDraggable(); - } - if (options.resizable && $.fn.resizable) { - self._makeResizable(); - } - - self._createButtons(options.buttons); - self._isOpen = false; - - if ($.fn.bgiframe) { - uiDialog.bgiframe(); - } - }, - - _init: function() { - if ( this.options.autoOpen ) { - this.open(); - } - }, - - destroy: function() { - var self = this; - - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.hide(); - self.element - .unbind('.dialog') - .removeData('dialog') - .removeClass('ui-dialog-content ui-widget-content') - .hide().appendTo('body'); - self.uiDialog.remove(); - - if (self.originalTitle) { - self.element.attr('title', self.originalTitle); - } - - return self; - }, - - widget: function() { - return this.uiDialog; - }, - - close: function(event) { - var self = this, - maxZ, thisZ; - - if (false === self._trigger('beforeClose', event)) { - return; - } - - if (self.overlay) { - self.overlay.destroy(); - } - self.uiDialog.unbind('keypress.ui-dialog'); - - self._isOpen = false; - - if (self.options.hide) { - self.uiDialog.hide(self.options.hide, function() { - self._trigger('close', event); - }); - } else { - self.uiDialog.hide(); - self._trigger('close', event); - } - - $.ui.dialog.overlay.resize(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - if (self.options.modal) { - maxZ = 0; - $('.ui-dialog').each(function() { - if (this !== self.uiDialog[0]) { - thisZ = $(this).css('z-index'); - if(!isNaN(thisZ)) { - maxZ = Math.max(maxZ, thisZ); - } - } - }); - $.ui.dialog.maxZ = maxZ; - } - - return self; - }, - - isOpen: function() { - return this._isOpen; - }, - - // the force parameter allows us to move modal dialogs to their correct - // position on open - moveToTop: function(force, event) { - var self = this, - options = self.options, - saveScroll; - - if ((options.modal && !force) || - (!options.stack && !options.modal)) { - return self._trigger('focus', event); - } - - if (options.zIndex > $.ui.dialog.maxZ) { - $.ui.dialog.maxZ = options.zIndex; - } - if (self.overlay) { - $.ui.dialog.maxZ += 1; - self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ); - } - - //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed. - // http://ui.jquery.com/bugs/ticket/3193 - saveScroll = { scrollTop: self.element.scrollTop(), scrollLeft: self.element.scrollLeft() }; - $.ui.dialog.maxZ += 1; - self.uiDialog.css('z-index', $.ui.dialog.maxZ); - self.element.attr(saveScroll); - self._trigger('focus', event); - - return self; - }, - - open: function() { - if (this._isOpen) { return; } - - var self = this, - options = self.options, - uiDialog = self.uiDialog; - - self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null; - self._size(); - self._position(options.position); - uiDialog.show(options.show); - self.moveToTop(true); - - // prevent tabbing out of modal dialogs - if ( options.modal ) { - uiDialog.bind( "keydown.ui-dialog", function( event ) { - if ( event.keyCode !== $.ui.keyCode.TAB ) { - return; - } - - var tabbables = $(':tabbable', this), - first = tabbables.filter(':first'), - last = tabbables.filter(':last'); - - if (event.target === last[0] && !event.shiftKey) { - first.focus(1); - return false; - } else if (event.target === first[0] && event.shiftKey) { - last.focus(1); - return false; - } - }); - } - - // set focus to the first tabbable element in the content area or the first button - // if there are no tabbable elements, set focus on the dialog itself - $(self.element.find(':tabbable').get().concat( - uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat( - uiDialog.get()))).eq(0).focus(); - - self._isOpen = true; - self._trigger('open'); - - return self; - }, - - _createButtons: function(buttons) { - var self = this, - hasButtons = false, - uiDialogButtonPane = $('
                    ') - .addClass( - 'ui-dialog-buttonpane ' + - 'ui-widget-content ' + - 'ui-helper-clearfix' - ), - uiButtonSet = $( "
                    " ) - .addClass( "ui-dialog-buttonset" ) - .appendTo( uiDialogButtonPane ); - - // if we already have a button pane, remove it - self.uiDialog.find('.ui-dialog-buttonpane').remove(); - - if (typeof buttons === 'object' && buttons !== null) { - $.each(buttons, function() { - return !(hasButtons = true); - }); - } - if (hasButtons) { - $.each(buttons, function(name, props) { - props = $.isFunction( props ) ? - { click: props, text: name } : - props; - var button = $('') - .click(function() { - props.click.apply(self.element[0], arguments); - }) - .appendTo(uiButtonSet); - // can't use .attr( props, true ) with jQuery 1.3.2. - $.each( props, function( key, value ) { - if ( key === "click" ) { - return; - } - if ( key in button ) { - button[ key ]( value ); - } else { - button.attr( key, value ); - } - }); - if ($.fn.button) { - button.button(); - } - }); - uiDialogButtonPane.appendTo(self.uiDialog); - } - }, - - _makeDraggable: function() { - var self = this, - options = self.options, - doc = $(document), - heightBeforeDrag; - - function filteredUi(ui) { - return { - position: ui.position, - offset: ui.offset - }; - } - - self.uiDialog.draggable({ - cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', - handle: '.ui-dialog-titlebar', - containment: 'document', - start: function(event, ui) { - heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height(); - $(this).height($(this).height()).addClass("ui-dialog-dragging"); - self._trigger('dragStart', event, filteredUi(ui)); - }, - drag: function(event, ui) { - self._trigger('drag', event, filteredUi(ui)); - }, - stop: function(event, ui) { - options.position = [ui.position.left - doc.scrollLeft(), - ui.position.top - doc.scrollTop()]; - $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag); - self._trigger('dragStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }); - }, - - _makeResizable: function(handles) { - handles = (handles === undefined ? this.options.resizable : handles); - var self = this, - options = self.options, - // .ui-resizable has position: relative defined in the stylesheet - // but dialogs have to use absolute or fixed positioning - position = self.uiDialog.css('position'), - resizeHandles = (typeof handles === 'string' ? - handles : - 'n,e,s,w,se,sw,ne,nw' - ); - - function filteredUi(ui) { - return { - originalPosition: ui.originalPosition, - originalSize: ui.originalSize, - position: ui.position, - size: ui.size - }; - } - - self.uiDialog.resizable({ - cancel: '.ui-dialog-content', - containment: 'document', - alsoResize: self.element, - maxWidth: options.maxWidth, - maxHeight: options.maxHeight, - minWidth: options.minWidth, - minHeight: self._minHeight(), - handles: resizeHandles, - start: function(event, ui) { - $(this).addClass("ui-dialog-resizing"); - self._trigger('resizeStart', event, filteredUi(ui)); - }, - resize: function(event, ui) { - self._trigger('resize', event, filteredUi(ui)); - }, - stop: function(event, ui) { - $(this).removeClass("ui-dialog-resizing"); - options.height = $(this).height(); - options.width = $(this).width(); - self._trigger('resizeStop', event, filteredUi(ui)); - $.ui.dialog.overlay.resize(); - } - }) - .css('position', position) - .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se'); - }, - - _minHeight: function() { - var options = this.options; - - if (options.height === 'auto') { - return options.minHeight; - } else { - return Math.min(options.minHeight, options.height); - } - }, - - _position: function(position) { - var myAt = [], - offset = [0, 0], - isVisible; - - if (position) { - // deep extending converts arrays to objects in jQuery <= 1.3.2 :-( - // if (typeof position == 'string' || $.isArray(position)) { - // myAt = $.isArray(position) ? position : position.split(' '); - - if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) { - myAt = position.split ? position.split(' ') : [position[0], position[1]]; - if (myAt.length === 1) { - myAt[1] = myAt[0]; - } - - $.each(['left', 'top'], function(i, offsetPosition) { - if (+myAt[i] === myAt[i]) { - offset[i] = myAt[i]; - myAt[i] = offsetPosition; - } - }); - - position = { - my: myAt.join(" "), - at: myAt.join(" "), - offset: offset.join(" ") - }; - } - - position = $.extend({}, $.ui.dialog.prototype.options.position, position); - } else { - position = $.ui.dialog.prototype.options.position; - } - - // need to show the dialog to get the actual offset in the position plugin - isVisible = this.uiDialog.is(':visible'); - if (!isVisible) { - this.uiDialog.show(); - } - this.uiDialog - // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 - .css({ top: 0, left: 0 }) - .position($.extend({ of: window }, position)); - if (!isVisible) { - this.uiDialog.hide(); - } - }, - - _setOptions: function( options ) { - var self = this, - resizableOptions = {}, - resize = false; - - $.each( options, function( key, value ) { - self._setOption( key, value ); - - if ( key in sizeRelatedOptions ) { - resize = true; - } - if ( key in resizableRelatedOptions ) { - resizableOptions[ key ] = value; - } - }); - - if ( resize ) { - this._size(); - } - if ( this.uiDialog.is( ":data(resizable)" ) ) { - this.uiDialog.resizable( "option", resizableOptions ); - } - }, - - _setOption: function(key, value){ - var self = this, - uiDialog = self.uiDialog; - - switch (key) { - //handling of deprecated beforeclose (vs beforeClose) option - //Ticket #4669 http://dev.jqueryui.com/ticket/4669 - //TODO: remove in 1.9pre - case "beforeclose": - key = "beforeClose"; - break; - case "buttons": - self._createButtons(value); - break; - case "closeText": - // ensure that we always pass a string - self.uiDialogTitlebarCloseText.text("" + value); - break; - case "dialogClass": - uiDialog - .removeClass(self.options.dialogClass) - .addClass(uiDialogClasses + value); - break; - case "disabled": - if (value) { - uiDialog.addClass('ui-dialog-disabled'); - } else { - uiDialog.removeClass('ui-dialog-disabled'); - } - break; - case "draggable": - var isDraggable = uiDialog.is( ":data(draggable)" ); - if ( isDraggable && !value ) { - uiDialog.draggable( "destroy" ); - } - - if ( !isDraggable && value ) { - self._makeDraggable(); - } - break; - case "position": - self._position(value); - break; - case "resizable": - // currently resizable, becoming non-resizable - var isResizable = uiDialog.is( ":data(resizable)" ); - if (isResizable && !value) { - uiDialog.resizable('destroy'); - } - - // currently resizable, changing handles - if (isResizable && typeof value === 'string') { - uiDialog.resizable('option', 'handles', value); - } - - // currently non-resizable, becoming resizable - if (!isResizable && value !== false) { - self._makeResizable(value); - } - break; - case "title": - // convert whatever was passed in o a string, for html() to not throw up - $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || ' ')); - break; - } - - $.Widget.prototype._setOption.apply(self, arguments); - }, - - _size: function() { - /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content - * divs will both have width and height set, so we need to reset them - */ - var options = this.options, - nonContentHeight, - minContentHeight, - isVisible = this.uiDialog.is( ":visible" ); - - // reset content sizing - this.element.show().css({ - width: 'auto', - minHeight: 0, - height: 0 - }); - - if (options.minWidth > options.width) { - options.width = options.minWidth; - } - - // reset wrapper sizing - // determine the height of all the non-content elements - nonContentHeight = this.uiDialog.css({ - height: 'auto', - width: options.width - }) - .height(); - minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); - - if ( options.height === "auto" ) { - // only needed for IE6 support - if ( $.support.minHeight ) { - this.element.css({ - minHeight: minContentHeight, - height: "auto" - }); - } else { - this.uiDialog.show(); - var autoHeight = this.element.css( "height", "auto" ).height(); - if ( !isVisible ) { - this.uiDialog.hide(); - } - this.element.height( Math.max( autoHeight, minContentHeight ) ); - } - } else { - this.element.height( Math.max( options.height - nonContentHeight, 0 ) ); - } - - if (this.uiDialog.is(':data(resizable)')) { - this.uiDialog.resizable('option', 'minHeight', this._minHeight()); - } - } -}); - -$.extend($.ui.dialog, { - version: "1.8.24", - - uuid: 0, - maxZ: 0, - - getTitleId: function($el) { - var id = $el.attr('id'); - if (!id) { - this.uuid += 1; - id = this.uuid; - } - return 'ui-dialog-title-' + id; - }, - - overlay: function(dialog) { - this.$el = $.ui.dialog.overlay.create(dialog); - } -}); - -$.extend($.ui.dialog.overlay, { - instances: [], - // reuse old instances due to IE memory leak with alpha transparency (see #5185) - oldInstances: [], - maxZ: 0, - events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','), - function(event) { return event + '.dialog-overlay'; }).join(' '), - create: function(dialog) { - if (this.instances.length === 0) { - // prevent use of anchors and inputs - // we use a setTimeout in case the overlay is created from an - // event that we're going to be cancelling (see #2804) - setTimeout(function() { - // handle $(el).dialog().dialog('close') (see #4065) - if ($.ui.dialog.overlay.instances.length) { - $(document).bind($.ui.dialog.overlay.events, function(event) { - // stop events if the z-index of the target is < the z-index of the overlay - // we cannot return true when we don't want to cancel the event (#3523) - if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) { - return false; - } - }); - } - }, 1); - - // allow closing by pressing the escape key - $(document).bind('keydown.dialog-overlay', function(event) { - if (dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && - event.keyCode === $.ui.keyCode.ESCAPE) { - - dialog.close(event); - event.preventDefault(); - } - }); - - // handle window resize - $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize); - } - - var $el = (this.oldInstances.pop() || $('
                    ').addClass('ui-widget-overlay')) - .appendTo(document.body) - .css({ - width: this.width(), - height: this.height() - }); - - if ($.fn.bgiframe) { - $el.bgiframe(); - } - - this.instances.push($el); - return $el; - }, - - destroy: function($el) { - var indexOf = $.inArray($el, this.instances); - if (indexOf != -1){ - this.oldInstances.push(this.instances.splice(indexOf, 1)[0]); - } - - if (this.instances.length === 0) { - $([document, window]).unbind('.dialog-overlay'); - } - - $el.remove(); - - // adjust the maxZ to allow other modal dialogs to continue to work (see #4309) - var maxZ = 0; - $.each(this.instances, function() { - maxZ = Math.max(maxZ, this.css('z-index')); - }); - this.maxZ = maxZ; - }, - - height: function() { - var scrollHeight, - offsetHeight; - // handle IE 6 - if ($.browser.msie && $.browser.version < 7) { - scrollHeight = Math.max( - document.documentElement.scrollHeight, - document.body.scrollHeight - ); - offsetHeight = Math.max( - document.documentElement.offsetHeight, - document.body.offsetHeight - ); - - if (scrollHeight < offsetHeight) { - return $(window).height() + 'px'; - } else { - return scrollHeight + 'px'; - } - // handle "good" browsers - } else { - return $(document).height() + 'px'; - } - }, - - width: function() { - var scrollWidth, - offsetWidth; - // handle IE - if ( $.browser.msie ) { - scrollWidth = Math.max( - document.documentElement.scrollWidth, - document.body.scrollWidth - ); - offsetWidth = Math.max( - document.documentElement.offsetWidth, - document.body.offsetWidth - ); - - if (scrollWidth < offsetWidth) { - return $(window).width() + 'px'; - } else { - return scrollWidth + 'px'; - } - // handle "good" browsers - } else { - return $(document).width() + 'px'; - } - }, - - resize: function() { - /* If the dialog is draggable and the user drags it past the - * right edge of the window, the document becomes wider so we - * need to stretch the overlay. If the user then drags the - * dialog back to the left, the document will become narrower, - * so we need to shrink the overlay to the appropriate size. - * This is handled by shrinking the overlay before setting it - * to the full document size. - */ - var $overlays = $([]); - $.each($.ui.dialog.overlay.instances, function() { - $overlays = $overlays.add(this); - }); - - $overlays.css({ - width: 0, - height: 0 - }).css({ - width: $.ui.dialog.overlay.width(), - height: $.ui.dialog.overlay.height() - }); - } -}); - -$.extend($.ui.dialog.overlay.prototype, { - destroy: function() { - $.ui.dialog.overlay.destroy(this.$el); - } -}); - -}(jQuery)); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.dialog.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.dialog.min.js deleted file mode 100644 index 0e9e6c2f36..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.dialog.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.dialog.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("
                    ")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("
                    ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("
                    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),f=a("
                    ").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(f);a.each(d,function(a,b){if(a==="click")return;a in e?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||" "))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.24",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b') - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); - } - - return true; - - }, - - _mouseStart: function(event) { - - var o = this.options; - - //Create and append the visible helper - this.helper = this._createHelper(event); - - this.helper.addClass("ui-draggable-dragging"); - - //Cache the helper size - this._cacheHelperProportions(); - - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Store the helper's css position - this.cssPosition = this.helper.css("position"); - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.positionAbs = this.element.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this.position = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - //Trigger event + callbacks - if(this._trigger("start", event) === false) { - this._clear(); - return false; - } - - //Recache the helper size - this._cacheHelperProportions(); - - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - - this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - - //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) - if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event); - - return true; - }, - - _mouseDrag: function(event, noPropagation) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - //Call plugins and callbacks and use the resulting position if something is returned - if (!noPropagation) { - var ui = this._uiHash(); - if(this._trigger('drag', event, ui) === false) { - this._mouseUp({}); - return false; - } - this.position = ui.position; - } - - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - return false; - }, - - _mouseStop: function(event) { - - //If we are using droppables, inform the manager about the drop - var dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) - dropped = $.ui.ddmanager.drop(this, event); - - //if a drop comes from outside (a sortable) - if(this.dropped) { - dropped = this.dropped; - this.dropped = false; - } - - //if the original element is no longer in the DOM don't bother to continue (see #8269) - var element = this.element[0], elementInDom = false; - while ( element && (element = element.parentNode) ) { - if (element == document ) { - elementInDom = true; - } - } - if ( !elementInDom && this.options.helper === "original" ) - return false; - - if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - var self = this; - $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - if(self._trigger("stop", event) !== false) { - self._clear(); - } - }); - } else { - if(this._trigger("stop", event) !== false) { - this._clear(); - } - } - - return false; - }, - - _mouseUp: function(event) { - //Remove frame helpers - $("div.ui-draggable-iframeFix").each(function() { - this.parentNode.removeChild(this); - }); - - //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) - if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event); - - return $.ui.mouse.prototype._mouseUp.call(this, event); - }, - - cancel: function() { - - if(this.helper.is(".ui-draggable-dragging")) { - this._mouseUp({}); - } else { - this._clear(); - } - - return this; - - }, - - _getHandle: function(event) { - - var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; - $(this.options.handle, this.element) - .find("*") - .andSelf() - .each(function() { - if(this == event.target) handle = true; - }); - - return handle; - - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element); - - if(!helper.parents('body').length) - helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo)); - - if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) - helper.css("position", "absolute"); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.element.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.element.css("marginLeft"),10) || 0), - top: (parseInt(this.element.css("marginTop"),10) || 0), - right: (parseInt(this.element.css("marginRight"),10) || 0), - bottom: (parseInt(this.element.css("marginBottom"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, - o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, - (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) { - var c = $(o.containment); - var ce = c[0]; if(!ce) return; - var co = c.offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), - (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), - (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, - (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom - ]; - this.relative_container = c; - - } else if(o.containment.constructor == Array) { - this.containment = o.containment; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - var containment; - if(this.containment) { - if (this.relative_container){ - var co = this.relative_container.offset(); - containment = [ this.containment[0] + co.left, - this.containment[1] + co.top, - this.containment[2] + co.left, - this.containment[3] + co.top ]; - } - else { - containment = this.containment; - } - - if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top; - } - - if(o.grid) { - //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) - var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; - pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; - pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _clear: function() { - this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove(); - //if($.ui.ddmanager) $.ui.ddmanager.current = null; - this.helper = null; - this.cancelHelperRemoval = false; - }, - - // From now on bulk stuff - mainly helpers - - _trigger: function(type, event, ui) { - ui = ui || this._uiHash(); - $.ui.plugin.call(this, type, [event, ui]); - if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins - return $.Widget.prototype._trigger.call(this, type, event, ui); - }, - - plugins: {}, - - _uiHash: function(event) { - return { - helper: this.helper, - position: this.position, - originalPosition: this.originalPosition, - offset: this.positionAbs - }; - } - -}); - -$.extend($.ui.draggable, { - version: "1.8.24" -}); - -$.ui.plugin.add("draggable", "connectToSortable", { - start: function(event, ui) { - - var inst = $(this).data("draggable"), o = inst.options, - uiSortable = $.extend({}, ui, { item: inst.element }); - inst.sortables = []; - $(o.connectToSortable).each(function() { - var sortable = $.data(this, 'sortable'); - if (sortable && !sortable.options.disabled) { - inst.sortables.push({ - instance: sortable, - shouldRevert: sortable.options.revert - }); - sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). - sortable._trigger("activate", event, uiSortable); - } - }); - - }, - stop: function(event, ui) { - - //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("draggable"), - uiSortable = $.extend({}, ui, { item: inst.element }); - - $.each(inst.sortables, function() { - if(this.instance.isOver) { - - this.instance.isOver = 0; - - inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid' - if(this.shouldRevert) this.instance.options.revert = true; - - //Trigger the stop of the sortable - this.instance._mouseStop(event); - - this.instance.options.helper = this.instance.options._helper; - - //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper == 'original') - this.instance.currentItem.css({ top: 'auto', left: 'auto' }); - - } else { - this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance - this.instance._trigger("deactivate", event, uiSortable); - } - - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"), self = this; - - var checkPos = function(o) { - var dyClick = this.offset.click.top, dxClick = this.offset.click.left; - var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left; - var itemHeight = o.height, itemWidth = o.width; - var itemTop = o.top, itemLeft = o.left; - - return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth); - }; - - $.each(inst.sortables, function(i) { - - //Copy over some variables to allow calling the sortable's native _intersectsWith - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - - if(this.instance._intersectsWith(this.instance.containerCache)) { - - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!this.instance.isOver) { - - this.instance.isOver = 1; - //Now we fake the start of dragging for the sortable instance, - //by cloning the list group item, appending it to the sortable and using it as inst.currentItem - //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true); - this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it - this.instance.options.helper = function() { return ui.helper[0]; }; - - event.target = this.instance.currentItem[0]; - this.instance._mouseCapture(event, true); - this.instance._mouseStart(event, true, true); - - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - this.instance.offset.click.top = inst.offset.click.top; - this.instance.offset.click.left = inst.offset.click.left; - this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; - this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; - - inst._trigger("toSortable", event); - inst.dropped = this.instance.element; //draggable revert needs that - //hack so receive/update callbacks work (mostly) - inst.currentItem = inst.element; - this.instance.fromOutside = inst; - - } - - //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) this.instance._mouseDrag(event); - - } else { - - //If it doesn't intersect with the sortable, and it intersected before, - //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval - if(this.instance.isOver) { - - this.instance.isOver = 0; - this.instance.cancelHelperRemoval = true; - - //Prevent reverting on this forced stop - this.instance.options.revert = false; - - // The out event needs to be triggered independently - this.instance._trigger('out', event, this.instance._uiHash(this.instance)); - - this.instance._mouseStop(event, true); - this.instance.options.helper = this.instance.options._helper; - - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - this.instance.currentItem.remove(); - if(this.instance.placeholder) this.instance.placeholder.remove(); - - inst._trigger("fromSortable", event); - inst.dropped = false; //draggable revert needs that - } - - }; - - }); - - } -}); - -$.ui.plugin.add("draggable", "cursor", { - start: function(event, ui) { - var t = $('body'), o = $(this).data('draggable').options; - if (t.css("cursor")) o._cursor = t.css("cursor"); - t.css("cursor", o.cursor); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if (o._cursor) $('body').css("cursor", o._cursor); - } -}); - -$.ui.plugin.add("draggable", "opacity", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data('draggable').options; - if(t.css("opacity")) o._opacity = t.css("opacity"); - t.css('opacity', o.opacity); - }, - stop: function(event, ui) { - var o = $(this).data('draggable').options; - if(o._opacity) $(ui.helper).css('opacity', o._opacity); - } -}); - -$.ui.plugin.add("draggable", "scroll", { - start: function(event, ui) { - var i = $(this).data("draggable"); - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset(); - }, - drag: function(event, ui) { - - var i = $(this).data("draggable"), o = i.options, scrolled = false; - - if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') { - - if(!o.axis || o.axis != 'x') { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if(!o.axis || o.axis != 'y') { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(!o.axis || o.axis != 'x') { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(!o.axis || o.axis != 'y') { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(i, event); - - } -}); - -$.ui.plugin.add("draggable", "snap", { - start: function(event, ui) { - - var i = $(this).data("draggable"), o = i.options; - i.snapElements = []; - - $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() { - var $t = $(this); var $o = $t.offset(); - if(this != i.element[0]) i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("draggable"), o = inst.options; - var d = o.snapTolerance; - - var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, - y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - - for (var i = inst.snapElements.length - 1; i >= 0; i--){ - - var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width, - t = inst.snapElements[i].top, b = t + inst.snapElements[i].height; - - //Yes, I know, this is insane ;) - if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { - if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = false; - continue; - } - - if(o.snapMode != 'inner') { - var ts = Math.abs(t - y2) <= d; - var bs = Math.abs(b - y1) <= d; - var ls = Math.abs(l - x2) <= d; - var rs = Math.abs(r - x1) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; - } - - var first = (ts || bs || ls || rs); - - if(o.snapMode != 'outer') { - var ts = Math.abs(t - y1) <= d; - var bs = Math.abs(b - y2) <= d; - var ls = Math.abs(l - x1) <= d; - var rs = Math.abs(r - x2) <= d; - if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; - } - - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) - (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - - }; - - } -}); - -$.ui.plugin.add("draggable", "stack", { - start: function(event, ui) { - - var o = $(this).data("draggable").options; - - var group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); - if (!group.length) { return; } - - var min = parseInt(group[0].style.zIndex) || 0; - $(group).each(function(i) { - this.style.zIndex = min + i; - }); - - this[0].style.zIndex = min + group.length; - - } -}); - -$.ui.plugin.add("draggable", "zIndex", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("draggable").options; - if(t.css("zIndex")) o._zIndex = t.css("zIndex"); - t.css('zIndex', o.zIndex); - }, - stop: function(event, ui) { - var o = $(this).data("draggable").options; - if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex); - } -}); - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.draggable.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.draggable.min.js deleted file mode 100644 index 41acd3c163..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.draggable.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.draggable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},destroy:function(){if(!this.element.data("draggable"))return;return this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy(),this},_mouseCapture:function(b){var c=this.options;return this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(b),this.handle?(c.iframeFix&&a(c.iframeFix===!0?"iframe":c.iframeFix).each(function(){a('
                    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(a(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(b){var c=this.options;return this.helper=this._createHelper(b),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),a.ui.ddmanager&&(a.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,c.cursorAt&&this._adjustOffsetFromHelper(c.cursorAt),c.containment&&this._setContainment(),this._trigger("start",b)===!1?(this._clear(),!1):(this._cacheHelperProportions(),a.ui.ddmanager&&!c.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this._mouseDrag(b,!0),a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,b),!0)},_mouseDrag:function(b,c){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute");if(!c){var d=this._uiHash();if(this._trigger("drag",b,d)===!1)return this._mouseUp({}),!1;this.position=d.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),!1},_mouseStop:function(b){var c=!1;a.ui.ddmanager&&!this.options.dropBehaviour&&(c=a.ui.ddmanager.drop(this,b)),this.dropped&&(c=this.dropped,this.dropped=!1);var d=this.element[0],e=!1;while(d&&(d=d.parentNode))d==document&&(e=!0);if(!e&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!c||this.options.revert=="valid"&&c||this.options.revert===!0||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,c)){var f=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){f._trigger("stop",b)!==!1&&f._clear()})}else this._trigger("stop",b)!==!1&&this._clear();return!1},_mouseUp:function(b){return a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,b),a.ui.mouse.prototype._mouseUp.call(this,b)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?!0:!1;return a(this.options.handle,this.element).find("*").andSelf().each(function(){this==b.target&&(c=!0)}),c},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b])):c.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return d.parents("body").length||d.appendTo(c.appendTo=="parent"?this.element[0].parentNode:c.appendTo),d[0]!=this.element[0]&&!/(fixed|absolute)/.test(d.css("position"))&&d.css("position","absolute"),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[b.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,b.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(b.containment=="document"?0:a(window).scrollLeft())+a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(b.containment=="document"?0:a(window).scrollTop())+(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)&&b.containment.constructor!=Array){var c=a(b.containment),d=c[0];if(!d)return;var e=c.offset(),f=a(d).css("overflow")!="hidden";this.containment=[(parseInt(a(d).css("borderLeftWidth"),10)||0)+(parseInt(a(d).css("paddingLeft"),10)||0),(parseInt(a(d).css("borderTopWidth"),10)||0)+(parseInt(a(d).css("paddingTop"),10)||0),(f?Math.max(d.scrollWidth,d.offsetWidth):d.offsetWidth)-(parseInt(a(d).css("borderLeftWidth"),10)||0)-(parseInt(a(d).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(f?Math.max(d.scrollHeight,d.offsetHeight):d.offsetHeight)-(parseInt(a(d).css("borderTopWidth"),10)||0)-(parseInt(a(d).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=c}else b.containment.constructor==Array&&(this.containment=b.containment)},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName),f=b.pageX,g=b.pageY;if(this.originalPosition){var h;if(this.containment){if(this.relative_container){var i=this.relative_container.offset();h=[this.containment[0]+i.left,this.containment[1]+i.top,this.containment[2]+i.left,this.containment[3]+i.top]}else h=this.containment;b.pageX-this.offset.click.lefth[2]&&(f=h[2]+this.offset.click.left),b.pageY-this.offset.click.top>h[3]&&(g=h[3]+this.offset.click.top)}if(c.grid){var j=c.grid[1]?this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1]:this.originalPageY;g=h?j-this.offset.click.toph[3]?j-this.offset.click.toph[2]?k-this.offset.click.left=0;k--){var l=d.snapElements[k].left,m=l+d.snapElements[k].width,n=d.snapElements[k].top,o=n+d.snapElements[k].height;if(!(l-f= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - break; - default: - return false; - break; - } - -}; - -/* - This manager tracks offsets of draggables and droppables -*/ -$.ui.ddmanager = { - current: null, - droppables: { 'default': [] }, - prepareOffsets: function(t, event) { - - var m = $.ui.ddmanager.droppables[t.options.scope] || []; - var type = event ? event.type : null; // workaround for #2317 - var list = (t.currentItem || t.element).find(":data(droppable)").andSelf(); - - droppablesLoop: for (var i = 0; i < m.length; i++) { - - if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted - for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item - m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue - - if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables - - m[i].offset = m[i].element.offset(); - m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; - - } - - }, - drop: function(draggable, event) { - - var dropped = false; - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(!this.options) return; - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) - dropped = this._drop.call(this, event) || dropped; - - if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - this.isout = 1; this.isover = 0; - this._deactivate.call(this, event); - } - - }); - return dropped; - - }, - dragStart: function( draggable, event ) { - //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) - draggable.element.parents( ":not(body,html)" ).bind( "scroll.droppable", function() { - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); - }); - }, - drag: function(draggable, event) { - - //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event); - - //Run through all droppables and check their positions based on specific tolerance options - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(this.options.disabled || this.greedyChild || !this.visible) return; - var intersects = $.ui.intersect(draggable, this, this.options.tolerance); - - var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null); - if(!c) return; - - var parentInstance; - if (this.options.greedy) { - // find droppable parents with same scope - var scope = this.options.scope; - var parent = this.element.parents(':data(droppable)').filter(function () { - return $.data(this, 'droppable').options.scope === scope; - }); - - if (parent.length) { - parentInstance = $.data(parent[0], 'droppable'); - parentInstance.greedyChild = (c == 'isover' ? 1 : 0); - } - } - - // we just moved into a greedy child - if (parentInstance && c == 'isover') { - parentInstance['isover'] = 0; - parentInstance['isout'] = 1; - parentInstance._out.call(parentInstance, event); - } - - this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0; - this[c == "isover" ? "_over" : "_out"].call(this, event); - - // we just moved out of a greedy child - if (parentInstance && c == 'isout') { - parentInstance['isout'] = 0; - parentInstance['isover'] = 1; - parentInstance._over.call(parentInstance, event); - } - }); - - }, - dragStop: function( draggable, event ) { - draggable.element.parents( ":not(body,html)" ).unbind( "scroll.droppable" ); - //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) - if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event ); - } -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.droppable.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.droppable.min.js deleted file mode 100644 index b85c56db51..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.droppable.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.droppable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect"},_create:function(){var b=this.options,c=b.accept;this.isover=0,this.isout=1,this.accept=a.isFunction(c)?c:function(a){return a.is(c)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},a.ui.ddmanager.droppables[b.scope]=a.ui.ddmanager.droppables[b.scope]||[],a.ui.ddmanager.droppables[b.scope].push(this),b.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){var b=a.ui.ddmanager.droppables[this.options.scope];for(var c=0;c=k&&g<=l||h>=k&&h<=l||gl)&&(e>=i&&e<=j||f>=i&&f<=j||ej);default:return!1}},a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(b,c){var d=a.ui.ddmanager.droppables[b.options.scope]||[],e=c?c.type:null,f=(b.currentItem||b.element).find(":data(droppable)").andSelf();g:for(var h=0;h= 9) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate) - .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target == this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + '.preventClickEvent', true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(event) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(event) {}, - _mouseDrag: function(event) {}, - _mouseStop: function(event) {}, - _mouseCapture: function(event) { return true; } -}); - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.mouse.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.mouse.min.js deleted file mode 100644 index 32b71ad297..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.mouse.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.mouse.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c=!1;a(document).mouseup(function(a){c=!1}),a.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var b=this;this.element.bind("mousedown."+this.widgetName,function(a){return b._mouseDown(a)}).bind("click."+this.widgetName,function(c){if(!0===a.data(c.target,b.widgetName+".preventClickEvent"))return a.removeData(c.target,b.widgetName+".preventClickEvent"),c.stopImmediatePropagation(),!1}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(b){if(c)return;this._mouseStarted&&this._mouseUp(b),this._mouseDownEvent=b;var d=this,e=b.which==1,f=typeof this.options.cancel=="string"&&b.target.nodeName?a(b.target).closest(this.options.cancel).length:!1;if(!e||f||!this._mouseCapture(b))return!0;this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){d.mouseDelayMet=!0},this.options.delay));if(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)){this._mouseStarted=this._mouseStart(b)!==!1;if(!this._mouseStarted)return b.preventDefault(),!0}return!0===a.data(b.target,this.widgetName+".preventClickEvent")&&a.removeData(b.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(a){return d._mouseMove(a)},this._mouseUpDelegate=function(a){return d._mouseUp(a)},a(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),b.preventDefault(),c=!0,!0},_mouseMove:function(b){return!a.browser.msie||document.documentMode>=9||!!b.button?this._mouseStarted?(this._mouseDrag(b),b.preventDefault()):(this._mouseDistanceMet(b)&&this._mouseDelayMet(b)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,b)!==!1,this._mouseStarted?this._mouseDrag(b):this._mouseUp(b)),!this._mouseStarted):this._mouseUp(b)},_mouseUp:function(b){return a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,b.target==this._mouseDownEvent.target&&a.data(b.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(b)),!1},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(a){return this.mouseDelayMet},_mouseStart:function(a){},_mouseDrag:function(a){},_mouseStop:function(a){},_mouseCapture:function(a){return!0}})})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.position.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.position.js deleted file mode 100644 index 8b20179b1b..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.position.js +++ /dev/null @@ -1,308 +0,0 @@ -/*! - * jQuery UI Position 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Position - */ -(function( $, undefined ) { - -$.ui = $.ui || {}; - -var horizontalPositions = /left|center|right/, - verticalPositions = /top|center|bottom/, - center = "center", - support = {}, - _position = $.fn.position, - _offset = $.fn.offset; - -$.fn.position = function( options ) { - if ( !options || !options.of ) { - return _position.apply( this, arguments ); - } - - // make a copy, we don't want to modify arguments - options = $.extend( {}, options ); - - var target = $( options.of ), - targetElem = target[0], - collision = ( options.collision || "flip" ).split( " " ), - offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ], - targetWidth, - targetHeight, - basePosition; - - if ( targetElem.nodeType === 9 ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: 0, left: 0 }; - // TODO: use $.isWindow() in 1.9 - } else if ( targetElem.setTimeout ) { - targetWidth = target.width(); - targetHeight = target.height(); - basePosition = { top: target.scrollTop(), left: target.scrollLeft() }; - } else if ( targetElem.preventDefault ) { - // force left top to allow flipping - options.at = "left top"; - targetWidth = targetHeight = 0; - basePosition = { top: options.of.pageY, left: options.of.pageX }; - } else { - targetWidth = target.outerWidth(); - targetHeight = target.outerHeight(); - basePosition = target.offset(); - } - - // force my and at to have valid horizontal and veritcal positions - // if a value is missing or invalid, it will be converted to center - $.each( [ "my", "at" ], function() { - var pos = ( options[this] || "" ).split( " " ); - if ( pos.length === 1) { - pos = horizontalPositions.test( pos[0] ) ? - pos.concat( [center] ) : - verticalPositions.test( pos[0] ) ? - [ center ].concat( pos ) : - [ center, center ]; - } - pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center; - pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center; - options[ this ] = pos; - }); - - // normalize collision option - if ( collision.length === 1 ) { - collision[ 1 ] = collision[ 0 ]; - } - - // normalize offset option - offset[ 0 ] = parseInt( offset[0], 10 ) || 0; - if ( offset.length === 1 ) { - offset[ 1 ] = offset[ 0 ]; - } - offset[ 1 ] = parseInt( offset[1], 10 ) || 0; - - if ( options.at[0] === "right" ) { - basePosition.left += targetWidth; - } else if ( options.at[0] === center ) { - basePosition.left += targetWidth / 2; - } - - if ( options.at[1] === "bottom" ) { - basePosition.top += targetHeight; - } else if ( options.at[1] === center ) { - basePosition.top += targetHeight / 2; - } - - basePosition.left += offset[ 0 ]; - basePosition.top += offset[ 1 ]; - - return this.each(function() { - var elem = $( this ), - elemWidth = elem.outerWidth(), - elemHeight = elem.outerHeight(), - marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0, - marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0, - collisionWidth = elemWidth + marginLeft + - ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ), - collisionHeight = elemHeight + marginTop + - ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ), - position = $.extend( {}, basePosition ), - collisionPosition; - - if ( options.my[0] === "right" ) { - position.left -= elemWidth; - } else if ( options.my[0] === center ) { - position.left -= elemWidth / 2; - } - - if ( options.my[1] === "bottom" ) { - position.top -= elemHeight; - } else if ( options.my[1] === center ) { - position.top -= elemHeight / 2; - } - - // prevent fractions if jQuery version doesn't support them (see #5280) - if ( !support.fractions ) { - position.left = Math.round( position.left ); - position.top = Math.round( position.top ); - } - - collisionPosition = { - left: position.left - marginLeft, - top: position.top - marginTop - }; - - $.each( [ "left", "top" ], function( i, dir ) { - if ( $.ui.position[ collision[i] ] ) { - $.ui.position[ collision[i] ][ dir ]( position, { - targetWidth: targetWidth, - targetHeight: targetHeight, - elemWidth: elemWidth, - elemHeight: elemHeight, - collisionPosition: collisionPosition, - collisionWidth: collisionWidth, - collisionHeight: collisionHeight, - offset: offset, - my: options.my, - at: options.at - }); - } - }); - - if ( $.fn.bgiframe ) { - elem.bgiframe(); - } - elem.offset( $.extend( position, { using: options.using } ) ); - }); -}; - -$.ui.position = { - fit: { - left: function( position, data ) { - var win = $( window ), - over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(); - position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left ); - }, - top: function( position, data ) { - var win = $( window ), - over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(); - position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top ); - } - }, - - flip: { - left: function( position, data ) { - if ( data.at[0] === center ) { - return; - } - var win = $( window ), - over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), - myOffset = data.my[ 0 ] === "left" ? - -data.elemWidth : - data.my[ 0 ] === "right" ? - data.elemWidth : - 0, - atOffset = data.at[ 0 ] === "left" ? - data.targetWidth : - -data.targetWidth, - offset = -2 * data.offset[ 0 ]; - position.left += data.collisionPosition.left < 0 ? - myOffset + atOffset + offset : - over > 0 ? - myOffset + atOffset + offset : - 0; - }, - top: function( position, data ) { - if ( data.at[1] === center ) { - return; - } - var win = $( window ), - over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), - myOffset = data.my[ 1 ] === "top" ? - -data.elemHeight : - data.my[ 1 ] === "bottom" ? - data.elemHeight : - 0, - atOffset = data.at[ 1 ] === "top" ? - data.targetHeight : - -data.targetHeight, - offset = -2 * data.offset[ 1 ]; - position.top += data.collisionPosition.top < 0 ? - myOffset + atOffset + offset : - over > 0 ? - myOffset + atOffset + offset : - 0; - } - } -}; - -// offset setter from jQuery 1.4 -if ( !$.offset.setOffset ) { - $.offset.setOffset = function( elem, options ) { - // set position first, in-case top/left are set even on static elem - if ( /static/.test( $.curCSS( elem, "position" ) ) ) { - elem.style.position = "relative"; - } - var curElem = $( elem ), - curOffset = curElem.offset(), - curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0, - curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0, - props = { - top: (options.top - curOffset.top) + curTop, - left: (options.left - curOffset.left) + curLeft - }; - - if ( 'using' in options ) { - options.using.call( elem, props ); - } else { - curElem.css( props ); - } - }; - - $.fn.offset = function( options ) { - var elem = this[ 0 ]; - if ( !elem || !elem.ownerDocument ) { return null; } - if ( options ) { - if ( $.isFunction( options ) ) { - return this.each(function( i ) { - $( this ).offset( options.call( this, i, $( this ).offset() ) ); - }); - } - return this.each(function() { - $.offset.setOffset( this, options ); - }); - } - return _offset.call( this ); - }; -} - -// jQuery <1.4.3 uses curCSS, in 1.4.3 - 1.7.2 curCSS = css, 1.8+ only has css -if ( !$.curCSS ) { - $.curCSS = $.css; -} - -// fraction support test (older versions of jQuery don't support fractions) -(function () { - var body = document.getElementsByTagName( "body" )[ 0 ], - div = document.createElement( "div" ), - testElement, testElementParent, testElementStyle, offset, offsetTotal; - - //Create a "fake body" for testing based on method used in jQuery.support - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - $.extend( testElementStyle, { - position: "absolute", - left: "-1000px", - top: "-1000px" - }); - } - for ( var i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || document.documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - div.style.cssText = "position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;"; - - offset = $( div ).offset( function( _, offset ) { - return offset; - }).offset(); - - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); - - offsetTotal = offset.top + offset.left + ( body ? 2000 : 0 ); - support.fractions = offsetTotal > 21 && offsetTotal < 22; -})(); - -}( jQuery )); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.position.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.position.min.js deleted file mode 100644 index ba6e4eebb7..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.position.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.position.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.ui=a.ui||{};var c=/left|center|right/,d=/top|center|bottom/,e="center",f={},g=a.fn.position,h=a.fn.offset;a.fn.position=function(b){if(!b||!b.of)return g.apply(this,arguments);b=a.extend({},b);var h=a(b.of),i=h[0],j=(b.collision||"flip").split(" "),k=b.offset?b.offset.split(" "):[0,0],l,m,n;return i.nodeType===9?(l=h.width(),m=h.height(),n={top:0,left:0}):i.setTimeout?(l=h.width(),m=h.height(),n={top:h.scrollTop(),left:h.scrollLeft()}):i.preventDefault?(b.at="left top",l=m=0,n={top:b.of.pageY,left:b.of.pageX}):(l=h.outerWidth(),m=h.outerHeight(),n=h.offset()),a.each(["my","at"],function(){var a=(b[this]||"").split(" ");a.length===1&&(a=c.test(a[0])?a.concat([e]):d.test(a[0])?[e].concat(a):[e,e]),a[0]=c.test(a[0])?a[0]:e,a[1]=d.test(a[1])?a[1]:e,b[this]=a}),j.length===1&&(j[1]=j[0]),k[0]=parseInt(k[0],10)||0,k.length===1&&(k[1]=k[0]),k[1]=parseInt(k[1],10)||0,b.at[0]==="right"?n.left+=l:b.at[0]===e&&(n.left+=l/2),b.at[1]==="bottom"?n.top+=m:b.at[1]===e&&(n.top+=m/2),n.left+=k[0],n.top+=k[1],this.each(function(){var c=a(this),d=c.outerWidth(),g=c.outerHeight(),h=parseInt(a.curCSS(this,"marginLeft",!0))||0,i=parseInt(a.curCSS(this,"marginTop",!0))||0,o=d+h+(parseInt(a.curCSS(this,"marginRight",!0))||0),p=g+i+(parseInt(a.curCSS(this,"marginBottom",!0))||0),q=a.extend({},n),r;b.my[0]==="right"?q.left-=d:b.my[0]===e&&(q.left-=d/2),b.my[1]==="bottom"?q.top-=g:b.my[1]===e&&(q.top-=g/2),f.fractions||(q.left=Math.round(q.left),q.top=Math.round(q.top)),r={left:q.left-h,top:q.top-i},a.each(["left","top"],function(c,e){a.ui.position[j[c]]&&a.ui.position[j[c]][e](q,{targetWidth:l,targetHeight:m,elemWidth:d,elemHeight:g,collisionPosition:r,collisionWidth:o,collisionHeight:p,offset:k,my:b.my,at:b.at})}),a.fn.bgiframe&&c.bgiframe(),c.offset(a.extend(q,{using:b.using}))})},a.ui.position={fit:{left:function(b,c){var d=a(window),e=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft();b.left=e>0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.progressbar.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.progressbar.js deleted file mode 100644 index 7cea1baafe..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.progressbar.js +++ /dev/null @@ -1,109 +0,0 @@ -/*! - * jQuery UI Progressbar 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget( "ui.progressbar", { - options: { - value: 0, - max: 100 - }, - - min: 0, - - _create: function() { - this.element - .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .attr({ - role: "progressbar", - "aria-valuemin": this.min, - "aria-valuemax": this.options.max, - "aria-valuenow": this._value() - }); - - this.valueDiv = $( "
                    " ) - .appendTo( this.element ); - - this.oldValue = this._value(); - this._refreshValue(); - }, - - destroy: function() { - this.element - .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) - .removeAttr( "role" ) - .removeAttr( "aria-valuemin" ) - .removeAttr( "aria-valuemax" ) - .removeAttr( "aria-valuenow" ); - - this.valueDiv.remove(); - - $.Widget.prototype.destroy.apply( this, arguments ); - }, - - value: function( newValue ) { - if ( newValue === undefined ) { - return this._value(); - } - - this._setOption( "value", newValue ); - return this; - }, - - _setOption: function( key, value ) { - if ( key === "value" ) { - this.options.value = value; - this._refreshValue(); - if ( this._value() === this.options.max ) { - this._trigger( "complete" ); - } - } - - $.Widget.prototype._setOption.apply( this, arguments ); - }, - - _value: function() { - var val = this.options.value; - // normalize invalid value - if ( typeof val !== "number" ) { - val = 0; - } - return Math.min( this.options.max, Math.max( this.min, val ) ); - }, - - _percentage: function() { - return 100 * this._value() / this.options.max; - }, - - _refreshValue: function() { - var value = this.value(); - var percentage = this._percentage(); - - if ( this.oldValue !== value ) { - this.oldValue = value; - this._trigger( "change" ); - } - - this.valueDiv - .toggle( value > this.min ) - .toggleClass( "ui-corner-right", value === this.options.max ) - .width( percentage.toFixed(0) + "%" ); - this.element.attr( "aria-valuenow", value ); - } -}); - -$.extend( $.ui.progressbar, { - version: "1.8.24" -}); - -})( jQuery ); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.progressbar.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.progressbar.min.js deleted file mode 100644 index 60a9d85c4c..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.progressbar.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.progressbar.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("
                    ").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.24"})})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.resizable.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.resizable.js deleted file mode 100644 index 6cc6f41fb6..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.resizable.js +++ /dev/null @@ -1,807 +0,0 @@ -/*! - * jQuery UI Resizable 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget("ui.resizable", $.ui.mouse, { - widgetEventPrefix: "resize", - options: { - alsoResize: false, - animate: false, - animateDuration: "slow", - animateEasing: "swing", - aspectRatio: false, - autoHide: false, - containment: false, - ghost: false, - grid: false, - handles: "e,s,se", - helper: false, - maxHeight: null, - maxWidth: null, - minHeight: 10, - minWidth: 10, - zIndex: 1000 - }, - _create: function() { - - var self = this, o = this.options; - this.element.addClass("ui-resizable"); - - $.extend(this, { - _aspectRatio: !!(o.aspectRatio), - aspectRatio: o.aspectRatio, - originalElement: this.element, - _proportionallyResizeElements: [], - _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null - }); - - //Wrap the element if it cannot hold child nodes - if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { - - //Create a wrapper element and set the wrapper to the new current internal element - this.element.wrap( - $('
                    ').css({ - position: this.element.css('position'), - width: this.element.outerWidth(), - height: this.element.outerHeight(), - top: this.element.css('top'), - left: this.element.css('left') - }) - ); - - //Overwrite the original this.element - this.element = this.element.parent().data( - "resizable", this.element.data('resizable') - ); - - this.elementIsWrapper = true; - - //Move margins to the wrapper - this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); - this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); - - //Prevent Safari textarea resize - this.originalResizeStyle = this.originalElement.css('resize'); - this.originalElement.css('resize', 'none'); - - //Push the actual element to our proportionallyResize internal array - this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' })); - - // avoid IE jump (hard set the margin) - this.originalElement.css({ margin: this.originalElement.css('margin') }); - - // fix handlers offset - this._proportionallyResize(); - - } - - this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' }); - if(this.handles.constructor == String) { - - if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw'; - var n = this.handles.split(","); this.handles = {}; - - for(var i = 0; i < n.length; i++) { - - var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle; - var axis = $('
                    '); - - // Apply zIndex to all handles - see #7960 - axis.css({ zIndex: o.zIndex }); - - //TODO : What's going on here? - if ('se' == handle) { - axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se'); - }; - - //Insert into internal handles object and append to element - this.handles[handle] = '.ui-resizable-'+handle; - this.element.append(axis); - } - - } - - this._renderAxis = function(target) { - - target = target || this.element; - - for(var i in this.handles) { - - if(this.handles[i].constructor == String) - this.handles[i] = $(this.handles[i], this.element).show(); - - //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) - if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { - - var axis = $(this.handles[i], this.element), padWrapper = 0; - - //Checking the correct pad and border - padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); - - //The padding type i have to apply... - var padPos = [ 'padding', - /ne|nw|n/.test(i) ? 'Top' : - /se|sw|s/.test(i) ? 'Bottom' : - /^e$/.test(i) ? 'Right' : 'Left' ].join(""); - - target.css(padPos, padWrapper); - - this._proportionallyResize(); - - } - - //TODO: What's that good for? There's not anything to be executed left - if(!$(this.handles[i]).length) - continue; - - } - }; - - //TODO: make renderAxis a prototype function - this._renderAxis(this.element); - - this._handles = $('.ui-resizable-handle', this.element) - .disableSelection(); - - //Matching axis name - this._handles.mouseover(function() { - if (!self.resizing) { - if (this.className) - var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); - //Axis, default = se - self.axis = axis && axis[1] ? axis[1] : 'se'; - } - }); - - //If we want to auto hide the elements - if (o.autoHide) { - this._handles.hide(); - $(this.element) - .addClass("ui-resizable-autohide") - .hover(function() { - if (o.disabled) return; - $(this).removeClass("ui-resizable-autohide"); - self._handles.show(); - }, - function(){ - if (o.disabled) return; - if (!self.resizing) { - $(this).addClass("ui-resizable-autohide"); - self._handles.hide(); - } - }); - } - - //Initialize the mouse interaction - this._mouseInit(); - - }, - - destroy: function() { - - this._mouseDestroy(); - - var _destroy = function(exp) { - $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") - .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove(); - }; - - //TODO: Unwrap at same DOM position - if (this.elementIsWrapper) { - _destroy(this.element); - var wrapper = this.element; - wrapper.after( - this.originalElement.css({ - position: wrapper.css('position'), - width: wrapper.outerWidth(), - height: wrapper.outerHeight(), - top: wrapper.css('top'), - left: wrapper.css('left') - }) - ).remove(); - } - - this.originalElement.css('resize', this.originalResizeStyle); - _destroy(this.originalElement); - - return this; - }, - - _mouseCapture: function(event) { - var handle = false; - for (var i in this.handles) { - if ($(this.handles[i])[0] == event.target) { - handle = true; - } - } - - return !this.options.disabled && handle; - }, - - _mouseStart: function(event) { - - var o = this.options, iniPos = this.element.position(), el = this.element; - - this.resizing = true; - this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() }; - - // bugfix for http://dev.jquery.com/ticket/1749 - if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) { - el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left }); - } - - this._renderProxy(); - - var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top')); - - if (o.containment) { - curleft += $(o.containment).scrollLeft() || 0; - curtop += $(o.containment).scrollTop() || 0; - } - - //Store needed variables - this.offset = this.helper.offset(); - this.position = { left: curleft, top: curtop }; - this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalPosition = { left: curleft, top: curtop }; - this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; - this.originalMousePosition = { left: event.pageX, top: event.pageY }; - - //Aspect Ratio - this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - - var cursor = $('.ui-resizable-' + this.axis).css('cursor'); - $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor); - - el.addClass("ui-resizable-resizing"); - this._propagate("start", event); - return true; - }, - - _mouseDrag: function(event) { - - //Increase performance, avoid regex - var el = this.helper, o = this.options, props = {}, - self = this, smp = this.originalMousePosition, a = this.axis; - - var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0; - var trigger = this._change[a]; - if (!trigger) return false; - - // Calculate the attrs that will be change - var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff; - - // Put this in the mouseDrag handler since the user can start pressing shift while resizing - this._updateVirtualBoundaries(event.shiftKey); - if (this._aspectRatio || event.shiftKey) - data = this._updateRatio(data, event); - - data = this._respectSize(data, event); - - // plugins callbacks need to be called first - this._propagate("resize", event); - - el.css({ - top: this.position.top + "px", left: this.position.left + "px", - width: this.size.width + "px", height: this.size.height + "px" - }); - - if (!this._helper && this._proportionallyResizeElements.length) - this._proportionallyResize(); - - this._updateCache(data); - - // calling the user callback at the end - this._trigger('resize', event, this.ui()); - - return false; - }, - - _mouseStop: function(event) { - - this.resizing = false; - var o = this.options, self = this; - - if(this._helper) { - var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var s = { width: (self.helper.width() - soffsetw), height: (self.helper.height() - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - if (!o.animate) - this.element.css($.extend(s, { top: top, left: left })); - - self.helper.height(self.size.height); - self.helper.width(self.size.width); - - if (this._helper && !o.animate) this._proportionallyResize(); - } - - $('body').css('cursor', 'auto'); - - this.element.removeClass("ui-resizable-resizing"); - - this._propagate("stop", event); - - if (this._helper) this.helper.remove(); - return false; - - }, - - _updateVirtualBoundaries: function(forceAspectRatio) { - var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b; - - b = { - minWidth: isNumber(o.minWidth) ? o.minWidth : 0, - maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, - minHeight: isNumber(o.minHeight) ? o.minHeight : 0, - maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity - }; - - if(this._aspectRatio || forceAspectRatio) { - // We want to create an enclosing box whose aspect ration is the requested one - // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension - pMinWidth = b.minHeight * this.aspectRatio; - pMinHeight = b.minWidth / this.aspectRatio; - pMaxWidth = b.maxHeight * this.aspectRatio; - pMaxHeight = b.maxWidth / this.aspectRatio; - - if(pMinWidth > b.minWidth) b.minWidth = pMinWidth; - if(pMinHeight > b.minHeight) b.minHeight = pMinHeight; - if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth; - if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight; - } - this._vBoundaries = b; - }, - - _updateCache: function(data) { - var o = this.options; - this.offset = this.helper.offset(); - if (isNumber(data.left)) this.position.left = data.left; - if (isNumber(data.top)) this.position.top = data.top; - if (isNumber(data.height)) this.size.height = data.height; - if (isNumber(data.width)) this.size.width = data.width; - }, - - _updateRatio: function(data, event) { - - var o = this.options, cpos = this.position, csize = this.size, a = this.axis; - - if (isNumber(data.height)) data.width = (data.height * this.aspectRatio); - else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio); - - if (a == 'sw') { - data.left = cpos.left + (csize.width - data.width); - data.top = null; - } - if (a == 'nw') { - data.top = cpos.top + (csize.height - data.height); - data.left = cpos.left + (csize.width - data.width); - } - - return data; - }, - - _respectSize: function(data, event) { - - var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis, - ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), - isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height); - - if (isminw) data.width = o.minWidth; - if (isminh) data.height = o.minHeight; - if (ismaxw) data.width = o.maxWidth; - if (ismaxh) data.height = o.maxHeight; - - var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height; - var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - - if (isminw && cw) data.left = dw - o.minWidth; - if (ismaxw && cw) data.left = dw - o.maxWidth; - if (isminh && ch) data.top = dh - o.minHeight; - if (ismaxh && ch) data.top = dh - o.maxHeight; - - // fixing jump error on top/left - bug #2330 - var isNotwh = !data.width && !data.height; - if (isNotwh && !data.left && data.top) data.top = null; - else if (isNotwh && !data.top && data.left) data.left = null; - - return data; - }, - - _proportionallyResize: function() { - - var o = this.options; - if (!this._proportionallyResizeElements.length) return; - var element = this.helper || this.element; - - for (var i=0; i < this._proportionallyResizeElements.length; i++) { - - var prel = this._proportionallyResizeElements[i]; - - if (!this.borderDif) { - var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')], - p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')]; - - this.borderDif = $.map(b, function(v, i) { - var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0; - return border + padding; - }); - } - - if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length))) - continue; - - prel.css({ - height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, - width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 - }); - - }; - - }, - - _renderProxy: function() { - - var el = this.element, o = this.options; - this.elementOffset = el.offset(); - - if(this._helper) { - - this.helper = this.helper || $('
                    '); - - // fix ie6 offset TODO: This seems broken - var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0), - pxyoffset = ( ie6 ? 2 : -1 ); - - this.helper.addClass(this._helper).css({ - width: this.element.outerWidth() + pxyoffset, - height: this.element.outerHeight() + pxyoffset, - position: 'absolute', - left: this.elementOffset.left - ie6offset +'px', - top: this.elementOffset.top - ie6offset +'px', - zIndex: ++o.zIndex //TODO: Don't modify option - }); - - this.helper - .appendTo("body") - .disableSelection(); - - } else { - this.helper = this.element; - } - - }, - - _change: { - e: function(event, dx, dy) { - return { width: this.originalSize.width + dx }; - }, - w: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { left: sp.left + dx, width: cs.width - dx }; - }, - n: function(event, dx, dy) { - var o = this.options, cs = this.originalSize, sp = this.originalPosition; - return { top: sp.top + dy, height: cs.height - dy }; - }, - s: function(event, dx, dy) { - return { height: this.originalSize.height + dy }; - }, - se: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - sw: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - }, - ne: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - nw: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - } - }, - - _propagate: function(n, event) { - $.ui.plugin.call(this, n, [event, this.ui()]); - (n != "resize" && this._trigger(n, event, this.ui())); - }, - - plugins: {}, - - ui: function() { - return { - originalElement: this.originalElement, - element: this.element, - helper: this.helper, - position: this.position, - size: this.size, - originalSize: this.originalSize, - originalPosition: this.originalPosition - }; - } - -}); - -$.extend($.ui.resizable, { - version: "1.8.24" -}); - -/* - * Resizable Extensions - */ - -$.ui.plugin.add("resizable", "alsoResize", { - - start: function (event, ui) { - var self = $(this).data("resizable"), o = self.options; - - var _store = function (exp) { - $(exp).each(function() { - var el = $(this); - el.data("resizable-alsoresize", { - width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), - left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10) - }); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function (exp) { _store(exp); }); } - }else{ - _store(o.alsoResize); - } - }, - - resize: function (event, ui) { - var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition; - - var delta = { - height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0, - top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0 - }, - - _alsoResize = function (exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("resizable-alsoresize"), style = {}, - css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left']; - - $.each(css, function (i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) - style[prop] = sum || null; - }); - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); - } - }, - - stop: function (event, ui) { - $(this).removeData("resizable-alsoresize"); - } -}); - -$.ui.plugin.add("resizable", "animate", { - - stop: function(event, ui) { - var self = $(this).data("resizable"), o = self.options; - - var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height, - soffsetw = ista ? 0 : self.sizeDiff.width; - - var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) }, - left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null, - top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null; - - self.element.animate( - $.extend(style, top && left ? { top: top, left: left } : {}), { - duration: o.animateDuration, - easing: o.animateEasing, - step: function() { - - var data = { - width: parseInt(self.element.css('width'), 10), - height: parseInt(self.element.css('height'), 10), - top: parseInt(self.element.css('top'), 10), - left: parseInt(self.element.css('left'), 10) - }; - - if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height }); - - // propagating resize, and updating values for each animation step - self._updateCache(data); - self._propagate("resize", event); - - } - } - ); - } - -}); - -$.ui.plugin.add("resizable", "containment", { - - start: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, el = self.element; - var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - if (!ce) return; - - self.containerElement = $(ce); - - if (/document/.test(oc) || oc == document) { - self.containerOffset = { left: 0, top: 0 }; - self.containerPosition = { left: 0, top: 0 }; - - self.parentData = { - element: $(document), left: 0, top: 0, - width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight - }; - } - - // i'm a node, so compute top, left, right, bottom - else { - var element = $(ce), p = []; - $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); - - self.containerOffset = element.offset(); - self.containerPosition = element.position(); - self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - - var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width, - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); - - self.parentData = { - element: ce, left: co.left, top: co.top, width: width, height: height - }; - } - }, - - resize: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, - ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position, - pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement; - - if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co; - - if (cp.left < (self._helper ? co.left : 0)) { - self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left)); - if (pRatio) self.size.height = self.size.width / self.aspectRatio; - self.position.left = o.helper ? co.left : 0; - } - - if (cp.top < (self._helper ? co.top : 0)) { - self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top); - if (pRatio) self.size.width = self.size.height * self.aspectRatio; - self.position.top = self._helper ? co.top : 0; - } - - self.offset.left = self.parentData.left+self.position.left; - self.offset.top = self.parentData.top+self.position.top; - - var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ), - hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height ); - - var isParent = self.containerElement.get(0) == self.element.parent().get(0), - isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position')); - - if(isParent && isOffsetRelative) woset -= self.parentData.left; - - if (woset + self.size.width >= self.parentData.width) { - self.size.width = self.parentData.width - woset; - if (pRatio) self.size.height = self.size.width / self.aspectRatio; - } - - if (hoset + self.size.height >= self.parentData.height) { - self.size.height = self.parentData.height - hoset; - if (pRatio) self.size.width = self.size.height * self.aspectRatio; - } - }, - - stop: function(event, ui){ - var self = $(this).data("resizable"), o = self.options, cp = self.position, - co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement; - - var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height; - - if (self._helper && !o.animate && (/relative/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - if (self._helper && !o.animate && (/static/).test(ce.css('position'))) - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - - } -}); - -$.ui.plugin.add("resizable", "ghost", { - - start: function(event, ui) { - - var self = $(this).data("resizable"), o = self.options, cs = self.size; - - self.ghost = self.originalElement.clone(); - self.ghost - .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) - .addClass('ui-resizable-ghost') - .addClass(typeof o.ghost == 'string' ? o.ghost : ''); - - self.ghost.appendTo(self.helper); - - }, - - resize: function(event, ui){ - var self = $(this).data("resizable"), o = self.options; - if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width }); - }, - - stop: function(event, ui){ - var self = $(this).data("resizable"), o = self.options; - if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0)); - } - -}); - -$.ui.plugin.add("resizable", "grid", { - - resize: function(event, ui) { - var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey; - o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid; - var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1); - - if (/^(se|s|e)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - } - else if (/^(ne)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; - } - else if (/^(sw)$/.test(a)) { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.left = op.left - ox; - } - else { - self.size.width = os.width + ox; - self.size.height = os.height + oy; - self.position.top = op.top - oy; - self.position.left = op.left - ox; - } - } - -}); - -var num = function(v) { - return parseInt(v, 10) || 0; -}; - -var isNumber = function(value) { - return !isNaN(parseInt(value, 10)); -}; - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.resizable.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.resizable.min.js deleted file mode 100644 index 99fe8d7a74..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.resizable.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.resizable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.resizable",a.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1e3},_create:function(){var b=this,c=this.options;this.element.addClass("ui-resizable"),a.extend(this,{_aspectRatio:!!c.aspectRatio,aspectRatio:c.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:c.helper||c.ghost||c.animate?c.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(a('
                    ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=c.handles||(a(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var d=this.handles.split(",");this.handles={};for(var e=0;e');h.css({zIndex:c.zIndex}),"se"==f&&h.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[f]=".ui-resizable-"+f,this.element.append(h)}}this._renderAxis=function(b){b=b||this.element;for(var c in this.handles){this.handles[c].constructor==String&&(this.handles[c]=a(this.handles[c],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var d=a(this.handles[c],this.element),e=0;e=/sw|ne|nw|se|n|s/.test(c)?d.outerHeight():d.outerWidth();var f=["padding",/ne|nw|n/.test(c)?"Top":/se|sw|s/.test(c)?"Bottom":/^e$/.test(c)?"Right":"Left"].join("");b.css(f,e),this._proportionallyResize()}if(!a(this.handles[c]).length)continue}},this._renderAxis(this.element),this._handles=a(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!b.resizing){if(this.className)var a=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=a&&a[1]?a[1]:"se"}}),c.autoHide&&(this._handles.hide(),a(this.element).addClass("ui-resizable-autohide").hover(function(){if(c.disabled)return;a(this).removeClass("ui-resizable-autohide"),b._handles.show()},function(){if(c.disabled)return;b.resizing||(a(this).addClass("ui-resizable-autohide"),b._handles.hide())})),this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(b){a(b).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){b(this.element);var c=this.element;c.after(this.originalElement.css({position:c.css("position"),width:c.outerWidth(),height:c.outerHeight(),top:c.css("top"),left:c.css("left")})).remove()}return this.originalElement.css("resize",this.originalResizeStyle),b(this.originalElement),this},_mouseCapture:function(b){var c=!1;for(var d in this.handles)a(this.handles[d])[0]==b.target&&(c=!0);return!this.options.disabled&&c},_mouseStart:function(b){var d=this.options,e=this.element.position(),f=this.element;this.resizing=!0,this.documentScroll={top:a(document).scrollTop(),left:a(document).scrollLeft()},(f.is(".ui-draggable")||/absolute/.test(f.css("position")))&&f.css({position:"absolute",top:e.top,left:e.left}),this._renderProxy();var g=c(this.helper.css("left")),h=c(this.helper.css("top"));d.containment&&(g+=a(d.containment).scrollLeft()||0,h+=a(d.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:g,top:h},this.size=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalSize=this._helper?{width:f.outerWidth(),height:f.outerHeight()}:{width:f.width(),height:f.height()},this.originalPosition={left:g,top:h},this.sizeDiff={width:f.outerWidth()-f.width(),height:f.outerHeight()-f.height()},this.originalMousePosition={left:b.pageX,top:b.pageY},this.aspectRatio=typeof d.aspectRatio=="number"?d.aspectRatio:this.originalSize.width/this.originalSize.height||1;var i=a(".ui-resizable-"+this.axis).css("cursor");return a("body").css("cursor",i=="auto"?this.axis+"-resize":i),f.addClass("ui-resizable-resizing"),this._propagate("start",b),!0},_mouseDrag:function(b){var c=this.helper,d=this.options,e={},f=this,g=this.originalMousePosition,h=this.axis,i=b.pageX-g.left||0,j=b.pageY-g.top||0,k=this._change[h];if(!k)return!1;var l=k.apply(this,[b,i,j]),m=a.browser.msie&&a.browser.version<7,n=this.sizeDiff;this._updateVirtualBoundaries(b.shiftKey);if(this._aspectRatio||b.shiftKey)l=this._updateRatio(l,b);return l=this._respectSize(l,b),this._propagate("resize",b),c.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",b,this.ui()),!1},_mouseStop:function(b){this.resizing=!1;var c=this.options,d=this;if(this._helper){var e=this._proportionallyResizeElements,f=e.length&&/textarea/i.test(e[0].nodeName),g=f&&a.ui.hasScroll(e[0],"left")?0:d.sizeDiff.height,h=f?0:d.sizeDiff.width,i={width:d.helper.width()-h,height:d.helper.height()-g},j=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,k=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;c.animate||this.element.css(a.extend(i,{top:k,left:j})),d.helper.height(d.size.height),d.helper.width(d.size.width),this._helper&&!c.animate&&this._proportionallyResize()}return a("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",b),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(a){var b=this.options,c,e,f,g,h;h={minWidth:d(b.minWidth)?b.minWidth:0,maxWidth:d(b.maxWidth)?b.maxWidth:Infinity,minHeight:d(b.minHeight)?b.minHeight:0,maxHeight:d(b.maxHeight)?b.maxHeight:Infinity};if(this._aspectRatio||a)c=h.minHeight*this.aspectRatio,f=h.minWidth/this.aspectRatio,e=h.maxHeight*this.aspectRatio,g=h.maxWidth/this.aspectRatio,c>h.minWidth&&(h.minWidth=c),f>h.minHeight&&(h.minHeight=f),ea.width,k=d(a.height)&&e.minHeight&&e.minHeight>a.height;j&&(a.width=e.minWidth),k&&(a.height=e.minHeight),h&&(a.width=e.maxWidth),i&&(a.height=e.maxHeight);var l=this.originalPosition.left+this.originalSize.width,m=this.position.top+this.size.height,n=/sw|nw|w/.test(g),o=/nw|ne|n/.test(g);j&&n&&(a.left=l-e.minWidth),h&&n&&(a.left=l-e.maxWidth),k&&o&&(a.top=m-e.minHeight),i&&o&&(a.top=m-e.maxHeight);var p=!a.width&&!a.height;return p&&!a.left&&a.top?a.top=null:p&&!a.top&&a.left&&(a.left=null),a},_proportionallyResize:function(){var b=this.options;if(!this._proportionallyResizeElements.length)return;var c=this.helper||this.element;for(var d=0;d');var d=a.browser.msie&&a.browser.version<7,e=d?1:0,f=d?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+f,height:this.element.outerHeight()+f,position:"absolute",left:this.elementOffset.left-e+"px",top:this.elementOffset.top-e+"px",zIndex:++c.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(a,b,c){return{width:this.originalSize.width+b}},w:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{left:f.left+b,width:e.width-b}},n:function(a,b,c){var d=this.options,e=this.originalSize,f=this.originalPosition;return{top:f.top+c,height:e.height-c}},s:function(a,b,c){return{height:this.originalSize.height+c}},se:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},sw:function(b,c,d){return a.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,c,d]))},ne:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,c,d]))},nw:function(b,c,d){return a.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,c,d]))}},_propagate:function(b,c){a.ui.plugin.call(this,b,[c,this.ui()]),b!="resize"&&this._trigger(b,c,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),a.extend(a.ui.resizable,{version:"1.8.24"}),a.ui.plugin.add("resizable","alsoResize",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=function(b){a(b).each(function(){var b=a(this);b.data("resizable-alsoresize",{width:parseInt(b.width(),10),height:parseInt(b.height(),10),left:parseInt(b.css("left"),10),top:parseInt(b.css("top"),10)})})};typeof e.alsoResize=="object"&&!e.alsoResize.parentNode?e.alsoResize.length?(e.alsoResize=e.alsoResize[0],f(e.alsoResize)):a.each(e.alsoResize,function(a){f(a)}):f(e.alsoResize)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.originalSize,g=d.originalPosition,h={height:d.size.height-f.height||0,width:d.size.width-f.width||0,top:d.position.top-g.top||0,left:d.position.left-g.left||0},i=function(b,d){a(b).each(function(){var b=a(this),e=a(this).data("resizable-alsoresize"),f={},g=d&&d.length?d:b.parents(c.originalElement[0]).length?["width","height"]:["width","height","top","left"];a.each(g,function(a,b){var c=(e[b]||0)+(h[b]||0);c&&c>=0&&(f[b]=c||null)}),b.css(f)})};typeof e.alsoResize=="object"&&!e.alsoResize.nodeType?a.each(e.alsoResize,function(a,b){i(a,b)}):i(e.alsoResize)},stop:function(b,c){a(this).removeData("resizable-alsoresize")}}),a.ui.plugin.add("resizable","animate",{stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d._proportionallyResizeElements,g=f.length&&/textarea/i.test(f[0].nodeName),h=g&&a.ui.hasScroll(f[0],"left")?0:d.sizeDiff.height,i=g?0:d.sizeDiff.width,j={width:d.size.width-i,height:d.size.height-h},k=parseInt(d.element.css("left"),10)+(d.position.left-d.originalPosition.left)||null,l=parseInt(d.element.css("top"),10)+(d.position.top-d.originalPosition.top)||null;d.element.animate(a.extend(j,l&&k?{top:l,left:k}:{}),{duration:e.animateDuration,easing:e.animateEasing,step:function(){var c={width:parseInt(d.element.css("width"),10),height:parseInt(d.element.css("height"),10),top:parseInt(d.element.css("top"),10),left:parseInt(d.element.css("left"),10)};f&&f.length&&a(f[0]).css({width:c.width,height:c.height}),d._updateCache(c),d._propagate("resize",b)}})}}),a.ui.plugin.add("resizable","containment",{start:function(b,d){var e=a(this).data("resizable"),f=e.options,g=e.element,h=f.containment,i=h instanceof a?h.get(0):/parent/.test(h)?g.parent().get(0):h;if(!i)return;e.containerElement=a(i);if(/document/.test(h)||h==document)e.containerOffset={left:0,top:0},e.containerPosition={left:0,top:0},e.parentData={element:a(document),left:0,top:0,width:a(document).width(),height:a(document).height()||document.body.parentNode.scrollHeight};else{var j=a(i),k=[];a(["Top","Right","Left","Bottom"]).each(function(a,b){k[a]=c(j.css("padding"+b))}),e.containerOffset=j.offset(),e.containerPosition=j.position(),e.containerSize={height:j.innerHeight()-k[3],width:j.innerWidth()-k[1]};var l=e.containerOffset,m=e.containerSize.height,n=e.containerSize.width,o=a.ui.hasScroll(i,"left")?i.scrollWidth:n,p=a.ui.hasScroll(i)?i.scrollHeight:m;e.parentData={element:i,left:l.left,top:l.top,width:o,height:p}}},resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.containerSize,g=d.containerOffset,h=d.size,i=d.position,j=d._aspectRatio||b.shiftKey,k={top:0,left:0},l=d.containerElement;l[0]!=document&&/static/.test(l.css("position"))&&(k=g),i.left<(d._helper?g.left:0)&&(d.size.width=d.size.width+(d._helper?d.position.left-g.left:d.position.left-k.left),j&&(d.size.height=d.size.width/d.aspectRatio),d.position.left=e.helper?g.left:0),i.top<(d._helper?g.top:0)&&(d.size.height=d.size.height+(d._helper?d.position.top-g.top:d.position.top),j&&(d.size.width=d.size.height*d.aspectRatio),d.position.top=d._helper?g.top:0),d.offset.left=d.parentData.left+d.position.left,d.offset.top=d.parentData.top+d.position.top;var m=Math.abs((d._helper?d.offset.left-k.left:d.offset.left-k.left)+d.sizeDiff.width),n=Math.abs((d._helper?d.offset.top-k.top:d.offset.top-g.top)+d.sizeDiff.height),o=d.containerElement.get(0)==d.element.parent().get(0),p=/relative|absolute/.test(d.containerElement.css("position"));o&&p&&(m-=d.parentData.left),m+d.size.width>=d.parentData.width&&(d.size.width=d.parentData.width-m,j&&(d.size.height=d.size.width/d.aspectRatio)),n+d.size.height>=d.parentData.height&&(d.size.height=d.parentData.height-n,j&&(d.size.width=d.size.height*d.aspectRatio))},stop:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.position,g=d.containerOffset,h=d.containerPosition,i=d.containerElement,j=a(d.helper),k=j.offset(),l=j.outerWidth()-d.sizeDiff.width,m=j.outerHeight()-d.sizeDiff.height;d._helper&&!e.animate&&/relative/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m}),d._helper&&!e.animate&&/static/.test(i.css("position"))&&a(this).css({left:k.left-h.left-g.left,width:l,height:m})}}),a.ui.plugin.add("resizable","ghost",{start:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size;d.ghost=d.originalElement.clone(),d.ghost.css({opacity:.25,display:"block",position:"relative",height:f.height,width:f.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof e.ghost=="string"?e.ghost:""),d.ghost.appendTo(d.helper)},resize:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})},stop:function(b,c){var d=a(this).data("resizable"),e=d.options;d.ghost&&d.helper&&d.helper.get(0).removeChild(d.ghost.get(0))}}),a.ui.plugin.add("resizable","grid",{resize:function(b,c){var d=a(this).data("resizable"),e=d.options,f=d.size,g=d.originalSize,h=d.originalPosition,i=d.axis,j=e._aspectRatio||b.shiftKey;e.grid=typeof e.grid=="number"?[e.grid,e.grid]:e.grid;var k=Math.round((f.width-g.width)/(e.grid[0]||1))*(e.grid[0]||1),l=Math.round((f.height-g.height)/(e.grid[1]||1))*(e.grid[1]||1);/^(se|s|e)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l):/^(ne)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l):/^(sw)$/.test(i)?(d.size.width=g.width+k,d.size.height=g.height+l,d.position.left=h.left-k):(d.size.width=g.width+k,d.size.height=g.height+l,d.position.top=h.top-l,d.position.left=h.left-k)}});var c=function(a){return parseInt(a,10)||0},d=function(a){return!isNaN(parseInt(a,10))}})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.selectable.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.selectable.js deleted file mode 100644 index 44c6e8c54e..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.selectable.js +++ /dev/null @@ -1,267 +0,0 @@ -/*! - * jQuery UI Selectable 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget("ui.selectable", $.ui.mouse, { - options: { - appendTo: 'body', - autoRefresh: true, - distance: 0, - filter: '*', - tolerance: 'touch' - }, - _create: function() { - var self = this; - - this.element.addClass("ui-selectable"); - - this.dragged = false; - - // cache selectee children based on filter - var selectees; - this.refresh = function() { - selectees = $(self.options.filter, self.element[0]); - selectees.addClass("ui-selectee"); - selectees.each(function() { - var $this = $(this); - var pos = $this.offset(); - $.data(this, "selectable-item", { - element: this, - $element: $this, - left: pos.left, - top: pos.top, - right: pos.left + $this.outerWidth(), - bottom: pos.top + $this.outerHeight(), - startselected: false, - selected: $this.hasClass('ui-selected'), - selecting: $this.hasClass('ui-selecting'), - unselecting: $this.hasClass('ui-unselecting') - }); - }); - }; - this.refresh(); - - this.selectees = selectees.addClass("ui-selectee"); - - this._mouseInit(); - - this.helper = $("
                    "); - }, - - destroy: function() { - this.selectees - .removeClass("ui-selectee") - .removeData("selectable-item"); - this.element - .removeClass("ui-selectable ui-selectable-disabled") - .removeData("selectable") - .unbind(".selectable"); - this._mouseDestroy(); - - return this; - }, - - _mouseStart: function(event) { - var self = this; - - this.opos = [event.pageX, event.pageY]; - - if (this.options.disabled) - return; - - var options = this.options; - - this.selectees = $(options.filter, this.element[0]); - - this._trigger("start", event); - - $(options.appendTo).append(this.helper); - // position helper (lasso) - this.helper.css({ - "left": event.clientX, - "top": event.clientY, - "width": 0, - "height": 0 - }); - - if (options.autoRefresh) { - this.refresh(); - } - - this.selectees.filter('.ui-selected').each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.startselected = true; - if (!event.metaKey && !event.ctrlKey) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - }); - - $(event.target).parents().andSelf().each(function() { - var selectee = $.data(this, "selectable-item"); - if (selectee) { - var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected'); - selectee.$element - .removeClass(doSelect ? "ui-unselecting" : "ui-selected") - .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); - selectee.unselecting = !doSelect; - selectee.selecting = doSelect; - selectee.selected = doSelect; - // selectable (UN)SELECTING callback - if (doSelect) { - self._trigger("selecting", event, { - selecting: selectee.element - }); - } else { - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - return false; - } - }); - - }, - - _mouseDrag: function(event) { - var self = this; - this.dragged = true; - - if (this.options.disabled) - return; - - var options = this.options; - - var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; - if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); - - this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"); - //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element == self.element[0]) - return; - var hit = false; - if (options.tolerance == 'touch') { - hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance == 'fit') { - hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); - } - - if (hit) { - // SELECT - if (selectee.selected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - } - if (selectee.unselecting) { - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - } - if (!selectee.selecting) { - selectee.$element.addClass('ui-selecting'); - selectee.selecting = true; - // selectable SELECTING callback - self._trigger("selecting", event, { - selecting: selectee.element - }); - } - } else { - // UNSELECT - if (selectee.selecting) { - if ((event.metaKey || event.ctrlKey) && selectee.startselected) { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - selectee.$element.addClass('ui-selected'); - selectee.selected = true; - } else { - selectee.$element.removeClass('ui-selecting'); - selectee.selecting = false; - if (selectee.startselected) { - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - } - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - if (selectee.selected) { - if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { - selectee.$element.removeClass('ui-selected'); - selectee.selected = false; - - selectee.$element.addClass('ui-unselecting'); - selectee.unselecting = true; - // selectable UNSELECTING callback - self._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - } - }); - - return false; - }, - - _mouseStop: function(event) { - var self = this; - - this.dragged = false; - - var options = this.options; - - $('.ui-unselecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-unselecting'); - selectee.unselecting = false; - selectee.startselected = false; - self._trigger("unselected", event, { - unselected: selectee.element - }); - }); - $('.ui-selecting', this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass('ui-selecting').addClass('ui-selected'); - selectee.selecting = false; - selectee.selected = true; - selectee.startselected = true; - self._trigger("selected", event, { - selected: selectee.element - }); - }); - this._trigger("stop", event); - - this.helper.remove(); - - return false; - } - -}); - -$.extend($.ui.selectable, { - version: "1.8.24" -}); - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.selectable.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.selectable.min.js deleted file mode 100644 index 10f96c04bb..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.selectable.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.selectable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.selectable",a.ui.mouse,{options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var b=this;this.element.addClass("ui-selectable"),this.dragged=!1;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]),c.addClass("ui-selectee"),c.each(function(){var b=a(this),c=b.offset();a.data(this,"selectable-item",{element:this,$element:b,left:c.left,top:c.top,right:c.left+b.outerWidth(),bottom:c.top+b.outerHeight(),startselected:!1,selected:b.hasClass("ui-selected"),selecting:b.hasClass("ui-selecting"),unselecting:b.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=c.addClass("ui-selectee"),this._mouseInit(),this.helper=a("
                    ")},destroy:function(){return this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable"),this._mouseDestroy(),this},_mouseStart:function(b){var c=this;this.opos=[b.pageX,b.pageY];if(this.options.disabled)return;var d=this.options;this.selectees=a(d.filter,this.element[0]),this._trigger("start",b),a(d.appendTo).append(this.helper),this.helper.css({left:b.clientX,top:b.clientY,width:0,height:0}),d.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var d=a.data(this,"selectable-item");d.startselected=!0,!b.metaKey&&!b.ctrlKey&&(d.$element.removeClass("ui-selected"),d.selected=!1,d.$element.addClass("ui-unselecting"),d.unselecting=!0,c._trigger("unselecting",b,{unselecting:d.element}))}),a(b.target).parents().andSelf().each(function(){var d=a.data(this,"selectable-item");if(d){var e=!b.metaKey&&!b.ctrlKey||!d.$element.hasClass("ui-selected");return d.$element.removeClass(e?"ui-unselecting":"ui-selected").addClass(e?"ui-selecting":"ui-unselecting"),d.unselecting=!e,d.selecting=e,d.selected=e,e?c._trigger("selecting",b,{selecting:d.element}):c._trigger("unselecting",b,{unselecting:d.element}),!1}})},_mouseDrag:function(b){var c=this;this.dragged=!0;if(this.options.disabled)return;var d=this.options,e=this.opos[0],f=this.opos[1],g=b.pageX,h=b.pageY;if(e>g){var i=g;g=e,e=i}if(f>h){var i=h;h=f,f=i}return this.helper.css({left:e,top:f,width:g-e,height:h-f}),this.selectees.each(function(){var i=a.data(this,"selectable-item");if(!i||i.element==c.element[0])return;var j=!1;d.tolerance=="touch"?j=!(i.left>g||i.righth||i.bottome&&i.rightf&&i.bottom" ) - .appendTo( this.element ) - .addClass( "ui-slider-range" + - // note: this isn't the most fittingly semantic framework class for this element, - // but worked best visually with a variety of themes - " ui-widget-header" + - ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) ); - } - - for ( var i = existingHandles.length; i < handleCount; i += 1 ) { - handles.push( handle ); - } - - this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( self.element ) ); - - this.handle = this.handles.eq( 0 ); - - this.handles.add( this.range ).filter( "a" ) - .click(function( event ) { - event.preventDefault(); - }) - .hover(function() { - if ( !o.disabled ) { - $( this ).addClass( "ui-state-hover" ); - } - }, function() { - $( this ).removeClass( "ui-state-hover" ); - }) - .focus(function() { - if ( !o.disabled ) { - $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" ); - $( this ).addClass( "ui-state-focus" ); - } else { - $( this ).blur(); - } - }) - .blur(function() { - $( this ).removeClass( "ui-state-focus" ); - }); - - this.handles.each(function( i ) { - $( this ).data( "index.ui-slider-handle", i ); - }); - - this.handles - .keydown(function( event ) { - var index = $( this ).data( "index.ui-slider-handle" ), - allowed, - curVal, - newVal, - step; - - if ( self.options.disabled ) { - return; - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - case $.ui.keyCode.END: - case $.ui.keyCode.PAGE_UP: - case $.ui.keyCode.PAGE_DOWN: - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - event.preventDefault(); - if ( !self._keySliding ) { - self._keySliding = true; - $( this ).addClass( "ui-state-active" ); - allowed = self._start( event, index ); - if ( allowed === false ) { - return; - } - } - break; - } - - step = self.options.step; - if ( self.options.values && self.options.values.length ) { - curVal = newVal = self.values( index ); - } else { - curVal = newVal = self.value(); - } - - switch ( event.keyCode ) { - case $.ui.keyCode.HOME: - newVal = self._valueMin(); - break; - case $.ui.keyCode.END: - newVal = self._valueMax(); - break; - case $.ui.keyCode.PAGE_UP: - newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.PAGE_DOWN: - newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) ); - break; - case $.ui.keyCode.UP: - case $.ui.keyCode.RIGHT: - if ( curVal === self._valueMax() ) { - return; - } - newVal = self._trimAlignValue( curVal + step ); - break; - case $.ui.keyCode.DOWN: - case $.ui.keyCode.LEFT: - if ( curVal === self._valueMin() ) { - return; - } - newVal = self._trimAlignValue( curVal - step ); - break; - } - - self._slide( event, index, newVal ); - }) - .keyup(function( event ) { - var index = $( this ).data( "index.ui-slider-handle" ); - - if ( self._keySliding ) { - self._keySliding = false; - self._stop( event, index ); - self._change( event, index ); - $( this ).removeClass( "ui-state-active" ); - } - - }); - - this._refreshValue(); - - this._animateOff = false; - }, - - destroy: function() { - this.handles.remove(); - this.range.remove(); - - this.element - .removeClass( "ui-slider" + - " ui-slider-horizontal" + - " ui-slider-vertical" + - " ui-slider-disabled" + - " ui-widget" + - " ui-widget-content" + - " ui-corner-all" ) - .removeData( "slider" ) - .unbind( ".slider" ); - - this._mouseDestroy(); - - return this; - }, - - _mouseCapture: function( event ) { - var o = this.options, - position, - normValue, - distance, - closestHandle, - self, - index, - allowed, - offset, - mouseOverHandle; - - if ( o.disabled ) { - return false; - } - - this.elementSize = { - width: this.element.outerWidth(), - height: this.element.outerHeight() - }; - this.elementOffset = this.element.offset(); - - position = { x: event.pageX, y: event.pageY }; - normValue = this._normValueFromMouse( position ); - distance = this._valueMax() - this._valueMin() + 1; - self = this; - this.handles.each(function( i ) { - var thisDistance = Math.abs( normValue - self.values(i) ); - if ( distance > thisDistance ) { - distance = thisDistance; - closestHandle = $( this ); - index = i; - } - }); - - // workaround for bug #3736 (if both handles of a range are at 0, - // the first is always used as the one with least distance, - // and moving it is obviously prevented by preventing negative ranges) - if( o.range === true && this.values(1) === o.min ) { - index += 1; - closestHandle = $( this.handles[index] ); - } - - allowed = this._start( event, index ); - if ( allowed === false ) { - return false; - } - this._mouseSliding = true; - - self._handleIndex = index; - - closestHandle - .addClass( "ui-state-active" ) - .focus(); - - offset = closestHandle.offset(); - mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" ); - this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { - left: event.pageX - offset.left - ( closestHandle.width() / 2 ), - top: event.pageY - offset.top - - ( closestHandle.height() / 2 ) - - ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - - ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + - ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) - }; - - if ( !this.handles.hasClass( "ui-state-hover" ) ) { - this._slide( event, index, normValue ); - } - this._animateOff = true; - return true; - }, - - _mouseStart: function( event ) { - return true; - }, - - _mouseDrag: function( event ) { - var position = { x: event.pageX, y: event.pageY }, - normValue = this._normValueFromMouse( position ); - - this._slide( event, this._handleIndex, normValue ); - - return false; - }, - - _mouseStop: function( event ) { - this.handles.removeClass( "ui-state-active" ); - this._mouseSliding = false; - - this._stop( event, this._handleIndex ); - this._change( event, this._handleIndex ); - - this._handleIndex = null; - this._clickOffset = null; - this._animateOff = false; - - return false; - }, - - _detectOrientation: function() { - this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; - }, - - _normValueFromMouse: function( position ) { - var pixelTotal, - pixelMouse, - percentMouse, - valueTotal, - valueMouse; - - if ( this.orientation === "horizontal" ) { - pixelTotal = this.elementSize.width; - pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); - } else { - pixelTotal = this.elementSize.height; - pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); - } - - percentMouse = ( pixelMouse / pixelTotal ); - if ( percentMouse > 1 ) { - percentMouse = 1; - } - if ( percentMouse < 0 ) { - percentMouse = 0; - } - if ( this.orientation === "vertical" ) { - percentMouse = 1 - percentMouse; - } - - valueTotal = this._valueMax() - this._valueMin(); - valueMouse = this._valueMin() + percentMouse * valueTotal; - - return this._trimAlignValue( valueMouse ); - }, - - _start: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - return this._trigger( "start", event, uiHash ); - }, - - _slide: function( event, index, newVal ) { - var otherVal, - newValues, - allowed; - - if ( this.options.values && this.options.values.length ) { - otherVal = this.values( index ? 0 : 1 ); - - if ( ( this.options.values.length === 2 && this.options.range === true ) && - ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) - ) { - newVal = otherVal; - } - - if ( newVal !== this.values( index ) ) { - newValues = this.values(); - newValues[ index ] = newVal; - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal, - values: newValues - } ); - otherVal = this.values( index ? 0 : 1 ); - if ( allowed !== false ) { - this.values( index, newVal, true ); - } - } - } else { - if ( newVal !== this.value() ) { - // A slide can be canceled by returning false from the slide callback - allowed = this._trigger( "slide", event, { - handle: this.handles[ index ], - value: newVal - } ); - if ( allowed !== false ) { - this.value( newVal ); - } - } - } - }, - - _stop: function( event, index ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "stop", event, uiHash ); - }, - - _change: function( event, index ) { - if ( !this._keySliding && !this._mouseSliding ) { - var uiHash = { - handle: this.handles[ index ], - value: this.value() - }; - if ( this.options.values && this.options.values.length ) { - uiHash.value = this.values( index ); - uiHash.values = this.values(); - } - - this._trigger( "change", event, uiHash ); - } - }, - - value: function( newValue ) { - if ( arguments.length ) { - this.options.value = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, 0 ); - return; - } - - return this._value(); - }, - - values: function( index, newValue ) { - var vals, - newValues, - i; - - if ( arguments.length > 1 ) { - this.options.values[ index ] = this._trimAlignValue( newValue ); - this._refreshValue(); - this._change( null, index ); - return; - } - - if ( arguments.length ) { - if ( $.isArray( arguments[ 0 ] ) ) { - vals = this.options.values; - newValues = arguments[ 0 ]; - for ( i = 0; i < vals.length; i += 1 ) { - vals[ i ] = this._trimAlignValue( newValues[ i ] ); - this._change( null, i ); - } - this._refreshValue(); - } else { - if ( this.options.values && this.options.values.length ) { - return this._values( index ); - } else { - return this.value(); - } - } - } else { - return this._values(); - } - }, - - _setOption: function( key, value ) { - var i, - valsLength = 0; - - if ( $.isArray( this.options.values ) ) { - valsLength = this.options.values.length; - } - - $.Widget.prototype._setOption.apply( this, arguments ); - - switch ( key ) { - case "disabled": - if ( value ) { - this.handles.filter( ".ui-state-focus" ).blur(); - this.handles.removeClass( "ui-state-hover" ); - this.handles.propAttr( "disabled", true ); - this.element.addClass( "ui-disabled" ); - } else { - this.handles.propAttr( "disabled", false ); - this.element.removeClass( "ui-disabled" ); - } - break; - case "orientation": - this._detectOrientation(); - this.element - .removeClass( "ui-slider-horizontal ui-slider-vertical" ) - .addClass( "ui-slider-" + this.orientation ); - this._refreshValue(); - break; - case "value": - this._animateOff = true; - this._refreshValue(); - this._change( null, 0 ); - this._animateOff = false; - break; - case "values": - this._animateOff = true; - this._refreshValue(); - for ( i = 0; i < valsLength; i += 1 ) { - this._change( null, i ); - } - this._animateOff = false; - break; - } - }, - - //internal value getter - // _value() returns value trimmed by min and max, aligned by step - _value: function() { - var val = this.options.value; - val = this._trimAlignValue( val ); - - return val; - }, - - //internal values getter - // _values() returns array of values trimmed by min and max, aligned by step - // _values( index ) returns single value trimmed by min and max, aligned by step - _values: function( index ) { - var val, - vals, - i; - - if ( arguments.length ) { - val = this.options.values[ index ]; - val = this._trimAlignValue( val ); - - return val; - } else { - // .slice() creates a copy of the array - // this copy gets trimmed by min and max and then returned - vals = this.options.values.slice(); - for ( i = 0; i < vals.length; i+= 1) { - vals[ i ] = this._trimAlignValue( vals[ i ] ); - } - - return vals; - } - }, - - // returns the step-aligned value that val is closest to, between (inclusive) min and max - _trimAlignValue: function( val ) { - if ( val <= this._valueMin() ) { - return this._valueMin(); - } - if ( val >= this._valueMax() ) { - return this._valueMax(); - } - var step = ( this.options.step > 0 ) ? this.options.step : 1, - valModStep = (val - this._valueMin()) % step, - alignValue = val - valModStep; - - if ( Math.abs(valModStep) * 2 >= step ) { - alignValue += ( valModStep > 0 ) ? step : ( -step ); - } - - // Since JavaScript has problems with large floats, round - // the final value to 5 digits after the decimal point (see #4124) - return parseFloat( alignValue.toFixed(5) ); - }, - - _valueMin: function() { - return this.options.min; - }, - - _valueMax: function() { - return this.options.max; - }, - - _refreshValue: function() { - var oRange = this.options.range, - o = this.options, - self = this, - animate = ( !this._animateOff ) ? o.animate : false, - valPercent, - _set = {}, - lastValPercent, - value, - valueMin, - valueMax; - - if ( this.options.values && this.options.values.length ) { - this.handles.each(function( i, j ) { - valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - if ( self.options.range === true ) { - if ( self.orientation === "horizontal" ) { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } else { - if ( i === 0 ) { - self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); - } - if ( i === 1 ) { - self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - lastValPercent = valPercent; - }); - } else { - value = this.value(); - valueMin = this._valueMin(); - valueMax = this._valueMax(); - valPercent = ( valueMax !== valueMin ) ? - ( value - valueMin ) / ( valueMax - valueMin ) * 100 : - 0; - _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; - this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); - - if ( oRange === "min" && this.orientation === "horizontal" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "horizontal" ) { - this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - if ( oRange === "min" && this.orientation === "vertical" ) { - this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); - } - if ( oRange === "max" && this.orientation === "vertical" ) { - this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); - } - } - } - -}); - -$.extend( $.ui.slider, { - version: "1.8.24" -}); - -}(jQuery)); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.slider.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.slider.min.js deleted file mode 100644 index 1836d967bd..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.slider.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.slider.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("
                    ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;ic&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.24"})})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.sortable.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.sortable.js deleted file mode 100644 index 9e0cac68e0..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.sortable.js +++ /dev/null @@ -1,1094 +0,0 @@ -/*! - * jQuery UI Sortable 1.8.24 - * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Sortables - * - * Depends: - * jquery.ui.core.js - * jquery.ui.mouse.js - * jquery.ui.widget.js - */ -(function( $, undefined ) { - -$.widget("ui.sortable", $.ui.mouse, { - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: 'auto', - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: '> *', - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000 - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true - - }, - - destroy: function() { - $.Widget.prototype.destroy.call( this ); - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) - this.items[i].item.removeData(this.widgetName + "-item"); - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget() - [ value ? "addClass" : "removeClass"]( "ui-sortable-disabled" ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type == 'static') return false; - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - var currentItem = null, self = this, nodes = $(event.target).parents().each(function() { - if($.data(this, that.widgetName + '-item') == self) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + '-item') == self) currentItem = $(event.target); - - if(!currentItem) return false; - if(this.options.handle && !overrideHandle) { - var validHandle = false; - - $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; }); - if(!validHandle) return false; - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var o = this.options, self = this; - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] != this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) - this._setContainment(); - - if(o.cursor) { // cursor option - if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor"); - $('body').css("cursor", o.cursor); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity"); - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex"); - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') - this.overflowOffset = this.scrollParent.offset(); - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) - this._cacheHelperProportions(); - - - //Post 'activate' events to possible containers - if(!noActivation) { - for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); } - } - - //Prepare possible droppables - if($.ui.ddmanager) - $.ui.ddmanager.current = this; - - if ($.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - var o = this.options, scrolled = false; - if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) - $.ui.ddmanager.prepareOffsets(this, event); - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px'; - if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px'; - - //Rearrange - for (var i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item); - if (!intersection) continue; - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) continue; - - if (itemElement != this.currentItem[0] //cannot intersect with itself - && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before - && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked - && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true) - //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container - ) { - - this.direction = intersection == 1 ? "down" : "up"; - - if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) $.ui.ddmanager.drag(this, event); - - //Call callbacks - this._trigger('sort', event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) return; - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) - $.ui.ddmanager.drop(this, event); - - if(this.options.revert) { - var self = this; - var cur = self.placeholder.offset(); - - self.reverting = true; - - $(this.helper).animate({ - left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft), - top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop) - }, parseInt(this.options.revert, 10) || 500, function() { - self._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - var self = this; - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper == "original") - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - else - this.currentItem.show(); - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, self._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, self._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove(); - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var str = []; o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/)); - if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2])); - }); - - if(!str.length && o.key) { - str.push(o.key + '='); - } - - return str.join('&'); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected); - var ret = []; o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height; - - var l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height; - - var dyClick = this.offset.click.top, - dxClick = this.offset.click.left; - - var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; - - if( this.options.tolerance == "pointer" - || this.options.forcePointerForContainers - || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height']) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) // Right Half - && x2 - (this.helperProportions.width / 2) < r // Left Half - && t < y1 + (this.helperProportions.height / 2) // Bottom Half - && y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === 'x') || $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === 'y') || $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) - return false; - - return this.floating ? - ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta != 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta != 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor == String - ? [options.connectWith] - : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var self = this; - var items = []; - var queries = []; - var connectWith = this._connectWith(); - - if(connectWith && connected) { - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], this.widgetName); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]); - } - }; - }; - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]); - - for (var i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - }; - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - for (var i=0; i < this.items.length; i++) { - - for (var j=0; j < list.length; j++) { - if(list[j] == this.items[i].item[0]) - this.items.splice(i,1); - }; - - }; - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - var items = this.items; - var self = this; - var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]]; - var connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (var i = connectWith.length - 1; i >= 0; i--){ - var cur = $(connectWith[i]); - for (var j = cur.length - 1; j >= 0; j--){ - var inst = $.data(cur[j], this.widgetName); - if(inst && inst != this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - }; - }; - } - - for (var i = queries.length - 1; i >= 0; i--) { - var targetData = queries[i][1]; - var _queries = queries[i][0]; - - for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) { - var item = $(_queries[j]); - - item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - }; - }; - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - for (var i = this.items.length - 1; i >= 0; i--){ - var item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0]) - continue; - - var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - var p = t.offset(); - item.left = p.left; - item.top = p.top; - }; - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (var i = this.containers.length - 1; i >= 0; i--){ - var p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - }; - } - - return this; - }, - - _createPlaceholder: function(that) { - - var self = that || this, o = self.options; - - if(!o.placeholder || o.placeholder.constructor == String) { - var className = o.placeholder; - o.placeholder = { - element: function() { - - var el = $(document.createElement(self.currentItem[0].nodeName)) - .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper")[0]; - - if(!className) - el.style.visibility = "hidden"; - - return el; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) return; - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); }; - if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); }; - } - }; - } - - //Create the placeholder - self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem)); - - //Append it after the actual current item - self.currentItem.after(self.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(self, self.placeholder); - - }, - - _contactContainers: function(event) { - - // get innermost container that intersects with item - var innermostContainer = null, innermostIndex = null; - - - for (var i = this.containers.length - 1; i >= 0; i--){ - - // never consider a container that's located within the item itself - if($.ui.contains(this.currentItem[0], this.containers[i].element[0])) - continue; - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0])) - continue; - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) return; - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } else if(this.currentContainer != this.containers[innermostIndex]) { - - //When entering a new container, we will find the item with the least distance and append our item near it - var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top']; - for (var j = this.items.length - 1; j >= 0; j--) { - if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue; - var cur = this.containers[innermostIndex].floating ? this.items[j].item.offset().left : this.items[j].item.offset().top; - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = (cur - base > 0) ? 'down' : 'up'; - } - } - - if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled - return; - - this.currentContainer = this.containers[innermostIndex]; - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options; - var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem); - - if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already - $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - - if(helper[0] == this.currentItem[0]) - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - - if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width()); - if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height()); - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj == 'string') { - obj = obj.split(' '); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ('left' in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ('right' in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ('top' in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ('bottom' in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information - || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix - po = { top: 0, left: 0 }; - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition == "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var o = this.options; - if(o.containment == 'parent') o.containment = this.helper[0].parentNode; - if(o.containment == 'document' || o.containment == 'window') this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - - if(!(/^(document|window|parent)$/).test(o.containment)) { - var ce = $(o.containment)[0]; - var co = $(o.containment).offset(); - var over = ($(ce).css("overflow") != 'hidden'); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) pos = this.position; - var mod = d == "absolute" ? 1 : -1; - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top // The absolute mouse position - + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left // The absolute mouse position - + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent - + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border) - - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - var pageX = event.pageX; - var pageY = event.pageY; - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left; - if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top; - if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left; - if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top; - } - - if(o.grid) { - var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY // The absolute mouse position - - this.offset.click.top // Click offset (relative to the element) - - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.top // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX // The absolute mouse position - - this.offset.click.left // Click offset (relative to the element) - - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent - - this.offset.parent.left // The offsetParent's offset without borders (offset + border) - + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var self = this, counter = this.counter; - - window.setTimeout(function() { - if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - },0); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var delayedTriggers = [], self = this; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem); - this._noFinalSort = null; - - if(this.helper[0] == this.currentItem[0]) { - for(var i in this._storedCSS) { - if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = ''; - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - //Post events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor - if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity - if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) this._trigger("beforeStop", event, this._uiHash()); - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null; - - if(!noPropagation) { - for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(inst) { - var self = inst || this; - return { - helper: self.helper, - placeholder: self.placeholder || $([]), - position: self.position, - originalPosition: self.originalPosition, - offset: self.positionAbs, - item: self.currentItem, - sender: inst ? inst.element : null - }; - } - -}); - -$.extend($.ui.sortable, { - version: "1.8.24" -}); - -})(jQuery); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.sortable.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.sortable.min.js deleted file mode 100644 index d302408781..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.sortable.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.sortable.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){a.widget("ui.sortable",a.ui.mouse,{widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var a=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?a.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},destroy:function(){a.Widget.prototype.destroy.call(this),this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var b=this.items.length-1;b>=0;b--)this.items[b].item.removeData(this.widgetName+"-item");return this},_setOption:function(b,c){b==="disabled"?(this.options[b]=c,this.widget()[c?"addClass":"removeClass"]("ui-sortable-disabled")):a.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(b,c){var d=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(b);var e=null,f=this,g=a(b.target).parents().each(function(){if(a.data(this,d.widgetName+"-item")==f)return e=a(this),!1});a.data(b.target,d.widgetName+"-item")==f&&(e=a(b.target));if(!e)return!1;if(this.options.handle&&!c){var h=!1;a(this.options.handle,e).find("*").andSelf().each(function(){this==b.target&&(h=!0)});if(!h)return!1}return this.currentItem=e,this._removeCurrentsFromItems(),!0},_mouseStart:function(b,c,d){var e=this.options,f=this;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(b),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(b),this.originalPageX=b.pageX,this.originalPageY=b.pageY,e.cursorAt&&this._adjustOffsetFromHelper(e.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),e.containment&&this._setContainment(),e.cursor&&(a("body").css("cursor")&&(this._storedCursor=a("body").css("cursor")),a("body").css("cursor",e.cursor)),e.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",e.opacity)),e.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",e.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",b,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!d)for(var g=this.containers.length-1;g>=0;g--)this.containers[g]._trigger("activate",b,f._uiHash(this));return a.ui.ddmanager&&(a.ui.ddmanager.current=this),a.ui.ddmanager&&!e.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,b),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(b),!0},_mouseDrag:function(b){this.position=this._generatePosition(b),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var c=this.options,d=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-b.pageY=0;e--){var f=this.items[e],g=f.item[0],h=this._intersectsWithPointer(f);if(!h)continue;if(f.instance!==this.currentContainer)continue;if(g!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=g&&!a.ui.contains(this.placeholder[0],g)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],g):!0)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(f))this._rearrange(b,f);else break;this._trigger("change",b,this._uiHash());break}}return this._contactContainers(b),a.ui.ddmanager&&a.ui.ddmanager.drag(this,b),this._trigger("sort",b,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(b,c){if(!b)return;a.ui.ddmanager&&!this.options.dropBehaviour&&a.ui.ddmanager.drop(this,b);if(this.options.revert){var d=this,e=d.placeholder.offset();d.reverting=!0,a(this.helper).animate({left:e.left-this.offset.parent.left-d.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-d.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){d._clear(b)})}else this._clear(b,c);return!1},cancel:function(){var b=this;if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("deactivate",null,b._uiHash(this)),this.containers[c].containerCache.over&&(this.containers[c]._trigger("out",null,b._uiHash(this)),this.containers[c].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),a.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?a(this.domPosition.prev).after(this.currentItem):a(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},a(c).each(function(){var c=(a(b.item||this).attr(b.attribute||"id")||"").match(b.expression||/(.+)[-=_](.+)/);c&&d.push((b.key||c[1]+"[]")+"="+(b.key&&b.expression?c[1]:c[2]))}),!d.length&&b.key&&d.push(b.key+"="),d.join("&")},toArray:function(b){var c=this._getItemsAsjQuery(b&&b.connected),d=[];return b=b||{},c.each(function(){d.push(a(b.item||this).attr(b.attribute||"id")||"")}),d},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,d=this.positionAbs.top,e=d+this.helperProportions.height,f=a.left,g=f+a.width,h=a.top,i=h+a.height,j=this.offset.click.top,k=this.offset.click.left,l=d+j>h&&d+jf&&b+ka[this.floating?"width":"height"]?l:f0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){return this._refreshItems(a),this.refreshPositions(),this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(b){var c=this,d=[],e=[],f=this._connectWith();if(f&&b)for(var g=f.length-1;g>=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&e.push([a.isFunction(j.options.items)?j.options.items.call(j.element):a(j.options.items,j.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),j])}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var g=e.length-1;g>=0;g--)e[g][0].each(function(){d.push(this)});return a(d)},_removeCurrentsFromItems:function(){var a=this.currentItem.find(":data("+this.widgetName+"-item)");for(var b=0;b=0;g--){var h=a(f[g]);for(var i=h.length-1;i>=0;i--){var j=a.data(h[i],this.widgetName);j&&j!=this&&!j.options.disabled&&(e.push([a.isFunction(j.options.items)?j.options.items.call(j.element[0],b,{item:this.currentItem}):a(j.options.items,j.element),j]),this.containers.push(j))}}for(var g=e.length-1;g>=0;g--){var k=e[g][1],l=e[g][0];for(var i=0,m=l.length;i=0;c--){var d=this.items[c];if(d.instance!=this.currentContainer&&this.currentContainer&&d.item[0]!=this.currentItem[0])continue;var e=this.options.toleranceElement?a(this.options.toleranceElement,d.item):d.item;b||(d.width=e.outerWidth(),d.height=e.outerHeight());var f=e.offset();d.left=f.left,d.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var c=this.containers.length-1;c>=0;c--){var f=this.containers[c].element.offset();this.containers[c].containerCache.left=f.left,this.containers[c].containerCache.top=f.top,this.containers[c].containerCache.width=this.containers[c].element.outerWidth(),this.containers[c].containerCache.height=this.containers[c].element.outerHeight()}return this},_createPlaceholder:function(b){var c=b||this,d=c.options;if(!d.placeholder||d.placeholder.constructor==String){var e=d.placeholder;d.placeholder={element:function(){var b=a(document.createElement(c.currentItem[0].nodeName)).addClass(e||c.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return e||(b.style.visibility="hidden"),b},update:function(a,b){if(e&&!d.forcePlaceholderSize)return;b.height()||b.height(c.currentItem.innerHeight()-parseInt(c.currentItem.css("paddingTop")||0,10)-parseInt(c.currentItem.css("paddingBottom")||0,10)),b.width()||b.width(c.currentItem.innerWidth()-parseInt(c.currentItem.css("paddingLeft")||0,10)-parseInt(c.currentItem.css("paddingRight")||0,10))}}}c.placeholder=a(d.placeholder.element.call(c.element,c.currentItem)),c.currentItem.after(c.placeholder),d.placeholder.update(c,c.placeholder)},_contactContainers:function(b){var c=null,d=null;for(var e=this.containers.length-1;e>=0;e--){if(a.ui.contains(this.currentItem[0],this.containers[e].element[0]))continue;if(this._intersectsWith(this.containers[e].containerCache)){if(c&&a.ui.contains(this.containers[e].element[0],c.element[0]))continue;c=this.containers[e],d=e}else this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",b,this._uiHash(this)),this.containers[e].containerCache.over=0)}if(!c)return;if(this.containers.length===1)this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1;else if(this.currentContainer!=this.containers[d]){var f=1e4,g=null,h=this.positionAbs[this.containers[d].floating?"left":"top"];for(var i=this.items.length-1;i>=0;i--){if(!a.ui.contains(this.containers[d].element[0],this.items[i].item[0]))continue;var j=this.containers[d].floating?this.items[i].item.offset().left:this.items[i].item.offset().top;Math.abs(j-h)0?"down":"up")}if(!g&&!this.options.dropOnEmpty)return;this.currentContainer=this.containers[d],g?this._rearrange(b,g,null,!0):this._rearrange(b,null,this.containers[d].element,!0),this._trigger("change",b,this._uiHash()),this.containers[d]._trigger("change",b,this._uiHash(this)),this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[d]._trigger("over",b,this._uiHash(this)),this.containers[d].containerCache.over=1}},_createHelper:function(b){var c=this.options,d=a.isFunction(c.helper)?a(c.helper.apply(this.element[0],[b,this.currentItem])):c.helper=="clone"?this.currentItem.clone():this.currentItem;return d.parents("body").length||a(c.appendTo!="parent"?c.appendTo:this.currentItem[0].parentNode)[0].appendChild(d[0]),d[0]==this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(d[0].style.width==""||c.forceHelperSize)&&d.width(this.currentItem.width()),(d[0].style.height==""||c.forceHelperSize)&&d.height(this.currentItem.height()),d},_adjustOffsetFromHelper:function(b){typeof b=="string"&&(b=b.split(" ")),a.isArray(b)&&(b={left:+b[0],top:+b[1]||0}),"left"in b&&(this.offset.click.left=b.left+this.margins.left),"right"in b&&(this.offset.click.left=this.helperProportions.width-b.right+this.margins.left),"top"in b&&(this.offset.click.top=b.top+this.margins.top),"bottom"in b&&(this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(b.left+=this.scrollParent.scrollLeft(),b.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)b={top:0,left:0};return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var b=this.options;b.containment=="parent"&&(b.containment=this.helper[0].parentNode);if(b.containment=="document"||b.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(b.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(b.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(b.containment)){var c=a(b.containment)[0],d=a(b.containment).offset(),e=a(c).css("overflow")!="hidden";this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(e?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(e?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(b,c){c||(c=this.position);var d=b=="absolute"?1:-1,e=this.options,f=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=/(html|body)/i.test(f[0].tagName);return{top:c.top+this.offset.relative.top*d+this.offset.parent.top*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():g?0:f.scrollTop())*d),left:c.left+this.offset.relative.left*d+this.offset.parent.left*d-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:f.scrollLeft())*d)}},_generatePosition:function(b){var c=this.options,d=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(d[0].tagName);this.cssPosition=="relative"&&(this.scrollParent[0]==document||this.scrollParent[0]==this.offsetParent[0])&&(this.offset.relative=this._getRelativeOffset());var f=b.pageX,g=b.pageY;if(this.originalPosition){this.containment&&(b.pageX-this.offset.click.leftthis.containment[2]&&(f=this.containment[2]+this.offset.click.left),b.pageY-this.offset.click.top>this.containment[3]&&(g=this.containment[3]+this.offset.click.top));if(c.grid){var h=this.originalPageY+Math.round((g-this.originalPageY)/c.grid[1])*c.grid[1];g=this.containment?h-this.offset.click.topthis.containment[3]?h-this.offset.click.topthis.containment[2]?i-this.offset.click.left=0;f--)c||d.push(function(a){return function(b){a._trigger("deactivate",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over&&(d.push(function(a){return function(b){a._trigger("out",b,this._uiHash(this))}}.call(this,this.containers[f])),this.containers[f].containerCache.over=0);this._storedCursor&&a("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!c){this._trigger("beforeStop",b,this._uiHash());for(var f=0;f", - remove: null, - select: null, - show: null, - spinner: "Loading…", - tabTemplate: "
                  • #{label}
                  • " - }, - - _create: function() { - this._tabify( true ); - }, - - _setOption: function( key, value ) { - if ( key == "selected" ) { - if (this.options.collapsible && value == this.options.selected ) { - return; - } - this.select( value ); - } else { - this.options[ key ] = value; - this._tabify(); - } - }, - - _tabId: function( a ) { - return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || - this.options.idPrefix + getNextTabId(); - }, - - _sanitizeSelector: function( hash ) { - // we need this because an id may contain a ":" - return hash.replace( /:/g, "\\:" ); - }, - - _cookie: function() { - var cookie = this.cookie || - ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); - return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); - }, - - _ui: function( tab, panel ) { - return { - tab: tab, - panel: panel, - index: this.anchors.index( tab ) - }; - }, - - _cleanup: function() { - // restore all former loading tabs labels - this.lis.filter( ".ui-state-processing" ) - .removeClass( "ui-state-processing" ) - .find( "span:data(label.tabs)" ) - .each(function() { - var el = $( this ); - el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" ); - }); - }, - - _tabify: function( init ) { - var self = this, - o = this.options, - fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash - - this.list = this.element.find( "ol,ul" ).eq( 0 ); - this.lis = $( " > li:has(a[href])", this.list ); - this.anchors = this.lis.map(function() { - return $( "a", this )[ 0 ]; - }); - this.panels = $( [] ); - - this.anchors.each(function( i, a ) { - var href = $( a ).attr( "href" ); - // For dynamically created HTML that contains a hash as href IE < 8 expands - // such href to the full page url with hash and then misinterprets tab as ajax. - // Same consideration applies for an added tab with a fragment identifier - // since a[href=#fragment-identifier] does unexpectedly not match. - // Thus normalize href attribute... - var hrefBase = href.split( "#" )[ 0 ], - baseEl; - if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] || - ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) { - href = a.hash; - a.href = href; - } - - // inline tab - if ( fragmentId.test( href ) ) { - self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) ); - // remote tab - // prevent loading the page itself if href is just "#" - } else if ( href && href !== "#" ) { - // required for restore on destroy - $.data( a, "href.tabs", href ); - - // TODO until #3808 is fixed strip fragment identifier from url - // (IE fails to load from such url) - $.data( a, "load.tabs", href.replace( /#.*$/, "" ) ); - - var id = self._tabId( a ); - a.href = "#" + id; - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .insertAfter( self.panels[ i - 1 ] || self.list ); - $panel.data( "destroy.tabs", true ); - } - self.panels = self.panels.add( $panel ); - // invalid tab href - } else { - o.disabled.push( i ); - } - }); - - // initialization from scratch - if ( init ) { - // attach necessary classes for styling - this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); - this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); - this.lis.addClass( "ui-state-default ui-corner-top" ); - this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); - - // Selected tab - // use "selected" option or try to retrieve: - // 1. from fragment identifier in url - // 2. from cookie - // 3. from selected class attribute on
                  • - if ( o.selected === undefined ) { - if ( location.hash ) { - this.anchors.each(function( i, a ) { - if ( a.hash == location.hash ) { - o.selected = i; - return false; - } - }); - } - if ( typeof o.selected !== "number" && o.cookie ) { - o.selected = parseInt( self._cookie(), 10 ); - } - if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); - } - o.selected = o.selected || ( this.lis.length ? 0 : -1 ); - } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release - o.selected = -1; - } - - // sanity check - default to first tab... - o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) - ? o.selected - : 0; - - // Take disabling tabs via class attribute from HTML - // into account and update option properly. - // A selected tab cannot become disabled. - o.disabled = $.unique( o.disabled.concat( - $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { - return self.lis.index( n ); - }) - ) ).sort(); - - if ( $.inArray( o.selected, o.disabled ) != -1 ) { - o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 ); - } - - // highlight selected tab - this.panels.addClass( "ui-tabs-hide" ); - this.lis.removeClass( "ui-tabs-selected ui-state-active" ); - // check for length avoids error when initializing empty list - if ( o.selected >= 0 && this.anchors.length ) { - self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" ); - this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); - - // seems to be expected behavior that the show callback is fired - self.element.queue( "tabs", function() { - self._trigger( "show", null, - self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); - }); - - this.load( o.selected ); - } - - // clean up to avoid memory leaks in certain versions of IE 6 - // TODO: namespace this event - $( window ).bind( "unload", function() { - self.lis.add( self.anchors ).unbind( ".tabs" ); - self.lis = self.anchors = self.panels = null; - }); - // update selected after add/remove - } else { - o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); - } - - // update collapsible - // TODO: use .toggleClass() - this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" ); - - // set or update cookie after init and add/remove respectively - if ( o.cookie ) { - this._cookie( o.selected, o.cookie ); - } - - // disable tabs - for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { - $( li )[ $.inArray( i, o.disabled ) != -1 && - // TODO: use .toggleClass() - !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" ); - } - - // reset cache if switching from cached to not cached - if ( o.cache === false ) { - this.anchors.removeData( "cache.tabs" ); - } - - // remove all handlers before, tabify may run on existing tabs after add or option change - this.lis.add( this.anchors ).unbind( ".tabs" ); - - if ( o.event !== "mouseover" ) { - var addState = function( state, el ) { - if ( el.is( ":not(.ui-state-disabled)" ) ) { - el.addClass( "ui-state-" + state ); - } - }; - var removeState = function( state, el ) { - el.removeClass( "ui-state-" + state ); - }; - this.lis.bind( "mouseover.tabs" , function() { - addState( "hover", $( this ) ); - }); - this.lis.bind( "mouseout.tabs", function() { - removeState( "hover", $( this ) ); - }); - this.anchors.bind( "focus.tabs", function() { - addState( "focus", $( this ).closest( "li" ) ); - }); - this.anchors.bind( "blur.tabs", function() { - removeState( "focus", $( this ).closest( "li" ) ); - }); - } - - // set up animations - var hideFx, showFx; - if ( o.fx ) { - if ( $.isArray( o.fx ) ) { - hideFx = o.fx[ 0 ]; - showFx = o.fx[ 1 ]; - } else { - hideFx = showFx = o.fx; - } - } - - // Reset certain styles left over from animation - // and prevent IE's ClearType bug... - function resetStyle( $el, fx ) { - $el.css( "display", "" ); - if ( !$.support.opacity && fx.opacity ) { - $el[ 0 ].style.removeAttribute( "filter" ); - } - } - - // Show a tab... - var showTab = showFx - ? function( clicked, $show ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way - .animate( showFx, showFx.duration || "normal", function() { - resetStyle( $show, showFx ); - self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); - }); - } - : function( clicked, $show ) { - $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); - $show.removeClass( "ui-tabs-hide" ); - self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); - }; - - // Hide a tab, $show is optional... - var hideTab = hideFx - ? function( clicked, $hide ) { - $hide.animate( hideFx, hideFx.duration || "normal", function() { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); - resetStyle( $hide, hideFx ); - self.element.dequeue( "tabs" ); - }); - } - : function( clicked, $hide, $show ) { - self.lis.removeClass( "ui-tabs-selected ui-state-active" ); - $hide.addClass( "ui-tabs-hide" ); - self.element.dequeue( "tabs" ); - }; - - // attach tab event handler, unbind to avoid duplicates from former tabifying... - this.anchors.bind( o.event + ".tabs", function() { - var el = this, - $li = $(el).closest( "li" ), - $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), - $show = self.element.find( self._sanitizeSelector( el.hash ) ); - - // If tab is already selected and not collapsible or tab disabled or - // or is already loading or click callback returns false stop here. - // Check if click handler returns false last so that it is not executed - // for a disabled or loading tab! - if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || - $li.hasClass( "ui-state-disabled" ) || - $li.hasClass( "ui-state-processing" ) || - self.panels.filter( ":animated" ).length || - self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) { - this.blur(); - return false; - } - - o.selected = self.anchors.index( this ); - - self.abort(); - - // if tab may be closed - if ( o.collapsible ) { - if ( $li.hasClass( "ui-tabs-selected" ) ) { - o.selected = -1; - - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } - - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }).dequeue( "tabs" ); - - this.blur(); - return false; - } else if ( !$hide.length ) { - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } - - self.element.queue( "tabs", function() { - showTab( el, $show ); - }); - - // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 - self.load( self.anchors.index( this ) ); - - this.blur(); - return false; - } - } - - if ( o.cookie ) { - self._cookie( o.selected, o.cookie ); - } - - // show new tab - if ( $show.length ) { - if ( $hide.length ) { - self.element.queue( "tabs", function() { - hideTab( el, $hide ); - }); - } - self.element.queue( "tabs", function() { - showTab( el, $show ); - }); - - self.load( self.anchors.index( this ) ); - } else { - throw "jQuery UI Tabs: Mismatching fragment identifier."; - } - - // Prevent IE from keeping other link focussed when using the back button - // and remove dotted border from clicked link. This is controlled via CSS - // in modern browsers; blur() removes focus from address bar in Firefox - // which can become a usability and annoying problem with tabs('rotate'). - if ( $.browser.msie ) { - this.blur(); - } - }); - - // disable click in any case - this.anchors.bind( "click.tabs", function(){ - return false; - }); - }, - - _getIndex: function( index ) { - // meta-function to give users option to provide a href string instead of a numerical index. - // also sanitizes numerical indexes to valid values. - if ( typeof index == "string" ) { - index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); - } - - return index; - }, - - destroy: function() { - var o = this.options; - - this.abort(); - - this.element - .unbind( ".tabs" ) - .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ) - .removeData( "tabs" ); - - this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); - - this.anchors.each(function() { - var href = $.data( this, "href.tabs" ); - if ( href ) { - this.href = href; - } - var $this = $( this ).unbind( ".tabs" ); - $.each( [ "href", "load", "cache" ], function( i, prefix ) { - $this.removeData( prefix + ".tabs" ); - }); - }); - - this.lis.unbind( ".tabs" ).add( this.panels ).each(function() { - if ( $.data( this, "destroy.tabs" ) ) { - $( this ).remove(); - } else { - $( this ).removeClass([ - "ui-state-default", - "ui-corner-top", - "ui-tabs-selected", - "ui-state-active", - "ui-state-hover", - "ui-state-focus", - "ui-state-disabled", - "ui-tabs-panel", - "ui-widget-content", - "ui-corner-bottom", - "ui-tabs-hide" - ].join( " " ) ); - } - }); - - if ( o.cookie ) { - this._cookie( null, o.cookie ); - } - - return this; - }, - - add: function( url, label, index ) { - if ( index === undefined ) { - index = this.anchors.length; - } - - var self = this, - o = this.options, - $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), - id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); - - $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); - - // try to find an existing element before creating a new one - var $panel = self.element.find( "#" + id ); - if ( !$panel.length ) { - $panel = $( o.panelTemplate ) - .attr( "id", id ) - .data( "destroy.tabs", true ); - } - $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); - - if ( index >= this.lis.length ) { - $li.appendTo( this.list ); - $panel.appendTo( this.list[ 0 ].parentNode ); - } else { - $li.insertBefore( this.lis[ index ] ); - $panel.insertBefore( this.panels[ index ] ); - } - - o.disabled = $.map( o.disabled, function( n, i ) { - return n >= index ? ++n : n; - }); - - this._tabify(); - - if ( this.anchors.length == 1 ) { - o.selected = 0; - $li.addClass( "ui-tabs-selected ui-state-active" ); - $panel.removeClass( "ui-tabs-hide" ); - this.element.queue( "tabs", function() { - self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); - }); - - this.load( 0 ); - } - - this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; - }, - - remove: function( index ) { - index = this._getIndex( index ); - var o = this.options, - $li = this.lis.eq( index ).remove(), - $panel = this.panels.eq( index ).remove(); - - // If selected tab was removed focus tab to the right or - // in case the last tab was removed the tab to the left. - if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { - this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); - } - - o.disabled = $.map( - $.grep( o.disabled, function(n, i) { - return n != index; - }), - function( n, i ) { - return n >= index ? --n : n; - }); - - this._tabify(); - - this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); - return this; - }, - - enable: function( index ) { - index = this._getIndex( index ); - var o = this.options; - if ( $.inArray( index, o.disabled ) == -1 ) { - return; - } - - this.lis.eq( index ).removeClass( "ui-state-disabled" ); - o.disabled = $.grep( o.disabled, function( n, i ) { - return n != index; - }); - - this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - return this; - }, - - disable: function( index ) { - index = this._getIndex( index ); - var self = this, o = this.options; - // cannot disable already selected tab - if ( index != o.selected ) { - this.lis.eq( index ).addClass( "ui-state-disabled" ); - - o.disabled.push( index ); - o.disabled.sort(); - - this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); - } - - return this; - }, - - select: function( index ) { - index = this._getIndex( index ); - if ( index == -1 ) { - if ( this.options.collapsible && this.options.selected != -1 ) { - index = this.options.selected; - } else { - return this; - } - } - this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); - return this; - }, - - load: function( index ) { - index = this._getIndex( index ); - var self = this, - o = this.options, - a = this.anchors.eq( index )[ 0 ], - url = $.data( a, "load.tabs" ); - - this.abort(); - - // not remote or from cache - if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) { - this.element.dequeue( "tabs" ); - return; - } - - // load remote from here on - this.lis.eq( index ).addClass( "ui-state-processing" ); - - if ( o.spinner ) { - var span = $( "span", a ); - span.data( "label.tabs", span.html() ).html( o.spinner ); - } - - this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, { - url: url, - success: function( r, s ) { - self.element.find( self._sanitizeSelector( a.hash ) ).html( r ); - - // take care of tab labels - self._cleanup(); - - if ( o.cache ) { - $.data( a, "cache.tabs", true ); - } - - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - o.ajaxOptions.success( r, s ); - } - catch ( e ) {} - }, - error: function( xhr, s, e ) { - // take care of tab labels - self._cleanup(); - - self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - o.ajaxOptions.error( xhr, s, index, a ); - } - catch ( e ) {} - } - } ) ); - - // last, so that load event is fired before show... - self.element.dequeue( "tabs" ); - - return this; - }, - - abort: function() { - // stop possibly running animations - this.element.queue( [] ); - this.panels.stop( false, true ); - - // "tabs" queue must not contain more than two elements, - // which are the callbacks for the latest clicked tab... - this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) ); - - // terminate pending requests from other tabs - if ( this.xhr ) { - this.xhr.abort(); - delete this.xhr; - } - - // take care of tab labels - this._cleanup(); - return this; - }, - - url: function( index, url ) { - this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url ); - return this; - }, - - length: function() { - return this.anchors.length; - } -}); - -$.extend( $.ui.tabs, { - version: "1.8.24" -}); - -/* - * Tabs Extensions - */ - -/* - * Rotate - */ -$.extend( $.ui.tabs.prototype, { - rotation: null, - rotate: function( ms, continuing ) { - var self = this, - o = this.options; - - var rotate = self._rotate || ( self._rotate = function( e ) { - clearTimeout( self.rotation ); - self.rotation = setTimeout(function() { - var t = o.selected; - self.select( ++t < self.anchors.length ? t : 0 ); - }, ms ); - - if ( e ) { - e.stopPropagation(); - } - }); - - var stop = self._unrotate || ( self._unrotate = !continuing - ? function(e) { - if (e.clientX) { // in case of a true click - self.rotate(null); - } - } - : function( e ) { - rotate(); - }); - - // start rotation - if ( ms ) { - this.element.bind( "tabsshow", rotate ); - this.anchors.bind( o.event + ".tabs", stop ); - rotate(); - // stop rotation - } else { - clearTimeout( self.rotation ); - this.element.unbind( "tabsshow", rotate ); - this.anchors.unbind( o.event + ".tabs", stop ); - delete this._rotate; - delete this._unrotate; - } - - return this; - } -}); - -})( jQuery ); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.tabs.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.tabs.min.js deleted file mode 100644 index 3cfd65af18..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/jquery.ui.tabs.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! jQuery UI - v1.8.24 - 2012-09-28 -* https://github.com/jquery/jquery-ui -* Includes: jquery.ui.tabs.js -* Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ -(function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
                    ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
                  • #{label}
                  • "},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.24"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a
                    " ), + innerDiv = div.children()[0]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[0].clientWidth; + } + + div.remove(); + + return (cachedScrollbarWidth = w1 - w2); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-x" ), + overflowY = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; + return { + element: withinElement, + isWindow: isWindow, + isDocument: isDocument, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: isWindow ? withinElement.width() : withinElement.outerWidth(), + height: isWindow ? withinElement.height() : withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + // if the browser doesn't support fractions, then round for consistent results + if ( !supportsOffsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); + } + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem: elem + }); + } + }); + + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { + position.top += myOffset + atOffset + offset; + } + } else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +// fraction support test +(function() { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +})(); + +return $.ui.position; + +})); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery-ui/widget.js b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/widget.js new file mode 100644 index 0000000000..53f4757a58 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Scripts/jquery-ui/widget.js @@ -0,0 +1,543 @@ +/*! + * jQuery UI Widget 1.11.0 + * http://jqueryui.com + * + * Copyright 2014 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/jQuery.widget/ + */ +(function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "jquery" ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +}(function( $ ) { + +var widget_uuid = 0, + widget_slice = Array.prototype.slice; + +$.cleanData = (function( orig ) { + return function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + orig( elems ); + }; +})( $.cleanData ); + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); + + return constructor; +}; + +$.widget.extend = function( target ) { + var input = widget_slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = widget_slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.widget.extend.apply( null, [ options ].concat(args) ) : + options; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( options === "instance" ) { + returnValue = instance; + return false; + } + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
                    ", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = widget_uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled", !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + } + + return this; + }, + + enable: function() { + return this._setOptions({ disabled: false }); + }, + disable: function() { + return this._setOptions({ disabled: true }); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^([\w:-]*)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +return $.widget; + +})); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery.pnotify.js b/src/Presentation/SmartStore.Web/Scripts/jquery.pnotify.js index 82ce002561..78f20a8045 100644 --- a/src/Presentation/SmartStore.Web/Scripts/jquery.pnotify.js +++ b/src/Presentation/SmartStore.Web/Scripts/jquery.pnotify.js @@ -38,20 +38,20 @@ bootstrap: { container: "alert", notice: "", - notice_icon: "icon-exclamation-sign", + notice_icon: "fa fa-exclamation", info: "alert-info", - info_icon: "icon-info-sign", + info_icon: "fa fa-info", success: "alert-success", - success_icon: "icon-ok-sign", - error: "alert-error", - error_icon: "icon-warning-sign", - closer: "icon-remove", - pin_up: "icon-pause", - pin_down: "icon-play", + success_icon: "fa fa-check", + error: "alert-error alert-danger", + error_icon: "fa fa-exclamation-triangle", + closer: "fa fa-times", + pin_up: "fa fa-thumb-tack fa-rotate-90", + pin_down: "fa fa-thumb-tack", hi_menu: "well", hi_btn: "btn", hi_btnhov: "", - hi_hnd: "icon-chevron-down" + hi_hnd: "fa fa-chevron-down" } }; // Set global variables. diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery.pnotify.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery.pnotify.min.js deleted file mode 100644 index 6101753928..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/jquery.pnotify.min.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * jQuery Pines Notify (pnotify) Plugin 1.2.2 - * - * http://pinesframework.org/pnotify/ - * Copyright (c) 2009-2012 Hunter Perrin - * - * Triple license under the GPL, LGPL, and MPL: - * http://www.gnu.org/licenses/gpl.html - * http://www.gnu.org/licenses/lgpl.html - * http://www.mozilla.org/MPL/MPL-1.1.html - */ -(function(d){var q,j,r,i=d(window),u={jqueryui:{container:"ui-widget ui-widget-content ui-corner-all",notice:"ui-state-highlight",notice_icon:"ui-icon ui-icon-info",info:"",info_icon:"ui-icon ui-icon-info",success:"ui-state-default",success_icon:"ui-icon ui-icon-circle-check",error:"ui-state-error",error_icon:"ui-icon ui-icon-alert",closer:"ui-icon ui-icon-close",pin_up:"ui-icon ui-icon-pin-w",pin_down:"ui-icon ui-icon-pin-s",hi_menu:"ui-state-default ui-corner-bottom",hi_btn:"ui-state-default ui-corner-all", -hi_btnhov:"ui-state-hover",hi_hnd:"ui-icon ui-icon-grip-dotted-horizontal"},bootstrap:{container:"alert",notice:"",notice_icon:"icon-exclamation-sign",info:"alert-info",info_icon:"icon-info-sign",success:"alert-success",success_icon:"icon-ok-sign",error:"alert-error",error_icon:"icon-warning-sign",closer:"icon-remove",pin_up:"icon-pause",pin_down:"icon-play",hi_menu:"well",hi_btn:"btn",hi_btnhov:"",hi_hnd:"icon-chevron-down"}},s=function(){r=d("body");i=d(window);i.bind("resize",function(){j&&clearTimeout(j); -j=setTimeout(d.pnotify_position_all,10)})};document.body?s():d(s);d.extend({pnotify_remove_all:function(){var e=i.data("pnotify");e&&e.length&&d.each(e,function(){this.pnotify_remove&&this.pnotify_remove()})},pnotify_position_all:function(){j&&clearTimeout(j);j=null;var e=i.data("pnotify");e&&e.length&&(d.each(e,function(){var d=this.opts.stack;if(d)d.nextpos1=d.firstpos1,d.nextpos2=d.firstpos2,d.addpos2=0,d.animation=true}),d.each(e,function(){this.pnotify_position()}))},pnotify:function(e){var g, -a;typeof e!="object"?(a=d.extend({},d.pnotify.defaults),a.text=e):a=d.extend({},d.pnotify.defaults,e);for(var p in a)typeof p=="string"&&p.match(/^pnotify_/)&&(a[p.replace(/^pnotify_/,"")]=a[p]);if(a.before_init&&a.before_init(a)===false)return null;var k,o=function(a,c){b.css("display","none");var f=document.elementFromPoint(a.clientX,a.clientY);b.css("display","block");var e=d(f),g=e.css("cursor");b.css("cursor",g!="auto"?g:"default");if(!k||k.get(0)!=f)k&&(n.call(k.get(0),"mouseleave",a.originalEvent), -n.call(k.get(0),"mouseout",a.originalEvent)),n.call(f,"mouseenter",a.originalEvent),n.call(f,"mouseover",a.originalEvent);n.call(f,c,a.originalEvent);k=e},f=u[a.styling],b=d("
                    ",{"class":"ui-pnotify "+a.addclass,css:{display:"none"},mouseenter:function(l){a.nonblock&&l.stopPropagation();a.mouse_reset&&g=="out"&&(b.stop(true),g="in",b.css("height","auto").animate({width:a.width,opacity:a.nonblock?a.nonblock_opacity:a.opacity},"fast"));a.nonblock&&b.animate({opacity:a.nonblock_opacity},"fast"); -a.hide&&a.mouse_reset&&b.pnotify_cancel_remove();a.sticker&&!a.nonblock&&b.sticker.trigger("pnotify_icon").css("visibility","visible");a.closer&&!a.nonblock&&b.closer.css("visibility","visible")},mouseleave:function(l){a.nonblock&&l.stopPropagation();k=null;b.css("cursor","auto");a.nonblock&&g!="out"&&b.animate({opacity:a.opacity},"fast");a.hide&&a.mouse_reset&&b.pnotify_queue_remove();a.sticker_hover&&b.sticker.css("visibility","hidden");a.closer_hover&&b.closer.css("visibility","hidden");d.pnotify_position_all()}, -mouseover:function(b){a.nonblock&&b.stopPropagation()},mouseout:function(b){a.nonblock&&b.stopPropagation()},mousemove:function(b){a.nonblock&&(b.stopPropagation(),o(b,"onmousemove"))},mousedown:function(b){a.nonblock&&(b.stopPropagation(),b.preventDefault(),o(b,"onmousedown"))},mouseup:function(b){a.nonblock&&(b.stopPropagation(),b.preventDefault(),o(b,"onmouseup"))},click:function(b){a.nonblock&&(b.stopPropagation(),o(b,"onclick"))},dblclick:function(b){a.nonblock&&(b.stopPropagation(),o(b,"ondblclick"))}}); -b.opts=a;b.container=d("
                    ",{"class":f.container+" ui-pnotify-container "+(a.type=="error"?f.error:a.type=="info"?f.info:a.type=="success"?f.success:f.notice)}).appendTo(b);a.cornerclass!=""&&b.container.removeClass("ui-corner-all").addClass(a.cornerclass);a.shadow&&b.container.addClass("ui-pnotify-shadow");b.pnotify_version="1.2.2";b.pnotify=function(l){var c=a;typeof l=="string"?a.text=l:a=d.extend({},a,l);for(var e in a)typeof e=="string"&&e.match(/^pnotify_/)&&(a[e.replace(/^pnotify_/,"")]= -a[e]);b.opts=a;a.cornerclass!=c.cornerclass&&b.container.removeClass("ui-corner-all").addClass(a.cornerclass);a.shadow!=c.shadow&&(a.shadow?b.container.addClass("ui-pnotify-shadow"):b.container.removeClass("ui-pnotify-shadow"));a.addclass===false?b.removeClass(c.addclass):a.addclass!==c.addclass&&b.removeClass(c.addclass).addClass(a.addclass);a.title===false?b.title_container.slideUp("fast"):a.title!==c.title&&(a.title_escape?b.title_container.text(a.title).slideDown(200):b.title_container.html(a.title).slideDown(200)); -a.text===false?b.text_container.slideUp("fast"):a.text!==c.text&&(a.text_escape?b.text_container.text(a.text).slideDown(200):b.text_container.html(a.insert_brs?String(a.text).replace(/\n/g,"
                    "):a.text).slideDown(200));b.pnotify_history=a.history;b.pnotify_hide=a.hide;a.type!=c.type&&b.container.removeClass(f.error+" "+f.notice+" "+f.success+" "+f.info).addClass(a.type=="error"?f.error:a.type=="info"?f.info:a.type=="success"?f.success:f.notice);if(a.icon!==c.icon||a.icon===true&&a.type!=c.type)b.container.find("div.ui-pnotify-icon").remove(), -a.icon!==false&&d("
                    ",{"class":"ui-pnotify-icon"}).append(d("",{"class":a.icon===true?a.type=="error"?f.error_icon:a.type=="info"?f.info_icon:a.type=="success"?f.success_icon:f.notice_icon:a.icon})).prependTo(b.container);a.width!==c.width&&b.animate({width:a.width});a.min_height!==c.min_height&&b.container.animate({minHeight:a.min_height});a.opacity!==c.opacity&&b.fadeTo(a.animate_speed,a.opacity);!a.closer||a.nonblock?b.closer.css("display","none"):b.closer.css("display","block"); -!a.sticker||a.nonblock?b.sticker.css("display","none"):b.sticker.css("display","block");b.sticker.trigger("pnotify_icon");a.sticker_hover?b.sticker.css("visibility","hidden"):a.nonblock||b.sticker.css("visibility","visible");a.closer_hover?b.closer.css("visibility","hidden"):a.nonblock||b.closer.css("visibility","visible");a.hide?c.hide||b.pnotify_queue_remove():b.pnotify_cancel_remove();b.pnotify_queue_position();return b};b.pnotify_position=function(a){var c=b.opts.stack;if(c){if(!c.nextpos1)c.nextpos1= -c.firstpos1;if(!c.nextpos2)c.nextpos2=c.firstpos2;if(!c.addpos2)c.addpos2=0;var d=b.css("display")=="none";if(!d||a){var f,e={},g;switch(c.dir1){case "down":g="top";break;case "up":g="bottom";break;case "left":g="right";break;case "right":g="left"}a=parseInt(b.css(g));isNaN(a)&&(a=0);if(typeof c.firstpos1=="undefined"&&!d)c.firstpos1=a,c.nextpos1=c.firstpos1;var h;switch(c.dir2){case "down":h="top";break;case "up":h="bottom";break;case "left":h="right";break;case "right":h="left"}f=parseInt(b.css(h)); -isNaN(f)&&(f=0);if(typeof c.firstpos2=="undefined"&&!d)c.firstpos2=f,c.nextpos2=c.firstpos2;if(c.dir1=="down"&&c.nextpos1+b.height()>i.height()||c.dir1=="up"&&c.nextpos1+b.height()>i.height()||c.dir1=="left"&&c.nextpos1+b.width()>i.width()||c.dir1=="right"&&c.nextpos1+b.width()>i.width())c.nextpos1=c.firstpos1,c.nextpos2+=c.addpos2+(typeof c.spacing2=="undefined"?25:c.spacing2),c.addpos2=0;if(c.animation&&c.nextpos2c.addpos2)c.addpos2=b.height();break;case "left":case "right":if(b.outerWidth(true)>c.addpos2)c.addpos2=b.width()}if(c.nextpos1)if(c.animation&&(a>c.nextpos1||e.top||e.bottom||e.right||e.left))switch(c.dir1){case "down":e.top=c.nextpos1+"px";break;case "up":e.bottom=c.nextpos1+"px";break;case "left":e.right=c.nextpos1+"px"; -break;case "right":e.left=c.nextpos1+"px"}else b.css(g,c.nextpos1+"px");(e.top||e.bottom||e.right||e.left)&&b.animate(e,{duration:500,queue:false});switch(c.dir1){case "down":case "up":c.nextpos1+=b.height()+(typeof c.spacing1=="undefined"?25:c.spacing1);break;case "left":case "right":c.nextpos1+=b.width()+(typeof c.spacing1=="undefined"?25:c.spacing1)}}}};b.pnotify_queue_position=function(a){j&&clearTimeout(j);a||(a=10);j=setTimeout(d.pnotify_position_all,a)};b.pnotify_display=function(){b.parent().length|| -b.appendTo(r);a.before_open&&a.before_open(b)===false||(a.stack.push!="top"&&b.pnotify_position(true),a.animation=="fade"||a.animation.effect_in=="fade"?b.show().fadeTo(0,0).hide():a.opacity!=1&&b.show().fadeTo(0,a.opacity).hide(),b.animate_in(function(){a.after_open&&a.after_open(b);b.pnotify_queue_position();a.hide&&b.pnotify_queue_remove()}))};b.pnotify_remove=function(){if(b.timer)window.clearTimeout(b.timer),b.timer=null;a.before_close&&a.before_close(b)===false||b.animate_out(function(){a.after_close&& -a.after_close(b)===false||(b.pnotify_queue_position(),a.remove&&b.detach())})};b.animate_in=function(d){g="in";var c;c=typeof a.animation.effect_in!="undefined"?a.animation.effect_in:a.animation;c=="none"?(b.show(),d()):c=="show"?b.show(a.animate_speed,d):c=="fade"?b.show().fadeTo(a.animate_speed,a.opacity,d):c=="slide"?b.slideDown(a.animate_speed,d):typeof c=="function"?c("in",d,b):b.show(c,typeof a.animation.options_in=="object"?a.animation.options_in:{},a.animate_speed,d)};b.animate_out=function(d){g= -"out";var c;c=typeof a.animation.effect_out!="undefined"?a.animation.effect_out:a.animation;c=="none"?(b.hide(),d()):c=="show"?b.hide(a.animate_speed,d):c=="fade"?b.fadeOut(a.animate_speed,d):c=="slide"?b.slideUp(a.animate_speed,d):typeof c=="function"?c("out",d,b):b.hide(c,typeof a.animation.options_out=="object"?a.animation.options_out:{},a.animate_speed,d)};b.pnotify_cancel_remove=function(){b.timer&&window.clearTimeout(b.timer)};b.pnotify_queue_remove=function(){b.pnotify_cancel_remove();b.timer= -window.setTimeout(function(){b.pnotify_remove()},isNaN(a.delay)?0:a.delay)};b.closer=d("
                    ",{"class":"ui-pnotify-closer",css:{cursor:"pointer",visibility:a.closer_hover?"hidden":"visible"},click:function(){b.pnotify_remove();b.sticker.css("visibility","hidden");b.closer.css("visibility","hidden")}}).append(d("",{"class":f.closer})).appendTo(b.container);(!a.closer||a.nonblock)&&b.closer.css("display","none");b.sticker=d("
                    ",{"class":"ui-pnotify-sticker",css:{cursor:"pointer",visibility:a.sticker_hover? -"hidden":"visible"},click:function(){a.hide=!a.hide;a.hide?b.pnotify_queue_remove():b.pnotify_cancel_remove();d(this).trigger("pnotify_icon")}}).bind("pnotify_icon",function(){d(this).children().removeClass(f.pin_up+" "+f.pin_down).addClass(a.hide?f.pin_up:f.pin_down)}).append(d("",{"class":f.pin_up})).appendTo(b.container);(!a.sticker||a.nonblock)&&b.sticker.css("display","none");a.icon!==false&&d("
                    ",{"class":"ui-pnotify-icon"}).append(d("",{"class":a.icon===true?a.type=="error"? -f.error_icon:a.type=="info"?f.info_icon:a.type=="success"?f.success_icon:f.notice_icon:a.icon})).prependTo(b.container);b.title_container=d("

                    ",{"class":"ui-pnotify-title"}).appendTo(b.container);a.title===false?b.title_container.hide():a.title_escape?b.title_container.text(a.title):b.title_container.html(a.title);b.text_container=d("
                    ",{"class":"ui-pnotify-text"}).appendTo(b.container);a.text===false?b.text_container.hide():a.text_escape?b.text_container.text(a.text):b.text_container.html(a.insert_brs? -String(a.text).replace(/\n/g,"
                    "):a.text);typeof a.width=="string"&&b.css("width",a.width);typeof a.min_height=="string"&&b.container.css("min-height",a.min_height);b.pnotify_history=a.history;b.pnotify_hide=a.hide;var h=i.data("pnotify");if(h==null||typeof h!="object")h=[];h=a.stack.push=="top"?d.merge([b],h):d.merge(h,[b]);i.data("pnotify",h);a.stack.push=="top"&&b.pnotify_queue_position(1);a.after_init&&a.after_init(b);if(a.history){var m=i.data("pnotify_history");typeof m=="undefined"&&(m= -d("
                    ",{"class":"ui-pnotify-history-container "+f.hi_menu,mouseleave:function(){m.animate({top:"-"+q+"px"},{duration:100,queue:false})}}).append(d("
                    ",{"class":"ui-pnotify-history-header",text:"Redisplay"})).append(d("

                    /// Any valid jQuery selector. - var $forms = $(selector) - .parents("form") - .andSelf() - .add($(selector).find("form")) - .filter("form"); - - // :input is a psuedoselector provided by jQuery which selects input and input-like elements - // combining :input with other selectors significantly decreases performance. - $(selector).find(":input").filter("[data-val=true]").each(function () { + + // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one + // element with data-val=true + var $selector = $(selector), + $forms = $selector.parents() + .addBack() + .filter("form") + .add($selector.find("form")) + .has("[data-val=true]"); + + $selector.find("[data-val=true]").each(function () { $jQval.unobtrusive.parseElement(this, true); }); diff --git a/src/Presentation/SmartStore.Web/Scripts/jquery.validate.unobtrusive.min.js b/src/Presentation/SmartStore.Web/Scripts/jquery.validate.unobtrusive.min.js index 4fdb9c7fb3..db91044eb7 100644 --- a/src/Presentation/SmartStore.Web/Scripts/jquery.validate.unobtrusive.min.js +++ b/src/Presentation/SmartStore.Web/Scripts/jquery.validate.unobtrusive.min.js @@ -16,4 +16,4 @@ ** Unobtrusive validation support library for jQuery and jQuery Validate ** Copyright (C) Microsoft Corporation. All rights reserved. */ -(function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
                  • ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(c){var b=a(c),d=b.data(e),f=a.proxy(n,c);if(!d){d={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(m,c),invalidHandler:a.proxy(l,c),messages:{},rules:{},success:a.proxy(k,c)},attachValidation:function(){b.unbind("reset."+e,f).bind("reset."+e,f).validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(e,d)}return d}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(b){var c=a(b).parents("form").andSelf().add(a(b).find("form")).filter("form");a(b).find(":input").filter("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});c.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input").filter("[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery); \ No newline at end of file +(function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("
                  • ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(b){var c=a(b),f=c.data(e),i=a.proxy(n,b),g=d.unobtrusive.options||{},h=function(e,d){var c=g[e];c&&a.isFunction(c)&&c.apply(b,d)};if(!f){f={options:{errorClass:g.errorClass||"input-validation-error",errorElement:g.errorElement||"span",errorPlacement:function(){m.apply(b,arguments);h("errorPlacement",arguments)},invalidHandler:function(){l.apply(b,arguments);h("invalidHandler",arguments)},messages:{},rules:{},success:function(){k.apply(b,arguments);h("success",arguments)}},attachValidation:function(){c.off("reset."+e,i).on("reset."+e,i).validate(this.options)},validate:function(){c.validate();return c.valid()}};c.data(e,f)}return f}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(c){var b=a(c),e=b.parents().addBack().filter("form").add(b.find("form")).has("[data-val=true]");b.find("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});e.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input").filter("[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/load-image.js b/src/Presentation/SmartStore.Web/Scripts/load-image.js deleted file mode 100644 index 2eda67a620..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/load-image.js +++ /dev/null @@ -1,228 +0,0 @@ -/* - * JavaScript Load Image 1.2.2 - * https://github.com/blueimp/JavaScript-Load-Image - * - * Copyright 2011, Sebastian Tschan - * https://blueimp.net - * - * iOS image scaling fixes based on - * https://github.com/stomita/ios-imagefile-megapixel - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT - */ - -/*jslint nomen: true, bitwise: true */ -/*global window, document, URL, webkitURL, Blob, File, FileReader, define */ - -(function ($) { - 'use strict'; - - // Loads an image for a given File object. - // Invokes the callback with an img or optional canvas - // element (if supported by the browser) as parameter: - var loadImage = function (file, callback, options) { - var img = document.createElement('img'), - url, - oUrl; - img.onerror = callback; - img.onload = function () { - if (oUrl && !(options && options.noRevoke)) { - loadImage.revokeObjectURL(oUrl); - } - callback(loadImage.scale(img, options)); - }; - if ((window.Blob && file instanceof Blob) || - // Files are also Blob instances, but some browsers - // (Firefox 3.6) support the File API but not Blobs: - (window.File && file instanceof File)) { - url = oUrl = loadImage.createObjectURL(file); - // Store the file type for resize processing: - img._type = file.type; - } else { - url = file; - } - if (url) { - img.src = url; - return img; - } - return loadImage.readFile(file, function (url) { - img.src = url; - }); - }, - // The check for URL.revokeObjectURL fixes an issue with Opera 12, - // which provides URL.createObjectURL but doesn't properly implement it: - urlAPI = (window.createObjectURL && window) || - (window.URL && URL.revokeObjectURL && URL) || - (window.webkitURL && webkitURL); - - // Detects subsampling in JPEG images: - loadImage.detectSubsampling = function (img) { - var iw = img.width, - ih = img.height, - canvas, - ctx; - if (iw * ih > 1024 * 1024) { // only consider mexapixel images - canvas = document.createElement('canvas'); - canvas.width = canvas.height = 1; - ctx = canvas.getContext('2d'); - ctx.drawImage(img, -iw + 1, 0); - // subsampled image becomes half smaller in rendering size. - // check alpha channel value to confirm image is covering edge pixel or not. - // if alpha value is 0 image is not covering, hence subsampled. - return ctx.getImageData(0, 0, 1, 1).data[3] === 0; - } - return false; - }; - - // Detects vertical squash in JPEG images: - loadImage.detectVerticalSquash = function (img, ih) { - var canvas = document.createElement('canvas'), - ctx = canvas.getContext('2d'), - data, - sy, - ey, - py, - alpha; - canvas.width = 1; - canvas.height = ih; - ctx.drawImage(img, 0, 0); - data = ctx.getImageData(0, 0, 1, ih).data; - // search image edge pixel position in case it is squashed vertically: - sy = 0; - ey = ih; - py = ih; - while (py > sy) { - alpha = data[(py - 1) * 4 + 3]; - if (alpha === 0) { - ey = py; - } else { - sy = py; - } - py = (ey + sy) >> 1; - } - return py / ih; - }; - - // Renders image to canvas while working around iOS image scaling bugs: - // https://github.com/blueimp/JavaScript-Load-Image/issues/13 - loadImage.renderImageToCanvas = function (img, canvas, width, height) { - var iw = img.width, - ih = img.height, - ctx = canvas.getContext('2d'), - vertSquashRatio, - d = 1024, // size of tiling canvas - tmpCanvas = document.createElement('canvas'), - tmpCtx, - sy, - sh, - sx, - sw; - ctx.save(); - if (loadImage.detectSubsampling(img)) { - iw /= 2; - ih /= 2; - } - vertSquashRatio = loadImage.detectVerticalSquash(img, ih); - tmpCanvas.width = tmpCanvas.height = d; - tmpCtx = tmpCanvas.getContext('2d'); - sy = 0; - while (sy < ih) { - sh = sy + d > ih ? ih - sy : d; - sx = 0; - while (sx < iw) { - sw = sx + d > iw ? iw - sx : d; - tmpCtx.clearRect(0, 0, d, d); - tmpCtx.drawImage(img, -sx, -sy); - ctx.drawImage( - tmpCanvas, - 0, - 0, - sw, - sh, - Math.floor(sx * width / iw), - Math.floor(sy * height / ih / vertSquashRatio), - Math.ceil(sw * width / iw), - Math.ceil(sh * height / ih / vertSquashRatio) - ); - sx += d; - } - sy += d; - } - ctx.restore(); - tmpCanvas = tmpCtx = null; - }; - - // Scales the given image (img or canvas HTML element) - // using the given options. - // Returns a canvas object if the browser supports canvas - // and the canvas option is true or a canvas object is passed - // as image, else the scaled image: - loadImage.scale = function (img, options) { - options = options || {}; - var canvas = document.createElement('canvas'), - width = img.width, - height = img.height, - scale = Math.max( - (options.minWidth || width) / width, - (options.minHeight || height) / height - ); - if (scale > 1) { - width = parseInt(width * scale, 10); - height = parseInt(height * scale, 10); - } - scale = Math.min( - (options.maxWidth || width) / width, - (options.maxHeight || height) / height - ); - if (scale < 1) { - width = parseInt(width * scale, 10); - height = parseInt(height * scale, 10); - } - if (img.getContext || (options.canvas && canvas.getContext)) { - canvas.width = width; - canvas.height = height; - if (img._type === 'image/jpeg') { - loadImage - .renderImageToCanvas(img, canvas, width, height); - } else { - canvas.getContext('2d') - .drawImage(img, 0, 0, width, height); - } - return canvas; - } - img.width = width; - img.height = height; - return img; - }; - - loadImage.createObjectURL = function (file) { - return urlAPI ? urlAPI.createObjectURL(file) : false; - }; - - loadImage.revokeObjectURL = function (url) { - return urlAPI ? urlAPI.revokeObjectURL(url) : false; - }; - - // Loads a given File object via FileReader interface, - // invokes the callback with a data url: - loadImage.readFile = function (file, callback) { - if (window.FileReader && FileReader.prototype.readAsDataURL) { - var fileReader = new FileReader(); - fileReader.onload = function (e) { - callback(e.target.result); - }; - fileReader.readAsDataURL(file); - return fileReader; - } - return false; - }; - - if (typeof define === 'function' && define.amd) { - define(function () { - return loadImage; - }); - } else { - $.loadImage = loadImage; - } -}(this)); diff --git a/src/Presentation/SmartStore.Web/Scripts/modernizr-2.7.1.js b/src/Presentation/SmartStore.Web/Scripts/modernizr-2.7.1.js deleted file mode 100644 index e6992b2ca4..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/modernizr-2.7.1.js +++ /dev/null @@ -1,1406 +0,0 @@ -/*! - * Modernizr v2.7.1 - * www.modernizr.com - * - * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton - * Available under the BSD and MIT licenses: www.modernizr.com/license/ - */ - -/* - * Modernizr tests which native CSS3 and HTML5 features are available in - * the current UA and makes the results available to you in two ways: - * as properties on a global Modernizr object, and as classes on the - * element. This information allows you to progressively enhance - * your pages with a granular level of control over the experience. - * - * Modernizr has an optional (not included) conditional resource loader - * called Modernizr.load(), based on Yepnope.js (yepnopejs.com). - * To get a build that includes Modernizr.load(), as well as choosing - * which tests to include, go to www.modernizr.com/download/ - * - * Authors Faruk Ates, Paul Irish, Alex Sexton - * Contributors Ryan Seddon, Ben Alman - */ - -window.Modernizr = (function( window, document, undefined ) { - - var version = '2.7.1', - - Modernizr = {}, - - /*>>cssclasses*/ - // option for enabling the HTML classes to be added - enableClasses = true, - /*>>cssclasses*/ - - docElement = document.documentElement, - - /** - * Create our "modernizr" element that we do most feature tests on. - */ - mod = 'modernizr', - modElem = document.createElement(mod), - mStyle = modElem.style, - - /** - * Create the input element for various Web Forms feature tests. - */ - inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ , - - /*>>smile*/ - smile = ':)', - /*>>smile*/ - - toString = {}.toString, - - // TODO :: make the prefixes more granular - /*>>prefixes*/ - // List of property values to set for css tests. See ticket #21 - prefixes = ' -webkit- -moz- -o- -ms- '.split(' '), - /*>>prefixes*/ - - /*>>domprefixes*/ - // Following spec is to expose vendor-specific style properties as: - // elem.style.WebkitBorderRadius - // and the following would be incorrect: - // elem.style.webkitBorderRadius - - // Webkit ghosts their properties in lowercase but Opera & Moz do not. - // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ - // erik.eae.net/archives/2008/03/10/21.48.10/ - - // More here: github.com/Modernizr/Modernizr/issues/issue/21 - omPrefixes = 'Webkit Moz O ms', - - cssomPrefixes = omPrefixes.split(' '), - - domPrefixes = omPrefixes.toLowerCase().split(' '), - /*>>domprefixes*/ - - /*>>ns*/ - ns = {'svg': 'http://www.w3.org/2000/svg'}, - /*>>ns*/ - - tests = {}, - inputs = {}, - attrs = {}, - - classes = [], - - slice = classes.slice, - - featureName, // used in testing loop - - - /*>>teststyles*/ - // Inject element with style element and some CSS rules - injectElementWithStyles = function( rule, callback, nodes, testnames ) { - - var style, ret, node, docOverflow, - div = document.createElement('div'), - // After page load injecting a fake body doesn't work so check if body exists - body = document.body, - // IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it. - fakeBody = body || document.createElement('body'); - - if ( parseInt(nodes, 10) ) { - // In order not to give false positives we create a node for each test - // This also allows the method to scale for unspecified uses - while ( nodes-- ) { - node = document.createElement('div'); - node.id = testnames ? testnames[nodes] : mod + (nodes + 1); - div.appendChild(node); - } - } - - // '].join(''); - div.id = mod; - // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody. - // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 - (body ? div : fakeBody).innerHTML += style; - fakeBody.appendChild(div); - if ( !body ) { - //avoid crashing IE8, if background image is used - fakeBody.style.background = ''; - //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible - fakeBody.style.overflow = 'hidden'; - docOverflow = docElement.style.overflow; - docElement.style.overflow = 'hidden'; - docElement.appendChild(fakeBody); - } - - ret = callback(div, rule); - // If this is done after page load we don't want to remove the body so check if body exists - if ( !body ) { - fakeBody.parentNode.removeChild(fakeBody); - docElement.style.overflow = docOverflow; - } else { - div.parentNode.removeChild(div); - } - - return !!ret; - - }, - /*>>teststyles*/ - - /*>>mq*/ - // adapted from matchMedia polyfill - // by Scott Jehl and Paul Irish - // gist.github.com/786768 - testMediaQuery = function( mq ) { - - var matchMedia = window.matchMedia || window.msMatchMedia; - if ( matchMedia ) { - return matchMedia(mq).matches; - } - - var bool; - - injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) { - bool = (window.getComputedStyle ? - getComputedStyle(node, null) : - node.currentStyle)['position'] == 'absolute'; - }); - - return bool; - - }, - /*>>mq*/ - - - /*>>hasevent*/ - // - // isEventSupported determines if a given element supports the given event - // kangax.github.com/iseventsupported/ - // - // The following results are known incorrects: - // Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative - // Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333 - // ... - isEventSupported = (function() { - - var TAGNAMES = { - 'select': 'input', 'change': 'input', - 'submit': 'form', 'reset': 'form', - 'error': 'img', 'load': 'img', 'abort': 'img' - }; - - function isEventSupported( eventName, element ) { - - element = element || document.createElement(TAGNAMES[eventName] || 'div'); - eventName = 'on' + eventName; - - // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those - var isSupported = eventName in element; - - if ( !isSupported ) { - // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element - if ( !element.setAttribute ) { - element = document.createElement('div'); - } - if ( element.setAttribute && element.removeAttribute ) { - element.setAttribute(eventName, ''); - isSupported = is(element[eventName], 'function'); - - // If property was created, "remove it" (by setting value to `undefined`) - if ( !is(element[eventName], 'undefined') ) { - element[eventName] = undefined; - } - element.removeAttribute(eventName); - } - } - - element = null; - return isSupported; - } - return isEventSupported; - })(), - /*>>hasevent*/ - - // TODO :: Add flag for hasownprop ? didn't last time - - // hasOwnProperty shim by kangax needed for Safari 2.0 support - _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp; - - if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) { - hasOwnProp = function (object, property) { - return _hasOwnProperty.call(object, property); - }; - } - else { - hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ - return ((property in object) && is(object.constructor.prototype[property], 'undefined')); - }; - } - - // Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js - // es5.github.com/#x15.3.4.5 - - if (!Function.prototype.bind) { - Function.prototype.bind = function bind(that) { - - var target = this; - - if (typeof target != "function") { - throw new TypeError(); - } - - var args = slice.call(arguments, 1), - bound = function () { - - if (this instanceof bound) { - - var F = function(){}; - F.prototype = target.prototype; - var self = new F(); - - var result = target.apply( - self, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return self; - - } else { - - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - - } - - }; - - return bound; - }; - } - - /** - * setCss applies given styles to the Modernizr DOM node. - */ - function setCss( str ) { - mStyle.cssText = str; - } - - /** - * setCssAll extrapolates all vendor-specific css strings. - */ - function setCssAll( str1, str2 ) { - return setCss(prefixes.join(str1 + ';') + ( str2 || '' )); - } - - /** - * is returns a boolean for if typeof obj is exactly type. - */ - function is( obj, type ) { - return typeof obj === type; - } - - /** - * contains returns a boolean for if substr is found within str. - */ - function contains( str, substr ) { - return !!~('' + str).indexOf(substr); - } - - /*>>testprop*/ - - // testProps is a generic CSS / DOM property test. - - // In testing support for a given CSS property, it's legit to test: - // `elem.style[styleName] !== undefined` - // If the property is supported it will return an empty string, - // if unsupported it will return undefined. - - // We'll take advantage of this quick test and skip setting a style - // on our modernizr element, but instead just testing undefined vs - // empty string. - - // Because the testing of the CSS property names (with "-", as - // opposed to the camelCase DOM properties) is non-portable and - // non-standard but works in WebKit and IE (but not Gecko or Opera), - // we explicitly reject properties with dashes so that authors - // developing in WebKit or IE first don't end up with - // browser-specific content by accident. - - function testProps( props, prefixed ) { - for ( var i in props ) { - var prop = props[i]; - if ( !contains(prop, "-") && mStyle[prop] !== undefined ) { - return prefixed == 'pfx' ? prop : true; - } - } - return false; - } - /*>>testprop*/ - - // TODO :: add testDOMProps - /** - * testDOMProps is a generic DOM property test; if a browser supports - * a certain property, it won't return undefined for it. - */ - function testDOMProps( props, obj, elem ) { - for ( var i in props ) { - var item = obj[props[i]]; - if ( item !== undefined) { - - // return the property name as a string - if (elem === false) return props[i]; - - // let's bind a function - if (is(item, 'function')){ - // default to autobind unless override - return item.bind(elem || obj); - } - - // return the unbound function or obj or value - return item; - } - } - return false; - } - - /*>>testallprops*/ - /** - * testPropsAll tests a list of DOM properties we want to check against. - * We specify literally ALL possible (known and/or likely) properties on - * the element including the non-vendor prefixed one, for forward- - * compatibility. - */ - function testPropsAll( prop, prefixed, elem ) { - - var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), - props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); - - // did they call .prefixed('boxSizing') or are we just testing a prop? - if(is(prefixed, "string") || is(prefixed, "undefined")) { - return testProps(props, prefixed); - - // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) - } else { - props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); - return testDOMProps(props, prefixed, elem); - } - } - /*>>testallprops*/ - - - /** - * Tests - * ----- - */ - - // The *new* flexbox - // dev.w3.org/csswg/css3-flexbox - - tests['flexbox'] = function() { - return testPropsAll('flexWrap'); - }; - - // The *old* flexbox - // www.w3.org/TR/2009/WD-css3-flexbox-20090723/ - - tests['flexboxlegacy'] = function() { - return testPropsAll('boxDirection'); - }; - - // On the S60 and BB Storm, getContext exists, but always returns undefined - // so we actually have to call getContext() to verify - // github.com/Modernizr/Modernizr/issues/issue/97/ - - tests['canvas'] = function() { - var elem = document.createElement('canvas'); - return !!(elem.getContext && elem.getContext('2d')); - }; - - tests['canvastext'] = function() { - return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function')); - }; - - // webk.it/70117 is tracking a legit WebGL feature detect proposal - - // We do a soft detect which may false positive in order to avoid - // an expensive context creation: bugzil.la/732441 - - tests['webgl'] = function() { - return !!window.WebGLRenderingContext; - }; - - /* - * The Modernizr.touch test only indicates if the browser supports - * touch events, which does not necessarily reflect a touchscreen - * device, as evidenced by tablets running Windows 7 or, alas, - * the Palm Pre / WebOS (touch) phones. - * - * Additionally, Chrome (desktop) used to lie about its support on this, - * but that has since been rectified: crbug.com/36415 - * - * We also test for Firefox 4 Multitouch Support. - * - * For more info, see: modernizr.github.com/Modernizr/touch.html - */ - - tests['touch'] = function() { - var bool; - - if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { - bool = true; - } else { - injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) { - bool = node.offsetTop === 9; - }); - } - - return bool; - }; - - - // geolocation is often considered a trivial feature detect... - // Turns out, it's quite tricky to get right: - // - // Using !!navigator.geolocation does two things we don't want. It: - // 1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513 - // 2. Disables page caching in WebKit: webk.it/43956 - // - // Meanwhile, in Firefox < 8, an about:config setting could expose - // a false positive that would throw an exception: bugzil.la/688158 - - tests['geolocation'] = function() { - return 'geolocation' in navigator; - }; - - - tests['postmessage'] = function() { - return !!window.postMessage; - }; - - - // Chrome incognito mode used to throw an exception when using openDatabase - // It doesn't anymore. - tests['websqldatabase'] = function() { - return !!window.openDatabase; - }; - - // Vendors had inconsistent prefixing with the experimental Indexed DB: - // - Webkit's implementation is accessible through webkitIndexedDB - // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB - // For speed, we don't test the legacy (and beta-only) indexedDB - tests['indexedDB'] = function() { - return !!testPropsAll("indexedDB", window); - }; - - // documentMode logic from YUI to filter out IE8 Compat Mode - // which false positives. - tests['hashchange'] = function() { - return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7); - }; - - // Per 1.6: - // This used to be Modernizr.historymanagement but the longer - // name has been deprecated in favor of a shorter and property-matching one. - // The old API is still available in 1.6, but as of 2.0 will throw a warning, - // and in the first release thereafter disappear entirely. - tests['history'] = function() { - return !!(window.history && history.pushState); - }; - - tests['draganddrop'] = function() { - var div = document.createElement('div'); - return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div); - }; - - // FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10 - // will be supported until FF19 (2/12/13), at which time, ESR becomes FF17. - // FF10 still uses prefixes, so check for it until then. - // for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/ - tests['websockets'] = function() { - return 'WebSocket' in window || 'MozWebSocket' in window; - }; - - - // css-tricks.com/rgba-browser-support/ - tests['rgba'] = function() { - // Set an rgba() color and check the returned value - - setCss('background-color:rgba(150,255,150,.5)'); - - return contains(mStyle.backgroundColor, 'rgba'); - }; - - tests['hsla'] = function() { - // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally, - // except IE9 who retains it as hsla - - setCss('background-color:hsla(120,40%,100%,.5)'); - - return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla'); - }; - - tests['multiplebgs'] = function() { - // Setting multiple images AND a color on the background shorthand property - // and then querying the style.background property value for the number of - // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! - - setCss('background:url(https://),url(https://),red url(https://)'); - - // If the UA supports multiple backgrounds, there should be three occurrences - // of the string "url(" in the return value for elemStyle.background - - return (/(url\s*\(.*?){3}/).test(mStyle.background); - }; - - - - // this will false positive in Opera Mini - // github.com/Modernizr/Modernizr/issues/396 - - tests['backgroundsize'] = function() { - return testPropsAll('backgroundSize'); - }; - - tests['borderimage'] = function() { - return testPropsAll('borderImage'); - }; - - - // Super comprehensive table about all the unique implementations of - // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance - - tests['borderradius'] = function() { - return testPropsAll('borderRadius'); - }; - - // WebOS unfortunately false positives on this test. - tests['boxshadow'] = function() { - return testPropsAll('boxShadow'); - }; - - // FF3.0 will false positive on this test - tests['textshadow'] = function() { - return document.createElement('div').style.textShadow === ''; - }; - - - tests['opacity'] = function() { - // Browsers that actually have CSS Opacity implemented have done so - // according to spec, which means their return values are within the - // range of [0.0,1.0] - including the leading zero. - - setCssAll('opacity:.55'); - - // The non-literal . in this regex is intentional: - // German Chrome returns this value as 0,55 - // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 - return (/^0.55$/).test(mStyle.opacity); - }; - - - // Note, Android < 4 will pass this test, but can only animate - // a single property at a time - // daneden.me/2011/12/putting-up-with-androids-bullshit/ - tests['cssanimations'] = function() { - return testPropsAll('animationName'); - }; - - - tests['csscolumns'] = function() { - return testPropsAll('columnCount'); - }; - - - tests['cssgradients'] = function() { - /** - * For CSS Gradients syntax, please see: - * webkit.org/blog/175/introducing-css-gradients/ - * developer.mozilla.org/en/CSS/-moz-linear-gradient - * developer.mozilla.org/en/CSS/-moz-radial-gradient - * dev.w3.org/csswg/css3-images/#gradients- - */ - - var str1 = 'background-image:', - str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', - str3 = 'linear-gradient(left top,#9f9, white);'; - - setCss( - // legacy webkit syntax (FIXME: remove when syntax not in use anymore) - (str1 + '-webkit- '.split(' ').join(str2 + str1) + - // standard syntax // trailing 'background-image:' - prefixes.join(str3 + str1)).slice(0, -str1.length) - ); - - return contains(mStyle.backgroundImage, 'gradient'); - }; - - - tests['cssreflections'] = function() { - return testPropsAll('boxReflect'); - }; - - - tests['csstransforms'] = function() { - return !!testPropsAll('transform'); - }; - - - tests['csstransforms3d'] = function() { - - var ret = !!testPropsAll('perspective'); - - // Webkit's 3D transforms are passed off to the browser's own graphics renderer. - // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in - // some conditions. As a result, Webkit typically recognizes the syntax but - // will sometimes throw a false positive, thus we must do a more thorough check: - if ( ret && 'webkitPerspective' in docElement.style ) { - - // Webkit allows this media query to succeed only if the feature is enabled. - // `@media (transform-3d),(-webkit-transform-3d){ ... }` - injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) { - ret = node.offsetLeft === 9 && node.offsetHeight === 3; - }); - } - return ret; - }; - - - tests['csstransitions'] = function() { - return testPropsAll('transition'); - }; - - - /*>>fontface*/ - // @font-face detection routine by Diego Perini - // javascript.nwbox.com/CSSSupport/ - - // false positives: - // WebOS github.com/Modernizr/Modernizr/issues/342 - // WP7 github.com/Modernizr/Modernizr/issues/538 - tests['fontface'] = function() { - var bool; - - injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) { - var style = document.getElementById('smodernizr'), - sheet = style.sheet || style.styleSheet, - cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : ''; - - bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0; - }); - - return bool; - }; - /*>>fontface*/ - - // CSS generated content detection - tests['generatedcontent'] = function() { - var bool; - - injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) { - bool = node.offsetHeight >= 3; - }); - - return bool; - }; - - - - // These tests evaluate support of the video/audio elements, as well as - // testing what types of content they support. - // - // We're using the Boolean constructor here, so that we can extend the value - // e.g. Modernizr.video // true - // Modernizr.video.ogg // 'probably' - // - // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 - // thx to NielsLeenheer and zcorpan - - // Note: in some older browsers, "no" was a return value instead of empty string. - // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2 - // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5 - - tests['video'] = function() { - var elem = document.createElement('video'), - bool = false; - - // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224 - try { - if ( bool = !!elem.canPlayType ) { - bool = new Boolean(bool); - bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,''); - - // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546 - bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,''); - - bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,''); - } - - } catch(e) { } - - return bool; - }; - - tests['audio'] = function() { - var elem = document.createElement('audio'), - bool = false; - - try { - if ( bool = !!elem.canPlayType ) { - bool = new Boolean(bool); - bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,''); - bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,''); - - // Mimetypes accepted: - // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements - // bit.ly/iphoneoscodecs - bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,''); - bool.m4a = ( elem.canPlayType('audio/x-m4a;') || - elem.canPlayType('audio/aac;')) .replace(/^no$/,''); - } - } catch(e) { } - - return bool; - }; - - - // In FF4, if disabled, window.localStorage should === null. - - // Normally, we could not test that directly and need to do a - // `('localStorage' in window) && ` test first because otherwise Firefox will - // throw bugzil.la/365772 if cookies are disabled - - // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem - // will throw the exception: - // QUOTA_EXCEEDED_ERRROR DOM Exception 22. - // Peculiarly, getItem and removeItem calls do not throw. - - // Because we are forced to try/catch this, we'll go aggressive. - - // Just FWIW: IE8 Compat mode supports these features completely: - // www.quirksmode.org/dom/html5.html - // But IE8 doesn't support either with local files - - tests['localstorage'] = function() { - try { - localStorage.setItem(mod, mod); - localStorage.removeItem(mod); - return true; - } catch(e) { - return false; - } - }; - - tests['sessionstorage'] = function() { - try { - sessionStorage.setItem(mod, mod); - sessionStorage.removeItem(mod); - return true; - } catch(e) { - return false; - } - }; - - - tests['webworkers'] = function() { - return !!window.Worker; - }; - - - tests['applicationcache'] = function() { - return !!window.applicationCache; - }; - - - // Thanks to Erik Dahlstrom - tests['svg'] = function() { - return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; - }; - - // specifically for SVG inline in HTML, not within XHTML - // test page: paulirish.com/demo/inline-svg - tests['inlinesvg'] = function() { - var div = document.createElement('div'); - div.innerHTML = ''; - return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; - }; - - // SVG SMIL animation - tests['smil'] = function() { - return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate'))); - }; - - // This test is only for clip paths in SVG proper, not clip paths on HTML content - // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg - - // However read the comments to dig into applying SVG clippaths to HTML content here: - // github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491 - tests['svgclippaths'] = function() { - return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath'))); - }; - - /*>>webforms*/ - // input features and input types go directly onto the ret object, bypassing the tests loop. - // Hold this guy to execute in a moment. - function webforms() { - /*>>input*/ - // Run through HTML5's new input attributes to see if the UA understands any. - // We're using f which is the element created early on - // Mike Taylr has created a comprehensive resource for testing these attributes - // when applied to all input types: - // miketaylr.com/code/input-type-attr.html - // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary - - // Only input placeholder is tested while textarea's placeholder is not. - // Currently Safari 4 and Opera 11 have support only for the input placeholder - // Both tests are available in feature-detects/forms-placeholder.js - Modernizr['input'] = (function( props ) { - for ( var i = 0, len = props.length; i < len; i++ ) { - attrs[ props[i] ] = !!(props[i] in inputElem); - } - if (attrs.list){ - // safari false positive's on datalist: webk.it/74252 - // see also github.com/Modernizr/Modernizr/issues/146 - attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement); - } - return attrs; - })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); - /*>>input*/ - - /*>>inputtypes*/ - // Run through HTML5's new input types to see if the UA understands any. - // This is put behind the tests runloop because it doesn't return a - // true/false like all the other tests; instead, it returns an object - // containing each input type with its corresponding true/false value - - // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/ - Modernizr['inputtypes'] = (function(props) { - - for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) { - - inputElem.setAttribute('type', inputElemType = props[i]); - bool = inputElem.type !== 'text'; - - // We first check to see if the type we give it sticks.. - // If the type does, we feed it a textual value, which shouldn't be valid. - // If the value doesn't stick, we know there's input sanitization which infers a custom UI - if ( bool ) { - - inputElem.value = smile; - inputElem.style.cssText = 'position:absolute;visibility:hidden;'; - - if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) { - - docElement.appendChild(inputElem); - defaultView = document.defaultView; - - // Safari 2-4 allows the smiley as a value, despite making a slider - bool = defaultView.getComputedStyle && - defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' && - // Mobile android web browser has false positive, so must - // check the height to see if the widget is actually there. - (inputElem.offsetHeight !== 0); - - docElement.removeChild(inputElem); - - } else if ( /^(search|tel)$/.test(inputElemType) ){ - // Spec doesn't define any special parsing or detectable UI - // behaviors so we pass these through as true - - // Interestingly, opera fails the earlier test, so it doesn't - // even make it here. - - } else if ( /^(url|email)$/.test(inputElemType) ) { - // Real url and email support comes with prebaked validation. - bool = inputElem.checkValidity && inputElem.checkValidity() === false; - - } else { - // If the upgraded input compontent rejects the :) text, we got a winner - bool = inputElem.value != smile; - } - } - - inputs[ props[i] ] = !!bool; - } - return inputs; - })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); - /*>>inputtypes*/ - } - /*>>webforms*/ - - - // End of test definitions - // ----------------------- - - - - // Run through all tests and detect their support in the current UA. - // todo: hypothetically we could be doing an array of tests and use a basic loop here. - for ( var feature in tests ) { - if ( hasOwnProp(tests, feature) ) { - // run the test, throw the return value into the Modernizr, - // then based on that boolean, define an appropriate className - // and push it into an array of classes we'll join later. - featureName = feature.toLowerCase(); - Modernizr[featureName] = tests[feature](); - - classes.push((Modernizr[featureName] ? '' : 'no-') + featureName); - } - } - - /*>>webforms*/ - // input tests need to run. - Modernizr.input || webforms(); - /*>>webforms*/ - - - /** - * addTest allows the user to define their own feature tests - * the result will be added onto the Modernizr object, - * as well as an appropriate className set on the html element - * - * @param feature - String naming the feature - * @param test - Function returning true if feature is supported, false if not - */ - Modernizr.addTest = function ( feature, test ) { - if ( typeof feature == 'object' ) { - for ( var key in feature ) { - if ( hasOwnProp( feature, key ) ) { - Modernizr.addTest( key, feature[ key ] ); - } - } - } else { - - feature = feature.toLowerCase(); - - if ( Modernizr[feature] !== undefined ) { - // we're going to quit if you're trying to overwrite an existing test - // if we were to allow it, we'd do this: - // var re = new RegExp("\\b(no-)?" + feature + "\\b"); - // docElement.className = docElement.className.replace( re, '' ); - // but, no rly, stuff 'em. - return Modernizr; - } - - test = typeof test == 'function' ? test() : test; - - if (typeof enableClasses !== "undefined" && enableClasses) { - docElement.className += ' ' + (test ? '' : 'no-') + feature; - } - Modernizr[feature] = test; - - } - - return Modernizr; // allow chaining. - }; - - - // Reset modElem.cssText to nothing to reduce memory footprint. - setCss(''); - modElem = inputElem = null; - - /*>>shiv*/ - /** - * @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed - */ - ;(function(window, document) { - /*jshint evil:true */ - /** version */ - var version = '3.7.0'; - - /** Preset options */ - var options = window.html5 || {}; - - /** Used to skip problem elements */ - var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i; - - /** Not all elements can be cloned in IE **/ - var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i; - - /** Detect whether the browser supports default html5 styles */ - var supportsHtml5Styles; - - /** Name of the expando, to work with multiple documents or to re-shiv one document */ - var expando = '_html5shiv'; - - /** The id for the the documents expando */ - var expanID = 0; - - /** Cached data for each document */ - var expandoData = {}; - - /** Detect whether the browser supports unknown elements */ - var supportsUnknownElements; - - (function() { - try { - var a = document.createElement('a'); - a.innerHTML = ''; - //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles - supportsHtml5Styles = ('hidden' in a); - - supportsUnknownElements = a.childNodes.length == 1 || (function() { - // assign a false positive if unable to shiv - (document.createElement)('a'); - var frag = document.createDocumentFragment(); - return ( - typeof frag.cloneNode == 'undefined' || - typeof frag.createDocumentFragment == 'undefined' || - typeof frag.createElement == 'undefined' - ); - }()); - } catch(e) { - // assign a false positive if detection fails => unable to shiv - supportsHtml5Styles = true; - supportsUnknownElements = true; - } - - }()); - - /*--------------------------------------------------------------------------*/ - - /** - * Creates a style sheet with the given CSS text and adds it to the document. - * @private - * @param {Document} ownerDocument The document. - * @param {String} cssText The CSS text. - * @returns {StyleSheet} The style element. - */ - function addStyleSheet(ownerDocument, cssText) { - var p = ownerDocument.createElement('p'), - parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; - - p.innerHTML = 'x'; - return parent.insertBefore(p.lastChild, parent.firstChild); - } - - /** - * Returns the value of `html5.elements` as an array. - * @private - * @returns {Array} An array of shived element node names. - */ - function getElements() { - var elements = html5.elements; - return typeof elements == 'string' ? elements.split(' ') : elements; - } - - /** - * Returns the data associated to the given document - * @private - * @param {Document} ownerDocument The document. - * @returns {Object} An object of data. - */ - function getExpandoData(ownerDocument) { - var data = expandoData[ownerDocument[expando]]; - if (!data) { - data = {}; - expanID++; - ownerDocument[expando] = expanID; - expandoData[expanID] = data; - } - return data; - } - - /** - * returns a shived element for the given nodeName and document - * @memberOf html5 - * @param {String} nodeName name of the element - * @param {Document} ownerDocument The context document. - * @returns {Object} The shived element. - */ - function createElement(nodeName, ownerDocument, data){ - if (!ownerDocument) { - ownerDocument = document; - } - if(supportsUnknownElements){ - return ownerDocument.createElement(nodeName); - } - if (!data) { - data = getExpandoData(ownerDocument); - } - var node; - - if (data.cache[nodeName]) { - node = data.cache[nodeName].cloneNode(); - } else if (saveClones.test(nodeName)) { - node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); - } else { - node = data.createElem(nodeName); - } - - // Avoid adding some elements to fragments in IE < 9 because - // * Attributes like `name` or `type` cannot be set/changed once an element - // is inserted into a document/fragment - // * Link elements with `src` attributes that are inaccessible, as with - // a 403 response, will cause the tab/window to crash - // * Script elements appended to fragments will execute when their `src` - // or `text` property is set - return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node; - } - - /** - * returns a shived DocumentFragment for the given document - * @memberOf html5 - * @param {Document} ownerDocument The context document. - * @returns {Object} The shived DocumentFragment. - */ - function createDocumentFragment(ownerDocument, data){ - if (!ownerDocument) { - ownerDocument = document; - } - if(supportsUnknownElements){ - return ownerDocument.createDocumentFragment(); - } - data = data || getExpandoData(ownerDocument); - var clone = data.frag.cloneNode(), - i = 0, - elems = getElements(), - l = elems.length; - for(;i>shiv*/ - - // Assign private properties to the return object with prefix - Modernizr._version = version; - - // expose these for the plugin API. Look in the source for how to join() them against your input - /*>>prefixes*/ - Modernizr._prefixes = prefixes; - /*>>prefixes*/ - /*>>domprefixes*/ - Modernizr._domPrefixes = domPrefixes; - Modernizr._cssomPrefixes = cssomPrefixes; - /*>>domprefixes*/ - - /*>>mq*/ - // Modernizr.mq tests a given media query, live against the current state of the window - // A few important notes: - // * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false - // * A max-width or orientation query will be evaluated against the current state, which may change later. - // * You must specify values. Eg. If you are testing support for the min-width media query use: - // Modernizr.mq('(min-width:0)') - // usage: - // Modernizr.mq('only screen and (max-width:768)') - Modernizr.mq = testMediaQuery; - /*>>mq*/ - - /*>>hasevent*/ - // Modernizr.hasEvent() detects support for a given event, with an optional element to test on - // Modernizr.hasEvent('gesturestart', elem) - Modernizr.hasEvent = isEventSupported; - /*>>hasevent*/ - - /*>>testprop*/ - // Modernizr.testProp() investigates whether a given style property is recognized - // Note that the property names must be provided in the camelCase variant. - // Modernizr.testProp('pointerEvents') - Modernizr.testProp = function(prop){ - return testProps([prop]); - }; - /*>>testprop*/ - - /*>>testallprops*/ - // Modernizr.testAllProps() investigates whether a given style property, - // or any of its vendor-prefixed variants, is recognized - // Note that the property names must be provided in the camelCase variant. - // Modernizr.testAllProps('boxSizing') - Modernizr.testAllProps = testPropsAll; - /*>>testallprops*/ - - - /*>>teststyles*/ - // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards - // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... }) - Modernizr.testStyles = injectElementWithStyles; - /*>>teststyles*/ - - - /*>>prefixed*/ - // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input - // Modernizr.prefixed('boxSizing') // 'MozBoxSizing' - - // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style. - // Return values will also be the camelCase variant, if you need to translate that to hypenated style use: - // - // str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-'); - - // If you're trying to ascertain which transition end event to bind to, you might do something like... - // - // var transEndEventNames = { - // 'WebkitTransition' : 'webkitTransitionEnd', - // 'MozTransition' : 'transitionend', - // 'OTransition' : 'oTransitionEnd', - // 'msTransition' : 'MSTransitionEnd', - // 'transition' : 'transitionend' - // }, - // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ]; - - Modernizr.prefixed = function(prop, obj, elem){ - if(!obj) { - return testPropsAll(prop, 'pfx'); - } else { - // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame' - return testPropsAll(prop, obj, elem); - } - }; - /*>>prefixed*/ - - - /*>>cssclasses*/ - // Remove "no-js" class from element, if it exists: - docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') + - - // Add the new classes to the element. - (enableClasses ? ' js ' + classes.join(' ') : ''); - /*>>cssclasses*/ - - return Modernizr; - -})(this, this.document); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/modernizr-2.7.2.js b/src/Presentation/SmartStore.Web/Scripts/modernizr-2.7.2.js new file mode 100644 index 0000000000..6829dc3cef --- /dev/null +++ b/src/Presentation/SmartStore.Web/Scripts/modernizr-2.7.2.js @@ -0,0 +1,1406 @@ +/*! + * Modernizr v2.7.2 + * www.modernizr.com + * + * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton + * Available under the BSD and MIT licenses: www.modernizr.com/license/ + */ + +/* + * Modernizr tests which native CSS3 and HTML5 features are available in + * the current UA and makes the results available to you in two ways: + * as properties on a global Modernizr object, and as classes on the + * element. This information allows you to progressively enhance + * your pages with a granular level of control over the experience. + * + * Modernizr has an optional (not included) conditional resource loader + * called Modernizr.load(), based on Yepnope.js (yepnopejs.com). + * To get a build that includes Modernizr.load(), as well as choosing + * which tests to include, go to www.modernizr.com/download/ + * + * Authors Faruk Ates, Paul Irish, Alex Sexton + * Contributors Ryan Seddon, Ben Alman + */ + +window.Modernizr = (function( window, document, undefined ) { + + var version = '2.7.2', + + Modernizr = {}, + + /*>>cssclasses*/ + // option for enabling the HTML classes to be added + enableClasses = true, + /*>>cssclasses*/ + + docElement = document.documentElement, + + /** + * Create our "modernizr" element that we do most feature tests on. + */ + mod = 'modernizr', + modElem = document.createElement(mod), + mStyle = modElem.style, + + /** + * Create the input element for various Web Forms feature tests. + */ + inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ , + + /*>>smile*/ + smile = ':)', + /*>>smile*/ + + toString = {}.toString, + + // TODO :: make the prefixes more granular + /*>>prefixes*/ + // List of property values to set for css tests. See ticket #21 + prefixes = ' -webkit- -moz- -o- -ms- '.split(' '), + /*>>prefixes*/ + + /*>>domprefixes*/ + // Following spec is to expose vendor-specific style properties as: + // elem.style.WebkitBorderRadius + // and the following would be incorrect: + // elem.style.webkitBorderRadius + + // Webkit ghosts their properties in lowercase but Opera & Moz do not. + // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+ + // erik.eae.net/archives/2008/03/10/21.48.10/ + + // More here: github.com/Modernizr/Modernizr/issues/issue/21 + omPrefixes = 'Webkit Moz O ms', + + cssomPrefixes = omPrefixes.split(' '), + + domPrefixes = omPrefixes.toLowerCase().split(' '), + /*>>domprefixes*/ + + /*>>ns*/ + ns = {'svg': 'http://www.w3.org/2000/svg'}, + /*>>ns*/ + + tests = {}, + inputs = {}, + attrs = {}, + + classes = [], + + slice = classes.slice, + + featureName, // used in testing loop + + + /*>>teststyles*/ + // Inject element with style element and some CSS rules + injectElementWithStyles = function( rule, callback, nodes, testnames ) { + + var style, ret, node, docOverflow, + div = document.createElement('div'), + // After page load injecting a fake body doesn't work so check if body exists + body = document.body, + // IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it. + fakeBody = body || document.createElement('body'); + + if ( parseInt(nodes, 10) ) { + // In order not to give false positives we create a node for each test + // This also allows the method to scale for unspecified uses + while ( nodes-- ) { + node = document.createElement('div'); + node.id = testnames ? testnames[nodes] : mod + (nodes + 1); + div.appendChild(node); + } + } + + // '].join(''); + div.id = mod; + // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody. + // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270 + (body ? div : fakeBody).innerHTML += style; + fakeBody.appendChild(div); + if ( !body ) { + //avoid crashing IE8, if background image is used + fakeBody.style.background = ''; + //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible + fakeBody.style.overflow = 'hidden'; + docOverflow = docElement.style.overflow; + docElement.style.overflow = 'hidden'; + docElement.appendChild(fakeBody); + } + + ret = callback(div, rule); + // If this is done after page load we don't want to remove the body so check if body exists + if ( !body ) { + fakeBody.parentNode.removeChild(fakeBody); + docElement.style.overflow = docOverflow; + } else { + div.parentNode.removeChild(div); + } + + return !!ret; + + }, + /*>>teststyles*/ + + /*>>mq*/ + // adapted from matchMedia polyfill + // by Scott Jehl and Paul Irish + // gist.github.com/786768 + testMediaQuery = function( mq ) { + + var matchMedia = window.matchMedia || window.msMatchMedia; + if ( matchMedia ) { + return matchMedia(mq).matches; + } + + var bool; + + injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) { + bool = (window.getComputedStyle ? + getComputedStyle(node, null) : + node.currentStyle)['position'] == 'absolute'; + }); + + return bool; + + }, + /*>>mq*/ + + + /*>>hasevent*/ + // + // isEventSupported determines if a given element supports the given event + // kangax.github.com/iseventsupported/ + // + // The following results are known incorrects: + // Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative + // Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333 + // ... + isEventSupported = (function() { + + var TAGNAMES = { + 'select': 'input', 'change': 'input', + 'submit': 'form', 'reset': 'form', + 'error': 'img', 'load': 'img', 'abort': 'img' + }; + + function isEventSupported( eventName, element ) { + + element = element || document.createElement(TAGNAMES[eventName] || 'div'); + eventName = 'on' + eventName; + + // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those + var isSupported = eventName in element; + + if ( !isSupported ) { + // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element + if ( !element.setAttribute ) { + element = document.createElement('div'); + } + if ( element.setAttribute && element.removeAttribute ) { + element.setAttribute(eventName, ''); + isSupported = is(element[eventName], 'function'); + + // If property was created, "remove it" (by setting value to `undefined`) + if ( !is(element[eventName], 'undefined') ) { + element[eventName] = undefined; + } + element.removeAttribute(eventName); + } + } + + element = null; + return isSupported; + } + return isEventSupported; + })(), + /*>>hasevent*/ + + // TODO :: Add flag for hasownprop ? didn't last time + + // hasOwnProperty shim by kangax needed for Safari 2.0 support + _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp; + + if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) { + hasOwnProp = function (object, property) { + return _hasOwnProperty.call(object, property); + }; + } + else { + hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */ + return ((property in object) && is(object.constructor.prototype[property], 'undefined')); + }; + } + + // Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js + // es5.github.com/#x15.3.4.5 + + if (!Function.prototype.bind) { + Function.prototype.bind = function bind(that) { + + var target = this; + + if (typeof target != "function") { + throw new TypeError(); + } + + var args = slice.call(arguments, 1), + bound = function () { + + if (this instanceof bound) { + + var F = function(){}; + F.prototype = target.prototype; + var self = new F(); + + var result = target.apply( + self, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return self; + + } else { + + return target.apply( + that, + args.concat(slice.call(arguments)) + ); + + } + + }; + + return bound; + }; + } + + /** + * setCss applies given styles to the Modernizr DOM node. + */ + function setCss( str ) { + mStyle.cssText = str; + } + + /** + * setCssAll extrapolates all vendor-specific css strings. + */ + function setCssAll( str1, str2 ) { + return setCss(prefixes.join(str1 + ';') + ( str2 || '' )); + } + + /** + * is returns a boolean for if typeof obj is exactly type. + */ + function is( obj, type ) { + return typeof obj === type; + } + + /** + * contains returns a boolean for if substr is found within str. + */ + function contains( str, substr ) { + return !!~('' + str).indexOf(substr); + } + + /*>>testprop*/ + + // testProps is a generic CSS / DOM property test. + + // In testing support for a given CSS property, it's legit to test: + // `elem.style[styleName] !== undefined` + // If the property is supported it will return an empty string, + // if unsupported it will return undefined. + + // We'll take advantage of this quick test and skip setting a style + // on our modernizr element, but instead just testing undefined vs + // empty string. + + // Because the testing of the CSS property names (with "-", as + // opposed to the camelCase DOM properties) is non-portable and + // non-standard but works in WebKit and IE (but not Gecko or Opera), + // we explicitly reject properties with dashes so that authors + // developing in WebKit or IE first don't end up with + // browser-specific content by accident. + + function testProps( props, prefixed ) { + for ( var i in props ) { + var prop = props[i]; + if ( !contains(prop, "-") && mStyle[prop] !== undefined ) { + return prefixed == 'pfx' ? prop : true; + } + } + return false; + } + /*>>testprop*/ + + // TODO :: add testDOMProps + /** + * testDOMProps is a generic DOM property test; if a browser supports + * a certain property, it won't return undefined for it. + */ + function testDOMProps( props, obj, elem ) { + for ( var i in props ) { + var item = obj[props[i]]; + if ( item !== undefined) { + + // return the property name as a string + if (elem === false) return props[i]; + + // let's bind a function + if (is(item, 'function')){ + // default to autobind unless override + return item.bind(elem || obj); + } + + // return the unbound function or obj or value + return item; + } + } + return false; + } + + /*>>testallprops*/ + /** + * testPropsAll tests a list of DOM properties we want to check against. + * We specify literally ALL possible (known and/or likely) properties on + * the element including the non-vendor prefixed one, for forward- + * compatibility. + */ + function testPropsAll( prop, prefixed, elem ) { + + var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), + props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' '); + + // did they call .prefixed('boxSizing') or are we just testing a prop? + if(is(prefixed, "string") || is(prefixed, "undefined")) { + return testProps(props, prefixed); + + // otherwise, they called .prefixed('requestAnimationFrame', window[, elem]) + } else { + props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' '); + return testDOMProps(props, prefixed, elem); + } + } + /*>>testallprops*/ + + + /** + * Tests + * ----- + */ + + // The *new* flexbox + // dev.w3.org/csswg/css3-flexbox + + tests['flexbox'] = function() { + return testPropsAll('flexWrap'); + }; + + // The *old* flexbox + // www.w3.org/TR/2009/WD-css3-flexbox-20090723/ + + tests['flexboxlegacy'] = function() { + return testPropsAll('boxDirection'); + }; + + // On the S60 and BB Storm, getContext exists, but always returns undefined + // so we actually have to call getContext() to verify + // github.com/Modernizr/Modernizr/issues/issue/97/ + + tests['canvas'] = function() { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('2d')); + }; + + tests['canvastext'] = function() { + return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function')); + }; + + // webk.it/70117 is tracking a legit WebGL feature detect proposal + + // We do a soft detect which may false positive in order to avoid + // an expensive context creation: bugzil.la/732441 + + tests['webgl'] = function() { + return !!window.WebGLRenderingContext; + }; + + /* + * The Modernizr.touch test only indicates if the browser supports + * touch events, which does not necessarily reflect a touchscreen + * device, as evidenced by tablets running Windows 7 or, alas, + * the Palm Pre / WebOS (touch) phones. + * + * Additionally, Chrome (desktop) used to lie about its support on this, + * but that has since been rectified: crbug.com/36415 + * + * We also test for Firefox 4 Multitouch Support. + * + * For more info, see: modernizr.github.com/Modernizr/touch.html + */ + + tests['touch'] = function() { + var bool; + + if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { + bool = true; + } else { + injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) { + bool = node.offsetTop === 9; + }); + } + + return bool; + }; + + + // geolocation is often considered a trivial feature detect... + // Turns out, it's quite tricky to get right: + // + // Using !!navigator.geolocation does two things we don't want. It: + // 1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513 + // 2. Disables page caching in WebKit: webk.it/43956 + // + // Meanwhile, in Firefox < 8, an about:config setting could expose + // a false positive that would throw an exception: bugzil.la/688158 + + tests['geolocation'] = function() { + return 'geolocation' in navigator; + }; + + + tests['postmessage'] = function() { + return !!window.postMessage; + }; + + + // Chrome incognito mode used to throw an exception when using openDatabase + // It doesn't anymore. + tests['websqldatabase'] = function() { + return !!window.openDatabase; + }; + + // Vendors had inconsistent prefixing with the experimental Indexed DB: + // - Webkit's implementation is accessible through webkitIndexedDB + // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB + // For speed, we don't test the legacy (and beta-only) indexedDB + tests['indexedDB'] = function() { + return !!testPropsAll("indexedDB", window); + }; + + // documentMode logic from YUI to filter out IE8 Compat Mode + // which false positives. + tests['hashchange'] = function() { + return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7); + }; + + // Per 1.6: + // This used to be Modernizr.historymanagement but the longer + // name has been deprecated in favor of a shorter and property-matching one. + // The old API is still available in 1.6, but as of 2.0 will throw a warning, + // and in the first release thereafter disappear entirely. + tests['history'] = function() { + return !!(window.history && history.pushState); + }; + + tests['draganddrop'] = function() { + var div = document.createElement('div'); + return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div); + }; + + // FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10 + // will be supported until FF19 (2/12/13), at which time, ESR becomes FF17. + // FF10 still uses prefixes, so check for it until then. + // for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/ + tests['websockets'] = function() { + return 'WebSocket' in window || 'MozWebSocket' in window; + }; + + + // css-tricks.com/rgba-browser-support/ + tests['rgba'] = function() { + // Set an rgba() color and check the returned value + + setCss('background-color:rgba(150,255,150,.5)'); + + return contains(mStyle.backgroundColor, 'rgba'); + }; + + tests['hsla'] = function() { + // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally, + // except IE9 who retains it as hsla + + setCss('background-color:hsla(120,40%,100%,.5)'); + + return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla'); + }; + + tests['multiplebgs'] = function() { + // Setting multiple images AND a color on the background shorthand property + // and then querying the style.background property value for the number of + // occurrences of "url(" is a reliable method for detecting ACTUAL support for this! + + setCss('background:url(https://),url(https://),red url(https://)'); + + // If the UA supports multiple backgrounds, there should be three occurrences + // of the string "url(" in the return value for elemStyle.background + + return (/(url\s*\(.*?){3}/).test(mStyle.background); + }; + + + + // this will false positive in Opera Mini + // github.com/Modernizr/Modernizr/issues/396 + + tests['backgroundsize'] = function() { + return testPropsAll('backgroundSize'); + }; + + tests['borderimage'] = function() { + return testPropsAll('borderImage'); + }; + + + // Super comprehensive table about all the unique implementations of + // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance + + tests['borderradius'] = function() { + return testPropsAll('borderRadius'); + }; + + // WebOS unfortunately false positives on this test. + tests['boxshadow'] = function() { + return testPropsAll('boxShadow'); + }; + + // FF3.0 will false positive on this test + tests['textshadow'] = function() { + return document.createElement('div').style.textShadow === ''; + }; + + + tests['opacity'] = function() { + // Browsers that actually have CSS Opacity implemented have done so + // according to spec, which means their return values are within the + // range of [0.0,1.0] - including the leading zero. + + setCssAll('opacity:.55'); + + // The non-literal . in this regex is intentional: + // German Chrome returns this value as 0,55 + // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632 + return (/^0.55$/).test(mStyle.opacity); + }; + + + // Note, Android < 4 will pass this test, but can only animate + // a single property at a time + // goo.gl/v3V4Gp + tests['cssanimations'] = function() { + return testPropsAll('animationName'); + }; + + + tests['csscolumns'] = function() { + return testPropsAll('columnCount'); + }; + + + tests['cssgradients'] = function() { + /** + * For CSS Gradients syntax, please see: + * webkit.org/blog/175/introducing-css-gradients/ + * developer.mozilla.org/en/CSS/-moz-linear-gradient + * developer.mozilla.org/en/CSS/-moz-radial-gradient + * dev.w3.org/csswg/css3-images/#gradients- + */ + + var str1 = 'background-image:', + str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));', + str3 = 'linear-gradient(left top,#9f9, white);'; + + setCss( + // legacy webkit syntax (FIXME: remove when syntax not in use anymore) + (str1 + '-webkit- '.split(' ').join(str2 + str1) + + // standard syntax // trailing 'background-image:' + prefixes.join(str3 + str1)).slice(0, -str1.length) + ); + + return contains(mStyle.backgroundImage, 'gradient'); + }; + + + tests['cssreflections'] = function() { + return testPropsAll('boxReflect'); + }; + + + tests['csstransforms'] = function() { + return !!testPropsAll('transform'); + }; + + + tests['csstransforms3d'] = function() { + + var ret = !!testPropsAll('perspective'); + + // Webkit's 3D transforms are passed off to the browser's own graphics renderer. + // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in + // some conditions. As a result, Webkit typically recognizes the syntax but + // will sometimes throw a false positive, thus we must do a more thorough check: + if ( ret && 'webkitPerspective' in docElement.style ) { + + // Webkit allows this media query to succeed only if the feature is enabled. + // `@media (transform-3d),(-webkit-transform-3d){ ... }` + injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) { + ret = node.offsetLeft === 9 && node.offsetHeight === 3; + }); + } + return ret; + }; + + + tests['csstransitions'] = function() { + return testPropsAll('transition'); + }; + + + /*>>fontface*/ + // @font-face detection routine by Diego Perini + // javascript.nwbox.com/CSSSupport/ + + // false positives: + // WebOS github.com/Modernizr/Modernizr/issues/342 + // WP7 github.com/Modernizr/Modernizr/issues/538 + tests['fontface'] = function() { + var bool; + + injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) { + var style = document.getElementById('smodernizr'), + sheet = style.sheet || style.styleSheet, + cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : ''; + + bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0; + }); + + return bool; + }; + /*>>fontface*/ + + // CSS generated content detection + tests['generatedcontent'] = function() { + var bool; + + injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) { + bool = node.offsetHeight >= 3; + }); + + return bool; + }; + + + + // These tests evaluate support of the video/audio elements, as well as + // testing what types of content they support. + // + // We're using the Boolean constructor here, so that we can extend the value + // e.g. Modernizr.video // true + // Modernizr.video.ogg // 'probably' + // + // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845 + // thx to NielsLeenheer and zcorpan + + // Note: in some older browsers, "no" was a return value instead of empty string. + // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2 + // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5 + + tests['video'] = function() { + var elem = document.createElement('video'), + bool = false; + + // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224 + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,''); + + // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546 + bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,''); + + bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,''); + } + + } catch(e) { } + + return bool; + }; + + tests['audio'] = function() { + var elem = document.createElement('audio'), + bool = false; + + try { + if ( bool = !!elem.canPlayType ) { + bool = new Boolean(bool); + bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,''); + bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,''); + + // Mimetypes accepted: + // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements + // bit.ly/iphoneoscodecs + bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,''); + bool.m4a = ( elem.canPlayType('audio/x-m4a;') || + elem.canPlayType('audio/aac;')) .replace(/^no$/,''); + } + } catch(e) { } + + return bool; + }; + + + // In FF4, if disabled, window.localStorage should === null. + + // Normally, we could not test that directly and need to do a + // `('localStorage' in window) && ` test first because otherwise Firefox will + // throw bugzil.la/365772 if cookies are disabled + + // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem + // will throw the exception: + // QUOTA_EXCEEDED_ERRROR DOM Exception 22. + // Peculiarly, getItem and removeItem calls do not throw. + + // Because we are forced to try/catch this, we'll go aggressive. + + // Just FWIW: IE8 Compat mode supports these features completely: + // www.quirksmode.org/dom/html5.html + // But IE8 doesn't support either with local files + + tests['localstorage'] = function() { + try { + localStorage.setItem(mod, mod); + localStorage.removeItem(mod); + return true; + } catch(e) { + return false; + } + }; + + tests['sessionstorage'] = function() { + try { + sessionStorage.setItem(mod, mod); + sessionStorage.removeItem(mod); + return true; + } catch(e) { + return false; + } + }; + + + tests['webworkers'] = function() { + return !!window.Worker; + }; + + + tests['applicationcache'] = function() { + return !!window.applicationCache; + }; + + + // Thanks to Erik Dahlstrom + tests['svg'] = function() { + return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect; + }; + + // specifically for SVG inline in HTML, not within XHTML + // test page: paulirish.com/demo/inline-svg + tests['inlinesvg'] = function() { + var div = document.createElement('div'); + div.innerHTML = ''; + return (div.firstChild && div.firstChild.namespaceURI) == ns.svg; + }; + + // SVG SMIL animation + tests['smil'] = function() { + return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate'))); + }; + + // This test is only for clip paths in SVG proper, not clip paths on HTML content + // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg + + // However read the comments to dig into applying SVG clippaths to HTML content here: + // github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491 + tests['svgclippaths'] = function() { + return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath'))); + }; + + /*>>webforms*/ + // input features and input types go directly onto the ret object, bypassing the tests loop. + // Hold this guy to execute in a moment. + function webforms() { + /*>>input*/ + // Run through HTML5's new input attributes to see if the UA understands any. + // We're using f which is the element created early on + // Mike Taylr has created a comprehensive resource for testing these attributes + // when applied to all input types: + // miketaylr.com/code/input-type-attr.html + // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary + + // Only input placeholder is tested while textarea's placeholder is not. + // Currently Safari 4 and Opera 11 have support only for the input placeholder + // Both tests are available in feature-detects/forms-placeholder.js + Modernizr['input'] = (function( props ) { + for ( var i = 0, len = props.length; i < len; i++ ) { + attrs[ props[i] ] = !!(props[i] in inputElem); + } + if (attrs.list){ + // safari false positive's on datalist: webk.it/74252 + // see also github.com/Modernizr/Modernizr/issues/146 + attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement); + } + return attrs; + })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ')); + /*>>input*/ + + /*>>inputtypes*/ + // Run through HTML5's new input types to see if the UA understands any. + // This is put behind the tests runloop because it doesn't return a + // true/false like all the other tests; instead, it returns an object + // containing each input type with its corresponding true/false value + + // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/ + Modernizr['inputtypes'] = (function(props) { + + for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) { + + inputElem.setAttribute('type', inputElemType = props[i]); + bool = inputElem.type !== 'text'; + + // We first check to see if the type we give it sticks.. + // If the type does, we feed it a textual value, which shouldn't be valid. + // If the value doesn't stick, we know there's input sanitization which infers a custom UI + if ( bool ) { + + inputElem.value = smile; + inputElem.style.cssText = 'position:absolute;visibility:hidden;'; + + if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) { + + docElement.appendChild(inputElem); + defaultView = document.defaultView; + + // Safari 2-4 allows the smiley as a value, despite making a slider + bool = defaultView.getComputedStyle && + defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' && + // Mobile android web browser has false positive, so must + // check the height to see if the widget is actually there. + (inputElem.offsetHeight !== 0); + + docElement.removeChild(inputElem); + + } else if ( /^(search|tel)$/.test(inputElemType) ){ + // Spec doesn't define any special parsing or detectable UI + // behaviors so we pass these through as true + + // Interestingly, opera fails the earlier test, so it doesn't + // even make it here. + + } else if ( /^(url|email)$/.test(inputElemType) ) { + // Real url and email support comes with prebaked validation. + bool = inputElem.checkValidity && inputElem.checkValidity() === false; + + } else { + // If the upgraded input compontent rejects the :) text, we got a winner + bool = inputElem.value != smile; + } + } + + inputs[ props[i] ] = !!bool; + } + return inputs; + })('search tel url email datetime date month week time datetime-local number range color'.split(' ')); + /*>>inputtypes*/ + } + /*>>webforms*/ + + + // End of test definitions + // ----------------------- + + + + // Run through all tests and detect their support in the current UA. + // todo: hypothetically we could be doing an array of tests and use a basic loop here. + for ( var feature in tests ) { + if ( hasOwnProp(tests, feature) ) { + // run the test, throw the return value into the Modernizr, + // then based on that boolean, define an appropriate className + // and push it into an array of classes we'll join later. + featureName = feature.toLowerCase(); + Modernizr[featureName] = tests[feature](); + + classes.push((Modernizr[featureName] ? '' : 'no-') + featureName); + } + } + + /*>>webforms*/ + // input tests need to run. + Modernizr.input || webforms(); + /*>>webforms*/ + + + /** + * addTest allows the user to define their own feature tests + * the result will be added onto the Modernizr object, + * as well as an appropriate className set on the html element + * + * @param feature - String naming the feature + * @param test - Function returning true if feature is supported, false if not + */ + Modernizr.addTest = function ( feature, test ) { + if ( typeof feature == 'object' ) { + for ( var key in feature ) { + if ( hasOwnProp( feature, key ) ) { + Modernizr.addTest( key, feature[ key ] ); + } + } + } else { + + feature = feature.toLowerCase(); + + if ( Modernizr[feature] !== undefined ) { + // we're going to quit if you're trying to overwrite an existing test + // if we were to allow it, we'd do this: + // var re = new RegExp("\\b(no-)?" + feature + "\\b"); + // docElement.className = docElement.className.replace( re, '' ); + // but, no rly, stuff 'em. + return Modernizr; + } + + test = typeof test == 'function' ? test() : test; + + if (typeof enableClasses !== "undefined" && enableClasses) { + docElement.className += ' ' + (test ? '' : 'no-') + feature; + } + Modernizr[feature] = test; + + } + + return Modernizr; // allow chaining. + }; + + + // Reset modElem.cssText to nothing to reduce memory footprint. + setCss(''); + modElem = inputElem = null; + + /*>>shiv*/ + /** + * @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed + */ + ;(function(window, document) { + /*jshint evil:true */ + /** version */ + var version = '3.7.0'; + + /** Preset options */ + var options = window.html5 || {}; + + /** Used to skip problem elements */ + var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i; + + /** Not all elements can be cloned in IE **/ + var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i; + + /** Detect whether the browser supports default html5 styles */ + var supportsHtml5Styles; + + /** Name of the expando, to work with multiple documents or to re-shiv one document */ + var expando = '_html5shiv'; + + /** The id for the the documents expando */ + var expanID = 0; + + /** Cached data for each document */ + var expandoData = {}; + + /** Detect whether the browser supports unknown elements */ + var supportsUnknownElements; + + (function() { + try { + var a = document.createElement('a'); + a.innerHTML = ''; + //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles + supportsHtml5Styles = ('hidden' in a); + + supportsUnknownElements = a.childNodes.length == 1 || (function() { + // assign a false positive if unable to shiv + (document.createElement)('a'); + var frag = document.createDocumentFragment(); + return ( + typeof frag.cloneNode == 'undefined' || + typeof frag.createDocumentFragment == 'undefined' || + typeof frag.createElement == 'undefined' + ); + }()); + } catch(e) { + // assign a false positive if detection fails => unable to shiv + supportsHtml5Styles = true; + supportsUnknownElements = true; + } + + }()); + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a style sheet with the given CSS text and adds it to the document. + * @private + * @param {Document} ownerDocument The document. + * @param {String} cssText The CSS text. + * @returns {StyleSheet} The style element. + */ + function addStyleSheet(ownerDocument, cssText) { + var p = ownerDocument.createElement('p'), + parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement; + + p.innerHTML = 'x'; + return parent.insertBefore(p.lastChild, parent.firstChild); + } + + /** + * Returns the value of `html5.elements` as an array. + * @private + * @returns {Array} An array of shived element node names. + */ + function getElements() { + var elements = html5.elements; + return typeof elements == 'string' ? elements.split(' ') : elements; + } + + /** + * Returns the data associated to the given document + * @private + * @param {Document} ownerDocument The document. + * @returns {Object} An object of data. + */ + function getExpandoData(ownerDocument) { + var data = expandoData[ownerDocument[expando]]; + if (!data) { + data = {}; + expanID++; + ownerDocument[expando] = expanID; + expandoData[expanID] = data; + } + return data; + } + + /** + * returns a shived element for the given nodeName and document + * @memberOf html5 + * @param {String} nodeName name of the element + * @param {Document} ownerDocument The context document. + * @returns {Object} The shived element. + */ + function createElement(nodeName, ownerDocument, data){ + if (!ownerDocument) { + ownerDocument = document; + } + if(supportsUnknownElements){ + return ownerDocument.createElement(nodeName); + } + if (!data) { + data = getExpandoData(ownerDocument); + } + var node; + + if (data.cache[nodeName]) { + node = data.cache[nodeName].cloneNode(); + } else if (saveClones.test(nodeName)) { + node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode(); + } else { + node = data.createElem(nodeName); + } + + // Avoid adding some elements to fragments in IE < 9 because + // * Attributes like `name` or `type` cannot be set/changed once an element + // is inserted into a document/fragment + // * Link elements with `src` attributes that are inaccessible, as with + // a 403 response, will cause the tab/window to crash + // * Script elements appended to fragments will execute when their `src` + // or `text` property is set + return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node; + } + + /** + * returns a shived DocumentFragment for the given document + * @memberOf html5 + * @param {Document} ownerDocument The context document. + * @returns {Object} The shived DocumentFragment. + */ + function createDocumentFragment(ownerDocument, data){ + if (!ownerDocument) { + ownerDocument = document; + } + if(supportsUnknownElements){ + return ownerDocument.createDocumentFragment(); + } + data = data || getExpandoData(ownerDocument); + var clone = data.frag.cloneNode(), + i = 0, + elems = getElements(), + l = elems.length; + for(;i>shiv*/ + + // Assign private properties to the return object with prefix + Modernizr._version = version; + + // expose these for the plugin API. Look in the source for how to join() them against your input + /*>>prefixes*/ + Modernizr._prefixes = prefixes; + /*>>prefixes*/ + /*>>domprefixes*/ + Modernizr._domPrefixes = domPrefixes; + Modernizr._cssomPrefixes = cssomPrefixes; + /*>>domprefixes*/ + + /*>>mq*/ + // Modernizr.mq tests a given media query, live against the current state of the window + // A few important notes: + // * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false + // * A max-width or orientation query will be evaluated against the current state, which may change later. + // * You must specify values. Eg. If you are testing support for the min-width media query use: + // Modernizr.mq('(min-width:0)') + // usage: + // Modernizr.mq('only screen and (max-width:768)') + Modernizr.mq = testMediaQuery; + /*>>mq*/ + + /*>>hasevent*/ + // Modernizr.hasEvent() detects support for a given event, with an optional element to test on + // Modernizr.hasEvent('gesturestart', elem) + Modernizr.hasEvent = isEventSupported; + /*>>hasevent*/ + + /*>>testprop*/ + // Modernizr.testProp() investigates whether a given style property is recognized + // Note that the property names must be provided in the camelCase variant. + // Modernizr.testProp('pointerEvents') + Modernizr.testProp = function(prop){ + return testProps([prop]); + }; + /*>>testprop*/ + + /*>>testallprops*/ + // Modernizr.testAllProps() investigates whether a given style property, + // or any of its vendor-prefixed variants, is recognized + // Note that the property names must be provided in the camelCase variant. + // Modernizr.testAllProps('boxSizing') + Modernizr.testAllProps = testPropsAll; + /*>>testallprops*/ + + + /*>>teststyles*/ + // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards + // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... }) + Modernizr.testStyles = injectElementWithStyles; + /*>>teststyles*/ + + + /*>>prefixed*/ + // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input + // Modernizr.prefixed('boxSizing') // 'MozBoxSizing' + + // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style. + // Return values will also be the camelCase variant, if you need to translate that to hypenated style use: + // + // str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-'); + + // If you're trying to ascertain which transition end event to bind to, you might do something like... + // + // var transEndEventNames = { + // 'WebkitTransition' : 'webkitTransitionEnd', + // 'MozTransition' : 'transitionend', + // 'OTransition' : 'oTransitionEnd', + // 'msTransition' : 'MSTransitionEnd', + // 'transition' : 'transitionend' + // }, + // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ]; + + Modernizr.prefixed = function(prop, obj, elem){ + if(!obj) { + return testPropsAll(prop, 'pfx'); + } else { + // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame' + return testPropsAll(prop, obj, elem); + } + }; + /*>>prefixed*/ + + + /*>>cssclasses*/ + // Remove "no-js" class from element, if it exists: + docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') + + + // Add the new classes to the element. + (enableClasses ? ' js ' + classes.join(' ') : ''); + /*>>cssclasses*/ + + return Modernizr; + +})(this, this.document); diff --git a/src/Presentation/SmartStore.Web/Scripts/public.accordion.js b/src/Presentation/SmartStore.Web/Scripts/public.accordion.js deleted file mode 100644 index 61234600fc..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/public.accordion.js +++ /dev/null @@ -1,98 +0,0 @@ -var Accordion = { - checkAllow: false, - disallowAccessToNextSections: false, - sections: new Array(), - currentSection: false, - headers: new Array(), - - init: function (elem, clickableEntity, checkAllow) { - this.checkAllow = checkAllow || false; - this.disallowAccessToNextSections = false; - this.sections = $('#' + elem + ' .section'); - this.currentSectionId = false; - var headers = $('#' + elem + ' .section ' + clickableEntity); - headers.click(function () { - Accordion.headerClicked($(this)); - }); - }, - - headerClicked: function (section) { - Accordion.openSection(section.parent('.section')); - }, - - openSection: function (section) { - var section = $(section); - - if (this.checkAllow && !section.hasClass('allow')) { - return; - } - if (section.attr('id') != this.currentSectionId) { - this.closeExistingSection(); - this.currentSectionId = section.attr('id'); - $('#' + this.currentSectionId).addClass('active'); - var contents = section.children('.a-item'); - $(contents[0]).show(); - - - if (this.disallowAccessToNextSections) { - var pastCurrentSection = false; - for (var i = 0; i < this.sections.length; i++) { - if (pastCurrentSection) { - $(this.sections[i]).removeClass('allow') - } - if ($(this.sections[i]).attr('id') == section.attr('id')) { - pastCurrentSection = true; - } - } - } - } - }, - - closeSection: function (section) { - var section = $(section); - section.removeClass('active'); - var contents = section.children('.a-item'); - $(contents[0]).hide(); - }, - - openNextSection: function (setAllow) { - for (section in this.sections) { - var nextIndex = parseInt(section) + 1; - if (this.sections[section].id == this.currentSectionId && this.sections[nextIndex]) { - if (setAllow) { - $(this.sections[nextIndex]).addClass('allow') - } - this.openSection(this.sections[nextIndex]); - return; - } - } - }, - - openPrevSection: function (setAllow, onlyAllowed) { - var prevIndex = 0; - for (section in this.sections) { - if (onlyAllowed) { - //ensure that the section is allowed - var tmp = parseInt(section) - 1; - if (!isNaN(tmp) && $(this.sections[tmp]).hasClass('allow')) { - prevIndex = tmp; - } - } else { - prevIndex = parseInt(section) - 1; - } - if (this.sections[section].id == this.currentSectionId && this.sections[prevIndex]) { - if (setAllow) { - $(this.sections[prevIndex]).addClass('allow') - } - this.openSection(this.sections[prevIndex]); - return; - } - } - }, - - closeExistingSection: function () { - if (this.currentSectionId) { - this.closeSection($('#' + this.currentSectionId)); - } - } -}; \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/public.onepagecheckout.js b/src/Presentation/SmartStore.Web/Scripts/public.onepagecheckout.js deleted file mode 100644 index 0bb2000e0d..0000000000 --- a/src/Presentation/SmartStore.Web/Scripts/public.onepagecheckout.js +++ /dev/null @@ -1,455 +0,0 @@ -var Checkout = { - loadWaiting: false, - failureUrl: false, - steps: new Array(), - - init: function (failureUrl) { - this.loadWaiting = false; - this.failureUrl = failureUrl; - this.steps = ['billing', 'shipping', 'shipping_method', 'payment_method', 'payment_info', 'confirm_order']; - - Accordion.disallowAccessToNextSections = true; - }, - - ajaxFailure: function () { - location.href = Checkout.failureUrl; - }, - - _disableEnableAll: function (element, isDisabled) { - var descendants = element.find('*'); - $(descendants).each(function() { - if (isDisabled) { - $(this).attr('disabled', 'disabled'); - } else { - $(this).removeAttr('disabled'); - } - }); - - if (isDisabled) { - element.attr('disabled', 'disabled'); - } else { - element.removeAttr('disabled'); - } - }, - - setLoadWaiting: function (step, keepDisabled) { - if (step) { - if (this.loadWaiting) { - this.setLoadWaiting(false); - } - var container = $('#' + step + '-buttons-container'); - container.addClass('disabled'); - container.css('opacity', '.5'); - this._disableEnableAll(container, true); - $('#' + step + '-please-wait').show(); - } else { - if (this.loadWaiting) { - var container = $('#' + this.loadWaiting + '-buttons-container'); - var isDisabled = (keepDisabled ? true : false); - if (!isDisabled) { - container.removeClass('disabled'); - container.css('opacity', '1'); - } - this._disableEnableAll(container, isDisabled); - $('#' + this.loadWaiting + '-please-wait').hide(); - } - } - this.loadWaiting = step; - }, - - gotoSection: function (section) { - section = $('#opc-' + section); - section.addClass('allow'); - applyCommonPlugins(section); //codehint: sm-add - Accordion.openSection(section); - }, - - back: function () { - if (this.loadWaiting) return; - Accordion.openPrevSection(true, true); - }, - - setStepResponse: function (response) { - if (response.update_section) { - $('#checkout-' + response.update_section.name + '-load').html(response.update_section.html); - } - if (response.allow_sections) { - response.allow_sections.each(function (e) { - $('#opc-' + e).addClass('allow'); - }); - } - - applyCommonPlugins($("body")); - - //TODO move it to a new method - if ($("#billing-address-select").length > 0) { - Billing.newAddress(!$('#billing-address-select').val()); - } - if ($("#shipping-address-select").length > 0) { - Shipping.newAddress(!$('#shipping-address-select').val()); - } - - if (response.goto_section) { - Checkout.gotoSection(response.goto_section); - return true; - } - if (response.redirect) { - location.href = response.redirect; - return true; - } - return false; - } -}; - - - - - -var Billing = { - form: false, - saveUrl: false, - - init: function (form, saveUrl) { - this.form = form; - this.saveUrl = saveUrl; - }, - - newAddress: function (isNew) { - if (isNew) { - this.resetSelectedAddress(); - $('#billing-new-address-form').show(); - } else { - $('#billing-new-address-form').hide(); - } - }, - - resetSelectedAddress: function () { - var selectElement = $('#billing-address-select') - if (selectElement) { - selectElement.value = ''; - } - }, - - save: function () { - if (Checkout.loadWaiting != false) return; - - Checkout.setLoadWaiting('billing'); - - console.log(this.saveUrl); - - $.ajax({ - url: this.saveUrl, - data: $(this.form).serialize(), - type: 'post', - success: this.nextStep, - complete: this.resetLoadWaiting, - error: function (xhr, ajaxOptions, thrownError) { - //Checkout.ajaxFailure - alert(xhr.status); - alert(thrownError); - } - }); - }, - - resetLoadWaiting: function () { - Checkout.setLoadWaiting(false); - }, - - nextStep: function (response) { - if (response.error) { - if ((typeof response.message) == 'string') { - alert(response.message); - } else { - alert(response.message.join("\n")); - } - - return false; - } - - Checkout.setStepResponse(response); - } -}; - - - -var Shipping = { - form: false, - saveUrl: false, - - init: function (form, saveUrl) { - this.form = form; - this.saveUrl = saveUrl; - }, - - newAddress: function (isNew) { - if (isNew) { - this.resetSelectedAddress(); - $('#shipping-new-address-form').show(); - } else { - $('#shipping-new-address-form').hide(); - } - }, - - resetSelectedAddress: function () { - var selectElement = $('#shipping-address-select') - if (selectElement) { - selectElement.value = ''; - } - }, - - save: function () { - if (Checkout.loadWaiting != false) return; - - Checkout.setLoadWaiting('shipping'); - - $.ajax({ - url: this.saveUrl, - data: $(this.form).serialize(), - type: 'post', - success: this.nextStep, - complete: this.resetLoadWaiting, - error: Checkout.ajaxFailure - }); - }, - - resetLoadWaiting: function () { - Checkout.setLoadWaiting(false); - }, - - nextStep: function (response) { - if (response.error) { - if ((typeof response.message) == 'string') { - alert(response.message); - } else { - alert(response.message.join("\n")); - } - - return false; - } - - Checkout.setStepResponse(response); - } -}; - - - -var ShippingMethod = { - form: false, - saveUrl: false, - - init: function (form, saveUrl) { - this.form = form; - this.saveUrl = saveUrl; - }, - - validate: function() { - var methods = document.getElementsByName('shippingoption'); - if (methods.length==0) { - alert('Your order cannot be completed at this time as there is no shipping methods available for it. Please make necessary changes in your shipping address.'); - return false; - } - - for (var i = 0; i< methods.length; i++) { - if (methods[i].checked) { - return true; - } - } - alert('Please specify shipping method.'); - return false; - }, - - save: function () { - if (Checkout.loadWaiting != false) return; - - if (this.validate()) { - Checkout.setLoadWaiting('shipping-method'); - - $.ajax({ - url: this.saveUrl, - data: $(this.form).serialize(), - type: 'post', - success: this.nextStep, - complete: this.resetLoadWaiting, - error: Checkout.ajaxFailure - }); - } - }, - - resetLoadWaiting: function () { - Checkout.setLoadWaiting(false); - }, - - nextStep: function (response) { - if (response.error) { - if ((typeof response.message) == 'string') { - alert(response.message); - } else { - alert(response.message.join("\n")); - } - - return false; - } - - Checkout.setStepResponse(response); - } -}; - - - -var PaymentMethod = { - form: false, - saveUrl: false, - - init: function (form, saveUrl) { - this.form = form; - this.saveUrl = saveUrl; - }, - - validate: function () { - var methods = document.getElementsByName('paymentmethod'); - if (methods.length == 0) { - alert('Your order cannot be completed at this time as there is no payment methods available for it.'); - return false; - } - - for (var i = 0; i < methods.length; i++) { - if (methods[i].checked) { - return true; - } - } - alert('Please specify payment method.'); - return false; - }, - - save: function () { - if (Checkout.loadWaiting != false) return; - - if (this.validate()) { - Checkout.setLoadWaiting('payment-method'); - $.ajax({ - url: this.saveUrl, - data: $(this.form).serialize(), - type: 'post', - success: this.nextStep, - complete: this.resetLoadWaiting, - error: Checkout.ajaxFailure - }); - } - }, - - resetLoadWaiting: function () { - Checkout.setLoadWaiting(false); - }, - - nextStep: function (response) { - if (response.error) { - if ((typeof response.message) == 'string') { - alert(response.message); - } else { - alert(response.message.join("\n")); - } - - return false; - } - - Checkout.setStepResponse(response); - } -}; - - - -var PaymentInfo = { - form: false, - saveUrl: false, - - init: function (form, saveUrl) { - this.form = form; - this.saveUrl = saveUrl; - }, - - save: function () { - if (Checkout.loadWaiting != false) return; - - Checkout.setLoadWaiting('payment-info'); - $.ajax({ - url: this.saveUrl, - data: $(this.form).serialize(), - type: 'post', - success: this.nextStep, - complete: this.resetLoadWaiting, - error: Checkout.ajaxFailure - }); - }, - - resetLoadWaiting: function () { - Checkout.setLoadWaiting(false); - }, - - nextStep: function (response) { - if (response.error) { - if ((typeof response.message) == 'string') { - alert(response.message); - } else { - alert(response.message.join("\n")); - } - - return false; - } - - Checkout.setStepResponse(response); - } -}; - - - -var ConfirmOrder = { - form: false, - saveUrl: false, - isSuccess: false, - - init: function (saveUrl, successUrl) { - this.saveUrl = saveUrl; - this.successUrl = successUrl; - }, - - save: function () { - if (Checkout.loadWaiting != false) return; - - Checkout.setLoadWaiting('confirm-order'); - $.ajax({ - url: this.saveUrl, - type: 'post', - success: this.nextStep, - complete: this.resetLoadWaiting, - error: Checkout.ajaxFailure - }); - }, - - resetLoadWaiting: function (transport) { - Checkout.setLoadWaiting(false, ConfirmOrder.isSuccess); - }, - - nextStep: function (response) { - if (response.error) { - if ((typeof response.message) == 'string') { - alert(response.message); - } else { - alert(response.message.join("\n")); - } - - return false; - } - - if (response.redirect) { - ConfirmOrder.isSuccess = true; - location.href = response.redirect; - return; - } - if (response.success) { - ConfirmOrder.isSuccess = true; - window.location = ConfirmOrder.successUrl; - } - - Checkout.setStepResponse(response); - } -}; \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js b/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js index 6d91bed4a5..90e9d734aa 100644 --- a/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js +++ b/src/Presentation/SmartStore.Web/Scripts/public.product-detail.js @@ -25,15 +25,25 @@ // update product data and gallery $(el).find(':input').change(function () { + var inputType = $(this).attr('type'); + if (inputType && (inputType === 'file' || inputType === 'submit')) + return this; + var context = $(this).closest('.update-container'); - if (context[0]) { // associated or bundled item + if (context[0]) { } else { context = el; } - context.doAjax({ + var url = context.attr('data-url'); + if (!url) { + return this; + } + + $({}).doAjax({ + url: url, data: context.find(':input').serialize(), callbackSuccess: function (response) { self.updateDetailData(response, context); @@ -62,7 +72,7 @@ if (data.GalleryHtml) { var cnt = $('#pd-gallery-container'); cnt.stop(true, true).transition({ opacity: 0 }, 300, "ease-out", function () { - gallery.reset(); + gallery.reset(); cnt.html(data.GalleryHtml); self.createGallery(data.GalleryStartIndex); @@ -93,6 +103,7 @@ var deliveryTime = priceBlock.find(".delivery-time"); if (data.Delivery.DisplayAccordingToStock) { + deliveryTime.toggle(true); deliveryTime.find(".delivery-time-value").html(data.Delivery.Name); deliveryTime.find(".delivery-time-color") .css("background-color", data.Delivery.Color) @@ -102,6 +113,7 @@ else { deliveryTime.find(".delivery-time-value").html(data.Stock.Availability.Text); deliveryTime.find(".delivery-time-color").toggle(false); + deliveryTime.toggle(data.Stock.Availability.Text.length > 0); } //attributes @@ -128,7 +140,15 @@ updateAttrLine(".attr-length", data.Measure.Length.Text); updateAttrLine(".attr-width", data.Measure.Width.Text); updateAttrLine(".attr-height", data.Measure.Height.Text); - updateAttrLine(".attr-stock", data.Stock.Availability.Text); + + if (data.Stock.Quantity.Show) + { + updateAttrLine(".attr-stock", data.Stock.Availability.Text); + } + else + { + updateAttrLine(".attr-stock", ""); + } context.find('.add-to-cart .form-inline').toggle(data.Stock.Availability.Available); @@ -151,17 +171,16 @@ var opts = this.options; gallery = $('#pd-gallery').smartGallery({ - width: opts.galleryWidth, height: opts.galleryHeight, enableDescription: opts.showImageDescription, - thumbSize: opts.galleryThumbSize || 50, startIndex: startIndex || 0, zoom: { enabled: opts.enableZoom, zoomType: opts.zoomType }, box: { - enabled: true + enabled: true, + hidePageScrollbars: false } }); } diff --git a/src/Presentation/SmartStore.Web/Scripts/public.product-detail.mobile.js b/src/Presentation/SmartStore.Web/Scripts/public.product-detail.mobile.js new file mode 100644 index 0000000000..3f4d6c1aa3 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Scripts/public.product-detail.mobile.js @@ -0,0 +1,153 @@ +;(function ( $, window, document, undefined ) { + + var pluginName = 'productDetailMobile'; + + function productDetailMobile(element, options) { + + var self = this; + + this.element = element; + var el = this.el = $(element); + + var meta = $.metadata ? $.metadata.get(element) : {}; + var opts = this.options = $.extend(true, {}, options, meta || {}); + + this.init = function() { + + var opts = this.options; + + // update product data. grouped product not supported because associated product has no mobile view. + $(el).find(':input').change(function () { + var inputType = $(this).attr('type'); + if (inputType && (inputType === 'file' || inputType === 'submit')) + return this; + + var context = $(this).closest('.update-container'); + + if (context[0]) { + } + else { + context = el; + } + + var url = context.attr('data-url'); + if (!url) { + return this; + } + + $({}).doAjax({ + url: url, + data: context.find(':input').serialize(), + callbackSuccess: function (response) { + self.updateDetailData(response, context); + + if (context.hasClass('bundle-item')) { + // update bundle price too + $('#TotalPriceUpdateContainer').doAjax({ + data: $('#ProductBundleItems').find(':input').serialize(), + callbackSuccess: function (response2) { + self.updateDetailData(response2, $('#AddToCart, #ProductBundleOverview')); + } + }); + } + + } + }); + }); + + return this; + }; + + this.updateDetailData = function (data, context) { + var referTo = $(context).attr('data-referto'); + + //update detail data in view + if (referTo) + context = $(referTo); + + //prices + var priceBlock = $(context).find('.price-block').addBack(); + priceBlock.find(".base-price").html(data.Price.Base.Info); + priceBlock.find(".old-product-price").html(data.Price.Old.Text); + priceBlock.find('.product-price-without-discount').html(data.Price.WithoutDiscount.Text); + priceBlock.find('.product-price-with-discount').html(data.Price.WithDiscount.Text); + + //delivery time + var deliveryTime = priceBlock.find(".delivery-time"); + + if (data.Delivery.DisplayAccordingToStock) { + deliveryTime.toggle(true); + deliveryTime.find(".delivery-time-value").html(data.Delivery.Name); + deliveryTime.find(".delivery-time-color") + .css("background-color", data.Delivery.Color) + .attr("title", data.Delivery.Name) + .toggle(data.Stock.Availability.Available); + } + else { + deliveryTime.find(".delivery-time-value").html(data.Stock.Availability.Text); + deliveryTime.find(".delivery-time-color").toggle(false); + deliveryTime.toggle(data.Stock.Availability.Text.length > 0); + } + + //attributes + var attributesBlock = $(context).find('.attributes').addBack(); + + function updateAttrLine(className, newValue) { + + attrLine = attributesBlock.find(className); + if (newValue && newValue != "") { + attrLine.find(".value").html(newValue); + attrLine.removeClass("hide"); + attrLine.addClass("in"); + } + else { + attrLine.find(".value").html(); + attrLine.addClass("hide"); + attrLine.removeClass("in"); + } + } + + updateAttrLine(".attr-sku", data.Number.Sku.Value); + updateAttrLine(".attr-gtin", data.Number.Gtin.Value); + updateAttrLine(".attr-mpn", data.Number.Mpn.Value); + updateAttrLine(".attr-weight", data.Measure.Weight.Text); + updateAttrLine(".attr-length", data.Measure.Length.Text); + updateAttrLine(".attr-width", data.Measure.Width.Text); + updateAttrLine(".attr-height", data.Measure.Height.Text); + updateAttrLine(".attr-stock", data.Stock.Availability.Text); + + UpdateMainImage(imageUrls[data.GalleryStartIndex]); + + context.find('.add-to-cart .form-inline').toggle(data.Stock.Availability.Available); + + }; + + this.initialized = false; + this.init(); + this.initialized = true; + } + + productDetailMobile.prototype = { + activePictureIndex: 0 + } + + // the global, default plugin options + _.provide('$.' + pluginName); + $[pluginName].defaults = { + // whether to show the image description + showImageDescription: false, + // url to the ajax method, which loads variant combination data + updateUrl: null, + } + + $.fn[pluginName] = function( options ) { + + return this.each(function() { + if (!$.data(this, 'plugin_' + pluginName)) { + options = $.extend( true, {}, $[pluginName].defaults, options ); + $.data(this, 'plugin_' + pluginName, new productDetailMobile(this, options)); + } + }); + } + +})(jQuery, window, document); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/public.product-filter.js b/src/Presentation/SmartStore.Web/Scripts/public.product-filter.js index b9efaa1387..1e0bd55521 100644 --- a/src/Presentation/SmartStore.Web/Scripts/public.product-filter.js +++ b/src/Presentation/SmartStore.Web/Scripts/public.product-filter.js @@ -66,7 +66,8 @@ // submit multi select filtering dialog.on('click', '.btn-primary', function () { var form = dialog.find('.multi-select-form'), - filter = $.parseJSON(form.find('[name=filter]').val()), + nameEl = form.find('[name=filter]'), + filter = nameEl.val() ? $.parseJSON(nameEl.val()) : null, values = []; if (filter != null) { @@ -80,7 +81,7 @@ var valueString = '[' + values.join(',') + ']'; - form.find('[name=filter]').val(valueString); + nameEl.val(valueString); form.submit(); }); } diff --git a/src/Presentation/SmartStore.Web/Scripts/public.product-list-scroller.js b/src/Presentation/SmartStore.Web/Scripts/public.product-list-scroller.js index c0a489774d..0878cdc0b8 100644 --- a/src/Presentation/SmartStore.Web/Scripts/public.product-list-scroller.js +++ b/src/Presentation/SmartStore.Web/Scripts/public.product-list-scroller.js @@ -16,7 +16,7 @@ list.evenIfHidden(function(el) { var visibleElemnts = parseInt(list.outerWidth() / list.find(".item-box:first").outerWidth()); - visibleElemnts = (visibleElemnts == 0) ? 1 : (visibleElemnts - 1); + visibleElemnts = (visibleElemnts >= 1) ? 1 : (visibleElemnts - 1); list.find('.pl-row').wrap('
                    ') ; diff --git a/src/Presentation/SmartStore.Web/Scripts/public.shopbar.js b/src/Presentation/SmartStore.Web/Scripts/public.shopbar.js index 1ae9feb17b..f28bf1c9a5 100644 --- a/src/Presentation/SmartStore.Web/Scripts/public.shopbar.js +++ b/src/Presentation/SmartStore.Web/Scripts/public.shopbar.js @@ -117,8 +117,8 @@ var ShopBar = (function($) { var tool = tools[data.type]; var items = $(data.src).closest(".items"); if (items.length) { - // deletion occuured within the dropdown itself, so reload html! - items.throbber({ white: true, small: true }); + // deletion occured within the dropdown itself, so reload html! + items.throbber({ white: true, small: true, message: '' }); ShopBar.loadHtml(tool, true, function () { //items.data("throbber").hide(); }); @@ -179,19 +179,28 @@ var ShopBar = (function($) { var tool = _.isString(type) ? tools[type] : type; if (!tool) return; + var cnt = tool.find('.shopbar-flyout'); + var spinner = cnt.find('.spinner-container'); + if (spinner.length === 0) { + spinner = $('
                    ').appendTo(cnt).append(createCircularSpinner(32)); + } + if (!keepOpen) { tool.removeClass("loaded").addClass("loading"); + spinner.addClass("active"); } - var cnt = tool.find('.shopbar-flyout'); + $.ajax({ cache: false, type: "POST", url: cnt.data("href"), success: function (data) { - cnt.empty().html(data); + cnt.find('.shopbar-flyout-inner').remove(); + cnt.append(data); }, complete: function (jqXHR, textStatus) { tool.removeClass("loading").addClass("loaded"); + spinner.removeClass("active"); if (_.isFunction(fn)) { fn.apply(this); } diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.common.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.common.js index 11ed4f493c..ff2f5be51f 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.common.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.common.js @@ -37,7 +37,7 @@ EventBroker.publish("message", { text: msg, type: type, - delay: delay || 5000, + delay: delay || (type == "success" ? 2000 : 5000), hide: !sticky }) }; @@ -52,9 +52,80 @@ } } + window.createCircularSpinner = function (size, active, strokeWidth, boxed, white) { + var spinner = $('
                    '); + if (active) spinner.addClass('active'); + if (boxed) spinner.addClass('spinner-boxed').css('font-size', size + 'px'); + if (white) spinner.addClass('white'); + + if (!_.isNumber(strokeWidth)) { + strokeWidth = 6; + } + + var svg = ''.format(size, 32 - strokeWidth, strokeWidth); + spinner.append($(svg)); + + return spinner; + } + + window.copyTextToClipboard = function (text) { + var result = false; + + if (window.clipboardData && window.clipboardData.setData) { + result = clipboardData.setData('Text', text); + } + else if (document.queryCommandSupported && document.queryCommandSupported('copy')) { + var textarea = document.createElement('textarea'), + focusElement = document.activeElement; + + textarea.textContent = text; + textarea.style.position = 'fixed'; + document.body.appendChild(textarea); + textarea.focus(); + textarea.setSelectionRange(0, textarea.value.length); + + try { + result = document.execCommand('copy'); + } + catch (e) { + } + finally { + document.body.removeChild(textarea); + if (focusElement) { + focusElement.focus(); + } + } + } + return result; + } + + // on document ready $(function () { + function getFunction(code, argNames) { + var fn = window, parts = (code || "").split("."); + while (fn && parts.length) { + fn = fn[parts.shift()]; + } + if (typeof (fn) === "function") { + return fn; + } + argNames.push(code); + return Function.constructor.apply(null, argNames); + } + + function decode(str) { + try { + if (str) + return decodeURIComponent(escape(str)); + } + catch (e) { + return str; + } + return str; + } + if (!Modernizr.csstransitions) { $.fn.transition = $.fn.animate; } @@ -63,18 +134,21 @@ if ($.pnotify) { $.extend($.pnotify.defaults, { history: false, - animate_speed: "fast" + animate_speed: "normal", + shadow: true, + width: "400px", + icon: true }); } // global notification subscriber if (window.EventBroker && window._ && $.pnotify) { - var stack_bottomright = { "dir1": "up", "dir2": "left", "firstpos1": 25, "firstpos2": 25 }; - //var stack_topright = { "dir1": "down", "dir2": "left", "firstpos1": 60 }; + //var stack_bottomright = { "dir1": "up", "dir2": "left", "firstpos1": 25, "firstpos2": 25 }; + var stack_bottomcenter = { "dir1": "up", "dir2": "right", "firstpos1": 100, "firstpos2": 10 }; EventBroker.subscribe("message", function (message, data) { var opts = _.isString(data) ? { text: data } : data; - opts.stack = stack_bottomright; - opts.addclass = "stack-bottomright"; + opts.stack = stack_bottomcenter; + opts.addclass = "stack-bottomcenter"; $.pnotify(opts); }); } @@ -100,20 +174,103 @@ } }); + // Telerik grid smart AJAX state preserving + $('.t-grid.grid-preservestate').on('dataBound', function (e) { + var grid = $(this).data("tGrid"), + href = $(this).data("statepreserver-href"), + gridId = $(this).data("statepreserver-key"); + + if (href) { + $.ajax({ + type: "POST", + url: href, + async: true, + data: { + gridId: gridId, + path: location.pathname + location.search, + page: grid.currentPage, + size: grid.pageSize, + orderBy: grid.orderBy, + groupBy: grid.groupBy, + filter: grid.filterBy + }, + global: false + }); + } + }); + + // AJAX tabs + $('.nav a[data-ajax-url]').on('show', function (e) { + var newTab = $(e.target), + tabbable = newTab.closest('.tabbable'), + pane = tabbable.find(newTab.attr("href")), + url = newTab.data('ajax-url'); + + if (newTab.data("loaded") || !url) + return; + + $.ajax({ + cache: false, + type: "GET", + async: false, + global: false, + url: url, + beforeSend: function (xhr) { + getFunction(tabbable.data("ajax-onbegin"), ["tab", "pane", "xhr"]).apply(this, [newTab, pane, xhr]); + }, + success: function (data, status, xhr) { + pane.html(data); + getFunction(tabbable.data("ajax-onsuccess"), ["tab", "pane", "data", "status", "xhr"]).apply(this, [newTab, pane, data, status, xhr]); + }, + error: function (xhr, ajaxOptions, thrownError) { + pane.html('
                    Error while loading resource: ' + thrownError + '
                    '); + getFunction(tabbable.data("ajax-onfailure"), ["tab", "pane", "xhr", "ajaxOptions", "thrownError"]).apply(this, [newTab, pane, xhr, ajaxOptions, thrownError]); + }, + complete: function (xhr, status) { + newTab.data("loaded", true); + var tabName = newTab.data('tab-name') || newTab.attr("href").replace(/#/, ""); + tabbable.append(''); + + getFunction(tabbable.data("ajax-oncomplete"), ["tab", "pane", "xhr", "status"]).apply(this, [newTab, pane, xhr, status]); + } + }); + }); + // Handle ajax notifications $(document) .ajaxSuccess(function (ev, xhr) { var msg = xhr.getResponseHeader('X-Message'); if (msg) { - displayNotification(msg, xhr.getResponseHeader('X-Message-Type')); + displayNotification(decode(msg), xhr.getResponseHeader('X-Message-Type')); } }) .ajaxError(function (ev, xhr) { - displayNotification(xhr.responseText, "error"); - }); + var msg = xhr.getResponseHeader('X-Message'); + if (msg) { + displayNotification(decode(msg), xhr.getResponseHeader('X-Message-Type')); + } + else { + try { + var data = JSON.parse(xhr.responseText); + if (data.error && data.message) { + displayNotification(decode(data.message), "error"); + } + } + catch (ex) { + displayNotification(xhr.responseText, "error"); + } + } + } + ); // html text collapser - $('.more-less').moreLess(); + if ($({}).moreLess) { + $('.more-less').moreLess(); + } + + // fixes bootstrap 2 bug: non functional links on mobile devices + // https://github.com/twbs/bootstrap/issues/4550 + $('body').on('touchstart.dropdown', '.dropdown-menu a', function (e) { e.stopPropagation(); }); }); })( jQuery, this, document ); diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.doAjax.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.doAjax.js index 0aba22bf44..7521d4c677 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.doAjax.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.doAjax.js @@ -22,6 +22,38 @@ /* [...] */ }; + $.fn.doPostData = function (options) { + function createAndSubmitForm() { + var id = 'DynamicForm_' + Math.random().toString().substring(2), + form = '
                    '; + + if (!_.isUndefined(options.data)) { + $.each(options.data, function (key, val) { + form += ''; + }); + } + + form += '
                    '; + + $('body').append(form); + $('#' + id).submit(); + } + + normalizeOptions(this, options); + + if (_.isEmpty(options.url)) { + console.log('doPostData can\'t find the url!'); + } + else if (_.isEmpty(options.ask)) { + createAndSubmitForm(); + } + else if (confirm(options.ask)) { + createAndSubmitForm(); + } + + return this.each(function () { }); + } + function normalizeOptions(element, opt) { opt.ask = (_.isUndefined(opt.ask) ? $(element).attr('data-ask') : opt.ask); @@ -65,10 +97,10 @@ $.throbber.show(opt.curtainTitle); } else if (opt.throbber) { - $(opt.throbber).removeData('throbber').throbber({ white: true, small: true }); + $(opt.throbber).removeData('throbber').throbber({ white: true, small: true, message: '' }); } else if (opt.smallIcon) { - $(opt.smallIcon).append(''); + $(opt.smallIcon).append(window.createCircularSpinner(16, true)); } } @@ -77,8 +109,9 @@ $.throbber.hide(true); if (opt.throbber) $(opt.throbber).data('throbber').hide(true); - if (opt.smallIcon) - $(opt.smallIcon).find('span.ajax-loader-small').remove(); + if (opt.smallIcon) { + $(opt.smallIcon).find('.spinner').remove(); + } } function doRequest(opt) { diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.entityPicker.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.entityPicker.js new file mode 100644 index 0000000000..2bfc9fc193 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.entityPicker.js @@ -0,0 +1,345 @@ +/* +* Project: SmartStore entity picker +* Author: Marcus Gesing, SmartStore AG +*/ + +; (function ($, window, document, undefined) { + + var methods = { + loadDialog: function (options) { + options = normalizeOptions(options, this); + + return this.each(function () { + loadDialog(options); + }); + }, + + initDialog: function () { + return this.each(function () { + initDialog(this); + }); + }, + + fillList: function (options) { + return this.each(function () { + fillList(this, options); + }); + }, + + itemClick: function () { + return this.each(function () { + itemClick(this); + }); + } + }; + + $.fn.entityPicker = function (method) { + return main.apply(this, arguments); + }; + + $.entityPicker = function () { + return main.apply($('.entity-picker:first'), arguments); + }; + + + function main(method) { + if (methods[method]) + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + + if (typeof method === 'object' || !method) + return methods.init.apply(this, arguments); + + EventBroker.publish("message", { title: 'Method "' + method + '" does not exist on jQuery.entityPicker', type: "error" }); + return null; + } + + function normalizeOptions(options, context) { + var self = $(context), + selector = self.selector; + + var defaults = { + url: '', + entity: 'product', + caption: ' ', + disableIf: '', + disableIds: '', + thumbZoomer: false, + highligtSearchTerm: true, + returnField: 'id', + returnValueDelimiter: ',', + returnSelector: '', + maxReturnValues: 0, + onLoadDialogBefore: null, + onLoadDialogComplete: null, + onOkClicked: null + }; + + options = $.extend({}, defaults, options); + + if (_.isEmpty(options.url)) { + options.url = self.attr('data-url'); + } + + if (_.isEmpty(options.url)) { + console.log('entityPicker cannot find the url for entity picker!'); + } + + if (_.isString(selector) && !_.isEmpty(selector) && $(selector).is('input')) { + options.returnSelector = selector; + } + + return options; + } + + function ajaxErrorHandler(objXml) { + try { + if (objXml != null && objXml.responseText != null && objXml.responseText !== '') { + EventBroker.publish("message", { title: objXml.responseText, type: "error" }); + } + } + catch (e) { } + } + + function showStatus(dialog, noteClass, condition) { + var footerNote = $(dialog).find('.footer-note'); + footerNote.find('span').hide(); + footerNote.find('.' + (noteClass || 'default')).show(); + } + + function loadDialog(opt) { + var dialog = $('#entity-picker-' + opt.entity + '-dialog'); + + function showAndFocusDialog() { + dialog = $('#entity-picker-' + opt.entity + '-dialog'); + dialog.find('.caption').html(opt.caption || ' '); + dialog.data('entitypicker', opt); + dialog.modal('show'); + + fillList(dialog, { append: false }); + + setTimeout(function () { + dialog.find('.modal-body :input:visible:enabled:first').focus(); + }, 800); + } + + if (dialog.length) { + showAndFocusDialog(); + } + else { + $.ajax({ + cache: false, + type: 'GET', + data: { + "Entity": opt.entity, + "HighligtSearchTerm": opt.highligtSearchTerm, + "ReturnField": opt.returnField, + "MaxReturnValues": opt.maxReturnValues, + "DisableIf": opt.disableIf, + "DisableIds": opt.disableIds + }, + url: opt.url, + beforeSend: function () { + if (_.isFunction(opt.onLoadDialogBefore)) { + return opt.onLoadDialogBefore(); + } + }, + success: function (response) { + $('body').append(response); + showAndFocusDialog(); + }, + complete: function () { + if (_.isFunction(opt.onLoadDialogComplete)) { + opt.onLoadDialogComplete(); + } + }, + error: ajaxErrorHandler + }); + } + } + + function initDialog(context) { + var dialog = $(context), + keyUpTimer = null, + currentValue = ''; + + // search entities + dialog.find('button[name=SearchEntities]').click(function (e) { + e.preventDefault(); + fillList(this, { append: false }); + return false; + }); + + // toggle filters + dialog.find('button[name=FilterEntities]').click(function () { + dialog.find('.entity-picker-filter').slideToggle(); + }); + + // hit enter or key up starts searching + dialog.find('input.entity-picker-searchterm').keydown(function (e) { + if (e.keyCode == 13) { + e.preventDefault(); + return false; + } + }).bind('keyup change paste', function (e) { + try { + var val = $(this).val(); + + if (val !== currentValue) { + if (keyUpTimer) { + keyUpTimer = clearTimeout(keyUpTimer); + } + + keyUpTimer = setTimeout(function () { + fillList(dialog, { + append: false, + onSuccess: function () { + currentValue = val; + } + }); + }, 500); + } + } + catch (err) { } + }); + + // filter change starts searching + dialog.find('.entity-picker-filter .item').change(function () { + fillList(this, { append: false }); + }); + + // lazy loading + dialog.find('.modal-body').on('scroll', function (e) { + if ($('.load-more:not(.loading)').visible(true, false, 'vertical')) { + fillList(this, { append: true }); + } + }); + + // item select and item hover + dialog.find('.entity-picker-list').on('click', '.item', function (e) { + var item = $(this); + + if (item.hasClass('disable')) + return false; + + var dialog = item.closest('.entity-picker'), + list = item.closest('.entity-picker-list'), + data = dialog.data('entitypicker'); + + if (data.maxReturnValues === 1) { + list.find('.item').removeClass('selected'); + item.addClass('selected'); + } + else if (item.hasClass('selected')) { + item.removeClass('selected'); + } + else if (data.maxReturnValues === 0 || list.find('.selected').length < data.maxReturnValues) { + item.addClass('selected'); + } + + dialog.find('.modal-footer .btn-primary').prop('disabled', list.find('.selected').length <= 0); + }).on({ + mouseenter: function () { + if ($(this).hasClass('disable')) + showStatus($(this).closest('.entity-picker'), 'not-selectable'); + }, + mouseleave: function () { + if ($(this).hasClass('disable')) + showStatus($(this).closest('.entity-picker')); + } + }, '.item'); + + // return value(s) + dialog.find('.modal-footer .btn-primary').click(function () { + var dialog = $(this).closest('.entity-picker'), + items = dialog.find('.entity-picker-list .selected'), + data = dialog.data('entitypicker'), + result = ''; + + items.each(function (index, elem) { + var val = $(elem).attr('data-returnvalue'); + if (!_.isEmpty(val)) { + result = (_.isEmpty(result) ? val : (result + data.returnValueDelimiter + val)); + } + }); + + if (!_.isEmpty(data.returnSelector)) { + $(data.returnSelector).val(result).focus().blur(); + } + + if (_.isFunction(data.onOkClicked)) { + if (data.onOkClicked(result)) { + dialog.modal('hide'); + } + } + else { + dialog.modal('hide'); + } + }); + + // cancel + dialog.find('button[class=btn][data-dismiss=modal]').click(function () { + dialog.find('.entity-picker-list').empty(); + dialog.find('.footer-note span').hide(); + dialog.find('.modal-footer .btn-primary').prop('disabled', true); + }); + } + + function fillList(context, opt) { + var dialog = $(context).closest('.entity-picker'); + + if (_.isTrue(opt.append)) { + var pageElement = dialog.find('input[name=PageIndex]'), + pageIndex = parseInt(pageElement.val()); + + pageElement.val(pageIndex + 1); + } + else { + dialog.find('input[name=PageIndex]').val('0'); + } + + $.ajax({ + cache: false, + type: 'POST', + data: dialog.find('form:first').serialize(), + url: dialog.find('form:first').attr('action'), + beforeSend: function () { + if (_.isTrue(opt.append)) { + dialog.find('.load-more').addClass('loading'); + } + else { + dialog.find('.entity-picker-list').empty(); + dialog.find('.modal-footer .btn-primary').prop('disabled', true); + } + + dialog.find('button[name=SearchEntities]').button('loading').prop('disabled', true); + dialog.find('.load-more').append(createCircularSpinner(20, true)); + }, + success: function (response) { + var list = dialog.find('.entity-picker-list'), + data = dialog.data('entitypicker'); + + list.stop().append(response); + + if (_.isFalse(opt.append)) { + dialog.find('.entity-picker-filter').slideUp(); + showStatus(dialog); + } + + if (list.thumbZoomer && _.isTrue(data.thumbZoomer)) { + list.find('.thumb img:not(.zoomable-thumb)').addClass('zoomable-thumb'); + list.thumbZoomer(); + } + + if (_.isFunction(opt.onSuccess)) { + opt.onSuccess(); + } + }, + complete: function () { + dialog.find('button[name=SearchEntities]').prop('disabled', false).button('reset'); + dialog.find('.load-more.loading').parent().remove(); + }, + error: ajaxErrorHandler + }); + } + +})(jQuery, window, document); \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.globalize.adapter.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.globalize.adapter.js index 6dd730de25..020840176b 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.globalize.adapter.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.globalize.adapter.js @@ -1,7 +1,7 @@ (function ($) { - $(document).ready(function () { + $(function () { // init Globalize if (Globalize) { @@ -9,23 +9,23 @@ var data = $("meta[name='accept-language']").attr("content") // Tell jQuery to figure it out also on the client side. Globalize.culture(data || "en-US"); - if ($.fn.datepicker) { - // globalize bootstrap datepicker - var c = Globalize.culture().calendars.standard; - $.fn.datepicker.defaults = { - format: c.patterns['d'].toLowerCase(), - weekStart: c.firstDay, - autoclose: true, - todayHighlight: true - }; - $.fn.datepicker.dates['glob'] = { - days: c.days.names, - daysShort: c.days.namesShort, - daysMin: c.days.namesAbbr, - months: c.months.names, - monthsShort: c.months.namesAbbr, - today: "Today" // TODO: Localize - }; + if ($.fn.datetimepicker) { + // globalize bootstrap datepicker + var c = Globalize.culture().calendars.standard; + $.fn.datetimepicker.defaults = { + format: c.patterns['d'], + weekStart: c.firstDay, + autoclose: true, + todayHighlight: true + }; + $.fn.datetimepicker.dates['glob'] = { + days: c.days.names, + daysShort: c.days.namesShort, + daysMin: c.days.namesAbbr, + months: c.months.names, + monthsShort: c.months.namesAbbr, + today: "Today" // TODO: Localize + }; } // Use the Globalization plugin to parse some values diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.hacks.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.hacks.js index d3d6ddc859..655b897d8a 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.hacks.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.hacks.js @@ -2,67 +2,23 @@ var Hacks = { Telerik: { - // TODO: temp > Handle k-textbox with an EditorTemplate - handleTextBox: function (el) { - //el.addClass("k-textbox"); - }, - // TODO: temp > Handle Button with MVC handleButton: function (el) { el.removeClass("t-button").addClass("btn"); el.each(function () { var btn = $(this); if (btn.hasClass("t-grid-add")) { - btn.addClass("btn-warning").prepend(' '); + btn.addClass("btn-link").prepend(' '); + } + else if (btn.hasClass("t-grid-save-changes")) { + btn.addClass("btn-primary").prepend(' '); + } + else if (btn.hasClass("t-grid-cancel-changes")) { + btn.addClass("btn-link"); } }); } - }, - - Kendo: { - - // Kendo doesn't set content elements display to block - // when window is opened - windowContentVisibility: function (elWindow) { - var kendoWindow = elWindow.data('kendoWindow'); - - kendoWindow.bind("open", function (e) { - elWindow.css("display", "block"); - }); - - kendoWindow.bind("deactivate", function (e) { - elWindow.css("display", "none"); - }); - }, - - // Temporary hack to bypass a kendo grid bug, which - // attempts to sort any column, whether disabled or not. - fixGridSorting: function (elGrid, sortable) { - // if 'sortable' is true, all columns NOT in arglist are not sortable, - // if false, all columns NOT in arglist are sortable - var colNames; - if (_.isArray(arguments[2])) - colNames = arguments[2]; - else - colNames = _.toArray(arguments).slice(2); - - if (colNames.length > 0) { - elGrid.find(".k-header .k-link").on("click", function (e) { - var clickedColumnName = $(this).parent().data("field"); - - var match = _.any(colNames, function (val) { - return (val == clickedColumnName); - }); - - if ((sortable && !match) || (!sortable && match)) { - e.stopPropagation(); - } - - }); - } - } - } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.instantsearch.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.instantsearch.js new file mode 100644 index 0000000000..957e35f1a9 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.instantsearch.js @@ -0,0 +1,97 @@ +(function ($, window, document, undefined) { + + // on document ready + $(function () { + + var _baseHighlighter = $.fn.typeahead.Constructor.prototype.highlighter; + + var searchBox = $('#instantsearch'); + if (searchBox.length == 0) + return; + + var searchResult, + minLength = searchBox.data("minlength"), + showThumbs = searchBox.data("showthumbs"), + url = searchBox.data("url"); + + searchBox.typeahead({ + items: 16, + minLength: minLength, + keyUpDelay: 400, + menu: ''.format(showThumbs ? " rich" : ""), + autoSelectFirstItem: false, + source: function (query, process) { + var spinner = $('#instantsearch-progress'); + if (spinner.length === 0) { + spinner = createCircularSpinner(20).attr('id', 'instantsearch-progress').appendTo(searchBox.parent()); + } + spinner.addClass('active'); + + return $.ajax({ + dataType: "json", + url: url, + data: { term: query }, + type: 'GET', + success: function (json) { + searchResult = json; + var items = $.map(json, function (val, i) { + return val.label; + }); + process(items); + }, + error: function () { + searchResult = null; + }, + complete: function () { + spinner.removeClass('active'); + } + }); + }, + updater: function (label) { + if (!searchResult) + return; + + var item = _.find(searchResult, function (x) { return x.label == label }); + setLocation(item.producturl); + }, + matcher: function (item) { + // items are filtered already. Do not filter again! + return true; + }, + highlighter: function (label) { + var inner = _baseHighlighter.call(this, label); + if (!showThumbs) { + return inner; + } + + var item = _.find(searchResult, function (x) { return x.label == label }); + + var html = '' + + "
                    " + + "
                    " + + "
                    " + + "
                    " + inner + "
                    " + + "
                    " + item.secondary + "
                    " + + "
                    " + + "
                    "; + + return html; + } + }); + + searchBox.closest("form").on("submit", function (e) { + if (!searchBox.val()) { + var frm = $(this); + var shakeOpts = { direction: "right", distance: 4, times: 2 }; + frm.stop(true, true).effect("shake", shakeOpts, 400, function () { + searchBox.trigger("focus").removeClass("placeholder") + }); + return false; + } + + return true; + }); + }); + +})( jQuery, this, document ); + diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.jquery.utils.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.jquery.utils.js index adaa9cae0a..a7e2d285e4 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.jquery.utils.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.jquery.utils.js @@ -6,14 +6,6 @@ $.extend({ - fixIE7ZIndexBug: function () { - var zIndexNumber = 4000; - $('div').each(function () { - $(this).css('zIndex', zIndexNumber); - zIndexNumber -= 10; - }); - }, - topZIndex: function (selector) { /* /// summary @@ -99,73 +91,12 @@ .html(); }, - max: function (callback) { - var n; - jQuery.each(this, function () { - var m = callback.apply(this); - n = n ? Math.max(n, m) : m; - }); - return n; - }, - - min: function (callback) { - var n; - jQuery.each(this, function () { - var m = callback.apply(this); - n = n ? Math.min(n, m) : m; - }); - return n; - }, - - sum: function (callback) { - var n; - jQuery.each(this, function () { - m = callback.apply(this); - n = n ? n + m : m; - }); - return n; - }, - - ellipsis: function (enableUpdating) { - // currently sets only the 'title' attribute - // on element if ellipsized by browser. - // Since FF7+ now supports ellipsis, no need - // to update the text anymore. - return this.each(function () { - var el = $(this); - - if (el.css("overflow") == "hidden") { - var text = el.text(); - var multiline = false; //el.hasClass('multiline'); - var t = $(this.cloneNode(true)) - .hide() - .css('position', 'absolute') - .css('overflow', 'visible') - .width(multiline ? el.width() : 'auto') - .height(multiline ? 'auto' : el.height()); - - el.after(t); - - function height() { return t.height() > el.height(); }; - function width() { return t.width() > el.width(); }; - - var func = multiline ? height : width; - - if (func()) { - el.attr('title', text); - } - - t.remove(); - } - }); - }, - evenIfHidden: function (callback) { return this.each(function () { var self = $(this); var styleBackups = []; - var hiddenElements = self.parents().andSelf().filter(':hidden'); + var hiddenElements = self.parents().addBack().filter(':hidden'); if (!hiddenElements.length) { callback(self); @@ -207,7 +138,7 @@ var elems = el.find(opts.childrenOnly ? '>[data-bind-to]' : '[data-bind-to]'); if (opts.includeSelf) - elems = elems.andSelf(); + elems = elems.addBack(); elems.each(function () { var elem = $(this); @@ -236,11 +167,75 @@ }); }, + /** + * Copyright 2012, Digital Fusion + * Licensed under the MIT license. + * http://teamdf.com/jquery-plugins/license/ + * + * @author Sam Sehnert + * @desc A small plugin that checks whether elements are within + * the user visible viewport of a web browser. + * only accounts for vertical position, not horizontal. + */ + visible: function (partial, hidden, direction) { + if (this.length < 1) + return; + + var $w = $(window); + var $t = this.length > 1 ? this.eq(0) : this, + t = $t.get(0), + vpWidth = $w.width(), + vpHeight = $w.height(), + direction = (direction) ? direction : 'both', + clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true; + + if (typeof t.getBoundingClientRect === 'function') { + + // Use this native browser method, if available. + var rec = t.getBoundingClientRect(), + tViz = rec.top >= 0 && rec.top < vpHeight, + bViz = rec.bottom > 0 && rec.bottom <= vpHeight, + lViz = rec.left >= 0 && rec.left < vpWidth, + rViz = rec.right > 0 && rec.right <= vpWidth, + vVisible = partial ? tViz || bViz : tViz && bViz, + hVisible = partial ? lViz || rViz : lViz && rViz; + + if (direction === 'both') + return clientSize && vVisible && hVisible; + else if (direction === 'vertical') + return clientSize && vVisible; + else if (direction === 'horizontal') + return clientSize && hVisible; + } else { + + var viewTop = $w.scrollTop(), + viewBottom = viewTop + vpHeight, + viewLeft = $w.scrollLeft(), + viewRight = viewLeft + vpWidth, + offset = $t.offset(), + _top = offset.top, + _bottom = _top + $t.height(), + _left = offset.left, + _right = _left + $t.width(), + compareTop = partial === true ? _bottom : _top, + compareBottom = partial === true ? _top : _bottom, + compareLeft = partial === true ? _right : _left, + compareRight = partial === true ? _left : _right; + + if (direction === 'both') + return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft)); + else if (direction === 'vertical') + return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)); + else if (direction === 'horizontal') + return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft)); + } + }, + moreLess: function () { - var moreText = ''; - var lessText = ''; + var moreText = ''; + var lessText = ''; - return this.each(function () { + return this.each(function () { var el = $(this), opt = $.extend({ adjustheight: 260 }, el.data('options')); diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.navbar.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.navbar.js index ece254cbea..0c9a19ca07 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.navbar.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.navbar.js @@ -28,17 +28,8 @@ a = el.find("> a").removeAttr("data-toggle"), /* remove default bootstrap toggle attribute */ ulSub = null; - // init mouse aiming towards submenu - drop.menuAim({ - rowSelector: "li.drop-list-item", - submenuSelector: ".dropdown-submenu", - activate: function(item) { - $(item).addClass("aimed"); - }, - deactivate: function (item) { - $(item).removeClass("aimed"); - } - }); + // init mouse aiming towards submenu + drop.menuAim(opts.menuAim); inner.data("initial-height", inner.height()); inner.css("height", inner.data("initial-height")); @@ -111,7 +102,16 @@ // the global, default plugin options var defaults = { - // [...] + menuAim: { + rowSelector: "li.drop-list-item", + submenuSelector: ".dropdown-submenu", + activate: function (item) { + $(item).addClass("aimed"); + }, + deactivate: function (item) { + $(item).removeClass("aimed"); + } + } } $[pluginName] = { defaults: defaults }; @@ -120,7 +120,7 @@ return this.each(function () { if (!$.data(this, pluginName)) { - options = $.extend( {}, $[pluginName].defaults, options ); + options = $.extend( true, {}, $[pluginName].defaults, options ); $.data(this, pluginName, new Navbar(this, options)); } }); diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.placeholder.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.placeholder.js index cf9cef8c07..be6a353f4e 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.placeholder.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.placeholder.js @@ -59,18 +59,6 @@ var input = this.input; input.attr('realType', 'password'); this.isPassword = true; - // IE < 9 doesn't allow changing the type of password inputs - if ($.browser.msie && input[0].outerHTML) { - var fakeHTML = $(input[0].outerHTML.replace(/type=(['"])?password\1/gi, 'type=$1text$1')); - this.fakePassword = fakeHTML.val(input.attr('placeholder')).addClass('placeholder').focus(function() { - input.trigger('focus'); - $(this).hide(); - }); - $(input[0].form).submit(function() { - fakeHTML.remove(); - input.show() - }); - } } }; @@ -116,7 +104,7 @@ // On page refresh, IE doesn't re-populate user input // until the window.onload event is fired. - if ($.browser.msie) { + if (navigator.isIE) { $(window).load(function() { if(input.val()) { input.removeClass("placeholder"); diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.scrollbutton.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.scrollbutton.js index a065534c77..c79467b3bf 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.scrollbutton.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.scrollbutton.js @@ -5,10 +5,10 @@ (function( $, undefined ) { var iconClasses = { - left: "icon-chevron-left", - right: "icon-chevron-right", - up: "icon-chevron-up", - down: "icon-chevron-down" + left: "fa fa-chevron-left", + right: "fa fa-chevron-right", + up: "fa fa-chevron-up", + down: "fa fa-chevron-down" }; $.ScrollButton = function(el, buttons, target, options) { diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.selectwrapper.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.selectwrapper.js index 2115ec0f55..5d569ca584 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.selectwrapper.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.selectwrapper.js @@ -9,6 +9,11 @@ $.fn.selectWrapper = function (options) { + if (options && !_.str.isBlank(options.resetDataUrl) && lists[options.resetDataUrl]) { + lists[options.resetDataUrl] = null; + return this.each(function () { }); + } + return this.each(function () { var sel = $(this); @@ -152,7 +157,7 @@ $.each(lists[url], function () { var o = $(document.createElement('option')) .attr('value', this.id) - .text(this.text) + .text(this.text || this.name) .appendTo(sel); if (this.selected) { o.attr("selected", "selected"); diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js index ed37983e13..56fbff1fc5 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.smartgallery.js @@ -1,6 +1,6 @@ /* * Project: smartstore.smartgallery - * Version: 1.0 + * Version: 1.1 * Author: Murat Cakir */ @@ -8,7 +8,7 @@ var pluginName = 'smartGallery'; - var defaultEasing = "easeInQuad"; + var defaultEasing = "easeInOutQuad"; var animations = { 'slide': function (cnt, dir, desc) { var curLeft = parseInt(cnt.css('left'), 10); @@ -83,23 +83,19 @@ var meta = $.metadata ? $.metadata.get(element) : {}; var opts = this.options = $.extend(true, {}, options, meta || {}); - this.init = function() { + this.init = function(isRefresh) { this.setupElements(); // DO - if (opts.width) { - this.imageWrapperWidth = opts.width; - this.imageWrapper.width(opts.width); - el.width(opts.width); - } - else { - this.imageWrapperWidth = this.imageWrapper.width(); - } - this.imageWrapper.height(opts.height || 400); - this.imageWrapperHeight = opts.height; + this.imageWrapperWidth = this.imageWrapper.width(); + this.imageWrapperHeight = opts.height || 300; + + if (this.imageWrapperHeight > 300) { + this.imageWrapper.css({ height: this.imageWrapperHeight + 'px' }) + } this.navDisplayWidth = this.nav.width(); this.currentIndex = 0; - + this.findImages(); if (this.options.box && this.options.box.enabled) { @@ -136,30 +132,19 @@ }; }; - this.loading(true); + if (this.images[startAt]) { + this.loading(true); + } this.showImage(startAt); - /* // TODO: (MC) this is more challenging than i thought (!) - if (opts.responsive && (!opts.width)) { - EventBroker.subscribe("page.resized", function (data) { - // recalc some metrics on page resize - self.imageWrapperWidth = self.imageWrapper.width(); - self.navDisplayWidth = self.nav.width(); - - // center current image - var imgContainer = self.imageWrapper.find('.sg-image'); - var img = imgContainer.find("img"); - self._centerImage(imgContainer, img.width(), img.height()); - - // hide show/scroll buttons - // [...] + if (opts.responsive && !isRefresh) { + EventBroker.subscribe("page.resized", function (data) { + self.reset(); + self.inTransition = false; + self.init(true); }); } - */ - - /*this.fireCallback(opts.callbacks.init);*/ - }; this.initialized = false; @@ -170,12 +155,11 @@ SmartGallery.prototype = { imageWrapper: null, - //imageOverlay: null, nav: null, loader: null, preloads: null, thumbsWrapper: null, - box: null, + box: null, // (blueImp) image gallery element imageWrapperWidth: 0, imageWrapperHeight: 0, @@ -199,33 +183,52 @@ this.origHtml = this.el.outerHtml(); this.imageWrapper = el.find('.sg-image-wrapper').empty(); - this.nav = el.find('.sg-nav').addClass("invisible"); + this.nav = el.find('.sg-nav').css("opacity", "0"); this.thumbsWrapper = this.nav.find('.sg-thumbs'); this.preloads = $('
                    '); - this.loader = $('
                    '); + this.loader = $('
                    ').append(createCircularSpinner(24, false, null, true)); this.imageWrapper.append(this.loader); - this.loader.hide(); $(document.body).append(this.preloads); }, reset: function () { - var self = this; + var self = this; + + self.imageWrapperWidth = 0; + self.imageWrapperHeight = 0; + self.navDisplayWidth = 0; + self.navListWidth = 0; + self.noScrollers = false; + self.nav.removeClass("has-buttons"); + self.thumbsWrapper.find('> ul > li > a').off('click mouseenter'); + self.thumbsWrapper.css('width', 'initial'); + if (self.preloads) { self.preloads.remove(); } + if (self.loader) { + self.loader.remove(); + } var oldZoomImage = self.imageWrapper.find('.sg-image img').data("elevateZoom"); if (oldZoomImage) { - console.log(oldZoomImage); oldZoomImage.reset(); } + + self.imageWrapper.find('.sg-image').remove(); + + $('.smartgallery-overlay').remove(); + if (self.box) { + self.box.remove(); + } + self.box = null; }, loading: function(value) { if (value) { - this.loader.show(); + this.loader.addClass('active'); } else { - this.loader.hide(); + this.loader.removeClass('active'); }; }, @@ -245,23 +248,23 @@ thumbs.each( function(i) { var link = $(this); - var imageSrc = link.attr('href'); + var imageSrc = link.data('medium-image'); var thumb = link.find('img'); + + thumbWrapperWidth += this.parentNode.offsetWidth; // parent LI of A + // Check if the thumb has already been loaded if (!self.isImageLoaded(thumb[0])) { thumb.load(function() { - thumbWrapperWidth += this.parentNode.parentNode.offsetWidth; thumbsLoaded++; }); } else{ - thumbWrapperWidth += thumb[0].parentNode.parentNode.offsetWidth; thumbsLoaded++; } - var linkSize = self.options.thumbSize + 2; - link.addClass('sg-thumb' + i) - .css({ width: linkSize + "px", height: linkSize + "px", lineHeight: (linkSize-2) + "px" }); + + link.addClass('sg-thumb' + i); link.on({ 'click': function () { @@ -299,7 +302,7 @@ self.images[i] = { thumb: thumb.attr('src'), image: imageSrc, - zoom: link.data("zoom-image"), + zoom: link.attr("href"), error: false, preloaded: false, desc: desc, @@ -309,48 +312,40 @@ }; }); - // Wait until all thumbs are loaded, and then set the width of the ul - var list = self.nav.find('.sg-thumb-list'); - var setULWidth = function() { - + // Wait until all thumbs are loaded, and then set the width of the UL wrapper + var listWrapper = self.nav.find('.sg-thumbs'); + var setULWrapperWidth = function() { if (thumbCount == thumbsLoaded) { var scrollers = self.nav.find('.scroll-button'); if (thumbWrapperWidth <= self.navDisplayWidth) { - // Liste passt in den Container. - // ScrollButtons entfernen + // List fits into container: remove ScrollButtons scrollers.each(function() { $(this).parent().remove(); }); - // ...und verhindern, dass ein ThumbJump durchgefhrt wrde. + // ...and prevent a ThumbJump self.noScrollers = true; - // ...und Liste horizontal zentrieren - list.css('left', (self.navDisplayWidth - thumbWrapperWidth) / 2 +'px'); } else { - // Liste ist grer als Container! - // wir brauchen ScrollButtons: + // List ist wider than container: we need ScrollButtons if (scrollers.length > 0) { self.nav.addClass("has-buttons"); // der hier hat die paddings var parentHeight = scrollers.parent().innerHeight(); scrollers.height(parentHeight - scrollers.verticalCushioning()); } } - + + thumbWrapperWidth += listWrapper.horizontalCushioning() - thumbsLoaded + 1; + // tatschliche Breite der Liste setzen - //list.css('width', (thumbWrapperWidth) +'px'); - list.css('width', (thumbWrapperWidth + 1) +'px'); + listWrapper.css('width', (thumbWrapperWidth) + 'px'); clearInterval(inter); - - self.navListWidth = list.outerWidth(true); - - self.nav.removeClass("invisible"); - + self.navListWidth = thumbWrapperWidth; + self.nav.css("opacity", "1"); } } - var inter = setInterval( setULWidth, 50 ); - + var inter = setInterval(setULWrapperWidth, 50); }, initKeyEvents: function() { @@ -394,12 +389,15 @@ if (self.options.scrollJump >>> 0) { width = self.options.scrollJump; } + var left; if (dir == 'right') { - var left = self.thumbsWrapper.scrollLeft() + width; + left = self.thumbsWrapper.scrollLeft() + width; } else { - var left = self.thumbsWrapper.scrollLeft() - width; + left = self.thumbsWrapper.scrollLeft() - width; } + left = Math.min(left, self.navListWidth - self.navDisplayWidth); + self.thumbsWrapper.animate({ scrollLeft: left +'px' }, 400, "easeOutQuad"); self._toggleScrollButtons(left); return false; @@ -424,67 +422,121 @@ initBox: function() { var self = this; - - //this.box = $('
                    ').hide(0).appendTo(this.el); - - /*$.each(this.images, function(i, img) { - self.box.append( - ''.format( - img.link || img.image, - img.desc || img.title - ) - ); - });*/ + + var getWidget = function (id) { + var widget = $('#' + id); + if (widget.length > 0) { + return widget; + } + + widget = $('') + .append('
                    ') + .append('') + .append('') + .append('' + String.fromCharCode(215) + '') + .append('
                      '); + widget.appendTo('body'); + + self.box = widget; + + var prevY = null; + + var onMouseMove = function (e) { + if (!_.isNumber(prevY)) { + prevY = e.pageY; + return; + } + + if (e.pageY - prevY > 25) { + // moved down by 25px + widget.find('>.indicator').removeClass('out').data("explicit-move", true); + } + else if (prevY - e.pageY > 25) { + // moved up by 25px + widget.find('>.indicator').addClass('out'); + } + + prevY = e.pageY; + }; + + // trigger mousemove all 100ms + var throttledMouseMove = _.throttle(onMouseMove, 100, { leading: false, trailing: false }); + widget.find('> .slides').on('mousemove', throttledMouseMove); + + return widget; + }; + + var getOverlay = function (widget) { + var gov = $('.smartgallery-overlay'); + if (gov.length == 0) { + gov = $('').insertBefore(widget[0]); + } + return gov; + }; if (this.options.displayImage) { - this.imageWrapper.on("click", ".sg-image > a", function (event) { - - event.preventDefault(); - $('#modal-gallery').modal({ - "target": "#modal-gallery", - "selector": ".sg-thumb-list li a", - "index": self.currentIndex - }).on('beforeOpen', function () { - var modalData = $(this).data('modal'); - modalData.options.index = self.currentIndex; - }); + // Global click handler to open links with data-gallery attribute + // in the Gallery lightbox: + $(document).on('click', '.sg-image > a', function (e) { + e.preventDefault(); + + var id = $(this).data('gallery') || 'default', + widget = getWidget(id == 'default' ? 'image-gallery-default' : id), + container = (widget.length && widget) || $(Gallery.prototype.options.container), + callbacks = { + onopen: function () { + var gov = getOverlay(widget); + gov.on('click', function (e) { + widget.data('gallery').close(); + }); + gov.show().addClass("in"); + container.data('gallery', this).trigger('open'); + }, + onopened: function () { + container.trigger('opened'); + }, + onslide: function () { + container.trigger('slide', arguments); + }, + onslideend: function () { + container.trigger('slideend', arguments); + }, + onslidecomplete: function () { + container.trigger('slidecomplete', arguments); + }, + onclose: function () { + getOverlay(widget).removeClass("in"); + container.trigger('close'); + }, + onclosed: function () { + getOverlay(widget).css('display', 'none'); + container.trigger('closed').removeData('gallery'); + } + }, + options = $.extend( + // Retrieve custom options from data-attributes + // on the Gallery widget: + container.data(), + { + container: container[0], + index: self.currentIndex, + event: e + }, + callbacks, + self.options.box || {} + ), + // Select all links with the same data-gallery attribute: + links = $('[data-gallery="' + id + '"]').not($(this)); + + if (options.filter) { + links = links.filter(options.filter); + } + return new blueimp.Gallery(links, options); }); } }, - refreshDetailImage: function(src) { - - var self = this, - imgWrapper = this.imageWrapper, - image = imgWrapper.find('.sg-image img'), - newImgWidth = "", - newImgHeight = ""; - - image - .attr("src", src) - .removeAttr("width") - .removeAttr("height"); - - image.load(function(){ - var newImage = imgWrapper.find('.sg-image img'); - newImgWidth = newImage.width(); - newImgHeight = newImage.height(); - newImage.attr("width", newImgWidth).attr("height", newImgHeight); - - imgWrapper.find('.sg-image').css({ - 'width': newImgWidth + 'px', - 'height': newImgHeight + 'px' - }); - - self._centerImage(imgWrapper.find('.sg-image'), newImgWidth, newImgHeight); - - if (imgWrapper.parent().attr('id') == 'pd-gallery-big') { - imgWrapper.find('.sg-image a').attr('href', src); - } - }); - }, - _showBox: function (idx) { idx = idx === undefined ? this.currentIndex : idx; this.imageWrapper.find('.sg-image > a').click(); @@ -498,7 +550,7 @@ var fwd = this.scrollForward, back = this.scrollBack; var plugin, enabled = true; scrollLeft = scrollLeft !== undefined ? scrollLeft : this.thumbsWrapper.scrollLeft(); - var listWidth = this.navListWidth || this.nav.find('.sg-thumb-list').outerWidth(true); + var listWidth = this.navListWidth || this.thumbsWrapper.outerWidth(true); if (fwd) { enabled = (this.navDisplayWidth - (listWidth - scrollLeft)) < 0; plugin = fwd.data("ScrollButton"); @@ -515,7 +567,7 @@ * Checks if the image is small enough to fit inside the container * If it's not, shrink it proportionally */ - _getContainedImageSize: function(imageWidth, imageHeight) { + _getContainedImageSize: function (imageWidth, imageHeight) { var ratio = 0; if (imageHeight > this.imageWrapperHeight) { ratio = imageWidth / imageHeight; @@ -527,7 +579,7 @@ imageWidth = this.imageWrapperWidth; imageHeight = this.imageWrapperWidth * ratio; }; - return {width: imageWidth, height: imageHeight}; + return { width: imageWidth, height: imageHeight }; }, /** @@ -587,12 +639,13 @@ var self = this; var image = this.images[index]; var opts = self.options; + var thumb = this.nav.find('.sg-thumb' + index); var imgContainer = $(document.createElement('div')).addClass('sg-image'); var img = $(new Image()).attr('src', image.image); if (image.link) { - var link = $(''); - link.append(img); + var link = $(''); + link.append(img).data('gallery', thumb.data('gallery')); imgContainer.append(link); } else { @@ -600,10 +653,10 @@ } this.imageWrapper.prepend(imgContainer); + var size = this._getContainedImageSize(image.size.width, image.size.height); - img.attr('width', size.width); - img.attr('height', size.height); - imgContainer.css({ width: size.width +'px', height: size.height +'px' }); + img.css('max-height', opts.height); + imgContainer.css({ width: size.width + 'px', height: size.height + 'px' }); this._centerImage(imgContainer, size.width, size.height); if (opts.enableDescription) { @@ -616,7 +669,7 @@ }; } - this.highlightThumb(this.nav.find('.sg-thumb'+ index)); + this.highlightThumb(thumb); var direction = 'right'; if (this.currentIndex < index) { @@ -664,17 +717,18 @@ // enable zoom if ($.isPlainObject(opts.zoom) && opts.zoom.enabled === true && image.zoom) { - img.attr("data-zoom-image", image.zoom); + if (img.data("elevateZoom") === undefined) { + img.attr("data-zoom-image", image.zoom); + var zoomOpts = $.extend({}, defaultZoomOpts, opts.zoom); - var zoomOpts = $.extend({}, defaultZoomOpts, opts.zoom); + if (!zoomOpts.zoomWindowHeight) + zoomOpts.zoomWindowHeight = self.el.height() - 2; - if (!zoomOpts.zoomWindowHeight) - zoomOpts.zoomWindowHeight = self.el.height() - 2; + if (zoomOpts.lensShape === "round" && zoomOpts.zoomType !== "lens") + zoomOpts.lensShape = undefined; - if (zoomOpts.lensShape === "round" && zoomOpts.zoomType !== "lens") - zoomOpts.lensShape = undefined; - - img.elevateZoom(zoomOpts); + img.elevateZoom(zoomOpts); + } } }, @@ -750,7 +804,7 @@ image.size = { width: $(this).width(), height: $(this).height() }; self.fireCallback(callback); }) - .error(function() { + .on("error", function(e) { image.error = true; image.preloaded = false; image.size = false; @@ -779,13 +833,17 @@ return true; }, - highlightThumb: function(thumb) { + highlightThumb: function (thumb) { + if (thumb.hasClass('sg-active')) + return; + this.thumbsWrapper.find('.sg-active').removeClass('sg-active'); thumb.addClass('sg-active'); if (!this.noScrollers) { - var left = thumb[0].parentNode.offsetLeft; + var left = thumb[0].parentNode.offsetLeft + toInt(this.thumbsWrapper.css('margin-left')); left -= (this.navDisplayWidth / 2) - (thumb[0].offsetWidth / 2); - this.thumbsWrapper.animate({ scrollLeft: left +'px' }); + left = Math.min(left, this.navListWidth - this.navDisplayWidth); + this.thumbsWrapper.animate({ scrollLeft: left + 'px' }); this._toggleScrollButtons(left); } }, @@ -804,18 +862,14 @@ $[pluginName].defaults = { // whether the gallery should be update on windows/viewport resize responsive: true, - // the max width and/or height of thumbnails - thumbSize: 50, // 0-based index of image to start with startIndex: 0, // animation type: slide, fade, none animation: "slide", // speed of animation in ms. animationSpeed: 400, - // width of outermost container in px. - width: null, - // height of outermost container in px. - height: null, + // height of image container in px. + height: 300, // display the top toolbar displayImage: true, // ... @@ -836,8 +890,9 @@ }, // full size image box options box: { - enabled: true - /* {...} bootstrap image gallery options are passed through */ + enabled: true, + closeOnSlideClick: false + /* {...} blueimp image gallery options are passed through */ }, callbacks: { imageClick: null, diff --git a/src/Presentation/SmartStore.Web/Scripts/smartstore.throbber.js b/src/Presentation/SmartStore.Web/Scripts/smartstore.throbber.js index fc0d3f4c61..0929bab9bd 100644 --- a/src/Presentation/SmartStore.Web/Scripts/smartstore.throbber.js +++ b/src/Presentation/SmartStore.Web/Scripts/smartstore.throbber.js @@ -17,7 +17,7 @@ opts = this.options = options, throbber = this.throbber = null, throbberContent = this.throbberContent = null; - + this.visible = false; this.init = function () { @@ -29,48 +29,21 @@ this.initialized = false; this.init(); - + } Throbber.prototype = { - - _reposition: function() { - var self = this, - size = null; - if (self.throbber.hasClass("global")) { - size = { - left: (self.el.width() - self.throbberContent.outerWidth()) / 2, - top: (self.el.height() - self.throbberContent.outerHeight()) / 2 - } - } - else { - // not global - var pos = self.el.position(); - self.throbber.find(".throbber-overlay").css({ - left: pos.left + parseInt(self.el.css("margin-left")), - top: pos.top + parseInt(self.el.css("margin-top")), - width: self.el.outerWidth(), - height: self.el.outerHeight() - }); - size = { - left: pos.left + ((self.el.outerWidth() - self.throbberContent.outerWidth()) / 2), - top: pos.top + ((self.el.outerHeight() - self.throbberContent.outerHeight()) / 2) - } - } - self.throbberContent.css(size); - }, show: function (o) { - if (this.visible) return; - var self = this, - opts = $.extend( { }, this.options, o); - + var self = this, + opts = $.extend({}, this.options, o); + // create throbber if not avail if (!self.throbber) { - self.throbber = $('
                      ') + self.throbber = $('
                      ') .addClass(opts.cssClass) .addClass(opts.small ? "small" : "large") .appendTo(opts._global ? 'body' : self.el); @@ -80,54 +53,57 @@ if (opts._global) { self.throbber.addClass("global"); } - + else { + if (/static/.test(self.el.css("position"))) { + self.el.css("position", "relative"); + } + } + self.throbberContent = self.throbber.find(".throbber-content"); + var spinner = window.createCircularSpinner(opts.small ? 50 : 100, true, 3); + spinner.insertAfter(self.throbberContent); self.initialized = true; } - // set text and reposition + // set text self.throbber.css({ visibility: 'hidden', display: 'block' }); self.throbberContent.html(opts.message); - self._reposition(); - self.throbber.css({ visibility: 'visible', display: 'none' }); - - var show = function() { - if (_.isFunction(opts.callback)) { - opts.callback.apply(this); - } - if (!self.visible) { + self.throbberContent.toggleClass('hide', !(_.isString(opts.message) && opts.message.trim().length > 0)); + self.throbber.css({ visibility: 'visible', opacity: 0 }); + + var show = function () { + if (_.isFunction(opts.callback)) { + opts.callback.apply(this); + } + if (!self.visible) { // could have been set to false in 'hide'. // this can happen in very short running processes. self.hide(); - } + } } - + self.visible = true; - opts.speed - ? self.throbber.delay(opts.delay).fadeIn(opts.speed, show) - : self.throbber.delay(opts.delay).fadeIn(0, show); + self.throbber.delay(opts.delay).transition({ opacity: 1 }, opts.speed || 0, "linear", show); if (opts.timeout) { - window.setTimeout(self.hide, opts.timeout + opts.delay); + var hideFn = _.bind(self.hide, this); + window.setTimeout(hideFn, opts.timeout + opts.delay); } }, - hide: function(immediately) { + hide: function (immediately) { var self = this, opts = this.options; - if (self.throbber && self.visible) { - - var hide = function() { - // [...] + var hide = function () { + self.throbber.css('display', 'none'); } - self.visible = false; - defaults.speed && _.isFalse(immediately) - ? self.throbber.stop(true).fadeOut(opts.speed, hide) - : self.throbber.stop(true).hide(0, hide); + !defaults.speed || _.isTrue(immediately) + ? self.throbber.stop(true).hide(0, hide) + : self.throbber.stop(true).transition({ opacity: 0 }, opts.speed || 0, "linear", hide); } } @@ -137,10 +113,9 @@ // A really lightweight plugin wrapper around the constructor, // preventing against multiple instantiations $.fn[pluginName] = function (options) { - return this.each(function () { if (!$.data(this, pluginName)) { - options = $.extend( {}, $[pluginName].defaults, options ); + options = $.extend({}, $[pluginName].defaults, options); $.data(this, pluginName, new Throbber(this, options)); } }); @@ -163,40 +138,30 @@ // internal _global: false }; - - // global resize event - $(window).on('resize.throbber', function() { - // resize all active/visible throbbers - $.each(throbbers, function(i, throbber) { - if (throbber.initialized && throbber.visible) { - throbber._reposition(); - } - }) - }); $[pluginName] = { - + // the global, default plugin options defaults: defaults, // options: a message string || options object - show: function(options) { - var opts = $.extend( defaults, _.isString(options) ? { message: options } : options, { show: false, _global: true } ); + show: function (options) { + var opts = $.extend(defaults, _.isString(options) ? { message: options } : options, { show: false, _global: true }); if (!globalThrobber) { globalThrobber = $(window).throbber(opts).data("throbber"); } globalThrobber.show(opts); - }, - hide: function() { + hide: function (immediately) { if (globalThrobber) { - globalThrobber.hide(); + globalThrobber.hide(immediately); } } } // $.throbber })(jQuery, window, document); + diff --git a/src/Presentation/SmartStore.Web/Scripts/underscore.mixins.js b/src/Presentation/SmartStore.Web/Scripts/underscore.mixins.js index 6c59ecabde..32978c431f 100644 --- a/src/Presentation/SmartStore.Web/Scripts/underscore.mixins.js +++ b/src/Presentation/SmartStore.Web/Scripts/underscore.mixins.js @@ -232,7 +232,7 @@ if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { - var cookie = _.trim(cookies[i]); + var cookie = _.str.trim(cookies[i]); if (cookie.substring(0, name.length + 1) == (name + '=')) { return decodeURIComponent(cookie.substring(name.length + 1)); } diff --git a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj index 3257f0c837..8340a62bfb 100644 --- a/src/Presentation/SmartStore.Web/SmartStore.Web.csproj +++ b/src/Presentation/SmartStore.Web/SmartStore.Web.csproj @@ -1,5 +1,5 @@  - + Debug @@ -13,7 +13,7 @@ Properties SmartStore.Web SmartStore.Web - v4.5 + v4.5.1 false true @@ -36,6 +36,7 @@ + 7e91da2d true @@ -47,6 +48,7 @@ 4 false AnyCPU + AllFilesInProjectFolder pdbonly @@ -56,26 +58,27 @@ prompt 4 false - AllFilesInTheProject + AllFilesInProjectFolder false false + AnyCPU - - False - ..\..\packages\AjaxMin.5.8.5172.27710\lib\net40\AjaxMin.dll + + ..\..\packages\AjaxMin.5.14.5506.26202\lib\net40\AjaxMin.dll + True False ..\..\packages\Antlr.3.5.0.2\lib\Antlr3.Runtime.dll - - False - ..\..\packages\Autofac.3.4.1\lib\net40\Autofac.dll + + ..\..\packages\Autofac.3.5.2\lib\net40\Autofac.dll + True - False - ..\..\packages\Autofac.Mvc5.3.3.0\lib\net45\Autofac.Integration.Mvc.dll + ..\..\packages\Autofac.Mvc5.3.3.4\lib\net45\Autofac.Integration.Mvc.dll + True False @@ -94,34 +97,31 @@ False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.dll False - ..\..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll + ..\..\packages\EntityFramework.6.1.3\lib\net45\EntityFramework.SqlServer.dll False - ..\..\packages\EntityFramework.SqlServerCompact.6.1.0\lib\net45\EntityFramework.SqlServerCompact.dll - - - False - ..\..\packages\51Degrees.mobi.2.1.19.4\lib\NET40\FiftyOne.Foundation.dll + ..\..\packages\EntityFramework.SqlServerCompact.6.1.3\lib\net45\EntityFramework.SqlServerCompact.dll - - False - ..\..\packages\FluentValidation.5.0.0.1\lib\Net40\FluentValidation.dll + + ..\..\packages\FluentValidation.5.6.2.0\lib\Net45\FluentValidation.dll + True - - False - ..\..\packages\FluentValidation.MVC4.5.0.0.1\lib\Net40\FluentValidation.Mvc.dll + + ..\..\packages\FluentValidation.MVC5.5.6.2.0\lib\Net45\FluentValidation.Mvc.dll + True - - False - ..\..\packages\JavaScriptEngineSwitcher.Core.1.1.3\lib\net40\JavaScriptEngineSwitcher.Core.dll + + ..\..\packages\JavaScriptEngineSwitcher.Core.1.2.4\lib\net40\JavaScriptEngineSwitcher.Core.dll + True - - ..\..\packages\JavaScriptEngineSwitcher.Msie.1.1.4\lib\net40\JavaScriptEngineSwitcher.Msie.dll + + ..\..\packages\JavaScriptEngineSwitcher.Msie.1.2.11\lib\net40\JavaScriptEngineSwitcher.Msie.dll + True False @@ -131,15 +131,13 @@ True ..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - - ..\..\packages\MsieJavaScriptEngine.1.4.2\lib\net40\MsieJavaScriptEngine.dll - - - False - ..\..\packages\Newtonsoft.Json.6.0.1\lib\net45\Newtonsoft.Json.dll + + ..\..\packages\MsieJavaScriptEngine.1.5.6\lib\net40\MsieJavaScriptEngine.dll + True - - ..\..\packages\recaptcha.1.0.5.0\lib\.NetFramework 4.0\Recaptcha.dll + + ..\..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll + True @@ -147,30 +145,30 @@ True ..\..\packages\Microsoft.SqlServer.Compact.4.0.8876.1\lib\net40\System.Data.SqlServerCe.dll + False ..\..\packages\System.Linq.Dynamic.1.0.0\lib\net40\System.Linq.Dynamic.dll - - + False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.Helpers.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - + False - ..\..\packages\Microsoft.AspNet.Mvc.5.1.2\lib\net45\System.Web.Mvc.dll + ..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll False @@ -178,20 +176,20 @@ False - ..\..\packages\Microsoft.AspNet.Razor.3.1.2\lib\net45\System.Web.Razor.dll + ..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Deployment.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll False - ..\..\packages\Microsoft.AspNet.WebPages.3.1.2\lib\net45\System.Web.WebPages.Razor.dll + ..\..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll @@ -199,7 +197,8 @@ - ..\..\packages\TelerikMvcExtensions.2012.2.607\lib\net40\Telerik.Web.Mvc.dll + False + ..\..\..\lib\Telerik\Telerik.Web.Mvc.dll True @@ -214,47 +213,50 @@ Properties\AssemblyVersionInfo.cs - + True True - EditorLocalization.de-DE.resx + EditorLocalization.de.resx True True EditorLocalization.resx - + True True - EditorLocalization.en-US.resx + GridLocalization.de.resx - + True True - GridLocalization.de-DE.resx + GridLocalization.resx - + True True - GridLocalization.resx + MvcLocalization.resx - + True True - GridLocalization.en-US.resx + MvcLocalization.de.resx + + + - + @@ -271,14 +273,15 @@ - Global.asax + - + + @@ -286,7 +289,8 @@ - + + @@ -333,6 +337,7 @@ + @@ -341,8 +346,8 @@ - + @@ -439,6 +444,8 @@ + + @@ -457,257 +464,352 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + ResXFileCodeGenerator + MvcLocalization.de.Designer.cs + Designer + + Designer - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + - - - - + - + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -718,78 +820,22 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -810,183 +856,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -997,53 +891,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1053,21 +906,30 @@ - - - - + + + + + + + + + + + + - + + + + - - @@ -1084,14 +946,18 @@ + + - - + + + + @@ -1101,27 +967,10 @@ - - - - - - - - - - - - - - - - - @@ -1138,8 +987,6 @@ - - @@ -1152,47 +999,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1445,87 +1251,16 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1539,140 +1274,22 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1684,19 +1301,16 @@ - - - - - - - + + + + @@ -1716,8 +1330,7 @@ - - + @@ -1726,37 +1339,35 @@ - - - - - + + + + + - - + + - + - - - - - - - - - - + + + + + + + + + - @@ -1774,27 +1385,15 @@ - - - - - Designer - - - - - - - - - + + + - - + + - Designer @@ -1802,12 +1401,12 @@ - + - + @@ -1846,10 +1445,9 @@ - - + @@ -1862,25 +1460,25 @@ - - + + - + - + - + @@ -1893,7 +1491,6 @@ - @@ -1903,9 +1500,9 @@ - - - + + + @@ -1913,32 +1510,81 @@ - + - - + Code - + - - + + - - + + Code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -1969,7 +1615,7 @@ - + @@ -1988,9 +1634,6 @@ - - - @@ -2009,22 +1652,22 @@ - - - - + + + + - - - - - - - - - + + + + + + + + + - + @@ -2033,7 +1676,6 @@ - @@ -2044,20 +1686,19 @@ - + - - + + - + - @@ -2071,8 +1712,8 @@ - - + + @@ -2082,7 +1723,7 @@ - + @@ -2101,14 +1742,14 @@ - + - - + + @@ -2132,14 +1773,9 @@ - - - - - @@ -2171,39 +1807,27 @@ - + GlobalResourceProxyGenerator - GridLocalization.designer.cs + EditorLocalization.de.designer.cs - - - - GlobalResourceProxyGenerator - GridLocalization.en-US.designer.cs - - - - - GlobalResourceProxyGenerator - GridLocalization.de-DE.designer.cs - - - GlobalResourceProxyGenerator EditorLocalization.designer.cs - - - + + GlobalResourceProxyGenerator + GridLocalization.de.designer.cs + + GlobalResourceProxyGenerator - EditorLocalization.en-US.designer.cs + GridLocalization.designer.cs - + GlobalResourceProxyGenerator - EditorLocalization.de-DE.designer.cs + MvcLocalization.Designer.cs @@ -2234,25 +1858,12 @@ - - if not exist "$(TargetDir)x86" md "$(TargetDir)x86" - xcopy /s /y "$(SolutionDir)..\lib\sqlce\x86\*.*" "$(TargetDir)x86" - xcopy /s /y "$(SolutionDir)..\lib\ClearScript.V8\Native\x86\*.*" "$(TargetDir)x86" -if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64" - xcopy /s /y "$(SolutionDir)..\lib\sqlce\amd64\*.*" "$(TargetDir)amd64" - xcopy /s /y "$(SolutionDir)..\lib\ClearScript.V8\Native\amd64\*.*" "$(TargetDir)amd64" - -if not exist "$(TargetDir)ClearScript.V8" md "$(TargetDir)ClearScript.V8" - xcopy /s /y "$(SolutionDir)..\lib\ClearScript.V8\lib\*.*" "$(TargetDir)ClearScript.V8" + + @@ -2263,5 +1874,80 @@ if not exist "$(TargetDir)ClearScript.V8" md "$(TargetDir)ClearScript.V8" + + + + false + + + + + **\*.cs; + **\*.orig; + **\*.bak; + **\*.log; + **\*.csproj; + **\*.csproj.user; + **\*.DotSettings.user; + **\packages.config; + **\*.Debug.config; + **\*.Release.config; + **\obj\**; + **\bin\*.xml; + **\bin\HostRestart\**; + Administration\bin\**; + App_Data\_Backup\**; + App_Data\_temp\**; + App_Data\ExportProfiles\**; + App_Data\ImportProfiles\**; + App_Data\Migrations\**; + App_Data\InstalledPlugins.txt; + App_Data\Licenses.lic; + App_Data\Settings.txt; + App_Data\SmartStore.Db.sdf; + Exchange\**; + Content\Files\ExportImport\**; + Content\Images\Thumbs\**; + Media\**\*.png; + Media\**\*.jpg; + Media\**\*.jpeg; + Media\**\*.gif; + Media\**\*.pdf; + Media\**\*.docx; + Properties\**; + Plugins\*\bin\**; + + + + + + + + + + + + + + + + + + + + + + + + $(ProjectDir)Media\Thumbs\placeholder.txt + + + + + + + + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/blocks.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/blocks.less new file mode 100644 index 0000000000..5560cd9dc7 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/blocks.less @@ -0,0 +1,108 @@ +// +// Block & Container Styles +// -------------------------------------------------- + +@baseBlockRadius: @var_ContainerRadius; +@baseBlockHeaderGradient: @var_ContainerHeaderBackground; + +.block { + margin: 12px 0 24px 0; +} + +.block.topic-html-content { + margin-top: 12px; + margin-bottom: 12px; +} + +.block .block-title, +.section-title, +fieldset > legend { + padding-bottom: 8px; + font-family: @pageTitleFontFamily; + font-weight: @pageTitleFontWeight; + font-size: 20px; + line-height: 28px; + border-bottom: 1px solid @var_SimpleBoxHeaderColor; + + & > * { + // probably h1-h6 + font-family: inherit; + font-weight: inherit; + color: inherit; + margin: 0; + padding: 0; + } +} + +.block .block-body { + padding: 16px 0; +} + + +.block.block-bordered { + background: @var_ContainerBodyBackground; + border: 1px solid @var_ContainerBorder; + .border-radius(@baseBlockRadius); + margin: 0 0 10px 0; + + #content-left & { + border-left: none; + .border-radius(0 @baseBlockRadius @baseBlockRadius 0); +} + + #content-right & { + border-right: none; + .border-radius(@baseBlockRadius 0 0 @baseBlockRadius); + } +} + +.block.block-bordered .block-title { + border-bottom: 1px solid @var_ContainerBorder; + margin: 0; + padding: 8px 10px; + font-family: inherit; + color: @var_ContainerHeaderFontColor; + font-weight: bold; + line-height: @var_ContainerHeaderHeight !important; + .smaller(); + text-transform: uppercase; + .border-radius(@baseBlockRadius @baseBlockRadius 0 0); + + #gradient > .vertical( lighten(@baseBlockHeaderGradient, 7%), @baseBlockHeaderGradient); + + #content-left & { + .border-radius(0 @baseBlockRadius 0 0) + } + #content-right & { + .border-radius(@baseBlockRadius 0 0 0) + } +} + +.block.block-bordered .block-body { + padding: 10px; + color: @var_ContainerBodyFontColor; + + #content-left & { + .border-radius(0 0 (@baseBlockRadius - 1) 0) + } + #content-right & { + .border-radius(0 0 0 (@baseBlockRadius - 1) ) + } +} + +.block.block-bordered .listbox { padding: 10px } +.block.block-bordered a { + text-decoration: none; + color: @var_ContainerBodyLinkColor; + .transition(color .1s linear); + &:hover { color: #333 } +} +.block.block-bordered ul { margin: 0 } +.block.block-bordered ul ul { margin-left: 1.2em } +.block.block-bordered li { + list-style: none; + &.active > a, + &.selected > a { font-weight: bold; color: inherit } +} +.block.block-bordered li.separator { display: block; height:1px; line-height:1px; background:#f93; font-size:1px; margin: 5px 0; } +.block.block-bordered .view-all { font-weight: bold; margin-top: 0.4em } diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/blog.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/blog.less new file mode 100644 index 0000000000..48aac52bf4 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/blog.less @@ -0,0 +1,103 @@ +// +// Blog Styles +// -------------------------------------------------- + +.blog-page .blogpost { + .hr(); + padding: 20px 0; +} + +.blog-page .blogpost .blogpost-info { + + .blogpost-comments { + position: relative; + display: block; + text-decoration: none; + font-weight: bold; + width: 50px; + height: 50px; + float: right; + } + + .blogpost-comments .blogpost-comments-icon { + position: absolute; + font-size: 50px; + line-height: 50px; + color: #f1f1f1; + } + + .blogpost-comments .blogpost-comments-count { + position: absolute; + top: 13px; + font-size: 13px; + line-height: 16px; + width: 38px; + text-align: center; + color: #c5c5c5; + } + + .blogpost-comments.vivid { + .blogpost-comments-icon { color: @textColor; } + .blogpost-comments-count { color: @bodyBackground; } + } + + .blogpost-date { + clear: both; + float: right; + text-align: right; + margin-bottom: 8px; + } + + .blogpost-tags { + clear: both; + } +} + +.blog-page .blogpost .blogpost-content { + .blogpost-title { + .title-typo(); + margin-top: 0; + & > a { + text-decoration: none; + } + } +} + +.news-item-page .news-date, +.blogpost-page .blogpost-date { + float: right; + margin-top: 12px; +} + +.new-comment .comment-title { + width: 70%; +} +.new-comment .comment-text { + width: 70%; + height: 150px; +} + +.comment-item { + margin-bottom: 20px; + position: relative; + .comment-avatar { + position: absolute; + top: 2px; + left: 0; + } + .comment-content { } + .comment-content .comment-info { + margin-bottom: 12px; + .username { + font-weight: bold; + color: inherit; + font-size: 16px; + } + .comment-time { + margin-left: 4px; + color: #bbb; + } + } +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/bootstrap.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/bootstrap.less new file mode 100644 index 0000000000..d4c3a5acd4 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/bootstrap.less @@ -0,0 +1,79 @@ +/*! + * Uses Bootstrap v2.2.1 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +// CSS Reset +@import "~/Content/bootstrap/reset.less"; + +// Core variables and mixins +@import "variables.less"; +@import "variables.custom.less"; +@import "~/Content/bootstrap/mixins.less"; +@import "~/Content/bootstrap/custom/mixins.less"; + +// Grid system and page structure +@import "~/Content/bootstrap/scaffolding.less"; +@import "~/Content/bootstrap/grid.less"; +@import "~/Content/bootstrap/responsive-1200px-min.less"; +//@import "~/Content/bootstrap/responsive-768px-979px.less"; +@import "~/Content/bootstrap/responsive-767px-max.less"; +@import "~/Content/bootstrap/layouts.less"; + +// Base CSS +@import "~/Content/bootstrap/type.less"; +@import "~/Content/bootstrap/code.less"; +@import "~/Content/bootstrap/forms.less"; +@import "~/Content/bootstrap/tables.less"; + +// Components: common +//@import "~/Content/bootstrap/font/font-awesome.less"; +@import "~/Content/bootstrap/dropdowns.less"; +@import "~/Content/bootstrap/wells.less"; +@import "~/Content/bootstrap/component-animations.less"; +@import "~/Content/bootstrap/close.less"; + +// Components: Buttons & Alerts +@import "~/Content/bootstrap/buttons.less"; +@import "~/Content/bootstrap/button-groups.less"; +@import "~/Content/bootstrap/alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less + +// Components: Nav +@import "~/Content/bootstrap/navs.less"; +@import "~/Content/bootstrap/navbar.less"; +@import "~/Content/bootstrap/breadcrumbs.less"; +@import "~/Content/bootstrap/pagination.less"; +@import "~/Content/bootstrap/pager.less"; + +// Components: Popovers +@import "~/Content/bootstrap/modals.less"; +@import "~/Content/bootstrap/tooltip.less"; +@import "~/Content/bootstrap/popovers.less"; + +// Components: Misc +@import "~/Content/bootstrap/thumbnails.less"; +@import "~/Content/bootstrap/media.less"; +@import "~/Content/bootstrap/labels-badges.less"; +@import "~/Content/bootstrap/progress-bars.less"; +@import "~/Content/bootstrap/carousel.less"; + +// (MC) extra 3rd party or own components +@import "~/Content/bootstrap/custom/spinner.less"; +@import "~/Content/bootstrap/custom/throbber.less"; +@import "~/Content/bootstrap/custom/select2.less"; +@import "~/Content/bootstrap/custom/datetimepicker.less"; +@import "~/Content/bootstrap/custom/navbar.less"; +@import "~/Content/bootstrap/custom/scrollbutton.less"; +@import "~/Content/bootstrap/custom/star-rating.less"; + +// (MC) extra tweaks and corrections +@import "~/Content/bootstrap/custom/custom.less"; + +// Utility classes +@import "~/Content/bootstrap/utilities.less"; // Has to be last to override when necessary + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/cart.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/cart.less new file mode 100644 index 0000000000..1db6a5e082 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/cart.less @@ -0,0 +1,152 @@ +// +// ShoppingCart, OrderSummary & WishList Styles +// -------------------------------------------------- + +.order-summary-content .delivery-time { + text-align: left; +} + +.order-summary-content .base-price.muted { + font-size: .85em; +} + +.order-totals-left .column { + float: left; + width: 48%; + box-sizing: border-box; +} + +.order-totals-left .column:last-child { + margin-left: 4%; +} + +.wishlist-page .share-label .fa-share { + color: inherit; + font-size: 24px; +} + +.cart { + border-bottom: 1px solid #ddd; + margin-top: 20px; +} + +.cart .omega { + text-align: right; +} + +.cart .unit-price { + text-align: right; +} + +.cart .cart-item-row .remove, +.cart .cart-item-row .addtocart { + text-align: center; + vertical-align: top; +} + +.cart .cart-item-row .productpicture img { + max-width: 70px; +} +.cart .cart-item-row .product { + width: 100%; +} + +.cart .product .short-desc { + font-size: 12px; +} + +.cart .cart-item-row .product-subtotal, +.cart .cart-item-row .product > a, +.cart .product-bundle-row .bundle-headline { + font-weight: bold; +} +.cart .cart-item-row .qty-input { + width: 32px; +} +.cart .cart-item-row .measure-unit { + vertical-align: top; +} +.order-summary-content .cart-footer { + margin-top: 20px; +} + +.order-summary-content .cart-footer { + margin-top: 20px; +} + +.order-summary-content .cart-box { } +.order-summary-content .cart-box .title { + margin: 0 0 12px 0; + color: inherit; + font-weight: bold; +} +.order-summary-content .cart-box .hint { + margin-bottom: 12px; +} +.order-summary-content .cart-box .alert { + margin: 0 0 12px 0; +} +.order-summary-content .cart-box .current-code { + margin: 12px 0 0 0; +} +.order-summary-content .cart-box .input-append > .prompt { + width: 70%; +} +.estimate-shipping.cart-box .shipping-options { + .smaller(); +} +.estimate-shipping.cart-box .shipping-options .option-name { + font-weight: bold; +} + +.order-summary-content .cart-total .cart-total-left { + padding-left: 4px; + max-width: 200px; + overflow: hidden; +} +.cart-total-left-below { + text-align: right; + vertical-align: top; +} +.order-summary-content .cart-total .cart-total-right { + text-align: right; + font-weight: bold; + padding-right: 8px; + + & .info { + font-weight: normal; + .smaller(); + color: @grayLight; + } +} +.order-summary-content .cart-total .selected-shipping-method { + .smaller(); +} +.order-summary-content .cart-total .order-total { + .text-success; +} +.order-summary-content .cart-total tr td { + border-top: none; +} +.order-summary-content .cart-total .lined td { + border-top: 1px solid #ddd; +} +.order-summary-content .cart-total .omega td { + // order totals + border-top-width: 2px; +} + +.order-summary-content .selected-checkout-attributes, +.order-details .checkout-attributes { + .attr-caption { + font-weight: bold; + padding-right: 10px; + &:after { + content: ': ' + } + } + .attr-value { + text-align: left; + } +} + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/catalog.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/catalog.less new file mode 100644 index 0000000000..d9d5aff4e6 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/catalog.less @@ -0,0 +1,106 @@ +// +// Catalog Styles +// -------------------------------------------------- + +.delivery-time { + text-align: center; + padding-bottom: 5px; + .smaller(); + .delivery-time-label { + padding-right: 4px; + font-weight: bold; + } + .delivery-time-color { + height: 8px; + width: 32px; + display: inline-block; + border: 1px solid rgba(0,0,0, .25); + background-image: url('images/deliv-bg-aero.png'); + } +} + +.label-discount-sign { + font-weight: normal; + vertical-align: text-bottom; +} + +.featured-product-grid { + margin-bottom: 20px; + + .section-title { + margin-bottom: 15px; + } +} + + +.product-tags-all-page .product-tags-list li { + display: inline; +} +.product-tags-all-page .product-tags-list li a { + margin: 0 2px 0 0; + &:hover { text-decoration: underline } +} + +.category-grid, +.manufacturer-grid { + margin-bottom: 12px; + .item-box { + text-align: center; + vertical-align: text-top; + } +} + +.category-grid .category-item .category-title, +.manufacturer-grid .manufacturer-item .man-title { + .font-inherit(); + font-weight: bold; + display: block; + overflow: hidden; + margin: 0; + line-height: 18px; + padding-top: 8px; + & a { + color: inherit; + } +} +.category-grid .category-item .picture, +.manufacturer-grid .manufacturer-item .picture { + padding: 10px 0; +} +.category-description { + margin-bottom: 20px; +} + +// +// Product List Options (paging, sorting etc.) +// -------------------------------------------------- + +.product-list-options { + padding: 10px 0 15px 0; + margin-bottom: 15px; + border-bottom: 1px solid #ddd; + border-bottom-color: rgba(0,0,0, 0.12); +} + +.product-list-options label { + margin: 6px 7px 0 7px +} + +.product-list-options .btn { + border-radius: 0 0 0 0 !important; + padding: 10px; + .text-overflow(); +} + +// +// Search panel +// -------------------------------------------------- + +.search-page .basic-search { + border-bottom: 1px solid #ddd; + border-bottom-color: rgba(0,0,0, 0.12); + margin-bottom: 6px; +} + + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/checkout.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/checkout.less new file mode 100644 index 0000000000..60e01fb235 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/checkout.less @@ -0,0 +1,274 @@ +// +// Checkout Styles +// -------------------------------------------------- + + +/* Checkout +================================================ */ + +.checkout-data { + .opt-list { + margin-bottom: 20px; + } + .opt-list-item { + position: relative; + padding: 12px 12px; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin-top: -1px; + } + .opt-list-item.selected { + background-color: #f9f9f9; + border-color: #f9f9f9; + } + .opt-info, + .opt-info-item { + margin-top: 6px; + margin-left: 32px; + } + .opt-info .form-horizontal { + margin-top: 20px; + } + .opt-info .form-horizontal .control-label { + text-align: left; + width: 200px; + &.required { + font-weight: normal; + } + } + .opt-info .form-horizontal .controls { + margin-left: 220px; + } + .opt-info .form-horizontal .control-group { + margin-bottom: 12px; + } + .opt-info .media .pull-left { + width: 120px; + } + .opt-info .media-object { + max-width: 120px; + text-align: center; + } + .opt-info .media-body { + .muted(); + } + .opt-control { + padding-right: 100px; + } + .opt-control label { + cursor: pointer; + margin-bottom: 0; + } + .opt-name { + font-weight: bold; + margin-left: 12px; + .text-overflow(); + } +} + + +/* Order Progress +================================================ */ + +.order-progress { + margin: 0 auto; + text-align: center; + border-bottom: 1px solid #ddd; + padding: 8px 0; + background-color: @var_CheckoutProgressBackgroundColor; +} +.order-progress ul li { + display: inline; +} +.order-progress .order-progress-step { + position: relative; + display: inline-block; + padding: 38px 12px 4px; + text-decoration: none; + color: #818181; + border: 1px solid transparent; + cursor: default; + .transition(opacity .1s linear); +} +.order-progress .visited .order-progress-step { + cursor: pointer; + color: #333; + .opacity(75); + &:hover { + .opacity(100); + } +} +.order-progress .active .order-progress-step { + .opacity(100); + background: #f2f2f2; + color: #333; + border-color: #ccc; + .border-radius(4px); + .box-shadow(~"inset 0 2px 8px rgba(0,0,0,.08)"); +} +.order-progress .inactive .order-progress-step { + .opacity(50); +} +.order-progress .order-progress-step:before { + position: absolute; + top: 8px; + left: 50%; + margin-left: -16px; + font-family: FontAwesome; + font-weight: normal; + font-size: 32px; + line-height: 32px; + width: 32px; + height: 32px; + content: '\f07a'; + display: inline-block; + text-decoration: inherit; + .opacity(75); +} +.order-progress .order-progress-step.step-address:before { content: '\f015' /* fa-home */; } +.order-progress .order-progress-step.step-shipping:before { content: '\f0d1' /* fa-truck */; } +.order-progress .order-progress-step.step-payment:before { content: '\f09d' /* fa-creditcard */ } +.order-progress .order-progress-step.step-confirm:before { content: '\f087' /* fa-thumbs-up */; } +.order-progress .order-progress-step.step-complete:before { content: '\f058' /* fa-ok-sign */ } + +.order-summary-page #content-body { + margin-top: 0; +} + + +/* Checkout Data +================================================ */ + +.checkout-data .select-address-title, +.checkout-data .enter-address-title { + padding:10px 10px 5px 0; + font-family: 'Segoe UI light','Segoe UI'; + font-weight: 100; + color: #aaa; +} +.checkout-data .enter-address .buttons { + border-top: 1px solid #ccc; + padding-top: 10px; +} + +.checkout-data .address-grid { + padding-bottom: 0; +} +.checkout-data .address-grid .item-box { + text-align:center; + vertical-align:text-top; +} +.checkout-data .address-grid .address-item { + padding: 12px; +} +.checkout-data .address-grid .address-item .select-button { + margin-bottom: 10px; +} +.checkout-data .address-grid .address-item .address-box { + text-align:left; +} + +.address-required-hint { + margin-bottom: 12px; + font-size: 12px; +} + +.checkout-data .payment-info { + padding: 10px 0; + border-top: 1px solid #d7d7d7; + border-bottom: 1px solid #d7d7d7; +} +.checkout-data .payment-info .select-button { + padding-top: 10px; + border-top: 1px solid #d7d7d7; +} +.checkout-data .order-completed .select-button { + padding-top: 15px; +} + +.order-details-table .item-box { + padding: 10px; + margin: 0 20px 20px 0; +} +.order-details-table .shippinginfo .item-box { + margin-right: 0; +} + +/* Checkout Confirm +================================================ */ + +.checkout-confirm-page .terms-of-service { + margin: 10px 0; +} + +.checkout-data .change-checkout-data { + font-weight: normal; + text-transform: none; + color: @linkColor; + &:hover { color: @linkColorHover } +} + +.checkout-confirm-page .comment-box textarea { + width: 99%; + height: 50px; +} + +.checkout-confirm-page .order-summary-content form { + border: 1px solid #bbb; + border-bottom: none; + background: #efefef; + margin: 0 !important; + padding-bottom: 20px; + .border-radius(@var_ContainerRadius @var_ContainerRadius 0 0); +} +.checkout-confirm-page .checkout-data > .confirm-order { + border: 1px solid #bbb; + background: #efefef; + border-top: none; + padding: 20px; + margin-bottom: 30px; + .border-radius(0 0 @var_ContainerRadius @var_ContainerRadius); +} +.checkout-confirm-page .confirm-order-legal-hint { + border-left: 1px solid #bbb !important; + border-right: 1px solid #bbb !important; + margin: auto; + text-align: center; + .border-radius(0); +} + + +/* Terms of service +================================================ */ +.terms-of-service.alert { + padding-bottom: 4px !important; + a.read { + font-weight: bold; + &:hover { + cursor: pointer; + } + } +} + + +/* Checkout Completed +================================================ */ + +.checkout-completed-page .page-title { + margin-bottom: 0; +} + +.checkout-completed-page .page-title h1 { + text-transform: uppercase; + text-align: center; + margin-bottom: 0; +} + +.checkout-completed-page .page-body { + text-align: center; + margin-top: 40px; +} + +.checkout-completed-page .thank-you { + text-align: center; +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/common.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/common.less new file mode 100644 index 0000000000..327e7c7ea5 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/common.less @@ -0,0 +1,185 @@ +// +// Common CSS & mixins +// -------------------------------------------------- + + +/* Mixins +================================================ */ + +.hr() { + border-top: 1px solid #ddd; + &:first-child { + border-top: none; + } +} + + +/* General +================================================ */ + +body { + background-attachment: fixed; + @bodyBgColor: @var_SiteBackground; + #gradient > .vertical(@bodyBgColor, lighten(@bodyBgColor, 4%)); +} + +body.popup { + background: @bodyBackground; +} + + +#content { + background-color: @bodyBackground; + .box-shadow(~'0 0 15px rgba(0,0,0, .15), 0 10px 6px -10px rgba(0,0,0, .4)'); + padding: 0; + z-index: 2; +} + +select { + min-width: initial; +} + +legend { + color: #acacac; +} + +.checkbox input[type="checkbox"] { + margin-top: 4px; +} + +// required for placeholder plugin (< IE10) +input.placeholder { + color: @grayLight !important; +} + +.control-group.buttons { + padding-top: 20px; + border-top: 1px solid #ddd; +} + +body.popup { + margin: 0; + padding: 0; + border: 0; +} + +nav ul, nav li { + margin: 0; + padding: 0; + list-style-type: none; +} + +// Hide only visually, but have it available for screenreaders: by Jon Neal. +.hidden-accessible { + border: 0; + clip: rect(0,0,0,0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px +} + +.nobr { + white-space: nowrap !important; +} +.wrap { + white-space: normal !important; +} + +.clear { + border: medium none; + clear: both; + float: none; + font-size: 0; + height: 0; + line-height: 0; +} + +.first-col { margin-left: 10px } +.last-col { margin-right: 10px } + +.date-part { + margin-right: 5px; +} + + +/* Validation & Errors +================================================ */ + +.message-error { + .small(); + color: @red; +} +.message-error ul { + padding: 0px; +} +.message-error ul li { + list-style: none; +} + +.message-error, +.validation-summary-errors, +.field-validation-error, +.required { + .small(); + color: @red; +} + +/* Misc +================================================ */ + +#popup-content { + margin: 20px; +} + +.captcha-box { + margin-bottom: 12px; +} + +.simple-link-list-prepend > div { + padding-bottom: 5px; +} +.simple-link-list-append > div { + margin-top: 5px; +} +.simple-link-list h5 { + margin: 0; +} +.simple-link-list ul { + list-style-type: none; + margin: 0 0 10px 1px; +} +.simple-link-list li { + line-height: 26px; + vertical-align: middle; +} + +.addon-buttons { + clear: both; +} + +.glimpse-nowrap { + z-index: 100; +} + +.mini-button-icon { + font-size: 10px; + padding-right: 5px; +} + +p.continued { + margin-bottom: 2px; +} + +#switch-to-mobile { + text-align: center; + margin: 0 0 10px 0; + display: none; +} + + + + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/custom.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/custom.less new file mode 100644 index 0000000000..f59e5af7aa --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/custom.less @@ -0,0 +1,5 @@ +// +// Customize the (child) theme here with css overrides +// or new selectors (for theme developers)) +// -------------------------------------------------- + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/datalist.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/datalist.less new file mode 100644 index 0000000000..6cd5cfe191 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/datalist.less @@ -0,0 +1,303 @@ +// +// DataList Styles +// -------------------------------------------------- + + +/* Data Lists +================================================ */ + +.data-list .thumbnail .caption { + padding: 4px; +} +.data-list-grid .data-list-row, +.data-list .data-list-item { + margin-bottom: 12px; +} + + +/* Item Box +================================================ */ + +.item-box { + position: relative; + .small(); + + background: @var_BoxBackground; + border: 1px solid #ddd; + .box-shadow(0 1px 3px rgba(0,0,0,.055)); + .transition(~'box-shadow .12s linear, border-color .12s linear'); + + &:hover { + border: 1px solid @var_ItemBoxBoxShadowColor; + .box-shadow(0px 0px 6px fade(@var_ItemBoxBoxShadowColor, 40%)); + } +} + +.item-box.no-border { + border-color: transparent; + .box-shadow(0 0 0 rgba(0,0,0,.0)); +} + +.item-box.product-compact { + .small(); + text-align: center; +} + +.item-box .name { + font-family: inherit; + font-weight: normal; + font-size: inherit; + line-height: inherit; + overflow: hidden; + margin-bottom: 0.3em; + margin-top: 0; + color: inherit; + a { + font-weight: bold; + text-decoration: none; + color: inherit; //#555; + &:hover { + color: darken(@textColor, 12%); + } + + > span { + vertical-align: middle; + } + } +} + +.item-box .name .label.label-isnew { + font-size: 10px; + line-height: 10px; + font-weight: normal; + text-shadow: none; + text-transform: uppercase; +} + +.item-box.details { + margin-bottom: 20px; +} + +.item-box.details .name { + margin-top: 10px; +} + +.item-box.details .name a { + font-size: 15px; +} + +.item-box figure.picture { + position: relative; + z-index: 0; + padding: 12px 12px 4px 12px; + text-align: center; + margin: 0; + min-height: 100px; +} + +.item-box figure.picture a { + display: inline-block; + position: relative; + z-index: 0; +} + +.item-box figure.picture .colors { + position: absolute; + left: 4%; + right: 4%; + bottom: 3px; + z-index: 1; + .opacity(0); + text-align: center; + line-height: 6px; + font-size: 0; + overflow: hidden; + .transition(opacity .15s linear); + -webkit-transform: translateZ(0); +} + +.item-box:hover figure.picture .colors { + .opacity(100); +} + +.item-box.details figure.picture .colors { + position: relative; + .opacity(50); + top: 12px; + bottom: auto; + text-align: left; +} + +.item-box figure.picture .colors > span { + display: inline-block; + width: 6px; + height: 6px; + margin-right: 3px; + border: 1px solid rgba(0,0,0,.3); + *border-color: #aaa; +} + +.item-box .data { + padding: 12px; + padding-top: 8px; +} + +.item-box.details .data { + padding: 0 8px 0 0; +} + +.item-box .description { + color: #999; + font-size: 1em; +} + +.item-box .description a[rel=tooltip] { + color: inherit; + text-decoration: none; +} + +.item-box .buttons { + text-align: center; + margin-top: 10px; +} + +.item-box.details .delivery-time { + text-align: left !important; +} + +.item-box.details .delivery-time .attr-label span strong { + color: #464646 !important; +} + +.item-box .prices { + text-align: center; + .product-price { + margin-bottom: 0; + .price { + font-weight: bold; + font-size: @baseFontSize; + color: @productListsPriceColor; + } + } + .old-product-price { + margin: 0; + .price { + text-decoration: line-through; + color: #aaa; + } + } + .old-product-price .prefix, + .base-price, + .transport-charge { + .smaller(); + } +} + +.item-box.details .attribute-block { + width:60%; + .attributes { + .smaller(); + .attr-label { + width: 30%; + white-space: nowrap; + padding-right: 3px; + color: #aaa; + } + } + .manufacturer-pics img{ + max-height: 40px; + padding: 10px 0 0 0; + } +} +.item-box.details .price-block { + width: 40%; + text-align: right; + .prices { + text-align: right; + } + .product-price { + margin-bottom: 0; + .price { + font-size: 20px; + color: @productListsPriceColor; + } + } + .transport-charge, + .base-price, + .legal-info { + .smaller(); + } + .legal-info a { + color: inherit; //#555; + font-weight: bold; + } +} +.item-box.details .buttons { + padding: 8px 0 8px 8px; +} + +.item-box .quicklinks { + padding: 5px 8px; + overflow: hidden; + .smaller(); + position: absolute; + z-index: 1; + left: 0; + top: 0; + right: 1px; + background: #fff; + background: rgba(255,255,255, .7); + .opacity(0); + .transition(opacity .2s linear); + -webkit-transform: translateZ(0); + a { + color: #666; + text-shadow: none; + &:hover { + color: #000; + text-decoration: none; + } + } + .fa { + font-size: 13px; + } +} +.item-box:hover .quicklinks { + .opacity(100); +} + +.item-box.details .quicklinks { + padding: 30px 0 0 0; + position: relative; + z-index: 1; + background: #fff; + border: 0; + .opacity(100); + a { + color: #646464; + text-shadow: none; + .smaller(); + padding-right: 3px; + .transition(color .2s linear); + &:hover { + color: #000; + } + } +} + +@media (max-width: 1200px) { + .item-box:not(.details) .quicklinks a > i { + // container is too small to display labels with icons + display: none; + } +} + +.item-box .reviews { + text-align: center; +} +.item-box.details .reviews { + position: absolute; + bottom: 7px; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/footer.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/footer.less new file mode 100644 index 0000000000..566d78aa6f --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/footer.less @@ -0,0 +1,74 @@ +// +// Footer Styles +// -------------------------------------------------- + + +#footer { + padding: 10px 0; + color: @var_FooterFontColor; + z-index: 1; + + @bgColor: @var_FooterBackground; + background-color: @bgColor; + .border-radius(@var_FooterRadius); + a { + color: @var_FooterLinkColor; + text-decoration: none; + .transition(color 0.1s linear); + &:hover { color: lighten(@var_FooterLinkColor, 25%) } + } +} + +#footer .row-fluid { + -webkit-transform: translateZ(0); +} + +#footer .footer-seals .content, +#footer .footer-social .content, +#footer .theme-selector .content { + margin-top: 15px; +} +#footer .footer-seals a, +#footer .footer-social a { + padding-right: 8px; + color: @var_FooterLinkColor; + &:hover { color: lighten(@var_FooterLinkColor, 18%) } + &.pull-right { padding-right: 0; } +} + +#footer h4 { + color: @var_FooterHeading; + font-family: @var_PageTitleFontFamily; //'Segoe UI Light', 'Segoe UI', Helvetica, Arial, sans-serif; + font-weight: @var_PageTitleFontWeight; + border-bottom: 1px solid mix(@var_FooterHeading, @var_FooterBackground); + padding-bottom: 8px; +} +.footer-disclaimer { + background-color: transparent; + color: mix(@var_SiteBackground, contrast(@var_SiteBackground), 70%); + padding: 8px 0; + .small(); +} +.footer-disclaimer a { + color: @var_HeaderLinkColor; + text-decoration: none; +} +.footer-disclaimer a.sm-hint { + color: inherit; +} +.footer-disclaimer a:hover { + color: @var_HeaderHoverColor; +} + +#footer .theme-selector form { + margin: 0; +} + +#newsletter-email { + width: 70%; +} +#newsletter-subscribe-button { + width: 30%; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/forum.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/forum.less new file mode 100644 index 0000000000..b37a0dfa77 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/forum.less @@ -0,0 +1,261 @@ +// +// Forum Styles +// -------------------------------------------------- + +/* Forum Inputs +================================================ */ + +.forum-topic-title-text, +.pm-title-text, +.forum-search-text { + width: 500px; +} +.forum-post-text, +.bb-editor-text{ + width:100%; + height:300px; +} +.watch-topic-link-button, +.watch-topic-link-button:hover { + color: #646464; + font-weight: bold; +} + + +/* Forum Main +================================================ */ + +.forum-group .forum .image, +.active-discussionstopics .image, +.topics-group .image{ + vertical-align: middle; + text-align: center; + i { + font-size: 32px; + } +} +.active-discussionstopics .topic-starter, +.topics-group .topic-starter { + margin: 3px 10px 0 0; + .smaller(); + a { + color: #646464; + } +} +.active-discussionstopics .pagination-mini, +.topics-group .pagination-mini { + margin: 0; +} + +.forum-group .forum .topics, +.forum-group .forum .posts, +.active-discussionstopics .replies, +.active-discussionstopics .views, +.topics-group .replies, +.topics-group .views { + text-align: center; +} +.forums-main .current-time { + padding-top: 5px; +} +.forums-main .topic-html-content { + margin-top: -30px; + .block-title { + font-size: 34px; + } +} + +.forums-main .group-header .forum-spacer, +.active-discussions-header .topic-name, +.topics-group .topic-name { + width: 100%; +} +.forums-main .group-header .last-post, +.active-discussions-header .last-post, +.topics-group .last-post { + min-width: 200px; +} +.forum-group .last-post, +.topics-group .last-post, +.active-discussionstopics .last-post { + .smaller(); +} +.forum-group .forum-title a, +.active-discussionstopics .topic-title, +.topics-group .topic-title { + font-weight: bold; +} + +.forums-main .group-header th, +.active-discussions-header th, +.topics-group th { + white-space: nowrap; +} + + +/* Forum Topic Edit +================================================ */ + +.post-edit .wrapper{ + padding: 5px; +} +.post-edit .post-topic{ + width: 100%; + vertical-align: middle; + border-collapse: collapse; +} +.post-edit .post-topic td{ + padding: 4px; +} +.post-edit .post-topic .fieldname{ + font-weight: bold; + width: 20%; + text-align: right; + padding-right: 10px; +} +.post-edit .post-topic .options{ + text-align: right; +} +.move-forum-topic .move-topic .options { + padding: 20px 0 0 10px; +} +.move-forum-topic .move-topic .select2-container{ + padding-left: 10px; +} + +.forum .page-title .link-rss{ + margin: 17px 0 0 10px; +} +.active-discussions { + .link-rss { + margin: 14px 0 0 10px; + } + .btn-link { + color: #646464; + font-weight: bold; + } +} + + +/* Forum Topic +================================================ */ + +.active-discussions-page .forum-search-box form, +.forum-topic .forum-search-box form { + margin-bottom: 10px; +} + +.page.forum .top h3 { + margin-top: -5px; +} +.page.forum .page-title { + margin: 20px 0; +} + +.forum-topic .posts .block-title .pull-right { + text-transform: none; + a { + padding: 0 12px 0 0; + } + .post-link { + padding: 0 !important; + } +} +.forum-topic .topic-options { + margin-bottom: 5px; + .pagination { + margin: 0; + } + .pull-left { + padding: 10px 0 0 5px; + min-width: 250px + } +} +.forum-topic .topic-options.bottom .pull-left { + padding-top: 0; +} + +.forum-topic .post-info { + min-width: 160px; + margin: 0 10px 10px 0; +} +.forum-topic .manage.btn-group { + margin: 0 0 20px 0; +} + +.subscribe-to-post { + padding-top: 10px !important; +} +.post-info .user-info .user-stats, +.post-content .posttime { + .smaller(); +} +.post-info .user-info { + text-align: center; + margin-top: 10px; +} +.post-info .user-info .button-pm { + margin-top: 10px; + min-width: 100px +} +.forum-post { + position: relative; +} +.post-content { + margin: 0 0 50px 170px; +} +.post-content .functions { + position: absolute; + right: 10px; + bottom: 10px; + .fa-quote-left { + font-size: 10px; + } +} +.post-content .signature { + position: absolute; + bottom: 10px; + right: 0; + left: 0; + text-align: center; + margin-top: 20px; +} + +.posttext .quotefrom { + color: inherit; + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} + +.posttext blockquote { + margin-bottom: 0; +} + +.post-content .posttime { + margin-bottom: 5px; +} + + +/* Forum Search +================================================ */ + +.forum-search-box{ + font-size: .9em; + float: right; + text-align: right; + padding: 15px 0 0 0; +} +#advanced-search-block { + .title { + padding-right: 10px; + text-align: right; + } + .data { + padding: 5px 0; + } +} + + + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/header.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/header.less new file mode 100644 index 0000000000..012a75ee71 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/header.less @@ -0,0 +1,128 @@ +// +// Header Styles +// -------------------------------------------------- + +#header { + position: relative; + padding: 46px 0 0 0; +} + +.store-closed #header { + padding-top: 0; +} + +#logobar { + position: relative; + padding: 10px 0; + min-height: 50px; +} + +#logobar .brand { + float: left; + display: block; + position: relative; + + &.textual { + position: absolute; + top: 50%; + font-size: 26px; + line-height: 26px; + margin-top: -13px; + text-decoration: none; + font-family: @headingsFontFamily; + font-weight: @headingsFontWeight; + } +} + +.ie8 #logobar img { + max-width: auto; +} + +#nav-home li { + float: left; +} + +#nav-home li a { + display: block; +} + + +/* Regional Selectors +================================================ */ + +.regional-selectors { + position: absolute; + right: 0; + bottom: 0; +} + +.regional-selector li { + float: left; +} + +.regional-selector .regional-label { + display: block; + border: 1px solid @var_ChooserBorderColor; + background: @var_ChooserBackgroundColor; + color: @var_ChooserFontColor; + padding: 3px; + font-size: 12px; + line-height: 12px; + height: 12px; + min-width: 12px; + margin: 0 2px; + text-align: center; + vertical-align: middle; + text-decoration: none; + font-family: Arial, Helvetica, sans-serif; +} + +.regional-selector .selected .regional-label { + font-weight: bold; +} + +.regional-selector .selected .regional-label, +.regional-selector .regional-label:hover { + background: @var_ChooserActiveStateColor; +} + + +/* Currency Selector +================================================ */ + +#currency-selector { + float: left; + margin-left: 12px; +} + + +/* Language Selector +================================================ */ + +#language-selector { + float: left; +} + +#language-selector .regional-label { + font-size: 11px; +} + +#language-selector .flag { + float: left; + margin-right: 4px; + margin-bottom: 2px; + line-height: 13px; + border-top: 2px solid transparent; + .opacity(50); + .transition(opacity .1s linear); +} + +#language-selector li:hover .flag, +#language-selector .selected .flag { + .opacity(100); +} + +#language-selector .selected .flag { + border-top-color: @warningText; +} + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ajax_loader_large.gif b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ajax_loader_large.gif deleted file mode 100644 index fb2c7a3ddb..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ajax_loader_large.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/bbeditor-button-bg.gif b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/bbeditor-button-bg.gif deleted file mode 100644 index a93ffcaa3b..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/bbeditor-button-bg.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/gradient.png b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/gradient.png deleted file mode 100644 index 7c0307f62c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/gradient.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-delete.gif b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-delete.gif deleted file mode 100644 index 2ca8b23523..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-delete.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-edit.gif b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-edit.gif deleted file mode 100644 index 137a605679..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-edit.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-move-topic.gif b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-move-topic.gif deleted file mode 100644 index a5ee14c907..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/ico-move-topic.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-off-12.png b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-off-12.png similarity index 100% rename from src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-off-12.png rename to src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-off-12.png diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-off.png b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-off.png similarity index 100% rename from src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-off.png rename to src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-off.png diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-on-12.png b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-on-12.png similarity index 100% rename from src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-on-12.png rename to src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-on-12.png diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-on.png b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-on.png similarity index 100% rename from src/Presentation/SmartStore.Web/Themes/Beta/Content/images/star-on.png rename to src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-on.png diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-x-active.gif b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-x-active.gif deleted file mode 100644 index 5732c3126c..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-x-active.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-x-inactive.gif b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-x-inactive.gif deleted file mode 100644 index 38f627f39f..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/images/star-x-inactive.gif and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/layout.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/layout.less new file mode 100644 index 0000000000..b6cb2e661c --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/layout.less @@ -0,0 +1,26 @@ +// +// Layout Styles +// -------------------------------------------------- + +#content-wrapper, +#content-body, +#footer { + position: relative; +} + +#content-body { + margin-top: 10px; + padding-bottom: 10px; + min-height: 400px; +} + +/* one column */ +#content-center.alpha .page { + margin-left: @gridGutterWidth; +} +/* two columns */ +#content-center.omega .page { + margin-right: @gridGutterWidth; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/login.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/login.less new file mode 100644 index 0000000000..f0bf3a99c0 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/login.less @@ -0,0 +1,112 @@ +// +// Login & Registration Styles +// -------------------------------------------------- + +/* Login +================================================ */ + +.login-wrapper { + position: relative; + overflow: hidden; + margin: 20px 0; + .border-radius(4px); + border: 1px solid #ddd; + background-color: #fafafa; +} + +.login-block .block { + margin: 0; +} + +.login-block .block-body { + padding-bottom: 0; +} + +.login-block-login form, +.login-block .control-group:last-child { + margin-bottom: 0; +} + +.login-block-register { + position: absolute; + padding: 0; + width: 50%; +} + +.login-block-register .login-block-inner { + padding: 20px; +} + +.login-block-login { + position: relative; + padding: 20px; + margin-left: 50%; + background-color: #fff; + .border-radius(0 3px 3px 0); + border-left: 1px solid #ccc; + .box-shadow(0 0 10px rgba(0,0,0, .2)); + + .control-label { + width: 90px; + text-align: left; + } + + .controls { + margin-left: 100px; + } + + .control-group.pwd { + margin-bottom: 10px; + } + + .control-group.signin { + margin-bottom: 0; + } + + .forgot-password { + margin-top: 4px; + font-size: 13px; + } + + .captcha-box { + margin-top: 12px; + margin-bottom: 0; + } + + .externalauthentication { + > * { margin-top: 10px } + > *:first-child { margin-top: 30px } + } + + .login-credentials-bottom { + > * { margin-top: 10px } + > *:first-child { margin-top: 30px } + } +} + +.btn-extauth { + text-align: left; + padding-left: 10px; +} + +@media (max-width: 1200px) { + .login-block-login .signin .pull-right { + float: left; + margin-top: 8px; + } +} + + +/* Registration +================================================ */ + +.registration-page .buttons, +.registration-result-page .buttons { + margin: 20px 0; + text-align: center; + padding-top: 20px; + border-top: 1px solid #ddd; + clear: both; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/misc.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/misc.less new file mode 100644 index 0000000000..f9c3f3e35c --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/misc.less @@ -0,0 +1,54 @@ +// +// Miscellaneous Styles +// -------------------------------------------------- + + +/* Code +================================================ */ + +.csharpcode, +.csharpcode pre { font-size: small; color: #000; background-color: #fff; } +.csharpcode pre { margin: 0; } +.csharpcode .rem { color: green; } +.csharpcode .kwrd { color: #00f; } +.csharpcode .str { color: #006080; } +.csharpcode .op { color: #0000c0; } +.csharpcode .preproc { color: #c63; } +.csharpcode .asp { background-color: #ff0; } +.csharpcode .html { color: maroon; } +.csharpcode .attr { color: red; } +.csharpcode .alt { background-color: #f4f4f4; width:100%; margin:0; } +.csharpcode .lnum { color: #606060; } + + +// +// List Scroller Styles +// -------------------------------------------------- + +.product-list.scroll { + position: relative; +} + +.product-list .pl-slider { + overflow: hidden; + position: relative; +} + +.product-list.scroll .pl-row { + width: 30000px; +} + +.product-list.scroll .pl-controls { + text-align: center !important; +} + +.product-list.scroll .pl-forward, +.product-list.scroll .pl-backward { + display: inline-block; + margin-right: 5px; +} + +.product-list.scroll .pl-scroll-prev, +.product-list.scroll .pl-scroll-next{ + position: absolute; +} diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/nav.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/nav.less new file mode 100644 index 0000000000..f40e78b4ab --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/nav.less @@ -0,0 +1,191 @@ +// +// Navigation Styles +// -------------------------------------------------- + + +/* Breadcrumb +================================================ */ + +#breadcrumb { + padding: 0; + padding-bottom: 5px; + margin: 0; + border-bottom: 1px solid #ddd; + border-bottom-color: rgba(0,0,0, 0.12); + background: transparent; + .border-radius(0); + > li { + .small(); + color: @grayLight; + } + + li a { + text-decoration: none; + .transition(color .1s linear); + } +} + + +/* Navigation Blocks +================================================ */ + +.block-category-navigation.block-bordered .listbox { + padding-top: 0; + padding-bottom: 0; +} + +.block-category-navigation .level-1, +.block-account-navigation ul { + .small(); + margin: 0 0 0 0.4em; +} + +.block-category-navigation .sub-level-2 { + .smaller(); +} + +.block-category-navigation .sub-level-3 > li { + line-height: 16px +} + +.block-category-navigation .sub-level-3 ul { + font-size: 1em; +} + +.nav-category .level-1 > li, +.block-account-navigation .listbox li { + border-bottom: 1px solid mix(@var_ContainerBodyLinkColor, @var_ContainerBodyBackground, 20%); + &:last-child { border: none; } + a { + display: inline-block; + padding: 0.3em 0; + } + .active { + font-weight: bold; + color: inherit; + } +} + +.nav-category .expanded > a { + font-weight: bold; +} + + +.block-popular-tags li, +.block-popular-blogtags li { + display: inline !important; +} + +.block-recently-viewed-products li { + padding: 3px; + border-bottom: 1px solid #e5e5e5; + .product-name { + .smaller(); + text-align: left; + margin-left: 40px; + display: block; + } + .picture img { + max-width: 32px; + max-height: 50px; + } + figure.picture { + margin: 0; + text-align: center; + width: 40px; + } +} +.block-recently-viewed-products .omega { + border: none; +} +.block-recently-viewed-products .listbox { + padding: 2px; +} + + +/* NAV-HOME (top menu) +------------------------------ */ +.nh-textshadow() when (lightness(@var_HeaderLinkColor) > 80) { + text-shadow: 0 1px 0 #000; +} +.nh-textshadow() when (lightness(@var_HeaderLinkColor) < 80) { + text-shadow: 0 1px 0 #fff; +} + +#nav-home { + position: absolute; + right: 0; +} +#nav-home li { + margin: 0 8px; +} +#nav-home li:first-child { + margin-left: 0; +} +#nav-home li:last-child { + margin-right: 0; +} +#nav-home li a { + color: @var_HeaderLinkColor; + .nh-textshadow(); + + text-decoration: none; + .transition(all .1s linear); + .small(); + line-height: 24px; + + &:last-child { + padding-right: 0; + } + &:hover { + color: @var_HeaderHoverColor; + } +} + +#nav-home .special { + margin-left: 30px; +} + +#nav-home .special li:last-child { + margin-left: 2px; +} + +#nav-home .special a { + font-weight: bold; + i { + color: @var_HeaderIconColor; + } + &:hover i { + color: @var_HeaderHoverColor; + } +} + +#nav-home .finish-impersonation { + margin-right: 25px; + a { color: @green } +} + + +/* Sitemap +================================================ */ + +.sitemap-page .entity { + margin: 5px 0 30px; +} +.sitemap-page .topic-box, +.sitemap-page .manufacturer-box, +.sitemap-page .category-box, +.sitemap-page .product-box { + text-align: center; + vertical-align:bottom; + + .item { + text-align: left; + margin: 3px 10px; + width: 150px; + border-bottom: 1px dotted #ADACAC; + } +} + + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/pages.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/pages.less new file mode 100644 index 0000000000..4df8f7751d --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/pages.less @@ -0,0 +1,184 @@ +// +// Common Page Styles +// -------------------------------------------------- + +.page-title { + h1 { font-size: 32px; line-height: 36px } + h2 { font-size: 26px; line-height: 30px } + h3 { font-size: 20px; line-height: 24px } + h4, h5, h6 { font-size: 14px; line-height: 16px } +} +.category-page h1.page-title, +.product-details-page .page-title h1 { + font-size: 26px; + line-height: 30px; +} + +.not-found-page { + text-align: center; +} +.not-found-page .page-title h1 { + color: mix(@textColor, @bodyBackground, 50%); + font-family: @baseFontFamily; + font-weight: 400; + font-size: 220px; + line-height: 280px; +} +.not-found-page .page-body { + font-size: 20px; + line-height: 30px; +} +.not-found-page .buttons { + margin: 50px 0; +} +.not-found-page .buttons .btn { + min-width: 150px; + &:first-child { margin-right: 10px } +} + +.page.order-list-page .buttons .btn, +.page.address-list-page .btn { + margin: 5px 0; +} + +.page.address-list-page .address-item label { + display: inline; +} + +.block-title a.link-rss, +.page-title a.link-rss { + float: right; + font-family: @baseFontFamily; + font-size: @baseFontSize; + line-height: @baseLineHeight; + font-weight: bold; + text-decoration: none; + text-transform: uppercase; + color: @successText !important; + &:hover { color: darken(@successText, 10%) !important } + .icon-rss { color: #999 } +} + + +/* Compare products +================================================ */ +.compare-products-table td { + .small(); +} +.compare-products-table tr.product-name { + background-color: #e5e5e5; + font-weight: bold; +} +.compare-products-table tr.product-name a { + color: #888; + text-decoration: none; + &:hover { color: #555 } +} + + +/* TellAFriend & ContactUs +================================================ */ +.contact-page .enquiry, +.email-a-friend-page .personal-message { + width: 350px; + height: 150px; +} + + +/* Search +================================================ */ +.search-page .price-from, +.search-page .price-to { + width: 40px; +} + +/* News Styles +================================================ */ +.news-list-homepage { + margin-top: 0; +} +.news-items .news-item { + border-bottom: 1px solid #ddd; + padding-bottom: 12px; + margin-bottom: 12px; +} + +.news-items .news-title { + color: inherit; + text-decoration: none; + &:hover { color: #000 } +} +.news-items .news-date { + .small(); + font-family: @baseFontFamily; + font-weight: 400; +} +.news-items .read-more { + display: inline-block; + margin-top: 12px; +} +.news-items .view-all { + font-weight: bold; +} +.news-item-page .news-content { + margin-bottom: 12px +} + +/* Poll & Vote Styles +================================================ */ +.poll-item { + .small(); + + .poll-display-text { + font-weight: bold; + margin-bottom: 8px; + } + + input[type=radio] { + font-size: inherit; + line-height: inherit; + } + + .btn { + margin-top: 8px; + } +} + +.poll-results .answer { + position: relative; + .vote-result-line { + margin-bottom: 3px; + padding-right: 18px; + } + + .vote-result-percent { + float: right; + } + + .progress { + height: 15px; + margin-bottom: 10px; + } +} + +.todays-poll-box-block .poll-item { + float: left; + width: 28%; + margin: 0 2% 12px 2%; + vertical-align: top; +} + +/* Manufacturers on homepage +================================================ */ + +.block-manufacturer-navigation .manufacturer-pic { + float: left; + width: 50px; + height: 50px; + margin: 0 0 10px 10px; + + img { + max-width: 50px; + max-height: 50px; + } +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/paginator.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/paginator.less new file mode 100644 index 0000000000..868f34a6b9 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/paginator.less @@ -0,0 +1,33 @@ +// +// Paginator Styles +// -------------------------------------------------- + +.pagination .pager-nav { + padding-left: 6px; + padding-right: 6px; + + i { + /* to apply the correct size to the icon (small, large etc.) */ + font-size: inherit; + line-height: inherit; + max-height: @baseLineHeight; + } +} +.pagination .active { + font-weight: bold +} +.pagination .shrinked span { + border-top: none; + border-bottom: none; + border-left: none; + padding-left: 4px; + padding-right: 4px; + background: transparent; +} +.pagination .pagination-summary { + display: inline-block; + font-weight: bold; + padding: 4px 1em 4px 0; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/product.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/product.less new file mode 100644 index 0000000000..0a0fde971a --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/product.less @@ -0,0 +1,498 @@ +// +// Product Styles +// -------------------------------------------------- + + +/* Product details +================================================ */ + +.pd-gallery { + margin: 0 auto; +} + +.product-details-page .top-content { + margin-top: 15px; +} + +.product-details-page .product-data { + position: relative; +} + +.product-details-page .product-data .product-name { + margin-top: 0; +} + +.product-details-page .product-data .btn-edit-product { + position: absolute; + right: 0; + display: none; +} + +.product-details-page .product-data:hover .btn-edit-product { + display: inline-block; +} + +.product-details-page .quick-links a { + text-decoration: none; +} + +.product-details-page .quick-links a .fa { + color: inherit; +} + + + +.product-details-page .bold { + font-weight: bold; +} +.product-details-page .stock { + min-height: 50px; +} +.product-details-page .details { + border: 1px solid #ccc; + border-radius: 6px; + padding: 10px; +} +.product-details-page .tabbable { + margin-top: 20px; +} +.product-tags-box .product-tags-list .product-tags-wrapper { + float: left; + margin-right: 5px; +} + +.product-details-page .variant-line-bottom .quick-links { + text-align: right; + padding-bottom: 10px; +} +.product-details-page .attributes .color-squares { + margin: 0; + padding: 0; + list-style-type: none; + li { + float: left; + margin-right: 3px; + } + .color-container { + cursor: pointer; + padding: 4px; + background-color: transparent; + display: inline-block; + .color { + width: 32px; + height: 32px; + display: inline-block; + background-image: url('images/color-overlay.png'); + border: 1px solid #646464; + border-color: rgba(0,0,0, .3); + .opacity(85); + .transition(all .15s linear); + &:hover { + opacity: 1; + border-color: #000; + } + } + } + .selected-value .color-container { + background-color: #d2d2d2; + } + .selected-value .color-container .color { + background-image: none; + border-color: #000; + opacity: 1; + } + input[type=radio] { + display: none; + } +} + +.ie8 .product-details-page .attributes .color-squares input[type=radio] { + display: inline-block !important; + margin-top: 6px; +} +.ie8 .product-details-page .attributes .color-squares li { + margin-right: 15px; +} + +.product-details-page .qty-cnt { + margin-bottom: 5px; +} + +.product-details-page .product-share-button { + height: 16px; +} +.product-details-page .addthis_toolbox.addthis_default_style { + float: left; + width: 50%; + right: 0; +} + +.product-details-page .well.product-cart { + #gradient > .vertical(#f5f5f5, #eee); + border-bottom-color: #d5d5d5; + margin-bottom: 10px; +} + +.product-details-page .page-title { + padding: 0; + border: 0; +} + +.manufacturer-pics-container { + min-height: 20px; +} + +#product-detail-tabs { + margin-top: 50px; +} + +.product-details-page #details-cnt > div { + padding: 10px 0; +} +.product-details-page #details-cnt > .line { + border-top: 1px solid #d5d5d5; +} +.product-details-page #details-cnt .line.alpha { + border: none; + padding-top: 0 !important; +} +.product-details-page .product-data .qty-input { + margin: 0 0 0 5px; +} +.product-details-page .price-details { + padding: 8px !important; + margin: 0; + .base-price { + text-align: center; + font-size: .85em; + } +} +.product-details-page .price-details .product-price { + font-size: 24px; + color: @productDetailsPriceColor; + line-height: 26px; + min-height: 28px; +} + +.product-details-page .price-details .call-for-price { + margin: 5px 0 10px 0; + text-align: center; + color: @errorText; +} + +.product-details-page .price-details .line-through .product-price-without-discount, +.product-details-page .price-details .old-product-price { + text-decoration: line-through; + color: #aaa; +} +.product-details-page .price-details .without-discount-block { + text-align: right; + padding: 6px 0 3px 0; +} +.product-details-page #details-cnt .short-description { + color: #aaa; +} +.product-details-page #details-cnt .price-details + div { + border-top: none; +} +.product-details-page #details-cnt .add-to-cart-button { + box-sizing: border-box; + min-width: 60%; + position: relative; + padding-right: 30px; +} +.product-details-page .add-to-cart { + padding-top: 10px; +} +.product-details-page #details-cnt .add-to-cart .fa-cart-plus { + position: absolute; + right: 6px; + top: 50%; + font-size: 20px; + margin-top: -10px; +} +.product-details-page .attributes { + width: 100%; +} +.product-details-page .attributes td { + width: 50%; + max-width: 50%; +} +.product-details-page .attributes td.caption { + text-align: right; + padding-right: 10px; +} + +.product-details-page .product-data .page-title { + margin-bottom: 10px; +} + +.product-details-page .price-details .legal-info { + text-align: center; + .smaller(); +} +.product-variant-line { + border-top: 1px solid #ccc; + margin-top: 20px; + padding-top: 20px; +} +.product-variant-line .variant-picture { + position: absolute; +} +.product-variant-line .variant-name { + font-weight: bold; + color: inherit; +} +.product-variant-line .variant-description { + margin: 5px 0; + clear: both; +} + +.control-label.required { + color: inherit; + font-weight: bold; + &:after { content: ' *' } +} + +.tier-prices { + padding-top: 0 !important; + font-size: 13px; + .prices-table { + border-top: 1px solid #ddd; + } +} +.tier-prices .prices-header { + color: inherit; + background-color: #f8fafc; + padding: 4px; + margin: 0; +} +.tier-prices .field-header { + font-weight: bold; + padding-left: 0; + vertical-align: middle; +} +.tier-prices .item-quantity { + vertical-align: middle; +} +.popover-inner .prices-table { + width: 100%; +} +.popover-inner .prices-table .field-header { + font-weight: bold; + width: 50%; + text-align: left; +} +.popover-inner .prices-table .item-quantity, +.popover-inner .prices-table .item-price { + width: 50%; +} + + +.product-variant-line .tier-prices .prices-header { + background: none; + padding-left: 0; +} +.variant-line-bottom { + padding-top: 10px; +} + +#back-in-stock-subscription-modal { + text-align: left; + width: 600px; + .modal-body { + padding: 0; + max-height: 300px; + } +} +#iframe-backinstocksubsription { + margin-bottom: -5px; + .border-radius(5px 5px 0 0); +} + +.related-products-grid .item, +.also-purchased-products-grid .item { + text-align: center; + padding: 5px; +} + +.manufacturer-pics .manufacturer-item{ + text-align: center; + padding: 10px; +} +.product-review-box { + line-height: 20px; + vertical-align: middle; +} + + +/* Product Bundle Items +================================================ */ + +.product-bundle { + .bundle-item-border { + border-top: 1px solid #ddd; + } +} + +.product-bundle .bundle-item { + margin-top: 10px; + padding-top: 10px; + + .bundle-item-attributes { + margin-top: 3px; + } + + .bundle-item-image { + float: left; + margin-right: 16px; + } + + .bundle-item-body { + display: table-cell; + } + + .bundle-item-name { + font-weight: bold; + } + + .bundle-item-price { + padding: 5px 0 5px 0; + + .product-price-without-discount, + .product-price-with-discount { + font-size: 1.1em; + } + + .product-price-without-discount, + .older-price { + text-decoration: line-through; + color: #aaa; + } + + .base-price { + font-size: 0.85em; + } + } + + .bundle-item-description { + font-size: 12px; + line-height: 18px; + } + + .bundle-item-attribute-info { + font-size: 0.85em; + line-height: 1.45em; + } + + .bundle-item-footer { + clear: both; + padding-top: 13px; + } +} + +#AddToCart.bundled-product { + border-top: none !important; +} + +.attributes .image-has-value { + display: table-cell; + padding-top: 10px; +} + +.attribute-value-image { + margin-right: 5px; + vertical-align: middle; +} +.mb-bundle-pictures .fa-plus { + padding: 4px 10px 0 10px; +} + +.mb-bundle-pictures a, +.mb-bundle-pictures i, +.attributes .attribute-value-image-checkbox { + float: left; +} +.attributes .attribute-value-image-checkbox { + margin-right: 10px; + padding-top: 10px; +} + +.mb-bundle-pictures img { + max-width: 24px; + max-height: 24px; +} + +.bundle-item-overview-headline { + margin-bottom: 14px; + + .you-save { + padding-right: 180px; + } + + .bundle-item-price, + .bundle-item-price-single-units { + white-space: nowrap; + } + + .bundle-item-price { + color: @red; + font-weight: bold; + } + + .bundle-item-price-single-units { + text-decoration: line-through; + color: #aaa; + } + + .add-to-cart-button { + min-width: 120px !important; + } + + .add-to-cart { + padding-top: 0 !important; + float: right; + } +} + +.bundle-item-overview-headline .form-inline { + text-align:right; +} + +.bundle-item-overview .fa-plus { + padding: 0 5px; +} + +.table-order-products { + .product-body:nth-child(odd) td { + background-color: @tableBackgroundAccent; + } + + .product-body, + .product-bundle-row td { + border: none !important; + } + + .bundle-item-indent { + padding-left: 70px; + } + + .product-body-bundle .bundle-item { + .bundle-item-image { + float: left; + margin-right: 16px; + } + + .bundle-item-body { + display: table-cell; + } + + .bundle-item-attribute-info { + font-size: 0.85em; + line-height: 1.45em; + margin-top: 2px; + } + } +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/productfilter.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/productfilter.less new file mode 100644 index 0000000000..eafccc84d9 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/productfilter.less @@ -0,0 +1,161 @@ +// +// Product Filter Box Styles +// -------------------------------------------------- + +.block-product-filters .listbox { + background-color: @var_ProductFilterBackgroundColor !important; + .small(); +} + +.product-filter-block .listbox { + background-color: @var_ProductFilterBackgroundColor !important; + .small(); + padding: 0 !important; + position: relative; + min-height: 32px; + + .spinner { + position: absolute; + left: 50%; + top: 50%; + margin-left: -8px; + margin-top: -8px; + } +} +.product-filter-block .filter-product-form { + display: none; +} +.product-filter-block .filter-group { + position: relative; + clear: both; + border-bottom: 1px dotted darken(@grayLighter, 10%); + .transition(background-color .1s ease-in); + + &:last-child { + border-bottom: none; + } + &:hover { + background-color: lighten(greyscale(@var_ProductFilterBackgroundColor), 10%); + } + .chevron-icon { + display: inline-block; + text-decoration: none; + text-align: center; + font-size: 12px; + width: 10px; + float: left; + &:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + display: inline-block; + text-decoration: none; + content: '\f054'; /* fa-chevron-right */ + } + } + &.expanded .chevron-icon:before { + content: '\f078'; /* fa-chevron-down */ + } +} + +.product-filter-block .name { + cursor: pointer; + font-weight: bold; + padding: 6px 6px; + .transition(color .1s ease-in); + span { + padding-left: 2px + } + i { + min-width: 13px; + text-align: left; + } + &:hover { + color: @black + } +} +.product-filter-block .filter-group.static .name { + cursor: default; +} +.product-filter-block .data { + padding: 2px 10px 10px 10px; + display: none; +} +.product-filter-block .filter-group.expanded .data { + display: block; +} +.product-filter-block .data .note { + font-style: italic; +} +.product-filter-block .data .count { + .smaller(); + color: @grayLight; +} +.product-filter-block .data > div { + line-height: normal; +} +.product-filter-block .data .filter-item { + clear: both; + padding-left: 14px; +} +.product-filter-block .data .filter-item a { + &.inactive:hover { text-decoration: underline; } +} +.product-filter-block .data .filter-item a.active { + color: #bbb; + text-shadow: 0 1px 0 #fff; + &:hover { color: @red } +} +.product-filter-block .data .filter-item .applied-filter { + .smaller(); + font-weight: bold; +} +.product-filter-block .data a.inactive { + color: @linkColor; + &:hover { color: @linkColorHover } +} +.product-filter-block .data a.active { + float: right; +} +.product-filter-block .data .foot { + margin-top: 4px; + padding-left: 14px; + text-shadow: 0 1px 0 #fff; + a { + color: #888; + &:hover { color: #333 } + } +} +.product-filter-block .no-filter { + font-style: italic; + padding: 6px 0 0 10px; +} + +#product-filter-modal .modal-body { + max-height: 304px; +} +#product-filter-modal .multi-select-container { + display: inline-block; + margin: 0 0 8px 0; +} +#product-filter-modal .checkbox-container { + float: left; + margin-right: 14px; + padding: 0 0 1px 0; +} +#product-filter-modal .checkbox-container .highlight { + font-weight: bold; +} +#product-filter-modal .remove-checkmarks, +#product-filter-modal .checkbox-container input { + float: left; +} +#product-filter-modal .checkbox-container label { + float: left; + display: inline; + margin: 0 0 0 4px; + width: 220px; + max-width: 220px; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/profile.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/profile.less new file mode 100644 index 0000000000..19cd3e181b --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/profile.less @@ -0,0 +1,139 @@ +// +// Customer Account & Profile Styles +// -------------------------------------------------- +.profile-page .profile-info-box .profile-stat { + font-weight: bold; + padding: 2px; +} +.profile-page .profile-info-box .profile-stat-value { + font-weight: normal; +} +.profile-page .profile-info-box .user-details { + padding: 10px; + text-align: center; +} +.profile-page .profile-info-box .user-details .avatar { + margin-bottom: 5px; +} +.profile-page .profile-info-box .user-stats { + padding: 10px 20px; +} +.profile-page .profile-info-box .user-stats .title { + text-transform: uppercase; + margin-bottom: 10px; + font-size: 18px; +} +.account-signature-text { + height: 100px; + width: 500px; + border: solid 1px #E3E3E3; +} + +.address-list-page .address-item { + margin: 12px 0 30px; +} +.address-list-page .address-item .title { + border-bottom: 1px solid #ddd; + padding-bottom: 12px; +} + +.back-in-stock-subscription-list-page .buttons { + margin: 12px 0; +} + +/* Order Details +================================================ */ +.order-details .order-details-table { + width: 100%; + border: 0; + border-collapse: collapse; + border-spacing: 0; +} +.order-details .order-details-table .billinginfo, +.order-details .order-details-table .shippinginfo { + width: 50%; +} +.order-details .order-details-table tr td { + vertical-align: top; +} +.order-details .order-details-table tr td:first-child { + padding-right: 40px; +} +.order-details .actions { + margin: 10px 0 10px 0; +} +.order-details .checkout-attributes { + text-align: right; +} +.order-details .cart-total-right { + text-align: right; + color: @successText; +} +.order-details .cart-total tr:last-child { + background-color: #f5f5f5; +} +.table-order-items { + border-bottom: 1px solid #ddd; +} + +/* Shipments +================================================ */ +.shipment-details .page-body { + border: 1px solid #d7d7d7; + padding: 10px; +} +.shipment-details .overview { + padding-bottom: 10px; +} + +/* Return Requests +================================================ */ +.return-request-list-page .request-item { + margin-bottom: 20px; + + .title { + margin-bottom: 10px; + } +} +.reward-points-page .reward-points-overview { + padding: 10px 10px 5px 0; + width: 100%; +} +.return-request-page .why .comment { + width: 350px; + height: 150px; +} + + +/* Private Messages +================================================ */ +.private-message-send-page table.post-message { + width: 100%; + vertical-align: middle; + border-collapse: collapse; +} +.private-message-send-page table.post-message td { + padding: 4px; +} +.private-message-send-page table.post-message td.fieldname { + font-weight: bold; + width: 20%; + text-align: right; +} +.private-message-send-page table.post-message td.options { + text-align: right; +} +.private-message-view-page td.options { + padding: 20px 0; +} +.private-message-view-page td.fieldname { + font-weight: bold; + text-align: right; + padding-right: 10px; +} +.pm-unread{ + font-weight: bold; + background: #f7f7f7; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/rating.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/rating.less new file mode 100644 index 0000000000..03a5f25b00 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/rating.less @@ -0,0 +1,72 @@ +// +// Review & Rating Styles +// -------------------------------------------------- + +/* Ratings +================================================ */ +.rating { + display: inline-block; + vertical-align: top; + height: 16px; + width: 80px; + padding: 2px 0; + background-image: url('images/star-off.png'); + background-repeat: repeat-x; + background-position: 0 50%; +} +.rating > div { + height: 16px; + background-image: url('images/star-on.png'); +} +.rating.rating-small { + height: 11px; + width: 60px; + padding: 1px 0; + background-image: url('images/star-off-12.png'); +} +.rating.rating-small > div { + height: 11px; + background-image: url('images/star-on-12.png'); +} + +/* Reviews +================================================ */ +.product-reviews-page .write-review .inputs, +.product-reviews-page .write-review .captcha-box { + margin-bottom:12px; +} +.product-reviews-page .write-review .review-title { width:350px; } +.product-reviews-page .write-review .review-text{ width:350px; height:150px; } +.product-reviews-page .write-review .review-rating{ display:inline-block; } +.product-reviews-page .write-review .review-rating input{ vertical-align:bottom; } +.product-reviews-page .write-review .buttons{ text-align:left; } + +.product-review-item { + padding: 12px 0; + .hr(); +} +.product-review-item .review-title .rating { + margin-right: 8px; +} +.product-review-item .review-text, +.product-review-vote { + margin-top: 12px; +} +.product-review-vote .vote { + text-decoration: none; + margin-right: 2px; + padding: 0 2px; + &.vote-yes { color: @green } + &.vote-yes:hover { background: @green; color: #fff } + &.vote-no { color: @red } + &.vote-no:hover { background: @red; color: #fff } +} + +.product-review-vote .vote-count { + font-weight: bold; + .smaller(); +} +.product-review-vote .fa-thumbs-up, +.product-review-vote .fa-thumbs-down { + font-size: 16px; +} diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/shopbar.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/shopbar.less new file mode 100644 index 0000000000..474543e015 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/shopbar.less @@ -0,0 +1,457 @@ +// +// ShopBar Styles +// -------------------------------------------------- + +@shopBarBackgroundColor: @var_ShopBarBackgroundColor; +@shopBarBorderColor: @var_ShopBarBorderColor; +@shopBarTextColor: @var_ShopBarTextColor; +@shopBarIconColor: @var_ShopBarIconColor; + +.sb-textshadow() when (lightness(@shopBarBackgroundColor) > 80) { + text-shadow: 0 1px 0 #fff; +} + +#shopbar { + overflow: visible; + position: fixed; + top: 0; + left: 0; + right: 0; + .small(); + z-index: 1000; + + .transition(opacity 0.12s ease-in-out); + border-bottom: 1px solid @shopBarBorderColor; + .box-shadow(0 0px 8px @shopBarBorderColor); + + @bg: top, @shopBarBackgroundColor, @shopBarBackgroundColor 40%, darken(@shopBarBackgroundColor, 7%) 100%; + background-color: @shopBarBackgroundColor; + background-image: -webkit-linear-gradient(@bg); + background-image: linear-gradient(@bg); +} + +#shopbar.sticky { + .opacity(75); + &:hover { + .opacity(100); + } +} + +#shopbar .form-search { + margin: 0; + margin-right: 8px; + padding: 8px 0; +} + +#instantsearch { + width: 250px; +} + +@media (min-width: 1200px) { + #instantsearch { + width: 450px; + } +} + +#instantsearch-progress { + position: absolute; + right: 45px; + top: 50%; + margin-top: -10px; + z-index: 10; +} + +.typeahead { + @baseHeight: 36px; + &.dropdown-instantsearch.rich li { + border-bottom: 1px solid rgba(0,0,0, 0.12); + &:last-child { border-bottom: none } + } + .item-wrapper { + display: block; + height: @baseHeight; + padding: 5px 0; + } + .item-thumb { + float: left; + width: @baseHeight; + height: @baseHeight; + margin-right: 8px; + text-align: center; + } + .item-thumb > img { + max-height: 100% ; + } + .item-labels { + float: left; + height: @baseHeight; + } + .item-primary { + font-size: 13px; + line-height: @baseHeight / 2; + } + .item-secondary { + font-size: 11px; + line-height: (@baseHeight / 2) - 2px; + padding-top: 2px; + opacity: 0.7 + } +} + +#shopbar-account .shopbar-flyout-container .register { + text-align: center; +} +#shopbar-account .shopbar-flyout-container .fa { + font-size: 16px; +} + +.shopbar-flyout { + padding: 10px; + -webkit-transform: translateZ(0); +} + +.shopbar-button { + display: block; + text-decoration: none; + line-height: 14px; + + color: @shopBarTextColor; + .sb-textshadow(); + .transition(color 0.15s linear); + &:hover { + @textColor: contrast(@shopBarBackgroundColor); + color: @textColor; + } +} + +.shopbar-divider { + float: right; + height: 28px; + width: 1px; + background-color: rgba(0,0,0, .15); + margin: 8px; + padding: 0; + + border-right: 1px solid @shopBarBackgroundColor; + .no-rgba & { + background-color: darken(@shopBarBackgroundColor, 15%); + } +} + +.shopbar-button-label { + position: relative; + display: inline-block; +} + +.shopbar-tool { + position: relative; + padding: 8px 0; +} + +.shopbar-tool.open .shopbar-flyout { + visibility: visible; + .opacity(100); +} + +.shopbar-tool.open .dropdown-menu { + display: block; + margin: 0; + text-shadow: none; +} + +.shopbar-tool .shopbar-button-icon { + position: relative; + display: inline-block; + margin: 2px 4px 0 0; + + span.label { + position: absolute; + left: -3px; + top: -3px; + font-size: 11px; + padding-top: 1px; + padding-bottom: 1px; + } +} + +.shopbar-button-icon .fa { + display: inline-block; + font-size: 24px !important; + font-style: normal; + line-height: 28px; + vertical-align: middle; + + color: @shopBarIconColor; + .transition(color .1s linear); +} + +.shopbar-button:hover .shopbar-button-icon .fa { + color: darken(@shopBarIconColor, 22%); +} + +.shopbar-button .fa { + font-size: 12px; +} + +.shopbar-button .sm-arrow, +.shopbar-button .sm-arrow:after { + position: absolute; + display: inline-block; + width: 0; + height: 0; + border-style: solid; + border-color: transparent; + left: 50%; + bottom: 0; + border-top: 0; +} + +.shopbar-button .sm-arrow { + border-width: 8px; + z-index: 1002; + visibility: hidden; + margin-left: -8px; + border-bottom-color: #bbb; +} + +.shopbar-button .sm-arrow:after { + content: ""; + border-width: 7px; + bottom: -8px; + z-index: 1001; + margin-left: -7px; + border-bottom-color: #fff; +} + +.shopbar-tool.open .sm-arrow { + visibility: visible; +} + +/* taken from bootstrap */ +.shopbar-flyout { + position: absolute; + visibility: hidden; + .opacity(0); + top: 100%; + left: 0; + z-index: @zindexDropdown; + float: left; + min-width: 320px; + max-width: 420px; + padding: 5px 0; + margin: 0; + list-style: none; + -webkit-background-clip: padding-box; + background-clip: padding-box; + + height: 50px; + min-height: 50px; + background-image: none; + background-position: 50% 50%; + background-repeat: no-repeat; + + .transition(opacity 0.15s ease-in-out); + background-color: @dropdownBackground; + border: 1px solid @dropdownBorder; + border-color: rgba(0,0,0, 0.15); + *border-right-width: 2px; + *border-bottom-width: 2px; + .border-radius(@baseBorderRadius); + .box-shadow(0 2px 8px rgba(0,0,0,.2)); + + .shopbar-tool.loading & { + //background-image: url('images/loading.gif'); + } + + .spinner-container { + height: 100%; + } + + .shopbar-tool:not(.loading) & > .spinner-container { + display: none; + } + + .shopbar-tool.loading & > .shopbar-flyout-inner { + display: none; + } + + .shopbar-tool.loaded & { + height: auto; + } + + // Dividers (basically an hr) within the dropdown + .divider { + .nav-divider(@dropdownDividerTop, @dropdownDividerBottom); + } + + // Links within the dropdown menu + a { + font-weight: normal; + line-height: @baseLineHeight; + white-space: nowrap; + } +} + +.shopbar-tool .shopbar-flyout, +.shopbar-tool .shopbar-flyout-container { + margin-top: -1px !important; +} + +// Aligns the dropdown menu to right +.pull-right .shopbar-flyout, +.pull-right .shopbar-flyout-container { + right: 0; + left: auto; +} + +#shopbar-flyout-cart, +#shopbar-flyout-wishlist { + width: 340px; +} + +#shopbar-flyout-account { + width: 250px; +} + +.shopbar-flyout-inner { + position: relative; + min-height: 50px; +} + +.shopbar-flyout-inner a { + text-decoration: none; + .transition(color .1s linear); +} + +.shopbar-flyout-inner .no-items { + position: absolute; + left: 0; + right: 0; + top: 50%; + margin: -(@baseLineHeight / 2) 10px 0 10px; + text-align: center; +} + +.shopbar-flyout-inner .items { + padding: 0; + margin: 0; + .smaller(); +} + +.shopbar-flyout-inner .price { + text-align: right; +} + +.shopbar-flyout-inner .items .item { + position: relative; + padding: 8px 20px; + margin: 0; + border-bottom: 1px solid #e5e5e5; + + &.omega { + border-bottom: none + } + + &.more { + text-align: center; + .name { + color: #777; + font-size: 1.1em; + font-weight: bold; + &:hover { + color: @gray; + } + } + } + + .picture { + display: inline-block; + text-align: center; + margin: 0; + margin-right: 4px; + width: 32px; + + img { + max-width: 32px; + max-height: 50px + } + } + + .quantity { + width: 25px; + margin-left: 5px; + .times { + font-size: .9em; + } + } + + .data { + width: 160px; + overflow: hidden; + .text-overflow(); + } + + .data .attributes { + white-space: initial; + line-height: 12px; + } + + &.no-thumb .data { + width: 180px; + } + + .action { + padding-left: 4px; + i { font-size: 11px } + } + + .price { + width: 64px; + } + + .remove { + position: absolute; + right: 4px; + top: 8px; + .opacity(0); + color: #000; + .transition(opacity .1s linear); + } + + &:hover .remove { + .opacity(50); + } + + .remove:hover { + .opacity(100) + } +} + +#shopbar-flyout-wishlist .shopbar-flyout-inner .items .item { + .data { width: 136px } + &.no-thumb .data { width: 176px } +} + +#shopbar-flyout-compare .shopbar-flyout-inner .items .item { + .figure { margin-right: 8px } + .data { width: 170px } +} + +.shopbar-flyout-inner .summary { + padding: 12px 20px; + background: #f5f5f5; + border-top: 1px solid #c2c2c2; + border-bottom: 1px solid #d2d2d2; + font-weight: bold; + .box-shadow(inset 0px 5px 20px -9px rgba(0,0,0, .25)); +} + +.shopbar-flyout-inner .buttons { + padding: 20px 20px 12px 20px; +} + +#shopbar-flyout-account .shopbar-flyout-inner { + padding: 10px 20px; +} + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/site.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/site.less deleted file mode 100644 index 8e7695b9e8..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/site.less +++ /dev/null @@ -1,2568 +0,0 @@ - -.checkbox input[type="checkbox"] { - margin-top: 4px; -} - -// required for placeholder plugin (< IE10) -input.placeholder { - color: @grayLight !important; -} - -.control-group.buttons { - border-top: 1px solid #ddd; -} - -body { - background-attachment: fixed; - @bodyBgColor: @var_SiteBackground; - #gradient > .vertical(@bodyBgColor, lighten(@bodyBgColor, 4%)); -} - -body.popup { - background: @bodyBackground; -} - - -/* NAV-HOME (top menu) ------------------------------- */ -.nh-textshadow() when (lightness(@var_HeaderLinkColor) > 80) { - text-shadow: 0 1px 0 #000; -} -.nh-textshadow() when (lightness(@var_HeaderLinkColor) < 80) { - text-shadow: 0 1px 0 #fff; -} - - - -#nav-home { - position: absolute; - right: 0; -} -#nav-home li { - margin: 0 8px; -} -#nav-home ul > li:first-child { - margin-left: 0; -} -#nav-home ul > li:last-child { - margin-right: 0; -} -#nav-home li a { - color: @var_HeaderLinkColor; - .nh-textshadow(); - - text-decoration: none; - .transition(all .1s linear); - .small(); - line-height: 24px; - - &:last-child { - padding-right: 0; - } - &:hover { - color: @var_HeaderHoverColor; - } -} - -#nav-home ul.special { - margin-left: 30px; -} - -#nav-home ul.special li:last-child { - margin-left: 2px; -} - -#nav-home ul.special a { - font-weight: bold; - i { - //color: darken(#eaf0f4, 14%); - color: @var_HeaderIconColor; - } - &:hover i { - //color: @linkColorHover; - color: @var_HeaderHoverColor; - } -} - -#nav-home li.finish-impersonation { - margin-right: 25px; - a { color: @green } -} - - -/* SHOPBAR ------------------------------- */ -@shopBarBackgroundColor: @var_ShopBarBackgroundColor; -@shopBarBorderColor: @var_ShopBarBorderColor; -@shopBarTextColor: @var_ShopBarTextColor; -@shopBarIconColor: @var_ShopBarIconColor; - - -.sb-textshadow() when (lightness(@shopBarBackgroundColor) > 80) { - text-shadow: 0 1px 0 #fff; -} - -#shopbar { - .transition(opacity 0.12s ease-in-out); - border-bottom: 1px solid @shopBarBorderColor; - .box-shadow(0 0px 8px @shopBarBorderColor); - - @bg: top, @shopBarBackgroundColor, @shopBarBackgroundColor 40%, darken(@shopBarBackgroundColor, 7%) 100%; - background-color: @shopBarBackgroundColor; - background-image: -webkit-linear-gradient(@bg); - background-image: -moz-linear-gradient(@bg); - background-image: -ms-linear-gradient(@bg); - background-image: -o-linear-gradient(@bg); - background-image: linear-gradient(@bg); - - .no-cssgradients & { - // fix the ie9 "gradient dropdown transparent" bug - background-color: @shopBarBackgroundColor; - background-image: url('images/shopbar-bg.png'); - background-position: 0 100%; - background-repeat: repeat-x; - } - - .shopbar-button { - color: @shopBarTextColor; - .sb-textshadow(); - .transition(color 0.15s linear); - &:hover { - @textColor: contrast(@shopBarBackgroundColor); - color: @textColor; - } - } - - .shopbar-divider { - border-right: 1px solid @shopBarBackgroundColor; - .no-rgba & { - background-color: darken(@shopBarBackgroundColor, 15%); - } - } -} - -#quicksearch { - width: 250px; -} - -.shopbar-tool [class^="sm-icon-"] { - color: @shopBarIconColor; - .transition(color .1s linear); -} -.shopbar-button:hover [class^="sm-icon-"] { - color: darken(@shopBarIconColor, 22%); -} - -.shopbar-button [class^="icon-"] { - font-size: 12px; -} - -.shopbar-button .sm-arrow { - border-bottom-color: #bbb; -} - -.shopbar-button .sm-arrow:after { - border-bottom-color: #fff; -} - -/* taken from bootstrap */ -.shopbar-flyout { - .transition(opacity 0.15s ease-in-out); - background-color: @dropdownBackground; - border: 1px solid #bbb; - *border-right-width: 2px; - *border-bottom-width: 2px; - .border-radius(@borderRadiusLarge); - .box-shadow(0 5px 10px rgba(0,0,0,.2)); - - .shopbar-tool.loading & { - background-image: url('images/loading.gif'); - } -} - -.shopbar-flyout-inner a { - text-decoration: none; - .transition(color .1s linear); -} - -.shopbar-flyout-inner .items .item { - border-bottom: 1px solid #e5e5e5; - - &.omega { - border-bottom: none - } - - &.more { - text-align: center; - .name { - color: #777; - font-size: 1.1em; - font-weight: bold; - &:hover { - color: @gray; - } - } - } - - .remove { - color: #000; - .transition(opacity .1s linear); - } -} - -.shopbar-flyout-inner .summary { - background: #f5f5f5; - border-top: 1px solid #c2c2c2; - border-bottom: 1px solid #d2d2d2; - font-weight: bold; - .box-shadow(inset 0px 5px 20px -9px rgba(0,0,0, .25)); -} - -/* --------------------------- - SHOPBAR (END) */ - - -#content { - background-color: @bodyBackground; - .box-shadow(~'0 0 15px rgba(0,0,0, .15), 0 10px 6px -10px rgba(0,0,0, .4)'); - padding: 0 0; - z-index: 2; -} - -#breadcrumb { - padding: 0; - padding-bottom: 5px; - margin: 0; - border-bottom: 1px solid @var_ContainerBorder; - background: transparent; - .border-radius(0); - > li { - .small(); - color: @grayLight; - } - - li a { - text-decoration: none; - .transition(color .1s linear); - } -} - -#content-body { - margin-top: 10px; - padding-bottom: 10px; -} - -#footer { - padding: 10px 0; - color: @var_FooterFontColor; - z-index: 1; - - @bgColor: @var_FooterBackground; - background-color: @bgColor; - .border-radius(@var_FooterRadius); - a { - color: @var_FooterLinkColor; - text-decoration: none; - .transition(color 0.1s linear); - &:hover { color: lighten(@var_FooterLinkColor, 25%) } - } -} - -#footer .row-fluid { - -webkit-transform: translateZ(0); -} - -#footer .footer-seals .content, -#footer .footer-social .content, -#footer .theme-selector .content { - margin-top: 15px; -} -#footer .footer-seals a, -#footer .footer-social a { - padding-right: 8px; - color: @var_FooterLinkColor; - &:hover { color: lighten(@var_FooterLinkColor, 25%) } - &.pull-right { padding-right: 0; } - i { font-size: 60px; } -} - -#footer h4 { - color: @var_FooterHeading; - font-family: 'Segoe UI Light', 'Segoe UI', Helvetica, Arial, sans-serif; - font-weight: 100; - border-bottom: 1px solid @var_FooterHeading; - padding-bottom: 8px; -} -.footer-disclaimer { - background-color: transparent; - color: mix(@var_SiteBackground, contrast(@var_SiteBackground), 70%); - padding: 8px 0; - .small(); -} -.footer-disclaimer a { - color: @var_HeaderLinkColor; - text-decoration: none; -} -.footer-disclaimer a.sm-hint { - color: inherit; -} -.footer-disclaimer a:hover { - color: @var_HeaderHoverColor; -} - -.first-col { margin-left: 10px } -.last-col { margin-right: 10px } - - -form.form-search { - margin-right: 20px; -} - -/* one column */ -#content-center.alpha .page { - margin-left: @gridGutterWidth; -} -/* two columns */ -#content-center.omega .page { - margin-right: @gridGutterWidth; -} - -/* REGIONAL SELECTOR */ - -.regional-selectors { - position: absolute; - right: 0; - bottom: 0; -} - -.regional-selector li .regional-label { - border: 1px solid @var_ChooserBorderColor; - background: @var_ChooserBackgroundColor; - color: @var_ChooserFontColor; - padding: 3px; - font-size: 12px; - line-height: 12px; - height: 12px; - min-width: 12px; - margin: 0 2px; - text-align: center; - vertical-align: middle; - text-decoration: none; - font-family: Arial, Helvetica, sans-serif; -} - -.regional-selector li.selected .regional-label { - font-weight: bold; -} - -.regional-selector li.selected .regional-label, -.regional-selector li .regional-label:hover { - background: @var_ChooserActiveStateColor; -} - -/* CURRENCY SELECTOR */ - -#currency-selector { - float: left; - margin-left: 12px; -} - -/* LANGUAGE SELECTOR */ - -#language-selector { - float: left; -} - -#language-selector li .regional-label { - font-size: 11px; -} - -#language-selector li .flag { - float: left; - margin-right: 4px; - margin-bottom: 2px; - line-height: 13px; - border-top: 2px solid transparent; - .opacity(50); - .transition(opacity .1s linear); -} - -#language-selector li:hover .flag, -#language-selector li.selected .flag { - .opacity(100); -} - -#language-selector li.selected .flag { - border-top-color: @warningText; -} - -/* DATA LISTS */ - -.item-box { - background: @var_BoxBackground; - border: 1px solid #ddd; - .box-shadow(0 1px 3px rgba(0,0,0,.055)); - .transition(~'box-shadow .12s linear, border-color .12s linear'); - - &:hover { - border: 1px solid @var_ItemBoxBoxShadowColor; - .box-shadow(0px 0px 8px fade(@var_ItemBoxBoxShadowColor, 60%)); - } -} - -.item-box .name { - color: inherit; - - a { - font-weight: bold; - text-decoration: none; - color: inherit; //#555; - &:hover { - color: darken(@textColor, 12%); - } - - > span { - vertical-align: middle; - } - } -} - -.item-box figure.picture .colors { - .transition(opacity .15s linear); - -webkit-transform: translateZ(0); -} - -.item-box.details .delivery-time { - text-align: left !important; -} -.item-box.details .delivery-time .attr-label span strong { - color: #464646 !important; -} - -.item-box .description { - color: #999; - font-size: 1em; -} - -.delivery-time { - text-align: center; - padding-bottom: 5px; - .smaller(); - .delivery-time-label { - padding-right: 4px; - font-weight: bold; - } - .delivery-time-color { - height: 8px; - width: 32px; - display: inline-block; - border: 1px solid rgba(0,0,0, .25); - background-image: url('images/deliv-bg-aero.png'); - } -} -.order-summary-content .delivery-time { - text-align: left; -} - -.item-box .prices { - text-align: center; - .product-price { - margin-bottom: 0; - .price { - font-weight: bold; - font-size: @baseFontSize; - color: @productListsPriceColor; - } - } - .old-product-price { - margin: 0; - .prefix { - .smaller(); - } - .price { - text-decoration: line-through; - color: #aaa; - } - } - .transport-charge { - .smaller(); - } - .base-price { - .smaller(); - } -} - -.label-discount-sign { - font-weight: normal; - vertical-align: text-bottom; -} - - -.item-box.details { - margin-bottom: 20px; -} -.item-box.details .name a { - font-size: 15px; -} -.item-box.details .data { - padding: 0 8px 0 0; -} -.item-box.details .attribute-block { - width:60%; - .attributes { - .smaller(); - .attr-label { - width: 30%; - white-space: nowrap; - padding-right: 3px; - color: #aaa; - } - } - .manufacturer-pics img{ - max-height: 40px; - padding: 10px 0 0 0; - } -} -.item-box.details .price-block { - width: 40%; - text-align: right; - .prices { - text-align: right; - } - .product-price { - margin-bottom: 0; - .price { - font-size: 20px; - color: @productListsPriceColor; - } - } - .transport-charge, - .base-price, - .legal-info { - .smaller(); - } - .legal-info a { - color: inherit; //#555; - font-weight: bold; - } -} -.item-box.details .buttons { - padding: 8px 0 8px 8px; -} -.item-box .quicklinks { - padding: 5px 8px; - overflow: hidden; - .smaller(); - position: absolute; - z-index: 1; - left: 0; - top: 0; - right: 1px; - background: #fff; - background: rgba(255,255,255, .7); - .opacity(0); - .transition(opacity .2s linear); - -webkit-transform: translateZ(0); - a { - color: #666; - text-shadow: none; - &:hover { - color: #000; - text-decoration: none; - } - } -} -.item-box:hover .quicklinks { - .opacity(100); -} - -.item-box.details .quicklinks { - padding: 30px 0 0 0; - position: relative; - z-index: 1; - background: #fff; - border: 0; - .opacity(100); - a { - color: #646464; - text-shadow: none; - .smaller(); - padding-right: 3px; - .transition(color .2s linear); - &:hover { - color: #000; - } - } -} - -@media (max-width: 1200px) { - .item-box:not(.details) .quicklinks a > i { - // container is too small to display labels with icons - display: none; - } -} - -.item-box .reviews { - text-align: center; -} -.item-box.details .reviews { - position: absolute; - bottom: 7px; -} - - -/* MISC. CLASSES */ -.page-title { - h1 { font-size: 32px; line-height: 36px } - h2 { font-size: 26px; line-height: 30px } - h3 { font-size: 20px; line-height: 24px } - h4, h5, h6 { font-size: 14px; line-height: 16px } -} -.category-page h1.page-title, -.product-details-page .page-title h1 { - font-size: 26px; - line-height: 30px; -} - -.block-title a.link-rss, -.page-title a.link-rss { - float: right; - font-family: @baseFontFamily; - font-size: @baseFontSize; - line-height: @baseLineHeight; - font-weight: bold; - text-decoration: none; - text-transform: uppercase; - color: @successText !important; - &:hover { color: darken(@successText, 10%) !important } - .icon-rss { color: #999 } -} - - -/* SITEMAP */ -.sitemap-page .entity { - margin: 5px 0 30px; -} -.sitemap-page .topic-box, -.sitemap-page .manufacturer-box, -.sitemap-page .category-box, -.sitemap-page .product-box { - text-align: center; - vertical-align:bottom; - - .item { - text-align: left; - margin: 3px 10px; - width: 150px; - border-bottom: 1px dotted #ADACAC; - } -} - - -/* BLOCKS & CONTAINER */ - -.block .block-title, -.section-title, -fieldset > legend { - font-family: @pageTitleFontFamily; - font-weight: @pageTitleFontWeight; - font-size: 20px; - line-height: 28px; - border-bottom: 1px solid @var_SimpleBoxHeaderColor; -} - -@baseBlockRadius: @var_ContainerRadius; -@baseBlockHeaderGradient: @var_ContainerHeaderBackground; - -.block.block-bordered { - background: @var_ContainerBackground; - border: 1px solid @var_ContainerBorder; - .border-radius(@baseBlockRadius); - margin: 0 0 10px 0; - - #content-left & { - border-left: none; - .border-radius(0 @baseBlockRadius @baseBlockRadius 0); -} - - #content-right & { - border-right: none; - .border-radius(@baseBlockRadius 0 0 @baseBlockRadius); - } -} - -.block.block-bordered .block-title { - border-bottom: 1px solid @var_ContainerBorder; - margin: 0; - padding: 6px 10px; - font-family: inherit; - color: @var_ContainerHeaderFontColor; - font-weight: bold; - line-height: @var_ContainerHeaderHeight !important; - .smaller(); - text-transform: uppercase; - .border-radius(@baseBlockRadius @baseBlockRadius 0 0); - - #gradient > .vertical( lighten(@baseBlockHeaderGradient, 7%), @baseBlockHeaderGradient); - - #content-left & { - .border-radius(0 @baseBlockRadius 0 0) - } - #content-right & { - .border-radius(@baseBlockRadius 0 0 0) - } -} - -.block.block-bordered .block-body { - padding: 10px; - background: @var_ContainerBodyBackground; - color: @var_ContainerBodyFontColor; - - #content-left & { - .border-radius(0 0 (@baseBlockRadius - 1) 0) - } - #content-right & { - .border-radius(0 0 0 (@baseBlockRadius - 1) ) - } -} - -.block.block-bordered .listbox { padding: 10px } -.block.block-bordered a { - text-decoration: none; - color: @var_ContainerBodyLinkColor; - .transition(color .1s linear); - &:hover { color: #333 } -} -.block.block-bordered ul { margin: 0 } -.block.block-bordered ul ul { margin-left: 1.2em } -.block.block-bordered li { - list-style: none; - &.active > a, - &.selected > a { font-weight: bold; color: inherit } -} -.block.block-bordered li.separator { display: block; height:1px; line-height:1px; background:#f93; font-size:1px; margin: 5px 0; } -.block.block-bordered .view-all { font-weight: bold; margin-top: 0.4em } - - - -/* NAVIGATIONS */ - -.nav-category > ul > li, -.block-account-navigation .listbox > ul > li { - border-bottom: 1px solid #ddd; - &:last-child { border: none; } -} - - - -.block-popular-tags li, -.block-popular-blogtags li { - display: inline!important; -} - -.block-recently-viewed-products li { - padding: 3px; - border-bottom: 1px solid #e5e5e5; - .product-name { - .smaller(); - text-align: left; - margin-left: 40px; - display: block; - } - .picture img { - max-width: 32px; - max-height: 50px; - } - figure.picture { - margin: 0; - text-align: center; - width: 40px; - } -} -.block-recently-viewed-products li.omega { - border: none; -} -.block-recently-viewed-products .listbox { - padding: 2px; -} - -/* ORDER SUMMARY, SHOPPING CART, WISHLIST */ - -.wishlist-page .share-label .icon-share { - color: inherit; - font-size: 24px; -} - -table.cart { - border-bottom: 1px solid #ddd; - margin-top: 20px; -} - -table.cart .omega { - text-align: right; -} - -table.cart .unit-price { - text-align: right; -} - -table.cart .cart-item-row td.remove, -table.cart .cart-item-row td.addtocart { - text-align: center; - vertical-align: top; -} - -table.cart .cart-item-row td.productpicture img { - max-width: 70px; -} -table.cart .cart-item-row td.product { - width: 100%; -} - -table.cart td.product .short-desc { - font-size: 12px; -} -table.cart .cart-item-row .product-unit-price, -table.cart .cart-item-row .product-subtotal, -table.cart .cart-item-row td.product > a, -table.cart .product-bundle-row .bundle-headline { - font-weight: bold; -} -table.cart .cart-item-row .qty-input { - width: 32px; -} -.order-summary-content .cart-footer { - margin-top: 20px; -} - -.order-summary-content .cart-footer { - margin-top: 20px; -} - -.order-summary-content .cart-box { } -.order-summary-content .cart-box .title { - margin: 0 0 12px 0; - color: inherit; - font-weight: bold; -} -.order-summary-content .cart-box .hint { - margin-bottom: 12px; -} -.order-summary-content .cart-box .alert { - margin: 0 0 12px 0; -} -.order-summary-content .cart-box .current-code { - margin: 12px 0 0 0; -} -.order-summary-content .cart-box .input-append > .prompt { - width: 70%; -} -.estimate-shipping.cart-box .shipping-options { - .smaller(); -} -.estimate-shipping.cart-box .shipping-options .option-name { - font-weight: bold; -} - -.order-summary-content .cart-total td.cart-total-left { - padding-left: 4px; - font-weight: bold; - max-width: 200px; - overflow: hidden; -} -.cart-total-left-below { - text-align: right; - vertical-align: top; -} -.order-summary-content .cart-total td.cart-total-right { - text-align: right; - color: @successText; - font-weight: bold; - padding-right: 4px; - - & .info { - font-weight: normal; - .smaller(); - color: @grayLight; - } -} -.order-summary-content .cart-total .selected-shipping-method { - .smaller(); -} -.order-summary-content .cart-total tr.omega { - // order totals - background-color: #f5f5f5; -} - -.terms-of-service.alert { - padding-bottom: 4px !important; - a.read { - font-weight: bold; - } -} - -#iframe-terms-of-service { - width: 100%; -} - -.order-summary-content .selected-checkout-attributes, -.order-details .checkout-attributes { - .attr-caption { - font-weight: bold; - padding-right: 10px; - &:after { - content: ': ' - } - } - .attr-value { - text-align: left; - } -} - -/* CHECKOUT */ -.order-progress { - margin: 0 auto; - text-align: center; - border-bottom: 1px solid #ddd; - padding: 8px 0; - background-color: @var_CheckoutProgressBackgroundColor; -} -.order-progress ul li { - display: inline; -} -.order-progress .order-progress-step { - position: relative; - display: inline-block; - padding: 38px 12px 4px; - text-decoration: none; - color: #818181; - border: 1px solid transparent; - cursor: default; - .transition(opacity .1s linear); -} -.order-progress li.visited .order-progress-step { - cursor: pointer; - color: #333; - .opacity(75); - &:hover { - .opacity(100); - } -} -.order-progress li.active .order-progress-step { - .opacity(100); - background: #f2f2f2; - color: #333; - border-color: #ccc; - .border-radius(4px); - .box-shadow(~"inset 0 2px 8px rgba(0,0,0,.08)"); -} -.order-progress li.inactive .order-progress-step { - .opacity(50); -} -.order-progress .order-progress-step:before { - position: absolute; - top: 8px; - left: 50%; - margin-left: -16px; - font-family: FontAwesome; - font-weight: normal; - font-size: 32px; - line-height: 32px; - width: 32px; - height: 32px; - content: '\f07a'; - display: inline-block; - text-decoration: inherit; - .opacity(75); -} -.order-progress .order-progress-step.step-cart:before { } -.order-progress .order-progress-step.step-address:before { content: '\f015' /* icon-home */; } -.order-progress .order-progress-step.step-shipping:before { content: '\f0d1' /* icon-truck */; } -.order-progress .order-progress-step.step-payment:before { content: '\f09d' /* icon-creditcard */ } -.order-progress .order-progress-step.step-confirm:before { content: '\f087' /* icon-thumbs-up */; } -.order-progress .order-progress-step.step-complete:before { content: '\f058' /* icon-ok-sign */ } - -.order-summary-page #content-body { - margin-top: 0; -} - - -.checkout-data .select-address-title, -.checkout-data .enter-address-title { - padding:10px 10px 5px 0; - font-family: 'Segoe UI light','Segoe UI'; - font-weight: 100; - color: #aaa; -} -.checkout-data .enter-address .buttons { - border-top: 1px solid #ccc; - padding-top: 10px; -} - -.checkout-data .address-grid { - padding-bottom: 0; -} -.checkout-data .address-grid .item-box { - text-align:center; - vertical-align:text-top; -} -.checkout-data .address-grid .address-item { - padding: 12px; -} -.checkout-data .address-grid .address-item .select-button { - margin-bottom: 10px; -} -.checkout-data .address-grid .address-item .address-box { - text-align:left; -} -.shipping-options .option-name label, -.payment-methods .option-name label { - font-weight: bold; -} -.checkout-data .shipping-options, -.checkout-data .payment-methods { - border: 1px solid #d7d7d7; -} - - - - -.checkout-data .shipping-options .option-name, -.checkout-data .payment-methods .option-name { - margin: 0 100px 0 190px; -} -.checkout-data .shipping-options .no-left-margin .option-name, -.checkout-data .payment-methods .no-left-margin .option-name { - margin: 0 100px 0 0; -} -.checkout-data .shipping-options .branding, -.checkout-data .payment-methods .branding { - width: 180px; - /*text-align: center;*/ -} -.checkout-data .shipping-options .branding img, -.checkout-data .payment-methods .branding img { - max-width: 180px; - max-height: 60px; -} - - - -.checkout-data .payment-info { - padding: 10px 0; - border-top: 1px solid #d7d7d7; - border-bottom: 1px solid #d7d7d7; -} -.checkout-data .payment-info .select-button { - padding-top: 10px; - border-top: 1px solid #d7d7d7; -} -.checkout-data .order-completed .select-button { - padding-top: 15px; -} - -.checkout-data .shipping-option-item, -.checkout-data .payment-method-item { - padding: 10px 20px; - border-bottom: 1px solid #ccc; - - .payment-method-name { - .text-overflow(); - } - - .payment-method-desc { - display: inline-block; - clear: left; - } -} -.shipping-option-item.odd, -.payment-method-item.odd { - background: @alternateListItem; -} -.shipping-option-item.even, -.payment-method-item.even { - background: #ffffff; -} - -.checkout-data .shipping-option-item .option-description { - font-weight: normal; - display: block; -} -.checkout-data .shipping-option-item .shipping-fee, -.checkout-data .payment-method-item .payment-fee { - font-weight: bold; -} - -.checkout-data .shipping-options .select-button, -.checkout-data .payment-methods .select-button { - padding: 10px 20px; -} - -.order-details-table .item-box { - padding: 10px; - margin: 0 20px 20px 0; -} -.order-details-table .shippinginfo .item-box { - margin-right: 0; -} - -.checkout-confirm-page .terms-of-service { - margin: 10px 0; -} - -.checkout-data a.change-checkout-data { - font-weight: normal; - text-transform: none; - color: @linkColor; - &:hover { color: @linkColorHover } -} - -/* ONE PAGE CHECKOUT */ -.opc .buttons{margin-top:0;padding-top:2em;} -.opc .buttons.disabled button{display:none;} -.opc .buttons .please-wait{height:21px;line-height:21px;} -.opc .ul{list-style:disc outside; padding-left:18px;} -.opc ul, .opc ol, ul.opc, ol.opc{list-style:none outside none;} -.opc {position:relative;} -.opc li.section{} -.opc .step-title{ - border-width:0 1px; - border-style:solid; - border-color:#fff #d9dde3 #d9dde3; - background:#eee 0 100% repeat-x; - padding:4px 8px 6px; - text-align:right; -} -.opc .step-title .number{ - float:left; - background:#fff; - border:1px solid #fff; - padding:2px 6px; - margin:0 5px 0 0; - font:bold 11px/14px arial, helvetica, sans-serif; - color:#999; - border-radius: 4px; -} -.opc .step-title h2{ - float:left; - margin:2px 0 0 2px; - font:bold 13px/16px Arial, Helvetica, sans-serif; - color:#999; - text-transform:capitalize; -} -.opc .allow .step-title .number{ - background: #efefef; - border-color: #aaa; - color: #464646; -} -.opc .allow .step-title h2{ - color: #646464; -} -.opc .active .step-title{ - border: 1px solid #d7d7d7 !important; - padding: 10px 8px; - color: #f18200; - cursor: default; -} -.opc .allow .step-title { - background: lighten(@orange, 45%); - border: 1px solid #d7d7d7; - border-bottom: none; - padding: 10px 8px; - color: @infoText; - cursor: pointer; -} - -.opc .active .step-title .number{ - background: @orange; - border-color: #f19900; - color: #fff; -} -.opc .active .step-title h2{ - color: @orange; -} -.opc .step{ - border: 1px solid #d7d7d7; - border-top: 0; - background: lighten(@warningBackground, 4%); - padding: 15px 30px; - position: relative; -} -.opc #confirm-order-buttons-container { - height: 50px; -} -.opc #billing-new-address-form, -.opc #shipping-new-address-form { - margin-top: 30px; -} -#opc-payment_info .form-horizontal .control-label, -.payment-info-page .payment-info .form-horizontal .control-label { - min-width: 200px; - padding-right: 5px; -} - -/* ORDER DETAILS */ -.order-details{} -.order-details .page-title{text-align:left;} -.order-details .page-body{} -.order-details .order-overview{text-align:left;padding-bottom:10px;} -.order-details .order-overview .order-total-top{text-align:right;} -.order-details .order-details-box{text-align:left;padding:10px;border:1px solid #d7d7d7;height:auto;} -.order-details .order-overview .order-overview-table, .order-details .order-details-box .order-details-table{width:100%;border:0px;border-collapse:collapse;border-spacing:0;} -.order-details .order-details-box .order-details-table .billinginfo,.order-details .order-details-box .order-details-table .shippinginfo{width:50%;vertical-align:top;} -.order-details .order-details-box .repost{margin:10px 0px 10px 0px;} -.order-details .order-details-box .repost .hint{margin:0px;} -.order-details .products-box,.order-details .shipments-box,.order-details .ordernotes-box{} -.order-details .actions{margin:10px 0px 10px 0px;} - -.order-details .checkout-attributes { - text-align: right; -} -.order-details .cart-total-right { - text-align: right; - color: @successText; -} -.order-details .cart-total tr:last-child { - background-color: #f5f5f5; -} - -/* SHIPMENTS */ -.shipment-details{} -.shipment-details .page-title{text-align:left;} -.shipment-details .page-body{border:1px solid #d7d7d7;padding:10px;} -.shipment-details .overview{text-align:left;padding-bottom:10px;} -.shipment-details .tracking-url{color:#f93;text-decoration:none;} -.shipment-details .products-box,.shipment-details .shipment-status-events-box{text-align:left;height:auto;} - -/* FEATURED PRODUCTS */ -.featured-product-grid { - margin-bottom: 20px; - - .section-title { - margin-bottom: 6px; - } -} - -/* CATALOG PAGES */ - -.product-tags-all-page .product-tags-list li { - display: inline; -} -.product-tags-all-page .product-tags-list li a { - margin: 0 2px 0 0; - &:hover { text-decoration: underline } -} - -.category-grid, -.manufacturer-grid { - margin-bottom: 12px; - .item-box { - text-align: center; - vertical-align: text-top; - } -} - -.category-grid .category-item .category-title, -.manufacturer-grid .manufacturer-item .man-title { - .font-inherit(); - font-weight: bold; - display: block; - overflow: hidden; - margin: 0; - line-height: 18px; - padding-top: 8px; - & a { - color: inherit; - } -} -.category-grid .category-item .picture, -.manufacturer-grid .manufacturer-item .picture { - padding: 10px 0; -} -.category-description { - margin-bottom: 20px; -} -.product-list-options { - padding: 6px; - margin-bottom: 20px; - border: 1px solid lighten(@navbarBorder, 5%); - .border-radius(@baseBorderRadius); - @stopColor1: mix(@navbarBackground, @navbarBackgroundHighlight, 35%); - @stopColor2: darken(@stopColor1, 1.5%); - #gradient > .glossy(@navbarBackgroundHighlight, @stopColor1, @stopColor2, @navbarBackground); -} -.product-list-options label { margin: 5px 7px 0 0 } -.product-list-options .btn-group { - &.pull-left { margin-right: 18px } -} -.product-list-options .btn { max-width: 160px; .text-overflow(); } -.product-list-options .product-viewmode .btn { padding-left: 8px; padding-right: 8px } - - - - -/* sm */ -.block-product-filters .listbox { - background-color: @var_ProductFilterBackgroundColor !important; - .small(); -} -/* NEW PRODUCT FILTER */ -.product-filter-block { } -.product-filter-block .listbox { - background-color: @var_ProductFilterBackgroundColor !important; - .small(); - padding: 0 !important; - position: relative; - min-height: 32px; - - .ajax-loader-small { - position: absolute; - left: 50%; - top: 50%; - margin-left: -8px; - margin-top: -8px; - } -} -.product-filter-block .filter-product-form { - display: none; -} -.product-filter-block .filter-group { - position: relative; - clear: both; - border-bottom: 1px dotted darken(@grayLighter, 10%); - .transition(background-color .1s ease-in); - - &:last-child { - border-bottom: none; - } - &:hover { - background-color: lighten(greyscale(@var_ProductFilterBackgroundColor), 10%); - } - .chevron-icon { - display: inline-block; - text-decoration: none; - text-align: center; - font-size: 12px; - width: 10px; - float: left; - &:before { - font-family: FontAwesome; - font-weight: normal; - font-style: normal; - display: inline-block; - text-decoration: none; - content: '\f054'; /* icon-chevron-right */ - } - } - &.expanded .chevron-icon:before { - content: '\f078'; /* icon-chevron-down */ - } -} - -.product-filter-block .name { - cursor: pointer; - font-weight: bold; - padding: 6px 6px; - .transition(color .1s ease-in); - span { padding-left: 2px } - i { min-width: 13px; text-align: left; } - &:hover { color: @black } -} -.product-filter-block .filter-group.static .name { - cursor: default; -} -.product-filter-block .data { - padding: 2px 10px 10px 10px; - display: none; -} -.product-filter-block .filter-group.expanded .data { - display: block; -} -.product-filter-block .data .note { - font-style: italic; -} -.product-filter-block .data .count { - .smaller(); - color: @grayLight; -} -.product-filter-block .data > div { - line-height: normal; -} -.product-filter-block .data .filter-item { - clear: both; - padding-left: 14px; -} -.product-filter-block .data .filter-item a { - &.inactive:hover { text-decoration: underline; } -} -.product-filter-block .data .filter-item a.active { - color: #bbb; - text-shadow: 0 1px 0 #fff; - &:hover { color: @red } -} -.product-filter-block .data .filter-item .applied-filter { - .smaller(); - font-weight: bold; -} -.product-filter-block .data a.inactive { - color: @linkColor; - &:hover { color: @linkColorHover } -} -.product-filter-block .data a.active { - float: right; -} -.product-filter-block .data .foot { - margin-top: 4px; - padding-left: 14px; - text-shadow: 0 1px 0 #fff; - a { - color: #888; - &:hover { color: #333 } - } -} -.product-filter-block .no-filter { - font-style: italic; - padding: 6px 0 0 10px; -} -/*NEU*/ -#product-filter-modal .modal-body { - max-height: 304px; -} -#product-filter-modal .remove-checkmarks { - float: left; -} -#product-filter-modal .multi-select-container { - display: inline-block; - margin: 0 0 8px 0; -} -#product-filter-modal .checkbox-container { - float: left; - margin-right: 14px; - padding: 0 0 1px 0; -} -#product-filter-modal .checkbox-container .highlight { - font-weight: bold; -} -#product-filter-modal .checkbox-container input { - float: left; -} -#product-filter-modal .checkbox-container label { - float: left; - display: inline; - margin: 0 0 0 4px; - width: 220px; - max-width: 220px; -} - - - -/* COMPARE PRODUCTS */ -.compare-products-table td { - .small(); -} -.compare-products-table tr.product-name { - background-color: #e5e5e5; -} -.compare-products-table tr.product-name a { - color: #888; - text-decoration: none; - &:hover { color: #555 } -} - -.login-wrapper { - position: relative; - overflow: hidden; - margin: 20px 0; - .border-radius(6px); - border: 1px solid #ddd; - #gradient > .vertical(#f8f8f8, #f4f4f4); -} - -.login-block { - .block { - margin: 0; - } -} - -.login-block-register { - position: absolute; - padding: 0; - width: 50%; -} - -.login-block-register .login-block-inner { - padding: 20px; -} - -.login-block-login { - position: relative; - padding: 20px; - margin-left: 50%; - background-color: #fff; - .border-radius(0 5px 5px 0); - border-left: 1px solid #ccc; - .box-shadow(0 0 10px rgba(0,0,0, .2)); - - .control-label { - width: 90px; - text-align: left; - } - - .controls { - margin-left: 100px; - - .input-prepend { - .add-on i { color: #aaa; } - input { vertical-align: top; width: 180px } - } - - } -} - -.login-page .externalauthentication { - margin: 30px 0; -} - -/* REGISTRATION */ - -.registration-page .buttons, -.registration-result-page .buttons { - margin: 20px 0; - text-align: center; - padding-top: 20px; - border-top: 1px solid #ddd; - clear: both; -} - -/* NEWS */ -.news-list-homepage { - margin-top: 0; -} -.news-items .news-item { - border-bottom: 1px solid #ddd; - padding-bottom: 12px; - margin-bottom: 12px; -} - -.news-items .news-title { - color: inherit; - text-decoration: none; - &:hover { color: #000 } -} -.news-items .news-date { - .small(); - font-family: @baseFontFamily; - font-weight: 400; -} -.news-items .read-more { - display: inline-block; - margin-top: 12px; -} -.news-items .view-all { - font-weight: bold; -} - -/* BLOGS */ - -.blog-page .blogpost { - .hr(); - padding: 20px 0; -} - -.blog-page .blogpost .blogpost-info { - - .blogpost-comments { - position: relative; - display: block; - text-decoration: none; - font-weight: bold; - width: 50px; - height: 50px; - float: right; - } - - .blogpost-comments .blogpost-comments-icon { - position: absolute; - font-size: 50px; - line-height: 50px; - color: #f1f1f1; - } - - .blogpost-comments .blogpost-comments-count { - position: absolute; - top: 13px; - font-size: 13px; - line-height: 16px; - width: 38px; - text-align: center; - color: #c5c5c5; - } - - .blogpost-comments.vivid { - .blogpost-comments-icon { color: @textColor; } - .blogpost-comments-count { color: @bodyBackground; } - } - - .blogpost-date { - clear: both; - float: right; - text-align: right; - margin-bottom: 8px; - } - - .blogpost-tags { - clear: both; - } -} - -.blog-page .blogpost .blogpost-content { - .blogpost-title { - .title-typo(); - margin-top: 0; - & > a { - text-decoration: none; - } - } -} - -.news-item-page .news-date, -.blogpost-page .blogpost-date { - float: right; - margin-top: 12px; -} - -.new-comment .comment-title { - width: 70%; -} -.new-comment .comment-text { - width: 70%; - height: 150px; -} - -.comment-item { - margin-bottom: 20px; - position: relative; - .comment-avatar { - position: absolute; - top: 2px; - left: 0; - } - .comment-content { } - .comment-content .comment-info { - margin-bottom: 12px; - .username { - font-weight: bold; - color: inherit; - font-size: 16px; - } - .comment-time { - margin-left: 4px; - color: #bbb; - } - } -} - - -/* POLLS */ - -.poll-item { - .small(); - - .poll-display-text { - font-weight: bold; - margin-bottom: 8px; - } - - input[type=radio] { - font-size: inherit; - line-height: inherit; - } - - .btn { - margin-top: 8px; - } -} - -.poll-results .answer { - position: relative; - .vote-result-line { - margin-bottom: 3px; - padding-right: 18px; - } - - .vote-result-percent { - float: right; - } - - .progress { - height: 15px; - margin-bottom: 10px; - } -} - -.todays-poll-box-block .poll-item { - float: left; - width: 28%; - margin: 0 2% 12px 2%; - vertical-align: top; -} - -/* EMAIL A FRIEND */ -.email-a-friend-page .personal-message{width:350px;height:150px;} - -/* SEARCH */ -.search-page .price-from, -.search-page .price-to { - width: 40px; -} - -/* CONTACTS */ -.contact-page .enquiry { - width: 350px; - height: 150px; -} - -/* CUSTOMER ACCOUNT PAGES */ -.address-list-page .add-button { - margin: 12px 0; -} - -.address-list-page .address-item { - margin: 12px 0 30px; -} - -.address-list-page .address-item .title { - border-bottom: 1px solid #ddd; - padding-bottom: 12px; -} - -.back-in-stock-subscription-list-page .buttons{ - margin: 12px 0; -} - -.avatar-page{padding:10px;} -.avatar-page .buttons{margin:5px 0;} - -.forum-subscriptions-page{} -.forum-subscriptions-page .subscription-list{ - .rowcheckbox { - - } -} -.forum-subscriptions-page .description{} -.forum-subscriptions-page .no-data{} -.forum-subscriptions-page .buttons{margin-bottom:5px;margin-top:5px;text-align:left;} - -.username-available-status{color:green;padding-left:5px;} -.username-not-available-status{color:red;padding-left:5px;} -.account-signature-text{height:100px;width:500px;border:solid 1px #E3E3E3;vertical-align:top;} - -.return-request-list-page{} -.return-request-list-page .request-item{} -.return-request-list-page .request-item .title{font-size:13px;} -.return-request-list-page .request-item .info{} -.reward-points-page{} -.reward-points-page .reward-points-overview{padding:10px 10px 5px 0;width:100%;} -.reward-points-page .reward-points-history{} - -/* RETURN REQUEST */ -.return-request-page{} -.return-request-page .products-box{} -.return-request-page .why{} -.return-request-page .why .return-reasons{} -.return-request-page .why .return-actions{} -.return-request-page .why .comment{width:350px;height:150px;} -.return-request-page .buttons{} - -/* PRODUCT DETAILS PAGE */ -@smallGalleryWidth: 320px; -@smallGallery1200Width: 420px; - -.product-details-page .top-content { - position: relative; - margin-top: 20px; -} - -.product-details-page .product-image { - position: absolute; - width: @smallGalleryWidth; - top: 10px; // very important, columns are not equalized otherwise -} - -.product-details-page .product-data { - position: relative; - margin-left: @smallGalleryWidth + @gridGutterWidth; -} - -.product-details-page .bold { - font-weight: bold; -} -.product-details-page .stock { - min-height: 50px; -} -.product-details-page .details { - border: 1px solid #ccc; - border-radius: 6px; - padding: 10px; -} -.product-details-page .tabbable { - margin-top: 20px; -} -.product-tags-box .product-tags-list .product-tags-wrapper { - float: left; - margin-right: 5px; -} - -.product-details-page .quick-links a { - text-decoration: none; - - i { - width: 16px; - color: @grayLight; - } -} -.product-details-page .variant-line-bottom .quick-links { - text-align: right; - padding-bottom: 10px; -} -.product-details-page .attributes .color-squares { - margin: 0; - padding: 0; - list-style-type: none; - li { - float: left; - margin-right: 3px; - } - .color-container { - cursor: pointer; - padding: 4px; - background-color: transparent; - display: inline-block; - .color { - width: 32px; - height: 32px; - display: inline-block; - background-image: url('images/color-overlay.png'); - border: 1px solid #646464; - border-color: rgba(0,0,0, .3); - .opacity(85); - .transition(all .15s linear); - &:hover { - opacity: 1; - border-color: #000; - } - } - } - .selected-value .color-container { - background-color: #d2d2d2; - } - .selected-value .color-container .color { - background-image: none; - border-color: #000; - opacity: 1; - } - input[type=radio] { - display: none; - } -} - -.ie8 .product-details-page .attributes .color-squares input[type=radio] { - display: inline-block !important; - margin-top: 6px; -} -.ie8 .product-details-page .attributes .color-squares li { - margin-right: 15px; -} - -.product-details-page .qty-cnt { - margin-bottom: 5px; -} - -.product-details-page .product-share-button { - height: 16px; -} -.product-details-page .addthis_toolbox.addthis_default_style { - float: left; - width: 50%; - right: 0; -} - -.product-details-page .well.product-cart { - #gradient > .vertical(#f5f5f5, #eee); - border-bottom-color: #d5d5d5; - margin-bottom: 10px; -} - -.product-details-page .page-title { - padding: 0; - border: 0; -} - -#product-detail-tabs { - margin-top: 50px; -} - -.product-details-page #details-cnt > div { - border-top: 1px solid #d5d5d5; - padding: 10px 0; -} -.product-details-page #details-cnt .line.alpha { - border: none; - padding-top: 0 !important; -} -.product-details-page .product-data .qty-input { - margin: 0 10px 0 5px; -} -.product-details-page .price-details { - text-shadow: 0 -1px 0 #fff; - .base-price { - text-align: center; - font-size: .85em; - } -} -.product-details-page .price-details .product-price { - font-size: 24px; - color: @productDetailsPriceColor; - line-height: 26px; - min-height: 28px; -} - -.product-details-page .price-details .call-for-price { - margin: 5px 0 10px 0; - text-align: center; - color: @errorText; -} - -.product-details-page .price-details .old-product-price { - text-decoration: line-through; - color: #aaa; -} -.product-details-page .price-details .without-discount-block { - text-align: right; - padding: 6px 0 3px 0; -} -.product-details-page #details-cnt .short-description { - color: #aaa; -} -.product-details-page .price-details { - background: #f8fafc; - padding: 8px !important; - margin: 0; -} -.product-details-page #details-cnt .price-details + div { - border-top: none; -} -.product-details-page #details-cnt .add-to-cart-button { - min-width: 200px; - position: relative; - padding-left: 25px; - padding-right: 25px; -} -.product-details-page .add-to-cart { - padding-top: 10px; -} -.product-details-page #details-cnt .add-to-cart .icon-plus-sign { - position: absolute; - right: 6px; - top: 50%; - font-size: 20px; - margin-top: -10px; -} -.product-details-page table.attributes { - width: 100%; -} -.product-details-page table.attributes td { - width: 50%; - max-width: 50%; -} -.product-details-page table.attributes td.caption { - text-align: right; - padding-right: 10px; -} - -.product-details-page .product-data .page-title { - margin-bottom: 10px; -} -#content-center.omega .page.product-details-page { -} -.product-details-page .product-data, -.product-details-page .bottom-content { -} -.product-details-page .price-details .legal-info { - text-align: center; - .smaller(); -} -.product-variant-line { - border-top: 1px solid #ccc; - margin-top: 20px; - padding-top: 20px; -} -.product-variant-line .variant-picture { - position: absolute; -} -.product-variant-line .variant-name { - font-weight: bold; - color: inherit; -} -.product-variant-line .variant-description { - margin: 5px 0; - clear: both; -} -.product-details-page .no-associated-products, -.product-details-page .no-bundled-products { - font-weight: bold; -} -.control-label.required { - color: inherit; - font-weight: bold; - &:after { content: ' *' } -} - -.tier-prices { - padding-top: 0 !important; - font-size: 13px; - .prices-table { - border-top: 1px solid #ddd; - } -} -.tier-prices .prices-header { - color: inherit; - background-color: #f8fafc; - padding: 4px; - margin: 0; -} -.tier-prices .field-header { - font-weight: bold; - padding-left: 0; - vertical-align: middle; -} -.tier-prices .item-quantity { - vertical-align: middle; -} -.popover-inner .prices-table { - width: 100%; -} -.popover-inner .prices-table .field-header { - font-weight: bold; - width: 50%; - text-align: left; -} -.popover-inner .prices-table .item-quantity, -.popover-inner .prices-table .item-price { - width: 50%; -} - - -.product-variant-line .tier-prices .prices-header { - background: none; - padding-left: 0; -} -.variant-line-bottom { - padding-top: 10px; -} - -.date-part { - margin-right: 5px; -} -#back-in-stock-subscription-modal { - text-align: left; - width: 600px; - .modal-body { - padding: 0; - max-height: 300px; - } -} -#iframe-backinstocksubsription { - margin-bottom: -5px; - .border-radius(5px 5px 0 0); -} - -/* SMARTGALLERY IN PRODUCT-DETAIL */ -.pd-gallery { - margin: 10px auto 0 auto; -} - -.related-products-grid .item, -.also-purchased-products-grid .item { - text-align: center; - padding: 5px; -} - -.manufacturer-pics .manufacturer-item{ - text-align: center; - padding: 10px; -} -.product-review-box { - line-height: 20px; - vertical-align: middle; -} - -/* PRODUCT REVIEWS PAGE */ -.product-reviews-page{} -.product-reviews-page .page-title a{text-decoration:underline;} -.product-reviews-page .result{} -.product-reviews-page .write-review{margin-top:10px;} -.product-reviews-page .write-review .inputs{margin-bottom:12px;clear:both;} -.product-reviews-page .write-review .captcha-box{margin-bottom:12px;} -.product-reviews-page .write-review .review-title{width:350px;} -.product-reviews-page .write-review .review-text{width:350px;height:150px;} -.product-reviews-page .write-review .review-rating{display:inline-block;} -.product-reviews-page .write-review .review-rating input{vertical-align:bottom;} -.product-reviews-page .write-review .buttons{text-align:left;} - -.product-review-item { - padding: 12px 0; - .hr(); - -} - -.product-review-item .review-title .rating { - margin-right: 8px; -} - -.product-review-item .review-text { - margin-top: 12px; -} - -.product-review-vote { - margin-top: 12px; -} -.product-review-vote .vote { - text-decoration: none; - margin-right: 2px; - padding: 0 2px; - &.vote-yes { color: @green } - &.vote-yes:hover { background: @green; color: #fff } - &.vote-no { color: @red } - &.vote-no:hover { background: @red; color: #fff } -} - -.product-review-vote .vote-count { - font-weight: bold; - .smaller(); -} - -.product-review-vote .icon-thumbs-up, -.product-review-vote .icon-thumbs-down { - font-size: 16px; -} - -/* PRIVATE MESSAGES */ -.private-message-send-page table.post-message { - width:100%; - vertical-align:middle; - border-collapse:collapse; -} -.private-message-send-page table.post-message td { - padding:4px; -} -.private-message-send-page table.post-message td.fieldname { - font-weight: bold; - width: 20%; - text-align: right; -} -.private-message-send-page table.post-message td.options { - text-align:right; -} -.private-message-view-page td.options { - padding: 20px 0; -} -.private-message-view-page td.fieldname { - font-weight: bold; - text-align: right; - padding-right: 10px; -} -.pm-unread{ - font-weight:bold; - background: #f7f7f7; -} - -/* FORUM INPUTS */ - -.forum-topic-title-text,.pm-title-text{width:500px;border:1px solid #acacac;vertical-align:top;font-size:12px;} -.forum-post-text,.bb-editor-text{width:100%;height:300px;} -.private-message-subject-text{width:500px;border:1px solid #acacac;vertical-align:top;font-size:12px;} -.forum-search-text{width:500px;border:1px solid #acacac;font-size:14px;} -.forum-search-box-text{border:1px solid #acacac;font-size:12px;} -.bb-editor-text{border:#cec6b5 1px solid;} -.edit-topic-link-button{padding-right:5px;padding-left:18px;background:url(images/ico-edit.gif) no-repeat;} -.delete-topic-link-button{padding-right:5px;padding-left:18px;background:url(images/ico-delete.gif) no-repeat;} -.move-topic-link-button{padding-right:5px;padding-left:18px;background:url(images/ico-move-topic.gif) no-repeat;} - -.reply-topic-link-button, -.watch-topic-link-button, -.watch-topic-link-button:hover { - padding: 0 15px 0 0; - color: #646464; - font-weight: bold; -} - -/* FORUM MAIN */ -.forum-group tr.forum td.image, -.active-discussionstopics td.image, -.topics-group td.image{ - vertical-align: middle; - text-align: center; - i { - font-size: 32px; - } -} -.active-discussionstopics .topic-starter, -.topics-group .topic-starter { - margin: 3px 10px 0 0; - .smaller(); - a { - color: #646464; - } -} -.active-discussionstopics .pagination-mini, -.topics-group .pagination-mini { - margin: 0; -} - -.forum-group tr.forum td.topics, -.forum-group tr.forum td.posts, -.active-discussionstopics td.replies, -.active-discussionstopics td.views, -.topics-group td.replies, -.topics-group td.views { - text-align: center; -} -.forums-main .current-time { - padding-top: 5px; -} -.forums-main .topic-html-content { - margin-top: -30px; - .block-title { - font-size: 34px; - } -} - -.forums-main .group-header .forum-spacer, -.active-discussions-header .topic-name, -.topics-group .topic-name { - width: 100%; -} -.forums-main .group-header .last-post, -.active-discussions-header .last-post, -.topics-group .last-post { - min-width: 200px; -} -.forum-group td.last-post, -.topics-group td.last-post, -.active-discussionstopics td.last-post { - .smaller(); -} -.forum-group .forum-title a, -.active-discussionstopics .topic-title, -.topics-group .topic-title { - font-weight: bold; -} - -.forums-main .group-header th, -.active-discussions-header th, -.topics-group th { - white-space: nowrap; -} - - -/* FORUM PAGE */ - - -/* FORUM TOPIC EDIT */ -.post-edit .wrapper{ - padding: 5px; -} -.post-edit table.post-topic{ - width: 100%; - vertical-align: middle; - border-collapse: collapse; -} -.post-edit table.post-topic td{ - padding: 4px; -} -.post-edit table.post-topic td.fieldname{ - font-weight: bold; - width: 20%; - text-align: right; - padding-right: 10px; -} -.post-edit table.post-topic td.options{ - text-align: right; -} -.move-forum-topic table.move-topic .options { - padding: 20px 0 0 10px; -} -.move-forum-topic table.move-topic .select2-container{ - padding-left: 10px; -} - -.forum .page-title .link-rss{ - margin: 17px 0 0 10px; -} -.active-discussions { - .link-rss { - margin: 14px 0 0 10px; - } - .btn-link { - color: #646464; - font-weight: bold; - } -} - -/* FORUM TOPIC */ -.active-discussions-page .forum-search-box form, -.forum-topic .forum-search-box form { - margin-bottom: 10px; -} - -.page.forum .top h3 { - margin-top: -5px; -} -.page.forum .page-title { - margin: 20px 0; -} - -.forum-topic .posts .block-title .pull-right { - text-transform: none; - a { - padding: 0 12px 0 0; - } - .post-link { - padding: 0 !important; - } -} -.forum-topic .topic-options { - margin-bottom: 5px; - .pagination { - margin: 0; - } - .pull-left { - padding: 10px 0 0 5px; - min-width: 250px - } -} -.forum-topic .topic-options.bottom { - .pull-left { - padding-top: 0; - } -} - -.forum-topic .post-info { - min-width: 160px; - margin: 0 10px 10px 0; -} -.forum-topic .manage.btn-group { - margin: 0 0 20px 0; -} - -.subscribe-to-post { - padding-top: 10px !important; -} -.post-info .user-info .user-stats, -.post-content .posttime { - .smaller(); -} -.post-info .user-info { - text-align: center; - margin-top: 10px; -} -.post-info .user-info .button-pm { - margin-top: 10px; - min-width: 100px -} -.forum-post { - position: relative; -} -.post-content { - margin: 0 0 50px 170px; -} -.post-content .functions { - position: absolute; - right: 10px; - bottom: 10px; - .icon-quote-left { - font-size: 10px; - } -} -.post-content .signature { - position: absolute; - bottom: 10px; - right: 0; - left: 0; - text-align: center; - margin-top: 20px; -} - -/* FORUM SEARCH */ -.forum-search-box{ - font-size:.9em; - float:right; - text-align:right; - padding:15px 0 0 0; -} -#advanced-search-block { - .title { - padding-right: 10px; - text-align: right; - } - .data { - padding: 5px 0; - } -} - -/* PROFILE PAGE */ - -.profile-page{} -.profile-page .page-body { } -.profile-page .profile-info-box { } -.profile-page .profile-info-box, .profile-page .user-last-posts { } -.profile-page .profile-info-box .title {} -.profile-page .profile-info-box .profile-stat { font-weight: bold; padding: 2px; } -.profile-page .profile-info-box .profile-stat .profile-stat-value { font-weight: 400; } -.profile-page .profile-info-box .user-details { padding: 10px; height: 100%; text-align: center; } -.profile-page .profile-info-box .user-details .avatar { margin-bottom: 5px; } -.profile-page .profile-info-box .user-details .avatar .avatar-img { } -.profile-page .profile-info-box .user-stats { padding: 10px 20px; } -.profile-page .profile-info-box .user-stats .title { text-transform: uppercase; margin-bottom: 10px; font-size: 18px} -.profile-page .user-last-posts{} -.profile-page .user-last-posts .topic{ border: solid 1px #F3F3F3; margin-bottom: 10px;} -.profile-page .user-last-posts .topic-title{font-weight:700;line-height:20px;background:#e3f3f3;padding:3px;} -.profile-page .user-last-posts .topic-body{padding:10px;} -.profile-page .user-last-posts .topic-body a{color:#f93;text-decoration:underline;} -.profile-page .user-last-posts .topic-body .quote{padding:5px;border:dashed 1px #000;background-color:#fff;} -.profile-page .user-last-posts .topic-data{background:#f3f3f3;padding:3px;color:#555;font-size:.9em;} -.profile-page .user-last-posts .posts-table{width:100%;border:0px;border-collapse:collapse;border-spacing:0;empty-cells:show;} - -/* ACTIVE DISCUSSIONS */ - -/* BBCODES */ - - - - -@media (min-width: 1200px) { - - #quicksearch { - width: 450px; - } - - .product-details-page .product-image { - width: @smallGallery1200Width; - } - .product-details-page .product-data { - margin-left: @smallGallery1200Width + @gridGutterWidth; - } -} - - -/* - BUTTONS -*/ - -.btn { - @color: @btnColor; - color: @color; - .btn-text-shadow(contrast(@color)); -} - -.btn:hover, -.btn.active, -.btn:active, -.btn.disabled, -.btn[disabled] { - background-color: @btnBackgroundHighlight; - color: @btnColor; -} - -.btn-primary { - @color: @btnPrimaryColor; - color: @color; - .btn-text-shadow(contrast(@color)); - &:hover, - &:active { - background-color: @btnPrimaryBackgroundHighlight; - color: @color; - } -} -.btn-info { - @color: @btnInfoColor; - color: @color; - .btn-text-shadow(contrast(@color)); - &:hover, - &:active { - background-color: @btnInfoBackgroundHighlight; - color: @color; - } -} -.btn-success { - color: @btnSuccessColor; - .btn-text-shadow(contrast(@btnSuccessColor)); - &:hover, - &:active { - background-color: @btnSuccessBackgroundHighlight; - color: @btnSuccessColor; - } -} -.btn-warning { - @color: @btnWarningColor; - color: @color; - .btn-text-shadow(contrast(@color)); - &:hover, - &:active { - background-color: @btnWarningBackgroundHighlight; - color: @color; - } -} -.btn-danger { - @color: @btnDangerColor; - color: @color; - .btn-text-shadow(contrast(@color)); - &:hover, - &:active { - background-color: @btnDangerBackgroundHighlight; - color: @color; - } -} -.btn-inverse { - @color: @btnInverseColor; - color: @color; - .btn-text-shadow(contrast(@color)); - &:hover, - &:active { - background-color: @btnInverseBackgroundHighlight; - color: @color; - } -} - - -.checkout-confirm-page .order-summary-content form { - border: 1px solid #bbb; - background: #efefef; - border-bottom: none; - margin: 0 !important; - padding-bottom: 20px; - .border-radius(@baseBlockRadius @baseBlockRadius 0 0); -} -.checkout-confirm-page .checkout-data > .confirm-order { - border: 1px solid #bbb; - background: #efefef; - border-top: none; - padding: 20px; - margin-bottom: 30px; - .border-radius(0 0 @baseBlockRadius @baseBlockRadius); -} -.checkout-confirm-page .confirm-order-legal-hint { - border-left: 1px solid #bbb !important; - border-right: 1px solid #bbb !important; - margin: auto; - text-align: center; - .border-radius(0); -} - -#switch-to-mobile { - text-align: center; - margin: 0 0 10px 0; - display: none; -} - diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/skin.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/skin.less new file mode 100644 index 0000000000..b4fed4741d --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/skin.less @@ -0,0 +1,5 @@ +// +// Theme specific sugar +// -------------------------------------------------- + + diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/slider.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/slider.less index d2671bafe8..22a5a10f90 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/slider.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/slider.less @@ -17,7 +17,7 @@ Aside from these comments, you may modify and distribute this file as you please @sliderHeight: 300px; -@sliderUseRadialBg: @var_SliderUseRadialBg; +@sliderUseRadialBg: @var_SliderUseRadialBg; @sliderBackgroundColor: @var_SliderBackgroundColor; @sliderTitleColor: @var_SliderTitleColor; @@ -68,9 +68,12 @@ Aside from these comments, you may modify and distribute this file as you please display: block; overflow: hidden; .box-shadow(inset 0px 10px 8px -10px rgba(0,0,0, .5), inset 0px -10px 8px -10px rgba(0,0,0, .4)); - .transition(background-position 1.5s ease-out); - + + .transform(translate3d(0, 0, 0)); + -webkit-perspective: 1000; -moz-perspective: 1000; perspective: 1000; + -webkit-transform-style: preserve-3d; transform-style: preserve-3d; + // backface-visibility prevents graphical glitches when frames are animating -moz-backface-visibility: hidden; -ms-backface-visibility: hidden; @@ -119,7 +122,6 @@ Aside from these comments, you may modify and distribute this file as you please right: 15px; &:before { content: "\203a"; } } - } .slider:hover .arrows span { @@ -211,7 +213,6 @@ Aside from these comments, you may modify and distribute this file as you please padding: 0; list-style-type: none; background-color: transparent; - .radial-bg(); } @@ -263,9 +264,14 @@ Aside from these comments, you may modify and distribute this file as you please .sequence-canvas { .title, .info, .buttons { - left: 100%; - width: 40%; + box-sizing: border-box; + left: 75%; + width: 50%; + padding-right: 20px; .opacity(0); + .transform(scale3d(1, 1, 1)); + -webkit-perspective: 1000; -moz-perspective: 100; perspective: 1000; + -webkit-transform-style: preserve-3d; transform-style: preserve-3d; } .title { @@ -284,19 +290,22 @@ Aside from these comments, you may modify and distribute this file as you please } .picture { - left: 20%; - width: 45%; + box-sizing: border-box; + left: 25%; + width: 50%; + padding-right: 20px; height: 100%; top: 0; .opacity(0); - .transform(scale(2, 2)); + -webkit-perspective: 1000; -moz-perspective: 1000; perspective: 1000; + -webkit-transform-style: preserve-3d; transform-style: preserve-3d; } } .sequence-canvas .animate-in { .title, .info, .buttons { - left: 50%; top: auto; + .transform(translate3d(-50%, 0, 0)); .opacity(100); } @@ -314,16 +323,15 @@ Aside from these comments, you may modify and distribute this file as you please } .picture { - left: 0; .opacity(100); .transition-duration(1s); - .transform(none); + .transform(translate3d(-50%, 0, 0)); } } .sequence-canvas .animate-out { .title, .info, .buttons { - left: 25%; + .transform(translate3d(-75%, 0, 0)); .opacity(0); } @@ -341,10 +349,9 @@ Aside from these comments, you may modify and distribute this file as you please } .picture { - left: -10%; .opacity(0); .transition-duration(1s); - .transform(scale(.5, .5)); + .transform(translate3d(-75%, 0, 0)); } } diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less index 783c58e66b..a1c1b682af 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/theme.less @@ -1,124 +1,40 @@ -/*! - * Uses Bootstrap v2.2.1 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ -@bsPath: '../../../Content/bootstrap'; +/* Theme: ALPHA +------------------------------ */ +// Theme variables @import "~/.db/themevars.less"; // Fonts -//@import "fontastic.less"; -@import "~/Content/fonts/fontastic.less"; +@import "typo.less"; -// CSS Reset -@import "~/Content/bootstrap/reset.less"; - -// Core variables and mixins -@import "variables.less"; -@import "variables.custom.less"; -@import "~/Content/bootstrap/mixins.less"; -@import "~/Content/bootstrap/custom/mixins.less"; - -// Grid system and page structure -@import "~/Content/bootstrap/scaffolding.less"; -@import "~/Content/bootstrap/grid.less"; -@import "~/Content/bootstrap/responsive-1200px-min.less"; -//@import "~/Content/bootstrap/responsive-768px-979px.less"; -@import "~/Content/bootstrap/responsive-767px-max.less"; -@import "~/Content/bootstrap/layouts.less"; - -// Base CSS -@import "~/Content/bootstrap/type.less"; -@import "~/Content/bootstrap/code.less"; -@import "~/Content/bootstrap/forms.less"; -@import "~/Content/bootstrap/tables.less"; - -// Components: common -@import "~/Content/bootstrap/font/font-awesome.less"; // @import "sprites.less"; -@import "~/Content/bootstrap/dropdowns.less"; -@import "~/Content/bootstrap/wells.less"; -@import "~/Content/bootstrap/component-animations.less"; -@import "~/Content/bootstrap/close.less"; - -// Components: Buttons & Alerts -@import "~/Content/bootstrap/buttons.less"; -@import "~/Content/bootstrap/button-groups.less"; -@import "~/Content/bootstrap/alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less - -// Components: Nav -@import "~/Content/bootstrap/navs.less"; -@import "~/Content/bootstrap/navbar.less"; -@import "~/Content/bootstrap/breadcrumbs.less"; -@import "~/Content/bootstrap/pagination.less"; -@import "~/Content/bootstrap/pager.less"; - -// Components: Popovers -@import "~/Content/bootstrap/modals.less"; -@import "~/Content/bootstrap/tooltip.less"; -@import "~/Content/bootstrap/popovers.less"; - -// Components: Misc -@import "~/Content/bootstrap/thumbnails.less"; -@import "~/Content/bootstrap/media.less"; -@import "~/Content/bootstrap/labels-badges.less"; -@import "~/Content/bootstrap/progress-bars.less"; -@import "~/Content/bootstrap/carousel.less"; - -// (MC) extra 3rd party or own components -@import "~/Content/bootstrap/custom/throbber.less"; -@import "~/Content/bootstrap/custom/select2.less"; -@import "~/Content/bootstrap/custom/datepicker.less"; -@import "~/Content/bootstrap/custom/navbar.less"; -@import "~/Content/bootstrap/custom/image-gallery.less"; -@import "~/Content/bootstrap/custom/scrollbutton.less"; -@import "~/Content/bootstrap/custom/star-rating.less"; - -// (MC) extra tweaks and corrections -@import "~/Content/bootstrap/custom/custom.less"; - -// Utility classes -@import "~/Content/bootstrap/utilities.less"; // Has to be last to override when necessary - -// codehint: sm-add (start) -// this is redundant, but doable in order -// to avoid css class cluttering. - -.clearfix { - *zoom: 1; - &:before, - &:after { - display: table; - content: ""; - // Fixes Opera/contenteditable bug: - // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 - line-height: 0; - } - &:after { - clear: both; - } -} -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.input-block-level { - display: block; - width: 100%; - min-height: 28px; // Make inputs at least the height of their button counterpart - .box-sizing(border-box); // Makes inputs behave like true block-level elements -} -// codehint: sm-add (end) +// Bootstrap +@import "bootstrap.less"; // Main -@import "~/Content/theme.common.less"; -@import "site.less"; +@import "common.less"; +@import "layout.less"; +@import "shopbar.less"; +@import "header.less"; +@import "nav.less"; +@import "blocks.less"; +@import "datalist.less"; +@import "paginator.less"; +@import "rating.less"; +@import "pages.less"; +@import "cart.less"; +@import "login.less"; +@import "profile.less"; +@import "catalog.less"; +@import "product.less"; +@import "productfilter.less"; +@import "blog.less"; +@import "forum.less"; +@import "checkout.less"; +@import "footer.less"; +@import "misc.less"; + +@import "skin.less"; + +@import "custom.less"; @import "user.less"; diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/typo.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/typo.less new file mode 100644 index 0000000000..48444d59e4 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/typo.less @@ -0,0 +1,3 @@ +// +// Typography +// -------------------------------------------------- diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/user.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/user.less index c7a22a66cf..afea435651 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/user.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/user.less @@ -1,6 +1,6 @@ // -// Customize the theme here with css overrides -// or new selectors +// Customize the (child) theme here with css overrides +// or new selectors (for users) // -------------------------------------------------- diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.custom.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.custom.less index d2cd746412..a4de85d0c4 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.custom.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.custom.less @@ -9,21 +9,6 @@ @pageTitleFontWeight: @var_PageTitleFontWeight; @pageTitleColor: @var_PageTitleColor; -/* -@pageTitleFontFamily: 'Segoe UI Light', 'Segoe UI', Arial, Helvetica, sans-serif; -@pageTitleFontWeight: 400; -@pageTitleColor: @infoText; // @linkColor; // #009fff; -*/ - -//buttons -@btnColor: @var_BtnColor; -@btnPrimaryColor: @var_BtnPrimaryColor; -@btnInfoColor: @var_BtnInfoColor; -@btnSuccessColor: @var_BtnSuccessColor; -@btnWarningColor: @var_BtnWarningColor; -@btnDangerColor: @var_BtnDangerColor; -@btnInverseColor: @var_BtnInverseColor; - //productfilter @productFilter: @var_ProductFilterBackgroundColor; @checkoutProgress: @var_CheckoutProgressBackgroundColor; diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.less b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.less index 74aab1048a..c40876a5b5 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.less +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Content/variables.less @@ -32,30 +32,30 @@ // Scaffolding // ------------------------- -@bodyBackground: @var_BodyBackground; //@white; -@textColor: @var_TextColor; //#555; +@bodyBackground: @var_BodyBackground; +@textColor: @var_TextColor; // Links // ------------------------- -@linkColor: @var_LinkColor; //#08c; +@linkColor: @var_LinkColor; @linkColorHover: darken(@linkColor, 15%); // Typography // ------------------------- -@sansFontFamily: @var_SansFontFamily; //'Segoe UI', Tahoma, 'Helvetica Neue', Helvetica, Arial, 'sans-serif'; -@serifFontFamily: @var_SerifFontFamily; //Georgia, 'Times New Roman', Times, serif; -@monoFontFamily: @var_MonoFontFamily; //Menlo, Monaco, Consolas, 'Courier New', monospace; +@sansFontFamily: @var_SansFontFamily; +@serifFontFamily: @var_SerifFontFamily; +@monoFontFamily: @var_MonoFontFamily; -@baseFontSize: @var_BaseFontSize; //14px; +@baseFontSize: @var_BaseFontSize; @baseFontFamily: @sansFontFamily; -@baseLineHeight: @var_BaseLineHeight; //20px; +@baseLineHeight: @var_BaseLineHeight; @altFontFamily: @serifFontFamily; -@headingsFontFamily: @var_HeadingsFontFamily; //'Segoe UI Semibold', 'Segoe UI', Tahoma, 'Helvetica Neue', Helvetica, Arial, 'sans-serif'; -@headingsFontWeight: @var_HeadingsFontWeight; //600 /* Semibold doesn't get bolder anyway */ -@headingsColor: @var_HeadingsColor; //inherit; +@headingsFontFamily: @var_HeadingsFontFamily; +@headingsFontWeight: @var_HeadingsFontWeight; +@headingsColor: @var_HeadingsColor; @@ -63,74 +63,52 @@ // ------------------------- // Based on 14px font-size and 20px line-height -@fontSizeLarge: @baseFontSize * 1.25; // ~18px -@fontSizeSmall: @baseFontSize * 0.85; // ~12px -@fontSizeMini: @baseFontSize * 0.75; // ~11px +@fontSizeLarge: @baseFontSize * 1.25; +@fontSizeSmall: @baseFontSize * 0.87; +@fontSizeMini: @baseFontSize * 0.8; -@paddingLarge: 11px 19px; // 44px -@paddingSmall: 2px 10px; // 26px -@paddingMini: 1px 6px; // 24px +@paddingDefault: 6px 12px; +@paddingLarge: 10px 16px; +@paddingSmall: 4px 10px; +@paddingMini: 2px 6px; -@baseBorderRadius: 4px; -@borderRadiusLarge: 6px; -@borderRadiusSmall: 3px; +@baseBorderRadius: 3px; +@borderRadiusLarge: 5px; +@borderRadiusSmall: 2px; // Tables // ------------------------- -@tableBackground: @var_TableBackground; //transparent; // overall background-color -@tableBackgroundAccent: @var_TableBackgroundAccent; //#f9f9f9; // for striping -@tableBackgroundHover: @var_TableBackgroundHover; //#f5f5f5; // for hover -@tableBorder: @var_TableBorder; //#ddd; // table and cell border +@tableBackground: @var_TableBackground; +@tableBackgroundAccent: @var_TableBackgroundAccent; +@tableBackgroundHover: @var_TableBackgroundHover; +@tableBorder: @var_TableBorder; // Buttons // ------------------------- @btnBackground: @var_BtnBackground; -@btnBackgroundHighlight: @var_BtnBackgroundHighlight; +@btnBackgroundHighlight: darken(@btnBackground, 5%); @btnBorder: #ccc; //#c6c6c6; @btnPrimaryBackground: @var_BtnPrimaryBackground; -@btnPrimaryBackgroundHighlight: @var_BtnPrimaryBackgroundHighlight; +@btnPrimaryBackgroundHighlight: darken(@btnPrimaryBackground, 10%); @btnInfoBackground: @var_BtnInfoBackground; -@btnInfoBackgroundHighlight: @var_BtnInfoBackgroundHighlight; +@btnInfoBackgroundHighlight: darken(@btnInfoBackground, 10%); @btnSuccessBackground: @var_BtnSuccessBackground; -@btnSuccessBackgroundHighlight: @var_BtnSuccessBackgroundHighlight; +@btnSuccessBackgroundHighlight: darken(@btnSuccessBackground, 10%); @btnWarningBackground: @var_BtnWarningBackground; -@btnWarningBackgroundHighlight: @var_BtnWarningBackgroundHighlight; +@btnWarningBackgroundHighlight: darken(@btnWarningBackground, 10%); @btnDangerBackground: @var_BtnDangerBackground; -@btnDangerBackgroundHighlight: @var_BtnDangerBackgroundHighlight; +@btnDangerBackgroundHighlight: darken(@btnDangerBackground, 10%); @btnInverseBackground: @var_BtnInverseBackground; -@btnInverseBackgroundHighlight: @var_BtnInverseBackgroundHighlight; +@btnInverseBackgroundHighlight: darken(@btnInverseBackground, 10%); -/* -@btnBackground: @var_BtnBackground; //@white; -@btnBackgroundHighlight: darken(@btnBackground, 10%); // #ececec; -@btnBorder: #ccc; //#c6c6c6; - -@btnPrimaryBackground: @linkColor; // #33BCEF; -@btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 15%); // #019AD2; - -@btnInfoBackground: #5bc0de; -@btnInfoBackgroundHighlight: #2f96b4; - -@btnSuccessBackground: #62c462; -@btnSuccessBackgroundHighlight: #51a351; - -@btnWarningBackground: lighten(@orange, 15%); -@btnWarningBackgroundHighlight: @orange; - -@btnDangerBackground: #ee5f5b; -@btnDangerBackgroundHighlight: #bd362f; - -@btnInverseBackground: #444; -@btnInverseBackgroundHighlight: @grayDarker; -*/ // Forms // ------------------------- @@ -140,15 +118,6 @@ @inputDisabledBackground: @var_InputDisabledBackground; @formActionsBackground: @var_FormActionsBackground; @inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border - -/* -@inputBackground: @white; -@inputBorder: #ccc; -@inputBorderRadius: @baseBorderRadius; -@inputDisabledBackground: @grayLighter; -@formActionsBackground: #f5f5f5; -@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border -*/ // Dropdowns // ------------------------- @@ -164,20 +133,6 @@ @dropdownLinkBackgroundActive: @var_DropdownLinkBackgroundActive; @dropdownLinkBackgroundHover: @var_DropdownLinkBackgroundHover; -/* -@dropdownBackground: @white; -@dropdownBorder: rgba(0,0,0,.2); -@dropdownDividerTop: #e5e5e5; -@dropdownDividerBottom: @white; - -@dropdownLinkColor: @grayDark; - -@dropdownLinkColorHover: @white; -@dropdownLinkColorActive: @white; // @dropdownLinkColor; -@dropdownLinkBackgroundActive: #f9980f; //@linkColor; -@dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive; -*/ - // COMPONENT VARIABLES // -------------------------------------------------- @@ -219,10 +174,6 @@ // ------------------------- @wellBackground: @var_WellBackground; -/* -@wellBackground: #f5f5f5; -*/ - // Navbar // ------------------------- @navbarCollapseWidth: 979px; @@ -258,46 +209,7 @@ @navbarInverseSearchBackgroundFocus: @white; @navbarInverseSearchBorder: @navbarInverseBackground; @navbarInverseSearchPlaceholderColor: #ccc; - -@navbarInverseBrandColor: @navbarInverseLinkColor; - -/* -@navbarCollapseWidth: 979px; -@navbarCollapseDesktopWidth: @navbarCollapseWidth + 1; - -@navbarHeight: 32px; -@navbarBackgroundHighlight: #fff; -@navbarBackground: darken(@navbarBackgroundHighlight, 9%); -@navbarBorder: darken(@navbarBackground, 10%); - -@navbarText: #717171; // #777; -@navbarLinkColor: #717171; // #777; -@navbarLinkColorHover: #1a1a1a; //@grayDark; -@navbarLinkColorActive: @gray; -@navbarLinkBackgroundHover: transparent; -@navbarLinkBackgroundActive: transparent; //darken(@navbarBackground, 5%); - -@navbarBrandColor: @navbarLinkColor; - -// Inverted navbar -@navbarInverseBackground: #222; -@navbarInverseBackgroundHighlight: #666; -@navbarInverseBorder: #555; - -@navbarInverseText: #dadada; //@grayLight; -@navbarInverseLinkColor: #dadada; // @grayLight; -@navbarInverseLinkColorHover: @white; -@navbarInverseLinkColorActive: @navbarInverseLinkColorHover; -@navbarInverseLinkBackgroundHover: transparent; -@navbarInverseLinkBackgroundActive: transparent; // @navbarInverseBackground; - -@navbarInverseSearchBackground: lighten(@navbarInverseBackground, 25%); -@navbarInverseSearchBackgroundFocus: @white; -@navbarInverseSearchBorder: @navbarInverseBackground; -@navbarInverseSearchPlaceholderColor: #ccc; - @navbarInverseBrandColor: @navbarInverseLinkColor; -*/ // Pagination // ------------------------- @@ -305,12 +217,6 @@ @paginationBorder: @var_PaginationBorder; @paginationActiveBackground: @var_PaginationActiveBackground; -/* -@paginationBackground: #fff; -@paginationBorder: #ddd; -@paginationActiveBackground: #f5f5f5; -*/ - // Hero unit // ------------------------- @heroUnitBackground: @grayLighter; @@ -320,21 +226,21 @@ // Form states and alerts // ------------------------- -@warningText: #c09853; // #404040; -@warningBackground: #fcf8e3; // #EEDC94 -@warningBorder: darken(spin(@warningBackground, -10), 3%); // darken(spin(@warningBackground, -10), 6%); +@warningText: #c09853; +@warningBackground: #fcf8e3; +@warningBorder: darken(spin(@warningBackground, -10), 3%); -@errorText: #b94a48; // @white; -@errorBackground: #f2dede; // #C43C35; -@errorBorder: darken(spin(@errorBackground, -10), 3%); // darken(spin(@errorBackground, -10), 6%); +@errorText: #b94a48; +@errorBackground: #f2dede; +@errorBorder: darken(spin(@errorBackground, -10), 3%); -@successText: #468847; // @white; -@successBackground: #dff0d8; // #57a957; -@successBorder: darken(spin(@successBackground, -10), 3%); // darken(spin(@successBackground, -10), 6%); +@successText: #468847; +@successBackground: #dff0d8; +@successBorder: darken(spin(@successBackground, -10), 3%); -@infoText: #3a87ad; // @white; -@infoBackground: #d9edf7; // #339BB9; -@infoBorder: darken(spin(@infoBackground, -10), 3%); // darken(spin(@infoBackground, -10), 6%); +@infoText: #3a87ad; +@infoBackground: #d9edf7; +@infoBorder: darken(spin(@infoBackground, -10), 3%); // Tooltips and popovers @@ -376,23 +282,6 @@ @gridGutterWidth768: 20px; @gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1)); -/* -@gridColumns: 24; // 12 -@gridColumnWidth: 20px; // 60px -@gridGutterWidth: 20px; -@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); - -// 1200px min -@gridColumnWidth1200: 20px; // 70px; -@gridGutterWidth1200: 30px; -@gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1)); - -// 768px-979px -@gridColumnWidth768: 42px; -@gridGutterWidth768: 20px; -@gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1)); -*/ - // Fluid grid // ------------------------- @fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth); diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/ConfigureTheme.cshtml b/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/ConfigureTheme.cshtml index d0ef26b4be..7b282093c4 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/ConfigureTheme.cshtml +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/ConfigureTheme.cshtml @@ -1,26 +1,12 @@ @model IDictionary -@using System.Dynamic; -@using SmartStore.Core.Themes; -@using SmartStore.Web.Framework.Themes; -@using SmartStore.Utilities; +@using SmartStore.Web.Framework.Theming; @using SmartStore.Web.Framework.UI; @{ Layout = null; } -@functions { - protected override string ThemeName - { - get - { - return "Alpha"; - } - } -} - - @(Html.SmartStore().TabStrip().Name("theme-alpha-edit").HtmlAttributes(new { @class="theme-edit" }).Items(x => { var tabCommon = x.Add().Text(T("Common.General").Text).Content(@TabCommon()).Selected(true); @@ -52,27 +38,13 @@ @helper TabButtons() { - @ThemeVarEditor("BtnBackground", "Default") - @ThemeVarEditor("BtnBackgroundHighlight") - @ThemeVarEditor("BtnColor") - @ThemeVarEditor("BtnPrimaryBackground", "Primary") - @ThemeVarEditor("BtnPrimaryBackgroundHighlight") - @ThemeVarEditor("BtnPrimaryColor") - @ThemeVarEditor("BtnInfoBackground", "Info") - @ThemeVarEditor("BtnInfoBackgroundHighlight") - @ThemeVarEditor("BtnInfoColor") - @ThemeVarEditor("BtnSuccessBackground", "Success") - @ThemeVarEditor("BtnSuccessBackgroundHighlight") - @ThemeVarEditor("BtnSuccessColor") - @ThemeVarEditor("BtnWarningBackground", "Warning") - @ThemeVarEditor("BtnWarningBackgroundHighlight") - @ThemeVarEditor("BtnWarningColor") - @ThemeVarEditor("BtnDangerBackground", "Danger") - @ThemeVarEditor("BtnDangerBackgroundHighlight") - @ThemeVarEditor("BtnDangerColor") - @ThemeVarEditor("BtnInverseBackground", "Inverse") - @ThemeVarEditor("BtnInverseBackgroundHighlight") - @ThemeVarEditor("BtnInverseColor") + @ThemeVarEditor("BtnBackground") + @ThemeVarEditor("BtnPrimaryBackground") + @ThemeVarEditor("BtnInfoBackground") + @ThemeVarEditor("BtnSuccessBackground") + @ThemeVarEditor("BtnWarningBackground") + @ThemeVarEditor("BtnDangerBackground") + @ThemeVarEditor("BtnInverseBackground")
                      } @@ -110,7 +82,8 @@ @ThemeVarEditor("ShopBarIconColor") @ThemeVarEditor("ShopBarLabel") - @ThemeVarEditor("InverseNavbar", "Navbar") + @ThemeVarEditor("DisplayNavbar", "Navbar") + @ThemeVarEditor("InverseNavbar") @ThemeVarEditor("NavbarHeight") @ThemeVarEditor("NavbarBackgroundHighlight") @ThemeVarEditor("NavbarText") @@ -185,15 +158,15 @@ @ThemeVarEditor("TableBackgroundAccent") @ThemeVarEditor("TableBackgroundHover") @ThemeVarEditor("TableBorder") - @ThemeVarEditor("ContainerBackground", "Container") - @ThemeVarEditor("ContainerBorder") - @ThemeVarEditor("ContainerRadius") - @ThemeVarEditor("ContainerBodyLinkColor") - @ThemeVarEditor("ContainerHeaderBackground") - @ThemeVarEditor("ContainerHeaderFontColor") - @ThemeVarEditor("ContainerHeaderHeight") - @ThemeVarEditor("ContainerBodyBackground") + + @ThemeVarEditor("ContainerRadius", "Container") + @ThemeVarEditor("ContainerHeaderBackground") + @ThemeVarEditor("ContainerHeaderFontColor") + @ThemeVarEditor("ContainerHeaderHeight") + @ThemeVarEditor("ContainerBodyBackground") @ThemeVarEditor("ContainerBodyFontColor") + @ThemeVarEditor("ContainerBodyLinkColor") + @ThemeVarEditor("ContainerBorder") } @@ -238,16 +211,9 @@ if (groupName != null) { - @if(groupName != "") - { - -

                      @groupName

                      -
                      - - } - else { -
                      - } + +
                      @groupName
                      + } diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/Head.cshtml b/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/Head.cshtml index 0adcc29746..5ac574bc9a 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/Head.cshtml +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Shared/Head.cshtml @@ -1,10 +1,7 @@ -@using SmartStore.Core; -@using SmartStore.Core.Infrastructure; -@using SmartStore.Web.Framework.Themes; +@using SmartStore.Web.Framework.Theming; @{ - var supportRtl = EngineContext.Current.Resolve().WorkingLanguage.Rtl; - Html.AppendCssFileParts(false, "~/Themes/Alpha/Content/theme.less"); + Html.AppendCssFileParts(false, "~/Themes/Alpha/Content/theme.less"); } -@Html.Partial("ConditionalComments") \ No newline at end of file +@Html.Partial("ConditionalComments") \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Web.config b/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Web.config index d5bc031f95..bd9d09444f 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Web.config +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/Views/Web.config @@ -10,7 +10,7 @@ - + @@ -29,29 +29,6 @@ - - - - - - - - - - - - - diff --git a/src/Presentation/SmartStore.Web/Themes/Alpha/theme.config b/src/Presentation/SmartStore.Web/Themes/Alpha/theme.config index 6de4f874f7..6a5fcfc2eb 100644 --- a/src/Presentation/SmartStore.Web/Themes/Alpha/theme.config +++ b/src/Presentation/SmartStore.Web/Themes/Alpha/theme.config @@ -1,17 +1,11 @@  - + #eaf0f4 #fff - #555 + #444 #08c #fff @@ -28,7 +22,7 @@ inherit 'Segoe UI Light', 'Segoe UI', Arial, Helvetica, 'sans-serif' - 400 + 100 #3a87ad @@ -38,34 +32,13 @@ #ddd - #fff - #e6e6e6 - #333333 - #0088cc - #0044cc - #fff - #5bc0de - #2f96b4 - #fff - #62c462 - #51a351 - #fff - #fbb450 - #f89406 - #fff - #ee5f5b - #bd362f - #fff - #444 - #333 - #fff #fff @@ -75,8 +48,9 @@ label-info + true false - 32px + 38px #fff #717171 @@ -106,24 +80,23 @@ #555 - #7c7c7c - #7c7c7c + #888 + #888 #aaa 0 0 0 0 - #fff - #d6e0e6 3px - #888 #e1e9f0 #555 17px #fff #555 + #888 + #d6e0e6 - #f5f5f5 + #fafafa #f89406 #ddd #f4f8f9 @@ -145,20 +118,20 @@ #fff - #ddd + #ddd #f5f5f5 5/14/5 - 20px + 20px 20px 20px - 30px + 30px - + #fff #ccc - 4px + 2px #eee #f5f5f5 @@ -172,14 +145,14 @@ #fff #fff #f9980f - #f9980f + #f9980f - - -
                      - } - - - - @Html.Widget("checkout_billing_address_bottom") - - diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/CheckoutProgress.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/CheckoutProgress.cshtml deleted file mode 100644 index 6f34a52e70..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/CheckoutProgress.cshtml +++ /dev/null @@ -1,127 +0,0 @@ -@model CheckoutProgressModel - -@using SmartStore.Web.Models.Checkout; -@using System.Dynamic; - -@{ - var progresses = new List { - // Cart - new { - Step = CheckoutProgressStep.Cart, - ClassName = "step-cart", - Label = T("Checkout.Progress.Cart").Text, - Visited = Model.CheckoutProgressStep > CheckoutProgressStep.Cart, - Active = Model.CheckoutProgressStep == CheckoutProgressStep.Cart, - Href = Url.RouteUrl("ShoppingCart") - }, - // Address - new { - Step = CheckoutProgressStep.Address, - ClassName = "step-address", - Label = T("Checkout.Progress.Address").Text, - Visited = Model.CheckoutProgressStep > CheckoutProgressStep.Address, - Active = Model.CheckoutProgressStep == CheckoutProgressStep.Address, - Href = Url.RouteUrl("CheckoutBillingAddress") - }, - // Shipping - new { - Step = CheckoutProgressStep.Shipping, - ClassName = "step-shipping", - Label = T("Checkout.Progress.Shipping").Text, - Visited = Model.CheckoutProgressStep > CheckoutProgressStep.Shipping, - Active = Model.CheckoutProgressStep == CheckoutProgressStep.Shipping, - Href = Url.RouteUrl("CheckoutShippingMethod") - }, - // Payment - new { - Step = CheckoutProgressStep.Payment, - ClassName = "step-payment", - Label = T("Checkout.Progress.Payment").Text, - Visited = Model.CheckoutProgressStep > CheckoutProgressStep.Payment, - Active = Model.CheckoutProgressStep == CheckoutProgressStep.Payment, - Href = Url.RouteUrl("CheckoutPaymentMethod") - }, - // Confirm - new { - Step = CheckoutProgressStep.Confirm, - ClassName = "step-confirm", - Label = T("Checkout.Progress.Confirm").Text, - Visited = Model.CheckoutProgressStep > CheckoutProgressStep.Confirm, - Active = Model.CheckoutProgressStep == CheckoutProgressStep.Confirm, - Href = Url.RouteUrl("CheckoutConfirm") - }, - // Complete - new { - Step = CheckoutProgressStep.Complete, - ClassName = "step-complete", - Label = T("Checkout.Progress.Complete").Text, - Visited = Model.CheckoutProgressStep > CheckoutProgressStep.Complete, - Active = Model.CheckoutProgressStep == CheckoutProgressStep.Complete, - Href = "javascript:void(0)" - } - }; -} - - - - diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/Completed.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/Completed.cshtml deleted file mode 100644 index 2abaf4539a..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/Completed.cshtml +++ /dev/null @@ -1,47 +0,0 @@ -@model CheckoutCompletedModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Checkout; -@using SmartStore.Web.Models.Common; -@{ - Layout = "~/Views/Shared/_Checkout.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.Checkout").Text); -} -@section teaser { - -} -@Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Complete }) - -
                      - -
                      -

                      @T("Checkout.ThankYou")

                      -
                      - -
                      -
                      - @Html.Widget("checkout_completed_top") -
                      -

                      - @T("Checkout.YourOrderHasBeenSuccessfullyProcessed") -

                      -

                      - @T("Checkout.OrderNumber"): - @Model.OrderNumber -

                      -
                      -

                      - - - @T("Checkout.PlacedOrderDetails") - - - - @T("Checkout.Continue") - -

                      - @Html.Widget("checkout_completed_bottom") -
                      -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/Confirm.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/Confirm.cshtml deleted file mode 100644 index ecb3590d0b..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/Confirm.cshtml +++ /dev/null @@ -1,147 +0,0 @@ -@model CheckoutConfirmModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Checkout; -@using SmartStore.Web.Models.Common; -@{ - Layout = "~/Views/Shared/_Checkout.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.Checkout").Text); - - string termsLink = ""; - string disclaimerLink = ""; - string terms = string.Format(T("Checkout.TermsOfService.IAccept"), termsLink, "", disclaimerLink); -} -@section teaser { - -} -@Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Confirm }) - -
                      -
                      -

                      @T("Checkout.ConfirmYourOrder")

                      -
                      -
                      - @using (Html.BeginRouteForm("CheckoutConfirm", FormMethod.Post, new { id = "confirm-order-form" })) - { - @Html.Widget("checkout_confirm_top") -
                      - @Html.Raw(@T("Checkout.ConfirmHint")) -
                      - - if (Model.TermsOfServiceEnabled) - { -
                      - - - - - - -
                      - } - - - -
                      - @if (Model.Warnings.Count > 0) - { -
                      -
                        - @for (int i = 0; i < Model.Warnings.Count; i++) - { -
                      • @Model.Warnings[i]
                      • - } -
                      -
                      - } -
                      - } - - @Html.Widget("checkout_confirm_bottom") - -
                      - @Html.Action("OrderSummary", "ShoppingCart", new { prepareAndDisplayOrderReviewData = true }) -
                      - - @if (Model.ShowConfirmOrderLegalHint) - { - - } - -
                      - -
                      - @if (!String.IsNullOrEmpty(Model.MinOrderTotalWarning)) - { - @Model.MinOrderTotalWarning - } - else - { - - - -   - @T("Common.Back") - - - - } -
                      -
                      -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/PaymentInfo.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/PaymentInfo.cshtml deleted file mode 100644 index b201148985..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/PaymentInfo.cshtml +++ /dev/null @@ -1,57 +0,0 @@ -@model CheckoutPaymentInfoModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Checkout; -@using SmartStore.Web.Models.Common; -@{ - Layout = "~/Views/Shared/_Checkout.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.Checkout").Text); -} -@section teaser { - -} -@Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Payment }) - -
                      -
                      -

                      @T("Checkout.PaymentInfo")

                      -
                      - -
                      - @using (Html.BeginRouteForm("CheckoutPaymentInfo", FormMethod.Post)) - { - @Html.Widget("checkout_payment_info_top") -
                      -
                      - @Html.Action(Model.PaymentInfoActionName, Model.PaymentInfoControllerName, Model.PaymentInfoRouteValues) -
                      -
                      - -   - @T("Common.Back") - - - - - -
                      -
                      - -
                      - @Html.ValidationSummary(false) -
                      - @Html.Widget("checkout_payment_info_bottom") - } - - @*
                      - @T("Checkout.OrderSummary") -
                      -
                      - @Html.Action("OrderSummary", "ShoppingCart") -
                      *@ -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/PaymentMethod.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/PaymentMethod.cshtml deleted file mode 100644 index d4eb780581..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/PaymentMethod.cshtml +++ /dev/null @@ -1,135 +0,0 @@ -@model CheckoutPaymentMethodModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Checkout; -@using SmartStore.Web.Models.Common; -@{ - Layout = "~/Views/Shared/_Checkout.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.Checkout").Text); - - string marginClass = " no-left-margin"; - - for (int i = 0; i < Model.PaymentMethods.Count; i++) - { - var paymentMethod = Model.PaymentMethods[i]; - - if (!String.IsNullOrEmpty(paymentMethod.BrandUrl)) - { - marginClass = ""; - break; - } - } -} -@section teaser { - -} -@Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Payment }) - -
                      -
                      -

                      @T("Checkout.SelectPaymentMethod")

                      -
                      -
                      - @using (Html.BeginRouteForm("CheckoutPaymentMethod", FormMethod.Post)) - { - @Html.Widget("checkout_payment_method_top") - if (Model.DisplayRewardPoints && Model.PaymentMethods.Count > 0) - { -
                      - -
                      - } -
                      - @*var hasImages = @Model.PaymentMethods.Any(x => !string.IsNullOrEmpty(x.BrandUrl));*@ - @if (Model.PaymentMethods.Count > 0) - { -
                      - @for (int i = 0; i < Model.PaymentMethods.Count; i++) - { - var paymentMethod = Model.PaymentMethods[i]; - - string cssClass = "line"; - if (i == 0) - { - cssClass += " alpha"; - } - if (i == Model.PaymentMethods.Count - 1) - { - cssClass += " omega"; - } - if (i % 2 == 0) - { - cssClass += " even"; - } - else - { - cssClass += " odd"; - } - cssClass += marginClass; - -
                      -
                      - @if (!String.IsNullOrEmpty(paymentMethod.BrandUrl)) - { - - } -
                      -
                      - @if (!String.IsNullOrEmpty(paymentMethod.Fee)) - { - @paymentMethod.Fee - } -
                      -
                      - - @if (!String.IsNullOrWhiteSpace(paymentMethod.Description)) - { -
                      - @Html.Raw(paymentMethod.Description) -
                      - } -
                      -
                      - } -
                      - -   - @T("Common.Back") - - - - - - -
                      -
                      - } - else - { -
                      - @T("Checkout.NoPaymentMethods") -
                      - } -
                      - - @Html.Widget("checkout_payment_method_bottom") - } - - @*
                      - @T("Checkout.OrderSummary") -
                      -
                      - @Html.Action("OrderSummary", "ShoppingCart") -
                      *@ -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/ShippingAddress.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/ShippingAddress.cshtml deleted file mode 100644 index ddccc8fa32..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/ShippingAddress.cshtml +++ /dev/null @@ -1,164 +0,0 @@ -@model CheckoutShippingAddressModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Checkout; -@using SmartStore.Web.Models.Common; -@{ - Layout = "~/Views/Shared/_Checkout.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.Checkout").Text); -} -@section teaser { - -} -@Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Address }) - -
                      -
                      -

                      @T("Checkout.ShippingAddress")

                      -
                      -
                      - @Html.Widget("checkout_shipping_address_top") - @if (Model.ExistingAddresses.Count > 0) - { -
                      -
                      - @T("Checkout.SelectShippingAddress") -
                      -
                      -
                      - @(Html.DataList(Model.ExistingAddresses, 3, - @
                      -
                      -
                      - -
                      -
                      -
                      - @item.FirstName @item.LastName -
                      - - @if (item.PhoneEnabled) - { -
                      - @T("Address.Fields.PhoneNumber"): - @item.PhoneNumber -
                      - } - @if (item.FaxEnabled) - { -
                      - @T("Address.Fields.FaxNumber"): - @item.FaxNumber -
                      - } - @if (item.CompanyEnabled && !String.IsNullOrEmpty(item.Company)) - { -
                      - @item.Company -
                      - } - @if (item.StreetAddressEnabled) - { -
                      - @item.Address1 -
                      - } - @if (item.StreetAddress2Enabled && !String.IsNullOrEmpty(item.Address2)) - { -
                      - @item.Address2 -
                      - } - @if (item.CityEnabled || item.StateProvinceEnabled || item.ZipPostalCodeEnabled) - { -
                      - @if (item.CityEnabled) - { - @item.City - } - @if (item.CityEnabled && (item.StateProvinceEnabled || item.ZipPostalCodeEnabled)) - { - , - } - @if (item.StateProvinceEnabled) - { - @item.StateProvinceName - } - @if (item.ZipPostalCodeEnabled) - { - @item.ZipPostalCode - } -
                      - } - @if (item.CountryEnabled && !String.IsNullOrEmpty(item.CountryName)) - { -
                      - @item.CountryName -
                      - } -
                      -
                      -
                      - )) -
                      -
                      -
                      - } - @Html.Widget("checkout_shipping_address_middle") - -
                      -
                      - @if (Model.ExistingAddresses.Count > 0) - { - @T("Checkout.OrEnterNewAddress") - } - else - { - @T("Checkout.EnterShippingAddress") - } -
                      - -
                      -
                      - @using (Html.BeginRouteForm("CheckoutShippingAddress", FormMethod.Post)) - { -
                      - @{ - var dataDictAddress = new ViewDataDictionary(); - //Merge ModelState (required for validation) - dataDictAddress.ModelState.Merge(ViewData.ModelState); - dataDictAddress.TemplateInfo.HtmlFieldPrefix = "NewAddress"; - @Html.Partial("_CreateOrUpdateAddress", Model.NewAddress, dataDictAddress) - } -
                      -
                      - -   - @T("Common.Back") - - - - - - -
                      - } -
                      -
                      -
                      - @Html.Widget("checkout_shipping_address_bottom") -
                      - - @*
                      - @T("Checkout.OrderSummary") -
                      -
                      - @Html.Action("OrderSummary", "ShoppingCart") -
                      *@ -
                      diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/ShippingMethod.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/ShippingMethod.cshtml deleted file mode 100644 index eaa9c396fe..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Checkout/ShippingMethod.cshtml +++ /dev/null @@ -1,126 +0,0 @@ -@model CheckoutShippingMethodModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Checkout; -@using SmartStore.Web.Models.Common; -@{ - Layout = "~/Views/Shared/_Checkout.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.Checkout").Text); - - string marginClass = " no-left-margin"; - - for (int i = 0; i < Model.ShippingMethods.Count; i++) - { - var shippingMethod = Model.ShippingMethods[i]; - - if(!String.IsNullOrEmpty(shippingMethod.BrandUrl)) - { - marginClass = ""; - break; - } - } -} -@section teaser { - -} -@Html.Action("CheckoutProgress", "Checkout", new { step = CheckoutProgressStep.Shipping }) - -
                      -
                      -

                      @T("Checkout.SelectShippingMethod")

                      -
                      -
                      - @using (Html.BeginRouteForm("CheckoutShippingMethod", FormMethod.Post)) - { - @Html.Widget("checkout_shipping_method_top") -
                      - @if (Model.Warnings.Count == 0) - { -
                      - - @for (int i = 0; i < Model.ShippingMethods.Count; i++) - { - var shippingMethod = Model.ShippingMethods[i]; - - string cssClass = "line"; - if (i == 0) - { - cssClass += " alpha"; - } - if (i == Model.ShippingMethods.Count -1) - { - cssClass += " omega"; - } - if (i % 2 == 0) - { - cssClass += " odd"; - } - else - { - cssClass += " even"; - } - cssClass += marginClass; - -
                      -
                      - @if (!String.IsNullOrEmpty(shippingMethod.BrandUrl)) - { - - } -
                      -
                      - @shippingMethod.Fee -
                      -
                      - -
                      -
                      - } -
                      - -   - @T("Common.Back") - - - - -
                      -
                      - } - else - { -
                      -
                        - @for (int i = 0; i < Model.Warnings.Count; i++) - { -
                      • @Model.Warnings[i]
                      • - } -
                      -
                      - } -
                      - @Html.Widget("checkout_shipping_method_bottom") - } - - @*
                      - @T("Checkout.OrderSummary") -
                      -
                      - @Html.Action("OrderSummary", "ShoppingCart") -
                      *@ -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Common/Footer.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Common/Footer.cshtml deleted file mode 100644 index c36ddc3f00..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Common/Footer.cshtml +++ /dev/null @@ -1,187 +0,0 @@ -@model FooterModel -@using SmartStore.Web.Models.Common; - - - - - -
                      - @Html.Action("ChangeDeviceBlock", "Common") -
                      - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Common/ShopBar.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Common/ShopBar.cshtml deleted file mode 100644 index 19513a1d6b..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Common/ShopBar.cshtml +++ /dev/null @@ -1,112 +0,0 @@ -@model ShopBarModel -@using SmartStore.Web.Models.Common; - -
                      - -
                      - - @if (Model.ShoppingCartEnabled) - { - - - } - - @{ - string accountUrl = Model.IsAuthenticated ? Url.RouteUrl("CustomerInfo") : Url.RouteUrl("Login"); - } - - - - - - @if (Model.WishlistEnabled) - { -
                      - - - } - - - @if (Model.CompareProductsEnabled) - { -
                      - - - } - - - @Html.Action("SearchBox", "Catalog") - -
                      -
                      \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Home/Index.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Home/Index.cshtml deleted file mode 100644 index 8ba454b483..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Home/Index.cshtml +++ /dev/null @@ -1,29 +0,0 @@ -@using SmartStore.Web.Framework.Themes; - -@{ - Layout = "~/Themes/Beta-sym/Views/Shared/_ColumnsThree.cshtml"; -} - -
                      -
                      - @Html.Widget("home_page_top") - @Html.Action("TopicBlock", "Topic", new { systemName = "HomePageText" }) - - @Html.Action("HomepageCategories", "Catalog") - - @Html.Action("HomepageProducts", "Catalog") - - @Html.Action("HomepageBestSellers", "Catalog") - - @Html.Action("HomePageNews", "News") - - @Html.Action("HomePagePolls", "Poll") - @Html.Widget("home_page_bottom") -
                      -
                      - -@section teaser { -
                      - @Html.Action("ContentSlider", "Home") -
                      -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/ConfigureTheme.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/ConfigureTheme.cshtml deleted file mode 100644 index 5f2b6912c7..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/ConfigureTheme.cshtml +++ /dev/null @@ -1,261 +0,0 @@ -@model IDictionary - -@using System.Dynamic; -@using SmartStore.Core.Themes; -@using SmartStore.Web.Framework.Themes; -@using SmartStore.Utilities; -@using SmartStore.Web.Framework.UI; - -@{ - Layout = null; - var infos = this.ThemeManifest.Variables; - var values = this.ThemeVariables as IDictionary; -} - -@functions { - protected override string ThemeName - { - get - { - return "Beta"; - } - } -} - - -@(Html.SmartStore().TabStrip().Name("theme-beta-edit").HtmlAttributes(new { @class="theme-edit" }).Items(x => -{ - var tabCommon = x.Add().Text(T("Common.General").Text).Content(@TabCommon()).Selected(true); - var tabFonts = x.Add().Text(T("Admin.Themes.Fonts").Text).Content(@TabFonts()); - var tabGrid = x.Add().Text(T("Admin.Themes.Grid").Text).Content(@TabGrid()); - var tabButtons = x.Add().Text(T("Admin.Themes.Buttons").Text).Content(@TabButtons()); - //var tabHeader = x.Add().Text(T("Admin.Themes.Header").Text).Content(@TabHeader()); - var tabHeader = x.Add().Text("Header").Content(@TabHeader()); - var tabShopbar = x.Add().Text(T("Admin.Themes.Shopbar").Text).Content(@TabShopBar()); - var tabContentSlider = x.Add().Text(T("Admin.Themes.ContentSlider").Text).Content(@TabContentSlider()); - var tabTableAndContainer = x.Add().Text(T("Admin.Themes.Tables").Text).Content(@TabTableAndContainer()); - var tabMisc = x.Add().Text(T("Admin.Themes.Misc").Text).Content(@TabMisc()); - var tabFooter = x.Add().Text(T("Admin.Themes.Footer").Text).Content(@TabFooter()); - -} -)) - -@helper TabGrid() -{ - - @ThemeVarEditor("GridSettings") - @ThemeVarEditor("GridColumnWidth") - @ThemeVarEditor("GridGutterWidth") - @ThemeVarEditor("GridColumnWidth1200") - @ThemeVarEditor("GridGutterWidth1200") -
                      -} - -@helper TabButtons() -{ - - @ThemeVarEditor("BtnBackground", "Default") - @ThemeVarEditor("BtnBackgroundHighlight") - @ThemeVarEditor("BtnColor") - @ThemeVarEditor("BtnPrimaryBackground", "Primary") - @ThemeVarEditor("BtnPrimaryBackgroundHighlight") - @ThemeVarEditor("BtnPrimaryColor") - @ThemeVarEditor("BtnInfoBackground", "Info") - @ThemeVarEditor("BtnInfoBackgroundHighlight") - @ThemeVarEditor("BtnInfoColor") - @ThemeVarEditor("BtnSuccessBackground", "Success") - @ThemeVarEditor("BtnSuccessBackgroundHighlight") - @ThemeVarEditor("BtnSuccessColor") - @ThemeVarEditor("BtnWarningBackground", "Warning") - @ThemeVarEditor("BtnWarningBackgroundHighlight") - @ThemeVarEditor("BtnWarningColor") - @ThemeVarEditor("BtnDangerBackground", "Danger") - @ThemeVarEditor("BtnDangerBackgroundHighlight") - @ThemeVarEditor("BtnDangerColor") - @ThemeVarEditor("BtnInverseBackground", "Inverse") - @ThemeVarEditor("BtnInverseBackgroundHighlight") - @ThemeVarEditor("BtnInverseColor") -
                      -} - -@helper TabHeader() -{ - - @ThemeVarEditor("HeaderLinkColor") - @ThemeVarEditor("HeaderHoverColor") - @ThemeVarEditor("HeaderIconColor") - - @ThemeVarEditor("ChooserBorderColor", "Chooser") - @ThemeVarEditor("ChooserBackgroundColor") - @ThemeVarEditor("ChooserActiveStateColor") - @ThemeVarEditor("ChooserFontColor") -
                      -} - -@helper TabFooter() -{ - - @ThemeVarEditor("FooterBackground") - @ThemeVarEditor("FooterHeading") - @ThemeVarEditor("FooterFontColor") - @ThemeVarEditor("FooterLinkColor") - @ThemeVarEditor("FooterRadius") -
                      -} - -@helper TabShopBar() -{ - - @ThemeVarEditor("ShopBarBackgroundColor", "Shopbar") - @ThemeVarEditor("ShopBarBorderColor") - @ThemeVarEditor("ShopBarTextColor") - @ThemeVarEditor("ShopBarIconColor") - @ThemeVarEditor("ShopBarLabel") - - @ThemeVarEditor("InverseNavbar", "Navbar") - @ThemeVarEditor("NavbarHeight") - @ThemeVarEditor("NavbarBackgroundHighlight") - @ThemeVarEditor("NavbarText") - @ThemeVarEditor("NavbarLinkColor") - @ThemeVarEditor("NavbarLinkColorHover") - @ThemeVarEditor("NavbarLinkColorActive") - - @ThemeVarEditor("NavbarInverseBackground") - @ThemeVarEditor("NavbarInverseBackgroundHighlight") - @ThemeVarEditor("NavbarInverseBorder") - @ThemeVarEditor("NavbarInverseText") - @ThemeVarEditor("NavbarInverseLinkColor") - @ThemeVarEditor("NavbarInverseLinkColorHover") - @ThemeVarEditor("NavbarInverseLinkColorActive") - -
                      -} - -@helper TabCommon() -{ - - @ThemeVarEditor("SiteBackground") - @ThemeVarEditor("BodyBackground") - @ThemeVarEditor("TextColor") - @ThemeVarEditor("LinkColor") - @ThemeVarEditor("BoxBackground") - -
                      -} - -@helper TabFonts() -{ - - @ThemeVarEditor("SansFontFamily", T("Common.General")) - @ThemeVarEditor("SerifFontFamily") - @ThemeVarEditor("MonoFontFamily") - @ThemeVarEditor("BaseFontSize") - @ThemeVarEditor("BaseLineHeight") - - @ThemeVarEditor("HeadingsFontFamily", T("ThemeVar.Beta.Headings")) - @ThemeVarEditor("HeadingsFontWeight") - @ThemeVarEditor("HeadingsColor") - - @ThemeVarEditor("PageTitleFontFamily", T("ThemeVar.Beta.PageTitle")) - @ThemeVarEditor("PageTitleFontWeight") - @ThemeVarEditor("PageTitleColor") - -
                      -} - -@helper TabContentSlider() -{ - - @ThemeVarEditor("SliderBgSlide") - @ThemeVarEditor("SliderBackgroundColor") - @ThemeVarEditor("SliderTitleColor") - @ThemeVarEditor("SliderTitleFontFamily") - @ThemeVarEditor("SliderTitleFontWeight") - @ThemeVarEditor("SliderInfoColor") - @ThemeVarEditor("SliderInfoFontFamily") - @ThemeVarEditor("SliderInfoFontWeight") -
                      -} - - -@helper TabTableAndContainer() -{ - - - @ThemeVarEditor("TableBackground", T("ThemeVar.Beta.Tables")) - @ThemeVarEditor("TableBackgroundAccent") - @ThemeVarEditor("TableBackgroundHover") - @ThemeVarEditor("TableBorder") - @ThemeVarEditor("ContainerBackground", "Container") - @ThemeVarEditor("ContainerBorder") - @ThemeVarEditor("ContainerRadius") - @ThemeVarEditor("ContainerBodyLinkColor") - @ThemeVarEditor("ContainerHeaderBackground") - @ThemeVarEditor("ContainerHeaderFontColor") - @ThemeVarEditor("ContainerHeaderHeight") - @ThemeVarEditor("ContainerBodyBackground") - @ThemeVarEditor("ContainerBodyFontColor") - -
                      -} - -@helper TabMisc() -{ - - @ThemeVarEditor("WellBackground") - @ThemeVarEditor("ItemBoxBoxShadowColor") - @ThemeVarEditor("SimpleBoxHeaderColor") - @ThemeVarEditor("PaginationBackground", "Paginator") - @ThemeVarEditor("PaginationBorder") - @ThemeVarEditor("PaginationActiveBackground") - - @ThemeVarEditor("InputBackground", T("ThemeVar.Beta.Forms")) - @ThemeVarEditor("InputBorder") - @ThemeVarEditor("InputBorderRadius") - @ThemeVarEditor("InputDisabledBackground") - @ThemeVarEditor("FormActionsBackground") - - @ThemeVarEditor("DropdownBackground", "Dropdowns") - @ThemeVarEditor("DropdownBorder") - @ThemeVarEditor("DropdownDividerTop") - @ThemeVarEditor("DropdownDividerBottom") - @ThemeVarEditor("DropdownLinkColor") - @ThemeVarEditor("DropdownLinkColorHover") - @ThemeVarEditor("DropdownLinkColorActive") - @ThemeVarEditor("DropdownLinkBackgroundActive") - @ThemeVarEditor("DropdownLinkBackgroundHover") - - @ThemeVarEditor("ProductFilterBackgroundColor", "Product Filter") - @ThemeVarEditor("CheckoutProgressBackgroundColor", "Checkout Progress Bar") - @ThemeVarEditor("AlternateListItemBackgroundColor", "Alternate List Item") - -
                      -} - -@helper ThemeVarEditor(string varName, string groupName = null) -{ - if (groupName != null) - { - - @if(groupName != "") - { - -

                      @groupName

                      -
                      - - } - else { -
                      - } - - } - - - @Html.ThemeVarLabel(ThemeManifest.Variables[varName]) - - - @Html.ThemeVarEditor(ThemeManifest.Variables[varName], Model[varName]) - - -} - diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/Head.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/Head.cshtml deleted file mode 100644 index acd315d610..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/Head.cshtml +++ /dev/null @@ -1,13 +0,0 @@ -@using SmartStore.Core; -@using SmartStore.Core.Infrastructure; -@using SmartStore.Web.Framework.Themes; - -@{ - var supportRtl = EngineContext.Current.Resolve().WorkingLanguage.Rtl; -} -@{ - Html.AppendCssFileParts(false, "~/Themes/Beta/Content/theme.less"); - -} - -@Html.Partial("ConditionalComments") \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_Checkout.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_Checkout.cshtml deleted file mode 100644 index e4e5dd51eb..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_Checkout.cshtml +++ /dev/null @@ -1,13 +0,0 @@ -@{ - Layout = "~/Views/Shared/_ColumnsOne.cshtml"; - Html.AddBodyCssClass("checkout-page"); -} - -@section teaser { - -} - -@Html.Widget("main_column_before") -@RenderBody() -@Html.Widget("main_column_after") - diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_ColumnsThree.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_ColumnsThree.cshtml deleted file mode 100644 index 9f8ce52e48..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_ColumnsThree.cshtml +++ /dev/null @@ -1,64 +0,0 @@ -@{ - Layout = "~/Themes/Beta-sym/Views/Shared/_Root.cshtml"; - Html.AddBodyCssClass("lyt-cols-3"); // codehint: sm-add - - string[] spanWidths = GetThemeVariable("GridSettings", "5/14/5").Split('/'); -} -@section teaser { - @RenderSection("teaser", required: false) -} - -
                      - @if (IsSectionDefined("left")) - { - @RenderSection("left") - } - else - { - @Html.Widget("left_side_column_before") - - @Html.Action("CategoryNavigation", "Catalog", new { currentCategoryId = this.CurrentCategoryId, currentProductId = this.CurrentProductId }) - @Html.Widget("left_side_column_after_category_navigation") - - @Html.Action("ManufacturerNavigation", "Catalog", new { currentManufacturerId = this.CurrentManufacturerId }) - @Html.Widget("left_side_column_after_manufacturer_navigation") - - @Html.Action("PopularProductTags", "Catalog") - @Html.Widget("left_side_column_after_tags") - - @Html.Action("InfoBlock", "Common") - @Html.Widget("left_side_column_after_info") - - @Html.Action("PollBlock", "Poll", new { systemKeyword = "LeftColumnPoll" }) - @Html.Widget("left_side_column_after_poll") - - @Html.Widget("left_side_column_after") - } -
                      -
                      - @Html.Widget("main_column_before") - @RenderBody() - @Html.Widget("main_column_after") -
                      -
                      - @if (IsSectionDefined("right_top")) - { - @RenderSection("right_top", false) - } - - @if (IsSectionDefined("right")) - { - @RenderSection("right") - } - else - { - @Html.Widget("right_side_column_before") - - @Html.Action("RecentlyViewedProductsBlock", "Catalog") - @Html.Widget("right_side_column_after_recentlyviewed") - @Html.Action("PollBlock", "Poll", new { systemKeyword = "RightColumnPoll" }) - @Html.Widget("right_side_column_after_poll") - - @Html.Widget("right_side_column_after") - } -
                      diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_Root.cshtml b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_Root.cshtml deleted file mode 100644 index 1b2baf024e..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Shared/_Root.cshtml +++ /dev/null @@ -1,44 +0,0 @@ -@{ - Layout = "~/Views/Shared/_Root.Head.cshtml"; -} -@Html.Widget("body_start_html_tag_after") -@Html.Partial("_Notifications") -
                      - - @if (IsSectionDefined("header")) - { - @RenderSection("header") - } - else { - - } - - @Html.Action("JavaScriptDisabledWarning", "Common") -
                      -
                      - @Html.Widget("content_before") -
                      - @RenderBody() - @Html.Widget("content_after") -
                      -
                      -
                      - - @if (IsSectionDefined("footer")) - { - @RenderSection("footer") - } - else { - - } - -
                      -@Html.Widget("body_end_html_tag_before") - diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Web.config b/src/Presentation/SmartStore.Web/Themes/Beta/Views/Web.config deleted file mode 100644 index 27f777189e..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Views/Web.config +++ /dev/null @@ -1,63 +0,0 @@ - - - - - -
                      -
                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Web.Debug.config b/src/Presentation/SmartStore.Web/Themes/Beta/Web.Debug.config deleted file mode 100644 index e57a6dcf21..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Web.Debug.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Web.Release.config b/src/Presentation/SmartStore.Web/Themes/Beta/Web.Release.config deleted file mode 100644 index 0e85a2ea51..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Web.Release.config +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/Web.config b/src/Presentation/SmartStore.Web/Themes/Beta/Web.config deleted file mode 100644 index b8d4897788..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/Web.config +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/preview.png b/src/Presentation/SmartStore.Web/Themes/Beta/preview.png deleted file mode 100644 index 6e39c02392..0000000000 Binary files a/src/Presentation/SmartStore.Web/Themes/Beta/preview.png and /dev/null differ diff --git a/src/Presentation/SmartStore.Web/Themes/Beta/theme.config b/src/Presentation/SmartStore.Web/Themes/Beta/theme.config deleted file mode 100644 index af35de7154..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/Beta/theme.config +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - label-inverse - #fff - #555 - #646464 - #fff - - - 'Segoe UI', Tahoma, 'Helvetica Neue', Helvetica, Arial, 'sans-serif' - Georgia, 'Times New Roman', Times, serif - Menlo, Monaco, Consolas, 'Courier New', monospace - 14px - 20px - - - 'Segoe UI Semibold', 'Segoe UI', Tahoma, 'Helvetica Neue', Helvetica, Arial, 'sans-serif' - 600 - inherit - - 'Segoe UI Light', 'Segoe UI', Arial, Helvetica, 'sans-serif' - 400 - #3a87ad - - - transparent - #f9f9f9 - #f5f5f5 - #ddd - - - - #fff - #e6e6e6 - #333333 - - #0088cc - #0044cc - #fff - - #5bc0de - #2f96b4 - #fff - - #62c462 - #51a351 - #fff - - #646464 - #464646 - #efefef - - #ee5f5b - #bd362f - #fff - - #444 - #333 - #fff - - - #fff - #abc2d1 - #696969 - #d2d2d2 - label-inverse - - - false - 42px - #fff - - #717171 - #717171 - #1a1a1a - #555 - - - #222 - #666 - #555 - - #dadada - #dadada - #fff - #fff - - - #464646 - #646464 - #333 - - #cfdde6 - transparent - #cfdde6 - #888 - - - #fff - #7c7c7c - #7c7c7c - #aaa - 12px 12px 0 0 - - - #fff - #ededed - 3px - #888 - #eee - #555 - 17px - #fff - #555 - - - #f5f5f5 - #f89406 - #ddd - #f4f8f9 - #f5f5f5 - #f5f5f5 - - - off - transparent - #464646 - 'Segoe UI Light', 'Segoe UI', Arial, sans-serif - 100 - #464646 - inherit - inherit - - - #fff - #ddd - #f5f5f5 - - - 5/14/5 - 20px - 20px - 20px - 30px - - - #fff - #ccc - 4px - #eee - #f5f5f5 - - - #fff - #bbb - #e5e5e5 - #fff - - #333 - #fff - #fff - #f9980f - #f9980f - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css b/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css index 72812e99ea..dbf4b3d68c 100644 --- a/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css +++ b/src/Presentation/SmartStore.Web/Themes/Mobile/Content/styles.css @@ -1,4 +1,5 @@ .foo{} +img { max-width: 100% } /* MISC. CLASSES */ .nobr{white-space:nowrap!important;} @@ -55,7 +56,7 @@ #pagination-bottom .active a {color: #464646;} /* NAVIGATION BLOCKS */ -.block{margin-bottom:15px;padding-bottom:5px;padding-left:0;color:#FFF;} +.block{margin-bottom:15px;padding-bottom:5px;padding-left:0;/*color:#FFF;*/} .block .title{font-size:.9em;font-weight:700;text-transform:uppercase;padding:7px 10px;color:#333;} /* PRODUCTS IN LINES - TEMPLATE */ @@ -155,12 +156,19 @@ .checkout-data .use-reward-points{margin:0;padding:10px;background:#F7F5E8;border:dotted 1px #d3d3d3;} .checkout-data .payment-methods{text-align:left;height:auto;} .checkout-data .payment-methods .payment-method-item{text-align:left;vertical-align:text-top;} -.checkout-data .payment-methods .payment-method-item .payment-method-desc{margin:0 0 14px 46px;} +.checkout-data .payment-methods .payment-method-item .payment-method-description{margin:0 0 15px 15px;} .checkout-data .payment-methods .select-button{text-align:left;} .checkout-data .payment-methods .message-error{text-align:left;} .checkout-data .payment-info{text-align:left;height:auto;} .checkout-data .payment-info .body{text-align:left;vertical-align:text-top;} .checkout-data .payment-info .select-button{text-align:left;} +.checkout-data .payment-method-info .pull-left { + float: left; + margin: 0 10px 10px 15px; +} +.checkout-data .payment-method-info .media-body { + margin: 5px 10px 10px 15px; +} .checkout-data .confirm-order{text-align:left;height:auto;} .checkout-data .confirm-order .select-button{text-align:left;} .checkout-data .confirm-order .message-error{text-align:left;} @@ -431,6 +439,8 @@ .product-details-page .add-to-cart .qty-input{display:inline-block;width:40px;} .product-details-page .add-to-cart .qty-dropdown{} .product-details-page .attributes{} +.product-details-page .attributes .in { display: inline-block } +.product-details-page .attributes .hide { display: none } .product-details-page .attributes .text-prompt{font-weight:bold;} .product-details-page .attributes .attribute-description{} .product-details-page .attributes ul.option-list{padding:0px;margin:0px;} @@ -679,3 +689,10 @@ pre{white-space:pre-wrap;/* css-3 */white-space:0;/* Mozilla, since 1999 */white .legal-hints .footer-legal { color: green; } +.change-device button{ + display: inline; + margin: 0; + border: 0; + background: none; + padding: 7px; +} diff --git a/src/Presentation/SmartStore.Web/Themes/Mobile/Content/user.css b/src/Presentation/SmartStore.Web/Themes/Mobile/Content/user.css new file mode 100644 index 0000000000..dac21231b8 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Mobile/Content/user.css @@ -0,0 +1,6 @@ +// +// Customize the (child) theme here with css overrides +// or new selectors (for users) +// -------------------------------------------------- + + diff --git a/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Shared/Head.Mobile.cshtml b/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Shared/Head.Mobile.cshtml index 8552c7c51b..fd125c4cef 100644 --- a/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Shared/Head.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Shared/Head.Mobile.cshtml @@ -1,4 +1,6 @@ @{ - Html.AppendCssFileParts(Url.Content("~/Themes/Mobile/Content/jquery.mobile-1.3.2.min.css")); - Html.AppendCssFileParts(Url.Content("~/Themes/Mobile/Content/styles.css")); + Html.AppendCssFileParts( + "~/Themes/Mobile/Content/jquery.mobile.structure-1.3.2.css", + "~/Themes/Mobile/Content/jquery.mobile.theme-1.3.2.css"); + Html.AppendCssFileParts("~/Themes/Mobile/Content/styles.css", "~/Themes/Mobile/Content/user.css"); } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Web.config b/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Web.config index d5bc031f95..bd9d09444f 100644 --- a/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Web.config +++ b/src/Presentation/SmartStore.Web/Themes/Mobile/Views/Web.config @@ -10,7 +10,7 @@ - + @@ -29,29 +29,6 @@ - - - - - - - - - - - - - diff --git a/src/Presentation/SmartStore.Web/Themes/Mobile/preview.png b/src/Presentation/SmartStore.Web/Themes/Mobile/preview.png index 0fce6c4c0b..69d34f4d8b 100644 Binary files a/src/Presentation/SmartStore.Web/Themes/Mobile/preview.png and b/src/Presentation/SmartStore.Web/Themes/Mobile/preview.png differ diff --git a/src/Presentation/SmartStore.Web/Themes/Mobile/theme.config b/src/Presentation/SmartStore.Web/Themes/Mobile/theme.config index 5b9b41beee..42c0d992eb 100644 --- a/src/Presentation/SmartStore.Web/Themes/Mobile/theme.config +++ b/src/Presentation/SmartStore.Web/Themes/Mobile/theme.config @@ -2,7 +2,7 @@ \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/jquery.mobile.theme-1.3.2.css b/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/jquery.mobile.theme-1.3.2.css new file mode 100644 index 0000000000..d39bdb660c --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/jquery.mobile.theme-1.3.2.css @@ -0,0 +1,1074 @@ +/*! +* jQuery Mobile 1.3.2 +* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC +* http://jquerymobile.com +* +* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors +* Released under the MIT license. +* http://jquery.org/license +* +*/ + + +/* Swatches */ +/* A +-----------------------------------------------------------------------------------------------------------*/ +.ui-bar-a { + border: 1px solid #b3b3b3 /*{a-bar-border}*/; + background: #eeeeee /*{a-bar-background-color}*/; + color: #3e3e3e /*{a-bar-color}*/; + font-weight: bold; + text-shadow: 0 /*{a-bar-shadow-x}*/ 1px /*{a-bar-shadow-y}*/ 0 /*{a-bar-shadow-radius}*/ #ffffff /*{a-bar-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{a-bar-background-start}*/), to( #dddddd /*{a-bar-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f0f0f0 /*{a-bar-background-start}*/, #dddddd /*{a-bar-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f0f0f0 /*{a-bar-background-start}*/, #dddddd /*{a-bar-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f0f0f0 /*{a-bar-background-start}*/, #dddddd /*{a-bar-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f0f0f0 /*{a-bar-background-start}*/, #dddddd /*{a-bar-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f0f0f0 /*{a-bar-background-start}*/, #dddddd /*{a-bar-background-end}*/); +} +.ui-bar-a .ui-link-inherit { + color: #3e3e3e /*{a-bar-color}*/; +} +.ui-bar-a a.ui-link { + color: #7cc4e7 /*{a-bar-link-color}*/; + font-weight: bold; +} +.ui-bar-a a.ui-link:visited { + color: #2489ce /*{a-bar-link-visited}*/; +} +.ui-bar-a a.ui-link:hover { + color: #2489ce /*{a-bar-link-hover}*/; +} +.ui-bar-a a.ui-link:active { + color: #2489ce /*{a-bar-link-active}*/; +} +.ui-bar-a, +.ui-bar-a input, +.ui-bar-a select, +.ui-bar-a textarea, +.ui-bar-a button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-a, +.ui-overlay-a { + border: 1px solid #aaaaaa /*{a-body-border}*/; + color: #333333 /*{a-body-color}*/; + text-shadow: 0 /*{a-body-shadow-x}*/ 1px /*{a-body-shadow-y}*/ 0 /*{a-body-shadow-radius}*/ #ffffff /*{a-body-shadow-color}*/; + background: #f9f9f9 /*{a-body-background-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{a-body-background-start}*/), to( #eeeeee /*{a-body-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f9f9f9 /*{a-body-background-start}*/, #eeeeee /*{a-body-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f9f9f9 /*{a-body-background-start}*/, #eeeeee /*{a-body-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f9f9f9 /*{a-body-background-start}*/, #eeeeee /*{a-body-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f9f9f9 /*{a-body-background-start}*/, #eeeeee /*{a-body-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f9f9f9 /*{a-body-background-start}*/, #eeeeee /*{a-body-background-end}*/); +} +.ui-overlay-a { + background-image: none; + border-width: 0; +} +.ui-body-a, +.ui-body-a input, +.ui-body-a select, +.ui-body-a textarea, +.ui-body-a button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-a .ui-link-inherit { + color: #333333 /*{a-body-color}*/; +} +.ui-body-a .ui-link { + color: #2489ce /*{a-body-link-color}*/; + font-weight: bold; +} +.ui-body-a .ui-link:visited { + color: #2489ce /*{a-body-link-visited}*/; +} +.ui-body-a .ui-link:hover { + color: #2489ce /*{a-body-link-hover}*/; +} +.ui-body-a .ui-link:active { + color: #2489ce /*{a-body-link-active}*/; +} +.ui-btn-up-a { + border: 1px solid #cccccc /*{a-bup-border}*/; + background: #eeeeee /*{a-bup-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{a-bup-color}*/; + text-shadow: 0 /*{a-bup-shadow-x}*/ 1px /*{a-bup-shadow-y}*/ 0 /*{a-bup-shadow-radius}*/ #ffffff /*{a-bup-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #ffffff /*{a-bup-background-start}*/), to( #f1f1f1 /*{a-bup-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #ffffff /*{a-bup-background-start}*/, #f1f1f1 /*{a-bup-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #ffffff /*{a-bup-background-start}*/, #f1f1f1 /*{a-bup-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #ffffff /*{a-bup-background-start}*/, #f1f1f1 /*{a-bup-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #ffffff /*{a-bup-background-start}*/, #f1f1f1 /*{a-bup-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #ffffff /*{a-bup-background-start}*/, #f1f1f1 /*{a-bup-background-end}*/); +} +.ui-btn-up-a:visited, +.ui-btn-up-a a.ui-link-inherit { + color: #2f3e46 /*{a-bup-color}*/; +} +.ui-btn-hover-a { + border: 1px solid #bbbbbb /*{a-bhover-border}*/; + background: #dfdfdf /*{a-bhover-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{a-bhover-color}*/; + text-shadow: 0 /*{a-bhover-shadow-x}*/ 1px /*{a-bhover-shadow-y}*/ 0 /*{a-bhover-shadow-radius}*/ #ffffff /*{a-bhover-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{a-bhover-background-start}*/), to( #e0e0e0 /*{a-bhover-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f6f6f6 /*{a-bhover-background-start}*/, #e0e0e0 /*{a-bhover-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f6f6f6 /*{a-bhover-background-start}*/, #e0e0e0 /*{a-bhover-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f6f6f6 /*{a-bhover-background-start}*/, #e0e0e0 /*{a-bhover-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f6f6f6 /*{a-bhover-background-start}*/, #e0e0e0 /*{a-bhover-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f6f6f6 /*{a-bhover-background-start}*/, #e0e0e0 /*{a-bhover-background-end}*/); +} +.ui-btn-hover-a:visited, +.ui-btn-hover-a:hover, +.ui-btn-hover-a a.ui-link-inherit { + color: #2f3e46 /*{a-bhover-color}*/; +} +.ui-btn-down-a { + border: 1px solid #bbbbbb /*{a-bdown-border}*/; + background: #d6d6d6 /*{a-bdown-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{a-bdown-color}*/; + text-shadow: 0 /*{a-bdown-shadow-x}*/ 1px /*{a-bdown-shadow-y}*/ 0 /*{a-bdown-shadow-radius}*/ #ffffff /*{a-bdown-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{a-bdown-background-start}*/), to( #dfdfdf /*{a-bdown-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #d0d0d0 /*{a-bdown-background-start}*/, #dfdfdf /*{a-bdown-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #d0d0d0 /*{a-bdown-background-start}*/, #dfdfdf /*{a-bdown-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #d0d0d0 /*{a-bdown-background-start}*/, #dfdfdf /*{a-bdown-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #d0d0d0 /*{a-bdown-background-start}*/, #dfdfdf /*{a-bdown-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #d0d0d0 /*{a-bdown-background-start}*/, #dfdfdf /*{a-bdown-background-end}*/); +} +.ui-btn-down-a:visited, +.ui-btn-down-a:hover, +.ui-btn-down-a a.ui-link-inherit { + color: #2f3e46 /*{a-bdown-color}*/; +} +.ui-btn-up-a, +.ui-btn-hover-a, +.ui-btn-down-a { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; + text-decoration: none; +} +/* B +-----------------------------------------------------------------------------------------------------------*/ +.ui-bar-b { + border: 1px solid #b3b3b3 /*{b-bar-border}*/; + background: #eeeeee /*{b-bar-background-color}*/; + color: #3e3e3e /*{b-bar-color}*/; + font-weight: bold; + text-shadow: 0 /*{b-bar-shadow-x}*/ 1px /*{b-bar-shadow-y}*/ 0 /*{b-bar-shadow-radius}*/ #ffffff /*{b-bar-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{b-bar-background-start}*/), to( #dddddd /*{b-bar-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f0f0f0 /*{b-bar-background-start}*/, #dddddd /*{b-bar-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f0f0f0 /*{b-bar-background-start}*/, #dddddd /*{b-bar-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f0f0f0 /*{b-bar-background-start}*/, #dddddd /*{b-bar-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f0f0f0 /*{b-bar-background-start}*/, #dddddd /*{b-bar-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f0f0f0 /*{b-bar-background-start}*/, #dddddd /*{b-bar-background-end}*/); +} +.ui-bar-b .ui-link-inherit { + color: #3e3e3e /*{b-bar-color}*/; +} +.ui-bar-b a.ui-link { + color: #7cc4e7 /*{b-bar-link-color}*/; + font-weight: bold; +} +.ui-bar-b a.ui-link:visited { + color: #2489ce /*{b-bar-link-visited}*/; +} +.ui-bar-b a.ui-link:hover { + color: #2489ce /*{b-bar-link-hover}*/; +} +.ui-bar-b a.ui-link:active { + color: #2489ce /*{b-bar-link-active}*/; +} +.ui-bar-b, +.ui-bar-b input, +.ui-bar-b select, +.ui-bar-b textarea, +.ui-bar-b button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-b, +.ui-overlay-b { + border: 1px solid #aaaaaa /*{b-body-border}*/; + color: #333333 /*{b-body-color}*/; + text-shadow: 0 /*{b-body-shadow-x}*/ 1px /*{b-body-shadow-y}*/ 0 /*{b-body-shadow-radius}*/ #ffffff /*{b-body-shadow-color}*/; + background: #f9f9f9 /*{b-body-background-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{b-body-background-start}*/), to( #eeeeee /*{b-body-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f9f9f9 /*{b-body-background-start}*/, #eeeeee /*{b-body-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f9f9f9 /*{b-body-background-start}*/, #eeeeee /*{b-body-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f9f9f9 /*{b-body-background-start}*/, #eeeeee /*{b-body-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f9f9f9 /*{b-body-background-start}*/, #eeeeee /*{b-body-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f9f9f9 /*{b-body-background-start}*/, #eeeeee /*{b-body-background-end}*/); +} +.ui-overlay-b { + background-image: none; + border-width: 0; +} +.ui-body-b, +.ui-body-b input, +.ui-body-b select, +.ui-body-b textarea, +.ui-body-b button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-b .ui-link-inherit { + color: #333333 /*{b-body-color}*/; +} +.ui-body-b .ui-link { + color: #2489ce /*{b-body-link-color}*/; + font-weight: bold; +} +.ui-body-b .ui-link:visited { + color: #2489ce /*{b-body-link-visited}*/; +} +.ui-body-b .ui-link:hover { + color: #2489ce /*{b-body-link-hover}*/; +} +.ui-body-b .ui-link:active { + color: #2489ce /*{b-body-link-active}*/; +} +.ui-btn-up-b { + border: 1px solid #cccccc /*{b-bup-border}*/; + background: #eeeeee /*{b-bup-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{b-bup-color}*/; + text-shadow: 0 /*{b-bup-shadow-x}*/ 1px /*{b-bup-shadow-y}*/ 0 /*{b-bup-shadow-radius}*/ #ffffff /*{b-bup-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #ffffff /*{b-bup-background-start}*/), to( #f1f1f1 /*{b-bup-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #ffffff /*{b-bup-background-start}*/, #f1f1f1 /*{b-bup-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #ffffff /*{b-bup-background-start}*/, #f1f1f1 /*{b-bup-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #ffffff /*{b-bup-background-start}*/, #f1f1f1 /*{b-bup-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #ffffff /*{b-bup-background-start}*/, #f1f1f1 /*{b-bup-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #ffffff /*{b-bup-background-start}*/, #f1f1f1 /*{b-bup-background-end}*/); +} +.ui-btn-up-b:visited, +.ui-btn-up-b a.ui-link-inherit { + color: #2f3e46 /*{b-bup-color}*/; +} +.ui-btn-hover-b { + border: 1px solid #bbbbbb /*{b-bhover-border}*/; + background: #dfdfdf /*{b-bhover-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{b-bhover-color}*/; + text-shadow: 0 /*{b-bhover-shadow-x}*/ 1px /*{b-bhover-shadow-y}*/ 0 /*{b-bhover-shadow-radius}*/ #ffffff /*{b-bhover-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{b-bhover-background-start}*/), to( #e0e0e0 /*{b-bhover-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f6f6f6 /*{b-bhover-background-start}*/, #e0e0e0 /*{b-bhover-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f6f6f6 /*{b-bhover-background-start}*/, #e0e0e0 /*{b-bhover-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f6f6f6 /*{b-bhover-background-start}*/, #e0e0e0 /*{b-bhover-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f6f6f6 /*{b-bhover-background-start}*/, #e0e0e0 /*{b-bhover-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f6f6f6 /*{b-bhover-background-start}*/, #e0e0e0 /*{b-bhover-background-end}*/); +} +.ui-btn-hover-b:visited, +.ui-btn-hover-b:hover, +.ui-btn-hover-b a.ui-link-inherit { + color: #2f3e46 /*{b-bhover-color}*/; +} +.ui-btn-down-b { + border: 1px solid #bbbbbb /*{b-bdown-border}*/; + background: #d6d6d6 /*{b-bdown-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{b-bdown-color}*/; + text-shadow: 0 /*{b-bdown-shadow-x}*/ 1px /*{b-bdown-shadow-y}*/ 0 /*{b-bdown-shadow-radius}*/ #ffffff /*{b-bdown-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{b-bdown-background-start}*/), to( #dfdfdf /*{b-bdown-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #d0d0d0 /*{b-bdown-background-start}*/, #dfdfdf /*{b-bdown-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #d0d0d0 /*{b-bdown-background-start}*/, #dfdfdf /*{b-bdown-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #d0d0d0 /*{b-bdown-background-start}*/, #dfdfdf /*{b-bdown-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #d0d0d0 /*{b-bdown-background-start}*/, #dfdfdf /*{b-bdown-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #d0d0d0 /*{b-bdown-background-start}*/, #dfdfdf /*{b-bdown-background-end}*/); +} +.ui-btn-down-b:visited, +.ui-btn-down-b:hover, +.ui-btn-down-b a.ui-link-inherit { + color: #2f3e46 /*{b-bdown-color}*/; +} +.ui-btn-up-b, +.ui-btn-hover-b, +.ui-btn-down-b { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; + text-decoration: none; +} + + +/* C +-----------------------------------------------------------------------------------------------------------*/ +.ui-bar-c { + border: 1px solid #b3b3b3 /*{c-bar-border}*/; + background: #eeeeee /*{c-bar-background-color}*/; + color: #3e3e3e /*{c-bar-color}*/; + font-weight: bold; + text-shadow: 0 /*{c-bar-shadow-x}*/ 1px /*{c-bar-shadow-y}*/ 0 /*{c-bar-shadow-radius}*/ #ffffff /*{c-bar-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{c-bar-background-start}*/), to( #dddddd /*{c-bar-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #dddddd /*{c-bar-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #dddddd /*{c-bar-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #dddddd /*{c-bar-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #dddddd /*{c-bar-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #dddddd /*{c-bar-background-end}*/); +} +.ui-bar-c .ui-link-inherit { + color: #3e3e3e /*{c-bar-color}*/; +} +.ui-bar-c a.ui-link { + color: #7cc4e7 /*{c-bar-link-color}*/; + font-weight: bold; +} +.ui-bar-c a.ui-link:visited { + color: #2489ce /*{c-bar-link-visited}*/; +} +.ui-bar-c a.ui-link:hover { + color: #2489ce /*{c-bar-link-hover}*/; +} +.ui-bar-c a.ui-link:active { + color: #2489ce /*{c-bar-link-active}*/; +} +.ui-bar-c, +.ui-bar-c input, +.ui-bar-c select, +.ui-bar-c textarea, +.ui-bar-c button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-c, +.ui-overlay-c { + border: 1px solid #aaaaaa /*{c-body-border}*/; + color: #333333 /*{c-body-color}*/; + text-shadow: 0 /*{c-body-shadow-x}*/ 1px /*{c-body-shadow-y}*/ 0 /*{c-body-shadow-radius}*/ #ffffff /*{c-body-shadow-color}*/; + background: #f9f9f9 /*{c-body-background-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{c-body-background-start}*/), to( #eeeeee /*{c-body-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); +} +.ui-overlay-c { + background-image: none; + border-width: 0; +} +.ui-body-c, +.ui-body-c input, +.ui-body-c select, +.ui-body-c textarea, +.ui-body-c button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-c .ui-link-inherit { + color: #333333 /*{c-body-color}*/; +} +.ui-body-c .ui-link { + color: #2489ce /*{c-body-link-color}*/; + font-weight: bold; +} +.ui-body-c .ui-link:visited { + color: #2489ce /*{c-body-link-visited}*/; +} +.ui-body-c .ui-link:hover { + color: #2489ce /*{c-body-link-hover}*/; +} +.ui-body-c .ui-link:active { + color: #2489ce /*{c-body-link-active}*/; +} +.ui-btn-up-c { + border: 1px solid #cccccc /*{c-bup-border}*/; + background: #eeeeee /*{c-bup-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{c-bup-color}*/; + text-shadow: 0 /*{c-bup-shadow-x}*/ 1px /*{c-bup-shadow-y}*/ 0 /*{c-bup-shadow-radius}*/ #ffffff /*{c-bup-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #ffffff /*{c-bup-background-start}*/), to( #f1f1f1 /*{c-bup-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); +} +.ui-btn-up-c:visited, +.ui-btn-up-c a.ui-link-inherit { + color: #2f3e46 /*{c-bup-color}*/; +} +.ui-btn-hover-c { + border: 1px solid #bbbbbb /*{c-bhover-border}*/; + background: #dfdfdf /*{c-bhover-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{c-bhover-color}*/; + text-shadow: 0 /*{c-bhover-shadow-x}*/ 1px /*{c-bhover-shadow-y}*/ 0 /*{c-bhover-shadow-radius}*/ #ffffff /*{c-bhover-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{c-bhover-background-start}*/), to( #e0e0e0 /*{c-bhover-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); +} +.ui-btn-hover-c:visited, +.ui-btn-hover-c:hover, +.ui-btn-hover-c a.ui-link-inherit { + color: #2f3e46 /*{c-bhover-color}*/; +} +.ui-btn-down-c { + border: 1px solid #bbbbbb /*{c-bdown-border}*/; + background: #d6d6d6 /*{c-bdown-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{c-bdown-color}*/; + text-shadow: 0 /*{c-bdown-shadow-x}*/ 1px /*{c-bdown-shadow-y}*/ 0 /*{c-bdown-shadow-radius}*/ #ffffff /*{c-bdown-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{c-bdown-background-start}*/), to( #dfdfdf /*{c-bdown-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); +} +.ui-btn-down-c:visited, +.ui-btn-down-c:hover, +.ui-btn-down-c a.ui-link-inherit { + color: #2f3e46 /*{c-bdown-color}*/; +} +.ui-btn-up-c, +.ui-btn-hover-c, +.ui-btn-down-c { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; + text-decoration: none; +} + + +/* D +-----------------------------------------------------------------------------------------------------------*/ +.ui-bar-d { + border: 1px solid #b3b3b3 /*{d-bar-border}*/; + background: #eeeeee /*{d-bar-background-color}*/; + color: #3e3e3e /*{d-bar-color}*/; + font-weight: bold; + text-shadow: 0 /*{d-bar-shadow-x}*/ 1px /*{d-bar-shadow-y}*/ 0 /*{d-bar-shadow-radius}*/ #ffffff /*{d-bar-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{d-bar-background-start}*/), to( #dddddd /*{d-bar-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #f0f0f0 /*{d-bar-background-start}*/, #dddddd /*{d-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #f0f0f0 /*{d-bar-background-start}*/, #dddddd /*{d-bar-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f0f0f0 /*{d-bar-background-start}*/, #dddddd /*{d-bar-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f0f0f0 /*{d-bar-background-start}*/, #dddddd /*{d-bar-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #f0f0f0 /*{d-bar-background-start}*/, #dddddd /*{d-bar-background-end}*/); +} +.ui-bar-d .ui-link-inherit { + color: #3e3e3e /*{d-bar-color}*/; +} +.ui-bar-d a.ui-link { + color: #7cc4e7 /*{d-bar-link-color}*/; + font-weight: bold; +} +.ui-bar-d a.ui-link:visited { + color: #2489ce /*{d-bar-link-visited}*/; +} +.ui-bar-d a.ui-link:hover { + color: #2489ce /*{d-bar-link-hover}*/; +} +.ui-bar-d a.ui-link:active { + color: #2489ce /*{d-bar-link-active}*/; +} +.ui-bar-d, +.ui-bar-d input, +.ui-bar-d select, +.ui-bar-d textarea, +.ui-bar-d button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-d, +.ui-overlay-d { + border: 1px solid #aaaaaa /*{d-body-border}*/; + color: #333333 /*{d-body-color}*/; + text-shadow: 0 /*{d-body-shadow-x}*/ 1px /*{d-body-shadow-y}*/ 0 /*{d-body-shadow-radius}*/ #ffffff /*{d-body-shadow-color}*/; + background: #f9f9f9 /*{d-body-background-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{d-body-background-start}*/), to( #eeeeee /*{d-body-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #f9f9f9 /*{d-body-background-start}*/, #eeeeee /*{d-body-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #f9f9f9 /*{d-body-background-start}*/, #eeeeee /*{d-body-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f9f9f9 /*{d-body-background-start}*/, #eeeeee /*{d-body-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f9f9f9 /*{d-body-background-start}*/, #eeeeee /*{d-body-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #f9f9f9 /*{d-body-background-start}*/, #eeeeee /*{d-body-background-end}*/); +} +.ui-overlay-d { + background-image: none; + border-width: 0; +} +.ui-body-d, +.ui-body-d input, +.ui-body-d select, +.ui-body-d textarea, +.ui-body-d button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-d .ui-link-inherit { + color: #333333 /*{d-body-color}*/; +} +.ui-body-d .ui-link { + color: #2489ce /*{d-body-link-color}*/; + font-weight: bold; +} +.ui-body-d .ui-link:visited { + color: #2489ce /*{d-body-link-visited}*/; +} +.ui-body-d .ui-link:hover { + color: #2489ce /*{d-body-link-hover}*/; +} +.ui-body-d .ui-link:active { + color: #2489ce /*{d-body-link-active}*/; +} +.ui-btn-up-d { + border: 1px solid #cccccc /*{d-bup-border}*/; + background: #eeeeee /*{d-bup-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{d-bup-color}*/; + text-shadow: 0 /*{d-bup-shadow-x}*/ 1px /*{d-bup-shadow-y}*/ 0 /*{d-bup-shadow-radius}*/ #ffffff /*{d-bup-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #ffffff /*{d-bup-background-start}*/), to( #f1f1f1 /*{d-bup-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #ffffff /*{d-bup-background-start}*/, #f1f1f1 /*{d-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #ffffff /*{d-bup-background-start}*/, #f1f1f1 /*{d-bup-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #ffffff /*{d-bup-background-start}*/, #f1f1f1 /*{d-bup-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #ffffff /*{d-bup-background-start}*/, #f1f1f1 /*{d-bup-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #ffffff /*{d-bup-background-start}*/, #f1f1f1 /*{d-bup-background-end}*/); +} +.ui-btn-up-d:visited, +.ui-btn-up-d a.ui-link-inherit { + color: #2f3e46 /*{d-bup-color}*/; +} +.ui-btn-hover-d { + border: 1px solid #bbbbbb /*{d-bhover-border}*/; + background: #dfdfdf /*{d-bhover-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{d-bhover-color}*/; + text-shadow: 0 /*{d-bhover-shadow-x}*/ 1px /*{d-bhover-shadow-y}*/ 0 /*{d-bhover-shadow-radius}*/ #ffffff /*{d-bhover-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{d-bhover-background-start}*/), to( #e0e0e0 /*{d-bhover-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #f6f6f6 /*{d-bhover-background-start}*/, #e0e0e0 /*{d-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #f6f6f6 /*{d-bhover-background-start}*/, #e0e0e0 /*{d-bhover-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f6f6f6 /*{d-bhover-background-start}*/, #e0e0e0 /*{d-bhover-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f6f6f6 /*{d-bhover-background-start}*/, #e0e0e0 /*{d-bhover-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #f6f6f6 /*{d-bhover-background-start}*/, #e0e0e0 /*{d-bhover-background-end}*/); +} +.ui-btn-hover-d:visited, +.ui-btn-hover-d:hover, +.ui-btn-hover-d a.ui-link-inherit { + color: #2f3e46 /*{d-bhover-color}*/; +} +.ui-btn-down-d { + border: 1px solid #bbbbbb /*{d-bdown-border}*/; + background: #d6d6d6 /*{d-bdown-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{d-bdown-color}*/; + text-shadow: 0 /*{d-bdown-shadow-x}*/ 1px /*{d-bdown-shadow-y}*/ 0 /*{d-bdown-shadow-radius}*/ #ffffff /*{d-bdown-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{d-bdown-background-start}*/), to( #dfdfdf /*{d-bdown-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #d0d0d0 /*{d-bdown-background-start}*/, #dfdfdf /*{d-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #d0d0d0 /*{d-bdown-background-start}*/, #dfdfdf /*{d-bdown-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #d0d0d0 /*{d-bdown-background-start}*/, #dfdfdf /*{d-bdown-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #d0d0d0 /*{d-bdown-background-start}*/, #dfdfdf /*{d-bdown-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #d0d0d0 /*{d-bdown-background-start}*/, #dfdfdf /*{d-bdown-background-end}*/); +} +.ui-btn-down-d:visited, +.ui-btn-down-d:hover, +.ui-btn-down-d a.ui-link-inherit { + color: #2f3e46 /*{d-bdown-color}*/; +} +.ui-btn-up-d, +.ui-btn-hover-d, +.ui-btn-down-d { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; + text-decoration: none; +} + + +/* E +-----------------------------------------------------------------------------------------------------------*/ +.ui-bar-e { + border: 1px solid #b3b3b3 /*{e-bar-border}*/; + background: #eeeeee /*{e-bar-background-color}*/; + color: #3e3e3e /*{e-bar-color}*/; + font-weight: bold; + text-shadow: 0 /*{e-bar-shadow-x}*/ 1px /*{e-bar-shadow-y}*/ 0 /*{e-bar-shadow-radius}*/ #ffffff /*{e-bar-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{e-bar-background-start}*/), to( #dddddd /*{e-bar-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #f0f0f0 /*{e-bar-background-start}*/, #dddddd /*{e-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #f0f0f0 /*{e-bar-background-start}*/, #dddddd /*{e-bar-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f0f0f0 /*{e-bar-background-start}*/, #dddddd /*{e-bar-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f0f0f0 /*{e-bar-background-start}*/, #dddddd /*{e-bar-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #f0f0f0 /*{e-bar-background-start}*/, #dddddd /*{e-bar-background-end}*/); +} +.ui-bar-e .ui-link-inherit { + color: #3e3e3e /*{e-bar-color}*/; +} +.ui-bar-e a.ui-link { + color: #7cc4e7 /*{e-bar-link-color}*/; + font-weight: bold; +} +.ui-bar-e a.ui-link:visited { + color: #2489ce /*{e-bar-link-visited}*/; +} +.ui-bar-e a.ui-link:hover { + color: #2489ce /*{e-bar-link-hover}*/; +} +.ui-bar-e a.ui-link:active { + color: #2489ce /*{e-bar-link-active}*/; +} +.ui-bar-e, +.ui-bar-e input, +.ui-bar-e select, +.ui-bar-e textarea, +.ui-bar-e button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-e, +.ui-overlay-e { + border: 1px solid #aaaaaa /*{e-body-border}*/; + color: #333333 /*{e-body-color}*/; + text-shadow: 0 /*{e-body-shadow-x}*/ 1px /*{e-body-shadow-y}*/ 0 /*{e-body-shadow-radius}*/ #ffffff /*{e-body-shadow-color}*/; + background: #f9f9f9 /*{e-body-background-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{e-body-background-start}*/), to( #eeeeee /*{e-body-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #f9f9f9 /*{e-body-background-start}*/, #eeeeee /*{e-body-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #f9f9f9 /*{e-body-background-start}*/, #eeeeee /*{e-body-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f9f9f9 /*{e-body-background-start}*/, #eeeeee /*{e-body-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f9f9f9 /*{e-body-background-start}*/, #eeeeee /*{e-body-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #f9f9f9 /*{e-body-background-start}*/, #eeeeee /*{e-body-background-end}*/); +} +.ui-overlay-e { + background-image: none; + border-width: 0; +} +.ui-body-e, +.ui-body-e input, +.ui-body-e select, +.ui-body-e textarea, +.ui-body-e button { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-body-e .ui-link-inherit { + color: #333333 /*{e-body-color}*/; +} +.ui-body-e .ui-link { + color: #2489ce /*{e-body-link-color}*/; + font-weight: bold; +} +.ui-body-e .ui-link:visited { + color: #2489ce /*{e-body-link-visited}*/; +} +.ui-body-e .ui-link:hover { + color: #2489ce /*{e-body-link-hover}*/; +} +.ui-body-e .ui-link:active { + color: #2489ce /*{e-body-link-active}*/; +} +.ui-btn-up-e { + border: 1px solid #cccccc /*{e-bup-border}*/; + background: #eeeeee /*{e-bup-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{e-bup-color}*/; + text-shadow: 0 /*{e-bup-shadow-x}*/ 1px /*{e-bup-shadow-y}*/ 0 /*{e-bup-shadow-radius}*/ #ffffff /*{e-bup-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #ffffff /*{e-bup-background-start}*/), to( #f1f1f1 /*{e-bup-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #ffffff /*{e-bup-background-start}*/, #f1f1f1 /*{e-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #ffffff /*{e-bup-background-start}*/, #f1f1f1 /*{e-bup-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #ffffff /*{e-bup-background-start}*/, #f1f1f1 /*{e-bup-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #ffffff /*{e-bup-background-start}*/, #f1f1f1 /*{e-bup-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #ffffff /*{e-bup-background-start}*/, #f1f1f1 /*{e-bup-background-end}*/); +} +.ui-btn-up-e:visited, +.ui-btn-up-e a.ui-link-inherit { + color: #2f3e46 /*{e-bup-color}*/; +} +.ui-btn-hover-e { + border: 1px solid #bbbbbb /*{e-bhover-border}*/; + background: #dfdfdf /*{e-bhover-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{e-bhover-color}*/; + text-shadow: 0 /*{e-bhover-shadow-x}*/ 1px /*{e-bhover-shadow-y}*/ 0 /*{e-bhover-shadow-radius}*/ #ffffff /*{e-bhover-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{e-bhover-background-start}*/), to( #e0e0e0 /*{e-bhover-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #f6f6f6 /*{e-bhover-background-start}*/, #e0e0e0 /*{e-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #f6f6f6 /*{e-bhover-background-start}*/, #e0e0e0 /*{e-bhover-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #f6f6f6 /*{e-bhover-background-start}*/, #e0e0e0 /*{e-bhover-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #f6f6f6 /*{e-bhover-background-start}*/, #e0e0e0 /*{e-bhover-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #f6f6f6 /*{e-bhover-background-start}*/, #e0e0e0 /*{e-bhover-background-end}*/); +} +.ui-btn-hover-e:visited, +.ui-btn-hover-e:hover, +.ui-btn-hover-e a.ui-link-inherit { + color: #2f3e46 /*{e-bhover-color}*/; +} +.ui-btn-down-e { + border: 1px solid #bbbbbb /*{e-bdown-border}*/; + background: #d6d6d6 /*{e-bdown-background-color}*/; + font-weight: bold; + color: #2f3e46 /*{e-bdown-color}*/; + text-shadow: 0 /*{e-bdown-shadow-x}*/ 1px /*{e-bdown-shadow-y}*/ 0 /*{e-bdown-shadow-radius}*/ #ffffff /*{e-bdown-shadow-color}*/; + background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{e-bdown-background-start}*/), to( #dfdfdf /*{e-bdown-background-end}*/)); /* Saf4+, Chrome */ + background-image: -webkit-linear-gradient( #d0d0d0 /*{e-bdown-background-start}*/, #dfdfdf /*{e-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */ + background-image: -moz-linear-gradient( #d0d0d0 /*{e-bdown-background-start}*/, #dfdfdf /*{e-bdown-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #d0d0d0 /*{e-bdown-background-start}*/, #dfdfdf /*{e-bdown-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #d0d0d0 /*{e-bdown-background-start}*/, #dfdfdf /*{e-bdown-background-end}*/); /* Opera 11.10+ */ + background-image: linear-gradient( #d0d0d0 /*{e-bdown-background-start}*/, #dfdfdf /*{e-bdown-background-end}*/); +} +.ui-btn-down-e:visited, +.ui-btn-down-e:hover, +.ui-btn-down-e a.ui-link-inherit { + color: #2f3e46 /*{e-bdown-color}*/; +} +.ui-btn-up-e, +.ui-btn-hover-e, +.ui-btn-down-e { + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; + text-decoration: none; +} + + +/* Structure */ +/* links within "buttons" +-----------------------------------------------------------------------------------------------------------*/ +a.ui-link-inherit { + text-decoration: none !important; +} +/* Active class used as the "on" state across all themes +-----------------------------------------------------------------------------------------------------------*/ +.ui-btn-active { + border: 1px solid #2373a5 /*{global-active-border}*/; + background: #387bbe /*{global-active-background-color}*/; + font-weight: bold; + color: #ffffff /*{global-active-color}*/; + cursor: pointer; + text-shadow: 0 /*{global-active-shadow-x}*/ 1px /*{global-active-shadow-y}*/ 0 /*{global-active-shadow-radius}*/ #3373a5 /*{global-active-shadow-color}*/; + text-decoration: none; + background-image: -webkit-gradient(linear, left top, left bottom, from( #5393c5 /*{global-active-background-start}*/), to( #6facd5 /*{global-active-background-end}*/)); /* Saf4 , Chrome */ + background-image: -webkit-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Chrome 10 , Saf5.1 */ + background-image: -moz-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* FF3.6 */ + background-image: -ms-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* IE10 */ + background-image: -o-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Opera 11.10 */ + background-image: linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); + font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/; +} +.ui-btn-active:visited, +.ui-btn-active:hover, +.ui-btn-active a.ui-link-inherit { + color: #ffffff /*{global-active-color}*/; +} +/* button inner top highlight +-----------------------------------------------------------------------------------------------------------*/ +.ui-btn-inner { + border-top: 1px solid #fff; + border-color: rgba(255,255,255,.3); +} +/* corner rounding classes +-----------------------------------------------------------------------------------------------------------*/ +.ui-corner-all { + -webkit-border-radius: 0.3em /*{global-radii-blocks}*/; + border-radius: 0.3em /*{global-radii-blocks}*/; +} +/* Form field separator +-----------------------------------------------------------------------------------------------------------*/ +.ui-br { + border-color: rgb(130,130,130); + border-color: rgba(130,130,130,.3); + border-style: solid; +} +/* Interaction cues +-----------------------------------------------------------------------------------------------------------*/ +.ui-disabled { + filter: Alpha(Opacity=30); + opacity: .3; + zoom: 1; +} +.ui-disabled, +.ui-disabled a { + cursor: default !important; + pointer-events: none; +} +/* Icons +-----------------------------------------------------------------------------------------------------------*/ +.ui-icon, +.ui-icon-searchfield:after { + background: #666666 /*{global-icon-color}*/; + background: rgba(0,0,0,.4) /*{global-icon-disc}*/; + background-image: url(images/icons-18-white.png) /*{global-icon-set}*/; + background-repeat: no-repeat; + -webkit-border-radius: 9px; + border-radius: 9px; +} +/* Alt icon color +-----------------------------------------------------------------------------------------------------------*/ +.ui-icon-alt .ui-icon, +.ui-icon-alt .ui-icon-searchfield:after { + background-color: #fff; + background-color: rgba(255,255,255,.3); + background-image: url(images/icons-18-black.png); + background-repeat: no-repeat; +} +/* No disc +-----------------------------------------------------------------------------------------------------------*/ +.ui-icon-nodisc .ui-icon, +.ui-icon-nodisc .ui-icon-searchfield:after, +.ui-icon-nodisc .ui-icon-alt .ui-icon, +.ui-icon-nodisc .ui-icon-alt .ui-icon-searchfield:after { + background-color: transparent; +} +/* Icon sprite +-----------------------------------------------------------------------------------------------------------*/ +/* plus minus */ +.ui-icon-plus { + background-position: -1px -1px; +} +.ui-icon-minus { + background-position: -37px -1px; +} +/* delete/close */ +.ui-icon-delete { + background-position: -73px -1px; +} +/* arrows */ +.ui-icon-arrow-r { + background-position: -108px -1px; +} +.ui-icon-arrow-l { + background-position: -144px -1px; +} +.ui-icon-arrow-u { + background-position: -180px -1px; +} +.ui-icon-arrow-d { + background-position: -216px -1px; +} +/* misc */ +.ui-icon-check { + background-position: -252px -1px; +} +.ui-icon-gear { + background-position: -288px -1px; +} +.ui-icon-refresh { + background-position: -323px -1px; +} +.ui-icon-forward { + background-position: -360px -1px; +} +.ui-icon-back { + background-position: -396px -1px; +} +.ui-icon-grid { + background-position: -432px -1px; +} +.ui-icon-star { + background-position: -467px -1px; +} +.ui-icon-alert { + background-position: -503px -1px; +} +.ui-icon-info { + background-position: -539px -1px; +} +.ui-icon-home { + background-position: -575px -1px; +} +/* search */ +.ui-icon-search, +.ui-icon-searchfield:after { + background-position: -611px -1px; +} +/* checkbox radio */ +.ui-icon-checkbox-on { + background-position: -647px -1px; +} +.ui-icon-checkbox-off { + background-position: -683px -1px; +} +.ui-icon-radio-on { + background-position: -718px -1px; +} +.ui-icon-radio-off { + background-position: -754px -1px; +} +/* menu edit */ +.ui-icon-bars { + background-position: -788px -1px; +} +.ui-icon-edit { + background-position: -824px -1px; +} +/* HD/"retina" sprite +-----------------------------------------------------------------------------------------------------------*/ +@media only screen and (-webkit-min-device-pixel-ratio: 1.3), + only screen and (min--moz-device-pixel-ratio: 1.3), + only screen and (min-resolution: 200dpi) { + + .ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r, + .ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check, + .ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back, + .ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-bars, .ui-icon-edit, + .ui-icon-search, .ui-icon-searchfield:after, + .ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on { + background-image: url(images/icons-36-white.png); + -moz-background-size: 864px 18px; + -o-background-size: 864px 18px; + -webkit-background-size: 864px 18px; + background-size: 864px 18px; + } + .ui-icon-alt .ui-icon { + background-image: url(images/icons-36-black.png); + } + .ui-icon-plus { + background-position: 0 50%; + } + .ui-icon-minus { + background-position: -36px 50%; + } + .ui-icon-delete { + background-position: -72px 50%; + } + .ui-icon-arrow-r { + background-position: -108px 50%; + } + .ui-icon-arrow-l { + background-position: -144px 50%; + } + .ui-icon-arrow-u { + background-position: -179px 50%; + } + .ui-icon-arrow-d { + background-position: -215px 50%; + } + .ui-icon-check { + background-position: -252px 50%; + } + .ui-icon-gear { + background-position: -287px 50%; + } + .ui-icon-refresh { + background-position: -323px 50%; + } + .ui-icon-forward { + background-position: -360px 50%; + } + .ui-icon-back { + background-position: -395px 50%; + } + .ui-icon-grid { + background-position: -431px 50%; + } + .ui-icon-star { + background-position: -467px 50%; + } + .ui-icon-alert { + background-position: -503px 50%; + } + .ui-icon-info { + background-position: -538px 50%; + } + .ui-icon-home { + background-position: -575px 50%; + } + .ui-icon-search, + .ui-icon-searchfield:after { + background-position: -611px 50%; + } + .ui-icon-checkbox-on { + background-position: -647px 50%; + } + .ui-icon-checkbox-off { + background-position: -683px 50%; + } + .ui-icon-radio-on { + background-position: -718px 50%; + } + .ui-icon-radio-off { + background-position: -754px 50%; + } + .ui-icon-bars { + background-position: -788px 50%; + + }.ui-icon-edit { + background-position: -824px 50%; + } +} +/* checks,radios */ +.ui-checkbox .ui-icon, +.ui-selectmenu-list .ui-icon { + -webkit-border-radius: 3px; + border-radius: 3px; +} +.ui-icon-checkbox-off, +.ui-icon-radio-off { + background-color: transparent; +} +.ui-checkbox-on .ui-icon, +.ui-radio-on .ui-icon { + background-color: #387bbe /*{global-active-background-color}*/; /* NOTE: this hex should match the active state color. It's repeated here for cascade */ +} +/* loading icon */ +.ui-icon-loading { + background: url(images/ajax-loader.gif); + background-size: 46px 46px; +} +/* Button corner class +-----------------------------------------------------------------------------------------------------------*/ +.ui-btn-corner-all { + -webkit-border-radius: 0.4em /*{global-radii-buttons}*/; + border-radius: 0.4em /*{global-radii-buttons}*/; +} +/* radius clip workaround for cleaning up corner trapping */ +.ui-corner-all, +.ui-btn-corner-all { + -webkit-background-clip: padding; + background-clip: padding-box; +} +/* Overlay / modal +-----------------------------------------------------------------------------------------------------------*/ +.ui-overlay { + background: #666; + filter: Alpha(Opacity=50); + opacity: .5; + position: absolute; + width: 100%; + height: 100%; +} +.ui-overlay-shadow { + -moz-box-shadow: 0 0 12px rgba(0,0,0,.6); + -webkit-box-shadow: 0 0 12px rgba(0,0,0,.6); + box-shadow: 0 0 12px rgba(0,0,0,.6); +} +.ui-shadow { + -moz-box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/; + -webkit-box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/; + box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/ +} +.ui-bar-a .ui-shadow, +.ui-bar-b .ui-shadow , +.ui-bar-c .ui-shadow { + -moz-box-shadow: 0 1px 0 rgba(255,255,255,.3); + -webkit-box-shadow: 0 1px 0 rgba(255,255,255,.3); + box-shadow: 0 1px 0 rgba(255,255,255,.3); +} +.ui-shadow-inset { + -moz-box-shadow: inset 0 1px 4px rgba(0,0,0,.2); + -webkit-box-shadow: inset 0 1px 4px rgba(0,0,0,.2); + box-shadow: inset 0 1px 4px rgba(0,0,0,.2); +} +.ui-icon-shadow { + -moz-box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/; + -webkit-box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/; + box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/; +} +/* Focus state - set here for specificity (note: these classes are added by JavaScript) +-----------------------------------------------------------------------------------------------------------*/ +.ui-btn:focus, .ui-link-inherit:focus { + outline: 0; +} +.ui-btn.ui-focus { + z-index: 1; +} +.ui-focus, +.ui-btn:focus { + -moz-box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/; + -webkit-box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/; + box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/; +} +.ui-input-text.ui-focus, +.ui-input-search.ui-focus { + -moz-box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/; + -webkit-box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/; + box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/; +} +/* unset box shadow in browsers that don't do it right +-----------------------------------------------------------------------------------------------------------*/ +.ui-mobile-nosupport-boxshadow * { + -moz-box-shadow: none !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; +} +/* ...and bring back focus */ +.ui-mobile-nosupport-boxshadow .ui-focus, +.ui-mobile-nosupport-boxshadow .ui-btn:focus, +.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus { + outline-width: 1px; + outline-style: auto; +} + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/jquery.mobile.theme-1.3.2.min.css b/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/jquery.mobile.theme-1.3.2.min.css new file mode 100644 index 0000000000..4825a86e58 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/jquery.mobile.theme-1.3.2.min.css @@ -0,0 +1,12 @@ +/*! +* jQuery Mobile 1.3.2 +* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC +* http://jquerymobile.com +* +* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors +* Released under the MIT license. +* http://jquery.org/license +* +*/ + +.ui-bar-a{border:1px solid #b3b3b3 ;background:#eeeeee ;color:#3e3e3e ;font-weight:bold;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f0f0f0 ),to( #dddddd )); background-image:-webkit-linear-gradient( #f0f0f0,#dddddd ); background-image: -moz-linear-gradient( #f0f0f0,#dddddd ); background-image: -ms-linear-gradient( #f0f0f0,#dddddd ); background-image: -o-linear-gradient( #f0f0f0,#dddddd ); background-image: linear-gradient( #f0f0f0,#dddddd );}.ui-bar-a .ui-link-inherit{color:#3e3e3e ;}.ui-bar-a a.ui-link{color:#7cc4e7 ;font-weight:bold;}.ui-bar-a a.ui-link:visited{ color:#2489ce ;}.ui-bar-a a.ui-link:hover{color:#2489ce ;}.ui-bar-a a.ui-link:active{color:#2489ce ;}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{ font-family:Helvetica,Arial,sans-serif ;}.ui-body-a,.ui-overlay-a{border:1px solid #aaaaaa ;color:#333333 ;text-shadow:0 1px 0 #ffffff ;background:#f9f9f9 ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f9f9f9 ),to( #eeeeee )); background-image:-webkit-linear-gradient( #f9f9f9,#eeeeee ); background-image: -moz-linear-gradient( #f9f9f9,#eeeeee ); background-image: -ms-linear-gradient( #f9f9f9,#eeeeee ); background-image: -o-linear-gradient( #f9f9f9,#eeeeee ); background-image: linear-gradient( #f9f9f9,#eeeeee );}.ui-overlay-a{background-image:none;border-width:0;}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{ font-family:Helvetica,Arial,sans-serif ;}.ui-body-a .ui-link-inherit{color:#333333 ;}.ui-body-a .ui-link{color:#2489ce ;font-weight:bold;}.ui-body-a .ui-link:visited{ color:#2489ce ;}.ui-body-a .ui-link:hover{color:#2489ce ;}.ui-body-a .ui-link:active{color:#2489ce ;}.ui-btn-up-a{border:1px solid #cccccc ;background:#eeeeee ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #ffffff ),to( #f1f1f1 )); background-image:-webkit-linear-gradient( #ffffff,#f1f1f1 ); background-image: -moz-linear-gradient( #ffffff,#f1f1f1 ); background-image: -ms-linear-gradient( #ffffff,#f1f1f1 ); background-image: -o-linear-gradient( #ffffff,#f1f1f1 ); background-image: linear-gradient( #ffffff,#f1f1f1 );}.ui-btn-up-a:visited,.ui-btn-up-a a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-hover-a{border:1px solid #bbbbbb ;background:#dfdfdf ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f6f6f6 ),to( #e0e0e0 )); background-image:-webkit-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -moz-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -ms-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -o-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: linear-gradient( #f6f6f6,#e0e0e0 );}.ui-btn-hover-a:visited,.ui-btn-hover-a:hover,.ui-btn-hover-a a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-down-a{border:1px solid #bbbbbb ;background:#d6d6d6 ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #d0d0d0 ),to( #dfdfdf )); background-image:-webkit-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -moz-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -ms-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -o-linear-gradient( #d0d0d0,#dfdfdf ); background-image: linear-gradient( #d0d0d0,#dfdfdf );}.ui-btn-down-a:visited,.ui-btn-down-a:hover,.ui-btn-down-a a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{ font-family:Helvetica,Arial,sans-serif ;text-decoration:none;}.ui-bar-b{border:1px solid #b3b3b3 ;background:#eeeeee ;color:#3e3e3e ;font-weight:bold;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f0f0f0 ),to( #dddddd )); background-image:-webkit-linear-gradient( #f0f0f0,#dddddd ); background-image: -moz-linear-gradient( #f0f0f0,#dddddd ); background-image: -ms-linear-gradient( #f0f0f0,#dddddd ); background-image: -o-linear-gradient( #f0f0f0,#dddddd ); background-image: linear-gradient( #f0f0f0,#dddddd );}.ui-bar-b .ui-link-inherit{color:#3e3e3e ;}.ui-bar-b a.ui-link{color:#7cc4e7 ;font-weight:bold;}.ui-bar-b a.ui-link:visited{ color:#2489ce ;}.ui-bar-b a.ui-link:hover{color:#2489ce ;}.ui-bar-b a.ui-link:active{color:#2489ce ;}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{ font-family:Helvetica,Arial,sans-serif ;}.ui-body-b,.ui-overlay-b{border:1px solid #aaaaaa ;color:#333333 ;text-shadow:0 1px 0 #ffffff ;background:#f9f9f9 ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f9f9f9 ),to( #eeeeee )); background-image:-webkit-linear-gradient( #f9f9f9,#eeeeee ); background-image: -moz-linear-gradient( #f9f9f9,#eeeeee ); background-image: -ms-linear-gradient( #f9f9f9,#eeeeee ); background-image: -o-linear-gradient( #f9f9f9,#eeeeee ); background-image: linear-gradient( #f9f9f9,#eeeeee );}.ui-overlay-b{background-image:none;border-width:0;}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{ font-family:Helvetica,Arial,sans-serif ;}.ui-body-b .ui-link-inherit{color:#333333 ;}.ui-body-b .ui-link{color:#2489ce ;font-weight:bold;}.ui-body-b .ui-link:visited{ color:#2489ce ;}.ui-body-b .ui-link:hover{color:#2489ce ;}.ui-body-b .ui-link:active{color:#2489ce ;}.ui-btn-up-b{border:1px solid #cccccc ;background:#eeeeee ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #ffffff ),to( #f1f1f1 )); background-image:-webkit-linear-gradient( #ffffff,#f1f1f1 ); background-image: -moz-linear-gradient( #ffffff,#f1f1f1 ); background-image: -ms-linear-gradient( #ffffff,#f1f1f1 ); background-image: -o-linear-gradient( #ffffff,#f1f1f1 ); background-image: linear-gradient( #ffffff,#f1f1f1 );}.ui-btn-up-b:visited,.ui-btn-up-b a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-hover-b{border:1px solid #bbbbbb ;background:#dfdfdf ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f6f6f6 ),to( #e0e0e0 )); background-image:-webkit-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -moz-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -ms-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -o-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: linear-gradient( #f6f6f6,#e0e0e0 );}.ui-btn-hover-b:visited,.ui-btn-hover-b:hover,.ui-btn-hover-b a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-down-b{border:1px solid #bbbbbb ;background:#d6d6d6 ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #d0d0d0 ),to( #dfdfdf )); background-image:-webkit-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -moz-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -ms-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -o-linear-gradient( #d0d0d0,#dfdfdf ); background-image: linear-gradient( #d0d0d0,#dfdfdf );}.ui-btn-down-b:visited,.ui-btn-down-b:hover,.ui-btn-down-b a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-up-b,.ui-btn-hover-b,.ui-btn-down-b{ font-family:Helvetica,Arial,sans-serif ;text-decoration:none;}.ui-bar-c{border:1px solid #b3b3b3 ;background:#eeeeee ;color:#3e3e3e ;font-weight:bold;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f0f0f0 ),to( #dddddd )); background-image:-webkit-linear-gradient( #f0f0f0,#dddddd ); background-image: -moz-linear-gradient( #f0f0f0,#dddddd ); background-image: -ms-linear-gradient( #f0f0f0,#dddddd ); background-image: -o-linear-gradient( #f0f0f0,#dddddd ); background-image: linear-gradient( #f0f0f0,#dddddd );}.ui-bar-c .ui-link-inherit{color:#3e3e3e ;}.ui-bar-c a.ui-link{color:#7cc4e7 ;font-weight:bold;}.ui-bar-c a.ui-link:visited{ color:#2489ce ;}.ui-bar-c a.ui-link:hover{color:#2489ce ;}.ui-bar-c a.ui-link:active{color:#2489ce ;}.ui-bar-c,.ui-bar-c input,.ui-bar-c select,.ui-bar-c textarea,.ui-bar-c button{ font-family:Helvetica,Arial,sans-serif ;}.ui-body-c,.ui-overlay-c{border:1px solid #aaaaaa ;color:#333333 ;text-shadow:0 1px 0 #ffffff ;background:#f9f9f9 ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f9f9f9 ),to( #eeeeee )); background-image:-webkit-linear-gradient( #f9f9f9,#eeeeee ); background-image: -moz-linear-gradient( #f9f9f9,#eeeeee ); background-image: -ms-linear-gradient( #f9f9f9,#eeeeee ); background-image: -o-linear-gradient( #f9f9f9,#eeeeee ); background-image: linear-gradient( #f9f9f9,#eeeeee );}.ui-overlay-c{background-image:none;border-width:0;}.ui-body-c,.ui-body-c input,.ui-body-c select,.ui-body-c textarea,.ui-body-c button{ font-family:Helvetica,Arial,sans-serif ;}.ui-body-c .ui-link-inherit{color:#333333 ;}.ui-body-c .ui-link{color:#2489ce ;font-weight:bold;}.ui-body-c .ui-link:visited{ color:#2489ce ;}.ui-body-c .ui-link:hover{color:#2489ce ;}.ui-body-c .ui-link:active{color:#2489ce ;}.ui-btn-up-c{border:1px solid #cccccc ;background:#eeeeee ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #ffffff ),to( #f1f1f1 )); background-image:-webkit-linear-gradient( #ffffff,#f1f1f1 ); background-image: -moz-linear-gradient( #ffffff,#f1f1f1 ); background-image: -ms-linear-gradient( #ffffff,#f1f1f1 ); background-image: -o-linear-gradient( #ffffff,#f1f1f1 ); background-image: linear-gradient( #ffffff,#f1f1f1 );}.ui-btn-up-c:visited,.ui-btn-up-c a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-hover-c{border:1px solid #bbbbbb ;background:#dfdfdf ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f6f6f6 ),to( #e0e0e0 )); background-image:-webkit-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -moz-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -ms-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -o-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: linear-gradient( #f6f6f6,#e0e0e0 );}.ui-btn-hover-c:visited,.ui-btn-hover-c:hover,.ui-btn-hover-c a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-down-c{border:1px solid #bbbbbb ;background:#d6d6d6 ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #d0d0d0 ),to( #dfdfdf )); background-image:-webkit-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -moz-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -ms-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -o-linear-gradient( #d0d0d0,#dfdfdf ); background-image: linear-gradient( #d0d0d0,#dfdfdf );}.ui-btn-down-c:visited,.ui-btn-down-c:hover,.ui-btn-down-c a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c{ font-family:Helvetica,Arial,sans-serif ;text-decoration:none;}.ui-bar-d{border:1px solid #b3b3b3 ;background:#eeeeee ;color:#3e3e3e ;font-weight:bold;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f0f0f0 ),to( #dddddd )); background-image:-webkit-linear-gradient( #f0f0f0,#dddddd ); background-image: -moz-linear-gradient( #f0f0f0,#dddddd ); background-image: -ms-linear-gradient( #f0f0f0,#dddddd ); background-image: -o-linear-gradient( #f0f0f0,#dddddd ); background-image: linear-gradient( #f0f0f0,#dddddd );}.ui-bar-d .ui-link-inherit{color:#3e3e3e ;}.ui-bar-d a.ui-link{color:#7cc4e7 ;font-weight:bold;}.ui-bar-d a.ui-link:visited{ color:#2489ce ;}.ui-bar-d a.ui-link:hover{color:#2489ce ;}.ui-bar-d a.ui-link:active{color:#2489ce ;}.ui-bar-d,.ui-bar-d input,.ui-bar-d select,.ui-bar-d textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif ;}.ui-body-d,.ui-overlay-d{border:1px solid #aaaaaa ;color:#333333 ;text-shadow:0 1px 0 #ffffff ;background:#f9f9f9 ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f9f9f9 ),to( #eeeeee )); background-image:-webkit-linear-gradient( #f9f9f9,#eeeeee ); background-image: -moz-linear-gradient( #f9f9f9,#eeeeee ); background-image: -ms-linear-gradient( #f9f9f9,#eeeeee ); background-image: -o-linear-gradient( #f9f9f9,#eeeeee ); background-image: linear-gradient( #f9f9f9,#eeeeee );}.ui-overlay-d{background-image:none;border-width:0;}.ui-body-d,.ui-body-d input,.ui-body-d select,.ui-body-d textarea,.ui-body-d button{font-family:Helvetica,Arial,sans-serif ;}.ui-body-d .ui-link-inherit{color:#333333 ;}.ui-body-d .ui-link{color:#2489ce ;font-weight:bold;}.ui-body-d .ui-link:visited{ color:#2489ce ;}.ui-body-d .ui-link:hover{color:#2489ce ;}.ui-body-d .ui-link:active{color:#2489ce ;}.ui-btn-up-d{border:1px solid #cccccc ;background:#eeeeee ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #ffffff ),to( #f1f1f1 )); background-image:-webkit-linear-gradient( #ffffff,#f1f1f1 ); background-image: -moz-linear-gradient( #ffffff,#f1f1f1 ); background-image: -ms-linear-gradient( #ffffff,#f1f1f1 ); background-image: -o-linear-gradient( #ffffff,#f1f1f1 ); background-image: linear-gradient( #ffffff,#f1f1f1 );}.ui-btn-up-d:visited,.ui-btn-up-d a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-hover-d{border:1px solid #bbbbbb ;background:#dfdfdf ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f6f6f6 ),to( #e0e0e0 )); background-image:-webkit-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -moz-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -ms-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -o-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: linear-gradient( #f6f6f6,#e0e0e0 );}.ui-btn-hover-d:visited,.ui-btn-hover-d:hover,.ui-btn-hover-d a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-down-d{border:1px solid #bbbbbb ;background:#d6d6d6 ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #d0d0d0 ),to( #dfdfdf )); background-image:-webkit-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -moz-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -ms-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -o-linear-gradient( #d0d0d0,#dfdfdf ); background-image: linear-gradient( #d0d0d0,#dfdfdf );}.ui-btn-down-d:visited,.ui-btn-down-d:hover,.ui-btn-down-d a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d{font-family:Helvetica,Arial,sans-serif ;text-decoration:none;}.ui-bar-e{border:1px solid #b3b3b3 ;background:#eeeeee ;color:#3e3e3e ;font-weight:bold;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f0f0f0 ),to( #dddddd )); background-image:-webkit-linear-gradient( #f0f0f0,#dddddd ); background-image: -moz-linear-gradient( #f0f0f0,#dddddd ); background-image: -ms-linear-gradient( #f0f0f0,#dddddd ); background-image: -o-linear-gradient( #f0f0f0,#dddddd ); background-image: linear-gradient( #f0f0f0,#dddddd );}.ui-bar-e .ui-link-inherit{color:#3e3e3e ;}.ui-bar-e a.ui-link{color:#7cc4e7 ;font-weight:bold;}.ui-bar-e a.ui-link:visited{ color:#2489ce ;}.ui-bar-e a.ui-link:hover{color:#2489ce ;}.ui-bar-e a.ui-link:active{color:#2489ce ;}.ui-bar-e,.ui-bar-e input,.ui-bar-e select,.ui-bar-e textarea,.ui-bar-e button{font-family:Helvetica,Arial,sans-serif ;}.ui-body-e,.ui-overlay-e{border:1px solid #aaaaaa ;color:#333333 ;text-shadow:0 1px 0 #ffffff ;background:#f9f9f9 ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f9f9f9 ),to( #eeeeee )); background-image:-webkit-linear-gradient( #f9f9f9,#eeeeee ); background-image: -moz-linear-gradient( #f9f9f9,#eeeeee ); background-image: -ms-linear-gradient( #f9f9f9,#eeeeee ); background-image: -o-linear-gradient( #f9f9f9,#eeeeee ); background-image: linear-gradient( #f9f9f9,#eeeeee );}.ui-overlay-e{background-image:none;border-width:0;}.ui-body-e,.ui-body-e input,.ui-body-e select,.ui-body-e textarea,.ui-body-e button{font-family:Helvetica,Arial,sans-serif ;}.ui-body-e .ui-link-inherit{color:#333333 ;}.ui-body-e .ui-link{color:#2489ce ;font-weight:bold;}.ui-body-e .ui-link:visited{ color:#2489ce ;}.ui-body-e .ui-link:hover{color:#2489ce ;}.ui-body-e .ui-link:active{color:#2489ce ;}.ui-btn-up-e{border:1px solid #cccccc ;background:#eeeeee ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #ffffff ),to( #f1f1f1 )); background-image:-webkit-linear-gradient( #ffffff,#f1f1f1 ); background-image: -moz-linear-gradient( #ffffff,#f1f1f1 ); background-image: -ms-linear-gradient( #ffffff,#f1f1f1 ); background-image: -o-linear-gradient( #ffffff,#f1f1f1 ); background-image: linear-gradient( #ffffff,#f1f1f1 );}.ui-btn-up-e:visited,.ui-btn-up-e a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-hover-e{border:1px solid #bbbbbb ;background:#dfdfdf ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #f6f6f6 ),to( #e0e0e0 )); background-image:-webkit-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -moz-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -ms-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: -o-linear-gradient( #f6f6f6,#e0e0e0 ); background-image: linear-gradient( #f6f6f6,#e0e0e0 );}.ui-btn-hover-e:visited,.ui-btn-hover-e:hover,.ui-btn-hover-e a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-down-e{border:1px solid #bbbbbb ;background:#d6d6d6 ;font-weight:bold;color:#2f3e46 ;text-shadow:0 1px 0 #ffffff ;background-image:-webkit-gradient(linear,left top,left bottom,from( #d0d0d0 ),to( #dfdfdf )); background-image:-webkit-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -moz-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -ms-linear-gradient( #d0d0d0,#dfdfdf ); background-image: -o-linear-gradient( #d0d0d0,#dfdfdf ); background-image: linear-gradient( #d0d0d0,#dfdfdf );}.ui-btn-down-e:visited,.ui-btn-down-e:hover,.ui-btn-down-e a.ui-link-inherit{color:#2f3e46 ;}.ui-btn-up-e,.ui-btn-hover-e,.ui-btn-down-e{font-family:Helvetica,Arial,sans-serif ;text-decoration:none;}a.ui-link-inherit{text-decoration:none !important;}.ui-btn-active{border:1px solid #2373a5 ;background:#387bbe ;font-weight:bold;color:#ffffff ;cursor:pointer;text-shadow:0 1px 0 #3373a5 ;text-decoration:none;background-image:-webkit-gradient(linear,left top,left bottom,from( #5393c5 ),to( #6facd5 )); background-image:-webkit-linear-gradient( #5393c5,#6facd5 ); background-image: -moz-linear-gradient( #5393c5,#6facd5 ); background-image: -ms-linear-gradient( #5393c5,#6facd5 ); background-image: -o-linear-gradient( #5393c5,#6facd5 ); background-image: linear-gradient( #5393c5,#6facd5 ); font-family:Helvetica,Arial,sans-serif ;}.ui-btn-active:visited,.ui-btn-active:hover,.ui-btn-active a.ui-link-inherit{color:#ffffff ;}.ui-btn-inner{border-top:1px solid #fff;border-color:rgba(255,255,255,.3);}.ui-corner-all{-webkit-border-radius:0.3em ;border-radius:0.3em ;}.ui-br{border-color:rgb(130,130,130);border-color:rgba(130,130,130,.3);border-style:solid;}.ui-disabled{filter:Alpha(Opacity=30);opacity:.3;zoom:1;}.ui-disabled,.ui-disabled a{cursor:default !important;pointer-events:none;}.ui-icon,.ui-icon-searchfield:after{background:#666666 ;background:rgba(0,0,0,.4) ;background-image:url(images/icons-18-white.png) ;background-repeat:no-repeat;-webkit-border-radius:9px;border-radius:9px;}.ui-icon-alt .ui-icon,.ui-icon-alt .ui-icon-searchfield:after{background-color:#fff;background-color:rgba(255,255,255,.3);background-image:url(images/icons-18-black.png);background-repeat:no-repeat;}.ui-icon-nodisc .ui-icon,.ui-icon-nodisc .ui-icon-searchfield:after,.ui-icon-nodisc .ui-icon-alt .ui-icon,.ui-icon-nodisc .ui-icon-alt .ui-icon-searchfield:after{background-color:transparent;}.ui-icon-plus{background-position:-1px -1px;}.ui-icon-minus{background-position:-37px -1px;}.ui-icon-delete{background-position:-73px -1px;}.ui-icon-arrow-r{background-position:-108px -1px;}.ui-icon-arrow-l{background-position:-144px -1px;}.ui-icon-arrow-u{background-position:-180px -1px;}.ui-icon-arrow-d{background-position:-216px -1px;}.ui-icon-check{background-position:-252px -1px;}.ui-icon-gear{background-position:-288px -1px;}.ui-icon-refresh{background-position:-323px -1px;}.ui-icon-forward{background-position:-360px -1px;}.ui-icon-back{background-position:-396px -1px;}.ui-icon-grid{background-position:-432px -1px;}.ui-icon-star{background-position:-467px -1px;}.ui-icon-alert{background-position:-503px -1px;}.ui-icon-info{background-position:-539px -1px;}.ui-icon-home{background-position:-575px -1px;}.ui-icon-search,.ui-icon-searchfield:after{background-position:-611px -1px;}.ui-icon-checkbox-on{background-position:-647px -1px;}.ui-icon-checkbox-off{background-position:-683px -1px;}.ui-icon-radio-on{background-position:-718px -1px;}.ui-icon-radio-off{background-position:-754px -1px;}.ui-icon-bars{background-position:-788px -1px;}.ui-icon-edit{background-position:-824px -1px;}@media only screen and (-webkit-min-device-pixel-ratio:1.3), only screen and (min--moz-device-pixel-ratio:1.3), only screen and (min-resolution:200dpi){.ui-icon-plus,.ui-icon-minus,.ui-icon-delete,.ui-icon-arrow-r,.ui-icon-arrow-l,.ui-icon-arrow-u,.ui-icon-arrow-d,.ui-icon-check,.ui-icon-gear,.ui-icon-refresh,.ui-icon-forward,.ui-icon-back,.ui-icon-grid,.ui-icon-star,.ui-icon-alert,.ui-icon-info,.ui-icon-home,.ui-icon-bars,.ui-icon-edit,.ui-icon-search,.ui-icon-searchfield:after,.ui-icon-checkbox-off,.ui-icon-checkbox-on,.ui-icon-radio-off,.ui-icon-radio-on{background-image:url(images/icons-36-white.png);-moz-background-size:864px 18px;-o-background-size:864px 18px;-webkit-background-size:864px 18px;background-size:864px 18px;}.ui-icon-alt .ui-icon{background-image:url(images/icons-36-black.png);}.ui-icon-plus{background-position:0 50%;}.ui-icon-minus{background-position:-36px 50%;}.ui-icon-delete{background-position:-72px 50%;}.ui-icon-arrow-r{background-position:-108px 50%;}.ui-icon-arrow-l{background-position:-144px 50%;}.ui-icon-arrow-u{background-position:-179px 50%;}.ui-icon-arrow-d{background-position:-215px 50%;}.ui-icon-check{background-position:-252px 50%;}.ui-icon-gear{background-position:-287px 50%;}.ui-icon-refresh{background-position:-323px 50%;}.ui-icon-forward{background-position:-360px 50%;}.ui-icon-back{background-position:-395px 50%;}.ui-icon-grid{background-position:-431px 50%;}.ui-icon-star{background-position:-467px 50%;}.ui-icon-alert{background-position:-503px 50%;}.ui-icon-info{background-position:-538px 50%;}.ui-icon-home{background-position:-575px 50%;}.ui-icon-search,.ui-icon-searchfield:after{background-position:-611px 50%;}.ui-icon-checkbox-on{background-position:-647px 50%;}.ui-icon-checkbox-off{background-position:-683px 50%;}.ui-icon-radio-on{background-position:-718px 50%;}.ui-icon-radio-off{background-position:-754px 50%;}.ui-icon-bars{background-position:-788px 50%;}.ui-icon-edit{background-position:-824px 50%;}}.ui-checkbox .ui-icon,.ui-selectmenu-list .ui-icon{-webkit-border-radius:3px;border-radius:3px;}.ui-icon-checkbox-off,.ui-icon-radio-off{background-color:transparent;}.ui-checkbox-on .ui-icon,.ui-radio-on .ui-icon{background-color:#387bbe ; }.ui-icon-loading{background:url(images/ajax-loader.gif);background-size:46px 46px;}.ui-btn-corner-all{-webkit-border-radius:0.4em ;border-radius:0.4em ;}.ui-corner-all,.ui-btn-corner-all{-webkit-background-clip:padding;background-clip:padding-box;}.ui-overlay{background:#666;filter:Alpha(Opacity=50);opacity:.5;position:absolute;width:100%;height:100%;}.ui-overlay-shadow{-moz-box-shadow:0 0 12px rgba(0,0,0,.6);-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6);}.ui-shadow{-moz-box-shadow:0 1px 3px rgba(0,0,0,.2) ;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.2) ;box-shadow:0 1px 3px rgba(0,0,0,.2) }.ui-bar-a .ui-shadow,.ui-bar-b .ui-shadow,.ui-bar-c .ui-shadow {-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3);}.ui-shadow-inset{-moz-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);box-shadow:inset 0 1px 4px rgba(0,0,0,.2);}.ui-icon-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.4) ;-webkit-box-shadow:0 1px 0 rgba(255,255,255,.4) ;box-shadow:0 1px 0 rgba(255,255,255,.4) ;}.ui-btn:focus,.ui-link-inherit:focus{outline:0;}.ui-btn.ui-focus{z-index:1;}.ui-focus,.ui-btn:focus{-moz-box-shadow:inset 0 0 3px #387bbe,0 0 9px #387bbe ;-webkit-box-shadow:inset 0 0 3px #387bbe,0 0 9px #387bbe ;box-shadow:inset 0 0 3px #387bbe,0 0 9px #387bbe ;}.ui-input-text.ui-focus,.ui-input-search.ui-focus{-moz-box-shadow:0 0 12px #387bbe ;-webkit-box-shadow:0 0 12px #387bbe ;box-shadow:0 0 12px #387bbe ;}.ui-mobile-nosupport-boxshadow *{-moz-box-shadow:none !important;-webkit-box-shadow:none !important;box-shadow:none !important;}.ui-mobile-nosupport-boxshadow .ui-focus,.ui-mobile-nosupport-boxshadow .ui-btn:focus,.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus{outline-width:1px;outline-style:auto;} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/user.css b/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/user.css new file mode 100644 index 0000000000..cffe7dcfd7 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/MobileLight/Content/user.css @@ -0,0 +1,10 @@ +/* +// Customize the (child) theme here with css overrides +// or new selectors (for users) +// -------------------------------------------------- +*/ + +.legal-hints { + background: none !important; + border-bottom: 1px solid #aaa !important; +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/MobileLight/Views/Web.config b/src/Presentation/SmartStore.Web/Themes/MobileLight/Views/Web.config new file mode 100644 index 0000000000..bd9d09444f --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/MobileLight/Views/Web.config @@ -0,0 +1,40 @@ + + + + + +
                      +
                      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Presentation/SmartStore.Web/Themes/MobileLight/preview.png b/src/Presentation/SmartStore.Web/Themes/MobileLight/preview.png new file mode 100644 index 0000000000..0139e74853 Binary files /dev/null and b/src/Presentation/SmartStore.Web/Themes/MobileLight/preview.png differ diff --git a/src/Presentation/SmartStore.Web/Themes/MobileLight/theme.config b/src/Presentation/SmartStore.Web/Themes/MobileLight/theme.config new file mode 100644 index 0000000000..4712434fa8 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/MobileLight/theme.config @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/Web.config b/src/Presentation/SmartStore.Web/Themes/Web.config new file mode 100644 index 0000000000..c182d25b01 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Themes/Web.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Themes/print.css b/src/Presentation/SmartStore.Web/Themes/print.css deleted file mode 100644 index 1c3d1b55ee..0000000000 --- a/src/Presentation/SmartStore.Web/Themes/print.css +++ /dev/null @@ -1,33 +0,0 @@ -.foo{} - -body,h1,h2,h3,h4,h5,h6,address,blockquote,dd,dl,hr,form,input{margin:0;padding:0;} -body{font-family:arial, verdana, helvetica, sans-serif;font-size:12px;text-align:center;} - -.nobr{white-space:nowrap!important;} -.wrap{ white-space:normal!important;} -.a-left{text-align:left!important;} -.a-center{text-align:center!important;} -.a-right{text-align:right!important;} -.section-title{padding:10px 10px 5px 0;font-weight:700;clear:both;} -/* data table */ -.data-table{width:100%;border:1px solid;border-collapse:collapse;border-spacing:0;empty-cells:show;} -.data-table th{font-weight:bold;padding:3px 8px;white-space:nowrap;vertical-align:middle;} -.data-table td{padding:3px 8px;} -.data-table th,.data-table td{border-bottom:1px solid;border-right:1px solid;} -.data-table .odd{} -.data-table .even{background-color: #F4FAFF;} - -.cart-total-left{width:100%;text-align:right;vertical-align:middle;height:21px;font-weight:700;color:#353434;} -.cart-total-left-below{width:100%;text-align:right;vertical-align:top;height:30px;} -.cart-total-right{text-align:right;vertical-align:middle;padding-left:5px;} - -.order-details{margin-bottom:15px;padding:0;} -.order-details .page-body{border:1px solid #d7d7d7;padding:10px;} -.order-details .order-overview{text-align:left;padding-bottom:10px;} -.order-details .order-overview .order-total-top{text-align:right;} -.order-details .order-details-box{text-align:left;padding:10px;border:1px solid #d7d7d7;height:auto;} -.order-details .order-overview .order-overview-table, .order-details .order-details-box .order-details-table{width:100%;border:0px;border-collapse:collapse;border-spacing:0;} -.order-details .order-details-box .order-details-table .billinginfo,.order-details .order-details-box .order-details-table .shippinginfo{width:50%;vertical-align:top;} -.order-details .products-box,.order-details .ordernotes-box{text-align:left;padding:10px;border:1px solid #d7d7d7;height:auto;} -.order-details .checkout-attributes{text-align:right;vertical-align:middle;padding:10px;height:auto;} -.order-details .cart-total-left{color:#000;} diff --git a/src/Presentation/SmartStore.Web/Validators/Common/AddressValidator.cs b/src/Presentation/SmartStore.Web/Validators/Common/AddressValidator.cs index a2fa7b5c7a..6b26e7ef0e 100644 --- a/src/Presentation/SmartStore.Web/Validators/Common/AddressValidator.cs +++ b/src/Presentation/SmartStore.Web/Validators/Common/AddressValidator.cs @@ -59,6 +59,15 @@ public AddressValidator(ILocalizationService localizationService, AddressSetting { RuleFor(x => x.FaxNumber).NotEmpty().WithMessage(localizationService.GetResource("Account.Fields.Fax.Required")); } + if (addressSettings.ValidateEmailAddress) + { + RuleFor(x => x.EmailMatch) + .NotEmpty() + .WithMessage(localizationService.GetResource("Admin.Address.Fields.EmailMatch.Required")) + .Equal(x => x.Email) + .WithMessage(localizationService.GetResource("Admin.Address.Fields.EmailMatch.MustMatchEmail")); + } + } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Validators/Common/ContactUsValidator.cs b/src/Presentation/SmartStore.Web/Validators/Common/ContactUsValidator.cs index 7e9b037037..9e42f7ed02 100644 --- a/src/Presentation/SmartStore.Web/Validators/Common/ContactUsValidator.cs +++ b/src/Presentation/SmartStore.Web/Validators/Common/ContactUsValidator.cs @@ -8,6 +8,11 @@ public class ContactUsValidator : AbstractValidator { public ContactUsValidator(ILocalizationService localizationService) { + RuleFor(x => x.PrivacyAgreement) + .Must(x => x == true) + .WithMessage(localizationService.GetResource("ContactUs.PrivacyAgreement.MustBeAccepted")) + .When(x => x.DisplayPrivacyAgreement == true); + RuleFor(x => x.Email).NotEmpty().WithMessage(localizationService.GetResource("ContactUs.Email.Required")); RuleFor(x => x.Email).EmailAddress().WithMessage(localizationService.GetResource("Common.WrongEmail")); RuleFor(x => x.FullName).NotEmpty().WithMessage(localizationService.GetResource("ContactUs.FullName.Required")); diff --git a/src/Presentation/SmartStore.Web/Validators/Customer/RegisterValidator.cs b/src/Presentation/SmartStore.Web/Validators/Customer/RegisterValidator.cs index b04dd7468b..3c9516c656 100644 --- a/src/Presentation/SmartStore.Web/Validators/Customer/RegisterValidator.cs +++ b/src/Presentation/SmartStore.Web/Validators/Customer/RegisterValidator.cs @@ -1,5 +1,6 @@ using FluentValidation; using SmartStore.Core.Domain.Customers; +using SmartStore.Core.Domain.Tax; using SmartStore.Services.Localization; using SmartStore.Web.Models.Customer; @@ -7,7 +8,7 @@ namespace SmartStore.Web.Validators.Customer { public class RegisterValidator : AbstractValidator { - public RegisterValidator(ILocalizationService localizationService, CustomerSettings customerSettings) + public RegisterValidator(ILocalizationService localizationService, CustomerSettings customerSettings, TaxSettings taxSettings) { RuleFor(x => x.Email).NotEmpty().WithMessage(localizationService.GetResource("Account.Fields.Email.Required")); RuleFor(x => x.Email).EmailAddress().WithMessage(localizationService.GetResource("Common.WrongEmail")); @@ -50,6 +51,11 @@ public RegisterValidator(ILocalizationService localizationService, CustomerSetti { RuleFor(x => x.Fax).NotEmpty().WithMessage(localizationService.GetResource("Account.Fields.Fax.Required")); } + + if (taxSettings.EuVatEnabled && taxSettings.VatRequired) + { + RuleFor(x => x.VatNumber).NotEmpty().WithMessage(localizationService.GetResource("Account.Fields.Vat.Required")); + } } } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Validators/Install/InstallValidator.cs b/src/Presentation/SmartStore.Web/Validators/Install/InstallValidator.cs index 0d1d042e9f..c7fc19f99b 100644 --- a/src/Presentation/SmartStore.Web/Validators/Install/InstallValidator.cs +++ b/src/Presentation/SmartStore.Web/Validators/Install/InstallValidator.cs @@ -14,7 +14,6 @@ public InstallValidator(IInstallationLocalizationService locService) RuleFor(x => x.ConfirmPassword).NotEmpty().WithMessage(locService.GetResource("ConfirmPasswordRequired")); RuleFor(x => x.AdminPassword).Equal(x => x.ConfirmPassword).WithMessage(locService.GetResource("PasswordsDoNotMatch")); RuleFor(x => x.DataProvider).NotEmpty().WithMessage(locService.GetResource("DataProviderRequired")); - // codehint: sm-add RuleFor(x => x.PrimaryLanguage).NotEmpty().WithMessage(locService.GetResource("PrimaryLanguageRequired")); } } diff --git a/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.Mobile.cshtml index e061a76a21..3c49bafc7a 100644 --- a/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.Mobile.cshtml @@ -50,13 +50,6 @@ @Html.TextAreaFor(model => model.AddNewComment.CommentText) @Html.ValidationMessageFor(model => model.AddNewComment.CommentText) - string result = TempData["sm.blog.addcomment.result"] as string; - if (!String.IsNullOrEmpty(result)) - { -
                      - @result -
                      - }
                      @Html.ValidationSummary(true)
                      @@ -85,11 +78,11 @@
                      diff --git a/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.cshtml b/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.cshtml index bf47fbdf46..02b64785ba 100644 --- a/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Blog/BlogPost.cshtml @@ -38,7 +38,7 @@ @if (Model.Tags.Count > 0) {
                      - + @for (int i = 0, length = Model.Tags.Count; i < length; i++) { var tag = Model.Tags[i]; @@ -56,27 +56,13 @@ @using (Html.BeginForm()) {
                      - @if (!ViewData.ModelState.IsValid) - { - @Html.ValidationSummary(true) - } - @{ - string result = TempData["sm.blog.addcomment.result"] as string; - } - @if (!String.IsNullOrEmpty(result)) - { -
                      - - @result -
                      - } + @Html.ValidationSummary()
                      @Html.LabelFor(model => model.AddNewComment.CommentText)
                      @Html.TextAreaFor(model => model.AddNewComment.CommentText, new { @class = "comment-text" })
                      - @Html.ValidationMessageFor(model => model.AddNewComment.CommentText)
                      @if (Model.AddNewComment.DisplayCaptcha) { @@ -88,7 +74,7 @@
                      @@ -120,7 +106,7 @@
                      @if (comment.AllowViewingProfiles) { - @(comment.CustomerName) + @(comment.CustomerName) } else { diff --git a/src/Presentation/SmartStore.Web/Views/Blog/List.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Blog/List.Mobile.cshtml index 25f6536419..22744d5602 100644 --- a/src/Presentation/SmartStore.Web/Views/Blog/List.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Blog/List.Mobile.cshtml @@ -1,6 +1,5 @@ @model BlogPostListModel @using SmartStore.Web; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Models.Blogs; @using SmartStore.Web.Framework.UI; @{ diff --git a/src/Presentation/SmartStore.Web/Views/Blog/List.cshtml b/src/Presentation/SmartStore.Web/Views/Blog/List.cshtml index 27f09130b0..ea9ef5b10c 100644 --- a/src/Presentation/SmartStore.Web/Views/Blog/List.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Blog/List.cshtml @@ -1,6 +1,5 @@ @model BlogPostListModel @using SmartStore.Web; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Models.Blogs; @using SmartStore.Web.Framework.UI; @{ @@ -16,7 +15,7 @@
                      - + @T("Blog.RSS")

                      @@ -53,7 +52,7 @@ href="@Url.RouteUrl("BlogPost", new { SeName = item.SeName })" title="@string.Format(@T("Blog.CommentsLink").Text, item.NumberOfComments)" rel="tooltip"> - + @item.NumberOfComments } @@ -65,7 +64,7 @@ @if (item.Tags.Count > 0) {
                      - + @for (int i = 0, length = item.Tags.Count; i < length; i++) { var tag = item.Tags[i]; diff --git a/src/Presentation/SmartStore.Web/Views/Boards/Forum.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Boards/Forum.Mobile.cshtml index 7f3fcf6b9e..5375ecbf56 100644 --- a/src/Presentation/SmartStore.Web/Views/Boards/Forum.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Boards/Forum.Mobile.cshtml @@ -4,7 +4,6 @@ @using SmartStore.Services.Forums; @using SmartStore.Services.Seo; @using SmartStore.Web; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Models; @using SmartStore.Web.Models.Boards; @using SmartStore.Web.Models.Common; @@ -25,7 +24,7 @@ @Model.Description

                      @@ -35,7 +34,7 @@ var pager = Html.SmartStore().Pager(Model.TopicPageIndex, Model.TopicPageSize, Model.TopicTotalRecords) .Name("paginator") .ShowSummary(false) - .Route("ForumSlugPaged", new RouteValues { id = Model.Id, slug = Model.SeName }) + .Route("ForumSlug", new RouteValues { id = Model.Id, slug = Model.SeName }) .Alignment(PagerAlignment.Right); } @pager @@ -97,7 +96,7 @@ $.ajax({ cache: false, type: 'POST', - url: '@Url.RouteUrl("ForumWatch", new { id = @Model.Id })', + url: '@Url.Action("ForumWatch", new { id = @Model.Id })', dataType: 'json', success: function (data) { $('#watch-forum').val(data.Text); diff --git a/src/Presentation/SmartStore.Web/Views/Boards/Forum.cshtml b/src/Presentation/SmartStore.Web/Views/Boards/Forum.cshtml index cd2974e7eb..360904b263 100644 --- a/src/Presentation/SmartStore.Web/Views/Boards/Forum.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Boards/Forum.cshtml @@ -4,7 +4,6 @@ @using SmartStore.Services.Forums; @using SmartStore.Services.Seo; @using SmartStore.Web; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Models; @using SmartStore.Web.Models.Boards; @using SmartStore.Web.Models.Common; @@ -13,21 +12,19 @@ Layout = "~/Views/Shared/_ColumnsOne.cshtml"; Html.AddTitleParts(Model.Name); + Html.AddMetaDescriptionParts(Model.Name); } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/ProductTemplate.Simple.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/ProductTemplate.Simple.Mobile.cshtml deleted file mode 100644 index c64859f49f..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/ProductTemplate.Simple.Mobile.cshtml +++ /dev/null @@ -1,151 +0,0 @@ -@model ProductDetailsModel -@using SmartStore.Core.Domain.Catalog; -@using SmartStore.Web.Models.Catalog; -@using SmartStore.Web.Extensions; -@{ - Layout = "~/Views/Shared/_Root.cshtml"; - - Html.AddTitleParts(!String.IsNullOrEmpty(Model.MetaTitle) ? Model.MetaTitle : Model.Name); -} - -@helper BundleProducts() -{ - foreach (var item in Model.BundledItems.Where(x => x.BundleItem.Visible)) - { -
                      -
                      - @if (item.VisibleIndividually) - { - @item.Name - } - else - { - @item.Name - } - @if (item.BundleItem.Quantity > 1) - { - - × @item.BundleItem.Quantity - - } -
                      - @if (!String.IsNullOrWhiteSpace(item.StockAvailability)) - { -
                      - @T("Products.Availability"): @item.StockAvailability -
                      - } - @if (!String.IsNullOrWhiteSpace(item.ProductPrice.PriceWithDiscount)) - { -
                      - @Html.Raw(item.ProductPrice.PriceWithDiscount) -
                      - } - @if (!String.IsNullOrEmpty(item.AttributeInfo)) - { -
                      - @Html.Raw(item.AttributeInfo) -
                      - } - - @if (item.ProductVariantAttributes.ShouldBeRendered()) - { - - } -
                      - } -} - -
                      -
                      - @Html.Widget("mobile_productdetails_top") - @*we add enctype = "multipart/form-data" because "File upload" attribute control type requries it*@ - @using (Html.BeginRouteForm("Product", new { SeName = Model.SeName }, FormMethod.Post, new { enctype = "multipart/form-data", id = "product-details-form" })) - { -
                      -
                      -

                      - @Model.Name -

                      -
                      - @Html.Raw(Model.ShortDescription) -
                      - @Html.Widget("mobile_productdetails_before_pictures") - - @Html.Widget("mobile_productdetails_after_pictures") - @Html.Action("ProductManufacturers", "Catalog", new { productId = Model.Id }) - @Html.Action("ProductReviewOverview", "Catalog", new { productId = Model.Id }) - @Html.Action("ProductEmailAFriendButton", "Catalog", new { productId = Model.Id }) - @Html.Action("CompareProductsButton", "Catalog", new { productId = Model.Id }) -
                      - @if (Model.ProductType == ProductType.BundledProduct) - { -
                      - @if (Model.RenderBundleTitle()) - { -
                      -

                      @Model.BundleTitleText

                      -
                      - } -
                      - @BundleProducts() -
                      - @if (Model.BundledItems.Where(x => x.BundleItem.Visible).Count() == 0) - { -
                      @T("Products.NoBundledItems")
                      - } -
                      - } -
                      - @Html.Raw(Html.CollapsedText(Model.FullDescription)) -
                      -
                      -
                      -
                      -
                      - @Html.Partial("_DownloadSample", Model) - @Html.Action("ProductTierPrices", "Catalog", new { productId = Model.Id }) - @if (Model.ProductType != ProductType.BundledProduct && Model.ProductVariantAttributes.ShouldBeRendered()) - { - var dataDictAttributes = new ViewDataDictionary(); - dataDictAttributes.TemplateInfo.HtmlFieldPrefix = string.Format("attributes_{0}", Model.Id); - @Html.Partial("_ProductAttributes", Model.ProductVariantAttributes, dataDictAttributes) - } - - @Html.Partial("_SKU_Man_Stock", Model) - - @Html.Partial("_BackInStockSubscription", Model) - @{ - var dataDictGiftCard = new ViewDataDictionary(); - dataDictGiftCard.TemplateInfo.HtmlFieldPrefix = string.Format("giftcard_{0}_0", Model.Id); - @Html.Partial("_GiftCardInfo", Model.GiftCard, dataDictGiftCard) - } - @{ - var dataDictPrice = new ViewDataDictionary(); - dataDictPrice.TemplateInfo.HtmlFieldPrefix = string.Format("price_{0}", Model.Id); - @Html.Partial("_ProductPrice", Model.ProductPrice, dataDictPrice) - } - @{ - var dataDictAddToCart = new ViewDataDictionary(); - dataDictAddToCart.TemplateInfo.HtmlFieldPrefix = string.Format("addtocart_{0}", Model.Id); - @Html.Partial("_AddToCart", Model.AddToCart, dataDictAddToCart) - } -
                      -
                      - @Html.Action("ProductSpecifications", "Catalog", new { productId = Model.Id }) -
                      -
                      - @Html.Action("ProductTags", "Catalog", new { productId = Model.Id }) -
                      -
                      - @Html.Action("ProductsAlsoPurchased", "Catalog", new { productId = Model.Id }) - @Html.Action("RelatedProducts", "Catalog", new { productId = Model.Id }) -
                      - } - @Html.Widget("mobile_productdetails_bottom") -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.Mobile.cshtml index 37317f1a21..891021bb1b 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.Mobile.cshtml @@ -10,7 +10,6 @@ @using SmartStore.Core.Infrastructure; @using SmartStore.Web; @using SmartStore.Web.Models.Catalog; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Framework.UI; @*product search box*@ @Html.Action("SearchBox", "Catalog") diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.cshtml index 49a0816834..0672cda4e3 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/ProductsByTag.cshtml @@ -4,7 +4,7 @@ @using SmartStore.Web.Models.Catalog; @using SmartStore.Web; @using SmartStore.Web.Models.Catalog; -@using SmartStore.Web.Extensions; +@using SmartStore.Web; @using SmartStore.Web.Framework.UI; @using SmartStore.Core.Domain.Seo; diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.Mobile.cshtml index 34bcc4772a..1f19e9cadf 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.Mobile.cshtml @@ -1,4 +1,4 @@ -@model IList +@model RecentlyAddedProductsModel @{ Layout = "~/Views/Shared/_Root.cshtml"; @@ -13,11 +13,11 @@

                      @T("Products.NewProducts")

                      - @if (Model.Count > 0) + @if (Model.Products.Count > 0) {
                        - @foreach (var product in Model) + @foreach (var product in Model.Products) {
                      • @Html.Partial("_ProductBox", product) diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml index db5b531560..f4aa453cce 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyAddedProducts.cshtml @@ -1,5 +1,4 @@ -@*codehint: sm-edit*@ -@model RecentlyAddedProductsModel +@model RecentlyAddedProductsModel @{ Layout = "~/Views/Shared/_ColumnsThree.cshtml"; @@ -13,27 +12,18 @@ @using SmartStore.Core.Domain.Catalog; @using SmartStore.Web.Framework.UI; -@*@functions{ - private bool ShowListOptions() { - return Model.Products.Count > 0 && - (Model.PagingFilteringContext.AllowProductViewModeChanging || - Model.PagingFilteringContext.AllowProductSorting || - Model.PagingFilteringContext.AllowCustomersToSelectPageSize); - } -}*@ -
                        -
                        -
                        + +
                        +
                        - - @*@if (ShowListOptions()) { - @Html.Partial("_ProductListOptions", Model.PagingFilteringContext) - }*@ @if (Model.Products.Count > 0) { @@ -65,7 +55,5 @@
                        - @*@Html.SmartStore().Pager(Model.PagingFilteringContext).Name("pagination-bottom").QueryParam("pagenumber")*@ -
                        diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyViewedProductsBlock.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyViewedProductsBlock.cshtml index 19d35797c0..d374c9044b 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyViewedProductsBlock.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/RecentlyViewedProductsBlock.cshtml @@ -1,5 +1,4 @@ -@*codehint: sm-edit nearly completly*@ -@model IList +@model IList @using SmartStore.Core; @using SmartStore.Core.Infrastructure; @using SmartStore.Web.Models.Catalog; @@ -27,8 +26,11 @@
                      • - - @product.DefaultPictureModel.AlternateText + @if (product.DefaultPictureModel.ImageUrl.HasValue()) + { + + @product.DefaultPictureModel.AlternateText + }
                        @product.Name diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/Search.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/Search.Mobile.cshtml index ca3b6f0b97..3dc10f951c 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/Search.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/Search.Mobile.cshtml @@ -3,7 +3,6 @@ @using SmartStore.Core.Infrastructure; @using SmartStore.Web; @using SmartStore.Web.Models.Catalog; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Framework.UI; @{ diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/Search.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/Search.cshtml index 6b06eca415..8809946c25 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/Search.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/Search.cshtml @@ -1,16 +1,11 @@ -@model SearchModel +@using SmartStore.Web.Models.Catalog; +@using SmartStore.Web.Framework.UI; +@model SearchModel @{ Layout = "~/Views/Shared/_ColumnsThree.cshtml"; - //title Html.AddTitleParts(T("PageTitle.Search").Text); } -@using SmartStore.Core; -@using SmartStore.Core.Infrastructure; -@using SmartStore.Web; -@using SmartStore.Web.Models.Catalog; -@using SmartStore.Web.Extensions; -@using SmartStore.Web.Framework.UI; @functions{ private bool ShowListOptions() { @@ -33,11 +28,12 @@ - @*codehint: sm-edit begin *@ - @if (!String.IsNullOrEmpty(Model.Warning)) {
                        @@ -75,7 +69,7 @@
                      - diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.Mobile.cshtml index cb047ff5a5..b1b4ae70d4 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.Mobile.cshtml @@ -1,8 +1,8 @@  \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.cshtml index bfe6dad16f..18ccaf58ff 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/SearchBox.cshtml @@ -1,59 +1,26 @@ @model SearchBoxModel @using SmartStore.Web.Models.Catalog; - @using (Html.BeginRouteForm("ProductSearch", FormMethod.Get, new { onsubmit = "return check_small_search_form()", @class = "form-search pull-right" })) - { -
                      - - - -
                      - - @Html.Widget("searchbox") - } \ No newline at end of file +@using (Html.BeginRouteForm("ProductSearch", FormMethod.Get, new { @class = "form-search pull-right" })) +{ +
                      + + +
                      + @Html.Widget("searchbox") +} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_AddToCart.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_AddToCart.Mobile.cshtml deleted file mode 100644 index 3e7b90de81..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_AddToCart.Mobile.cshtml +++ /dev/null @@ -1,45 +0,0 @@ -@model ProductDetailsModel.AddToCartModel -@using SmartStore.Web.Models.Catalog; -
                      - @if (Model.CustomerEntersPrice) - { -
                      -
                      - @Html.LabelFor(model => model.CustomerEnteredPrice, new { @class = "enter-price-label" }) - @*round price*@ - @Html.TextBox("CustomerEnteredPrice", Convert.ToInt32(Math.Ceiling(Model.CustomerEnteredPrice)), new { @class = "enter-price-input" }) -
                      -
                      - @Model.CustomerEnteredPriceRange -
                      -
                      - } - @if (!Model.DisableBuyButton || !Model.DisableWishlistButton) - { -
                      - @if (Model.AllowedQuantities.Count > 0) - { -
                      -
                      - @Html.LabelFor(model => model.EnteredQuantity, new { @class = "qty-label" }) - @Html.DropDownListFor(model => model.EnteredQuantity, Model.AllowedQuantities, new { @class = "qty-dropdown" }) -
                      -
                      - } - else - { - @Html.LabelFor(model => model.EnteredQuantity, new { @class = "qty-label" }) - @Html.TextBoxFor(model => model.EnteredQuantity, new { @class = "qty-input" }) - } -
                      - if (!Model.DisableBuyButton) - { - - } - if (!Model.DisableWishlistButton) - { - - } - } - @Html.Widget("mobile_productdetails_add_info") -
                      diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_AddToCart.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_AddToCart.cshtml deleted file mode 100644 index 7b82fc3f58..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_AddToCart.cshtml +++ /dev/null @@ -1,136 +0,0 @@ -@model ProductDetailsModel -@using SmartStore.Web.Models.Catalog; -@using SmartStore.Core.Domain.Orders; -@using System.Globalization; -@using System.Text.RegularExpressions; - - @if (Model.AddToCart.CustomerEntersPrice) - { -
                      - @Html.LabelFor(model => Model.AddToCart.CustomerEnteredPrice, new { @class = "enter-price-label" }) - @*round price*@ - @Html.TextBox("CustomerEnteredPrice", Convert.ToInt32(Math.Ceiling(Model.AddToCart.CustomerEnteredPrice)), new { @class = "enter-price-input" }) -
                      - @Model.AddToCart.CustomerEnteredPriceRange -
                      -
                      - } - - @if (!Model.AddToCart.DisableBuyButton || !Model.AddToCart.DisableWishlistButton) - { -
                      - @if(!Model.ProductPrice.CallForPrice) - { -
                      - -
                      - @if (!String.IsNullOrWhiteSpace(Model.ProductPrice.OldPrice)) - { - @T("Products.Price.OldPrice"): - @Html.Raw(Model.ProductPrice.OldPrice) -
                      - } - - @Html.Raw(Model.ProductPrice.NoteWithoutDiscount) - - class="product-price current text-success" - } - > - - @if (!String.IsNullOrWhiteSpace(Model.ProductPrice.Price)) - { - @Html.Raw(Model.ProductPrice.Price) - } - - -
                      - -
                      - @if (!String.IsNullOrWhiteSpace(Model.ProductPrice.OldPrice)) - { -
                      - } - @Html.Raw(Model.ProductPrice.NoteWithDiscount) - - - - @if (!String.IsNullOrWhiteSpace(Model.ProductPrice.PriceWithDiscount)) - { - @Html.Raw(Model.ProductPrice.PriceWithDiscount) - } - - -
                      - -
                      - } - else - { -

                      @T("Products.CallForPrice")

                      - } - - -
                      - @Model.BasePriceInfo -
                      - - - @if (Model.DisplayDeliveryTime && Model.IsShipEnabled) - { -
                      - @T("Products.DeliveryTime") - - @if (Model.DisplayDeliveryTimeAccordingToStock) - { - - @Model.DeliveryTimeName - } - else - { - - @Model.StockAvailability - } -
                      - } - - @if(Model.ShowLegalInfo) - { - - } - -
                      -
                      -
                      - @if (!Model.AddToCart.DisableBuyButton) - { - @Html.LabelFor(model => Model.AddToCart.EnteredQuantity, new { @class = "qty-label" }): - if (Model.AddToCart.AllowedQuantities.Count > 0) - { - @Html.DropDownListFor(model => Model.AddToCart.EnteredQuantity, Model.AddToCart.AllowedQuantities, new { @class = "qty-dropdown" }) - } - else - { - @Html.TextBoxFor(model => Model.AddToCart.EnteredQuantity, new { @class = "qty-input", style="width:25px" }) - } - - - @(Model.AddToCart.AvailableForPreOrder ? T("ShoppingCart.PreOrder") : T("ShoppingCart.AddToCart")) - - - } -
                      - -
                      - } - @Html.Widget("productdetails_add_info") \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_BackInStockSubscription.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_BackInStockSubscription.Mobile.cshtml deleted file mode 100644 index 67f10d510f..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_BackInStockSubscription.Mobile.cshtml +++ /dev/null @@ -1,15 +0,0 @@ -@model ProductDetailsModel -@using SmartStore.Web.Models.Catalog; -@if (Model.DisplayBackInStockSubscription) -{ -
                      - @if (Model.IsCurrentCustomerRegistered) - { - @T("BackInStockSubscriptions.NotifyMeWhenAvailable") - } - else - { - @T("BackInStockSubscriptions.NotifyMeWhenAvailable") - } -
                      -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_DownloadSample.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_DownloadSample.cshtml deleted file mode 100644 index edb916cf41..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_DownloadSample.cshtml +++ /dev/null @@ -1,10 +0,0 @@ -@model ProductDetailsModel -@using SmartStore.Web.Models.Catalog; -@if (Model.HasSampleDownload) -{ - -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductAttributes.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductAttributes.Mobile.cshtml deleted file mode 100644 index 6ada9cf195..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductAttributes.Mobile.cshtml +++ /dev/null @@ -1,108 +0,0 @@ -@model IList -@using SmartStore.Web.Models.Catalog; -@using SmartStore.Core.Domain.Catalog; -@using SmartStore.Core.Infrastructure; -@using SmartStore.Core; -@using System.Text; -@using System.Globalization; -@using SmartStore.Services.Customers; -@using SmartStore.Services.Security; -@using SmartStore.Web.Extensions; -@{ - var hidePrices = !EngineContext.Current.Resolve().Authorize(StandardPermissionProvider.DisplayPrices); -} -@if (Model.Count > 0) -{ -
                      -
                      - @foreach (var attribute in Model) - { - string controlId = string.Format("product_attribute_{0}_{1}_{2}_{3}", attribute.ProductId, attribute.BundleItemId, attribute.ProductAttributeId, attribute.Id); - string textPrompt = !string.IsNullOrEmpty(attribute.TextPrompt) ? attribute.TextPrompt : attribute.Name; - string disabled = (attribute.IsDisabled ? " disabled=\"disabled\"" : null); - -
                      - @textPrompt - - @if (attribute.IsRequired) - { - * - } - @if (!string.IsNullOrEmpty(attribute.Description)) - { -
                      - @Html.Raw(attribute.Description) -
                      - } -
                      -
                      - @switch (attribute.AttributeControlType) - { - case AttributeControlType.DropdownList: - { - - } - break; - case AttributeControlType.RadioList: - case AttributeControlType.ColorSquares: - { -
                        - @foreach (var pvaValue in attribute.Values) - { -
                      • - - -
                      • - } -
                      - } - break; - case AttributeControlType.Checkboxes: - { -
                        - @foreach (var pvaValue in attribute.Values) - { -
                      • - - -
                      • - } -
                      - } - break; - case AttributeControlType.TextBox: - { - - } - break; - case AttributeControlType.MultilineTextbox: - { - - } - break; - case AttributeControlType.Datepicker: - { - @Html.DatePickerDropDowns(controlId + "_day", controlId + "_month", controlId + "_year", DateTime.Now.Year, DateTime.Now.Year + 1, attribute.SelectedDay, attribute.SelectedMonth, attribute.SelectedYear, true, attribute.IsDisabled) - } - break; - case AttributeControlType.FileUpload: - { - - } - break; - } -
                      - - } -
                      -
                      -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductAttributes.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductAttributes.cshtml deleted file mode 100644 index 8c99eb957f..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductAttributes.cshtml +++ /dev/null @@ -1,245 +0,0 @@ -@model IList -@using SmartStore.Web.Models.Catalog; -@using SmartStore.Core.Domain.Catalog; -@using SmartStore.Core.Infrastructure; -@using SmartStore.Core; -@using System.Text; -@using System.Globalization; -@using SmartStore.Services.Customers; -@using SmartStore.Services.Security; -@using SmartStore.Web.Extensions; -@using SmartStore.Utilities; - -@{ - var storeUrl = EngineContext.Current.Resolve().GetStoreLocation(false); -} - -
                      - - @foreach (var attribute in Model.Where(x => x.ShouldBeRendered())) - { - string controlId = string.Format("product_attribute_{0}_{1}_{2}_{3}", attribute.ProductId, attribute.BundleItemId, attribute.ProductAttributeId, attribute.Id); - string textPrompt = !string.IsNullOrEmpty(attribute.TextPrompt) ? attribute.TextPrompt : attribute.Name; - string disabled = (attribute.IsDisabled ? " disabled=\"disabled\"" : null); - -
                      - - - @if (!string.IsNullOrEmpty(attribute.Description)) - { -
                      - @Html.Raw(attribute.Description) -
                      - } - -
                      - @switch (attribute.AttributeControlType) - { - case AttributeControlType.DropdownList: - { - - } - break; - case AttributeControlType.RadioList: - { - foreach (var pvaValue in attribute.Values) - { - if (pvaValue.ImageUrl.HasValue()) - { - if (!String.IsNullOrEmpty(pvaValue.SeName)) - { - - - - } - else - { - - } - } - - - } - - } - break; - case AttributeControlType.Checkboxes: - { - foreach (var pvaValue in attribute.Values) - { - if (pvaValue.ImageUrl.HasValue()) - { - if (!String.IsNullOrEmpty(pvaValue.SeName)) - { - - - - } - else - { - - } - } - - - } - } - break; - case AttributeControlType.TextBox: - { - - } - break; - case AttributeControlType.MultilineTextbox: - { - - } - break; - case AttributeControlType.Datepicker: - { - @Html.DatePickerDropDowns(controlId + "_day", controlId + "_month", controlId + "_year", attribute.BeginYear, attribute.EndYear, attribute.SelectedDay, attribute.SelectedMonth, attribute.SelectedYear, true, attribute.IsDisabled) - } - break; - case AttributeControlType.FileUpload: - { - Html.AddScriptParts(true, - "~/Content/fileupload/jquery.iframe-transport.js", - "~/Content/fileupload/jquery.fileupload.js", - "~/Content/fileupload/jquery.fileupload-single-ui.js"); - Html.AddCssFileParts(true, "~/Content/fileupload/jquery.fileupload-single-ui.css"); - - var random = CommonHelper.GenerateRandomInteger(); - var clientId = "upload" + CommonHelper.GenerateRandomInteger(); - - //ex. ['jpg', 'jpeg', 'png', 'gif'] or [] - var allowedFileExtensions = string.Join("|", attribute.AllowedFileExtensions.Select(x => x.Trim()).ToList()); - - -
                      - - - - - - - - @T("Common.Fileuploader.Upload") - - - - - - -
                      - -
                      -
                      -
                      - -
                       
                      -
                      - -
                      -
                      - -
                      - - - } - break; - - case AttributeControlType.ColorSquares: - { -
                        - @foreach (var pvaValue in attribute.Values) - { -
                      • - -
                      • - } -
                      - - } - break; - } -
                      -
                      - } -
                      diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBox.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBox.cshtml deleted file mode 100644 index a30dbbc0e6..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBox.cshtml +++ /dev/null @@ -1,186 +0,0 @@ -@model ProductOverviewModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Catalog; -@{ - //prepare "Add to cart" AJAX link - string addtocartlink = ""; - if (Model.ProductPrice.ForceRedirectionAfterAddingToCart) - { - addtocartlink = Url.RouteUrl("AddProductToCart-Catalog", new { productId = Model.Id, forceredirection = Model.ProductPrice.ForceRedirectionAfterAddingToCart }); - } - else - { - addtocartlink = Url.RouteUrl("AddProductToCart-Catalog", new { productId = Model.Id }); - } - - bool showQuicklinks = !Model.ProductPrice.DisableWishListButton || Model.CompareEnabled; -} - -@if (showQuicklinks) -{ - -} - -
                      - - @Model.DefaultPictureModel.AlternateText - - @if (Model.ColorAttributes.Any()) - { -
                      - @foreach (var clr in Model.ColorAttributes) - { - - } -
                      - } -
                      -
                      - - @if (Model.ShowReviews) { - int ratingPercent = 0; - if (Model.TotalReviews != 0) - { - ratingPercent = ((Model.RatingSum * 100) / Model.TotalReviews) / 5; - } - - string reviewTitle = ""; - if (Model.TotalReviews > 0) - { - reviewTitle = Model.TotalReviews + (Model.TotalReviews == 1 ? T("Reviews.Overview.Review") : T("Reviews.Overview.Reviews")); - } -
                      -
                      -
                      -
                      -
                      - } - - @{ - string name = null, nameTitle = null; - name = Model.Name.Truncate(50, "..."); - if (Model.Name.Length > name.Length) - { - nameTitle = Model.Name; - } - } -

                      - - @if (Model.IsNew) - { - @T("Common.New") - } - @name - -

                      - @{ - string desc = null, descTitle = null; - if (Model.ShortDescription.HasValue()) { - desc = Model.ShortDescription.Truncate(50, "..."); - if (Model.ShortDescription.Length > desc.Length) { - descTitle = Model.ShortDescription; - } - } - } -

                      - @Html.Raw(desc) -

                      - - @if (Model.ShowDeliveryTimes) - { -
                      - @if ((!String.IsNullOrEmpty(Model.DeliveryTimeName) && !String.IsNullOrEmpty(Model.DeliveryTimeHexValue)) && Model.IsShipEnabled) - { - @T("Products.DeliveryTime") - if(Model.DisplayDeliveryTimeAccordingToStock) - { - - } - else { - - } - - } -
                      - } - -
                      - @if (!String.IsNullOrEmpty(Model.ProductPrice.OldPrice)) - { -

                      - @Model.ProductPrice.OldPrice -

                      - } -

                      - @if (Model.ProductPrice.ShowDiscountSign && Model.ProductPrice.HasDiscount) - { - % - } - @Model.ProductPrice.Price -

                      - - @if (Model.DisplayBasePrice && !String.IsNullOrEmpty(Model.BasePriceInfo)) - { -
                      - @Model.BasePriceInfo -
                      - } - - @if (Model.TransportSurcharge.HasValue()) - { -
                      - @Model.TransportSurcharge -
                      - } -
                      - -
                      - - @if (!Model.ProductPrice.DisableBuyButton && !Model.HideBuyButtonInLists) - { - var title = (Model.ProductPrice.AvailableForPreOrder ? T("ShoppingCart.PreOrder") : T("ShoppingCart.AddToCart")); - - - - } - - - @T("Products.Details") - -
                      - - @Html.Widget("productbox_add_info") - -
                      diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxCompact.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxCompact.cshtml deleted file mode 100644 index eb0e7e1fef..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxCompact.cshtml +++ /dev/null @@ -1,30 +0,0 @@ -@model ProductOverviewModel -@using SmartStore.Core.Domain.Orders; -@using SmartStore.Web.Models.Catalog; - -
                      - - @Model.DefaultPictureModel.AlternateText -
                      -
                      - @{ - string name = null, nameTitle = null; - name = Model.Name.Truncate(50, "..."); - if (Model.Name.Length > name.Length) - { - nameTitle = Model.Name; - } - } -

                      - - @if (Model.IsNew) - { - @T("Common.New") - } - @name - -

                      -
                      -
                      @Model.ProductPrice.Price
                      -
                      -
                      \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml index 94f2b1d5d7..e1963da9a2 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBoxList.cshtml @@ -2,18 +2,18 @@ @using SmartStore.Web.Models.Catalog; @using SmartStore.Core.Domain.Orders; @{ - //prepare "Add to cart" AJAX link + // Perf: we use RouteValueDictionary instead of anonymous objects in this view because it's slightly faster + // prepare "Add to cart" AJAX link string addtocartlink = ""; if (Model.ProductPrice.ForceRedirectionAfterAddingToCart) { - addtocartlink = Url.RouteUrl("AddProductToCart-Catalog", new { productId = Model.Id, forceredirection = Model.ProductPrice.ForceRedirectionAfterAddingToCart }); + addtocartlink = Url.Action("AddProductSimple", "ShoppingCart", new RouteValueDictionary { { "productId", Model.Id }, { "forceredirection", Model.ProductPrice.ForceRedirectionAfterAddingToCart } }); } else - { - addtocartlink = Url.RouteUrl("AddProductToCart-Catalog", new { productId = Model.Id }); + { + addtocartlink = Url.Action("AddProductSimple", "ShoppingCart", new RouteValueDictionary { { "productId", Model.Id } }); } - //codehint: sm-add begin string leftContentWidth = (Model.ThumbDimension + 20).ToString() + "px"; int ratingPercent = 0; @@ -29,15 +29,16 @@ } bool showQuicklinks = !Model.ProductPrice.DisableWishListButton || Model.CompareEnabled; - - //codehint: sm-add end }
                      - - @Model.DefaultPictureModel.AlternateText - + @if (Model.DefaultPictureModel.ImageUrl.HasValue()) + { + + @Model.DefaultPictureModel.AlternateText + + } @if (Model.ColorAttributes.Any()) {
                      @@ -59,7 +60,7 @@
                      diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBundleItems.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBundleItems.cshtml deleted file mode 100644 index 19754e56b4..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBundleItems.cshtml +++ /dev/null @@ -1,100 +0,0 @@ -@model ProductDetailsModel -@using SmartStore.Web.Models.Catalog; -@using SmartStore.Web.Extensions; - -@foreach (var item in Model.BundledItems.Where(x => x.BundleItem.Visible)) -{ - string bundleItemClass = (Model.BundledItems.IndexOf(item) == 0 && !Model.RenderBundleTitle()) ? "" : " bundle-item-border"; - -
                      - - @if (item.DetailsPictureModel.DefaultPictureModel.ImageUrl.HasValue() && !item.BundleItem.HideThumbnail) - { -
                      - @item.DetailsPictureModel.AlternateText -
                      - } -
                      -
                      - @if (item.VisibleIndividually) - { - @item.Name - } - else - { - @item.Name - } - @if (item.BundleItem.Quantity > 1) - { - - × @item.BundleItem.Quantity - - } -
                      - - @if (!String.IsNullOrWhiteSpace(item.ShortDescription)) - { -
                      - @Html.Raw(item.ShortDescription.Truncate(170, "...")) - @if (item.ShortDescription.Length > 170) { ... } -
                      - } - -
                      - - - - - -
                      - @T("Products.Availability"): - - @item.StockAvailability -
                      -
                      - - @if (!(String.IsNullOrWhiteSpace(item.ProductPrice.Price) && String.IsNullOrWhiteSpace(item.ProductPrice.PriceWithDiscount))) - { -
                      - @{ - string priceClass = String.IsNullOrWhiteSpace(item.ProductPrice.PriceWithDiscount) ? "" : " older-price"; - } - - - @Html.Raw(item.ProductPrice.Price)@* no line break cause of strike through *@ - - - @Html.Raw(item.ProductPrice.PriceWithDiscount) - - -
                      - @item.BasePriceInfo -
                      -
                      - } - - @if (!String.IsNullOrEmpty(item.AttributeInfo)) - { -
                      - @Html.Raw(item.AttributeInfo) -
                      - } -
                      - - @if (item.ProductVariantAttributes.ShouldBeRendered()) - { -
                      - @Html.Partial("_ProductAttributes", item.ProductVariantAttributes, new ViewDataDictionary()) -
                      - } - - @if (item.GiftCard.IsGiftCard) - { - var dataDictBundleItemGiftCard = new ViewDataDictionary(); - dataDictBundleItemGiftCard.TemplateInfo.HtmlFieldPrefix = string.Format("giftcard_{0}_{1}", item.Id, item.BundleItem.Id); - - } -
                      -} diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBundleItemsAddToCart.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBundleItemsAddToCart.cshtml deleted file mode 100644 index 74f3873993..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductBundleItemsAddToCart.cshtml +++ /dev/null @@ -1,88 +0,0 @@ -@model ProductDetailsModel -@using SmartStore.Web.Models.Catalog; -@using SmartStore.Core.Domain.Orders; -@using System.Globalization; -@using System.Text.RegularExpressions; - -
                      - -
                      -
                      - @if (!Model.AddToCart.DisableBuyButton) - { - @*@Html.LabelFor(model => Model.AddToCart.EnteredQuantity, new { @class = "qty-label" }): - if (Model.AddToCart.AllowedQuantities.Count > 0) - { - @Html.DropDownListFor(model => Model.AddToCart.EnteredQuantity, Model.AddToCart.AllowedQuantities, new { @class = "qty-dropdown" }) - } - else - { - @Html.TextBoxFor(model => Model.AddToCart.EnteredQuantity, new { @class = "qty-input", style = "width:25px" }) - }*@ - - - @(Model.AddToCart.AvailableForPreOrder ? T("ShoppingCart.PreOrder") : T("ShoppingCart.AddToCart")) - - - } -
                      -
                      - -
                      - @if (Model.ProductPrice.PriceWithDiscount.IsNullOrEmpty()) - { - @Html.Raw(T("Products.Bundle.YouSaveWithoutDiscount", - "" + Model.ProductPrice.Price + "")); - } - else - { - @Html.Raw(T("Products.Bundle.YouSave", - "" + Model.ProductPrice.PriceWithDiscount + "", - "" + Model.ProductPrice.Price + "")); - } -
                      -
                      - -
                      - - @{ - int i = 0; - int bundleItemAmount = Model.BundledItems.Count; - } - - @foreach (var item in Model.BundledItems.Where(x => x.BundleItem.Visible)) - { - - if (item.VisibleIndividually) - { - - @item.Name - @* img and a in same line cause of hover underlines *@ - } - else - { - @item.Name - } - - if (item.BundleItem.Quantity > 1) - { - - × @item.BundleItem.Quantity - - } - - if (bundleItemAmount != (i + 1)) - { - - } - - i++; - } - -
                      diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductDetailsPictures.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductDetailsPictures.Mobile.cshtml deleted file mode 100644 index 29d30b86e0..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductDetailsPictures.Mobile.cshtml +++ /dev/null @@ -1,76 +0,0 @@ -@*codehint: sm-edit (new model)*@ -@model ProductDetailsPictureModel -@using SmartStore.Web.Models.Catalog; -@if (Model.PictureModels.Count > 0) -{ - //we do not use Model.DefaultPictureModel in mobile version - var defaultPicture = Model.PictureModels.FirstOrDefault(); -
                      - @defaultPicture.AlternateText -
                      -} -@if (Model.PictureModels.Count > 1) -{ - - -
                      -
                      -
                      - -
                      -
                      -
                      -
                      -
                      - -
                      -
                      -
                      -} \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductDetailsPictures.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductDetailsPictures.cshtml deleted file mode 100644 index 8f282cd6f1..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductDetailsPictures.cshtml +++ /dev/null @@ -1,48 +0,0 @@ -@*codehint: sm-edit (new model)*@ -@model ProductDetailsPictureModel -@using SmartStore.Web.Models.Catalog; -@{ - Html.AddScriptParts(true, - "~/Scripts/load-image.js", - "~/Content/bootstrap/js/custom/bootstrap-image-gallery.js"); - - var zoomEnabled = Model.DefaultPictureZoomEnabled; -} - \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductListOptions.cshtml b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductListOptions.cshtml index 90095e5400..0c9475b9a2 100644 --- a/src/Presentation/SmartStore.Web/Views/Catalog/_ProductListOptions.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Catalog/_ProductListOptions.cshtml @@ -1,21 +1,22 @@ @model PagingFilteringModel @using SmartStore.Web.Models.Catalog; -@* codehint: sm-add (whole file) *@ - -@helper CreateOptionChooser(IList options, string label = "", bool rightFloat = false) { +@helper CreateOptionChooser(IList options, string label = "", string icon = "", bool rightFloat = false) +{ var selectedOption = options.FirstOrDefault(x => x.Selected); var floatClass = rightFloat ? "pull-right" : "pull-left"; - if (label.HasValue()) { - - }
                      - @selectedOption.Text - - - + + @if (icon.HasValue()) + { + + } + @selectedOption.Text + + -@if (Model.BlogEnabled || Model.ForumEnabled || Model.DisplayAdminLink || Model.DisplayAdminLink) +@if (Model.NewsEnabled || Model.BlogEnabled || Model.ForumEnabled || Model.DisplayAdminLink || Model.DisplayLoginLink) { } diff --git a/src/Presentation/SmartStore.Web/Views/Common/PageNotFound.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Common/PageNotFound.Mobile.cshtml deleted file mode 100644 index 7df5b5901c..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Common/PageNotFound.Mobile.cshtml +++ /dev/null @@ -1,16 +0,0 @@ -@{ - Layout = "~/Views/Shared/_Root.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.PageNotFound").Text); -} -
                      -
                      -

                      @T("PageTitle.PageNotFound")

                      -
                      -
                      -
                      -
                      - @Html.Action("TopicBlock", "Topic", new { systemName = "PageNotFound" }) -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Views/Common/PageNotFound.cshtml b/src/Presentation/SmartStore.Web/Views/Common/PageNotFound.cshtml deleted file mode 100644 index 460b2c81e5..0000000000 --- a/src/Presentation/SmartStore.Web/Views/Common/PageNotFound.cshtml +++ /dev/null @@ -1,16 +0,0 @@ -@{ - Layout = "~/Views/Shared/_ColumnsOne.cshtml"; - - //title - Html.AddTitleParts(T("PageTitle.PageNotFound").Text); -} -
                      -
                      -

                      @T("PageTitle.PageNotFound")

                      -
                      -
                      -
                      -
                      - @Html.Action("TopicBlock", "Topic", new { systemName = "PageNotFound" }) -
                      -
                      diff --git a/src/Presentation/SmartStore.Web/Views/Common/PdfReceiptFooter.cshtml b/src/Presentation/SmartStore.Web/Views/Common/PdfReceiptFooter.cshtml new file mode 100644 index 0000000000..dfa4162d96 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Views/Common/PdfReceiptFooter.cshtml @@ -0,0 +1,99 @@ +@model PdfReceiptHeaderFooterModel +@using SmartStore.Web.Framework.Pdf; + +@{ + Layout = ViewBag.IsPartial == true ? "" : "~/Views/Shared/_Print.cshtml"; + + var company = Model.MerchantCompanyInfo; + var bank = Model.MerchantBankAccount; + var contact = Model.MerchantContactData; + +} + +@functions { + private IHtmlString JoinValues(string[] values, string separator = " ") + { + var normalized = values.Where(x => x.HasValue()); + return MvcHtmlString.Create(String.Join(separator, normalized)); + } +} + +
                      + @Html.Widget("invoice_footer_before") + + + + + + +
                      + @if (company.CompanyName.HasValue()) + { +
                      @company.CompanyName
                      + } + @{ + var fullName = JoinValues(new string[] { company.Salutation, company.Title, company.Firstname, company.Lastname }); + } + @if (fullName.ToString().HasValue()) + { +
                      @fullName
                      + } + +
                      @JoinValues(new string[] { company.Street, company.Street2 }, " · ")
                      +
                      @JoinValues(new string[] { company.ZipCode, company.City })
                      +
                      @JoinValues(new string[] { company.CountryName, company.StateName }, ", ")
                      +
                      +
                      @T("PDFInvoice.Footer.Url", Model.StoreUrl)
                      + @if (contact.ContactEmailAddress.HasValue()) + { +
                      @T("PDFInvoice.Footer.Mail", contact.ContactEmailAddress)
                      + } + @if (contact.CompanyTelephoneNumber.HasValue()) + { +
                      @T("PDFInvoice.Footer.Fon", contact.CompanyTelephoneNumber)
                      + } + @if (contact.CompanyFaxNumber.HasValue()) + { +
                      @T("PDFInvoice.Footer.Fax", contact.CompanyFaxNumber)
                      + } + @if (company.TaxNumber.HasValue()) + { +
                      @T("PDFInvoice.TaxNumber") @company.TaxNumber
                      + } + @if (company.VatId.HasValue()) + { +
                      @T("PDFInvoice.VatId") @company.VatId
                      + } + @if (company.CommercialRegister.HasValue()) + { +
                      @T("PDFInvoice.CommercialRegisterHeading") @company.CommercialRegister
                      + } +
                      + @if (bank.Bankname.HasValue()) + { +
                      @bank.Bankname
                      + } + @if (bank.Bankcode.HasValue()) + { +
                      @T("PDFInvoice.Footer.Bankcode", bank.Bankcode)
                      + } + @if (bank.AccountNumber.HasValue()) + { +
                      @T("PDFInvoice.Footer.AccountNumber", bank.AccountNumber)
                      + } + @if (bank.AccountHolder.HasValue()) + { +
                      @T("PDFInvoice.Footer.AccountHolder", bank.AccountHolder)
                      + } + @if (bank.Iban.HasValue()) + { +
                      @T("PDFInvoice.Footer.Iban", bank.Iban)
                      + } + @if (bank.Bic.HasValue()) + { +
                      @T("PDFInvoice.Footer.Bic", bank.Bic)
                      + } +
                      + @Html.Widget("invoice_footer_after") +
                      + diff --git a/src/Presentation/SmartStore.Web/Views/Common/PdfReceiptHeader.cshtml b/src/Presentation/SmartStore.Web/Views/Common/PdfReceiptHeader.cshtml new file mode 100644 index 0000000000..80e9b85716 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Views/Common/PdfReceiptHeader.cshtml @@ -0,0 +1,29 @@ +@model PdfReceiptHeaderFooterModel +@using SmartStore.Web.Framework.Pdf; + +@{ + Layout = ViewBag.IsPartial == true ? "" : "~/Views/Shared/_Print.cshtml"; +} + +
                      + @Html.Widget("invoice_header_before") + + + + + +
                      + @if (Model.LogoUrl.HasValue()) + { + + } + else + { +

                      @Model.StoreName

                      + } +
                      + @Html.Widget("invoice_header_right") +
                      + @Html.Widget("invoice_header_after") +
                      + diff --git a/src/Presentation/SmartStore.Web/Views/Common/Config.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Common/Settings.Mobile.cshtml similarity index 100% rename from src/Presentation/SmartStore.Web/Views/Common/Config.Mobile.cshtml rename to src/Presentation/SmartStore.Web/Views/Common/Settings.Mobile.cshtml diff --git a/src/Presentation/SmartStore.Web/Views/Common/Settings.cshtml b/src/Presentation/SmartStore.Web/Views/Common/Settings.cshtml new file mode 100644 index 0000000000..56cc8417bb --- /dev/null +++ b/src/Presentation/SmartStore.Web/Views/Common/Settings.cshtml @@ -0,0 +1,8 @@ +@{ + Layout = "~/Views/Shared/_ColumnsTwo.cshtml"; + + //title + Html.AddTitleParts(T("Common.Config").Text); +} +@*Desktop version doesn't have settings page +Empty page is required in case if redirection is made from mobile version ('View full' link clicked)*@ diff --git a/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml b/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml index 2050ef8e8b..1c09e0a289 100644 --- a/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Common/ShopBar.cshtml @@ -11,12 +11,12 @@
                      - + @Model.ShoppingCartItems
                      @T("ShoppingCart.Totals.SubTotal"): @Model.ShoppingCartAmount
                      - @T("Common.Shopbar.Basket") + @T("Common.Shopbar.Basket")
                      @@ -27,32 +27,33 @@ } @{ - string accountUrl = Model.IsAuthenticated ? Url.RouteUrl("CustomerInfo") : Url.RouteUrl("Login"); + string accountUrl = Model.IsAuthenticated ? Url.Action("Info", "Customer") : Url.RouteUrl("Login", new { ReturnUrl = Request.RawUrl }); }
                      - -
                      - -
                      - - @if (Model.IsAuthenticated) - { - @Model.CustomerEmailUsername
                      - - @T("Account.MyAccount") - - - } - else - { - @T("Common.Shopbar.GuestGreeting")
                      - @T("Account.Login") - } -
                      - -
                      + +
                      + +
                      + + @if (Model.IsAuthenticated) + { + @Model.CustomerEmailUsername
                      + + @T("Account.MyAccount") + + + } + else + { + @T("Common.Shopbar.GuestGreeting")
                      + @T("Account.Login") + } +
                      + +
                      + @if (Model.IsAuthenticated) { @Html.Action("AccountDropdown", "Common") @@ -67,12 +68,12 @@
                      - + @Model.WishlistItems
                      @T("Common.Shopbar.WishlistPartOne")
                      - @T("Common.Shopbar.WishlistPartTwo") + @T("Common.Shopbar.WishlistPartTwo")
                      @@ -90,12 +91,12 @@
                      - + @Model.CompareItems
                      @T("Common.Shopbar.CompareProductsPartOne")
                      - @T("Common.Shopbar.CompareProductsPartTwo") + @T("Common.Shopbar.CompareProductsPartTwo")
                      diff --git a/src/Presentation/SmartStore.Web/Views/Common/StoreThemeSelector.cshtml b/src/Presentation/SmartStore.Web/Views/Common/StoreThemeSelector.cshtml index 4088f040dc..d7d162f2b3 100644 --- a/src/Presentation/SmartStore.Web/Views/Common/StoreThemeSelector.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Common/StoreThemeSelector.cshtml @@ -2,7 +2,7 @@ @using SmartStore.Web.Models.Common; @if (Model.AvailableStoreThemes.Count > 1) { - using (Ajax.BeginForm("StoreThemeSelected", "Common", null, new AjaxOptions { OnComplete = "onStoreThemeChangedRequestCompleted();" }, new { id = "form-store-theme-selector" })) + using (Ajax.BeginForm("ChangeTheme", "Common", null, new AjaxOptions { OnComplete = "onStoreThemeChangedRequestCompleted();" }, new { id = "form-store-theme-selector" })) { var themes = Model.AvailableStoreThemes.Select(x => new SelectListItem { @@ -11,7 +11,7 @@ Selected = x.Name.Equals(Model.CurrentStoreTheme.Name, StringComparison.InvariantCultureIgnoreCase) }); - @T("StoreTheme"): @Html.DropDownList("themeName", themes, new { @class = "store-theme-list noskin" }) + @Html.DropDownList("themeName", themes, new { @class = "store-theme-list noskin" }) } *@ + + + @T("Common.Fileuploader.Upload") + + -
                      + - -
                      - - @if (!String.IsNullOrEmpty(Model.AvatarUrl)) - { - -

                      @T("Account.Avatar.UploadRules")

                      - } + +
                      + +
                      +
                      +
                      + +
                       
                      + +
                      +
                      +
                      -} \ No newline at end of file +} + + diff --git a/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.Mobile.cshtml index 8ddb014bab..5c22e04e99 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.Mobile.cshtml @@ -1,6 +1,5 @@ @model CustomerBackInStockSubscriptionsModel @using SmartStore.Web; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Models.Customer; @using SmartStore.Web.Framework.UI; @{ @@ -28,7 +27,7 @@ @Html.RouteLink(biss.ProductName, "Product", new { SeName = biss.SeName })
                    1. @@ -36,7 +35,7 @@ @if (Model.TotalPages > 1) { - @Html.SmartStore().Pager(Model).Name("paginator").Route("CustomerBackInStockSubscriptionsPaged") + @Html.SmartStore().Pager(Model).Name("paginator").Action("BackInStockSubscriptions", "Customer") } } diff --git a/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.cshtml index 2cb9d9e55f..7e4bcfc311 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/BackInStockSubscriptions.cshtml @@ -1,6 +1,5 @@ @model CustomerBackInStockSubscriptionsModel @using SmartStore.Web; -@using SmartStore.Web.Extensions; @using SmartStore.Web.Models.Customer; @using SmartStore.Web.Framework.UI; @{ @@ -31,14 +30,14 @@ $('.subscription-list .rowcheckbox').attr('checked', $(this).is(':checked')).change(); }); - $('.subscription-list .rowcheckbox').live('change', function (e) { + $(document).on('change', '.subscription-list .rowcheckbox', function (e) { var numChkBoxes = $('.subscription-list .rowcheckbox').length; var numChkBoxesChecked = $('.subscription-list .rowcheckbox:checked').length; $('#selectall').attr('checked', numChkBoxes == numChkBoxesChecked && numChkBoxes > 0); }); }); - using (Html.BeginRouteForm("CustomerBackInStockSubscriptions", FormMethod.Post)) + using (Html.BeginForm()) {
                      @@ -69,7 +68,7 @@
                      @if (Model.TotalPages > 1) { - @Html.SmartStore().Pager(Model).Name("paginator").Route("CustomerBackInStockSubscriptionsPaged") + @Html.SmartStore().Pager(Model).Name("paginator").Action("BackInStockSubscriptions", "Customer") }
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/ChangePassword.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/ChangePassword.cshtml index dc7f456ad7..3d038d3cab 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/ChangePassword.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/ChangePassword.cshtml @@ -10,7 +10,7 @@ { @Html.Partial("MyAccountNavigation", Model.NavigationModel, new ViewDataDictionary()) } -@*codehint: sm-edit*@ + @using (Html.BeginForm("ChangePassword", "Customer", FormMethod.Post, new { @class = "form-horizontal" })) { @Html.AntiForgeryToken() @@ -56,7 +56,7 @@
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/DownloadableProducts.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/DownloadableProducts.Mobile.cshtml index 769fb491ed..894ef657cb 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/DownloadableProducts.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/DownloadableProducts.Mobile.cshtml @@ -3,7 +3,6 @@ @{ Layout = "~/Views/Shared/_Root.cshtml"; - //title Html.AddTitleParts(T("PageTitle.Account").Text); } diff --git a/src/Presentation/SmartStore.Web/Views/Customer/Orders.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/Orders.cshtml index f2c3837fdb..94938bb554 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/Orders.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/Orders.cshtml @@ -1,11 +1,10 @@ -@model CustomerOrderListModel +@using SmartStore.Web.Models.Customer; +@model CustomerOrderListModel @{ Layout = "~/Views/Shared/_ColumnsTwo.cshtml"; - //title Html.AddTitleParts(T("PageTitle.Account").Text); } -@using SmartStore.Web.Models.Customer; @section left { @Html.Partial("MyAccountNavigation", Model.NavigationModel, new ViewDataDictionary()) @@ -19,7 +18,6 @@
                      @if (Model.RecurringOrders.Count > 0) { - using (Html.BeginForm()) {
                      @@ -74,18 +72,16 @@ @item.CyclesRemaining - @*codehint: sm-edit *@ - - - @string.Format(@T("Account.CustomerOrders.RecurringOrders.ViewInitialOrder").Text, item.InitialOrderId) - + + + @string.Format(@T("Account.CustomerOrders.RecurringOrders.ViewInitialOrder").Text, item.InitialOrderId) + @if (item.CanCancel) { - @*codehint: sm-edit *@ } @@ -108,46 +104,47 @@
                      } } + + @if (Model.Orders.Count == 0) + { +
                      + @T("Account.CustomerOrders.NoOrders") +
                      + } +
                      - @if (Model.Orders.Count > 0) - { - foreach (var order in Model.Orders) - { -
                      - @T("Account.CustomerOrders.OrderNumber"): @order.OrderNumber -
                      -
                      -
                      @T("Account.CustomerOrders.OrderStatus"):
                      -
                      @order.OrderStatus
                      -
                      @T("Account.CustomerOrders.OrderDate"):
                      -
                      @order.CreatedOn.ToString()
                      -
                      @T("Account.CustomerOrders.OrderTotal"):
                      -
                      @order.OrderTotal
                      -
                      -
                      - -
                      - } - } - else - { - - @T("Account.CustomerOrders.NoOrders") - - } + @foreach (var order in Model.Orders) + { +
                      + @T("Account.CustomerOrders.OrderNumber"): @order.OrderNumber +
                      +
                      +
                      @T("Account.CustomerOrders.OrderStatus"):
                      +
                      @order.OrderStatus
                      +
                      @T("Account.CustomerOrders.OrderDate"):
                      +
                      @order.CreatedOn.ToString()
                      +
                      @T("Account.CustomerOrders.OrderTotal"):
                      +
                      @order.OrderTotal
                      +
                      +
                      + +
                      + }
                      + + @Html.SmartStore().Pager(Model.Orders).Name("orders-paginator").Action("Orders", "Customer")
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.Mobile.cshtml index 77782f2fa4..b6681691c6 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.Mobile.cshtml @@ -24,7 +24,7 @@
                      @Html.LabelFor(model => model.Email) - @Html.TextBoxFor(model => model.Email, new { @class = "email" }) + @Html.TextBoxFor(model => model.Email, new { @class = "email", @type = "email" }) @Html.ValidationMessageFor(model => model.Email)
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.cshtml index 3123bb9ffd..eaca87e410 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/PasswordRecovery.cshtml @@ -29,7 +29,7 @@
                      @Html.LabelFor(model => model.Email, new { @class = "control-label required" })
                      - @Html.TextBoxFor(model => model.Email, new { @class = "email" }) + @Html.TextBoxFor(model => model.Email, new { @class = "email", @type = "email" }) @Html.ValidationMessageFor(model => model.Email)
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/Register.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/Register.Mobile.cshtml index 82d893e156..9dc2b291dc 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/Register.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/Register.Mobile.cshtml @@ -18,7 +18,7 @@ $.ajax({ cache: false, type: "GET", - url: "@(Url.RouteUrl("GetStatesByCountryId"))", + url: "@(Url.Action("GetStatesByCountryId", "Country"))", data: { "countryId": selectedItem, "addEmptyStateIfRequired": "true" }, success: function (data) { ddlStates.html(''); @@ -168,10 +168,10 @@ } @if (Model.ZipPostalCodeEnabled) { -
                      @Html.LabelFor(model => model.ZipPostalCode) @Html.EditorFor(model => model.ZipPostalCode) - @Html.ValidationMessageFor(model => model.ZipPostalCode)> + @Html.ValidationMessageFor(model => model.ZipPostalCode)
                      } @if (Model.CityEnabled) @@ -186,14 +186,14 @@ {
                      @Html.LabelFor(model => model.CountryId) - @Html.DropDownList("CountryId", Model.AvailableCountries) + @Html.DropDownList("CountryId", Model.AvailableCountries, new { data_native_menu = "false" })
                      } @if (Model.CountryEnabled && Model.StateProvinceEnabled) {
                      @Html.LabelFor(model => model.StateProvinceId) - @Html.DropDownList("StateProvinceId", Model.AvailableStates) + @Html.DropDownList("StateProvinceId", Model.AvailableStates, new { data_native_menu = "false" })
                      }
                      @@ -245,7 +245,7 @@ {
                      @Html.LabelFor(model => model.TimeZoneId) - @Html.DropDownList("TimeZoneId", Model.AvailableTimeZones) + @Html.DropDownList("TimeZoneId", Model.AvailableTimeZones, new { data_native_menu = "false" }) @Html.ValidationMessageFor(model => model.TimeZoneId)
                      } diff --git a/src/Presentation/SmartStore.Web/Views/Customer/Register.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/Register.cshtml index 7cea4c8fbf..165aca91df 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/Register.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/Register.cshtml @@ -2,7 +2,6 @@ @using SmartStore.Core.Infrastructure; @using SmartStore.Core.Infrastructure.DependencyManagement; -@*codehint: sm-refactored-completly *@ @model RegisterModel @using SmartStore.Web.Models.Customer; @{ @@ -23,7 +22,7 @@ $.ajax({ cache: false, type: "GET", - url: "@(Url.RouteUrl("GetStatesByCountryId"))", + url: "@(Url.Action("GetStatesByCountryId", "Country"))", data: { "countryId": selectedItem, "addEmptyStateIfRequired": "true" }, success: function (data) { ddlStates.html(''); @@ -137,10 +136,12 @@ @if (Model.DisplayVatNumber) {
                      - @Html.LabelFor(model => model.VatNumber, new { @class = "control-label", @for = "VatNumber" }) + @Html.LabelFor(model => model.VatNumber, new { @class = "control-label" + (Model.VatRequired ? " required" : ""), @for = "VatNumber" })
                      - @Html.TextBoxFor(model => model.VatNumber, new { placeholder = "Optional" })   @Model.VatNumberStatusNote + @Html.EditorFor(model => model.VatNumber, new { placeholder = Model.VatRequired ? "" : "Optional" })   @Model.VatNumberStatusNote @T("Account.Fields.VatNumber.Note") + + @Html.ValidationMessageFor(model => model.VatNumber)
                      } diff --git a/src/Presentation/SmartStore.Web/Views/Customer/RegisterResult.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/RegisterResult.cshtml index a3a9ac9314..c4bcbfbfdb 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/RegisterResult.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/RegisterResult.cshtml @@ -4,21 +4,17 @@ @using SmartStore.Core.Infrastructure; @using SmartStore.Core.Infrastructure.DependencyManagement; @{ - Layout = "~/Views/Shared/_ColumnsThree.cshtml"; + Layout = "~/Views/Shared/_ColumnsThree.cshtml"; - //title - Html.AddTitleParts(T("PageTitle.Register").Text); + // title + Html.AddTitleParts(T("PageTitle.Register").Text); - //continue URL - var continueUrl = ""; - if (!String.IsNullOrEmpty(this.Context.Request.QueryString["returnUrl"])) - { - continueUrl = this.Context.Request.QueryString["returnUrl"]; - } - else - { - continueUrl = Url.RouteUrl("HomePage"); - } + // continue URL + var continueUrl = this.Context.Request.QueryString["returnUrl"]; + if (!continueUrl.HasValue() || (continueUrl.HasValue() && !Url.IsLocalUrl(continueUrl))) + { + continueUrl = Url.RouteUrl("HomePage"); + } }
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.Mobile.cshtml index a8a56e20ad..7882db1446 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.Mobile.cshtml @@ -3,7 +3,6 @@ @{ Layout = "~/Views/Shared/_Root.cshtml"; - //title Html.AddTitleParts(T("PageTitle.Account").Text); }
                      - @T("Account.CustomerReturnRequests.Item") @item.ProductName + @T("Account.CustomerReturnRequests.Item") + @item.ProductName x @item.Quantity
                      @@ -35,7 +35,8 @@ @string.Format(T("Account.CustomerReturnRequests.Date").Text, item.CreatedOn.ToString())
                      @if (!String.IsNullOrEmpty(item.Comments)) - {
                      + { +
                      @T("Account.CustomerReturnRequests.Comments")
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.cshtml index f913a29eef..06e0467f9e 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/ReturnRequests.cshtml @@ -3,7 +3,6 @@ @{ Layout = "~/Views/Shared/_ColumnsTwo.cshtml"; - //title Html.AddTitleParts(T("PageTitle.Account").Text); } @section left @@ -14,16 +13,20 @@

                      @T("Account.MyAccount") - @T("Account.CustomerReturnRequests")

                      -
                      -
                      + +
                      +
                      @foreach (var item in Model.Items) {
                      - @string.Format(T("Account.CustomerReturnRequests.Title").Text, item.Id, item.ReturnRequestStatus) + + @string.Format(T("Account.CustomerReturnRequests.Title").Text, item.Id, item.ReturnRequestStatus) +
                      - @T("Account.CustomerReturnRequests.Item") @item.ProductName + @T("Account.CustomerReturnRequests.Item") + @item.ProductName x @item.Quantity
                      @@ -46,8 +49,8 @@ }
                      -
                      -
                      + +
                      }
                      diff --git a/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.Mobile.cshtml index c146487173..7d2b9708d1 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.Mobile.cshtml @@ -26,7 +26,7 @@
                    2. - @T("RewardPoints.Fields.Date"): @rph.CreatedOn + @T("Common.CreatedOn"): @rph.CreatedOn
                      @T("RewardPoints.Fields.Points"): @rph.Points diff --git a/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.cshtml index e026a89644..84d42b2d54 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/RewardPoints.cshtml @@ -33,7 +33,7 @@ - @T("RewardPoints.Fields.Date") + @T("Common.CreatedOn") @T("RewardPoints.Fields.Points") diff --git a/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.Mobile.cshtml index 51d22035f8..38d9fe65bc 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.Mobile.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.Mobile.cshtml @@ -49,7 +49,7 @@
                    3. diff --git a/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.cshtml index 41b21ae1d3..40de7650cd 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/UserAgreement.cshtml @@ -13,25 +13,33 @@ function toggleContinueButton() { if ($('#agreement-agree').is(':checked')) { - $('#continue-downloading').removeAttr('disabled'); + $('#continue-downloading').removeAttr('disabled').addClass("btn-info"); } else { - $('#continue-downloading').attr('disabled', 'disabled'); + $('#continue-downloading').attr('disabled', 'disabled').removeClass("btn-info"); } } +

                      @T("DownloadableProducts.UserAgreement")

                      -
                      -
                      - @Html.Raw(Model.UserAgreementText) -
                      - +
                      + @Html.Raw(Model.UserAgreementText)
                      - + + +

                      + +
                      -
                      +
                      \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Customer/_CheckUsernameAvailability.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/_CheckUsernameAvailability.cshtml index 4078e8998e..fffbbe4a6b 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/_CheckUsernameAvailability.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/_CheckUsernameAvailability.cshtml @@ -1,26 +1,26 @@  \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Customer/_ExternalAuthentication.AssociateMessage.cshtml b/src/Presentation/SmartStore.Web/Views/Customer/_ExternalAuthentication.AssociateMessage.cshtml index 7ddd11c290..247ec19e35 100644 --- a/src/Presentation/SmartStore.Web/Views/Customer/_ExternalAuthentication.AssociateMessage.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Customer/_ExternalAuthentication.AssociateMessage.cshtml @@ -6,8 +6,8 @@ {
                      @T("Account.AssociatedExternalAuth.YourAccountWillBeLinkedTo") @openAuthParameters.ExternalIdentifier - - (@T("Common.Remove")) - + + (@T("Common.Remove")) +
                      } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Filter/Products.cshtml b/src/Presentation/SmartStore.Web/Views/Filter/Products.cshtml index c8155ee2db..0cd18a8d77 100644 --- a/src/Presentation/SmartStore.Web/Views/Filter/Products.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Filter/Products.cshtml @@ -3,42 +3,50 @@ @model ProductFilterModel @{ - Layout = null; + Layout = null; } -@helper FilterGroupContent(IEnumerable criteria) { - if (criteria == null) { +@helper FilterGroupContent(IEnumerable criteria) +{ + if (criteria == null) + { return; } foreach (var itm in criteria) {
                      - @if (itm.IsInactive) { - @itm.ToDescription() - (@itm.MatchCount) - } - else { - - - -
                      @itm.ToDescription()
                      - } + @if (itm.IsInactive) + { + @itm.ToDescription() + (@itm.MatchCount) + } + else + { + + + +
                      @itm.ToDescription()
                      + }
                      } - if (criteria.Count() > 0) { + if (criteria.Count() > 0) + { } - else { + else + {
                      @T("Products.Filter.NoneFound").
                      } } -@helper FilterGroup(IEnumerable criteria, string caption, bool show = true) { - if (criteria == null || criteria.Any()) { +@helper FilterGroup(IEnumerable criteria, string caption, bool show = true) +{ + if (criteria == null || criteria.Any()) + {
                      c.IsInactive) ? "" : " static")">
                      @@ -51,18 +59,23 @@ } } -@if (Model.Context.Criteria.Count <= 0) { +@if (Model.Context.Criteria.Count <= 0) +{
                      @T("Products.Filter.NoneFound").
                      } -else { - @FilterGroup(Model.Context.Criteria.Where(c => c.Entity == FilterService.ShortcutPrice), T("Products.Price"), true) +else +{ + @FilterGroup(Model.Context.Criteria.Where(c => c.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutPrice)), T("Products.Price"), true) - @FilterGroup(Model.Context.Criteria.Where(c => c.Entity == "Manufacturer"), T("Products.Manufacturer"), true) + @FilterGroup(Model.Context.Criteria.Where(c => c.Entity.IsCaseInsensitiveEqual("Manufacturer")), T("Products.Manufacturer"), true) - foreach (var grp in Model.Context.Criteria.Where(c => c.Entity == FilterService.ShortcutSpecAttribute).GroupBy(c => c.Name).OrderBy(g => g.Key)) { - bool isActive = (Model.Context.Criteria.FirstOrDefault(c => c.Entity == FilterService.ShortcutSpecAttribute && c.Name == grp.Key && !c.IsInactive) != null); + foreach (var grp in Model.Context.Criteria.Where(c => c.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutSpecAttribute)).GroupBy(c => c.Name)) + { + var first = grp.FirstOrDefault(); + bool isActive = (Model.Context.Criteria.FirstOrDefault(c => c.Entity.IsCaseInsensitiveEqual(FilterService.ShortcutSpecAttribute) && c.Name.IsCaseInsensitiveEqual(grp.Key) && !c.IsInactive) != null); var criterias = grp.Where(c => c.IsInactive != isActive); - - @FilterGroup(isActive ? criterias : criterias.Take(FilterService.MaxDisplayCriteria), grp.Key, isActive) + var caption = (first != null && first.NameLocalized.HasValue() ? first.NameLocalized : grp.Key); + + @FilterGroup(isActive ? criterias : criterias.Take(Model.MaxFilterItemsToDisplay), caption, Model.ExpandAllFilterGroups ? true : isActive) } } \ No newline at end of file diff --git a/src/Presentation/SmartStore.Web/Views/Filter/ProductsMultiSelect.cshtml b/src/Presentation/SmartStore.Web/Views/Filter/ProductsMultiSelect.cshtml index 7bf5889e53..f841e6caa2 100644 --- a/src/Presentation/SmartStore.Web/Views/Filter/ProductsMultiSelect.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Filter/ProductsMultiSelect.cshtml @@ -14,7 +14,8 @@ - @foreach (var itm in Model.Context.Criteria.Where(c => c.IsInactive).OrderBy(c => c.Value)) { + @foreach (var itm in Model.Context.Criteria.Where(c => c.IsInactive).OrderBy(c => c.Value)) + {
                      @Html.LabelFor(model => model.Email) - @Html.TextBoxFor(model => model.Email, new { @class = "email" }) + @Html.TextBoxFor(model => model.Email, new { @class = "email", @type = "email" }) @Html.ValidationMessageFor(model => model.Email)
                      diff --git a/src/Presentation/SmartStore.Web/Views/Home/ContactUs.cshtml b/src/Presentation/SmartStore.Web/Views/Home/ContactUs.cshtml new file mode 100644 index 0000000000..7105b3d794 --- /dev/null +++ b/src/Presentation/SmartStore.Web/Views/Home/ContactUs.cshtml @@ -0,0 +1,98 @@ +@model ContactUsModel +@using SmartStore.Web.Models.Common; +@{ + Layout = "~/Views/Shared/_ColumnsTwo.cshtml"; + + //title + Html.AddTitleParts(T("PageTitle.ContactUs").Text); +} +
                      + @Html.Action("TopicBlock", "Topic", new { systemName = "ContactUs" }) + +
                      + @Html.Widget("contactus_top") + @if (Model.SuccessfullySent) + { +
                      + + @Model.Result +
                      + } + else + { + using (Html.BeginRouteForm("ContactUs", FormMethod.Post, new { @class = "form-horizontal" })) + { +
                      + + @T("PageTitle.ContactUs") + +
                      + @Html.LabelFor(model => model.FullName, new { @class="control-label required" , @for="FullName" } ) +
                      + @Html.TextBoxFor(model => model.FullName, new { @class = "fullname", placeholder = T("ContactUs.FullName.Hint") }) + @Html.ValidationMessageFor(model => model.FullName) +
                      +
                      + +
                      + @Html.LabelFor(model => model.Email, new { @class="control-label required" , @for="Email" } ) +
                      + @Html.TextBoxFor(model => model.Email, new { @class = "email", @type = "email", placeholder = T("ContactUs.Email.Hint") }) + @Html.ValidationMessageFor(model => model.Email) +
                      +
                      + +
                      + @Html.LabelFor(model => model.Enquiry, new { @class="control-label required" , @for="Enquiry" } ) +
                      + @Html.TextAreaFor(model => model.Enquiry, new { @class = "enquiry", placeholder = T("ContactUs.Enquiry.Hint") }) + @Html.ValidationMessageFor(model => model.Enquiry) +
                      +
                      + + @if(Model.DisplayPrivacyAgreement) + { + @Html.HiddenFor(model => model.DisplayPrivacyAgreement) + +
                      + @Html.LabelFor(model => model.PrivacyAgreement, new { @class = "control-label required", @for = "PrivacyAgreement" }) +
                      +
                      + +
                      +
                      + @Html.ValidationMessageFor(model => model.PrivacyAgreement) +
                      +
                      +
                      + } + + @if (Model.DisplayCaptcha) + { +
                      +
                      + @Html.Raw(Html.GenerateCaptcha()) +
                      +
                      + } + +
                      +
                      + +
                      +
                      + +
                      + } + } + @Html.Widget("contactus_bottom") +
                      +
                      diff --git a/src/Presentation/SmartStore.Web/Views/Home/ContentSlider.cshtml b/src/Presentation/SmartStore.Web/Views/Home/ContentSlider.cshtml index df967860e9..b0bb365ac3 100644 --- a/src/Presentation/SmartStore.Web/Views/Home/ContentSlider.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Home/ContentSlider.cshtml @@ -1,6 +1,7 @@ @model ContentSliderSettings + @using SmartStore.Core.Domain.Cms; -@using SmartStore.Web.Framework.Themes; +@using SmartStore.Web.Framework.Theming; @functions { @@ -22,11 +23,8 @@ if (isActive) { - Html.AddCssFileParts(false, Html.ThemePath("Content/slider.less")); - Html.AddScriptParts( - "~/Scripts/jquery.backgroundpos.js", - "~/Scripts/jquery.sequence.js", - "~/Scripts/jquery.sequence.custom.js"); + Html.AddCssFileParts(false, Html.ThemePath("Content/slider.less")); + Html.AddScriptParts("~/bundles/sequencejs"); } } @@ -65,15 +63,15 @@ @if (slide.Button1.Published || slide.Button2.Published || slide.Button3.Published) {
                      - @if (slide.Button1.Published) + @if (slide.Button1.Published && slide.Button1.Url.HasValue()) { @slide.Button1.Text } - @if (slide.Button2.Published) + @if (slide.Button2.Published && slide.Button2.Url.HasValue()) { @slide.Button2.Text } - @if (slide.Button3.Published) + @if (slide.Button3.Published && slide.Button3.Url.HasValue()) { @slide.Button3.Text } @@ -82,7 +80,7 @@ @if (!String.IsNullOrEmpty(@slide.PictureUrl)) { -
                      +
                      @slide.Title
                      } } diff --git a/src/Presentation/SmartStore.Web/Views/Home/Index.cshtml b/src/Presentation/SmartStore.Web/Views/Home/Index.cshtml index bd6753de94..5354d21ea5 100644 --- a/src/Presentation/SmartStore.Web/Views/Home/Index.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Home/Index.cshtml @@ -1,8 +1,9 @@ -@using SmartStore.Web.Framework.Themes; +@using SmartStore.Web.Framework.Theming; @{ Layout = "~/Views/Shared/_ColumnsThree.cshtml"; } +
                      @Html.Widget("home_page_top") diff --git a/src/Presentation/SmartStore.Web/Views/Common/Sitemap.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Home/Sitemap.Mobile.cshtml similarity index 100% rename from src/Presentation/SmartStore.Web/Views/Common/Sitemap.Mobile.cshtml rename to src/Presentation/SmartStore.Web/Views/Home/Sitemap.Mobile.cshtml diff --git a/src/Presentation/SmartStore.Web/Views/Common/Sitemap.cshtml b/src/Presentation/SmartStore.Web/Views/Home/Sitemap.cshtml similarity index 100% rename from src/Presentation/SmartStore.Web/Views/Common/Sitemap.cshtml rename to src/Presentation/SmartStore.Web/Views/Home/Sitemap.cshtml diff --git a/src/Presentation/SmartStore.Web/Views/Common/StoreClosed.Mobile.cshtml b/src/Presentation/SmartStore.Web/Views/Home/StoreClosed.Mobile.cshtml similarity index 100% rename from src/Presentation/SmartStore.Web/Views/Common/StoreClosed.Mobile.cshtml rename to src/Presentation/SmartStore.Web/Views/Home/StoreClosed.Mobile.cshtml diff --git a/src/Presentation/SmartStore.Web/Views/Common/StoreClosed.cshtml b/src/Presentation/SmartStore.Web/Views/Home/StoreClosed.cshtml similarity index 89% rename from src/Presentation/SmartStore.Web/Views/Common/StoreClosed.cshtml rename to src/Presentation/SmartStore.Web/Views/Home/StoreClosed.cshtml index e848f13ad2..f174ee3abe 100644 --- a/src/Presentation/SmartStore.Web/Views/Common/StoreClosed.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Home/StoreClosed.cshtml @@ -3,13 +3,12 @@ //title Html.AddTitleParts(T("PageTitle.StoreClosed").Text); + Html.AddBodyCssClass("store-closed"); }

                      @T("StoreClosed")

                      -
                      -
                      @T("StoreClosed.Hint")
                      diff --git a/src/Presentation/SmartStore.Web/Views/Install/Index.cshtml b/src/Presentation/SmartStore.Web/Views/Install/Index.cshtml index d40a4e3cfc..c368339816 100644 --- a/src/Presentation/SmartStore.Web/Views/Install/Index.cshtml +++ b/src/Presentation/SmartStore.Web/Views/Install/Index.cshtml @@ -23,11 +23,15 @@ @Html.Partial("ConditionalComments") @* styles *@ + @* scripts (head) *@ - - + + + + + @@ -111,20 +115,57 @@ -
                      - -
                      -